mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-27 10:51:22 +00:00
feat(gui): multi-nozzle UI for H2C/A2L
Multi-nozzle sync widget, AMS rack-nozzle mapping popup, calibration rework, send-dialog nozzle mapping and extruder-count UI. Includes the fix to persist the AMS sync badge on filament cards (H2C/A2L and direct-sync printers).
This commit is contained in:
@@ -4,5 +4,15 @@ list(APPEND SLIC3R_GUI_SOURCES
|
||||
GUI/DeviceTab/uiAmsHumidityPopup.cpp
|
||||
GUI/DeviceTab/uiDeviceUpdateVersion.h
|
||||
GUI/DeviceTab/uiDeviceUpdateVersion.cpp
|
||||
GUI/DeviceTab/wgtDeviceNozzleRackNozzleItem.h
|
||||
GUI/DeviceTab/wgtDeviceNozzleRackNozzleItem.cpp
|
||||
GUI/DeviceTab/wgtDeviceNozzleRack.h
|
||||
GUI/DeviceTab/wgtDeviceNozzleRack.cpp
|
||||
GUI/DeviceTab/wgtDeviceNozzleRackUpdate.h
|
||||
GUI/DeviceTab/wgtDeviceNozzleRackUpdate.cpp
|
||||
GUI/DeviceTab/wgtDeviceNozzleSelect.h
|
||||
GUI/DeviceTab/wgtDeviceNozzleSelect.cpp
|
||||
GUI/DeviceTab/wgtMsgBox.h
|
||||
GUI/DeviceTab/wgtMsgBox.cpp
|
||||
)
|
||||
set(SLIC3R_GUI_SOURCES ${SLIC3R_GUI_SOURCES} PARENT_SCOPE)
|
||||
@@ -0,0 +1,700 @@
|
||||
//**********************************************************/
|
||||
/* File: wgtDeviceNozzleRack.cpp
|
||||
* Description: The Device-tab panel with the toolhead nozzle and the H2C induction hotend rack.
|
||||
*
|
||||
* \n class wgtDeviceNozzleRack;
|
||||
* \n class wgtDeviceNozzleRackToolHead;
|
||||
* \n class wgtDeviceNozzleRackArea;
|
||||
* \n class wgtDeviceNozzleRackPos;
|
||||
*
|
||||
* The wgtDeviceNozzleRackNozzleItem tile and the EVT_NOZZLE_RACK_NOZZLE_ITEM_SELECTED event live in
|
||||
* wgtDeviceNozzleRackNozzleItem.{h,cpp}, so they are not redefined here.
|
||||
//**********************************************************/
|
||||
|
||||
#include "wgtDeviceNozzleRack.h"
|
||||
#include "wgtDeviceNozzleRackUpdate.h"
|
||||
|
||||
#include "slic3r/GUI/DeviceCore/DevNozzleSystem.h"
|
||||
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/MainFrame.hpp"
|
||||
#include "slic3r/GUI/wxExtensions.hpp"
|
||||
|
||||
#include "slic3r/GUI/Widgets/Button.hpp"
|
||||
#include "slic3r/GUI/Widgets/Label.hpp"
|
||||
|
||||
#define WX_DIP_SIZE(x, y) wxSize(FromDIP(x), FromDIP(y))
|
||||
|
||||
#define L_RAW_A_STR _L("Row A")
|
||||
#define L_RAW_B_STR _L("Row B")
|
||||
|
||||
// Orca: StateColor lacks these grey constants, so mirror the values here.
|
||||
static const wxColour WGT_GREY200 = wxColour(248, 248, 248);
|
||||
static const wxColour WGT_GREY300 = wxColour(238, 238, 238);
|
||||
|
||||
static wxColour s_hgreen_clr("#00AE42");
|
||||
|
||||
namespace Slic3r::GUI
|
||||
{
|
||||
|
||||
// Tints the "yellow" template pixels of a nozzle bitmap with the loaded filament colour.
|
||||
// Duplicates the file-local helper of the same purpose in wgtDeviceNozzleRackNozzleItem.cpp.
|
||||
static wxBitmap SetNozzleBmpColor(const wxBitmap& bmp, const std::string& color_str) {
|
||||
if(color_str.empty()) return bmp;
|
||||
|
||||
wxImage img = bmp.ConvertToImage();
|
||||
wxColour color("#" + color_str);
|
||||
|
||||
for (int y = 0; y < img.GetHeight(); ++y) {
|
||||
for (int x = 0; x < img.GetWidth(); ++x) {
|
||||
unsigned char r = img.GetRed(x, y);
|
||||
unsigned char g = img.GetGreen(x, y);
|
||||
unsigned char b = img.GetBlue(x, y);
|
||||
|
||||
/*replace yellow with color*/
|
||||
if ( r >= 180 && g >= 180 && b <= 150) {
|
||||
img.SetRGB(x, y, color.Red(), color.Green(), color.Blue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return wxBitmap(img, -1, bmp.GetScaleFactor());
|
||||
}
|
||||
|
||||
// Orca: StateColor has no gray button style, so define one file-local. This panel is its only
|
||||
// consumer, so keeping it here avoids touching the shared StateColor widget.
|
||||
static StateColor s_button_style_gray()
|
||||
{
|
||||
return StateColor(std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Pressed),
|
||||
std::pair<wxColour, int>(*wxWHITE, StateColor::Focused),
|
||||
std::pair<wxColour, int>(wxColour(238, 238, 238), StateColor::Hovered),
|
||||
std::pair<wxColour, int>(*wxWHITE, StateColor::Normal));
|
||||
}
|
||||
|
||||
wgtDeviceNozzleRack::wgtDeviceNozzleRack(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
|
||||
: wxPanel(parent, id, pos, size, style)
|
||||
{
|
||||
CreateGui();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRack::CreateGui()
|
||||
{
|
||||
m_toolhead_panel = new wgtDeviceNozzleRackToolHead(this);
|
||||
m_rack_area = new wgtDeviceNozzleRackArea(this);
|
||||
|
||||
wxPanel* separator = new wxPanel(this);
|
||||
separator->SetMaxSize(wxSize(FromDIP(1), -1));
|
||||
separator->SetMinSize(wxSize(FromDIP(1), -1));
|
||||
separator->SetBackgroundColour(WGT_GREY300);
|
||||
|
||||
wxSizer* main_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
main_sizer->AddStretchSpacer();
|
||||
main_sizer->Add(m_toolhead_panel, 0, wxEXPAND);
|
||||
main_sizer->Add(separator, 0, wxEXPAND);
|
||||
main_sizer->Add(m_rack_area, 0, wxEXPAND);
|
||||
main_sizer->AddStretchSpacer();
|
||||
|
||||
SetSizer(main_sizer);
|
||||
SetMaxSize(WX_DIP_SIZE(586, -1));
|
||||
SetMinSize(WX_DIP_SIZE(586, -1));
|
||||
SetSize(WX_DIP_SIZE(586, -1));
|
||||
Layout();
|
||||
|
||||
wxGetApp().UpdateDarkUIWin(this);
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRack::UpdateRackInfo(std::shared_ptr<DevNozzleRack> rack)
|
||||
{
|
||||
if (!rack->IsSupported()) { return; }
|
||||
|
||||
m_nozzle_rack = rack;
|
||||
if (m_nozzle_rack.expired()) { return; }
|
||||
|
||||
DevNozzleSystem* nozzle_system = m_nozzle_rack.lock()->GetNozzleSystem();
|
||||
if (nozzle_system)
|
||||
{
|
||||
m_toolhead_panel->UpdateToolHeadInfo(nozzle_system->GetExtNozzle(MAIN_EXTRUDER_ID));
|
||||
m_rack_area->UpdateRackInfo(m_nozzle_rack);
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRack::Rescale()
|
||||
{
|
||||
m_toolhead_panel->Rescale();
|
||||
m_rack_area->Rescale();
|
||||
Layout();
|
||||
}
|
||||
|
||||
class wgtDeviceNozzleRackTitle : public StaticBox
|
||||
{
|
||||
public:
|
||||
wgtDeviceNozzleRackTitle(wxWindow* parent, const wxString& title) : StaticBox(parent)
|
||||
{
|
||||
SetBackgroundColour(WGT_GREY200);
|
||||
SetBorderColor(*wxWHITE);
|
||||
SetCornerRadius(0);
|
||||
|
||||
m_title_label = new Label(this, title);
|
||||
m_title_label->SetFont(Label::Body_14);
|
||||
m_title_label->SetBackgroundColour(WGT_GREY200);
|
||||
|
||||
wxSizer* title_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
title_sizer->AddStretchSpacer();
|
||||
title_sizer->Add(m_title_label, 0, wxEXPAND | wxALIGN_CENTER | wxTOP | wxBOTTOM, FromDIP(5));
|
||||
title_sizer->AddStretchSpacer();
|
||||
SetSizer(title_sizer);
|
||||
};
|
||||
|
||||
public:
|
||||
void SetLabel(const wxString& new_label) { m_title_label->SetLabel(new_label); }
|
||||
|
||||
private:
|
||||
Label* m_title_label;
|
||||
};
|
||||
|
||||
|
||||
void wgtDeviceNozzleRackToolHead::CreateGui()
|
||||
{
|
||||
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// Create Header
|
||||
wgtDeviceNozzleRackTitle* title_box = new wgtDeviceNozzleRackTitle(this, _L("Toolhead"));
|
||||
mainSizer->Add(title_box, 0, wxEXPAND | wxTOP);
|
||||
mainSizer->AddStretchSpacer();
|
||||
|
||||
// Image
|
||||
m_extruder_nozzle_empty = new ScalableBitmap(this, "dev_rack_toolhead_empty", 98);
|
||||
m_extruder_nozzle_normal = new ScalableBitmap(this, "dev_rack_toolhead_normal", 98);
|
||||
m_toolhead_icon = new wxStaticBitmap(this, wxID_ANY, m_extruder_nozzle_empty->bmp(), wxDefaultPosition, WX_DIP_SIZE(98, 98));
|
||||
mainSizer->Add(m_toolhead_icon, 0, wxALIGN_CENTRE_HORIZONTAL | wxTOP, FromDIP(20));
|
||||
|
||||
// Nozzle info
|
||||
m_nozzle_diamenter_label = new Label(this);
|
||||
m_nozzle_diamenter_label->SetFont(Label::Body_13);
|
||||
m_nozzle_diamenter_label->SetBackgroundColour(*wxWHITE);
|
||||
mainSizer->Add(m_nozzle_diamenter_label, 0, wxALIGN_CENTRE_HORIZONTAL | wxBOTTOM | wxTOP, FromDIP(5));
|
||||
|
||||
m_nozzle_flowtype_label = new Label(this);
|
||||
m_nozzle_flowtype_label->SetFont(Label::Body_13);
|
||||
m_nozzle_flowtype_label->SetBackgroundColour(*wxWHITE);
|
||||
mainSizer->Add(m_nozzle_flowtype_label, 0, wxALIGN_CENTRE_HORIZONTAL);
|
||||
mainSizer->AddStretchSpacer();
|
||||
|
||||
// Set sizer
|
||||
SetSizer(mainSizer);
|
||||
SetMaxSize(WX_DIP_SIZE(132, -1));
|
||||
SetMinSize(WX_DIP_SIZE(132, -1));
|
||||
SetSize(WX_DIP_SIZE(132, -1));
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackToolHead::UpdateToolHeadInfo(const DevNozzle& extruder_nozzle)
|
||||
{
|
||||
/* Labels */
|
||||
if (extruder_nozzle.IsEmpty())
|
||||
{
|
||||
m_nozzle_diamenter_label->Show(false);
|
||||
m_nozzle_flowtype_label->SetLabel(_L("Empty"));
|
||||
}
|
||||
else if (extruder_nozzle.IsUnknown())
|
||||
{
|
||||
m_nozzle_diamenter_label->Show(false);
|
||||
m_nozzle_flowtype_label->SetLabel(_L("Unknown"));
|
||||
}
|
||||
else if (extruder_nozzle.IsAbnormal())
|
||||
{
|
||||
m_nozzle_diamenter_label->Show(false);
|
||||
m_nozzle_flowtype_label->SetLabel(_L("Error"));
|
||||
}
|
||||
else /*extruder_nozzle.IsNormal()*/
|
||||
{
|
||||
m_nozzle_diamenter_label->Show(true);
|
||||
m_nozzle_diamenter_label->SetLabel(extruder_nozzle.GetNozzleDiameterStr());
|
||||
m_nozzle_flowtype_label->SetLabel(extruder_nozzle.GetNozzleFlowTypeStr());
|
||||
}
|
||||
|
||||
/* Icon*/
|
||||
bool extruder_exist = !extruder_nozzle.IsEmpty();
|
||||
if (m_extruder_nozzle_exist != extruder_exist)
|
||||
{
|
||||
m_extruder_nozzle_exist = extruder_exist;
|
||||
m_filament_color = extruder_nozzle.GetFilamentColor();
|
||||
m_toolhead_icon->SetBitmap(m_extruder_nozzle_exist ? SetNozzleBmpColor(m_extruder_nozzle_normal->bmp(), m_filament_color) : m_extruder_nozzle_empty->bmp());
|
||||
m_toolhead_icon->Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackToolHead::Rescale()
|
||||
{
|
||||
m_extruder_nozzle_normal->msw_rescale();
|
||||
m_extruder_nozzle_empty->msw_rescale();
|
||||
m_toolhead_icon->SetBitmap(m_extruder_nozzle_exist ? SetNozzleBmpColor(m_extruder_nozzle_normal->bmp(), m_filament_color) : m_extruder_nozzle_empty->bmp());
|
||||
|
||||
Layout();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackArea::CreateGui()
|
||||
{
|
||||
wxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// Create Header
|
||||
m_title_nozzle_rack = new wgtDeviceNozzleRackTitle(this, _L("Induction Hotend Rack"));
|
||||
main_sizer->Add(m_title_nozzle_rack, 0, wxEXPAND | wxTOP);
|
||||
|
||||
// Create Simple Book
|
||||
m_simple_book = new wxSimplebook(this, wxID_ANY);
|
||||
|
||||
wxSizer* content_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
m_panel_content = new wxPanel(m_simple_book, wxID_ANY);
|
||||
m_panel_refresh = new wxPanel(m_simple_book, wxID_ANY);
|
||||
|
||||
// Create Hotends ans Rack Position Panel
|
||||
wxSizer* hotends_rack_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
// Hotends
|
||||
m_hotends_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
m_arow_nozzles_box = CreateNozzleBox( { 0, 2, 4});
|
||||
m_brow_nozzles_box = CreateNozzleBox( { 1, 3, 5});
|
||||
m_hotends_sizer->Add(m_arow_nozzles_box);
|
||||
m_hotends_sizer->Add(m_brow_nozzles_box);
|
||||
hotends_rack_sizer->Add(m_hotends_sizer, 0, wxLEFT, FromDIP(8));
|
||||
|
||||
// Rack
|
||||
m_rack_pos_panel = new wgtDeviceNozzleRackPos(m_panel_content);
|
||||
hotends_rack_sizer->Add(m_rack_pos_panel, 0, wxEXPAND);
|
||||
content_sizer->Add(hotends_rack_sizer, 0);
|
||||
|
||||
wxSizer* btn_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_btn_hotends_infos = new Button(m_panel_content, _L("Hotends Info"));
|
||||
m_btn_hotends_infos->SetFont(Label::Body_12);
|
||||
m_btn_hotends_infos->SetBackgroundColor(s_button_style_gray());
|
||||
m_btn_hotends_infos->SetBackgroundColour(*wxWHITE);
|
||||
m_btn_hotends_infos->Bind(wxEVT_BUTTON, &wgtDeviceNozzleRackArea::OnBtnHotendsInfos, this);
|
||||
|
||||
m_btn_read_all = new Button(m_panel_content, _L("Read All"));
|
||||
m_btn_read_all->SetFont(Label::Body_12);
|
||||
m_btn_read_all->SetBackgroundColor(s_button_style_gray());
|
||||
m_btn_read_all->SetBackgroundColour(*wxWHITE);
|
||||
m_btn_read_all->Bind(wxEVT_BUTTON, &wgtDeviceNozzleRackArea::OnBtnReadAll, this);
|
||||
|
||||
btn_sizer->Add(m_btn_hotends_infos, 0, wxLEFT);
|
||||
btn_sizer->Add(m_btn_read_all, 0, wxLEFT, FromDIP(5));
|
||||
content_sizer->Add(btn_sizer, 0, wxLEFT, FromDIP(10));
|
||||
|
||||
/* refresh panel */
|
||||
wxSizer* refresh_sizer = CreateRefreshBook(m_panel_refresh);
|
||||
|
||||
m_panel_content->SetSizer(content_sizer);
|
||||
m_panel_refresh->SetSizer(refresh_sizer);
|
||||
m_simple_book->AddPage(m_panel_content, "Content");
|
||||
m_simple_book->AddPage(m_panel_refresh, "Refresh");
|
||||
main_sizer->Add(m_simple_book, 1, wxEXPAND);
|
||||
|
||||
m_simple_book->SetSelection(0);
|
||||
|
||||
SetSizer(main_sizer);
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
|
||||
wxSizer* wgtDeviceNozzleRackArea::CreateRefreshBook(wxPanel* parent)
|
||||
{
|
||||
wxSizer* refresh_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
std::vector<std::string> list{"ams_rfid_1", "ams_rfid_2", "ams_rfid_3", "ams_rfid_4"};
|
||||
m_refresh_icon = new AnimaIcon(parent, wxID_ANY, list, "refresh_printer", 100);
|
||||
m_refresh_icon->SetMinSize(wxSize(FromDIP(25), FromDIP(25)));
|
||||
|
||||
wxSizer* progress_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
Label* progress_prefix = new Label(parent, _L("Reading "));
|
||||
progress_prefix->SetBackgroundColour(*wxWHITE);
|
||||
m_progress_refresh = new Label(parent, "(1/6)");
|
||||
m_progress_refresh->SetFont(Label::Body_14);
|
||||
m_progress_refresh->SetBackgroundColour(*wxWHITE);
|
||||
m_progress_refresh->SetForegroundColour(*wxGREEN);
|
||||
Label* progress_suffix = new Label(parent, " ...");
|
||||
progress_suffix->SetBackgroundColour(*wxWHITE);
|
||||
|
||||
progress_sizer->Add(progress_prefix, 0, wxLEFT);
|
||||
progress_sizer->Add(m_progress_refresh, 0, wxLEFT);
|
||||
progress_sizer->Add(progress_suffix, 0, wxLEFT);
|
||||
|
||||
Label* refresh_tip = new Label(parent, _L("Please wait"));
|
||||
refresh_tip->SetBackgroundColour(*wxWHITE);
|
||||
|
||||
refresh_sizer->Add(0, 0, 1, wxEXPAND, 0);
|
||||
refresh_sizer->Add(m_refresh_icon, 0, wxALIGN_CENTER_HORIZONTAL, 0);
|
||||
refresh_sizer->Add(progress_sizer, 0, wxALIGN_CENTER_HORIZONTAL, FromDIP(0));
|
||||
refresh_sizer->Add(refresh_tip, 0, wxALIGN_CENTER_HORIZONTAL, FromDIP(0));
|
||||
refresh_sizer->Add(0, 0, 1, wxEXPAND, 0);
|
||||
|
||||
return refresh_sizer;
|
||||
}
|
||||
|
||||
StaticBox* wgtDeviceNozzleRackArea::CreateNozzleBox(const std::vector<int> nozzle_idxes)
|
||||
{
|
||||
StaticBox* nozzle_box = new StaticBox(m_panel_content);
|
||||
nozzle_box->SetBackgroundColor(*wxWHITE);
|
||||
nozzle_box->SetBorderColor(*wxWHITE);
|
||||
nozzle_box->SetCornerRadius(0);
|
||||
|
||||
wxSizer* h_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
for (auto start_idx : nozzle_idxes)
|
||||
{
|
||||
wgtDeviceNozzleRackNozzleItem* nozzle_item = new wgtDeviceNozzleRackNozzleItem(nozzle_box, start_idx);
|
||||
m_nozzle_items[start_idx] = nozzle_item;
|
||||
h_sizer->Add(nozzle_item, 0, wxALL, FromDIP(8));
|
||||
}
|
||||
|
||||
nozzle_box->SetSizer(h_sizer);
|
||||
return nozzle_box;
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackArea::UpdateNozzleItems(const std::unordered_map<int, wgtDeviceNozzleRackNozzleItem*>& nozzle_items,
|
||||
std::shared_ptr<DevNozzleRack> nozzle_rack)
|
||||
{
|
||||
for (auto iter : nozzle_items)
|
||||
{
|
||||
iter.second->Update(nozzle_rack);
|
||||
}
|
||||
|
||||
/*update nozzle possition and background*/
|
||||
if (nozzle_rack->GetReadingCount() != 0)
|
||||
{
|
||||
m_progress_refresh->SetLabel(wxString::Format("(%d/%d)", nozzle_rack->GetReadingIdx(), nozzle_rack->GetReadingCount()));
|
||||
if(!m_refresh_icon->IsPlaying()) {
|
||||
m_simple_book->SetSelection(1);
|
||||
m_refresh_icon->Play();
|
||||
}
|
||||
return;
|
||||
} else{
|
||||
m_refresh_icon->Stop();
|
||||
m_simple_book->SetSelection(0);
|
||||
}
|
||||
|
||||
const DevNozzleRack::RackPos new_pos = nozzle_rack->GetPosition();
|
||||
const DevNozzleRack::RackStatus new_status = nozzle_rack->GetStatus();
|
||||
if (m_rack_pos != new_pos || m_rack_status != new_status)
|
||||
{
|
||||
m_rack_pos = new_pos;
|
||||
m_rack_status = new_status;
|
||||
if (m_rack_status == DevNozzleRack::RACK_STATUS_IDLE)
|
||||
{
|
||||
m_hotends_sizer->Clear();
|
||||
if (m_rack_pos == DevNozzleRack::RACK_POS_B_TOP)
|
||||
{
|
||||
m_hotends_sizer->Add(m_brow_nozzles_box);
|
||||
m_hotends_sizer->Add(m_arow_nozzles_box);
|
||||
}
|
||||
else if (m_rack_pos == DevNozzleRack::RACK_POS_A_TOP)
|
||||
{
|
||||
m_hotends_sizer->Add(m_arow_nozzles_box);
|
||||
m_hotends_sizer->Add(m_brow_nozzles_box);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hotends_sizer->Add(m_arow_nozzles_box);
|
||||
m_hotends_sizer->Add(m_brow_nozzles_box);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackArea::UpdateRackInfo(std::weak_ptr<DevNozzleRack> rack)
|
||||
{
|
||||
m_nozzle_rack = rack;
|
||||
const auto& nozzle_rack = rack.lock();
|
||||
if (nozzle_rack)
|
||||
{
|
||||
UpdateNozzleItems(m_nozzle_items, nozzle_rack);
|
||||
m_rack_pos_panel->UpdateRackPos(nozzle_rack);
|
||||
m_btn_read_all->Enable(nozzle_rack->CtrlCanReadAll());
|
||||
}
|
||||
|
||||
if (m_rack_upgrade_dlg && m_rack_upgrade_dlg->IsShown())
|
||||
{
|
||||
m_rack_upgrade_dlg->UpdateRackInfo(nozzle_rack);
|
||||
}
|
||||
};
|
||||
|
||||
void wgtDeviceNozzleRackArea::OnBtnHotendsInfos(wxCommandEvent& evt)
|
||||
{
|
||||
const auto& nozzle_rack = m_nozzle_rack.lock();
|
||||
if (nozzle_rack)
|
||||
{
|
||||
m_rack_upgrade_dlg = new wgtDeviceNozzleRackUpgradeDlg((wxWindow*)wxGetApp().mainframe, nozzle_rack);
|
||||
m_rack_upgrade_dlg->ShowModal();
|
||||
|
||||
delete m_rack_upgrade_dlg;
|
||||
m_rack_upgrade_dlg = nullptr;
|
||||
}
|
||||
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackArea::OnBtnReadAll(wxCommandEvent& evt)
|
||||
{
|
||||
if (const auto nozzle_rack = m_nozzle_rack.lock())
|
||||
{
|
||||
nozzle_rack->CtrlRackReadAll(true);
|
||||
}
|
||||
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackArea::Rescale()
|
||||
{
|
||||
for (auto item : m_nozzle_items)
|
||||
{
|
||||
item.second->Rescale();
|
||||
}
|
||||
|
||||
m_rack_pos_panel->Rescale();
|
||||
m_btn_hotends_infos->Rescale();
|
||||
m_btn_read_all->Rescale();
|
||||
}
|
||||
|
||||
static void s_set_bg_style(StaticBox* box,
|
||||
ScalableButton* btn,
|
||||
Label* label_row,
|
||||
Label* label_row_status,
|
||||
const wxColour& clr)
|
||||
{
|
||||
box->SetBorderColor(clr);
|
||||
box->SetBackgroundColor(clr);
|
||||
btn->SetBackgroundColour(clr);
|
||||
label_row->SetBackgroundColour(clr);
|
||||
label_row_status->SetBackgroundColour(clr);
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackPos::CreateGui()
|
||||
{
|
||||
// RowA
|
||||
m_rowup_panel = new StaticBox(this, wxID_ANY);
|
||||
m_rowup_panel->SetCornerRadius(0);
|
||||
|
||||
wxBoxSizer* rowa_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
rowa_sizer->AddStretchSpacer();
|
||||
m_btn_rowup = new ScalableButton(m_rowup_panel, wxID_ANY, "dev_rack_row_up", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, false, 25);
|
||||
m_btn_rowup->Bind(wxEVT_ENTER_WINDOW, [this](auto&) { SetCursor(wxCURSOR_HAND); });
|
||||
m_btn_rowup->Bind(wxEVT_LEAVE_WINDOW, [this](auto&) { SetCursor(wxCURSOR_ARROW); });
|
||||
m_btn_rowup->Bind(wxEVT_BUTTON, &wgtDeviceNozzleRackPos::OnMoveRackUp, this);
|
||||
rowa_sizer->Add(m_btn_rowup, 0, wxALIGN_CENTER | wxEXPAND | wxLEFT | wxRIGHT, FromDIP(10));
|
||||
|
||||
m_label_rowup_status = new Label(m_rowup_panel);
|
||||
m_label_rowup_status->SetFont(Label::Body_12);
|
||||
m_label_rowup_status->Show(false);
|
||||
rowa_sizer->Add(m_label_rowup_status, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, FromDIP(10));
|
||||
|
||||
m_label_rowup = new Label(m_rowup_panel);
|
||||
m_label_rowup->SetFont(Label::Body_14);
|
||||
rowa_sizer->Add(m_label_rowup, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, FromDIP(10));
|
||||
rowa_sizer->AddStretchSpacer();
|
||||
|
||||
m_rowup_panel->SetSizer(rowa_sizer);
|
||||
|
||||
// homing
|
||||
m_btn_homing = new ScalableButton(this, wxID_ANY, "dev_rack_home", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, false, 25);
|
||||
m_btn_homing->SetBackgroundColour(WGT_GREY200);
|
||||
m_btn_homing->Bind(wxEVT_ENTER_WINDOW, [this](auto&) { SetCursor(wxCURSOR_HAND); });
|
||||
m_btn_homing->Bind(wxEVT_LEAVE_WINDOW, [this](auto&) { SetCursor(wxCURSOR_ARROW); });
|
||||
m_btn_homing->Bind(wxEVT_BUTTON, &wgtDeviceNozzleRackPos::OnBtnHomingRack, this);
|
||||
|
||||
// Row B
|
||||
m_rowbottom_panel = new StaticBox(this, wxID_ANY);
|
||||
m_rowbottom_panel->SetCornerRadius(0);
|
||||
|
||||
wxBoxSizer* rowb_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
rowb_sizer->AddStretchSpacer();
|
||||
|
||||
m_btn_rowbottom_up = new ScalableButton(m_rowbottom_panel, wxID_ANY, "dev_rack_row_up", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, false, 25);
|
||||
m_btn_rowbottom_up->Bind(wxEVT_BUTTON, &wgtDeviceNozzleRackPos::OnMoveRackDown, this);
|
||||
m_btn_rowbottom_up->Bind(wxEVT_ENTER_WINDOW, [this](auto&) { SetCursor(wxCURSOR_HAND); });
|
||||
m_btn_rowbottom_up->Bind(wxEVT_LEAVE_WINDOW, [this](auto&) { SetCursor(wxCURSOR_ARROW); });
|
||||
rowb_sizer->Add(m_btn_rowbottom_up, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, FromDIP(10));
|
||||
|
||||
m_label_rowbottom_status = new Label(m_rowbottom_panel);
|
||||
m_label_rowbottom_status->SetFont(Label::Body_12);
|
||||
m_label_rowbottom_status->Show(false);
|
||||
rowb_sizer->Add(m_label_rowbottom_status, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, FromDIP(10));
|
||||
|
||||
m_label_rowbottom = new Label(m_rowbottom_panel);
|
||||
m_label_rowbottom->SetFont(Label::Body_14);
|
||||
rowb_sizer->Add(m_label_rowbottom, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, FromDIP(10));
|
||||
rowb_sizer->AddStretchSpacer();
|
||||
|
||||
m_rowbottom_panel->SetSizer(rowb_sizer);
|
||||
|
||||
// bg style
|
||||
SetBackgroundColour(*wxWHITE);
|
||||
s_set_bg_style(m_rowup_panel, m_btn_rowup, m_label_rowup, m_label_rowup_status, *wxWHITE);
|
||||
s_set_bg_style(m_rowbottom_panel, m_btn_rowbottom_up, m_label_rowbottom, m_label_rowbottom_status, *wxWHITE);
|
||||
|
||||
// main sizer
|
||||
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->Add(m_rowup_panel, 1, wxALIGN_TOP | wxEXPAND | wxALIGN_CENTER);
|
||||
main_sizer->Add(m_btn_homing, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, FromDIP(10));
|
||||
main_sizer->Add(m_rowbottom_panel, 1, wxALIGN_BOTTOM | wxEXPAND | wxALIGN_CENTER);
|
||||
SetSizer(main_sizer);
|
||||
|
||||
SetMinSize(WX_DIP_SIZE(85, -1));
|
||||
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackPos::UpdateRackPos(const std::shared_ptr<DevNozzleRack>& rack)
|
||||
{
|
||||
m_rack = rack;
|
||||
if (rack)
|
||||
{
|
||||
UpdateRackPos(rack->GetPosition(), rack->GetStatus(), rack->GetReadingCount() > 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void s_show_label(Label* label, const wxString& text)
|
||||
{
|
||||
label->SetLabel(text);
|
||||
label->Show();
|
||||
}
|
||||
|
||||
static void s_show_label(Label* label, const wxString& text, const wxColour& text_color)
|
||||
{
|
||||
label->SetLabel(text);
|
||||
label->SetForegroundColour(StateColor::darkModeColorFor(text_color));
|
||||
label->Show();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackPos::UpdateRackPos(DevNozzleRack::RackPos new_pos,
|
||||
DevNozzleRack::RackStatus new_status, bool is_reading)
|
||||
{
|
||||
// While reading, both rows show a "Running..." status and the move buttons are hidden.
|
||||
if (is_reading)
|
||||
{
|
||||
s_show_label(m_label_rowup, L_RAW_A_STR, *wxBLACK);
|
||||
s_show_label(m_label_rowup_status, _L("Running..."));
|
||||
|
||||
s_show_label(m_label_rowbottom, L_RAW_B_STR, *wxBLACK);
|
||||
s_show_label(m_label_rowbottom_status, _L("Running..."));
|
||||
|
||||
m_btn_rowup->Show(false);
|
||||
m_btn_rowbottom_up->Show(false);
|
||||
|
||||
m_rack_pos = DevNozzleRack::RACK_POS_UNKNOWN;
|
||||
m_rack_status = DevNozzleRack::RACK_STATUS_UNKNOWN;
|
||||
return;
|
||||
}
|
||||
|
||||
if (new_pos != m_rack_pos || m_rack_status != new_status)
|
||||
{
|
||||
m_rack_pos = new_pos;
|
||||
m_rack_status = new_status;
|
||||
|
||||
if (m_rack_status != DevNozzleRack::RACK_STATUS_IDLE)
|
||||
{
|
||||
s_show_label(m_label_rowup, L_RAW_A_STR, *wxBLACK);
|
||||
s_show_label(m_label_rowup_status, _L("Running..."));
|
||||
|
||||
s_show_label(m_label_rowbottom, L_RAW_B_STR, *wxBLACK);
|
||||
s_show_label(m_label_rowbottom_status, _L("Running..."));
|
||||
|
||||
m_btn_rowup->Show(false);
|
||||
m_btn_rowbottom_up->Show(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (new_pos == DevNozzleRack::RACK_POS_A_TOP)
|
||||
{
|
||||
s_show_label(m_label_rowup, L_RAW_A_STR, s_hgreen_clr);
|
||||
s_show_label(m_label_rowup_status, _L("Raised"));
|
||||
|
||||
m_rowbottom_panel->SetBorderColor(*wxWHITE);
|
||||
m_rowbottom_panel->SetBackgroundColor(*wxWHITE);
|
||||
s_show_label(m_label_rowbottom, L_RAW_B_STR, *wxBLACK);
|
||||
m_label_rowbottom_status->Show(false);
|
||||
|
||||
m_btn_rowup->Show(false);
|
||||
m_btn_rowbottom_up->Show(true);
|
||||
}
|
||||
else if (new_pos == DevNozzleRack::RACK_POS_B_TOP)
|
||||
{
|
||||
s_show_label(m_label_rowup, L_RAW_B_STR, s_hgreen_clr);
|
||||
s_show_label(m_label_rowup_status, _L("Raised"));
|
||||
s_show_label(m_label_rowbottom, L_RAW_A_STR, *wxBLACK);
|
||||
m_label_rowbottom_status->Show(false);
|
||||
|
||||
m_btn_rowup->Show(false);
|
||||
m_btn_rowbottom_up->Show(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
s_show_label(m_label_rowup, L_RAW_A_STR, *wxBLACK);
|
||||
m_label_rowup_status->Show(false);
|
||||
|
||||
s_show_label(m_label_rowbottom, L_RAW_B_STR, *wxBLACK);
|
||||
m_label_rowbottom_status->Show(false);
|
||||
|
||||
m_btn_rowup->Show(true);
|
||||
m_btn_rowbottom_up->Show(true);
|
||||
}
|
||||
}
|
||||
|
||||
Layout();
|
||||
Refresh();
|
||||
}
|
||||
};
|
||||
|
||||
void wgtDeviceNozzleRackPos::OnMoveRackUp(wxCommandEvent& evt)
|
||||
{
|
||||
auto rack = m_rack.lock();
|
||||
if (rack)
|
||||
{
|
||||
if (m_label_rowup->GetLabel() == L_RAW_A_STR)
|
||||
{
|
||||
rack->CtrlRackPosMove(DevNozzleRack::RACK_POS_A_TOP);
|
||||
}
|
||||
else if (m_label_rowup->GetLabel() == L_RAW_B_STR)
|
||||
{
|
||||
rack->CtrlRackPosMove(DevNozzleRack::RACK_POS_B_TOP);
|
||||
}
|
||||
}
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackPos::OnMoveRackDown(wxCommandEvent& evt)
|
||||
{
|
||||
auto rack = m_rack.lock();
|
||||
if (rack)
|
||||
{
|
||||
if (m_label_rowbottom->GetLabel() == L_RAW_A_STR)
|
||||
{
|
||||
rack->CtrlRackPosMove(DevNozzleRack::RACK_POS_A_TOP);
|
||||
}
|
||||
else if (m_label_rowbottom->GetLabel() == L_RAW_B_STR)
|
||||
{
|
||||
rack->CtrlRackPosMove(DevNozzleRack::RACK_POS_B_TOP);
|
||||
}
|
||||
}
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackPos::OnBtnHomingRack(wxCommandEvent& evt)
|
||||
{
|
||||
if (auto rack = m_rack.lock())
|
||||
{
|
||||
rack->CtrlRackPosGoHome();
|
||||
}
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackPos::Rescale()
|
||||
{
|
||||
m_btn_rowup->msw_rescale();
|
||||
m_btn_rowbottom_up->msw_rescale();
|
||||
m_btn_homing->msw_rescale();
|
||||
}
|
||||
|
||||
};// end of namespace Slic3r::GUI
|
||||
@@ -0,0 +1,196 @@
|
||||
//**********************************************************/
|
||||
/* File: wgtDeviceNozzleRack.h
|
||||
* Description: The Device-tab panel with the toolhead nozzle and the H2C induction hotend rack.
|
||||
*
|
||||
* \n class wgtDeviceNozzleRack; // toolhead panel + rack area, side by side
|
||||
* \n class wgtDeviceNozzleRackToolHead;
|
||||
* \n class wgtDeviceNozzleRackArea;
|
||||
* \n class wgtDeviceNozzleRackPos;
|
||||
*
|
||||
* The single-nozzle tile class wgtDeviceNozzleRackNozzleItem lives in its own translation unit
|
||||
* (wgtDeviceNozzleRackNozzleItem.{h,cpp}), so it is included here rather than redeclared.
|
||||
* The Hotends-Info upgrade dialog (wgtDeviceNozzleRackUpgradeDlg) is intentionally not wired yet
|
||||
* (see the TODO markers in the .cpp).
|
||||
//**********************************************************/
|
||||
|
||||
#pragma once
|
||||
#include "slic3r/GUI/DeviceCore/DevNozzleRack.h"
|
||||
|
||||
#include "wgtDeviceNozzleRackNozzleItem.h"
|
||||
|
||||
#include "slic3r/GUI/Widgets/StaticBox.hpp"
|
||||
#include "slic3r/GUI/Widgets/AnimaController.hpp"
|
||||
|
||||
#include <wx/panel.h>
|
||||
#include <wx/simplebook.h>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
// Previous definitions
|
||||
class Button;
|
||||
class Label;
|
||||
class ScalableBitmap;
|
||||
class ScalableButton;
|
||||
namespace Slic3r
|
||||
{
|
||||
struct DevNozzle;
|
||||
class DevNozzleRack;
|
||||
namespace GUI
|
||||
{
|
||||
class wgtDeviceNozzleRackArea;
|
||||
class wgtDeviceNozzleRackNozzleItem;
|
||||
class wgtDeviceNozzleRackToolHead;
|
||||
class wgtDeviceNozzleRackPos;
|
||||
class wgtDeviceNozzleRackTitle;
|
||||
class wgtDeviceNozzleRackUpgradeDlg;
|
||||
}
|
||||
};
|
||||
|
||||
namespace Slic3r::GUI
|
||||
{
|
||||
class wgtDeviceNozzleRack : public wxPanel
|
||||
{
|
||||
public:
|
||||
wgtDeviceNozzleRack(wxWindow* parent,
|
||||
wxWindowID id = wxID_ANY,
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = wxTAB_TRAVERSAL);
|
||||
~wgtDeviceNozzleRack() = default;
|
||||
|
||||
public:
|
||||
void UpdateRackInfo(std::shared_ptr<DevNozzleRack> rack);
|
||||
void Rescale();
|
||||
|
||||
private:
|
||||
void CreateGui();
|
||||
|
||||
private:
|
||||
std::weak_ptr<DevNozzleRack> m_nozzle_rack;
|
||||
|
||||
// GUI
|
||||
wgtDeviceNozzleRackToolHead* m_toolhead_panel{ nullptr };
|
||||
wgtDeviceNozzleRackArea* m_rack_area{ nullptr };
|
||||
};
|
||||
|
||||
|
||||
class wgtDeviceNozzleRackToolHead : public wxPanel
|
||||
{
|
||||
public:
|
||||
wgtDeviceNozzleRackToolHead(wxWindow* parent) : wxPanel(parent) { CreateGui();}
|
||||
|
||||
public:
|
||||
void UpdateToolHeadInfo(const DevNozzle& extruder_nozzle);
|
||||
void Rescale();
|
||||
|
||||
private:
|
||||
void CreateGui();
|
||||
|
||||
private:
|
||||
bool m_extruder_nozzle_exist = false;
|
||||
std::string m_filament_color;
|
||||
|
||||
// GUI
|
||||
ScalableBitmap* m_extruder_nozzle_normal = nullptr;
|
||||
ScalableBitmap* m_extruder_nozzle_empty = nullptr;
|
||||
wxStaticBitmap* m_toolhead_icon;
|
||||
|
||||
Label* m_nozzle_diamenter_label;
|
||||
Label* m_nozzle_flowtype_label;
|
||||
};
|
||||
|
||||
|
||||
class wgtDeviceNozzleRackArea : public wxPanel
|
||||
{
|
||||
public:
|
||||
wgtDeviceNozzleRackArea(wxWindow* parent) : wxPanel(parent) { CreateGui();}
|
||||
|
||||
public:
|
||||
void UpdateRackInfo(std::weak_ptr<DevNozzleRack> rack);
|
||||
void Rescale();
|
||||
|
||||
private:
|
||||
void CreateGui();
|
||||
StaticBox* CreateNozzleBox(const std::vector<int> nozzle_idxes);
|
||||
wxSizer* CreateRefreshBook(wxPanel* parent);
|
||||
|
||||
// updates
|
||||
void UpdateNozzleItems(const std::unordered_map<int, wgtDeviceNozzleRackNozzleItem*>& nozzle_items,
|
||||
std::shared_ptr<DevNozzleRack> nozzle_rack);
|
||||
|
||||
// events
|
||||
void OnBtnHotendsInfos(wxCommandEvent& evt);
|
||||
void OnBtnReadAll(wxCommandEvent& evt);
|
||||
|
||||
private:
|
||||
std::weak_ptr<DevNozzleRack> m_nozzle_rack;
|
||||
DevNozzleRack::RackPos m_rack_pos = DevNozzleRack::RACK_POS_UNKNOWN;
|
||||
DevNozzleRack::RackStatus m_rack_status = DevNozzleRack::RACK_STATUS_UNKNOWN;
|
||||
|
||||
// GUI
|
||||
wxSimplebook* m_simple_book{ nullptr };
|
||||
wxPanel* m_panel_content{ nullptr };
|
||||
wxPanel* m_panel_refresh{ nullptr };
|
||||
|
||||
wgtDeviceNozzleRackTitle* m_title_nozzle_rack;
|
||||
wxBoxSizer* m_hotends_sizer;
|
||||
StaticBox* m_arow_nozzles_box;
|
||||
StaticBox* m_brow_nozzles_box;
|
||||
std::unordered_map<int, wgtDeviceNozzleRackNozzleItem*> m_nozzle_items;
|
||||
|
||||
wgtDeviceNozzleRackPos* m_rack_pos_panel;
|
||||
|
||||
Button* m_btn_hotends_infos;
|
||||
Button* m_btn_read_all;
|
||||
|
||||
/* refresh book */
|
||||
Label* m_progress_refresh{ nullptr };
|
||||
AnimaIcon* m_refresh_icon{ nullptr };
|
||||
|
||||
// "Hotends Info" upgrade dialog. Owned for its ShowModal lifetime by
|
||||
// OnBtnHotendsInfos; UpdateRackInfo forwards live device pushes to it while it is shown.
|
||||
wgtDeviceNozzleRackUpgradeDlg* m_rack_upgrade_dlg = nullptr;
|
||||
};
|
||||
|
||||
class wgtDeviceNozzleRackPos : public wxPanel
|
||||
{
|
||||
public:
|
||||
explicit wgtDeviceNozzleRackPos(wxWindow* parent) : wxPanel(parent) { CreateGui();}
|
||||
|
||||
public:
|
||||
void UpdateRackPos(const std::shared_ptr<DevNozzleRack>& rack);
|
||||
void Rescale();
|
||||
|
||||
private:
|
||||
void CreateGui();
|
||||
|
||||
void UpdateRackPos(DevNozzleRack::RackPos new_pos,
|
||||
DevNozzleRack::RackStatus new_status,
|
||||
bool is_reading);
|
||||
|
||||
// events
|
||||
void OnMoveRackUp(wxCommandEvent& evt);
|
||||
void OnMoveRackDown(wxCommandEvent& evt);
|
||||
void OnBtnHomingRack(wxCommandEvent& evt);
|
||||
|
||||
private:
|
||||
std::weak_ptr<DevNozzleRack> m_rack;
|
||||
DevNozzleRack::RackPos m_rack_pos = DevNozzleRack::RACK_POS_UNKNOWN;
|
||||
DevNozzleRack::RackStatus m_rack_status = DevNozzleRack::RACK_STATUS_UNKNOWN;
|
||||
|
||||
// GUI
|
||||
StaticBox* m_rowup_panel;
|
||||
ScalableButton* m_btn_rowup;
|
||||
Label* m_label_rowup_status{ nullptr };
|
||||
Label* m_label_rowup{ nullptr };
|
||||
|
||||
StaticBox* m_rowbottom_panel;
|
||||
ScalableButton* m_btn_rowbottom_up;
|
||||
Label* m_label_rowbottom_status{ nullptr };
|
||||
Label* m_label_rowbottom{ nullptr };
|
||||
|
||||
ScalableButton* m_btn_homing{ nullptr };
|
||||
};
|
||||
|
||||
};// end of namespace Slic3r::GUI
|
||||
@@ -0,0 +1,347 @@
|
||||
//**********************************************************/
|
||||
/* File: wgtDeviceNozzleRackNozzleItem.cpp
|
||||
* Description: One nozzle cell of the H2C hotend rack view. Holds the
|
||||
* wgtDeviceNozzleRackNozzleItem widget, the SetNozzleBmpColor helper and the layout
|
||||
* constants it needs.
|
||||
//**********************************************************/
|
||||
|
||||
#include "wgtDeviceNozzleRackNozzleItem.h"
|
||||
|
||||
#include "slic3r/GUI/DeviceCore/DevNozzleSystem.h"
|
||||
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/MsgDialog.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/wxExtensions.hpp"
|
||||
|
||||
#include "slic3r/GUI/Widgets/Label.hpp"
|
||||
|
||||
#define WX_DIP_SIZE_46 wxSize(FromDIP(46), FromDIP(46))
|
||||
#define WX_DIP_SIZE(x, y) wxSize(FromDIP(x), FromDIP(y))
|
||||
|
||||
#define WGT_RACK_NOZZLE_SIZE WX_DIP_SIZE(88, 100)
|
||||
|
||||
static wxColour s_gray_clr("#B0B0B0");
|
||||
static wxColour s_hgreen_clr("#00AE42");
|
||||
static wxColour s_red_clr("#D01B1B");
|
||||
|
||||
wxDEFINE_EVENT(EVT_NOZZLE_RACK_NOZZLE_ITEM_SELECTED, wxCommandEvent);
|
||||
|
||||
namespace Slic3r::GUI
|
||||
{
|
||||
|
||||
static wxBitmap SetNozzleBmpColor(const wxBitmap& bmp, const std::string& color_str) {
|
||||
if(color_str.empty()) return bmp;
|
||||
|
||||
wxImage img = bmp.ConvertToImage();
|
||||
wxColour color("#" + color_str);
|
||||
|
||||
for (int y = 0; y < img.GetHeight(); ++y) {
|
||||
for (int x = 0; x < img.GetWidth(); ++x) {
|
||||
unsigned char r = img.GetRed(x, y);
|
||||
unsigned char g = img.GetGreen(x, y);
|
||||
unsigned char b = img.GetBlue(x, y);
|
||||
|
||||
/*replace yellow with color*/
|
||||
if ( r >= 180 && g >= 180 && b <= 150) {
|
||||
img.SetRGB(x, y, color.Red(), color.Green(), color.Blue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return wxBitmap(img, -1, bmp.GetScaleFactor());
|
||||
}
|
||||
|
||||
wgtDeviceNozzleRackNozzleItem::wgtDeviceNozzleRackNozzleItem(wxWindow* parent, int nozzle_id)
|
||||
: StaticBox(parent, wxID_ANY), m_nozzle_id(nozzle_id)
|
||||
{
|
||||
CreateGui();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackNozzleItem::CreateGui()
|
||||
{
|
||||
// Background
|
||||
SetCornerRadius(FromDIP(5));
|
||||
SetBackgroundColor(*wxWHITE);
|
||||
|
||||
// Top H
|
||||
wxSizer *top_h_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
m_nozzle_label_id = new Label(this);
|
||||
m_nozzle_label_id->SetFont(Label::Body_12);
|
||||
m_nozzle_label_id->SetBackgroundColour(*wxWHITE);
|
||||
m_nozzle_label_id->SetLabel(wxString::Format("%d", m_nozzle_id + 1));
|
||||
|
||||
m_status = NOZZLE_STATUS::NOZZLE_EMPTY;
|
||||
m_nozzle_empty_image = new ScalableBitmap(this, "dev_rack_nozzle_empty", 46);
|
||||
m_nozzle_icon = new wxStaticBitmap(this, wxID_ANY, m_nozzle_empty_image->bmp(), wxDefaultPosition, WX_DIP_SIZE_46);
|
||||
m_nozzle_icon->SetBackgroundColour(*wxWHITE);
|
||||
|
||||
m_nozzle_selected_bitmap = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap, wxDefaultPosition, WX_DIP_SIZE(20, 20));
|
||||
m_nozzle_selected_bitmap->SetBackgroundColour(*wxWHITE);
|
||||
|
||||
top_h_sizer->Add(m_nozzle_label_id, 0, wxTOP | wxLEFT, FromDIP(6));
|
||||
top_h_sizer->AddStretchSpacer(1);
|
||||
top_h_sizer->Add(m_nozzle_icon, 0, wxTOP, FromDIP(10));
|
||||
top_h_sizer->AddStretchSpacer(1);
|
||||
top_h_sizer->Add(m_nozzle_selected_bitmap, 0, wxTOP | wxRIGHT, FromDIP(2));
|
||||
|
||||
// Bottom V
|
||||
wxBoxSizer* bottom_v = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
wxSizer* label_h_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_nozzle_label_1 = new Label(this);
|
||||
m_nozzle_label_1->SetFont(Label::Body_12);
|
||||
m_nozzle_label_1->SetBackgroundColour(*wxWHITE);
|
||||
m_nozzle_label_1->SetLabel(_L("Empty"));
|
||||
|
||||
label_h_sizer->Add(m_nozzle_label_1, 0, wxALIGN_LEFT);
|
||||
|
||||
auto status_icon = create_scaled_bitmap("dev_rack_nozzle_error_icon", this, 14);
|
||||
m_nozzle_status_icon = new wxStaticBitmap(this, wxID_ANY, status_icon, wxDefaultPosition, WX_DIP_SIZE(14, 14));
|
||||
m_nozzle_status_icon->Bind(wxEVT_LEFT_DOWN, &wgtDeviceNozzleRackNozzleItem::OnBtnNozzleStatus, this);
|
||||
m_nozzle_status_icon->Bind(wxEVT_ENTER_WINDOW, [this](auto&) { SetCursor(wxCURSOR_HAND); });
|
||||
m_nozzle_status_icon->Bind(wxEVT_LEAVE_WINDOW, [this](auto&) { SetCursor(wxCURSOR_ARROW); });
|
||||
m_nozzle_status_icon->SetBackgroundColour(*wxWHITE);
|
||||
m_nozzle_status_icon->Show(false);
|
||||
|
||||
label_h_sizer->Add(m_nozzle_status_icon, 0, wxALIGN_CENTER | wxLEFT, FromDIP(2));
|
||||
bottom_v->Add(label_h_sizer, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, FromDIP(2));
|
||||
|
||||
m_nozzle_label_2 = new Label(this);
|
||||
m_nozzle_label_2->SetFont(Label::Body_12);
|
||||
m_nozzle_label_2->SetBackgroundColour(*wxWHITE);
|
||||
bottom_v->Add(m_nozzle_label_2, 0, wxALIGN_CENTER_HORIZONTAL);
|
||||
|
||||
// Main sizer
|
||||
wxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->Add(top_h_sizer, 0, wxEXPAND);
|
||||
main_sizer->Add(bottom_v, 0, wxALIGN_CENTER_HORIZONTAL);
|
||||
SetSizer(main_sizer);
|
||||
|
||||
SetMinSize(WGT_RACK_NOZZLE_SIZE);
|
||||
SetMaxSize(WGT_RACK_NOZZLE_SIZE);
|
||||
SetSize(WGT_RACK_NOZZLE_SIZE);
|
||||
Layout();
|
||||
};
|
||||
|
||||
void wgtDeviceNozzleRackNozzleItem::SetSelected(bool selected)
|
||||
{
|
||||
if (!m_enable_select){
|
||||
assert(false && "not support select");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_is_selected != selected) {
|
||||
m_is_selected = selected;
|
||||
if (selected) {
|
||||
if (!m_nozzle_selected_image) {
|
||||
m_nozzle_selected_image = new ScalableBitmap(this, "dev_rack_nozzle_selected", 20);
|
||||
}
|
||||
|
||||
m_nozzle_selected_bitmap->SetBitmap(m_nozzle_selected_image->bmp());
|
||||
SetBorderColor(StateColor::darkModeColorFor(s_hgreen_clr));
|
||||
} else {
|
||||
m_nozzle_selected_bitmap->SetBitmap(wxNullBitmap);
|
||||
SetBorderColor(StateColor::darkModeColorFor(s_gray_clr));
|
||||
}
|
||||
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackNozzleItem::Update(const std::shared_ptr<DevNozzleRack> rack, bool on_rack /*= true*/)
|
||||
{
|
||||
m_rack = rack;
|
||||
|
||||
if (rack) {
|
||||
const auto &nozzle_info = on_rack ? rack->GetNozzle(m_nozzle_id) : rack->GetNozzleSystem()->GetExtNozzle(m_nozzle_id);
|
||||
const wxString &diameter_str = nozzle_info.GetNozzleDiameterStr();
|
||||
const wxString &flowtype_str = nozzle_info.GetNozzleFlowTypeStr();
|
||||
const std::string &color = nozzle_info.GetFilamentColor();
|
||||
|
||||
/*check empty first*/
|
||||
if (nozzle_info.IsEmpty()) {
|
||||
SetNozzleStatus(NOZZLE_STATUS::NOZZLE_EMPTY, _L("Empty"), wxEmptyString, color);
|
||||
} else if (nozzle_info.IsNormal()) {
|
||||
SetNozzleStatus(NOZZLE_STATUS::NOZZLE_NORMAL, diameter_str, flowtype_str, color);
|
||||
} else if (nozzle_info.IsAbnormal()) {
|
||||
SetNozzleStatus(NOZZLE_STATUS::NOZZLE_ERROR, _L("Error"), wxEmptyString, color);
|
||||
} else if (nozzle_info.IsUnknown()) {
|
||||
SetNozzleStatus(NOZZLE_STATUS::NOZZLE_UNKNOWN, _L("Unknown"), wxEmptyString, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackNozzleItem::SetNozzleStatus(NOZZLE_STATUS status, const wxString& str1, const wxString& str2, const std::string& color)
|
||||
{
|
||||
if (m_status != status || m_filament_color != color)
|
||||
{
|
||||
m_status = status;
|
||||
m_filament_color = color;
|
||||
switch (status)
|
||||
{
|
||||
case Slic3r::GUI::wgtDeviceNozzleRackNozzleItem::NOZZLE_EMPTY:
|
||||
{
|
||||
if (!m_nozzle_empty_image) { m_nozzle_empty_image = new ScalableBitmap(this, "dev_rack_nozzle_empty", 46);}
|
||||
m_nozzle_icon->SetBitmap(m_nozzle_empty_image->bmp());
|
||||
break;
|
||||
}
|
||||
case Slic3r::GUI::wgtDeviceNozzleRackNozzleItem::NOZZLE_NORMAL:
|
||||
{
|
||||
if (!m_nozzle_normal_image) { m_nozzle_normal_image = new ScalableBitmap(this, "dev_rack_nozzle_normal", 46);}
|
||||
m_nozzle_icon->SetBitmap(SetNozzleBmpColor(m_nozzle_normal_image->bmp(), m_filament_color));
|
||||
break;
|
||||
}
|
||||
case Slic3r::GUI::wgtDeviceNozzleRackNozzleItem::NOZZLE_UNKNOWN:
|
||||
{
|
||||
if (!m_nozzle_unknown_image) { m_nozzle_unknown_image = new ScalableBitmap(this, "dev_rack_nozzle_unknown", 46);}
|
||||
m_nozzle_icon->SetBitmap(m_nozzle_unknown_image->bmp());
|
||||
break;
|
||||
}
|
||||
case Slic3r::GUI::wgtDeviceNozzleRackNozzleItem::NOZZLE_ERROR:
|
||||
{
|
||||
if (!m_nozzle_error_image) { m_nozzle_error_image = new ScalableBitmap(this, "dev_rack_nozzle_error", 46);}
|
||||
m_nozzle_icon->SetBitmap(m_nozzle_error_image->bmp());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (status == wgtDeviceNozzleRackNozzleItem::NOZZLE_ERROR)
|
||||
{
|
||||
m_nozzle_label_1->SetForegroundColour(StateColor::darkModeColorFor(s_red_clr));
|
||||
m_nozzle_status_icon->Show(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nozzle_label_1->SetForegroundColour(StateColor::darkModeColorFor(*wxBLACK));
|
||||
m_nozzle_status_icon->Show(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool update_layout = (m_nozzle_label_1->GetLabel() != str1 || m_nozzle_label_2->GetLabel() != str2);
|
||||
m_nozzle_label_1->SetLabel(str1);
|
||||
m_nozzle_label_2->SetLabel(str2);
|
||||
|
||||
if (update_layout) {
|
||||
Layout();
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackNozzleItem::OnBtnNozzleStatus(wxMouseEvent& evt)
|
||||
{
|
||||
if (m_is_disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto rack = m_rack.lock();
|
||||
if (rack && m_status == wgtDeviceNozzleRackNozzleItem::NOZZLE_ERROR)
|
||||
{
|
||||
// Orca: show the abnormal-hotend warning as an informational dialog only, with no
|
||||
// "Jump to the upgrade page" button, since Orca's MessageDialog and device Upgrade UI
|
||||
// have no such entry point. Fires when tapping an error-state rack nozzle's status icon.
|
||||
MessageDialog dlg(nullptr, _L("The hotend is in an abnormal state and currently unavailable. "
|
||||
"Please go to 'Device -> Upgrade' to upgrade firmware."), _L("Abnormal Hotend"), wxICON_WARNING | wxOK);
|
||||
dlg.ShowModal();
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackNozzleItem::Rescale()
|
||||
{
|
||||
if (m_nozzle_normal_image) { m_nozzle_normal_image->msw_rescale(); }
|
||||
if (m_nozzle_empty_image) { m_nozzle_empty_image->msw_rescale(); }
|
||||
if (m_nozzle_unknown_image) { m_nozzle_unknown_image->msw_rescale(); }
|
||||
if (m_nozzle_error_image) { m_nozzle_error_image->msw_rescale(); }
|
||||
|
||||
auto status_icon = create_scaled_bitmap("dev_rack_nozzle_error_icon", this, 14);
|
||||
m_nozzle_status_icon->SetBitmap(status_icon);
|
||||
m_nozzle_status_icon->Refresh();
|
||||
|
||||
if (m_nozzle_selected_image) {
|
||||
m_nozzle_selected_image->msw_rescale();
|
||||
if (m_is_selected) {
|
||||
m_nozzle_selected_bitmap->SetBitmap(m_nozzle_selected_image->bmp());
|
||||
}
|
||||
};
|
||||
|
||||
switch (m_status)
|
||||
{
|
||||
case Slic3r::GUI::wgtDeviceNozzleRackNozzleItem::NOZZLE_EMPTY:
|
||||
{
|
||||
m_nozzle_icon->SetBitmap(m_nozzle_empty_image->bmp());
|
||||
break;
|
||||
}
|
||||
case Slic3r::GUI::wgtDeviceNozzleRackNozzleItem::NOZZLE_NORMAL:
|
||||
{
|
||||
m_nozzle_icon->SetBitmap(SetNozzleBmpColor(m_nozzle_normal_image->bmp(), m_filament_color));
|
||||
break;
|
||||
}
|
||||
case Slic3r::GUI::wgtDeviceNozzleRackNozzleItem::NOZZLE_UNKNOWN:
|
||||
{
|
||||
m_nozzle_icon->SetBitmap(m_nozzle_unknown_image->bmp());
|
||||
break;
|
||||
}
|
||||
case Slic3r::GUI::wgtDeviceNozzleRackNozzleItem::NOZZLE_ERROR:
|
||||
{
|
||||
m_nozzle_icon->SetBitmap(m_nozzle_error_image->bmp());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void wgtDeviceNozzleRackNozzleItem::EnableSelect()
|
||||
{
|
||||
if (m_enable_select == true) {
|
||||
return;
|
||||
};
|
||||
|
||||
m_enable_select = true;
|
||||
m_nozzle_icon->Bind(wxEVT_LEFT_DOWN, [this](auto& evt) { OnItemSelected(evt); });
|
||||
m_nozzle_label_id->Bind(wxEVT_LEFT_DOWN, [this](auto& evt) { OnItemSelected(evt); });
|
||||
m_nozzle_label_1->Bind(wxEVT_LEFT_DOWN, [this](auto& evt) { OnItemSelected(evt); });
|
||||
m_nozzle_label_2->Bind(wxEVT_LEFT_DOWN, [this](auto& evt) { OnItemSelected(evt); });
|
||||
Bind(wxEVT_LEFT_DOWN, [this](auto& evt) { OnItemSelected(evt); });
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackNozzleItem::OnItemSelected(wxMouseEvent& evt)
|
||||
{
|
||||
if (m_enable_select && !m_is_disabled){
|
||||
SetSelected(true);
|
||||
wxCommandEvent command_evt(EVT_NOZZLE_RACK_NOZZLE_ITEM_SELECTED, GetId());
|
||||
command_evt.SetEventObject(this);
|
||||
ProcessEvent(command_evt);
|
||||
}
|
||||
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
|
||||
void wgtDeviceNozzleRackNozzleItem::SetDisable(bool disabled)
|
||||
{
|
||||
if (m_is_disabled == disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_is_disabled = disabled;
|
||||
|
||||
auto bg_clr = disabled ? StateColor::darkModeColorFor("#E5E7EB") : StateColor::darkModeColorFor(*wxWHITE);
|
||||
m_nozzle_icon->SetBackgroundColour(bg_clr);
|
||||
m_nozzle_label_id->SetBackgroundColour(bg_clr);
|
||||
m_nozzle_label_1->SetBackgroundColour(bg_clr);
|
||||
m_nozzle_status_icon->SetBackgroundColour(bg_clr);
|
||||
m_nozzle_label_2->SetBackgroundColour(bg_clr);
|
||||
m_nozzle_selected_bitmap->SetBackgroundColour(bg_clr);
|
||||
|
||||
SetBackgroundColor(bg_clr);
|
||||
Refresh();
|
||||
};
|
||||
|
||||
};// end of namespace Slic3r::GUI
|
||||
@@ -0,0 +1,99 @@
|
||||
//**********************************************************/
|
||||
/* File: wgtDeviceNozzleRackNozzleItem.h
|
||||
* Description: One nozzle cell of the H2C hotend rack view.
|
||||
*
|
||||
* This header defines only the single-nozzle-cell widget (and the selection event it emits), which
|
||||
* is the one dependency MultiNozzleSync's HotEndTable needs. The rest of the Device-tab rack panel
|
||||
* (wgtDeviceNozzleRack / ...Area / ...ToolHead / ...Pos) is not provided here.
|
||||
//**********************************************************/
|
||||
|
||||
#pragma once
|
||||
#include "slic3r/GUI/DeviceCore/DevNozzleRack.h"
|
||||
|
||||
#include "slic3r/GUI/Widgets/StaticBox.hpp"
|
||||
#include "slic3r/GUI/Widgets/Label.hpp" // complete type required by the inline SetDisplayIdText below
|
||||
|
||||
#include <wx/panel.h>
|
||||
#include <memory>
|
||||
|
||||
// Previous definitions
|
||||
class ScalableBitmap;
|
||||
namespace Slic3r
|
||||
{
|
||||
struct DevNozzle;
|
||||
class DevNozzleRack;
|
||||
};
|
||||
|
||||
// Events
|
||||
wxDECLARE_EVENT(EVT_NOZZLE_RACK_NOZZLE_ITEM_SELECTED, wxCommandEvent);
|
||||
|
||||
namespace Slic3r::GUI
|
||||
{
|
||||
class wgtDeviceNozzleRackNozzleItem : public StaticBox
|
||||
{
|
||||
public:
|
||||
enum NOZZLE_STATUS
|
||||
{
|
||||
NOZZLE_EMPTY,
|
||||
NOZZLE_NORMAL,
|
||||
NOZZLE_UNKNOWN,
|
||||
NOZZLE_ERROR
|
||||
};
|
||||
|
||||
public:
|
||||
wgtDeviceNozzleRackNozzleItem(wxWindow* parent, int nozzle_id);
|
||||
|
||||
public:
|
||||
void Update(const std::shared_ptr<DevNozzleRack> rack, bool on_rack = true); // on_rack is false means extruder nozzle
|
||||
|
||||
int GetNozzleId() const { return m_nozzle_id; }
|
||||
void SetDisplayIdText(const wxString& text) { m_nozzle_label_id->SetLabel(text);};
|
||||
|
||||
void EnableSelect();;
|
||||
void SetSelected(bool selected);
|
||||
bool IsSelected() const { return m_is_selected; }
|
||||
|
||||
bool IsDisabled() const { return m_is_disabled; }
|
||||
void SetDisable(bool disabled);
|
||||
|
||||
void Rescale();
|
||||
|
||||
private:
|
||||
void CreateGui();
|
||||
|
||||
void SetNozzleStatus(NOZZLE_STATUS status, const wxString& str1, const wxString& str2, const std::string& color);
|
||||
|
||||
void OnBtnNozzleStatus(wxMouseEvent& evt);
|
||||
void OnItemSelected(wxMouseEvent& evt);
|
||||
|
||||
private:
|
||||
std::weak_ptr<DevNozzleRack> m_rack;
|
||||
|
||||
int m_nozzle_id; // internal id, from 0 to 5
|
||||
std::string m_filament_color;
|
||||
NOZZLE_STATUS m_status = NOZZLE_STATUS::NOZZLE_EMPTY;
|
||||
|
||||
// select
|
||||
bool m_is_selected = false;
|
||||
bool m_enable_select = false;
|
||||
ScalableBitmap* m_nozzle_selected_image{ nullptr };
|
||||
wxStaticBitmap* m_nozzle_selected_bitmap{ nullptr };
|
||||
|
||||
// enable or disable
|
||||
bool m_is_disabled = false;
|
||||
|
||||
// Images
|
||||
ScalableBitmap* m_nozzle_normal_image{ nullptr };
|
||||
ScalableBitmap* m_nozzle_empty_image{ nullptr };
|
||||
ScalableBitmap* m_nozzle_unknown_image{ nullptr };
|
||||
ScalableBitmap* m_nozzle_error_image{ nullptr };
|
||||
|
||||
// GUI
|
||||
wxStaticBitmap* m_nozzle_icon{ nullptr };
|
||||
Label* m_nozzle_label_id { nullptr };
|
||||
Label* m_nozzle_label_1{ nullptr };
|
||||
wxStaticBitmap* m_nozzle_status_icon = nullptr;
|
||||
Label* m_nozzle_label_2{ nullptr };
|
||||
};
|
||||
|
||||
};// end of namespace Slic3r::GUI
|
||||
@@ -0,0 +1,696 @@
|
||||
//**********************************************************/
|
||||
/* File: wgtDeviceNozzleRackUpdate.cpp
|
||||
* Description: The dialog for reading/upgrading the H2C induction-hotend-rack firmware.
|
||||
*
|
||||
* \n class wgtDeviceNozzleRackUpdate
|
||||
//**********************************************************/
|
||||
|
||||
#include "wgtDeviceNozzleRackUpdate.h"
|
||||
|
||||
#include "slic3r/GUI/DeviceCore/DevNozzleSystem.h"
|
||||
|
||||
#include "slic3r/GUI/MainFrame.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/MsgDialog.hpp"
|
||||
#include "slic3r/GUI/wxExtensions.hpp"
|
||||
|
||||
#include "slic3r/GUI/Widgets/Button.hpp"
|
||||
#include "slic3r/GUI/Widgets/Label.hpp"
|
||||
|
||||
#define WX_DIP_SIZE(x, y) wxSize(FromDIP(x), FromDIP(y))
|
||||
|
||||
static wxColour s_red_clr("#D01B1B");
|
||||
|
||||
namespace Slic3r::GUI
|
||||
{
|
||||
|
||||
wxDEFINE_EVENT(wxEVT_NOZZLE_JUMP_UPGRADE, wxCommandEvent);
|
||||
|
||||
wgtDeviceNozzleRackUpgradeDlg::wgtDeviceNozzleRackUpgradeDlg(wxWindow* parent, const std::shared_ptr<DevNozzleRack> rack)
|
||||
: DPIDialog(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX)
|
||||
{
|
||||
m_rack_upgrade_panel = new wgtDeviceNozzleRackUprade(this);
|
||||
m_rack_upgrade_panel->UpdateRackInfo(rack);
|
||||
|
||||
Bind(wxEVT_NOZZLE_JUMP_UPGRADE, [this](wxCommandEvent&) {
|
||||
EndModal(wxID_OK);
|
||||
});
|
||||
|
||||
auto main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->Add(m_rack_upgrade_panel, 0, wxEXPAND);
|
||||
SetSizer(main_sizer);
|
||||
Layout();
|
||||
Fit();
|
||||
|
||||
wxGetApp().UpdateDlgDarkUI(this);
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackUpgradeDlg::UpdateRackInfo(const std::shared_ptr<DevNozzleRack> rack)
|
||||
{
|
||||
m_rack_upgrade_panel->UpdateRackInfo(rack);
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackUpgradeDlg::on_dpi_changed(const wxRect& suggested_rect)
|
||||
{
|
||||
m_rack_upgrade_panel->Rescale();
|
||||
}
|
||||
|
||||
wgtDeviceNozzleRackUprade::wgtDeviceNozzleRackUprade(wxWindow* parent,
|
||||
wxWindowID id,
|
||||
const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
long style)
|
||||
: wxPanel(parent, id, pos, size, style)
|
||||
{
|
||||
CreateGui();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackUprade::CreateGui()
|
||||
{
|
||||
SetBackgroundColour(*wxWHITE);
|
||||
|
||||
// Main vertical sizer
|
||||
auto* main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// Header: title + buttons
|
||||
auto* header_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
// Title label
|
||||
auto* title_label = new Label(this, _L("Hotends Info"));
|
||||
title_label->SetFont(Label::Head_14);
|
||||
header_sizer->Add(title_label, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(20));
|
||||
|
||||
// Spacer
|
||||
header_sizer->AddStretchSpacer();
|
||||
main_sizer->Add(header_sizer, 0, wxEXPAND | wxTOP | wxRIGHT, FromDIP(10));
|
||||
|
||||
// "Nozzles"
|
||||
m_extruder_nozzle_item = new wgtDeviceNozzleRackHotendUpdate(this, "R");
|
||||
m_extruder_nozzle_item->UpdateColourStyle(wxColour("#F8F8F8"));
|
||||
m_extruder_nozzle_item->SetExtruderNozzleId(MAIN_EXTRUDER_ID);
|
||||
|
||||
main_sizer->Add(m_extruder_nozzle_item, 0, wxEXPAND | wxALL, FromDIP(12));
|
||||
for (int id = 0; id < 6; id ++)
|
||||
{
|
||||
auto item = new wgtDeviceNozzleRackHotendUpdate(this, wxString::Format("%d", id + 1));
|
||||
item->SetRackNozzleId(id);
|
||||
m_nozzle_items[id] = item;
|
||||
|
||||
main_sizer->Add(item, 0, wxEXPAND | wxALL, FromDIP(12));
|
||||
if (id < 5)
|
||||
{
|
||||
wxPanel* separator = new wxPanel(this);
|
||||
separator->SetMaxSize(wxSize(-1, FromDIP(1)));
|
||||
separator->SetMinSize(wxSize(-1, FromDIP(1)));
|
||||
separator->SetBackgroundColour(wxColour(238, 238, 238));// Orca: grey300 spelled out as a literal RGB, since Orca has no equivalent grey-300 colour macro
|
||||
main_sizer->Add(separator, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(12));
|
||||
}
|
||||
}
|
||||
|
||||
main_sizer->AddSpacer(FromDIP(20));
|
||||
|
||||
// Set sizer
|
||||
this->SetSizer(main_sizer);
|
||||
this->Layout();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackUprade::UpdateRackInfo(const std::shared_ptr<DevNozzleRack> rack)
|
||||
{
|
||||
m_nozzle_rack = rack;
|
||||
if (!rack) { return;}
|
||||
|
||||
// update the nozzles
|
||||
m_extruder_nozzle_item->UpdateExtruderNozzleInfo(rack);
|
||||
for (auto iter : m_nozzle_items)
|
||||
{
|
||||
iter.second->UpdateRackNozzleInfo(rack);
|
||||
}
|
||||
|
||||
// update layout
|
||||
Layout();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackUprade::OnBtnReadAll(wxCommandEvent& e)
|
||||
{
|
||||
if (auto rack = m_nozzle_rack.lock())
|
||||
{
|
||||
rack->CtrlRackReadAll(true);
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackUprade::Rescale()
|
||||
{
|
||||
m_extruder_nozzle_item->Rescale();
|
||||
for (auto& iter : m_nozzle_items)
|
||||
{
|
||||
iter.second->Rescale();
|
||||
}
|
||||
}
|
||||
|
||||
#define WGT_DEVICE_NOZZLE_RACK_HOTEND_UPDATE_DEFAULT_BG *wxWHITE
|
||||
wgtDeviceNozzleRackHotendUpdate::wgtDeviceNozzleRackHotendUpdate(wxWindow* parent, const wxString& idx_text)
|
||||
: StaticBox(parent, wxID_ANY)
|
||||
{
|
||||
CreateGui();
|
||||
|
||||
m_idx_label->SetLabel(idx_text);
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackHotendUpdate::CreateGui()
|
||||
{
|
||||
SetBackgroundColour(WGT_DEVICE_NOZZLE_RACK_HOTEND_UPDATE_DEFAULT_BG);
|
||||
SetBorderColor(WGT_DEVICE_NOZZLE_RACK_HOTEND_UPDATE_DEFAULT_BG);
|
||||
SetCornerRadius(0);
|
||||
|
||||
//load nozzle hs image
|
||||
for (int i = 1; i <= 4; i++)
|
||||
{
|
||||
auto normalImage = new ScalableBitmap(this, "Nozzle_HS_01_0" + std::to_string(i * 2), 46);
|
||||
auto bigImage = new ScalableBitmap(this, "Big_Nozzle_HS_01_0" + std::to_string(i * 2), 216);
|
||||
nozzle_hs.push_back({normalImage, bigImage});
|
||||
}
|
||||
for (int i = 2; i <= 4; i++)
|
||||
{
|
||||
auto normalImage = new ScalableBitmap(this, "Nozzle_HH_01_0" + std::to_string(i * 2), 46);
|
||||
auto bigImage = new ScalableBitmap(this, "Big_Nozzle_HH_01_0" + std::to_string(i * 2), 216);
|
||||
nozzle_hh.push_back({normalImage, bigImage});
|
||||
}
|
||||
|
||||
auto* content_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
// Index
|
||||
m_idx_label = new Label(this);
|
||||
m_idx_label->SetFont(Label::Head_14);
|
||||
m_idx_label->SetBackgroundColour(WGT_DEVICE_NOZZLE_RACK_HOTEND_UPDATE_DEFAULT_BG);
|
||||
content_sizer->Add(m_idx_label, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(25));
|
||||
|
||||
// Icon
|
||||
wxPanel* imagePanel = new wxPanel(this);
|
||||
imagePanel->SetMaxSize(WX_DIP_SIZE(46, -1));
|
||||
imagePanel->SetMinSize(WX_DIP_SIZE(46, -1));
|
||||
imagePanel->SetSize(wxSize(FromDIP(46), FromDIP(-1)));
|
||||
wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL);
|
||||
imagePanel->SetSizer(panelSizer);
|
||||
|
||||
m_nozzle_empty_image = new ScalableBitmap(imagePanel, "dev_rack_nozzle_empty", 46);
|
||||
m_icon_bitmap = new wxStaticBitmap(imagePanel, wxID_ANY, m_nozzle_empty_image->bmp());
|
||||
panelSizer->Add(m_icon_bitmap, 0, wxALIGN_CENTER);
|
||||
content_sizer->Add(imagePanel, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(25));
|
||||
m_icon_bitmap->Bind(wxEVT_ENTER_WINDOW, &wgtDeviceNozzleRackHotendUpdate::OnBitmapHoverEnter, this);
|
||||
m_icon_bitmap->Bind(wxEVT_LEAVE_WINDOW, &wgtDeviceNozzleRackHotendUpdate::OnBitmapHoverLeave, this);
|
||||
|
||||
// Diameter/type (vertical)
|
||||
wxPanel* type_panel = new wxPanel(this);
|
||||
auto* main_type_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
auto* type_sizer_row_1 = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto* type_sizer_row_2 = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
m_material_label = new Label(type_panel);
|
||||
m_material_label->SetFont(Label::Body_12);
|
||||
m_material_label->SetBackgroundColour(WGT_DEVICE_NOZZLE_RACK_HOTEND_UPDATE_DEFAULT_BG);
|
||||
|
||||
m_colour_box = new StaticBox(type_panel);
|
||||
m_colour_box->SetMaxSize(WX_DIP_SIZE(16, 16));
|
||||
m_colour_box->SetMinSize(WX_DIP_SIZE(16, 16));
|
||||
m_colour_box->SetCornerRadius(FromDIP(2));
|
||||
m_colour_box->SetSize(wxSize(FromDIP(16), FromDIP(16)));
|
||||
|
||||
type_sizer_row_1->Add(m_colour_box, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
|
||||
type_sizer_row_1->AddStretchSpacer(1);
|
||||
type_sizer_row_1->Add(m_material_label, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(2));
|
||||
|
||||
m_diameter_label = new Label(type_panel);
|
||||
m_diameter_label->SetFont(Label::Body_12);
|
||||
m_diameter_label->SetBackgroundColour(WGT_DEVICE_NOZZLE_RACK_HOTEND_UPDATE_DEFAULT_BG);
|
||||
|
||||
m_flowtype_label = new Label(type_panel);
|
||||
m_flowtype_label->SetFont(Label::Body_12);
|
||||
m_flowtype_label->SetBackgroundColour(WGT_DEVICE_NOZZLE_RACK_HOTEND_UPDATE_DEFAULT_BG);
|
||||
|
||||
m_type_label = new Label(type_panel);
|
||||
m_type_label->SetFont(Label::Body_12);
|
||||
m_type_label->SetBackgroundColour(WGT_DEVICE_NOZZLE_RACK_HOTEND_UPDATE_DEFAULT_BG);
|
||||
|
||||
type_sizer_row_2->Add(m_diameter_label, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT );
|
||||
type_sizer_row_2->Add(m_flowtype_label, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(2));
|
||||
type_sizer_row_2->Add(m_type_label, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(2));
|
||||
|
||||
main_type_sizer->Add(type_sizer_row_1, 0, wxALIGN_LEFT);
|
||||
main_type_sizer->Add(type_sizer_row_2, 1, wxALIGN_LEFT | wxEXPAND | wxTOP, FromDIP(4));
|
||||
type_panel->SetSizer(main_type_sizer);
|
||||
type_panel->SetMaxSize(WX_DIP_SIZE(160, 40));
|
||||
type_panel->SetMinSize(WX_DIP_SIZE(160, 40));
|
||||
type_panel->SetSize(WX_DIP_SIZE(160, 40));
|
||||
|
||||
content_sizer->Add(type_panel, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(12));
|
||||
|
||||
// SN and version (vertical)
|
||||
wxPanel* info_panel = new wxPanel(this);
|
||||
auto* info_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
m_sn_label = new Label(info_panel);
|
||||
m_sn_label->SetFont(Label::Body_12);
|
||||
m_sn_label->SetBackgroundColour(WGT_DEVICE_NOZZLE_RACK_HOTEND_UPDATE_DEFAULT_BG);
|
||||
|
||||
auto* version_h_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_version_label = new Label(info_panel);
|
||||
m_version_label->SetFont(Label::Body_12);
|
||||
m_version_label->SetBackgroundColour(WGT_DEVICE_NOZZLE_RACK_HOTEND_UPDATE_DEFAULT_BG);
|
||||
|
||||
m_version_new_label = new Label(info_panel);
|
||||
m_version_new_label->SetFont(Label::Body_12);
|
||||
m_version_new_label->SetBackgroundColour(WGT_DEVICE_NOZZLE_RACK_HOTEND_UPDATE_DEFAULT_BG);
|
||||
m_version_new_label->SetForegroundColour(wxColour(0, 168, 84)); // Green
|
||||
|
||||
version_h_sizer->Add(m_version_label, 0, wxALIGN_CENTER_VERTICAL);
|
||||
version_h_sizer->Add(m_version_new_label, 0, wxALIGN_CENTER_VERTICAL);
|
||||
info_sizer->Add(m_sn_label, 0, wxALIGN_LEFT);
|
||||
info_sizer->Add(version_h_sizer, 0, wxALIGN_LEFT | wxTOP, FromDIP(4));
|
||||
info_panel->SetSizer(info_sizer);
|
||||
info_panel->SetMaxSize(WX_DIP_SIZE(183, 40));
|
||||
info_panel->SetMinSize(WX_DIP_SIZE(183, 40));
|
||||
info_panel->SetSize(WX_DIP_SIZE(183, 40));
|
||||
|
||||
//Used Time
|
||||
m_used_time = new Label(this);
|
||||
m_used_time->SetFont(Label::Body_12);
|
||||
m_used_time->SetBackgroundColour(WGT_DEVICE_NOZZLE_RACK_HOTEND_UPDATE_DEFAULT_BG);
|
||||
|
||||
m_refresh_icon = new ScalableBitmap(this, "refresh_printer", 12);
|
||||
m_error_icon = new ScalableBitmap(this, "error", 14);
|
||||
m_status_bitmap = new wxStaticBitmap(this, wxID_ANY, m_refresh_icon->bmp());
|
||||
m_status_bitmap->Bind(wxEVT_LEFT_UP, &wgtDeviceNozzleRackHotendUpdate::OnStatusIconClick, this);
|
||||
|
||||
std::vector<std::string> list{"refresh_nozzle_1", "refresh_nozzle_2", "refresh_nozzle_3", "refresh_nozzle_4"};
|
||||
// Orca: AnimaIcon has no per-instance size argument (it fixes 25px internally), so no size is
|
||||
// passed here.
|
||||
m_refreshing_icon = new AnimaIcon(this, wxID_ANY, list, "refresh_nozzle", 100);
|
||||
m_refreshing_icon->Show(false);
|
||||
|
||||
|
||||
m_status_label = new Label(this);
|
||||
m_status_label->SetFont(Label::Body_12);
|
||||
|
||||
content_sizer->Add(info_panel, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(20));
|
||||
content_sizer->Add(m_used_time, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(20));
|
||||
content_sizer->Add(m_status_label, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(20));
|
||||
content_sizer->Add(m_status_bitmap, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(2));
|
||||
content_sizer->Add(m_refreshing_icon, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(2));
|
||||
content_sizer->AddSpacer(FromDIP(25));
|
||||
|
||||
auto* main_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
main_sizer->Add(content_sizer, 0, wxEXPAND | wxTOP | wxBOTTOM, FromDIP(10));
|
||||
|
||||
SetSizer(main_sizer);
|
||||
Layout();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackHotendUpdate::OnStatusIconClick(wxMouseEvent& event)
|
||||
{
|
||||
if (m_status_label->GetLabel() == _L("Refresh"))
|
||||
{
|
||||
m_status_label->SetForegroundColour(wxColour("#A3A3A3"));
|
||||
m_status_label->SetLabel(_L("Refreshing"));
|
||||
m_status_bitmap->Show(false);
|
||||
if(!m_refreshing_icon->IsPlaying())
|
||||
{
|
||||
m_refreshing_icon->Play();
|
||||
m_refreshing_icon->Show();
|
||||
}
|
||||
if (auto shared = m_nozzle_rack.lock())
|
||||
{
|
||||
shared->CrtlRackReadNozzle(m_rack_nozzle_id);
|
||||
}
|
||||
Layout();
|
||||
}
|
||||
|
||||
if (m_status_label->GetLabel() == _L("Error") /*&& m_nozzle_status == NOZZLE_STATUS_ABNORMAL*/)
|
||||
{
|
||||
if (auto shared = m_nozzle_rack.lock())
|
||||
{
|
||||
MessageDialog dlg(nullptr, _L("Hotend status abnormal, unavailable at present. Please upgrade the firmware"
|
||||
" and try again."), _L("Update"), wxICON_WARNING);
|
||||
dlg.AddButton(wxID_CANCEL, _L("Cancel"), false);
|
||||
dlg.AddButton(wxID_OK,_L("Jump to the upgrade page"), true);
|
||||
|
||||
if (dlg.ShowModal() == wxID_OK)
|
||||
{
|
||||
wxGetApp().mainframe->m_monitor->jump_to_Upgrade();
|
||||
|
||||
wxCommandEvent evt(wxEVT_NOZZLE_JUMP_UPGRADE, GetId());
|
||||
evt.SetEventObject(this);
|
||||
wxWindow* target = GetParent();
|
||||
if (target)
|
||||
{
|
||||
target = target->GetParent();
|
||||
if (target)
|
||||
{
|
||||
wxPostEvent(target, evt);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackHotendUpdate::OnBitmapHoverEnter(wxMouseEvent& event)
|
||||
{
|
||||
int scaledW = FromDIP(240);
|
||||
int scaledH = FromDIP(240);
|
||||
|
||||
ScalableBitmap* scaledBmp{nullptr};
|
||||
if (m_nozzle_status == NOZZLE_STATUS_EMPTY || m_nozzle_status == NOZZLE_STATUS_UNKNOWN || !findNozzleImage)
|
||||
{
|
||||
if (!m_scaled_nozzle_empty_image) {m_scaled_nozzle_empty_image = new ScalableBitmap(this, "dev_rack_nozzle_empty", 216);}
|
||||
|
||||
scaledBmp = m_scaled_nozzle_empty_image;
|
||||
}
|
||||
else
|
||||
{
|
||||
scaledBmp = m_scaled_nozzle_image;
|
||||
}
|
||||
|
||||
m_hoverFrame = new wxFrame(nullptr, wxID_ANY, "",
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
wxFRAME_NO_TASKBAR | wxBORDER_NONE | wxTRANSPARENT_WINDOW);
|
||||
m_hoverFrame->SetBackgroundColour(WGT_DEVICE_NOZZLE_RACK_HOTEND_UPDATE_DEFAULT_BG);
|
||||
m_hoverFrame->SetSize(scaledW, scaledH);
|
||||
wxBoxSizer* frameSizer = new wxBoxSizer(wxVERTICAL);
|
||||
m_hoverFrame->SetSizer(frameSizer);
|
||||
|
||||
wxStaticBitmap* hoverBmp = new wxStaticBitmap(m_hoverFrame, wxID_ANY, scaledBmp->bmp());
|
||||
frameSizer->Add(hoverBmp, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP | wxBOTTOM, FromDIP(12));
|
||||
|
||||
wxPoint mousePos = wxGetMousePosition();
|
||||
m_hoverFrame->SetPosition(wxPoint(mousePos.x + 10, mousePos.y));
|
||||
m_hoverFrame->Layout();
|
||||
m_hoverFrame->Show(true);
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackHotendUpdate::OnBitmapHoverLeave(wxMouseEvent& event)
|
||||
{
|
||||
if (m_hoverFrame)
|
||||
{
|
||||
m_hoverFrame->Destroy();
|
||||
m_hoverFrame = nullptr;
|
||||
}
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackHotendUpdate::updateNozzleImage(const DevNozzle& nozzle)
|
||||
{
|
||||
if (m_nozzle_status == NOZZLE_STATUS_UNKNOWN || m_nozzle_status == NOZZLE_STATUS_EMPTY)
|
||||
{
|
||||
if (!m_nozzle_empty_image) {m_nozzle_empty_image = new ScalableBitmap(this, "dev_rack_nozzle_empty", 46);}
|
||||
m_icon_bitmap->SetBitmap(m_nozzle_empty_image->bmp());
|
||||
m_icon_bitmap->Refresh();
|
||||
return;
|
||||
}
|
||||
findNozzleImage = false;
|
||||
int index = -1;
|
||||
switch (nozzle.GetNozzleDiameterType()) {
|
||||
case NOZZLE_DIAMETER_0_2: index = 0; break;
|
||||
case NOZZLE_DIAMETER_0_4: index = 1; break;
|
||||
case NOZZLE_DIAMETER_0_6: index = 2; break;
|
||||
case NOZZLE_DIAMETER_0_8: index = 3; break;
|
||||
default: index = -1; break;
|
||||
}
|
||||
NozzleType nozzleType = nozzle.GetNozzleType();
|
||||
if (nozzleType == ntHardenedSteel || nozzleType == ntStainlessSteel)
|
||||
{
|
||||
if (nozzle.GetNozzleFlowType() == H_FLOW && index >= 1)
|
||||
{
|
||||
m_nozzle_image = nozzle_hh[index - 1][0];
|
||||
m_icon_bitmap->SetBitmap(m_nozzle_image->bmp());
|
||||
m_scaled_nozzle_image = nozzle_hh[index - 1][1];
|
||||
findNozzleImage = true;
|
||||
}
|
||||
else if (nozzle.GetNozzleFlowType() == S_FLOW && index >= 0)
|
||||
{
|
||||
m_nozzle_image = nozzle_hs[index][0];
|
||||
m_icon_bitmap->SetBitmap(m_nozzle_image->bmp());
|
||||
m_scaled_nozzle_image = nozzle_hs[index][1];
|
||||
findNozzleImage = true;
|
||||
}
|
||||
}
|
||||
if (!findNozzleImage)
|
||||
{
|
||||
if (!m_nozzle_empty_image) {m_nozzle_empty_image = new ScalableBitmap(this, "dev_rack_nozzle_empty", 46);}
|
||||
m_icon_bitmap->SetBitmap(m_nozzle_empty_image->bmp());
|
||||
}
|
||||
m_icon_bitmap->Refresh();
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackHotendUpdate::UpdateColourStyle(const wxColour& clr)
|
||||
{
|
||||
SetBackgroundColour(clr);
|
||||
SetBorderColor(clr);
|
||||
|
||||
// BFS: Update all children background color
|
||||
auto children = GetChildren();
|
||||
while (!children.IsEmpty())
|
||||
{
|
||||
auto win = children.front();
|
||||
children.pop_front();
|
||||
win->SetBackgroundColour(clr);
|
||||
|
||||
for (auto child : win->GetChildren())
|
||||
{
|
||||
children.push_back(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackHotendUpdate::UpdateExtruderNozzleInfo(const std::shared_ptr<DevNozzleRack> rack)
|
||||
{
|
||||
m_nozzle_rack = rack;
|
||||
if (rack)
|
||||
{
|
||||
DevNozzleSystem* nozzle_system = rack->GetNozzleSystem();
|
||||
if (nozzle_system)
|
||||
{
|
||||
UpdateInfo(nozzle_system->GetExtNozzle(m_ext_nozzle_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackHotendUpdate::UpdateRackNozzleInfo(const std::shared_ptr<DevNozzleRack> rack)
|
||||
{
|
||||
m_nozzle_rack = rack;
|
||||
if (rack)
|
||||
{
|
||||
UpdateInfo(rack->GetNozzle(m_rack_nozzle_id));
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackHotendUpdate::UpdateInfo(const DevNozzle& nozzle)
|
||||
{
|
||||
/*update nozzle possition and background*/
|
||||
if (auto share = m_nozzle_rack.lock())
|
||||
{
|
||||
// if (share->GetReadingCount() > 0 && m_status_label->IsShown())
|
||||
if (share->GetReadingCount() > 0 && m_status_label->IsShown() && m_status_label->GetLabel() == _L("Refreshing"))
|
||||
{
|
||||
m_refreshing_icon->Play();
|
||||
m_refreshing_icon->Show();
|
||||
m_nozzle_status = NOZZLE_STATUS_DC;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_refreshing_icon->Stop();
|
||||
m_refreshing_icon->Show(false);
|
||||
}
|
||||
}
|
||||
|
||||
wxString filamentDisplayName{};
|
||||
for (auto iter = GUI::wxGetApp().preset_bundle->filaments.begin(); iter != GUI::wxGetApp().preset_bundle->filaments.end(); ++iter)
|
||||
{
|
||||
const Preset& filament_preset = *iter;
|
||||
// const auto& config = filament_preset.config;
|
||||
if (filament_preset.filament_id == nozzle.GetFilamentId())
|
||||
{
|
||||
filamentDisplayName = wxString(filament_preset.alias);
|
||||
}
|
||||
}
|
||||
|
||||
if (nozzle.IsEmpty() && m_nozzle_status != NOZZLE_STATUS_EMPTY)
|
||||
{
|
||||
m_nozzle_status = NOZZLE_STATUS_EMPTY;
|
||||
|
||||
m_material_label->Show(false);
|
||||
m_colour_box->Show(false);
|
||||
|
||||
m_diameter_label->Show(false);
|
||||
m_flowtype_label->Show(false);
|
||||
m_type_label->SetLabel(_L("Empty"));
|
||||
m_type_label->SetForegroundColour(StateColor::darkModeColorFor(*wxBLACK));
|
||||
|
||||
m_sn_label->Show(false);
|
||||
m_version_label->Show(false);
|
||||
m_version_new_label->Show(false);
|
||||
|
||||
updateNozzleImage(nozzle);
|
||||
|
||||
m_used_time->Show(false);
|
||||
m_status_label->Show(false);
|
||||
m_status_bitmap->Show(false);
|
||||
|
||||
}
|
||||
else if (nozzle.IsNormal() && m_nozzle_status != NOZZLE_STATUS_NORMAL)
|
||||
{
|
||||
m_nozzle_status = NOZZLE_STATUS_NORMAL;
|
||||
|
||||
m_material_label->SetLabel(filamentDisplayName);
|
||||
m_colour_box->SetBackgroundColour(wxColour("#" + nozzle.GetFilamentColor()));
|
||||
m_colour_box->SetBorderColor(wxColour("#" + nozzle.GetFilamentColor()));
|
||||
m_material_label->Show(true);
|
||||
m_colour_box->Show(true);
|
||||
|
||||
m_diameter_label->Show(true);
|
||||
m_flowtype_label->Show(true);
|
||||
m_diameter_label->SetLabel(nozzle.GetNozzleDiameterStr());
|
||||
m_flowtype_label->SetLabel(nozzle.GetNozzleFlowTypeStr());
|
||||
m_type_label->SetLabel(nozzle.GetNozzleTypeStr());
|
||||
m_type_label->SetForegroundColour(StateColor::darkModeColorFor(*wxBLACK));
|
||||
|
||||
m_sn_label->Show(true);
|
||||
m_version_label->Show(true);
|
||||
|
||||
updateNozzleImage(nozzle);
|
||||
|
||||
m_used_time->Show(true);
|
||||
m_status_label->Show(false);
|
||||
m_status_bitmap->Show(false);
|
||||
}
|
||||
else if (nozzle.IsAbnormal() && m_nozzle_status != NOZZLE_STATUS_ABNORMAL)
|
||||
{
|
||||
m_nozzle_status = NOZZLE_STATUS_ABNORMAL;
|
||||
|
||||
m_material_label->SetLabel(filamentDisplayName);
|
||||
m_colour_box->SetBackgroundColour(wxColour("#" + nozzle.GetFilamentColor()));
|
||||
m_colour_box->SetBorderColor(wxColour("#" + nozzle.GetFilamentColor()));
|
||||
m_material_label->Show(true);
|
||||
m_colour_box->Show(true);
|
||||
|
||||
m_diameter_label->Show(true);
|
||||
m_flowtype_label->Show(true);
|
||||
m_diameter_label->SetLabel(nozzle.GetNozzleDiameterStr());
|
||||
m_flowtype_label->SetLabel(nozzle.GetNozzleFlowTypeStr());
|
||||
m_type_label->SetLabel(nozzle.GetNozzleTypeStr());
|
||||
m_type_label->SetForegroundColour(StateColor::darkModeColorFor(*wxBLACK));
|
||||
|
||||
updateNozzleImage(nozzle);
|
||||
|
||||
m_status_label->Show(true);
|
||||
m_status_bitmap->Show(true);
|
||||
m_status_label->SetForegroundColour(StateColor::darkModeColorFor(wxColour("#E14747")));
|
||||
m_status_label->SetLabel(_L("Error"));
|
||||
m_status_bitmap->SetBitmap(m_error_icon->bmp());
|
||||
m_status_bitmap->Refresh();
|
||||
}
|
||||
else if (nozzle.IsUnknown() && m_nozzle_status != NOZZLE_STATUS_UNKNOWN)
|
||||
{
|
||||
m_nozzle_status = NOZZLE_STATUS_UNKNOWN;
|
||||
|
||||
m_colour_box->Show(false);
|
||||
m_material_label->SetLabel(wxString("--"));
|
||||
m_material_label->Show(true);
|
||||
|
||||
m_diameter_label->Show(false);
|
||||
m_flowtype_label->Show(false);
|
||||
m_type_label->SetLabel(_L("Unknown"));
|
||||
m_type_label->SetForegroundColour(StateColor::darkModeColorFor(*wxBLACK));
|
||||
|
||||
m_sn_label->Show(true);
|
||||
m_version_label->Show(true);
|
||||
|
||||
updateNozzleImage(nozzle);
|
||||
|
||||
m_used_time->Show(true);
|
||||
m_status_label->Show(true);
|
||||
m_status_bitmap->Show(true);
|
||||
m_status_label->SetForegroundColour(wxColour("#00AE42"));
|
||||
m_status_label->SetLabel(_L("Refresh"));
|
||||
m_status_bitmap->SetBitmap(m_refresh_icon->bmp());
|
||||
m_status_bitmap->Refresh();
|
||||
}
|
||||
|
||||
// Update firmware info
|
||||
const DevFirmwareVersionInfo& firmware = nozzle.GetFirmwareInfo();
|
||||
if (nozzle.IsUnknown())
|
||||
{
|
||||
m_sn_label->SetLabel(wxString::Format("%s: --", _L("SN")));
|
||||
m_version_label->SetLabel(wxString::Format("%s: --", _L("Version")));
|
||||
m_version_new_label->Show(false);
|
||||
}
|
||||
if (nozzle.IsNormal() || nozzle.IsAbnormal())
|
||||
{
|
||||
if (firmware.isValid())
|
||||
{
|
||||
m_sn_label->SetLabel(wxString::Format("%s: %s", _L("SN"), firmware.sn));
|
||||
|
||||
if (!firmware.sw_new_ver.empty() && firmware.sw_new_ver != firmware.sw_ver)
|
||||
{
|
||||
m_version_label->SetLabel(wxString::Format("%s: %s > ", _L("Version"), firmware.sw_ver));
|
||||
m_version_new_label->SetLabel(wxString::Format("%s", firmware.sw_new_ver));
|
||||
m_version_new_label->Show(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_version_label->SetLabel(wxString::Format("%s:%s", _L("Version"), firmware.sw_ver));
|
||||
m_version_new_label->Show(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sn_label->SetLabel(wxString::Format("%s: --", _L("SN")));
|
||||
m_version_label->SetLabel(wxString::Format("%s: --", _L("Version")));
|
||||
m_version_new_label->Show(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!nozzle.IsEmpty())
|
||||
{
|
||||
if (nozzle.IsUnknown())
|
||||
{
|
||||
m_used_time->SetLabel(wxString::Format(_L("Used Time: %s"), "--h"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update used time
|
||||
int usedSeconds = nozzle.GetNozzlePrintTime();
|
||||
if (usedSeconds < 60)
|
||||
{
|
||||
m_used_time->SetLabel(wxString::Format(_L("Used Time: %s"), "0 h"));
|
||||
}
|
||||
else
|
||||
{
|
||||
int printTime = (usedSeconds >= 3600 ? usedSeconds / 3600 : usedSeconds / 60);
|
||||
std::string printTimeStr = (usedSeconds >= 3600 ? std::to_string(printTime) + " h" : std::to_string(printTime) + " min");
|
||||
m_used_time->SetLabel(wxString::Format(_L("Used Time: %s"), printTimeStr.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackHotendUpdate::Rescale()
|
||||
{
|
||||
// update images
|
||||
if (m_nozzle_image) { m_nozzle_image->msw_rescale(); }
|
||||
if (m_nozzle_empty_image) { m_nozzle_empty_image->msw_rescale(); }
|
||||
if (m_nozzle_status == NOZZLE_STATUS_EMPTY && m_nozzle_empty_image)
|
||||
{
|
||||
m_icon_bitmap->SetBitmap(m_nozzle_empty_image->bmp());
|
||||
}
|
||||
else if (m_nozzle_image != nullptr)
|
||||
{
|
||||
m_icon_bitmap->SetBitmap(m_nozzle_image->bmp());
|
||||
}
|
||||
m_icon_bitmap->Refresh();
|
||||
}
|
||||
|
||||
};// namespace Slic3r::GUI
|
||||
@@ -0,0 +1,175 @@
|
||||
//**********************************************************/
|
||||
/* File: wgtDeviceNozzleRackUpdate.h
|
||||
* Description: The dialog for reading/upgrading the H2C induction-hotend-rack firmware.
|
||||
*
|
||||
* \n class wgtDeviceNozzleRackUpgradeDlg; // modal "Hotends Info" dialog
|
||||
* \n class wgtDeviceNozzleRackUprade; // the dialog's content panel (per-nozzle rows)
|
||||
* \n class wgtDeviceNozzleRackHotendUpdate; // one hotend row (toolhead "R" + rack 1..6)
|
||||
*
|
||||
* Opened from the Device-tab rack panel's "Hotends Info" button (wgtDeviceNozzleRack.cpp) and
|
||||
* reused by the Device->Upgrade page "Hotends on Rack" section
|
||||
* (UpgradePanel::createNozzleRackWidgets). All device data + MQTT commands live in
|
||||
* DevNozzleRack / DevNozzleSystem, so this is additive GUI gated behind
|
||||
* DevNozzleRack::IsSupported() — dormant for every non-rack printer.
|
||||
//**********************************************************/
|
||||
|
||||
#pragma once
|
||||
#include "slic3r/GUI/DeviceCore/DevNozzleRack.h"
|
||||
|
||||
#include "slic3r/GUI/GUI_Utils.hpp"
|
||||
#include "slic3r/GUI/Widgets/StaticBox.hpp"
|
||||
#include "slic3r/GUI/Widgets/AnimaController.hpp"
|
||||
|
||||
#include <wx/panel.h>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
// Previous definitions
|
||||
class Button;
|
||||
class Label;
|
||||
class ScalableBitmap;
|
||||
class ScalableButton;
|
||||
namespace Slic3r
|
||||
{
|
||||
struct DevNozzle;
|
||||
class DevNozzleRack;
|
||||
namespace GUI
|
||||
{
|
||||
class wgtDeviceNozzleRackUprade;
|
||||
class wgtDeviceNozzleRackHotendUpdate;
|
||||
}
|
||||
};
|
||||
|
||||
namespace Slic3r::GUI
|
||||
{
|
||||
class wgtDeviceNozzleRackUpgradeDlg : public DPIDialog
|
||||
{
|
||||
public:
|
||||
wgtDeviceNozzleRackUpgradeDlg(wxWindow* parent, const std::shared_ptr<DevNozzleRack> rack);
|
||||
|
||||
public:
|
||||
void UpdateRackInfo(const std::shared_ptr<DevNozzleRack> rack);
|
||||
|
||||
public:
|
||||
void on_dpi_changed(const wxRect& suggested_rect) override;
|
||||
|
||||
private:
|
||||
wgtDeviceNozzleRackUprade* m_rack_upgrade_panel;
|
||||
};
|
||||
|
||||
|
||||
class wgtDeviceNozzleRackUprade : public wxPanel
|
||||
{
|
||||
public:
|
||||
wgtDeviceNozzleRackUprade(wxWindow* parent,
|
||||
wxWindowID id = wxID_ANY,
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = wxTAB_TRAVERSAL);
|
||||
~wgtDeviceNozzleRackUprade() = default;
|
||||
|
||||
public:
|
||||
void UpdateRackInfo(const std::shared_ptr<DevNozzleRack> rack);
|
||||
void Rescale();
|
||||
|
||||
private:
|
||||
void CreateGui();
|
||||
|
||||
void OnBtnReadAll(wxCommandEvent& e);
|
||||
|
||||
private:
|
||||
std::weak_ptr<DevNozzleRack> m_nozzle_rack;
|
||||
|
||||
// GUI
|
||||
wgtDeviceNozzleRackHotendUpdate* m_extruder_nozzle_item;
|
||||
std::unordered_map<int, wgtDeviceNozzleRackHotendUpdate*> m_nozzle_items;
|
||||
};
|
||||
|
||||
// Using for rack nozzle id or extruder nozzle id
|
||||
class wgtDeviceNozzleRackHotendUpdate : public StaticBox
|
||||
{
|
||||
public:
|
||||
wgtDeviceNozzleRackHotendUpdate(wxWindow* parent, const wxString& idx_text);
|
||||
|
||||
public:
|
||||
// Color
|
||||
void UpdateColourStyle(const wxColour& clr);
|
||||
|
||||
// extruder nozzle
|
||||
int GetExtruderNozzleId() const { return m_ext_nozzle_id; }
|
||||
void SetExtruderNozzleId(int ext_nozzle_id) { m_ext_nozzle_id = ext_nozzle_id; }
|
||||
void UpdateExtruderNozzleInfo(const std::shared_ptr<DevNozzleRack> rack);
|
||||
|
||||
// rack nozzle
|
||||
void SetRackNozzleId(int rack_nozzle_id) { m_rack_nozzle_id = rack_nozzle_id; }
|
||||
int GetRackNozzleId() const { return m_rack_nozzle_id; }
|
||||
void UpdateRackNozzleInfo(const std::shared_ptr<DevNozzleRack> rack);
|
||||
|
||||
// gui
|
||||
void Rescale();
|
||||
|
||||
private:
|
||||
void CreateGui();
|
||||
|
||||
void UpdateInfo(const DevNozzle& nozzle);
|
||||
|
||||
void OnBitmapHoverEnter(wxMouseEvent& event);
|
||||
void OnBitmapHoverLeave(wxMouseEvent& event);
|
||||
void OnStatusIconClick(wxMouseEvent& event);
|
||||
void updateNozzleImage(const DevNozzle& nozzle);
|
||||
|
||||
private:
|
||||
enum NozzleStatus : int
|
||||
{
|
||||
NOZZLE_STATUS_DC = -1,
|
||||
NOZZLE_STATUS_EMPTY,
|
||||
NOZZLE_STATUS_NORMAL,
|
||||
NOZZLE_STATUS_ABNORMAL,
|
||||
NOZZLE_STATUS_UNKNOWN,
|
||||
};
|
||||
|
||||
private:
|
||||
int m_ext_nozzle_id = -1;
|
||||
int m_rack_nozzle_id = -1;
|
||||
bool m_isRefreshFinish = false;
|
||||
bool findNozzleImage = false;
|
||||
|
||||
NozzleStatus m_nozzle_status = NOZZLE_STATUS_DC;
|
||||
std::weak_ptr<DevNozzleRack> m_nozzle_rack;
|
||||
|
||||
std::vector<std::vector<ScalableBitmap*>> nozzle_hs;
|
||||
std::vector<std::vector<ScalableBitmap*>> nozzle_hh;
|
||||
// GUI
|
||||
ScalableBitmap* m_nozzle_image = nullptr;
|
||||
ScalableBitmap* m_nozzle_empty_image = nullptr;
|
||||
ScalableBitmap* m_scaled_nozzle_image = nullptr;
|
||||
ScalableBitmap* m_scaled_nozzle_empty_image = nullptr;
|
||||
ScalableBitmap* m_refresh_icon = nullptr;
|
||||
AnimaIcon* m_refreshing_icon = nullptr;
|
||||
ScalableBitmap* m_error_icon = nullptr;
|
||||
|
||||
Label* m_idx_label;
|
||||
wxStaticBitmap* m_icon_bitmap{ nullptr };
|
||||
wxStaticBitmap* m_status_bitmap{ nullptr };
|
||||
|
||||
Label* m_material_label{ nullptr };
|
||||
StaticBox* m_colour_box{ nullptr };
|
||||
wxFrame* m_hoverFrame{ nullptr };
|
||||
|
||||
Label* m_status_label{ nullptr };
|
||||
Label* m_used_time{ nullptr };
|
||||
|
||||
Label* m_diameter_label;
|
||||
Label* m_flowtype_label;
|
||||
Label* m_type_label;
|
||||
ScalableButton* m_error_button{ nullptr };
|
||||
|
||||
Label* m_sn_label;
|
||||
Label* m_version_label;
|
||||
Label* m_version_new_label;
|
||||
};
|
||||
|
||||
wxDECLARE_EVENT(wxEVT_NOZZLE_JUMP_UPGRADE, wxCommandEvent);
|
||||
|
||||
};// end of namespace Slic3r::GUI
|
||||
@@ -0,0 +1,289 @@
|
||||
//**********************************************************/
|
||||
/* File: wgtDeviceNozzleSelect.cpp
|
||||
* Description: The panel to select nozzle
|
||||
*
|
||||
* \n class wgtDeviceNozzleSelect;
|
||||
//**********************************************************/
|
||||
|
||||
#include "wgtDeviceNozzleSelect.h"
|
||||
#include "wgtDeviceNozzleRackNozzleItem.h" // the nozzle-item widget lives in its own header
|
||||
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/DeviceTab/wgtMsgBox.h"
|
||||
#include "slic3r/GUI/Widgets/Label.hpp"
|
||||
|
||||
static wxColour s_gray_clr("#B0B0B0");
|
||||
static wxColour s_hgreen_clr("#00AE42");
|
||||
static wxColour s_red_clr("#D01B1B");
|
||||
|
||||
static std::vector<int> a_nozzle_seq = {16, 18, 20, 17, 19, 21};
|
||||
|
||||
wxDEFINE_EVENT(EVT_NOZZLE_SELECT_CHANGED, wxCommandEvent);
|
||||
wxDEFINE_EVENT(EVT_NOZZLE_SELECT_CLICKED, wxCommandEvent);
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
wgtDeviceNozzleRackSelect::wgtDeviceNozzleRackSelect(wxWindow *parent) : wxPanel(parent, wxID_ANY) { CreateGui(); }
|
||||
|
||||
static wxPanel* s_create_title(wxWindow *parent, const wxString& text)
|
||||
{
|
||||
wxPanel *panel = new wxPanel(parent, wxID_ANY);
|
||||
|
||||
auto title = new Label(panel, text);
|
||||
title->SetFont(::Label::Body_13);
|
||||
title->SetBackgroundColour(*wxWHITE);
|
||||
title->SetForegroundColour(0x909090);
|
||||
|
||||
auto split_line = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
split_line->SetBackgroundColour(0xeeeeee);
|
||||
split_line->SetMinSize(wxSize(-1, 1));
|
||||
split_line->SetMaxSize(wxSize(-1, 1));
|
||||
|
||||
wxBoxSizer *sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(0, 0, 0, wxEXPAND, 0);
|
||||
sizer->Add(title, 0, wxALIGN_CENTER, 0);
|
||||
sizer->Add(split_line, 1, wxALIGN_CENTER_VERTICAL | wxEXPAND, 0);
|
||||
panel->SetSizer(sizer);
|
||||
panel->Layout();
|
||||
return panel;
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackSelect::CreateGui()
|
||||
{
|
||||
wxSizer *main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
wxColour tip_bg_clr("#FFF0E0");
|
||||
m_title_tips_dynamic = new wgtMsgBox(this);
|
||||
m_title_tips_dynamic->SetBackgroundColour(tip_bg_clr);
|
||||
m_title_tips_dynamic->SetBorderColor(wxColour("#FF6F00"));
|
||||
m_title_tips_dynamic->SetCornerRadius(1);
|
||||
m_title_tips_dynamic->SetBorderWidth(1);
|
||||
auto text_label = m_title_tips_dynamic->GetTextLabel();
|
||||
text_label->SetFont(::Label::Body_12);
|
||||
text_label->SetForegroundColour("#FF6F00");
|
||||
text_label->SetBackgroundColour(tip_bg_clr);
|
||||
text_label->SetLabel(_L("Dynamic nozzles are allocated on the current plate. Picking hotend is not supported."));
|
||||
text_label->Wrap(FromDIP(300));
|
||||
text_label->Fit();
|
||||
m_title_tips_dynamic->Layout();
|
||||
m_title_tips_dynamic->Refresh();
|
||||
|
||||
// nozzles
|
||||
wxGridSizer *nozzle_sizer = new wxGridSizer(2, 3, FromDIP(10), FromDIP(10));
|
||||
for (auto idx : a_nozzle_seq) {
|
||||
wgtDeviceNozzleRackNozzleItem *nozzle_item = new wgtDeviceNozzleRackNozzleItem(this, idx - 16);
|
||||
nozzle_item->EnableSelect();
|
||||
nozzle_item->Bind(EVT_NOZZLE_RACK_NOZZLE_ITEM_SELECTED, &wgtDeviceNozzleRackSelect::OnNozzleItemSelected, this);
|
||||
m_nozzle_items[idx] = nozzle_item;
|
||||
nozzle_sizer->Add(nozzle_item, 0);
|
||||
}
|
||||
|
||||
// toolhead area
|
||||
m_toolhead_nozzle_l = new wgtDeviceNozzleRackNozzleItem(this, 1);
|
||||
m_toolhead_nozzle_l->EnableSelect();
|
||||
m_toolhead_nozzle_l->SetDisplayIdText("L");
|
||||
m_toolhead_nozzle_l->Bind(EVT_NOZZLE_RACK_NOZZLE_ITEM_SELECTED, &wgtDeviceNozzleRackSelect::OnNozzleItemSelected, this);
|
||||
|
||||
m_toolhead_nozzle_r = new wgtDeviceNozzleRackNozzleItem(this, 0);
|
||||
m_toolhead_nozzle_r->EnableSelect();
|
||||
m_toolhead_nozzle_r->SetDisplayIdText("R");
|
||||
m_toolhead_nozzle_r->Bind(EVT_NOZZLE_RACK_NOZZLE_ITEM_SELECTED, &wgtDeviceNozzleRackSelect::OnNozzleItemSelected, this);
|
||||
|
||||
wxSizer* toolhead_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
toolhead_sizer->Add(m_toolhead_nozzle_l, 0, wxRIGHT, FromDIP(5));
|
||||
toolhead_sizer->Add(m_toolhead_nozzle_r, 0, wxLEFT, FromDIP(5));
|
||||
|
||||
main_sizer->Add(m_title_tips_dynamic, 0, wxALIGN_CENTRE_VERTICAL | wxBOTTOM, FromDIP(10));
|
||||
main_sizer->Add(s_create_title(this, _L("Hotend Rack")), 0, wxEXPAND);
|
||||
main_sizer->Add(nozzle_sizer, 0, wxTOP | wxBOTTOM | wxALIGN_LEFT, FromDIP(10));
|
||||
main_sizer->Add(s_create_title(this, _L("ToolHead")), 0, wxEXPAND);
|
||||
main_sizer->AddSpacer(FromDIP(10));
|
||||
main_sizer->Add(toolhead_sizer, 0, wxALIGN_LEFT);
|
||||
|
||||
SetBackgroundColour(*wxWHITE);
|
||||
SetSizer(main_sizer);
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
|
||||
static void s_update_nozzle_info(wgtDeviceNozzleRackNozzleItem* item,
|
||||
std::shared_ptr<DevNozzleRack> rack,
|
||||
const DevNozzle& nozzle_info)
|
||||
{
|
||||
item->Update(rack, nozzle_info.IsOnRack());
|
||||
if (nozzle_info.IsUnknown()) {
|
||||
if (item->GetToolTipText() != _L("Nozzle information needs to be read")) {
|
||||
item->SetToolTip(_L("Nozzle information needs to be read"));
|
||||
}
|
||||
} else {
|
||||
item->SetToolTip(wxEmptyString);
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackSelect::UpdateNozzleInfos(std::shared_ptr<DevNozzleRack> rack)
|
||||
{
|
||||
m_nozzle_rack = rack;
|
||||
if (rack) {
|
||||
s_update_nozzle_info(m_toolhead_nozzle_l, rack, rack->GetNozzleSystem()->GetNozzleByPosId(DEPUTY_EXTRUDER_ID));
|
||||
s_update_nozzle_info(m_toolhead_nozzle_r, rack, rack->GetNozzleSystem()->GetNozzleByPosId(MAIN_EXTRUDER_ID));
|
||||
for (const auto& item : m_nozzle_items) {
|
||||
s_update_nozzle_info(item.second, rack, rack->GetNozzleSystem()->GetNozzleByPosId(item.first));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void s_enable_item_if_match(wgtDeviceNozzleRackNozzleItem* item,
|
||||
const DevNozzle& nozzle_info,
|
||||
const DevNozzle& selected_nozzle)
|
||||
{
|
||||
if (item) {
|
||||
if (nozzle_info.GetLogicExtruderId() != selected_nozzle.GetLogicExtruderId()) {
|
||||
item->SetDisable(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nozzle_info.IsEmpty() && !nozzle_info.IsAbnormal() && !nozzle_info.IsUnknown() &&
|
||||
nozzle_info.GetNozzleType() == selected_nozzle.GetNozzleType() &&
|
||||
nozzle_info.GetNozzleDiameter() == selected_nozzle.GetNozzleDiameter() &&
|
||||
nozzle_info.GetNozzleFlowType() == selected_nozzle.GetNozzleFlowType()) {
|
||||
item->SetDisable(false);
|
||||
} else {
|
||||
item->SetDisable(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackSelect::UpdatSelectedNozzle(std::shared_ptr<DevNozzleRack> rack, int selected_nozzle_pos_id)
|
||||
{
|
||||
m_nozzle_rack = rack;
|
||||
if (rack) {
|
||||
SetSelectedNozzle(rack->GetNozzleSystem()->GetNozzleByPosId(selected_nozzle_pos_id));
|
||||
if (m_enable_manual_nozzle_pick) {
|
||||
s_enable_item_if_match(m_toolhead_nozzle_r, rack->GetNozzleSystem()->GetNozzleByPosId(MAIN_EXTRUDER_ID), m_selected_nozzle);
|
||||
s_enable_item_if_match(m_toolhead_nozzle_l, rack->GetNozzleSystem()->GetNozzleByPosId(DEPUTY_EXTRUDER_ID), m_selected_nozzle);
|
||||
for (auto& item : m_nozzle_items) {
|
||||
s_enable_item_if_match(item.second, rack->GetNozzleSystem()->GetNozzleByPosId(item.first), m_selected_nozzle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackSelect::UpdatSelectedNozzles(std::shared_ptr<DevNozzleRack> rack,
|
||||
std::vector<int> selected_nozzle_pos_vec,
|
||||
bool use_dynamic_switch,
|
||||
std::optional<PrintFromType> /*print_from_type*/)
|
||||
{
|
||||
m_nozzle_rack = rack;
|
||||
m_enable_manual_nozzle_pick = !use_dynamic_switch;
|
||||
m_title_tips_dynamic->Show(use_dynamic_switch);
|
||||
|
||||
UpdateNozzleInfos(rack);
|
||||
if (!use_dynamic_switch) {
|
||||
if (selected_nozzle_pos_vec.size() > 0) {
|
||||
return UpdatSelectedNozzle(rack, selected_nozzle_pos_vec.at(0));
|
||||
} else {
|
||||
return ClearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
if (rack) {
|
||||
ClearSelection();
|
||||
for (const auto& pos_id : selected_nozzle_pos_vec) {
|
||||
if (pos_id == MAIN_EXTRUDER_ID) {
|
||||
m_toolhead_nozzle_r->SetSelected(true);
|
||||
} else if (pos_id == DEPUTY_EXTRUDER_ID) {
|
||||
m_toolhead_nozzle_l->SetSelected(true);
|
||||
} else if (auto it = m_nozzle_items.find(pos_id); it != m_nozzle_items.end()) {
|
||||
it->second->SetSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_toolhead_nozzle_l->IsSelected()) {
|
||||
m_toolhead_nozzle_l->SetDisable(true);
|
||||
}
|
||||
|
||||
if (!m_toolhead_nozzle_r->IsSelected()) {
|
||||
m_toolhead_nozzle_r->SetDisable(true);
|
||||
}
|
||||
|
||||
for (const auto& item : m_nozzle_items) {
|
||||
if (!item.second->IsSelected()) {
|
||||
item.second->SetDisable(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackSelect::ClearSelection()
|
||||
{
|
||||
m_selected_nozzle = DevNozzle();
|
||||
m_toolhead_nozzle_l->SetSelected(false);
|
||||
m_toolhead_nozzle_r->SetSelected(false);
|
||||
for (auto &item : m_nozzle_items) { item.second->SetSelected(false); }
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackSelect::SetSelectedNozzle(const DevNozzle &nozzle)
|
||||
{
|
||||
int new_selected_pos_id = nozzle.GetNozzlePosId();
|
||||
if (m_selected_nozzle.GetNozzlePosId() != new_selected_pos_id) {
|
||||
ClearSelection();
|
||||
|
||||
m_selected_nozzle = nozzle;
|
||||
if (new_selected_pos_id == MAIN_EXTRUDER_ID) {
|
||||
m_toolhead_nozzle_r->SetSelected(true);
|
||||
} else if (new_selected_pos_id == DEPUTY_EXTRUDER_ID) {
|
||||
m_toolhead_nozzle_l->SetSelected(true);
|
||||
} else if (auto it = m_nozzle_items.find(m_selected_nozzle.GetNozzlePosId()); it != m_nozzle_items.end()) {
|
||||
it->second->SetSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
volatile int sGetNozzlePosId(wgtDeviceNozzleRackNozzleItem* item,
|
||||
wgtDeviceNozzleRackNozzleItem* l_item,
|
||||
wgtDeviceNozzleRackNozzleItem* r_item)
|
||||
{
|
||||
int to_select_pos_id = -1;
|
||||
if (item == l_item) {
|
||||
to_select_pos_id = DEPUTY_EXTRUDER_ID;
|
||||
} else if (item == r_item) {
|
||||
to_select_pos_id = MAIN_EXTRUDER_ID;
|
||||
} else {
|
||||
to_select_pos_id = item->GetNozzleId() + 0x10;
|
||||
}
|
||||
|
||||
return to_select_pos_id;
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackSelect::OnNozzleItemSelected(wxCommandEvent &evt)
|
||||
{
|
||||
if (!m_enable_manual_nozzle_pick) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *item = dynamic_cast<wgtDeviceNozzleRackNozzleItem *>(evt.GetEventObject());
|
||||
if (item; auto ptr = m_nozzle_rack.lock()) {
|
||||
int to_select_pos_id = sGetNozzlePosId(item, m_toolhead_nozzle_l, m_toolhead_nozzle_r);
|
||||
if (to_select_pos_id > -1 && to_select_pos_id != GetSelectedNozzlePosID()) {
|
||||
SetSelectedNozzle(ptr->GetNozzleSystem()->GetNozzleByPosId(to_select_pos_id));
|
||||
wxCommandEvent change_evt(EVT_NOZZLE_SELECT_CHANGED, GetId());
|
||||
change_evt.SetEventObject(this);
|
||||
ProcessEvent(change_evt);
|
||||
evt.Skip();
|
||||
} else {
|
||||
wxCommandEvent change_evt(EVT_NOZZLE_SELECT_CLICKED, GetId());
|
||||
change_evt.SetEventObject(this);
|
||||
ProcessEvent(change_evt);
|
||||
evt.Skip();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackSelect::Rescale()
|
||||
{
|
||||
m_toolhead_nozzle_l->Rescale();
|
||||
m_toolhead_nozzle_r->Rescale();
|
||||
for (auto &item : m_nozzle_items) { item.second->Rescale(); }
|
||||
}
|
||||
|
||||
}; // namespace Slic3r::GUI
|
||||
@@ -0,0 +1,74 @@
|
||||
//**********************************************************/
|
||||
/* File: wgtDeviceNozzleSelect.h
|
||||
* Description: The panel to select nozzle
|
||||
*
|
||||
* \n class wgtDeviceNozzleSelect;
|
||||
//**********************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "slic3r/GUI/DeviceCore/DevNozzleSystem.h" // DevNozzle (value member) + DevDefs.h (PrintFromType, MAIN/DEPUTY_EXTRUDER_ID)
|
||||
|
||||
#include <wx/panel.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
// Previous definitions
|
||||
class Label;
|
||||
namespace Slic3r
|
||||
{
|
||||
struct DevNozzle;
|
||||
class DevNozzleRack;
|
||||
namespace GUI
|
||||
{
|
||||
class wgtDeviceNozzleRackNozzleItem;
|
||||
class wgtMsgBox;
|
||||
}
|
||||
};
|
||||
|
||||
wxDECLARE_EVENT(EVT_NOZZLE_SELECT_CHANGED, wxCommandEvent);
|
||||
wxDECLARE_EVENT(EVT_NOZZLE_SELECT_CLICKED, wxCommandEvent);
|
||||
namespace Slic3r::GUI
|
||||
{
|
||||
class wgtDeviceNozzleRackSelect : public wxPanel
|
||||
{
|
||||
public:
|
||||
wgtDeviceNozzleRackSelect(wxWindow* parent);
|
||||
~wgtDeviceNozzleRackSelect() = default;
|
||||
|
||||
public:
|
||||
int GetSelectedNozzlePosID() const { return m_selected_nozzle.GetNozzlePosId();}
|
||||
void UpdatSelectedNozzles(std::shared_ptr<DevNozzleRack> rack, std::vector<int> selected_nozzle_pos_vec, bool use_dynamic_switch, std::optional<PrintFromType> print_from_type);// for slicing with dynamic switch
|
||||
void Rescale();
|
||||
|
||||
private:
|
||||
void CreateGui();
|
||||
|
||||
void ClearSelection();
|
||||
void SetSelectedNozzle(const DevNozzle &nozzle);
|
||||
void UpdatSelectedNozzle(std::shared_ptr<DevNozzleRack> rack, int selected_nozzle_pos_id = -1); // for slicing without dynamic switch
|
||||
|
||||
void UpdateNozzleInfos(std::shared_ptr<DevNozzleRack> rack);
|
||||
|
||||
void OnNozzleItemSelected(wxCommandEvent& evt);
|
||||
|
||||
private:
|
||||
DevNozzle m_selected_nozzle;
|
||||
std::weak_ptr<DevNozzleRack> m_nozzle_rack;
|
||||
|
||||
// pick
|
||||
bool m_enable_manual_nozzle_pick = true;
|
||||
|
||||
// Label
|
||||
wgtMsgBox* m_title_tips_dynamic;
|
||||
|
||||
// GUI
|
||||
wgtDeviceNozzleRackNozzleItem * m_toolhead_nozzle_l{nullptr};
|
||||
wgtDeviceNozzleRackNozzleItem * m_toolhead_nozzle_r{nullptr};
|
||||
std::unordered_map<int, wgtDeviceNozzleRackNozzleItem *> m_nozzle_items; // from 16 to 21
|
||||
};
|
||||
|
||||
};// end of namespace Slic3r::GUI
|
||||
@@ -0,0 +1,43 @@
|
||||
#include "wgtMsgBox.h"
|
||||
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/Widgets/Label.hpp"
|
||||
#include "slic3r/GUI/wxExtensions.hpp"
|
||||
|
||||
#include <wx/sizer.h>
|
||||
|
||||
namespace Slic3r::GUI
|
||||
{
|
||||
|
||||
wgtMsgBox::wgtMsgBox(wxWindow* parent)
|
||||
: StaticBox(parent, wxID_ANY)
|
||||
{
|
||||
CreateGUI();
|
||||
}
|
||||
|
||||
void wgtMsgBox::CreateGUI()
|
||||
{
|
||||
wxBoxSizer* mainSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
m_txt_label = new Label(this);
|
||||
m_txt_label->SetFont(::Label::Body_13);
|
||||
m_txt_label->SetBackgroundColour(*wxWHITE);
|
||||
|
||||
auto padding_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
padding_sizer->Add(m_txt_label, 0, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(5));
|
||||
mainSizer->Add(padding_sizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
|
||||
//Button* btnClose = CreateCloseButton();
|
||||
//wxButton* btnClose = CreateCloseButton();
|
||||
//mainSizer->Add(btnClose, 0, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
SetSizer(mainSizer);
|
||||
mainSizer->Fit(this);
|
||||
}
|
||||
|
||||
void wgtMsgBox::OnCloseClicked(wxCommandEvent& evt)
|
||||
{
|
||||
this->Hide();
|
||||
}
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef WGTMSGBOX_H
|
||||
#define WGTMSGBOX_H
|
||||
|
||||
#include <wx/wx.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/button.h>
|
||||
|
||||
#include "slic3r/GUI/Widgets/StaticBox.hpp"
|
||||
|
||||
class Label;
|
||||
namespace Slic3r::GUI
|
||||
{
|
||||
class wgtMsgBox : public StaticBox
|
||||
{
|
||||
public:
|
||||
wgtMsgBox(wxWindow* parent);
|
||||
|
||||
public:
|
||||
Label* GetTextLabel() const { return m_txt_label; }
|
||||
|
||||
private:
|
||||
Label* m_txt_label;
|
||||
|
||||
private:
|
||||
void CreateGUI();
|
||||
void OnCloseClicked(wxCommandEvent& evt);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // WGTMSGBOX_H
|
||||
Reference in New Issue
Block a user