FIX: support more device components

jira: [STUDIO-9275]
Change-Id: I8105828183d42496eed77793daa1c1a618e252bf
This commit is contained in:
xin.zhang 2025-01-02 16:01:54 +08:00 committed by lane.wei
parent c141ed25f5
commit 478fc597c4
10 changed files with 804 additions and 2 deletions

177
resources/images/cut.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 63 KiB

249
resources/images/laser.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 147 KiB

View File

@ -546,6 +546,8 @@ set(SLIC3R_GUI_SOURCES
Utils/FontUtils.hpp Utils/FontUtils.hpp
) )
add_subdirectory(GUI/DeviceTab)
if (WIN32) if (WIN32)
list(APPEND SLIC3R_GUI_SOURCES list(APPEND SLIC3R_GUI_SOURCES
GUI/dark_mode/dark_mode.hpp GUI/dark_mode/dark_mode.hpp

View File

@ -1409,6 +1409,24 @@ std::map<int, MachineObject::ModuleVersionInfo> MachineObject::get_ams_version()
return result; return result;
} }
void MachineObject::store_version_info(const ModuleVersionInfo& info)
{
if (info.isAirPump())
{
air_pump_version_info = info;
}
else if (info.isLaszer())
{
laser_version_info = info;
}
else if (info.isCuttingModule())
{
cutting_module_version_info = info;
}
module_vers.emplace(info.name, info);
}
bool MachineObject::is_system_printing() bool MachineObject::is_system_printing()
{ {
if (is_in_calibration() && is_in_printing_status(print_status)) if (is_in_calibration() && is_in_printing_status(print_status))
@ -3177,6 +3195,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only)
for (auto it = j_module.begin(); it != j_module.end(); it++) { for (auto it = j_module.begin(); it != j_module.end(); it++) {
ModuleVersionInfo ver_info; ModuleVersionInfo ver_info;
ver_info.name = (*it)["name"].get<std::string>(); ver_info.name = (*it)["name"].get<std::string>();
ver_info.product_name = wxString::FromUTF8((*it).value("product_name", json()).get<string>());
if ((*it).contains("sw_ver")) if ((*it).contains("sw_ver"))
ver_info.sw_ver = (*it)["sw_ver"].get<std::string>(); ver_info.sw_ver = (*it)["sw_ver"].get<std::string>();
if ((*it).contains("sn")) if ((*it).contains("sn"))
@ -3185,7 +3204,8 @@ int MachineObject::parse_json(std::string payload, bool key_field_only)
ver_info.hw_ver = (*it)["hw_ver"].get<std::string>(); ver_info.hw_ver = (*it)["hw_ver"].get<std::string>();
if((*it).contains("flag")) if((*it).contains("flag"))
ver_info.firmware_status= (*it)["flag"].get<int>(); ver_info.firmware_status= (*it)["flag"].get<int>();
module_vers.emplace(ver_info.name, ver_info);
store_version_info(ver_info);
if (ver_info.name == "ota") { if (ver_info.name == "ota") {
NetworkAgent* agent = GUI::wxGetApp().getAgent(); NetworkAgent* agent = GUI::wxGetApp().getAgent();
if (agent) { if (agent) {

View File

@ -533,6 +533,7 @@ public:
{ {
public: public:
std::string name; std::string name;
wxString product_name;
std::string sn; std::string sn;
std::string hw_ver; std::string hw_ver;
std::string sw_ver; std::string sw_ver;
@ -541,6 +542,12 @@ public:
ModuleVersionInfo() :firmware_status(0) { ModuleVersionInfo() :firmware_status(0) {
}; };
public:
bool isValid() const { return !sn.empty(); }
bool isAirPump() const { return product_name.Contains("Air Pump"); }
bool isLaszer() const { return product_name.Contains("Laser"); }
bool isCuttingModule() const { return product_name.Contains("Cutting Module"); }
}; };
enum SdcardState { enum SdcardState {
@ -769,6 +776,10 @@ public:
std::string ota_new_version_number; std::string ota_new_version_number;
std::string ahb_new_version_number; std::string ahb_new_version_number;
int get_version_retry = 0; int get_version_retry = 0;
ModuleVersionInfo air_pump_version_info;
ModuleVersionInfo laser_version_info;
ModuleVersionInfo cutting_module_version_info;
std::map<std::string, ModuleVersionInfo> module_vers; std::map<std::string, ModuleVersionInfo> module_vers;
std::map<std::string, ModuleVersionInfo> new_ver_list; std::map<std::string, ModuleVersionInfo> new_ver_list;
std::map<std::string, ExtrusionRatioInfo> extrusion_ratio_map; std::map<std::string, ExtrusionRatioInfo> extrusion_ratio_map;
@ -786,6 +797,7 @@ public:
wxString get_upgrade_result_str(int upgrade_err_code); wxString get_upgrade_result_str(int upgrade_err_code);
// key: ams_id start as 0,1,2,3 // key: ams_id start as 0,1,2,3
std::map<int, ModuleVersionInfo> get_ams_version(); std::map<int, ModuleVersionInfo> get_ams_version();
void store_version_info(const ModuleVersionInfo& info);
/* printing */ /* printing */
std::string print_type; std::string print_type;

View File

@ -0,0 +1,10 @@
# GUI/DeviceTab
# usage -- GUI about device tab for BambuStudio
# date -- 2025.01.01
# status -- Building
list(APPEND SLIC3R_GUI_SOURCES
GUI/DeviceTab/uiDeviceUpdateVersion.h
GUI/DeviceTab/uiDeviceUpdateVersion.cpp
)
set(SLIC3R_GUI_SOURCES ${SLIC3R_GUI_SOURCES} PARENT_SCOPE)

View File

@ -0,0 +1,103 @@
//**********************************************************/
/* File: uiDeviceUpdateVersion.cpp
* Description: The panel with firmware info
*
* \n class uiDeviceUpdateVersion
//**********************************************************/
#include "uiDeviceUpdateVersion.h"
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/wxExtensions.hpp"
#include <wx/stattext.h>
#define SERIAL_STR "Serial:"
#define VERSION_STR "Version:"
using namespace Slic3r::GUI;
uiDeviceUpdateVersion::uiDeviceUpdateVersion(wxWindow* parent,
wxWindowID id /*= wxID_ANY*/,
const wxPoint& pos /*= wxDefaultPosition*/,
const wxSize& size /*= wxDefaultSize*/,
long style /*= wxTAB_TRAVERSAL*/)
: wxPanel(parent, id, pos, size, style)
{
CreateWidgets();
}
void uiDeviceUpdateVersion::UpdateInfo(const MachineObject::ModuleVersionInfo& info)
{
SetName(info.product_name);
SetSerial(info.sn);
SetVersion(info.sw_ver, info.sw_new_ver);
}
void uiDeviceUpdateVersion::SetVersion(const wxString& cur_version, const wxString& latest_version)
{
if (cur_version.empty())
{
return;
}
if (!latest_version.empty() && (cur_version != latest_version))
{
const wxString& shown_ver = wxString::Format("%s->%s", cur_version, latest_version);
m_dev_version->SetLabel(shown_ver);
if (!m_dev_upgrade_indicator->IsShown())
{
m_dev_upgrade_indicator->Show(true);
}
}
else
{
const wxString& shown_ver = wxString::Format("%s(%s)", cur_version, _L("Latest version"));
m_dev_version->SetLabel(shown_ver);
if (m_dev_upgrade_indicator->IsShown())
{
m_dev_upgrade_indicator->Hide();
}
}
}
void uiDeviceUpdateVersion::CreateWidgets()
{
m_dev_name = new wxStaticText(this, wxID_ANY, "_");
m_dev_snl = new wxStaticText(this, wxID_ANY, "_");
m_dev_version = new wxStaticText(this, wxID_ANY, "_");
wxStaticText* serial_text = new wxStaticText(this, wxID_ANY, SERIAL_STR);
wxStaticText* version_text = new wxStaticText(this, wxID_ANY, VERSION_STR);
// The main sizer
wxFlexGridSizer* main_sizer = new wxFlexGridSizer(3, 3, 0, 0);
main_sizer->AddGrowableCol(1);
main_sizer->SetFlexibleDirection(wxHORIZONTAL);
main_sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
main_sizer->Add(m_dev_name, 0, wxALIGN_RIGHT | wxALL, FromDIP(5));
main_sizer->Add(0, 0, wxALL, wxEXPAND);
main_sizer->Add(0, 0, wxALL, wxEXPAND);
main_sizer->Add(serial_text, 0, wxALIGN_RIGHT | wxALL, FromDIP(5));
main_sizer->Add(m_dev_snl, 0, wxALIGN_LEFT | wxALL, FromDIP(5));
main_sizer->Add(0, 0, wxALL, wxEXPAND);
m_dev_upgrade_indicator = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize(FromDIP(5), FromDIP(5)));
m_dev_upgrade_indicator->SetBitmap(ScalableBitmap(this, "monitor_upgrade_online", 5).bmp());
wxBoxSizer* version_hsizer = new wxBoxSizer(wxHORIZONTAL);
version_hsizer->Add(m_dev_upgrade_indicator, 0, wxALIGN_CENTER_VERTICAL);
version_hsizer->AddSpacer(FromDIP(5));
version_hsizer->Add(version_text, 0);
main_sizer->Add(version_hsizer, 0, wxALIGN_RIGHT | wxALL, FromDIP(5));
main_sizer->Add(m_dev_version, 0, wxALIGN_LEFT | wxALL, FromDIP(5));
main_sizer->Add(0, 0, wxALL, wxEXPAND);
// Updating
SetSizer(main_sizer);
Layout();
}

View File

@ -0,0 +1,47 @@
//**********************************************************/
/* File: uiDeviceUpdateVersion.h
* Description: The panel with firmware info
*
* \n class uiDeviceUpdateVersion
//**********************************************************/
#pragma once
#include <wx/panel.h>
#include "slic3r/GUI/wxExtensions.hpp"
#include "slic3r/GUI/DeviceManager.hpp"
// Previous defintions
class wxStaticText;
class wxStaticBitmap;
namespace Slic3r::GUI
{
// @Class uiDeviceUpdateVersion
// @Note The panel with firmware info
class uiDeviceUpdateVersion : public wxPanel
{
public:
uiDeviceUpdateVersion(wxWindow* parent,
wxWindowID id = wxID_ANY,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxTAB_TRAVERSAL);
~uiDeviceUpdateVersion() = default;
public:
void UpdateInfo(const MachineObject::ModuleVersionInfo& info);
private:
void CreateWidgets();
void SetName(const wxString& str) { m_dev_name->SetLabel(str); };
void SetSerial(const wxString& str) { m_dev_snl->SetLabel(str); };
void SetVersion(const wxString& cur_version, const wxString& latest_version);
private:
wxStaticText* m_dev_name;
wxStaticText* m_dev_snl;
wxStaticText* m_dev_version;
wxStaticBitmap* m_dev_upgrade_indicator;
};
};// end of namespace Slic3r::GUI

View File

@ -2,6 +2,8 @@
#include <slic3r/GUI/Widgets/SideTools.hpp> #include <slic3r/GUI/Widgets/SideTools.hpp>
#include <slic3r/GUI/Widgets/Label.hpp> #include <slic3r/GUI/Widgets/Label.hpp>
#include <slic3r/GUI/I18N.hpp> #include <slic3r/GUI/I18N.hpp>
#include "slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.h"
#include "GUI.hpp" #include "GUI.hpp"
#include "GUI_App.hpp" #include "GUI_App.hpp"
#include "libslic3r/Thread.hpp" #include "libslic3r/Thread.hpp"
@ -207,7 +209,10 @@ MachineInfoPanel::MachineInfoPanel(wxWindow* parent, wxWindowID id, const wxPoin
m_main_left_sizer->Add(m_ext_sizer, 0, wxEXPAND, 0); m_main_left_sizer->Add(m_ext_sizer, 0, wxEXPAND, 0);
/* cutting module */
createCuttingWidgets(m_main_left_sizer);
createLaserWidgets(m_main_left_sizer);
createAirPumpWidgets(m_main_left_sizer);
m_main_sizer->Add(m_main_left_sizer, 1, wxEXPAND, 0); m_main_sizer->Add(m_main_left_sizer, 1, wxEXPAND, 0);
@ -318,6 +323,69 @@ wxPanel *MachineInfoPanel::create_caption_panel(wxWindow *parent)
return caption_panel; return caption_panel;
} }
void MachineInfoPanel::createAirPumpWidgets(wxBoxSizer* main_left_sizer)
{
m_air_pump_line_above = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL);
m_air_pump_line_above->SetBackgroundColour(wxColour(206, 206, 206));
main_left_sizer->Add(m_air_pump_line_above, 0, wxEXPAND | wxLEFT, FromDIP(40));
m_air_pump_img = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize(FromDIP(200), FromDIP(200)));
m_air_pump_img->SetBitmap(m_img_air_pump.bmp());
wxBoxSizer* content_sizer = new wxBoxSizer(wxVERTICAL);
content_sizer->Add(0, 40, 0, wxEXPAND, FromDIP(5));
m_air_pump_version = new uiDeviceUpdateVersion(this, wxID_ANY);
content_sizer->Add(m_air_pump_version, 0, wxEXPAND, 0);
m_air_pump_sizer = new wxBoxSizer(wxHORIZONTAL);
m_air_pump_sizer->Add(m_air_pump_img, 0, wxALIGN_TOP | wxALL, FromDIP(5));
m_air_pump_sizer->Add(content_sizer, 1, wxEXPAND, 0);
main_left_sizer->Add(m_air_pump_sizer, 0, wxEXPAND, 0);
}
void MachineInfoPanel::createCuttingWidgets(wxBoxSizer* main_left_sizer)
{
m_cutting_line_above = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL);
m_cutting_line_above->SetBackgroundColour(wxColour(206, 206, 206));
main_left_sizer->Add(m_cutting_line_above, 0, wxEXPAND | wxLEFT, FromDIP(40));
m_cutting_img = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize(FromDIP(200), FromDIP(200)));
m_cutting_img->SetBitmap(m_img_cutting.bmp());
wxBoxSizer* content_sizer = new wxBoxSizer(wxVERTICAL);
content_sizer->Add(0, 40, 0, wxEXPAND, FromDIP(5));
m_cutting_version = new uiDeviceUpdateVersion(this, wxID_ANY);
content_sizer->Add(m_cutting_version, 0, wxEXPAND, 0);
m_cutting_sizer = new wxBoxSizer(wxHORIZONTAL);
m_cutting_sizer->Add(m_cutting_img, 0, wxALIGN_TOP | wxALL, FromDIP(5));
m_cutting_sizer->Add(content_sizer, 1, wxEXPAND, 0);
main_left_sizer->Add(m_cutting_sizer, 0, wxEXPAND, 0);
};
void MachineInfoPanel::createLaserWidgets(wxBoxSizer* main_left_sizer)
{
m_laser_line_above = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL);
m_laser_line_above->SetBackgroundColour(wxColour(206, 206, 206));
main_left_sizer->Add(m_laser_line_above, 0, wxEXPAND | wxLEFT, FromDIP(40));
m_lazer_img = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize(FromDIP(200), FromDIP(200)));
m_lazer_img->SetBitmap(m_img_laser.bmp());
wxBoxSizer* content_sizer = new wxBoxSizer(wxVERTICAL);
content_sizer->Add(0, 40, 0, wxEXPAND, FromDIP(5));
m_laser_version = new uiDeviceUpdateVersion(this, wxID_ANY);
content_sizer->Add(m_laser_version, 0, wxEXPAND, 0);
m_laser_sizer = new wxBoxSizer(wxHORIZONTAL);
m_laser_sizer->Add(m_lazer_img, 0, wxALIGN_TOP | wxALL, FromDIP(5));
m_laser_sizer->Add(content_sizer, 1, wxEXPAND, 0);
main_left_sizer->Add(m_laser_sizer, 0, wxEXPAND, 0);
}
void MachineInfoPanel::msw_rescale() void MachineInfoPanel::msw_rescale()
{ {
rescale_bitmaps(); rescale_bitmaps();
@ -345,6 +413,11 @@ void MachineInfoPanel::init_bitmaps()
else { else {
m_img_extra_ams = ScalableBitmap(this, "extra_icon", 160); m_img_extra_ams = ScalableBitmap(this, "extra_icon", 160);
} }
m_img_air_pump = ScalableBitmap(this, "printer_thumbnail", 160);/*TODO: replace the bitmap*/
m_img_laser = ScalableBitmap(this, "laser", 160);
m_img_cutting = ScalableBitmap(this, "cut", 160);
upgrade_green_icon = ScalableBitmap(this, "monitor_upgrade_online", 5); upgrade_green_icon = ScalableBitmap(this, "monitor_upgrade_online", 5);
upgrade_gray_icon = ScalableBitmap(this, "monitor_upgrade_offline", 5); upgrade_gray_icon = ScalableBitmap(this, "monitor_upgrade_offline", 5);
upgrade_yellow_icon = ScalableBitmap(this, "monitor_upgrade_busy", 5); upgrade_yellow_icon = ScalableBitmap(this, "monitor_upgrade_busy", 5);
@ -434,6 +507,11 @@ void MachineInfoPanel::update(MachineObject* obj)
// update ams and extension // update ams and extension
update_ams_ext(obj); update_ams_ext(obj);
// update
update_air_pump(obj);
update_cut(obj);
update_laszer(obj);
//update progress //update progress
int upgrade_percent = obj->get_upgrade_percent(); int upgrade_percent = obj->get_upgrade_percent();
if (obj->upgrade_display_state == (int) MachineObject::UpgradingDisplayState::UpgradingInProgress) { if (obj->upgrade_display_state == (int) MachineObject::UpgradingDisplayState::UpgradingInProgress) {
@ -900,6 +978,45 @@ void MachineInfoPanel::update_ams_ext(MachineObject *obj)
this->Fit(); this->Fit();
} }
void MachineInfoPanel::update_air_pump(MachineObject* obj)
{
if (obj && obj->air_pump_version_info.isValid())
{
m_air_pump_version->UpdateInfo(obj->air_pump_version_info);
show_air_pump(true);
}
else
{
show_air_pump(false);
}
}
void MachineInfoPanel::update_cut(MachineObject* obj)
{
if (obj && obj->cutting_module_version_info.isValid())
{
m_cutting_version->UpdateInfo(obj->cutting_module_version_info);
show_cut(true);
}
else
{
show_cut(false);
}
}
void MachineInfoPanel::update_laszer(MachineObject* obj)
{
if (obj && obj->laser_version_info.isValid())
{
m_laser_version->UpdateInfo(obj->laser_version_info);
show_laszer(true);
}
else
{
show_laszer(false);
}
}
void MachineInfoPanel::show_status(int status, std::string upgrade_status_str) void MachineInfoPanel::show_status(int status, std::string upgrade_status_str)
{ {
if (last_status == status && last_status_str == upgrade_status_str) return; if (last_status == status && last_status_str == upgrade_status_str) return;
@ -994,6 +1111,36 @@ void MachineInfoPanel::show_extra_ams(bool show, bool force_update) {
m_last_extra_ams_show = show; m_last_extra_ams_show = show;
} }
void MachineInfoPanel::show_air_pump(bool show)
{
if (m_air_pump_version->IsShown() != show)
{
m_air_pump_img->Show(show);
m_air_pump_line_above->Show(show);
m_air_pump_version->Show(show);
}
}
void MachineInfoPanel::show_cut(bool show)
{
if (m_cutting_version->IsShown() != show)
{
m_cutting_img->Show(show);
m_cutting_line_above->Show(show);
m_cutting_version->Show(show);
}
}
void MachineInfoPanel::show_laszer(bool show)
{
if (m_laser_version->IsShown() != show)
{
m_lazer_img->Show(show);
m_laser_line_above->Show(show);
m_laser_version->Show(show);
}
}
void MachineInfoPanel::on_sys_color_changed() void MachineInfoPanel::on_sys_color_changed()
{ {
if (m_obj) { if (m_obj) {

View File

@ -12,6 +12,9 @@
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
// Previous definitions
class uiDeviceUpdateVersion;
class ExtensionPanel : public wxPanel class ExtensionPanel : public wxPanel
{ {
public: public:
@ -105,6 +108,24 @@ protected:
bool m_last_extra_ams_show = true; bool m_last_extra_ams_show = true;
wxBoxSizer* m_extra_ams_sizer; wxBoxSizer* m_extra_ams_sizer;
/* air_pump info*/
wxBoxSizer* m_air_pump_sizer = nullptr;
wxStaticBitmap* m_air_pump_img = nullptr;
wxStaticLine* m_air_pump_line_above = nullptr;;
uiDeviceUpdateVersion* m_air_pump_version = nullptr;
/* cutting module info*/
wxBoxSizer* m_cutting_sizer = nullptr;
wxStaticBitmap* m_cutting_img = nullptr;
wxStaticLine* m_cutting_line_above = nullptr;;
uiDeviceUpdateVersion* m_cutting_version = nullptr;
/* laser info*/
wxBoxSizer* m_laser_sizer = nullptr;
wxStaticBitmap* m_lazer_img = nullptr;
wxStaticLine* m_laser_line_above = nullptr;;
uiDeviceUpdateVersion* m_laser_version = nullptr;
/* upgrade widgets */ /* upgrade widgets */
wxBoxSizer* m_upgrading_sizer; wxBoxSizer* m_upgrading_sizer;
wxStaticText * m_staticText_upgrading_info; wxStaticText * m_staticText_upgrading_info;
@ -122,6 +143,9 @@ protected:
ScalableBitmap m_img_monitor_ams; ScalableBitmap m_img_monitor_ams;
ScalableBitmap m_img_extra_ams; ScalableBitmap m_img_extra_ams;
ScalableBitmap m_img_printer; ScalableBitmap m_img_printer;
ScalableBitmap m_img_air_pump;
ScalableBitmap m_img_cutting;
ScalableBitmap m_img_laser;
ScalableBitmap upgrade_gray_icon; ScalableBitmap upgrade_gray_icon;
ScalableBitmap upgrade_green_icon; ScalableBitmap upgrade_green_icon;
ScalableBitmap upgrade_yellow_icon; ScalableBitmap upgrade_yellow_icon;
@ -151,10 +175,16 @@ public:
void update(MachineObject *obj); void update(MachineObject *obj);
void update_version_text(MachineObject *obj); void update_version_text(MachineObject *obj);
void update_ams_ext(MachineObject *obj); void update_ams_ext(MachineObject *obj);
void update_air_pump(MachineObject* obj);
void update_cut(MachineObject* obj);
void update_laszer(MachineObject* obj);
void show_status(int status, std::string upgrade_status_str = ""); void show_status(int status, std::string upgrade_status_str = "");
void show_ams(bool show = false, bool force_update = false); void show_ams(bool show = false, bool force_update = false);
void show_ext(bool show = false, bool force_update = false); void show_ext(bool show = false, bool force_update = false);
void show_extra_ams(bool show = false, bool force_update = false); void show_extra_ams(bool show = false, bool force_update = false);
void show_air_pump(bool show = true);
void show_cut(bool show = true);
void show_laszer(bool show = true);
void on_upgrade_firmware(wxCommandEvent &event); void on_upgrade_firmware(wxCommandEvent &event);
void on_consisitency_upgrade_firmware(wxCommandEvent &event); void on_consisitency_upgrade_firmware(wxCommandEvent &event);
@ -171,6 +201,11 @@ public:
ptOtaPanel, ptOtaPanel,
ptAmsPanel, ptAmsPanel,
}panel_type; }panel_type;
private:
void createAirPumpWidgets(wxBoxSizer* main_left_sizer);
void createCuttingWidgets(wxBoxSizer* main_left_sizer);
void createLaserWidgets(wxBoxSizer* main_left_sizer);
}; };
//enum UpgradeMode { //enum UpgradeMode {