Merge branch 'main' into dev/h2d-2

# Conflicts:
#	localization/i18n/list.txt
#	src/slic3r/GUI/CalibrationWizardPresetPage.cpp
#	src/slic3r/GUI/DeviceManager.cpp
#	src/slic3r/GUI/DeviceManager.hpp
#	src/slic3r/GUI/Printer/PrinterFileSystem.cpp
#	src/slic3r/GUI/Printer/PrinterFileSystem.h
#	src/slic3r/GUI/SelectMachine.hpp
#	src/slic3r/GUI/SendToPrinter.cpp
#	src/slic3r/GUI/SendToPrinter.hpp
#	src/slic3r/GUI/StatusPanel.hpp
#	src/slic3r/GUI/Widgets/AnimaController.cpp
This commit is contained in:
Noisyfox
2025-10-24 09:44:41 +08:00
36 changed files with 3565 additions and 80 deletions

View File

@@ -5415,9 +5415,9 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionBool(false));
def = this->add("support_remove_small_overhang", coBool);
def->label = L("Remove small overhangs");
def->label = L("Ignore small overhangs");
def->category = L("Support");
def->tooltip = L("Remove small overhangs that possibly need no supports.");
def->tooltip = L("Ignore small overhangs that possibly don't require support.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(true));

View File

@@ -405,6 +405,11 @@ set(SLIC3R_GUI_SOURCES
GUI/SavePresetDialog.hpp
GUI/SceneRaycaster.cpp
GUI/SceneRaycaster.hpp
GUI/PartSkipCommon.hpp
GUI/PartSkipDialog.cpp
GUI/PartSkipDialog.hpp
GUI/SkipPartCanvas.cpp
GUI/SkipPartCanvas.hpp
GUI/Search.cpp
GUI/Search.hpp
GUI/Selection.cpp

View File

@@ -1336,6 +1336,17 @@ int MachineObject::command_go_home()
return this->is_in_printing() ? this->publish_gcode("G28 X\n") : this->publish_gcode("G28 \n");
}
int MachineObject::command_task_partskip(std::vector<int> part_ids)
{
BOOST_LOG_TRIVIAL(trace) << "command_task_partskip: ";
json j;
j["print"]["command"] = "skip_objects";
j["print"]["obj_list"] = part_ids;
j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
return this->publish_json(j, 1);
}
int MachineObject::command_task_abort()
{
BOOST_LOG_TRIVIAL(trace) << "command_task_abort: ";
@@ -2313,6 +2324,7 @@ void MachineObject::reset()
}
}
subtask_ = nullptr;
m_partskip_ids.clear();
}
void MachineObject::set_print_state(std::string status)
@@ -2567,6 +2579,29 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
print_json.diff2all_base_reset(j_pre);
}
if (j_pre["print"].contains("s_obj")){
if(j_pre["print"]["s_obj"].is_array()){
m_partskip_ids.clear();
for(auto it=j_pre["print"]["s_obj"].begin(); it!=j_pre["print"]["s_obj"].end(); it++){
m_partskip_ids.push_back(it.value().get<int>());
}
}
}
}
}
if (j_pre["print"].contains("plate_idx")){ // && m_plate_index == -1
if (j_pre["print"]["plate_idx"].is_number())
{
m_plate_index = j_pre["print"]["plate_idx"].get<int>();
}
else if (j_pre["print"]["plate_idx"].is_string())
{
try
{
m_plate_index = std::stoi(j_pre["print"]["plate_idx"].get<std::string>());
}
catch (...) { BOOST_LOG_TRIVIAL(error) << "parse_json: failed to convert plate_idx to int"; }
}
}
}
@@ -4407,6 +4442,7 @@ void MachineObject::update_slice_info(std::string project_id, std::string profil
if (plate_idx >= 0) {
plate_index = plate_idx;
this->m_plate_index = plate_idx;
}
else {
std::string subtask_json;
@@ -4469,8 +4505,7 @@ void MachineObject::update_slice_info(std::string project_id, std::string profil
BOOST_LOG_TRIVIAL(error) << "task_info: get subtask id failed!";
}
}
this->m_plate_index = plate_index;
// this->m_plate_index = plate_index;
});
}
}
@@ -4880,6 +4915,7 @@ void MachineObject::parse_new_info(json print)
is_support_airprinting_detection = get_flag_bits(fun, 45);
m_fan->SetSupportCoolingFilter(get_flag_bits(fun, 46));
is_support_ext_change_assist = get_flag_bits(fun, 48);
is_support_partskip = get_flag_bits(fun, 49);
}
/*aux*/

View File

@@ -554,6 +554,9 @@ public:
time_t xcam_prompt_sound_hold_start = 0;
time_t xcam_filament_tangle_detect_hold_start = 0;
// part skip
std::vector<int> m_partskip_ids;
/*target from Studio-SwitchBoard, default to INVALID_NOZZLE_ID if no switching control from PC*/
int targ_nozzle_id_from_pc = INVALID_EXTRUDER_ID;
@@ -593,6 +596,7 @@ public:
bool m_support_mqtt_homing { false };// fun[32]
bool is_support_brtc{false}; // fun[31], support tcp and upload protocol
bool is_support_ext_change_assist{false};
bool is_support_partskip{false};
// refine printer function options
bool is_support_spaghetti_detection{false};
@@ -689,6 +693,7 @@ public:
int command_task_abort();
/* cancelled the job_id */
int command_task_partskip(std::vector<int> part_ids);
int command_task_cancel(std::string job_id);
int command_task_pause();
int command_task_resume();

View File

@@ -0,0 +1,18 @@
#ifndef PARTSKIPCOMMON_H
#define PARTSKIPCOMMON_H
namespace Slic3r { namespace GUI {
enum PartState {
psUnCheck,
psChecked,
psSkipped
};
typedef std::vector<std::pair<int, PartState>> PartsInfo;
}}
#endif // PARTSKIPCOMMON_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,163 @@
#include <wx/panel.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/sizer.h>
#include <wx/gbsizer.h>
#include <wx/webrequest.h>
#include <wx/control.h>
#include <wx/dcclient.h>
#include <wx/display.h>
#include <wx/mstream.h>
#include <wx/sstream.h>
#include <wx/zstream.h>
#include <wx/window.h>
#include <wx/dcgraph.h>
#include <wx/simplebook.h>
#include "Widgets/Label.hpp"
#include "Widgets/CheckBox.hpp"
#include "Widgets/Button.hpp"
#include "Widgets/AnimaController.hpp"
#include "DeviceManager.hpp"
#include "PartSkipCommon.hpp"
#include "Printer/PrinterFileSystem.h"
#include "I18N.hpp"
#include "GUI_Utils.hpp"
namespace Slic3r { namespace GUI {
class SkipPartCanvas;
enum URL_STATE {
URL_TCP,
URL_TUTK,
};
class PartSkipConfirmDialog : public DPIDialog
{
private:
protected:
Label *m_msg_label;
Label *m_tip_label;
Button *m_apply_button;
public:
PartSkipConfirmDialog(wxWindow *parent);
~PartSkipConfirmDialog();
void on_dpi_changed(const wxRect &suggested_rect);
Button *GetConfirmButton();
void SetMsgLabel(wxString msg);
void SetTipLabel(wxString msg);
bool Show(bool show);
};
class PartSkipDialog : public DPIDialog
{
public:
PartSkipDialog(wxWindow *parent);
~PartSkipDialog();
void on_dpi_changed(const wxRect &suggested_rect);
bool Show(bool show);
void UpdatePartsStateFromPrinter(MachineObject *obj_);
void SetSimplebookPage(int page);
void InitSchedule(MachineObject *obj_);
void InitDialogUI();
int GetAllSkippedPartsNum();
MachineObject *m_obj{nullptr};
wxSimplebook *m_simplebook;
wxPanel *m_book_third_panel;
wxPanel *m_book_second_panel;
wxPanel *m_book_first_panel;
SkipPartCanvas *m_canvas;
Button *m_zoom_in_btn;
Button *m_zoom_out_btn;
Button *m_switch_drag_btn;
CheckBox *m_all_checkbox;
Button *m_percent_label;
Label *m_all_label;
wxPanel *m_line;
wxPanel *m_line_top;
wxScrolledWindow *m_list_view;
wxPanel *m_dlg_placeholder;
Label *m_cnt_label;
Label *m_tot_label;
Button *m_apply_btn;
Label *m_loading_label;
Label *m_retry_label;
ScalableBitmap *m_retry_icon;
wxStaticBitmap *m_retry_bitmap;
wxBoxSizer *m_sizer;
wxBoxSizer *m_dlg_sizer;
wxBoxSizer *m_dlg_content_sizer;
wxBoxSizer *m_dlg_btn_sizer;
wxBoxSizer *m_canvas_sizer;
wxBoxSizer *m_canvas_btn_sizer;
wxBoxSizer *m_list_sizer;
wxBoxSizer *m_scroll_sizer;
wxBoxSizer *m_book_first_sizer;
wxBoxSizer *m_book_second_sizer;
wxBoxSizer *m_book_second_btn_sizer;
Button *m_second_retry_btn;
AnimaIcon *m_loading_icon;
private:
int m_plate_idx{-1};
int m_zoom_percent{100};
bool m_is_drag{false};
bool m_print_lock{true};
bool m_enable_apply_btn{false};
bool is_model_support_partskip{false};
std::map<uint32_t, PartState> m_parts_state;
std::map<uint32_t, std::string> m_parts_name;
std::vector<int> m_partskip_ids;
enum URL_STATE m_url_state = URL_STATE::URL_TCP;
PartsInfo GetPartsInfo();
bool is_drag_mode();
boost::shared_ptr<PrinterFileSystem> m_file_sys;
bool m_file_sys_result{false};
std::string m_timestamp;
std::string m_tmp_path;
std::vector<string> m_local_paths;
std::vector<string> m_target_paths;
std::string create_tmp_path();
bool is_local_file_existed(const std::vector<string> &local_paths);
void DownloadPartsFile();
void OnFileSystemEvent(wxCommandEvent &event);
void OnFileSystemResult(wxCommandEvent &event);
void fetchUrl(boost::weak_ptr<PrinterFileSystem> wfs);
void OnZoomIn(wxCommandEvent &event);
void OnZoomOut(wxCommandEvent &event);
void OnSwitchDrag(wxCommandEvent &event);
void OnZoomPercent(wxCommandEvent &event);
void UpdatePartsStateFromCanvas(wxCommandEvent &event);
void UpdateZoomPercent();
void UpdateCountLabel();
void UpdateDialogUI();
void UpdateApplyButtonStatus();
bool IsAllChecked();
bool IsAllCancled();
void OnRetryButton(wxCommandEvent &event);
void OnAllCheckbox(wxCommandEvent &event);
void OnApplyDialog(wxCommandEvent &event);
};
}} // namespace Slic3r::GUI

View File

@@ -39,6 +39,7 @@ wxDEFINE_EVENT(EVT_FILE_CHANGED, wxCommandEvent);
wxDEFINE_EVENT(EVT_SELECT_CHANGED, wxCommandEvent);
wxDEFINE_EVENT(EVT_THUMBNAIL, wxCommandEvent);
wxDEFINE_EVENT(EVT_DOWNLOAD, wxCommandEvent);
wxDEFINE_EVENT(EVT_RAMDOWNLOAD, wxCommandEvent);
wxDEFINE_EVENT(EVT_MEDIA_ABILITY_CHANGED, wxCommandEvent);
wxDEFINE_EVENT(EVT_UPLOADING, wxCommandEvent);
wxDEFINE_EVENT(EVT_UPLOAD_CHANGED, wxCommandEvent);
@@ -271,6 +272,149 @@ struct PrinterFileSystem::Upload : Progress
boost::filesystem::ifstream ifs;
};
void PrinterFileSystem::GetPickImages(const std::vector<std::string> &local_paths, const std::vector<std::string> &targetpaths)
{
m_download_states.clear();
GetPickImage(1, local_paths[0], targetpaths[0]);
GetPickImage(2, local_paths[1], targetpaths[1]);
GetPickImage(3, local_paths[2], targetpaths[2]);
}
void PrinterFileSystem::GetPickImage(int id, const std::string &local_path, const std::string &targetpath)
{
json j;
j["sequence_id"] = id;
j["version"] = 1;
j["peer_host"] = "studio";
j["command"] = "get_project_file";
j["file_rel_path"] = targetpath;
std::string param = j.dump();
DownloadRamFile(16, local_path, param);
}
void PrinterFileSystem::DownloadRamFile(int index, const std::string &local_path, const std::string & param)
{
std::shared_ptr<Download> download(new Download);
download->local_path = local_path;
json req;
req["path"] = "mem:/" + std::to_string(index);
req["offset"] = 0;
req["mem_dl_param_size"] = param.size();
m_download_seq = SendRequest<Progress>(
FILE_DOWNLOAD, req,
[download](json const &resp, Progress &prog, unsigned char const *data) -> int {
size_t size = resp.value("size", 0);
prog.size = resp["offset"];
prog.total = resp["total"];
if (resp.contains("mem_dl_param_size")) {
size_t s = resp["mem_dl_param_size"].get<size_t>();
std::string json_str(reinterpret_cast<const char *>(data), s);
// OutputDebugStringA(json_str.c_str());
// OutputDebugStringA("\n");
json mem_dl_json = json::parse(json_str);
// download->mem_dl_param_size = size;
if (!mem_dl_json.contains("result") || mem_dl_json["result"] == 1 ) {
wxLogWarning("Download failed: result = 1");
return ERROR_JSON;
}
if(mem_dl_json.contains("size") && mem_dl_json["size"] == 0 )
return FILE_SIZE_ERR;
return CONTINUE;
}
if (prog.size == 0 ) {
download->ofs.open(download->local_path, std::ios::binary);
if (!download->ofs) {
download->error = last_system_error();
wxLogWarning("DownloadImageFromRam open error: %s\n", wxString::FromUTF8(download->error));
return FILE_OPEN_ERR;
}
}
download->ofs.write(reinterpret_cast<const char *>(data), size);
if (!download->ofs) {
download->error = last_system_error();
wxLogWarning("DownloadImageFromRam write error: %s\n", wxString::FromUTF8(download->error));
return FILE_READ_WRITE_ERR;
}
download->boost_md5.process_bytes(data, size);
prog.size += size;
download->total = prog.total;
download->size = prog.size;
if (prog.size < prog.total) {
return 0;
}
download->ofs.close();
std::string md5 = resp["file_md5"];
boost::uuids::detail::md5::digest_type digest;
download->boost_md5.get_digest(digest);
for (int i = 0; i < 4; ++i) digest[i] = boost::endian::endian_reverse(digest[i]);
std::string str_md5;
const auto char_digest = reinterpret_cast<const char *>(&digest[0]);
boost::algorithm::hex(char_digest, char_digest + sizeof(digest), std::back_inserter(str_md5));
if (!boost::iequals(str_md5, md5)) {
wxLogWarning("DownloadImageFromRam checksum error: %s != %s\n", str_md5, md5);
boost::system::error_code ec;
boost::filesystem::rename(download->local_path, download->local_path + ".tmp", ec);
return FILE_CHECK_ERR;
}
return SUCCESS;
},
[this, download](int result, Progress const &data) {
//OutputDebugStringA(std::to_string(result).c_str());
//OutputDebugStringA("\n");
if (result == CONTINUE) { return; }
std::string msg;
if (result == SUCCESS) {
if (std::filesystem::exists(download->local_path)) {
m_download_states.emplace_back(true);
BOOST_LOG_TRIVIAL(info) <<"DownloadImageFromRam finished: " << download->local_path << "result = " << result;
}else{
m_download_states.emplace_back(false);
BOOST_LOG_TRIVIAL(warning) <<"DownloadImageFromRam finished, but file not exist: " << download->local_path << "result = " << result;
}
} else if (result != CONTINUE) {
m_download_states.emplace_back(false);
BOOST_LOG_TRIVIAL(warning) << "DownloadImageFromRam failed: " << download->error << "result = " << result;
}
if(m_download_states.size() == 3){
if(m_download_states[0] && m_download_states[1] && m_download_states[2]){
SendChangedEvent(EVT_RAMDOWNLOAD, SUCCESS);
}else{
// FILE_NO_EXIST is not really error_code
SendChangedEvent(EVT_RAMDOWNLOAD, FILE_NO_EXIST);
}
}else{
BOOST_LOG_TRIVIAL(warning) << "m_download_states current size is : " << m_download_states.size();
}
},param);
}
void PrinterFileSystem::SendExistedFile(){
SendChangedEvent(EVT_RAMDOWNLOAD, SUCCESS);
}
void PrinterFileSystem::SendConnectFail(){
SendChangedEvent(EVT_RAMDOWNLOAD, ERROR_PIPE);
}
void PrinterFileSystem::DownloadFiles(size_t index, std::string const &path)
{
if (index == (size_t) -1) {
@@ -304,6 +448,10 @@ void PrinterFileSystem::DownloadFiles(size_t index, std::string const &path)
DownloadNextFile();
}
void PrinterFileSystem::DownloadCheckFiles(std::string const &path)
{
for (size_t i = 0; i < m_file_list.size(); ++i) {
@@ -1280,7 +1428,7 @@ void PrinterFileSystem::CancelUploadTask(bool send_cancel_req)
}
}
boost::uint32_t PrinterFileSystem::SendRequest(int type, json const &req, callback_t2 const &callback)
boost::uint32_t PrinterFileSystem::SendRequest(int type, json const &req, callback_t2 const &callback,const std::string& param)
{
if (m_session.tunnel == nullptr) {
Retry();
@@ -1294,6 +1442,13 @@ boost::uint32_t PrinterFileSystem::SendRequest(int type, json const &req, callba
root["req"] = req;
std::ostringstream oss;
oss << root;
if (!param.empty()) {
oss << "\n\n";
oss << param;
}
// OutputDebugStringA(oss.str().c_str());
// OutputDebugStringA("\n");
auto msg = oss.str();
boost::unique_lock l(m_mutex);
m_messages.push_back(msg);

View File

@@ -22,6 +22,7 @@ wxDECLARE_EVENT(EVT_FILE_CHANGED, wxCommandEvent);
wxDECLARE_EVENT(EVT_SELECT_CHANGED, wxCommandEvent);
wxDECLARE_EVENT(EVT_THUMBNAIL, wxCommandEvent);
wxDECLARE_EVENT(EVT_DOWNLOAD, wxCommandEvent);
wxDECLARE_EVENT(EVT_RAMDOWNLOAD, wxCommandEvent);
wxDECLARE_EVENT(EVT_MEDIA_ABILITY_CHANGED, wxCommandEvent);
wxDECLARE_EVENT(EVT_UPLOADING, wxCommandEvent);
wxDECLARE_EVENT(EVT_UPLOAD_CHANGED, wxCommandEvent);
@@ -183,6 +184,17 @@ public:
void DownloadFiles(size_t index, std::string const &path);
void GetPickImage(int id, const std::string &local_path, const std::string &path);
void GetPickImages(const std::vector<std::string> &local_paths, const std::vector<std::string> &targetpaths);
void DownloadRamFile(int index, const std::string &local_path, const std::string &param);
void SendExistedFile();
void SendConnectFail();
void DownloadCheckFiles(std::string const &path);
bool DownloadCheckFile(size_t index);
@@ -275,7 +287,7 @@ private:
typedef std::function<int(std::string &msg)> callback_t3;
template<typename T> boost::uint32_t SendRequest(int type, json const &req, Translator<T> const &translator, Callback<T> const &callback)
template<typename T> boost::uint32_t SendRequest(int type, json const &req, Translator<T> const &translator, Callback<T> const &callback, const std::string &param = "")
{
auto c = [translator, callback, this](int result, json const &resp, unsigned char const *data) -> int
{
@@ -292,7 +304,7 @@ private:
PostCallback<T>(callback, result, t);
return result;
};
return SendRequest(type, req, c);
return SendRequest(type, req, c, param);
}
template<typename T> using Applier = std::function<void(T const &)>;
@@ -322,7 +334,7 @@ private:
InstallNotify(type, c);
}
boost::uint32_t SendRequest(int type, json const &req, callback_t2 const &callback);
boost::uint32_t SendRequest(int type, json const &req, callback_t2 const &callback, const std::string &param = "");
void InstallNotify(int type, callback_t2 const &callback);
@@ -365,6 +377,8 @@ private:
size_t m_lock_end = 0;
int m_task_flags = 0;
std::vector<bool> m_download_states;
private:
struct Session
{

View File

@@ -0,0 +1,697 @@
#include <GL/glew.h>
#include "SkipPartCanvas.hpp"
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <boost/log/trivial.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/nowide/fstream.hpp>
#include <expat.h>
#include <earcut/earcut.hpp>
#include <libslic3r/Color.hpp>
#include <filesystem>
#include <map>
wxDEFINE_EVENT(EVT_ZOOM_PERCENT, wxCommandEvent);
wxDEFINE_EVENT(EVT_CANVAS_PART, wxCommandEvent);
namespace Slic3r {
namespace GUI {
SkipPartCanvas::SkipPartCanvas(wxWindow *parent, const wxGLAttributes& dispAttrs)
: wxGLCanvas(parent, dispAttrs) {
context_ = new wxGLContext(this);
this->Bind(wxEVT_PAINT, &SkipPartCanvas::OnPaint, this);
this->Bind(wxEVT_MOUSEWHEEL, &SkipPartCanvas::OnMouseWheel, this);
this->Bind(wxEVT_LEFT_DOWN, &SkipPartCanvas::OnMouseLeftDown, this);
this->Bind(wxEVT_LEFT_DCLICK, &SkipPartCanvas::OnMouseLeftDown, this);
this->Bind(wxEVT_LEFT_UP, &SkipPartCanvas::OnMouseLeftUp, this);
this->Bind(wxEVT_RIGHT_DOWN, &SkipPartCanvas::OnMouseRightDown, this);
this->Bind(wxEVT_RIGHT_UP, &SkipPartCanvas::OnMouseRightUp, this);
this->Bind(wxEVT_SIZE, &SkipPartCanvas::OnSize, this);
this->Bind(wxEVT_MOTION, &SkipPartCanvas::OnMouseMotion, this);
}
void SkipPartCanvas::LoadPickImage(const std::string & path)
{
if(!std::filesystem::exists(path)) return;
auto ParseShapeId = [](cv::Mat image, const std::vector<std::vector<cv::Point>> &contours, const std::vector<cv::Vec4i> &hierarchy, int root_idx) -> uint32_t {
cv::Mat mask = cv::Mat::zeros(image.size(), CV_8UC1);
cv::drawContours(mask, contours, root_idx, 255, cv::FILLED);
int child = hierarchy[root_idx][2];
while (child != -1) {
cv::drawContours(mask, contours, child, 0, cv::FILLED);
child = hierarchy[child][0];
}
std::vector<cv::Vec3b> pixels;
for (int y = 0; y < image.rows; ++y) {
for (int x = 0; x < image.cols; ++x) {
if (mask.at<uchar>(y, x)) { pixels.push_back(image.at<cv::Vec3b>(y, x)); }
}
}
std::map<cv::Vec3b, int, std::function<bool(const cv::Vec3b &, const cv::Vec3b &)>> colorCount(
[](const cv::Vec3b &a, const cv::Vec3b &b) { return std::lexicographical_compare(a.val, a.val + 3, b.val, b.val + 3); });
for (auto &c : pixels) colorCount[c]++;
cv::Vec3b main_color;
int max_count = 0;
int total_count = 0;
for (const auto &kv : colorCount) {
if (kv.second > max_count) {
max_count = kv.second;
main_color = kv.first;
}
total_count += kv.second;
}
SkipIdHelper helper{main_color[2], main_color[1], main_color[0]};
helper.reverse();
return (max_count * 2 > total_count) ? helper.value : 0;
};
parts_state_.clear();
parts_triangles_.clear();
pick_parts_.clear();
int preffered_w{FromDIP(400)}, preffered_h{FromDIP(400)};
cv::Mat src_image = cv::imread(path, cv::IMREAD_UNCHANGED);
cv::cvtColor(src_image, src_image, cv::COLOR_BGRA2BGR); // remove alpha
float zoom_x{static_cast<float>(preffered_w) / src_image.cols};
float zoom_y{static_cast<float>(preffered_h) / src_image.rows};
float image_scale{0};
if (abs(zoom_x - 1) > abs(zoom_y - 1))
image_scale = zoom_x;
else
image_scale = zoom_y;
image_view_scale_ = 1 / image_scale;
pick_image_ = src_image;
std::vector<cv::Mat> channels;
cv::Mat gray; // convert to gray
cv::cvtColor(pick_image_, gray, cv::COLOR_BGR2GRAY);
cv::Mat mask; // convery to binary
cv::threshold(gray, mask, 0, 255, cv::THRESH_BINARY);
std::vector<std::vector<cv::Point>> pick_counters;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(mask, pick_counters, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_TC89_KCOS);
auto compute_depth = [&](int idx) {
int depth = 0;
while (hierarchy[idx][3] != -1) {
depth++;
idx = hierarchy[idx][3];
}
return depth;
};
for (int i = 0; i < pick_counters.size(); ++i) {
int depth = compute_depth(i);
int parent = hierarchy[i][3];
if (parent != -1) continue;
auto id = ParseShapeId(pick_image_, pick_counters, hierarchy, i);
if (id > 0) {
std::vector<FloatPoint> flat_points;
std::vector<std::vector<FloatPoint>> polygon;
// part body
{
polygon.emplace_back();
for (const auto &pt : pick_counters[i]) {
FloatPoint fp{pt.x * 1.0f, pt.y * 1.0f};
polygon.back().push_back(fp);
flat_points.push_back(fp);
}
int child = hierarchy[i][2];
while (child != -1) {
polygon.emplace_back();
for (const auto &pt : pick_counters[child]) {
FloatPoint fp{pt.x * 1.0f, pt.y * 1.0f};
polygon.back().push_back(fp);
flat_points.push_back(fp);
}
child = hierarchy[child][0];
}
std::vector<uint32_t> indices = mapbox::earcut<uint32_t>(polygon);
std::vector<FloatPoint> final_counter;
for (size_t j = 0; j < indices.size(); j += 3) {
final_counter.push_back(flat_points[indices[j]]);
final_counter.push_back(flat_points[indices[j + 1]]);
final_counter.push_back(flat_points[indices[j + 2]]);
}
parts_triangles_[id].emplace_back(final_counter);
}
// part outlines
{
pick_parts_[id].emplace_back(pick_counters[i]);
int child = hierarchy[i][2];
while (child != -1) {
pick_parts_[id].emplace_back(pick_counters[child]);
child = hierarchy[child][0];
}
}
if (parts_state_.find(id) == parts_state_.end()) parts_state_.emplace(id, psUnCheck);
}
}
}
void SkipPartCanvas::ZoomIn(const int zoom_percent)
{
SetZoomPercent(zoom_percent_ + zoom_percent);
Refresh();
}
void SkipPartCanvas::ZoomOut(const int zoom_percent)
{
SetZoomPercent(zoom_percent_ - zoom_percent);
Refresh();
}
void SkipPartCanvas::SwitchDrag(const bool drag_on)
{
fixed_draging_ = drag_on;
AutoSetCursor();
}
void SkipPartCanvas::UpdatePartsInfo(const PartsInfo& parts)
{
for (auto const& part : parts) {
if (auto res = parts_state_.find(part.first); res != parts_state_.end())
res->second = part.second;
}
Refresh();
}
void DrawRoundedRect(float x, float y, float width, float height, float radius, const ColorRGB& color, int segments = 16)
{
glColor3f(color.r(), color.g(), color.b());
// 1. Draw center rectangle
glBegin(GL_QUADS);
glVertex2f(x + radius, y + radius);
glVertex2f(x + width - radius, y + radius);
glVertex2f(x + width - radius, y + height - radius);
glVertex2f(x + radius, y + height - radius);
glEnd();
// 2. Draw side rectangles (excluding corners)
glBegin(GL_QUADS);
// Left
glVertex2f(x, y + radius);
glVertex2f(x + radius, y + radius);
glVertex2f(x + radius, y + height - radius);
glVertex2f(x, y + height - radius);
// Right
glVertex2f(x + width - radius, y + radius);
glVertex2f(x + width, y + radius);
glVertex2f(x + width, y + height - radius);
glVertex2f(x + width - radius, y + height - radius);
// Top
glVertex2f(x + radius, y + height - radius);
glVertex2f(x + width - radius, y + height - radius);
glVertex2f(x + width - radius, y + height);
glVertex2f(x + radius, y + height);
// Bottom
glVertex2f(x + radius, y);
glVertex2f(x + width - radius, y);
glVertex2f(x + width - radius, y + radius);
glVertex2f(x + radius, y + radius);
glEnd();
// 3. Draw corners
auto drawCorner = [&](float cx, float cy, float startAngle) {
glBegin(GL_TRIANGLE_FAN);
glVertex2f(cx, cy);
for (int i = 0; i <= segments; ++i) {
float angle = startAngle + (M_PI * 0.5f) * (float)i / segments;
glVertex2f(cx + cosf(angle) * radius, cy + sinf(angle) * radius);
}
glEnd();
};
drawCorner(x + radius, y + radius, M_PI); // bottom-left
drawCorner(x + width - radius, y + radius, 1.5f * M_PI); // bottom-right
drawCorner(x + width - radius, y + height - radius, 0.0f); // top-right
drawCorner(x + radius, y + height - radius, 0.5f * M_PI); // top-left
}
void SkipPartCanvas::Render()
{
constexpr float border_w = 3.f;
constexpr int uncheckd_stencil =1;
constexpr int checkd_stencil = 2;
constexpr int skipped_stencil = 3;
SetCurrent(*context_);
glPushAttrib(GL_ALL_ATTRIB_BITS);
int w, h;
GetClientSize(&w, &h);
#if defined(__APPLE__)
double scale = GetDPIScaleFactor();
glViewport(0, 0, w * scale, h * scale);
#else
glViewport(0, 0, w, h);
#endif
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
auto view_rect = ViewPtToImagePt(wxPoint(w, h));
glOrtho(offset_.x, view_rect.x, view_rect.y, offset_.y, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(parent_color_.r(), parent_color_.g(), parent_color_.b(), 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
float rx = offset_.x;
float ry = offset_.y;
float rw = view_rect.x - offset_.x;
float rh = view_rect.y - offset_.y;
float radius = std::min(rw, rh) * 0.05f;
DrawRoundedRect(rx, ry, rw, rh, radius, ColorRGB{0.9f, 0.9f, 0.9f});
glEnable(GL_BLEND);
glEnable(GL_MULTISAMPLE);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glEnable(GL_STENCIL_TEST);
auto draw_shape = [this, border_w](const int stencil, const PartState part_type, const ColorRGB& rgb) {
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_ALWAYS, stencil, 0xFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
for (const auto& contour : parts_triangles_) {
auto part_info = parts_state_.find(contour.first);
if (part_info == parts_state_.end() || part_info->second != part_type)
continue;
glColor3f(1, 1, 1);
for (const auto &contour_item : contour.second) {
glBegin(GL_TRIANGLES);
for (size_t i = 0; i < contour_item.size(); i += 3) {
glVertex2f(contour_item[i][0], contour_item[i][1]);
glVertex2f(contour_item[i + 1][0], contour_item[i + 1][1]);
glVertex2f(contour_item[i + 2][0], contour_item[i + 2][1]);
}
glEnd();
}
}
for (const auto& contour : pick_parts_) {
if (contour.first != this->hover_id_) continue;
auto part_info = parts_state_.find(contour.first);
if (part_info == parts_state_.end() || part_info->second != part_type)
continue;
glColor3f(rgb.r(), rgb.g(), rgb.b());
glLineWidth(border_w);
for (const auto &contour_item : contour.second) {
glBegin(GL_LINE_LOOP);
for (const auto &pt : contour_item) { glVertex2f(pt.x, pt.y); }
glEnd();
}
}
};
// draw unchecked shapes
// stencil1 => unchecked
draw_shape(uncheckd_stencil, psUnCheck, ColorRGB{0, 174 / 255.f, 66 / 255.f});
// draw checked shapes
// stencil2 => checked
draw_shape(checkd_stencil, psChecked, ColorRGB{208 / 255.f, 27 / 255.f, 66 / 255.f});
// draw skipped shapes
// stencil3 => skipped
draw_shape(skipped_stencil, psSkipped, ColorRGB{95 / 255.f, 95 / 255.f, 95 / 255.f});
auto draw_mask = [this, view_rect, border_w, w, h](const int stencil, const PartState part_type,
const ColorRGB& background, const ColorRGB& line, const ColorRGB& bound) {
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_EQUAL, stencil, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // Don't change stencil
glColor3f(background.r(), background.g(), background.b());
glBegin(GL_POLYGON);
glVertex2f(offset_.x, offset_.y);
glVertex2f(offset_.x, view_rect.y);
glVertex2f(view_rect.x, view_rect.y);
glVertex2f(view_rect.x, offset_.y);
glEnd();
// draw main color
glColor3f(line.r(), line.g(), line.b());
// re-draw shape bound
for (const auto& contour : pick_parts_) {
auto part_info = parts_state_.find(contour.first);
if (part_info == parts_state_.end() || part_info->second != part_type)
continue;
glColor3f(bound.r(), bound.g(), bound.b());
glLineWidth(border_w);
for (const auto &contour_item : contour.second) {
glBegin(GL_LINE_LOOP);
for (const auto &pt : contour_item) { glVertex2f(pt.x, pt.y); }
glEnd();
}
}
};
draw_mask(checkd_stencil, psChecked, ColorRGB{239 / 255.f, 175 / 255.f, 175 / 255.f},
ColorRGB{225 / 255.f, 71 / 255.f, 71 / 255.f}, ColorRGB{208 / 255.f, 27 / 255.f, 27 / 255.f});
draw_mask(skipped_stencil, psSkipped, ColorRGB{159 / 255.f, 159 / 255.f, 159 / 255.f},
ColorRGB{95 / 255.f, 95 / 255.f, 95 / 255.f}, ColorRGB{95 / 255.f, 95 / 255.f, 95 / 255.f});
glDisable(GL_STENCIL_TEST);
glPopAttrib();
glFlush();
}
void SkipPartCanvas::DebugLogLine(std::string str)
{
//if (!log_ctrl)
// return;
//log_ctrl->AppendText(str + "\n");
}
void SkipPartCanvas::SendSelectEvent(int id, PartState state) {
wxCommandEvent evt(EVT_CANVAS_PART);
evt.SetExtraLong(id);
evt.SetInt(static_cast<int>(state));
wxPostEvent(this, evt);
}
void SkipPartCanvas::SendZoomEvent(int zoom_percent) {
wxCommandEvent evt(EVT_ZOOM_PERCENT);
evt.SetInt(zoom_percent_);
wxPostEvent(this, evt);
}
inline double SkipPartCanvas::Zoom() const
{
return zoom_percent_ / 100.0f;
}
inline wxPoint SkipPartCanvas::ViewPtToImagePt(const wxPoint& view_pt) const
{
return wxPoint(view_pt.x * image_view_scale_ / Zoom(), view_pt.y * image_view_scale_ / Zoom()) + offset_;
}
uint32_t SkipPartCanvas::GetIdAtImagePt(const wxPoint& image_pt) const
{
if (image_pt.x >= 0 && image_pt.x < pick_image_.cols
&& image_pt.y >= 0 && image_pt.y < pick_image_.rows) {
// at(row, col)=>at(y, x)
cv::Vec3b bgr = pick_image_.at<cv::Vec3b>(image_pt.y, image_pt.x);
SkipIdHelper helper{bgr[2], bgr[1], bgr[0]};
helper.reverse();
return helper.value;
} else {
return 0;
}
}
inline uint32_t SkipPartCanvas::GetIdAtViewPt(const wxPoint& view_pt) const
{
wxPoint pt_at_image = ViewPtToImagePt(view_pt);
return GetIdAtImagePt(pt_at_image);
}
void SkipPartCanvas::SetZoomPercent(const int value)
{
zoom_percent_ = std::clamp(value, 100, 1000);
std::ostringstream oss;
oss << "zoom to " << zoom_percent_;
DebugLogLine(oss.str());
SendZoomEvent(zoom_percent_);
}
void SkipPartCanvas::SetOffset(const wxPoint& value)
{
int w, h;
GetClientSize(&w, &h);
int max_w = static_cast<int>(w * (1 - 1 / Zoom())) >= 0 ? static_cast<int>(w * (1 - 1 / Zoom())) : 0;
int max_h = static_cast<int>(w * (1 - 1 / Zoom())) >= 0 ? static_cast<int>(h * (1 - 1 / Zoom())) : 0;
offset_.x = std::clamp(value.x, 0, max_w);
offset_.y = std::clamp(value.y, 0, max_h);
}
void SkipPartCanvas::AutoSetCursor()
{
if(is_draging_ || fixed_draging_)
SetCursor(wxCursor(wxCURSOR_HAND));
else
SetCursor(wxCursor(wxCURSOR_NONE));
}
void SkipPartCanvas::StartDrag(const wxPoint& mouse_pt)
{
drag_start_pt_ = mouse_pt;
drag_start_offset_ = offset_;
is_draging_ = true;
AutoSetCursor();
}
void SkipPartCanvas::ProcessDrag(const wxPoint& mouse_pt)
{
wxPoint drag_offset = (mouse_pt - drag_start_pt_) * image_view_scale_;
SetOffset(- wxPoint(drag_offset.x / Zoom(), drag_offset.y / Zoom()) + drag_start_offset_);
Refresh();
}
void SkipPartCanvas::ProcessHover(const wxPoint& mouse_pt)
{
auto id_at_mouse = GetIdAtViewPt(mouse_pt);
int new_hover_id { -1 };
auto part_state = parts_state_.find(id_at_mouse);
if (part_state != parts_state_.end() && part_state->second == psUnCheck) {
new_hover_id = id_at_mouse;
};
if (new_hover_id != this->hover_id_) {
this->hover_id_ = new_hover_id;
Refresh();
}
}
void SkipPartCanvas::EndDrag()
{
is_draging_ = false;
AutoSetCursor();
}
void SkipPartCanvas::OnPaint(wxPaintEvent &event)
{
wxPaintDC dc(this);
if (!IsShown()) return;
SetCurrent(*context_);
Render();
SwapBuffers();
}
void SkipPartCanvas::OnSize(wxSizeEvent& event)
{
event.Skip();
}
void SkipPartCanvas::OnMouseLeftDown(wxMouseEvent& event)
{
DebugLogLine("OnMouseLeftDown");
if (!event.LeftIsDown()) {
event.Skip();
DebugLogLine("skip----OnMouseLeftDown");
return;
}
if (fixed_draging_)
StartDrag(wxPoint(event.GetX(), event.GetY()));
left_down_ = true;
}
void SkipPartCanvas::OnMouseLeftUp(wxMouseEvent& event)
{
DebugLogLine("OnMouseLeftUp");
if (event.LeftIsDown() || !left_down_) {
event.Skip();
DebugLogLine("skip----OnMouseLeftUp");
return;
}
auto id_at_mouse = GetIdAtViewPt(wxPoint(event.GetX(), event.GetY()));
auto part_state = parts_state_.find(id_at_mouse);
if (part_state != parts_state_.end() && part_state->second != psSkipped) {
if (part_state->second == psUnCheck)
part_state = parts_state_.insert_or_assign(part_state->first, psChecked).first;
else
part_state = parts_state_.insert_or_assign(part_state->first, psUnCheck).first;
// if (select_callback_)
// select_callback_(part_state->first, part_state->second);
SendSelectEvent(part_state->first, part_state->second);
}
left_down_ = false;
if (fixed_draging_)
EndDrag();
else {
Refresh();
}
}
void SkipPartCanvas::OnMouseRightDown(wxMouseEvent& event)
{
DebugLogLine("OnMouseRightDown");
if (!event.RightIsDown()) {
event.Skip();
DebugLogLine("skip----OnMouseRightDown");
return;
}
StartDrag(wxPoint(event.GetX(), event.GetY()));
}
void SkipPartCanvas::OnMouseRightUp(wxMouseEvent& event)
{
DebugLogLine("OnMouseRightUp");
if (event.RightIsDown() || !is_draging_) {
event.Skip();
DebugLogLine("skip----OnMouseRightUp");
return;
}
EndDrag();
}
void SkipPartCanvas::OnMouseMotion(wxMouseEvent& event)
{
ProcessHover(wxPoint(event.GetX(), event.GetY()));
if (!event.RightIsDown() && !(event.LeftIsDown() && fixed_draging_)) {
event.Skip();
return;
}
ProcessDrag(wxPoint(event.GetX(), event.GetY()));
}
void SkipPartCanvas::OnMouseWheel(wxMouseEvent& event)
{
wxPoint view_mouse = wxPoint(event.GetX(), event.GetY());
auto pre_image_pos = ViewPtToImagePt(view_mouse);
SetZoomPercent(zoom_percent_ + 10 * (event.GetWheelRotation() / 120.0));
auto now_image_pos = ViewPtToImagePt(view_mouse);
SetOffset(offset_ - (now_image_pos - pre_image_pos));
Refresh();
}
// Base class with error messages management
void _BBS_3MF_Base::add_error(const std::string &error) const
{
boost::unique_lock l(mutex);
m_errors.push_back(error);
}
void _BBS_3MF_Base::clear_errors() { m_errors.clear(); }
void _BBS_3MF_Base::log_errors()
{
for (const std::string &error : m_errors) BOOST_LOG_TRIVIAL(error) << error;
}
ModelSettingHelper::ModelSettingHelper(const std::string &path) : path_(path) {}
bool ModelSettingHelper::Parse()
{
boost::nowide::fstream fs(path_);
if (!fs) {
add_error("Failed to open file\n");
return false;
}
XML_Parser parser = XML_ParserCreate(nullptr);
if (!parser) {
add_error("Unable to create parser");
return false;
}
XML_SetUserData(parser, this);
XML_SetElementHandler(parser, ModelSettingHelper::StartElementHandler, ModelSettingHelper::EndElementHandler);
try {
char buffer[4000];
while (fs.read(buffer, sizeof(buffer)) || fs.gcount() > 0) {
auto ret = XML_Parse(parser, buffer, static_cast<int>(fs.gcount()), fs.eof());
if (ret != XML_STATUS_OK) {
add_error("return value of XML_Parse doesn't match XM_STATUS_OK");
XML_ParserFree(parser);
return false;
}
}
}
catch (std::exception& e) {
add_error(std::string("exception:") + e.what());
XML_ParserFree(parser);
return false;
}
XML_ParserFree(parser);
return true;
}
void XMLCALL ModelSettingHelper::StartElementHandler(void *userData, const XML_Char *name, const XML_Char **atts)
{
ModelSettingHelper *self = static_cast<ModelSettingHelper *>(userData);
if (strcmp(name, "plate") == 0) {
self->context_.current_plate = PlateInfo(); // start a new plate
self->context_.in_plate = true;
} else if (strcmp(name, "metadata") == 0 && self->context_.in_plate) {
std::string key, value;
for (int i = 0; atts[i]; i += 2) {
if (strcmp(atts[i], "key") == 0) key = atts[i + 1];
if (strcmp(atts[i], "value") == 0) value = atts[i + 1];
}
if (key == "index") { self->context_.current_plate.index = std::stoi(value); }
if (key == "label_object_enabled") { self->context_.current_plate.label_object_enabled = value == "true"; }
} else if (strcmp(name, "object") == 0 && self->context_.in_plate) {
ObjectInfo obj;
for (int i = 0; atts[i]; i += 2) {
if (strcmp(atts[i], "identify_id") == 0) obj.identify_id = atoi(atts[i + 1]);
if (strcmp(atts[i], "name") == 0) obj.name = atts[i + 1];
}
self->context_.current_plate.objects.push_back(obj);
}
}
void XMLCALL ModelSettingHelper::EndElementHandler(void *userData, const XML_Char *name)
{
ModelSettingHelper *self = static_cast<ModelSettingHelper *>(userData);
if (strcmp(name, "plate") == 0 && self->context_.in_plate) {
self->context_.plates.push_back(self->context_.current_plate);
self->context_.current_plate = PlateInfo(); // reset
self->context_.in_plate = false;
}
}
std::vector<ObjectInfo> ModelSettingHelper::GetPlateObjects(int plate_idx) {
for (const auto &plate : context_.plates) {
if (plate.index == plate_idx) {
return plate.objects;
}
}
return std::vector<ObjectInfo>();
}
bool ModelSettingHelper::GetLabelObjectEnabled(int plate_idx)
{
for (const auto &plate : context_.plates) {
if (plate.index == plate_idx) { return plate.label_object_enabled; }
}
return false;
}
void ModelSettingHelper::DataHandler(const XML_Char *s, int len)
{
// do nothing
}
}
}

View File

@@ -0,0 +1,169 @@
#ifndef SKIPPARTCANVAS_H
#define SKIPPARTCANVAS_H
#include <wx/wx.h>
#include <wx/glcanvas.h>
#include <opencv2/opencv.hpp>
#include <wx/textctrl.h>
#include <vector>
#include <expat.h>
#include <libslic3r/Color.hpp>
#include <boost/thread/mutex.hpp>
#include "PartSkipCommon.hpp"
wxDECLARE_EVENT(EVT_ZOOM_PERCENT, wxCommandEvent);
wxDECLARE_EVENT(EVT_CANVAS_PART, wxCommandEvent);
namespace Slic3r {
namespace GUI {
using Coord = float;
using FloatPoint = std::array<Coord, 2>;
struct ObjectInfo {
std::string name{""};
int identify_id{-1};
PartState state{psUnCheck};
};
class SkipPartCanvas : public wxGLCanvas
{
union SkipIdHelper
{
uint32_t value = 0;
struct
{
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t _padding;
};
uint8_t bytes[4];
SkipIdHelper() = default;
SkipIdHelper(uint8_t red, uint8_t green, uint8_t blue)
: r(red), g(green), b(blue), _padding(0) {}
SkipIdHelper(uint32_t val): value(val){}
void reverse() {
uint8_t tmp{r};
r = b;
b = tmp;
}
};
public:
SkipPartCanvas(wxWindow *parent, const wxGLAttributes& dispAttrs);
~SkipPartCanvas() = default;
void SetParentBackground(const ColorRGB& color) {
parent_color_ = color;
}
void LoadPickImage(const std::string& path);
void ZoomIn(const int zoom_percent);
void ZoomOut(const int zoom_percent);
void SwitchDrag(const bool drag_on);
void UpdatePartsInfo(const PartsInfo& parts);
void SetZoomPercent(const int value);
void SetOffset(const wxPoint &value);
wxTextCtrl* log_ctrl;
protected:
void OnPaint(wxPaintEvent& event);
void OnSize(wxSizeEvent& event);
void OnMouseLeftDown(wxMouseEvent& event);
void OnMouseLeftUp(wxMouseEvent& event);
void OnMouseRightDown(wxMouseEvent& event);
void OnMouseRightUp(wxMouseEvent& event);
void OnMouseMotion(wxMouseEvent& event);
void OnMouseWheel(wxMouseEvent& event);
private:
wxGLContext* context_;
cv::Mat pick_image_;
std::unordered_map < uint32_t, std::vector<std::vector<FloatPoint>>> parts_triangles_;
std::unordered_map < uint32_t, std::vector<std::vector<cv::Point>>> pick_parts_;
std::unordered_map<uint32_t, PartState> parts_state_;
bool gl_inited_{false};
int zoom_percent_{100};
wxPoint offset_{0,0};
wxPoint drag_start_offset_{0,0};
wxPoint drag_start_pt_{0,0};
bool is_draging_{false};
bool fixed_draging_{false};
bool left_down_{false};
ColorRGB parent_color_ = ColorRGB();
int hover_id_{-1};
double image_view_scale_{1};
void SendSelectEvent(int id, PartState state);
void SendZoomEvent(int zoom_percent);
inline double Zoom() const;
inline wxPoint ViewPtToImagePt(const wxPoint& view_pt) const;
uint32_t GetIdAtImagePt(const wxPoint& image_pt) const;
inline uint32_t GetIdAtViewPt(const wxPoint& view_pt) const;
void ProcessHover(const wxPoint& mouse_pt);
void AutoSetCursor();
void StartDrag(const wxPoint& mouse_pt);
void ProcessDrag(const wxPoint& mouse_pt);
void EndDrag();
void Render();
void DebugLogLine(std::string str);
};
class _BBS_3MF_Base
{
mutable boost::mutex mutex;
mutable std::vector<std::string> m_errors;
protected:
void add_error(const std::string& error) const;
void clear_errors();
public:
void log_errors();
};
struct PlateInfo
{
int index{-1};
std::vector<ObjectInfo> objects;
bool label_object_enabled = false;
};
class ModelSettingHelper : public _BBS_3MF_Base
{
struct ParseContext
{
std::vector<PlateInfo> plates;
PlateInfo current_plate;
ObjectInfo temp_object;
bool in_plate = false;
};
public:
ModelSettingHelper(const std::string &path);
bool Parse();
std::vector<ObjectInfo> GetPlateObjects(int plate_idx);
bool GetLabelObjectEnabled(int plate_idx);
private:
std::string path_;
ParseContext context_;
static void XMLCALL StartElementHandler(void *userData, const XML_Char *name, const XML_Char **atts);
static void XMLCALL EndElementHandler(void *userData, const XML_Char *name);
void DataHandler(const XML_Char *s, int len);
};
}
}
#endif //SKIPPARTCANVAS_H

View File

@@ -584,12 +584,6 @@ void PrintingTaskPanel::create_panel(wxWindow* parent)
bSizer_task_name->Add(task_name_panel, 0, wxEXPAND, FromDIP(5));
/* wxFlexGridSizer *fgSizer_task = new wxFlexGridSizer(2, 2, 0, 0);
fgSizer_task->AddGrowableCol(0);
fgSizer_task->SetFlexibleDirection(wxVERTICAL);
fgSizer_task->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);*/
m_printing_stage_value = new wxStaticText(parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT | wxST_ELLIPSIZE_END);
m_printing_stage_value->Wrap(-1);
m_printing_stage_value->SetMaxSize(wxSize(FromDIP(800),-1));
@@ -612,24 +606,34 @@ void PrintingTaskPanel::create_panel(wxWindow* parent)
m_staticText_profile_value->SetForegroundColour(0x6B6B6B);
auto progress_lr_panel = new wxPanel(parent, wxID_ANY);
progress_lr_panel->SetBackgroundColour(*wxWHITE);
auto m_panel_progress = new wxPanel(parent, wxID_ANY);
m_panel_progress->SetBackgroundColour(*wxWHITE);
auto m_sizer_progressbar = new wxBoxSizer(wxHORIZONTAL);
m_gauge_progress = new ProgressBar(m_panel_progress, wxID_ANY, 100, wxDefaultPosition, wxDefaultSize);
m_gauge_progress = new ProgressBar(progress_lr_panel, wxID_ANY, 100, wxDefaultPosition, wxDefaultSize);
m_gauge_progress->SetValue(0);
m_gauge_progress->SetHeight(PROGRESSBAR_HEIGHT);
m_gauge_progress->SetMaxSize(wxSize(FromDIP(600), -1));
m_panel_progress->SetSizer(m_sizer_progressbar);
m_panel_progress->Layout();
m_panel_progress->SetSize(wxSize(-1, FromDIP(24)));
m_panel_progress->SetMaxSize(wxSize(-1, FromDIP(24)));
wxBoxSizer *bSizer_task_btn = new wxBoxSizer(wxHORIZONTAL);
bSizer_task_btn->Add(FromDIP(10), 0, 0);
m_button_pause_resume = new ScalableButton(m_panel_progress, wxID_ANY, "print_control_pause", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER,true);
StateColor white_bg(std::pair<wxColour, int>(wxColour(255, 255, 255), StateColor::Disabled), std::pair<wxColour, int>(wxColour(255, 255, 255), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(255, 255, 255), StateColor::Hovered), std::pair<wxColour, int>(wxColour(255, 255, 255), StateColor::Enabled),
std::pair<wxColour, int>(wxColour(255, 255, 255), StateColor::Normal));
m_button_partskip = new Button(progress_lr_panel, wxEmptyString, "print_control_partskip_disable", 0, 20, wxID_ANY);
m_button_partskip->Enable(false);
m_button_partskip->Hide();
m_button_partskip->SetBackgroundColor(white_bg);
m_button_partskip->SetIcon("print_control_partskip_disable");
m_button_partskip->SetBorderColor(*wxWHITE);
m_button_partskip->SetFont(Label::Body_12);
m_button_partskip->SetCornerRadius(0);
m_button_partskip->SetToolTip(_L("Parts Skip"));
m_button_partskip->Bind(wxEVT_ENTER_WINDOW, [this](auto &e) { m_button_partskip->SetIcon("print_control_partskip_hover"); });
m_button_partskip->Bind(wxEVT_LEAVE_WINDOW, [this](auto &e) { m_button_partskip->SetIcon("print_control_partskip"); });
m_button_pause_resume = new ScalableButton(progress_lr_panel, wxID_ANY, "print_control_pause", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER,true);
m_button_pause_resume->Bind(wxEVT_ENTER_WINDOW, [this](auto &e) {
if (m_button_pause_resume->GetToolTipText() == _L("Pause")) {
@@ -652,7 +656,7 @@ void PrintingTaskPanel::create_panel(wxWindow* parent)
}
});
m_button_abort = new ScalableButton(m_panel_progress, wxID_ANY, "print_control_stop", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true);
m_button_abort = new ScalableButton(progress_lr_panel, wxID_ANY, "print_control_stop", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true);
m_button_abort->SetToolTip(_L("Stop"));
m_button_abort->Bind(wxEVT_ENTER_WINDOW, [this](auto &e) {
@@ -663,19 +667,14 @@ void PrintingTaskPanel::create_panel(wxWindow* parent)
m_button_abort->SetBitmap_("print_control_stop"); }
);
m_sizer_progressbar->Add(m_gauge_progress, 1, wxALIGN_CENTER_VERTICAL, 0);
m_sizer_progressbar->Add(0, 0, 0, wxEXPAND|wxLEFT, FromDIP(18));
m_sizer_progressbar->Add(m_button_pause_resume, 0, wxALL, FromDIP(5));
m_sizer_progressbar->Add(0, 0, 0, wxEXPAND|wxLEFT, FromDIP(18));
m_sizer_progressbar->Add(m_button_abort, 0, wxALL, FromDIP(5));
wxBoxSizer *bSizer_buttons = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer *bSizer_text = new wxBoxSizer(wxHORIZONTAL);
wxPanel* penel_bottons = new wxPanel(parent);
wxPanel* penel_text = new wxPanel(penel_bottons);
wxBoxSizer *bSizer_finish_time = new wxBoxSizer(wxHORIZONTAL);
wxPanel* penel_text = new wxPanel(progress_lr_panel);
wxPanel* penel_finish_time = new wxPanel(progress_lr_panel);
penel_text->SetBackgroundColour(*wxWHITE);
penel_bottons->SetBackgroundColour(*wxWHITE);
penel_finish_time->SetBackgroundColour(*wxWHITE);
wxBoxSizer *sizer_percent = new wxBoxSizer(wxVERTICAL);
sizer_percent->Add(0, 0, 1, wxEXPAND, 0);
@@ -708,55 +707,65 @@ void PrintingTaskPanel::create_panel(wxWindow* parent)
m_staticText_progress_left->SetFont(wxFont(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxT("HarmonyOS Sans SC")));
m_staticText_progress_left->SetForegroundColour(wxColour(146, 146, 146));
// Orca: display the end time of the print
m_staticText_progress_end = new wxStaticText(penel_text, wxID_ANY, L("N/A"), wxDefaultPosition, wxDefaultSize, 0);
m_staticText_progress_end->Wrap(-1);
m_staticText_progress_end->SetFont(
wxFont(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxT("HarmonyOS Sans SC")));
m_staticText_progress_end->SetForegroundColour(wxColour(146, 146, 146));
//fgSizer_task->Add(bSizer_buttons, 0, wxEXPAND, 0);
//fgSizer_task->Add(0, 0, 0, wxEXPAND, FromDIP(5));
wxPanel* panel_button_block = new wxPanel(penel_bottons, wxID_ANY);
panel_button_block->SetMinSize(wxSize(TASK_BUTTON_SIZE.x * 2 + FromDIP(5) * 4, -1));
panel_button_block->SetMinSize(wxSize(TASK_BUTTON_SIZE.x * 2 + FromDIP(5) * 4, -1));
panel_button_block->SetSize(wxSize(TASK_BUTTON_SIZE.x * 2 + FromDIP(5) * 2, -1));
panel_button_block->SetBackgroundColour(*wxWHITE);
m_staticText_layers = new wxStaticText(penel_text, wxID_ANY, _L("Layer: N/A"));
m_staticText_layers->SetFont(wxFont(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxT("HarmonyOS Sans SC")));
m_staticText_layers->SetForegroundColour(wxColour(146, 146, 146));
m_staticText_layers->Hide();
//bSizer_text->Add(m_staticText_progress_percent, 0, wxALL, 0);
bSizer_text->Add(sizer_percent, 0, wxEXPAND, 0);
bSizer_text->Add(sizer_percent_icon, 0, wxEXPAND, 0);
bSizer_text->Add(0, 0, 1, wxEXPAND, 0);
bSizer_text->Add(m_staticText_layers, 0, wxALIGN_CENTER | wxALL, 0);
bSizer_text->Add(m_staticText_layers, 0, wxALIGN_CENTER_VERTICAL | wxALL, 0);
bSizer_text->Add(0, 0, 0, wxLEFT, FromDIP(20));
bSizer_text->Add(m_staticText_progress_left, 0, wxALIGN_CENTER | wxALL, 0);
// Orca: display the end time of the print
bSizer_text->Add(0, 0, 0, wxLEFT, FromDIP(8));
bSizer_text->Add(m_staticText_progress_end, 0, wxALIGN_CENTER | wxALL, 0);
bSizer_text->Add(m_staticText_progress_left, 0, wxALIGN_CENTER_VERTICAL | wxALL, 0);
penel_text->SetMaxSize(wxSize(FromDIP(600), -1));
// penel_text->SetMaxSize(wxSize(FromDIP(600), -1));
penel_text->SetSizer(bSizer_text);
penel_text->Layout();
bSizer_buttons->Add(penel_text, 1, wxEXPAND | wxALL, 0);
bSizer_buttons->Add(panel_button_block, 0, wxALIGN_CENTER | wxALL, 0);
// Orca: display the end time of the print
m_staticText_progress_end = new wxStaticText(penel_finish_time, wxID_ANY, L("N/A"), wxDefaultPosition, wxDefaultSize, 0);
m_staticText_progress_end->Wrap(-1);
m_staticText_progress_end->SetFont(
wxFont(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxT("HarmonyOS Sans SC")));
m_staticText_progress_end->SetForegroundColour(wxColour(146, 146, 146));
bSizer_finish_time->Add(0, 0, 1, wxEXPAND, 0);
bSizer_finish_time->Add(m_staticText_progress_end, 0, wxLEFT | wxEXPAND, 0);
// penel_finish_time->SetMaxSize(wxSize(FromDIP(600), -1));
penel_finish_time->SetSizer(bSizer_finish_time);
penel_finish_time->Layout();
penel_bottons->SetSizer(bSizer_buttons);
penel_bottons->Layout();
auto progress_lr_sizer = new wxBoxSizer(wxHORIZONTAL);
auto progress_left_sizer = new wxBoxSizer(wxVERTICAL);
auto progress_right_sizer = new wxBoxSizer(wxHORIZONTAL);
progress_left_sizer->Add(penel_text, 0, wxEXPAND | wxALL, 0);
progress_left_sizer->Add(m_gauge_progress, 0, wxEXPAND | wxTOP | wxBOTTOM, FromDIP(10));
progress_left_sizer->Add(penel_finish_time, 0, wxEXPAND |wxALL, 0);
// progress_left_sizer->SetMaxSize(wxSize(FromDIP(600), -1));
progress_right_sizer->Add(0, 0, 0, wxEXPAND | wxLEFT, FromDIP(18));
progress_right_sizer->Add(m_button_partskip, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(0));//5
progress_right_sizer->Add(0, 0, 0, wxEXPAND | wxLEFT, FromDIP(18));
progress_right_sizer->Add(m_button_pause_resume, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(0));
progress_right_sizer->Add(0, 0, 0, wxEXPAND | wxLEFT, FromDIP(18));
progress_right_sizer->Add(m_button_abort, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(0));
progress_right_sizer->Add(0, 0, 0, wxEXPAND | wxLEFT, FromDIP(18));
progress_lr_sizer->Add(progress_left_sizer, 1, wxEXPAND | wxALL, 0);
progress_lr_sizer->Add(progress_right_sizer, 0, wxEXPAND | wxALL , 0);
progress_lr_panel->SetSizer(progress_lr_sizer);
progress_lr_panel->SetMaxSize(wxSize(FromDIP(720), -1));
progress_lr_panel->Layout();
progress_lr_panel->Fit();
bSizer_subtask_info->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(14));
bSizer_subtask_info->Add(bSizer_task_name, 0, wxEXPAND|wxRIGHT, FromDIP(18));
bSizer_subtask_info->Add(m_staticText_profile_value, 0, wxEXPAND | wxTOP, FromDIP(5));
bSizer_subtask_info->Add(m_printing_stage_value, 0, wxEXPAND | wxTOP, FromDIP(5));
bSizer_subtask_info->Add(penel_bottons, 0, wxEXPAND | wxTOP, FromDIP(10));
bSizer_subtask_info->Add(m_panel_progress, 0, wxEXPAND|wxRIGHT, FromDIP(25));
bSizer_subtask_info->Add(progress_lr_panel, 0, wxEXPAND | wxTOP, FromDIP(5));
m_printing_sizer = new wxBoxSizer(wxHORIZONTAL);
m_printing_sizer->SetMinSize(wxSize(PAGE_MIN_WIDTH, -1));
@@ -764,7 +773,6 @@ void PrintingTaskPanel::create_panel(wxWindow* parent)
m_printing_sizer->Add(FromDIP(8), 0, 0, wxEXPAND, 0);
m_printing_sizer->Add(bSizer_subtask_info, 1, wxALL | wxEXPAND, 0);
m_staticline = new wxPanel( parent, wxID_ANY);
m_staticline->SetBackgroundColour(wxColour(238,238,238));
m_staticline->Layout();
@@ -994,6 +1002,24 @@ void PrintingTaskPanel::reset_printing_value()
this->set_plate_index(-1);
}
void PrintingTaskPanel::enable_partskip_button(MachineObject* obj, bool enable)
{
int stage = 0;
bool in_calibration_mode = false;
if( obj && (obj->print_type == "system" || CalibUtils::get_calib_mode_by_name(obj->subtask_name, stage) != CalibMode::Calib_None)){
in_calibration_mode = true;
}
if (!enable || in_calibration_mode) {
m_button_partskip->Enable(false);
m_button_partskip->SetLabel("");
m_button_partskip->SetIcon("print_control_partskip_disable");
}else if(obj && obj->is_support_brtc){
m_button_partskip->Enable(true);
m_button_partskip->SetIcon("print_control_partskip");
}
}
void PrintingTaskPanel::enable_pause_resume_button(bool enable, std::string type)
{
if (!enable) {
@@ -2248,6 +2274,7 @@ StatusPanel::StatusPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, co
//m_switch_fan->SetValue(false);
/* set default enable state */
m_project_task_panel->enable_partskip_button(nullptr, false);
m_project_task_panel->enable_pause_resume_button(false, "resume_disable");
m_project_task_panel->enable_abort_button(false);
@@ -2278,6 +2305,7 @@ StatusPanel::StatusPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, co
// Connect Events
m_project_task_panel->get_bitmap_thumbnail()->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(StatusPanel::refresh_thumbnail_webrequest), NULL, this);
m_project_task_panel->get_partskip_button()->Connect(wxEVT_LEFT_DOWN, wxCommandEventHandler(StatusPanel::on_subtask_partskip), NULL, this);
m_project_task_panel->get_pause_resume_button()->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_pause_resume), NULL, this);
m_project_task_panel->get_abort_button()->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_abort), NULL, this);
m_project_task_panel->get_market_scoring_button()->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_market_scoring), NULL, this);
@@ -2338,6 +2366,7 @@ StatusPanel::~StatusPanel()
{
// Disconnect Events
m_project_task_panel->get_bitmap_thumbnail()->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(StatusPanel::refresh_thumbnail_webrequest), NULL, this);
m_project_task_panel->get_partskip_button()->Disconnect(wxEVT_LEFT_DOWN, wxCommandEventHandler(StatusPanel::on_subtask_partskip), NULL, this);
m_project_task_panel->get_pause_resume_button()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_pause_resume), NULL, this);
m_project_task_panel->get_abort_button()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_abort), NULL, this);
m_project_task_panel->get_market_scoring_button()->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_market_scoring), NULL, this);
@@ -2472,6 +2501,35 @@ void StatusPanel::on_market_retry(wxCommandEvent &event)
}
}
void StatusPanel::update_partskip_button(MachineObject *obj) {
if (!obj) return;
auto partskip_button = m_project_task_panel->get_partskip_button();
if( obj->is_support_partskip ){
partskip_button->Show();
}else{
partskip_button->Hide();
}
BOOST_LOG_TRIVIAL(info) << "part skip: is_support_partskip: "<< obj->is_support_partskip;
}
void StatusPanel::on_subtask_partskip(wxCommandEvent &event)
{
if (m_partskip_dlg == nullptr) {
m_partskip_dlg = new PartSkipDialog(this->GetParent());
}
auto dm = GUI::wxGetApp().getDeviceManager();
m_partskip_dlg->InitSchedule(dm->get_selected_machine());
BOOST_LOG_TRIVIAL(info) << "part skip: initial part skip dialog.";
if(m_partskip_dlg->ShowModal() == wxID_OK){
int cnt = m_partskip_dlg->GetAllSkippedPartsNum();
m_project_task_panel->set_part_skipped_count(cnt);
m_project_task_panel->set_part_skipped_dirty(5);
BOOST_LOG_TRIVIAL(info) << "part skip: prepare to filter printer dirty data.";
}
}
void StatusPanel::on_subtask_pause_resume(wxCommandEvent &event)
{
if (obj) {
@@ -3609,13 +3667,17 @@ void StatusPanel::update_subtask(MachineObject *obj)
m_project_task_panel->show_layers_num(obj->is_support_layer_num);
update_model_info();
update_partskip_button(obj);
if (obj->is_system_printing() || obj->is_in_calibration()) {
reset_printing_values();
} else if (obj->is_in_printing() || obj->print_status == "FINISH") {
update_partskip_subtask(obj);
if (obj->is_in_prepare() || obj->print_status == "SLICING") {
m_project_task_panel->market_scoring_hide();
m_project_task_panel->get_request_failed_panel()->Hide();
m_project_task_panel->enable_partskip_button(nullptr, false);
m_project_task_panel->enable_abort_button(false);
m_project_task_panel->enable_pause_resume_button(false, "pause_disable");
wxString prepare_text;
@@ -3657,7 +3719,7 @@ void StatusPanel::update_subtask(MachineObject *obj)
} else {
m_project_task_panel->enable_pause_resume_button(true, "pause");
}
m_project_task_panel->enable_partskip_button(obj, true);
// update printing stage
m_project_task_panel->update_left_time(obj->mc_left_time);
if (obj->subtask_) {
@@ -3674,6 +3736,7 @@ void StatusPanel::update_subtask(MachineObject *obj)
if (obj->is_printing_finished()) {
obj->update_model_task();
m_project_task_panel->enable_abort_button(false);
m_project_task_panel->enable_partskip_button(nullptr, false);
m_project_task_panel->enable_pause_resume_button(false, "resume_disable");
// is makeworld subtask
if (wxGetApp().has_model_mall() && obj->is_makeworld_subtask()) {
@@ -3741,6 +3804,32 @@ void StatusPanel::update_subtask(MachineObject *obj)
Layout();
}
void StatusPanel::update_partskip_subtask(MachineObject *obj){
if (!obj) return;
if (!obj->subtask_) return;
auto partskip_button = m_project_task_panel->get_partskip_button();
if (partskip_button) {
int part_cnt = 0;
if(m_project_task_panel->get_part_skipped_dirty() > 0){
m_project_task_panel->set_part_skipped_dirty(m_project_task_panel->get_part_skipped_dirty() - 1);
part_cnt = m_project_task_panel->get_part_skipped_count();
BOOST_LOG_TRIVIAL(info) << "part skip: stop recv printer dirty data.";
}else{
part_cnt = obj->m_partskip_ids.size();
BOOST_LOG_TRIVIAL(info) << "part skip: recv printer normal data.";
}
if (part_cnt > 0)
partskip_button->SetLabel(wxString::Format(_L("(%d)"), part_cnt));
else
partskip_button->SetLabel("");
}
if(m_partskip_dlg && m_partskip_dlg->IsShown()) {
m_partskip_dlg->UpdatePartsStateFromPrinter(obj);
}
}
void StatusPanel::update_cloud_subtask(MachineObject *obj)
{
if (!obj) return;
@@ -3807,6 +3896,7 @@ void StatusPanel::update_sdcard_subtask(MachineObject *obj)
void StatusPanel::reset_printing_values()
{
m_project_task_panel->enable_partskip_button(nullptr, false);
m_project_task_panel->enable_pause_resume_button(false, "pause_disable");
m_project_task_panel->enable_abort_button(false);
m_project_task_panel->reset_printing_value();

View File

@@ -33,6 +33,7 @@
#include "Widgets/FilamentLoad.hpp"
#include "Widgets/FanControl.hpp"
#include "HMS.hpp"
#include "PartSkipDialog.hpp"
#include "DeviceErrorDialog.hpp"
class StepIndicator;
@@ -260,7 +261,7 @@ public:
private:
MachineObject* m_obj;
MachineObject* m_obj{nullptr};
ScalableBitmap m_thumbnail_placeholder;
wxBitmap m_thumbnail_bmp_display;
ScalableBitmap m_bitmap_use_time;
@@ -292,6 +293,7 @@ private:
wxStaticBitmap* m_bitmap_static_use_weight;
ScalableButton* m_button_pause_resume;
ScalableButton* m_button_abort;
Button* m_button_partskip;
Button* m_button_market_scoring;
Button* m_button_clean;
Button * m_button_market_retry;
@@ -303,6 +305,10 @@ private:
std::vector<ScalableButton *> m_score_star;
bool m_star_count_dirty = false;
// partskip button
int m_part_skipped_count{ 0 };
int m_part_skipped_dirty{ 0 };
ProgressBar* m_gauge_progress;
Label* m_error_text;
PrintingTaskType m_type;
@@ -317,6 +323,7 @@ public:
void msw_rescale();
public:
void enable_partskip_button(MachineObject* obj, bool enable);
void enable_pause_resume_button(bool enable, std::string type);
void enable_abort_button(bool enable);
void update_subtask_name(wxString name);
@@ -337,6 +344,7 @@ public:
public:
ScalableButton* get_abort_button() {return m_button_abort;};
ScalableButton* get_pause_resume_button() {return m_button_pause_resume;};
Button* get_partskip_button() { return m_button_partskip; };
Button* get_market_scoring_button() {return m_button_market_scoring;};
Button * get_market_retry_buttom() { return m_button_market_retry; };
Button* get_clean_button() {return m_button_clean;};
@@ -347,6 +355,10 @@ public:
std::vector<ScalableButton *> &get_score_star() { return m_score_star; }
bool get_star_count_dirty() { return m_star_count_dirty; }
void set_star_count_dirty(bool dirty) { m_star_count_dirty = dirty; }
int get_part_skipped_count() { return m_part_skipped_count; }
void set_part_skipped_count(int count) { m_part_skipped_count = count; }
int get_part_skipped_dirty() { return m_part_skipped_dirty; }
void set_part_skipped_dirty(int dirty) { m_part_skipped_dirty = dirty; }
void set_has_reted_text(bool has_rated);
void paint(wxPaintEvent&);
};
@@ -432,6 +444,7 @@ protected:
wxStaticText * m_staticText_progress_left;
wxStaticText * m_staticText_layers;
Button * m_button_report;
Button * m_button_partskip;
ScalableButton *m_button_pause_resume;
ScalableButton *m_button_abort;
Button * m_button_clean;
@@ -526,6 +539,7 @@ protected:
StaticBox* m_filament_load_box;
// Virtual event handlers, override them in your derived class
virtual void on_subtask_partskip(wxCommandEvent &event) { event.Skip(); }
virtual void on_subtask_pause_resume(wxCommandEvent &event) { event.Skip(); }
virtual void on_subtask_abort(wxCommandEvent &event) { event.Skip(); }
virtual void on_lamp_switch(wxCommandEvent &event) { event.Skip(); }
@@ -612,6 +626,7 @@ protected:
FanControlPopupNew* m_fan_control_popup{nullptr};
ExtrusionCalibration *m_extrusion_cali_dlg{nullptr};
PartSkipDialog *m_partskip_dlg{nullptr};
wxString m_request_url;
bool m_start_loading_thumbnail = false;
@@ -652,6 +667,7 @@ protected:
void on_market_scoring(wxCommandEvent &event);
void on_market_retry(wxCommandEvent &event);
void on_subtask_partskip(wxCommandEvent &event);
void on_subtask_pause_resume(wxCommandEvent &event);
void on_subtask_abort(wxCommandEvent &event);
void on_print_error_clean(wxCommandEvent &event);
@@ -728,6 +744,7 @@ protected:
void update_basic_print_data(bool def = false);
void update_model_info();
void update_subtask(MachineObject* obj);
void update_partskip_subtask(MachineObject *obj);
void update_cloud_subtask(MachineObject *obj);
void update_sdcard_subtask(MachineObject *obj);
void update_temp_ctrl(MachineObject *obj);
@@ -747,6 +764,9 @@ protected:
void update_camera_state(MachineObject* obj);
bool show_vcamera = false;
// partskip button
void update_partskip_button(MachineObject* obj);
public:
void update_error_message();

View File

@@ -2529,7 +2529,7 @@ void TabPrint::build()
optgroup->append_single_option_line("raft_first_layer_expansion", "support_settings_support#initial-layer-expansion");
optgroup->append_single_option_line("support_on_build_plate_only", "support_settings_support#on-build-plate-only");
optgroup->append_single_option_line("support_critical_regions_only", "support_settings_support#support-critical-regions-only");
optgroup->append_single_option_line("support_remove_small_overhang", "support_settings_support#remove-small-overhangs");
optgroup->append_single_option_line("support_remove_small_overhang", "support_settings_support#ignore-small-overhangs");
//optgroup->append_single_option_line("enforce_support_layers", "support_settings_support");
optgroup = page->new_optgroup(L("Raft"), L"param_raft");

View File

@@ -9,8 +9,9 @@
AnimaIcon::AnimaIcon(wxWindow *parent, wxWindowID id, std::vector<std::string> img_list, std::string img_enable, int ivt)
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize), m_ivt(ivt)
{
auto sizer = new wxBoxSizer(wxHORIZONTAL);
SetBackgroundColour((wxColour(255, 255, 255)));
m_size = 20;
m_size = 25;
//add ScalableBitmap
for (const auto &filename : img_list) m_images.emplace_back(create_scaled_bitmap(filename, this, m_size));
@@ -47,12 +48,13 @@ AnimaIcon::AnimaIcon(wxWindow *parent, wxWindowID id, std::vector<std::string> i
SetCursor(wxCursor(wxCURSOR_ARROW));
e.Skip();
});
sizer->Add(m_bitmap, 0, wxALIGN_CENTER, 0);
SetSizer(sizer);
SetSize(wxSize(FromDIP(m_size), FromDIP(m_size)));
SetMaxSize(wxSize(FromDIP(m_size), FromDIP(m_size)));
SetMinSize(wxSize(FromDIP(m_size), FromDIP(m_size)));
Refresh();
Layout();
Fit();
Play();
}
@@ -73,5 +75,3 @@ void AnimaIcon::Enable()
{
if (m_bitmap) { m_bitmap->SetBitmap(m_image_enable); }
}

View File

@@ -813,7 +813,7 @@ void ProgressDialog::DoSetSize(int x, int y, int width, int height, int sizeFlag
// m_block_right->SetPosition(wxPoint(PROGRESSDIALOG_GAUGE_SIZE.x - 2, 0));
//}
#endif
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
wxDialog::DoSetSize(x, y, width, height, sizeFlags);
}
void ProgressDialog::DisableOtherWindows()