diff --git a/resources/config.json b/resources/config.json index 73890dcff..84f6e48f8 100644 --- a/resources/config.json +++ b/resources/config.json @@ -5,6 +5,7 @@ "func": { "FUNC_LOCAL_TUNNEL": false }, + "camera_resolution":["720p","1080p"], "model_id": "BL-P002", "printer_type": "3DPrinter-X1" }, @@ -14,6 +15,7 @@ "FUNC_LOCAL_TUNNEL": false }, "model_id": "BL-P001", + "camera_resolution":["720p","1080p"], "printer_type": "3DPrinter-X1-Carbon" } ] diff --git a/resources/images/camera_setting.svg b/resources/images/camera_setting.svg new file mode 100644 index 000000000..2cf473ba2 --- /dev/null +++ b/resources/images/camera_setting.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/camera_setting_hover.svg b/resources/images/camera_setting_hover.svg new file mode 100644 index 000000000..725e9a2d2 --- /dev/null +++ b/resources/images/camera_setting_hover.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/recording.svg b/resources/images/recording.svg new file mode 100644 index 000000000..76a7a59ef --- /dev/null +++ b/resources/images/recording.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/resources/images/recording_off_hover.svg b/resources/images/recording_off_hover.svg deleted file mode 100644 index 0f59b4dee..000000000 --- a/resources/images/recording_off_hover.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/recording_off_normal.svg b/resources/images/recording_off_normal.svg deleted file mode 100644 index 3ba0450e8..000000000 --- a/resources/images/recording_off_normal.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/recording_on_hover.svg b/resources/images/recording_on_hover.svg deleted file mode 100644 index 45a46c0fd..000000000 --- a/resources/images/recording_on_hover.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/recording_on_normal.svg b/resources/images/recording_on_normal.svg deleted file mode 100644 index b75b916e9..000000000 --- a/resources/images/recording_on_normal.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/sdcard_state_abnormal.svg b/resources/images/sdcard_state_abnormal.svg new file mode 100644 index 000000000..5798a2634 --- /dev/null +++ b/resources/images/sdcard_state_abnormal.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/resources/images/sdcard_state_off.svg b/resources/images/sdcard_state_off.svg deleted file mode 100644 index 97b4866de..000000000 --- a/resources/images/sdcard_state_off.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/resources/images/sdcard_state_on.svg b/resources/images/sdcard_state_on.svg index deef48a11..5bcaec8bb 100644 --- a/resources/images/sdcard_state_on.svg +++ b/resources/images/sdcard_state_on.svg @@ -1,7 +1,7 @@ - - - - - - + + + + + + diff --git a/resources/images/timelapse.svg b/resources/images/timelapse.svg new file mode 100644 index 000000000..52548b05f --- /dev/null +++ b/resources/images/timelapse.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/resources/images/timelapse_off_hover.svg b/resources/images/timelapse_off_hover.svg deleted file mode 100644 index d21e599c2..000000000 --- a/resources/images/timelapse_off_hover.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/resources/images/timelapse_off_normal.svg b/resources/images/timelapse_off_normal.svg deleted file mode 100644 index ec30c1b72..000000000 --- a/resources/images/timelapse_off_normal.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/resources/images/timelapse_on_hover.svg b/resources/images/timelapse_on_hover.svg deleted file mode 100644 index 7ea45dc91..000000000 --- a/resources/images/timelapse_on_hover.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/resources/images/timelapse_on_normal.svg b/resources/images/timelapse_on_normal.svg deleted file mode 100644 index 09655e134..000000000 --- a/resources/images/timelapse_on_normal.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/resources/images/vcamera.svg b/resources/images/vcamera.svg new file mode 100644 index 000000000..e72c5dc76 --- /dev/null +++ b/resources/images/vcamera.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/resources/images/vcamera_off_hover.svg b/resources/images/vcamera_off_hover.svg deleted file mode 100644 index 1693162c9..000000000 --- a/resources/images/vcamera_off_hover.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/resources/images/vcamera_off_normal.svg b/resources/images/vcamera_off_normal.svg deleted file mode 100644 index f90e972b1..000000000 --- a/resources/images/vcamera_off_normal.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/resources/images/vcamera_on_hover.svg b/resources/images/vcamera_on_hover.svg deleted file mode 100644 index ea7708347..000000000 --- a/resources/images/vcamera_on_hover.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/resources/images/vcamera_on_normal.svg b/resources/images/vcamera_on_normal.svg deleted file mode 100644 index 1c12fe644..000000000 --- a/resources/images/vcamera_on_normal.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/src/slic3r/GUI/CameraPopup.cpp b/src/slic3r/GUI/CameraPopup.cpp index 2683b347e..ed1c89ad5 100644 --- a/src/slic3r/GUI/CameraPopup.cpp +++ b/src/slic3r/GUI/CameraPopup.cpp @@ -20,9 +20,10 @@ wxBEGIN_EVENT_TABLE(CameraPopup, wxPopupTransientWindow) EVT_KILL_FOCUS(CameraPopup::OnKillFocus ) wxEND_EVENT_TABLE() +wxDEFINE_EVENT(EVT_VCAMERA_SWITCH, wxMouseEvent); +wxDEFINE_EVENT(EVT_SDCARD_ABSENT_HINT, wxCommandEvent); -static const wxFont TEXT_FONT = Label::Body_14; -static wxColour TEXT_COL = wxColour(43, 52, 54); +const wxColour TEXT_COL = wxColour(43, 52, 54); CameraPopup::CameraPopup(wxWindow *parent, MachineObject* obj) : wxPopupTransientWindow(parent, wxBORDER_NONE | wxPU_CONTAINS_CONTROLS), @@ -33,34 +34,70 @@ CameraPopup::CameraPopup(wxWindow *parent, MachineObject* obj) #endif m_panel = new wxScrolledWindow(this, wxID_ANY); m_panel->SetBackgroundColour(*wxWHITE); - + m_panel->SetMinSize(wxSize(FromDIP(180),-1)); m_panel->Bind(wxEVT_MOTION, &CameraPopup::OnMouse, this); - wxBoxSizer * main_sizer = new wxBoxSizer(wxHORIZONTAL); - wxFlexGridSizer* top_sizer = new wxFlexGridSizer(0, 2, 0, 0); + main_sizer = new wxBoxSizer(wxVERTICAL); + wxFlexGridSizer* top_sizer = new wxFlexGridSizer(0, 2, 0, FromDIP(50)); top_sizer->AddGrowableCol(0); top_sizer->SetFlexibleDirection(wxBOTH); top_sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); + //timelapse m_text_timelapse = new wxStaticText(m_panel, wxID_ANY, _L("Timelapse")); m_text_timelapse->Wrap(-1); - m_text_timelapse->SetFont(TEXT_FONT); + m_text_timelapse->SetFont(Label::Head_14); m_text_timelapse->SetForegroundColour(TEXT_COL); m_switch_timelapse = new SwitchButton(m_panel); if (obj) m_switch_timelapse->SetValue(obj->camera_timelapse); + + //recording m_text_recording = new wxStaticText(m_panel, wxID_ANY, _L("Monitoring Recording")); m_text_recording->Wrap(-1); - m_text_recording->SetFont(TEXT_FONT); + m_text_recording->SetFont(Label::Head_14); m_text_recording->SetForegroundColour(TEXT_COL); m_switch_recording = new SwitchButton(m_panel); if (obj) m_switch_recording->SetValue(obj->camera_recording_when_printing); - top_sizer->Add(m_text_timelapse, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, FromDIP(5)); - top_sizer->Add(m_switch_timelapse, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, FromDIP(5)); - top_sizer->Add(m_text_recording, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, FromDIP(5)); - top_sizer->Add(m_switch_recording, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, FromDIP(5)); + //vcamera + m_text_vcamera = new wxStaticText(m_panel, wxID_ANY, _L("Virtual Camera")); + m_text_vcamera->Wrap(-1); + m_text_vcamera->SetFont(Label::Head_14); + m_text_vcamera->SetForegroundColour(TEXT_COL); + m_switch_vcamera = new SwitchButton(m_panel); + + top_sizer->Add(m_text_timelapse, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, FromDIP(5)); + top_sizer->Add(m_switch_timelapse, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, FromDIP(5)); + top_sizer->Add(m_text_recording, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, FromDIP(5)); + top_sizer->Add(m_switch_recording, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, FromDIP(5)); + top_sizer->Add(m_text_vcamera, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, FromDIP(5)); + top_sizer->Add(m_switch_vcamera, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, FromDIP(5)); + + //resolution + m_text_resolution = new wxStaticText(m_panel, wxID_ANY, _L("Resolution")); + m_text_resolution->Wrap(-1); + m_text_resolution->SetFont(Label::Head_14); + m_text_resolution->SetForegroundColour(TEXT_COL); + top_sizer->Add(m_text_resolution, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, FromDIP(5)); + top_sizer->Add(0, 0, wxALL, 0); + for (int i = 0; i < (int)RESOLUTION_OPTIONS_NUM; ++i) + { + m_resolution_options[i] = create_item_radiobox(to_resolution_label_string(CameraResolution(i)), m_panel, wxEmptyString, FromDIP(10)); + top_sizer->Add(m_resolution_options[i], 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, FromDIP(5)); + top_sizer->Add(0, 0, wxALL, 0); + } + if (obj) + sync_resolution_setting(obj->camera_resolution); + main_sizer->Add(top_sizer, 0, wxALL, FromDIP(10)); + + auto url = wxString::Format(L"https://wiki.bambulab.com/%s/software/bambu-studio/virtual-camera", L"en"); + vcamera_guide_link = new wxHyperlinkCtrl(m_panel, wxID_ANY, _L("Show 'Streaming Video' guide page."), + url, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE); + vcamera_guide_link->Hide(); + main_sizer->Add(vcamera_guide_link, 0, wxALL, FromDIP(15)); + m_panel->SetSizer(main_sizer); m_panel->Layout(); @@ -69,12 +106,32 @@ CameraPopup::CameraPopup(wxWindow *parent, MachineObject* obj) SetClientSize(m_panel->GetSize()); m_switch_timelapse->Connect(wxEVT_LEFT_DOWN, wxCommandEventHandler(CameraPopup::on_switch_timelapse), NULL, this); m_switch_recording->Connect(wxEVT_LEFT_DOWN, wxCommandEventHandler(CameraPopup::on_switch_recording), NULL, this); + m_switch_vcamera->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { + wxMouseEvent evt(EVT_VCAMERA_SWITCH); + evt.SetEventObject(this); + GetEventHandler()->ProcessEvent(evt); + }); + #ifdef __APPLE__ + m_panel->Bind(wxEVT_LEFT_UP, &CameraPopup::OnLeftUp, this); + #endif //APPLE + + check_func_supported(); +} + +void CameraPopup::sdcard_absent_hint() +{ + wxCommandEvent evt(EVT_SDCARD_ABSENT_HINT); + evt.SetEventObject(this); + GetEventHandler()->ProcessEvent(evt); } void CameraPopup::on_switch_timelapse(wxCommandEvent& event) { if (!m_obj) return; - + if (m_obj->sdcard_state != MachineObject::SdcardState::HAS_SDCARD_NORMAL) { + sdcard_absent_hint(); + return; + } bool value = m_switch_timelapse->GetValue(); m_switch_timelapse->SetValue(!value); m_obj->command_ipcam_timelapse(!value); @@ -83,12 +140,22 @@ void CameraPopup::on_switch_timelapse(wxCommandEvent& event) void CameraPopup::on_switch_recording(wxCommandEvent& event) { if (!m_obj) return; - + if (m_obj->sdcard_state != MachineObject::SdcardState::HAS_SDCARD_NORMAL) { + sdcard_absent_hint(); + return; + } bool value = m_switch_recording->GetValue(); m_switch_recording->SetValue(!value); m_obj->command_ipcam_record(!value); } +void CameraPopup::on_set_resolution() +{ + if (!m_obj) return; + + m_obj->command_ipcam_resolution_set(to_resolution_msg_string(curr_sel_resolution)); +} + void CameraPopup::Popup(wxWindow *WXUNUSED(focus)) { wxPoint curr_position = this->GetPosition(); @@ -98,6 +165,235 @@ void CameraPopup::Popup(wxWindow *WXUNUSED(focus)) wxPopupTransientWindow::Popup(); } +wxWindow* CameraPopup::create_item_radiobox(wxString title, wxWindow* parent, wxString tooltip, int padding_left) +{ + wxWindow *item = new wxWindow(parent, wxID_ANY, wxDefaultPosition, wxSize(-1, FromDIP(20))); + item->SetBackgroundColour(*wxWHITE); + + RadioBox *radiobox = new RadioBox(item); + radiobox->SetPosition(wxPoint(padding_left, (item->GetSize().GetHeight() - radiobox->GetSize().GetHeight()) / 2)); + resolution_rbtns.push_back(radiobox); + int btn_idx = resolution_rbtns.size() - 1; + radiobox->Bind(wxEVT_LEFT_DOWN, [this, btn_idx](wxMouseEvent &e) { + if (m_obj && allow_alter_resolution) { + select_curr_radiobox(btn_idx, false); + on_set_resolution(); + } + }); + + wxStaticText *text = new wxStaticText(item, wxID_ANY, title, wxDefaultPosition, wxDefaultSize); + resolution_texts.push_back(text); + text->SetPosition(wxPoint(padding_left + radiobox->GetSize().GetWidth() + 10, (item->GetSize().GetHeight() - text->GetSize().GetHeight()) / 2)); + text->SetFont(Label::Body_13); + text->SetForegroundColour(0x6B6B6B); + text->Bind(wxEVT_LEFT_DOWN, [this, btn_idx](wxMouseEvent &e) { + if (m_obj && allow_alter_resolution) { + select_curr_radiobox(btn_idx, false); + on_set_resolution(); + } + }); + + radiobox->SetToolTip(tooltip); + text->SetToolTip(tooltip); + return item; +} + +void CameraPopup::select_curr_radiobox(int btn_idx, bool ui_change) +{ + int len = resolution_rbtns.size(); + for (int i = 0; i < len; ++i) { + if (i == btn_idx) { + curr_sel_resolution = CameraResolution(i); + if (ui_change) + resolution_rbtns[i]->SetValue(true); + } + else { + if (ui_change) + resolution_rbtns[i]->SetValue(false); + } + } +} + +void CameraPopup::sync_resolution_setting(std::string resolution) +{ + if (resolution == "") { + reset_resolution_setting(); + return; + } + int res = 0; + for (CameraResolution i = RESOLUTION_720P; i < RESOLUTION_OPTIONS_NUM; i = CameraResolution(i+1)){ + if (resolution == to_resolution_msg_string(i)) { + res = int(i); + break; + } + } + select_curr_radiobox(res, true); +} + +void CameraPopup::reset_resolution_setting() +{ + int len = resolution_rbtns.size(); + for (int i = 0; i < len; ++i) { + resolution_rbtns[i]->SetValue(false); + } + curr_sel_resolution = RESOLUTION_OPTIONS_NUM; +} + +void CameraPopup::sync_vcamera_state(bool show_vcamera) +{ + is_vcamera_show = show_vcamera; + if (is_vcamera_show) { + m_switch_vcamera->SetValue(true); + vcamera_guide_link->Show(); + } + else { + m_switch_vcamera->SetValue(false); + vcamera_guide_link->Hide(); + } + + rescale(); +} + +void CameraPopup::check_func_supported() +{ + // function supported + if (m_obj->is_function_supported(PrinterFunction::FUNC_TIMELAPSE) && m_obj->has_ipcam) { + m_text_timelapse->Show(); + m_switch_timelapse->Show(); + } else { + m_text_timelapse->Hide(); + m_switch_timelapse->Hide(); + } + + if (m_obj->is_function_supported(PrinterFunction::FUNC_RECORDING) && m_obj->has_ipcam) { + m_text_recording->Show(); + m_switch_recording->Show(); + } else { + m_text_recording->Hide(); + m_switch_recording->Hide(); + } + + if (m_obj->is_function_supported(PrinterFunction::FUNC_VIRTUAL_CAMERA) && m_obj->has_ipcam) { + m_text_vcamera->Show(); + m_switch_vcamera->Show(); + if (is_vcamera_show) + vcamera_guide_link->Show(); + } else { + m_text_vcamera->Hide(); + m_switch_vcamera->Hide(); + vcamera_guide_link->Hide(); + } + + allow_alter_resolution = (m_obj->is_function_supported(PrinterFunction::FUNC_ALTER_RESOLUTION) && m_obj->has_ipcam); + + //resolution supported + std::vector resolution_supported = m_obj->get_resolution_supported(); + for (int i = 0; i < (int)RESOLUTION_OPTIONS_NUM; ++i){ + auto curr_res = to_resolution_msg_string(CameraResolution(i)); + std::vector ::iterator it = std::find(resolution_supported.begin(), resolution_supported.end(), curr_res); + if (it!= resolution_supported.end()) + m_resolution_options[i] -> Show(); + else + m_resolution_options[i] -> Hide(); + } +} + +void CameraPopup::update() +{ + if (!m_obj) return; + check_func_supported(); + m_switch_timelapse->SetValue(m_obj->camera_timelapse); + m_switch_recording->SetValue(m_obj->camera_recording_when_printing); + sync_resolution_setting(m_obj->camera_resolution); + + rescale(); +} + +wxString CameraPopup::to_resolution_label_string(CameraResolution resolution) { + switch (resolution) { + case RESOLUTION_720P: + return _L("720p"); + case RESOLUTION_1080P: + return _L("1080p"); + default: + return _L(""); + } + return ""; +} + +std::string CameraPopup::to_resolution_msg_string(CameraResolution resolution) { + switch (resolution) { + case RESOLUTION_720P: + return std::string("720p"); + case RESOLUTION_1080P: + return std::string("1080p"); + default: + return ""; + } + return ""; +} + +void CameraPopup::rescale() +{ + m_panel->Layout(); + main_sizer->Fit(m_panel); + SetClientSize(m_panel->GetSize()); + wxPopupTransientWindow::Update(); +} + +void CameraPopup::OnLeftUp(wxMouseEvent &event) +{ + auto mouse_pos = ClientToScreen(event.GetPosition()); + auto wxscroll_win_pos = m_panel->ClientToScreen(wxPoint(0, 0)); + + if (mouse_pos.x > wxscroll_win_pos.x && mouse_pos.y > wxscroll_win_pos.y && mouse_pos.x < (wxscroll_win_pos.x + m_panel->GetSize().x) && mouse_pos.y < (wxscroll_win_pos.y + m_panel->GetSize().y)) { + //timelapse + auto timelapse_rect = m_switch_timelapse->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > timelapse_rect.x && mouse_pos.y > timelapse_rect.y && mouse_pos.x < (timelapse_rect.x + m_switch_timelapse->GetSize().x) && mouse_pos.y < (timelapse_rect.y + m_switch_timelapse->GetSize().y)) { + wxMouseEvent timelapse_evt(wxEVT_LEFT_DOWN); + m_switch_timelapse->GetEventHandler()->ProcessEvent(timelapse_evt); + return; + } + //recording + auto recording_rect = m_switch_recording->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > recording_rect.x && mouse_pos.y > recording_rect.y && mouse_pos.x < (recording_rect.x + m_switch_recording->GetSize().x) && mouse_pos.y < (recording_rect.y + m_switch_recording->GetSize().y)) { + wxMouseEvent recording_evt(wxEVT_LEFT_DOWN); + m_switch_recording->GetEventHandler()->ProcessEvent(recording_evt); + return; + } + //vcamera + auto vcamera_rect = m_switch_vcamera->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > vcamera_rect.x && mouse_pos.y > vcamera_rect.y && mouse_pos.x < (vcamera_rect.x + m_switch_vcamera->GetSize().x) && mouse_pos.y < (vcamera_rect.y + m_switch_vcamera->GetSize().y)) { + wxMouseEvent vcamera_evt(wxEVT_LEFT_DOWN); + m_switch_vcamera->GetEventHandler()->ProcessEvent(vcamera_evt); + return; + } + //resolution + for (int i = 0; i < (int)RESOLUTION_OPTIONS_NUM; ++i){ + auto resolution_rbtn = resolution_rbtns[i]; + auto rbtn_rect = resolution_rbtn->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > rbtn_rect.x && mouse_pos.y > rbtn_rect.y && mouse_pos.x < (rbtn_rect.x + resolution_rbtn->GetSize().x) && mouse_pos.y < (rbtn_rect.y + resolution_rbtn->GetSize().y)) { + wxMouseEvent resolution_evt(wxEVT_LEFT_DOWN); + resolution_rbtn->GetEventHandler()->ProcessEvent(resolution_evt); + return; + } + auto resolution_txt = resolution_texts[i]; + auto txt_rect = resolution_txt->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > txt_rect.x && mouse_pos.y > txt_rect.y && mouse_pos.x < (txt_rect.x + resolution_txt->GetSize().x) && mouse_pos.y < (txt_rect.y + resolution_txt->GetSize().y)) { + wxMouseEvent resolution_evt(wxEVT_LEFT_DOWN); + resolution_txt->GetEventHandler()->ProcessEvent(resolution_evt); + return; + } + } + //hyper link + auto h_rect = vcamera_guide_link->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > h_rect.x && mouse_pos.y > h_rect.y && mouse_pos.x < (h_rect.x + vcamera_guide_link->GetSize().x) && mouse_pos.y < (h_rect.y + vcamera_guide_link->GetSize().y)) { + auto url = wxString::Format(L"https://wiki.bambulab.com/%s/software/bambu-studio/virtual-camera", L"en"); + wxLaunchDefaultBrowser(url); + } + } +} + void CameraPopup::OnDismiss() { wxPopupTransientWindow::OnDismiss(); } @@ -106,6 +402,7 @@ bool CameraPopup::ProcessLeftDown(wxMouseEvent &event) { return wxPopupTransientWindow::ProcessLeftDown(event); } + bool CameraPopup::Show(bool show) { return wxPopupTransientWindow::Show(show); @@ -131,18 +428,15 @@ void CameraPopup::OnMouse(wxMouseEvent &event) event.Skip(); } - -CameraItem::CameraItem(wxWindow *parent,std::string off_normal, std::string on_normal, std::string off_hover, std::string on_hover) +CameraItem::CameraItem(wxWindow *parent, std::string normal, std::string hover) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize) { #ifdef __WINDOWS__ SetDoubleBuffered(true); #endif //__WINDOWS__ - m_bitmap_on_normal = ScalableBitmap(this, on_normal, 20); - m_bitmap_off_normal = ScalableBitmap(this, off_normal, 20); - m_bitmap_on_hover = ScalableBitmap(this, on_hover, 20); - m_bitmap_off_hover = ScalableBitmap(this, off_hover, 20); + m_bitmap_normal = ScalableBitmap(this, normal, 20); + m_bitmap_hover = ScalableBitmap(this, hover, 20); SetSize(wxSize(FromDIP(20), FromDIP(20))); SetMinSize(wxSize(FromDIP(20), FromDIP(20))); @@ -156,12 +450,6 @@ CameraItem::~CameraItem() {} void CameraItem::msw_rescale() {} -void CameraItem::set_switch(bool is_on) -{ - m_on = is_on; - Refresh(); -} - void CameraItem::on_enter_win(wxMouseEvent &evt) { m_hover = true; @@ -206,20 +494,12 @@ void CameraItem::render(wxDC &dc) void CameraItem::doRender(wxDC &dc) { - if (m_on) { - if (m_hover) { - dc.DrawBitmap(m_bitmap_on_hover.bmp(), wxPoint((GetSize().x - m_bitmap_on_hover.GetBmpSize().x) / 2, (GetSize().y - m_bitmap_on_hover.GetBmpSize().y) / 2)); - } else { - dc.DrawBitmap(m_bitmap_on_normal.bmp(), wxPoint((GetSize().x - m_bitmap_on_normal.GetBmpSize().x) / 2, (GetSize().y - m_bitmap_on_normal.GetBmpSize().y) / 2)); - } - + if (m_hover) { + dc.DrawBitmap(m_bitmap_hover.bmp(), wxPoint((GetSize().x - m_bitmap_hover.GetBmpSize().x) / 2, (GetSize().y - m_bitmap_hover.GetBmpSize().y) / 2)); } else { - if (m_hover) { - dc.DrawBitmap(m_bitmap_off_hover.bmp(), wxPoint((GetSize().x - m_bitmap_off_hover.GetBmpSize().x) / 2, (GetSize().y - m_bitmap_off_hover.GetBmpSize().y) / 2)); - } else { - dc.DrawBitmap(m_bitmap_off_normal.bmp(), wxPoint((GetSize().x - m_bitmap_off_normal.GetBmpSize().x) / 2, (GetSize().y - m_bitmap_off_normal.GetBmpSize().y) / 2)); - } + dc.DrawBitmap(m_bitmap_normal.bmp(), wxPoint((GetSize().x - m_bitmap_normal.GetBmpSize().x) / 2, (GetSize().y - m_bitmap_normal.GetBmpSize().y) / 2)); } } + } } \ No newline at end of file diff --git a/src/slic3r/GUI/CameraPopup.hpp b/src/slic3r/GUI/CameraPopup.hpp index 6be911779..35d6cdfea 100644 --- a/src/slic3r/GUI/CameraPopup.hpp +++ b/src/slic3r/GUI/CameraPopup.hpp @@ -10,11 +10,16 @@ #include #include #include +#include #include "Widgets/SwitchButton.hpp" +#include "Widgets/RadioBox.hpp" namespace Slic3r { namespace GUI { +wxDECLARE_EVENT(EVT_VCAMERA_SWITCH, wxMouseEvent); +wxDECLARE_EVENT(EVT_SDCARD_ABSENT_HINT, wxCommandEvent); + class CameraPopup : public wxPopupTransientWindow { public: @@ -27,9 +32,31 @@ public: virtual bool ProcessLeftDown(wxMouseEvent &event) wxOVERRIDE; virtual bool Show(bool show = true) wxOVERRIDE; + void sync_vcamera_state(bool show_vcamera); + void check_func_supported(); + void update(); + + enum CameraResolution + { + RESOLUTION_720P = 0, + RESOLUTION_1080P = 1, + RESOLUTION_OPTIONS_NUM = 2 + }; + + void rescale(); + protected: void on_switch_timelapse(wxCommandEvent& event); void on_switch_recording(wxCommandEvent& event); + void on_set_resolution(); + void sdcard_absent_hint(); + + wxWindow * create_item_radiobox(wxString title, wxWindow *parent, wxString tooltip, int padding_left); + void select_curr_radiobox(int btn_idx, bool ui_change); + void sync_resolution_setting(std::string resolution); + void reset_resolution_setting(); + wxString to_resolution_label_string(CameraResolution resolution); + std::string to_resolution_msg_string(CameraResolution resolution); private: MachineObject* m_obj { nullptr }; @@ -37,12 +64,24 @@ private: SwitchButton* m_switch_recording; wxStaticText* m_text_timelapse; SwitchButton* m_switch_timelapse; + wxStaticText* m_text_vcamera; + SwitchButton* m_switch_vcamera; + wxStaticText* m_text_resolution; + wxWindow* m_resolution_options[RESOLUTION_OPTIONS_NUM]; wxScrolledWindow *m_panel; + wxBoxSizer* main_sizer; + std::vector resolution_rbtns; + std::vector resolution_texts; + CameraResolution curr_sel_resolution = RESOLUTION_1080P; + wxHyperlinkCtrl* vcamera_guide_link { nullptr }; + bool is_vcamera_show = false; + bool allow_alter_resolution = false; void OnMouse(wxMouseEvent &event); void OnSize(wxSizeEvent &event); void OnSetFocus(wxFocusEvent &event); void OnKillFocus(wxFocusEvent &event); + void OnLeftUp(wxMouseEvent& event); private: wxDECLARE_ABSTRACT_CLASS(CameraPopup); @@ -53,20 +92,15 @@ private: class CameraItem : public wxPanel { public: - CameraItem(wxWindow *parent, std::string off_normal, std::string on_normal, std::string off_hover, std::string on_hover); + CameraItem(wxWindow *parent, std::string normal, std::string hover); ~CameraItem(); MachineObject *m_obj{nullptr}; - bool m_on{false}; bool m_hover{false}; - ScalableBitmap m_bitmap_on_normal; - ScalableBitmap m_bitmap_on_hover; - ScalableBitmap m_bitmap_off_normal; - ScalableBitmap m_bitmap_off_hover; + ScalableBitmap m_bitmap_normal; + ScalableBitmap m_bitmap_hover; void msw_rescale(); - void set_switch(bool is_on); - bool get_switch_status() { return m_on; }; void on_enter_win(wxMouseEvent &evt); void on_level_win(wxMouseEvent &evt); void paintEvent(wxPaintEvent &evt); diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index bff43f705..55d9d43be 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -1149,8 +1149,9 @@ void MachineObject::parse_status(int flag) else { ams_auto_switch_filament_flag = ((flag >> 10) & 0x1) != 0; } + + sdcard_state = MachineObject::SdcardState((flag >> 8) & 0x11); } - PrintingSpeedLevel MachineObject::_parse_printing_speed_lvl(int lvl) { @@ -1173,7 +1174,12 @@ bool MachineObject::is_sdcard_printing() bool MachineObject::has_sdcard() { - return camera_has_sdcard; + return (sdcard_state == MachineObject::SdcardState::HAS_SDCARD_NORMAL); +} + +MachineObject::SdcardState MachineObject::get_sdcard_state() +{ + return sdcard_state; } bool MachineObject::has_timelapse() @@ -1608,6 +1614,16 @@ int MachineObject::command_ipcam_timelapse(bool on_off) return this->publish_json(j.dump()); } +int MachineObject::command_ipcam_resolution_set(std::string resolution) +{ + json j; + j["camera"]["command"] = "ipcam_resolution_set"; + j["camera"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + j["camera"]["resolution"] = resolution; + BOOST_LOG_TRIVIAL(info) << "command:ipcam_resolution_set" << ", resolution:" << resolution; + return this->publish_json(j.dump()); +} + int MachineObject::command_xcam_control(std::string module_name, bool on_off, std::string lvl) { json j; @@ -1620,8 +1636,7 @@ int MachineObject::command_xcam_control(std::string module_name, bool on_off, st if (!lvl.empty()) { j["xcam"]["halt_print_sensitivity"] = lvl; } - BOOST_LOG_TRIVIAL(info) << "command:xcam_control_set" << ", sequence_id:" << std::to_string(MachineObject::m_sequence_id)<< - ", module_name:" << module_name << ", control:" << on_off << ", halt_print_sensitivity:" << lvl; + BOOST_LOG_TRIVIAL(info) << "command:xcam_control_set" << ", module_name:" << module_name << ", control:" << on_off << ", halt_print_sensitivity:" << lvl; return this->publish_json(j.dump()); } @@ -1753,6 +1768,7 @@ void MachineObject::reset() camera_recording = false; camera_recording_when_printing = false; camera_timelapse = false; + camera_resolution = ""; printing_speed_mag = 100; gcode_file_prepare_percent = 0; iot_print_status = ""; @@ -1889,12 +1905,20 @@ bool MachineObject::is_function_supported(PrinterFunction func) case FUNC_USE_AMS: func_name = "FUNC_USE_AMS"; break; + case FUNC_ALTER_RESOLUTION: + func_name = "FUNC_ALTER_RESOLUTION"; + break; default: return true; } return DeviceManager::is_function_supported(printer_type, func_name); } +std::vector MachineObject::get_resolution_supported() +{ + return DeviceManager::get_resolution_supported(printer_type); +} + bool MachineObject::is_support_print_with_timelapse() { //TODO version check, set true by default @@ -2239,10 +2263,13 @@ int MachineObject::parse_json(std::string payload) // media try { if (jj.contains("sdcard")) { - camera_has_sdcard = jj["sdcard"].get(); + if (jj["sdcard"].get()) + sdcard_state = MachineObject::SdcardState::HAS_SDCARD_NORMAL; + else + sdcard_state = MachineObject::SdcardState::NO_SDCARD; } else { //do not check sdcard if no sdcard field - camera_has_sdcard = false; + sdcard_state = MachineObject::SdcardState::NO_SDCARD; } } catch (...) { @@ -2367,6 +2394,9 @@ int MachineObject::parse_json(std::string payload) has_ipcam = false; } } + if (jj["ipcam"].contains("resolution")) { + camera_resolution = jj["ipcam"]["resolution"].get(); + } } } catch (...) { @@ -2831,6 +2861,8 @@ int MachineObject::parse_json(std::string payload) this->camera_recording_when_printing = true; if (j["camera"]["control"].get() == "disable") this->camera_recording_when_printing = false; + } else if (j["camera"]["command"].get() == "ipcam_resolution_set") { + this->camera_resolution = j["camera"]["resolution"].get(); } } } @@ -3524,6 +3556,22 @@ bool DeviceManager::is_function_supported(std::string type_str, std::string func return true; } +std::vector DeviceManager::get_resolution_supported(std::string type_str) +{ + std::vector resolution_supported; + if (DeviceManager::function_table.contains("printers")) { + for (auto printer : DeviceManager::function_table["printers"]) { + if (printer.contains("model_id") && printer["model_id"].get() == type_str) { + if (printer.contains("camera_resolution")) { + for (auto res : printer["camera_resolution"]) + resolution_supported.emplace_back(res.get()); + } + } + } + } + return resolution_supported; +} + bool DeviceManager::load_functional_config(std::string config_file) { std::ifstream json_file(config_file.c_str()); diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index f4f11e5a3..660e0cce6 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -11,6 +11,7 @@ #include "libslic3r/ProjectTask.hpp" #include "slic3r/Utils/json_diff.hpp" #include "slic3r/Utils/NetworkAgent.hpp" +#include "CameraPopup.hpp" #define USE_LOCAL_SOCKET_BIND 0 @@ -74,6 +75,7 @@ enum PrinterFunction { FUNC_PRINT_WITHOUT_SD, FUNC_VIRTUAL_CAMERA, FUNC_USE_AMS, + FUNC_ALTER_RESOLUTION, FUNC_MAX }; @@ -346,6 +348,13 @@ public: std::string sw_new_ver; }; + enum SdcardState { + NO_SDCARD = 0, + HAS_SDCARD_NORMAL = 1, + HAS_SDCARD_ABNORMAL = 2, + SDCARD_STATE_NUM = 3 + }; + /* static members and functions */ static inline int m_sequence_id = 20000; static std::string parse_printer_type(std::string type_str); @@ -530,7 +539,7 @@ public: bool camera_recording { false }; bool camera_recording_when_printing { false }; bool camera_timelapse { false }; - bool camera_has_sdcard { false }; + std::string camera_resolution = ""; bool xcam_first_layer_inspector { false }; int xcam_first_layer_hold_count = 0; @@ -543,6 +552,10 @@ public: int xcam_auto_recovery_hold_count = 0; int ams_print_option_count = 0; + /* sdcard */ + MachineObject::SdcardState sdcard_state { NO_SDCARD }; + MachineObject::SdcardState get_sdcard_state(); + /* HMS */ std::vector hms_list; @@ -626,6 +639,7 @@ public: // camera control int command_ipcam_record(bool on_off); int command_ipcam_timelapse(bool on_off); + int command_ipcam_resolution_set(std::string resolution); int command_xcam_control(std::string module_name, bool on_off, std::string lvl = ""); int command_xcam_control_ai_monitoring(bool on_off, std::string lvl); int command_xcam_control_first_layer_inspector(bool on_off, bool print_halt); @@ -655,6 +669,7 @@ public: bool is_online() { return m_is_online; } bool is_info_ready(); bool is_function_supported(PrinterFunction func); + std::vector get_resolution_supported(); bool is_support_print_with_timelapse(); @@ -724,6 +739,7 @@ public: static std::string parse_printer_type(std::string type_str); static std::string get_printer_display_name(std::string type_str); static bool is_function_supported(std::string type_str, std::string function_name); + static std::vector get_resolution_supported(std::string type_str); static bool load_functional_config(std::string config_file); }; diff --git a/src/slic3r/GUI/MediaPlayCtrl.cpp b/src/slic3r/GUI/MediaPlayCtrl.cpp index 74373cf31..343f1eeb4 100644 --- a/src/slic3r/GUI/MediaPlayCtrl.cpp +++ b/src/slic3r/GUI/MediaPlayCtrl.cpp @@ -273,7 +273,7 @@ void MediaPlayCtrl::ToggleStream() std::string file_ff_cfg = data_dir() + "/cameratools/ffmpeg.cfg"; #endif if (!boost::filesystem::exists(file_source) || !boost::filesystem::exists(file_ffmpeg) || !boost::filesystem::exists(file_ff_cfg)) { - auto res = MessageDialog(this, _L("Virtual Camera Tools is required for this task!\nDo you want to install them?"), _L("Error"), + auto res = MessageDialog(this, _L("Virtual Camera Tools is required for this task!\nDo you want to install them?"), _L("Info"), wxOK | wxCANCEL).ShowModal(); if (res == wxID_OK) { // download tools @@ -345,18 +345,6 @@ void MediaPlayCtrl::ToggleStream() file.write(url2.c_str(), url2.size()); file.close(); m_streaming = true; - if (wxGetApp().app_config->get("not_show_vcamera_wiki") != "1") { - MessageDialog dlg(this, _L("Virtual camera is started.\nPress 'OK' to navigate the guide page of 'Streaming video of Bambu Printer'."), _L("Information"), - wxOK | wxCANCEL | wxICON_INFORMATION); - dlg.show_dsa_button(); - auto res = dlg.ShowModal(); - if (dlg.get_checkbox_state()) - wxGetApp().app_config->set("not_show_vcamera_wiki", "1"); - if (res == wxID_OK) { - auto url = wxString::Format(L"https://wiki.bambulab.com/%s/software/bambu-studio/virtual-camera", L"en"); - wxLaunchDefaultBrowser(url); - } - } }); }); } diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 95de716c0..91f56545c 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -1690,7 +1690,7 @@ bool SelectMachineDialog::has_tips(MachineObject* obj) // must set to a status if return true if (select_timelapse->IsShown() && m_checkbox_list["timelapse"]->GetValue()) { - if (!obj->has_sdcard()) { + if (obj->get_sdcard_state() == MachineObject::SdcardState::NO_SDCARD) { show_status(PrintDialogStatus::PrintStatusTimelapseNoSdcard); return true; } @@ -2518,14 +2518,14 @@ void SelectMachineDialog::update_show_status() show_status(PrintDialogStatus::PrintStatusInPrinting); return; } - else if (!obj_->is_function_supported(PrinterFunction::FUNC_PRINT_WITHOUT_SD) && !obj_->has_sdcard()) { + else if (!obj_->is_function_supported(PrinterFunction::FUNC_PRINT_WITHOUT_SD) && (obj_->get_sdcard_state() == MachineObject::SdcardState::NO_SDCARD)) { show_status(PrintDialogStatus::PrintStatusNoSdcard); return; } // check sdcard when if lan mode printer if (obj_->is_lan_mode_printer()) { - if (!obj_->has_sdcard()) { + if (obj_->get_sdcard_state() == MachineObject::SdcardState::NO_SDCARD) { show_status(PrintDialogStatus::PrintStatusLanModeNoSdcard); return; } diff --git a/src/slic3r/GUI/SendToPrinter.cpp b/src/slic3r/GUI/SendToPrinter.cpp index 865f8e5e8..6507e9461 100644 --- a/src/slic3r/GUI/SendToPrinter.cpp +++ b/src/slic3r/GUI/SendToPrinter.cpp @@ -904,7 +904,7 @@ void SendToPrinterDialog::update_show_status() // check sdcard when if lan mode printer /* if (obj_->is_lan_mode_printer()) { }*/ - if (!obj_->has_sdcard()) { + if (obj_->get_sdcard_state() == MachineObject::SdcardState::NO_SDCARD) { show_status(PrintDialogStatus::PrintStatusNoSdcard); return; } diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index cf4ceeb84..441a09a08 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -186,7 +186,10 @@ void StatusBasePanel::init_bitmaps() m_bitmap_extruder_empty_unload = *cache.load_png("monitor_extruder_empty_unload", FromDIP(28), FromDIP(70), false, false); m_bitmap_extruder_filled_unload = *cache.load_png("monitor_extruder_filled_unload", FromDIP(28), FromDIP(70), false, false); m_bitmap_sdcard_state_on = create_scaled_bitmap("sdcard_state_on", nullptr, 20); - m_bitmap_sdcard_state_off = create_scaled_bitmap("sdcard_state_off", nullptr, 20); + m_bitmap_sdcard_state_abnormal = create_scaled_bitmap("sdcard_state_abnormal", nullptr, 20); + m_bitmap_recording = create_scaled_bitmap("recording", nullptr, 20); + m_bitmap_timelapse = create_scaled_bitmap("timelapse", nullptr, 20); + m_bitmap_vcamera = create_scaled_bitmap("vcamera", nullptr, 20); } wxBoxSizer *StatusBasePanel::create_monitoring_page() @@ -223,33 +226,42 @@ wxBoxSizer *StatusBasePanel::create_monitoring_page() //m_bitmap_camera_img->SetMinSize(wxSize(FromDIP(32), FromDIP(18))); //bSizer_monitoring_title->Add(m_bitmap_camera_img, 0, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(5)); - m_bitmap_sdcard_off_img = new wxStaticBitmap(m_panel_monitoring_title, wxID_ANY, m_bitmap_sdcard_state_off, wxDefaultPosition, wxSize(FromDIP(38), FromDIP(24)), 0); - m_bitmap_sdcard_off_img->SetMinSize(wxSize(FromDIP(38), FromDIP(24))); + m_bitmap_sdcard_abnormal_img = new wxStaticBitmap(m_panel_monitoring_title, wxID_ANY, m_bitmap_sdcard_state_abnormal, wxDefaultPosition, wxSize(FromDIP(38), FromDIP(24)), 0); + m_bitmap_sdcard_abnormal_img->SetMinSize(wxSize(FromDIP(38), FromDIP(24))); m_bitmap_sdcard_on_img = new wxStaticBitmap(m_panel_monitoring_title, wxID_ANY, m_bitmap_sdcard_state_on, wxDefaultPosition, wxSize(FromDIP(38), FromDIP(24)), 0); m_bitmap_sdcard_on_img->SetMinSize(wxSize(FromDIP(38), FromDIP(24))); m_bitmap_sdcard_on_img->Hide(); + m_bitmap_sdcard_abnormal_img->Hide(); - m_timelapse_button = new CameraItem(m_panel_monitoring_title, "timelapse_off_normal", "timelapse_on_normal", "timelapse_off_hover", "timelapse_on_hover"); - m_timelapse_button->SetMinSize(wxSize(FromDIP(38), FromDIP(24))); - m_timelapse_button->SetBackgroundColour(STATUS_TITLE_BG); + m_bitmap_timelapse_img = new wxStaticBitmap(m_panel_monitoring_title, wxID_ANY, m_bitmap_timelapse, wxDefaultPosition, wxSize(FromDIP(38), FromDIP(24)), 0); + m_bitmap_timelapse_img->SetMinSize(wxSize(FromDIP(38), FromDIP(24))); + m_bitmap_timelapse_img->Hide(); - m_recording_button = new CameraItem(m_panel_monitoring_title, "recording_off_normal", "recording_on_normal", "recording_off_hover", "recording_on_hover"); - m_recording_button->SetMinSize(wxSize(FromDIP(38), FromDIP(24))); - m_recording_button->SetBackgroundColour(STATUS_TITLE_BG); + m_bitmap_recording_img = new wxStaticBitmap(m_panel_monitoring_title, wxID_ANY, m_bitmap_recording, wxDefaultPosition, wxSize(FromDIP(38), FromDIP(24)), 0); + m_bitmap_recording_img->SetMinSize(wxSize(FromDIP(38), FromDIP(24))); + m_bitmap_timelapse_img->Hide(); - m_vcamera_button = new CameraItem(m_panel_monitoring_title, "vcamera_off_normal", "vcamera_on_normal", "vcamera_off_hover", "vcamera_on_hover"); - m_vcamera_button->SetMinSize(wxSize(FromDIP(38), FromDIP(24))); - m_vcamera_button->SetBackgroundColour(STATUS_TITLE_BG); + m_bitmap_vcamera_img = new wxStaticBitmap(m_panel_monitoring_title, wxID_ANY, m_bitmap_vcamera, wxDefaultPosition, wxSize(FromDIP(38), FromDIP(24)), 0); + m_bitmap_vcamera_img->SetMinSize(wxSize(FromDIP(38), FromDIP(24))); + m_bitmap_vcamera_img->Hide(); - m_timelapse_button->SetToolTip(_L("Timelapse")); - m_recording_button->SetToolTip(_L("Video")); - m_vcamera_button->SetToolTip(_L("Virtual Camera")); + m_setting_button = new CameraItem(m_panel_monitoring_title, "camera_setting", "camera_setting_hover"); + m_setting_button->SetMinSize(wxSize(FromDIP(38), FromDIP(24))); + m_setting_button->SetBackgroundColour(STATUS_TITLE_BG); - bSizer_monitoring_title->Add(m_bitmap_sdcard_off_img, 0, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(5)); + m_bitmap_sdcard_on_img->SetToolTip(_L("SD Card")); + m_bitmap_sdcard_abnormal_img->SetToolTip(_L("SD Card Abnormal")); + m_bitmap_timelapse_img->SetToolTip(_L("Timelapse")); + m_bitmap_recording_img->SetToolTip(_L("Video")); + m_bitmap_vcamera_img->SetToolTip(_L("Virtual Camera")); + m_setting_button->SetToolTip(_L("Camera Setting")); + + bSizer_monitoring_title->Add(m_bitmap_sdcard_abnormal_img, 0, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(5)); bSizer_monitoring_title->Add(m_bitmap_sdcard_on_img, 0, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(5)); - bSizer_monitoring_title->Add(m_timelapse_button, 0, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(5)); - bSizer_monitoring_title->Add(m_recording_button, 0, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(5)); - bSizer_monitoring_title->Add(m_vcamera_button, 0, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(5)); + bSizer_monitoring_title->Add(m_bitmap_timelapse_img, 0, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(5)); + bSizer_monitoring_title->Add(m_bitmap_recording_img, 0, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(5)); + bSizer_monitoring_title->Add(m_bitmap_vcamera_img, 0, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(5)); + bSizer_monitoring_title->Add(m_setting_button, 0, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(5)); bSizer_monitoring_title->Add(FromDIP(13), 0, 0); @@ -1027,39 +1039,46 @@ void StatusBasePanel::show_ams_group(bool show) m_show_ams_group = show; } -void StatusBasePanel::upodate_camera_state(bool recording, bool timelapse, bool has_sdcard) +void StatusPanel::update_img_status(wxStaticBitmap* img, bool on_off) { + if (on_off) + img->Show(); + else + img->Hide(); +} +void StatusPanel::update_camera_state(bool recording, bool timelapse, MachineObject::SdcardState sdcard_state) +{ //sdcard - /* if (has_sdcard && !m_bitmap_sdcard_img->IsShown()) { - m_bitmap_sdcard_img->Show(); - m_panel_monitoring_title->Layout(); + switch (sdcard_state) { + case MachineObject::SdcardState::NO_SDCARD: + m_bitmap_sdcard_on_img->Hide(); + m_bitmap_sdcard_abnormal_img->Hide(); + break; + case MachineObject::SdcardState::HAS_SDCARD_NORMAL: + m_bitmap_sdcard_on_img->Show(); + m_bitmap_sdcard_abnormal_img->Hide(); + break; + case MachineObject::SdcardState::HAS_SDCARD_ABNORMAL: + m_bitmap_sdcard_on_img->Hide(); + m_bitmap_sdcard_abnormal_img->Show(); + break; + default: + ; } - if (!has_sdcard && m_bitmap_sdcard_img->IsShown()) { - m_bitmap_sdcard_img->Hide(); - m_panel_monitoring_title->Layout(); - }*/ - - if (has_sdcard) { - if (m_bitmap_sdcard_off_img->IsShown()) { - m_bitmap_sdcard_on_img->Show(); - m_bitmap_sdcard_off_img->Hide(); - m_panel_monitoring_title->Layout(); - } - } else { - if (m_bitmap_sdcard_on_img->IsShown()) { - m_bitmap_sdcard_on_img->Hide(); - m_bitmap_sdcard_off_img->Show(); - m_panel_monitoring_title->Layout(); - } - } - - //recording - m_recording_button->set_switch(recording); - m_vcamera_button->set_switch(m_media_play_ctrl->IsStreaming()); - + //recording + update_img_status(m_bitmap_recording_img, recording); //timelapse - m_timelapse_button->set_switch(timelapse); + update_img_status(m_bitmap_timelapse_img, timelapse); + //vcamera + update_img_status(m_bitmap_vcamera_img, m_media_play_ctrl->IsStreaming()); + show_vcamera = m_media_play_ctrl->IsStreaming(); + //camera setting + if (m_camera_popup) { + m_camera_popup->update(); + m_camera_popup->sync_vcamera_state(show_vcamera); + } + m_panel_monitoring_title->Layout(); } StatusPanel::StatusPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style, const wxString &name) @@ -1110,10 +1129,8 @@ StatusPanel::StatusPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, co // Connect Events //m_bitmap_thumbnail->Connect(wxEVT_ENTER_WINDOW, wxMouseEventHandler(StatusPanel::on_thumbnail_enter), NULL, this); //m_bitmap_thumbnail->Connect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(StatusPanel::on_thumbnail_leave), NULL, this); - m_recording_button->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(StatusPanel::on_switch_recording), NULL, this); - m_vcamera_button->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(StatusPanel::on_switch_vcamera), NULL, this); + m_setting_button->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(StatusPanel::on_camera_enter), NULL, this); m_project_task_panel->Connect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(StatusPanel::on_thumbnail_leave), NULL, this); - m_button_pause_resume->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_pause_resume), NULL, this); m_button_abort->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_abort), NULL, this); m_button_clean->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_print_error_clean), NULL, this); @@ -1151,8 +1168,7 @@ StatusPanel::~StatusPanel() // Disconnect Events //m_bitmap_thumbnail->Disconnect(wxEVT_ENTER_WINDOW, wxMouseEventHandler(StatusPanel::on_thumbnail_enter), NULL, this); //m_bitmap_thumbnail->Disconnect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(StatusPanel::on_thumbnail_leave), NULL, this); - m_recording_button->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(StatusPanel::on_switch_recording), NULL, this); - m_vcamera_button->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(StatusPanel::on_switch_vcamera), NULL, this); + m_setting_button->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(StatusPanel::on_camera_enter), NULL, this); m_button_pause_resume->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_pause_resume), NULL, this); m_button_abort->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_subtask_abort), NULL, this); m_button_clean->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(StatusPanel::on_print_error_clean), NULL, this); @@ -1181,6 +1197,9 @@ StatusPanel::~StatusPanel() if (abort_dlg != nullptr) delete abort_dlg; + + if (sdcard_hint_dlg != nullptr) + delete sdcard_hint_dlg; } void StatusPanel::init_scaled_buttons() @@ -1388,24 +1407,6 @@ void StatusPanel::update(MachineObject *obj) m_options_btn->Hide(); } - if (obj->is_function_supported(PrinterFunction::FUNC_TIMELAPSE)) { - m_timelapse_button->Show(); - } else { - m_timelapse_button->Hide(); - } - - if (obj->is_function_supported(PrinterFunction::FUNC_RECORDING) || obj->has_ipcam) { - m_recording_button->Show(); - } else { - m_recording_button->Hide(); - } - - if (obj->is_function_supported(PrinterFunction::FUNC_VIRTUAL_CAMERA) && obj->has_ipcam) { - m_vcamera_button->Show(); - } else { - m_vcamera_button->Hide(); - } - if (obj->is_function_supported(PrinterFunction::FUNC_CHAMBER_TEMP)) { m_tempCtrl_frame->Enable(); } else { @@ -1417,7 +1418,8 @@ void StatusPanel::update(MachineObject *obj) update_error_message(); } - upodate_camera_state(obj->is_recording_enable(), obj->has_timelapse(), obj->has_sdcard()); + update_camera_state(obj->is_recording_enable(), obj->has_timelapse(), obj->get_sdcard_state()); + m_machine_ctrl_panel->Thaw(); } @@ -2552,25 +2554,30 @@ void StatusPanel::on_thumbnail_leave(wxMouseEvent &event) } } -void StatusPanel::on_switch_recording(wxMouseEvent &event) -{ - if (!obj) return; - bool value = m_recording_button->get_switch_status(); - obj->command_ipcam_record(!value); -} - void StatusPanel::on_switch_vcamera(wxMouseEvent &event) { //if (!obj) return; //bool value = m_recording_button->get_switch_status(); //obj->command_ipcam_record(!value); m_media_play_ctrl->ToggleStream(); + show_vcamera = m_media_play_ctrl->IsStreaming(); + if (m_camera_popup) + m_camera_popup->sync_vcamera_state(show_vcamera); } void StatusPanel::on_camera_enter(wxMouseEvent& event) { if (obj) { m_camera_popup = std::make_shared(this, obj); + m_camera_popup->sync_vcamera_state(show_vcamera); + m_camera_popup->Bind(EVT_VCAMERA_SWITCH, &StatusPanel::on_switch_vcamera, this); + m_camera_popup->Bind(EVT_SDCARD_ABSENT_HINT, [this](wxCommandEvent &e) { + if (sdcard_hint_dlg == nullptr) { + sdcard_hint_dlg = new SecondaryCheckDialog(this->GetParent(), wxID_ANY, _L("Warning"), SecondaryCheckDialog::ButtonStyle::ONLY_CONFIRM); + sdcard_hint_dlg->update_text(_L("Can't start this without SD card.")); + } + sdcard_hint_dlg->on_show(); + }); wxWindow* ctrl = (wxWindow*)event.GetEventObject(); wxPoint pos = ctrl->ClientToScreen(wxPoint(0, 0)); wxSize sz = ctrl->GetSize(); @@ -2654,9 +2661,10 @@ void StatusPanel::set_default() m_show_ams_group = false; reset_printing_values(); - m_timelapse_button->Show(); - m_recording_button->Show(); - m_vcamera_button->Show(); + m_bitmap_timelapse_img->Hide(); + m_bitmap_recording_img->Hide(); + m_bitmap_vcamera_img->Hide(); + m_setting_button->Show(); m_tempCtrl_frame->Show(); m_options_btn->Show(); @@ -2730,10 +2738,11 @@ void StatusPanel::msw_rescale() //m_bitmap_camera_img->SetBitmap(m_bitmap_camera); //m_bitmap_camera_img->SetMinSize(wxSize(FromDIP(32), FromDIP(18))); - m_timelapse_button->SetMinSize(wxSize(38, 24)); - m_recording_button->SetMinSize(wxSize(38, 24)); - m_vcamera_button->SetMinSize(wxSize(38, 24)); - m_bitmap_sdcard_off_img->SetMinSize(wxSize(FromDIP(38), FromDIP(24))); + m_bitmap_timelapse_img->SetMinSize(wxSize(38, 24)); + m_bitmap_recording_img->SetMinSize(wxSize(38, 24)); + m_bitmap_vcamera_img->SetMinSize(wxSize(38, 24)); + m_setting_button->SetMinSize(wxSize(38, 24)); + m_bitmap_sdcard_abnormal_img->SetMinSize(wxSize(FromDIP(38), FromDIP(24))); m_bitmap_sdcard_on_img->SetMinSize(wxSize(FromDIP(38), FromDIP(24))); m_bpButton_xy->Rescale(); diff --git a/src/slic3r/GUI/StatusPanel.hpp b/src/slic3r/GUI/StatusPanel.hpp index 1488ffd6a..fb7d2043b 100644 --- a/src/slic3r/GUI/StatusPanel.hpp +++ b/src/slic3r/GUI/StatusPanel.hpp @@ -90,13 +90,14 @@ protected: CameraTimelapseStatus m_state_timelapse{CameraTimelapseStatus::TIMELAPSE_NONE}; - CameraItem *m_timelapse_button; - CameraItem *m_recording_button; - CameraItem *m_vcamera_button; + CameraItem *m_setting_button; wxBitmap m_bitmap_camera; wxBitmap m_bitmap_sdcard_state_on; - wxBitmap m_bitmap_sdcard_state_off; + wxBitmap m_bitmap_sdcard_state_abnormal; + wxBitmap m_bitmap_recording; + wxBitmap m_bitmap_timelapse; + wxBitmap m_bitmap_vcamera; /* title panel */ wxPanel * media_ctrl_panel; @@ -112,8 +113,10 @@ protected: wxStaticBitmap *m_bitmap_camera_img; wxStaticBitmap *m_bitmap_recording_img; + wxStaticBitmap *m_bitmap_timelapse_img; + wxStaticBitmap* m_bitmap_vcamera_img; wxStaticBitmap *m_bitmap_sdcard_on_img; - wxStaticBitmap *m_bitmap_sdcard_off_img; + wxStaticBitmap *m_bitmap_sdcard_abnormal_img; wxStaticBitmap *m_bitmap_static_use_time; wxStaticBitmap *m_bitmap_static_use_weight; @@ -239,7 +242,6 @@ public: wxBoxSizer *create_settings_group(wxWindow *parent); void show_ams_group(bool show = true); - void upodate_camera_state(bool recording, bool timelapse, bool has_sdcard); }; @@ -259,6 +261,7 @@ protected: AMSMaterialsSetting *m_filament_setting_dlg{nullptr}; SecondaryCheckDialog* m_print_error_dlg = nullptr; SecondaryCheckDialog* abort_dlg = nullptr; + SecondaryCheckDialog* sdcard_hint_dlg = nullptr; wxString m_request_url; bool m_start_loading_thumbnail = false; @@ -323,7 +326,6 @@ protected: void on_nozzle_fan_switch(wxCommandEvent &event); void on_thumbnail_enter(wxMouseEvent &event); void on_thumbnail_leave(wxMouseEvent &event); - void on_switch_recording(wxMouseEvent &event); void on_switch_vcamera(wxMouseEvent &event); void on_camera_enter(wxMouseEvent &event); void on_camera_leave(wxMouseEvent& event); @@ -355,6 +357,11 @@ protected: void on_webrequest_state(wxWebRequestEvent &evt); bool is_task_changed(MachineObject* obj); + /* camera */ + void update_camera_state(bool recording, bool timelapse, MachineObject::SdcardState sdcard_state); + void update_img_status(wxStaticBitmap* img, bool on_off); + bool show_vcamera = false; + public: StatusPanel(wxWindow * parent, wxWindowID id = wxID_ANY,