#include "SendMultiMachinePage.hpp" #include "TaskManager.hpp" #include "I18N.hpp" #include "GUI_App.hpp" #include "MainFrame.hpp" #include "Widgets/RadioBox.hpp" #include namespace Slic3r { namespace GUI { WX_DEFINE_LIST(AmsRadioSelectorList); class ScrolledWindow : public wxScrolledWindow { public: ScrolledWindow(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxVSCROLL) : wxScrolledWindow(parent, id, pos, size, style) {} bool ShouldScrollToChildOnFocus(wxWindow* child) override { return false; } }; SendDeviceItem::SendDeviceItem(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(DEVICE_ITEM_MAX_WIDTH), FromDIP(SEND_ITEM_MAX_HEIGHT))); SetMaxSize(wxSize(FromDIP(DEVICE_ITEM_MAX_WIDTH), FromDIP(SEND_ITEM_MAX_HEIGHT))); Bind(wxEVT_PAINT, &SendDeviceItem::paintEvent, this); Bind(wxEVT_ENTER_WINDOW, &SendDeviceItem::OnEnterWindow, this); Bind(wxEVT_LEAVE_WINDOW, &SendDeviceItem::OnLeaveWindow, this); Bind(wxEVT_LEFT_DOWN, &SendDeviceItem::OnLeftDown, this); Bind(wxEVT_MOTION, &SendDeviceItem::OnMove, this); Bind(EVT_MULTI_DEVICE_SELECTED, &SendDeviceItem::OnSelectedDevice, this); wxGetApp().UpdateDarkUIWin(this); } void SendDeviceItem::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 SendDeviceItem::OnEnterWindow(wxMouseEvent& evt) { m_hover = true; Refresh(false); } void SendDeviceItem::OnLeaveWindow(wxMouseEvent& evt) { m_hover = false; Refresh(false); } void SendDeviceItem::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); } void SendDeviceItem::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)) { if (state_printable <= 2 && state_local_task > 1) { post_event(wxCommandEvent(EVT_MULTI_DEVICE_SELECTED)); } } } void SendDeviceItem::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 SendDeviceItem::paintEvent(wxPaintEvent& evt) { wxPaintDC dc(this); render(dc); } void SendDeviceItem::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 SendDeviceItem::doRender(wxDC& dc) { wxSize size = GetSize(); dc.SetPen(wxPen(*wxBLACK)); int left = FromDIP(SEND_LEFT_PADDING_LEFT); //checkbox if (state_printable > 2) { dc.DrawBitmap(m_bitmap_check_disable.bmp(), wxPoint(left, (size.y - m_bitmap_check_disable.GetBmpSize().y) / 2 )); } else { 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 )); } } //task status if (state_local_task <= 1) { dc.DrawBitmap(m_bitmap_check_disable.bmp(), wxPoint(left, (size.y - m_bitmap_check_disable.GetBmpSize().y) / 2 )); } left += FromDIP(SEND_LEFT_PRINTABLE); //dev names DrawTextWithEllipsis(dc, wxString::FromUTF8(get_obj()->dev_name), FromDIP(SEND_LEFT_DEV_NAME), left); left += FromDIP(SEND_LEFT_DEV_NAME); //device state if (state_printable <= 2) { //dc.SetTextForeground(wxColour(0, 174, 66)); dc.SetTextForeground(wxColour(0x9A5F21)); } else { dc.SetTextForeground(wxColour(208, 27, 27)); } DrawTextWithEllipsis(dc, get_state_printable(), FromDIP(SEND_LEFT_DEV_NAME), left); left += FromDIP(SEND_LEFT_DEV_STATUS); dc.SetTextForeground(*wxBLACK); //task state //DrawTextWithEllipsis(dc, get_local_state_task(), FromDIP(SEND_LEFT_DEV_NAME), left); //left += FromDIP(SEND_LEFT_DEV_STATUS); //AMS if (!obj_->has_ams()) { DrawTextWithEllipsis(dc, _L("No AMS"), FromDIP(SEND_LEFT_DEV_NAME), left); } else { DrawTextWithEllipsis(dc, _L("AMS"), FromDIP(SEND_LEFT_DEV_NAME), left); } if (m_hover) { //dc.SetPen(wxPen(wxColour(0, 174, 66))); dc.SetPen(wxPen(wxColour(0x9A5F21))); dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRoundedRectangle(0, 0, size.x, size.y, 3); } } void SendDeviceItem::post_event(wxCommandEvent&& event) { event.SetEventObject(this); event.SetString(obj_->dev_id); event.SetInt(state_selected); wxPostEvent(this, event); } void SendDeviceItem::DoSetSize(int x, int y, int width, int height, int sizeFlags /*= wxSIZE_AUTO*/) { wxWindow::DoSetSize(x, y, width, height, sizeFlags); } SendMultiMachinePage::SendMultiMachinePage(Plater* plater) : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, _L("Send to Multi-device"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX | wxRESIZE_BORDER) ,m_plater(plater) { #ifdef __WINDOWS__ SetDoubleBuffered(true); #endif //__WINDOWS__ app_config = get_app_config(); SetBackgroundColour(*wxWHITE); // icon std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.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)); main_sizer->Add(line_top, 0, wxEXPAND, 0); main_sizer->AddSpacer(FromDIP(10)); m_main_scroll = new ScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL); m_main_scroll->SetBackgroundColour(*wxWHITE); m_main_scroll->SetScrollRate(5, 5); m_sizer_body = new wxBoxSizer(wxVERTICAL); m_main_page = create_page(); m_sizer_body->Add(m_main_page, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(38)); m_main_scroll->SetSizerAndFit(m_sizer_body); m_main_scroll->Layout(); m_main_scroll->Fit(); m_main_scroll->Centre(wxBOTH); main_sizer->Add(m_main_scroll, 1, wxEXPAND); SetSizer(main_sizer); Layout(); Fit(); Centre(wxBOTH); m_mapping_popup = new AmsMapingPopup(m_main_page); Bind(EVT_SET_FINISH_MAPPING, &SendMultiMachinePage::on_set_finish_mapping, this); Bind(wxEVT_LEFT_DOWN, [this](auto& e) {check_fcous_state(this); e.Skip(); }); m_main_page->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {check_fcous_state(this); e.Skip(); }); m_main_scroll->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {check_fcous_state(this); e.Skip(); }); init_timer(); Bind(wxEVT_TIMER, &SendMultiMachinePage::on_timer, this); wxGetApp().UpdateDlgDarkUI(this); } SendMultiMachinePage::~SendMultiMachinePage() { // TODO m_radio_group.DeleteContents(true); if (m_refresh_timer) m_refresh_timer->Stop(); delete m_refresh_timer; } void SendMultiMachinePage::prepare(int plate_idx) { // TODO m_print_plate_idx = plate_idx; } void SendMultiMachinePage::on_dpi_changed(const wxRect& suggested_rect) { m_select_checkbox->Rescale(); m_printer_name->Rescale(); m_printer_name->SetMinSize(wxSize(FromDIP(SEND_LEFT_DEV_NAME), FromDIP(SEND_ITEM_MAX_HEIGHT))); m_printer_name->SetMaxSize(wxSize(FromDIP(SEND_LEFT_DEV_NAME), FromDIP(SEND_ITEM_MAX_HEIGHT))); m_device_status->Rescale(); m_device_status->SetMinSize(wxSize(FromDIP(SEND_LEFT_DEV_STATUS), FromDIP(SEND_ITEM_MAX_HEIGHT))); m_device_status->SetMaxSize(wxSize(FromDIP(SEND_LEFT_DEV_STATUS), FromDIP(SEND_ITEM_MAX_HEIGHT))); m_ams->Rescale(); m_ams->SetMinSize(wxSize(FromDIP(TASK_LEFT_SEND_TIME), FromDIP(SEND_ITEM_MAX_HEIGHT))); m_ams->SetMaxSize(wxSize(FromDIP(TASK_LEFT_SEND_TIME), FromDIP(SEND_ITEM_MAX_HEIGHT))); m_refresh_button->Rescale(); m_refresh_button->SetMinSize(wxSize(FromDIP(50), FromDIP(SEND_ITEM_MAX_HEIGHT))); m_refresh_button->SetMaxSize(wxSize(FromDIP(50), FromDIP(SEND_ITEM_MAX_HEIGHT))); m_rename_button->msw_rescale(); print_time->msw_rescale(); print_weight->msw_rescale(); timeimg->SetBitmap(print_time->bmp()); weightimg->SetBitmap(print_weight->bmp()); m_button_add->Rescale(); m_button_add->SetMinSize(wxSize(FromDIP(90), FromDIP(36))); m_button_add->SetMaxSize(wxSize(FromDIP(90), FromDIP(36))); m_button_send->Rescale(); m_button_send->SetMinSize(wxSize(FromDIP(120), FromDIP(40))); m_button_send->SetMinSize(wxSize(FromDIP(120), FromDIP(40))); for (auto it = m_device_items.begin(); it != m_device_items.end(); ++it) { it->second->Refresh(); } Fit(); Layout(); Refresh(); } void SendMultiMachinePage::on_sys_color_changed() { } void SendMultiMachinePage::refresh_user_device() { 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 all_machine = dev->get_my_cloud_machine_list(); auto user_machine = std::map(); //selected machine for (int i = 0; i < PICK_DEVICE_MAX; i++) { auto dev_id = app_config->get("multi_devices", std::to_string(i)); if (all_machine.count(dev_id) > 0) { user_machine[dev_id] = all_machine[dev_id]; } } auto task_manager = wxGetApp().getTaskManager(); std::vector subscribe_list; std::vector dev_temp; for (auto it = user_machine.begin(); it != user_machine.end(); ++it) { SendDeviceItem* di = new SendDeviceItem(scroll_macine_list, it->second); 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); } dev_temp.push_back(m_device_items[it->first]); subscribe_list.push_back(it->first); } dev->subscribe_device_list(subscribe_list); if (m_sort.rule == SortItem::SortRule::SR_None) { this->device_printable_big = false; m_sort.set_role(SortItem::SR_DEV_STATE, device_printable_big); } std::sort(dev_temp.begin(), dev_temp.end(), m_sort.get_call_back()); for (auto i = 0; i < dev_temp.size(); ++i) { sizer_machine_list->Add(dev_temp[i], 0, wxALL | wxEXPAND, 0); } // maintenance dev_items auto it = m_device_items.begin(); while (it != m_device_items.end()) { if (user_machine.find(it->first) != user_machine.end()) { ++it; } else { it->second->Destroy(); it = m_device_items.erase(it); } } m_tip_text->Show(m_device_items.empty()); m_button_add->Show(m_device_items.empty()); sizer_machine_list->Layout(); Layout(); Fit(); } BBL::PrintParams SendMultiMachinePage::request_params(MachineObject* obj) { BBL::PrintParams params; //get all setting bool bed_leveling = app_config->get("print", "bed_leveling") == "1" ? true : false; bool flow_cali = app_config->get("print", "flow_cali") == "1" ? true : false; bool timelapse = app_config->get("print", "timelapse") == "1" ? true : false; auto use_ams = false; AmsRadioSelectorList::Node* node = m_radio_group.GetFirst(); auto groupid = 0; while (node) { AmsRadioSelector* rs = node->GetData(); if (rs->m_param_name == "use_ams" && rs->m_radiobox->GetValue()) { use_ams = true; } if (rs->m_param_name == "use_extra" && rs->m_radiobox->GetValue()) { use_ams = false; } node = node->GetNext(); } //use ams PrintPrepareData job_data; m_plater->get_print_job_data(&job_data); if (&job_data) { std::string temp_file = Slic3r::resources_dir() + "/check_access_code.txt"; auto check_access_code_path = temp_file.c_str(); BOOST_LOG_TRIVIAL(trace) << "sned_job: check_access_code_path = " << check_access_code_path; job_data._temp_path = fs::path(check_access_code_path); } int curr_plate_idx; if (job_data.plate_idx >= 0) curr_plate_idx = job_data.plate_idx + 1; else if (job_data.plate_idx == PLATE_CURRENT_IDX) curr_plate_idx = m_plater->get_partplate_list().get_curr_plate_index() + 1; else if (job_data.plate_idx == PLATE_ALL_IDX) curr_plate_idx = m_plater->get_partplate_list().get_curr_plate_index() + 1; else curr_plate_idx = m_plater->get_partplate_list().get_curr_plate_index() + 1; params.dev_ip = obj->dev_ip; params.dev_id = obj->dev_id; params.dev_name = obj->dev_name; params.ftp_folder = obj->get_ftp_folder(); params.connection_type = obj->connection_type(); params.print_type = "from_normal"; params.filename = job_data._3mf_path.string(); params.config_filename = job_data._3mf_config_path.string(); params.plate_index = curr_plate_idx; params.task_bed_leveling = bed_leveling; params.task_flow_cali = flow_cali; params.task_vibration_cali = false; params.task_layer_inspect = true; params.task_record_timelapse = timelapse; if (use_ams) { std::string ams_array; std::string mapping_info; get_ams_mapping_result(ams_array, mapping_info); params.ams_mapping = ams_array; params.ams_mapping_info = mapping_info; } else { params.ams_mapping = ""; params.ams_mapping_info = ""; } params.connection_type = obj->connection_type(); params.task_use_ams = use_ams; PartPlate* curr_plate = m_plater->get_partplate_list().get_curr_plate(); if (curr_plate) { params.task_bed_type = bed_type_to_gcode_string( curr_plate->get_bed_type(true)); } wxString filename; if (m_current_project_name.IsEmpty()) { filename = m_plater->get_export_gcode_filename("", true, m_print_plate_idx == PLATE_ALL_IDX ? true : false); } else { filename = m_current_project_name; } if (m_print_plate_idx == PLATE_ALL_IDX && filename.empty()) { filename = _L("Untitled"); } if (filename.empty()) { filename = m_plater->get_export_gcode_filename("", true); if (filename.empty()) filename = _L("Untitled"); } if (params.preset_name.empty()) { params.preset_name = wxString::Format("%s_plate_%d", filename, m_print_plate_idx).ToStdString(); } if (params.project_name.empty()) { params.project_name = filename.ToUTF8(); } // check access code and ip address if (obj->connection_type() == "lan") { /*params.dev_id = m_dev_id; params.project_name = "verify_job"; params.filename = job_data._temp_path.string(); params.connection_type = this->connection_type; result = m_agent->start_send_gcode_to_sdcard(params, nullptr, nullptr, nullptr); if (result != 0) { BOOST_LOG_TRIVIAL(error) << "access code is invalid"; m_enter_ip_address_fun_fail(); m_job_finished = true; return; } params.project_name = ""; params.filename = "";*/ } else { if (params.dev_ip.empty()) params.comments = "no_ip"; else if (obj->is_support_cloud_print_only) params.comments = "low_version"; else if (!obj->has_sdcard()) params.comments = "no_sdcard"; else if (params.password.empty()) params.comments = "no_password"; } return params; } bool SendMultiMachinePage::get_ams_mapping_result(std::string& mapping_array_str, std::string& ams_mapping_info) { if (m_ams_mapping_result.empty()) return false; bool valid_mapping_result = true; int invalid_count = 0; for (int i = 0; i < m_ams_mapping_result.size(); i++) { if (m_ams_mapping_result[i].tray_id == -1) { valid_mapping_result = false; invalid_count++; } } if (invalid_count == m_ams_mapping_result.size()) { return false; } else { json j = json::array(); json mapping_info_json = json::array(); for (int i = 0; i < wxGetApp().preset_bundle->filament_presets.size(); i++) { int tray_id = -1; json mapping_item; mapping_item["ams"] = tray_id; mapping_item["targetColor"] = ""; mapping_item["filamentId"] = ""; mapping_item["filamentType"] = ""; for (int k = 0; k < m_ams_mapping_result.size(); k++) { if (m_ams_mapping_result[k].id == i) { tray_id = m_ams_mapping_result[k].tray_id; mapping_item["ams"] = tray_id; mapping_item["filamentType"] = m_filaments[k].type; auto it = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i]); if (it != nullptr) { mapping_item["filamentId"] = it->filament_id; } //convert #RRGGBB to RRGGBBAA mapping_item["sourceColor"] = m_filaments[k].color; mapping_item["targetColor"] = m_ams_mapping_result[k].color; } } j.push_back(tray_id); mapping_info_json.push_back(mapping_item); } mapping_array_str = j.dump(); ams_mapping_info = mapping_info_json.dump(); return valid_mapping_result; } return true; } void SendMultiMachinePage::on_send(wxCommandEvent& event) { event.Skip(); BOOST_LOG_TRIVIAL(info) << "SendMultiMachinePage: on_send"; int result = m_plater->send_gcode(m_print_plate_idx, [this](int export_stage, int current, int total, bool& cancel) { if (m_is_canceled) return; bool cancelled = false; wxString msg = _L("Preparing print job"); //m_status_bar->update_status(msg, cancelled, 10, true); //m_export_3mf_cancel = cancel = cancelled; }); if (m_is_canceled || m_export_3mf_cancel) { BOOST_LOG_TRIVIAL(info) << "print_job: m_export_3mf_cancel or m_is_canceled"; //m_status_bar->set_status_text(task_canceled_text); return; } if (result < 0) { wxString msg = _L("Abnormal print file data. Please slice again"); //m_status_bar->set_status_text(msg); return; } // export config 3mf if needed result = m_plater->export_config_3mf(m_print_plate_idx); if (result < 0) { BOOST_LOG_TRIVIAL(trace) << "export_config_3mf failed, result = " << result; return; } if (m_is_canceled || m_export_3mf_cancel) { BOOST_LOG_TRIVIAL(info) << "print_job: m_export_3mf_cancel or m_is_canceled"; //m_status_bar->set_status_text(task_canceled_text); return; } std::vector print_params; for (auto it = m_device_items.begin(); it != m_device_items.end(); ++it) { auto obj = it->second->get_obj(); if (obj && obj->is_online() && !obj->can_abort() && !obj->is_in_upgrading() && it->second->get_state_selected() == 1 && it->second->state_printable <= 2) { if (!it->second->is_blocking_printing(obj)) { BBL::PrintParams params = request_params(obj); print_params.push_back(params); } } } if (print_params.size() <= 0) { MessageDialog msg_wingow(nullptr, _L("There is no device available to send printing."), "", wxICON_WARNING | wxOK); msg_wingow.ShowModal(); return; } if (wxGetApp().getTaskManager()) { TaskSettings settings; try { if (app_config->get("sending_interval").empty()) { app_config->set("sending_interval", "1"); app_config->save(); } if ( app_config->get("max_send").empty()) { app_config->set("max_send", "10"); app_config->save(); } settings.sending_interval = std::stoi(app_config->get("sending_interval")) * 60; settings.max_sending_at_same_time = std::stoi(app_config->get("max_send")); if (settings.max_sending_at_same_time <= 0) { MessageDialog msg_wingow(nullptr, _L("The number of printers in use simultaneously cannot be equal to 0."), "", wxICON_WARNING | wxOK); msg_wingow.ShowModal(); return; } wxGetApp().getTaskManager()->start_print(print_params, &settings); } catch (...) {} } //jump to info EndModal(wxCLOSE); wxGetApp().mainframe->jump_to_multipage(); } bool SendMultiMachinePage::Show(bool show) { if (show) { refresh_user_device(); set_default(); 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()); } } return wxDialog::Show(show); } wxBoxSizer* SendMultiMachinePage::create_item_title(wxString title, wxWindow* parent, wxString tooltip) { wxBoxSizer* m_sizer_title = new wxBoxSizer(wxHORIZONTAL); auto m_title = new wxStaticText(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, 0); m_title->SetForegroundColour(DESIGN_GRAY800_COLOR); m_title->SetFont(::Label::Head_13); m_title->Wrap(-1); m_title->SetToolTip(tooltip); auto m_line = new wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); m_line->SetBackgroundColour(DESIGN_GRAY400_COLOR); m_sizer_title->Add(m_title, 0, wxALIGN_CENTER | wxALL, 3); m_sizer_title->Add(0, 0, 0, wxLEFT, 9); wxBoxSizer* sizer_line = new wxBoxSizer(wxVERTICAL); sizer_line->Add(m_line, 0, wxEXPAND, 0); m_sizer_title->Add(sizer_line, 1, wxALIGN_CENTER, 0); return m_sizer_title; } wxBoxSizer* SendMultiMachinePage::create_item_checkbox(wxString title, wxWindow* parent, wxString tooltip, int padding_left, std::string param) { wxBoxSizer* m_sizer_checkbox = new wxBoxSizer(wxHORIZONTAL); m_sizer_checkbox->Add(0, 0, 0, wxEXPAND | wxLEFT, 23); auto checkbox = new ::CheckBox(parent); checkbox->SetValue((app_config->get("print", param) == "1") ? true : false); m_sizer_checkbox->Add(checkbox, 0, wxALIGN_CENTER, 0); m_sizer_checkbox->Add(0, 0, 0, wxEXPAND | wxLEFT, 8); auto checkbox_title = new wxStaticText(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, 0); checkbox_title->SetForegroundColour(DESIGN_GRAY900_COLOR); checkbox_title->SetFont(::Label::Body_13); auto size = checkbox_title->GetTextExtent(title); checkbox_title->SetMinSize(wxSize(size.x + FromDIP(5), -1)); checkbox_title->Wrap(-1); m_sizer_checkbox->Add(checkbox_title, 0, wxALIGN_CENTER | wxALL, 3); // save checkbox->Bind(wxEVT_TOGGLEBUTTON, [this, checkbox, param](wxCommandEvent& e) { app_config->set_str("print", param, checkbox->GetValue() ? std::string("1") : std::string("0")); app_config->save(); e.Skip(); }); checkbox->SetToolTip(tooltip); m_checkbox_map.emplace(param, checkbox); return m_sizer_checkbox; } wxBoxSizer* SendMultiMachinePage::create_item_input(wxString str_before, wxString str_after, wxWindow* parent, wxString tooltip, std::string param) { wxBoxSizer* sizer_input = new wxBoxSizer(wxHORIZONTAL); auto input_title = new wxStaticText(parent, wxID_ANY, str_before); input_title->SetForegroundColour(DESIGN_GRAY900_COLOR); input_title->SetFont(::Label::Body_13); input_title->SetToolTip(tooltip); input_title->Wrap(-1); auto input = new ::TextInput(parent, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, DESIGN_INPUT_SIZE, wxTE_PROCESS_ENTER); StateColor input_bg(std::pair(wxColour("#F0F0F1"), StateColor::Disabled), std::pair(*wxWHITE, StateColor::Enabled)); input->SetBackgroundColor(input_bg); input->GetTextCtrl()->SetValue(app_config->get(param)); wxTextValidator validator(wxFILTER_DIGITS); input->GetTextCtrl()->SetValidator(validator); auto second_title = new wxStaticText(parent, wxID_ANY, str_after, wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END); second_title->SetForegroundColour(DESIGN_GRAY900_COLOR); second_title->SetFont(::Label::Body_13); second_title->SetToolTip(tooltip); second_title->Wrap(-1); sizer_input->Add(0, 0, 0, wxEXPAND | wxLEFT, 23); sizer_input->Add(input_title, 0, wxALIGN_CENTER_VERTICAL | wxALL, 3); sizer_input->Add(input, 0, wxALIGN_CENTER_VERTICAL, 0); sizer_input->Add(0, 0, 0, wxEXPAND | wxLEFT, 3); sizer_input->Add(second_title, 0, wxALIGN_CENTER_VERTICAL | wxALL, 3); input->GetTextCtrl()->Bind(wxEVT_TEXT_ENTER, [this, param, input](wxCommandEvent& e) { auto value = input->GetTextCtrl()->GetValue(); app_config->set(param, std::string(value.mb_str())); app_config->save(); e.Skip(); }); input->GetTextCtrl()->Bind(wxEVT_KILL_FOCUS, [this, param, input](wxFocusEvent& e) { auto value = input->GetTextCtrl()->GetValue(); app_config->set(param, std::string(value.mb_str())); app_config->save(); e.Skip(); }); m_input_map.emplace(param, input); return sizer_input; } wxBoxSizer* SendMultiMachinePage::create_item_radiobox(wxString title, wxWindow* parent, wxString tooltip, int groupid, std::string param) { wxBoxSizer* radiobox_sizer = new wxBoxSizer(wxHORIZONTAL); RadioBox* radiobox = new RadioBox(parent); radiobox->SetBackgroundColour(wxColour(248, 248, 248)); radiobox->Bind(wxEVT_LEFT_DOWN, &SendMultiMachinePage::OnSelectRadio, this); AmsRadioSelector* rs = new AmsRadioSelector; rs->m_groupid = groupid; rs->m_param_name = param; rs->m_radiobox = radiobox; rs->m_selected = false; m_radio_group.Append(rs); wxStaticText* text = new wxStaticText(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize); radiobox_sizer->Add(radiobox, 0, wxLEFT, FromDIP(23)); radiobox_sizer->Add(text, 0, wxLEFT, FromDIP(10)); radiobox->SetToolTip(tooltip); text->SetToolTip(tooltip); return radiobox_sizer; } void SendMultiMachinePage::OnSelectRadio(wxMouseEvent& event) { AmsRadioSelectorList::Node* node = m_radio_group.GetFirst(); auto groupid = 0; while (node) { AmsRadioSelector* rs = node->GetData(); if (rs->m_radiobox->GetId() == event.GetId()) groupid = rs->m_groupid; node = node->GetNext(); } node = m_radio_group.GetFirst(); while (node) { AmsRadioSelector* rs = node->GetData(); if (rs->m_groupid == groupid && rs->m_radiobox->GetId() == event.GetId()) rs->m_radiobox->SetValue(true); if (rs->m_groupid == groupid && rs->m_radiobox->GetId() != event.GetId()) rs->m_radiobox->SetValue(false); node = node->GetNext(); } } void SendMultiMachinePage::on_select_radio(std::string param) { AmsRadioSelectorList::Node* node = m_radio_group.GetFirst(); auto groupid = 0; while (node) { AmsRadioSelector* rs = node->GetData(); if (rs->m_param_name == param) groupid = rs->m_groupid; node = node->GetNext(); } node = m_radio_group.GetFirst(); while (node) { AmsRadioSelector* rs = node->GetData(); if (rs->m_groupid == groupid && rs->m_param_name == param) rs->m_radiobox->SetValue(true); if (rs->m_groupid == groupid && rs->m_param_name != param) rs->m_radiobox->SetValue(false); node = node->GetNext(); } } bool SendMultiMachinePage::get_value_radio(std::string param) { AmsRadioSelectorList::Node* node = m_radio_group.GetFirst(); auto groupid = 0; while (node) { AmsRadioSelector* rs = node->GetData(); if (rs->m_groupid == groupid && rs->m_param_name == param) return rs->m_radiobox->GetValue(); node = node->GetNext(); } return false; } void SendMultiMachinePage::on_set_finish_mapping(wxCommandEvent& evt) { auto selection_data = evt.GetString(); auto selection_data_arr = wxSplit(selection_data.ToStdString(), '|'); BOOST_LOG_TRIVIAL(info) << "The ams mapping selection result: data is " << selection_data; if (selection_data_arr.size() == 6) { auto ams_colour = wxColour(wxAtoi(selection_data_arr[0]), wxAtoi(selection_data_arr[1]), wxAtoi(selection_data_arr[2]), wxAtoi(selection_data_arr[3])); int old_filament_id = (int)wxAtoi(selection_data_arr[5]); int ctype = 0; std::vector material_cols; std::vector tray_cols; for (auto mapping_item : m_mapping_popup->m_mapping_item_list) { if (mapping_item->m_tray_data.id == evt.GetInt()) { ctype = mapping_item->m_tray_data.ctype; material_cols = mapping_item->m_tray_data.material_cols; for (auto col : mapping_item->m_tray_data.material_cols) { wxString color = wxString::Format("#%02X%02X%02X%02X", col.Red(), col.Green(), col.Blue(), col.Alpha()); tray_cols.push_back(color.ToStdString()); } break; } } for (auto i = 0; i < m_ams_mapping_result.size(); i++) { if (m_ams_mapping_result[i].id == wxAtoi(selection_data_arr[5])) { m_ams_mapping_result[i].tray_id = evt.GetInt(); auto ams_colour = wxColour(wxAtoi(selection_data_arr[0]), wxAtoi(selection_data_arr[1]), wxAtoi(selection_data_arr[2]), wxAtoi(selection_data_arr[3])); wxString color = wxString::Format("#%02X%02X%02X%02X", ams_colour.Red(), ams_colour.Green(), ams_colour.Blue(), ams_colour.Alpha()); m_ams_mapping_result[i].color = color.ToStdString(); m_ams_mapping_result[i].ctype = ctype; m_ams_mapping_result[i].colors = tray_cols; } BOOST_LOG_TRIVIAL(trace) << "The ams mapping result: id is " << m_ams_mapping_result[i].id << "tray_id is " << m_ams_mapping_result[i].tray_id; } MaterialHash::iterator iter = m_material_list.begin(); while (iter != m_material_list.end()) { Material* item = iter->second; MaterialItem* m = item->item; if (item->id == m_current_filament_id) { auto ams_colour = wxColour(wxAtoi(selection_data_arr[0]), wxAtoi(selection_data_arr[1]), wxAtoi(selection_data_arr[2]), wxAtoi(selection_data_arr[3])); m->set_ams_info(ams_colour, selection_data_arr[4], ctype, material_cols); } iter++; } } } wxPanel* SendMultiMachinePage::create_page() { auto main_page = new wxPanel(m_main_scroll, wxID_ANY, wxDefaultPosition, wxDefaultSize); main_page->SetBackgroundColour(*wxWHITE); wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); // add title m_title_panel = new wxPanel(main_page, wxID_ANY, wxDefaultPosition, wxDefaultSize); m_title_panel->SetBackgroundColour(*wxWHITE); m_title_sizer = new wxBoxSizer(wxHORIZONTAL); m_rename_switch_panel = new wxSimplebook(m_title_panel); m_rename_switch_panel->SetMinSize(wxSize(FromDIP(240), FromDIP(25))); m_rename_switch_panel->SetMaxSize(wxSize(FromDIP(240), FromDIP(25))); m_rename_normal_panel = new wxPanel(m_rename_switch_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); m_rename_normal_panel->SetBackgroundColour(*wxWHITE); rename_sizer_v = new wxBoxSizer(wxVERTICAL); rename_sizer_h = new wxBoxSizer(wxHORIZONTAL); m_task_name = new wxStaticText(m_rename_normal_panel, wxID_ANY, wxT("MyLabel"), wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END | wxALIGN_CENTRE); m_task_name->SetFont(::Label::Body_13); m_task_name->SetMinSize(wxSize(FromDIP(200), -1)); m_task_name->SetMaxSize(wxSize(FromDIP(200), -1)); m_rename_button = new ScalableButton(m_rename_normal_panel, wxID_ANY, "ams_editable"); m_rename_button->SetBackgroundColour(*wxWHITE); rename_sizer_h->Add(m_task_name, 0, wxALIGN_CENTER, 0); rename_sizer_h->Add(m_rename_button, 0, wxALIGN_CENTER, 0); rename_sizer_v->Add(rename_sizer_h, 1, wxALIGN_CENTER, 0); m_rename_normal_panel->SetSizer(rename_sizer_v); m_rename_normal_panel->Layout(); rename_sizer_v->Fit(m_rename_normal_panel); //rename edit m_rename_edit_panel = new wxPanel(m_rename_switch_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); m_rename_edit_panel->SetBackgroundColour(*wxWHITE); auto rename_edit_sizer_v = new wxBoxSizer(wxVERTICAL); m_rename_input = new ::TextInput(m_rename_edit_panel, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); m_rename_input->GetTextCtrl()->SetFont(::Label::Body_13); m_rename_input->SetSize(wxSize(FromDIP(220), FromDIP(24))); m_rename_input->SetMinSize(wxSize(FromDIP(220), FromDIP(24))); m_rename_input->SetMaxSize(wxSize(FromDIP(220), FromDIP(24))); m_rename_input->Bind(wxEVT_TEXT_ENTER, [this](auto& e) {on_rename_enter(); }); m_rename_input->Bind(wxEVT_KILL_FOCUS, [this](auto& e) { if (!m_rename_input->HasFocus() && !m_task_name->HasFocus()) on_rename_enter(); else e.Skip(); }); rename_edit_sizer_v->Add(m_rename_input, 1, wxALIGN_CENTER, 0); m_rename_edit_panel->SetSizer(rename_edit_sizer_v); m_rename_edit_panel->Layout(); rename_edit_sizer_v->Fit(m_rename_edit_panel); m_rename_button->Bind(wxEVT_BUTTON, &SendMultiMachinePage::on_rename_click, this); m_rename_switch_panel->AddPage(m_rename_normal_panel, wxEmptyString, true); m_rename_switch_panel->AddPage(m_rename_edit_panel, wxEmptyString, false); Bind(wxEVT_CHAR_HOOK, [this](wxKeyEvent& e) { if (e.GetKeyCode() == WXK_ESCAPE) { if (m_rename_switch_panel->GetSelection() == 0) { e.Skip(); } else { m_rename_switch_panel->SetSelection(0); m_task_name->SetLabel(m_current_project_name); m_rename_normal_panel->Layout(); } } else { e.Skip(); } }); m_text_sizer = new wxBoxSizer(wxVERTICAL); m_text_sizer->Add(m_rename_switch_panel, 0, wxALIGN_CENTER_HORIZONTAL, 0); m_panel_image = new wxPanel(m_title_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); m_image_sizer = new wxBoxSizer(wxHORIZONTAL); m_thumbnail_panel = new ThumbnailPanel(m_panel_image); m_thumbnail_panel->SetSize(wxSize(THUMBNAIL_SIZE, THUMBNAIL_SIZE)); m_thumbnail_panel->SetMinSize(wxSize(THUMBNAIL_SIZE, THUMBNAIL_SIZE)); m_thumbnail_panel->SetMaxSize(wxSize(THUMBNAIL_SIZE, THUMBNAIL_SIZE)); m_thumbnail_panel->SetBackgroundColour(*wxRED); m_image_sizer->Add(m_thumbnail_panel, 0, wxALIGN_CENTER, 0); m_panel_image->SetSizer(m_image_sizer); m_panel_image->Layout(); m_title_sizer->Add(m_panel_image, 0, wxLEFT, 0); wxBoxSizer* m_sizer_basic = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* m_sizer_basic_time = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* m_sizer_basic_weight = new wxBoxSizer(wxHORIZONTAL); print_time = new ScalableBitmap(m_title_panel, "print-time", 18); timeimg = new wxStaticBitmap(m_title_panel, wxID_ANY, print_time->bmp(), wxDefaultPosition, wxSize(FromDIP(18), FromDIP(18)), 0); m_sizer_basic_time->Add(timeimg, 1, wxEXPAND | wxALL, FromDIP(5)); m_stext_time = new wxStaticText(m_title_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); m_sizer_basic_time->Add(m_stext_time, 0, wxALL, FromDIP(5)); m_sizer_basic->Add(m_sizer_basic_time, 0, wxALIGN_CENTER, 0); m_sizer_basic->Add(0, 0, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30)); print_weight = new ScalableBitmap(m_title_panel, "print-weight", 18); weightimg = new wxStaticBitmap(m_title_panel, wxID_ANY, print_weight->bmp(), wxDefaultPosition, wxSize(FromDIP(18), FromDIP(18)), 0); m_sizer_basic_weight->Add(weightimg, 1, wxEXPAND | wxALL, FromDIP(5)); m_stext_weight = new wxStaticText(m_title_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); m_sizer_basic_weight->Add(m_stext_weight, 0, wxALL, FromDIP(5)); m_sizer_basic->Add(m_sizer_basic_weight, 0, wxALIGN_CENTER, 0); m_text_sizer->Add(m_sizer_basic, wxALIGN_CENTER, 0); m_title_sizer->Add(m_text_sizer, 0, wxALIGN_CENTER_VERTICAL, 0); m_title_panel->SetSizer(m_title_sizer); m_title_panel->Layout(); sizer->Add(m_title_panel, 0, wxALIGN_CENTER_HORIZONTAL, 0); // add filament wxBoxSizer* title_filament = create_item_title(_L("Filament"), main_page, ""); wxBoxSizer* radio_sizer = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* use_external_sizer = create_item_radiobox(_L("Use External Spool"), main_page, "", 0, "use_external"); wxBoxSizer* use_ams_sizer = create_item_radiobox(_L("Use AMS"), main_page, "", 0, "use_ams"); radio_sizer->Add(use_external_sizer, 0, wxLeft, FromDIP(20)); radio_sizer->Add(use_ams_sizer, 0, wxLeft, FromDIP(5)); sizer->Add(title_filament, 0, wxEXPAND, 0); sizer->Add(radio_sizer, 0, wxLEFT, FromDIP(20)); sizer->AddSpacer(FromDIP(5)); on_select_radio("use_external"); // add ams item m_ams_list_sizer = new wxGridSizer(0, 4, 0, FromDIP(5)); //sync_ams_list(); sizer->Add(m_ams_list_sizer, 0, wxLEFT, FromDIP(25)); sizer->AddSpacer(FromDIP(10)); // select printer wxBoxSizer* title_select_printer = create_item_title(_L("Select Printers"), main_page, ""); // add table head StateColor head_bg( std::pair(TABLE_HEAD_PRESSED_COLOUR, StateColor::Pressed), std::pair(TABLE_HEAR_NORMAL_COLOUR, StateColor::Normal) ); m_table_head_panel = new wxPanel(main_page, 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_select_checkbox = new CheckBox(m_table_head_panel, wxID_ANY); m_table_head_sizer->AddSpacer(FromDIP(SEND_LEFT_PADDING_LEFT)); m_table_head_sizer->Add(m_select_checkbox, 0, wxALIGN_CENTER_VERTICAL, 0); m_select_checkbox->Bind(wxEVT_TOGGLEBUTTON, [this](wxCommandEvent& e) { if (m_select_checkbox->GetValue()) { for (auto it = m_device_items.begin(); it != m_device_items.end(); it++) { if (it->second->state_printable <= 2) { it->second->selected(); } } } else { for (auto it = m_device_items.begin(); it != m_device_items.end(); it++) { it->second->unselected(); } } Refresh(false); e.Skip(); }); 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->SetCornerRadius(0); m_printer_name->SetFont(TABLE_HEAD_FONT); m_printer_name->SetMinSize(wxSize(FromDIP(SEND_LEFT_DEV_NAME), FromDIP(SEND_ITEM_MAX_HEIGHT))); m_printer_name->SetMaxSize(wxSize(FromDIP(SEND_LEFT_DEV_NAME), FromDIP(SEND_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_name_big = !device_name_big; this->m_sort.set_role(SortItem::SortRule::SR_DEV_NAME, device_name_big); this->refresh_user_device(); }); m_table_head_sizer->Add( 0, 0, 0, wxLEFT, FromDIP(10) ); m_table_head_sizer->Add(m_printer_name, 0, wxALIGN_CENTER_VERTICAL, 0); m_device_status = new Button(m_table_head_panel, _L("Device Status"), "toolbar_double_directional_arrow", wxNO_BORDER, ICON_SIZE); m_device_status->SetBackgroundColor(head_bg); m_device_status->SetFont(TABLE_HEAD_FONT); m_device_status->SetCornerRadius(0); m_device_status->SetMinSize(wxSize(FromDIP(SEND_LEFT_DEV_STATUS), FromDIP(SEND_ITEM_MAX_HEIGHT))); m_device_status->SetMaxSize(wxSize(FromDIP(SEND_LEFT_DEV_STATUS), FromDIP(SEND_ITEM_MAX_HEIGHT))); m_device_status->SetCenter(false); m_device_status->Bind(wxEVT_ENTER_WINDOW, [&](wxMouseEvent& evt) { SetCursor(wxCURSOR_HAND); }); m_device_status->Bind(wxEVT_LEAVE_WINDOW, [&](wxMouseEvent& evt) { SetCursor(wxCURSOR_ARROW); }); m_device_status->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& evt) { device_printable_big = !device_printable_big; this->m_sort.set_role(SortItem::SortRule::SR_PRINTABLE, device_printable_big); this->refresh_user_device(); evt.Skip(); }); m_table_head_sizer->Add(m_device_status, 0, wxALIGN_CENTER_VERTICAL, 0); /*m_task_status = new Button(m_table_head_panel, _L("Task Status"), "toolbar_double_directional_arrow", wxNO_BORDER, ICON_SIZE); m_task_status->SetBackgroundColor(head_bg); m_task_status->SetFont(TABLE_HEAD_FONT); m_task_status->SetCornerRadius(0); m_task_status->SetMinSize(wxSize(FromDIP(SEND_LEFT_DEV_STATUS), FromDIP(DEVICE_ITEM_MAX_HEIGHT))); m_task_status->SetMaxSize(wxSize(FromDIP(SEND_LEFT_DEV_STATUS), FromDIP(DEVICE_ITEM_MAX_HEIGHT))); m_task_status->SetCenter(false); m_task_status->Bind(wxEVT_ENTER_WINDOW, [&](wxMouseEvent& evt) { SetCursor(wxCURSOR_HAND); }); m_task_status->Bind(wxEVT_LEAVE_WINDOW, [&](wxMouseEvent& evt) { SetCursor(wxCURSOR_ARROW); }); m_task_status->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& evt) { device_printable_big = !device_printable_big; this->m_sort.set_role(SortItem::SortRule::SR_PRINTABLE, device_printable_big); this->refresh_user_device(); evt.Skip(); });*/ //m_table_head_sizer->Add(m_task_status, 0, wxALIGN_CENTER_VERTICAL, 0); m_ams = new Button(m_table_head_panel, _L("Ams Status"), "toolbar_double_directional_arrow", wxNO_BORDER, ICON_SIZE, false); m_ams->SetBackgroundColor(head_bg); m_ams->SetCornerRadius(0); m_ams->SetFont(TABLE_HEAD_FONT); m_ams->SetMinSize(wxSize(FromDIP(TASK_LEFT_SEND_TIME), FromDIP(SEND_ITEM_MAX_HEIGHT))); m_ams->SetMaxSize(wxSize(FromDIP(TASK_LEFT_SEND_TIME), FromDIP(SEND_ITEM_MAX_HEIGHT))); m_ams->SetCenter(false); m_ams->Bind(wxEVT_ENTER_WINDOW, [&](wxMouseEvent& evt) { SetCursor(wxCURSOR_HAND); }); m_ams->Bind(wxEVT_LEAVE_WINDOW, [&](wxMouseEvent& evt) { SetCursor(wxCURSOR_ARROW); }); m_ams->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& evt) { device_en_ams_big = !device_en_ams_big; this->m_sort.set_role(SortItem::SortRule::SR_EN_AMS, device_en_ams_big); this->refresh_user_device(); evt.Skip(); }); m_table_head_sizer->Add(m_ams, 0, wxALIGN_CENTER_VERTICAL, 0); m_refresh_button = new Button(m_table_head_panel, "", "mall_control_refresh", wxNO_BORDER, ICON_SIZE, false); m_refresh_button->SetBackgroundColor(head_bg); m_refresh_button->SetCornerRadius(0); m_refresh_button->SetFont(TABLE_HEAD_FONT); m_refresh_button->SetMinSize(wxSize(FromDIP(50), FromDIP(SEND_ITEM_MAX_HEIGHT))); m_refresh_button->SetMaxSize(wxSize(FromDIP(50), FromDIP(SEND_ITEM_MAX_HEIGHT))); m_refresh_button->Bind(wxEVT_ENTER_WINDOW, [&](wxMouseEvent& evt) { SetCursor(wxCURSOR_HAND); }); m_refresh_button->Bind(wxEVT_LEAVE_WINDOW, [&](wxMouseEvent& evt) { SetCursor(wxCURSOR_ARROW); }); m_refresh_button->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& evt) { this->refresh_user_device(); evt.Skip(); }); m_table_head_sizer->Add(m_refresh_button, 0, wxALIGN_CENTER_VERTICAL, 0); m_table_head_panel->SetSizer(m_table_head_sizer); m_table_head_panel->Layout(); m_tip_text = new wxStaticText(main_page, 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(DESIGN_GRAY800_COLOR); m_tip_text->SetFont(::Label::Head_20); m_tip_text->Wrap(-1); auto m_btn_bg_enable = StateColor( std::pair(wxColour(27, 136, 68), StateColor::Pressed), std::pair(wxColour(61, 203, 115), StateColor::Hovered), //std::pair(wxColour(0, 174, 66), StateColor::Normal) std::pair(wxColour(0x9A5F21), StateColor::Normal) ); m_button_add = new Button(main_page, _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(); }); scroll_macine_list = new wxScrolledWindow(main_page, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(800), FromDIP(300)), wxHSCROLL | wxVSCROLL); scroll_macine_list->SetBackgroundColour(*wxWHITE); scroll_macine_list->SetScrollRate(5, 5); scroll_macine_list->SetMinSize(wxSize(FromDIP(DEVICE_ITEM_MAX_WIDTH), 10 * FromDIP(SEND_ITEM_MAX_HEIGHT))); scroll_macine_list->SetMaxSize(wxSize(FromDIP(DEVICE_ITEM_MAX_WIDTH), 10 * FromDIP(SEND_ITEM_MAX_HEIGHT))); sizer_machine_list = new wxBoxSizer(wxVERTICAL); scroll_macine_list->SetSizer(sizer_machine_list); scroll_macine_list->Layout(); sizer->Add(title_select_printer, 0, wxEXPAND, 0); sizer->Add(m_table_head_panel, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, FromDIP(40)); sizer->Add(m_tip_text, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, FromDIP(100)); sizer->Add(m_button_add, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, FromDIP(20)); sizer->Add(scroll_macine_list, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, FromDIP(40)); sizer->AddSpacer(FromDIP(10)); // add printing options wxBoxSizer* title_print_option = create_item_title(_L("Printing Options"), main_page, ""); wxBoxSizer* item_bed_level = create_item_checkbox(_L("Bed Leveling"), main_page, "", 50, "bed_leveling"); wxBoxSizer* item_timelapse = create_item_checkbox(_L("Timelapse"), main_page, "", 50, "timelapse"); wxBoxSizer* item_flow_dy_ca = create_item_checkbox(_L("Flow Dynamics Calibration"), main_page, "", 50, "flow_cali"); sizer->Add(title_print_option, 0, wxEXPAND, 0); wxBoxSizer* options_sizer_v = new wxBoxSizer(wxHORIZONTAL); options_sizer_v->Add(item_bed_level, 0, wxLEFT, 0); options_sizer_v->Add(item_timelapse, 0, wxLEFT, FromDIP(100)); sizer->Add(options_sizer_v, 0, wxLEFT, FromDIP(20)); sizer->Add(item_flow_dy_ca, 0, wxLEFT, FromDIP(20)); sizer->AddSpacer(FromDIP(10)); // add send option wxBoxSizer* title_send_option = create_item_title(_L("Send Options"), main_page, ""); wxBoxSizer* max_printer_send = create_item_input(_L("Send"), _L("printers at the same time.(It depends on how many devices can undergo heating at the same time.)"), main_page, "", "max_send"); wxBoxSizer* delay_time = create_item_input(_L("Wait"), _L("minute each batch.(It depends on how long it takes to complete the heating.)"), main_page, "", "sending_interval"); sizer->Add(title_send_option, 0, wxEXPAND, 0); sizer->Add(max_printer_send, 0, wxLEFT, FromDIP(20)); sizer->AddSpacer(FromDIP(3)); sizer->Add(delay_time, 0, wxLEFT, FromDIP(20)); sizer->AddSpacer(FromDIP(10)); // add send button btn_bg_enable = StateColor(std::pair(wxColour(27, 136, 68), StateColor::Pressed), std::pair(wxColour(61, 203, 115), StateColor::Hovered), //std::pair(wxColour(0, 174, 66), StateColor::Normal)); std::pair(wxColour(0x9A5F21), StateColor::Normal)); m_button_send = new Button(main_page, _L("Send")); m_button_send->SetBackgroundColor(btn_bg_enable); m_button_send->SetBorderColor(btn_bg_enable); m_button_send->SetTextColor(StateColor::darkModeColorFor("#FFFFFE")); m_button_send->SetSize(wxSize(FromDIP(120), FromDIP(40))); m_button_send->SetMinSize(wxSize(FromDIP(120), FromDIP(40))); m_button_send->SetMinSize(wxSize(FromDIP(120), FromDIP(40))); m_button_send->SetCornerRadius(FromDIP(5)); m_button_send->Bind(wxEVT_BUTTON, &SendMultiMachinePage::on_send, this); //m_button_send->Disable(); //m_button_send->SetBackgroundColor(wxColour(0x90, 0x90, 0x90)); //m_button_send->SetBorderColor(wxColour(0x90, 0x90, 0x90)); sizer->Add(m_button_send, 0, wxALIGN_CENTER, 0); main_page->SetSizer(sizer); main_page->Layout(); main_page->Fit(); return main_page; } void SendMultiMachinePage::sync_ams_list() { // for black list std::vector materials; std::vector brands; std::vector display_materials; std::vector m_filaments_id; auto preset_bundle = wxGetApp().preset_bundle; for (auto filament_name : preset_bundle->filament_presets) { for (int f_index = 0; f_index < preset_bundle->filaments.size(); f_index++) { PresetCollection* filament_presets = &wxGetApp().preset_bundle->filaments; Preset* preset = &filament_presets->preset(f_index); if (preset && filament_name.compare(preset->name) == 0) { std::string display_filament_type; std::string filament_type = preset->config.get_filament_type(display_filament_type); std::string m_filament_id = preset->filament_id; display_materials.push_back(display_filament_type); materials.push_back(filament_type); m_filaments_id.push_back(m_filament_id); std::string m_vendor_name = ""; auto vendor = dynamic_cast(preset->config.option("filament_vendor")); if (vendor && (vendor->values.size() > 0)) { std::string vendor_name = vendor->values[0]; m_vendor_name = vendor_name; } brands.push_back(m_vendor_name); } } } auto extruders = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_used_extruders(); BitmapCache bmcache; MaterialHash::iterator iter = m_material_list.begin(); while (iter != m_material_list.end()) { int id = iter->first; Material* item = iter->second; item->item->Destroy(); delete item; iter++; } m_ams_list_sizer->Clear(); m_material_list.clear(); m_filaments.clear(); m_ams_mapping_result.clear(); for (auto i = 0; i < extruders.size(); i++) { auto extruder = extruders[i] - 1; auto colour = wxGetApp().preset_bundle->project_config.opt_string("filament_colour", (unsigned int)extruder); unsigned char rgb[4]; bmcache.parse_color4(colour, rgb); auto colour_rgb = wxColour((int)rgb[0], (int)rgb[1], (int)rgb[2], (int)rgb[3]); if (extruder >= materials.size() || extruder < 0 || extruder >= display_materials.size()) continue; MaterialItem* item = new MaterialItem(m_main_page, colour_rgb, _L(display_materials[extruder])); item->set_ams_info(wxColour("#CECECE"), "A1", 0, std::vector()); m_ams_list_sizer->Add(item, 0, wxALL, FromDIP(4)); item->Bind(wxEVT_LEFT_UP, [this, item, materials, extruder](wxMouseEvent& e) {}); item->Bind(wxEVT_LEFT_DOWN, [this, item, materials, extruder](wxMouseEvent& e) { MaterialHash::iterator iter = m_material_list.begin(); while (iter != m_material_list.end()) { int id = iter->first; Material* item = iter->second; MaterialItem* m = item->item; m->on_normal(); iter++; } m_current_filament_id = extruder; item->on_selected(); auto mouse_pos = ClientToScreen(e.GetPosition()); wxPoint rect = item->ClientToScreen(wxPoint(0, 0)); // update ams data if (get_value_radio("use_ams")) { if (m_mapping_popup->IsShown()) return; wxPoint pos = item->ClientToScreen(wxPoint(0, 0)); pos.y += item->GetRect().height; m_mapping_popup->Move(pos); m_mapping_popup->set_parent_item(item); m_mapping_popup->set_current_filament_id(extruder); m_mapping_popup->set_tag_texture(materials[extruder]); m_mapping_popup->update_ams_data_multi_machines(); m_mapping_popup->Popup(); } }); Material* material_item = new Material(); material_item->id = extruder; material_item->item = item; m_material_list[i] = material_item; // build for ams mapping if (extruder < materials.size() && extruder >= 0) { FilamentInfo info; info.id = extruder; info.tray_id = 0; info.type = materials[extruder]; info.brand = brands[extruder]; info.filament_id = m_filaments_id[extruder]; //info.color = wxString::Format("#%02X%02X%02X%02X", colour_rgb.Red(), colour_rgb.Green(), colour_rgb.Blue(), colour_rgb.Alpha()).ToStdString(); info.color = "#CECECEFF"; m_filaments.push_back(info); m_ams_mapping_result.push_back(info); } } if (extruders.size() <= 8) { m_ams_list_sizer->SetCols(extruders.size()); } else { m_ams_list_sizer->SetCols(8); } } void SendMultiMachinePage::set_default_normal(const ThumbnailData& data) { if (data.is_valid()) { wxImage image(data.width, data.height); image.InitAlpha(); for (unsigned int r = 0; r < data.height; ++r) { unsigned int rr = (data.height - 1 - r) * data.width; for (unsigned int c = 0; c < data.width; ++c) { unsigned char* px = (unsigned char*)data.pixels.data() + 4 * (rr + c); image.SetRGB((int)c, (int)r, px[0], px[1], px[2]); image.SetAlpha((int)c, (int)r, px[3]); } } image = image.Rescale(THUMBNAIL_SIZE, THUMBNAIL_SIZE); m_thumbnail_panel->set_thumbnail(image); } m_main_scroll->Layout(); m_main_scroll->Fit(); // basic info auto aprint_stats = m_plater->get_partplate_list().get_current_fff_print().print_statistics(); wxString time; PartPlate* plate = m_plater->get_partplate_list().get_curr_plate(); if (plate) { if (plate->get_slice_result()) { time = wxString::Format("%s", short_time(get_time_dhms(plate->get_slice_result()->print_statistics.modes[0].time))); } } char weight[64]; if (wxGetApp().app_config->get("use_inches") == "1") { ::sprintf(weight, " %.2f oz", aprint_stats.total_weight * 0.035274); } else { ::sprintf(weight, " %.2f g", aprint_stats.total_weight); } m_stext_time->SetLabel(time); m_stext_weight->SetLabel(weight); } void SendMultiMachinePage::set_default() { wxString filename = m_plater->get_export_gcode_filename("", true, m_print_plate_idx == PLATE_ALL_IDX ? true : false); if (m_print_plate_idx == PLATE_ALL_IDX && filename.empty()) { filename = _L("Untitled"); } if (filename.empty()) { filename = m_plater->get_export_gcode_filename("", true); if (filename.empty()) filename = _L("Untitled"); } fs::path filename_path(filename.c_str()); std::string file_name = filename_path.filename().string(); if (from_u8(file_name).find(_L("Untitled")) != wxString::npos) { PartPlate* part_plate = m_plater->get_partplate_list().get_plate(m_print_plate_idx); if (part_plate) { if (std::vector objects = part_plate->get_objects_on_this_plate(); objects.size() > 0) { file_name = objects[0]->name; for (int i = 1; i < objects.size(); i++) { file_name += (" + " + objects[i]->name); } } if (file_name.size() > 100) { file_name = file_name.substr(0, 97) + "..."; } } } m_current_project_name = wxString::FromUTF8(file_name); //unsupported character filter m_current_project_name = from_u8(filter_characters(m_current_project_name.ToUTF8().data(), "<>[]:/\\|?*\"")); m_task_name->SetLabel(m_current_project_name); sync_ams_list(); set_default_normal(m_plater->get_partplate_list().get_curr_plate()->thumbnail_data); } void SendMultiMachinePage::on_rename_enter() { if (m_is_rename_mode == false) { return; } else { m_is_rename_mode = false; } auto new_file_name = m_rename_input->GetTextCtrl()->GetValue(); wxString temp; int num = 0; for (auto t : new_file_name) { if (t == wxString::FromUTF8("\x20")) { num++; if (num == 1) temp += t; } else { num = 0; temp += t; } } new_file_name = temp; auto m_valid_type = Valid; wxString info_line; const char* unusable_symbols = "<>[]:/\\|?*\""; const std::string unusable_suffix = PresetCollection::get_suffix_modified(); //"(modified)"; for (size_t i = 0; i < std::strlen(unusable_symbols); i++) { if (new_file_name.find_first_of(unusable_symbols[i]) != std::string::npos) { info_line = _L("Name is invalid;") + "\n" + _L("illegal characters:") + " " + unusable_symbols; m_valid_type = NoValid; break; } } if (m_valid_type == Valid && new_file_name.find(unusable_suffix) != std::string::npos) { info_line = _L("Name is invalid;") + "\n" + _L("illegal suffix:") + "\n\t" + from_u8(PresetCollection::get_suffix_modified()); m_valid_type = NoValid; } if (m_valid_type == Valid && new_file_name.empty()) { info_line = _L("The name is not allowed to be empty."); m_valid_type = NoValid; } if (m_valid_type == Valid && new_file_name.find_first_of(' ') == 0) { info_line = _L("The name is not allowed to start with space character."); m_valid_type = NoValid; } if (m_valid_type == Valid && new_file_name.find_last_of(' ') == new_file_name.length() - 1) { info_line = _L("The name is not allowed to end with space character."); m_valid_type = NoValid; } if (m_valid_type == Valid && new_file_name.size() >= 100) { info_line = _L("The name length exceeds the limit."); m_valid_type = NoValid; } if (m_valid_type != Valid) { MessageDialog msg_wingow(nullptr, info_line, "", wxICON_WARNING | wxOK); if (msg_wingow.ShowModal() == wxID_OK) { m_rename_switch_panel->SetSelection(0); m_task_name->SetLabel(m_current_project_name); m_rename_normal_panel->Layout(); return; } } m_current_project_name = new_file_name; m_rename_switch_panel->SetSelection(0); m_task_name->SetLabelText(m_current_project_name); m_rename_normal_panel->Layout(); } void SendMultiMachinePage::check_fcous_state(wxWindow* window) { check_focus(window); auto children = window->GetChildren(); for (auto child : children) { check_fcous_state(child); } } void SendMultiMachinePage::check_focus(wxWindow* window) { if (window == m_rename_input || window == m_rename_input->GetTextCtrl()) { on_rename_enter(); } } void SendMultiMachinePage::on_rename_click(wxCommandEvent& event) { m_is_rename_mode = true; m_rename_input->GetTextCtrl()->SetValue(m_current_project_name); m_rename_switch_panel->SetSelection(1); m_rename_input->GetTextCtrl()->SetFocus(); m_rename_input->GetTextCtrl()->SetInsertionPointEnd(); } void SendMultiMachinePage::init_timer() { m_refresh_timer = new wxTimer(); } void SendMultiMachinePage::on_timer(wxTimerEvent& event) { for (auto it = m_device_items.begin(); it != m_device_items.end(); it++) { it->second->sync_state(); it->second->Refresh(); } } } // namespace GUI } // namespace Slic3r