mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-08-05 21:14:01 -06:00
NEW: management camera video stream in device panel
Change-Id: I39634af900071cc5c01a88100457880a513e416f
This commit is contained in:
parent
1068baf10e
commit
4d4fcc1780
24 changed files with 334 additions and 56 deletions
|
@ -70,6 +70,7 @@ enum PrinterFunction {
|
|||
FUNC_REMOTE_TUNNEL,
|
||||
FUNC_LOCAL_TUNNEL,
|
||||
FUNC_PRINT_WITHOUT_SD,
|
||||
FUNC_VIRTUAL_CAMERA,
|
||||
FUNC_MAX
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)));
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -48,6 +48,10 @@ public:
|
|||
|
||||
void SetCanFocus(bool canFocus) override;
|
||||
|
||||
void SetValue(bool state);
|
||||
|
||||
bool GetValue() const;
|
||||
|
||||
void Rescale();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
|
||||
int states() const { return states_ | states2_; }
|
||||
|
||||
void set_state(int state, int mask);
|
||||
|
||||
private:
|
||||
StateHandler(StateHandler * parent, wxWindow *owner);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue