NEW: management camera video stream in device panel

Change-Id: I39634af900071cc5c01a88100457880a513e416f
This commit is contained in:
chunmao.guo 2022-09-19 09:50:34 +08:00 committed by Lane.Wei
parent 1068baf10e
commit 4d4fcc1780
24 changed files with 334 additions and 56 deletions

View file

@ -70,6 +70,7 @@ enum PrinterFunction {
FUNC_REMOTE_TUNNEL,
FUNC_LOCAL_TUNNEL,
FUNC_PRINT_WITHOUT_SD,
FUNC_VIRTUAL_CAMERA,
FUNC_MAX
};

View file

@ -141,12 +141,12 @@ bool DownloadProgressDialog::Show(bool show)
{
if (show) {
m_simplebook_status->SetSelection(0);
m_upgrade_job = std::make_shared<UpgradeNetworkJob>(m_status_bar);
m_upgrade_job = make_job(m_status_bar);
m_upgrade_job->set_event_handle(this);
m_status_bar->set_progress(0);
Bind(EVT_UPGRADE_NETWORK_SUCCESS, [this](wxCommandEvent& evt) {
m_status_bar->change_button_label(_L("Finish"));
wxGetApp().restart_networking();
on_finish();
m_status_bar->set_cancel_callback_fina(
[this]() {
this->Close();
@ -205,4 +205,8 @@ void DownloadProgressDialog::on_dpi_changed(const wxRect &suggested_rect) {}
void DownloadProgressDialog::update_release_note(std::string release_note, std::string version) {}
std::shared_ptr<UpgradeNetworkJob> DownloadProgressDialog::make_job(std::shared_ptr<ProgressIndicator> pri) { return std::make_shared<UpgradeNetworkJob>(pri); }
void DownloadProgressDialog::on_finish() { wxGetApp().restart_networking(); }
}} // namespace Slic3r::GUI

View file

@ -50,7 +50,9 @@ public:
std::shared_ptr<UpgradeNetworkJob> m_upgrade_job { nullptr };
wxPanel * m_panel_download;
protected:
virtual std::shared_ptr<UpgradeNetworkJob> make_job(std::shared_ptr<ProgressIndicator> pri);
virtual void on_finish();
};

View file

@ -1257,13 +1257,13 @@ std::string GUI_App::get_http_url(std::string country_code)
return url;
}
std::string GUI_App::get_plugin_url(std::string country_code)
std::string GUI_App::get_plugin_url(std::string name, std::string country_code)
{
std::string url = get_http_url(country_code);
std::string curr_version = SLIC3R_VERSION;
std::string using_version = curr_version.substr(0, 9) + "00";
url += (boost::format("?slicer/plugins/cloud=%1%") % using_version).str();
url += (boost::format("?slicer/%1%/cloud=%2%") % name % using_version).str();
//url += (boost::format("?slicer/plugins/cloud=%1%") % "01.01.00.00").str();
return url;
}
@ -1283,7 +1283,7 @@ static std::string decode(std::string const& extra, std::string const& path = {}
return Slic3r::decode_path(path.c_str());
}
int GUI_App::download_plugin(InstallProgressFn pro_fn, WasCancelledFn cancel_fn)
int GUI_App::download_plugin(std::string name, std::string package_name, InstallProgressFn pro_fn, WasCancelledFn cancel_fn)
{
int result = 0;
// get country_code
@ -1294,12 +1294,12 @@ int GUI_App::download_plugin(InstallProgressFn pro_fn, WasCancelledFn cancel_fn)
BOOST_LOG_TRIVIAL(info) << "[download_plugin]: enter";
m_networking_cancel_update = false;
// get temp path
fs::path target_file_path = (fs::temp_directory_path() / "network_plugin.zip");
fs::path target_file_path = (fs::temp_directory_path() / package_name);
fs::path tmp_path = target_file_path;
tmp_path += format(".%1%%2%", get_current_pid(), ".tmp");
// get_url
std::string url = get_plugin_url(app_config->get_country_code());
std::string url = get_plugin_url(name, app_config->get_country_code());
std::string download_url;
Slic3r::Http http_url = Slic3r::Http::get(url);
BOOST_LOG_TRIVIAL(info) << "[download_plugin]: check the plugin from " << url;
@ -1418,16 +1418,16 @@ int GUI_App::download_plugin(InstallProgressFn pro_fn, WasCancelledFn cancel_fn)
return result;
}
int GUI_App::install_plugin(InstallProgressFn pro_fn, WasCancelledFn cancel_fn)
int GUI_App::install_plugin(std::string name, std::string package_name, InstallProgressFn pro_fn, WasCancelledFn cancel_fn)
{
bool cancel = false;
std::string target_file_path = (fs::temp_directory_path() / "network_plugin.zip").string();
std::string target_file_path = (fs::temp_directory_path() / package_name).string();
BOOST_LOG_TRIVIAL(info) << "[install_plugin] enter";
// get plugin folder
std::string data_dir_str = data_dir();
boost::filesystem::path data_dir_path(data_dir_str);
auto plugin_folder = data_dir_path / "plugins";
auto plugin_folder = data_dir_path / name;
//auto plugin_folder = boost::filesystem::path(wxStandardPaths::Get().GetUserDataDir().ToUTF8().data()) / "plugins";
auto backup_folder = plugin_folder/"backup";
if (!boost::filesystem::exists(plugin_folder)) {
@ -1534,7 +1534,8 @@ int GUI_App::install_plugin(InstallProgressFn pro_fn, WasCancelledFn cancel_fn)
if (pro_fn)
pro_fn(InstallStatusInstallCompleted, 100, cancel);
app_config->set_str("app", "installed_networking", "1");
if (name == "plugins")
app_config->set_str("app", "installed_networking", "1");
BOOST_LOG_TRIVIAL(info) << "[install_plugin] success";
return 0;
}

View file

@ -534,9 +534,9 @@ public:
void associate_files(std::wstring extend);
void disassociate_files(std::wstring extend);
#endif // __WXMSW__
std::string get_plugin_url(std::string country_code);
int download_plugin(InstallProgressFn pro_fn = nullptr, WasCancelledFn cancel_fn = nullptr);
int install_plugin(InstallProgressFn pro_fn = nullptr, WasCancelledFn cancel_fn = nullptr);
std::string get_plugin_url(std::string name, std::string country_code);
int download_plugin(std::string name, std::string package_name, InstallProgressFn pro_fn = nullptr, WasCancelledFn cancel_fn = nullptr);
int install_plugin(std::string name, std::string package_name, InstallProgressFn pro_fn = nullptr, WasCancelledFn cancel_fn = nullptr);
std::string get_http_url(std::string country_code);
bool is_compatibility_version();
bool check_networking_version();

View file

@ -16,7 +16,8 @@ wxDEFINE_EVENT(EVT_INSTALL_NETWORK_FAILED, wxCommandEvent);
UpgradeNetworkJob::UpgradeNetworkJob(std::shared_ptr<ProgressIndicator> pri)
: Job{std::move(pri)}
{
;
name = "plugins";
package_name = "networking_plugins.zip";
}
void UpgradeNetworkJob::on_exception(const std::exception_ptr &eptr)
@ -56,7 +57,7 @@ void UpgradeNetworkJob::process()
BOOST_LOG_TRIVIAL(info) << "[UpgradeNetworkJob process]: enter";
// get temp path
fs::path target_file_path = (fs::temp_directory_path() / "network_plugin.zip");
fs::path target_file_path = (fs::temp_directory_path() / package_name);
fs::path tmp_path = target_file_path;
auto path_str = tmp_path.string() + wxString::Format(".%d%s", get_current_pid(), ".tmp").ToStdString();
tmp_path = fs::path(path_str);
@ -67,7 +68,7 @@ void UpgradeNetworkJob::process()
return was_canceled();
};
int curr_percent = 0;
result = wxGetApp().download_plugin(
result = wxGetApp().download_plugin(name, package_name,
[this, &curr_percent](int state, int percent, bool &cancel) {
if (state == InstallStatusNormal) {
update_status(percent, _L("Downloading"));
@ -95,7 +96,9 @@ void UpgradeNetworkJob::process()
return;
}
result = wxGetApp().install_plugin([this](int state, int percent, bool&cancel) {
result = wxGetApp().install_plugin(
name, package_name,
[this](int state, int percent, bool &cancel) {
if (state == InstallStatusInstallCompleted) {
update_status(percent, _L("Finish"));
} else {

View file

@ -29,6 +29,9 @@ class UpgradeNetworkJob : public Job
InstallProgressFn pro_fn { nullptr };
protected:
std::string name;
std::string package_name;
void on_exception(const std::exception_ptr &) override;
public:
UpgradeNetworkJob(std::shared_ptr<ProgressIndicator> pri);

View file

@ -125,13 +125,7 @@ MediaFilePanel::MediaFilePanel(wxWindow * parent)
m_button_year->Bind(wxEVT_COMMAND_BUTTON_CLICKED, time_button_clicked);
m_button_month->Bind(wxEVT_COMMAND_BUTTON_CLICKED, time_button_clicked);
m_button_all->Bind(wxEVT_COMMAND_BUTTON_CLICKED, time_button_clicked);
{
wxCommandEvent e(wxEVT_CHECKBOX);
auto b = m_button_all;
e.SetEventObject(b);
b->GetEventHandler()->ProcessEvent(e);
}
m_button_all->SetValue(true);
// File type
auto type_button_clicked = [this](wxEvent &e) {
@ -143,26 +137,12 @@ MediaFilePanel::MediaFilePanel(wxWindow * parent)
return;
m_image_grid->SetFileType(type);
m_last_type = type;
{
wxCommandEvent e(wxEVT_CHECKBOX);
e.SetEventObject(m_button_timelapse);
m_button_timelapse->GetEventHandler()->ProcessEvent(e);
}
{
wxCommandEvent e(wxEVT_CHECKBOX);
e.SetEventObject(m_button_video);
m_button_video->GetEventHandler()->ProcessEvent(e);
}
m_button_timelapse->SetValue(!m_button_timelapse->GetValue());
m_button_video->SetValue(!m_button_video->GetValue());
};
m_button_video->Bind(wxEVT_COMMAND_BUTTON_CLICKED, type_button_clicked);
m_button_timelapse->Bind(wxEVT_COMMAND_BUTTON_CLICKED, type_button_clicked);
{
wxCommandEvent e(wxEVT_CHECKBOX);
auto b = m_button_timelapse;
e.SetEventObject(b);
b->GetEventHandler()->ProcessEvent(e);
}
m_button_timelapse->SetValue(true);
// File management
m_button_management->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](auto &e) {
@ -310,15 +290,12 @@ void MediaFilePanel::modeChanged(wxCommandEvent& e1)
if (m_last_mode == mode)
return;
::Button* buttons[] = {m_button_all, m_button_month, m_button_year};
wxCommandEvent e(wxEVT_CHECKBOX);
auto b = buttons[m_last_mode];
b->SetFont(Label::Body_14);
e.SetEventObject(b);
b->GetEventHandler()->ProcessEvent(e);
b->SetValue(false);
b = buttons[mode];
b->SetFont(Label::Head_14);
e.SetEventObject(b);
b->GetEventHandler()->ProcessEvent(e);
b->SetValue(true);
m_last_mode = mode;
}

View file

@ -5,6 +5,21 @@
#include "GUI_App.hpp"
#include "libslic3r/AppConfig.hpp"
#include "I18N.hpp"
#include "MsgDialog.hpp"
#include "DownloadProgressDialog.hpp"
#undef pid_t
#include <boost/process.hpp>
#ifdef __WIN32__
#include <boost/process/windows.hpp>
#elif __APPLE__
#include <sys/ipc.h>
#include <sys/shm.h>
#else
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#endif
namespace Slic3r {
namespace GUI {
@ -21,8 +36,7 @@ MediaPlayCtrl::MediaPlayCtrl(wxWindow *parent, wxMediaCtrl2 *media_ctrl, const w
m_label_status = new Label(this, "", LB_HYPERLINK);
m_button_play->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](auto & e) { TogglePlay(); });
m_button_play->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](auto &e) { TogglePlay(); });
m_button_play->Bind(wxEVT_RIGHT_UP, [this](auto & e) { m_media_ctrl->Play(); });
m_label_status->Bind(wxEVT_LEFT_UP, [this](auto &e) {
auto url = wxString::Format(L"https://wiki.bambulab.com/%s/software/bambu-studio/faq/live-view", L"en");
@ -90,6 +104,12 @@ void MediaPlayCtrl::SetMachineObject(MachineObject* obj)
}
m_machine = machine;
m_failed_retry = 0;
std::string stream_url;
if (get_stream_url(&stream_url)) {
m_streaming = boost::algorithm::contains(stream_url, "device=" + m_machine);
} else {
m_streaming = false;
}
if (m_last_state != MEDIASTATE_IDLE)
Stop();
if (m_next_retry.IsValid())
@ -217,6 +237,127 @@ void MediaPlayCtrl::TogglePlay()
}
}
struct detach_process
#ifdef __WIN32__
: public ::boost::process::detail::windows::handler_base_ext
#else
: public ::boost::process::detail::posix::handler_base_ext
#endif
{
#ifdef __WIN32__
template<class Executor> void on_setup(Executor &exec) const {
exec.creation_flags |= ::boost::winapi::CREATE_NO_WINDOW_;
}
#endif
};
void MediaPlayCtrl::ToggleStream()
{
std::string file_url = data_dir() + "/cameratools/url.txt";
if (m_streaming) {
boost::nowide::ofstream file(file_url);
file.close();
m_streaming = false;
return;
} else if (!boost::filesystem::exists(file_url)) {
boost::nowide::ofstream file(file_url);
file.close();
}
std::string url;
if (!get_stream_url(&url)) {
// create stream pipeline
#ifdef __WIN32__
std::string file_source = data_dir() + "\\cameratools\\bambu_source.exe";
std::string file_ffmpeg = data_dir() + "\\cameratools\\ffmpeg.exe";
std::string file_ff_cfg = data_dir() + "\\cameratools\\ffmpeg.cfg";
#else
std::string file_source = data_dir() + "/cameratools/bambu_source";
std::string file_ffmpeg = data_dir() + "/cameratools/ffmpeg";
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"),
wxOK | wxCANCEL).ShowModal();
if (res == wxID_OK) {
// download tools
struct DownloadProgressDialog2 : DownloadProgressDialog
{
MediaPlayCtrl *ctrl;
DownloadProgressDialog2(MediaPlayCtrl *ctrl) : DownloadProgressDialog(_L("Downloading Virtual Camera Tools")), ctrl(ctrl) {}
struct UpgradeNetworkJob2 : UpgradeNetworkJob
{
UpgradeNetworkJob2(std::shared_ptr<ProgressIndicator> pri) : UpgradeNetworkJob(pri) {
name = "cameratools";
package_name = "camera_tools.zip";
}
};
std::shared_ptr<UpgradeNetworkJob> make_job(std::shared_ptr<ProgressIndicator> pri) override
{ return std::make_shared<UpgradeNetworkJob2>(pri); }
void on_finish() override
{
wxGetApp().CallAfter([ctrl = this->ctrl] { ctrl->ToggleStream(); });
EndModal(wxID_CLOSE);
}
};
DownloadProgressDialog2 dlg(this);
dlg.ShowModal();
}
return;
}
wxString url = L"bambu:///camera/" + from_u8(file_url);
url.Replace("\\", "/");
url = wxURI(url).BuildURI();
std::string configs;
try {
boost::filesystem::load_string_file(file_ff_cfg, configs);
} catch (...) {}
std::vector<std::string> configss;
boost::algorithm::split(configss, configs, boost::algorithm::is_any_of("\r\n"));
configss.erase(std::remove(configss.begin(), configss.end(), std::string()), configss.end());
boost::process::pipe intermediate;
boost::process::child process_source(file_source, url.data().AsInternal(), boost::process::std_out > intermediate, detach_process(),
boost::process::start_dir(boost::filesystem::path(data_dir()) / "plugins"));
boost::process::child process_ffmpeg(file_ffmpeg, configss, boost::process::std_in < intermediate, detach_process());
process_source.detach();
process_ffmpeg.detach();
}
if (!url.empty() && wxGetApp().app_config->get("not_show_vcamera_stop_prev") != "1") {
MessageDialog dlg(this, _L("Another virtual camera is running.\nBambu Studio supports only a single virtual camera.\nDo you want to stop this virtual camera?"), _L("Warning"),
wxYES | wxCANCEL | wxICON_INFORMATION);
dlg.show_dsa_button();
auto res = dlg.ShowModal();
if (dlg.get_checkbox_state())
wxGetApp().app_config->set("not_show_vcamera_stop_prev", "1");
if (res == wxID_CANCEL) return;
}
NetworkAgent *agent = wxGetApp().getAgent();
if (!agent) return;
agent->get_camera_url(m_machine, [this, m = m_machine](std::string url) {
BOOST_LOG_TRIVIAL(info) << "camera_url: " << url;
CallAfter([this, m, url] {
if (m != m_machine || url.empty()) return;
std::string file_url = data_dir() + "/cameratools/url.txt";
boost::nowide::ofstream file(file_url);
auto url2 = encode_path((url + "&device=" + m).c_str());
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);
}
}
});
});
}
void MediaPlayCtrl::SetStatus(wxString const &msg2, bool hyperlink)
{
auto msg = wxString::Format(msg2, m_failed_code);
@ -236,6 +377,8 @@ void MediaPlayCtrl::SetStatus(wxString const &msg2, bool hyperlink)
Layout();
}
bool MediaPlayCtrl::IsStreaming() const { return m_streaming; }
void MediaPlayCtrl::media_proc()
{
boost::unique_lock lock(m_mutex);
@ -270,6 +413,54 @@ void MediaPlayCtrl::media_proc()
}
}
bool MediaPlayCtrl::get_stream_url(std::string *url)
{
#ifdef __WIN32__
HANDLE shm = ::OpenFileMapping(FILE_MAP_READ, FALSE, L"bambu_stream_url");
if (shm == NULL) return false;
if (url) {
char *addr = (char *) MapViewOfFile(shm, FILE_MAP_READ, 0, 0, 0);
if (addr) {
*url = addr;
UnmapViewOfFile(addr);
url = nullptr;
}
}
CloseHandle(shm);
#elif __APPLE__
std::string file_url = data_dir() + "/url.txt";
key_t key = ::ftok(file_url.c_str(), 1000);
int shm = ::shmget(key, 1024, 0);
if (shm == -1) return false;
struct shmid_ds ds;
::shmctl(shm, IPC_STAT, &ds);
if (ds.shm_nattch == 0) {
return false;
}
if (url) {
char *addr = (char *) ::shmat(shm, nullptr, 0);
if (addr != (void*) -1) {
*url = addr;
::shmdt(addr);
url = nullptr;
}
}
#else
int shm = ::shm_open("bambu_stream_url", O_RDONLY, 0);
if (shm == -1) return false;
if (url) {
char *addr = (char *) ::mmap(nullptr, 1024, PROT_READ, MAP_SHARED, shm, 0);
if (addr != MAP_FAILED) {
*url = addr;
::munmap(addr, 1024);
url = nullptr;
}
}
::close(shm);
#endif
return url == nullptr;
}
void MediaPlayCtrl::onStateChanged(wxMediaEvent& event)
{
auto last_state = m_last_state;

View file

@ -35,6 +35,10 @@ public:
void SetMachineObject(MachineObject * obj);
bool IsStreaming() const;
void ToggleStream();
protected:
void onStateChanged(wxMediaEvent & event);
@ -49,6 +53,8 @@ protected:
private:
void media_proc();
bool get_stream_url(std::string * url = nullptr);
private:
static constexpr wxMediaState MEDIASTATE_IDLE = (wxMediaState) 3;
static constexpr wxMediaState MEDIASTATE_INITIALIZING = (wxMediaState) 4;
@ -71,11 +77,12 @@ private:
boost::condition_variable m_cond;
boost::thread m_thread;
bool m_streaming = false;
int m_failed_retry = 0;
int m_failed_code = 0;
wxDateTime m_next_retry;
::Button * m_button_play;
::Button *m_button_play;
::Label * m_label_status;
};

View file

@ -566,7 +566,7 @@ void NetworkTestDialog::start_test_oss_download()
tmp_path += (boost::format(".%1%%2%") % get_current_pid() % ".tmp").str();
// get_url
std::string url = wxGetApp().get_plugin_url(app_config->get_country_code());
std::string url = wxGetApp().get_plugin_url("plugins", app_config->get_country_code());
std::string download_url;
Slic3r::Http http_url = Slic3r::Http::get(url);
update_status(-1, "[test_oss_download]: url=" + url);

View file

@ -8318,7 +8318,7 @@ int GUI::Plater::close_with_confirm(std::function<bool(bool)> second_check)
auto result = MessageDialog(static_cast<wxWindow*>(this), _L("The current project has unsaved changes, save it before continue?"),
wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Save"), wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxCENTRE).ShowModal();
if (result == wxID_CANCEL)
return result;
return result;
else if (result == wxID_YES) {
result = save_project();
if (result == wxID_CANCEL)

View file

@ -235,13 +235,19 @@ wxBoxSizer *StatusBasePanel::create_monitoring_page()
m_recording_button->SetMinSize(wxSize(FromDIP(38), FromDIP(24)));
m_recording_button->SetBackgroundColour(STATUS_TITLE_BG);
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_timelapse_button->SetToolTip(_L("Timelapse"));
m_recording_button->SetToolTip(_L("Video"));
m_vcamera_button->SetToolTip(_L("Virtual Camera"));
bSizer_monitoring_title->Add(m_bitmap_sdcard_off_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(FromDIP(13), 0, 0);
@ -1029,6 +1035,7 @@ void StatusBasePanel::upodate_camera_state(bool recording, bool timelapse, bool
//recording
m_recording_button->set_switch(recording);
m_vcamera_button->set_switch(m_media_play_ctrl->IsStreaming());
//timelapse
m_timelapse_button->set_switch(timelapse);
@ -1083,6 +1090,7 @@ StatusPanel::StatusPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, co
//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_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);
@ -1123,6 +1131,7 @@ StatusPanel::~StatusPanel()
//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_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_subtask_clean), NULL, this);
@ -1355,6 +1364,12 @@ void StatusPanel::update(MachineObject *obj)
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 {
@ -2489,6 +2504,14 @@ void StatusPanel::on_switch_recording(wxMouseEvent &event)
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();
}
void StatusPanel::on_camera_enter(wxMouseEvent& event)
{
if (obj) {
@ -2578,6 +2601,7 @@ void StatusPanel::set_default()
m_timelapse_button->Show();
m_recording_button->Show();
m_vcamera_button->Show();
m_tempCtrl_frame->Show();
m_options_btn->Show();
@ -2652,6 +2676,7 @@ void StatusPanel::msw_rescale()
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_sdcard_on_img->SetMinSize(wxSize(FromDIP(38), FromDIP(24)));

View file

@ -91,6 +91,7 @@ protected:
CameraItem *m_timelapse_button;
CameraItem *m_recording_button;
CameraItem *m_vcamera_button;
wxBitmap m_bitmap_camera;
wxBitmap m_bitmap_sdcard_state_on;
@ -319,6 +320,7 @@ protected:
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);
void on_auto_leveling(wxCommandEvent &event);

View file

@ -309,12 +309,14 @@ void DownPluginFrame::OnScriptResponseMessage(wxCommandEvent &WXUNUSED(evt))
int DownPluginFrame::DownloadPlugin()
{
return wxGetApp().download_plugin([this](int status, int percent, bool &cancel) { return ShowPluginStatus(status, percent, cancel); }, nullptr);
return wxGetApp().download_plugin(
"plugins", "network_plugin.zip", [this](int status, int percent, bool &cancel) { return ShowPluginStatus(status, percent, cancel); }, nullptr);
}
int DownPluginFrame::InstallPlugin()
{
return wxGetApp().install_plugin([this](int status, int percent, bool &cancel) { return ShowPluginStatus(status, percent, cancel); });
return wxGetApp().install_plugin(
"plugins", "network_plugin.zip", [this](int status, int percent, bool &cancel) { return ShowPluginStatus(status, percent, cancel); });
}
int DownPluginFrame::ShowPluginStatus(int status, int percent, bool &cancel)

View file

@ -1509,6 +1509,7 @@ bool GuideFrame::LoadFile(std::string jPath, std::string &sContent)
int GuideFrame::DownloadPlugin()
{
return wxGetApp().download_plugin(
"plugins", "network_plugin.zip",
[this](int status, int percent, bool& cancel) {
return ShowPluginStatus(status, percent, cancel);
}
@ -1517,7 +1518,7 @@ int GuideFrame::DownloadPlugin()
int GuideFrame::InstallPlugin()
{
return wxGetApp().install_plugin(
return wxGetApp().install_plugin("plugins", "network_plugin.zip",
[this](int status, int percent, bool &cancel) {
return ShowPluginStatus(status, percent, cancel);
}

View file

@ -127,6 +127,14 @@ bool Button::Enable(bool enable)
void Button::SetCanFocus(bool canFocus) { this->canFocus = canFocus; }
void Button::SetValue(bool state)
{
if (GetValue() == state) return;
state_handler.set_state(state ? StateHandler::Checked : 0, StateHandler::Checked);
}
bool Button::GetValue() const { return state_handler.states() & StateHandler::Checked; }
void Button::Rescale()
{
if (this->active_icon.bmp().IsOk())

View file

@ -48,6 +48,10 @@ public:
void SetCanFocus(bool canFocus) override;
void SetValue(bool state);
bool GetValue() const;
void Rescale();
protected:

View file

@ -69,6 +69,19 @@ void StateHandler::update_binds()
for (auto &c : children_) c->update_binds();
}
void StateHandler::set_state(int state, int mask)
{
if (states_ & mask == state & mask) return;
int old = states_;
states_ = states_ & ~mask | state & mask;
if (old != states_ && (old | states2_) != (states_ | states2_)) {
if (parent_)
parent_->changed(states_ | states2_);
else
owner_->Refresh();
}
}
StateHandler::StateHandler(StateHandler *parent, wxWindow *owner)
: StateHandler(owner)
{

View file

@ -41,6 +41,8 @@ public:
int states() const { return states_ | states2_; }
void set_state(int state, int mask);
private:
StateHandler(StateHandler * parent, wxWindow *owner);