#include <wx/dcgraph.h>
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "MainFrame.hpp"
#include "CalibrationPanel.hpp"
#include "I18N.hpp"

namespace Slic3r { namespace GUI {

#define REFRESH_INTERVAL       1000
    
#define INITIAL_NUMBER_OF_MACHINES 0
#define LIST_REFRESH_INTERVAL 200
#define MACHINE_LIST_REFRESH_INTERVAL 2000
wxDEFINE_EVENT(EVT_FINISHED_UPDATE_MLIST, wxCommandEvent);
wxDEFINE_EVENT(EVT_UPDATE_USER_MLIST, wxCommandEvent);

wxString get_calibration_type_name(CalibMode cali_mode)
{
    switch (cali_mode) {
    case CalibMode::Calib_PA_Line:
        return _L("Flow Dynamics");
    case CalibMode::Calib_Flow_Rate:
        return _L("Flow Rate");
    case CalibMode::Calib_Vol_speed_Tower:
        return _L("Max Volumetric Speed");
    case CalibMode::Calib_Temp_Tower:
        return _L("Temperature");
    case CalibMode::Calib_Retraction_tower:
        return _L("Retraction");
    default:
        return "";
    }
}

MObjectPanel::MObjectPanel(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
{
    wxPanel::Create(parent, id, pos, SELECT_MACHINE_ITEM_SIZE, style, name);
    Bind(wxEVT_PAINT, &MObjectPanel::OnPaint, this);
    SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE));


    m_printer_status_offline = ScalableBitmap(this, "printer_status_offline", 12);
    m_printer_status_busy = ScalableBitmap(this, "printer_status_busy", 12);
    m_printer_status_idle = ScalableBitmap(this, "printer_status_idle", 12);
    m_printer_status_lock = ScalableBitmap(this, "printer_status_lock", 16);
    m_printer_in_lan = ScalableBitmap(this, "printer_in_lan", 16);

    Bind(wxEVT_ENTER_WINDOW, &MObjectPanel::on_mouse_enter, this);
    Bind(wxEVT_LEAVE_WINDOW, &MObjectPanel::on_mouse_leave, this);
    Bind(wxEVT_LEFT_UP, &MObjectPanel::on_mouse_left_up, this);
}


MObjectPanel::~MObjectPanel() {}


void MObjectPanel::set_printer_state(PrinterState state)
{
    m_state = state;
    Refresh();
}

void MObjectPanel::OnPaint(wxPaintEvent & event)
{
    wxPaintDC dc(this);
    doRender(dc);
}

void MObjectPanel::render(wxDC& dc)
{
#ifdef __WXMSW__
    wxSize     size = GetSize();
    wxMemoryDC memdc;
    wxBitmap   bmp(size.x, size.y);
    memdc.SelectObject(bmp);
    memdc.Blit({ 0, 0 }, size, &dc, { 0, 0 });

    {
        wxGCDC dc2(memdc);
        doRender(dc2);
    }

    memdc.SelectObject(wxNullBitmap);
    dc.DrawBitmap(bmp, 0, 0);
#else
    doRender(dc);
#endif
}

void MObjectPanel::doRender(wxDC& dc)
{
    auto   left = 10;
    wxSize size = GetSize();
    dc.SetPen(*wxTRANSPARENT_PEN);

    auto dwbitmap = m_printer_status_offline;
    if (m_state == PrinterState::IDLE) { dwbitmap = m_printer_status_idle; }
    if (m_state == PrinterState::BUSY) { dwbitmap = m_printer_status_busy; }
    if (m_state == PrinterState::OFFLINE) { dwbitmap = m_printer_status_offline; }
    if (m_state == PrinterState::LOCK) { dwbitmap = m_printer_status_lock; }
    if (m_state == PrinterState::IN_LAN) { dwbitmap = m_printer_in_lan; }

    // dc.DrawCircle(left, size.y / 2, 3);
    dc.DrawBitmap(dwbitmap.bmp(), wxPoint(left, (size.y - dwbitmap.GetBmpSize().y) / 2));

    left += dwbitmap.GetBmpSize().x + 8;
    dc.SetFont(Label::Body_13);
    dc.SetBackgroundMode(wxTRANSPARENT);
    dc.SetTextForeground(StateColor::darkModeColorFor(SELECT_MACHINE_GREY900));
    wxString dev_name = "";
    if (m_info) {
        dev_name = from_u8(m_info->dev_name);

        if (m_state == PrinterState::IN_LAN) {
            dev_name += _L("(LAN)");
        }
    }
    auto        sizet = dc.GetTextExtent(dev_name);
    auto        text_end = size.x - FromDIP(15);

    wxString finally_name = dev_name;
    if (sizet.x > (text_end - left)) {
        auto limit_width = text_end - left - dc.GetTextExtent("...").x - 15;
        for (auto i = 0; i < dev_name.length(); i++) {
            auto curr_width = dc.GetTextExtent(dev_name.substr(0, i));
            if (curr_width.x >= limit_width) {
                finally_name = dev_name.substr(0, i) + "...";
                break;
            }
        }
    }

    dc.DrawText(finally_name, wxPoint(left, (size.y - sizet.y) / 2));


    if (m_hover) {
        dc.SetPen(SELECT_MACHINE_BRAND);
        dc.SetBrush(*wxTRANSPARENT_BRUSH);
        dc.DrawRectangle(0, 0, size.x, size.y);
    }

}

void MObjectPanel::update_machine_info(MachineObject* info, bool is_my_devices)
{
    m_info = info;
    m_is_my_devices = is_my_devices;
    Refresh();
}

void MObjectPanel::on_mouse_enter(wxMouseEvent& evt)
{
    m_hover = true;
    Refresh();
}

void MObjectPanel::on_mouse_leave(wxMouseEvent& evt)
{
    m_hover = false;
    Refresh();
}

void MObjectPanel::on_mouse_left_up(wxMouseEvent& evt)
{
    if (m_is_my_devices) {
        if (m_info && m_info->is_lan_mode_printer()) {
            if (m_info->has_access_right() && m_info->is_avaliable()) {
                Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
                if (!dev) return;
                dev->set_selected_machine(m_info->dev_id);
            }
        }
        else {
            Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
            if (!dev) return;
            dev->set_selected_machine(m_info->dev_id);
        }
        wxCommandEvent event(EVT_DISSMISS_MACHINE_LIST);
        event.SetEventObject(this->GetParent()->GetParent());
        wxPostEvent(this, event);
    }
}

SelectMObjectPopup::SelectMObjectPopup(wxWindow* parent)
    :PopupWindow(parent, wxBORDER_NONE | wxPU_CONTAINS_CONTROLS), m_dismiss(false)
{
#ifdef __WINDOWS__
    SetDoubleBuffered(true);
#endif //__WINDOWS__


    SetSize(SELECT_MACHINE_POPUP_SIZE);
    SetMinSize(SELECT_MACHINE_POPUP_SIZE);
    SetMaxSize(SELECT_MACHINE_POPUP_SIZE);

    Freeze();
    wxBoxSizer* m_sizer_main = new wxBoxSizer(wxVERTICAL);
    SetBackgroundColour(SELECT_MACHINE_GREY400);



    m_scrolledWindow = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, SELECT_MACHINE_LIST_SIZE, wxHSCROLL | wxVSCROLL);
    m_scrolledWindow->SetBackgroundColour(*wxWHITE);
    m_scrolledWindow->SetMinSize(SELECT_MACHINE_LIST_SIZE);
    m_scrolledWindow->SetScrollRate(0, 5);
    auto m_sizxer_scrolledWindow = new wxBoxSizer(wxVERTICAL);
    m_scrolledWindow->SetSizer(m_sizxer_scrolledWindow);
    m_scrolledWindow->Layout();
    m_sizxer_scrolledWindow->Fit(m_scrolledWindow);

    m_sizer_my_devices = new wxBoxSizer(wxVERTICAL);
    m_sizxer_scrolledWindow->Add(m_sizer_my_devices, 0, wxEXPAND, 0);


    m_sizer_main->Add(m_scrolledWindow, 0, wxALL | wxEXPAND, FromDIP(2));

    SetSizer(m_sizer_main);
    Layout();
    Thaw();

#ifdef __APPLE__
    m_scrolledWindow->Bind(wxEVT_LEFT_UP, &SelectMObjectPopup::OnLeftUp, this);
#endif // __APPLE__

    m_refresh_timer = new wxTimer();
    m_refresh_timer->SetOwner(this);
    Bind(EVT_UPDATE_USER_MLIST, &SelectMObjectPopup::update_machine_list, this);
    Bind(wxEVT_TIMER, &SelectMObjectPopup::on_timer, this);
    Bind(EVT_DISSMISS_MACHINE_LIST, &SelectMObjectPopup::on_dissmiss_win, this);
}

SelectMObjectPopup::~SelectMObjectPopup() { delete m_refresh_timer; }

void SelectMObjectPopup::Popup(wxWindow* WXUNUSED(focus))
{
    BOOST_LOG_TRIVIAL(trace) << "get_print_info: start";
    if (m_refresh_timer) {
        m_refresh_timer->Stop();
        m_refresh_timer->Start(MACHINE_LIST_REFRESH_INTERVAL);
    }

    if (wxGetApp().is_user_login()) {
        if (!get_print_info_thread) {
            get_print_info_thread = new boost::thread(Slic3r::create_thread([&] {
                NetworkAgent* agent = wxGetApp().getAgent();
                unsigned int http_code;
                std::string body;
                int result = agent->get_user_print_info(&http_code, &body);
                if (result == 0) {
                    m_print_info = body;
                }
                else {
                    m_print_info = "";
                }
                wxCommandEvent event(EVT_UPDATE_USER_MLIST);
                event.SetEventObject(this);
                wxPostEvent(this, event);
                }));
        }
    }

    wxPostEvent(this, wxTimerEvent());
    PopupWindow::Popup();
}

void SelectMObjectPopup::OnDismiss()
{
    BOOST_LOG_TRIVIAL(trace) << "get_print_info: dismiss";
    m_dismiss = true;

    if (m_refresh_timer) {
        m_refresh_timer->Stop();
    }
    if (get_print_info_thread) {
        if (get_print_info_thread->joinable()) {
            get_print_info_thread->join();
            delete get_print_info_thread;
            get_print_info_thread = nullptr;
        }
    }

    wxCommandEvent event(EVT_FINISHED_UPDATE_MLIST);
    event.SetEventObject(this);
    wxPostEvent(this, event);
}

bool SelectMObjectPopup::ProcessLeftDown(wxMouseEvent& event) {
    return PopupWindow::ProcessLeftDown(event);
}

bool SelectMObjectPopup::Show(bool show) {
    if (show) {
        for (int i = 0; i < m_user_list_machine_panel.size(); i++) {
            m_user_list_machine_panel[i]->mPanel->update_machine_info(nullptr);
            m_user_list_machine_panel[i]->mPanel->Hide();
        }
    }
    return PopupWindow::Show(show);
}

void SelectMObjectPopup::on_timer(wxTimerEvent& event)
{
    BOOST_LOG_TRIVIAL(trace) << "SelectMObjectPopup on_timer";
    wxGetApp().reset_to_active();
    wxCommandEvent user_event(EVT_UPDATE_USER_MLIST);
    user_event.SetEventObject(this);
    wxPostEvent(this, user_event);
}

void SelectMObjectPopup::update_user_devices()
{
    Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
    if (!dev) return;

    if (!m_print_info.empty()) {
        dev->parse_user_print_info(m_print_info);
        m_print_info = "";
    }

    m_bind_machine_list.clear();
    m_bind_machine_list = dev->get_my_machine_list();

    //sort list
    std::vector<std::pair<std::string, MachineObject*>> user_machine_list;
    for (auto& it : m_bind_machine_list) {
        user_machine_list.push_back(it);
    }

    std::sort(user_machine_list.begin(), user_machine_list.end(), [&](auto& a, auto& b) {
        if (a.second && b.second) {
            return a.second->dev_name.compare(b.second->dev_name) < 0;
        }
        return false;
        });

    BOOST_LOG_TRIVIAL(trace) << "SelectMObjectPopup update_machine_list start";
    this->Freeze();
    m_scrolledWindow->Freeze();
    int i = 0;

    for (auto& elem : user_machine_list) {
        MachineObject* mobj = elem.second;
        MObjectPanel* op = nullptr;
        if (i < m_user_list_machine_panel.size()) {
            op = m_user_list_machine_panel[i]->mPanel;
            op->Show();
        }
        else {
            op = new MObjectPanel(m_scrolledWindow, wxID_ANY);
            MPanel* mpanel = new MPanel();
            mpanel->mIndex = wxString::Format("%d", i);
            mpanel->mPanel = op;
            m_user_list_machine_panel.push_back(mpanel);
            m_sizer_my_devices->Add(op, 0, wxEXPAND, 0);
        }
        i++;
        op->update_machine_info(mobj, true);
        //set in lan
        if (mobj->is_lan_mode_printer()) {
            if (!mobj->is_online()) {
                continue;
            }
            else {
                if (mobj->has_access_right() && mobj->is_avaliable()) {
                    op->set_printer_state(PrinterState::IN_LAN);
                    op->SetToolTip(_L("Online"));
                }
                else {
                    op->set_printer_state(PrinterState::LOCK);
                }
            }
        }
        else {
            if (!mobj->is_online()) {
                op->SetToolTip(_L("Offline"));
                op->set_printer_state(PrinterState::OFFLINE);
            }
            else {
                if (mobj->is_in_printing()) {
                    op->SetToolTip(_L("Busy"));
                    op->set_printer_state(PrinterState::BUSY);
                }
                else {
                    op->SetToolTip(_L("Online"));
                    op->set_printer_state(PrinterState::IDLE);
                }
            }
        }
    }

    for (int j = i; j < m_user_list_machine_panel.size(); j++) {
        m_user_list_machine_panel[j]->mPanel->update_machine_info(nullptr);
        m_user_list_machine_panel[j]->mPanel->Hide();
    }
    //m_sizer_my_devices->Layout();

    if (m_my_devices_count != i) {
        m_scrolledWindow->Fit();
    }
    m_scrolledWindow->Layout();
    m_scrolledWindow->Thaw();
    Layout();
    Fit();
    this->Thaw();
    m_my_devices_count = i;
}

void SelectMObjectPopup::on_dissmiss_win(wxCommandEvent& event)
{
    Dismiss();
}

void SelectMObjectPopup::update_machine_list(wxCommandEvent& event)
{
    update_user_devices();
    BOOST_LOG_TRIVIAL(trace) << "SelectMObjectPopup update_machine_list end";
}

void SelectMObjectPopup::OnLeftUp(wxMouseEvent& event)
{
    auto mouse_pos = ClientToScreen(event.GetPosition());
    auto wxscroll_win_pos = m_scrolledWindow->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_scrolledWindow->GetSize().x) &&
        mouse_pos.y < (wxscroll_win_pos.y + m_scrolledWindow->GetSize().y)) {

        for (MPanel* p : m_user_list_machine_panel) {
            auto p_rect = p->mPanel->ClientToScreen(wxPoint(0, 0));
            if (mouse_pos.x > p_rect.x && mouse_pos.y > p_rect.y && mouse_pos.x < (p_rect.x + p->mPanel->GetSize().x) && mouse_pos.y < (p_rect.y + p->mPanel->GetSize().y)) {
                wxMouseEvent event(wxEVT_LEFT_UP);
                auto         tag_pos = p->mPanel->ScreenToClient(mouse_pos);
                event.SetPosition(tag_pos);
                event.SetEventObject(p->mPanel);
                wxPostEvent(p->mPanel, event);
            }
        }
    }
}


CalibrationPanel::CalibrationPanel(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
    : wxPanel(parent, id, pos, size, style),
    m_mobjectlist_popup(SelectMObjectPopup(this))
{
    SetBackgroundColour(*wxWHITE);

    init_tabpanel();

    wxBoxSizer* sizer_main = new wxBoxSizer(wxVERTICAL);
    sizer_main->Add(m_tabpanel, 1, wxEXPAND, 0);

    SetSizerAndFit(sizer_main);
    Layout();

    init_timer();
    Bind(wxEVT_TIMER, &CalibrationPanel::on_timer, this);
}

void CalibrationPanel::init_tabpanel() {
    m_side_tools = new SideTools(this, wxID_ANY);
    m_side_tools->get_panel()->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(CalibrationPanel::on_printer_clicked), NULL, this);


    wxBoxSizer* sizer_side_tools = new wxBoxSizer(wxVERTICAL);
    sizer_side_tools->Add(m_side_tools, 1, wxEXPAND, 0);

    m_tabpanel = new Tabbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, sizer_side_tools, wxNB_LEFT | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME);
    m_side_tools->set_table_panel(m_tabpanel);
    m_tabpanel->SetBackgroundColour(*wxWHITE);

    m_cali_panels[0] = new PressureAdvanceWizard(m_tabpanel);
    m_cali_panels[1] = new FlowRateWizard(m_tabpanel);
    //m_cali_panels[2] = new MaxVolumetricSpeedWizard(m_tabpanel);

    for (int i = 0; i < (int)CALI_MODE_COUNT; i++) {
        bool selected = false;
        if (i == 0)
            selected = true;
        m_tabpanel->AddPage(m_cali_panels[i],
            get_calibration_type_name(m_cali_panels[i]->get_calibration_mode()),
            "",
            selected);
    }

    for (int i = 0; i < (int)CALI_MODE_COUNT; i++)
        m_tabpanel->SetPageImage(i, "");

    auto padding_size = m_tabpanel->GetBtnsListCtrl()->GetPaddingSize(0);
    m_tabpanel->GetBtnsListCtrl()->SetPaddingSize({ FromDIP(15), padding_size.y });

    m_initialized = true;
}

void CalibrationPanel::init_timer()
{
    m_refresh_timer = new wxTimer();
    m_refresh_timer->SetOwner(this);
    m_refresh_timer->Start(REFRESH_INTERVAL);
    wxPostEvent(this, wxTimerEvent());
}

void CalibrationPanel::on_timer(wxTimerEvent& event) {
    update_all();
}

void CalibrationPanel::update_print_error_info(int code, std::string msg, std::string extra) {
    // update current wizard only
    int curr_selected = m_tabpanel->GetSelection();
    if (curr_selected >= 0 && curr_selected < CALI_MODE_COUNT) {
        if (m_cali_panels[curr_selected]) {
            auto page = m_cali_panels[curr_selected]->get_curr_step()->page;
            if(page && page->get_page_type() == CaliPageType::CALI_PAGE_PRESET){
                auto preset_page = static_cast<CalibrationPresetPage*>(page);
                if (preset_page->get_page_status() == CaliPresetPageStatus::CaliPresetStatusSending)
                    preset_page->update_print_error_info(code, msg, extra);
            }
        }
    }
}

void CalibrationPanel::update_all() {

    NetworkAgent* m_agent = wxGetApp().getAgent();
    Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
    if (!dev) return;
    obj = dev->get_selected_machine();

    // check valid machine
    if (obj && dev->get_my_machine(obj->dev_id) == nullptr) {
        dev->set_selected_machine("");
        if (m_agent) m_agent->set_user_selected_machine("");
        show_status((int) MONITOR_NO_PRINTER);
        return;
    }

    // update current wizard only
    int curr_selected = m_tabpanel->GetSelection();

    if (curr_selected >= 0 && curr_selected < CALI_MODE_COUNT) {
        if (m_cali_panels[curr_selected])
            m_cali_panels[curr_selected]->update(obj);
    }

    if (obj) {
        if (last_obj != obj && obj->is_info_ready()) {
            for (int i = 0; i < CALI_MODE_COUNT; i++) {
                m_cali_panels[i]->on_device_connected(obj);
            }
            last_obj = obj;
        }
    }

    if (wxGetApp().is_user_login()) {
        dev->check_pushing();
        try {
            m_agent->refresh_connection();
        }
        catch (...) {
            ;
        }
    }

    if (obj) {
        wxGetApp().reset_to_active();
        if (obj->connection_type() != last_conn_type) {
            last_conn_type = obj->connection_type();
        }
    }

    m_side_tools->update_status(obj);

    if (!obj) {
        show_status((int)MONITOR_NO_PRINTER);
        return;
    }

    if (obj->is_connecting()) {
        show_status(MONITOR_CONNECTING);
        return;
    }
    else if (!obj->is_connected()) {
        int server_status = 0;
        // only disconnected server in cloud mode
        if (obj->connection_type() != "lan") {
            if (m_agent) {
                server_status = m_agent->is_server_connected() ? 0 : (int)MONITOR_DISCONNECTED_SERVER;
            }
        }
        show_status((int)MONITOR_DISCONNECTED + server_status);
        return;
    }

    show_status(MONITOR_NORMAL);
}

void CalibrationPanel::show_status(int status)
{
    if (!m_initialized) return;
    if (last_status == status)return;
    if (last_status & (int)MonitorStatus::MONITOR_CONNECTING != 0) {
        NetworkAgent* agent = wxGetApp().getAgent();
        json j;
        j["dev_id"] = obj ? obj->dev_id : "obj_nullptr";
        if (status & (int)MonitorStatus::MONITOR_DISCONNECTED != 0) {
            j["result"] = "failed";
            if (agent) {
                agent->track_event("connect_dev", j.dump());
            }
        }
        else if (status & (int)MonitorStatus::MONITOR_NORMAL != 0) {
            j["result"] = "success";
            if (agent) {
                agent->track_event("connect_dev", j.dump());
            }
        }
    }
    last_status = status;

    BOOST_LOG_TRIVIAL(info) << "monitor: show_status = " << status;


    Freeze();
    // update panels
    if (m_side_tools) { m_side_tools->show_status(status); };

    if ((status & (int)MonitorStatus::MONITOR_NO_PRINTER) != 0) {
        set_default();
        m_tabpanel->Layout();
    }
    else if (((status & (int)MonitorStatus::MONITOR_NORMAL) != 0)
        || ((status & (int)MonitorStatus::MONITOR_DISCONNECTED) != 0)
        || ((status & (int)MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0)
        || ((status & (int)MonitorStatus::MONITOR_CONNECTING) != 0))
    {

        if (((status & (int)MonitorStatus::MONITOR_DISCONNECTED) != 0)
            || ((status & (int)MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0)
            || ((status & (int)MonitorStatus::MONITOR_CONNECTING) != 0))
        {
            set_default();
        }
        m_tabpanel->Layout();
    }
    Layout();
    Thaw();
}

bool CalibrationPanel::Show(bool show) {
    if (show) {
        m_refresh_timer->Stop();
        m_refresh_timer->SetOwner(this);
        m_refresh_timer->Start(REFRESH_INTERVAL);
        wxPostEvent(this, wxTimerEvent());

        DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
        if (dev) {
            //set a default machine when obj is null
            obj = dev->get_selected_machine();
            if (obj == nullptr) {
                dev->load_last_machine();
                obj = dev->get_selected_machine();
                if (obj)
                    GUI::wxGetApp().sidebar().load_ams_list(obj->dev_id, obj);
            }
            else {
                obj->reset_update_time();
            }
        }

    }
    else {
        m_refresh_timer->Stop();
    }
    return wxPanel::Show(show);
}

void CalibrationPanel::on_printer_clicked(wxMouseEvent& event)
{
    auto mouse_pos = ClientToScreen(event.GetPosition());
    wxPoint rect = m_side_tools->ClientToScreen(wxPoint(0, 0));

    if (!m_side_tools->is_in_interval()) {
        wxPoint pos = m_side_tools->ClientToScreen(wxPoint(0, 0));
        pos.y += m_side_tools->GetRect().height;
        m_mobjectlist_popup.Move(pos);

#ifdef __linux__
        m_mobjectlist_popup.SetSize(wxSize(m_side_tools->GetSize().x, -1));
        m_mobjectlist_popup.SetMaxSize(wxSize(m_side_tools->GetSize().x, -1));
        m_mobjectlist_popup.SetMinSize(wxSize(m_side_tools->GetSize().x, -1));
#endif

        m_mobjectlist_popup.Popup();
    }
}

void CalibrationPanel::set_default()
{
    obj = nullptr;
    last_conn_type = "undefined";
    wxGetApp().sidebar().load_ams_list({}, {});
}

void CalibrationPanel::msw_rescale()
{
    for (int i = 0; i < (int)CALI_MODE_COUNT; i++) {
        m_cali_panels[i]->msw_rescale();
    }
}

void CalibrationPanel::on_sys_color_changed()
{
    for (int i = 0; i < (int)CALI_MODE_COUNT; i++) {
        m_cali_panels[i]->on_sys_color_changed();
    }
}

CalibrationPanel::~CalibrationPanel() {
    m_side_tools->get_panel()->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(CalibrationPanel::on_printer_clicked), NULL, this);
    if (m_refresh_timer)
        m_refresh_timer->Stop();
    delete m_refresh_timer;
}

}}