diff --git a/resources/icons/X-MAX 3_thumbnail.png b/resources/icons/X-MAX 3_thumbnail.png new file mode 100644 index 0000000..071cfdf Binary files /dev/null and b/resources/icons/X-MAX 3_thumbnail.png differ diff --git a/resources/icons/X-Plus 3_thumbnail.png b/resources/icons/X-Plus 3_thumbnail.png new file mode 100644 index 0000000..72af6e0 Binary files /dev/null and b/resources/icons/X-Plus 3_thumbnail.png differ diff --git a/resources/icons/X-smart 3_thumbnail.png b/resources/icons/X-smart 3_thumbnail.png new file mode 100644 index 0000000..decd308 Binary files /dev/null and b/resources/icons/X-smart 3_thumbnail.png differ diff --git a/resources/icons/arrow-left-s-line.svg b/resources/icons/arrow-left-s-line.svg new file mode 100644 index 0000000..eb9c77f --- /dev/null +++ b/resources/icons/arrow-left-s-line.svg @@ -0,0 +1,6 @@ + + + + + diff --git a/resources/icons/arrow-right-s-line.svg b/resources/icons/arrow-right-s-line.svg new file mode 100644 index 0000000..12db6f6 --- /dev/null +++ b/resources/icons/arrow-right-s-line.svg @@ -0,0 +1,6 @@ + + + + + diff --git a/resources/icons/printer_state.svg b/resources/icons/printer_state.svg new file mode 100644 index 0000000..b0ac56b --- /dev/null +++ b/resources/icons/printer_state.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/resources/icons/refresh-line.svg b/resources/icons/refresh-line.svg new file mode 100644 index 0000000..402400e --- /dev/null +++ b/resources/icons/refresh-line.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 53f115e..f67127b 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -55,11 +55,17 @@ #include #endif // _WIN32 +//B45 +#include + + namespace Slic3r { namespace GUI { wxDEFINE_EVENT(EVT_LOAD_URL, wxCommandEvent); wxDEFINE_EVENT(EVT_LOAD_PRINTER_URL, wxCommandEvent); -int count = 0; + + + enum class ERescaleTarget { Mainframe, @@ -886,6 +892,9 @@ void MainFrame::create_preset_tabs() else #endif m_tabpanel->AddPage(m_guide_view, _L("Guide")); + //B45 + m_tabpanel->Bind(wxCUSTOMEVT_NOTEBOOK_SEL_CHANGED, &MainFrame::OnTabPanelSelectionChanged, this); + } @@ -2097,22 +2106,129 @@ void MainFrame::select_tab(Tab* tab) page_idx++; select_tab(size_t(page_idx)); } + +//B45 +void MainFrame::OnTabPanelSelectionChanged(wxCommandEvent &event) +{ + + m_printer_view->PauseButton(); + event.Skip(); +} + + + //B4 +//B45 void MainFrame::select_tab(size_t tab/* = size_t(-1)*/) { bool tabpanel_was_hidden = false; // Controls on page are created on active page of active tab now. // We should select/activate tab before its showing to avoid an UI-flickering + //B45 + auto select = [this, tab](bool was_hidden) { // when tab == -1, it means we should show the last selected tab size_t new_selection = tab == (size_t)(-1) ? m_last_selected_tab : (m_layout == ESettingsLayout::Dlg && tab != 0) ? tab - 1 : tab; //B4 if (m_tabpanel->GetSelection() == 4) { if (const DynamicPrintConfig *cfg = wxGetApp().preset_bundle->physical_printers.get_selected_printer_config(); cfg) { + std::string select_name = wxGetApp().preset_bundle->physical_printers.get_selected_full_printer_name(); PresetBundle & preset_bundle = *wxGetApp().preset_bundle; const PhysicalPrinter &pp = preset_bundle.physical_printers.get_selected_printer(); wxString host = pp.config.opt_string("print_host"); + //B45 + const PhysicalPrinterCollection &ph_printers = preset_bundle.physical_printers; + struct PhysicalPrinterPresetData + { + wxString lower_name; // just for sorting + std::string name; // preset_name + std::string fullname; // full name + bool selected; // is selected + }; + std::vector preset_data; + for (PhysicalPrinterCollection::ConstIterator it = ph_printers.begin(); it != ph_printers.end(); ++it) { + for (const std::string &preset_name : it->get_preset_names()) { + preset_data.push_back({wxString::FromUTF8(it->get_full_name(preset_name)).Lower(), preset_name, + it->get_full_name(preset_name), ph_printers.is_selected(it, preset_name)}); + } + } + m_collection = &preset_bundle.printers; + std::vector missingPresets; + std::vector m_buttons = (m_printer_view->GetButton()); + + for (auto it = m_buttons.begin(); it != m_buttons.end();) { + bool foundPreset = false; + for (const PhysicalPrinterPresetData &data : preset_data) { + if ((*it)->getLabel() == data.fullname) { + foundPreset = true; + break; + } + } + if (!foundPreset) { + (*it)->StopStatusThread(); + + delete *it; + + it = m_buttons.erase(it); + m_printer_view->SetButtons(m_buttons); + m_printer_view->UpdateLayout(); + } else { + ++it; + } + } + + + + + + for (const PhysicalPrinterPresetData &data : preset_data) { + bool foundButton = false; + for (MachineListButton *button : m_buttons) { + if (button->getLabel() == data.fullname) { + foundButton = true; + break; + } + } + if (!foundButton) { + missingPresets.push_back(&data); + } + } + for (const PhysicalPrinterPresetData *data : missingPresets) { + Preset *preset = m_collection->find_preset(data->name); + if (!preset || !preset->is_visible) + continue; + //auto printer = preset_bundle.physical_printers.printer(count); + + wxStringTokenizer tokenizer((data->fullname), " "); + + + auto *printer = preset_bundle.physical_printers.find_printer(std::string(tokenizer.GetNextToken().mb_str())); + + + //wxString host = printer.config.opt_string("print_host"); + wxString host = (printer->config.opt_string("print_host")); + + std::regex ipRegex(R"(\b(?:\d{1,3}\.){3}\d{1,3}\b)"); + bool isValidIPAddress = std::regex_match(host.ToStdString(), ipRegex); + + DynamicPrintConfig *cfg_t = &(printer->config); + if (isValidIPAddress) { + m_printer_view->AddButton( + data->fullname, "Name: " + data->fullname + "\nIp: " + host, + [host, this](wxMouseEvent &event) { + wxString formattedHost = wxString::Format("http://%s", host); + if (!host.Lower().starts_with("http")) + wxString formattedHost = wxString::Format("http://%s", host); + if (!formattedHost.Lower().ends_with("10088")) + formattedHost = wxString::Format("%s:10088", formattedHost); + this->m_printer_view->load_url(formattedHost); + }, + (data->selected), cfg_t); + } + } + m_printer_view->ResumeButton(); + if (host.empty()) { tem_host = ""; host = wxString::Format("file://%s/web/qidi/missing_connection.html", from_u8(resources_dir())); @@ -2124,10 +2240,10 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/) host = wxString::Format("%s:10088", host); } if (tem_host != host) { + //B45 m_printer_view->load_url(host); tem_host = host; } - } else { tem_host = ""; wxString url = wxString::Format("file://%s/web/qidi/missing_connection.html", from_u8(resources_dir())); diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index f3e257e..6af9a81 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -196,6 +196,9 @@ public: // When tab == -1, will be selected last selected tab void select_tab(Tab* tab); void select_tab(size_t tab = size_t(-1)); + //B45 + void OnTabPanelSelectionChanged(wxCommandEvent &event); + void select_view(const std::string& direction); // Propagate changed configuration from the Tab to the Plater and save changes to the AppConfig void on_config_changed(DynamicPrintConfig* cfg) const ; @@ -220,6 +223,10 @@ public: PrinterWebView * m_printer_view{nullptr}; //B28 GuideWebView * m_guide_view{nullptr}; + //B45 + PresetCollection *m_collection{nullptr}; + + wxBookCtrlBase * m_tabpanel{nullptr}; SettingsDialog m_settings_dialog; DiffPresetDialog diff_dialog; diff --git a/src/slic3r/GUI/PrinterWebView.cpp b/src/slic3r/GUI/PrinterWebView.cpp index f23cfcf..0bbe1f8 100644 --- a/src/slic3r/GUI/PrinterWebView.cpp +++ b/src/slic3r/GUI/PrinterWebView.cpp @@ -17,12 +17,128 @@ namespace pt = boost::property_tree; namespace Slic3r { namespace GUI { + + +wxBEGIN_EVENT_TABLE(MachineListButton, wxButton) EVT_PAINT(MachineListButton::OnPaint) EVT_ENTER_WINDOW(MachineListButton::OnMouseEnter) + EVT_LEAVE_WINDOW(MachineListButton::OnMouseLeave) EVT_LEFT_DOWN(MachineListButton::OnMouseLeftDown) EVT_LEFT_UP(MachineListButton::OnMouseLeftUp) + wxEND_EVENT_TABLE() + +void MachineListButton::OnPaint(wxPaintEvent &event) +{ + wxPaintDC dc(this); + //m_bitmap = get_bmp_bundle("X-MAX 3_thumbnail", 80)->GetBitmapFor(this); + + if (m_isSimpleMode) { + dc.SetFont(wxFont(15, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD)); + dc.SetTextForeground(wxColour(230, 230, 230)); + dc.DrawText(m_name_text, 10 , 10); + } else { + dc.DrawBitmap(m_bitmap, 10, (GetSize().GetHeight() - m_bitmap.GetHeight()) / 2, true); + + dc.SetFont(wxFont(15, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD)); + dc.SetTextForeground(wxColour(230, 230, 230)); + dc.DrawText(m_name_text, 10 + m_bitmap.GetWidth() + 10, 10); + dc.SetFont(wxFont(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD)); + dc.SetTextForeground(wxColour(174, 174, 174)); + + dc.DrawText("IP:" + m_ip_text, 10 + m_bitmap.GetWidth() + 10, 40); + + wxBitmap m_bitmap_state = get_bmp_bundle("printer_state", 20)->GetBitmapFor(this); + dc.DrawBitmap(m_bitmap_state, 10 + m_bitmap.GetWidth() + 10, 55, true); + + dc.SetFont(wxFont(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD)); + dc.SetTextForeground(wxColour(174, 174, 174)); + + dc.DrawText(m_state_text, 10 + m_bitmap.GetWidth() + m_bitmap_state.GetWidth() + 15, 60); + if (m_state_text == "printing") { + dc.SetFont(wxFont(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD)); + dc.SetTextForeground(wxColour(33, 148, 239)); + dc.DrawText(m_progress_text, 10 + m_bitmap.GetWidth() + m_bitmap_state.GetWidth() + 77, 62); + } + } + +} + +void MachineListButton::OnMouseEnter(wxMouseEvent &event) +{ + SetBackgroundColour(wxColour(100, 100, 105)); + Refresh(); +} + +void MachineListButton::OnMouseLeave(wxMouseEvent &event) +{ + if (m_isSelected) + SetBackgroundColour(wxColour(100, 100, 105)); + else + SetBackgroundColour(wxColour(67, 67, 71)); + Refresh(); +} + +void MachineListButton::OnMouseLeftDown(wxMouseEvent &event) +{ + SetBackgroundColour(wxColour(120, 120, 125)); + Refresh(); +} + +void MachineListButton::OnMouseLeftUp(wxMouseEvent &event) +{ + SetBackgroundColour(wxColour(100, 100, 105)); + if (m_handlerl) { + m_handlerl(event); + } + Refresh(); +} + + +//B45 PrinterWebView::PrinterWebView(wxWindow *parent) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize) { - wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL); - // Create the webview + int leftsizerWidth = 300; + topsizer = new wxBoxSizer(wxHORIZONTAL); + leftScrolledWindow = new wxScrolledWindow(this, wxID_ANY); + leftScrolledWindow->SetBackgroundColour(wxColour(45, 45, 48)); + leftsizer = new wxBoxSizer(wxVERTICAL); + wxFont font(wxFontInfo().Bold()); + + wxBoxSizer *titlesizer = new wxBoxSizer(wxHORIZONTAL); + wxStaticText *text = new wxStaticText(leftScrolledWindow, wxID_ANY, "MACHINE LIST", wxDefaultPosition, wxDefaultSize); + text->SetForegroundColour(wxColour(255, 255, 255)); + text->SetFont(wxFont(wxFontInfo(18).Bold())); + titlesizer->Add(text, wxSizerFlags().Align(wxALIGN_LEFT).Border(wxALL, 5)); + titlesizer->AddStretchSpacer(); + //wxBU_EXACTFIT wxBORDER_NONE + wxButton *refresh_button = new wxButton(leftScrolledWindow, wxID_ANY, "", wxDefaultPosition, wxSize(20, 20), wxBORDER_NONE); + refresh_button->SetBackgroundColour(leftScrolledWindow->GetBackgroundColour()); + refresh_button->SetForegroundColour(leftScrolledWindow->GetBackgroundColour()); + + refresh_button->SetMinSize(wxSize(40, -1)); + refresh_button->SetBitmap(*get_bmp_bundle("refresh-line", 20)); + //leftsizer->Add(button2, wxSizerFlags().Align(wxALIGN_RIGHT).Border(wxALL, 2)); + titlesizer->Add(refresh_button, wxSizerFlags().Align(wxALIGN_LEFT).CenterVertical().Border(wxALL, 2)); + refresh_button->Bind(wxEVT_BUTTON, &PrinterWebView::OnRightButtonClick, this); + + arrow_button = new wxButton(leftScrolledWindow, wxID_ANY, "", wxDefaultPosition, wxSize(20, 20), wxBORDER_NONE); + arrow_button->SetFont(font); + arrow_button->SetBackgroundColour(leftScrolledWindow->GetBackgroundColour()); + arrow_button->SetForegroundColour(leftScrolledWindow->GetBackgroundColour()); + arrow_button->SetMinSize(wxSize(40, -1)); + arrow_button->SetBitmap(*get_bmp_bundle("arrow-left-s-line", 20)); + // leftsizer->Add(arrow_button, wxSizerFlags().Align(wxALIGN_RIGHT | wxALIGN_TOP).Border(wxALL, 2)); + titlesizer->Add(arrow_button, wxSizerFlags().Align(wxALIGN_LEFT).CenterVertical().Border(wxALL, 2)); + arrow_button->Bind(wxEVT_BUTTON, &PrinterWebView::OnLeftButtonClick, this); + + titlesizer->Layout(); + + leftsizer->Add(titlesizer, wxSizerFlags().Expand().Align(wxALIGN_TOP).Border(wxALL, 0)); + + leftsizer->Layout(); + + leftScrolledWindow->SetSizer(leftsizer); + leftScrolledWindow->SetScrollRate(10, 10); + leftScrolledWindow->SetMinSize(wxSize(leftsizerWidth, -1)); + leftScrolledWindow->FitInside(); m_browser = WebView::CreateWebView(this, ""); if (m_browser == nullptr) { wxLogError("Could not init m_browser"); @@ -30,40 +146,240 @@ PrinterWebView::PrinterWebView(wxWindow *parent) } SetSizer(topsizer); + topsizer->Add(leftScrolledWindow, wxSizerFlags(0).Expand()); + topsizer->Add(m_browser, wxSizerFlags(1).Expand().Border(wxALL, 0)); - topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1)); - - // Log backend information - //if (wxGetApp().get_mode() == comDevelop) { - // wxLogMessage(wxWebView::GetBackendVersionInfo().ToString()); - // wxLogMessage("Backend: %s Version: %s", m_browser->GetClassInfo()->GetClassName(), - // wxWebView::GetBackendVersionInfo().ToString()); - // wxLogMessage("User Agent: %s", m_browser->GetUserAgent()); - //} - - //Zoom + // Zoom m_zoomFactor = 100; + leftScrolledWindow->Bind(wxEVT_SCROLLWIN_TOP, &PrinterWebView::OnScroll, this); + leftScrolledWindow->Bind(wxEVT_SCROLLWIN_BOTTOM, &PrinterWebView::OnScroll, this); + leftScrolledWindow->Bind(wxEVT_SCROLLWIN_LINEUP, &PrinterWebView::OnScroll, this); + leftScrolledWindow->Bind(wxEVT_SCROLLWIN_LINEDOWN, &PrinterWebView::OnScroll, this); + leftScrolledWindow->Bind(wxEVT_SCROLLWIN_PAGEUP, &PrinterWebView::OnScroll, this); + leftScrolledWindow->Bind(wxEVT_SCROLLWIN_PAGEDOWN, &PrinterWebView::OnScroll, this); + + //B45 + Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &PrinterWebView::OnScriptMessage, this); + + //Connect the idle events Bind(wxEVT_CLOSE_WINDOW, &PrinterWebView::OnClose, this); } -PrinterWebView::~PrinterWebView() -{ - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Start"; - SetEvtHandlerEnabled(false); - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " End"; + + + + +void PrinterWebView::AddButton(const wxString & buttonText, + const wxString & moreInfo, + const std::function &handler, + bool isSelected, + DynamicPrintConfig * cfg_t) + { + + wxStringTokenizer tokenizer(moreInfo, " "); + + + tokenizer.GetNextToken(); + wxString Name = tokenizer.GetNextToken(); + tokenizer.GetNextToken(); + wxString Machine_Type = tokenizer.GetNextToken(); + wxString Machine_Count = tokenizer.GetNextToken(); + tokenizer.GetNextToken(); + tokenizer.GetNextToken(); + wxString Machine_IP = tokenizer.GetNextToken(); + wxString Machine_Name = Machine_Name.Format("%s %s%s", Machine_Type, Machine_Count, "_thumbnail"); + + MachineListButton *customButton = new MachineListButton(leftScrolledWindow, wxID_ANY, buttonText, wxDefaultPosition, wxDefaultSize, wxBORDER_DOUBLE, + wxDefaultValidator, wxButtonNameStr, isSelected); + customButton->SetMinSize(wxSize(80, -1)); + customButton->SetBitmap(*get_bmp_bundle(std::string(Machine_Name.mb_str()), 80)); + customButton->SetBitMap(get_bmp_bundle(std::string(Machine_Name.mb_str()), 80)->GetBitmapFor(this)); + customButton->SetNameText(Name); + customButton->SetIPText(Machine_IP); + customButton->SetStateText("standby"); + customButton->SetProgressText("(0%)"); + customButton->SetMinSize(wxSize(200, -1)); + customButton->SetClickHandler(handler); + customButton->SetStatusThread(std::move(customButton->CreatThread(buttonText, cfg_t))); + customButton->SetSimpleMode(false); + + leftsizer->Add(customButton, wxSizerFlags().Border(wxALL, 1).Expand()); + leftsizer->Layout(); + m_buttons.push_back(customButton); + } + + //B45 + void PrinterWebView::PauseButton() + { + //BOOST_LOG_TRIVIAL(error) << " Pause"; + + if (m_buttons.empty()) { + BOOST_LOG_TRIVIAL(info) << " empty"; + } else { + for (MachineListButton *button : m_buttons) { + button->PauseStatusThread(); + } + } + } + //B45 + void PrinterWebView::ResumeButton() + { + //BOOST_LOG_TRIVIAL(error) << " Resume"; + + if (m_buttons.empty()) { + BOOST_LOG_TRIVIAL(info) << " empty"; + } else { + for (MachineListButton *button : m_buttons) { + button->ResumeStatusThread(); + } + } + } + + + //B45 + void PrinterWebView::DeleteButton() +{ + if (m_buttons.empty()) { + BOOST_LOG_TRIVIAL(info) <<" empty"; + } else { + for (MachineListButton *button : m_buttons) { + + button->StopStatusThread(); + + delete button; + } + m_buttons.clear(); + } } + // B45 +void PrinterWebView::SetButtons(std::vector buttons) { m_buttons = buttons; } + + PrinterWebView::~PrinterWebView() +{ + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Start"; + SetEvtHandlerEnabled(false); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " End"; +} + +void PrinterWebView::OnLeftButtonClick(wxCommandEvent &event) +{ + m_isSimpleMode = !m_isSimpleMode; + + if (!m_isSimpleMode) { + leftScrolledWindow->SetMinSize(wxSize(300, -1)); + arrow_button->SetBitmap(*get_bmp_bundle("arrow-left-s-line", 20)); + for (MachineListButton *button : m_buttons) { + button->SetBitmap(*get_bmp_bundle(std::string("X-MAX 3_thumbnail"), 80)); + button->SetSimpleMode(m_isSimpleMode); + } + } + else { + arrow_button->SetBitmap(*get_bmp_bundle("arrow-right-s-line", 20)); + + leftScrolledWindow->SetMinSize(wxSize(260, -1)); + for (MachineListButton *button : m_buttons) { + button->SetBitmap(*get_bmp_bundle(std::string("X-MAX 3_thumbnail"), 30)); + button->SetSimpleMode(m_isSimpleMode); + } + } + + leftsizer->Layout(); + + + leftScrolledWindow->Layout(); + + topsizer->Layout(); +} + +void PrinterWebView::OnRightButtonClick(wxCommandEvent &event) +{ + for (MachineListButton *button : m_buttons) { + button->ResumeStatusThread(); + } +} + + + +void PrinterWebView::SendRecentList(int images) +{ + boost::property_tree::wptree req; + boost::property_tree::wptree data; + //wxGetApp().mainframe->get_recent_projects(data, images); + req.put(L"sequence_id", ""); + req.put(L"command", L"studio_set_mallurl"); + //req.put_child(L"response", data); + std::wostringstream oss; + pt::write_json(oss, req, false); + RunScript(wxString::Format("window.postMessage(%s)", oss.str())); +} + + + +void PrinterWebView::OnScriptMessage(wxWebViewEvent &evt) +{ + + wxLogMessage("Script message received; value = %s, handler = %s", evt.GetString(), evt.GetMessageHandler()); + //std::string response = wxGetApp().handle_web_request(evt.GetString().ToUTF8().data()); + //if (response.empty()) + // return; + SendRecentList(1); + ///* remove \n in response string */ + //response.erase(std::remove(response.begin(), response.end(), '\n'), response.end()); + //if (!response.empty()) { + // m_response_js = wxString::Format("window.postMessage('%s')", response); + // wxCommandEvent *event = new wxCommandEvent(EVT_RESPONSE_MESSAGE, this->GetId()); + // wxQueueEvent(this, event); + //} else { + // m_response_js.clear(); + //} +} + + +void PrinterWebView::UpdateLayout() +{ + //leftScrolledWindow->SetVirtualSize(leftsizer->GetMinSize()); + leftScrolledWindow->FitInside(); + topsizer->Layout(); + if (!m_buttons.empty()) { + for (MachineListButton *button : m_buttons) { + button->Layout(); + button->Refresh(); + } + } +} + + +void PrinterWebView::OnScroll(wxScrollWinEvent &event) +{ + UpdateLayout(); + event.Skip(); +} + +//B45 void PrinterWebView::load_url(wxString& url) { // this->Show(); // this->Raise(); if (m_browser == nullptr) return; + + for (MachineListButton *button : m_buttons) { + + size_t pos = url.Find((button->getIPLabel())); + if (pos != wxString::npos) { + button->SetSelect(true); + } else { + button->SetSelect(false); + } + } + + m_browser->LoadURL(url); //m_browser->SetFocus(); UpdateState(); @@ -82,6 +398,14 @@ void PrinterWebView::OnClose(wxCloseEvent& evt) this->Hide(); } +void PrinterWebView::RunScript(const wxString &javascript) +{ + // Remember the script we run in any case, so the next time the user opens + // the "Run Script" dialog box, it is shown there for convenient updating. + + + WebView::RunScript(m_browser, javascript); +} } // GUI diff --git a/src/slic3r/GUI/PrinterWebView.hpp b/src/slic3r/GUI/PrinterWebView.hpp index e79cc3f..97f75bb 100644 --- a/src/slic3r/GUI/PrinterWebView.hpp +++ b/src/slic3r/GUI/PrinterWebView.hpp @@ -30,10 +30,166 @@ #include #endif +//B45 +#include "PrintHostDialogs.hpp" +#include namespace Slic3r { namespace GUI { +class MachineListButton : public wxButton +{ +public: + MachineListButton(wxWindow * parent, + wxWindowID id, + const wxString & label, + const wxPoint & pos = wxDefaultPosition, + const wxSize & size = wxDefaultSize, + long style = wxBORDER_DOUBLE, + const wxValidator &validator = wxDefaultValidator, + const wxString & name = wxButtonNameStr, + bool isSelected = false) + : wxButton(parent, id, label, pos, size, style, validator, name) + { + full_label = label; + m_isSelected = isSelected; + if (isSelected) + SetBackgroundColour(wxColour(100, 100, 105)); + else + SetBackgroundColour(wxColour(67, 67, 71)); + //Bind(wxEVT_BUTTON, &MachineListButton::OnMouseLeftUp, this); + } + wxString getLabel() { return full_label; } + wxString getIPLabel() { return m_ip_text; } + + + void SetBitMap(const wxBitmap &bitmap) + { + m_bitmap = bitmap; + Refresh(); + } + + + void SetNameText(const wxString &text) + { + m_name_text = text; + Refresh(); + } + void SetIPText(const wxString &text) + { + m_ip_text = text; + Refresh(); + } + void SetStateText(const wxString &text) + { + m_state_text = text; + Refresh(); + } + + void SetProgressText(const wxString &text) + { + m_progress_text = text; + Refresh(); + } + void SetSelect(bool isselectd) + { + m_isSelected = isselectd; + if (m_isSelected) + SetBackgroundColour(wxColour(100, 100, 105)); + else + SetBackgroundColour(wxColour(67, 67, 71)); + Refresh(); + } + + void SetSimpleMode(bool issimplemode) + { + m_isSimpleMode = issimplemode; + //if (m_isSelected) + // SetBackgroundColour(wxColour(100, 100, 105)); + //else + // SetBackgroundColour(wxColour(67, 67, 71)); + Refresh(); + } + + void SetClickHandler(const std::function &handler) { m_handlerl = handler; } + void PauseStatusThread() { m_pauseThread = true; } + void ResumeStatusThread() { m_pauseThread = false; } + void StopStatusThread() + { + m_stopThread = true; + if (m_statusThread.joinable()) { + m_statusThread.join(); + } + } + void OnPaint(wxPaintEvent &event); + void OnMouseEnter(wxMouseEvent &event); + void OnMouseLeave(wxMouseEvent &event); + void OnMouseLeftDown(wxMouseEvent &event); + void OnMouseLeftUp(wxMouseEvent &event); + void OnClickHandler(wxCommandEvent &event); + void SetStatusThread(std::thread thread) { m_statusThread = std::move(thread); } + std::thread CreatThread(const wxString &buttonText, DynamicPrintConfig *cfg_t) + { + + std::thread thread([this, buttonText, cfg_t]() { + std::unique_ptr printhost(PrintHost::get_print_host(cfg_t)); + if (!printhost) { + BOOST_LOG_TRIVIAL(error) << ("Could not get a valid Printer Host reference"); + return; + } + wxString msg; + std::string state = "standby"; + float progress = 0; + while (true) { + if (!m_pauseThread) { + state = printhost->get_status(msg); + if (state == "offline") { + //BOOST_LOG_TRIVIAL(error) << boost::format("%1%Got state: %2%") % buttonText % state; + m_pauseThread = true; + } + BOOST_LOG_TRIVIAL(info) << boost::format("%1%Got state: %2%") % buttonText % state; + SetStateText(state); + if (state == "printing") { + progress = (printhost->get_progress(msg)) * 100; + int progressInt = static_cast(progress); + SetStateText(state); + SetProgressText(wxString::Format(wxT("(%d%%)"), progressInt)); + BOOST_LOG_TRIVIAL(info) << boost::format("%1%Got progress: %2%") % buttonText % progress; + } + ; + } else + std::this_thread::sleep_for(std::chrono::seconds(3)); + if (m_stopThread) + break; + } + }); + return thread; + } + +private: + + std::atomic m_stopThread{false}; + std::atomic m_pauseThread{false}; + + bool m_isSimpleMode; + bool m_isSelected; + + std::thread m_statusThread; + + wxBitmap m_bitmap; + bool m_isHovered; + wxString full_label; + wxString m_name_text; + wxString m_ip_text; + wxString m_state_text; + wxString m_progress_text; + std::function m_handlerl; + wxDECLARE_EVENT_TABLE(); + //wxDECLARE_EVENT_TABLE(); +}; + + + class PrinterWebView : public wxPanel { public: @@ -44,7 +200,41 @@ public: void UpdateState(); void OnClose(wxCloseEvent& evt); + //B45 + void OnLeftButtonClick(wxCommandEvent &event); + void OnRightButtonClick(wxCommandEvent &event); + + void RunScript(const wxString &javascript); + //void OnScriptMessageReceived(wxWebViewEvent &event); + void OnScriptMessage(wxWebViewEvent &evt); + + void UpdateLayout(); + void OnScroll(wxScrollWinEvent &event); + + //B45 + void SendRecentList(int images); + void SetButtons(std::vector buttons); + void AddButton(const wxString & buttonText, + const wxString & moreInfo, + const std::function &handler, + bool isOnline, + DynamicPrintConfig * cfg_t); + void DeleteButton(); + void PauseButton(); + void ResumeButton(); + std::vector GetButton() { return m_buttons; }; + private: + //B45 + wxBoxSizer *leftsizer; + wxBoxSizer *topsizer; + bool m_isSimpleMode = false; + + wxButton *arrow_button; + + wxScrolledWindow * leftScrolledWindow; + + std::vector m_buttons; wxWebView* m_browser; long m_zoomFactor; diff --git a/src/slic3r/Utils/AstroBox.hpp b/src/slic3r/Utils/AstroBox.hpp index 72ab273..c6d33cc 100644 --- a/src/slic3r/Utils/AstroBox.hpp +++ b/src/slic3r/Utils/AstroBox.hpp @@ -21,6 +21,11 @@ public: const char* get_name() const override; bool test(wxString &curl_msg) const override; + + //B45 + virtual std::string get_status(wxString &curl_msg) const override { return "1"; }; + virtual float get_progress(wxString &curl_msg) const override { return 1; }; + wxString get_test_ok_msg () const override; wxString get_test_failed_msg (wxString &msg) const override; bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const override; diff --git a/src/slic3r/Utils/Duet.hpp b/src/slic3r/Utils/Duet.hpp index 2a91aa8..24c6c92 100644 --- a/src/slic3r/Utils/Duet.hpp +++ b/src/slic3r/Utils/Duet.hpp @@ -20,6 +20,10 @@ public: const char* get_name() const override; bool test(wxString &curl_msg) const override; + //B45 + virtual std::string get_status(wxString &curl_msg) const override { return "1"; }; + virtual float get_progress(wxString &curl_msg) const override { return 1; }; + wxString get_test_ok_msg() const override; wxString get_test_failed_msg(wxString &msg) const override; bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const override; diff --git a/src/slic3r/Utils/FlashAir.hpp b/src/slic3r/Utils/FlashAir.hpp index ba60644..cd77e7f 100644 --- a/src/slic3r/Utils/FlashAir.hpp +++ b/src/slic3r/Utils/FlashAir.hpp @@ -21,6 +21,11 @@ public: const char* get_name() const override; bool test(wxString &curl_msg) const override; + + //B45 + virtual std::string get_status(wxString &curl_msg) const override { return "1"; }; + virtual float get_progress(wxString &curl_msg) const override { return 1; }; + wxString get_test_ok_msg() const override; wxString get_test_failed_msg(wxString &msg) const override; bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const override; diff --git a/src/slic3r/Utils/MKS.hpp b/src/slic3r/Utils/MKS.hpp index 79143fd..0c445a6 100644 --- a/src/slic3r/Utils/MKS.hpp +++ b/src/slic3r/Utils/MKS.hpp @@ -20,6 +20,11 @@ public: const char* get_name() const override; bool test(wxString& curl_msg) const override; + + //B45 + virtual std::string get_status(wxString &curl_msg) const override { return "1"; }; + virtual float get_progress(wxString &curl_msg) const override { return 1; }; + wxString get_test_ok_msg() const override; wxString get_test_failed_msg(wxString& msg) const override; bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const override; diff --git a/src/slic3r/Utils/Moonraker.cpp b/src/slic3r/Utils/Moonraker.cpp index d2d6ba4..7266b23 100644 --- a/src/slic3r/Utils/Moonraker.cpp +++ b/src/slic3r/Utils/Moonraker.cpp @@ -142,6 +142,129 @@ bool Moonraker::test(wxString& msg) const return res; } +//B45 +std::string Moonraker::get_status(wxString &msg) const +{ + // GET /server/info + + // Since the request is performed synchronously here, + // it is ok to refer to `msg` from within the closure + const char *name = get_name(); + + bool res = true; + std::string print_state = "standby"; + auto url = make_url("printer/objects/query?print_stats=state"); + + BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Get version at: %2%") % name % url; + + auto http = Http::get(std::move(url)); + set_auth(http); + http.on_error([&](std::string body, std::string error, unsigned status) { + BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error getting version: %2%, HTTP %3%, body: `%4%`") % name % error % status % + body; + print_state = "offline"; + msg = format_error(body, error, status); + }) + .on_complete([&](std::string body, unsigned) { + BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got print_stats: %2%") % name % body; + + try { + // All successful HTTP requests will return a json encoded object in the form of : + // {result: } + std::stringstream ss(body); + pt::ptree ptree; + pt::read_json(ss, ptree); + if (ptree.front().first != "result") { + msg = "Could not parse server response"; + print_state = "offline"; + return; + } + if (!ptree.front().second.get_optional("status")) { + msg = "Could not parse server response"; + print_state = "offline"; + return; + } + print_state = ptree.get("result.status.print_stats.state"); + BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Got state: %2%") % name % print_state; + ; + } catch (const std::exception &) { + print_state = "offline"; + msg = "Could not parse server response"; + } + }) +#ifdef _WIN32 + .ssl_revoke_best_effort(m_ssl_revoke_best_effort) + .on_ip_resolve([&](std::string address) { + // Workaround for Windows 10/11 mDNS resolve issue, where two mDNS resolves in succession fail. + // Remember resolved address to be reused at successive REST API call. + msg = GUI::from_u8(address); + }) +#endif // _WIN32 + .perform_sync(); + + return print_state; +} + +float Moonraker::get_progress(wxString &msg) const +{ + // GET /server/info + + // Since the request is performed synchronously here, + // it is ok to refer to `msg` from within the closure + const char *name = get_name(); + + bool res = true; + auto url = make_url("printer/objects/query?display_status=progress"); + float process = 0; + BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Get version at: %2%") % name % url; + + auto http = Http::get(std::move(url)); + set_auth(http); + http.on_error([&](std::string body, std::string error, unsigned status) { + BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error getting version: %2%, HTTP %3%, body: `%4%`") % name % error % status % + body; + res = false; + msg = format_error(body, error, status); + }) + .on_complete([&](std::string body, unsigned) { + BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got display_status: %2%") % name % body; + + try { + // All successful HTTP requests will return a json encoded object in the form of : + // {result: } + std::stringstream ss(body); + pt::ptree ptree; + pt::read_json(ss, ptree); + if (ptree.front().first != "result") { + msg = "Could not parse server response"; + res = false; + return; + } + if (!ptree.front().second.get_optional("status")) { + msg = "Could not parse server response"; + res = false; + return; + } + process = std::stof(ptree.get("result.status.display_status.progress")); + BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Got state: %2%") % name % process; + } catch (const std::exception &) { + res = false; + msg = "Could not parse server response"; + } + }) +#ifdef _WIN32 + .ssl_revoke_best_effort(m_ssl_revoke_best_effort) + .on_ip_resolve([&](std::string address) { + // Workaround for Windows 10/11 mDNS resolve issue, where two mDNS resolves in succession fail. + // Remember resolved address to be reused at successive REST API call. + msg = GUI::from_u8(address); + }) +#endif // _WIN32 + .perform_sync(); + + return process; +} + bool Moonraker::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const { // POST /server/files/upload diff --git a/src/slic3r/Utils/Moonraker.hpp b/src/slic3r/Utils/Moonraker.hpp index 09a231f..509de27 100644 --- a/src/slic3r/Utils/Moonraker.hpp +++ b/src/slic3r/Utils/Moonraker.hpp @@ -25,6 +25,11 @@ public: const char* get_name() const override; virtual bool test(wxString &curl_msg) const override; + + //B45 + virtual std::string get_status(wxString &curl_msg) const override; + virtual float get_progress(wxString &curl_msg) const override; + wxString get_test_ok_msg () const override; wxString get_test_failed_msg (wxString &msg) const override; bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const override; diff --git a/src/slic3r/Utils/OctoPrint.hpp b/src/slic3r/Utils/OctoPrint.hpp index 3377cba..9577e7d 100644 --- a/src/slic3r/Utils/OctoPrint.hpp +++ b/src/slic3r/Utils/OctoPrint.hpp @@ -24,6 +24,10 @@ public: const char* get_name() const override; virtual bool test(wxString &curl_msg) const override; + //B45 + virtual std::string get_status(wxString &curl_msg) const override { return "1"; }; + virtual float get_progress(wxString &curl_msg) const override { return 1; }; + wxString get_test_ok_msg () const override; wxString get_test_failed_msg (wxString &msg) const override; bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const override; diff --git a/src/slic3r/Utils/PrintHost.hpp b/src/slic3r/Utils/PrintHost.hpp index 1e00599..cd05e17 100644 --- a/src/slic3r/Utils/PrintHost.hpp +++ b/src/slic3r/Utils/PrintHost.hpp @@ -50,6 +50,9 @@ public: virtual const char* get_name() const = 0; virtual bool test(wxString &curl_msg) const = 0; + //B45 + virtual std::string get_status(wxString &curl_msg) const = 0; + virtual float get_progress(wxString &curl_msg) const = 0; virtual wxString get_test_ok_msg () const = 0; virtual wxString get_test_failed_msg (wxString &msg) const = 0; virtual bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const = 0; diff --git a/src/slic3r/Utils/Repetier.hpp b/src/slic3r/Utils/Repetier.hpp index 00bc929..02d6015 100644 --- a/src/slic3r/Utils/Repetier.hpp +++ b/src/slic3r/Utils/Repetier.hpp @@ -21,6 +21,9 @@ public: const char* get_name() const override; bool test(wxString &curl_msg) const override; + //B45 + virtual std::string get_status(wxString &curl_msg) const override { return "1"; }; + virtual float get_progress(wxString &curl_msg) const override { return 1; }; wxString get_test_ok_msg () const override; wxString get_test_failed_msg (wxString &msg) const override; bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const override;