Merge some features from BS1.9 beta4 (#5181)

* FIX: linux: fix the building issue on Linux Mint 21.3 Virginia

github: https://github.com/bambulab/BambuStudio/issues/3874
author: https://github.com/lucianoloder

Change-Id: Ia3db6923d5dd68dba532d7bdba6f93f73cc51d59

* FIX: auto-arranging incorrect with rotation enabled

auto-arranging incorrect with rotation enabled and the objects already have been rotated.

jira: STUDIO-6022
Change-Id: I349d663efb1fc71367c8a77aa8ed5047a0bf2017
(cherry picked from commit 75fe40257a274ed83886e1ee20ce8dedd0de48f6)

* ENH: update X1C & X1E start gcode

1.Fix fan problem

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I68ee5be78e142e8a2a210a1a70f5663893390610

* ENH: update A series gcode

1. Update A1 series start gcode and change filament gcode
2. Add G2814 command
3. Add multi-filament extrusion compensation and vibration suppression

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I57d2bc8e98d3e547881dc1369c1fb31413c6205d

* FIX: fix some cali problem of P series

jira: none
Change-Id: Id57ea8d65da22ab653cca49509cb923ff065e43f

* FIX: fix can't enter ',' in multiplicator

github: #3805

Change-Id: I6dd70822d1c2e79d66c70514d6dd580ab029c7ea

* calib wizard

* NEW: FlipLines infill

jira:6701

New infill pattern that combine block lines infill and switching layers for smooth transition.

Change-Id: I2608a2d39b14efcdfe9d39a9437280da350b94c0
(cherry picked from commit 8d0a09c8b763dfc924cbba9913c241e6afadbc7f)

* ENH: add nozzle blob detection and air printing detection

jira: new

Change-Id: Ie4a19a7ad7d0b10a021c516cbc3a84b4ae734302

* FIX: Top surface bridging fail on 3DHC & FL infill

Add 45 degree angle offset when processing the bridge.
Need to raise infill_direction to invalidate posPrepareInfill

jira: 6774
Change-Id: I5e6bef3aa814b01c5f30398ac745937a67e3ef4c
(cherry picked from commit 7b12cab10b88f432a11414f8caa1c6427777a1ba)

* FIX: the error display when reset virtual slot

jira: none
Change-Id: I5ae5899baf1bfc2aaadb832083b277855a669fd5

* FIX: Error "Voronoi cell doesn't contain a sourcepoint"

github: 3859
Change-Id: Idca84992bcba5380bfe05e63ac9a5e40419dcfdf

* fix build error

* FIX: CLI: fix the crash issue caused by get_min_flush_volumes

JIRA: no jira
Change-Id: I0d5bfd605e51ebddac8fddc4d83dab5055b0fbf2

* FIX: can't use support filament in gcode.3mf

1. Add total_filament_volumes, directly access it to get used filaments

github:#3865

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I4fae4f1947b4ebd16e394e0f3cf5fb0e9f979717

* ENH: p series support long retraction

1. P series support long retraction in filament
2. Add long retraction params in common.json

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: Ib94184fa1f0b5ab151360f1f053d8c8ff92e7e18

* ENH::modify some logs level

jira:[for log]

Change-Id: I6a46b8fcd3a030b4b630e800fe9a9ac5c387f117

* NEW: support multi device

JIRA: STUDIO-6072

Change-Id: Ic514c4097767b0a728368c9ea48ee103c031fbb0
Signed-off-by: Stone Li <stone.li@bambulab.com>

* ENH: update A1 series  gcode

1.Update filament change gcode and machine start gcode for
  A1 and A1 mini

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I2f3be3fd89fef21e717a32f2b89985fc046f7f6e

* FIX: always have 0th filament in ams mapping

1. Only set the filament id in map when flush length is not 0

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I6e0aeaf010f6e6dcbdc3bca5c0034aa60750bb67

* ENH: add filament id in slice info

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: Ic5fe4632bca8acacc9ffd072ee2ed207c1da37aa

* ENH: refine ui for multi machine

JIRA: STUDIO-6819 STUDIO-6824
1. Shrink the Send Print dialog box
2. add input box for flipping panel

Change-Id: I4174c79ecd239c374ee11478951e12be399c57ce

* FIX: fix Issues with sending multiple devices

JIRA: STUDIO-6876

Signed-off-by: Kunlong Ma <kunlong.ma@bambulab.com>
Change-Id: I33c6a932863fc715c3f0eb5dfd4b299f980a4918

* NEW: support hms error code

Change-Id: Ic256a83cf501fb05bb9d3203f3d24cb1d1290fa4

* FIX:fixed some multi job issue

Change-Id: I338078ad8fcf809888db9d8daeb470a9bf4eab46

* NEW:support pin code binding

Change-Id: Ida5d47881fbd83f3ffedc80369cfe377114d7f13

* ENH:add printable check for devices

Change-Id: I672988fa9cfa986d924bfc64331752f4aef68067
(cherry picked from commit 69de9e5b8334ec94eec7fcee31038b8ff42d1d3b)

* FIX: add more fonts

jira: none
Change-Id: I6bafed3563083858f29e92a3d84906a2e53dcb5c
(cherry picked from commit afbea693e807dcc1c406a59aa5376b9ea2a5d606)

* ENH: load more fonts

this feature is according to Prusa by Filip Sykala<filip.sykala@prusa3d.cz>, thanks to Filip Sykala
jira: none
Change-Id: I55e92f184f750c0b93b679d4382aaa5b164ec5c3
(cherry picked from commit d05522c4cc5d7ee4cac42de398b88d347a55f74b)

* ENH: add ProfileDescription for translate

1.Add ProfileDescription.hpp simply for translating

jira:NEW

Signed-off-by: XunZhangBambu <xun.zhang@bambulab.com>
Change-Id: Iaa3ced1edccf67eaeebde35c1e8b36442d2e9a6f

* ENH: Improve CrossHatch transation layers

jira: 6701

Change name from Flippingline to CrossHatch.

Reduce noise, improve speed by 6.5%. Improve transation layers by
gradually increasing rotation angle and overshoot the transation
layer while direction changed.

Change-Id: I17fcc45b409074d121bf5bb5702e15553d925b51

* UP

* ENH: modify the default config for multi-device

JIRA: STUDIO-6072

Change-Id: If6e7582a8274eb5e685b8b8545f6eab5d17de3f5
Signed-off-by: Stone Li <stone.li@bambulab.com>

* ENH: add long retraction for P series

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I6890695b67e674fc5cdc2a208e89bd9e41404213

* FIX: all plates stats data missing issue

jira: new

Change-Id: I137a2b6d69ad08791f5a9a9788653621960dc63f

* ENH:update pre print options

jira:[for multi]

Change-Id: I2e9bb8a09436a71749af98a0bad94e9922f95c81

* FIX:fixed can't popup pinbind win on macos

jira:[STUDIO-6895]

Change-Id: I664bba78cf27420d736b586df19e3c09c6f8ed21

* FIX:fixed the task of padding cannot be cancelled

Change-Id: I401a22118c14ca7601be7a925cfd8e4796dfc1e9

* ENH:Play video after redirecting to device page

jira:[STUDIO-6884]

Change-Id: Ia5e2ac84e3d71baacfcf941b782dab2325f35d54

* FIX: fix ui bug in send multi machine page for mac

JIRA: STUDIO-6882
Incorrect background color when renaming during multi machine printing

Change-Id: I6c551f5023ffe747e7a7e2f5703b0707c9505922

* FIX: Fix some bugs in maintaining the selected status of local tasks

JIRA: STUDIO-6824

Change-Id: I12c4da3fc56ac5077b3ccd7e89a4b57c3675eaf5

* ENH: local task sort by send time by default

JIRA: STUDIO-6885

Change-Id: I03b5881a39ab2e90c5b9cf46052ba465ee707ccc

* FIX: Clicking to continue printing does not take effect in error code

JIRA: STUDIO-6830
Detected an incomplete printing task error pop-up when power outage occurred. Clicking to continue printing did not take effect

Change-Id: Ie85a1602093dabac861cd1f41ea21e1c312c83e9

* ENH: use designTitle when designId > 0

JIRA: STUDIO-6072

Change-Id: I8342df053edeab16f930522e099e2eef91e5c5a4
Signed-off-by: Stone Li <stone.li@bambulab.com>

* NEW:import vertex and mtl color from obj file

Jira: STUDIO-6805

Change-Id: Iaacb13ee2451effdb83e5aba4b7fe1637b7fc95f

* FIX:change the strategy of merge_ka_kd

Upgrade ui, users can directly ok to proceed to the next step
jira: STUDIO-6805

Change-Id: Ia81019c2eacb503666680c0b8583d026baa0134c
(cherry picked from commit 38a2434753c8e3b422267283b16c75f6ad195b14)

* FIX:use default_strategy after modifed cluster number

jira: STUDIO-6915
Change-Id: I4e0c3d62f5a766f73d48d1e06c4364fc6babe1ac

* FIX: the bug of incorrect button without restarting

JIRA: STUDIO-6824
The bug can cause the user to not restart when opening the multi-device option, but the button of send multi-devices appears

Change-Id: I0837fa79ecc1d8ab5ce98273ad134fa2f830421e

* FIX: wrong default value for long retraction

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: Ifc2ec57a320fdb14e7ca746e5795501ed146ff32

* FIX: error code pop-up window without retry button in some code

JIRA: STUDIO-6922

Change-Id: I67464bebaba4558618301592c455db8824bbfe30

* FIX: air printing and nozzle blob detection issue

jira: STUDIO-6897

Change-Id: I008ddb24b74119d7e4124ae26310b4b86c42a799

* FIX:fix bugs of algo and read quad in obj file

Jira: STUDIO-6805
Change-Id: I6c33e8197225f27dccdfa0681e64d76d1df14f61

* dd

* ENH:Set the default nozzle diameter to 0.4

jira:[for nozzle]

Change-Id: I74a5c9b0460046496b897eae3d9f917ac1b99052

* FIX:fixed backspace error on macos

Change-Id: I76066391783c04857c1a60a6f8438111501b6d7c

* ENH:Subscription list deduplication

jira:[for mulit]

Change-Id: I10e9d849986c9661b587c7b1a509180c2451816e

* ENH:update wiki url for Pin Code

jira:[pin code]

Change-Id: I95faaa396a839b5b159119ef235b650c76706a84

* NEW:add OpenCV.cmake in deps

jira: none
Change-Id: I1ae4a2bd5618e9e620b08a937904d6af5d00bc41

* FIX:cancel obj import restrictions

jira: none
Change-Id: Iaf3e799ca982ad6aeb3ec76e9a416c4c8e4d100c

* NEW:add multiple printer restrictions

jira:[for multiple]

Change-Id: I0bb5a0c1062a543c42f8d67a9347efa358b0864a

* ENH:Added two entrances for adding devices

jira:[multi device]

Change-Id: Ieb6197e067d422979606f93b22b337a2399aec74

* slic3r: Fix wxFont being undefined

[427/494] Building CXX object src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o
FAILED: src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o
/usr/bin/c++ -DBOOST_ATOMIC_NO_LIB -DBOOST_CHRONO_NO_LIB -DBOOST_DATE_TIME_NO_LIB -DBOOST_FILESYSTEM_NO_LIB -DBOOST_IOSTREAMS_NO_LIB -DBOOST_LOCALE_NO_LIB -DBOOST_LOG_NO_LIB -DBOOST_REGEX_NO_LIB -DBOOST_SYSTEM_NO_LIB -DBOOST_THREAD_NO_LIB -DCURL_STATICLIB -DGLEW_STATIC -DLIBNEST2D_GEOMETRIES_libslic3r -DLIBNEST2D_OPTIMIZER_nlopt -DLIBNEST2D_STATIC -DLIBNEST2D_THREADING_tbb -DOPENSSL_CERT_OVERRIDE -DOPENVDB_OPENEXR_STATICLIB -DOPENVDB_STATICLIB -DSLIC3R_CURRENTLY_COMPILING_GUI_MODULE -DSLIC3R_GUI -DTBB_USE_CAPTURED_EXCEPTION=0 -DUNICODE -DUSE_TBB -DWXINTL_NO_GETTEXT_MACRO -D_UNICODE -D__WXGTK3__ -D__WXGTK__ -DwxDEBUG_LEVEL=0 -DwxNO_UNSAFE_WXSTRING_CONV -DwxUSE_UNICODE -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/run/build/BambuStudio/src -I/run/build/BambuStudio/build/src/platform -I/run/build/BambuStudio/src/hidapi/include -I/run/build/BambuStudio/src/slic3r/Utils -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/webp -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/atk-1.0 -I/usr/include/fribidi -I/usr/include/pixman-1 -I/usr/include/harfbuzz -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/gio-unix-2.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/sysprof-6 -I/usr/include/gstreamer-1.0 -I/run/build/BambuStudio/build/src/libslic3r -I/run/build/BambuStudio/deps/build/destdir/usr/local/include/opencascade -I/run/build/BambuStudio/src/libnest2d/include -I/run/build/BambuStudio/src/miniz -I/run/build/BambuStudio/src/glu-libtess/include -I/run/build/BambuStudio/src/clipper2/Clipper2Lib/include -I/run/build/BambuStudio/src/minilzo -isystem /run/build/BambuStudio/src/eigen -isystem /run/build/BambuStudio/src/libigl -isystem /app/lib/wx/include/gtk3-unicode-static-3.1 -isystem /app/include/wx-3.1 -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include/opencv4 -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include/OpenEXR -std=gnu++20 -fext-numeric-literals -Wall -Wno-reorder -pthread -O3 -DNDEBUG -std=gnu++17 -fPIC -fsigned-char -Werror=return-type -Wno-ignored-attributes -Wno-unknown-pragmas -DOPENVDB_ABI_VERSION_NUMBER=8 -MD -MT src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o -MF src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o.d -o src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o -c /run/build/BambuStudio/src/slic3r/Utils/FontUtils.cpp
In file included from /run/build/BambuStudio/src/slic3r/Utils/FontUtils.cpp:1:
/run/build/BambuStudio/src/slic3r/Utils/FontUtils.hpp:51:21: error: ‘wxFont’ does not name a type
   51 | bool can_load(const wxFont &font);
      |                     ^~~~~~

* slic3r: Fix missing BOOST_LOG_TRIVIAL declaration

[427/494] Building CXX object src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o
FAILED: src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o
/usr/bin/c++ -DBOOST_ATOMIC_NO_LIB -DBOOST_CHRONO_NO_LIB -DBOOST_DATE_TIME_NO_LIB -DBOOST_FILESYSTEM_NO_LIB -DBOOST_IOSTREAMS_NO_LIB -DBOOST_LOCALE_NO_LIB -DBOOST_LOG_NO_LIB -DBOOST_REGEX_NO_LIB -DBOOST_SYSTEM_NO_LIB -DBOOST_THREAD_NO_LIB -DCURL_STATICLIB -DGLEW_STATIC -DLIBNEST2D_GEOMETRIES_libslic3r -DLIBNEST2D_OPTIMIZER_nlopt -DLIBNEST2D_STATIC -DLIBNEST2D_THREADING_tbb -DOPENSSL_CERT_OVERRIDE -DOPENVDB_OPENEXR_STATICLIB -DOPENVDB_STATICLIB -DSLIC3R_CURRENTLY_COMPILING_GUI_MODULE -DSLIC3R_GUI -DTBB_USE_CAPTURED_EXCEPTION=0 -DUNICODE -DUSE_TBB -DWXINTL_NO_GETTEXT_MACRO -D_UNICODE -D__WXGTK3__ -D__WXGTK__ -DwxDEBUG_LEVEL=0 -DwxNO_UNSAFE_WXSTRING_CONV -DwxUSE_UNICODE -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/run/build/BambuStudio/src -I/run/build/BambuStudio/build/src/platform -I/run/build/BambuStudio/src/hidapi/include -I/run/build/BambuStudio/src/slic3r/Utils -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/webp -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/atk-1.0 -I/usr/include/fribidi -I/usr/include/pixman-1 -I/usr/include/harfbuzz -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/gio-unix-2.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/sysprof-6 -I/usr/include/gstreamer-1.0 -I/run/build/BambuStudio/build/src/libslic3r -I/run/build/BambuStudio/deps/build/destdir/usr/local/include/opencascade -I/run/build/BambuStudio/src/libnest2d/include -I/run/build/BambuStudio/src/miniz -I/run/build/BambuStudio/src/glu-libtess/include -I/run/build/BambuStudio/src/clipper2/Clipper2Lib/include -I/run/build/BambuStudio/src/minilzo -isystem /run/build/BambuStudio/src/eigen -isystem /run/build/BambuStudio/src/libigl -isystem /app/lib/wx/include/gtk3-unicode-static-3.1 -isystem /app/include/wx-3.1 -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include/opencv4 -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include/OpenEXR -std=gnu++20 -fext-numeric-literals -Wall -Wno-reorder -pthread -O3 -DNDEBUG -std=gnu++17 -fPIC -fsigned-char -Werror=return-type -Wno-ignored-attributes -Wno-unknown-pragmas -DOPENVDB_ABI_VERSION_NUMBER=8 -MD -MT src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o -MF src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o.d -o src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o -c /run/build/BambuStudio/src/slic3r/Utils/FontUtils.cpp
/run/build/BambuStudio/src/slic3r/Utils/FontUtils.cpp: In function ‘std::unique_ptr<Slic3r::FontFile> Slic3r::create_font_file(const char*)’:
/run/build/BambuStudio/src/slic3r/Utils/FontUtils.cpp:127:27: error: ‘error’ was not declared in this scope; did you mean ‘perror’?
  127 |         BOOST_LOG_TRIVIAL(error) << "Couldn't open " << file_path << " for reading.";
      |                           ^~~~~
      |                           perror

[447/494] Building CXX object src/slic3r/CMakeFiles/libslic3r_gui.dir/GUI/TaskManager.cpp.o
FAILED: src/slic3r/CMakeFiles/libslic3r_gui.dir/GUI/TaskManager.cpp.o
/usr/bin/c++ -DBOOST_ATOMIC_NO_LIB -DBOOST_CHRONO_NO_LIB -DBOOST_DATE_TIME_NO_LIB -DBOOST_FILESYSTEM_NO_LIB -DBOOST_IOSTREAMS_NO_LIB -DBOOST_LOCALE_NO_LIB -DBOOST_LOG_NO_LIB -DBOOST_REGEX_NO_LIB -DBOOST_SYSTEM_NO_LIB -DBOOST_THREAD_NO_LIB -DCURL_STATICLIB -DGLEW_STATIC -DLIBNEST2D_GEOMETRIES_libslic3r -DLIBNEST2D_OPTIMIZER_nlopt -DLIBNEST2D_STATIC -DLIBNEST2D_THREADING_tbb -DOPENSSL_CERT_OVERRIDE -DOPENVDB_OPENEXR_STATICLIB -DOPENVDB_STATICLIB -DSLIC3R_CURRENTLY_COMPILING_GUI_MODULE -DSLIC3R_GUI -DTBB_USE_CAPTURED_EXCEPTION=0 -DUNICODE -DUSE_TBB -DWXINTL_NO_GETTEXT_MACRO -D_UNICODE -D__WXGTK3__ -D__WXGTK__ -DwxDEBUG_LEVEL=0 -DwxNO_UNSAFE_WXSTRING_CONV -DwxUSE_UNICODE -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/run/build/BambuStudio/src -I/run/build/BambuStudio/build/src/platform -I/run/build/BambuStudio/src/hidapi/include -I/run/build/BambuStudio/src/slic3r/Utils -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/webp -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/atk-1.0 -I/usr/include/fribidi -I/usr/include/pixman-1 -I/usr/include/harfbuzz -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/gio-unix-2.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/sysprof-6 -I/usr/include/gstreamer-1.0 -I/run/build/BambuStudio/build/src/libslic3r -I/run/build/BambuStudio/deps/build/destdir/usr/local/include/opencascade -I/run/build/BambuStudio/src/libnest2d/include -I/run/build/BambuStudio/src/miniz -I/run/build/BambuStudio/src/glu-libtess/include -I/run/build/BambuStudio/src/clipper2/Clipper2Lib/include -I/run/build/BambuStudio/src/minilzo -isystem /run/build/BambuStudio/src/eigen -isystem /run/build/BambuStudio/src/libigl -isystem /app/lib/wx/include/gtk3-unicode-static-3.1 -isystem /app/include/wx-3.1 -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include/opencv4 -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include/OpenEXR -std=gnu++20 -fext-numeric-literals -Wall -Wno-reorder -pthread -O3 -DNDEBUG -std=gnu++17 -fPIC -fsigned-char -Werror=return-type -Wno-ignored-attributes -Wno-unknown-pragmas -DOPENVDB_ABI_VERSION_NUMBER=8 -MD -MT src/slic3r/CMakeFiles/libslic3r_gui.dir/GUI/TaskManager.cpp.o -MF src/slic3r/CMakeFiles/libslic3r_gui.dir/GUI/TaskManager.cpp.o.d -o src/slic3r/CMakeFiles/libslic3r_gui.dir/GUI/TaskManager.cpp.o -c /run/build/BambuStudio/src/slic3r/GUI/TaskManager.cpp
In file included from /run/build/BambuStudio/src/slic3r/GUI/TaskManager.cpp:1:
/run/build/BambuStudio/src/slic3r/GUI/TaskManager.hpp: In member function ‘void Slic3r::TaskStateInfo::set_state(Slic3r::TaskState)’:
/run/build/BambuStudio/src/slic3r/GUI/TaskManager.hpp:40:9: error: ‘BOOST_LOG_TRIVIAL’ was not declared in this scope
   40 |         BOOST_LOG_TRIVIAL(trace) << "TaskStateInfo set state = " << get_task_state_enum_str(ts);
      |         ^~~~~~~~~~~~~~~~~

* fix OpenCV

* wip - build break

* fix build error wip

* ENH: support preset description(tooltip)

Change-Id: Iff005baac4974c538d1109fb0ba1df20b04a8f69
Jira: STUDIO-5754

* fix more build errors

* Revert "ENH: load more fonts"

This reverts commit 32b6fd199a.

* change colors

* misc fixes

* restore export gcode btn

---------

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Signed-off-by: Stone Li <stone.li@bambulab.com>
Signed-off-by: Kunlong Ma <kunlong.ma@bambulab.com>
Signed-off-by: XunZhangBambu <xun.zhang@bambulab.com>
Co-authored-by: lane.wei <lane.wei@bambulab.com>
Co-authored-by: Arthur <arthur.tang@bambulab.com>
Co-authored-by: xun.zhang <xun.zhang@bambulab.com>
Co-authored-by: zhimin.zeng <zhimin.zeng@bambulab.com>
Co-authored-by: Kunlong Ma <kunlong.ma@bambulab.com>
Co-authored-by: jianjia.ma <jianjia.ma@bambulab.com>
Co-authored-by: liz.li <liz.li@bambulab.com>
Co-authored-by: tao wang <tao.wang@bambulab.com>
Co-authored-by: Stone Li <stone.li@bambulab.com>
Co-authored-by: zhou.xu <zhou.xu@bambulab.com>
Co-authored-by: Bastien Nocera <hadess@hadess.net>
Co-authored-by: chunmao.guo <chunmao.guo@bambulab.com>
This commit is contained in:
SoftFever
2024-04-28 22:58:47 +08:00
committed by GitHub
co-authored by lane.wei Arthur xun.zhang zhimin.zeng Kunlong Ma jianjia.ma liz.li tao wang Stone Li zhou.xu Bastien Nocera chunmao.guo
parent 78af750ed9
commit 226450ea6a
177 changed files with 24423 additions and 4255 deletions
+82 -36
View File
@@ -791,7 +791,8 @@ static int construct_assemble_list(std::vector<assemble_plate_info_t> &assemble_
else if (boost::algorithm::iends_with(assemble_object.path, ".obj"))
{
std::string message;
bool result = load_obj(path_str, &mesh, message);
ObjInfo obj_info;
bool result = load_obj(path_str, &mesh, obj_info, message);
if (!result) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": failed to read a valid mesh from obj file %1%, plate index %2%, object index %3%, error %4%") % assemble_object.path % (index + 1) % (obj_index + 1) % message;
return CLI_DATA_FILE_ERROR;
@@ -1456,6 +1457,12 @@ int CLI::run(int argc, char **argv)
m_models.push_back(std::move(model));
}
if (!is_bbl_3mf && plate_to_slice > 0)
{
BOOST_LOG_TRIVIAL(warning) << boost::format("%1%: not support to slice plate %2%, reset to 0")%__LINE__ %plate_to_slice;
plate_to_slice = 0;
}
//load custom gcode file
std::map<int, CustomGCode::Info> custom_gcodes_map;
if (!custom_gcode_file.empty()) {
@@ -2624,7 +2631,7 @@ int CLI::run(int argc, char **argv)
//set multiplier to 1?
m_print_config.option<ConfigOptionFloat>("flush_multiplier", true)->set(new ConfigOptionFloat(1.f));
const std::vector<int>& min_flush_volumes = Slic3r::GUI::get_min_flush_volumes();
const std::vector<int>& min_flush_volumes = Slic3r::GUI::get_min_flush_volumes(m_print_config);
if (filament_is_support->size() != project_filament_count)
{
@@ -3525,7 +3532,8 @@ int CLI::run(int argc, char **argv)
ap.apply();
}
partplate_list.rebuild_plates_after_arrangement(false, true, i);
//lock here
cur_plate->lock(true);
}
else {
size_t plate_obj_count = assemble_plate.loaded_obj_list.size();
@@ -3548,6 +3556,8 @@ int CLI::run(int argc, char **argv)
Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate*)partplate_list.get_plate(i);
cur_plate->lock(false);
}
partplate_list.reload_all_objects(false, -1);
}
else if (need_arrange)
{
@@ -4175,7 +4185,8 @@ int CLI::run(int argc, char **argv)
bool no_check = false;
std::string export_3mf_file, load_slice_data_dir, export_slice_data_dir;
std::vector<ThumbnailData*> calibration_thumbnails;
int max_slicing_time_per_plate = 0, max_triangle_count_per_plate = 0;
std::vector<int> plate_object_count(partplate_list.get_plate_count(), 0);
int max_slicing_time_per_plate = 0, max_triangle_count_per_plate = 0, sliced_plate = -1;
std::vector<bool> plate_has_skips(partplate_list.get_plate_count(), false);
std::vector<std::vector<size_t>> plate_skipped_objects(partplate_list.get_plate_count());
@@ -4269,6 +4280,7 @@ int CLI::run(int argc, char **argv)
} else if (opt_key == "slice") {
//BBS: slice 0 means all plates, i means plate i;
plate_to_slice = m_config.option<ConfigOptionInt>("slice")->value;
sliced_plate = plate_to_slice;
bool pre_check = (plate_to_slice == 0)?true:false;
bool finished = false;
@@ -4427,6 +4439,7 @@ int CLI::run(int argc, char **argv)
}
plate_triangle_counts[index] = triangle_count;
plate_object_count[index] = printable_instances;
BOOST_LOG_TRIVIAL(info) << "plate "<< index+1<< ": load cached data success, go on.";
}
// BBS: TODO
@@ -4734,6 +4747,28 @@ int CLI::run(int argc, char **argv)
PlateDataPtrs plate_data_list;
partplate_list.store_to_3mf_structure(plate_data_list);
if (sliced_plate == -1) {
for (int i = 0; i < plate_data_list.size(); i++) {
Slic3r::GUI::PartPlate *part_plate = partplate_list.get_plate(i);
plate_object_count[i] = part_plate->printable_instance_size();
}
}
else if (sliced_plate == 0){
//slicing all
for (int i = 0; i < plate_data_list.size(); i++) {
if (skip_useless_pick && (plate_object_count[i] == 1)) {
BOOST_LOG_TRIVIAL(info) << boost::format("only has 1 object, set plate %1%'s is_label_object_enabled from %2% to false")%(i+1) % (plate_data_list[i]->is_label_object_enabled);
plate_data_list[i]->is_label_object_enabled = false;
}
}
}
else {
if (skip_useless_pick && (plate_object_count[sliced_plate - 1] == 1)) {
BOOST_LOG_TRIVIAL(info) << boost::format("only has 1 object, set plate %1%'s is_label_object_enabled from %2% to false")%sliced_plate % (plate_data_list[sliced_plate - 1]->is_label_object_enabled);
plate_data_list[sliced_plate - 1]->is_label_object_enabled = false;
}
}
if (!outfile_dir.empty()) {
export_3mf_file = outfile_dir + "/"+export_3mf_file;
}
@@ -4752,7 +4787,7 @@ int CLI::run(int argc, char **argv)
// get type and color for platedata
auto* filament_types = dynamic_cast<const ConfigOptionStrings*>(m_print_config.option("filament_type"));
const ConfigOptionStrings* filament_color = dynamic_cast<const ConfigOptionStrings *>(m_print_config.option("filament_colour"));
//auto* filament_id = dynamic_cast<const ConfigOptionStrings*>(m_print_config.option("filament_ids"));
auto* filament_id = dynamic_cast<const ConfigOptionStrings*>(m_print_config.option("filament_ids"));
const ConfigOptionFloats* nozzle_diameter_option = dynamic_cast<const ConfigOptionFloats *>(m_print_config.option("nozzle_diameter"));
std::string nozzle_diameter_str;
if (nozzle_diameter_option)
@@ -4769,10 +4804,10 @@ int CLI::run(int argc, char **argv)
plate_data->nozzle_diameters = nozzle_diameter_str;
for (auto it = plate_data->slice_filaments_info.begin(); it != plate_data->slice_filaments_info.end(); it++) {
//it->filament_id = filament_id?filament_id->get_at(it->id):"unknown";
std::string display_filament_type;
it->type = m_print_config.get_filament_type(display_filament_type, it->id);
it->color = filament_color ? filament_color->get_at(it->id) : "#FFFFFF";
it->filament_id = filament_id?filament_id->get_at(it->id):"";
}
if (!plate_data->plate_thumbnail.is_valid()) {
@@ -4940,6 +4975,7 @@ int CLI::run(int argc, char **argv)
}
}
ThumbnailsParams thumbnail_params;
GLShaderProgram* shader = opengl_mgr.get_shader("thumbnail");
if (!shader) {
BOOST_LOG_TRIVIAL(error) << boost::format("can not get shader for rendering thumbnail");
@@ -5057,39 +5093,49 @@ int CLI::run(int argc, char **argv)
unsigned int thumbnail_width = 512, thumbnail_height = 512;
const ThumbnailsParams thumbnail_params = { {}, false, true, false, true, i };
BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s top/pick thumbnail missed, need to regenerate")%(i+1);
switch (Slic3r::GUI::OpenGLManager::get_framebuffers_type())
BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s top/pick thumbnail missed, need to regenerate, objects count %2%, skip_useless_pick %3%")%(i+1) %plate_object_count[i] %skip_useless_pick;
if (skip_useless_pick && ((plate_object_count[i] <= 1) || (plate_object_count[i] > 64)))
{
case Slic3r::GUI::OpenGLManager::EFramebufferType::Arb:
{
BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: ARB");
Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(*top_thumbnail,
thumbnail_width, thumbnail_height, thumbnail_params,
partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, true, false);
Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(*picking_thumbnail,
thumbnail_width, thumbnail_height, thumbnail_params,
partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, true, true);
//don't render pick and top
part_plate->top_thumbnail_data.reset();
part_plate->pick_thumbnail_data.reset();
plate_data->top_file.clear();
plate_data->pick_file.clear();
BOOST_LOG_TRIVIAL(info) << boost::format("skip rendering for top&&pick");
}
else {
switch (Slic3r::GUI::OpenGLManager::get_framebuffers_type())
{
case Slic3r::GUI::OpenGLManager::EFramebufferType::Arb:
{
BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: ARB");
Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(*top_thumbnail,
thumbnail_width, thumbnail_height, thumbnail_params,
partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, true, false);
Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(*picking_thumbnail,
thumbnail_width, thumbnail_height, thumbnail_params,
partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, true, true);
break;
}
case Slic3r::GUI::OpenGLManager::EFramebufferType::Ext:
{
BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: EXT");
Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer_ext(*top_thumbnail,
thumbnail_width, thumbnail_height, thumbnail_params,
partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, true, false);
Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer_ext(*picking_thumbnail,
thumbnail_width, thumbnail_height, thumbnail_params,
partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, true, true);
break;
}
default:
BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: unknown");
break;
}
case Slic3r::GUI::OpenGLManager::EFramebufferType::Ext:
{
BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: EXT");
Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer_ext(*top_thumbnail,
thumbnail_width, thumbnail_height, thumbnail_params,
partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, true, false);
Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer_ext(*picking_thumbnail,
thumbnail_width, thumbnail_height, thumbnail_params,
partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, true, true);
break;
}
default:
BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: unknown");
break;
}
plate_data->top_file = "valid_top";
plate_data->pick_file = "valid_pick";
BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s top_thumbnail,finished rendering")%(i+1);
}
plate_data->top_file = "valid_top";
plate_data->pick_file = "valid_pick";
BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s top_thumbnail,finished rendering")%(i+1);
}
}
+42
View File
@@ -186,6 +186,8 @@ void AppConfig::set_defaults()
if (get("show_hints").empty())
set_bool("show_hints", true);
//#endif
if (get("enable_multi_machine").empty())
set_bool("enable_multi_machine", false);
if (get("show_gcode_window").empty())
set_bool("show_gcode_window", true);
@@ -359,6 +361,14 @@ void AppConfig::set_defaults()
set("curr_bed_type", "1");
}
if (get("sending_interval").empty()) {
set("sending_interval", "5");
}
if (get("max_send").empty()) {
set("max_send", "3");
}
// #if BBL_RELEASE_TO_PUBLIC
if (get("iot_environment").empty()) {
set("iot_environment", "3");
@@ -1246,6 +1256,38 @@ bool AppConfig::is_engineering_region(){
return false;
}
void AppConfig::save_custom_color_to_config(const std::vector<std::string> &colors)
{
auto set_colors = [](std::map<std::string, std::string> &data, const std::vector<std::string> &colors) {
for (size_t i = 0; i < colors.size(); i++) {
data[std::to_string(10 + i)] = colors[i]; // for map sort:10 begin
}
};
if (colors.size() > 0) {
if (!has_section("custom_color_list")) {
std::map<std::string, std::string> data;
set_colors(data, colors);
set_section("custom_color_list", data);
} else {
auto data = get_section("custom_color_list");
auto data_modify = const_cast<std::map<std::string, std::string> *>(&data);
set_colors(*data_modify, colors);
set_section("custom_color_list", *data_modify);
}
}
}
std::vector<std::string> AppConfig::get_custom_color_from_config()
{
std::vector<std::string> colors;
if (has_section("custom_color_list")) {
auto data = get_section("custom_color_list");
for (auto iter : data) {
colors.push_back(iter.second);
}
}
return colors;
}
void AppConfig::reset_selections()
{
+3 -1
View File
@@ -233,7 +233,9 @@ public:
std::string get_country_code();
bool is_engineering_region();
// reset the current print / filament / printer selections, so that
void save_custom_color_to_config(const std::vector<std::string> &colors);
std::vector<std::string> get_custom_color_from_config();
// reset the current print / filament / printer selections, so that
// the PresetBundle::load_selections(const AppConfig &config) call will select
// the first non-default preset when called.
void reset_selections();
+1 -1
View File
@@ -987,7 +987,7 @@ void _arrange(
// polygon nesting, a convex hull needs to be calculated.
if (params.allow_rotations) {
for (auto &itm : shapes) {
itm.rotation(min_area_boundingbox_rotation(itm.rawShape()));
itm.rotation(min_area_boundingbox_rotation(itm.transformedShape()));
// If the item is too big, try to find a rotation that makes it fit
if constexpr (std::is_same_v<BinT, Box>) {
+5
View File
@@ -100,6 +100,8 @@ set(lisbslic3r_sources
Fill/FillConcentric.hpp
Fill/FillConcentricInternal.cpp
Fill/FillConcentricInternal.hpp
Fill/FillCrossHatch.cpp
Fill/FillCrossHatch.hpp
Fill/FillHoneycomb.cpp
Fill/FillHoneycomb.hpp
Fill/FillGyroid.cpp
@@ -232,6 +234,7 @@ set(lisbslic3r_sources
Arrange.cpp
NormalUtils.cpp
NormalUtils.hpp
ObjColorUtils.hpp
Orient.hpp
Orient.cpp
MultiPoint.cpp
@@ -473,6 +476,7 @@ set(CGAL_DO_NOT_WARN_ABOUT_CMAKE_BUILD_TYPE ON CACHE BOOL "" FORCE)
cmake_policy(PUSH)
cmake_policy(SET CMP0011 NEW)
find_package(CGAL REQUIRED)
find_package(OpenCV REQUIRED core)
cmake_policy(POP)
add_library(libslic3r_cgal STATIC
@@ -573,6 +577,7 @@ target_link_libraries(libslic3r
mcut
JPEG::JPEG
qoi
opencv_world
)
if(NOT WIN32)
+9 -1
View File
@@ -6,7 +6,15 @@
static const float INV_255 = 1.0f / 255.0f;
namespace Slic3r {
bool color_is_equal(const RGBA a, const RGBA& b)
{
for (size_t i = 0; i < 4; i++) {
if (abs(a[i] - b[i]) > 0.01) {
return false;
}
}
return true;
}
// Conversion from RGB to HSV color space
// The input RGB values are in the range [0, 1]
// The output HSV values are in the ranges h = [0, 360], and s, v = [0, 1]
+7 -2
View File
@@ -7,7 +7,10 @@
#include <algorithm>
namespace Slic3r {
using RGB = std::array<float, 3>;
using RGBA = std::array<float, 4>;
const RGBA UNDEFINE_COLOR = {0,0,0,0};
bool color_is_equal(const RGBA a, const RGBA &b);
class ColorRGB
{
std::array<float, 3> m_data{1.0f, 1.0f, 1.0f};
@@ -82,7 +85,9 @@ public:
ColorRGBA& operator = (const ColorRGBA& other) { m_data = other.m_data; return *this; }
bool operator == (const ColorRGBA& other) const { return m_data == other.m_data; }
bool operator==(const ColorRGBA &other) const{
return color_is_equal(m_data, other.m_data);
}
bool operator != (const ColorRGBA& other) const { return !operator==(other); }
bool operator < (const ColorRGBA& other) const;
bool operator > (const ColorRGBA& other) const;
+3
View File
@@ -831,6 +831,9 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex
else if (boost::iequals(it.key(), BBL_JSON_KEY_FROM)) {
key_values.emplace(BBL_JSON_KEY_FROM, it.value());
}
else if (boost::iequals(it.key(), BBL_JSON_KEY_DESCRIPTION)) {
key_values.emplace(BBL_JSON_KEY_DESCRIPTION, it.value());
}
else if (boost::iequals(it.key(), BBL_JSON_KEY_INSTANTIATION)) {
key_values.emplace(BBL_JSON_KEY_INSTANTIATION, it.value());
}
+2
View File
@@ -32,6 +32,7 @@
#include "FillLightning.hpp"
// BBS: new infill pattern header
#include "FillConcentricInternal.hpp"
#include "FillCrossHatch.hpp"
// #define INFILL_DEBUG_OUTPUT
@@ -51,6 +52,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
case ipGyroid: return new FillGyroid();
case ipRectilinear: return new FillRectilinear();
case ipAlignedRectilinear: return new FillAlignedRectilinear();
case ipCrossHatch: return new FillCrossHatch();
case ipMonotonic: return new FillMonotonic();
case ipLine: return new FillLine();
case ipGrid: return new FillGrid();
+227
View File
@@ -0,0 +1,227 @@
#include "../ClipperUtils.hpp"
#include "../ShortestPath.hpp"
#include "../Surface.hpp"
#include "FillCrossHatch.hpp"
namespace Slic3r {
// CrossHatch Infill: Enhances 3D Printing Speed & Reduces Noise
// CrossHatch, as its name hints, alternates line direction by 90 degrees every few layers to improve adhesion.
// It introduces transform layers between direction shifts for better line cohesion, which fixes the weakness of line infill.
// The transform technique is inspired by David Eccles, improved 3D honeycomb but we made a more flexible implementation.
// This method notably increases printing speed, meeting the demands of modern high-speed 3D printers, and reduces noise for most layers.
// By Bambu Lab
// graph credits: David Eccles (gringer).
// But we made a different definition for points.
/* o---o
* / \
* / \
* \ /
* \ /
* o---o
* p1 p2 p3 p4
*/
static Pointfs generate_one_cycle(double progress, coordf_t period)
{
Pointfs out;
double offset = progress * 1. / 8. * period;
out.reserve(4);
out.push_back(Vec2d(0.25 * period - offset, offset));
out.push_back(Vec2d(0.25 * period + offset, offset));
out.push_back(Vec2d(0.75 * period - offset, -offset));
out.push_back(Vec2d(0.75 * period + offset, -offset));
return out;
}
static Polylines generate_transform_pattern(double inprogress, int direction, coordf_t ingrid_size, coordf_t inwidth, coordf_t inheight)
{
coordf_t width = inwidth;
coordf_t height = inheight;
coordf_t grid_size = ingrid_size * 2; // we due with odd and even saparately.
double progress = inprogress;
Polylines out_polylines;
// generate template patterns;
Pointfs one_cycle_points = generate_one_cycle(progress, grid_size);
Polyline one_cycle;
one_cycle.points.reserve(one_cycle_points.size());
for (size_t i = 0; i < one_cycle_points.size(); i++) one_cycle.points.push_back(Point(one_cycle_points[i]));
// swap if vertical
if (direction < 0) {
width = height;
height = inwidth;
}
// replicate polylines;
Polylines odd_polylines;
Polyline odd_poly;
int num_of_cycle = width / grid_size + 2;
odd_poly.points.reserve(num_of_cycle * one_cycle.size());
// replicate to odd line
Point translate = Point(0, 0);
for (size_t i = 0; i < num_of_cycle; i++) {
Polyline odd_points;
odd_points = Polyline(one_cycle);
odd_points.translate(Point(i * grid_size, 0.0));
odd_poly.points.insert(odd_poly.points.end(), odd_points.begin(), odd_points.end());
}
// fill the height
int num_of_lines = height / grid_size + 2;
odd_polylines.reserve(num_of_lines * odd_poly.size());
for (size_t i = 0; i < num_of_lines; i++) {
Polyline poly = odd_poly;
poly.translate(Point(0.0, grid_size * i));
odd_polylines.push_back(poly);
}
// save to output
out_polylines.insert(out_polylines.end(), odd_polylines.begin(), odd_polylines.end());
// replicate to even lines
Polylines even_polylines;
even_polylines.reserve(odd_polylines.size());
for (size_t i = 0; i < odd_polylines.size(); i++) {
Polyline even = odd_poly;
even.translate(Point(-0.5 * grid_size, (i + 0.5) * grid_size));
even_polylines.push_back(even);
}
// save for output
out_polylines.insert(out_polylines.end(), even_polylines.begin(), even_polylines.end());
// change to vertical if need
if (direction < 0) {
// swap xy, see if we need better performance method
for (Polyline &poly : out_polylines) {
for (Point &p : poly) { std::swap(p.x(), p.y()); }
}
}
return out_polylines;
}
static Polylines generate_repeat_pattern(int direction, coordf_t grid_size, coordf_t inwidth, coordf_t inheight)
{
coordf_t width = inwidth;
coordf_t height = inheight;
Polylines out_polylines;
// swap if vertical
if (direction < 0) {
width = height;
height = inwidth;
}
int num_of_lines = height / grid_size + 1;
out_polylines.reserve(num_of_lines);
for (int i = 0; i < num_of_lines; i++) {
Polyline poly;
poly.points.reserve(2);
poly.append(Point(coordf_t(0), coordf_t(grid_size * i)));
poly.append(Point(width, coordf_t(grid_size * i)));
out_polylines.push_back(poly);
}
// change to vertical if needed
if (direction < 0) {
// swap xy
for (Polyline &poly : out_polylines) {
for (Point &p : poly) { std::swap(p.x(), p.y()); }
}
}
return out_polylines;
}
// it makes the real patterns that overlap the bounding box
// repeat_ratio define the ratio between the height of repeat pattern and grid
static Polylines generate_infill_layers(coordf_t z_height, double repeat_ratio, coordf_t grid_size, coordf_t width, coordf_t height)
{
Polylines result;
coordf_t trans_layer_size = grid_size * 0.4; // upper.
coordf_t repeat_layer_size = grid_size * repeat_ratio; // lower.
z_height += repeat_layer_size / 2; // offset to improve first few layer strength
coordf_t period = trans_layer_size + repeat_layer_size;
coordf_t remains = z_height - std::floor(z_height / period) * period;
coordf_t trans_z = remains - repeat_layer_size; // put repeat layer first.
coordf_t repeat_z = remains;
int phase = fmod(z_height, period * 2) - (period - 1); // add epsilon
int direction = phase <= 0 ? -1 : 1;
// this is a repeat layer
if (trans_z < 0) {
result = generate_repeat_pattern(direction, grid_size, width, height);
}
// this is a transform layer
else {
double progress = fmod(trans_z, trans_layer_size) / trans_layer_size;
// split the progress to forward and backward, with a opposite direction.
if (progress < 0.5)
result = generate_transform_pattern((progress + 0.1) * 2, direction, grid_size, width, height); // increase overlapping.
else
result = generate_transform_pattern((1.1 - progress) * 2, -1 * direction, grid_size, width, height);
}
return result;
}
void FillCrossHatch ::_fill_surface_single(
const FillParams &params, unsigned int thickness_layers, const std::pair<float, Point> &direction, ExPolygon expolygon, Polylines &polylines_out)
{
// rotate angle
auto infill_angle = float(this->angle);
if (std::abs(infill_angle) >= EPSILON) expolygon.rotate(-infill_angle);
// get the rotated bounding box
BoundingBox bb = expolygon.contour.bounding_box();
// linespace modifier
coord_t line_spacing = coord_t(scale_(this->spacing) / params.density);
// reduce density
if (params.density < 0.999) line_spacing *= 1.08;
bb.merge(align_to_grid(bb.min, Point(line_spacing * 4, line_spacing * 4)));
// generate pattern
Polylines polylines = generate_infill_layers(scale_(this->z), 1, line_spacing, bb.size()(0), bb.size()(1));
// shift the pattern to the actual space
for (Polyline &pl : polylines) { pl.translate(bb.min); }
polylines = intersection_pl(polylines, to_polygons(expolygon));
// --- remove small remains from gyroid infill
if (!polylines.empty()) {
// Remove very small bits, but be careful to not remove infill lines connecting thin walls!
// The infill perimeter lines should be separated by around a single infill line width.
const double minlength = scale_(0.8 * this->spacing);
polylines.erase(std::remove_if(polylines.begin(), polylines.end(), [minlength](const Polyline &pl)
{ return pl.length() < minlength; }), polylines.end());
}
if (!polylines.empty()) {
int infill_start_idx = polylines_out.size(); // only rotate what belongs to us.
// connect lines
if (params.dont_connect() || polylines.size() <= 1)
append(polylines_out, chain_polylines(std::move(polylines)));
else
this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params);
// rotate back
if (std::abs(infill_angle) >= EPSILON) {
for (auto it = polylines_out.begin() + infill_start_idx; it != polylines_out.end(); ++it) it->rotate(infill_angle);
}
}
}
} // namespace Slic3r
+29
View File
@@ -0,0 +1,29 @@
#ifndef slic3r_FillCrossHatch_hpp_
#define slic3r_FillCrossHatch_hpp_
#include <map>
#include "../libslic3r.h"
#include "FillBase.hpp"
namespace Slic3r {
class FillCrossHatch : public Fill
{
public:
Fill *clone() const override { return new FillCrossHatch(*this); };
~FillCrossHatch() override {}
protected:
void _fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon expolygon,
Polylines &polylines_out) override;
};
} // namespace Slic3r
#endif // slic3r_FillCrossHatch_hpp_
+106 -18
View File
@@ -21,19 +21,39 @@
namespace Slic3r {
bool load_obj(const char *path, TriangleMesh *meshptr, std::string &message)
bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::string &message)
{
if (meshptr == nullptr)
return false;
// Parse the OBJ file.
ObjParser::ObjData data;
ObjParser::MtlData mtl_data;
if (! ObjParser::objparse(path, data)) {
BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << path;
message = _L("load_obj: failed to parse");
return false;
}
bool exist_mtl = false;
if (data.mtllibs.size() > 0) { // read mtl
for (auto mtl_name : data.mtllibs) {
boost::filesystem::path full_path(path);
std::string dir = full_path.parent_path().string();
auto mtl_file = dir + "/" + mtl_name;
boost::filesystem::path mtl_path(mtl_file);
auto _mtl_path = mtl_path.string().c_str();
if (boost::filesystem::exists(mtl_path)) {
if (!ObjParser::mtlparse(_mtl_path, mtl_data)) {
BOOST_LOG_TRIVIAL(error) << "load_obj:load_mtl: failed to parse " << _mtl_path;
message = _L("load mtl in obj: failed to parse");
return false;
}
}
else {
BOOST_LOG_TRIVIAL(error) << "load_obj: failed to load mtl_path:" << _mtl_path;
}
}
exist_mtl = true;
}
// Count the faces and verify, that all faces are triangular.
size_t num_faces = 0;
size_t num_quads = 0;
@@ -59,17 +79,27 @@ bool load_obj(const char *path, TriangleMesh *meshptr, std::string &message)
i = j;
}
}
// Convert ObjData into indexed triangle set.
indexed_triangle_set its;
size_t num_vertices = data.coordinates.size() / 4;
size_t num_vertices = data.coordinates.size() / OBJ_VERTEX_LENGTH;
its.vertices.reserve(num_vertices);
its.indices.reserve(num_faces + num_quads);
for (size_t i = 0; i < num_vertices; ++ i) {
size_t j = i << 2;
its.vertices.emplace_back(data.coordinates[j], data.coordinates[j + 1], data.coordinates[j + 2]);
if (exist_mtl) {
obj_info.is_single_mtl = data.usemtls.size() == 1 && mtl_data.new_mtl_unmap.size() == 1;
obj_info.face_colors.reserve(num_faces + num_quads);
}
int indices[4];
bool has_color = data.has_vertex_color;
for (size_t i = 0; i < num_vertices; ++ i) {
size_t j = i * OBJ_VERTEX_LENGTH;
its.vertices.emplace_back(data.coordinates[j], data.coordinates[j + 1], data.coordinates[j + 2]);
if (data.has_vertex_color) {
RGBA color{std::clamp(data.coordinates[j + 3], 0.f, 1.f), std::clamp(data.coordinates[j + 4], 0.f, 1.f), std::clamp(data.coordinates[j + 5], 0.f, 1.f),
std::clamp(data.coordinates[j + 6], 0.f, 1.f)};
obj_info.vertex_colors.emplace_back(color);
}
}
int indices[ONE_FACE_SIZE];
int uvs[ONE_FACE_SIZE];
for (size_t i = 0; i < data.vertices.size();)
if (data.vertices[i].coordIdx == -1)
++ i;
@@ -79,20 +109,79 @@ bool load_obj(const char *path, TriangleMesh *meshptr, std::string &message)
if (const ObjParser::ObjVertex &vertex = data.vertices[i ++]; vertex.coordIdx == -1) {
break;
} else {
assert(cnt < 4);
assert(cnt < OBJ_VERTEX_LENGTH);
if (vertex.coordIdx < 0 || vertex.coordIdx >= int(its.vertices.size())) {
BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << path << ". The file contains invalid vertex index.";
message = _L("The file contains invalid vertex index.");
return false;
}
indices[cnt ++] = vertex.coordIdx;
indices[cnt] = vertex.coordIdx;
uvs[cnt] = vertex.textureCoordIdx;
cnt++;
}
if (cnt) {
assert(cnt == 3 || cnt == 4);
// Insert one or two faces (triangulate a quad).
its.indices.emplace_back(indices[0], indices[1], indices[2]);
if (cnt == 4)
int face_index =its.indices.size() - 1;
RGBA face_color;
auto set_face_color = [&uvs, &data, &mtl_data, &obj_info, &face_color](int face_index, const std::string mtl_name) {
if (mtl_data.new_mtl_unmap.find(mtl_name) != mtl_data.new_mtl_unmap.end()) {
bool is_merge_ka_kd = true;
for (size_t n = 0; n < 3; n++) {
if (float(mtl_data.new_mtl_unmap[mtl_name]->Ka[n] + mtl_data.new_mtl_unmap[mtl_name]->Kd[n]) > 1.0) {
is_merge_ka_kd=false;
break;
}
}
for (size_t n = 0; n < 3; n++) {
if (is_merge_ka_kd) {
face_color[n] = std::clamp(float(mtl_data.new_mtl_unmap[mtl_name]->Ka[n] + mtl_data.new_mtl_unmap[mtl_name]->Kd[n]), 0.f, 1.f);
}
else {
face_color[n] = std::clamp(float(mtl_data.new_mtl_unmap[mtl_name]->Kd[n]), 0.f, 1.f);
}
}
face_color[3] = mtl_data.new_mtl_unmap[mtl_name]->Tr; // alpha
if (mtl_data.new_mtl_unmap[mtl_name]->map_Kd.size() > 0) {
auto png_name = mtl_data.new_mtl_unmap[mtl_name]->map_Kd;
obj_info.has_uv_png = true;
if (obj_info.pngs.find(png_name) == obj_info.pngs.end()) { obj_info.pngs[png_name] = false; }
obj_info.uv_map_pngs[face_index] = png_name;
}
if (data.textureCoordinates.size() > 0) {
Vec2f uv0(data.textureCoordinates[uvs[0] * 2], data.textureCoordinates[uvs[0] * 2 + 1]);
Vec2f uv1(data.textureCoordinates[uvs[1] * 2], data.textureCoordinates[uvs[1] * 2 + 1]);
Vec2f uv2(data.textureCoordinates[uvs[2] * 2], data.textureCoordinates[uvs[2] * 2 + 1]);
std::array<Vec2f, 3> uv_array{uv0, uv1, uv2};
obj_info.uvs.emplace_back(uv_array);
}
obj_info.face_colors.emplace_back(face_color);
}
};
auto set_face_color_by_mtl = [&data, &set_face_color](int face_index) {
if (data.usemtls.size() == 1) {
set_face_color(face_index, data.usemtls[0].name);
} else {
for (size_t k = 0; k < data.usemtls.size(); k++) {
auto mtl = data.usemtls[k];
if (face_index >= mtl.face_start && face_index <= mtl.face_end) {
set_face_color(face_index, data.usemtls[k].name);
break;
}
}
}
};
if (exist_mtl) {
set_face_color_by_mtl(face_index);
}
if (cnt == 4) {
its.indices.emplace_back(indices[0], indices[2], indices[3]);
int face_index = its.indices.size() - 1;
if (exist_mtl) {
set_face_color_by_mtl(face_index);
}
}
}
}
@@ -107,12 +196,12 @@ bool load_obj(const char *path, TriangleMesh *meshptr, std::string &message)
return true;
}
bool load_obj(const char *path, Model *model, std::string &message, const char *object_name_in)
bool load_obj(const char *path, Model *model, ObjInfo& obj_info, std::string &message, const char *object_name_in)
{
TriangleMesh mesh;
bool ret = load_obj(path, &mesh, message);
bool ret = load_obj(path, &mesh, obj_info, message);
if (ret) {
std::string object_name;
if (object_name_in == nullptr) {
@@ -120,10 +209,9 @@ bool load_obj(const char *path, Model *model, std::string &message, const char *
object_name.assign((last_slash == nullptr) ? path : last_slash + 1);
} else
object_name.assign(object_name_in);
model->add_object(object_name.c_str(), path, std::move(mesh));
}
return ret;
}
+16 -4
View File
@@ -1,15 +1,27 @@
#ifndef slic3r_Format_OBJ_hpp_
#define slic3r_Format_OBJ_hpp_
#include "libslic3r/Color.hpp"
#include <unordered_map>
namespace Slic3r {
class TriangleMesh;
class Model;
class ModelObject;
typedef std::function<void(std::vector<RGBA> &input_colors, bool is_single_color, std::vector<unsigned char> &filament_ids, unsigned char &first_extruder_id)> ObjImportColorFn;
// Load an OBJ file into a provided model.
extern bool load_obj(const char *path, TriangleMesh *mesh, std::string &message);
extern bool load_obj(const char *path, Model *model, std::string &message, const char *object_name = nullptr);
struct ObjInfo {
std::vector<RGBA> vertex_colors;
std::vector<RGBA> face_colors;
bool is_single_mtl{false};
std::vector<std::array<Vec2f,3>> uvs;
std::string obj_dircetory;
std::map<std::string,bool> pngs;
std::unordered_map<int, std::string> uv_map_pngs;
bool has_uv_png{false};
};
extern bool load_obj(const char *path, TriangleMesh *mesh, ObjInfo &vertex_colors, std::string &message);
extern bool load_obj(const char *path, Model *model, ObjInfo &vertex_colors, std::string &message, const char *object_name = nullptr);
extern bool store_obj(const char *path, TriangleMesh *mesh);
extern bool store_obj(const char *path, ModelObject *model);
+7 -11
View File
@@ -213,6 +213,7 @@ static constexpr const char* FILAMENT_TYPE_TAG = "type";
static constexpr const char *FILAMENT_COLOR_TAG = "color";
static constexpr const char *FILAMENT_USED_M_TAG = "used_m";
static constexpr const char *FILAMENT_USED_G_TAG = "used_g";
static constexpr const char *FILAMENT_TRAY_INFO_ID_TAG = "tray_info_idx";
static constexpr const char* CONFIG_TAG = "config";
@@ -586,21 +587,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return ret;
};
for (auto it = ps.volumes_per_extruder.begin(); it != ps.volumes_per_extruder.end(); it++) {
for (auto it = ps.total_volumes_per_extruder.begin(); it != ps.total_volumes_per_extruder.end(); it++) {
double volume = it->second;
auto [used_filament_m, used_filament_g] = get_used_filament_from_volume(volume, it->first);
FilamentInfo info;
info.id = it->first;
if (ps.flush_per_filament.find(it->first) != ps.flush_per_filament.end()) {
volume = ps.flush_per_filament.at(it->first);
auto [flushed_filament_m, flushed_filament_g] = get_used_filament_from_volume(volume, it->first);
info.used_m = used_filament_m + flushed_filament_m;
info.used_g = used_filament_g + flushed_filament_g;
} else {
info.used_m = used_filament_m;
info.used_g = used_filament_g;
}
info.used_g = used_filament_g;
info.used_m = used_filament_m;
slice_filaments_info.push_back(info);
}
@@ -4231,13 +4225,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
std::string color = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_COLOR_TAG);
std::string used_m = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_USED_M_TAG);
std::string used_g = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_USED_G_TAG);
std::string filament_id = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_TRAY_INFO_ID_TAG);
FilamentInfo filament_info;
filament_info.id = atoi(id.c_str()) - 1;
filament_info.type = type;
filament_info.color = color;
filament_info.used_m = atof(used_m.c_str());
filament_info.used_g = atof(used_g.c_str());
filament_info.filament_id = filament_id;
m_curr_plater->slice_filaments_info.push_back(filament_info);
}
return true;
@@ -7659,6 +7654,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
for (auto it = plate_data->slice_filaments_info.begin(); it != plate_data->slice_filaments_info.end(); it++)
{
stream << " <" << FILAMENT_TAG << " " << FILAMENT_ID_TAG << "=\"" << std::to_string(it->id + 1) << "\" "
<< FILAMENT_TRAY_INFO_ID_TAG <<"=\""<< it->filament_id <<"\" "
<< FILAMENT_TYPE_TAG << "=\"" << it->type << "\" "
<< FILAMENT_COLOR_TAG << "=\"" << it->color << "\" "
<< FILAMENT_USED_M_TAG << "=\"" << it->used_m << "\" "
+301 -18
View File
@@ -9,16 +9,12 @@
#include "libslic3r/LocalesUtils.hpp"
namespace ObjParser {
#define EATWS() while (*line == ' ' || *line == '\t') ++line
static bool obj_parseline(const char *line, ObjData &data)
{
#define EATWS() while (*line == ' ' || *line == '\t') ++ line
if (*line == 0)
return true;
assert(Slic3r::is_decimal_separator_point());
// Ignore whitespaces at the beginning of the line.
//FIXME is this a good idea?
EATWS();
@@ -55,19 +51,19 @@ static bool obj_parseline(const char *line, ObjData &data)
line = endptr;
EATWS();
}
double w = 0;
/*double w = 0;
if (*line != 0) {
w = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
EATWS();
}
}*/
if (*line != 0)
return false;
data.textureCoordinates.push_back((float)u);
data.textureCoordinates.push_back((float)v);
data.textureCoordinates.push_back((float)w);
//data.textureCoordinates.push_back((float)w);
break;
}
case 'n':
@@ -156,23 +152,46 @@ static bool obj_parseline(const char *line, ObjData &data)
return false;
line = endptr;
EATWS();
double w = 1.0;
if (*line != 0) {
w = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
EATWS();
double color_x = 0.0, color_y = 0.0, color_z = 0.0, color_w = 0.0;//undefine color
if (*line != 0) {
if (!data.has_vertex_color) {
data.has_vertex_color = true;
}
color_x = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
EATWS();
color_y = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
EATWS();
color_z = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
EATWS();
color_w = 1.0;//default define alpha = 1.0
if (*line != 0) {
color_w = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
line = endptr;
EATWS();
}
}
// the following check is commented out because there may be obj files containing extra data, as those generated by Meshlab,
// see https://dev.prusa3d.com/browse/SPE-1019 for an example,
// and this would lead to a crash because no vertex would be stored
// and this would lead to a crash because no vertex would be stored
// if (*line != 0)
// return false;
data.coordinates.push_back((float)x);
data.coordinates.push_back((float)y);
data.coordinates.push_back((float)z);
data.coordinates.push_back((float)w);
data.coordinates.push_back((float) color_x);
data.coordinates.push_back((float) color_y);
data.coordinates.push_back((float) color_z);
data.coordinates.push_back((float) color_w);
break;
}
}
@@ -232,6 +251,24 @@ static bool obj_parseline(const char *line, ObjData &data)
data.vertices.push_back(vertex);
EATWS();
}
if (data.usemtls.size() > 0) {
data.usemtls.back().vertexIdxEnd = (int) data.vertices.size();
}
if (data.usemtls.size() > 0) {
int face_index_count = 0;
for (int i = data.vertices.size() - 1; i >= 0; i--) {
if (data.vertices[i].coordIdx == -1) {
break;
}
face_index_count++;
}
if (face_index_count == 3) {//tri
data.usemtls.back().face_end++;
} else if (face_index_count == 4) {//quad
data.usemtls.back().face_end++;
data.usemtls.back().face_end++;
}
}
vertex.coordIdx = -1;
vertex.normalIdx = -1;
vertex.textureCoordIdx = -1;
@@ -263,10 +300,23 @@ static bool obj_parseline(const char *line, ObjData &data)
// usemtl [material name]
// printf("usemtl %s\r\n", line);
EATWS();
if (data.usemtls.size()>0) {
data.usemtls.back().vertexIdxEnd = (int) data.vertices.size();
}
ObjUseMtl usemtl;
usemtl.vertexIdxFirst = (int)data.vertices.size();
usemtl.name = line;
data.usemtls.push_back(usemtl);
if (data.usemtls.size() == 1) {
data.usemtls.back().face_start = 0;
}
else {//>=2
auto count = data.usemtls.size();
auto& last_usemtl = data.usemtls[count-1];
auto& last_last_usemtl = data.usemtls[count - 2];
last_usemtl.face_start = last_last_usemtl.face_end + 1;
}
data.usemtls.back().face_end = data.usemtls.back().face_start - 1;
break;
}
case 'o':
@@ -323,6 +373,197 @@ static bool obj_parseline(const char *line, ObjData &data)
return true;
}
static std::string cur_mtl_name = "";
static bool mtl_parseline(const char *line, MtlData &data)
{
if (*line == 0) return true;
assert(Slic3r::is_decimal_separator_point());
// Ignore whitespaces at the beginning of the line.
// FIXME is this a good idea?
EATWS();
char c1 = *line++;
switch (c1) {
case '#': {// Comment, ignore the rest of the line.
break;
}
case 'n': {
if (*(line++) != 'e' || *(line++) != 'w' || *(line++) != 'm' || *(line++) != 't' || *(line++) != 'l')
return false;
EATWS();
ObjNewMtl new_mtl;
cur_mtl_name = line;
data.new_mtl_unmap[cur_mtl_name] = std::make_shared<ObjNewMtl>();
break;
}
case 'm': {
if (*(line++) != 'a' || *(line++) != 'p' || *(line++) != '_' || *(line++) != 'K' || *(line++) != 'd') return false;
EATWS();
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->map_Kd = line;
}
break;
}
case 'N': {
char cur_char = *(line++);
if (cur_char == 's') {
EATWS();
char * endptr = 0;
double ns = strtod(line, &endptr);
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Ns = (float) ns;
}
} else if (cur_char == 'i') {
EATWS();
char * endptr = 0;
double ni = strtod(line, &endptr);
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Ni = (float) ni;
}
}
break;
}
case 'K': {
char cur_char = *(line++);
if (cur_char == 'a') {
EATWS();
char * endptr = 0;
double x = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double y = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double z = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
line = endptr;
EATWS();
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Ka[0] = x;
data.new_mtl_unmap[cur_mtl_name]->Ka[1] = y;
data.new_mtl_unmap[cur_mtl_name]->Ka[2] = z;
}
} else if (cur_char == 'd') {
EATWS();
char * endptr = 0;
double x = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double y = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double z = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
line = endptr;
EATWS();
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Kd[0] = x;
data.new_mtl_unmap[cur_mtl_name]->Kd[1] = y;
data.new_mtl_unmap[cur_mtl_name]->Kd[2] = z;
}
} else if (cur_char == 's') {
EATWS();
char * endptr = 0;
double x = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double y = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double z = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
line = endptr;
EATWS();
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Ks[0] = x;
data.new_mtl_unmap[cur_mtl_name]->Ks[1] = y;
data.new_mtl_unmap[cur_mtl_name]->Ks[2] = z;
}
} else if (cur_char == 'e') {
EATWS();
char * endptr = 0;
double x = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double y = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double z = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
line = endptr;
EATWS();
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Ke[0] = x;
data.new_mtl_unmap[cur_mtl_name]->Ke[1] = y;
data.new_mtl_unmap[cur_mtl_name]->Ke[2] = z;
}
}
break;
}
case 'i': {
if (*(line++) != 'l' || *(line++) != 'l' || *(line++) != 'u' || *(line++) != 'm')
return false;
EATWS();
char * endptr = 0;
double illum = strtod(line, &endptr);
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->illum = (float) illum;
}
break;
}
case 'd': {
EATWS();
char * endptr = 0;
double d = strtod(line, &endptr);
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->d = (float) d;
}
break;
}
case 'T': {
char cur_char = *(line++);
if (cur_char == 'r') {
EATWS();
char * endptr = 0;
double tr = strtod(line, &endptr);
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Tr = (float) tr;
}
break;
} else if (cur_char == 'f') {
EATWS();
char * endptr = 0;
double x = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double y = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double z = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
line = endptr;
EATWS();
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Tf[0] = x;
data.new_mtl_unmap[cur_mtl_name]->Tf[1] = y;
data.new_mtl_unmap[cur_mtl_name]->Tf[2] = z;
}
break;
}
}
}
return true;
}
bool objparse(const char *path, ObjData &data)
{
@@ -369,10 +610,52 @@ bool objparse(const char *path, ObjData &data)
return true;
}
bool mtlparse(const char *path, MtlData &data)
{
Slic3r::CNumericLocalesSetter locales_setter;
FILE *pFile = boost::nowide::fopen(path, "rt");
if (pFile == 0) return false;
cur_mtl_name = "";
try {
char buf[65536 * 2];
size_t len = 0;
size_t lenPrev = 0;
while ((len = ::fread(buf + lenPrev, 1, 65536, pFile)) != 0) {
len += lenPrev;
size_t lastLine = 0;
for (size_t i = 0; i < len; ++i)
if (buf[i] == '\r' || buf[i] == '\n') {
buf[i] = 0;
char *c = buf + lastLine;
while (*c == ' ' || *c == '\t') ++c;
// FIXME check the return value and exit on error?
// Will it break parsing of some obj files?
mtl_parseline(c, data);
lastLine = i + 1;
}
lenPrev = len - lastLine;
if (lenPrev > 65536) {
BOOST_LOG_TRIVIAL(error) << "MtlParser: Excessive line length";
::fclose(pFile);
return false;
}
memmove(buf, buf + lastLine, lenPrev);
}
} catch (std::bad_alloc &) {
BOOST_LOG_TRIVIAL(error) << "MtlParser: Out of memory";
}
::fclose(pFile);
// printf("vertices: %d\r\n", data.vertices.size() / 4);
// printf("coords: %d\r\n", data.coordinates.size());
return true;
}
bool objparse(std::istream &stream, ObjData &data)
{
Slic3r::CNumericLocalesSetter locales_setter;
try {
char buf[65536 * 2];
size_t len = 0;
+38 -11
View File
@@ -3,6 +3,8 @@
#include <string>
#include <vector>
#include <array>
#include <unordered_map>
#include <istream>
namespace ObjParser {
@@ -16,22 +18,39 @@ struct ObjVertex
inline bool operator==(const ObjVertex &v1, const ObjVertex &v2)
{
return
v1.coordIdx == v2.coordIdx &&
v1.textureCoordIdx == v2.textureCoordIdx &&
return v1.coordIdx == v2.coordIdx &&
v1.textureCoordIdx == v2.textureCoordIdx &&
v1.normalIdx == v2.normalIdx;
}
struct ObjUseMtl
{
int vertexIdxFirst;
int vertexIdxEnd{-1};
int face_start;
int face_end{-1};
std::string name;
};
struct ObjNewMtl
{
std::string name;
float Ns;
float Ni;
float d;
float illum;
float Tr{1.0f}; // Transmission
std::array<float, 3> Tf;
std::array<float, 3> Ka;
std::array<float, 3> Kd;
std::array<float, 3> Ks;
std::array<float, 3> Ke;
std::string map_Kd;//defalut png
};
inline bool operator==(const ObjUseMtl &v1, const ObjUseMtl &v2)
{
return
v1.vertexIdxFirst == v2.vertexIdxFirst &&
return v1.vertexIdxFirst == v2.vertexIdxFirst &&
v1.name.compare(v2.name) == 0;
}
@@ -56,8 +75,7 @@ struct ObjGroup
inline bool operator==(const ObjGroup &v1, const ObjGroup &v2)
{
return
v1.vertexIdxFirst == v2.vertexIdxFirst &&
return v1.vertexIdxFirst == v2.vertexIdxFirst &&
v1.name.compare(v2.name) == 0;
}
@@ -69,17 +87,19 @@ struct ObjSmoothingGroup
inline bool operator==(const ObjSmoothingGroup &v1, const ObjSmoothingGroup &v2)
{
return
v1.vertexIdxFirst == v2.vertexIdxFirst &&
return v1.vertexIdxFirst == v2.vertexIdxFirst &&
v1.smoothingGroupID == v2.smoothingGroupID;
}
#define OBJ_VERTEX_COLOR_ALPHA 6
#define OBJ_VERTEX_LENGTH 7 // x, y, z, color_x,color_y,color_z,color_w
#define ONE_FACE_SIZE 4//ONE_FACE format: f 8/4/6 7/3/6 6/2/6 -1/-1/-1
struct ObjData {
// Version of the data structure for load / store in the private binary format.
int version;
// x, y, z, w
// x, y, z, color_x,color_y,color_z,color_w
std::vector<float> coordinates;
bool has_vertex_color{false};
// u, v, w
std::vector<float> textureCoordinates;
// x, y, z
@@ -97,7 +117,14 @@ struct ObjData {
std::vector<ObjVertex> vertices;
};
struct MtlData
{
// Version of the data structure for load / store in the private binary format.
int version;
std::unordered_map<std::string, std::shared_ptr<ObjNewMtl>> new_mtl_unmap;
};
extern bool objparse(const char *path, ObjData &data);
extern bool mtlparse(const char *path, MtlData &data);
extern bool objparse(std::istream &stream, ObjData &data);
extern bool objbinsave(const char *path, const ObjData &data);
+2 -46
View File
@@ -1382,52 +1382,8 @@ namespace DoExport {
double total_used_filament = 0.0;
double total_weight = 0.0;
double total_cost = 0.0;
for (auto volume : result.print_statistics.volumes_per_extruder) {
total_extruded_volume += volume.second;
size_t extruder_id = volume.first;
auto extruder = std::find_if(extruders.begin(), extruders.end(), [extruder_id](const Extruder& extr) { return extr.id() == extruder_id; });
if (extruder == extruders.end())
continue;
double s = PI * sqr(0.5* extruder->filament_diameter());
double weight = volume.second * extruder->filament_density() * 0.001;
total_used_filament += volume.second/s;
total_weight += weight;
total_cost += weight * extruder->filament_cost() * 0.001;
}
//BBS: add flush volume
for (auto volume : result.print_statistics.flush_per_filament) {
total_extruded_volume += volume.second;
size_t extruder_id = volume.first;
auto extruder = std::find_if(extruders.begin(), extruders.end(), [extruder_id](const Extruder& extr) { return extr.id() == extruder_id; });
if (extruder == extruders.end())
continue;
double s = PI * sqr(0.5* extruder->filament_diameter());
double weight = volume.second * extruder->filament_density() * 0.001;
total_used_filament += volume.second/s;
total_weight += weight;
total_cost += weight * extruder->filament_cost() * 0.001;
}
for (auto volume : result.print_statistics.wipe_tower_volumes_per_extruder) {
total_extruded_volume += volume.second;
size_t extruder_id = volume.first;
auto extruder = std::find_if(extruders.begin(), extruders.end(), [extruder_id](const Extruder& extr) {return extr.id() == extruder_id; });
if (extruder == extruders.end())
continue;
double s = PI * sqr(0.5* extruder->filament_diameter());
double weight = volume.second * extruder->filament_density() * 0.001;
total_used_filament += volume.second/s;
total_weight += weight;
total_cost += weight * extruder->filament_cost() * 0.001;
}
for (auto volume : result.print_statistics.support_volumes_per_extruder) {
for (auto volume : result.print_statistics.total_volumes_per_extruder) {
total_extruded_volume += volume.second;
size_t extruder_id = volume.first;
@@ -1447,7 +1403,7 @@ namespace DoExport {
print_statistics.total_weight = total_weight;
print_statistics.total_cost = total_cost;
print_statistics.filament_stats = result.print_statistics.volumes_per_extruder;
print_statistics.filament_stats = result.print_statistics.model_volumes_per_extruder;
}
// if any reserved keyword is found, returns a std::vector containing the first MAX_COUNT keywords found
+50 -21
View File
@@ -753,7 +753,7 @@ void GCodeProcessor::UsedFilaments::reset()
volumes_per_color_change = std::vector<double>();
model_extrude_cache = 0.0f;
volumes_per_extruder.clear();
model_volumes_per_extruder.clear();
flush_per_filament.clear();
@@ -761,16 +761,20 @@ void GCodeProcessor::UsedFilaments::reset()
filaments_per_role.clear();
wipe_tower_cache = 0.0f;
wipe_tower_volume_per_extruder.clear();
wipe_tower_volumes_per_extruder.clear();
support_volume_cache = 0.0f;
support_volume_per_extruder.clear();
support_volumes_per_extruder.clear();
total_volume_cache = 0.0f;
total_volumes_per_extruder.clear();
}
void GCodeProcessor::UsedFilaments::increase_support_caches(double extruded_volume)
{
support_volume_cache += extruded_volume;
role_cache += extruded_volume;
total_volume_cache += extruded_volume;
}
void GCodeProcessor::UsedFilaments::increase_model_caches(double extruded_volume)
@@ -778,12 +782,14 @@ void GCodeProcessor::UsedFilaments::increase_model_caches(double extruded_volume
color_change_cache += extruded_volume;
model_extrude_cache += extruded_volume;
role_cache += extruded_volume;
total_volume_cache += extruded_volume;
}
void GCodeProcessor::UsedFilaments::increase_wipe_tower_caches(double extruded_volume)
{
wipe_tower_cache += extruded_volume;
role_cache += extruded_volume;
total_volume_cache += extruded_volume;
}
void GCodeProcessor::UsedFilaments::process_color_change_cache()
@@ -794,14 +800,27 @@ void GCodeProcessor::UsedFilaments::process_color_change_cache()
}
}
void GCodeProcessor::UsedFilaments::process_total_volume_cache(GCodeProcessor* processor)
{
size_t active_extruder_id = processor->m_extruder_id;
if (total_volume_cache!= 0.0f) {
if (total_volumes_per_extruder.find(active_extruder_id) != total_volumes_per_extruder.end())
total_volumes_per_extruder[active_extruder_id] += total_volume_cache;
else
total_volumes_per_extruder[active_extruder_id] = total_volume_cache;
total_volume_cache = 0.0f;
}
}
void GCodeProcessor::UsedFilaments::process_model_cache(GCodeProcessor* processor)
{
size_t active_extruder_id = processor->m_extruder_id;
if (model_extrude_cache != 0.0f) {
if (volumes_per_extruder.find(active_extruder_id) != volumes_per_extruder.end())
volumes_per_extruder[active_extruder_id] += model_extrude_cache;
if (model_volumes_per_extruder.find(active_extruder_id) != model_volumes_per_extruder.end())
model_volumes_per_extruder[active_extruder_id] += model_extrude_cache;
else
volumes_per_extruder[active_extruder_id] = model_extrude_cache;
model_volumes_per_extruder[active_extruder_id] = model_extrude_cache;
model_extrude_cache = 0.0f;
}
}
@@ -810,10 +829,10 @@ void GCodeProcessor::UsedFilaments::process_wipe_tower_cache(GCodeProcessor* pro
{
size_t active_extruder_id = processor->m_extruder_id;
if (wipe_tower_cache != 0.0f) {
if (wipe_tower_volume_per_extruder.find(active_extruder_id) != wipe_tower_volume_per_extruder.end())
wipe_tower_volume_per_extruder[active_extruder_id] += wipe_tower_cache;
if (wipe_tower_volumes_per_extruder.find(active_extruder_id) != wipe_tower_volumes_per_extruder.end())
wipe_tower_volumes_per_extruder[active_extruder_id] += wipe_tower_cache;
else
wipe_tower_volume_per_extruder[active_extruder_id] = wipe_tower_cache;
wipe_tower_volumes_per_extruder[active_extruder_id] = wipe_tower_cache;
wipe_tower_cache = 0.0f;
}
}
@@ -822,20 +841,27 @@ void GCodeProcessor::UsedFilaments::process_support_cache(GCodeProcessor* proces
{
size_t active_extruder_id = processor->m_extruder_id;
if (support_volume_cache != 0.0f){
if (support_volume_per_extruder.find(active_extruder_id) != support_volume_per_extruder.end())
support_volume_per_extruder[active_extruder_id] += support_volume_cache;
if (support_volumes_per_extruder.find(active_extruder_id) != support_volumes_per_extruder.end())
support_volumes_per_extruder[active_extruder_id] += support_volume_cache;
else
support_volume_per_extruder[active_extruder_id] = support_volume_cache;
support_volumes_per_extruder[active_extruder_id] = support_volume_cache;
support_volume_cache = 0.0f;
}
}
void GCodeProcessor::UsedFilaments::update_flush_per_filament(size_t extrude_id, float flush_volume)
{
if (flush_per_filament.find(extrude_id) != flush_per_filament.end())
flush_per_filament[extrude_id] += flush_volume;
else
flush_per_filament[extrude_id] = flush_volume;
if (flush_volume != 0.f) {
if (flush_per_filament.find(extrude_id) != flush_per_filament.end())
flush_per_filament[extrude_id] += flush_volume;
else
flush_per_filament[extrude_id] = flush_volume;
if (total_volumes_per_extruder.find(extrude_id) != total_volumes_per_extruder.end())
total_volumes_per_extruder[extrude_id] += flush_volume;
else
total_volumes_per_extruder[extrude_id] = flush_volume;
}
}
void GCodeProcessor::UsedFilaments::process_role_cache(GCodeProcessor* processor)
@@ -865,6 +891,7 @@ void GCodeProcessor::UsedFilaments::process_caches(GCodeProcessor* processor)
process_role_cache(processor);
process_wipe_tower_cache(processor);
process_support_cache(processor);
process_total_volume_cache(processor);
}
#if ENABLE_GCODE_VIEWER_STATISTICS
@@ -4542,6 +4569,7 @@ void GCodeProcessor::process_filaments(CustomGCode::Type code)
if (code == CustomGCode::ToolChange) {
m_used_filaments.process_model_cache(this);
m_used_filaments.process_support_cache(this);
m_used_filaments.process_total_volume_cache(this);
//BBS: reset remaining filament
m_remaining_volume = m_nozzle_volume;
}
@@ -4573,11 +4601,12 @@ void GCodeProcessor::update_estimated_times_stats()
m_result.print_statistics.modes[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Stealth)].reset();
m_result.print_statistics.volumes_per_color_change = m_used_filaments.volumes_per_color_change;
m_result.print_statistics.volumes_per_extruder = m_used_filaments.volumes_per_extruder;
m_result.print_statistics.wipe_tower_volumes_per_extruder = m_used_filaments.wipe_tower_volume_per_extruder;
m_result.print_statistics.support_volumes_per_extruder = m_used_filaments.support_volume_per_extruder;
m_result.print_statistics.model_volumes_per_extruder = m_used_filaments.model_volumes_per_extruder;
m_result.print_statistics.wipe_tower_volumes_per_extruder = m_used_filaments.wipe_tower_volumes_per_extruder;
m_result.print_statistics.support_volumes_per_extruder = m_used_filaments.support_volumes_per_extruder;
m_result.print_statistics.flush_per_filament = m_used_filaments.flush_per_filament;
m_result.print_statistics.used_filaments_per_role = m_used_filaments.filaments_per_role;
m_result.print_statistics.total_volumes_per_extruder = m_used_filaments.total_volumes_per_extruder;
}
//BBS: ugly code...
@@ -4587,8 +4616,8 @@ void GCodeProcessor::update_slice_warnings()
auto get_used_extruders = [this]() {
std::vector<size_t> used_extruders;
used_extruders.reserve(m_used_filaments.volumes_per_extruder.size());
for (auto item : m_used_filaments.volumes_per_extruder) {
used_extruders.reserve(m_used_filaments.total_volumes_per_extruder.size());
for (auto item : m_used_filaments.total_volumes_per_extruder) {
used_extruders.push_back(item.first);
}
return used_extruders;
+12 -5
View File
@@ -73,9 +73,10 @@ namespace Slic3r {
};
std::vector<double> volumes_per_color_change;
std::map<size_t, double> volumes_per_extruder;
std::map<size_t, double> model_volumes_per_extruder;
std::map<size_t, double> wipe_tower_volumes_per_extruder;
std::map<size_t, double> support_volumes_per_extruder;
std::map<size_t, double> total_volumes_per_extruder;
//BBS: the flush amount of every filament
std::map<size_t, double> flush_per_filament;
std::map<ExtrusionRole, std::pair<double, double>> used_filaments_per_role;
@@ -92,7 +93,9 @@ namespace Slic3r {
volumes_per_color_change.clear();
volumes_per_color_change.shrink_to_fit();
wipe_tower_volumes_per_extruder.clear();
volumes_per_extruder.clear();
model_volumes_per_extruder.clear();
support_volumes_per_extruder.clear();
total_volumes_per_extruder.clear();
flush_per_filament.clear();
used_filaments_per_role.clear();
total_filamentchanges = 0;
@@ -500,17 +503,20 @@ namespace Slic3r {
std::vector<double> volumes_per_color_change;
double model_extrude_cache;
std::map<size_t, double> volumes_per_extruder;
std::map<size_t, double> model_volumes_per_extruder;
double wipe_tower_cache;
std::map<size_t, double>wipe_tower_volume_per_extruder;
std::map<size_t, double>wipe_tower_volumes_per_extruder;
double support_volume_cache;
std::map<size_t, double>support_volume_per_extruder;
std::map<size_t, double>support_volumes_per_extruder;
//BBS: the flush amount of every filament
std::map<size_t, double> flush_per_filament;
double total_volume_cache;
std::map<size_t, double>total_volumes_per_extruder;
double role_cache;
std::map<ExtrusionRole, std::pair<double, double>> filaments_per_role;
@@ -524,6 +530,7 @@ namespace Slic3r {
void process_model_cache(GCodeProcessor* processor);
void process_wipe_tower_cache(GCodeProcessor* processor);
void process_support_cache(GCodeProcessor* processor);
void process_total_volume_cache(GCodeProcessor* processor);
void update_flush_per_filament(size_t extrude_id, float flush_length);
void process_role_cache(GCodeProcessor* processor);
+5 -3
View File
@@ -160,10 +160,12 @@ VoronoiDiagram::detect_known_issues(const VoronoiDiagram &voronoi_diagram, Segme
return IssueType::FINITE_EDGE_WITH_NON_FINITE_VERTEX;
} else if (const IssueType cell_issue_type = detect_known_voronoi_cell_issues(voronoi_diagram, segment_begin, segment_end); cell_issue_type != IssueType::NO_ISSUE_DETECTED) {
return cell_issue_type;
} else if (!VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(voronoi_diagram, segment_begin, segment_end)) {
// Detection of non-planar Voronoi diagram detects at least GH issues #8474, #8514 and #8446.
return IssueType::NON_PLANAR_VORONOI_DIAGRAM;
}
// BBS: test no problem in BBS
//} else if (!VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(voronoi_diagram, segment_begin, segment_end)) {
// // Detection of non-planar Voronoi diagram detects at least GH issues #8474, #8514 and #8446.
// return IssueType::NON_PLANAR_VORONOI_DIAGRAM;
//}
return IssueType::NO_ISSUE_DETECTED;
}
+206 -6
View File
@@ -24,9 +24,6 @@
#include "TriangleSelector.hpp"
#include "Format/AMF.hpp"
#include "Format/OBJ.hpp"
#include "Format/STL.hpp"
#include "Format/STEP.hpp"
#include "Format/svg.hpp"
// BBS
#include "FaceDetector.hpp"
@@ -60,6 +57,9 @@
#define _L(s) Slic3r::I18N::translate(s)
namespace Slic3r {
const std::vector<std::string> CONST_FILAMENTS = {
"", "4", "8", "0C", "1C", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "AC", "BC", "CC", "DC",
}; // 5 10 15 16
// BBS initialization of static variables
std::map<size_t, ExtruderParams> Model::extruderParamsMap = { {0,{"",0,0}}};
GlobalSpeedMap Model::printSpeedMap{};
@@ -190,7 +190,12 @@ Model::~Model()
// Loading model from a file, it may be a simple geometry file as STL or OBJ, however it may be a project file as well.
Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions,
LoadStrategy options, PlateDataPtrs* plate_data, std::vector<Preset*>* project_presets, bool *is_xxx, Semver* file_version, Import3mfProgressFn proFn,
ImportstlProgressFn stlFn, ImportStepProgressFn stepFn, StepIsUtf8Fn stepIsUtf8Fn, BBLProject* project, int plate_id)
ImportstlProgressFn stlFn,
ImportStepProgressFn stepFn,
StepIsUtf8Fn stepIsUtf8Fn,
BBLProject * project,
int plate_id,
ObjImportColorFn objFn)
{
Model model;
@@ -221,8 +226,46 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c
result = load_stl(input_file.c_str(), &model, nullptr, stlFn);
else if (boost::algorithm::iends_with(input_file, ".oltp"))
result = load_stl(input_file.c_str(), &model, nullptr, stlFn,256);
else if (boost::algorithm::iends_with(input_file, ".obj"))
result = load_obj(input_file.c_str(), &model, message);
else if (boost::algorithm::iends_with(input_file, ".obj")) {
ObjInfo obj_info;
result = load_obj(input_file.c_str(), &model, obj_info, message);
if (result){
unsigned char first_extruder_id;
if (obj_info.vertex_colors.size() > 0) {
std::vector<unsigned char> vertex_filament_ids;
if (objFn) { // 1.result is ok and pop up a dialog
objFn(obj_info.vertex_colors, false, vertex_filament_ids, first_extruder_id);
if (vertex_filament_ids.size() > 0) {
result = obj_import_vertex_color_deal(vertex_filament_ids, first_extruder_id, & model);
}
} else { // test //todo delete
vertex_filament_ids.push_back(2);
vertex_filament_ids.push_back(3);
vertex_filament_ids.push_back(4);
vertex_filament_ids.push_back(1); // 4
vertex_filament_ids.push_back(1);
vertex_filament_ids.push_back(1);
vertex_filament_ids.push_back(1);
vertex_filament_ids.push_back(1); // 8
result = obj_import_vertex_color_deal(vertex_filament_ids, first_extruder_id, &model);
}
} else if (obj_info.face_colors.size() > 0 && obj_info.has_uv_png == false) { // mtl file
std::vector<unsigned char> face_filament_ids;
if (objFn) { // 1.result is ok and pop up a dialog
objFn(obj_info.face_colors, obj_info.is_single_mtl, face_filament_ids, first_extruder_id);
if (face_filament_ids.size() > 0) {
result = obj_import_face_color_deal(face_filament_ids, first_extruder_id, &model);
}
}
} /*else if (obj_info.has_uv_png && obj_info.uvs.size() > 0) {
boost::filesystem::path full_path(input_file);
std::string obj_directory = full_path.parent_path().string();
obj_info.obj_dircetory = obj_directory;
result = false;
message = _L("Importing obj with png function is developing.");
}*/
}
}
else if (boost::algorithm::iends_with(input_file, ".svg"))
result = load_svg(input_file.c_str(), &model, message);
//BBS: remove the old .amf.xml files
@@ -2866,6 +2909,163 @@ void Model::setExtruderParams(const DynamicPrintConfig& config, int extruders_co
}
}
static void get_real_filament_id(const unsigned char &id, std::string &result) {
if (id < CONST_FILAMENTS.size()) {
result = CONST_FILAMENTS[id];
} else {
result = "";//error
}
};
bool Model::obj_import_vertex_color_deal(const std::vector<unsigned char> &vertex_filament_ids, const unsigned char &first_extruder_id, Model *model)
{
if (vertex_filament_ids.size() == 0) {
return false;
}
// 2.generate mmu_segmentation_facets
if (model->objects.size() == 1 ) {
auto obj = model->objects[0];
obj->config.set("extruder", first_extruder_id);
if (obj->volumes.size() == 1) {
enum VertexColorCase {
_3_SAME_COLOR,
_3_DIFF_COLOR,
_2_SAME_1_DIFF_COLOR,
};
auto calc_vertex_color_case = [](const unsigned char &c0, const unsigned char &c1, const unsigned char &c2, VertexColorCase &vertex_color_case,
unsigned char &iso_index) {
if (c0 == c1 && c1 == c2) {
vertex_color_case = VertexColorCase::_3_SAME_COLOR;
} else if (c0 != c1 && c1 != c2 && c0 != c2) {
vertex_color_case = VertexColorCase::_3_DIFF_COLOR;
} else if (c0 == c1) {
vertex_color_case = _2_SAME_1_DIFF_COLOR;
iso_index = 2;
} else if (c1 == c2) {
vertex_color_case = _2_SAME_1_DIFF_COLOR;
iso_index = 0;
} else if (c0 == c2) {
vertex_color_case = _2_SAME_1_DIFF_COLOR;
iso_index = 1;
} else {
std::cout << "error";
}
};
auto calc_tri_area = [](const Vec3f &v0, const Vec3f &v1, const Vec3f &v2) {
return std::abs((v0 - v1).cross(v0 - v2).norm()) / 2;
};
auto volume = obj->volumes[0];
volume->config.set("extruder", first_extruder_id);
auto face_count = volume->mesh().its.indices.size();
volume->mmu_segmentation_facets.reserve(face_count);
if (volume->mesh().its.vertices.size() != vertex_filament_ids.size()) {
return false;
}
for (size_t i = 0; i < volume->mesh().its.indices.size(); i++) {
auto face = volume->mesh().its.indices[i];
auto filament_id0 = vertex_filament_ids[face[0]];
auto filament_id1 = vertex_filament_ids[face[1]];
auto filament_id2 = vertex_filament_ids[face[2]];
if (filament_id0 <= 1 && filament_id1 <= 1 && filament_id2 <= 2) {
continue;
}
if (i == 0) {
std::cout << "";
}
VertexColorCase vertex_color_case;
unsigned char iso_index;
calc_vertex_color_case(filament_id0, filament_id1, filament_id2, vertex_color_case, iso_index);
switch (vertex_color_case) {
case _3_SAME_COLOR: {
std::string result;
get_real_filament_id(filament_id0, result);
volume->mmu_segmentation_facets.set_triangle_from_string(i, result);
break;
}
case _3_DIFF_COLOR: {
std::string result0, result1, result2;
get_real_filament_id(filament_id0, result0);
get_real_filament_id(filament_id1, result1);
get_real_filament_id(filament_id2, result2);
auto v0 = volume->mesh().its.vertices[face[0]];
auto v1 = volume->mesh().its.vertices[face[1]];
auto v2 = volume->mesh().its.vertices[face[2]];
auto dir_0_1 = (v1 - v0).normalized();
auto dir_0_2 = (v2 - v0).normalized();
float sita0 = acos(dir_0_1.dot(dir_0_2));
auto dir_1_0 = -dir_0_1;
auto dir_1_2 = (v2 - v1).normalized();
float sita1 = acos(dir_1_0.dot(dir_1_2));
float sita2 = PI - sita0 - sita1;
std::array<float, 3> sitas = {sita0, sita1, sita2};
float max_sita = sitas[0];
int max_sita_vertex_index = 0;
for (size_t j = 1; j < sitas.size(); j++) {
if (sitas[j] > max_sita) {
max_sita_vertex_index = j;
max_sita = sitas[j];
}
}
if (max_sita_vertex_index == 0) {
volume->mmu_segmentation_facets.set_triangle_from_string(i, result0 + result1 + result2 + (result1 + result2 + "5" )+ "3"); //"1C0C2C0C1C13"
} else if (max_sita_vertex_index == 1) {
volume->mmu_segmentation_facets.set_triangle_from_string(i, result0 + result1 + result2 + (result0 + result2 + "9") + "3");
} else{// if (max_sita_vertex_index == 2)
volume->mmu_segmentation_facets.set_triangle_from_string(i, result0 + result1 + result2 + (result1 + result0 + "1") + "3");
}
break;
}
case _2_SAME_1_DIFF_COLOR: {
std::string result0, result1, result2;
get_real_filament_id(filament_id0, result0);
get_real_filament_id(filament_id1, result1);
get_real_filament_id(filament_id2, result2);
if (iso_index == 0) {
volume->mmu_segmentation_facets.set_triangle_from_string(i, result0 + result1 + result1 + "2");
} else if (iso_index == 1) {
volume->mmu_segmentation_facets.set_triangle_from_string(i, result1 + result0 + result0 + "6");
} else if (iso_index == 2) {
volume->mmu_segmentation_facets.set_triangle_from_string(i, result2 + result0 + result0 + "A");
}
break;
}
default: break;
}
}
return true;
}
}
return false;
}
bool Model::obj_import_face_color_deal(const std::vector<unsigned char> &face_filament_ids, const unsigned char &first_extruder_id, Model *model)
{
if (face_filament_ids.size() == 0) { return false; }
// 2.generate mmu_segmentation_facets
if (model->objects.size() == 1) {
auto obj = model->objects[0];
obj->config.set("extruder", first_extruder_id);
if (obj->volumes.size() == 1) {
auto volume = obj->volumes[0];
volume->config.set("extruder", first_extruder_id);
auto face_count = volume->mesh().its.indices.size();
volume->mmu_segmentation_facets.reserve(face_count);
if (volume->mesh().its.indices.size() != face_filament_ids.size()) { return false; }
for (size_t i = 0; i < volume->mesh().its.indices.size(); i++) {
auto face = volume->mesh().its.indices[i];
auto filament_id = face_filament_ids[i];
if (filament_id <= 1) { continue; }
std::string result;
get_real_filament_id(filament_id, result);
volume->mmu_segmentation_facets.set_triangle_from_string(i, result);
}
return true;
}
}
return false;
}
// update the maxSpeed of an object if it is different from the global configuration
double Model::findMaxSpeed(const ModelObject* object) {
auto objectKeys = object->config.keys();
+10 -1
View File
@@ -35,6 +35,7 @@
#include "Format/STEP.hpp"
//BBS: add stl
#include "Format/STL.hpp"
#include "Format/OBJ.hpp"
#include <map>
#include <memory>
@@ -1564,8 +1565,16 @@ public:
DynamicPrintConfig* config = nullptr, ConfigSubstitutionContext* config_substitutions = nullptr,
LoadStrategy options = LoadStrategy::AddDefaultInstances, PlateDataPtrs* plate_data = nullptr,
std::vector<Preset*>* project_presets = nullptr, bool* is_xxx = nullptr, Semver* file_version = nullptr, Import3mfProgressFn proFn = nullptr,
ImportstlProgressFn stlFn = nullptr, ImportStepProgressFn stepFn = nullptr, StepIsUtf8Fn stepIsUtf8Fn = nullptr, BBLProject* project = nullptr, int plate_id = 0);
ImportstlProgressFn stlFn = nullptr,
ImportStepProgressFn stepFn = nullptr,
StepIsUtf8Fn stepIsUtf8Fn = nullptr,
BBLProject * project = nullptr,
int plate_id = 0,
ObjImportColorFn objFn = nullptr
);
// BBS
static bool obj_import_vertex_color_deal(const std::vector<unsigned char> &vertex_filament_ids, const unsigned char &first_extruder_id, Model *model);
static bool obj_import_face_color_deal(const std::vector<unsigned char> &face_filament_ids, const unsigned char &first_extruder_id, Model *model);
static double findMaxSpeed(const ModelObject* object);
static double getThermalLength(const ModelVolume* modelVolumePtr);
static double getThermalLength(const std::vector<ModelVolume*> modelVolumePtrs);
+191
View File
@@ -0,0 +1,191 @@
#pragma once
#include <iostream>
#include <ctime>
#include "opencv2/opencv.hpp"
class QuantKMeans
{
public:
int m_alpha_thres;
cv::Mat m_flatten_labels;
cv::Mat m_centers8UC3;
QuantKMeans(int alpha_thres = 10) : m_alpha_thres(alpha_thres) {}
void apply(cv::Mat &ori_image, cv::Mat &new_image, int num_cluster, int color_space)
{
cv::Mat image;
convert_color_space(ori_image, image, color_space);
cv::Mat flatten_image = flatten(image);
apply(flatten_image, num_cluster, color_space);
replace_centers(ori_image, new_image);
}
void apply_aplha(cv::Mat &ori_image, cv::Mat &new_image, int num_cluster, int color_space)
{
// cout << " *** DoAlpha *** " << endl;
cv::Mat flatten_image8UC3 = flatten_alpha(ori_image);
cv::Mat image8UC3;
convert_color_space(flatten_image8UC3, image8UC3, color_space);
cv::Mat image32FC3(image8UC3.rows, 1, CV_32FC3);
for (int i = 0; i < image8UC3.rows; i++) image32FC3.at<cv::Vec3f>(i, 0) = image8UC3.at<cv::Vec3b>(i, 0);
apply(image32FC3, num_cluster, color_space);
repalce_centers_aplha(ori_image, new_image);
}
void apply(cv::Mat &flatten_image, int num_cluster, int color_space)
{
cv::Mat centers32FC3;
num_cluster = fmin(flatten_image.rows, num_cluster);
kmeans(flatten_image, num_cluster, this->m_flatten_labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 300, 0.5), 3, cv::KMEANS_PP_CENTERS,
centers32FC3);
this->m_centers8UC3 = cv::Mat(num_cluster, 1, CV_8UC3);
for (int i = 0; i < num_cluster; i++) this->m_centers8UC3.at<cv::Vec3b>(i) = centers32FC3.at<cv::Vec3f>(i);
convert_color_space(this->m_centers8UC3, this->m_centers8UC3, color_space, true);
}
void apply(const std::vector<std::array<float, 4>> &ori_colors,
std::vector<std::array<float, 4>> & cluster_results,
std::vector<int> & labels,
int num_cluster = -1,
int color_space = 2)
{
// 0~255
cv::Mat flatten_image8UC3 = flatten_vector(ori_colors);
cv::Mat image8UC3;
convert_color_space(flatten_image8UC3, image8UC3, color_space);
cv::Mat image32FC3(image8UC3.rows, 1, CV_32FC3);
for (int i = 0; i < image8UC3.rows; i++)
image32FC3.at<cv::Vec3f>(i, 0) = image8UC3.at<cv::Vec3b>(i, 0);
int best_cluster = 1;
double cur_score, best_score = 100;
int max_cluster = ori_colors.size();
num_cluster = fmin(num_cluster, max_cluster);
if (num_cluster < 1) {
cur_score = kmeans(image32FC3, 1, this->m_flatten_labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 300, 0.5), 3, cv::KMEANS_PP_CENTERS);
best_score = cur_score;
for (int cur_cluster = 2; cur_cluster < 16; cur_cluster++) {
if (cur_cluster > max_cluster)
break;
cur_score = kmeans(image32FC3, cur_cluster, this->m_flatten_labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 300, 0.5), 3,
cv::KMEANS_PP_CENTERS);
best_cluster = cur_score < best_score ? cur_cluster : best_cluster;
best_score = cur_score < best_score ? cur_score : best_score;
}
} else
best_cluster = num_cluster;
cv::Mat centers32FC3;
kmeans(image32FC3, best_cluster, this->m_flatten_labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 300, 0.5), 3, cv::KMEANS_PP_CENTERS,
centers32FC3);
this->m_centers8UC3 = cv::Mat(best_cluster, 1, CV_8UC3);
for (int i = 0; i < best_cluster; i++)
this->m_centers8UC3.at<cv::Vec3b>(i) = centers32FC3.at<cv::Vec3f>(i);
convert_color_space(this->m_centers8UC3, this->m_centers8UC3, color_space, true);
cluster_results.clear();
labels.clear();
for (int i = 0; i < ori_colors.size(); i++)
labels.emplace_back(this->m_flatten_labels.at<int>(i, 0));
for (int i = 0; i < best_cluster; i++) {
cv::Vec3f center = this->m_centers8UC3.at<cv::Vec3b>(i, 0);
cluster_results.emplace_back(std::array<float, 4>{center[0] / 255.f, center[1] / 255.f, center[2] / 255.f, 1.f});
}
}
void replace_centers(cv::Mat &ori_image, cv::Mat &new_image)
{
for (int i = 0; i < ori_image.rows; i++) {
for (int j = 0; j < ori_image.cols; j++) {
int idx = this->m_flatten_labels.at<int>(i * ori_image.cols + j, 0);
cv::Vec3b pixel = this->m_centers8UC3.at<cv::Vec3b>(idx);
new_image.at<cv::Vec3b>(i, j) = pixel;
}
}
}
void repalce_centers_aplha(cv::Mat &ori_image, cv::Mat &new_image)
{
int cnt = 0;
int idx;
cv::Vec3b center;
for (int i = 0; i < ori_image.rows; i++) {
for (int j = 0; j < ori_image.cols; j++) {
cv::Vec4b pixel = ori_image.at<cv::Vec4b>(i, j);
if ((int) pixel[3] < this->m_alpha_thres)
new_image.at<cv::Vec4b>(i, j) = pixel;
else {
idx = this->m_flatten_labels.at<int>(cnt++, 0);
center = this->m_centers8UC3.at<cv::Vec3b>(idx);
new_image.at<cv::Vec4b>(i, j) = cv::Vec4b(center[0], center[1], center[2], pixel[3]);
}
}
}
}
void convert_color_space(cv::Mat &ori_image, cv::Mat &image, int color_space, bool reverse = false)
{
switch (color_space) {
case 0: image = ori_image; break;
case 1:
if (reverse)
cvtColor(ori_image, image, cv::COLOR_HSV2BGR);
else
cvtColor(ori_image, image, cv::COLOR_BGR2HSV);
break;
case 2:
if (reverse)
cvtColor(ori_image, image, cv::COLOR_Lab2BGR);
else
cvtColor(ori_image, image, cv::COLOR_BGR2Lab);
break;
default: break;
}
}
cv::Mat flatten(cv::Mat &image)
{
int num_pixels = image.rows * image.cols;
cv::Mat img(num_pixels, 1, CV_32FC3);
for (int i = 0; i < image.rows; i++) {
for (int j = 0; j < image.cols; j++) {
cv::Vec3f pixel = image.at<cv::Vec3b>(i, j);
img.at<cv::Vec3f>(i * image.cols + j, 0) = pixel;
}
}
return img;
}
cv::Mat flatten_alpha(cv::Mat &image)
{
int num_pixels = image.rows * image.cols;
for (int i = 0; i < image.rows; i++)
for (int j = 0; j < image.cols; j++) {
cv::Vec4b pixel = image.at<cv::Vec4b>(i, j);
if ((int) pixel[3] < this->m_alpha_thres) num_pixels--;
}
cv::Mat img(num_pixels, 1, CV_8UC3);
int cnt = 0;
for (int i = 0; i < image.rows; i++) {
for (int j = 0; j < image.cols; j++) {
cv::Vec4b pixel = image.at<cv::Vec4b>(i, j);
if ((int) pixel[3] >= this->m_alpha_thres) img.at<cv::Vec3b>(cnt++, 0) = cv::Vec3b(pixel[0], pixel[1], pixel[2]);
}
}
return img;
}
cv::Mat flatten_vector(const std::vector<std::array<float, 4>> &ori_colors)
{
int num_pixels = ori_colors.size();
cv::Mat image8UC3(num_pixels, 1, CV_8UC3);
for (int i = 0; i < num_pixels; i++) {
std::array<float, 4> pixel = ori_colors[i];
image8UC3.at<cv::Vec3b>(i, 0) = cv::Vec3b((int) (pixel[0] * 255.f), (int) (pixel[1] * 255.f), (int) (pixel[2] * 255.f));
}
return image8UC3;
}
};
+2
View File
@@ -1138,6 +1138,8 @@ void PresetCollection::load_presets(
preset.filament_id = key_values[BBL_JSON_KEY_FILAMENT_ID];
if (key_values.find(BBL_JSON_KEY_IS_CUSTOM) != key_values.end())
preset.custom_defined = key_values[BBL_JSON_KEY_IS_CUSTOM];
if (key_values.find(BBL_JSON_KEY_DESCRIPTION) != key_values.end())
preset.description = key_values[BBL_JSON_KEY_DESCRIPTION];
if (key_values.find("instantiation") != key_values.end())
preset.is_visible = key_values["instantiation"] != "false";
+1
View File
@@ -241,6 +241,7 @@ public:
std::string base_id; // base id of preset
std::string sync_info; // enum: "delete", "create", "update", ""
std::string custom_defined; // enum: "1", "0", ""
std::string description; //
long long updated_time{0}; //last updated time
std::map<std::string, std::string> key_values;
+6 -3
View File
@@ -1964,7 +1964,8 @@ std::set<std::string> PresetBundle::get_printer_names_by_printer_type_and_nozzle
if (printer_it->name.find(nozzle_diameter_str) != std::string::npos) printer_names.insert(printer_it->name);
}
assert(printer_names.size() == 1);
//assert(printer_names.size() == 1);
for (auto& printer_name : printer_names) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << " printer name: " << printer_name;
@@ -3463,7 +3464,7 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
// Load the print, filament or printer preset.
std::string preset_name;
DynamicPrintConfig config;
std::string alias_name, inherits, instantiation, setting_id, filament_id;
std::string alias_name, inherits, description, instantiation, setting_id, filament_id;
std::vector<std::string> renamed_from;
const DynamicPrintConfig* default_config = nullptr;
std::string reason;
@@ -3480,7 +3481,8 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
return reason;
}
preset_name = key_values[BBL_JSON_KEY_NAME];
instantiation = key_values[BBL_JSON_KEY_INSTANTIATION];
description = key_values[BBL_JSON_KEY_DESCRIPTION];
instantiation = key_values[BBL_JSON_KEY_INSTANTIATION];
auto setting_it = key_values.find(BBL_JSON_KEY_SETTING_ID);
if (setting_it != key_values.end())
setting_id = setting_it->second;
@@ -3603,6 +3605,7 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
loaded.is_system = true;
loaded.vendor = current_vendor_profile;
loaded.version = current_vendor_profile->config_version;
loaded.description = description;
loaded.setting_id = setting_id;
loaded.filament_id = filament_id;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << loaded.name << " load filament_id: " << filament_id;
+4 -1
View File
@@ -160,7 +160,8 @@ static t_config_enum_values s_keys_map_InfillPattern {
{ "archimedeanchords", ipArchimedeanChords },
{ "octagramspiral", ipOctagramSpiral },
{ "supportcubic", ipSupportCubic },
{ "lightning", ipLightning }
{ "lightning", ipLightning },
{ "crosshatch", ipCrossHatch}
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(InfillPattern)
@@ -2049,6 +2050,7 @@ def = this->add("filament_loading_speed", coFloats);
def->enum_values.push_back("octagramspiral");
def->enum_values.push_back("supportcubic");
def->enum_values.push_back("lightning");
def->enum_values.push_back("crosshatch");
def->enum_labels.push_back(L("Concentric"));
def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Grid"));
@@ -2066,6 +2068,7 @@ def = this->add("filament_loading_speed", coFloats);
def->enum_labels.push_back(L("Octagram Spiral"));
def->enum_labels.push_back(L("Support Cubic"));
def->enum_labels.push_back(L("Lightning"));
def->enum_labels.push_back(L("Cross Hatch"));
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipCubic));
auto def_infill_anchor_min = def = this->add("infill_anchor", coFloatOrPercent);
+1 -1
View File
@@ -69,7 +69,7 @@ enum AuthorizationType {
enum InfillPattern : int {
ipConcentric, ipRectilinear, ipGrid, ipLine, ipCubic, ipTriangles, ipStars, ipGyroid, ipHoneycomb, ipAdaptiveCubic, ipMonotonic, ipMonotonicLine, ipAlignedRectilinear, ip3DHoneycomb,
ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSupportCubic, ipSupportBase, ipConcentricInternal,
ipLightning,
ipLightning, ipCrossHatch,
ipCount,
};
+12 -3
View File
@@ -2333,9 +2333,17 @@ void PrintObject::bridge_over_infill()
};
// LAMBDA do determine optimal bridging angle
auto determine_bridging_angle = [](const Polygons &bridged_area, const Lines &anchors, InfillPattern dominant_pattern) {
auto determine_bridging_angle = [](const Polygons &bridged_area, const Lines &anchors, InfillPattern dominant_pattern, double infill_direction) {
AABBTreeLines::LinesDistancer<Line> lines_tree(anchors);
// Check it the infill that require a fixed infill angle.
switch (dominant_pattern) {
case ip3DHoneycomb:
case ipCrossHatch:
return (infill_direction + 45.0) * 2.0 * M_PI / 360.;
default: break;
}
std::map<double, int> counted_directions;
for (const Polygon &p : bridged_area) {
double acc_distance = 0;
@@ -2715,11 +2723,12 @@ void PrintObject::bridge_over_infill()
double bridging_angle = 0;
if (!anchors.empty()) {
bridging_angle = determine_bridging_angle(area_to_be_bridge, to_lines(anchors),
candidate.region->region().config().sparse_infill_pattern.value);
candidate.region->region().config().sparse_infill_pattern.value,
candidate.region->region().config().infill_direction.value);
} else {
// use expansion boundaries as anchors.
// Also, use Infill pattern that is neutral for angle determination, since there are no infill lines.
bridging_angle = determine_bridging_angle(area_to_be_bridge, to_lines(boundary_plines), InfillPattern::ipLine);
bridging_angle = determine_bridging_angle(area_to_be_bridge, to_lines(boundary_plines), InfillPattern::ipLine, 0);
}
boundary_plines.insert(boundary_plines.end(), anchors.begin(), anchors.end());
+25
View File
@@ -208,6 +208,8 @@ set(SLIC3R_GUI_SOURCES
GUI/Plater.hpp
GUI/PartPlate.cpp
GUI/PartPlate.hpp
GUI/UserNotification.cpp
GUI/UserNotification.hpp
GUI/PresetComboBoxes.hpp
GUI/PresetComboBoxes.cpp
GUI/BitmapComboBox.hpp
@@ -304,6 +306,8 @@ set(SLIC3R_GUI_SOURCES
GUI/CameraUtils.hpp
GUI/wxExtensions.cpp
GUI/wxExtensions.hpp
GUI/ObjColorDialog.cpp
GUI/ObjColorDialog.hpp
GUI/WipeTowerDialog.cpp
GUI/RammingChart.cpp
GUI/RammingChart.hpp
@@ -321,6 +325,8 @@ set(SLIC3R_GUI_SOURCES
GUI/ImGuiWrapper.cpp
GUI/DeviceManager.hpp
GUI/DeviceManager.cpp
GUI/UserManager.hpp
GUI/UserManager.cpp
GUI/HttpServer.hpp
GUI/HttpServer.cpp
Config/Snapshot.cpp
@@ -467,6 +473,24 @@ set(SLIC3R_GUI_SOURCES
Utils/json_diff.cpp
GUI/KBShortcutsDialog.hpp
GUI/KBShortcutsDialog.cpp
GUI/MultiMachine.hpp
GUI/MultiMachine.cpp
GUI/MultiMachinePage.hpp
GUI/MultiMachinePage.cpp
GUI/MultiMachineManagerPage.cpp
GUI/MultiMachineManagerPage.hpp
GUI/MultiPrintJob.cpp
GUI/MultiPrintJob.hpp
GUI/MultiSendMachineModel.hpp
GUI/MultiSendMachineModel.cpp
GUI/MultiTaskManagerPage.hpp
GUI/MultiTaskManagerPage.cpp
GUI/MultiTaskModel.hpp
GUI/MultiTaskModel.cpp
GUI/SendMultiMachinePage.hpp
GUI/SendMultiMachinePage.cpp
GUI/TaskManager.cpp
GUI/TaskManager.hpp
Utils/Http.cpp
Utils/Http.hpp
Utils/FixModelByWin10.cpp
@@ -526,6 +550,7 @@ set(SLIC3R_GUI_SOURCES
GUI/calib_dlg.cpp
Utils/CalibUtils.cpp
Utils/CalibUtils.hpp
Utils/ProfileDescription.hpp
GUI/PrinterCloudAuthDialog.cpp
GUI/PrinterCloudAuthDialog.hpp
Utils/Obico.cpp
+47 -10
View File
@@ -8,12 +8,19 @@
#include <wx/colordlg.h>
#include <wx/dcgraph.h>
#include "CalibUtils.hpp"
#include "../Utils/ColorSpaceConvert.hpp"
namespace Slic3r { namespace GUI {
wxDEFINE_EVENT(EVT_SELECTED_COLOR, wxCommandEvent);
AMSMaterialsSetting::AMSMaterialsSetting(wxWindow *parent, wxWindowID id)
static std::string float_to_string_with_precision(float value, int precision = 3)
{
std::stringstream stream;
stream << std::fixed << std::setprecision(precision) << value;
return stream.str();
}
AMSMaterialsSetting::AMSMaterialsSetting(wxWindow *parent, wxWindowID id)
: DPIDialog(parent, id, _L("AMS Materials Setting"), wxDefaultPosition, wxDefaultSize, wxBORDER_NONE)
, m_color_picker_popup(ColorPickerPopup(this))
{
@@ -281,6 +288,14 @@ void AMSMaterialsSetting::create_panel_kn(wxWindow* parent)
m_ratio_text->SetForegroundColour(wxColour(50, 58, 61));
m_ratio_text->SetFont(Label::Head_14);
m_ratio_text->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_HAND); });
m_ratio_text->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_ARROW); });
m_ratio_text->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {
wxLaunchDefaultBrowser(wxT("https://wiki.bambulab.com/en/software/bambu-studio/calibration_pa"));
});
wxBoxSizer *m_sizer_cali_resutl = new wxBoxSizer(wxHORIZONTAL);
// pa profile
m_title_pa_profile = new wxStaticText(parent, wxID_ANY, _L("PA Profile"), wxDefaultPosition, wxSize(AMS_MATERIALS_SETTING_LABEL_WIDTH, -1), 0);
@@ -750,6 +765,16 @@ bool AMSMaterialsSetting::Show(bool show)
m_input_nozzle_min->GetTextCtrl()->SetSize(wxSize(-1, FromDIP(20)));
//m_clr_picker->set_color(m_clr_picker->GetParent()->GetBackgroundColour());
/*if (obj && (obj->is_function_supported(PrinterFunction::FUNC_EXTRUSION_CALI) || obj->is_high_printer_type())) {
m_ratio_text->Show();
m_k_param->Show();
m_input_k_val->Show();
}
else {
m_ratio_text->Hide();
m_k_param->Hide();
m_input_k_val->Hide();
}*/
m_ratio_text->Show();
m_k_param->Show();
m_input_k_val->Show();
@@ -922,8 +947,8 @@ void AMSMaterialsSetting::on_select_cali_result(wxCommandEvent &evt)
{
m_pa_cali_select_id = evt.GetSelection();
if (m_pa_cali_select_id >= 0) {
m_input_k_val->GetTextCtrl()->SetValue(std::to_string(m_pa_profile_items[m_pa_cali_select_id].k_value));
m_input_n_val->GetTextCtrl()->SetValue(std::to_string(m_pa_profile_items[m_pa_cali_select_id].n_coef));
m_input_k_val->GetTextCtrl()->SetValue(float_to_string_with_precision(m_pa_profile_items[m_pa_cali_select_id].k_value));
m_input_n_val->GetTextCtrl()->SetValue(float_to_string_with_precision(m_pa_profile_items[m_pa_cali_select_id].n_coef));
}
else{
m_input_k_val->GetTextCtrl()->SetValue(std::to_string(0.00));
@@ -1012,6 +1037,8 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt)
m_button_confirm->SetBorderColor(wxColour(0x90, 0x90, 0x90));
m_comboBox_cali_result->Clear();
m_comboBox_cali_result->SetValue(wxEmptyString);
m_input_k_val->GetTextCtrl()->SetValue(wxEmptyString);
m_input_n_val->GetTextCtrl()->SetValue(wxEmptyString);
return;
}
else {
@@ -1076,8 +1103,8 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt)
}
if (cali_select_idx >= 0) {
m_input_k_val->GetTextCtrl()->SetValue(std::to_string(m_pa_profile_items[cali_select_idx].k_value));
m_input_n_val->GetTextCtrl()->SetValue(std::to_string(m_pa_profile_items[cali_select_idx].n_coef));
m_input_k_val->GetTextCtrl()->SetValue(float_to_string_with_precision(m_pa_profile_items[cali_select_idx].k_value));
m_input_n_val->GetTextCtrl()->SetValue(float_to_string_with_precision(m_pa_profile_items[cali_select_idx].n_coef));
}
}
else {
@@ -1121,7 +1148,6 @@ ColorPicker::ColorPicker(wxWindow* parent, wxWindowID id, const wxPoint& pos /*=
m_bitmap_border = create_scaled_bitmap("color_picker_border", nullptr, 25);
m_bitmap_border_dark = create_scaled_bitmap("color_picker_border_dark", nullptr, 25);
m_bitmap_transparent_def = create_scaled_bitmap("transparent_color_picker", nullptr, 25);
m_bitmap_transparent = create_scaled_bitmap("transparent_color_picker", nullptr, 25);
}
@@ -1185,12 +1211,12 @@ void ColorPicker::doRender(wxDC& dc)
if (m_selected) radius -= FromDIP(1);
if (alpha == 0) {
dc.DrawBitmap(m_bitmap_transparent_def, 0, 0);
dc.DrawBitmap(m_bitmap_transparent, 0, 0);
}
else if (alpha != 254 && alpha != 255) {
if (transparent_changed) {
std::string rgb = (m_colour.GetAsString(wxC2S_HTML_SYNTAX)).ToStdString();
if (rgb.size() == 9) {
if (rgb.size() == 8) {
//delete alpha value
rgb = rgb.substr(0, rgb.size() - 2);
}
@@ -1201,8 +1227,8 @@ void ColorPicker::doRender(wxDC& dc)
replace.push_back(fill_replace);
m_bitmap_transparent = ScalableBitmap(this, "transparent_color_picker", 25, false, false, true, replace).bmp();
transparent_changed = false;
dc.DrawBitmap(m_bitmap_transparent, 0, 0);
}
dc.DrawBitmap(m_bitmap_transparent, 0, 0);
}
else {
dc.SetPen(wxPen(m_colour));
@@ -1439,11 +1465,22 @@ ColorPickerPopup::ColorPickerPopup(wxWindow* parent)
void ColorPickerPopup::on_custom_clr_picker(wxMouseEvent& event)
{
std::vector<std::string> colors = wxGetApp().app_config->get_custom_color_from_config();
for (int i = 0; i < colors.size(); i++) {
m_clrData->SetCustomColour(i, string_to_wxColor(colors[i]));
}
auto clr_dialog = new wxColourDialog(nullptr, m_clrData);
wxColour picker_color;
if (clr_dialog->ShowModal() == wxID_OK) {
m_clrData = &(clr_dialog->GetColourData());
if (colors.size() != CUSTOM_COLOR_COUNT) {
colors.resize(CUSTOM_COLOR_COUNT);
}
for (int i = 0; i < CUSTOM_COLOR_COUNT; i++) {
colors[i] = color_to_string(m_clrData->GetCustomColour(i));
}
wxGetApp().app_config->save_custom_color_to_config(colors);
picker_color = wxColour(
m_clrData->GetColour().Red(),
+1 -2
View File
@@ -5,8 +5,8 @@
#include "wxExtensions.hpp"
#include "GUI_Utils.hpp"
#include "DeviceManager.hpp"
#include "wx/colourdata.h"
#include "wx/clrpicker.h"
#include "wx/colourdata.h"
#include "Widgets/RadioBox.hpp"
#include "Widgets/Button.hpp"
#include "Widgets/RoundedRectangle.hpp"
@@ -36,7 +36,6 @@ public:
wxBitmap m_bitmap_border;
wxBitmap m_bitmap_border_dark;
wxBitmap m_bitmap_transparent;
wxBitmap m_bitmap_transparent_def; //default transparent material
wxColour m_colour;
std::vector<wxColour> m_cols;
+65
View File
@@ -193,6 +193,40 @@ void AMSSetting::create()
m_sizer_switch_filament_tip->Add(m_sizer_switch_filament_inline, 1, wxALIGN_CENTER, 0);
// checkbox area 5
wxBoxSizer* m_sizer_air_print = new wxBoxSizer(wxHORIZONTAL);
m_checkbox_air_print = new ::CheckBox(m_panel_body);
m_checkbox_air_print->Bind(wxEVT_TOGGLEBUTTON, &AMSSetting::on_air_print_detect, this);
m_sizer_air_print->Add(m_checkbox_air_print, 0, wxTOP, 1);
m_sizer_air_print->Add(0, 0, 0, wxLEFT, 12);
m_title_air_print = new wxStaticText(m_panel_body, wxID_ANY, _L("Air Printing Detection"), wxDefaultPosition, wxDefaultSize, 0);
m_title_air_print->SetFont(::Label::Head_13);
m_title_air_print->SetForegroundColour(AMS_SETTING_GREY800);
m_title_air_print->Wrap(AMS_SETTING_BODY_WIDTH);
m_sizer_air_print->Add(m_title_air_print, 1, wxEXPAND, 0);
wxBoxSizer* m_sizer_air_print_tip = new wxBoxSizer(wxHORIZONTAL);
m_sizer_air_print_tip->Add(0, 0, 0, wxLEFT, 10);
// tip line
auto m_sizer_air_print_inline = new wxBoxSizer(wxVERTICAL);
m_tip_air_print_line = new Label(m_panel_body,
_L("Detects clogging and filament grinding, halting printing immediately to conserve time and filament.")
);
m_tip_air_print_line->SetFont(::Label::Body_13);
m_tip_air_print_line->SetForegroundColour(AMS_SETTING_GREY700);
m_tip_air_print_line->SetSize(wxSize(AMS_SETTING_BODY_WIDTH, -1));
m_tip_air_print_line->Wrap(AMS_SETTING_BODY_WIDTH);
m_sizer_air_print_inline->Add(m_tip_air_print_line, 0, wxEXPAND, 0);
m_sizer_air_print_tip->Add(m_sizer_air_print_inline, 1, wxALIGN_CENTER, 0);
m_checkbox_air_print->Hide();
m_title_air_print->Hide();
m_tip_air_print_line->Hide();
// panel img
wxPanel* m_panel_img = new wxPanel(m_panel_body, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_panel_img->SetBackgroundColour(AMS_SETTING_GREY200);
@@ -221,6 +255,11 @@ void AMSSetting::create()
m_sizerl_body->Add(m_sizer_switch_filament_tip, 0, wxLEFT, 18);
m_sizerl_body->Add(0, 0, 0, wxTOP, 6);
m_sizerl_body->Add(0, 0, 0, wxTOP, FromDIP(5));
m_sizerl_body->Add(m_sizer_air_print, 0, wxEXPAND | wxTOP, FromDIP(8));
m_sizerl_body->Add(0, 0, 0, wxTOP, 8);
m_sizerl_body->Add(m_sizer_air_print_tip, 0, wxLEFT, 18);
m_sizerl_body->Add(0, 0, 0, wxTOP, 6);
m_sizerl_body->Add(0, 0, 0, wxTOP, FromDIP(5));
m_sizerl_body->Add(m_panel_img, 1, wxEXPAND | wxALL, FromDIP(5));
m_panel_body->SetSizer(m_sizerl_body);
@@ -285,6 +324,9 @@ void AMSSetting::update_insert_material_read_mode(bool selected, std::string ver
void AMSSetting::update_ams_img(std::string ams_icon_str)
{
if (wxGetApp().dark_mode()&& ams_icon_str=="extra_icon") {
ams_icon_str += "_dark";
}
m_am_img->SetBitmap(create_scaled_bitmap(ams_icon_str, nullptr, 126));
}
@@ -336,6 +378,22 @@ void AMSSetting::update_switch_filament(bool selected)
m_checkbox_switch_filament->SetValue(selected);
}
void AMSSetting::update_air_printing_detection(bool selected)
{
if (false/*obj->is_support_air_print_detection*/) {
m_checkbox_air_print->Show();
m_title_air_print->Show();
m_tip_air_print_line->Show();
}
else {
m_checkbox_air_print->Hide();
m_title_air_print->Hide();
m_tip_air_print_line->Hide();
}
Layout();
m_checkbox_air_print->SetValue(selected);
}
void AMSSetting::on_select_ok(wxMouseEvent &event)
{
@@ -415,6 +473,13 @@ void AMSSetting::on_switch_filament(wxCommandEvent& event)
event.Skip();
}
void AMSSetting::on_air_print_detect(wxCommandEvent& event)
{
bool air_print_detect = m_checkbox_air_print->GetValue();
obj->command_ams_air_print_detect(air_print_detect);
event.Skip();
}
wxString AMSSetting::append_title(wxString text)
{
wxString lab;
+6
View File
@@ -33,11 +33,13 @@ public:
void update_starting_read_mode(bool selected);
void update_remain_mode(bool selected);
void update_switch_filament(bool selected);
void update_air_printing_detection(bool selected);
void on_select_ok(wxMouseEvent& event);
void on_insert_material_read(wxCommandEvent &event);
void on_starting_read(wxCommandEvent &event);
void on_remain(wxCommandEvent& event);
void on_switch_filament(wxCommandEvent& event);
void on_air_print_detect(wxCommandEvent& event);
wxString append_title(wxString text);
wxStaticText *append_text(wxString text);
MachineObject *obj{nullptr};
@@ -70,6 +72,10 @@ protected:
wxStaticText* m_title_switch_filament;
Label* m_tip_switch_filament_line1;
CheckBox* m_checkbox_air_print;
wxStaticText* m_title_air_print;
Label* m_tip_air_print_line;
wxStaticText *m_tip_ams_img;
Button * m_button_auto_demarcate;
+42
View File
@@ -412,6 +412,48 @@ void AmsMapingPopup::on_left_down(wxMouseEvent &evt)
}
}
void AmsMapingPopup::update_ams_data_multi_machines()
{
m_has_unmatch_filament = false;
for (auto& ams_container : m_amsmapping_container_list) {
ams_container->Hide();
}
for (wxWindow* mitem : m_mapping_item_list) {
mitem->Destroy();
mitem = nullptr;
}
m_mapping_item_list.clear();
if (m_amsmapping_container_sizer_list.size() > 0) {
for (wxBoxSizer* siz : m_amsmapping_container_sizer_list) {
siz->Clear(true);
}
}
int m_amsmapping_container_list_index = 0;
std::vector<TrayData> tray_datas;
for (int i = 0; i < 4; ++i) {
TrayData td;
td.id = i;
td.type = EMPTY;
td.colour = wxColour(166, 169, 170);
td.name = "";
td.filament_type = "";
td.ctype = 0;
tray_datas.push_back(td);
}
m_amsmapping_container_list[m_amsmapping_container_list_index]->Show();
add_ams_mapping(tray_datas, m_amsmapping_container_list[m_amsmapping_container_list_index], m_amsmapping_container_sizer_list[m_amsmapping_container_list_index]);
m_warning_text->Show(m_has_unmatch_filament);
Layout();
Fit();
}
void AmsMapingPopup::update_ams_data(std::map<std::string, Ams*> amsList)
{
m_has_unmatch_filament = false;
+1
View File
@@ -157,6 +157,7 @@ public:
void update_materials_list(std::vector<std::string> list);
void set_tag_texture(std::string texture);
void update_ams_data(std::map<std::string, Ams *> amsList);
void update_ams_data_multi_machines();
void add_ams_mapping(std::vector<TrayData> tray_data, wxWindow* container, wxBoxSizer* sizer);
void set_current_filament_id(int id){m_current_filament_id = id;};
int get_current_filament_id(){return m_current_filament_id;};
+294
View File
@@ -54,6 +54,300 @@ wxString get_fail_reason(int code)
return _L("Unknown Failure");
}
PingCodeBindDialog::PingCodeBindDialog(Plater* plater /*= nullptr*/)
: DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, _L("Bind with Pin Code"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX)
{
#ifdef __WINDOWS__
SetDoubleBuffered(true);
#endif //__WINDOWS__
wxBoxSizer* sizer_main = new wxBoxSizer(wxVERTICAL);
std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str();
SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO));
SetBackgroundColour(*wxWHITE);
wxBoxSizer* m_sizer_main = new wxBoxSizer(wxVERTICAL);
auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL);
m_line_top->SetBackgroundColour(wxColour(166, 169, 170));
m_simplebook = new wxSimplebook(this);
m_simplebook->SetSize(wxSize(FromDIP(460), FromDIP(240)));
m_simplebook->SetMinSize(wxSize(FromDIP(460), FromDIP(240)));
m_simplebook->SetMaxSize(wxSize(FromDIP(460), FromDIP(240)));
request_bind_panel = new wxPanel(m_simplebook);
binding_panel = new wxPanel(m_simplebook);
request_bind_panel->SetSize(wxSize(FromDIP(460), FromDIP(240)));
request_bind_panel->SetMinSize(wxSize(FromDIP(460), FromDIP(240)));
request_bind_panel->SetMaxSize(wxSize(FromDIP(460), FromDIP(240)));
binding_panel->SetSize(wxSize(FromDIP(460), FromDIP(240)));
binding_panel->SetMinSize(wxSize(FromDIP(460), FromDIP(240)));
binding_panel->SetMaxSize(wxSize(FromDIP(460), FromDIP(240)));
request_bind_panel->SetBackgroundColour(*wxWHITE);
binding_panel->SetBackgroundColour(*wxWHITE);
m_status_text = new Label(request_bind_panel, _L("Please Find the Pin Code in Account page on printer screen,\n and type in the Pin Code below."));
m_status_text->SetBackgroundColour(*wxWHITE);
m_status_text->SetFont(Label::Body_14);
m_status_text->SetMaxSize(wxSize(FromDIP(440), -1));
m_status_text->Wrap(FromDIP(440));
m_status_text->SetForegroundColour(wxColour(38, 46, 48));
m_link_show_ping_code_wiki = new wxStaticText(request_bind_panel, wxID_ANY, _L("Can't find Pin Code?"));
m_link_show_ping_code_wiki->SetFont(Label::Body_14);
m_link_show_ping_code_wiki->SetBackgroundColour(*wxWHITE);
m_link_show_ping_code_wiki->SetForegroundColour(wxColour(31, 142, 234));
m_link_show_ping_code_wiki->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_HAND); });
m_link_show_ping_code_wiki->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_ARROW); });
m_link_show_ping_code_wiki->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {
m_ping_code_wiki = "https://wiki.bambulab.com/en/bambu-studio/manual/pin-code";
wxLaunchDefaultBrowser(m_ping_code_wiki);
});
m_text_input_title = new wxStaticText(request_bind_panel, wxID_ANY, _L("Pin Code"));
m_text_input_title->SetFont(Label::Body_14);
m_text_input_title->SetBackgroundColour(*wxWHITE);
wxBoxSizer* ping_code_input = new wxBoxSizer(wxHORIZONTAL);
for (int i = 0; i < PING_CODE_LENGTH; i++) {
m_text_input_single_code[i] = new TextInput(request_bind_panel, wxEmptyString, "", "", wxDefaultPosition, wxSize(FromDIP(38), FromDIP(38)), wxTE_PROCESS_ENTER | wxTE_CENTER);
wxTextAttr textAttr;
textAttr.SetAlignment(wxTEXT_ALIGNMENT_CENTER);
textAttr.SetTextColour(wxColour(34, 139, 34));
m_text_input_single_code[i]->GetTextCtrl()->SetDefaultStyle(textAttr);
m_text_input_single_code[i]->SetFont(Label::Body_16);
m_text_input_single_code[i]->GetTextCtrl()->SetMaxLength(1);
m_text_input_single_code[i]->GetTextCtrl()->Bind(wxEVT_TEXT, &PingCodeBindDialog::on_text_changed, this);
m_text_input_single_code[i]->GetTextCtrl()->Bind(wxEVT_KEY_DOWN, &PingCodeBindDialog::on_key_backspace, this);
m_text_input_single_code[i]->GetTextCtrl()->Bind(wxEVT_CHAR, &PingCodeBindDialog::on_key_input, this);
ping_code_input->Add(m_text_input_single_code[i], 0, wxALL, FromDIP(5));
}
wxBoxSizer* m_sizer_button = new wxBoxSizer(wxHORIZONTAL);
m_sizer_button->Add(0, 0, 1, wxEXPAND, 5);
m_button_bind = new Button(request_bind_panel, _L("Confirm"));
StateColor btn_bg_green(std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Disabled),
std::pair<wxColour, int>(wxColour(0, 137, 123), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
m_button_bind->SetBackgroundColor(btn_bg_green);
m_button_bind->SetBorderColor(*wxWHITE);
m_button_bind->SetTextColor(wxColour("#FFFFFE"));
m_button_bind->SetSize(BIND_DIALOG_BUTTON_SIZE);
m_button_bind->SetMinSize(BIND_DIALOG_BUTTON_SIZE);
m_button_bind->SetCornerRadius(FromDIP(12));
m_button_bind->Enable(false);
StateColor btn_bg_white(std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Hovered),
std::pair<wxColour, int>(*wxWHITE, StateColor::Normal));
m_button_cancel = new Button(request_bind_panel, _L("Cancel"));
m_button_cancel->SetBackgroundColor(btn_bg_white);
m_button_cancel->SetBorderColor(BIND_DIALOG_GREY900);
m_button_cancel->SetSize(BIND_DIALOG_BUTTON_SIZE);
m_button_cancel->SetMinSize(BIND_DIALOG_BUTTON_SIZE);
m_button_cancel->SetTextColor(BIND_DIALOG_GREY900);
m_button_cancel->SetCornerRadius(FromDIP(12));
m_sizer_button->Add(m_button_bind, 0, wxALIGN_CENTER, 0);
m_sizer_button->Add(0, 0, 0, wxLEFT, FromDIP(13));
m_sizer_button->Add(m_button_cancel, 0, wxALIGN_CENTER, 0);
m_simplebook->AddPage(request_bind_panel, wxEmptyString, true);
m_simplebook->AddPage(binding_panel, wxEmptyString, false);
auto sizer_request = new wxBoxSizer(wxVERTICAL);
sizer_request->Add(0, 0, 0, wxTOP, FromDIP(10));
sizer_request->Add(m_status_text, 0, wxLEFT, FromDIP(13));
sizer_request->Add(0, 0, 0, wxTOP, FromDIP(10));
sizer_request->Add(m_link_show_ping_code_wiki, 0, wxLEFT, FromDIP(13));
sizer_request->Add(0, 0, 0, wxTOP, FromDIP(15));
sizer_request->Add(m_text_input_title, 0, wxLEFT, FromDIP(13));
sizer_request->Add(0, 0, 0, wxTOP, FromDIP(5));
sizer_request->Add(ping_code_input, 0, wxLEFT, FromDIP(10));
sizer_request->Add(0, 0, 0, wxTOP, FromDIP(10));
sizer_request->Add(m_sizer_button, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, FromDIP(15));
request_bind_panel->SetSizer(sizer_request);
request_bind_panel->Layout();
request_bind_panel->Fit();
auto m_loading_txt = new Label(binding_panel, _L("Binding..."));
m_loading_txt->SetBackgroundColour(*wxWHITE);
m_loading_txt->SetFont(Label::Head_16);
auto m_loading_tip_txt = new Label(binding_panel, _L("Please confirm on the printer screen"));
m_loading_tip_txt->SetBackgroundColour(*wxWHITE);
m_loading_tip_txt->SetFont(Label::Body_15);
wxBoxSizer* m_sizer_binding_button = new wxBoxSizer(wxHORIZONTAL);
m_sizer_binding_button->Add(0, 0, 1, wxEXPAND, 5);
m_button_close = new Button(binding_panel, _L("Close"));
m_button_close->SetBackgroundColor(btn_bg_white);
m_button_close->SetBorderColor(BIND_DIALOG_GREY900);
m_button_close->SetSize(BIND_DIALOG_BUTTON_SIZE);
m_button_close->SetMinSize(BIND_DIALOG_BUTTON_SIZE);
m_button_close->SetTextColor(BIND_DIALOG_GREY900);
m_button_close->SetCornerRadius(FromDIP(12));
m_sizer_binding_button->Add(m_button_close, 0, wxALIGN_CENTER, 0);
auto sizer_binding = new wxBoxSizer(wxVERTICAL);
sizer_binding->Add(0, 0, 0, wxTOP, FromDIP(80));
sizer_binding->Add(m_loading_txt, 0, wxALIGN_CENTER, 0);
sizer_binding->Add(0, 0, 0, wxTOP, FromDIP(10));
sizer_binding->Add(m_loading_tip_txt, 0, wxALIGN_CENTER, 0);
sizer_binding->Add(0, 0, 0, wxTOP, FromDIP(30));
sizer_binding->Add(m_sizer_binding_button, 0, wxALIGN_RIGHT | wxRIGHT, FromDIP(20));
binding_panel->SetSizer(sizer_binding);
binding_panel->Layout();
binding_panel->Fit();
sizer_main->Add(m_line_top, 0, wxEXPAND, 0);
sizer_main->Add(m_simplebook, 0, wxEXPAND, 0);
SetSizer(sizer_main);
Layout();
Fit();
m_button_bind->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PingCodeBindDialog::on_bind_printer), NULL, this);
m_button_cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PingCodeBindDialog::on_cancel), NULL, this);
m_button_close->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PingCodeBindDialog::on_cancel), NULL, this);
m_simplebook->SetSelection(0);
}
void PingCodeBindDialog::on_key_input(wxKeyEvent& evt)
{
int keyCode = evt.GetKeyCode();
if (keyCode == WXK_BACK || (keyCode >= '0' && keyCode <= '9') || (keyCode >= 'a' && keyCode <= 'z') || (keyCode >= 'A' && keyCode <= 'Z'))
{
evt.Skip();
}
else
{
wxBell();
return;
}
}
void PingCodeBindDialog::on_text_changed(wxCommandEvent& event) {
//switch focus to the text text input
wxTextCtrl* text_input = static_cast<wxTextCtrl*>(event.GetEventObject());
int idx = -1;
for (int i = 0; i < PING_CODE_LENGTH; i++) {
if (text_input == m_text_input_single_code[i]->GetTextCtrl()) {
idx = i;
break;
}
}
if (idx != -1 && text_input->GetValue().Length() == 1) {
if (idx < PING_CODE_LENGTH-1) {
m_text_input_single_code[idx + 1]->SetFocus();
}
auto has_empty = false;
for (int i = 0; i < PING_CODE_LENGTH; i++) {
if (m_text_input_single_code[i]->GetTextCtrl()->GetValue().ToStdString().empty()) {
has_empty = true;
}
}
if (has_empty) {
m_button_bind->Enable(false);
}
else {
m_button_bind->Enable(true);
}
/*if (idx == PING_CODE_LENGTH - 1) {
m_button_bind->Enable(true);
}*/
}
}
void PingCodeBindDialog::on_key_backspace(wxKeyEvent& event)
{
wxTextCtrl* text_input = static_cast<wxTextCtrl*>(event.GetEventObject());
int idx = -1;
for (int i = 0; i < 6; i++) {
if (text_input == m_text_input_single_code[i]->GetTextCtrl()) {
idx = i;
break;
}
}
if (event.GetKeyCode() == WXK_BACK && idx >= 0) {
CallAfter([this, idx]() {
m_text_input_single_code[idx - 1]->SetFocus();
m_button_bind->Enable(false);
});
}
event.Skip();
}
void PingCodeBindDialog::on_bind_printer(wxCommandEvent& event)
{
wxString ping_code;
for (int i = 0; i < PING_CODE_LENGTH; i++) {
ping_code += m_text_input_single_code[i]->GetTextCtrl()->GetValue().ToStdString();
}
NetworkAgent* agent = wxGetApp().getAgent();
if (agent && agent->is_user_login() && ping_code.length() == PING_CODE_LENGTH) {
auto result = agent->ping_bind(ping_code.ToStdString());
if(result < 0){
MessageDialog msg_wingow(nullptr, _L("Log in failed. Please check the Pin Code."), "", wxAPPLY | wxOK);
msg_wingow.ShowModal();
return;
}
m_simplebook->SetSelection(1);
}
}
void PingCodeBindDialog::on_cancel(wxCommandEvent& event)
{
EndModal(wxCLOSE);
}
void PingCodeBindDialog::on_dpi_changed(const wxRect& suggested_rect)
{
Fit();
Refresh();
}
PingCodeBindDialog::~PingCodeBindDialog() {
m_button_bind->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PingCodeBindDialog::on_bind_printer), NULL, this);
m_button_cancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PingCodeBindDialog::on_cancel), NULL, this);
m_button_close->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PingCodeBindDialog::on_cancel), NULL, this);
}
BindMachineDialog::BindMachineDialog(Plater *plater /*= nullptr*/)
: DPIDialog(static_cast<wxWindow *>(wxGetApp().mainframe), wxID_ANY, _L("Log in printer"), wxDefaultPosition, wxDefaultSize, wxCAPTION)
{
+48 -2
View File
@@ -19,7 +19,6 @@
#include <wx/webrequest.h>
#include <wx/hyperlink.h>
#include "wxExtensions.hpp"
#include "Plater.hpp"
#include "Widgets/StepCtrl.hpp"
#include "Widgets/ProgressDialog.hpp"
#include "Widgets/Button.hpp"
@@ -29,15 +28,21 @@
#include "BBLStatusBar.hpp"
#include "BBLStatusBarBind.hpp"
#include "Jobs/Worker.hpp"
#include "GUI_Utils.hpp"
#include "Widgets/TextInput.hpp"
#include "Jobs/PrintJob.hpp"
#include "Jobs/SendJob.hpp"
#include "DeviceManager.hpp"
#define BIND_DIALOG_GREY200 wxColour(248, 248, 248)
#define BIND_DIALOG_GREY800 wxColour(50, 58, 61)
#define BIND_DIALOG_GREY900 wxColour(38, 46, 48)
#define BIND_DIALOG_BUTTON_SIZE wxSize(FromDIP(68), FromDIP(24))
#define BIND_DIALOG_BUTTON_PANEL_SIZE wxSize(FromDIP(450), FromDIP(30))
#define PING_CODE_LENGTH 6
namespace Slic3r { namespace GUI {
class Plater;
struct MemoryStruct
{
char * memory;
@@ -45,6 +50,47 @@ struct MemoryStruct
size_t size;
};
class PingCodeBindDialog : public DPIDialog
{
private:
Label* m_status_text;
wxStaticText* m_text_input_title;
wxStaticText* m_link_show_ping_code_wiki;
TextInput* m_text_input_single_code[PING_CODE_LENGTH];
Button* m_button_bind;
Button* m_button_cancel;
Button* m_button_close;
wxSimplebook* m_simplebook;
wxPanel* request_bind_panel;
wxPanel* binding_panel;
wxScrolledWindow* m_sw_bind_failed_info;
Label* m_bind_failed_info;
Label* m_st_txt_error_code{ nullptr };
Label* m_st_txt_error_desc{ nullptr };
Label* m_st_txt_extra_info{ nullptr };
wxHyperlinkCtrl* m_link_network_state{ nullptr };
wxString m_result_info;
wxString m_result_extra;
wxString m_ping_code_wiki;
bool m_show_error_info_state = true;
int m_result_code;
std::shared_ptr<BBLStatusBarBind> m_status_bar;
public:
PingCodeBindDialog(Plater* plater = nullptr);
~PingCodeBindDialog();
void on_key_input(wxKeyEvent& evt);
void on_text_changed(wxCommandEvent& event);
void on_key_backspace(wxKeyEvent& event);
void on_cancel(wxCommandEvent& event);
void on_bind_printer(wxCommandEvent& event);
void on_dpi_changed(const wxRect& suggested_rect) override;
};
class BindMachineDialog : public DPIDialog
{
private:
+2 -2
View File
@@ -323,7 +323,7 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_
// map of color replaces
std::map<std::string, std::string> replaces;
replaces["\"#0x00AE42\""] = "\"#009688\"";
replaces["\"#0x00AE42\""] = "\"#009688\"";
replaces["\"#00FF00\""] = "\"#52c7b8\"";
if (dark_mode) {
replaces["\"#262E30\""] = "\"#EFEFF0\"";
@@ -334,7 +334,7 @@ replaces["\"#0x00AE42\""] = "\"#009688\"";
replaces["\"#6B6B6B\""] = "\"#818182\"";
replaces["\"#909090\""] = "\"#FFFFFF\"";
replaces["\"#00FF00\""] = "\"#FF0000\"";
replaces["\"#009688\""] = "\"#00675b\"";
replaces["\"#009688\""] = "\"#00675b\"";
}
//if (!new_color.empty())
// replaces["\"#ED6B21\""] = "\"" + new_color + "\"";
+31 -27
View File
@@ -55,9 +55,10 @@ static wxString get_preset_name_by_filament_id(std::string filament_id)
return preset_name;
}
HistoryWindow::HistoryWindow(wxWindow* parent, const std::vector<PACalibResult>& calib_results_history)
HistoryWindow::HistoryWindow(wxWindow* parent, const std::vector<PACalibResult>& calib_results_history, bool& show)
: DPIDialog(parent, wxID_ANY, _L("Flow Dynamics Calibration Result"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
, m_calib_results_history(calib_results_history)
, m_show_history_dialog(show)
{
this->SetBackgroundColour(*wxWHITE);
auto main_sizer = new wxBoxSizer(wxVERTICAL);
@@ -73,11 +74,11 @@ HistoryWindow::HistoryWindow(wxWindow* parent, const std::vector<PACalibResult>&
scroll_window->SetSizer(scroll_sizer);
Button * mew_btn = new Button(scroll_window, _L("New"));
StateColor btn_bg_green(std::pair<wxColour, int>(wxColour(27, 136, 68), StateColor::Pressed), std::pair<wxColour, int>(wxColour(61, 203, 115), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 174, 66), StateColor::Normal));
StateColor btn_bg_green(std::pair<wxColour, int>(wxColour(0, 137, 123), StateColor::Pressed), std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
mew_btn->SetBackgroundColour(*wxWHITE);
mew_btn->SetBackgroundColor(btn_bg_green);
mew_btn->SetBorderColor(wxColour(0, 174, 66));
mew_btn->SetBorderColor(wxColour(0, 150, 136));
mew_btn->SetTextColor(wxColour("#FFFFFE"));
mew_btn->SetMinSize(wxSize(FromDIP(100), FromDIP(24)));
mew_btn->SetMaxSize(wxSize(FromDIP(100), FromDIP(24)));
@@ -138,11 +139,14 @@ HistoryWindow::HistoryWindow(wxWindow* parent, const std::vector<PACalibResult>&
m_refresh_timer->SetOwner(this);
m_refresh_timer->Start(200);
Bind(wxEVT_TIMER, &HistoryWindow::on_timer, this);
m_show_history_dialog = true;
}
HistoryWindow::~HistoryWindow()
{
m_refresh_timer->Stop();
m_show_history_dialog = false;
}
void HistoryWindow::sync_history_result(MachineObject* obj)
@@ -364,6 +368,12 @@ float HistoryWindow::get_nozzle_value()
void HistoryWindow::on_click_new_button(wxCommandEvent& event)
{
if (curr_obj && curr_obj->get_printer_series() == PrinterSeries::SERIES_P1P && m_calib_results_history.size() >= 16) {
MessageDialog msg_dlg(nullptr, wxString::Format(_L("This machine type can only hold %d history results per nozzle."), 16), wxEmptyString, wxICON_WARNING | wxOK);
msg_dlg.ShowModal();
return;
}
NewCalibrationHistoryDialog dlg(this, m_calib_results_history);
dlg.ShowModal();
}
@@ -560,7 +570,7 @@ wxArrayString NewCalibrationHistoryDialog::get_all_filaments(const MachineObject
}
NewCalibrationHistoryDialog::NewCalibrationHistoryDialog(wxWindow *parent, const std::vector<PACalibResult> history_results)
: DPIDialog(parent, wxID_ANY, _L("New Flow Dynamics Calibration"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
: DPIDialog(parent, wxID_ANY, _L("New Flow Dynamic Calibration"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
, m_history_results(history_results)
{
Slic3r::DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager();
@@ -570,6 +580,8 @@ NewCalibrationHistoryDialog::NewCalibrationHistoryDialog(wxWindow *parent, const
if (!obj)
return;
curr_obj = obj;
this->SetBackgroundColour(*wxWHITE);
auto main_sizer = new wxBoxSizer(wxVERTICAL);
@@ -628,11 +640,11 @@ NewCalibrationHistoryDialog::NewCalibrationHistoryDialog(wxWindow *parent, const
auto btn_sizer = new wxBoxSizer(wxHORIZONTAL);
Button * ok_btn = new Button(top_panel, _L("Ok"));
StateColor btn_bg_green(std::pair<wxColour, int>(wxColour(27, 136, 68), StateColor::Pressed), std::pair<wxColour, int>(wxColour(61, 203, 115), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 174, 66), StateColor::Normal));
StateColor btn_bg_green(std::pair<wxColour, int>(wxColour(0, 137, 123), StateColor::Pressed), std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
ok_btn->SetBackgroundColour(*wxWHITE);
ok_btn->SetBackgroundColor(btn_bg_green);
ok_btn->SetBorderColor(wxColour(0, 174, 66));
ok_btn->SetBorderColor(wxColour(0, 150, 136));
ok_btn->SetTextColor(wxColour("#FFFFFE"));
ok_btn->SetMinSize(wxSize(-1, FromDIP(24)));
ok_btn->SetCornerRadius(FromDIP(12));
@@ -699,26 +711,18 @@ void NewCalibrationHistoryDialog::on_ok(wxCommandEvent &event)
// Check for duplicate names from history
{
struct PACalibResult
{
size_t operator()(const std::pair<std::string, std::string> &item) const
{
return std::hash<string>()(item.first) * std::hash<string>()(item.second);
}
};
std::unordered_set<std::pair<std::string, std::string>, PACalibResult> set;
set.insert({m_new_result.name, m_new_result.filament_id});
auto iter = std::find_if(m_history_results.begin(), m_history_results.end(), [this](const PACalibResult &item) {
return item.name == m_new_result.name && item.filament_id == m_new_result.filament_id;
});
for (auto &result : m_history_results) {
if (!set.insert({result.name, result.filament_id}).second) {
MessageDialog msg_dlg(nullptr,
wxString::Format(_L("There is already a historical calibration result with the same name: %s. Only one of the results with the same name "
"is saved. Are you sure you want to override the historical result?"),
result.name),
wxEmptyString, wxICON_WARNING | wxYES_NO);
if (msg_dlg.ShowModal() != wxID_YES)
return;
}
if (iter != m_history_results.end()) {
MessageDialog msg_dlg(nullptr,
wxString::Format(_L("There is already a historical calibration result with the same name: %s. Only one of the results with the same name "
"is saved. Are you sure you want to override the historical result?"),
m_new_result.name),
wxEmptyString, wxICON_WARNING | wxYES_NO);
if (msg_dlg.ShowModal() != wxID_YES)
return;
}
}
+3 -1
View File
@@ -11,7 +11,7 @@ namespace GUI {
class HistoryWindow : public DPIDialog {
public:
HistoryWindow(wxWindow* parent, const std::vector<PACalibResult>& calib_results_history);
HistoryWindow(wxWindow* parent, const std::vector<PACalibResult>& calib_results_history, bool& show);
~HistoryWindow();
void on_dpi_changed(const wxRect& suggested_rect) {}
void on_select_nozzle(wxCommandEvent& evt);
@@ -33,6 +33,7 @@ protected:
wxTimer* m_refresh_timer { nullptr };
bool& m_show_history_dialog;
std::vector<PACalibResult> m_calib_results_history;
MachineObject* curr_obj { nullptr };
int history_version = -1;
@@ -74,6 +75,7 @@ protected:
protected:
PACalibResult m_new_result;
std::vector<PACalibResult> m_history_results;
MachineObject * curr_obj;
TextInput *m_name_value{nullptr};
TextInput *m_k_value{nullptr};
+57 -6
View File
@@ -18,6 +18,7 @@ static const wxString NA_STR = _L("N/A");
static const float MIN_PA_K_VALUE = 0.0;
static const float MAX_PA_K_VALUE = 0.3;
static const float MIN_PA_K_VALUE_STEP = 0.001;
static const int MAX_PA_HISTORY_RESULTS_NUMS = 16;
std::map<int, Preset*> get_cached_selected_filament(MachineObject* obj) {
std::map<int, Preset*> selected_filament_map;
@@ -429,7 +430,7 @@ void PressureAdvanceWizard::on_cali_action(wxCommandEvent& evt)
{
CaliPageActionType action = static_cast<CaliPageActionType>(evt.GetInt());
if (action == CaliPageActionType::CALI_ACTION_MANAGE_RESULT) {
HistoryWindow history_dialog(this, m_calib_results_history);
HistoryWindow history_dialog(this, m_calib_results_history, m_show_result_dialog);
history_dialog.on_device_connected(curr_obj);
history_dialog.ShowModal();
}
@@ -467,7 +468,17 @@ void PressureAdvanceWizard::on_cali_action(wxCommandEvent& evt)
void PressureAdvanceWizard::update(MachineObject* obj)
{
if (!obj)
return;
CalibrationWizard::update(obj);
if (!m_show_result_dialog) {
if (obj->cali_version != -1 && obj->cali_version != cali_version) {
cali_version = obj->cali_version;
CalibUtils::emit_get_PA_calib_info(obj->nozzle_diameter, "");
}
}
}
void PressureAdvanceWizard::on_device_connected(MachineObject* obj)
@@ -648,11 +659,21 @@ void PressureAdvanceWizard::on_cali_start()
cali_page->set_pa_cali_image(int(pa_cali_method));
curr_obj->manual_pa_cali_method = pa_cali_method;
CalibUtils::calib_generic_PA(calib_info, wx_err_string);
if (curr_obj->pa_calib_tab.size() >= MAX_PA_HISTORY_RESULTS_NUMS) {
MessageDialog msg_dlg(nullptr, wxString::Format(_L("This machine type can only hold 16 history results per nozzle. "
"You can delete the existing historical results and then start calibration. "
"Or you can continue the calibration, but you cannot create new calibration historical results. \n"
"Do you still want to continue the calibration?"), MAX_PA_HISTORY_RESULTS_NUMS), wxEmptyString, wxICON_WARNING | wxYES | wxCANCEL);
if (msg_dlg.ShowModal() != wxID_YES) {
return;
}
}
if (!wx_err_string.empty()) {
MessageDialog msg_dlg(nullptr, wx_err_string, wxEmptyString, wxICON_WARNING | wxOK);
msg_dlg.ShowModal();
if (!CalibUtils::calib_generic_PA(calib_info, wx_err_string)) {
if (!wx_err_string.empty()) {
MessageDialog msg_dlg(nullptr, wx_err_string, wxEmptyString, wxICON_WARNING | wxOK);
msg_dlg.ShowModal();
}
return;
}
@@ -713,6 +734,30 @@ void PressureAdvanceWizard::on_cali_save()
if (!save_page->get_manual_result(new_pa_cali_result)) {
return;
}
auto iter = std::find_if(curr_obj->pa_calib_tab.begin(), curr_obj->pa_calib_tab.end(), [&new_pa_cali_result](const PACalibResult &item) {
return item.name == new_pa_cali_result.name && item.filament_id == item.filament_id;
});
if (iter != curr_obj->pa_calib_tab.end()) {
MessageDialog
msg_dlg(nullptr,
wxString::Format(_L("There is already a historical calibration result with the same name: %s. Only one of the results with the same name "
"is saved. Are you sure you want to override the historical result?"),
new_pa_cali_result.name),
wxEmptyString, wxICON_WARNING | wxYES_NO);
if (msg_dlg.ShowModal() != wxID_YES)
return;
}
else if (curr_obj->pa_calib_tab.size() >= MAX_PA_HISTORY_RESULTS_NUMS) {
MessageDialog msg_dlg(nullptr,
wxString::Format(_L("This machine type can only hold %d history results per nozzle. This result will not be saved."), MAX_PA_HISTORY_RESULTS_NUMS),
wxEmptyString, wxICON_WARNING | wxOK);
msg_dlg.ShowModal();
return;
}
CalibUtils::set_PA_calib_result({new_pa_cali_result}, false);
} else {
auto save_page = static_cast<CalibrationPASavePage *>(save_step->page);
@@ -1020,7 +1065,13 @@ void FlowRateWizard::on_cali_start(CaliPresetStage stage, float cali_value, Flow
calib_info.filament_prest = temp_filament_preset;
if (cali_stage > 0) {
CalibUtils::calib_flowrate(cali_stage, calib_info, wx_err_string);
if (!CalibUtils::calib_flowrate(cali_stage, calib_info, wx_err_string)) {
if (!wx_err_string.empty()) {
MessageDialog msg_dlg(nullptr, wx_err_string, wxEmptyString, wxICON_WARNING | wxOK);
msg_dlg.ShowModal();
}
return;
}
}
else {
wx_err_string = _L("Internal Error") + wxString(": Invalid calibration stage");
+2
View File
@@ -121,7 +121,9 @@ protected:
void on_device_connected(MachineObject* obj) override;
bool m_show_result_dialog = false;
std::vector<PACalibResult> m_calib_results_history;
int cali_version = -1;
};
class FlowRateWizard : public CalibrationWizard {
+2 -2
View File
@@ -382,7 +382,7 @@ void CalibrationCaliPage::update_subtask(MachineObject* obj)
m_printing_panel->update_subtask_name(wxString::Format("%s", GUI::from_u8(obj->subtask_name)));
if (obj->get_modeltask() && obj->get_modeltask()->design_id > 0) {
m_printing_panel->show_profile_info(true, wxString::FromUTF8(obj->get_modeltask()->profile_name));
m_printing_panel->show_profile_info(wxString::FromUTF8(obj->get_modeltask()->profile_name));
}
else {
m_printing_panel->show_profile_info(false);
@@ -502,4 +502,4 @@ float CalibrationCaliPage::get_selected_calibration_nozzle_dia(MachineObject* ob
return 0.4;
}
}}
}}
+12 -11
View File
@@ -1,3 +1,4 @@
#include <regex>
#include "CalibrationWizardPresetPage.hpp"
#include "I18N.hpp"
#include "Widgets/Label.hpp"
@@ -312,7 +313,7 @@ void CaliPresetCustomRangePanel::create_panel(wxWindow* parent)
m_title_texts[i]->Wrap(-1);
m_title_texts[i]->SetFont(::Label::Body_14);
item_sizer->Add(m_title_texts[i], 0, wxALL, 0);
m_value_inputs[i] = new TextInput(parent, wxEmptyString, _L("\u2103"), "", wxDefaultPosition, CALIBRATION_FROM_TO_INPUT_SIZE, 0);
m_value_inputs[i] = new TextInput(parent, wxEmptyString, wxString::FromUTF8("°C"), "", wxDefaultPosition, CALIBRATION_FROM_TO_INPUT_SIZE, 0);
m_value_inputs[i]->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
m_value_inputs[i]->GetTextCtrl()->Bind(wxEVT_TEXT, [this, i](wxCommandEvent& event) {
std::string number = m_value_inputs[i]->GetTextCtrl()->GetValue().ToStdString();
@@ -391,7 +392,7 @@ void CaliPresetTipsPanel::create_panel(wxWindow* parent)
auto nozzle_temp_sizer = new wxBoxSizer(wxVERTICAL);
auto nozzle_temp_text = new Label(parent, _L("Nozzle temperature"));
nozzle_temp_text->SetFont(Label::Body_12);
m_nozzle_temp = new TextInput(parent, wxEmptyString, _L("\u2103"), "", wxDefaultPosition, CALIBRATION_FROM_TO_INPUT_SIZE, wxTE_READONLY);
m_nozzle_temp = new TextInput(parent, wxEmptyString, wxString::FromUTF8("°C"), "", wxDefaultPosition, CALIBRATION_FROM_TO_INPUT_SIZE, wxTE_READONLY);
m_nozzle_temp->SetBorderWidth(0);
nozzle_temp_sizer->Add(nozzle_temp_text, 0, wxALIGN_LEFT);
nozzle_temp_sizer->Add(m_nozzle_temp, 0, wxEXPAND);
@@ -406,7 +407,7 @@ void CaliPresetTipsPanel::create_panel(wxWindow* parent)
auto bed_temp_text = new Label(parent, _L("Bed temperature"));
bed_temp_text->SetFont(Label::Body_12);
m_bed_temp = new Label(parent, _L("- \u2103"));
m_bed_temp = new Label(parent, wxString::FromUTF8("- °C"));
m_bed_temp->SetFont(Label::Body_12);
bed_temp_sizer->Add(bed_temp_text, 0, wxALIGN_CENTER | wxRIGHT, FromDIP(10));
bed_temp_sizer->Add(m_bed_temp, 0, wxALIGN_CENTER);
@@ -414,7 +415,7 @@ void CaliPresetTipsPanel::create_panel(wxWindow* parent)
auto max_flow_sizer = new wxBoxSizer(wxVERTICAL);
auto max_flow_text = new Label(parent, _L("Max volumetric speed"));
max_flow_text->SetFont(Label::Body_12);
m_max_volumetric_speed = new TextInput(parent, wxEmptyString, _L("mm\u00B3"), "", wxDefaultPosition, CALIBRATION_FROM_TO_INPUT_SIZE, wxTE_READONLY);
m_max_volumetric_speed = new TextInput(parent, wxEmptyString, wxString::FromUTF8("mm³"), "", wxDefaultPosition, CALIBRATION_FROM_TO_INPUT_SIZE, wxTE_READONLY);
m_max_volumetric_speed->SetBorderWidth(0);
max_flow_sizer->Add(max_flow_text, 0, wxALIGN_LEFT);
max_flow_sizer->Add(m_max_volumetric_speed, 0, wxEXPAND);
@@ -1204,7 +1205,7 @@ void CalibrationPresetPage::update_show_status()
show_status(CaliPresetPageStatus::CaliPresetStatusInPrinting);
return;
}
else if (need_check_sdcard(obj_) && obj_->get_sdcard_state() == MachineObject::SdcardState::NO_SDCARD) {
else if (!obj_->is_support_print_without_sd && (obj_->get_sdcard_state() == MachineObject::SdcardState::NO_SDCARD)) {
show_status(CaliPresetPageStatus::CaliPresetStatusNoSdcard);
return;
}
@@ -1424,10 +1425,10 @@ void CalibrationPresetPage::set_cali_method(CalibrationMethod method)
m_custom_range_panel->set_titles(titles);
wxArrayString values;
values.push_back(_L("0"));
values.push_back(_L("0.5"));
values.push_back(_L("0.005"));
m_custom_range_panel->set_values(values);
values.push_back(wxString::Format(wxT("%.0f"), 0));
values.push_back(wxString::Format(wxT("%.2f"), 0.05));
values.push_back(wxString::Format(wxT("%.3f"), 0.005));
m_custom_range_panel->set_values(values);
m_custom_range_panel->set_unit("");
m_custom_range_panel->Show();
@@ -1479,7 +1480,7 @@ void CalibrationPresetPage::on_cali_cancel_job()
{
BOOST_LOG_TRIVIAL(info) << "CalibrationWizard::print_job: enter canceled";
if (CalibUtils::print_worker) {
BOOST_LOG_TRIVIAL(info) << "calibration_print_job: canceled";
BOOST_LOG_TRIVIAL(info) << "calibration_print_job: canceled";
CalibUtils::print_worker->cancel_all();
CalibUtils::print_worker->wait_for_idle();
}
@@ -1913,7 +1914,7 @@ MaxVolumetricSpeedPresetPage::MaxVolumetricSpeedPresetPage(
titles.push_back(_L("Step"));
m_custom_range_panel->set_titles(titles);
m_custom_range_panel->set_unit(_L("mm\u00B3/s"));
m_custom_range_panel->set_unit("mm³/s");
}
}
}}
+1 -1
View File
@@ -150,7 +150,7 @@ public:
// returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis
bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; }
bool is_looking_front() const { return abs(get_dir_up().dot(Vec3d::UnitZ())-1) < 0.001; }
// forces camera right vector to be parallel to XY plane
void recover_from_free_camera() {
if (std::abs(get_dir_right()(2)) > EPSILON)
File diff suppressed because it is too large Load Diff
+25 -3
View File
@@ -325,6 +325,9 @@ private:
std::string access_code;
std::string user_access_code;
// type, time stamp, delay
std::vector<std::tuple<std::string, uint64_t, uint64_t>> message_delay;
public:
enum LIGHT_EFFECT {
@@ -488,6 +491,7 @@ public:
bool ams_power_on_flag { false };
bool ams_calibrate_remain_flag { false };
bool ams_auto_switch_filament_flag { false };
bool ams_air_print_status { false };
bool ams_support_use_ams { false };
bool ams_support_virtual_tray { true };
int ams_humidity;
@@ -569,7 +573,7 @@ public:
int upgrade_display_state = 0; // 0 : upgrade unavailable, 1: upgrade idle, 2: upgrading, 3: upgrade_finished
int upgrade_display_hold_count = 0;
PrinterFirmwareType firmware_type; // engineer|production
PrinterFirmwareType lifecycle { PrinterFirmwareType::FIRMEARE_TYPE_UKNOWN };
PrinterFirmwareType lifecycle { PrinterFirmwareType::FIRMWARE_TYPE_PRODUCTION };
std::string upgrade_progress;
std::string upgrade_message;
std::string upgrade_status;
@@ -615,6 +619,7 @@ public:
int curr_layer = 0;
int total_layers = 0;
bool is_support_layer_num { false };
bool nozzle_blob_detection_enabled{ false };
int cali_version = -1;
float cali_selected_nozzle_dia { 0.0 };
@@ -754,6 +759,8 @@ public:
bool is_support_wait_sending_finish{false};
bool is_support_user_preset{false};
bool is_support_p1s_plus{false};
bool is_support_nozzle_blob_detection{false};
bool is_support_air_print_detection{false};
int nozzle_max_temperature = -1;
int bed_temperature_limit = -1;
@@ -844,6 +851,7 @@ public:
int command_ams_user_settings(int ams_id, bool start_read_opt, bool tray_read_opt, bool remain_flag = false);
int command_ams_user_settings(int ams_id, AmsOptionType op, bool value);
int command_ams_switch_filament(bool switch_filament);
int command_ams_air_print_detect(bool air_print_detect);
int command_ams_calibrate(int ams_id);
int command_ams_filament_settings(int ams_id, int tray_id, std::string filament_id, std::string setting_id, std::string tray_color, std::string tray_type, int nozzle_temp_min, int nozzle_temp_max);
int command_ams_select_tray(std::string tray_id);
@@ -868,6 +876,8 @@ public:
// set print option
int command_set_printing_option(bool auto_recovery);
int command_nozzle_blob_detect(bool nozzle_blob_detect);
// axis string is X, Y, Z, E
int command_axis_control(std::string axis, double unit = 1.0f, double input_val = 1.0f, int speed = 3000);
@@ -932,7 +942,7 @@ public:
int publish_json(std::string json_str, int qos = 0);
int cloud_publish_json(std::string json_str, int qos = 0);
int local_publish_json(std::string json_str, int qos = 0);
int parse_json(std::string payload);
int parse_json(std::string payload, bool key_filed_only = false);
int publish_gcode(std::string gcode_str);
std::string setting_id_to_type(std::string setting_id, std::string tray_type);
@@ -946,14 +956,16 @@ public:
bool m_firmware_thread_started { false };
void get_firmware_info();
bool is_firmware_info_valid();
std::string get_string_from_fantype(FanType type);
};
class DeviceManager
{
private:
NetworkAgent* m_agent { nullptr };
public:
static bool EnableMultiMachine;
DeviceManager(NetworkAgent* agent = nullptr);
~DeviceManager();
void set_agent(NetworkAgent* agent);
@@ -978,9 +990,14 @@ public:
bool set_selected_machine(std::string dev_id, bool need_disconnect = false);
MachineObject* get_selected_machine();
void add_user_subscribe();
void del_user_subscribe();
void subscribe_device_list(std::vector<std::string> dev_list);
/* return machine has access code and user machine if login*/
std::map<std::string, MachineObject*> get_my_machine_list();
std::map<std::string, MachineObject*> get_my_cloud_machine_list();
std::string get_first_online_user_machine();
void modify_device_name(std::string dev_id, std::string dev_name);
void update_user_machine_list_info();
@@ -997,6 +1014,11 @@ public:
std::map<std::string, MachineObject*> get_local_machine_list();
void load_last_machine();
std::vector<std::string> subscribe_list_cache;
static void set_key_field_parsing(bool enable) { DeviceManager::key_field_only = enable; }
static bool key_field_only;
static json function_table;
static json filaments_blacklist;
+41
View File
@@ -28,6 +28,7 @@
#include "Widgets/ComboBox.hpp"
#include "Widgets/TextCtrl.h"
#include "../Utils/ColorSpaceConvert.hpp"
#ifdef __WXOSX__
#define wxOSX true
#else
@@ -1704,6 +1705,7 @@ void ColourPicker::BUILD()
if (parent_is_custom_ctrl && m_opt.height < 0)
opt_height = (double)temp->GetSize().GetHeight() / m_em_unit;
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
convert_to_picker_widget(temp);
if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
wxGetApp().UpdateDarkUI(temp->GetPickerCtrl());
@@ -1760,6 +1762,7 @@ void ColourPicker::set_value(const boost::any& value, bool change_event)
boost::any& ColourPicker::get_value()
{
save_colors_to_config();
auto colour = static_cast<wxColourPickerCtrl*>(window)->GetColour();
if (colour == wxTransparentColour)
m_value = std::string("");
@@ -1798,6 +1801,44 @@ void ColourPicker::sys_color_changed()
#endif
}
void ColourPicker::on_button_click(wxCommandEvent &event) {
#if !defined(__linux__) && !defined(__LINUX__)
if (m_clrData) {
std::vector<std::string> colors = wxGetApp().app_config->get_custom_color_from_config();
for (int i = 0; i < colors.size(); i++) {
m_clrData->SetCustomColour(i, string_to_wxColor(colors[i]));
}
}
m_picker_widget->OnButtonClick(event);
#endif
}
void ColourPicker::convert_to_picker_widget(wxColourPickerCtrl *widget)
{
#if !defined(__linux__) && !defined(__LINUX__)
m_picker_widget = dynamic_cast<wxColourPickerWidget*>(widget->GetPickerCtrl());
if (m_picker_widget) {
m_picker_widget->Bind(wxEVT_BUTTON, &ColourPicker::on_button_click, this);
m_clrData = m_picker_widget->GetColourData();
}
#endif
}
void ColourPicker::save_colors_to_config() {
#if !defined(__linux__) && !defined(__LINUX__)
if (m_clrData) {
std::vector<std::string> colors;
if (colors.size() != CUSTOM_COLOR_COUNT) {
colors.resize(CUSTOM_COLOR_COUNT);
}
for (int i = 0; i < CUSTOM_COLOR_COUNT; i++) {
colors[i] = color_to_string(m_clrData->GetCustomColour(i));
}
wxGetApp().app_config->save_custom_color_to_config(colors);
}
#endif
}
void PointCtrl::BUILD()
{
auto temp = new wxBoxSizer(wxHORIZONTAL);
+8
View File
@@ -481,6 +481,14 @@ public:
void enable() override { dynamic_cast<wxColourPickerCtrl*>(window)->Enable(); }
void disable() override{ dynamic_cast<wxColourPickerCtrl*>(window)->Disable(); }
wxWindow* getWindow() override { return window; }
private:
void convert_to_picker_widget(wxColourPickerCtrl *widget);
void on_button_click(wxCommandEvent &WXUNUSED(ev));
void save_colors_to_config();
private:
wxColourData* m_clrData{nullptr};
wxColourPickerWidget* m_picker_widget{nullptr};
};
class PointCtrl : public Field {
+7 -7
View File
@@ -4183,10 +4183,10 @@ void GCodeViewer::render_all_plates_stats(const std::vector<const GCodeProcessor
auto plate_extruders = plate->get_extruders(true);
for (size_t extruder_id : plate_extruders) {
extruder_id -= 1;
if (plate_print_statistics.volumes_per_extruder.find(extruder_id) == plate_print_statistics.volumes_per_extruder.end())
flushed_volume_of_extruders_all_plates[extruder_id] += 0;
if (plate_print_statistics.model_volumes_per_extruder.find(extruder_id) == plate_print_statistics.model_volumes_per_extruder.end())
model_volume_of_extruders_all_plates[extruder_id] += 0;
else {
double model_volume = plate_print_statistics.volumes_per_extruder.at(extruder_id);
double model_volume = plate_print_statistics.model_volumes_per_extruder.at(extruder_id);
model_volume_of_extruders_all_plates[extruder_id] += model_volume;
}
if (plate_print_statistics.flush_per_filament.find(extruder_id) == plate_print_statistics.flush_per_filament.end())
@@ -4736,12 +4736,12 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
// used filament statistics
for (size_t extruder_id : m_extruder_ids) {
if (m_print_statistics.volumes_per_extruder.find(extruder_id) == m_print_statistics.volumes_per_extruder.end()) {
if (m_print_statistics.model_volumes_per_extruder.find(extruder_id) == m_print_statistics.model_volumes_per_extruder.end()) {
model_used_filaments_m.push_back(0.0);
model_used_filaments_g.push_back(0.0);
}
else {
double volume = m_print_statistics.volumes_per_extruder.at(extruder_id);
double volume = m_print_statistics.model_volumes_per_extruder.at(extruder_id);
auto [model_used_filament_m, model_used_filament_g] = get_used_filament_from_volume(volume, extruder_id);
model_used_filaments_m.push_back(model_used_filament_m);
model_used_filaments_g.push_back(model_used_filament_g);
@@ -4862,9 +4862,9 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
{
// calculate used filaments data
for (size_t extruder_id : m_extruder_ids) {
if (m_print_statistics.volumes_per_extruder.find(extruder_id) == m_print_statistics.volumes_per_extruder.end())
if (m_print_statistics.model_volumes_per_extruder.find(extruder_id) == m_print_statistics.model_volumes_per_extruder.end())
continue;
double volume = m_print_statistics.volumes_per_extruder.at(extruder_id);
double volume = m_print_statistics.model_volumes_per_extruder.at(extruder_id);
auto [model_used_filament_m, model_used_filament_g] = get_used_filament_from_volume(volume, extruder_id);
model_used_filaments_m.push_back(model_used_filament_m);
+2
View File
@@ -35,6 +35,8 @@ wxDEFINE_EVENT(EVT_GLTOOLBAR_EXPORT_ALL_SLICED_FILE, SimpleEvent);
wxDEFINE_EVENT(EVT_GLTOOLBAR_PRINT_SELECT, SimpleEvent);
wxDEFINE_EVENT(EVT_GLTOOLBAR_SEND_TO_PRINTER, SimpleEvent);
wxDEFINE_EVENT(EVT_GLTOOLBAR_SEND_TO_PRINTER_ALL, SimpleEvent);
wxDEFINE_EVENT(EVT_GLTOOLBAR_PRINT_MULTI_MACHINE, SimpleEvent);
wxDEFINE_EVENT(EVT_GLTOOLBAR_ADD, SimpleEvent);
wxDEFINE_EVENT(EVT_GLTOOLBAR_DELETE, SimpleEvent);
+2
View File
@@ -35,6 +35,8 @@ wxDECLARE_EVENT(EVT_GLTOOLBAR_EXPORT_ALL_SLICED_FILE, SimpleEvent);
wxDECLARE_EVENT(EVT_GLTOOLBAR_PRINT_SELECT, SimpleEvent);
wxDECLARE_EVENT(EVT_GLTOOLBAR_SEND_TO_PRINTER, SimpleEvent);
wxDECLARE_EVENT(EVT_GLTOOLBAR_SEND_TO_PRINTER_ALL, SimpleEvent);
wxDECLARE_EVENT(EVT_GLTOOLBAR_PRINT_MULTI_MACHINE, SimpleEvent);
wxDECLARE_EVENT(EVT_GLTOOLBAR_ADD, SimpleEvent);
wxDECLARE_EVENT(EVT_GLTOOLBAR_DELETE, SimpleEvent);
+166 -7
View File
@@ -3,6 +3,8 @@
#include "GUI_Init.hpp"
#include "GUI_ObjectList.hpp"
#include "GUI_Factories.hpp"
#include "slic3r/GUI/UserManager.hpp"
#include "slic3r/GUI/TaskManager.hpp"
#include "format.hpp"
#include "libslic3r_version.h"
@@ -151,6 +153,7 @@ class MainFrame;
void start_ping_test()
{
return;
wxArrayString output;
wxExecute("ping www.amazon.com", output, wxEXEC_NODISABLE);
@@ -1599,6 +1602,22 @@ void GUI_App::init_networking_callbacks()
return;
BOOST_LOG_TRIVIAL(trace) << "static: server connected";
m_agent->set_user_selected_machine(m_agent->get_user_selected_machine());
if (this->is_enable_multi_machine()) {
auto evt = new wxCommandEvent(EVT_UPDATE_MACHINE_LIST);
wxQueueEvent(this, evt);
}
m_agent->set_user_selected_machine(m_agent->get_user_selected_machine());
//subscribe device
if (m_agent->is_user_login()) {
m_agent->start_device_subscribe();
/* resubscribe the cache dev list */
if (this->is_enable_multi_machine()) {
DeviceManager* dev = this->getDeviceManager();
if (dev && !dev->subscribe_list_cache.empty()) {
dev->subscribe_device_list(dev->subscribe_list_cache);
}
}
}
});
});
@@ -1618,7 +1637,9 @@ void GUI_App::init_networking_callbacks()
obj->command_get_version();
obj->erase_user_access_code();
obj->command_get_access_code();
GUI::wxGetApp().sidebar().load_ams_list(obj->dev_id, obj);
if (!is_enable_multi_machine()) {
GUI::wxGetApp().sidebar().load_ams_list(obj->dev_id, obj);
}
}
});
});
@@ -1714,11 +1735,21 @@ void GUI_App::init_networking_callbacks()
MachineObject* obj = this->m_device_manager->get_user_machine(dev_id);
if (obj) {
obj->is_ams_need_update = false;
obj->parse_json(msg);
auto sel = this->m_device_manager->get_selected_machine();
if ((sel == obj || sel == nullptr) && obj->is_ams_need_update) {
GUI::wxGetApp().sidebar().load_ams_list(obj->dev_id, obj);
if (sel && sel->dev_id == dev_id) {
obj->parse_json(msg);
}
else {
obj->parse_json(msg, true);
}
if (!this->is_enable_multi_machine()) {
if ((sel == obj || sel == nullptr) && obj->is_ams_need_update) {
GUI::wxGetApp().sidebar().load_ams_list(obj->dev_id, obj);
}
}
}
});
@@ -1726,6 +1757,25 @@ void GUI_App::init_networking_callbacks()
m_agent->set_on_message_fn(message_arrive_fn);
auto user_message_arrive_fn = [this](std::string user_id, std::string msg) {
if (m_is_closing) {
return;
}
CallAfter([this, user_id, msg] {
if (m_is_closing)
return;
//check user
if (user_id == m_agent->get_user_id()) {
this->m_user_manager->parse_json(msg);
}
});
};
m_agent->set_on_user_message_fn(user_message_arrive_fn);
auto lan_message_arrive_fn = [this](std::string dev_id, std::string msg) {
if (m_is_closing) {
return;
@@ -1740,11 +1790,15 @@ void GUI_App::init_networking_callbacks()
}
if (obj) {
obj->parse_json(msg);
obj->parse_json(msg, DeviceManager::key_field_only);
if (this->m_device_manager->get_selected_machine() == obj && obj->is_ams_need_update) {
GUI::wxGetApp().sidebar().load_ams_list(obj->dev_id, obj);
}
}
obj = m_device_manager->get_local_machine(dev_id);
if (obj) {
obj->parse_json(msg, DeviceManager::key_field_only);
}
});
};
m_agent->set_on_local_message_fn(lan_message_arrive_fn);
@@ -2054,6 +2108,11 @@ int GUI_App::OnExit()
m_device_manager = nullptr;
}
if (m_user_manager) {
delete m_user_manager;
m_user_manager = nullptr;
}
if (m_agent) {
// BBS avoid a crash on mac platform
#ifdef __WINDOWS__
@@ -2402,6 +2461,7 @@ bool GUI_App::on_init_inner()
preset_bundle->set_default_suppressed(true);
Bind(EVT_SET_SELECTED_MACHINE, &GUI_App::on_set_selected_machine, this);
Bind(EVT_UPDATE_MACHINE_LIST, &GUI_App::on_update_machine_list, this);
Bind(EVT_USER_LOGIN, &GUI_App::on_user_login, this);
Bind(EVT_USER_LOGIN_HANDLE, &GUI_App::on_user_login_handle, this);
Bind(EVT_CHECK_PRIVACY_VER, &GUI_App::on_check_privacy_update, this);
@@ -2724,6 +2784,22 @@ __retry:
else
m_device_manager->set_agent(m_agent);
if (!m_user_manager)
m_user_manager = new Slic3r::UserManager(m_agent);
else
m_user_manager->set_agent(m_agent);
if (this->is_enable_multi_machine()) {
if (!m_task_manager) {
m_task_manager = new Slic3r::TaskManager(m_agent);
m_task_manager->start();
}
m_agent->enable_multi_machine(true);
DeviceManager::EnableMultiMachine = true;
} else {
m_agent->enable_multi_machine(false);
DeviceManager::EnableMultiMachine = false;
}
//BBS set config dir
if (m_agent) {
@@ -2753,6 +2829,9 @@ __retry:
if (!m_device_manager)
m_device_manager = new Slic3r::DeviceManager();
if (!m_user_manager)
m_user_manager = new Slic3r::UserManager();
}
return true;
@@ -3794,6 +3873,21 @@ std::string GUI_App::handle_web_request(std::string cmd)
if (path.has_value()) {
wxLaunchDefaultBrowser(path.value());
}
}
else if (command_str.compare("homepage_makerlab_get") == 0) {
//if (mainframe->m_webview) { mainframe->m_webview->SendMakerlabList(); }
}
else if (command_str.compare("makerworld_model_open") == 0)
{
if (root.get_child_optional("model") != boost::none) {
pt::ptree data_node = root.get_child("model");
boost::optional<std::string> path = data_node.get_optional<std::string>("url");
if (path.has_value())
{
wxString realurl = from_u8(url_decode(path.value()));
wxGetApp().request_model_download(realurl);
}
}
}
}
}
@@ -3947,9 +4041,17 @@ void GUI_App::enable_user_preset_folder(bool enable)
void GUI_App::on_set_selected_machine(wxCommandEvent &evt)
{
DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
if (!dev || m_agent) return;
if (dev) {
dev->set_selected_machine(m_agent->get_user_selected_machine());
}
}
dev->set_selected_machine(m_agent->get_user_selected_machine());
void GUI_App::on_update_machine_list(wxCommandEvent &evt)
{
/* DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
if (dev) {
dev->add_user_subscribe();
}*/
}
void GUI_App::on_user_login_handle(wxCommandEvent &evt)
@@ -4383,6 +4485,24 @@ std::string GUI_App::format_display_version()
return version_display;
}
std::string GUI_App::format_IP(const std::string& ip)
{
std::string format_ip = ip;
size_t pos_st = 0;
size_t pos_en = 0;
for (int i = 0; i < 2; i++) {
pos_en = format_ip.find('.', pos_st + 1);
if (pos_en == std::string::npos) {
return ip;
}
format_ip.replace(pos_st, pos_en - pos_st, "***");
pos_st = pos_en + 1;
}
return format_ip;
}
void GUI_App::show_dialog(wxString msg)
{
if (m_info_dialog_content.empty()) {
@@ -4393,6 +4513,26 @@ void GUI_App::show_dialog(wxString msg)
}
}
void GUI_App::push_notification(wxString msg, wxString title, UserNotificationStyle style)
{
if (!this->is_enable_multi_machine()) {
if (style == UserNotificationStyle::UNS_NORMAL) {
if (m_info_dialog_content.empty()) {
wxCommandEvent* evt = new wxCommandEvent(EVT_SHOW_DIALOG);
evt->SetString(msg);
GUI::wxGetApp().QueueEvent(evt);
m_info_dialog_content = msg;
}
}
else if (style == UserNotificationStyle::UNS_WARNING_CONFIRM) {
GUI::wxGetApp().CallAfter([msg, title] {
GUI::MessageDialog msg_dlg(nullptr, msg, title, wxICON_WARNING | wxOK);
msg_dlg.ShowModal();
});
}
}
}
void GUI_App::reload_settings()
{
if (preset_bundle && m_agent) {
@@ -5964,6 +6104,25 @@ std::string GUI_App::url_encode(std::string value) {
return Http::url_encode(value);
}
void GUI_App::popup_ping_bind_dialog()
{
if (m_ping_code_binding_dialog == nullptr) {
m_ping_code_binding_dialog = new PingCodeBindDialog();
m_ping_code_binding_dialog->ShowModal();
remove_ping_bind_dialog();
}
}
void GUI_App::remove_ping_bind_dialog()
{
if (m_ping_code_binding_dialog != nullptr) {
m_ping_code_binding_dialog->Destroy();
delete m_mall_publish_dialog;
m_ping_code_binding_dialog = nullptr;
}
}
void GUI_App::remove_mall_system_dialog()
{
if (m_mall_publish_dialog != nullptr) {
+16
View File
@@ -16,9 +16,11 @@
#include "libslic3r/Preset.hpp"
#include "libslic3r/PresetBundle.hpp"
#include "slic3r/GUI/DeviceManager.hpp"
#include "slic3r/GUI/UserNotification.hpp"
#include "slic3r/Utils/NetworkAgent.hpp"
#include "slic3r/GUI/WebViewDialog.hpp"
#include "slic3r/GUI/WebUserLoginDialog.hpp"
#include "slic3r/GUI/BindDialog.hpp"
#include "slic3r/GUI/HMS.hpp"
#include "slic3r/GUI/Jobs/UpgradeNetworkJob.hpp"
#include "slic3r/GUI/HttpServer.hpp"
@@ -55,8 +57,10 @@ class PresetBundle;
class PresetUpdater;
class ModelObject;
class Model;
class UserManager;
class DeviceManager;
class NetworkAgent;
class TaskManager;
namespace GUI{
@@ -74,6 +78,7 @@ struct GUI_InitParams;
class ParamsDialog;
class HMSQuery;
class ModelMallDialog;
class PingCodeBindDialog;
enum FileType
@@ -273,6 +278,8 @@ private:
//BBS
bool m_is_closing {false};
Slic3r::DeviceManager* m_device_manager { nullptr };
Slic3r::UserManager* m_user_manager { nullptr };
Slic3r::TaskManager* m_task_manager { nullptr };
NetworkAgent* m_agent { nullptr };
std::vector<std::string> need_delete_presets; // store setting ids of preset
std::vector<bool> m_create_preset_blocked { false, false, false, false, false, false }; // excceed limit
@@ -307,6 +314,7 @@ private:
bool OnInit() override;
int OnExit() override;
bool initialized() const { return m_initialized; }
inline bool is_enable_multi_machine() { return this->app_config&& this->app_config->get("enable_multi_machine") == "true"; }
std::map<std::string, bool> test_url_state;
@@ -318,6 +326,7 @@ private:
void show_message_box(std::string msg) { wxMessageBox(msg); }
EAppMode get_app_mode() const { return m_app_mode; }
Slic3r::DeviceManager* getDeviceManager() { return m_device_manager; }
Slic3r::TaskManager* getTaskManager() { return m_task_manager; }
HMSQuery* get_hms_query() { return hms_query; }
NetworkAgent* getAgent() { return m_agent; }
bool is_editor() const { return m_app_mode == EAppMode::Editor; }
@@ -442,6 +451,7 @@ private:
void handle_http_error(unsigned int status, std::string body);
void on_http_error(wxCommandEvent &evt);
void on_set_selected_machine(wxCommandEvent& evt);
void on_update_machine_list(wxCommandEvent& evt);
void on_user_login(wxCommandEvent &evt);
void on_user_login_handle(wxCommandEvent& evt);
void enable_user_preset_folder(bool enable);
@@ -460,7 +470,9 @@ private:
void set_skip_version(bool skip = true);
void no_new_version();
static std::string format_display_version();
std::string format_IP(const std::string& ip);
void show_dialog(wxString msg);
void push_notification(wxString msg, wxString title = wxEmptyString, UserNotificationStyle style = UserNotificationStyle::UNS_NORMAL);
void reload_settings();
void remove_user_presets();
void sync_preset(Preset* preset);
@@ -552,6 +564,7 @@ private:
std::string m_mall_model_download_url;
std::string m_mall_model_download_name;
ModelMallDialog* m_mall_publish_dialog{ nullptr };
PingCodeBindDialog* m_ping_code_binding_dialog{ nullptr };
void set_download_model_url(std::string url) {m_mall_model_download_url = url;}
void set_download_model_name(std::string name) {m_mall_model_download_name = name;}
@@ -570,6 +583,9 @@ private:
std::string url_encode(std::string value);
std::string url_decode(std::string value);
void popup_ping_bind_dialog();
void remove_ping_bind_dialog();
// Parameters extracted from the command line to be passed to GUI after initialization.
GUI_InitParams* init_params { nullptr };
+117 -1
View File
@@ -24,6 +24,7 @@
#include <imgui/imgui_internal.h>
#include "libslic3r/SVG.hpp"
#include <codecvt>
#include "wx/fontenum.h"
namespace Slic3r {
namespace GUI {
@@ -34,6 +35,119 @@ static const wxColour FONT_TEXTURE_FG = *wxWHITE;
static const int FONT_SIZE = 12;
static const float SELECTABLE_INNER_OFFSET = 8.0f;
static std::vector<std::string> font_black_list = {
#ifdef _WIN32
"MT Extra",
"Marlett",
"Symbol",
"Webdings",
"Wingdings",
"Wingdings 2",
"Wingdings 3",
#endif
};
static const wxFontEncoding font_encoding = wxFontEncoding::wxFONTENCODING_SYSTEM;
#ifdef _WIN32
static bool load_hfont(void *hfont, DWORD &dwTable, DWORD &dwOffset, size_t &size, HDC hdc = nullptr)
{
bool del_hdc = false;
if (hdc == nullptr) {
del_hdc = true;
hdc = ::CreateCompatibleDC(NULL);
if (hdc == NULL) return false;
}
// To retrieve the data from the beginning of the file for TrueType
// Collection files specify 'ttcf' (0x66637474).
dwTable = 0x66637474;
dwOffset = 0;
::SelectObject(hdc, hfont);
size = ::GetFontData(hdc, dwTable, dwOffset, NULL, 0);
if (size == GDI_ERROR) {
// HFONT is NOT TTC(collection)
dwTable = 0;
size = ::GetFontData(hdc, dwTable, dwOffset, NULL, 0);
}
if (size == 0 || size == GDI_ERROR) {
if (del_hdc) ::DeleteDC(hdc);
return false;
}
return true;
}
#endif // _WIN32
bool can_load(const wxFont &font)
{
#ifdef _WIN32
DWORD dwTable = 0, dwOffset = 0;
size_t size = 0;
void* hfont = font.GetHFONT();
if (!load_hfont(hfont, dwTable, dwOffset, size))
return false;
return hfont != nullptr;
#elif defined(__APPLE__)
return true;
#elif defined(__linux__)
return true;
#endif
return false;
}
std::vector<std::string> init_face_names()
{
std::vector<std::string> valid_font_names;
wxArrayString facenames = wxFontEnumerator::GetFacenames(font_encoding);
std::vector<wxString> bad_fonts;
// validation lambda
auto is_valid_font = [coding = font_encoding, bad = bad_fonts](const wxString &name) {
if (name.empty())
return false;
// vertical font start with @, we will filter it out
// Not sure if it is only in Windows so filtering is on all platforms
if (name[0] == '@')
return false;
// previously detected bad font
auto it = std::lower_bound(bad.begin(), bad.end(), name);
if (it != bad.end() && *it == name)
return false;
wxFont wx_font(wxFontInfo().FaceName(name).Encoding(coding));
// Faster chech if wx_font is loadable but not 100%
// names could contain not loadable font
if (!wx_font.IsOk())
return false;
if (!can_load(wx_font))
return false;
return true;
};
std::sort(facenames.begin(), facenames.end());
for (const wxString &name : facenames) {
if (is_valid_font(name)) {
valid_font_names.push_back(name.ToStdString());
}
else {
bad_fonts.emplace_back(name);
}
}
assert(std::is_sorted(bad_fonts.begin(), bad_fonts.end()));
for (auto iter = font_black_list.begin(); iter != font_black_list.end(); ++iter) {
valid_font_names.erase(std::remove(valid_font_names.begin(), valid_font_names.end(), *iter), valid_font_names.end());
}
return valid_font_names;
}
class Line_3D
{
public:
@@ -142,7 +256,9 @@ GLGizmoText::~GLGizmoText()
bool GLGizmoText::on_init()
{
m_avail_font_names = init_occt_fonts();
m_avail_font_names = init_face_names();
//m_avail_font_names = init_occt_fonts();
update_font_texture();
m_scale = m_imgui->get_font_size();
m_shortcut_key = WXK_CONTROL_T;
+94 -53
View File
@@ -41,30 +41,45 @@ int get_hms_info_version(std::string& version)
return result;
}
int HMSQuery::download_hms_info()
int HMSQuery::download_hms_related(std::string hms_type, json* receive_json)
{
std::string local_version = "0";
load_from_local(local_version, hms_type, receive_json);
AppConfig* config = wxGetApp().app_config;
if (!config) return -1;
std::string hms_host = wxGetApp().app_config->get_hms_host();
std::string lang;
std::string query_params = HMSQuery::build_query_params(lang);
std::string url = (boost::format("https://%1%/query.php?%2%") % hms_host % query_params).str();
std::string url;
if (hms_type.compare(QUERY_HMS_INFO) == 0) {
url = (boost::format("https://%1%/query.php?%2%&v=%3%") % hms_host % query_params % local_version).str();
}
else if (hms_type.compare(QUERY_HMS_ACTION) == 0) {
url = (boost::format("https://%1%/hms/GetActionImage.php?v=%2%") % hms_host % local_version).str();
}
BOOST_LOG_TRIVIAL(info) << "hms: download url = " << url;
Slic3r::Http http = Slic3r::Http::get(url);
m_hms_json.clear();
http.on_complete([this](std::string body, unsigned status) {
http.on_complete([this, receive_json, hms_type](std::string body, unsigned status) {
try {
json j = json::parse(body);
if (j.contains("result")) {
if (j["result"] == 0 && j.contains("data")) {
this->m_hms_json = j["data"];
if (hms_type.compare(QUERY_HMS_INFO) == 0) {
(*receive_json) = j["data"];
this->save_local = true;
}
else if (hms_type.compare(QUERY_HMS_ACTION) == 0) {
(*receive_json)["data"] = j["data"];
this->save_local = true;
}
if (j.contains("ver"))
m_hms_json["version"] = std::to_string(j["ver"].get<long long>());
} else {
this->m_hms_json.clear();
(*receive_json)["version"] = std::to_string(j["ver"].get<long long>());
} else if (j["result"] == 201){
BOOST_LOG_TRIVIAL(info) << "HMSQuery: HMS info is the latest version";
}else{
receive_json->clear();
BOOST_LOG_TRIVIAL(info) << "HMSQuery: update hms info error = " << j["result"].get<int>();
}
}
@@ -77,19 +92,21 @@ int HMSQuery::download_hms_info()
BOOST_LOG_TRIVIAL(error) << "HMSQuery: update hms info error = " << error << ", body = " << body << ", status = " << status;
}).perform_sync();
if (!m_hms_json.empty())
save_to_local(lang);
if (!receive_json->empty() && save_local == true) {
save_to_local(lang, hms_type, *receive_json);
save_local = false;
}
return 0;
}
int HMSQuery::load_from_local(std::string &version_info)
int HMSQuery::load_from_local(std::string& version_info, std::string hms_type, json* load_json)
{
if (data_dir().empty()) {
version_info = "";
version_info = "0";
BOOST_LOG_TRIVIAL(error) << "HMS: load_from_local, data_dir() is empty";
return -1;
}
std::string filename = get_hms_file(HMSQuery::hms_language_code());
std::string filename = get_hms_file(hms_type, HMSQuery::hms_language_code());
auto hms_folder = (boost::filesystem::path(data_dir()) / "hms");
if (!fs::exists(hms_folder))
fs::create_directory(hms_folder);
@@ -98,9 +115,9 @@ int HMSQuery::load_from_local(std::string &version_info)
std::ifstream json_file(encode_path(dir_str.c_str()));
try {
if (json_file.is_open()) {
json_file >> m_hms_json;
if (m_hms_json.contains("version")) {
version_info = m_hms_json["version"].get<std::string>();
json_file >> (*load_json);
if ((*load_json).contains("version")) {
version_info = (*load_json)["version"].get<std::string>();
return 0;
} else {
BOOST_LOG_TRIVIAL(warning) << "HMS: load_from_local, no version info";
@@ -108,28 +125,28 @@ int HMSQuery::load_from_local(std::string &version_info)
}
}
} catch(...) {
version_info = "";
version_info = "0";
BOOST_LOG_TRIVIAL(error) << "HMS: load_from_local failed";
return -1;
}
version_info = "";
version_info = "0";
return 0;
}
int HMSQuery::save_to_local(std::string lang)
int HMSQuery::save_to_local(std::string lang, std::string hms_type, json save_json)
{
if (data_dir().empty()) {
BOOST_LOG_TRIVIAL(error) << "HMS: save_to_local, data_dir() is empty";
return -1;
}
std::string filename = get_hms_file(lang);
std::string filename = get_hms_file(hms_type,lang);
auto hms_folder = (boost::filesystem::path(data_dir()) / "hms");
if (!fs::exists(hms_folder))
fs::create_directory(hms_folder);
std::string dir_str = (hms_folder / filename).make_preferred().string();
std::ofstream json_file(encode_path(dir_str.c_str()));
if (json_file.is_open()) {
json_file << std::setw(4) << m_hms_json << std::endl;
json_file << std::setw(4) << save_json << std::endl;
json_file.close();
return 0;
}
@@ -166,9 +183,13 @@ std::string HMSQuery::build_query_params(std::string& lang)
return query_params;
}
std::string HMSQuery::get_hms_file(std::string lang)
std::string HMSQuery::get_hms_file(std::string hms_type, std::string lang)
{
//std::string lang_code = HMSQuery::hms_language_code();
//return hms action filename
if (hms_type.compare(QUERY_HMS_ACTION) == 0) {
return (boost::format("hms_action.json")).str();
}
//return hms filename
return (boost::format("hms_%1%.json") % lang).str();
}
@@ -185,9 +206,9 @@ wxString HMSQuery::_query_hms_msg(std::string long_error_code, std::string lang_
if (long_error_code.empty())
return wxEmptyString;
if (m_hms_json.contains("device_hms")) {
if (m_hms_json["device_hms"].contains(lang_code)) {
for (auto item = m_hms_json["device_hms"][lang_code].begin(); item != m_hms_json["device_hms"][lang_code].end(); item++) {
if (m_hms_info_json.contains("device_hms")) {
if (m_hms_info_json["device_hms"].contains(lang_code)) {
for (auto item = m_hms_info_json["device_hms"][lang_code].begin(); item != m_hms_info_json["device_hms"][lang_code].end(); item++) {
if (item->contains("ecode")) {
std::string temp_string = (*item)["ecode"].get<std::string>();
if (boost::to_upper_copy(temp_string) == long_error_code) {
@@ -201,8 +222,8 @@ wxString HMSQuery::_query_hms_msg(std::string long_error_code, std::string lang_
} else {
BOOST_LOG_TRIVIAL(error) << "hms: query_hms_msg, do not contains lang_code = " << lang_code;
// return first language
if (!m_hms_json["device_hms"].empty()) {
for (auto lang : m_hms_json["device_hms"]) {
if (!m_hms_info_json["device_hms"].empty()) {
for (auto lang : m_hms_info_json["device_hms"]) {
for (auto item = lang.begin(); item != lang.end(); item++) {
if (item->contains("ecode")) {
std::string temp_string = (*item)["ecode"].get<std::string>();
@@ -225,9 +246,9 @@ wxString HMSQuery::_query_hms_msg(std::string long_error_code, std::string lang_
wxString HMSQuery::_query_error_msg(std::string error_code, std::string lang_code)
{
if (m_hms_json.contains("device_error")) {
if (m_hms_json["device_error"].contains(lang_code)) {
for (auto item = m_hms_json["device_error"][lang_code].begin(); item != m_hms_json["device_error"][lang_code].end(); item++) {
if (m_hms_info_json.contains("device_error")) {
if (m_hms_info_json["device_error"].contains(lang_code)) {
for (auto item = m_hms_info_json["device_error"][lang_code].begin(); item != m_hms_info_json["device_error"][lang_code].end(); item++) {
if (item->contains("ecode") && boost::to_upper_copy((*item)["ecode"].get<std::string>()) == error_code) {
if (item->contains("intro")) {
return wxString::FromUTF8((*item)["intro"].get<std::string>());
@@ -238,8 +259,8 @@ wxString HMSQuery::_query_error_msg(std::string error_code, std::string lang_cod
} else {
BOOST_LOG_TRIVIAL(error) << "hms: query_error_msg, do not contains lang_code = " << lang_code;
// return first language
if (!m_hms_json["device_error"].empty()) {
for (auto lang : m_hms_json["device_error"]) {
if (!m_hms_info_json["device_error"].empty()) {
for (auto lang : m_hms_info_json["device_error"]) {
for (auto item = lang.begin(); item != lang.end(); item++) {
if (item->contains("ecode") && boost::to_upper_copy((*item)["ecode"].get<std::string>()) == error_code) {
if (item->contains("intro")) {
@@ -258,6 +279,33 @@ wxString HMSQuery::_query_error_msg(std::string error_code, std::string lang_cod
return wxEmptyString;
}
wxString HMSQuery::_query_error_url_action(std::string long_error_code, std::string dev_id, std::vector<int>& button_action)
{
if (m_hms_action_json.contains("data")) {
for (auto item = m_hms_action_json["data"].begin(); item != m_hms_action_json["data"].end(); item++) {
if (item->contains("ecode") && boost::to_upper_copy((*item)["ecode"].get<std::string>()) == long_error_code) {
if (item->contains("device") && (boost::to_upper_copy((*item)["device"].get<std::string>()) == dev_id ||
(*item)["device"].get<std::string>() == "default")) {
if (item->contains("actions")) {
for (auto item_actions = (*item)["actions"].begin(); item_actions != (*item)["actions"].end(); item_actions++) {
button_action.emplace_back(item_actions->get<int>());
}
}
if (item->contains("image")) {
return wxString::FromUTF8((*item)["image"].get<std::string>());
}
}
}
}
}
else {
BOOST_LOG_TRIVIAL(info) << "data is not exists";
return wxEmptyString;
}
return wxEmptyString;
}
wxString HMSQuery::query_print_error_msg(int print_error)
{
char buf[32];
@@ -266,29 +314,22 @@ wxString HMSQuery::query_print_error_msg(int print_error)
return _query_error_msg(std::string(buf), lang_code);
}
wxString HMSQuery::query_print_error_url_action(int print_error, std::string dev_id, std::vector<int>& button_action)
{
char buf[32];
::sprintf(buf, "%08X", print_error);
//The first three digits of SN number
dev_id = dev_id.substr(0, 3);
return _query_error_url_action(std::string(buf), dev_id, button_action);
}
int HMSQuery::check_hms_info()
{
boost::thread check_thread = boost::thread([this] {
bool download_new_hms_info = true;
// load local hms json file
std::string version = "";
if (load_from_local(version) == 0) {
BOOST_LOG_TRIVIAL(info) << "HMS: check_hms_info current version = " << version;
std::string new_version;
get_hms_info_version(new_version);
BOOST_LOG_TRIVIAL(info) << "HMS: check_hms_info latest version = " << new_version;
if (new_version.empty()) {return 0;}
if (!version.empty() && version == new_version) {
download_new_hms_info = false;
}
}
BOOST_LOG_TRIVIAL(info) << "HMS: check_hms_info need download new hms info = " << download_new_hms_info;
// download if version is update
if (download_new_hms_info) {
download_hms_info();
}
download_hms_related(QUERY_HMS_INFO, &m_hms_info_json);
download_hms_related(QUERY_HMS_ACTION, &m_hms_action_json);
return 0;
});
return 0;
+14 -7
View File
@@ -16,23 +16,30 @@ namespace Slic3r {
namespace GUI {
#define HMS_INFO_FILE "hms.json"
#define QUERY_HMS_INFO "query_hms_info"
#define QUERY_HMS_ACTION "query_hms_action"
class HMSQuery {
protected:
json m_hms_json;
int download_hms_info();
int load_from_local(std::string& version_info);
int save_to_local(std::string lang);
std::string get_hms_file(std::string lang);
wxString _query_hms_msg(std::string long_error_code, std::string lang_code = "en");
wxString _query_error_msg(std::string long_error_code, std::string lang_code = "en");
json m_hms_info_json;
json m_hms_action_json;
int download_hms_related(std::string hms_type,json* receive_json);
int load_from_local(std::string& version_info, std::string hms_type, json* load_json);
int save_to_local(std::string lang, std::string hms_type,json save_json);
std::string get_hms_file(std::string hms_type, std::string lang = std::string("en"));
wxString _query_hms_msg(std::string long_error_code, std::string lang_code = std::string("en"));
wxString _query_error_msg(std::string long_error_code, std::string lang_code = std::string("en"));
wxString _query_error_url_action(std::string long_error_code, std::string dev_id, std::vector<int>& button_action);
public:
HMSQuery() {}
int check_hms_info();
wxString query_hms_msg(std::string long_error_code);
wxString query_print_error_msg(int print_error);
wxString query_print_error_url_action(int print_error, std::string dev_id, std::vector<int>& button_action);
static std::string hms_language_code();
static std::string build_query_params(std::string& lang);
bool save_local = false;
};
int get_hms_info_version(std::string &version);
+3 -3
View File
@@ -124,9 +124,9 @@ void BindJob::process(Ctl &ctl)
}
dev->update_user_machine_list_info();
wxCommandEvent event(EVT_BIND_MACHINE_SUCCESS);
event.SetEventObject(m_event_handle);
wxPostEvent(m_event_handle, event);
wxCommandEvent event(EVT_BIND_MACHINE_SUCCESS);
event.SetEventObject(m_event_handle);
wxPostEvent(m_event_handle, event);
return;
}
+2 -1
View File
@@ -979,7 +979,8 @@ TriangleMesh create_default_mesh()
std::string path = Slic3r::resources_dir() + "/data/embossed_text.obj";
TriangleMesh triangle_mesh;
std::string message;
if (!load_obj(path.c_str(), &triangle_mesh, message)) {
ObjInfo obj_info;
if (!load_obj(path.c_str(), &triangle_mesh, obj_info, message)) {
// when can't load mesh use cube
return TriangleMesh(its_make_cube(36., 4., 2.5));
}
+56 -10
View File
@@ -92,6 +92,7 @@ wxDEFINE_EVENT(EVT_CHECK_PRIVACY_VER, wxCommandEvent);
wxDEFINE_EVENT(EVT_CHECK_PRIVACY_SHOW, wxCommandEvent);
wxDEFINE_EVENT(EVT_SHOW_IP_DIALOG, wxCommandEvent);
wxDEFINE_EVENT(EVT_SET_SELECTED_MACHINE, wxCommandEvent);
wxDEFINE_EVENT(EVT_UPDATE_MACHINE_LIST, wxCommandEvent);
wxDEFINE_EVENT(EVT_UPDATE_PRESET_CB, SimpleEvent);
@@ -1078,14 +1079,21 @@ void MainFrame::init_tabpanel() {
m_printer_view->load_url(url, key);
});
m_printer_view->Hide();
if (wxGetApp().is_enable_multi_machine()) {
m_multi_machine = new MultiMachinePage(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_multi_machine->SetBackgroundColour(*wxWHITE);
// TODO: change the bitmap
m_tabpanel->AddPage(m_multi_machine, _L("Multi-device"), std::string("tab_multi_active"), std::string("tab_multi_active"), false);
}
m_project = new ProjectPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_project->SetBackgroundColour(*wxWHITE);
m_tabpanel->AddPage(m_project, _L("Project"), std::string("tab_auxiliary_active"), std::string("tab_auxiliary_active"), false);
m_calibration = new CalibrationPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_calibration->SetBackgroundColour(*wxWHITE);
m_tabpanel->AddPage(m_calibration, _L("Calibration"), std::string("tab_monitor_active"), std::string("tab_monitor_active"), false);
m_tabpanel->AddPage(m_calibration, _L("Calibration"), std::string("tab_calibration_active"), std::string("tab_calibration_active"), false);
if (m_plater) {
// load initial config
@@ -1479,6 +1487,7 @@ bool MainFrame::can_reslice() const
wxBoxSizer* MainFrame::create_side_tools()
{
enable_multi_machine = wxGetApp().is_enable_multi_machine();
int em = em_unit();
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
@@ -1536,7 +1545,7 @@ wxBoxSizer* MainFrame::create_side_tools()
m_print_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event)
{
//this->m_plater->select_view_3D("Preview");
if (m_print_select == ePrintAll || m_print_select == ePrintPlate)
if (m_print_select == ePrintAll || m_print_select == ePrintPlate || m_print_select == ePrintMultiMachine)
{
m_plater->apply_background_progress();
// check valid of print
@@ -1547,6 +1556,8 @@ wxBoxSizer* MainFrame::create_side_tools()
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_PRINT_ALL));
if (m_print_select == ePrintPlate)
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_PRINT_PLATE));
if(m_print_select == ePrintMultiMachine)
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_PRINT_MULTI_MACHINE));
}
}
else if (m_print_select == eExportGcode)
@@ -1563,6 +1574,8 @@ wxBoxSizer* MainFrame::create_side_tools()
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SEND_TO_PRINTER));
else if (m_print_select == eSendToPrinterAll)
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SEND_TO_PRINTER_ALL));
/* else if (m_print_select == ePrintMultiMachine)
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_PRINT_MULTI_MACHINE));*/
});
m_slice_option_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event)
@@ -1701,6 +1714,25 @@ wxBoxSizer* MainFrame::create_side_tools()
p->Dismiss();
});
p->append_button(print_plate_btn);
p->append_button(print_all_btn);
p->append_button(send_to_printer_btn);
p->append_button(send_to_printer_all_btn);
if (enable_multi_machine) {
SideButton* print_multi_machine_btn = new SideButton(p, _L("Send to Multi-device"), "");
print_multi_machine_btn->SetCornerRadius(0);
print_multi_machine_btn->Bind(wxEVT_BUTTON, [this, p](wxCommandEvent&) {
m_print_btn->SetLabel(_L("Send to Multi-device"));
m_print_select = ePrintMultiMachine;
m_print_enable = get_enable_print_status();
m_print_btn->Enable(m_print_enable);
this->Layout();
p->Dismiss();
});
p->append_button(print_multi_machine_btn);
}
p->append_button(export_sliced_file_btn);
p->append_button(export_all_sliced_file_btn);
SideButton* export_gcode_btn = new SideButton(p, _L("Export G-code file"), "");
export_gcode_btn->SetCornerRadius(0);
export_gcode_btn->Bind(wxEVT_BUTTON, [this, p](wxCommandEvent&) {
@@ -1710,13 +1742,7 @@ wxBoxSizer* MainFrame::create_side_tools()
m_print_btn->Enable(m_print_enable);
this->Layout();
p->Dismiss();
});
p->append_button(print_plate_btn);
p->append_button(print_all_btn);
p->append_button(send_to_printer_btn);
p->append_button(send_to_printer_all_btn);
p->append_button(export_sliced_file_btn);
p->append_button(export_all_sliced_file_btn);
});
p->append_button(export_gcode_btn);
}
@@ -1859,6 +1885,14 @@ bool MainFrame::get_enable_print_status()
enable = false;
}
}
else if (m_print_select == ePrintMultiMachine)
{
if (!current_plate->is_slice_result_ready_for_print())
{
enable = false;
}
enable = enable && !is_all_plates;
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": m_print_select %1%, enable= %2% ")%m_print_select %enable;
@@ -1979,6 +2013,7 @@ void MainFrame::on_dpi_changed(const wxRect& suggested_rect)
m_param_panel->msw_rescale();
m_project->msw_rescale();
m_monitor->msw_rescale();
m_multi_machine->msw_rescale();
m_calibration->msw_rescale();
// BBS
@@ -3290,6 +3325,13 @@ void MainFrame::jump_to_monitor(std::string dev_id)
((MonitorPanel*)m_monitor)->select_machine(dev_id);
}
void MainFrame::jump_to_multipage()
{
m_tabpanel->SetSelection(tpMultiDevice);
((MultiMachinePage*)m_multi_machine)->jump_to_send_page();
}
//BBS GUI refactor: remove unused layout new/dlg
void MainFrame::select_tab(size_t tab/* = size_t(-1)*/)
{
@@ -3655,6 +3697,10 @@ void MainFrame::update_side_preset_ui()
//BBS: update the preset
m_plater->sidebar().update_presets(Preset::TYPE_PRINTER);
m_plater->sidebar().update_presets(Preset::TYPE_FILAMENT);
//take off multi machine
if(m_multi_machine){m_multi_machine->clear_page();}
}
void MainFrame::on_select_default_preset(SimpleEvent& evt)
+24 -19
View File
@@ -32,6 +32,7 @@
#include "BBLTopbar.hpp"
#include "PrinterWebView.hpp"
#include "calib_dlg.hpp"
#include "MultiMachinePage.hpp"
#define ENABEL_PRINT_ALL 0
@@ -98,6 +99,7 @@ class MainFrame : public DPIFrame
wxMenuBar* m_menubar{ nullptr };
//wxMenu* publishMenu{ nullptr };
wxMenu * m_calib_menu{nullptr};
bool enable_multi_machine{ false };
#if 0
wxMenuItem* m_menu_item_repeat { nullptr }; // doesn't used now
@@ -199,21 +201,6 @@ protected:
#endif
public:
//BBS GUI refactor
enum PrintSelectType
{
ePrintAll = 0,
ePrintPlate = 1,
eExportSlicedFile = 2,
eExportGcode = 3,
eSendGcode = 4,
eSendToPrinter = 5,
eSendToPrinterAll = 6,
eUploadGcode = 7,
eExportAllSlicedFile = 8
};
MainFrame();
~MainFrame() = default;
@@ -224,10 +211,11 @@ public:
tp3DEditor = 1,
tpPreview = 2,
tpMonitor = 3,
tpProject = 4,
tpCalibration = 5,
tpAuxiliary = 6,
toDebugTool = 7,
tpMultiDevice = 4,
tpProject = 5,
tpCalibration = 6,
tpAuxiliary = 7,
toDebugTool = 8,
};
//BBS: add slice&&print status update logic
@@ -240,6 +228,20 @@ public:
eEventPrintUpdate = 4
};
// BBS GUI refactor
enum PrintSelectType {
ePrintAll = 0,
ePrintPlate = 1,
eExportSlicedFile = 2,
eExportGcode = 3,
eSendGcode = 4,
eSendToPrinter = 5,
eSendToPrinterAll = 6,
eUploadGcode = 7,
eExportAllSlicedFile = 8,
ePrintMultiMachine = 9
};
void update_layout();
// Called when closing the application and when switching the application language.
@@ -308,6 +310,7 @@ public:
void load_config(const DynamicPrintConfig& config);
//BBS: jump to monitor
void jump_to_monitor(std::string dev_id = "");
void jump_to_multipage();
//BBS: hint when jump to 3Deditor under preview only mode
bool preview_only_hint();
// Select tab in m_tabpanel
@@ -361,6 +364,7 @@ public:
MonitorPanel* m_monitor{ nullptr };
//AuxiliaryPanel* m_auxiliary{ nullptr };
MultiMachinePage* m_multi_machine{ nullptr };
ProjectPanel* m_project{ nullptr };
CalibrationPanel* m_calibration{ nullptr };
@@ -413,6 +417,7 @@ wxDECLARE_EVENT(EVT_CHECK_PRIVACY_VER, wxCommandEvent);
wxDECLARE_EVENT(EVT_CHECK_PRIVACY_SHOW, wxCommandEvent);
wxDECLARE_EVENT(EVT_SHOW_IP_DIALOG, wxCommandEvent);
wxDECLARE_EVENT(EVT_SET_SELECTED_MACHINE, wxCommandEvent);
wxDECLARE_EVENT(EVT_UPDATE_MACHINE_LIST, wxCommandEvent);
wxDECLARE_EVENT(EVT_UPDATE_PRESET_CB, SimpleEvent);
+1 -1
View File
@@ -120,7 +120,7 @@ MediaFilePanel::MediaFilePanel(wxWindow * parent)
m_button_management->SetTextColorNormal(*wxWHITE);
m_button_management->Enable(false);
m_button_refresh->SetBorderWidth(0);
m_button_refresh->SetBackgroundColorNormal(wxColor("#00AE42"));
m_button_refresh->SetBackgroundColorNormal(wxColor("#009688"));
m_button_refresh->SetTextColorNormal(*wxWHITE);
m_button_refresh->Enable(false);
+7
View File
@@ -546,6 +546,13 @@ void MediaPlayCtrl::msw_rescale() {
m_button_play->Rescale();
}
void MediaPlayCtrl::jump_to_play()
{
if (m_last_state != MEDIASTATE_IDLE)
return;
TogglePlay();
}
void MediaPlayCtrl::onStateChanged(wxMediaEvent &event)
{
auto last_state = m_last_state;
+2
View File
@@ -42,6 +42,8 @@ public:
void msw_rescale();
void jump_to_play();
protected:
void onStateChanged(wxMediaEvent & event);
+32 -1
View File
@@ -132,6 +132,8 @@ AddMachinePanel::~AddMachinePanel() {
update_hms_tag();
e.Skip();
});
Bind(EVT_JUMP_TO_HMS, &MonitorPanel::jump_to_HMS, this);
}
MonitorPanel::~MonitorPanel()
@@ -196,7 +198,7 @@ MonitorPanel::~MonitorPanel()
m_tabpanel->AddPage(m_upgrade_panel, _L("Update"), "", false);
m_hms_panel = new HMSPanel(m_tabpanel);
m_tabpanel->AddPage(m_hms_panel, _L("HMS"),"", false);
m_tabpanel->AddPage(m_hms_panel, "HMS","", false);
m_initialized = true;
show_status((int)MonitorStatus::MONITOR_NO_PRINTER);
@@ -530,5 +532,34 @@ Freeze();
Thaw();
}
std::string MonitorPanel::get_string_from_tab(PrinterTab tab)
{
switch (tab) {
case PT_STATUS :
return "status";
case PT_MEDIA:
return "sd_card";
case PT_UPDATE:
return "update";
case PT_HMS:
return "HMS";
case PT_DEBUG:
return "debug";
default:
return "";
}
return "";
}
void MonitorPanel::jump_to_HMS(wxCommandEvent& e)
{
if (!this->IsShown())
return;
auto page = m_tabpanel->GetCurrentPage();
if (page && page != m_hms_panel)
m_tabpanel->SetSelection(PT_HMS);
}
} // GUI
} // Slic3r
+4
View File
@@ -148,11 +148,15 @@ public:
void update_side_panel();
void show_status(int status);
std::string get_string_from_tab(PrinterTab tab);
MachineObject *obj { nullptr };
std::string last_conn_type = "undedefined";
void stop_update() {update_flag = false;};
void start_update() {update_flag = true;};
void jump_to_HMS(wxCommandEvent& e);
};
+3 -3
View File
@@ -550,7 +550,7 @@ Newer3mfVersionDialog::Newer3mfVersionDialog(wxWindow *parent, const Semver *fil
, m_new_keys(new_keys)
{
this->SetBackgroundColour(*wxWHITE);
std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") % resources_dir()).str();
std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str();
SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO));
wxBoxSizer *main_sizer = new wxBoxSizer(wxVERTICAL);
@@ -614,8 +614,8 @@ wxBoxSizer *Newer3mfVersionDialog::get_btn_sizer()
{
wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL);
horizontal_sizer->Add(0, 0, 1, wxEXPAND, 0);
StateColor btn_bg_green(std::pair<wxColour, int>(wxColour(27, 136, 68), StateColor::Pressed), std::pair<wxColour, int>(wxColour(61, 203, 115), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 174, 66), StateColor::Normal));
StateColor btn_bg_green(std::pair<wxColour, int>(wxColour(0, 137, 123), StateColor::Pressed), std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
StateColor btn_bg_white(std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Pressed), std::pair<wxColour, int>(wxColour(238, 238, 238), StateColor::Hovered),
std::pair<wxColour, int>(*wxWHITE, StateColor::Normal));
bool file_version_newer = (*m_file_version) > (*m_cloud_version);
+268
View File
@@ -0,0 +1,268 @@
#include "MultiMachine.hpp"
#include "I18N.hpp"
#include "GUI_App.hpp"
#include "MainFrame.hpp"
namespace Slic3r {
namespace GUI {
wxDEFINE_EVENT(EVT_MULTI_CLOUD_TASK_SELECTED, wxCommandEvent);
wxDEFINE_EVENT(EVT_MULTI_LOCAL_TASK_SELECTED, wxCommandEvent);
wxDEFINE_EVENT(EVT_MULTI_DEVICE_SELECTED, wxCommandEvent);
wxDEFINE_EVENT(EVT_MULTI_DEVICE_SELECTED_FINHSH, wxCommandEvent);
wxDEFINE_EVENT(EVT_MULTI_DEVICE_VIEW, wxCommandEvent);
wxDEFINE_EVENT(EVT_MULTI_REFRESH, wxCommandEvent);
DeviceItem::DeviceItem(wxWindow* parent, MachineObject* obj)
: wxWindow(parent, wxID_ANY)
, obj_(obj)
{
sync_state();
Bind(EVT_MULTI_REFRESH, &DeviceItem::on_refresh, this);
}
void DeviceItem::on_refresh(wxCommandEvent& evt)
{
Refresh();
}
void DeviceItem::sync_state()
{
if (obj_) {
state_online = obj_->is_online();
state_dev_name = obj_->dev_name;
//printable
if (obj_->print_status == "IDLE") {
state_printable = 0;
}
else if (obj_->print_status == "FINISH") {
state_printable = 1;
}
else if (obj_->print_status == "FAILED") {
state_printable = 2;
}
else if (obj_->is_in_printing()) {
state_printable = 3;
}
else {
state_printable = 6;
}
if (is_blocking_printing(obj_)) {
state_printable = 5;
}
if (obj_->is_in_upgrading()) {
state_printable = 4;
}
state_enable_ams = obj_->ams_exist_bits;
//device
if (obj_->print_status == "IDLE") {
state_device = 0;
}
else if (obj_->print_status == "FINISH") {
state_device = 1;
}
else if (obj_->print_status == "FAILED") {
state_device = 2;
}
else if (obj_->print_status == "RUNNING") {
state_device = 3;
}
else if (obj_->print_status == "PAUSE") {
state_device = 4;
}
else if (obj_->print_status == "PREPARE") {
state_device = 5;
}
else if (obj_->print_status == "SLICING") {
state_device = 6;
}
else {
state_device = 7;
}
}
}
void DeviceItem::selected()
{
if (state_selected != 2) {
state_selected = 1;
}
}
void DeviceItem::unselected()
{
if (state_selected != 2) {
state_selected = 0;
}
}
bool DeviceItem::is_blocking_printing(MachineObject* obj_)
{
DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
if (!dev) return true;
auto target_model = obj_->printer_type;
std::string source_model = "";
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
source_model = preset_bundle->printers.get_edited_preset().get_printer_type(preset_bundle);
if (source_model != target_model) {
std::vector<std::string> compatible_machine = dev->get_compatible_machine(target_model);
vector<std::string>::iterator it = find(compatible_machine.begin(), compatible_machine.end(), source_model);
if (it == compatible_machine.end()) {
return true;
}
}
return false;
}
void DeviceItem::update_item(const DeviceItem* item)
{
// Except for the selected status, everything else is updated
if (this == item)
return;
this->state_online = item->state_online;
this->state_printable = item->state_printable;
this->state_enable_ams = item->state_enable_ams;
this->state_device = item->state_device;
this->state_local_task = item->state_local_task;
}
wxString DeviceItem::get_state_printable()
{
//0-idle 1-finish 2-printing 3-upgrading 4-preset incompatible 5-unknown
std::vector<wxString> str_state_printable;
str_state_printable.push_back(_L("Idle"));
str_state_printable.push_back(_L("Idle"));
str_state_printable.push_back(_L("Idle"));
str_state_printable.push_back(_L("Printing"));
str_state_printable.push_back(_L("Upgrading"));
str_state_printable.push_back(_L("Incompatible"));
str_state_printable.push_back(_L("syncing"));
return str_state_printable[state_printable];
}
wxString DeviceItem::get_state_device()
{
//0-idle 1-finish 2-running 3-pause 4-failed 5-prepare
std::vector<wxString> str_state_device;
str_state_device.push_back(_L("Idle"));
str_state_device.push_back(_L("Printing Finish"));
str_state_device.push_back(_L("Printing Failed"));
str_state_device.push_back(_L("Printing"));
str_state_device.push_back(_L("PrintingPause"));
str_state_device.push_back(_L("Prepare"));
str_state_device.push_back(_L("Slicing"));
str_state_device.push_back(_L("syncing"));
return str_state_device[state_device];
}
wxString DeviceItem::get_local_state_task()
{
//0-padding 1-sending 2-sending finish 3-sending cancel 4-sending failed 5-Removed
std::vector<wxString> str_state_task;
str_state_task.push_back(_L("Pending"));
str_state_task.push_back(_L("Sending"));
str_state_task.push_back(_L("Sending Finish"));
str_state_task.push_back(_L("Sending Cancel"));
str_state_task.push_back(_L("Sending Failed"));
str_state_task.push_back(_L("Printing"));
str_state_task.push_back(_L("Print Success"));
str_state_task.push_back(_L("Print Failed"));
str_state_task.push_back(_L("Removed"));
str_state_task.push_back(_L("Idle"));
return str_state_task[state_local_task];
}
wxString DeviceItem::get_cloud_state_task()
{
//0-printing 1-printing finish 2-printing failed
std::vector<wxString> str_state_task;
str_state_task.push_back(_L("Printing"));
str_state_task.push_back(_L("Printing Finish"));
str_state_task.push_back(_L("Printing Failed"));
return str_state_task[state_cloud_task];
}
std::vector<DeviceItem*> selected_machines(const std::vector<DeviceItem*>& dev_item_list, std::string search_text)
{
std::vector<DeviceItem*> res;
for (const auto& item : dev_item_list) {
const MachineObject* dev = item->get_obj();
const std::string& dev_name = dev->dev_name;
const std::string& dev_ip = dev->dev_ip;
auto name_it = dev_name.find(search_text);
auto ip_it = dev_ip.find(search_text);
if (name_it != std::string::npos || ip_it != std::string::npos)
res.emplace_back(item);
}
return res;
}
SortItem::SortItem()
{
sort_map.emplace(std::make_pair(SortRule::SR_None, [this](const DeviceItem* d1, const DeviceItem* d2) {
return d1->state_dev_name > d2->state_dev_name;
}));
sort_map.emplace(std::make_pair(SortRule::SR_DEV_NAME, [this](const DeviceItem* d1, const DeviceItem* d2) {
return this->big ? d1->state_dev_name > d2->state_dev_name : d1->state_dev_name < d2->state_dev_name;
}));
sort_map.emplace(std::make_pair(SortRule::SR_ONLINE, [this](const DeviceItem* d1, const DeviceItem* d2) {
return this->big ? d1->state_online > d2->state_online : d1->state_online < d2->state_online;
}));
sort_map.emplace(std::make_pair(SortRule::SR_PRINTABLE, [this](const DeviceItem* d1, const DeviceItem* d2) {
return this->big ? d1->state_printable > d2->state_printable : d1->state_printable < d2->state_printable;
}));
sort_map.emplace(std::make_pair(SortRule::SR_EN_AMS, [this](const DeviceItem* d1, const DeviceItem* d2) {
return this->big ? d1->state_enable_ams > d2->state_enable_ams : d1->state_enable_ams < d2->state_enable_ams;
}));
sort_map.emplace(std::make_pair(SortRule::SR_DEV_STATE, [this](const DeviceItem* d1, const DeviceItem* d2) {
return this->big ? d1->state_device > d2->state_device : d1->state_device < d2->state_device;
}));
sort_map.emplace(std::make_pair(SortRule::SR_LOCAL_TASK_STATE, [this](const DeviceItem* d1, const DeviceItem* d2) {
return this->big ? d1->state_local_task > d2->state_local_task : d1->state_local_task < d2->state_local_task;
}));
sort_map.emplace(std::make_pair(SortRule::SR_CLOUD_TASK_STATE, [this](const DeviceItem* d1, const DeviceItem* d2) {
return this->big ? d1->state_cloud_task > d2->state_cloud_task : d1->state_cloud_task < d2->state_cloud_task;
}));
sort_map.emplace(std::make_pair(SortRule::SR_SEND_TIME, [this](const DeviceItem* d1, const DeviceItem* d2) {
return this->big ? d1->m_send_time > d2->m_send_time : d1->m_send_time < d2->m_send_time;
}));
}
SortItem::SortCallBack SortItem::get_call_back()
{
return sort_map[rule];
}
void SortItem::set_role(SortRule rule, bool big)
{
this->rule = rule;
this->big = big;
}
void SortItem::set_role(SortMultiMachineCB cb, SortRule rl, bool big)
{
this->cb = cb;
this->rule = rl;
this->big = big;
}
} // namespace GUI
} // namespace Slic3r
+121
View File
@@ -0,0 +1,121 @@
#ifndef slic3r_MultiMachine_hpp_
#define slic3r_MultiMachine_hpp_
#include "GUI_Utils.hpp"
#include "DeviceManager.hpp"
#include <functional>
namespace Slic3r {
namespace GUI {
#define DEVICE_ITEM_MAX_WIDTH 900
#define SEND_ITEM_MAX_HEIGHT 30
#define DEVICE_ITEM_MAX_HEIGHT 50
#define TABLE_HEAR_NORMAL_COLOUR wxColour(238, 238, 238)
#define TABLE_HEAD_PRESSED_COLOUR wxColour(150, 150, 150)
#define CTRL_BUTTON_NORMAL_COLOUR wxColour(255, 255, 255)
#define CTRL_BUTTON_PRESSEN_COLOUR wxColour(150, 150, 150)
#define TABLE_HEAD_FONT Label::Body_13
#define ICON_SIZE FromDIP(16)
class DeviceItem : public wxWindow
{
public:
MachineObject* obj_{nullptr};
int state_online = { 0 }; //0-Offline 1-Online
std::string state_dev_name; //device name
int state_printable{ 0 }; //0-idle 1-finish 2-failed 3-printing 4-upgrading 5-preset incompatible 6-unknown
int state_selected{ 0 }; //0-selected 1-unselected 2-un selectable
int state_enable_ams{ 0 };//0-no ams 1-enabled ams 2-not enabled ams
int state_device{ 0 }; //0-idle 1-finish 2-failed 3-running 4-pause 5-prepare 6-slicing 7-removed
int state_local_task{ 0 }; //0-padding 1-sending 2-sending finish 3-sending cancel 4-sending failed 5-TS_PRINT_SUCCESS 6- TS_PRINT_FAILED 7-TS_REMOVED 8-TS_IDLE
int state_cloud_task{ 0 }; //0-printing 1-printing finish 2-printing failed
int state_optional{0}; //0-Not optional 1-Optional
std::string m_send_time;
public:
DeviceItem(wxWindow* parent, MachineObject* obj);
~DeviceItem() {};
void on_refresh(wxCommandEvent& evt);
void sync_state();
wxString get_state_printable();
wxString get_state_device();
wxString get_local_state_task();
wxString get_cloud_state_task();
MachineObject* get_obj() const { return obj_; }
int get_state_online() const { return state_online; }
int get_state_printable() const { return state_printable; }
int get_state_selected() const { return state_selected; }
int get_state_enable_ams() const { return state_enable_ams; }
int get_state_device() const { return state_device; }
int get_state_local_task() const { return state_local_task; }
int get_state_cloud_task() const { return state_cloud_task; }
std::string get_state_dev_name() const { return state_dev_name; }
void selected();
void unselected();
bool is_blocking_printing(MachineObject* obj_);
void update_item(const DeviceItem* item);
};
std::vector<DeviceItem*> selected_machines(const std::vector<DeviceItem*>& dev_item_list, std::string search_text);
struct ObjState
{
std::string dev_id;
std::string state_dev_name;
int state_device{ 0 };
};
struct SortItem
{
typedef std::function<bool(DeviceItem*, DeviceItem*)> SortCallBack;
typedef std::function<bool(ObjState s1, ObjState s2) > SortMultiMachineCB;
enum SortRule : uint8_t
{
SR_None = 0,
SR_DEV_NAME = 1,
SR_ONLINE,
SR_PRINTABLE,
SR_EN_AMS,
SR_DEV_STATE,
SR_LOCAL_TASK_STATE,
SR_CLOUD_TASK_STATE,
SR_SEND_TIME,
SR_MACHINE_NAME,
SR_MACHINE_STATE,
SR_COUNT
};
SortRule rule{ SortRule::SR_None };
bool big{ true };
std::unordered_map<SortRule, SortCallBack> sort_map;
SortMultiMachineCB cb;
SortItem();
SortItem(SortRule sr) { rule = sr; }
SortCallBack get_call_back();
void set_role(SortRule rule, bool big);
void set_role(SortMultiMachineCB cb, SortRule rl, bool big);
SortMultiMachineCB get_machine_call_back() const { return cb; }
};
wxDECLARE_EVENT(EVT_MULTI_DEVICE_SELECTED, wxCommandEvent);
wxDECLARE_EVENT(EVT_MULTI_DEVICE_SELECTED_FINHSH, wxCommandEvent);
wxDECLARE_EVENT(EVT_MULTI_DEVICE_VIEW, wxCommandEvent);
wxDECLARE_EVENT(EVT_MULTI_CLOUD_TASK_SELECTED, wxCommandEvent);
wxDECLARE_EVENT(EVT_MULTI_LOCAL_TASK_SELECTED, wxCommandEvent);
wxDECLARE_EVENT(EVT_MULTI_REFRESH, wxCommandEvent);
} // namespace GUI
} // namespace Slic3r
#endif
+725
View File
@@ -0,0 +1,725 @@
#include "MultiMachineManagerPage.hpp"
#include "GUI_App.hpp"
#include "MainFrame.hpp"
namespace Slic3r {
namespace GUI {
MultiMachineItem::MultiMachineItem(wxWindow* parent, MachineObject* obj)
: DeviceItem(parent, obj)
{
SetBackgroundColour(*wxWHITE);
SetMinSize(wxSize(FromDIP(DEVICE_ITEM_MAX_WIDTH), FromDIP(DEVICE_ITEM_MAX_HEIGHT)));
SetMaxSize(wxSize(FromDIP(DEVICE_ITEM_MAX_WIDTH), FromDIP(DEVICE_ITEM_MAX_HEIGHT)));
Bind(wxEVT_PAINT, &MultiMachineItem::paintEvent, this);
Bind(wxEVT_ENTER_WINDOW, &MultiMachineItem::OnEnterWindow, this);
Bind(wxEVT_LEAVE_WINDOW, &MultiMachineItem::OnLeaveWindow, this);
Bind(wxEVT_LEFT_DOWN, &MultiMachineItem::OnLeftDown, this);
Bind(wxEVT_MOTION, &MultiMachineItem::OnMove, this);
Bind(EVT_MULTI_DEVICE_VIEW, [this, obj](auto& e) {
wxGetApp().mainframe->jump_to_monitor(obj->dev_id);
if (wxGetApp().mainframe->m_monitor->get_status_panel()->get_media_play_ctrl()) {
wxGetApp().mainframe->m_monitor->get_status_panel()->get_media_play_ctrl()->jump_to_play();
}
});
wxGetApp().UpdateDarkUIWin(this);
}
void MultiMachineItem::OnEnterWindow(wxMouseEvent& evt)
{
m_hover = true;
Refresh();
}
void MultiMachineItem::OnLeaveWindow(wxMouseEvent& evt)
{
m_hover = false;
Refresh();
}
void MultiMachineItem::OnLeftDown(wxMouseEvent& evt)
{
int left = FromDIP(DEVICE_LEFT_PADDING_LEFT +
DEVICE_LEFT_DEV_NAME +
DEVICE_LEFT_PRO_NAME +
DEVICE_LEFT_PRO_INFO);
auto mouse_pos = ClientToScreen(evt.GetPosition());
auto item = this->ClientToScreen(wxPoint(0, 0));
if (mouse_pos.x > (item.x + left) &&
mouse_pos.x < (item.x + left + FromDIP(90)) &&
mouse_pos.y > item.y &&
mouse_pos.y < (item.y + DEVICE_ITEM_MAX_HEIGHT)) {
post_event(wxCommandEvent(EVT_MULTI_DEVICE_VIEW));
}
}
void MultiMachineItem::OnMove(wxMouseEvent& evt)
{
int left = FromDIP(DEVICE_LEFT_PADDING_LEFT +
DEVICE_LEFT_DEV_NAME +
DEVICE_LEFT_PRO_NAME +
DEVICE_LEFT_PRO_INFO);
auto mouse_pos = ClientToScreen(evt.GetPosition());
auto item = this->ClientToScreen(wxPoint(0, 0));
if (mouse_pos.x > (item.x + left) &&
mouse_pos.x < (item.x + left + FromDIP(90)) &&
mouse_pos.y > item.y &&
mouse_pos.y < (item.y + DEVICE_ITEM_MAX_HEIGHT)) {
SetCursor(wxCURSOR_HAND);
}
else {
SetCursor(wxCURSOR_ARROW);
}
}
void MultiMachineItem::paintEvent(wxPaintEvent& evt)
{
wxPaintDC dc(this);
render(dc);
}
void MultiMachineItem::render(wxDC& dc)
{
#ifdef __WXMSW__
wxSize size = GetSize();
wxMemoryDC memdc;
wxBitmap bmp(size.x, size.y);
memdc.SelectObject(bmp);
memdc.Blit({ 0, 0 }, size, &dc, { 0, 0 });
{
wxGCDC dc2(memdc);
doRender(dc2);
}
memdc.SelectObject(wxNullBitmap);
dc.DrawBitmap(bmp, 0, 0);
#else
doRender(dc);
#endif
}
void MultiMachineItem::DrawTextWithEllipsis(wxDC& dc, const wxString& text, int maxWidth, int left, int top) {
wxSize size = GetSize();
wxFont font = dc.GetFont();
wxSize textSize = dc.GetTextExtent(text);
dc.SetTextForeground(StateColor::darkModeColorFor(wxColour(50, 58, 61)));
int textWidth = textSize.GetWidth();
if (textWidth > maxWidth) {
wxString truncatedText = text;
int ellipsisWidth = dc.GetTextExtent("...").GetWidth();
int numChars = text.length();
for (int i = numChars - 1; i >= 0; --i) {
truncatedText = text.substr(0, i) + "...";
int truncatedWidth = dc.GetTextExtent(truncatedText).GetWidth();
if (truncatedWidth <= maxWidth - ellipsisWidth) {
break;
}
}
if (top == 0) {
dc.DrawText(truncatedText, left, (size.y - textSize.y) / 2);
}
else {
dc.DrawText(truncatedText, left, (size.y - textSize.y) / 2 - top);
}
}
else {
if (top == 0) {
dc.DrawText(text, left, (size.y - textSize.y) / 2);
}
else {
dc.DrawText(text, left, (size.y - textSize.y) / 2 - top);
}
}
}
void MultiMachineItem::doRender(wxDC& dc)
{
wxSize size = GetSize();
dc.SetPen(wxPen(*wxBLACK));
int left = FromDIP(DEVICE_LEFT_PADDING_LEFT);
if (obj_) {
//dev name
wxString dev_name = wxString::FromUTF8(obj_->dev_name);
if (!obj_->is_online()) {
dev_name = dev_name + "(" + _L("Offline") + ")";
}
dc.SetFont(Label::Body_13);
DrawTextWithEllipsis(dc, dev_name, FromDIP(DEVICE_LEFT_DEV_NAME), left);
left += FromDIP(DEVICE_LEFT_DEV_NAME);
//project name
wxString project_name = _L("No task");
if (obj_->is_in_printing()) {
project_name = wxString::Format("%s", GUI::from_u8(obj_->subtask_name));
}
dc.SetFont(Label::Body_13);
DrawTextWithEllipsis(dc, project_name, FromDIP(DEVICE_LEFT_PRO_NAME), left);
left += FromDIP(DEVICE_LEFT_PRO_NAME);
//state
dc.SetFont(Label::Body_13);
if (state_device == 0) {
dc.SetTextForeground(*wxBLACK);
DrawTextWithEllipsis(dc, get_state_device(), FromDIP(DEVICE_LEFT_PRO_INFO), left);
}
else if (state_device == 1) {
dc.SetTextForeground(wxColour(0,174,66));
DrawTextWithEllipsis(dc, get_state_device(), FromDIP(DEVICE_LEFT_PRO_INFO), left);
}
else if (state_device == 2)
{
dc.SetTextForeground(wxColour(208,27,27));
DrawTextWithEllipsis(dc, get_state_device(), FromDIP(DEVICE_LEFT_PRO_INFO), left);
}
else if (state_device > 2 && state_device < 7) {
dc.SetFont(Label::Body_12);
dc.SetTextForeground(wxColour(0, 150, 136));
if (obj_->get_curr_stage().IsEmpty() && obj_->subtask_) {
//wxString layer_info = wxString::Format(_L("Layer: %d/%d"), obj_->curr_layer, obj_->total_layers);
wxString progress_info = wxString::Format("%d", obj_->subtask_->task_progress);
wxString left_time = wxString::Format("%s", get_left_time(obj_->mc_left_time));
DrawTextWithEllipsis(dc, progress_info + "% | " + left_time, FromDIP(DEVICE_LEFT_PRO_INFO), left, FromDIP(10));
dc.SetPen(wxPen(wxColour(233,233,233)));
dc.SetBrush(wxBrush(wxColour(233,233,233)));
dc.DrawRoundedRectangle(left, FromDIP(30), FromDIP(DEVICE_LEFT_PRO_INFO), FromDIP(10), 2);
dc.SetPen(wxPen(wxColour(0, 150, 136)));
dc.SetBrush(wxBrush(wxColour(0, 150, 136)));
dc.DrawRoundedRectangle(left, FromDIP(30), FromDIP(DEVICE_LEFT_PRO_INFO) * (static_cast<float>(obj_->subtask_->task_progress) / 100.0f), FromDIP(10), 2);
}
else {
DrawTextWithEllipsis(dc, obj_->get_curr_stage(), FromDIP(DEVICE_LEFT_PRO_INFO), left);
}
}
else {
dc.SetTextForeground(*wxBLACK);
DrawTextWithEllipsis(dc, get_state_device(), FromDIP(DEVICE_LEFT_PRO_INFO), left);
}
left += FromDIP(DEVICE_LEFT_PRO_INFO);
//button
dc.SetPen(wxPen(wxColour(38, 46, 48)));
dc.SetBrush(wxBrush(wxColour(*wxWHITE)));
dc.DrawRoundedRectangle(left, (size.y - FromDIP(38)) / 2, FromDIP(90), FromDIP(38), 6);
dc.SetFont(Label::Body_14);
dc.SetTextForeground(*wxBLACK);
dc.DrawText(_L("View"),left + FromDIP(90) / 2 - dc.GetTextExtent(_L("View")).x / 2, (size.y -dc.GetTextExtent(_L("View")).y) / 2);
}
if (m_hover) {
dc.SetPen(wxPen(wxColour(0, 150, 136)));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRoundedRectangle(0, 0, size.x, size.y, 3);
}
}
void MultiMachineItem::post_event(wxCommandEvent&& event)
{
event.SetEventObject(this);
event.SetString(obj_->dev_id);
event.SetInt(state_selected);
wxPostEvent(this, event);
}
void MultiMachineItem::DoSetSize(int x, int y, int width, int height, int sizeFlags /*= wxSIZE_AUTO*/)
{
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
}
wxString MultiMachineItem::get_left_time(int mc_left_time)
{
// update gcode progress
std::string left_time;
wxString left_time_text = _L("N/A");
try {
left_time = get_bbl_monitor_time_dhm(mc_left_time);
}
catch (...) {
;
}
if (!left_time.empty()) left_time_text = wxString::Format("-%s", left_time);
return left_time_text;
}
MultiMachineManagerPage::MultiMachineManagerPage(wxWindow* parent)
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL)
{
#ifdef __WINDOWS__
SetDoubleBuffered(true);
#endif //__WINDOWS__
SetBackgroundColour(wxColour(0xEEEEEE));
m_main_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
m_main_panel->SetBackgroundColour(*wxWHITE);
m_main_sizer = new wxBoxSizer(wxVERTICAL);
StateColor head_bg(
std::pair<wxColour, int>(TABLE_HEAD_PRESSED_COLOUR, StateColor::Pressed),
std::pair<wxColour, int>(TABLE_HEAR_NORMAL_COLOUR, StateColor::Normal)
);
//edit prints
auto m_btn_bg_enable = StateColor(
std::pair<wxColour, int>(wxColour(0, 137, 123), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal)
);
StateColor clean_bg(std::pair<wxColour, int>(wxColour(255, 255, 255), StateColor::Disabled), std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(238, 238, 238), StateColor::Hovered), std::pair<wxColour, int>(wxColour(255, 255, 255), StateColor::Enabled),
std::pair<wxColour, int>(wxColour(255, 255, 255), StateColor::Normal));
StateColor clean_bd(std::pair<wxColour, int>(wxColour(144, 144, 144), StateColor::Disabled), std::pair<wxColour, int>(wxColour(38, 46, 48), StateColor::Enabled));
StateColor clean_text(std::pair<wxColour, int>(wxColour(144, 144, 144), StateColor::Disabled), std::pair<wxColour, int>(wxColour(38, 46, 48), StateColor::Enabled));
auto sizer_button_printer = new wxBoxSizer(wxHORIZONTAL);
sizer_button_printer->SetMinSize(wxSize(FromDIP(DEVICE_ITEM_MAX_WIDTH), -1));
m_button_edit = new Button(m_main_panel, _L("Edit Printers"));
m_button_edit->SetBackgroundColor(clean_bg);
m_button_edit->SetBorderColor(clean_bd);
m_button_edit->SetTextColor(clean_text);
m_button_edit->SetFont(Label::Body_12);
m_button_edit->SetCornerRadius(6);
m_button_edit->SetMinSize(wxSize(FromDIP(90), FromDIP(36)));
m_button_edit->SetMaxSize(wxSize(FromDIP(90), FromDIP(36)));
m_button_edit->Bind(wxEVT_BUTTON, [this](wxCommandEvent& evt) {
MultiMachinePickPage dlg;
dlg.ShowModal();
refresh_user_device();
evt.Skip();
});
sizer_button_printer->Add( 0, 0, 1, wxEXPAND, 5 );
sizer_button_printer->Add(m_button_edit, 0, wxALIGN_CENTER, 0);
m_table_head_panel = new wxPanel(m_main_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_table_head_panel->SetMinSize(wxSize(FromDIP(DEVICE_ITEM_MAX_WIDTH), -1));
m_table_head_panel->SetMaxSize(wxSize(FromDIP(DEVICE_ITEM_MAX_WIDTH), -1));
m_table_head_panel->SetBackgroundColour(TABLE_HEAR_NORMAL_COLOUR);
m_table_head_sizer = new wxBoxSizer(wxHORIZONTAL);
m_printer_name = new Button(m_table_head_panel, _L("Device Name"), "toolbar_double_directional_arrow", wxNO_BORDER, ICON_SIZE);
m_printer_name->SetBackgroundColor(head_bg);
m_printer_name->SetFont(TABLE_HEAD_FONT);
m_printer_name->SetCornerRadius(0);
m_printer_name->SetMinSize(wxSize(FromDIP(DEVICE_LEFT_DEV_NAME), FromDIP(DEVICE_ITEM_MAX_HEIGHT)));
m_printer_name->SetMaxSize(wxSize(FromDIP(DEVICE_LEFT_DEV_NAME), FromDIP(DEVICE_ITEM_MAX_HEIGHT)));
m_printer_name->SetCenter(false);
m_printer_name->Bind(wxEVT_ENTER_WINDOW, [&](wxMouseEvent& evt) {
SetCursor(wxCURSOR_HAND);
});
m_printer_name->Bind(wxEVT_LEAVE_WINDOW, [&](wxMouseEvent& evt) {
SetCursor(wxCURSOR_ARROW);
});
m_printer_name->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& evt) {
device_dev_name_big = !device_dev_name_big;
auto sortcb = [this](ObjState s1, ObjState s2) {
return device_dev_name_big ? s1.state_dev_name > s2.state_dev_name : s1.state_dev_name < s2.state_dev_name;
};
this->m_sort.set_role(sortcb, SortItem::SR_MACHINE_NAME, device_dev_name_big);
this->refresh_user_device();
});
m_task_name = new Button(m_table_head_panel, _L("Task Name"), "", wxNO_BORDER, ICON_SIZE);
m_task_name->SetBackgroundColor(TABLE_HEAR_NORMAL_COLOUR);
m_task_name->SetFont(TABLE_HEAD_FONT);
m_task_name->SetCornerRadius(0);
m_task_name->SetMinSize(wxSize(FromDIP(DEVICE_LEFT_DEV_NAME), FromDIP(DEVICE_ITEM_MAX_HEIGHT)));
m_task_name->SetMaxSize(wxSize(FromDIP(DEVICE_LEFT_DEV_NAME), FromDIP(DEVICE_ITEM_MAX_HEIGHT)));
m_task_name->SetCenter(false);
m_status = new Button(m_table_head_panel, _L("Device Status"), "toolbar_double_directional_arrow", wxNO_BORDER, ICON_SIZE);
m_status->SetBackgroundColor(head_bg);
m_status->SetFont(TABLE_HEAD_FONT);
m_status->SetCornerRadius(0);
m_status->SetMinSize(wxSize(FromDIP(DEVICE_LEFT_PRO_INFO), FromDIP(DEVICE_ITEM_MAX_HEIGHT)));
m_status->SetMaxSize(wxSize(FromDIP(DEVICE_LEFT_PRO_INFO), FromDIP(DEVICE_ITEM_MAX_HEIGHT)));
m_status->SetCenter(false);
m_status->Bind(wxEVT_ENTER_WINDOW, [&](wxMouseEvent& evt) {
SetCursor(wxCURSOR_HAND);
});
m_status->Bind(wxEVT_LEAVE_WINDOW, [&](wxMouseEvent& evt) {
SetCursor(wxCURSOR_ARROW);
});
m_status->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& evt) {
device_state_big = !device_state_big;
auto sortcb = [this](ObjState s1, ObjState s2) {
return device_state_big ? s1.state_device > s2.state_device : s1.state_device < s2.state_device;
};
this->m_sort.set_role(sortcb, SortItem::SortRule::SR_MACHINE_STATE, device_state_big);
this->refresh_user_device();
});
m_action = new Button(m_table_head_panel, _L("Actions"), "", wxNO_BORDER, ICON_SIZE, false);
m_action->SetBackgroundColor(TABLE_HEAR_NORMAL_COLOUR);
m_action->SetFont(TABLE_HEAD_FONT);
m_action->SetCornerRadius(0);
m_action->SetMinSize(wxSize(FromDIP(DEVICE_LEFT_PRO_NAME), FromDIP(DEVICE_ITEM_MAX_HEIGHT)));
m_action->SetMaxSize(wxSize(FromDIP(DEVICE_LEFT_PRO_NAME), FromDIP(DEVICE_ITEM_MAX_HEIGHT)));
m_action->SetCenter(false);
m_table_head_sizer->AddSpacer(FromDIP(DEVICE_LEFT_PADDING_LEFT));
m_table_head_sizer->Add(m_printer_name, 0, wxALIGN_CENTER_VERTICAL, 0);
m_table_head_sizer->Add(m_task_name, 0, wxALIGN_CENTER_VERTICAL, 0);
m_table_head_sizer->Add(m_status, 0, wxALIGN_CENTER_VERTICAL, 0);
m_table_head_sizer->Add(m_action, 0, wxLEFT, 0);
m_table_head_panel->SetSizer(m_table_head_sizer);
m_table_head_panel->Layout();
m_tip_text = new wxStaticText(m_main_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
m_tip_text->SetMinSize(wxSize(FromDIP(DEVICE_ITEM_MAX_WIDTH), -1));
m_tip_text->SetMaxSize(wxSize(FromDIP(DEVICE_ITEM_MAX_WIDTH), -1));
m_tip_text->SetLabel(_L("Please select the devices you would like to manage here (up to 6 devices)"));
m_tip_text->SetForegroundColour(wxColour(50, 58, 61));
m_tip_text->SetFont(::Label::Head_20);
m_tip_text->Wrap(-1);
m_button_add = new Button(m_main_panel, _L("Add"));
m_button_add->SetBackgroundColor(m_btn_bg_enable);
m_button_add->SetBorderColor(m_btn_bg_enable);
m_button_add->SetTextColor(*wxWHITE);
m_button_add->SetFont(Label::Body_12);
m_button_add->SetCornerRadius(6);
m_button_add->SetMinSize(wxSize(FromDIP(90), FromDIP(36)));
m_button_add->SetMaxSize(wxSize(FromDIP(90), FromDIP(36)));
m_button_add->Bind(wxEVT_BUTTON, [this](wxCommandEvent& evt) {
MultiMachinePickPage dlg;
dlg.ShowModal();
refresh_user_device();
evt.Skip();
});
m_machine_list = new wxScrolledWindow(m_main_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_machine_list->SetBackgroundColour(*wxWHITE);
m_machine_list->SetScrollRate(0, 5);
m_machine_list->SetMinSize(wxSize(FromDIP(DEVICE_ITEM_MAX_WIDTH), 10 * FromDIP(DEVICE_ITEM_MAX_HEIGHT)));
m_machine_list->SetMaxSize(wxSize(FromDIP(DEVICE_ITEM_MAX_WIDTH), 10 * FromDIP(DEVICE_ITEM_MAX_HEIGHT)));
m_sizer_machine_list = new wxBoxSizer(wxVERTICAL);
m_machine_list->SetSizer(m_sizer_machine_list);
m_machine_list->Layout();
// add flipping page
StateColor ctrl_bg(
std::pair<wxColour, int>(CTRL_BUTTON_PRESSEN_COLOUR, StateColor::Pressed),
std::pair<wxColour, int>(CTRL_BUTTON_NORMAL_COLOUR, StateColor::Normal)
);
m_flipping_panel = new wxPanel(m_main_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize);
m_flipping_panel->SetMinSize(wxSize(FromDIP(DEVICE_ITEM_MAX_WIDTH), -1));
m_flipping_panel->SetMaxSize(wxSize(FromDIP(DEVICE_ITEM_MAX_WIDTH), -1));
m_flipping_panel->SetBackgroundColour(*wxWHITE);
m_flipping_page_sizer = new wxBoxSizer(wxHORIZONTAL);
m_page_sizer = new wxBoxSizer(wxVERTICAL);
btn_last_page = new Button(m_flipping_panel, "", "go_last_plate", 0, FromDIP(20));
btn_last_page->SetMinSize(wxSize(FromDIP(20), FromDIP(20)));
btn_last_page->SetMaxSize(wxSize(FromDIP(20), FromDIP(20)));
btn_last_page->SetBackgroundColor(head_bg);
btn_last_page->Bind(wxEVT_LEFT_DOWN, [&](wxMouseEvent& evt) {
evt.Skip();
if (m_current_page == 0)
return;
btn_last_page->Enable(false);
btn_next_page->Enable(false);
start_timer();
m_current_page--;
if (m_current_page < 0)
m_current_page = 0;
refresh_user_device();
update_page_number();
});
st_page_number = new wxStaticText(m_flipping_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize);
btn_next_page = new Button(m_flipping_panel, "", "go_next_plate", 0, FromDIP(20));
btn_next_page->SetMinSize(wxSize(FromDIP(20), FromDIP(20)));
btn_next_page->SetMaxSize(wxSize(FromDIP(20), FromDIP(20)));
btn_next_page->SetBackgroundColor(head_bg);
btn_next_page->Bind(wxEVT_LEFT_DOWN, [&](wxMouseEvent& evt) {
evt.Skip();
if (m_current_page == m_total_page - 1)
return;
btn_last_page->Enable(false);
btn_next_page->Enable(false);
start_timer();
m_current_page++;
if (m_current_page > m_total_page - 1)
m_current_page = m_total_page - 1;
refresh_user_device();
update_page_number();
});
m_page_num_input = new ::TextInput(m_flipping_panel, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(50), -1), wxTE_PROCESS_ENTER);
StateColor input_bg(std::pair<wxColour, int>(wxColour("#F0F0F1"), StateColor::Disabled), std::pair<wxColour, int>(*wxWHITE, StateColor::Enabled));
m_page_num_input->SetBackgroundColor(input_bg);
m_page_num_input->GetTextCtrl()->SetValue("1");
wxTextValidator validator(wxFILTER_DIGITS);
m_page_num_input->GetTextCtrl()->SetValidator(validator);
m_page_num_input->GetTextCtrl()->Bind(wxEVT_TEXT_ENTER, [&](wxCommandEvent& e) {
page_num_enter_evt();
});
m_page_num_enter = new Button(m_flipping_panel, _("Go"));
m_page_num_enter->SetMinSize(wxSize(FromDIP(25), FromDIP(25)));
m_page_num_enter->SetMaxSize(wxSize(FromDIP(25), FromDIP(25)));
m_page_num_enter->SetBackgroundColor(ctrl_bg);
m_page_num_enter->SetCornerRadius(FromDIP(5));
m_page_num_enter->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [&](auto& evt) {
page_num_enter_evt();
});
m_flipping_page_sizer->Add(0, 0, 1, wxEXPAND, 0);
m_flipping_page_sizer->Add(btn_last_page, 0, wxALIGN_CENTER, 0);
m_flipping_page_sizer->Add(st_page_number, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, FromDIP(5));
m_flipping_page_sizer->Add(btn_next_page, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, FromDIP(5));
m_flipping_page_sizer->Add(m_page_num_input, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, FromDIP(20));
m_flipping_page_sizer->Add(m_page_num_enter, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, FromDIP(5));
m_page_sizer->Add(m_flipping_page_sizer, 0, wxALIGN_CENTER_HORIZONTAL, FromDIP(5));
m_flipping_panel->SetSizer(m_page_sizer);
m_flipping_panel->Layout();
m_main_sizer->AddSpacer(FromDIP(16));
m_main_sizer->Add(sizer_button_printer, 0, wxALIGN_CENTER_HORIZONTAL, 0);
m_main_sizer->AddSpacer(FromDIP(5));
m_main_sizer->Add(m_table_head_panel, 0, wxALIGN_CENTER_HORIZONTAL, 0);
m_main_sizer->Add(m_tip_text, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, FromDIP(50));
m_main_sizer->Add(m_button_add, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, FromDIP(16));
m_main_sizer->Add(m_machine_list, 0, wxALIGN_CENTER_HORIZONTAL, 0);
m_main_sizer->Add(m_flipping_panel, 0, wxALIGN_CENTER_HORIZONTAL, 0);
m_main_panel->SetSizer(m_main_sizer);
m_main_panel->Layout();
page_sizer = new wxBoxSizer(wxVERTICAL);
page_sizer->Add(m_main_panel, 1, wxALL | wxEXPAND, FromDIP(25));
SetSizer(page_sizer);
Layout();
Fit();
Bind(wxEVT_TIMER, &MultiMachineManagerPage::on_timer, this);
}
void MultiMachineManagerPage::update_page()
{
for (int i = 0; i < m_device_items.size(); i++) {
m_device_items[i]->sync_state();
m_device_items[i]->Refresh();
}
}
void MultiMachineManagerPage::refresh_user_device(bool clear)
{
m_sizer_machine_list->Clear(true);
m_device_items.clear();
if(clear) return;
Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
if (!dev) return;
auto all_machine = dev->get_my_cloud_machine_list();
auto user_machine = std::map<std::string, MachineObject*>();
//selected machine
for (int i = 0; i < PICK_DEVICE_MAX; i++) {
auto dev_id = wxGetApp().app_config->get("multi_devices", std::to_string(i));
if (all_machine.count(dev_id) > 0) {
user_machine[dev_id] = all_machine[dev_id];
}
}
m_total_count = user_machine.size();
m_state_objs.clear();
for (auto it = user_machine.begin(); it != user_machine.end(); ++it) {
sync_state(it->second);
}
//sort
if (m_sort.rule != SortItem::SortRule::SR_None) {
std::sort(m_state_objs.begin(), m_state_objs.end(), m_sort.get_machine_call_back());
}
double result = static_cast<double>(user_machine.size()) / m_count_page_item;
m_total_page = std::ceil(result);
std::vector<ObjState> sort_devices = extractRange(m_state_objs, m_current_page * m_count_page_item, (m_current_page + 1) * m_count_page_item - 1 );
std::vector<std::string> subscribe_list;
for (auto i = 0; i < sort_devices.size(); ++i) {
auto dev_id = sort_devices[i].dev_id;
auto machine = user_machine[dev_id];
MultiMachineItem* di = new MultiMachineItem(m_machine_list, machine);
m_device_items.push_back(di);
m_sizer_machine_list->Add(m_device_items[i], 0, wxALL | wxEXPAND, 0);
subscribe_list.push_back(dev_id);
}
dev->subscribe_device_list(subscribe_list);
m_tip_text->Show(m_device_items.empty());
m_button_add->Show(m_device_items.empty());
update_page_number();
m_flipping_panel->Show(m_total_page > 1);
m_sizer_machine_list->Layout();
Layout();
}
std::vector<ObjState> MultiMachineManagerPage::extractRange(const std::vector<ObjState>& source, int start, int end) {
std::vector<ObjState> result;
if (start < 0 || start > end || source.size() <= 0) {
return result;
}
if ( end >= source.size() ) {
end = source.size();
}
auto startIter = source.begin() + start;
auto endIter = source.begin() + end;
result.assign(startIter, endIter);
return result;
}
void MultiMachineManagerPage::sync_state(MachineObject* obj_)
{
ObjState state_obj;
if (obj_) {
state_obj.dev_id = obj_->dev_id;
state_obj.state_dev_name = obj_->dev_name;
if (obj_->print_status == "IDLE") {
state_obj.state_device = 0;
}
else if (obj_->print_status == "FINISH") {
state_obj.state_device = 1;
}
else if (obj_->print_status == "FAILED") {
state_obj.state_device = 2;
}
else if (obj_->print_status == "RUNNING") {
state_obj.state_device = 3;
}
else if (obj_->print_status == "PAUSE") {
state_obj.state_device = 4;
}
else if (obj_->print_status == "PREPARE") {
state_obj.state_device = 5;
}
else if (obj_->print_status == "SLICING") {
state_obj.state_device = 6;
}
else {
state_obj.state_device = 7;
}
}
m_state_objs.push_back(state_obj);
}
bool MultiMachineManagerPage::Show(bool show)
{
if (show) {
refresh_user_device();
}
else {
Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
if (dev) {
dev->subscribe_device_list(std::vector<std::string>());
}
}
return wxPanel::Show(show);
}
void MultiMachineManagerPage::start_timer()
{
if (m_flipping_timer) {
m_flipping_timer->Stop();
}
else {
m_flipping_timer = new wxTimer();
}
m_flipping_timer->SetOwner(this);
m_flipping_timer->Start(1000);
wxPostEvent(this, wxTimerEvent());
}
void MultiMachineManagerPage::update_page_number()
{
double result = static_cast<double>(m_total_count) / m_count_page_item;
m_total_page = std::ceil(result);
wxString number = wxString(std::to_string(m_current_page + 1)) + " / " + wxString(std::to_string(m_total_page));
st_page_number->SetLabel(number);
}
void MultiMachineManagerPage::on_timer(wxTimerEvent& event)
{
m_flipping_timer->Stop();
if (btn_last_page)
btn_last_page->Enable(true);
if (btn_next_page)
btn_next_page->Enable(true);
}
void MultiMachineManagerPage::clear_page()
{
}
void MultiMachineManagerPage::page_num_enter_evt()
{
btn_last_page->Enable(false);
btn_next_page->Enable(false);
start_timer();
auto value = m_page_num_input->GetTextCtrl()->GetValue();
long page_num = 0;
if (value.ToLong(&page_num)) {
if (page_num > m_total_page)
m_current_page = m_total_page - 1;
else if (page_num < 1)
m_current_page = 0;
else
m_current_page = page_num - 1;
}
refresh_user_device();
update_page_number();
}
} // namespace GUI
} // namespace Slic3r
+114
View File
@@ -0,0 +1,114 @@
#ifndef slic3r_MultiMachineMangerPage_hpp_
#define slic3r_MultiMachineMangerPage_hpp_
#include "GUI_Utils.hpp"
#include "MultiMachine.hpp"
namespace Slic3r {
namespace GUI {
#define DEVICE_LEFT_PADDING_LEFT 15
#define DEVICE_LEFT_DEV_NAME 180
#define DEVICE_LEFT_PRO_NAME 180
#define DEVICE_LEFT_PRO_INFO 320
class MultiMachineItem : public DeviceItem
{
public:
MultiMachineItem(wxWindow* parent, MachineObject* obj);
~MultiMachineItem() {};
void OnEnterWindow(wxMouseEvent& evt);
void OnLeaveWindow(wxMouseEvent& evt);
void OnLeftDown(wxMouseEvent& evt);
void OnMove(wxMouseEvent& evt);
void paintEvent(wxPaintEvent& evt);
void render(wxDC& dc);
void DrawTextWithEllipsis(wxDC& dc, const wxString& text, int maxWidth, int left, int top = 0);
void doRender(wxDC& dc);
void post_event(wxCommandEvent&& event);
virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO);
public:
bool m_hover{ false };
ScalableBitmap m_bitmap_check_disable;
ScalableBitmap m_bitmap_check_off;
ScalableBitmap m_bitmap_check_on;
wxString get_left_time(int mc_left_time);
};
class MultiMachineManagerPage : public wxPanel
{
public:
MultiMachineManagerPage(wxWindow* parent);
~MultiMachineManagerPage() {};
void update_page();
void refresh_user_device(bool clear = false);
void sync_state(MachineObject* obj_);
bool Show(bool show);
std::vector<ObjState> extractRange(const std::vector<ObjState>& source, int start, int end);
void start_timer();
void update_page_number();
void on_timer(wxTimerEvent& event);
void clear_page();
void page_num_enter_evt();
private:
std::vector<ObjState> m_state_objs;
std::vector<MultiMachineItem*> m_device_items;
SortItem m_sort;
bool device_dev_name_big{ true };
bool device_state_big{ true };
Button* m_button_edit{nullptr};
wxBoxSizer* page_sizer{ nullptr };
wxPanel* m_main_panel{ nullptr };
wxBoxSizer* m_main_sizer{nullptr};
wxBoxSizer* m_sizer_machine_list{nullptr};
wxScrolledWindow* m_machine_list{ nullptr };
wxStaticText* m_selected_num{ nullptr };
// table head
wxPanel* m_table_head_panel{ nullptr };
wxBoxSizer* m_table_head_sizer{ nullptr };
Button* m_printer_name{ nullptr };
Button* m_task_name{ nullptr };
Button* m_status{ nullptr };
Button* m_action{ nullptr };
Button* m_stop_all_botton{nullptr};
// tip when no device
wxStaticText* m_tip_text{ nullptr };
Button* m_button_add{ nullptr };
// Flipping pages
int m_current_page{ 0 };
int m_total_page{ 0 };
int m_total_count{ 0 };
int m_count_page_item{ 10 };
bool prev{ false };
bool next{ false };
Button* btn_last_page{ nullptr };
Button* btn_next_page{ nullptr };
wxStaticText* st_page_number{ nullptr };
wxBoxSizer* m_flipping_page_sizer{ nullptr };
wxBoxSizer* m_page_sizer{ nullptr };
wxPanel* m_flipping_panel{ nullptr };
wxTimer* m_flipping_timer{ nullptr };
TextInput* m_page_num_input{ nullptr };
Button* m_page_num_enter{ nullptr };
};
} // namespace GUI
} // namespace Slic3r
#endif
+485
View File
@@ -0,0 +1,485 @@
#include "MultiMachinePage.hpp"
#include "GUI_App.hpp"
#include "MainFrame.hpp"
namespace Slic3r {
namespace GUI {
MultiMachinePage::MultiMachinePage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
: wxPanel(parent, id, pos, size, style)
{
init_tabpanel();
m_main_sizer = new wxBoxSizer(wxHORIZONTAL);
m_main_sizer->Add(m_tabpanel, 1, wxEXPAND | wxLEFT, 0);
SetSizerAndFit(m_main_sizer);
Layout();
Fit();
wxGetApp().UpdateDarkUIWin(this);
init_timer();
Bind(wxEVT_TIMER, &MultiMachinePage::on_timer, this);
}
MultiMachinePage::~MultiMachinePage()
{
if (m_refresh_timer)
m_refresh_timer->Stop();
delete m_refresh_timer;
}
void MultiMachinePage::jump_to_send_page()
{
m_tabpanel->SetSelection(1);
}
void MultiMachinePage::on_sys_color_changed()
{
}
void MultiMachinePage::msw_rescale()
{
}
bool MultiMachinePage::Show(bool show)
{
if (show) {
m_refresh_timer->Stop();
m_refresh_timer->SetOwner(this);
m_refresh_timer->Start(2000);
wxPostEvent(this, wxTimerEvent());
}
else {
m_refresh_timer->Stop();
}
auto page = m_tabpanel->GetCurrentPage();
if (page)
page->Show(show);
return wxPanel::Show(show);
}
void MultiMachinePage::init_tabpanel()
{
auto m_side_tools = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(220), FromDIP(18)));
wxBoxSizer* sizer_side_tools = new wxBoxSizer(wxHORIZONTAL);
sizer_side_tools->Add(m_side_tools, 1, wxEXPAND, 0);
m_tabpanel = new Tabbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, sizer_side_tools, wxNB_LEFT | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME);
m_tabpanel->SetBackgroundColour(wxColour("#FEFFFF"));
m_tabpanel->Bind(wxEVT_BOOKCTRL_PAGE_CHANGED, [this](wxBookCtrlEvent& e) {; });
m_local_task_manager = new LocalTaskManagerPage(m_tabpanel);
m_cloud_task_manager = new CloudTaskManagerPage(m_tabpanel);
m_machine_manager = new MultiMachineManagerPage(m_tabpanel);
m_tabpanel->AddPage(m_machine_manager, _L("Device"), "", true);
m_tabpanel->AddPage(m_local_task_manager, _L("Task Sending"), "", false);
m_tabpanel->AddPage(m_cloud_task_manager, _L("Task Sent"), "", false);
}
void MultiMachinePage::init_timer()
{
m_refresh_timer = new wxTimer();
//m_refresh_timer->SetOwner(this);
//m_refresh_timer->Start(8000);
//wxPostEvent(this, wxTimerEvent());
}
void MultiMachinePage::on_timer(wxTimerEvent& event)
{
m_local_task_manager->update_page();
m_cloud_task_manager->update_page();
m_machine_manager->update_page();
}
void MultiMachinePage::clear_page()
{
m_local_task_manager->refresh_user_device(true);
m_cloud_task_manager->refresh_user_device(true);
m_machine_manager->refresh_user_device(true);
}
DevicePickItem::DevicePickItem(wxWindow* parent, MachineObject* obj)
: DeviceItem(parent, obj)
{
SetBackgroundColour(*wxWHITE);
m_bitmap_check_disable = ScalableBitmap(this, "check_off_disabled", 18);
m_bitmap_check_off = ScalableBitmap(this, "check_off_focused", 18);
m_bitmap_check_on = ScalableBitmap(this, "check_on", 18);
SetMinSize(wxSize(FromDIP(400), FromDIP(30)));
SetMaxSize(wxSize(FromDIP(400), FromDIP(30)));
Bind(wxEVT_PAINT, &DevicePickItem::paintEvent, this);
Bind(wxEVT_ENTER_WINDOW, &DevicePickItem::OnEnterWindow, this);
Bind(wxEVT_LEAVE_WINDOW, &DevicePickItem::OnLeaveWindow, this);
Bind(wxEVT_LEFT_DOWN, &DevicePickItem::OnLeftDown, this);
Bind(wxEVT_MOTION, &DevicePickItem::OnMove, this);
Bind(EVT_MULTI_DEVICE_SELECTED, &DevicePickItem::OnSelectedDevice, this);
wxGetApp().UpdateDarkUIWin(this);
}
void DevicePickItem::DrawTextWithEllipsis(wxDC& dc, const wxString& text, int maxWidth, int left, int top /*= 0*/)
{
wxSize size = GetSize();
wxFont font = dc.GetFont();
wxSize textSize = dc.GetTextExtent(text);
dc.SetTextForeground(StateColor::darkModeColorFor(wxColour(50, 58, 61)));
int textWidth = textSize.GetWidth();
if (textWidth > maxWidth) {
wxString truncatedText = text;
int ellipsisWidth = dc.GetTextExtent("...").GetWidth();
int numChars = text.length();
for (int i = numChars - 1; i >= 0; --i) {
truncatedText = text.substr(0, i) + "...";
int truncatedWidth = dc.GetTextExtent(truncatedText).GetWidth();
if (truncatedWidth <= maxWidth - ellipsisWidth) {
break;
}
}
if (top == 0) {
dc.DrawText(truncatedText, left, (size.y - textSize.y) / 2);
}
else {
dc.DrawText(truncatedText, left, (size.y - textSize.y) / 2 - top);
}
}
else {
if (top == 0) {
dc.DrawText(text, left, (size.y - textSize.y) / 2);
}
else {
dc.DrawText(text, left, (size.y - textSize.y) / 2 - top);
}
}
}
void DevicePickItem::OnEnterWindow(wxMouseEvent& evt)
{
m_hover = true;
Refresh(false);
}
void DevicePickItem::OnLeaveWindow(wxMouseEvent& evt)
{
m_hover = false;
Refresh(false);
}
void DevicePickItem::OnSelectedDevice(wxCommandEvent& evt)
{
auto dev_id = evt.GetString();
auto state = evt.GetInt();
if (state == 0) {
state_selected = 1;
}
else if (state == 1) {
state_selected = 0;
}
Refresh(false);
evt.Skip();
post_event(wxCommandEvent(EVT_MULTI_DEVICE_SELECTED_FINHSH));
}
void DevicePickItem::OnLeftDown(wxMouseEvent& evt)
{
int left = FromDIP(15);
auto mouse_pos = ClientToScreen(evt.GetPosition());
auto item = this->ClientToScreen(wxPoint(0, 0));
if (mouse_pos.x > (item.x + left) &&
mouse_pos.x < (item.x + left + m_bitmap_check_disable.GetBmpWidth()) &&
mouse_pos.y > item.y &&
mouse_pos.y < (item.y + DEVICE_ITEM_MAX_HEIGHT)) {
post_event(wxCommandEvent(EVT_MULTI_DEVICE_SELECTED));
}
}
void DevicePickItem::OnMove(wxMouseEvent& evt)
{
int left = FromDIP(15);
auto mouse_pos = ClientToScreen(evt.GetPosition());
auto item = this->ClientToScreen(wxPoint(0, 0));
if (mouse_pos.x > (item.x + left) &&
mouse_pos.x < (item.x + left + m_bitmap_check_disable.GetBmpWidth()) &&
mouse_pos.y > item.y &&
mouse_pos.y < (item.y + DEVICE_ITEM_MAX_HEIGHT)) {
SetCursor(wxCURSOR_HAND);
}
else {
SetCursor(wxCURSOR_ARROW);
}
}
void DevicePickItem::paintEvent(wxPaintEvent& evt)
{
wxPaintDC dc(this);
render(dc);
}
void DevicePickItem::render(wxDC& dc)
{
#ifdef __WXMSW__
wxSize size = GetSize();
wxMemoryDC memdc;
wxBitmap bmp(size.x, size.y);
memdc.SelectObject(bmp);
memdc.Blit({ 0, 0 }, size, &dc, { 0, 0 });
{
wxGCDC dc2(memdc);
doRender(dc2);
}
memdc.SelectObject(wxNullBitmap);
dc.DrawBitmap(bmp, 0, 0);
#else
doRender(dc);
#endif
}
void DevicePickItem::doRender(wxDC& dc)
{
wxSize size = GetSize();
dc.SetPen(wxPen(*wxBLACK));
int left = FromDIP(PICK_LEFT_PADDING_LEFT);
//checkbox
if (state_selected == 0) {
dc.DrawBitmap(m_bitmap_check_off.bmp(), wxPoint(left, (size.y - m_bitmap_check_disable.GetBmpSize().y) / 2));
}
else if (state_selected == 1) {
dc.DrawBitmap(m_bitmap_check_on.bmp(), wxPoint(left, (size.y - m_bitmap_check_disable.GetBmpSize().y) / 2));
}
left += FromDIP(PICK_LEFT_PRINTABLE);
//dev names
DrawTextWithEllipsis(dc, wxString::FromUTF8(get_obj()->dev_name), FromDIP(PICK_LEFT_DEV_NAME), left);
left += FromDIP(PICK_LEFT_DEV_NAME);
}
void DevicePickItem::post_event(wxCommandEvent&& event)
{
event.SetEventObject(this);
event.SetString(obj_->dev_id);
event.SetInt(state_selected);
wxPostEvent(this, event);
}
void DevicePickItem::DoSetSize(int x, int y, int width, int height, int sizeFlags /*= wxSIZE_AUTO*/)
{
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
}
MultiMachinePickPage::MultiMachinePickPage(Plater* plater /*= nullptr*/)
: DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY,
_L("Edit multiple printers"),
wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX | wxRESIZE_BORDER)
{
#ifdef __WINDOWS__
SetDoubleBuffered(true);
#endif //__WINDOWS__
app_config = get_app_config();
SetBackgroundColour(*wxWHITE);
// icon
std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str();
SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO));
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
auto line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL);
line_top->SetBackgroundColour(wxColour(166, 169, 170));
m_label = new Label(this, _L("Select connected printetrs (0/6)"));
scroll_macine_list = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL);
scroll_macine_list->SetSize(wxSize(FromDIP(400), FromDIP(10 * 30)));
scroll_macine_list->SetMinSize(wxSize(FromDIP(400), FromDIP(10 * 30)));
scroll_macine_list->SetMaxSize(wxSize(FromDIP(400), FromDIP(10 * 30)));
scroll_macine_list->SetBackgroundColour(*wxWHITE);
scroll_macine_list->SetScrollRate(0, 5);
sizer_machine_list = new wxBoxSizer(wxVERTICAL);
scroll_macine_list->SetSizer(sizer_machine_list);
scroll_macine_list->Layout();
main_sizer->Add(line_top, 0, wxEXPAND, 0);
main_sizer->AddSpacer(FromDIP(10));
main_sizer->Add(m_label, 0, wxLEFT, FromDIP(20));
main_sizer->Add(scroll_macine_list, 0, wxLEFT|wxRIGHT, FromDIP(20));
main_sizer->AddSpacer(FromDIP(10));
SetSizer(main_sizer);
Layout();
Fit();
Centre(wxBOTH);
wxGetApp().UpdateDlgDarkUI(this);
}
MultiMachinePickPage::~MultiMachinePickPage()
{
}
int MultiMachinePickPage::get_selected_count()
{
int count = 0;
for (auto it = m_device_items.begin(); it != m_device_items.end(); it++) {
if (it->second->state_selected == 1) {
count++;
}
}
return count;
}
void MultiMachinePickPage::update_selected_count()
{
std::vector<std::string> selected_multi_devices;
int count = 0;
for (auto it = m_device_items.begin(); it != m_device_items.end(); it++) {
if (it->second->state_selected == 1 ) {
selected_multi_devices.push_back(it->second->obj_->dev_id);
count++;
}
}
m_selected_count = count;
m_label->SetLabel(wxString::Format(_L("Select Connected Printetrs (%d/6)"), m_selected_count));
if (m_selected_count > PICK_DEVICE_MAX) {
MessageDialog msg_wingow(nullptr, wxString::Format(_L("The maximum number of printers that can be selected is %d"), PICK_DEVICE_MAX), "", wxAPPLY | wxOK);
if (msg_wingow.ShowModal() == wxOK) {
return;
}
}
for (int i = 0; i < PICK_DEVICE_MAX; i++) {
app_config->erase("multi_devices",std::to_string(i));
}
for (int j = 0; j < selected_multi_devices.size(); j++) {
app_config->set_str("multi_devices", std::to_string(j), selected_multi_devices[j]);
}
app_config->save();
}
void MultiMachinePickPage::on_dpi_changed(const wxRect& suggested_rect)
{
}
void MultiMachinePickPage::on_sys_color_changed()
{
}
void MultiMachinePickPage::refresh_user_device()
{
std::vector<std::string> selected_multi_devices;
for(int i = 0; i < PICK_DEVICE_MAX; i++){
auto dev_id = app_config->get("multi_devices", std::to_string(i));
selected_multi_devices.push_back(dev_id);
}
sizer_machine_list->Clear(false);
Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
if (!dev) {
for (auto it = m_device_items.begin(); it != m_device_items.end(); it++) {
wxWindow* child = it->second;
child->Destroy();
}
return;
}
auto user_machine = dev->get_my_cloud_machine_list();
auto task_manager = wxGetApp().getTaskManager();
std::vector<std::string> subscribe_list;
for (auto it = user_machine.begin(); it != user_machine.end(); ++it) {
DevicePickItem* di = new DevicePickItem(scroll_macine_list, it->second);
di->Bind(EVT_MULTI_DEVICE_SELECTED_FINHSH, [this, di](auto& e) {
int count = get_selected_count();
if (count > PICK_DEVICE_MAX) {
di->unselected();
return;
}
update_selected_count();
});
/* if (m_device_items.find(it->first) != m_device_items.end()) {
auto item = m_device_items[it->first];
if (item->state_selected == 1 && di->state_printable <= 2)
di->state_selected = item->state_selected;
item->Destroy();
}*/
m_device_items[it->first] = di;
//update state
if (task_manager) {
m_device_items[it->first]->state_local_task = task_manager->query_task_state(it->first);
}
//update selected
auto dev_it = std::find(selected_multi_devices.begin(), selected_multi_devices.end(), it->second->dev_id );
if (dev_it != selected_multi_devices.end()) {
di->state_selected = 1;
}
sizer_machine_list->Add(di, 0, wxALL | wxEXPAND, 0);
subscribe_list.push_back(it->first);
}
dev->subscribe_device_list(subscribe_list);
sizer_machine_list->Layout();
Layout();
Fit();
}
void MultiMachinePickPage::on_confirm(wxCommandEvent& event)
{
}
bool MultiMachinePickPage::Show(bool show)
{
if (show) {
refresh_user_device();
update_selected_count();
//m_refresh_timer->Stop();
//m_refresh_timer->SetOwner(this);
//m_refresh_timer->Start(4000);
//wxPostEvent(this, wxTimerEvent());
}
else {
//m_refresh_timer->Stop();
Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
if (dev) {
dev->subscribe_device_list(std::vector<std::string>());
}
}
return wxDialog::Show(show);
}
} // namespace GUI
} // namespace Slic3r
+104
View File
@@ -0,0 +1,104 @@
#ifndef slic3r_MultiMachinePage_hpp_
#define slic3r_MultiMachinePage_hpp_
#include "libslic3r/libslic3r.h"
#include "GUI_App.hpp"
#include "GUI_Utils.hpp"
#include "MultiTaskManagerPage.hpp"
#include "MultiMachineManagerPage.hpp"
#include "Tabbook.hpp"
#include "wx/button.h"
namespace Slic3r {
namespace GUI {
#define PICK_LEFT_PADDING_LEFT 15
#define PICK_LEFT_PRINTABLE 40
#define PICK_LEFT_DEV_NAME 250
#define PICK_LEFT_DEV_STATUS 250
#define PICK_DEVICE_MAX 6
class MultiMachinePage : public wxPanel
{
private:
wxTimer* m_refresh_timer = nullptr;
wxSizer* m_main_sizer{ nullptr };
LocalTaskManagerPage* m_local_task_manager{ nullptr };
CloudTaskManagerPage* m_cloud_task_manager{ nullptr };
MultiMachineManagerPage* m_machine_manager{ nullptr };
Tabbook* m_tabpanel{ nullptr };
public:
MultiMachinePage(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL);
~MultiMachinePage();
void jump_to_send_page();
void on_sys_color_changed();
void msw_rescale();
bool Show(bool show);
void init_tabpanel();
void init_timer();
void on_timer(wxTimerEvent& event);
void clear_page();
};
class DevicePickItem : public DeviceItem
{
public:
DevicePickItem(wxWindow* parent, MachineObject* obj);
~DevicePickItem() {};
void DrawTextWithEllipsis(wxDC& dc, const wxString& text, int maxWidth, int left, int top = 0);
void OnEnterWindow(wxMouseEvent& evt);
void OnLeaveWindow(wxMouseEvent& evt);
void OnSelectedDevice(wxCommandEvent& evt);
void OnLeftDown(wxMouseEvent& evt);
void OnMove(wxMouseEvent& evt);
void paintEvent(wxPaintEvent& evt);
void render(wxDC& dc);
void doRender(wxDC& dc);
void post_event(wxCommandEvent&& event);
virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO);
public:
bool m_hover{ false };
ScalableBitmap m_bitmap_check_disable;
ScalableBitmap m_bitmap_check_off;
ScalableBitmap m_bitmap_check_on;
};
class MultiMachinePickPage : public DPIDialog
{
private:
AppConfig* app_config;
Label* m_label{ nullptr };
wxScrolledWindow* scroll_macine_list{ nullptr };
wxBoxSizer* m_sizer_body{ nullptr };
wxBoxSizer* sizer_machine_list{ nullptr };
std::map<std::string, DevicePickItem*> m_device_items;
int m_selected_count{0};
public:
MultiMachinePickPage(Plater* plater = nullptr);
~MultiMachinePickPage();
int get_selected_count();
void update_selected_count();
void on_dpi_changed(const wxRect& suggested_rect);
void on_sys_color_changed();
void refresh_user_device();
void on_confirm(wxCommandEvent& event);
bool Show(bool show);
};
} // namespace GUI
} // namespace Slic3r
#endif
+7
View File
@@ -0,0 +1,7 @@
#include "MultiPrintJob.hpp"
namespace Slic3r {
namespace GUI {
} // namespace GUI
} // namespace Slic3r
+10
View File
@@ -0,0 +1,10 @@
#ifndef slic3r_MultiPrintJob_hpp_
#define slic3r_MultiPrintJob_hpp_
namespace Slic3r {
namespace GUI {
} // namespace GUI
} // namespace Slic3r
#endif
+33
View File
@@ -0,0 +1,33 @@
#include "MultiSendMachineModel.hpp"
namespace Slic3r {
namespace GUI {
MultiSendMachineModel::MultiSendMachineModel()
{
;
}
MultiSendMachineModel::~MultiSendMachineModel()
{
;
}
void MultiSendMachineModel::Init()
{
;
}
wxDataViewItem MultiSendMachineModel::AddMachine(MachineObject* obj)
{
wxString name = from_u8(obj->dev_name);
wxDataViewItem new_item;
// TODO
return new_item;
}
} // namespace GUI
} // namespace Slic3r
+25
View File
@@ -0,0 +1,25 @@
#ifndef slic3r_MultiSendMachineModel_hpp_
#define slic3r_MultiSendMachineModel_hpp_
#include "DeviceManager.hpp"
namespace Slic3r {
namespace GUI {
class MultiSendMachineModel : public wxDataViewModel
{
public:
MultiSendMachineModel();
~MultiSendMachineModel();
void Init();
wxDataViewItem AddMachine(MachineObject* obj);
private:
};
} // namespace GUI
} // namespace Slic3r
#endif
File diff suppressed because it is too large Load Diff
+208
View File
@@ -0,0 +1,208 @@
#ifndef slic3r_MultiTaskManagerPage_hpp_
#define slic3r_MultiTaskManagerPage_hpp_
#include "GUI_App.hpp"
#include "GUI_Utils.hpp"
#include "MultiMachine.hpp"
#include "DeviceManager.hpp"
#include "TaskManager.hpp"
#include "Widgets/Label.hpp"
#include "Widgets/Button.hpp"
#include "Widgets/CheckBox.hpp"
#include "Widgets/ComboBox.hpp"
#include "Widgets/ScrolledWindow.hpp"
#include "Widgets/PopupWindow.hpp"
#include "Widgets/TextInput.hpp"
namespace Slic3r {
namespace GUI {
#define CLOUD_TASK_ITEM_MAX_WIDTH 1100
#define TASK_ITEM_MAX_WIDTH 900
#define TASK_LEFT_PADDING_LEFT 15
#define TASK_LEFT_PRINTABLE 40
#define TASK_LEFT_PRO_NAME 180
#define TASK_LEFT_DEV_NAME 150
#define TASK_LEFT_PRO_STATE 170
#define TASK_LEFT_PRO_INFO 230
#define TASK_LEFT_SEND_TIME 180
class MultiTaskItem : public DeviceItem
{
public:
MultiTaskItem(wxWindow* parent, MachineObject* obj, int type);
~MultiTaskItem() {};
void OnEnterWindow(wxMouseEvent& evt);
void OnLeaveWindow(wxMouseEvent& evt);
void OnSelectedDevice(wxCommandEvent& evt);
void OnLeftDown(wxMouseEvent& evt);
void OnMove(wxMouseEvent& evt);
void paintEvent(wxPaintEvent& evt);
void render(wxDC& dc);
void doRender(wxDC& dc);
void DrawTextWithEllipsis(wxDC& dc, const wxString& text, int maxWidth, int left, int top = 0);
void post_event(wxCommandEvent&& event);
virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO);
bool m_hover{ false };
wxString get_left_time(int mc_left_time);
ScalableBitmap m_bitmap_check_disable;
ScalableBitmap m_bitmap_check_off;
ScalableBitmap m_bitmap_check_on;
int m_sending_percent{0};
int m_task_type{0}; //0-local 1-cloud
wxString m_project_name;
wxString m_dev_name;
std::string m_dev_id;
TaskStateInfo* task_obj { nullptr };
std::string m_job_id;
//std::string m_sent_time;
Button* m_button_resume{ nullptr };
Button* m_button_cancel{ nullptr };
Button* m_button_pause{ nullptr };
Button* m_button_stop{ nullptr };
void update_info();
void onPause();
void onResume();
void onStop();
void onCancel();
};
class LocalTaskManagerPage : public wxPanel
{
public:
LocalTaskManagerPage(wxWindow* parent);
~LocalTaskManagerPage() {};
void update_page();
void refresh_user_device(bool clear = false);
bool Show(bool show);
void cancel_all(wxCommandEvent& evt);
private:
SortItem m_sort;
std::map<int, MultiTaskItem*> m_task_items;
bool device_name_big{ true };
bool device_state_big{ true };
bool device_send_time{ true };
wxPanel* m_main_panel{ nullptr };
wxBoxSizer* m_main_sizer{ nullptr };
wxBoxSizer* page_sizer{ nullptr };
wxBoxSizer* m_sizer_task_list{ nullptr };
wxScrolledWindow* m_task_list{ nullptr };
wxStaticText* m_selected_num{ nullptr };
// table head
wxPanel* m_table_head_panel{ nullptr };
wxBoxSizer* m_table_head_sizer{ nullptr };
CheckBox* m_select_checkbox{ nullptr };
Button* m_task_name{ nullptr };
Button* m_printer_name{ nullptr };
Button* m_status{ nullptr };
Button* m_info{ nullptr };
Button* m_send_time{ nullptr };
Button* m_action{ nullptr };
// ctrl button for all
int m_sel_number{0};
wxPanel* m_ctrl_btn_panel{ nullptr };
wxBoxSizer* m_btn_sizer{ nullptr };
Button* btn_stop_all{ nullptr };
wxStaticText* m_sel_text{ nullptr };
// tip when no device
wxStaticText* m_tip_text{ nullptr };
};
class CloudTaskManagerPage : public wxPanel
{
public:
CloudTaskManagerPage(wxWindow* parent);
~CloudTaskManagerPage();
void update_page();
void refresh_user_device(bool clear = false);
std::string utc_time_to_date(std::string utc_time);
bool Show(bool show);
void update_page_number();
void start_timer();
void on_timer(wxTimerEvent& event);
void pause_all(wxCommandEvent& evt);
void resume_all(wxCommandEvent& evt);
void stop_all(wxCommandEvent& evt);
void enable_buttons(bool enable);
void page_num_enter_evt();
private:
SortItem m_sort;
bool device_name_big{ true };
bool device_state_big{ true };
bool device_send_time{ true };
/* job_id -> sel */
std::map <std::string, MultiTaskItem*> m_task_items;
wxPanel* m_main_panel{ nullptr };
wxBoxSizer* page_sizer{ nullptr };
wxBoxSizer* m_sizer_task_list{ nullptr };
wxBoxSizer* m_main_sizer{ nullptr };
wxScrolledWindow* m_task_list{ nullptr };
wxStaticText* m_selected_num{ nullptr };
// Flipping pages
int m_current_page{ 0 };
int m_total_page{0};
int m_total_count{ 0 };
int m_count_page_item{ 10 };
bool prev{ false };
bool next{ false };
Button* btn_last_page{ nullptr };
Button* btn_next_page{ nullptr };
wxStaticText* st_page_number{ nullptr };
wxBoxSizer* m_flipping_page_sizer{ nullptr };
wxBoxSizer* m_page_sizer{ nullptr };
wxPanel* m_flipping_panel{ nullptr };
wxTimer* m_flipping_timer{ nullptr };
TextInput* m_page_num_input{ nullptr };
Button* m_page_num_enter{ nullptr };
// table head
wxPanel* m_table_head_panel{ nullptr };
wxBoxSizer* m_table_head_sizer{ nullptr };
CheckBox* m_select_checkbox{ nullptr };
Button* m_task_name{ nullptr };
Button* m_printer_name{ nullptr };
Button* m_status{ nullptr };
Button* m_info{ nullptr };
Button* m_send_time{ nullptr };
Button* m_action{ nullptr };
// ctrl button for all
int m_sel_number;
wxPanel* m_ctrl_btn_panel{ nullptr };
wxBoxSizer* m_btn_sizer{ nullptr };
Button* btn_pause_all{ nullptr };
Button* btn_continue_all{ nullptr };
Button* btn_stop_all{ nullptr };
wxStaticText* m_sel_text{ nullptr };
// tip when no device
wxStaticText* m_tip_text{ nullptr };
wxStaticText* m_loading_text{ nullptr };
};
} // namespace GUI
} // namespace Slic3r
#endif
+6
View File
@@ -0,0 +1,6 @@
namespace Slic3r {
namespace GUI {
} // namespace GUI
} // namespace Slic3r
+11
View File
@@ -0,0 +1,11 @@
#ifndef slic3r_MultiTaskModel_hpp_
#define slic3r_MultiTaskModel_hpp_
namespace Slic3r {
namespace GUI {
} // namespace GUI
} // namespace Slic3r
#endif
+817
View File
@@ -0,0 +1,817 @@
#include <algorithm>
#include <sstream>
//#include "libslic3r/FlushVolCalc.hpp"
#include "ObjColorDialog.hpp"
#include "BitmapCache.hpp"
#include "GUI.hpp"
#include "I18N.hpp"
#include "GUI_App.hpp"
#include "MsgDialog.hpp"
#include "Widgets/Button.hpp"
#include "slic3r/Utils/ColorSpaceConvert.hpp"
#include "MainFrame.hpp"
#include "libslic3r/Config.hpp"
#include "BitmapComboBox.hpp"
#include "Widgets/ComboBox.hpp"
#include <wx/sizer.h>
#include "libslic3r/ObjColorUtils.hpp"
using namespace Slic3r;
using namespace Slic3r::GUI;
int objcolor_scale(const int val) { return val * Slic3r::GUI::wxGetApp().em_unit() / 10; }
int OBJCOLOR_ITEM_WIDTH() { return objcolor_scale(30); }
static const wxColour g_text_color = wxColour(107, 107, 107, 255);
const int HEADER_BORDER = 5;
const int CONTENT_BORDER = 3;
const int PANEL_WIDTH = 370;
const int COLOR_LABEL_WIDTH = 180;
#define ICON_SIZE wxSize(FromDIP(16), FromDIP(16))
#define MIN_OBJCOLOR_DIALOG_WIDTH FromDIP(400)
#define FIX_SCROLL_HEIGTH FromDIP(400)
#define BTN_SIZE wxSize(FromDIP(58), FromDIP(24))
#define BTN_GAP FromDIP(20)
static void update_ui(wxWindow* window)
{
Slic3r::GUI::wxGetApp().UpdateDarkUI(window);
}
static const char g_min_cluster_color = 1;
//static const char g_max_cluster_color = 15;
static const char g_max_color = 16;
const StateColor ok_btn_bg(std::pair<wxColour, int>(wxColour(0, 137, 123), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
const StateColor ok_btn_disable_bg(std::pair<wxColour, int>(wxColour(205, 201, 201), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(205, 201, 201), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(205, 201, 201), StateColor::Normal));
wxBoxSizer* ObjColorDialog::create_btn_sizer(long flags)
{
auto btn_sizer = new wxBoxSizer(wxHORIZONTAL);
btn_sizer->AddStretchSpacer();
StateColor ok_btn_bd(
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal)
);
StateColor ok_btn_text(
std::pair<wxColour, int>(wxColour(255, 255, 254), StateColor::Normal)
);
StateColor cancel_btn_bg(
std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(238, 238, 238), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(255, 255, 255), StateColor::Normal)
);
StateColor cancel_btn_bd_(
std::pair<wxColour, int>(wxColour(38, 46, 48), StateColor::Normal)
);
StateColor cancel_btn_text(
std::pair<wxColour, int>(wxColour(38, 46, 48), StateColor::Normal)
);
StateColor calc_btn_bg(
std::pair<wxColour, int>(wxColour(0, 137, 123), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal)
);
StateColor calc_btn_bd(
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal)
);
StateColor calc_btn_text(
std::pair<wxColour, int>(wxColour(255, 255, 254), StateColor::Normal)
);
if (flags & wxOK) {
Button* ok_btn = new Button(this, _L("OK"));
ok_btn->SetMinSize(BTN_SIZE);
ok_btn->SetCornerRadius(FromDIP(12));
ok_btn->Enable(false);
ok_btn->SetBackgroundColor(ok_btn_disable_bg);
ok_btn->SetBorderColor(ok_btn_bd);
ok_btn->SetTextColor(ok_btn_text);
ok_btn->SetFocus();
ok_btn->SetId(wxID_OK);
btn_sizer->Add(ok_btn, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, BTN_GAP);
m_button_list[wxOK] = ok_btn;
}
if (flags & wxCANCEL) {
Button* cancel_btn = new Button(this, _L("Cancel"));
cancel_btn->SetMinSize(BTN_SIZE);
cancel_btn->SetCornerRadius(FromDIP(12));
cancel_btn->SetBackgroundColor(cancel_btn_bg);
cancel_btn->SetBorderColor(cancel_btn_bd_);
cancel_btn->SetTextColor(cancel_btn_text);
cancel_btn->SetId(wxID_CANCEL);
btn_sizer->Add(cancel_btn, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, BTN_GAP);
m_button_list[wxCANCEL] = cancel_btn;
}
return btn_sizer;
}
void ObjColorDialog::on_dpi_changed(const wxRect &suggested_rect)
{
for (auto button_item : m_button_list)
{
if (button_item.first == wxRESET)
{
button_item.second->SetMinSize(wxSize(FromDIP(75), FromDIP(24)));
button_item.second->SetCornerRadius(FromDIP(12));
}
if (button_item.first == wxOK) {
button_item.second->SetMinSize(BTN_SIZE);
button_item.second->SetCornerRadius(FromDIP(12));
}
if (button_item.first == wxCANCEL) {
button_item.second->SetMinSize(BTN_SIZE);
button_item.second->SetCornerRadius(FromDIP(12));
}
}
m_panel_ObjColor->msw_rescale();
this->Refresh();
};
ObjColorDialog::ObjColorDialog(wxWindow * parent,
std::vector<Slic3r::RGBA> & input_colors,
bool is_single_color,
const std::vector<std::string> &extruder_colours,
std::vector<unsigned char> & filament_ids,
unsigned char & first_extruder_id)
: DPIDialog(parent ? parent : static_cast<wxWindow *>(wxGetApp().mainframe),
wxID_ANY,
_(L("Obj file Import color")),
wxDefaultPosition,
wxDefaultSize,
wxDEFAULT_DIALOG_STYLE /* | wxRESIZE_BORDER*/)
, m_filament_ids(filament_ids)
, m_first_extruder_id(first_extruder_id)
{
std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % Slic3r::resources_dir()).str();
SetIcon(wxIcon(Slic3r::encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO));
auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1));
m_line_top->SetBackgroundColour(wxColour(166, 169, 170));
this->SetBackgroundColour(*wxWHITE);
this->SetMinSize(wxSize(MIN_OBJCOLOR_DIALOG_WIDTH, -1));
m_panel_ObjColor = new ObjColorPanel(this, input_colors, is_single_color, extruder_colours, filament_ids, first_extruder_id);
auto main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(m_line_top, 0, wxEXPAND, 0);
// set min sizer width according to extruders count
auto sizer_width = (int) (2.8 * OBJCOLOR_ITEM_WIDTH());
sizer_width = sizer_width > MIN_OBJCOLOR_DIALOG_WIDTH ? sizer_width : MIN_OBJCOLOR_DIALOG_WIDTH;
main_sizer->SetMinSize(wxSize(sizer_width, -1));
main_sizer->Add(m_panel_ObjColor, 1, wxEXPAND | wxALL, 0);
auto btn_sizer = create_btn_sizer(wxOK | wxCANCEL);
{
m_button_list[wxOK]->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent &e) {
if (m_panel_ObjColor->is_ok() == m_button_list[wxOK]->IsEnabled()) { return; }
m_button_list[wxOK]->Enable(m_panel_ObjColor->is_ok());
m_button_list[wxOK]->SetBackgroundColor(m_panel_ObjColor->is_ok() ? ok_btn_bg : ok_btn_disable_bg);
}));
}
main_sizer->Add(btn_sizer, 0, wxBOTTOM | wxRIGHT | wxEXPAND, BTN_GAP);
SetSizer(main_sizer);
main_sizer->SetSizeHints(this);
if (this->FindWindowById(wxID_OK, this)) {
this->FindWindowById(wxID_OK, this)->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {// if OK button is clicked..
m_panel_ObjColor->update_filament_ids();
EndModal(wxID_OK);
}, wxID_OK);
}
if (this->FindWindowById(wxID_CANCEL, this)) {
update_ui(static_cast<wxButton*>(this->FindWindowById(wxID_CANCEL, this)));
this->FindWindowById(wxID_CANCEL, this)->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { EndModal(wxCANCEL); });
}
this->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { EndModal(wxCANCEL); });
wxGetApp().UpdateDlgDarkUI(this);
}
RGBA convert_to_rgba(const wxColour &color)
{
RGBA rgba;
rgba[0] = std::clamp(color.Red() / 255.f, 0.f, 1.f);
rgba[1] = std::clamp(color.Green() / 255.f, 0.f, 1.f);
rgba[2] = std::clamp(color.Blue() / 255.f, 0.f, 1.f);
rgba[3] = std::clamp(color.Alpha() / 255.f, 0.f, 1.f);
return rgba;
}
wxColour convert_to_wxColour(const RGBA &color)
{
auto r = std::clamp((int) (color[0] * 255.f), 0, 255);
auto g = std::clamp((int) (color[1] * 255.f), 0, 255);
auto b = std::clamp((int) (color[2] * 255.f), 0, 255);
auto a = std::clamp((int) (color[3] * 255.f), 0, 255);
wxColour wx_color(r,g,b,a);
return wx_color;
}
// This panel contains all control widgets for both simple and advanced mode (these reside in separate sizers)
ObjColorPanel::ObjColorPanel(wxWindow * parent,
std::vector<Slic3r::RGBA>& input_colors,
bool is_single_color,
const std::vector<std::string>& extruder_colours,
std::vector<unsigned char> & filament_ids,
unsigned char & first_extruder_id)
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize /*,wxBORDER_RAISED*/)
, m_input_colors(input_colors)
, m_filament_ids(filament_ids)
, m_first_extruder_id(first_extruder_id)
{
if (input_colors.size() == 0) { return; }
for (const std::string& color : extruder_colours) {
m_colours.push_back(wxColor(color));
}
//deal input_colors
m_input_colors_size = input_colors.size();
for (size_t i = 0; i < input_colors.size(); i++) {
if (color_is_equal(input_colors[i] , UNDEFINE_COLOR)) { // not define color range:0~1
input_colors[i]=convert_to_rgba( m_colours[0]);
}
}
if (is_single_color && input_colors.size() >=1) {
m_cluster_colors_from_algo.emplace_back(input_colors[0]);
m_cluster_colours.emplace_back(convert_to_wxColour(input_colors[0]));
m_cluster_labels_from_algo.reserve(m_input_colors_size);
for (size_t i = 0; i < m_input_colors_size; i++) {
m_cluster_labels_from_algo.emplace_back(0);
}
m_cluster_map_filaments.resize(m_cluster_colors_from_algo.size());
m_color_num_recommend = m_color_cluster_num_by_algo = m_cluster_colors_from_algo.size();
} else {//cluster deal
deal_algo(-1);
}
//end first cluster
//draw ui
auto sizer_width = FromDIP(300);
// Create two switched panels with their own sizers
m_sizer_simple = new wxBoxSizer(wxVERTICAL);
m_page_simple = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
m_page_simple->SetSizer(m_sizer_simple);
m_page_simple->SetBackgroundColour(*wxWHITE);
update_ui(m_page_simple);
// BBS
m_sizer_simple->AddSpacer(FromDIP(10));
// BBS: for tunning flush volumes
{
//color cluster results
wxBoxSizer * specify_cluster_sizer = new wxBoxSizer(wxHORIZONTAL);
wxStaticText *specify_color_cluster_title = new wxStaticText(m_page_simple, wxID_ANY, _L("Specify number of colors:"));
specify_color_cluster_title->SetFont(Label::Head_14);
specify_cluster_sizer->Add(specify_color_cluster_title, 0, wxALIGN_CENTER | wxALL, FromDIP(5));
m_color_cluster_num_by_user_ebox = new wxTextCtrl(m_page_simple, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(25), -1), wxTE_PROCESS_ENTER);
m_color_cluster_num_by_user_ebox->SetValue(std::to_string(m_color_cluster_num_by_algo).c_str());
{//event
auto on_apply_color_cluster_text_modify = [this](wxEvent &e) {
wxString str = m_color_cluster_num_by_user_ebox->GetValue();
int number = wxAtoi(str);
if (number > m_color_num_recommend || number < g_min_cluster_color) {
number = number < g_min_cluster_color ? g_min_cluster_color : m_color_num_recommend;
str = wxString::Format(("%d"), number);
m_color_cluster_num_by_user_ebox->SetValue(str);
MessageDialog dlg(nullptr, wxString::Format(_L("The color count should be in range [%d, %d]."), g_min_cluster_color, m_color_num_recommend),
_L("Warning"), wxICON_WARNING | wxOK);
dlg.ShowModal();
}
e.Skip();
};
m_color_cluster_num_by_user_ebox->Bind(wxEVT_TEXT_ENTER, on_apply_color_cluster_text_modify);
m_color_cluster_num_by_user_ebox->Bind(wxEVT_KILL_FOCUS, on_apply_color_cluster_text_modify);
m_color_cluster_num_by_user_ebox->Bind(wxEVT_COMMAND_TEXT_UPDATED, [this](wxCommandEvent &) {
wxString str = m_color_cluster_num_by_user_ebox->GetValue();
int number = wxAtof(str);
if (number > m_color_num_recommend || number < g_min_cluster_color) {
number = number < g_min_cluster_color ? g_min_cluster_color : m_color_num_recommend;
str = wxString::Format(("%d"), number);
m_color_cluster_num_by_user_ebox->SetValue(str);
m_color_cluster_num_by_user_ebox->SetInsertionPointEnd();
}
if (m_last_cluster_num != number) {
deal_algo(number, true);
Layout();
//Fit();
Refresh();
Update();
m_last_cluster_num = number;
}
});
m_color_cluster_num_by_user_ebox->Bind(wxEVT_CHAR, [this](wxKeyEvent &e) {
int keycode = e.GetKeyCode();
wxString input_char = wxString::Format("%c", keycode);
long value;
if (!input_char.ToLong(&value))
return;
e.Skip();
});
}
specify_cluster_sizer->AddSpacer(FromDIP(2));
specify_cluster_sizer->Add(m_color_cluster_num_by_user_ebox, 0, wxALIGN_CENTER | wxALL, 0);
specify_cluster_sizer->AddSpacer(FromDIP(15));
wxStaticText *recommend_color_cluster_title = new wxStaticText(m_page_simple, wxID_ANY, "(" + std::to_string(m_color_num_recommend) + " " + _L("Recommended ") + ")");
specify_cluster_sizer->Add(recommend_color_cluster_title, 0, wxALIGN_CENTER | wxALL, 0);
m_sizer_simple->Add(specify_cluster_sizer, 0, wxEXPAND | wxLEFT, FromDIP(20));
wxBoxSizer * current_filaments_title_sizer = new wxBoxSizer(wxHORIZONTAL);
wxStaticText *current_filaments_title = new wxStaticText(m_page_simple, wxID_ANY, _L("Current filament colors:"));
current_filaments_title->SetFont(Label::Head_14);
current_filaments_title_sizer->Add(current_filaments_title, 0, wxALIGN_CENTER | wxALL, FromDIP(5));
m_sizer_simple->Add(current_filaments_title_sizer, 0, wxEXPAND | wxLEFT, FromDIP(20));
wxBoxSizer * current_filaments_sizer = new wxBoxSizer(wxHORIZONTAL);
current_filaments_sizer->AddSpacer(FromDIP(10));
for (size_t i = 0; i < m_colours.size(); i++) {
auto extruder_icon_sizer = create_extruder_icon_and_rgba_sizer(m_page_simple, i, m_colours[i]);
current_filaments_sizer->Add(extruder_icon_sizer, 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL, FromDIP(10));
}
m_sizer_simple->Add(current_filaments_sizer, 0, wxEXPAND | wxLEFT, FromDIP(20));
//colors table
m_scrolledWindow = new wxScrolledWindow(m_page_simple,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxSB_VERTICAL);
m_sizer_simple->Add(m_scrolledWindow, 0, wxEXPAND | wxALL, FromDIP(5));
draw_table();
//buttons
wxBoxSizer *quick_set_sizer = new wxBoxSizer(wxHORIZONTAL);
wxStaticText *quick_set_title = new wxStaticText(m_page_simple, wxID_ANY, _L("Quick set:"));
quick_set_title->SetFont(Label::Head_12);
quick_set_sizer->Add(quick_set_title, 0, wxALIGN_CENTER | wxALL, 0);
quick_set_sizer->AddSpacer(FromDIP(10));
auto calc_approximate_match_btn_sizer = create_approximate_match_btn_sizer(m_page_simple);
auto calc_add_btn_sizer = create_add_btn_sizer(m_page_simple);
auto calc_reset_btn_sizer = create_reset_btn_sizer(m_page_simple);
quick_set_sizer->Add(calc_add_btn_sizer, 0, wxALIGN_CENTER | wxALL, 0);
quick_set_sizer->AddSpacer(FromDIP(10));
quick_set_sizer->Add(calc_approximate_match_btn_sizer, 0, wxALIGN_CENTER | wxALL, 0);
quick_set_sizer->AddSpacer(FromDIP(10));
quick_set_sizer->Add(calc_reset_btn_sizer, 0, wxALIGN_CENTER | wxALL, 0);
quick_set_sizer->AddSpacer(FromDIP(10));
m_sizer_simple->Add(quick_set_sizer, 0, wxEXPAND | wxLEFT, FromDIP(30));
wxBoxSizer *warning_sizer = new wxBoxSizer(wxHORIZONTAL);
m_warning_text = new wxStaticText(m_page_simple, wxID_ANY, "");
warning_sizer->Add(m_warning_text, 0, wxALIGN_CENTER | wxALL, 0);
m_sizer_simple->Add(warning_sizer, 0, wxEXPAND | wxLEFT, FromDIP(30));
m_sizer_simple->AddSpacer(10);
}
deal_default_strategy();
//page_simple//page_advanced
m_sizer = new wxBoxSizer(wxVERTICAL);
m_sizer->Add(m_page_simple, 0, wxEXPAND, 0);
m_sizer->SetSizeHints(this);
SetSizer(m_sizer);
this->Layout();
}
void ObjColorPanel::msw_rescale()
{
for (unsigned int i = 0; i < m_extruder_icon_list.size(); ++i) {
auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(i + 1), FromDIP(16), FromDIP(16));
m_extruder_icon_list[i]->SetBitmap(bitmap);
}
/* for (unsigned int i = 0; i < m_color_cluster_icon_list.size(); ++i) {
auto bitmap = *get_extruder_color_icon(m_cluster_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(i + 1), FromDIP(16), FromDIP(16));
m_color_cluster_icon_list[i]->SetBitmap(bitmap);
}*/
}
bool ObjColorPanel::is_ok() {
for (auto item : m_result_icon_list) {
if (item->bitmap_combox->IsShown()) {
auto selection = item->bitmap_combox->GetSelection();
if (selection < 1) {
return false;
}
}
}
return true;
}
void ObjColorPanel::update_filament_ids()
{
if (m_is_add_filament) {
for (auto c:m_new_add_colors) {
/*auto evt = new ColorEvent(EVT_ADD_CUSTOM_FILAMENT, c);
wxQueueEvent(wxGetApp().plater(), evt);*/
wxGetApp().sidebar().add_custom_filament(c);
}
}
//deal m_filament_ids
m_filament_ids.clear();
m_filament_ids.reserve(m_input_colors_size);
for (size_t i = 0; i < m_input_colors_size; i++) {
auto label = m_cluster_labels_from_algo[i];
m_filament_ids.emplace_back(m_cluster_map_filaments[label]);
}
m_first_extruder_id = m_cluster_map_filaments[0];
}
wxBoxSizer *ObjColorPanel::create_approximate_match_btn_sizer(wxWindow *parent)
{
auto btn_sizer = new wxBoxSizer(wxHORIZONTAL);
StateColor calc_btn_bg(std::pair<wxColour, int>(wxColour(0, 137, 123), StateColor::Pressed), std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
StateColor calc_btn_bd(std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
StateColor calc_btn_text(std::pair<wxColour, int>(wxColour(255, 255, 254), StateColor::Normal));
//create btn
m_quick_approximate_match_btn = new Button(parent, _L("Color match"));
m_quick_approximate_match_btn->SetToolTip(_L("Approximate color matching."));
auto cur_btn = m_quick_approximate_match_btn;
cur_btn->SetFont(Label::Body_13);
cur_btn->SetMinSize(wxSize(FromDIP(60), FromDIP(20)));
cur_btn->SetCornerRadius(FromDIP(10));
cur_btn->SetBackgroundColor(calc_btn_bg);
cur_btn->SetBorderColor(calc_btn_bd);
cur_btn->SetTextColor(calc_btn_text);
cur_btn->SetFocus();
btn_sizer->Add(cur_btn, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 0);
cur_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) {
deal_approximate_match_btn();
});
return btn_sizer;
}
wxBoxSizer *ObjColorPanel::create_add_btn_sizer(wxWindow *parent)
{
auto btn_sizer = new wxBoxSizer(wxHORIZONTAL);
StateColor calc_btn_bg(std::pair<wxColour, int>(wxColour(0, 137, 123), StateColor::Pressed), std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
StateColor calc_btn_bd(std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
StateColor calc_btn_text(std::pair<wxColour, int>(wxColour(255, 255, 254), StateColor::Normal));
// create btn
m_quick_add_btn = new Button(parent, _L("Append"));
m_quick_add_btn->SetToolTip(_L("Add consumable extruder after existing extruders."));
auto cur_btn = m_quick_add_btn;
cur_btn->SetFont(Label::Body_13);
cur_btn->SetMinSize(wxSize(FromDIP(60), FromDIP(20)));
cur_btn->SetCornerRadius(FromDIP(10));
cur_btn->SetBackgroundColor(calc_btn_bg);
cur_btn->SetBorderColor(calc_btn_bd);
cur_btn->SetTextColor(calc_btn_text);
cur_btn->SetFocus();
btn_sizer->Add(cur_btn, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 0);
cur_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) {
deal_add_btn();
});
return btn_sizer;
}
wxBoxSizer *ObjColorPanel::create_reset_btn_sizer(wxWindow *parent)
{
auto btn_sizer = new wxBoxSizer(wxHORIZONTAL);
StateColor calc_btn_bg(std::pair<wxColour, int>(wxColour(0, 137, 123), StateColor::Pressed), std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
StateColor calc_btn_bd(std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
StateColor calc_btn_text(std::pair<wxColour, int>(wxColour(255, 255, 254), StateColor::Normal));
// create btn
m_quick_reset_btn = new Button(parent, _L("Reset"));
m_quick_add_btn->SetToolTip(_L("Reset mapped extruders."));
auto cur_btn = m_quick_reset_btn;
cur_btn->SetFont(Label::Body_13);
cur_btn->SetMinSize(wxSize(FromDIP(60), FromDIP(20)));
cur_btn->SetCornerRadius(FromDIP(10));
cur_btn->SetBackgroundColor(calc_btn_bg);
cur_btn->SetBorderColor(calc_btn_bd);
cur_btn->SetTextColor(calc_btn_text);
cur_btn->SetFocus();
btn_sizer->Add(cur_btn, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 0);
cur_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) {
deal_reset_btn();
});
return btn_sizer;
}
wxBoxSizer *ObjColorPanel::create_extruder_icon_and_rgba_sizer(wxWindow *parent, int id, const wxColour &color)
{
auto icon_sizer = new wxBoxSizer(wxHORIZONTAL);
wxButton *icon = new wxButton(parent, wxID_ANY, {}, wxDefaultPosition, ICON_SIZE, wxBORDER_NONE | wxBU_AUTODRAW);
icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(id + 1), FromDIP(16), FromDIP(16)));
icon->SetCanFocus(false);
m_extruder_icon_list.emplace_back(icon);
icon_sizer->Add(icon, 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL, FromDIP(10)); // wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM
icon_sizer->AddSpacer(FromDIP(5));
return icon_sizer;
}
std::string ObjColorPanel::get_color_str(const wxColour &color) {
std::string str = ("R:" + std::to_string(color.Red()) +
std::string(" G:") + std::to_string(color.Green()) +
std::string(" B:") + std::to_string(color.Blue()) +
std::string(" A:") + std::to_string(color.Alpha()));
return str;
}
ComboBox *ObjColorPanel::CreateEditorCtrl(wxWindow *parent, int id) // wxRect labelRect,, const wxVariant &value
{
std::vector<wxBitmap *> icons = get_extruder_color_icons();
const double em = Slic3r::GUI::wxGetApp().em_unit();
bool thin_icon = false;
const int icon_width = lround((thin_icon ? 2 : 4.4) * em);
const int icon_height = lround(2 * em);
m_combox_icon_width = icon_width;
m_combox_icon_height = icon_height;
wxColour undefined_color(0,255,0,255);
icons.insert(icons.begin(), get_extruder_color_icon(undefined_color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(-1), icon_width, icon_height));
if (icons.empty())
return nullptr;
::ComboBox *c_editor = new ::ComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(m_combox_width), -1), 0, nullptr,
wxCB_READONLY | CB_NO_DROP_ICON | CB_NO_TEXT);
c_editor->SetMinSize(wxSize(FromDIP(m_combox_width), -1));
c_editor->SetMaxSize(wxSize(FromDIP(m_combox_width), -1));
c_editor->GetDropDown().SetUseContentWidth(true);
for (size_t i = 0; i < icons.size(); i++) {
c_editor->Append(wxString::Format("%d", i), *icons[i]);
if (i == 0) {
c_editor->SetItemTooltip(i,undefined_color.GetAsString(wxC2S_HTML_SYNTAX));
} else {
c_editor->SetItemTooltip(i, m_colours[i-1].GetAsString(wxC2S_HTML_SYNTAX));
}
}
c_editor->SetSelection(0);
c_editor->SetName(wxString::Format("%d", id));
c_editor->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &evt) {
auto *com_box = static_cast<ComboBox *>(evt.GetEventObject());
int i = atoi(com_box->GetName().c_str());
if (i < m_cluster_map_filaments.size()) { m_cluster_map_filaments[i] = com_box->GetSelection(); }
evt.StopPropagation();
});
return c_editor;
}
void ObjColorPanel::deal_approximate_match_btn()
{
auto calc_color_distance = [](wxColour c1, wxColour c2) {
float lab[2][3];
RGB2Lab(c1.Red(), c1.Green(), c1.Blue(), &lab[0][0], &lab[0][1], &lab[0][2]);
RGB2Lab(c2.Red(), c2.Green(), c2.Blue(), &lab[1][0], &lab[1][1], &lab[1][2]);
return DeltaE76(lab[0][0], lab[0][1], lab[0][2], lab[1][0], lab[1][1], lab[1][2]);
};
m_warning_text->SetLabelText("");
if (m_result_icon_list.size() == 0) { return; }
auto map_count = m_result_icon_list[0]->bitmap_combox->GetCount() -1;
if (map_count < 1) { return; }
for (size_t i = 0; i < m_cluster_colours.size(); i++) {
auto c = m_cluster_colours[i];
std::vector<ColorDistValue> color_dists;
color_dists.resize(map_count);
for (size_t j = 0; j < map_count; j++) {
auto tip_color = m_result_icon_list[0]->bitmap_combox->GetItemTooltip(j+1);
wxColour candidate_c(tip_color);
color_dists[j].distance = calc_color_distance(c, candidate_c);
color_dists[j].id = j + 1;
}
std::sort(color_dists.begin(), color_dists.end(), [](ColorDistValue &a, ColorDistValue& b) {
return a.distance < b.distance;
});
auto new_index= color_dists[0].id;
m_result_icon_list[i]->bitmap_combox->SetSelection(new_index);
m_cluster_map_filaments[i] = new_index;
}
}
void ObjColorPanel::show_sizer(wxSizer *sizer, bool show)
{
wxSizerItemList items = sizer->GetChildren();
for (wxSizerItemList::iterator it = items.begin(); it != items.end(); ++it) {
wxSizerItem *item = *it;
if (wxWindow *window = item->GetWindow()) {
window->Show(show);
}
if (wxSizer *son_sizer = item->GetSizer()) {
show_sizer(son_sizer, show);
}
}
}
void ObjColorPanel::redraw_part_table() {
//show all and set -1
deal_reset_btn();
for (size_t i = 0; i < m_row_sizer_list.size(); i++) {
show_sizer(m_row_sizer_list[i], true);
}
if (m_cluster_colours.size() < m_row_sizer_list.size()) { // show part
for (size_t i = m_cluster_colours.size(); i < m_row_sizer_list.size(); i++) {
show_sizer(m_row_sizer_list[i], false);
//m_row_panel_list[i]->Show(false); // show_sizer(m_left_color_cluster_boxsizer_list[i],false);
// m_result_icon_list[i]->bitmap_combox->Show(false);
}
} else if (m_cluster_colours.size() > m_row_sizer_list.size()) {
for (size_t i = m_row_sizer_list.size(); i < m_cluster_colours.size(); i++) {
int id = i;
wxPanel *row_panel = new wxPanel(m_scrolledWindow);
row_panel->SetBackgroundColour((i+1) % 2 == 0 ? *wxWHITE : wxColour(238, 238, 238));
auto row_sizer = new wxGridSizer(1, 2, 1, 3);
row_panel->SetSizer(row_sizer);
row_panel->SetMinSize(wxSize(FromDIP(PANEL_WIDTH), -1));
row_panel->SetMaxSize(wxSize(FromDIP(PANEL_WIDTH), -1));
auto cluster_color_icon_sizer = create_color_icon_and_rgba_sizer(row_panel, id, m_cluster_colours[id]);
row_sizer->Add(cluster_color_icon_sizer, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, FromDIP(CONTENT_BORDER));
// result_combox
create_result_button_sizer(row_panel, id);
row_sizer->Add(m_result_icon_list[id]->bitmap_combox, 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL, 0);
m_row_sizer_list.emplace_back(row_sizer);
m_gridsizer->Add(row_panel, 0, wxALIGN_LEFT | wxALL, FromDIP(HEADER_BORDER));
}
m_gridsizer->Layout();
}
for (size_t i = 0; i < m_cluster_colours.size(); i++) { // update data
// m_color_cluster_icon_list//m_color_cluster_text_list
update_color_icon_and_rgba_sizer(i, m_cluster_colours[i]);
}
m_scrolledWindow->Refresh();
}
void ObjColorPanel::draw_table()
{
auto row = std::max(m_cluster_colours.size(), m_colours.size()) + 1;
m_gridsizer = new wxGridSizer(row, 1, 1, 3); //(int rows, int cols, int vgap, int hgap );
m_color_cluster_icon_list.clear();
m_extruder_icon_list.clear();
float row_height ;
for (size_t ii = 0; ii < row; ii++) {
wxPanel *row_panel = new wxPanel(m_scrolledWindow);
row_panel->SetBackgroundColour(ii % 2 == 0 ? *wxWHITE : wxColour(238, 238, 238));
auto row_sizer = new wxGridSizer(1, 2, 1, 5);
row_panel->SetSizer(row_sizer);
row_panel->SetMinSize(wxSize(FromDIP(PANEL_WIDTH), -1));
row_panel->SetMaxSize(wxSize(FromDIP(PANEL_WIDTH), -1));
if (ii == 0) {
wxStaticText *colors_left_title = new wxStaticText(row_panel, wxID_ANY, _L("Cluster colors"));
colors_left_title->SetFont(Label::Head_14);
row_sizer->Add(colors_left_title, 0, wxALIGN_CENTER | wxALL, FromDIP(HEADER_BORDER));
wxStaticText *colors_middle_title = new wxStaticText(row_panel, wxID_ANY, _L("Map Filament"));
colors_middle_title->SetFont(Label::Head_14);
row_sizer->Add(colors_middle_title, 0, wxALIGN_CENTER | wxALL, FromDIP(HEADER_BORDER));
} else {
int id = ii - 1;
if (id < m_cluster_colours.size()) {
auto cluster_color_icon_sizer = create_color_icon_and_rgba_sizer(row_panel, id, m_cluster_colours[id]);
row_sizer->Add(cluster_color_icon_sizer, 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL, FromDIP(CONTENT_BORDER));
// result_combox
create_result_button_sizer(row_panel, id);
row_sizer->Add(m_result_icon_list[id]->bitmap_combox, 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL, FromDIP(CONTENT_BORDER));
}
}
row_height = row_panel->GetSize().GetHeight();
if (ii>=1) {
m_row_sizer_list.emplace_back(row_sizer);
}
m_gridsizer->Add(row_panel, 0, wxALIGN_LEFT | wxALL, FromDIP(HEADER_BORDER));
}
m_scrolledWindow->SetSizer(m_gridsizer);
int totalHeight = row_height *(row+1) * 2;
m_scrolledWindow->SetVirtualSize(MIN_OBJCOLOR_DIALOG_WIDTH, totalHeight);
auto look = FIX_SCROLL_HEIGTH;
if (totalHeight > FIX_SCROLL_HEIGTH) {
m_scrolledWindow->SetMinSize(wxSize(MIN_OBJCOLOR_DIALOG_WIDTH, FIX_SCROLL_HEIGTH));
m_scrolledWindow->SetMaxSize(wxSize(MIN_OBJCOLOR_DIALOG_WIDTH, FIX_SCROLL_HEIGTH));
}
else {
m_scrolledWindow->SetMinSize(wxSize(MIN_OBJCOLOR_DIALOG_WIDTH, totalHeight));
}
m_scrolledWindow->EnableScrolling(false, true);
m_scrolledWindow->ShowScrollbars(wxSHOW_SB_NEVER, wxSHOW_SB_DEFAULT);//wxSHOW_SB_ALWAYS
m_scrolledWindow->SetScrollRate(20, 20);
}
void ObjColorPanel::deal_algo(char cluster_number, bool redraw_ui)
{
if (m_last_cluster_number == cluster_number) {
return;
}
m_last_cluster_number = cluster_number;
QuantKMeans quant(10);
quant.apply(m_input_colors, m_cluster_colors_from_algo, m_cluster_labels_from_algo, (int)cluster_number);
m_cluster_colours.clear();
m_cluster_colours.reserve(m_cluster_colors_from_algo.size());
for (size_t i = 0; i < m_cluster_colors_from_algo.size(); i++) {
m_cluster_colours.emplace_back(convert_to_wxColour(m_cluster_colors_from_algo[i]));
}
if (m_cluster_colours.size() == 0) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ",m_cluster_colours.size() = 0\n";
return;
}
m_cluster_map_filaments.resize(m_cluster_colors_from_algo.size());
m_color_cluster_num_by_algo = m_cluster_colors_from_algo.size();
if (cluster_number == -1) {
m_color_num_recommend = m_color_cluster_num_by_algo;
}
//redraw ui
if (redraw_ui) {
redraw_part_table();
deal_default_strategy();
}
}
void ObjColorPanel::deal_default_strategy()
{
deal_add_btn();
deal_approximate_match_btn();
m_warning_text->SetLabelText(_L("Note:The color has been selected, you can choose OK \n to continue or manually adjust it."));
}
void ObjColorPanel::deal_add_btn()
{
if (m_colours.size() > g_max_color) { return; }
deal_reset_btn();
std::vector<wxBitmap *> new_icons;
auto new_color_size = m_cluster_colors_from_algo.size();
new_icons.reserve(new_color_size);
m_new_add_colors.clear();
m_new_add_colors.reserve(new_color_size);
int new_index = m_colours.size() + 1;
bool is_exceed = false;
for (size_t i = 0; i < new_color_size; i++) {
if (m_colours.size() + new_icons.size() >= g_max_color) {
is_exceed = true;
break;
}
wxColour cur_color = convert_to_wxColour(m_cluster_colors_from_algo[i]);
m_new_add_colors.emplace_back(cur_color);
new_icons.emplace_back(get_extruder_color_icon(cur_color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(),
std::to_string(new_index), m_combox_icon_width, m_combox_icon_height));
new_index++;
}
new_index = m_colours.size() + 1;
for (size_t i = 0; i < m_result_icon_list.size(); i++) {
auto item = m_result_icon_list[i];
for (size_t k = 0; k < new_icons.size(); k++) {
item->bitmap_combox->Append(wxString::Format("%d", item->bitmap_combox->GetCount()), *new_icons[k]);
item->bitmap_combox->SetItemTooltip(item->bitmap_combox->GetCount() -1,m_new_add_colors[k].GetAsString(wxC2S_HTML_SYNTAX));
}
item->bitmap_combox->SetSelection(new_index);
m_cluster_map_filaments[i] = new_index;
new_index++;
}
if (is_exceed) {
deal_approximate_match_btn();
m_warning_text->SetLabelText(_L("Waring:The count of newly added and \n current extruders exceeds 16."));
}
m_is_add_filament = true;
}
void ObjColorPanel::deal_reset_btn()
{
for (auto item : m_result_icon_list) {
// delete redundant bitmap
while (item->bitmap_combox->GetCount() > m_colours.size()+ 1) {
item->bitmap_combox->DeleteOneItem(item->bitmap_combox->GetCount() - 1);
}
item->bitmap_combox->SetSelection(0);
}
m_is_add_filament = false;
m_new_add_colors.clear();
m_warning_text->SetLabelText("");
}
void ObjColorPanel::create_result_button_sizer(wxWindow *parent, int id)
{
for (size_t i = m_result_icon_list.size(); i < id + 1; i++) {
m_result_icon_list.emplace_back(new ButtonState());
}
m_result_icon_list[id]->bitmap_combox = CreateEditorCtrl(parent,id);
}
wxBoxSizer *ObjColorPanel::create_color_icon_and_rgba_sizer(wxWindow *parent, int id, const wxColour& color)
{
auto icon_sizer = new wxBoxSizer(wxHORIZONTAL);
icon_sizer->AddSpacer(FromDIP(40));
wxButton *icon = new wxButton(parent, wxID_ANY, {}, wxDefaultPosition, ICON_SIZE, wxBORDER_NONE | wxBU_AUTODRAW);
icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(id + 1), FromDIP(16), FromDIP(16)));
icon->SetCanFocus(false);
m_color_cluster_icon_list.emplace_back(icon);
icon_sizer->Add(icon, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 0); // wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM
icon_sizer->AddSpacer(FromDIP(10));
std::string message = get_color_str(color);
wxStaticText *rgba_title = new wxStaticText(parent, wxID_ANY, message.c_str());
m_color_cluster_text_list.emplace_back(rgba_title);
rgba_title->SetMinSize(wxSize(FromDIP(COLOR_LABEL_WIDTH), -1));
rgba_title->SetMaxSize(wxSize(FromDIP(COLOR_LABEL_WIDTH), -1));
//rgba_title->SetFont(Label::Head_12);
icon_sizer->Add(rgba_title, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 0);
return icon_sizer;
}
void ObjColorPanel::update_color_icon_and_rgba_sizer(int id, const wxColour &color)
{
if (id < m_color_cluster_text_list.size()) {
auto icon = m_color_cluster_icon_list[id];
icon->SetBitmap(*get_extruder_color_icon(color.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(id + 1), FromDIP(16), FromDIP(16)));
std::string message = get_color_str(color);
m_color_cluster_text_list[id]->SetLabelText(message.c_str());
}
}
+114
View File
@@ -0,0 +1,114 @@
#ifndef _OBJ_COLOR_DIALOG_H_
#define _OBJ_COLOR_DIALOG_H_
#include "GUI_Utils.hpp"
#include "libslic3r/Color.hpp"
#include <wx/sizer.h>
#include <wx/spinctrl.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/checkbox.h>
#include <wx/msgdlg.h>
class Button;
class Label;
class ComboBox;
struct ColorDistValue
{
int id;
float distance;
};
class ObjColorPanel : public wxPanel
{
public:
// BBS
ObjColorPanel(wxWindow * parent,
std::vector<Slic3r::RGBA> & input_colors,bool is_single_color,
const std::vector<std::string> & extruder_colours,
std::vector<unsigned char> & filament_ids,
unsigned char & first_extruder_id);
void msw_rescale();
bool is_ok();
void update_filament_ids();
struct ButtonState
{
ComboBox* bitmap_combox{nullptr};
bool is_map{false};//int id{0};
};
private:
wxBoxSizer *create_approximate_match_btn_sizer(wxWindow *parent);
wxBoxSizer *create_add_btn_sizer(wxWindow *parent);
wxBoxSizer *create_reset_btn_sizer(wxWindow *parent);
wxBoxSizer *create_extruder_icon_and_rgba_sizer(wxWindow *parent, int id, const wxColour& color);
std::string get_color_str(const wxColour &color);
void create_result_button_sizer(wxWindow *parent, int id);
wxBoxSizer *create_color_icon_and_rgba_sizer(wxWindow *parent, int id, const wxColour& color);
void update_color_icon_and_rgba_sizer(int id, const wxColour &color);
ComboBox* CreateEditorCtrl(wxWindow *parent,int id);
void draw_table();
void show_sizer(wxSizer *sizer, bool show);
void redraw_part_table();
void deal_approximate_match_btn();
void deal_add_btn();
void deal_reset_btn();
void deal_algo(char cluster_number,bool redraw_ui =false);
void deal_default_strategy();
private:
//view ui
wxScrolledWindow * m_scrolledWindow = nullptr;
wxPanel * m_page_simple = nullptr;
wxBoxSizer * m_sizer = nullptr;
wxBoxSizer * m_sizer_simple = nullptr;
wxTextCtrl *m_color_cluster_num_by_user_ebox{nullptr};
wxStaticText * m_warning_text{nullptr};
Button * m_quick_approximate_match_btn{nullptr};
Button * m_quick_add_btn{nullptr};
Button * m_quick_reset_btn{nullptr};
std::vector<wxButton*> m_extruder_icon_list;
std::vector<wxButton*> m_color_cluster_icon_list;//need modeify
std::vector<wxStaticText*> m_color_cluster_text_list;//need modeify
std::vector<wxGridSizer*> m_row_sizer_list; // control show or not
std::vector<ButtonState*> m_result_icon_list;
int m_last_cluster_num{-1};
const int m_combox_width{50};
int m_combox_icon_width;
int m_combox_icon_height;
wxGridSizer* m_gridsizer = nullptr;
wxStaticText * m_test = nullptr;
//data
char m_last_cluster_number{-2};
std::vector<Slic3r::RGBA>& m_input_colors;
int m_color_num_recommend{0};
int m_color_cluster_num_by_algo{0};
int m_input_colors_size{0};
std::vector<wxColour> m_colours;//from project and show right
std::vector<int> m_cluster_map_filaments;//show middle
std::vector<wxColour> m_cluster_colours;//from_algo and show left
bool m_can_add_filament{true};
std::vector<wxColour> m_new_add_colors;
//algo result
std::vector<Slic3r::RGBA> m_cluster_colors_from_algo;
std::vector<int> m_cluster_labels_from_algo;
//result
bool m_is_add_filament{false};
unsigned char& m_first_extruder_id;
std::vector<unsigned char> &m_filament_ids;
};
class ObjColorDialog : public Slic3r::GUI::DPIDialog
{
public:
ObjColorDialog(wxWindow * parent,
std::vector<Slic3r::RGBA>& input_colors, bool is_single_color,
const std::vector<std::string> & extruder_colours,
std::vector<unsigned char>& filament_ids,
unsigned char & first_extruder_id);
wxBoxSizer* create_btn_sizer(long flags);
void on_dpi_changed(const wxRect &suggested_rect) override;
private:
ObjColorPanel* m_panel_ObjColor = nullptr;
std::unordered_map<int, Button *> m_button_list;
std::vector<unsigned char>& m_filament_ids;
unsigned char & m_first_extruder_id;
};
#endif // _WIPE_TOWER_DIALOG_H_
+1 -8
View File
@@ -1580,14 +1580,7 @@ std::vector<int> PartPlate::get_used_extruders()
std::set<int> used_extruders_set;
PrintEstimatedStatistics& ps = result->print_statistics;
// model usage
for (const auto&item:ps.volumes_per_extruder)
used_extruders_set.emplace(item.first + 1);
// support usage
for (const auto&item:ps.support_volumes_per_extruder)
used_extruders_set.emplace(item.first + 1);
// wipe tower usage
for (const auto&item:ps.wipe_tower_volumes_per_extruder)
for (const auto& item : ps.total_volumes_per_extruder)
used_extruders_set.emplace(item.first + 1);
return std::vector(used_extruders_set.begin(), used_extruders_set.end());
+174 -43
View File
@@ -116,6 +116,7 @@
#include "Jobs/BoostThreadWorker.hpp"
#include "BackgroundSlicingProcess.hpp"
#include "SelectMachine.hpp"
#include "SendMultiMachinePage.hpp"
#include "SendToPrinter.hpp"
#include "PublishDialog.hpp"
#include "ModelMall.hpp"
@@ -156,6 +157,7 @@
#include <libslic3r/CutUtils.hpp>
#include <wx/glcanvas.h> // Needs to be last because reasons :-/
#include "WipeTowerDialog.hpp"
#include "ObjColorDialog.hpp"
#include "libslic3r/CustomGCode.hpp"
#include "libslic3r/Platform.hpp"
@@ -209,7 +211,9 @@ wxDEFINE_EVENT(EVT_PRINT_FROM_SDCARD_VIEW, SimpleEvent);
wxDEFINE_EVENT(EVT_CREATE_FILAMENT, SimpleEvent);
wxDEFINE_EVENT(EVT_MODIFY_FILAMENT, SimpleEvent);
wxDEFINE_EVENT(EVT_ADD_FILAMENT, SimpleEvent);
wxDEFINE_EVENT(EVT_DEL_FILAMENT, SimpleEvent);
wxDEFINE_EVENT(EVT_ADD_CUSTOM_FILAMENT, ColorEvent);
bool Plater::has_illegal_filename_characters(const wxString& wxs_name)
{
std::string name = into_u8(wxs_name);
@@ -431,7 +435,7 @@ void Sidebar::priv::show_preset_comboboxes()
void Sidebar::priv::on_search_update()
{
m_object_list->assembly_plate_object_name();
wxString search_text = m_search_bar->GetValue();
m_object_list->GetModel()->search_object(search_text);
dia->update_list();
@@ -491,37 +495,63 @@ void Sidebar::priv::hide_rich_tip(wxButton* btn)
}
#endif
std::vector<int> get_min_flush_volumes()
std::vector<int> get_min_flush_volumes(const DynamicPrintConfig& full_config)
{
std::vector<int>extra_flush_volumes;
const auto& full_config = wxGetApp().preset_bundle->full_config();
auto& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
//const auto& full_config = wxGetApp().preset_bundle->full_config();
//auto& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
ConfigOption* nozzle_volume_opt = printer_config.option("nozzle_volume");
const ConfigOption* nozzle_volume_opt = full_config.option("nozzle_volume");
int nozzle_volume_val = nozzle_volume_opt ? (int)nozzle_volume_opt->getFloat() : 0;
int machine_enabled_level = printer_config.option<ConfigOptionInt>("enable_long_retraction_when_cut")->value;
bool machine_activated = printer_config.option<ConfigOptionBools>("long_retractions_when_cut")->values[0] == 1;
const ConfigOptionInt* enable_long_retraction_when_cut_opt = full_config.option<ConfigOptionInt>("enable_long_retraction_when_cut");
int machine_enabled_level = 0;
if (enable_long_retraction_when_cut_opt) {
machine_enabled_level = enable_long_retraction_when_cut_opt->value;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": get enable_long_retraction_when_cut from config, value=%1%")%machine_enabled_level;
}
const ConfigOptionBools* long_retractions_when_cut_opt = full_config.option<ConfigOptionBools>("long_retractions_when_cut");
bool machine_activated = false;
if (long_retractions_when_cut_opt) {
machine_activated = long_retractions_when_cut_opt->values[0] == 1;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": get long_retractions_when_cut from config, value=%1%, activated=%2%")%long_retractions_when_cut_opt->values[0] %machine_activated;
}
auto filament_retraction_distance_when_cut = full_config.option<ConfigOptionFloats>("filament_retraction_distances_when_cut");
auto printer_retraction_distance_when_cut = full_config.option<ConfigOptionFloats>("retraction_distances_when_cut");
auto filament_long_retractions_when_cut = full_config.option<ConfigOptionBools>("filament_long_retractions_when_cut");
size_t filament_size = full_config.option<ConfigOptionFloats>("filament_diameter")->values.size();
std::vector<double> filament_retraction_distance_when_cut(filament_size, 18.0f), printer_retraction_distance_when_cut(filament_size, 18.0f);
std::vector<unsigned char> filament_long_retractions_when_cut(filament_size, 0);
const ConfigOptionFloats* filament_retraction_distances_when_cut_opt = full_config.option<ConfigOptionFloats>("filament_retraction_distances_when_cut");
if (filament_retraction_distances_when_cut_opt) {
filament_retraction_distance_when_cut = filament_retraction_distances_when_cut_opt->values;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": get filament_retraction_distance_when_cut from config, size=%1%, values=%2%")%filament_retraction_distance_when_cut.size() %filament_retraction_distances_when_cut_opt->serialize();
}
const ConfigOptionFloats* printer_retraction_distance_when_cut_opt = full_config.option<ConfigOptionFloats>("retraction_distances_when_cut");
if (printer_retraction_distance_when_cut_opt) {
printer_retraction_distance_when_cut = printer_retraction_distance_when_cut_opt->values;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": get retraction_distances_when_cut from config, size=%1%, values=%2%")%printer_retraction_distance_when_cut.size() %printer_retraction_distance_when_cut_opt->serialize();
}
const ConfigOptionBools* filament_long_retractions_when_cut_opt = full_config.option<ConfigOptionBools>("filament_long_retractions_when_cut");
if (filament_long_retractions_when_cut_opt) {
filament_long_retractions_when_cut = filament_long_retractions_when_cut_opt->values;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": get filament_long_retractions_when_cut from config, size=%1%, values=%2%")%filament_long_retractions_when_cut.size() %filament_long_retractions_when_cut_opt->serialize();
}
size_t filament_size = filament_retraction_distance_when_cut->values.size();
for (size_t idx = 0; idx < filament_size; ++idx) {
int extra_flush_volume = nozzle_volume_val;
int retract_length = machine_enabled_level && machine_activated ? printer_retraction_distance_when_cut->values[0] : 0;
int retract_length = machine_enabled_level && machine_activated ? printer_retraction_distance_when_cut[0] : 0;
char filament_activated = filament_long_retractions_when_cut->values[idx];
double filament_retract_length = filament_retraction_distance_when_cut->values[idx];
unsigned char filament_activated = filament_long_retractions_when_cut[idx];
double filament_retract_length = filament_retraction_distance_when_cut[idx];
if (filament_activated == 0)
retract_length = 0;
else if (filament_activated == 1 && machine_enabled_level == LongRectrationLevel::EnableFilament) {
if (!std::isnan(filament_retract_length))
retract_length = (int)filament_retraction_distance_when_cut->values[idx];
retract_length = (int)filament_retraction_distance_when_cut[idx];
else
retract_length = printer_retraction_distance_when_cut->values[0];
retract_length = printer_retraction_distance_when_cut[0];
}
extra_flush_volume -= PI * 1.75 * 1.75 / 4 * retract_length;
@@ -849,7 +879,8 @@ Sidebar::Sidebar(Plater *parent)
float flush_multiplier = flush_multi_opt ? flush_multi_opt->getFloat() : 1.f;
const std::vector<std::string> extruder_colours = wxGetApp().plater()->get_extruder_colors_from_plater_config();
const auto& extra_flush_volumes = get_min_flush_volumes();
const auto& full_config = wxGetApp().preset_bundle->full_config();
const auto& extra_flush_volumes = get_min_flush_volumes(full_config);
WipingDialog dlg(parent, cast<float>(init_matrix), cast<float>(init_extruders), extruder_colours, extra_flush_volumes, flush_multiplier);
if (dlg.ShowModal() == wxID_OK) {
std::vector<float> matrix = dlg.get_matrix();
@@ -1266,7 +1297,7 @@ void Sidebar::update_presets(Preset::Type preset_type)
if (preset) {
if (preset->is_compatible) preset_bundle.set_filament_preset(0, name);
}
}
for (size_t i = 0; i < filament_cnt; i++)
@@ -1559,6 +1590,43 @@ void Sidebar::on_filaments_change(size_t num_filaments)
dynamic_filament_list.update();
}
void Sidebar::add_filament() {
// BBS: limit filament choices to 16
if (p->combos_filament.size() >= 16) return;
wxColour new_col = Plater::get_next_color_for_filament();
add_custom_filament(new_col);
}
void Sidebar::delete_filament() {
if (p->combos_filament.size() <= 1) return;
size_t filament_count = p->combos_filament.size() - 1;
if (wxGetApp().preset_bundle->is_the_only_edited_filament(filament_count) || (filament_count == 1)) {
wxGetApp().get_tab(Preset::TYPE_FILAMENT)->select_preset(wxGetApp().preset_bundle->filament_presets[0], false, "", true);
}
if (p->editing_filament >= filament_count) {
p->editing_filament = -1;
}
wxGetApp().preset_bundle->set_num_filaments(filament_count);
wxGetApp().plater()->on_filaments_change(filament_count);
wxGetApp().get_tab(Preset::TYPE_PRINT)->update();
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
}
void Sidebar::add_custom_filament(wxColour new_col) {
if (p->combos_filament.size() >= 16) return;
int filament_count = p->combos_filament.size() + 1;
std::string new_color = new_col.GetAsString(wxC2S_HTML_SYNTAX).ToStdString();
wxGetApp().preset_bundle->set_num_filaments(filament_count, new_color);
wxGetApp().plater()->on_filaments_change(filament_count);
wxGetApp().get_tab(Preset::TYPE_PRINT)->update();
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
auto_calc_flushing_volumes(filament_count - 1);
}
void Sidebar::on_bed_type_change(BedType bed_type)
{
// btDefault option is not included in global bed type setting
@@ -1894,13 +1962,14 @@ void Sidebar::auto_calc_flushing_volumes(const int modify_id)
auto& preset_bundle = wxGetApp().preset_bundle;
auto& project_config = preset_bundle->project_config;
auto& printer_config = preset_bundle->printers.get_edited_preset().config;
const auto& full_config = wxGetApp().preset_bundle->full_config();
auto& ams_multi_color_filament = preset_bundle->ams_multi_color_filment;
auto& ams_filament_list = preset_bundle->filament_ams_list;
const std::vector<double>& init_matrix = (project_config.option<ConfigOptionFloats>("flush_volumes_matrix"))->values;
const std::vector<double>& init_extruders = (project_config.option<ConfigOptionFloats>("flush_volumes_vector"))->values;
const std::vector<int>& min_flush_volumes= get_min_flush_volumes();
const std::vector<int>& min_flush_volumes= get_min_flush_volumes(full_config);
ConfigOptionFloat* flush_multi_opt = project_config.option<ConfigOptionFloat>("flush_multiplier");
float flush_multiplier = flush_multi_opt ? flush_multi_opt->getFloat() : 1.f;
@@ -2077,6 +2146,7 @@ struct Plater::priv
MenuFactory menus;
SelectMachineDialog* m_select_machine_dlg = nullptr;
SendMultiMachinePage* m_send_multi_dlg = nullptr;
SendToPrinterDialog* m_send_to_sdcard_dlg = nullptr;
PublishDialog *m_publish_dlg = nullptr;
@@ -2424,6 +2494,9 @@ struct Plater::priv
void on_action_layersediting(SimpleEvent&);
void on_create_filament(SimpleEvent &);
void on_modify_filament(SimpleEvent &);
void on_add_filament(SimpleEvent &);
void on_delete_filament(SimpleEvent &);
void on_add_custom_filament(ColorEvent &);
void on_object_select(SimpleEvent&);
void show_right_click_menu(Vec2d mouse_position, wxMenu *menu);
@@ -2540,6 +2613,7 @@ struct Plater::priv
//BBS: add popup object table logic
bool PopupObjectTable(int object_id, int volume_id, const wxPoint& position);
void on_action_send_to_printer(bool isall = false);
void on_action_send_to_multi_machine(SimpleEvent&);
int update_print_required_data(Slic3r::DynamicPrintConfig config, Slic3r::Model model, Slic3r::PlateDataPtrs plate_data_list, std::string file_name, std::string file_path);
private:
bool layers_height_allowed() const;
@@ -2580,7 +2654,6 @@ private:
//record print preset
void record_start_print_preset(std::string action);
};
const std::regex Plater::priv::pattern_bundle(".*[.](amf|amf[.]xml|zip[.]amf|3mf)", std::regex::icase);
@@ -2698,7 +2771,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
this->q->Bind(wxEVT_SYS_COLOUR_CHANGED, &priv::on_apple_change_color_mode, this);
this->q->Bind(EVT_CREATE_FILAMENT, &priv::on_create_filament, this);
this->q->Bind(EVT_MODIFY_FILAMENT, &priv::on_modify_filament, this);
this->q->Bind(EVT_ADD_CUSTOM_FILAMENT, &priv::on_add_custom_filament, this);
main_frame->m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGING, &priv::on_tab_selection_changing, this);
auto* panel_3d = new wxPanel(q);
@@ -2969,6 +3042,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
q->Bind(EVT_GLTOOLBAR_EXPORT_ALL_SLICED_FILE, &priv::on_action_export_all_sliced_file, this);
q->Bind(EVT_GLTOOLBAR_SEND_TO_PRINTER, &priv::on_action_export_to_sdcard, this);
q->Bind(EVT_GLTOOLBAR_SEND_TO_PRINTER_ALL, &priv::on_action_export_to_sdcard_all, this);
q->Bind(EVT_GLTOOLBAR_PRINT_MULTI_MACHINE, &priv::on_action_send_to_multi_machine, this);
q->Bind(EVT_GLCANVAS_PLATE_SELECT, &priv::on_plate_selected, this);
q->Bind(EVT_DOWNLOAD_PROJECT, &priv::on_action_download_project, this);
q->Bind(EVT_IMPORT_MODEL_ID, &priv::on_action_request_model_id, this);
@@ -3941,7 +4015,17 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
std::vector<Preset *> project_presets;
bool is_xxx;
Semver file_version;
//ObjImportColorFn obj_color_fun=nullptr;
auto obj_color_fun = [this, &path](std::vector<RGBA> &input_colors, bool is_single_color, std::vector<unsigned char> &filament_ids,
unsigned char &first_extruder_id) {
if (!boost::iends_with(path.string(), ".obj")) { return; }
const std::vector<std::string> extruder_colours = wxGetApp().plater()->get_extruder_colors_from_plater_config();
ObjColorDialog color_dlg(nullptr, input_colors, is_single_color, extruder_colours, filament_ids, first_extruder_id);
if (color_dlg.ShowModal() != wxID_OK) {
filament_ids.clear();
}
};
model = Slic3r::Model::read_from_file(
path.string(), nullptr, nullptr, strategy, &plate_data, &project_presets, &is_xxx, &file_version, nullptr,
[this, &dlg, real_filename, &progress_percent, &file_percent, INPUT_FILES_RATIO, total_files, i, &designer_model_id, &designer_country_code](int current, int total, bool &cancel, std::string &mode_id, std::string &code)
@@ -3971,7 +4055,8 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
if (!isUtf8StepFile)
Slic3r::GUI::show_info(nullptr, _L("Name of components inside step file is not UTF8 format!") + "\n\n" + _L("The name may show garbage characters!"),
_L("Attention!"));
});
},
nullptr, 0, obj_color_fun);
if (designer_model_id.empty() && boost::algorithm::iends_with(path.string(), ".stl")) {
@@ -6959,6 +7044,14 @@ void Plater::priv::on_action_print_plate(SimpleEvent&)
record_start_print_preset("print_plate");
}
void Plater::priv::on_action_send_to_multi_machine(SimpleEvent&)
{
if (!m_send_multi_dlg)
m_send_multi_dlg = new SendMultiMachinePage(q);
m_send_multi_dlg->prepare(partplate_list.get_curr_plate_index());
m_send_multi_dlg->ShowModal();
}
void Plater::priv::on_action_print_plate_from_sdcard(SimpleEvent&)
{
if (q != nullptr) {
@@ -7018,6 +7111,7 @@ void Plater::priv::on_action_send_to_printer(bool isall)
m_send_to_sdcard_dlg->ShowModal();
}
void Plater::priv::on_action_select_sliced_plate(wxCommandEvent &evt)
{
if (q != nullptr) {
@@ -7088,7 +7182,6 @@ void Plater::priv::on_action_export_to_sdcard_all(SimpleEvent&)
}
}
//BBS: add plate select logic
void Plater::priv::on_plate_selected(SimpleEvent&)
{
@@ -8071,6 +8164,19 @@ void Plater::priv::on_modify_filament(SimpleEvent &evt)
}
void Plater::priv::on_add_filament(SimpleEvent &evt) {
sidebar->add_filament();
}
void Plater::priv::on_delete_filament(SimpleEvent &evt) {
sidebar->delete_filament();
}
void Plater::priv::on_add_custom_filament(ColorEvent &evt)
{
sidebar->add_custom_filament(evt.data);
}
void Plater::priv::enter_gizmos_stack()
{
assert(m_undo_redo_stack_active == &m_undo_redo_stack_main);
@@ -8628,7 +8734,7 @@ int Plater::new_project(bool skip_confirm, bool silent, const wxString& project_
void Plater::load_project(wxString const& filename2,
wxString const& originfile)
{
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "filename is: " << filename2 << "and originfile is: " << originfile;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "filename is: " << filename2 << "and originfile is: " << originfile;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__;
auto filename = filename2;
auto check = [&filename, this] (bool yes_or_no) {
@@ -8702,13 +8808,13 @@ void Plater::load_project(wxString const& filename2,
if (load_restore && originfile.IsEmpty()) {
p->set_project_name(_L("Untitled"));
}
} else {
if (using_exported_file()) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " using ecported set project filename: " << filename;
p->set_project_filename(filename);
}
}
// BBS set default 3D view and direction after loading project
@@ -8869,6 +8975,14 @@ void Plater::import_model_id(wxString download_info)
{
vecFiles.clear();
wxString extension = fs::path(filename.wx_str()).extension().c_str();
//check file suffix
if (!extension.Contains(".3mf")) {
msg = _L("Download failed, unknown file format.");
return;
}
auto name = filename.substr(0, filename.length() - extension.length() - 1);
for (const auto& iter : boost::filesystem::directory_iterator(target_path))
@@ -8916,17 +9030,35 @@ void Plater::import_model_id(wxString download_info)
fs::path tmp_path = target_path;
tmp_path += format(".%1%", ".download");
auto filesize = 0;
bool size_limit = false;
auto http = Http::get(download_url.ToStdString());
while (cont && retry_count < max_retries) {
retry_count++;
http.on_progress([&percent, &cont, &msg](Http::Progress progress, bool& cancel) {
http.on_progress([&percent, &cont, &msg, &filesize, &size_limit](Http::Progress progress, bool& cancel) {
if (!cont) cancel = true;
if (progress.dltotal != 0) {
if (filesize == 0) {
filesize = progress.dltotal;
double megabytes = static_cast<double>(progress.dltotal) / (1024 * 1024);
//The maximum size of a 3mf file is 500mb
if (megabytes > 500) {
cont = false;
size_limit = true;
}
}
percent = progress.dlnow * 100 / progress.dltotal;
}
msg = wxString::Format(_L("Project downloaded %d%%"), percent);
if (size_limit) {
msg = _L("Download failed, File size exception.");
}
else {
msg = wxString::Format(_L("Project downloaded %d%%"), percent);
}
})
.on_error([&msg, &cont, &retry_count, max_retries](std::string body, std::string error, unsigned http_status) {
(void)body;
@@ -8936,7 +9068,7 @@ void Plater::import_model_id(wxString download_info)
error);
if (retry_count == max_retries) {
msg = _L("Importing to Orca Slicer failed. Please download the file and manually import it.");
msg = _L("Importing to Bambu Studio failed. Please download the file and manually import it.");
cont = false;
}
})
@@ -8985,7 +9117,7 @@ void Plater::import_model_id(wxString download_info)
}
// show save new project
p->set_project_filename(filename);
p->set_project_filename(target_path.wstring());
p->notification_manager->push_import_finished_notification(target_path.string(), target_path.parent_path().string(), false);
}
else {
@@ -8997,7 +9129,6 @@ void Plater::import_model_id(wxString download_info)
return;
}
}
//BBS download project by project id
void Plater::download_project(const wxString& project_id)
{
@@ -9731,14 +9862,12 @@ void Plater::load_gcode(const wxString& filename)
//BBS: add cost info when drag in gcode
auto& ps = current_result->print_statistics;
double total_cost = 0.0;
for (auto& volumes_map : { ps.volumes_per_extruder,ps.flush_per_filament ,ps.wipe_tower_volumes_per_extruder }) {
for (auto volume : volumes_map) {
size_t extruder_id = volume.first;
double density = current_result->filament_densities.at(extruder_id);
double cost = current_result->filament_costs.at(extruder_id);
double weight = volume.second * density * 0.001;
total_cost += weight * cost * 0.001;
}
for (auto volume : ps.total_volumes_per_extruder) {
size_t extruder_id = volume.first;
double density = current_result->filament_densities.at(extruder_id);
double cost = current_result->filament_costs.at(extruder_id);
double weight = volume.second * density * 0.001;
total_cost += weight * cost * 0.001;
}
current_print.print_statistics().total_cost = total_cost;
@@ -9757,7 +9886,7 @@ void Plater::load_gcode(const wxString& filename)
} else {
set_project_filename(filename);
}
}
void Plater::reload_gcode_from_disk()
@@ -11519,6 +11648,7 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy
// get type and color for platedata
auto* filament_color = dynamic_cast<const ConfigOptionStrings*>(cfg.option("filament_colour"));
auto* nozzle_diameter_option = dynamic_cast<const ConfigOptionFloats*>(cfg.option("nozzle_diameter"));
auto* filament_id_opt = dynamic_cast<const ConfigOptionStrings*>(cfg.option("filament_ids"));
std::string nozzle_diameter_str;
if (nozzle_diameter_option)
nozzle_diameter_str = nozzle_diameter_option->serialize();
@@ -11532,6 +11662,7 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy
for (auto it = plate_data->slice_filaments_info.begin(); it != plate_data->slice_filaments_info.end(); it++) {
std::string display_filament_type;
it->type = cfg.get_filament_type(display_filament_type, it->id);
it->filament_id = filament_id_opt ? filament_id_opt->get_at(it->id) : "";
it->color = filament_color ? filament_color->get_at(it->id) : "#FFFFFF";
// save filament info used in curr plate
int index = p->partplate_list.get_curr_plate_index();
+8 -2
View File
@@ -117,7 +117,10 @@ wxDECLARE_EVENT(EVT_GLCANVAS_COLOR_MODE_CHANGED, SimpleEvent);
wxDECLARE_EVENT(EVT_PRINT_FROM_SDCARD_VIEW, SimpleEvent);
wxDECLARE_EVENT(EVT_CREATE_FILAMENT, SimpleEvent);
wxDECLARE_EVENT(EVT_MODIFY_FILAMENT, SimpleEvent);
wxDECLARE_EVENT(EVT_ADD_FILAMENT, SimpleEvent);
wxDECLARE_EVENT(EVT_DEL_FILAMENT, SimpleEvent);
using ColorEvent = Event<wxColour>;
wxDECLARE_EVENT(EVT_ADD_CUSTOM_FILAMENT, ColorEvent);
const wxString DEFAULT_PROJECT_NAME = "Untitled";
class Sidebar : public wxPanel
@@ -153,6 +156,9 @@ public:
void jump_to_option(const std::string& opt_key, Preset::Type type, const std::wstring& category);
// BBS. Add on_filaments_change() method.
void on_filaments_change(size_t num_filaments);
void add_filament();
void delete_filament();
void add_custom_filament(wxColour new_col);
// BBS
void on_bed_type_change(BedType bed_type);
void load_ams_list(std::string const & device, MachineObject* obj);
@@ -827,7 +833,7 @@ private:
bool m_was_scheduled;
};
std::vector<int> get_min_flush_volumes();
std::vector<int> get_min_flush_volumes(const DynamicPrintConfig& full_config);
} // namespace GUI
} // namespace Slic3r
+2
View File
@@ -1046,6 +1046,7 @@ wxWindow* PreferencesDialog::create_general_page()
auto item_calc_mode = create_item_checkbox(_L("Flushing volumes: Auto-calculate everytime the color changed."), page, _L("If enabled, auto-calculate everytime the color changed."), 50, "auto_calculate");
auto item_calc_in_long_retract = create_item_checkbox(_L("Flushing volumes: Auto-calculate every time when the filament is changed."), page, _L("If enabled, auto-calculate every time when filament is changed"), 50, "auto_calculate_when_filament_change");
auto item_remember_printer_config = create_item_checkbox(_L("Remember printer configuration"), page, _L("If enabled, Orca will remember and switch filament/process configuration for each printer automatically."), 50, "remember_printer_config");
auto item_multi_machine = create_item_checkbox(_L("Multi-device Management(Take effect after restarting Studio)."), page, _L("With this option enabled, you can send a task to multiple devices at the same time and manage multiple devices."), 50, "enable_multi_machine");
auto title_presets = create_item_title(_L("Presets"), page, _L("Presets"));
auto title_network = create_item_title(_L("Network"), page, _L("Network"));
auto item_user_sync = create_item_checkbox(_L("Auto sync user presets(Printer/Filament/Process)"), page, _L("User Sync"), 50, "sync_user_preset");
@@ -1111,6 +1112,7 @@ wxWindow* PreferencesDialog::create_general_page()
sizer_page->Add(item_show_splash_screen, 0, wxTOP, FromDIP(3));
sizer_page->Add(item_hints, 0, wxTOP, FromDIP(3));
sizer_page->Add(item_calc_in_long_retract, 0, wxTOP, FromDIP(3));
sizer_page->Add(item_multi_machine, 0, wxTOP, FromDIP(3));
sizer_page->Add(title_presets, 0, wxTOP | wxEXPAND, FromDIP(20));
sizer_page->Add(item_calc_mode, 0, wxTOP, FromDIP(3));
sizer_page->Add(item_user_sync, 0, wxTOP, FromDIP(3));
+37 -68
View File
@@ -36,7 +36,9 @@
#include "../Utils/ASCIIFolding.hpp"
#include "../Utils/FixModelByWin10.hpp"
#include "../Utils/UndoRedo.hpp"
#include "../Utils/ColorSpaceConvert.hpp"
#include "BitmapCache.hpp"
#include "SavePresetDialog.hpp"
#include "MsgDialog.hpp"
#include "ParamsDialog.hpp"
@@ -625,37 +627,6 @@ bool PresetComboBox::selection_is_changed_according_to_physical_printers()
return true;
}
void PlaterPresetComboBox::save_custom_color_to_config(const std::vector<std::string>& colors)
{
auto set_colors = [](std::map<std::string, std::string> &data, const std::vector<std::string> &colors) {
for (size_t i = 0; i < colors.size(); i++) {
data[std::to_string(10 + i)] = colors[i]; //for map sort:10 begin
}
};
if (colors.size() > 0) {
if (!wxGetApp().app_config->has_section("custom_color_list")) {
std::map<std::string, std::string> data;
set_colors(data,colors);
wxGetApp().app_config->set_section("custom_color_list", data);
} else {
auto data = wxGetApp().app_config->get_section("custom_color_list");
auto data_modify = const_cast<std::map<std::string, std::string> *>(&data);
set_colors(*data_modify, colors);
wxGetApp().app_config->set_section("custom_color_list", *data_modify);
}
}
}
std::vector<std::string> PlaterPresetComboBox::get_custom_color_from_config() {
std::vector<std::string> colors;
if (wxGetApp().app_config->has_section("custom_color_list")) {
auto data = wxGetApp().app_config->get_section("custom_color_list");
for (auto iter : data) {
colors.push_back(iter.second);
}
}
return colors;
}
// ---------------------------------
// *** PlaterPresetComboBox ***
// ---------------------------------
@@ -704,21 +675,9 @@ PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset
m_clrData.SetColour(clr_picker->GetBackgroundColour());
m_clrData.SetChooseFull(true);
m_clrData.SetChooseAlpha(false);
auto color_to_string = [](const wxColour& color) {
std::string str = std::to_string(color.Red()) + "," + std::to_string(color.Green()) + "," + std::to_string(color.Blue()) + "," + std::to_string(color.Alpha());
return str;
};
auto string_to_wxColor = [](const std::string& str) {
wxColour color;
std::vector<std::string> result;
boost::split(result, str, boost::is_any_of(","));
if (result.size() == 4) {
color = wxColour(std::stoi(result[0]), std::stoi(result[1]), std::stoi(result[2]), std::stoi(result[3]));
}
return color;
};
std::vector<std::string> colors=get_custom_color_from_config();
for (int i = 0; i < colors.size(); i++) {
std::vector<std::string> colors = wxGetApp().app_config->get_custom_color_from_config();
for (int i = 0; i < colors.size(); i++) {
m_clrData.SetCustomColour(i, string_to_wxColor(colors[i]));
}
wxColourDialog dialog(this, &m_clrData);
@@ -726,13 +685,13 @@ PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset
if ( dialog.ShowModal() == wxID_OK )
{
m_clrData = dialog.GetColourData();
const int custom_color_count = 15;
if (colors.size() != custom_color_count) {
colors.resize(custom_color_count); }
for (int i = 0; i < custom_color_count; i++) {
if (colors.size() != CUSTOM_COLOR_COUNT) {
colors.resize(CUSTOM_COLOR_COUNT);
}
for (int i = 0; i < CUSTOM_COLOR_COUNT; i++) {
colors[i] = color_to_string(m_clrData.GetCustomColour(i));
}
save_custom_color_to_config(colors);
wxGetApp().app_config->save_custom_color_to_config(colors);
// get current color
DynamicPrintConfig* cfg = &wxGetApp().preset_bundle->project_config;
auto colors = static_cast<ConfigOptionStrings*>(cfg->option("filament_colour")->clone());
@@ -999,7 +958,8 @@ void PlaterPresetComboBox::update()
std::map<wxString, wxBitmap*> nonsys_presets;
//BBS: add project embedded presets logic
std::map<wxString, wxBitmap*> project_embedded_presets;
std::map<wxString, wxBitmap*> system_presets;
std::map<wxString, wxBitmap *> system_presets;
std::map<wxString, wxString> preset_descriptions;
//BBS: move system to the end
wxString selected_system_preset;
@@ -1040,13 +1000,15 @@ void PlaterPresetComboBox::update()
wxBitmap* bmp = get_bmp(preset);
assert(bmp);
const std::string name = preset.alias.empty() ? preset.name : preset.alias;
const wxString name = get_preset_name(preset);
preset_descriptions.emplace(name, from_u8(preset.description));
if (preset.is_default || preset.is_system) {
//BBS: move system to the end
system_presets.emplace(get_preset_name(preset), bmp);
system_presets.emplace(name, bmp);
if (is_selected) {
tooltip = get_tooltip(preset);
selected_system_preset = get_preset_name(preset);
selected_system_preset = name;
}
//Append(get_preset_name(preset), *bmp);
//validate_selection(is_selected);
@@ -1057,17 +1019,17 @@ void PlaterPresetComboBox::update()
//BBS: add project embedded preset logic
else if (preset.is_project_embedded)
{
project_embedded_presets.emplace(get_preset_name(preset), bmp);
project_embedded_presets.emplace(name, bmp);
if (is_selected) {
selected_user_preset = get_preset_name(preset);
selected_user_preset = name;
tooltip = wxString::FromUTF8(preset.name.c_str());
}
}
else
{
nonsys_presets.emplace(get_preset_name(preset), bmp);
nonsys_presets.emplace(name, bmp);
if (is_selected) {
selected_user_preset = get_preset_name(preset);
selected_user_preset = name;
//BBS set tooltip
tooltip = get_tooltip(preset);
}
@@ -1084,7 +1046,7 @@ void PlaterPresetComboBox::update()
{
set_label_marker(Append(separator(L("Project-inside presets")), wxNullBitmap));
for (std::map<wxString, wxBitmap*>::iterator it = project_embedded_presets.begin(); it != project_embedded_presets.end(); ++it) {
Append(it->first, *it->second);
SetItemTooltip(Append(it->first, *it->second), preset_descriptions[it->first]);
validate_selection(it->first == selected_user_preset);
}
}
@@ -1092,7 +1054,7 @@ void PlaterPresetComboBox::update()
{
set_label_marker(Append(separator(L("User presets")), wxNullBitmap));
for (std::map<wxString, wxBitmap*>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
Append(it->first, *it->second);
SetItemTooltip(Append(it->first, *it->second), preset_descriptions[it->first]);
validate_selection(it->first == selected_user_preset);
}
}
@@ -1101,7 +1063,7 @@ void PlaterPresetComboBox::update()
{
set_label_marker(Append(separator(L("System presets")), wxNullBitmap));
for (std::map<wxString, wxBitmap*>::iterator it = system_presets.begin(); it != system_presets.end(); ++it) {
Append(it->first, *it->second);
SetItemTooltip(Append(it->first, *it->second), preset_descriptions[it->first]);
validate_selection(it->first == selected_system_preset);
}
}
@@ -1250,6 +1212,7 @@ void TabPresetComboBox::update()
std::map<wxString, std::pair<wxBitmap*, bool>> project_embedded_presets;
//BBS: move system to the end
std::map<wxString, std::pair<wxBitmap*, bool>> system_presets;
std::map<wxString, wxString> preset_descriptions;
wxString selected = "";
//BBS: move system to the end
@@ -1276,11 +1239,14 @@ void TabPresetComboBox::update()
wxBitmap* bmp = get_bmp(preset);
assert(bmp);
const wxString name = get_preset_name(preset);
preset_descriptions.emplace(name, from_u8(preset.description));
if (preset.is_default || preset.is_system) {
//BBS: move system to the end
system_presets.emplace(get_preset_name(preset), std::pair<wxBitmap *, bool>(bmp, is_enabled));
system_presets.emplace(name, std::pair<wxBitmap *, bool>(bmp, is_enabled));
if (i == idx_selected)
selected = get_preset_name(preset);
selected = name;
//int item_id = Append(get_preset_name(preset), *bmp);
//if (!is_enabled)
// set_label_marker(item_id, LABEL_ITEM_DISABLED);
@@ -1290,16 +1256,16 @@ void TabPresetComboBox::update()
else if (preset.is_project_embedded)
{
//std::pair<wxBitmap*, bool> pair(bmp, is_enabled);
project_embedded_presets.emplace(get_preset_name(preset), std::pair<wxBitmap *, bool>(bmp, is_enabled));
project_embedded_presets.emplace(name, std::pair<wxBitmap *, bool>(bmp, is_enabled));
if (i == idx_selected)
selected = get_preset_name(preset);
selected = name;
}
else
{
std::pair<wxBitmap*, bool> pair(bmp, is_enabled);
nonsys_presets.emplace(get_preset_name(preset), std::pair<wxBitmap*, bool>(bmp, is_enabled));
nonsys_presets.emplace(name, std::pair<wxBitmap *, bool>(bmp, is_enabled));
if (i == idx_selected)
selected = get_preset_name(preset);
selected = name;
}
//BBS: move system to the end
//if (i + 1 == m_collection->num_default_presets())
@@ -1315,6 +1281,7 @@ void TabPresetComboBox::update()
set_label_marker(Append(separator(L("Project-inside presets")), wxNullBitmap));
for (std::map<wxString, std::pair<wxBitmap*, bool>>::iterator it = project_embedded_presets.begin(); it != project_embedded_presets.end(); ++it) {
int item_id = Append(it->first, *it->second.first);
SetItemTooltip(item_id, preset_descriptions[it->first]);
bool is_enabled = it->second.second;
if (!is_enabled)
set_label_marker(item_id, LABEL_ITEM_DISABLED);
@@ -1326,6 +1293,7 @@ void TabPresetComboBox::update()
set_label_marker(Append(separator(L("User presets")), wxNullBitmap));
for (std::map<wxString, std::pair<wxBitmap*, bool>>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
int item_id = Append(it->first, *it->second.first);
SetItemTooltip(item_id, preset_descriptions[it->first]);
bool is_enabled = it->second.second;
if (!is_enabled)
set_label_marker(item_id, LABEL_ITEM_DISABLED);
@@ -1338,6 +1306,7 @@ void TabPresetComboBox::update()
set_label_marker(Append(separator(L("System presets")), wxNullBitmap));
for (std::map<wxString, std::pair<wxBitmap*, bool>>::iterator it = system_presets.begin(); it != system_presets.end(); ++it) {
int item_id = Append(it->first, *it->second.first);
SetItemTooltip(item_id, preset_descriptions[it->first]);
bool is_enabled = it->second.second;
if (!is_enabled)
set_label_marker(item_id, LABEL_ITEM_DISABLED);
+1 -3
View File
@@ -2,9 +2,9 @@
#define slic3r_PresetComboBoxes_hpp_
//#include <wx/bmpcbox.h>
#include <wx/colourdata.h>
#include <wx/gdicmn.h>
#include <wx/clrpicker.h>
#include <wx/colourdata.h>
#include "libslic3r/Preset.hpp"
#include "wxExtensions.hpp"
@@ -164,8 +164,6 @@ public:
PlaterPresetComboBox(wxWindow *parent, Preset::Type preset_type);
~PlaterPresetComboBox();
void save_custom_color_to_config(const std::vector<std::string> &colors);
std::vector<std::string> get_custom_color_from_config();
ScalableButton* edit_btn { nullptr };
// BBS
+58 -1
View File
@@ -67,6 +67,12 @@ PrintOptionsDialog::PrintOptionsDialog(wxWindow* parent)
}
evt.Skip();
});
m_cb_nozzle_blob->Bind(wxEVT_TOGGLEBUTTON, [this](wxCommandEvent& evt) {
if (obj) {
obj->command_nozzle_blob_detect(m_cb_nozzle_blob->GetValue());
}
evt.Skip();
});
wxGetApp().UpdateDlgDarkUI(this);
}
@@ -163,6 +169,18 @@ void PrintOptionsDialog::update_options(MachineObject* obj_)
m_cb_filament_tangle->Hide();
line6->Hide();
}
if (false/*obj_->is_support_nozzle_blob_detection*/) {
text_nozzle_blob->Show();
m_cb_nozzle_blob->Show();
text_nozzle_blob_caption->Show();
line7->Show();
}
else {
text_nozzle_blob->Hide();
m_cb_nozzle_blob->Hide();
text_nozzle_blob_caption->Hide();
line7->Hide();
}
this->Freeze();
@@ -171,6 +189,7 @@ void PrintOptionsDialog::update_options(MachineObject* obj_)
m_cb_auto_recovery->SetValue(obj_->xcam_auto_recovery_step_loss);
m_cb_sup_sound->SetValue(obj_->xcam_allow_prompt_sound);
m_cb_filament_tangle->SetValue(obj_->xcam_filament_tangle_detect);
m_cb_nozzle_blob->SetValue(obj_->nozzle_blob_detection_enabled);
m_cb_ai_monitoring->SetValue(obj_->xcam_ai_monitoring);
for (auto i = AiMonitorSensitivityLevel::LOW; i < LEVELS_NUM; i = (AiMonitorSensitivityLevel) (i + 1)) {
@@ -325,6 +344,38 @@ wxBoxSizer* PrintOptionsDialog::create_settings_group(wxWindow* parent)
line6 = new StaticLine(parent, false);
line6->SetLineColour(STATIC_BOX_LINE_COL);
sizer->Add(line6, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(20));
sizer->Add(0, 0, 0, wxTOP, FromDIP(20));
//nozzle blob detect
line_sizer = new wxBoxSizer(wxHORIZONTAL);
m_cb_nozzle_blob = new CheckBox(parent);
text_nozzle_blob = new wxStaticText(parent, wxID_ANY, _L("Nozzle Clumping Detection"));
text_nozzle_blob->SetFont(Label::Body_14);
line_sizer->Add(FromDIP(5), 0, 0, 0);
line_sizer->Add(m_cb_nozzle_blob, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5));
line_sizer->Add(text_nozzle_blob, 1, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5));
sizer->Add(0, 0, 0, wxTOP, FromDIP(15));
sizer->Add(line_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(18));
line_sizer->Add(FromDIP(5), 0, 0, 0);
line_sizer = new wxBoxSizer(wxHORIZONTAL);
wxString nozzle_blob_caption_text = _L("Check if the nozzle is clumping by filament or other foreign objects.");
text_nozzle_blob_caption = new Label(parent, nozzle_blob_caption_text);
text_nozzle_blob_caption->SetFont(Label::Body_14);
text_nozzle_blob_caption->Wrap(-1);
text_nozzle_blob_caption->SetForegroundColour(STATIC_TEXT_CAPTION_COL);
line_sizer->Add(FromDIP(30), 0, 0, 0);
line_sizer->Add(text_nozzle_blob_caption, 1, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(0));
sizer->Add(line_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(18));
line7 = new StaticLine(parent, false);
line7->SetLineColour(STATIC_BOX_LINE_COL);
sizer->Add(line7, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(20));
text_nozzle_blob->Hide();
m_cb_nozzle_blob->Hide();
text_nozzle_blob_caption->Hide();
line7->Hide();
ai_monitoring_level_list->Connect( wxEVT_COMBOBOX, wxCommandEventHandler(PrintOptionsDialog::set_ai_monitor_sensitivity), NULL, this );
@@ -487,6 +538,8 @@ void PrinterPartsDialog::set_nozzle_type(wxCommandEvent& evt)
nozzle_diameter_checkbox->Append(wxString::Format(_L("%.1f"), diameter_list[i]));
}
nozzle_diameter_checkbox->SetSelection(0);
last_nozzle_type = type;
set_nozzle_diameter(evt);
}
@@ -526,7 +579,11 @@ bool PrinterPartsDialog::Show(bool show)
CentreOnParent();
auto type = obj->nozzle_type;
auto diameter = round(obj->nozzle_diameter * 10) / 10;
auto diameter = 0.4f;
if (obj->nozzle_diameter > 0) {
diameter = round(obj->nozzle_diameter * 10) / 10;
}
nozzle_type_checkbox->Clear();
nozzle_diameter_checkbox->Clear();
+4
View File
@@ -49,6 +49,7 @@ protected:
CheckBox* m_cb_auto_recovery;
CheckBox* m_cb_sup_sound;
CheckBox* m_cb_filament_tangle;
CheckBox* m_cb_nozzle_blob;
wxStaticText* text_first_layer;
wxStaticText* text_ai_monitoring;
wxStaticText* text_ai_monitoring_caption;
@@ -58,12 +59,15 @@ protected:
wxStaticText* text_auto_recovery;
wxStaticText* text_sup_sound;
wxStaticText* text_filament_tangle;
wxStaticText* text_nozzle_blob;
wxStaticText* text_nozzle_blob_caption;
StaticLine* line1;
StaticLine* line2;
StaticLine* line3;
StaticLine* line4;
StaticLine* line5;
StaticLine* line6;
StaticLine* line7;
wxBoxSizer* create_settings_group(wxWindow* parent);
bool print_halt = false;
+6 -8
View File
@@ -7,9 +7,9 @@
#include "../../Utils/NetworkAgent.hpp"
#include "../BitmapCache.hpp"
#include <boost/algorithm/hex.hpp>
#include <boost/endian/conversion.hpp>
#include <boost/log/trivial.hpp>
#include <boost/algorithm/hex.hpp>
#include <boost/uuid/detail/md5.hpp>
#include <boost/regex.hpp>
@@ -1139,8 +1139,7 @@ void PrinterFileSystem::RecvMessageThread()
if (n == 0) {
HandleResponse(l, sample);
} else if (n == Bambu_stream_end) {
if (m_status == ListSyncing)
m_stopped = true;
m_stopped = true;
Reconnect(l, m_status == ListSyncing ? ERROR_RES_BUSY : ERROR_PIPE);
} else if (n == Bambu_would_block) {
m_cond.timed_wait(l, boost::posix_time::milliseconds(m_messages.empty() && m_callbacks.empty() ? 1000 : 20));
@@ -1219,10 +1218,6 @@ void PrinterFileSystem::HandleResponse(boost::unique_lock<boost::mutex> &l, Bamb
}
}
namespace Slic3r { namespace GUI {
extern wxString hide_passwd(wxString url, std::vector<wxString> const &passwords);
}}
void PrinterFileSystem::Reconnect(boost::unique_lock<boost::mutex> &l, int result)
{
if (m_session.tunnel) {
@@ -1266,7 +1261,7 @@ void PrinterFileSystem::Reconnect(boost::unique_lock<boost::mutex> &l, int resul
if (m_last_error == 0)
m_stopped = true;
} else {
wxLogMessage("PrinterFileSystem::Reconnect Initialized: %s", Slic3r::GUI::hide_passwd(wxString::FromUTF8(url), {"authkey=", "passwd="}));
wxLogInfo("PrinterFileSystem::Reconnect Initialized: %s", wxString::FromUTF8(url));
l.unlock();
m_status = Status::Connecting;
wxLogMessage("PrinterFileSystem::Reconnect Connecting");
@@ -1288,6 +1283,9 @@ void PrinterFileSystem::Reconnect(boost::unique_lock<boost::mutex> &l, int resul
m_session.tunnel = tunnel;
wxLogMessage("PrinterFileSystem::Reconnect Connected");
break;
} else if (ret == 1) {
m_stopped = true;
ret = ERROR_RES_BUSY;
}
if (tunnel) {
Bambu_Close(tunnel);
+305 -1
View File
@@ -31,12 +31,16 @@ wxDEFINE_EVENT(EVT_SECONDARY_CHECK_CONFIRM, wxCommandEvent);
wxDEFINE_EVENT(EVT_SECONDARY_CHECK_CANCEL, wxCommandEvent);
wxDEFINE_EVENT(EVT_SECONDARY_CHECK_DONE, wxCommandEvent);
wxDEFINE_EVENT(EVT_SECONDARY_CHECK_RESUME, wxCommandEvent);
wxDEFINE_EVENT(EVT_LOAD_VAMS_TRAY, wxCommandEvent);
wxDEFINE_EVENT(EVT_CHECKBOX_CHANGE, wxCommandEvent);
wxDEFINE_EVENT(EVT_ENTER_IP_ADDRESS, wxCommandEvent);
wxDEFINE_EVENT(EVT_CLOSE_IPADDRESS_DLG, wxCommandEvent);
wxDEFINE_EVENT(EVT_CHECK_IP_ADDRESS_FAILED, wxCommandEvent);
wxDEFINE_EVENT(EVT_SECONDARY_CHECK_RETRY, wxCommandEvent);
wxDEFINE_EVENT(EVT_PRINT_ERROR_STOP, wxCommandEvent);
wxDEFINE_EVENT(EVT_UPDATE_NOZZLE, wxCommandEvent);
wxDEFINE_EVENT(EVT_JUMP_TO_HMS, wxCommandEvent);
wxDEFINE_EVENT(EVT_JUMP_TO_LIVEVIEW, wxCommandEvent);
ReleaseNoteDialog::ReleaseNoteDialog(Plater *plater /*= nullptr*/)
: DPIDialog(static_cast<wxWindow *>(wxGetApp().mainframe), wxID_ANY, _L("Release Note"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX)
@@ -860,6 +864,306 @@ void SecondaryCheckDialog::rescale()
m_button_cancel->Rescale();
}
PrintErrorDialog::PrintErrorDialog(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style)
:DPIFrame(parent, id, title, pos, size, style)
{
std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str();
SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO));
SetBackgroundColour(*wxWHITE);
btn_bg_white = StateColor(std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Pressed), std::pair<wxColour, int>(wxColour(238, 238, 238), StateColor::Hovered),
std::pair<wxColour, int>(*wxWHITE, StateColor::Normal));
m_sizer_main = new wxBoxSizer(wxVERTICAL);
auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(350), 1));
m_line_top->SetBackgroundColour(wxColour(166, 169, 170));
m_sizer_main->Add(m_line_top, 0, wxEXPAND, 0);
m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(5));
wxBoxSizer* m_sizer_right = new wxBoxSizer(wxVERTICAL);
m_sizer_right->Add(0, 0, 1, wxTOP, FromDIP(5));
m_vebview_release_note = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL);
m_vebview_release_note->SetScrollRate(0, 5);
m_vebview_release_note->SetBackgroundColour(*wxWHITE);
m_vebview_release_note->SetMinSize(wxSize(FromDIP(320), FromDIP(250)));
m_sizer_right->Add(m_vebview_release_note, 0, wxEXPAND | wxRIGHT | wxLEFT, FromDIP(15));
m_error_prompt_pic_static = new wxStaticBitmap(m_vebview_release_note, wxID_ANY, wxBitmap(), wxDefaultPosition, wxSize(FromDIP(300), FromDIP(180)));
auto bottom_sizer = new wxBoxSizer(wxVERTICAL);
m_sizer_button = new wxBoxSizer(wxVERTICAL);
bottom_sizer->Add(m_sizer_button, 0, wxEXPAND | wxRIGHT | wxLEFT, 0);
m_sizer_right->Add(bottom_sizer, 0, wxEXPAND | wxRIGHT | wxLEFT, FromDIP(15));
m_sizer_right->Add(0, 0, 0, wxTOP, FromDIP(10));
m_sizer_main->Add(m_sizer_right, 0, wxBOTTOM | wxEXPAND, FromDIP(5));
Bind(wxEVT_CLOSE_WINDOW, [this](auto& e) {this->on_hide(); });
Bind(wxEVT_ACTIVATE, [this](auto& e) { if (!e.GetActive()) this->RequestUserAttention(wxUSER_ATTENTION_ERROR); });
Bind(wxEVT_WEBREQUEST_STATE, &PrintErrorDialog::on_webrequest_state, this);
SetSizer(m_sizer_main);
Layout();
m_sizer_main->Fit(this);
init_button_list();
CenterOnParent();
wxGetApp().UpdateFrameDarkUI(this);
}
void PrintErrorDialog::post_event(wxCommandEvent&& event)
{
if (event_parent) {
event.SetString("");
event.SetEventObject(event_parent);
wxPostEvent(event_parent, event);
event.Skip();
}
}
void PrintErrorDialog::on_webrequest_state(wxWebRequestEvent& evt)
{
BOOST_LOG_TRIVIAL(trace) << "monitor: monitor_panel web request state = " << evt.GetState();
switch (evt.GetState()) {
case wxWebRequest::State_Completed: {
wxImage img(*evt.GetResponse().GetStream());
wxImage resize_img = img.Scale(FromDIP(320), FromDIP(180), wxIMAGE_QUALITY_HIGH);
wxBitmap error_prompt_pic = resize_img;
m_error_prompt_pic_static->SetBitmap(error_prompt_pic);
Layout();
Fit();
break;
}
case wxWebRequest::State_Failed:
case wxWebRequest::State_Cancelled:
case wxWebRequest::State_Unauthorized: {
m_error_prompt_pic_static->SetBitmap(wxBitmap());
break;
}
case wxWebRequest::State_Active:
case wxWebRequest::State_Idle: break;
default: break;
}
}
void PrintErrorDialog::update_text_image(wxString text, wxString image_url)
{
//if (!m_sizer_text_release_note) {
// m_sizer_text_release_note = new wxBoxSizer(wxVERTICAL);
//}
wxBoxSizer* sizer_text_release_note = new wxBoxSizer(wxVERTICAL);
if (!m_staticText_release_note) {
m_staticText_release_note = new Label(m_vebview_release_note, text, LB_AUTO_WRAP);
sizer_text_release_note->Add(m_error_prompt_pic_static, 0, wxALIGN_CENTER, FromDIP(5));
sizer_text_release_note->Add(m_staticText_release_note, 0, wxALIGN_CENTER , FromDIP(5));
m_vebview_release_note->SetSizer(sizer_text_release_note);
}
if (!image_url.empty()) {
web_request = wxWebSession::GetDefault().CreateRequest(this, image_url);
BOOST_LOG_TRIVIAL(trace) << "monitor: create new webrequest, state = " << web_request.GetState() << ", url = " << image_url;
if (web_request.GetState() == wxWebRequest::State_Idle)
web_request.Start();
BOOST_LOG_TRIVIAL(trace) << "monitor: start new webrequest, state = " << web_request.GetState() << ", url = " << image_url;
m_error_prompt_pic_static->Show();
}
else {
m_error_prompt_pic_static->Hide();
}
sizer_text_release_note->Layout();
m_staticText_release_note->SetMaxSize(wxSize(FromDIP(300), -1));
m_staticText_release_note->SetMinSize(wxSize(FromDIP(300), -1));
m_staticText_release_note->SetLabelText(text);
m_vebview_release_note->Layout();
auto text_size = m_staticText_release_note->GetBestSize();
if (text_size.y < FromDIP(360))
if (!image_url.empty()) {
m_vebview_release_note->SetMinSize(wxSize(FromDIP(320), text_size.y + FromDIP(220)));
}
else {
m_vebview_release_note->SetMinSize(wxSize(FromDIP(320), text_size.y + FromDIP(25)));
}
else {
m_vebview_release_note->SetMinSize(wxSize(FromDIP(320), FromDIP(340)));
}
Layout();
Fit();
}
void PrintErrorDialog::on_show()
{
wxGetApp().UpdateFrameDarkUI(this);
this->Show();
this->Raise();
}
void PrintErrorDialog::on_hide()
{
//m_sizer_button->Clear();
//m_sizer_button->Layout();
//m_used_button.clear();
this->Hide();
if (web_request.IsOk() && web_request.GetState() == wxWebRequest::State_Active) {
BOOST_LOG_TRIVIAL(info) << "web_request: cancelled";
web_request.Cancel();
}
m_error_prompt_pic_static->SetBitmap(wxBitmap());
if (wxGetApp().mainframe != nullptr) {
wxGetApp().mainframe->Show();
wxGetApp().mainframe->Raise();
}
}
void PrintErrorDialog::update_title_style(wxString title, std::vector<int> button_style, wxWindow* parent)
{
SetTitle(title);
event_parent = parent;
for (int used_button_id : m_used_button) {
if (m_button_list.find(used_button_id) != m_button_list.end()) {
m_button_list[used_button_id]->Hide();
}
}
m_sizer_button->Clear();
m_used_button = button_style;
for (int button_id : button_style) {
if (m_button_list.find(button_id) != m_button_list.end()) {
m_sizer_button->Add(m_button_list[button_id], 0, wxALL, FromDIP(5));
m_button_list[button_id]->Show();
}
}
Layout();
Fit();
}
void PrintErrorDialog::init_button(PrintErrorButton style,wxString buton_text) {
Button* print_error_button = new Button(this, buton_text);
print_error_button->SetBackgroundColor(btn_bg_white);
print_error_button->SetBorderColor(wxColour(38, 46, 48));
print_error_button->SetFont(Label::Body_14);
print_error_button->SetSize(wxSize(FromDIP(300), FromDIP(30)));
print_error_button->SetMinSize(wxSize(FromDIP(300), FromDIP(30)));
print_error_button->SetMaxSize(wxSize(-1, FromDIP(30)));
print_error_button->SetCornerRadius(FromDIP(5));
print_error_button->Hide();
m_button_list[style] = print_error_button;
}
void PrintErrorDialog::init_button_list() {
init_button(RESUME_PRINTING, _L("Resume Printing"));
m_button_list[RESUME_PRINTING]->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) {
post_event(wxCommandEvent(EVT_SECONDARY_CHECK_RESUME));
e.Skip();
});
init_button(RESUME_PRINTING_DEFECTS, _L("Resume Printing(defects acceptable)"));
m_button_list[RESUME_PRINTING_DEFECTS]->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) {
post_event(wxCommandEvent(EVT_SECONDARY_CHECK_RESUME));
e.Skip();
});
init_button(RESUME_PRINTING_PROBELM_SOLVED, _L("Resume Printing(problem solved)"));
m_button_list[RESUME_PRINTING_PROBELM_SOLVED]->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) {
post_event(wxCommandEvent(EVT_SECONDARY_CHECK_RESUME));
e.Skip();
});
init_button(STOP_PRINTING, _L("Stop Printing"));
m_button_list[STOP_PRINTING]->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) {
post_event(wxCommandEvent(EVT_PRINT_ERROR_STOP));
e.Skip();
});
init_button(CHECK_ASSISTANT, _L("Check Assistant"));
m_button_list[CHECK_ASSISTANT]->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) {
post_event(wxCommandEvent(EVT_JUMP_TO_HMS));
this->on_hide();
});
init_button(FILAMENT_EXTRUDED, _L("Filament Extruded, Continue"));
m_button_list[FILAMENT_EXTRUDED]->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) {
post_event(wxCommandEvent(EVT_SECONDARY_CHECK_DONE));
e.Skip();
});
init_button(RETRY_FILAMENT_EXTRUDED, _L("Not Extruded Yet, Retry"));
m_button_list[RETRY_FILAMENT_EXTRUDED]->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) {
wxCommandEvent evt(EVT_SECONDARY_CHECK_RETRY, GetId());
e.SetEventObject(this);
GetEventHandler()->ProcessEvent(evt);
this->on_hide();
});
init_button(CONTINUE, _L("Finished, Continue"));
m_button_list[CONTINUE]->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) {
post_event(wxCommandEvent(EVT_SECONDARY_CHECK_DONE));
e.Skip();
});
init_button(LOAD_VIRTUAL_TRAY, _L("Load Filament"));
m_button_list[LOAD_VIRTUAL_TRAY]->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) {
post_event(wxCommandEvent(EVT_LOAD_VAMS_TRAY));
e.Skip();
});
init_button(OK_BUTTON, _L("OK"));
m_button_list[OK_BUTTON]->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) {
wxCommandEvent evt(EVT_SECONDARY_CHECK_CONFIRM, GetId());
e.SetEventObject(this);
GetEventHandler()->ProcessEvent(evt);
this->on_hide();
});
init_button(FILAMENT_LOAD_RESUME, _L("Filament Loaded, Resume"));
m_button_list[FILAMENT_LOAD_RESUME]->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) {
post_event(wxCommandEvent(EVT_SECONDARY_CHECK_RESUME));
e.Skip();
});
init_button(JUMP_TO_LIVEVIEW, _L("View Liveview"));
m_button_list[JUMP_TO_LIVEVIEW]->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) {
post_event(wxCommandEvent(EVT_JUMP_TO_LIVEVIEW));
e.Skip();
});
}
PrintErrorDialog::~PrintErrorDialog()
{
}
void PrintErrorDialog::on_dpi_changed(const wxRect& suggested_rect)
{
rescale();
}
void PrintErrorDialog::msw_rescale() {
wxGetApp().UpdateFrameDarkUI(this);
Refresh();
}
void PrintErrorDialog::rescale()
{
for(auto used_button:m_used_button)
m_button_list[used_button]->Rescale();
}
ConfirmBeforeSendDialog::ConfirmBeforeSendDialog(wxWindow* parent, wxWindowID id, const wxString& title, enum ButtonStyle btn_style, const wxPoint& pos, const wxSize& size, long style, bool not_show_again_check)
:DPIDialog(parent, id, title, pos, size, style)
{
@@ -1121,7 +1425,7 @@ void ConfirmBeforeSendDialog::disable_button_ok()
void ConfirmBeforeSendDialog::enable_button_ok()
{
m_button_ok->Enable();
StateColor btn_bg_green(std::pair<wxColour, int>(wxColour(61, 203, 115), StateColor::Pressed), std::pair<wxColour, int>(wxColour(61, 203, 115), StateColor::Hovered),
StateColor btn_bg_green(std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Pressed), std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
std::pair<wxColour, int>(AMS_CONTROL_BRAND_COLOUR, StateColor::Normal));
m_button_ok->SetBackgroundColor(btn_bg_green);
m_button_ok->SetBorderColor(btn_bg_green);
+55
View File
@@ -47,7 +47,11 @@ wxDECLARE_EVENT(EVT_SECONDARY_CHECK_CANCEL, wxCommandEvent);
wxDECLARE_EVENT(EVT_SECONDARY_CHECK_RETRY, wxCommandEvent);
wxDECLARE_EVENT(EVT_SECONDARY_CHECK_DONE, wxCommandEvent);
wxDECLARE_EVENT(EVT_SECONDARY_CHECK_RESUME, wxCommandEvent);
wxDECLARE_EVENT(EVT_PRINT_ERROR_STOP, wxCommandEvent);
wxDECLARE_EVENT(EVT_UPDATE_NOZZLE, wxCommandEvent);
wxDECLARE_EVENT(EVT_LOAD_VAMS_TRAY, wxCommandEvent);
wxDECLARE_EVENT(EVT_JUMP_TO_HMS, wxCommandEvent);
wxDECLARE_EVENT(EVT_JUMP_TO_LIVEVIEW, wxCommandEvent);
class ReleaseNoteDialog : public DPIDialog
{
@@ -159,6 +163,57 @@ public:
std::string show_again_config_text = "";
};
class PrintErrorDialog : public DPIFrame
{
private:
wxWindow* event_parent{ nullptr };
public:
enum PrintErrorButton {
RESUME_PRINTING = 2,
RESUME_PRINTING_DEFECTS = 3,
RESUME_PRINTING_PROBELM_SOLVED = 4,
STOP_PRINTING = 5,
CHECK_ASSISTANT = 6,
FILAMENT_EXTRUDED = 7,
RETRY_FILAMENT_EXTRUDED = 8,
CONTINUE = 9,
LOAD_VIRTUAL_TRAY = 10,
OK_BUTTON = 11,
FILAMENT_LOAD_RESUME,
JUMP_TO_LIVEVIEW,
ERROR_BUTTON_COUNT
};
PrintErrorDialog(
wxWindow* parent,
wxWindowID id = wxID_ANY,
const wxString& title = wxEmptyString,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxCLOSE_BOX | wxCAPTION
);
void update_text_image(wxString text, wxString image_url);
void on_show();
void on_hide();
void update_title_style(wxString title, std::vector<int> style, wxWindow* parent = nullptr);
void post_event(wxCommandEvent&& event);
void rescale();
~PrintErrorDialog();
void on_dpi_changed(const wxRect& suggested_rect);
void msw_rescale();
void init_button(PrintErrorButton style, wxString buton_text);
void init_button_list();
void on_webrequest_state(wxWebRequestEvent& evt);
StateColor btn_bg_white;
wxWebRequest web_request;
wxStaticBitmap* m_error_prompt_pic_static;
Label* m_staticText_release_note{ nullptr };
wxBoxSizer* m_sizer_main;
wxBoxSizer* m_sizer_button;
wxScrolledWindow* m_vebview_release_note{ nullptr };
std::map<int, Button*> m_button_list;
std::vector<int> m_used_button;
};
struct ConfirmBeforeSendInfo
{
+91 -1
View File
@@ -398,12 +398,15 @@ SelectMachinePopup::SelectMachinePopup(wxWindow *parent)
auto other_title = create_title_panel(_L("Other Device"));
m_sizer_other_devices = new wxBoxSizer(wxVERTICAL);
m_panel_ping_code = new PinCodePanel(m_scrolledWindow, wxID_ANY, wxDefaultPosition, SELECT_MACHINE_ITEM_SIZE);
m_sizxer_scrolledWindow->Add(own_title, 0, wxEXPAND | wxLEFT, FromDIP(15));
m_sizxer_scrolledWindow->Add(m_sizer_my_devices, 0, wxEXPAND, 0);
m_sizxer_scrolledWindow->Add(m_panel_ping_code, 0, wxEXPAND, 0);
m_sizxer_scrolledWindow->Add(other_title, 0, wxEXPAND | wxLEFT, FromDIP(15));
m_sizxer_scrolledWindow->Add(m_sizer_other_devices, 0, wxEXPAND, 0);
m_sizer_main->Add(m_scrolledWindow, 0, wxALL | wxEXPAND, FromDIP(2));
SetSizer(m_sizer_main);
@@ -872,6 +875,17 @@ void SelectMachinePopup::OnLeftUp(wxMouseEvent &event)
}
}
//pin code
auto pc_rect = m_panel_ping_code->ClientToScreen(wxPoint(0, 0));
if (mouse_pos.x > pc_rect.x && mouse_pos.y > pc_rect.y && mouse_pos.x < (pc_rect.x + m_panel_ping_code->GetSize().x) && mouse_pos.y < (pc_rect.y + m_panel_ping_code->GetSize().y)) {
/*wxMouseEvent event(wxEVT_LEFT_UP);
auto tag_pos = m_panel_ping_code->ScreenToClient(mouse_pos);
event.SetPosition(tag_pos);
event.SetEventObject(m_panel_ping_code);
wxPostEvent(m_panel_ping_code, event);*/
wxGetApp().popup_ping_bind_dialog();
}
//hyper link
auto h_rect = m_hyperlink->ClientToScreen(wxPoint(0, 0));
if (mouse_pos.x > h_rect.x && mouse_pos.y > h_rect.y && mouse_pos.x < (h_rect.x + m_hyperlink->GetSize().x) && mouse_pos.y < (h_rect.y + m_hyperlink->GetSize().y)) {
@@ -4581,4 +4595,80 @@ void EditDevNameDialog::on_edit_name(wxCommandEvent &e)
ThumbnailPanel::~ThumbnailPanel() {}
PinCodePanel::PinCodePanel(wxWindow* parent, wxWindowID winid /*= wxID_ANY*/, const wxPoint& pos /*= wxDefaultPosition*/, const wxSize& size /*= wxDefaultSize*/)
{
wxPanel::Create(parent, winid, pos, SELECT_MACHINE_ITEM_SIZE);
Bind(wxEVT_PAINT, &PinCodePanel::OnPaint, this);
SetSize(SELECT_MACHINE_ITEM_SIZE);
SetMaxSize(SELECT_MACHINE_ITEM_SIZE);
SetMinSize(SELECT_MACHINE_ITEM_SIZE);
m_bitmap = ScalableBitmap(this, "bind_device_ping_code",10);
this->Bind(wxEVT_ENTER_WINDOW, &PinCodePanel::on_mouse_enter, this);
this->Bind(wxEVT_LEAVE_WINDOW, &PinCodePanel::on_mouse_leave, this);
this->Bind(wxEVT_LEFT_UP, &PinCodePanel::on_mouse_left_up, this);
}
void PinCodePanel::OnPaint(wxPaintEvent& event)
{
wxPaintDC dc(this);
render(dc);
}
void PinCodePanel::render(wxDC& dc)
{
#ifdef __WXMSW__
wxSize size = GetSize();
wxMemoryDC memdc;
wxBitmap bmp(size.x, size.y);
memdc.SelectObject(bmp);
memdc.Blit({ 0, 0 }, size, &dc, { 0, 0 });
{
wxGCDC dc2(memdc);
doRender(dc2);
}
memdc.SelectObject(wxNullBitmap);
dc.DrawBitmap(bmp, 0, 0);
#else
doRender(dc);
#endif
}
void PinCodePanel::doRender(wxDC& dc)
{
auto size = GetSize();
dc.DrawBitmap(m_bitmap.bmp(), wxPoint(FromDIP(20), (size.y - m_bitmap.GetBmpSize().y) / 2));
dc.SetFont(::Label::Head_13);
dc.SetTextForeground(wxColour(38, 46, 48));
wxString txt = _L("Bind with Pin Code");
auto txt_size = dc.GetTextExtent(txt);
dc.DrawText(txt, wxPoint(FromDIP(40), (size.y - txt_size.y) / 2));
if (m_hover) {
dc.SetPen(SELECT_MACHINE_BRAND);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(0, 0, size.x, size.y);
}
}
void PinCodePanel::on_mouse_enter(wxMouseEvent& evt)
{
m_hover = true;
Refresh();
}
void PinCodePanel::on_mouse_leave(wxMouseEvent& evt)
{
m_hover = false;
Refresh();
}
void PinCodePanel::on_mouse_left_up(wxMouseEvent& evt)
{
wxGetApp().popup_ping_bind_dialog();
}
}} // namespace Slic3r::GUI
+24
View File
@@ -210,6 +210,27 @@ public:
MachineObjectPanel *mPanel;
};
class PinCodePanel : public wxPanel
{
public:
PinCodePanel(wxWindow* parent,
wxWindowID winid = wxID_ANY,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize);
~PinCodePanel() {};
ScalableBitmap m_bitmap;
bool m_hover{false};
void OnPaint(wxPaintEvent& event);
void render(wxDC& dc);
void doRender(wxDC& dc);
void on_mouse_enter(wxMouseEvent& evt);
void on_mouse_leave(wxMouseEvent& evt);
void on_mouse_left_up(wxMouseEvent& evt);
};
class ThumbnailPanel;
@@ -232,8 +253,11 @@ public:
private:
int m_my_devices_count{0};
int m_other_devices_count{0};
PinCodePanel* m_panel_ping_code{nullptr};
wxWindow* m_placeholder_panel{nullptr};
wxHyperlinkCtrl* m_hyperlink{nullptr};
Label* m_ping_code_text{nullptr};
wxStaticBitmap* m_img_ping_code{nullptr};
wxBoxSizer * m_sizer_body{nullptr};
wxBoxSizer * m_sizer_my_devices{nullptr};
wxBoxSizer * m_sizer_other_devices{nullptr};
File diff suppressed because it is too large Load Diff
+210
View File
@@ -0,0 +1,210 @@
#ifndef slic3r_SendMultiMachinePage_hpp_
#define slic3r_SendMultiMachinePage_hpp_
#include "GUI_Utils.hpp"
#include "MultiMachine.hpp"
#include "DeviceManager.hpp"
#include "Widgets/Label.hpp"
#include "Widgets/Button.hpp"
#include "Widgets/CheckBox.hpp"
#include "Widgets/ComboBox.hpp"
#include "Widgets/ScrolledWindow.hpp"
#include "Widgets/PopupWindow.hpp"
#include "Widgets/TextInput.hpp"
#include "AmsMappingPopup.hpp"
#include "SelectMachine.hpp"
namespace Slic3r {
namespace GUI {
#define SEND_LEFT_PADDING_LEFT 15
#define SEND_LEFT_PRINTABLE 40
#define SEND_LEFT_DEV_NAME 250
#define SEND_LEFT_DEV_STATUS 250
#define SEND_LEFT_TAKS_STATUS 180
#define DESIGN_SELECTOR_NOMORE_COLOR wxColour(248, 248, 248)
#define DESIGN_GRAY900_COLOR wxColour(38, 46, 48)
#define DESIGN_GRAY800_COLOR wxColour(50, 58, 61)
#define DESIGN_GRAY600_COLOR wxColour(144, 144, 144)
#define DESIGN_GRAY400_COLOR wxColour(166, 169, 170)
#define DESIGN_RESOUTION_PREFERENCES wxSize(FromDIP(540), -1)
#define DESIGN_COMBOBOX_SIZE wxSize(FromDIP(140), -1)
#define DESIGN_LARGE_COMBOBOX_SIZE wxSize(FromDIP(160), -1)
#define DESIGN_INPUT_SIZE wxSize(FromDIP(50), -1)
#define MATERIAL_ITEM_SIZE wxSize(FromDIP(64), FromDIP(34))
#define MATERIAL_ITEM_REAL_SIZE wxSize(FromDIP(62), FromDIP(32))
#define MAPPING_ITEM_REAL_SIZE wxSize(FromDIP(48), FromDIP(45))
#define THUMBNAIL_SIZE FromDIP(128)
class RadioBox;
class AmsRadioSelector
{
public:
wxString m_param_name;
int m_groupid;
RadioBox* m_radiobox;
bool m_selected = false;
};
WX_DECLARE_LIST(AmsRadioSelector, AmsRadioSelectorList);
class SendDeviceItem : public DeviceItem
{
public:
SendDeviceItem(wxWindow* parent, MachineObject* obj);
~SendDeviceItem() {};
void DrawTextWithEllipsis(wxDC& dc, const wxString& text, int maxWidth, int left, int top = 0);
void OnEnterWindow(wxMouseEvent& evt);
void OnLeaveWindow(wxMouseEvent& evt);
void OnSelectedDevice(wxCommandEvent& evt);
void OnLeftDown(wxMouseEvent& evt);
void OnMove(wxMouseEvent& evt);
void paintEvent(wxPaintEvent& evt);
void render(wxDC& dc);
void doRender(wxDC& dc);
void post_event(wxCommandEvent&& event);
virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO);
public:
bool m_hover{false};
ScalableBitmap m_bitmap_check_disable;
ScalableBitmap m_bitmap_check_off;
ScalableBitmap m_bitmap_check_on;
};
class Plater;
class SendMultiMachinePage : public DPIDialog
{
private:
/* dev_id -> device_item */
std::map<std::string, SendDeviceItem*> m_device_items;
wxTimer* m_refresh_timer = nullptr;
// sort
SortItem m_sort;
bool device_name_big{ true };
bool device_printable_big{ true };
bool device_en_ams_big{ true };
Button* m_button_send{ nullptr };
wxScrolledWindow* scroll_macine_list{ nullptr };
wxBoxSizer* sizer_machine_list{ nullptr };
Plater* m_plater{ nullptr };
int m_print_plate_idx;
bool m_is_canceled{ false };
bool m_export_3mf_cancel{ false };
AppConfig* app_config;
wxPanel* m_main_page{ nullptr };
wxScrolledWindow* m_main_scroll{ nullptr };
wxBoxSizer* m_sizer_body{ nullptr };
wxGridSizer* m_ams_list_sizer{ nullptr };
AmsMapingPopup* m_mapping_popup{ nullptr };
AmsRadioSelectorList m_radio_group;
MaterialHash m_material_list;
std::map<std::string, CheckBox*> m_checkbox_map;
std::map<std::string, TextInput*> m_input_map;
std::vector<FilamentInfo> m_filaments;
std::vector<FilamentInfo> m_ams_mapping_result;
int m_current_filament_id{ 0 };
StateColor btn_bg_enable;
// table head
wxPanel* m_table_head_panel{ nullptr };
wxBoxSizer* m_table_head_sizer{ nullptr };
CheckBox* m_select_checkbox{ nullptr };
Button* m_printer_name{ nullptr };
Button* m_device_status{ nullptr };
//Button* m_task_status{ nullptr };
Button* m_ams{ nullptr };
Button* m_refresh_button{ nullptr };
// rename
wxSimplebook* m_rename_switch_panel{ nullptr };
wxPanel* m_rename_normal_panel{ nullptr };
wxPanel* m_rename_edit_panel{ nullptr };
TextInput* m_rename_input{ nullptr };
ScalableButton* m_rename_button{ nullptr };
wxBoxSizer* rename_sizer_v{ nullptr };
wxBoxSizer* rename_sizer_h{ nullptr };
wxStaticText* m_task_name{ nullptr };
wxString m_current_project_name;
bool m_is_rename_mode{ false };
// title and thumbnail
wxPanel* m_title_panel{ nullptr };
wxBoxSizer* m_title_sizer{ nullptr };
wxBoxSizer* m_text_sizer{ nullptr };
ScalableBitmap* m_print_time{ nullptr };
wxStaticBitmap* m_time_img{ nullptr };
wxStaticText* m_stext_time{ nullptr };
wxStaticText* m_stext_weight{ nullptr };
wxStaticBitmap* timeimg{ nullptr };
ScalableBitmap* print_time{ nullptr };
wxStaticBitmap* weightimg{ nullptr };
ScalableBitmap* print_weight{ nullptr };
wxBoxSizer* m_thumbnail_sizer{ nullptr };
ThumbnailPanel* m_thumbnail_panel{nullptr};
wxPanel* m_panel_image{ nullptr };
wxBoxSizer* m_image_sizer{ nullptr };
// tip when no device
wxStaticText* m_tip_text{ nullptr };
Button* m_button_add{ nullptr };
public:
SendMultiMachinePage(Plater* plater = nullptr);
~SendMultiMachinePage();
void prepare(int plate_idx);
void on_dpi_changed(const wxRect& suggested_rect);
void on_sys_color_changed();
void refresh_user_device();
void on_send(wxCommandEvent& event);
bool Show(bool show);
BBL::PrintParams request_params(MachineObject* obj);
bool get_ams_mapping_result(std::string& mapping_array_str, std::string& ams_mapping_info);
wxBoxSizer* create_item_title(wxString title, wxWindow* parent, wxString tooltip);
wxBoxSizer* create_item_checkbox(wxString title, wxWindow* parent, wxString tooltip, int padding_left, std::string param);
wxBoxSizer* create_item_input(wxString str_before, wxString str_after, wxWindow* parent, wxString tooltip, std::string param);
wxBoxSizer* create_item_radiobox(wxString title, wxWindow* parent, wxString tooltip, int groupid, std::string param);
wxPanel* create_page();
void sync_ams_list();
void set_default_normal(const ThumbnailData& data);
void set_default();
void on_rename_enter();
void check_fcous_state(wxWindow* window);
void check_focus(wxWindow* window);
protected:
void OnSelectRadio(wxMouseEvent& event);
void on_select_radio(std::string param);
bool get_value_radio(std::string param);
void on_set_finish_mapping(wxCommandEvent& evt);
void on_rename_click(wxCommandEvent& event);
void on_timer(wxTimerEvent& event);
void init_timer();
private:
};
} // namespace GUI
} // namespace Slic3r
#endif
+93 -39
View File
@@ -84,7 +84,8 @@ static std::vector<std::string> message_containing_retry{
"07FF 8011",
"07FF 8012",
"07FF 8013",
"12FF 8007"
"12FF 8007",
"1200 8006"
};
static std::vector<std::string> message_containing_done{
@@ -1779,6 +1780,14 @@ StatusPanel::StatusPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, co
Bind(EVT_FAN_CHANGED, &StatusPanel::on_fan_changed, this);
Bind(EVT_SECONDARY_CHECK_DONE, &StatusPanel::on_print_error_done, this);
Bind(EVT_SECONDARY_CHECK_RESUME, &StatusPanel::on_subtask_pause_resume, this);
Bind(EVT_PRINT_ERROR_STOP, &StatusPanel::on_subtask_abort, this);
Bind(EVT_LOAD_VAMS_TRAY, &StatusPanel::on_ams_load_vams, this);
Bind(EVT_JUMP_TO_LIVEVIEW, [this](wxCommandEvent& e) {
m_media_play_ctrl->jump_to_play();
if (m_print_error_dlg)
m_print_error_dlg->on_hide();
});
m_switch_speed->Connect(wxEVT_LEFT_DOWN, wxCommandEventHandler(StatusPanel::on_switch_speed), NULL, this);
m_calibration_btn->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_start_calibration), NULL, this);
@@ -1933,6 +1942,8 @@ void StatusPanel::on_subtask_pause_resume(wxCommandEvent &event)
}
if (m_print_error_dlg) {
m_print_error_dlg->on_hide();
}if (m_print_error_dlg_no_action) {
m_print_error_dlg_no_action->on_hide();
}
}
@@ -2156,52 +2167,76 @@ void StatusPanel::show_recenter_dialog() {
obj->command_go_home();
}
void StatusPanel::show_error_message(MachineObject* obj, wxString msg, std::string print_error_str)
void StatusPanel::show_error_message(MachineObject* obj, wxString msg, std::string print_error_str, wxString image_url, std::vector<int> used_button)
{
if (msg.IsEmpty()) {
error_info_reset();
} else {
m_project_task_panel->show_error_msg(msg);
auto it_retry = std::find(message_containing_retry.begin(), message_containing_retry.end(), print_error_str);
auto it_done = std::find(message_containing_done.begin(), message_containing_done.end(), print_error_str);
auto it_resume = std::find(message_containing_resume.begin(), message_containing_resume.end(), print_error_str);
if (!used_button.empty()) {
BOOST_LOG_TRIVIAL(info) << "show print error! error_msg = " << msg;
if (m_print_error_dlg == nullptr) {
m_print_error_dlg = new PrintErrorDialog(this->GetParent(), wxID_ANY, _L("Error"));
}
BOOST_LOG_TRIVIAL(info) << "show print error! error_msg = " << msg;
if (m_print_error_dlg == nullptr) {
m_print_error_dlg = new SecondaryCheckDialog(this->GetParent(), wxID_ANY, _L("Warning"), SecondaryCheckDialog::ButtonStyle::ONLY_CONFIRM);
}
m_print_error_dlg->update_title_style(_L("Error"), used_button, this);
m_print_error_dlg->update_text_image(msg, image_url);
m_print_error_dlg->Bind(EVT_SECONDARY_CHECK_CONFIRM, [this, obj](wxCommandEvent& e) {
if (obj) {
obj->command_clean_print_error(obj->subtask_id_, obj->print_error);
}
});
if (it_done != message_containing_done.end() && it_retry != message_containing_retry.end()) {
m_print_error_dlg->update_title_style(_L("Warning"), SecondaryCheckDialog::ButtonStyle::DONE_AND_RETRY, this);
}
else if (it_done != message_containing_done.end()) {
m_print_error_dlg->update_title_style(_L("Warning"), SecondaryCheckDialog::ButtonStyle::CONFIRM_AND_DONE, this);
}
else if (it_retry != message_containing_retry.end()) {
m_print_error_dlg->update_title_style(_L("Warning"), SecondaryCheckDialog::ButtonStyle::CONFIRM_AND_RETRY, this);
}
else if (it_resume!= message_containing_resume.end()) {
m_print_error_dlg->update_title_style(_L("Warning"), SecondaryCheckDialog::ButtonStyle::CONFIRM_AND_RESUME, this);
m_print_error_dlg->Bind(EVT_SECONDARY_CHECK_RETRY, [this, obj](wxCommandEvent& e) {
if (m_ams_control) {
m_ams_control->on_retry();
}
});
m_print_error_dlg->on_show();
}
else {
m_print_error_dlg->update_title_style(_L("Warning"), SecondaryCheckDialog::ButtonStyle::ONLY_CONFIRM, this);
//old error code dialog
auto it_retry = std::find(message_containing_retry.begin(), message_containing_retry.end(), print_error_str);
auto it_done = std::find(message_containing_done.begin(), message_containing_done.end(), print_error_str);
auto it_resume = std::find(message_containing_resume.begin(), message_containing_resume.end(), print_error_str);
BOOST_LOG_TRIVIAL(info) << "show print error! error_msg = " << msg;
if (m_print_error_dlg_no_action == nullptr) {
m_print_error_dlg_no_action = new SecondaryCheckDialog(this->GetParent(), wxID_ANY, _L("Warning"), SecondaryCheckDialog::ButtonStyle::ONLY_CONFIRM);
}
if (it_done != message_containing_done.end() && it_retry != message_containing_retry.end()) {
m_print_error_dlg_no_action->update_title_style(_L("Warning"), SecondaryCheckDialog::ButtonStyle::DONE_AND_RETRY, this);
}
else if (it_done != message_containing_done.end()) {
m_print_error_dlg_no_action->update_title_style(_L("Warning"), SecondaryCheckDialog::ButtonStyle::CONFIRM_AND_DONE, this);
}
else if (it_retry != message_containing_retry.end()) {
m_print_error_dlg_no_action->update_title_style(_L("Warning"), SecondaryCheckDialog::ButtonStyle::CONFIRM_AND_RETRY, this);
}
else if (it_resume != message_containing_resume.end()) {
m_print_error_dlg_no_action->update_title_style(_L("Warning"), SecondaryCheckDialog::ButtonStyle::CONFIRM_AND_RESUME, this);
}
else {
m_print_error_dlg_no_action->update_title_style(_L("Warning"), SecondaryCheckDialog::ButtonStyle::ONLY_CONFIRM, this);
}
m_print_error_dlg_no_action->update_text(msg);
m_print_error_dlg_no_action->Bind(EVT_SECONDARY_CHECK_CONFIRM, [this, obj](wxCommandEvent& e) {
if (obj) {
obj->command_clean_print_error(obj->subtask_id_, obj->print_error);
}
});
m_print_error_dlg_no_action->Bind(EVT_SECONDARY_CHECK_RETRY, [this, obj](wxCommandEvent& e) {
if (m_ams_control) {
m_ams_control->on_retry();
}
});
m_print_error_dlg_no_action->on_show();
}
m_print_error_dlg->update_text(msg);
m_print_error_dlg->Bind(EVT_SECONDARY_CHECK_CONFIRM, [this, obj](wxCommandEvent& e) {
if (obj) {
obj->command_clean_print_error(obj->subtask_id_, obj->print_error);
}
});
m_print_error_dlg->Bind(EVT_SECONDARY_CHECK_RETRY, [this, obj](wxCommandEvent& e) {
if (m_ams_control) {
m_ams_control->on_retry();
}
});
m_print_error_dlg->on_show();
wxGetApp().mainframe->RequestUserAttention(wxUSER_ATTENTION_ERROR);
}
}
@@ -2224,13 +2259,19 @@ void StatusPanel::update_error_message()
}
wxString error_msg = wxGetApp().get_hms_query()->query_print_error_msg(obj->print_error);
std::vector<int> used_button;
wxString error_image_url = wxGetApp().get_hms_query()->query_print_error_url_action(obj->print_error,obj->dev_id, used_button);
// special case
if (print_error_str == "0300 8003" || print_error_str == "0300 8002" || print_error_str == "0300 800A")
used_button.emplace_back(PrintErrorDialog::PrintErrorButton::JUMP_TO_LIVEVIEW);
if (!error_msg.IsEmpty()) {
wxDateTime now = wxDateTime::Now();
wxString show_time = now.Format("%H:%M:%S");
error_msg = wxString::Format("%s[%s %s]",
wxString show_time = now.Format("%Y-%m-%d %H:%M:%S");
error_msg = wxString::Format("%s\n[%s %s]",
error_msg,
print_error_str, show_time);
show_error_message(obj, error_msg, print_error_str);
show_error_message(obj, error_msg, print_error_str,error_image_url,used_button);
} else {
BOOST_LOG_TRIVIAL(info) << "show print error! error_msg is empty, print error = " << obj->print_error;
}
@@ -2531,6 +2572,7 @@ void StatusPanel::update_ams(MachineObject *obj)
m_ams_setting_dlg->update_starting_read_mode(obj->ams_power_on_flag);
m_ams_setting_dlg->update_remain_mode(obj->ams_calibrate_remain_flag);
m_ams_setting_dlg->update_switch_filament(obj->ams_auto_switch_filament_flag);
m_ams_setting_dlg->update_air_printing_detection(obj->ams_air_print_status);
}
}
if (m_filament_setting_dlg) { m_filament_setting_dlg->obj = obj; }
@@ -3515,6 +3557,16 @@ void StatusPanel::on_ams_load_curr()
}
}
void StatusPanel::on_ams_load_vams(wxCommandEvent& event) {
BOOST_LOG_TRIVIAL(info) << "on_ams_load_vams_tray";
m_ams_control->SwitchAms(std::to_string(VIRTUAL_TRAY_ID));
on_ams_load_curr();
if (m_print_error_dlg) {
m_print_error_dlg->on_hide();
}
}
void StatusPanel::on_ams_unload(SimpleEvent &event)
{
if (obj) { obj->command_ams_switch(255); }
@@ -3839,6 +3891,8 @@ void StatusPanel::on_print_error_done(wxCommandEvent& event)
obj->command_ams_control("done");
if (m_print_error_dlg) {
m_print_error_dlg->on_hide();
}if (m_print_error_dlg_no_action) {
m_print_error_dlg_no_action->on_hide();
}
}
}

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