900 lines
31 KiB
C++
900 lines
31 KiB
C++
#include "wx/wxprec.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/utils.h"
|
|
#include "wx/frame.h"
|
|
#include "wx/button.h"
|
|
#include "wx/stattext.h"
|
|
#include "wx/sizer.h"
|
|
#include "wx/event.h"
|
|
#include "wx/gauge.h"
|
|
#include "wx/intl.h"
|
|
#include "wx/dcclient.h"
|
|
#include "wx/timer.h"
|
|
#include "wx/settings.h"
|
|
#include "wx/app.h"
|
|
#endif
|
|
|
|
#include "../GUI.hpp"
|
|
#include "../GUI_App.hpp"
|
|
#include "../I18N.hpp"
|
|
#include "ProgressDialog.hpp"
|
|
#include "wx/evtloop.h"
|
|
#include "Label.hpp"
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// constants
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#define LAYOUT_MARGIN 12
|
|
|
|
static const int wxID_SKIP = 32000;
|
|
|
|
namespace Slic3r { namespace GUI {
|
|
void ProgressDialog::Init()
|
|
{
|
|
// we may disappear at any moment, let the others know about it
|
|
SetExtraStyle(GetExtraStyle() | wxWS_EX_TRANSIENT);
|
|
|
|
// Initialize all our members that we always use (even when we don't
|
|
// create a valid window in this class).
|
|
|
|
m_pdStyle = 0;
|
|
m_parentTop = NULL;
|
|
|
|
m_gauge = NULL;
|
|
m_msg = NULL;
|
|
m_elapsed = m_estimated = m_remaining = NULL;
|
|
|
|
m_state = Uncancelable;
|
|
m_maximum = 0;
|
|
|
|
m_timeStart = wxGetCurrentTime();
|
|
m_timeStop = (unsigned long) -1;
|
|
m_break = 0;
|
|
|
|
m_skip = false;
|
|
|
|
m_btnAbort = NULL;
|
|
m_btnSkip = NULL;
|
|
|
|
m_display_estimated = m_last_timeupdate = m_ctdelay = 0;
|
|
|
|
m_delay = 3;
|
|
|
|
m_winDisabler = NULL;
|
|
m_tempEventLoop = NULL;
|
|
|
|
SetWindowStyle(wxDEFAULT_DIALOG_STYLE);
|
|
}
|
|
|
|
ProgressDialog::ProgressDialog() : wxDialog() { Init(); }
|
|
|
|
ProgressDialog::ProgressDialog(const wxString &title, const wxString &message, int maximum, wxWindow *parent, int style, bool adaptive) : wxDialog()
|
|
{
|
|
m_adaptive = adaptive;
|
|
Init();
|
|
Create(title, message, maximum, parent, style);
|
|
Bind(wxEVT_PAINT, &ProgressDialog::OnPaint, this);
|
|
Bind(wxEVT_CLOSE_WINDOW, &ProgressDialog::OnClose, this);
|
|
}
|
|
|
|
void ProgressDialog::OnPaint(wxPaintEvent &evt) {}
|
|
|
|
void ProgressDialog::SetTopParent(wxWindow *parent)
|
|
{
|
|
m_parent = parent;
|
|
m_parentTop = parent;
|
|
}
|
|
|
|
wxString ProgressDialog::FormatString(wxString title)
|
|
{
|
|
if (!m_adaptive) {
|
|
auto current_width = 0;
|
|
m_mode = 0;
|
|
for (int i = 0; i < title.length(); i++) {
|
|
current_width = m_msg->GetTextExtent(title.SubString(0, i)).x;
|
|
if (current_width > PROGRESSDIALOG_GAUGE_SIZE.x) {
|
|
m_mode = 1;
|
|
// title.insert(i - 1, "\n");
|
|
break;
|
|
}
|
|
}
|
|
// set mode
|
|
if (m_mode == 0) {
|
|
m_simplebook->SetSelection(0);
|
|
m_msg->SetLabel(title);
|
|
} else {
|
|
wxSize content_size = m_msg->GetTextExtent(title);
|
|
int resized_height = (int(content_size.x / PROGRESSDIALOG_GAUGE_SIZE.x) + 1) * content_size.y;
|
|
set_panel_height(resized_height);
|
|
m_simplebook->SetSelection(1);
|
|
m_msg_2line->SetLabel(title);
|
|
}
|
|
} else {
|
|
m_msg->SetLabel(title);
|
|
m_msg->SetMaxSize(wxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x + 5, -1));
|
|
m_msg->SetMinSize(wxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x + 5, -1));
|
|
m_msg->Wrap(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x + 5);
|
|
m_msg->Layout();
|
|
m_msg->Fit();
|
|
|
|
m_msg_scrolledWindow->SetSize(wxSize(FromDIP(m_msg->GetSize().x + 5), FromDIP(150)));
|
|
m_msg_scrolledWindow->SetMinSize(wxSize(FromDIP(m_msg->GetSize().x + 5), FromDIP(150)));
|
|
m_msg_scrolledWindow->SetMaxSize(wxSize(FromDIP(m_msg->GetSize().x + 5), FromDIP(150)));
|
|
// m_msg_scrolledWindow->Layout();
|
|
m_msg_scrolledWindow->Fit();
|
|
}
|
|
|
|
|
|
//Fit();
|
|
return title;
|
|
}
|
|
|
|
bool ProgressDialog::Create(const wxString &title, const wxString &message, int maximum, wxWindow *parent, int style)
|
|
{
|
|
SetFont(wxGetApp().normal_font());
|
|
SetTopParent(parent);
|
|
|
|
m_pdStyle = style;
|
|
|
|
if (!wxDialog::Create(m_parentTop, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, GetWindowStyle())) return false;
|
|
SetBackgroundColour(PROGRESSDIALOG_DEF_BK);
|
|
|
|
/* SetSize(DESIGN_RESOUTION_PROGRESS_SIZE);
|
|
SetMinSize(DESIGN_RESOUTION_PROGRESS_SIZE);
|
|
SetMaxSize(DESIGN_RESOUTION_PROGRESS_SIZE);*/
|
|
|
|
SetMaximum(maximum);
|
|
EnsureActiveEventLoopExists();
|
|
|
|
#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
|
|
if (!HasPDFlag(wxPD_CAN_ABORT)) { EnableCloseButton(false); }
|
|
#endif // wxMSW
|
|
|
|
m_state = HasPDFlag(wxPD_CAN_ABORT) ? Continue : Uncancelable;
|
|
|
|
wxBoxSizer *m_sizer_main = new wxBoxSizer(wxVERTICAL);
|
|
|
|
m_top_line = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0);
|
|
m_top_line->SetBackgroundColour(wxColour(166, 169, 170));
|
|
|
|
m_sizer_main->Add(m_top_line, 0, wxEXPAND, 0);
|
|
m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(24));
|
|
|
|
if (!m_adaptive) {
|
|
m_simplebook = new wxSimplebook(this, wxID_ANY, wxDefaultPosition, PROGRESSDIALOG_SIMPLEBOOK_SIZE, 0);
|
|
|
|
m_panel_1line = new wxPanel(m_simplebook, wxID_ANY, wxDefaultPosition, PROGRESSDIALOG_SIMPLEBOOK_SIZE, 0);
|
|
m_panel_1line->SetMaxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE);
|
|
m_panel_1line->SetBackgroundColour(PROGRESSDIALOG_DEF_BK);
|
|
m_simplebook->AddPage(m_panel_1line, wxEmptyString, false);
|
|
|
|
m_panel_2line = new wxPanel(m_simplebook, wxID_ANY, wxDefaultPosition, PROGRESSDIALOG_SIMPLEBOOK_SIZE, 0);
|
|
m_panel_2line->SetMaxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE);
|
|
m_panel_2line->SetBackgroundColour(PROGRESSDIALOG_DEF_BK);
|
|
m_simplebook->AddPage(m_panel_2line, wxEmptyString, false);
|
|
|
|
wxBoxSizer *sizer_1line = new wxBoxSizer(wxHORIZONTAL);
|
|
m_msg = new wxStaticText(m_panel_1line, wxID_ANY, wxEmptyString, wxDefaultPosition, PROGRESSDIALOG_SIMPLEBOOK_SIZE, 0);
|
|
m_msg->Wrap(-1);
|
|
m_msg->SetFont(::Label::Body_13);
|
|
m_msg->SetForegroundColour(PROGRESSDIALOG_GREY_700);
|
|
sizer_1line->Add(m_msg, 0, wxALIGN_CENTER, 0);
|
|
m_panel_1line->SetSizer(sizer_1line);
|
|
m_panel_1line->Layout();
|
|
sizer_1line->Fit(m_panel_1line);
|
|
|
|
wxBoxSizer *sizer_2line = new wxBoxSizer(wxVERTICAL);
|
|
m_msg_2line = new wxStaticText(m_panel_2line, wxID_ANY, wxEmptyString, wxDefaultPosition, PROGRESSDIALOG_SIMPLEBOOK_SIZE, 0);
|
|
m_msg_2line->Wrap(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x);
|
|
m_msg_2line->SetFont(::Label::Body_13);
|
|
m_msg_2line->SetForegroundColour(PROGRESSDIALOG_GREY_700);
|
|
m_msg_2line->SetMaxSize(wxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x, -1));
|
|
sizer_2line->Add(m_msg_2line, 1, wxALL, 0);
|
|
m_panel_2line->SetSizer(sizer_2line);
|
|
m_panel_2line->Layout();
|
|
sizer_2line->Fit(m_panel_2line);
|
|
|
|
m_sizer_main->Add(m_simplebook, 1, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(28));
|
|
} else {
|
|
m_msg_scrolledWindow = new wxScrolledWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL );
|
|
m_msg_scrolledWindow->SetScrollRate(0,5);
|
|
wxBoxSizer* m_msg_sizer= new wxBoxSizer(wxVERTICAL);
|
|
|
|
m_msg = new wxStaticText(m_msg_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x, -1), 0);
|
|
m_msg->Wrap(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x);
|
|
m_msg->SetFont(::Label::Body_13);
|
|
m_msg->SetForegroundColour(PROGRESSDIALOG_GREY_700);
|
|
|
|
m_msg_sizer->Add(m_msg, 0, wxEXPAND | wxALL, 0);
|
|
m_msg_scrolledWindow->SetSizer(m_msg_sizer);
|
|
m_msg_scrolledWindow->Layout();
|
|
m_msg_sizer->Fit(m_msg_scrolledWindow);
|
|
m_sizer_main->Add(m_msg_scrolledWindow, 0, wxEXPAND | wxALL, FromDIP(28));
|
|
}
|
|
|
|
|
|
m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, 0);
|
|
|
|
int gauge_style = wxGA_HORIZONTAL;
|
|
if (style & wxPD_SMOOTH) gauge_style |= wxGA_SMOOTH;
|
|
gauge_style |= wxGA_PROGRESS;
|
|
|
|
#ifdef __WXMSW__
|
|
maximum /= m_factor;
|
|
#endif
|
|
|
|
if (!HasPDFlag(wxPD_NO_PROGRESS)) {
|
|
m_gauge = new wxGauge(this, wxID_ANY, maximum, wxDefaultPosition, PROGRESSDIALOG_GAUGE_SIZE, gauge_style);
|
|
m_gauge->SetValue(0);
|
|
m_sizer_main->Add(m_gauge, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(28));
|
|
}
|
|
|
|
#ifdef __WXMSW__
|
|
//m_block_left = new wxWindow(m_gauge, wxID_ANY, wxPoint(0, 0), wxSize(FromDIP(2), PROGRESSDIALOG_GAUGE_SIZE.y * 2));
|
|
//m_block_left->SetBackgroundColour(PROGRESSDIALOG_DEF_BK);
|
|
//m_block_right = new wxWindow(m_gauge, wxID_ANY, wxPoint(PROGRESSDIALOG_GAUGE_SIZE.x - 2, 0), wxSize(FromDIP(2), PROGRESSDIALOG_GAUGE_SIZE.y * 2));
|
|
//m_block_right->SetBackgroundColour(PROGRESSDIALOG_DEF_BK);
|
|
#endif
|
|
wxBoxSizer *m_sizer_bottom = new wxBoxSizer(wxHORIZONTAL);
|
|
|
|
m_sizer_bottom->Add(0, 0, 1, wxEXPAND, 0);
|
|
|
|
if (HasPDFlag(wxPD_CAN_ABORT)) {
|
|
m_button_cancel = new Button(this, _L("Cancel"));
|
|
m_button_cancel->SetTextColor(PROGRESSDIALOG_GREY_700);
|
|
m_button_cancel->SetMinSize(PROGRESSDIALOG_CANCEL_BUTTON_SIZE);
|
|
m_button_cancel->SetCornerRadius(PROGRESSDIALOG_CANCEL_BUTTON_SIZE.y / 2);
|
|
m_button_cancel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &event) {
|
|
if (m_state == Finished) {
|
|
event.Skip();
|
|
} else {
|
|
m_state = Canceled;
|
|
DisableAbort();
|
|
m_button_cancel->Enable(false);
|
|
DisableSkip();
|
|
OnCancel();
|
|
m_timeStop = wxGetCurrentTime();
|
|
}
|
|
});
|
|
m_sizer_bottom->Add(m_button_cancel, 0, wxALL, 0);
|
|
}
|
|
|
|
m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(16));
|
|
m_sizer_main->Add(m_sizer_bottom, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(28));
|
|
m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(10));
|
|
|
|
wxGetApp().UpdateDlgDarkUI(this);
|
|
|
|
SetSizer(m_sizer_main);
|
|
Layout();
|
|
Fit();
|
|
Centre(wxCENTER_FRAME | wxBOTH);
|
|
DisableOtherWindows();
|
|
FormatString(message);
|
|
|
|
Show();
|
|
Enable();
|
|
if (m_elapsed) { SetTimeLabel(0, m_elapsed); }
|
|
|
|
Update();
|
|
return true;
|
|
|
|
//
|
|
// sizerTop = new wxBoxSizer(wxVERTICAL);
|
|
// auto def_size_width = wxMin(wxGetClientDisplayRect().width / 3, 305);
|
|
//
|
|
// wxStaticLine *m_staticline2 = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxSize(def_size_width, 1), wxLI_HORIZONTAL);
|
|
// sizerTop->Add(m_staticline2, 0, wxEXPAND, 0);
|
|
// auto m_block_top = new wxWindow(this, wxID_ANY, wxDefaultPosition, wxSize(def_size_width, 20));
|
|
// m_block_top->SetBackgroundColour(wxColor(DESIGN_RESOUTION_DEF_BK_COLOR));
|
|
// sizerTop->Add(m_block_top, 0, wxEXPAND);
|
|
//
|
|
// m_message_area = new wxWindow(this, wxID_ANY, wxDefaultPosition, wxSize(def_size_width, 38));
|
|
// m_message_area->SetBackgroundColour(DESIGN_RESOUTION_DEF_BK_COLOR);
|
|
// sizerTop->Add(m_message_area, 0, wxLEFT | wxRIGHT | wxBottom | wxEXPAND, 2 * LAYOUT_MARGIN);
|
|
//
|
|
// m_msg = new wxStaticText(m_message_area, wxID_ANY, wxString(""), wxPoint(0, 10), wxSize(def_size_width, 20), wxST_ELLIPSIZE_END);
|
|
// m_msg->SetForegroundColour(wxColour(107, 107, 107));
|
|
// m_msg->SetBackgroundColour(DESIGN_RESOUTION_DEF_BK_COLOR);
|
|
// m_msg->SetMinSize(wxSize(def_size_width, 20));
|
|
// m_msg->SetMaxSize(wxSize(def_size_width, 20));
|
|
//
|
|
// m_msg_2line = new wxStaticText(m_message_area, wxID_ANY, wxString(""), wxPoint(0, 0), wxSize(def_size_width, 40), wxST_ELLIPSIZE_END);
|
|
// m_msg_2line->SetForegroundColour(wxColour(107, 107, 107));
|
|
// m_msg_2line->SetBackgroundColour(DESIGN_RESOUTION_DEF_BK_COLOR);
|
|
// m_msg_2line->SetMinSize(wxSize(def_size_width, 40));
|
|
// m_msg_2line->SetMaxSize(wxSize(def_size_width, 40));
|
|
//
|
|
// auto block_left = new wxWindow(m_gauge, -1, wxPoint(0, 0), wxSize(2, m_gauge->GetSize().GetHeight()));
|
|
// block_left->SetBackgroundColour(wxColor(255, 255, 255));
|
|
//
|
|
// auto block_right = new wxWindow(m_gauge, -1, wxPoint(m_gauge->GetSize().GetWidth() - 2, 0), wxSize(2, m_gauge->GetSize().GetHeight()));
|
|
// block_right->SetBackgroundColour(wxColor(255, 255, 255));
|
|
//
|
|
// sizerTop->Add(m_gauge, 0, wxLEFT | wxRIGHT | wxBottom, 2 * LAYOUT_MARGIN);
|
|
// m_gauge->SetValue(0);
|
|
//
|
|
// m_elapsed = m_estimated = m_remaining = NULL;
|
|
// size_t nTimeLabels = 0;
|
|
//
|
|
// wxSizer *const sizerLabels = new wxFlexGridSizer(2);
|
|
//
|
|
// if (style & wxPD_ELAPSED_TIME) {
|
|
// nTimeLabels++;
|
|
//
|
|
// m_elapsed = CreateLabel(GetElapsedLabel(), sizerLabels);
|
|
// }
|
|
//
|
|
// if (style & wxPD_ESTIMATED_TIME) {
|
|
// nTimeLabels++;
|
|
//
|
|
// m_estimated = CreateLabel(GetEstimatedLabel(), sizerLabels);
|
|
// }
|
|
//
|
|
// if (style & wxPD_REMAINING_TIME) {
|
|
// nTimeLabels++;
|
|
//
|
|
// m_remaining = CreateLabel(GetRemainingLabel(), sizerLabels);
|
|
// }
|
|
// sizerTop->Add(sizerLabels, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP | wxBottom, LAYOUT_MARGIN);
|
|
//
|
|
// wxStdDialogButtonSizer *buttonSizer = wxDialog::CreateStdDialogButtonSizer(0);
|
|
//
|
|
// const int borderFlags = wxALL;
|
|
//
|
|
// std::string icon_path = (boost::format("%1%/images/common_dialog_confirm.png") % resources_dir()).str();
|
|
// /*m_btnAbort = new wxBitmapButton(this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize(52, 24), wxBU_AUTODRAW | wxBORDER_NONE);
|
|
// m_btnAbort->SetBitmap(wxBitmap(icon_path, wxBITMAP_TYPE_ANY));
|
|
// m_btnAbort->SetBitmapDisabled(wxBitmap(icon_path, wxBITMAP_TYPE_ANY));
|
|
// m_btnAbort->SetBitmapPressed(wxBitmap(icon_path, wxBITMAP_TYPE_ANY));
|
|
// m_btnAbort->SetBitmapFocus(wxBitmap(icon_path, wxBITMAP_TYPE_ANY));
|
|
// m_btnAbort->SetBitmapCurrent(wxBitmap(icon_path, wxBITMAP_TYPE_ANY));*/
|
|
//
|
|
// m_btnAbort = new wxButton(this, wxID_CANCEL, wxString(""), wxDefaultPosition, wxSize(52,24));
|
|
//
|
|
// wxStaticBitmap *m_bitmatAbort = new wxStaticBitmap(m_btnAbort, wxID_ANY, wxBitmap(icon_path, wxBITMAP_TYPE_ANY), wxDefaultPosition, wxSize(52, 24), 0);
|
|
// wxStaticText *textAbort = new wxStaticText(m_btnAbort, wxID_ANY, _T("Cancel"), wxPoint(5, 3), wxSize(42, 19));
|
|
// textAbort->SetBa
|
|
// ckgroundColour(wxColor(0, 174, 66));
|
|
// textAbort->SetForegroundColour(DESIGN_RESOUTION_DEF_BK_COLOR);
|
|
//
|
|
// textAbort->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &event) {
|
|
// if (m_state == Finished) {
|
|
// event.Skip();
|
|
// } else {
|
|
// m_state = Canceled;
|
|
// //DisableAbort();
|
|
// DisableSkip();
|
|
// m_timeStop = wxGetCurrentTime();
|
|
// }
|
|
// });
|
|
//
|
|
// wxSizerFlags sizerFlags = wxSizerFlags().Border(borderFlags, LAYOUT_MARGIN);
|
|
// wxWindow *m_button_sizer = new wxWindow(this, wxID_ANY, wxDefaultPosition, wxSize(def_size_width, 26));
|
|
// m_button_sizer->SetBackgroundColour(DESIGN_RESOUTION_DEF_BK_COLOR);
|
|
//
|
|
// if (HasPDFlag(wxPD_CAN_SKIP)) {
|
|
// m_btnSkip = new wxButton(this, wxID_SKIP, wxGetTranslation("&Skip"));
|
|
// m_btnSkip->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ProgressDialog::OnSkip, this);
|
|
// buttonSizer->SetNegativeButton(m_btnSkip);
|
|
// }
|
|
//
|
|
// if (HasPDFlag(wxPD_CAN_ABORT)) {
|
|
// /*m_btnAbort = new wxButton(this, wxID_CANCEL);
|
|
// buttonSizer->SetCancelButton(m_btnAbort);
|
|
// m_btnAbort->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ProgressDialog::OnCancel, this);*/
|
|
//
|
|
// m_button_calcel = new Button(m_button_sizer, _T("Cancel"));
|
|
// m_button_calcel->SetTextColor(wxColour(107, 107, 107));
|
|
// m_button_calcel->SetSize(60, 24);
|
|
// m_button_calcel->SetPosition(wxPoint(m_button_sizer->GetSize().GetWidth() - m_button_calcel->GetSize().GetWidth(), 0));
|
|
//
|
|
// m_button_calcel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &event) {
|
|
// if (m_state == Finished) {
|
|
// event.Skip();
|
|
// } else {
|
|
// m_state = Canceled;
|
|
// DisableAbort();
|
|
// m_button_calcel->Enable(false);
|
|
// DisableSkip();
|
|
// m_timeStop = wxGetCurrentTime();
|
|
// }
|
|
// });
|
|
// }
|
|
//
|
|
// if (!HasPDFlag(wxPD_CAN_SKIP | wxPD_CAN_ABORT)) buttonSizer->AddSpacer(LAYOUT_MARGIN);
|
|
//
|
|
// sizerTop->Add(m_button_sizer, 1, wxEXPAND, 0);
|
|
//
|
|
// auto m_block_bottom = new wxWindow(this, wxID_ANY, wxDefaultPosition, wxSize(def_size_width, 15));
|
|
// m_block_bottom->SetBackgroundColour(DESIGN_RESOUTION_DEF_BK_COLOR);
|
|
// sizerTop->Add(m_block_bottom, 0, wxEXPAND);
|
|
//
|
|
// SetSizerAndFit(sizerTop);
|
|
// FormatString(message);
|
|
//
|
|
// Centre(wxCENTER_FRAME | wxBOTH);
|
|
//
|
|
// DisableOtherWindows();
|
|
//
|
|
// Show();
|
|
// Enable();
|
|
// if (m_elapsed) { SetTimeLabel(0, m_elapsed); }
|
|
//
|
|
// Update();
|
|
// return true;
|
|
}
|
|
|
|
void ProgressDialog::UpdateTimeEstimates(int value, unsigned long &elapsedTime, unsigned long &estimatedTime, unsigned long &remainingTime)
|
|
{
|
|
unsigned long elapsed = wxGetCurrentTime() - m_timeStart;
|
|
if (value != 0 && (m_last_timeupdate < elapsed || value == m_maximum)) {
|
|
m_last_timeupdate = elapsed;
|
|
unsigned long estimated = m_break + (unsigned long) (((double) (elapsed - m_break) * m_maximum) / ((double) value));
|
|
if (estimated > m_display_estimated && m_ctdelay >= 0) {
|
|
++m_ctdelay;
|
|
} else if (estimated < m_display_estimated && m_ctdelay <= 0) {
|
|
--m_ctdelay;
|
|
} else {
|
|
m_ctdelay = 0;
|
|
}
|
|
if (m_ctdelay >= m_delay // enough confirmations for a higher value
|
|
|| m_ctdelay <= (m_delay * -1) // enough confirmations for a lower value
|
|
|| value == m_maximum // to stay consistent
|
|
|| elapsed > m_display_estimated // to stay consistent
|
|
|| (elapsed > 0 && elapsed < 4) // additional updates in the beginning
|
|
) {
|
|
m_display_estimated = estimated;
|
|
m_ctdelay = 0;
|
|
}
|
|
}
|
|
|
|
if (value != 0) {
|
|
long display_remaining = m_display_estimated - elapsed;
|
|
if (display_remaining < 0) { display_remaining = 0; }
|
|
|
|
estimatedTime = m_display_estimated;
|
|
remainingTime = display_remaining;
|
|
}
|
|
|
|
elapsedTime = elapsed;
|
|
}
|
|
|
|
// static
|
|
wxString ProgressDialog::GetFormattedTime(unsigned long timeInSec)
|
|
{
|
|
wxString timeAsHMS;
|
|
|
|
if (timeInSec == (unsigned long) -1) {
|
|
timeAsHMS = wxGetTranslation("Unknown");
|
|
} else {
|
|
unsigned hours = timeInSec / 3600;
|
|
unsigned minutes = (timeInSec % 3600) / 60;
|
|
unsigned seconds = timeInSec % 60;
|
|
timeAsHMS.Printf("%u:%02u:%02u", hours, minutes, seconds);
|
|
}
|
|
|
|
return timeAsHMS;
|
|
}
|
|
|
|
void ProgressDialog::EnsureActiveEventLoopExists()
|
|
{
|
|
if (!wxEventLoopBase::GetActive()) {
|
|
m_tempEventLoop = new wxEventLoop;
|
|
wxEventLoop::SetActive(m_tempEventLoop);
|
|
}
|
|
}
|
|
|
|
wxStaticText *ProgressDialog::CreateLabel(const wxString &text, wxSizer *sizer)
|
|
{
|
|
wxStaticText *label = new wxStaticText(this, wxID_ANY, text);
|
|
wxStaticText *value = new wxStaticText(this, wxID_ANY, wxGetTranslation("unknown"));
|
|
|
|
// select placement most native or nice on target GUI
|
|
#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXGTK20__)
|
|
// value and time centered in one row
|
|
sizer->Add(label, 1, wxALIGN_RIGHT | wxTOP | wxRIGHT, LAYOUT_MARGIN);
|
|
sizer->Add(value, 1, wxALIGN_LEFT | wxTOP, LAYOUT_MARGIN);
|
|
#else
|
|
// value and time to the right in one row
|
|
sizer->Add(label);
|
|
sizer->Add(value, 0, wxLEFT, LAYOUT_MARGIN);
|
|
#endif
|
|
|
|
return value;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// ProgressDialog operations
|
|
// ----------------------------------------------------------------------------
|
|
|
|
bool ProgressDialog::Update(int value, const wxString &newmsg, bool *skip)
|
|
{
|
|
if (!DoBeforeUpdate(skip)) return false;
|
|
|
|
wxCHECK_MSG(m_msg || m_gauge, false, "dialog should be fully created");
|
|
|
|
#ifdef __WXMSW__
|
|
value /= m_factor;
|
|
#endif // __WXMSW__
|
|
|
|
wxASSERT_MSG(value <= m_maximum, wxT("invalid progress value"));
|
|
if (m_gauge)
|
|
m_gauge->SetValue(value);
|
|
|
|
UpdateMessage(newmsg);
|
|
|
|
if ((m_elapsed || m_remaining || m_estimated) && (value != 0)) {
|
|
unsigned long elapsed;
|
|
unsigned long display_remaining;
|
|
|
|
UpdateTimeEstimates(value, elapsed, m_display_estimated, display_remaining);
|
|
|
|
SetTimeLabel(elapsed, m_elapsed);
|
|
SetTimeLabel(m_display_estimated, m_estimated);
|
|
SetTimeLabel(display_remaining, m_remaining);
|
|
}
|
|
|
|
if (value == m_maximum) {
|
|
if (m_state == Finished) {
|
|
// ignore multiple calls to Update(m_maximum): it may sometimes be
|
|
// troublesome to ensure that Update() is not called twice with the
|
|
// same value (e.g. because of the rounding errors) and if we don't
|
|
// return now we're going to generate asserts below
|
|
return true;
|
|
}
|
|
|
|
// so that we return true below and that out [Cancel] handler knew what
|
|
// to do
|
|
m_state = Finished;
|
|
if (!HasPDFlag(wxPD_AUTO_HIDE)) {
|
|
EnableClose();
|
|
DisableSkip();
|
|
#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
|
|
EnableCloseButton();
|
|
#endif // __WXMSW__
|
|
|
|
if (newmsg.empty()) {
|
|
// also provide the finishing message if the application didn't
|
|
m_msg->SetLabel(wxGetTranslation("Done."));
|
|
}
|
|
|
|
// allow the window to repaint:
|
|
// NOTE: since we yield only for UI events with this call, there
|
|
// should be no side-effects
|
|
wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT);
|
|
|
|
// NOTE: this call results in a new event loop being created
|
|
// and to a call to ProcessPendingEvents() (which may generate
|
|
// unwanted re-entrancies).
|
|
(void) ShowModal();
|
|
} else // auto hide
|
|
{
|
|
// reenable other windows before hiding this one because otherwise
|
|
// Windows wouldn't give the focus back to the window which had
|
|
// been previously focused because it would still be disabled
|
|
ReenableOtherWindows();
|
|
|
|
Hide();
|
|
}
|
|
} else // not at maximum yet
|
|
{
|
|
DoAfterUpdate();
|
|
}
|
|
|
|
// update the display in case yielding above didn't do it
|
|
Update();
|
|
|
|
return m_state != Canceled;
|
|
}
|
|
|
|
bool ProgressDialog::Pulse(const wxString &newmsg, bool *skip)
|
|
{
|
|
if (!DoBeforeUpdate(skip)) return false;
|
|
|
|
wxCHECK_MSG(m_msg || m_gauge, false, "dialog should be fully created");
|
|
|
|
// show a bit of progress
|
|
if (m_gauge) m_gauge->Pulse();
|
|
|
|
UpdateMessage(newmsg);
|
|
|
|
if (m_elapsed || m_remaining || m_estimated) {
|
|
unsigned long elapsed = wxGetCurrentTime() - m_timeStart;
|
|
|
|
SetTimeLabel(elapsed, m_elapsed);
|
|
SetTimeLabel((unsigned long) -1, m_estimated);
|
|
SetTimeLabel((unsigned long) -1, m_remaining);
|
|
}
|
|
|
|
DoAfterUpdate();
|
|
|
|
return m_state != Canceled;
|
|
}
|
|
|
|
bool ProgressDialog::WasCanceled() const { return m_state == Canceled; }
|
|
|
|
bool ProgressDialog::DoBeforeUpdate(bool *skip)
|
|
{
|
|
// we have to yield because not only we want to update the display but
|
|
// also to process the clicks on the cancel and skip buttons
|
|
// NOTE: using YieldFor() this call shouldn't give re-entrancy problems
|
|
// for event handlers not interested to UI/user-input events.
|
|
wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT);
|
|
|
|
Update();
|
|
|
|
if (m_skip && skip && !*skip) {
|
|
*skip = true;
|
|
m_skip = false;
|
|
EnableSkip();
|
|
}
|
|
|
|
return m_state != Canceled;
|
|
}
|
|
|
|
void ProgressDialog::DoAfterUpdate()
|
|
{
|
|
// allow the window to repaint:
|
|
// NOTE: since we yield only for UI events with this call, there
|
|
// should be no side-effects
|
|
wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT);
|
|
}
|
|
|
|
void ProgressDialog::Resume()
|
|
{
|
|
m_state = Continue;
|
|
m_ctdelay = m_delay; // force an update of the elapsed/estimated/remaining time
|
|
m_break += wxGetCurrentTime() - m_timeStop;
|
|
|
|
EnableAbort();
|
|
m_button_cancel->Enable(true);
|
|
EnableSkip();
|
|
m_skip = false;
|
|
}
|
|
|
|
bool ProgressDialog::Show(bool show)
|
|
{
|
|
// reenable other windows before hiding this one because otherwise
|
|
// Windows wouldn't give the focus back to the window which had
|
|
// been previously focused because it would still be disabled
|
|
if (!show) ReenableOtherWindows();
|
|
return wxDialog::Show(show);
|
|
}
|
|
|
|
int ProgressDialog::GetValue() const
|
|
{
|
|
wxCHECK_MSG(m_gauge, -1, "dialog should be fully created");
|
|
|
|
return m_gauge->GetValue();
|
|
}
|
|
|
|
int ProgressDialog::GetRange() const { return m_maximum; }
|
|
|
|
wxString ProgressDialog::GetMessage() const { return m_msg->GetLabel(); }
|
|
|
|
void ProgressDialog::SetRange(int maximum)
|
|
{
|
|
wxCHECK_RET(m_gauge, "dialog should be fully created");
|
|
|
|
wxCHECK_RET(maximum > 0, "Invalid range");
|
|
|
|
m_gauge->SetRange(maximum);
|
|
|
|
SetMaximum(maximum);
|
|
}
|
|
|
|
void ProgressDialog::set_panel_height(int height) {
|
|
m_simplebook->SetSize(wxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x, height));
|
|
m_simplebook->SetMinSize(wxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x, height));
|
|
m_panel_2line->SetSize(wxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x, height));
|
|
m_panel_2line->SetMinSize(wxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x, height));
|
|
m_msg_2line->SetSize(wxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x, height));
|
|
m_msg_2line->SetMinSize(wxSize(PROGRESSDIALOG_SIMPLEBOOK_SIZE.x, height));
|
|
}
|
|
|
|
void ProgressDialog::SetMaximum(int maximum)
|
|
{
|
|
m_maximum = maximum;
|
|
|
|
#if defined(__WXMSW__)
|
|
// we can't have values > 65,536 in the progress control under Windows, so
|
|
// scale everything down
|
|
m_factor = m_maximum / 65536 + 1;
|
|
m_maximum /= m_factor;
|
|
#endif // __WXMSW__
|
|
}
|
|
|
|
bool ProgressDialog::WasCancelled() const { return HasPDFlag(wxPD_CAN_ABORT) && m_state == Canceled; }
|
|
|
|
bool ProgressDialog::WasSkipped() const { return HasPDFlag(wxPD_CAN_SKIP) && m_skip; }
|
|
|
|
// static
|
|
void ProgressDialog::SetTimeLabel(unsigned long val, wxStaticText *label)
|
|
{
|
|
if (label) {
|
|
wxString s;
|
|
|
|
if (val != (unsigned long) -1) {
|
|
s = GetFormattedTime(val);
|
|
} else {
|
|
s = wxGetTranslation("Unknown");
|
|
}
|
|
|
|
if (s != label->GetLabel()) label->SetLabel(s);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// event handlers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void ProgressDialog::OnCancel(wxCommandEvent &event)
|
|
{
|
|
if (m_state == Finished) {
|
|
// this means that the count down is already finished and we're being
|
|
// shown as a modal dialog - so just let the default handler do the job
|
|
event.Skip();
|
|
} else {
|
|
// request to cancel was received, the next time Update() is called we
|
|
// will handle it
|
|
m_state = Canceled;
|
|
|
|
// update the buttons state immediately so that the user knows that the
|
|
// request has been noticed
|
|
DisableAbort();
|
|
DisableSkip();
|
|
|
|
OnCancel();
|
|
|
|
// save the time when the dialog was stopped
|
|
m_timeStop = wxGetCurrentTime();
|
|
}
|
|
}
|
|
|
|
void ProgressDialog::OnSkip(wxCommandEvent &WXUNUSED(event))
|
|
{
|
|
DisableSkip();
|
|
m_skip = true;
|
|
}
|
|
|
|
void ProgressDialog::OnClose(wxCloseEvent &event)
|
|
{
|
|
if (m_state == Uncancelable) {
|
|
// can't close this dialog
|
|
event.Veto();
|
|
} else if (m_state == Finished) {
|
|
// let the default handler close the window as we already terminated
|
|
event.Skip();
|
|
} else {
|
|
// next Update() will notice it
|
|
m_state = Canceled;
|
|
DisableAbort();
|
|
DisableSkip();
|
|
OnCancel();
|
|
|
|
m_timeStop = wxGetCurrentTime();
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// destruction
|
|
// ----------------------------------------------------------------------------
|
|
|
|
ProgressDialog::~ProgressDialog()
|
|
{
|
|
// normally this should have been already done, but just in case
|
|
ReenableOtherWindows();
|
|
|
|
if (m_tempEventLoop) {
|
|
// If another event loop has been installed as active during the life
|
|
// time of this object, we shouldn't deactivate it, but we also can't
|
|
// delete our m_tempEventLoop in this case because it risks leaving the
|
|
// new event loop with a dangling pointer, which it will set back as
|
|
// the active loop when it exits, resulting in a crash. So we have no
|
|
// choice but to just leak this pointer then, which is, of course, bad
|
|
// and usually easily avoidable by just destroying the progress dialog
|
|
// sooner, so warn the programmer about it.
|
|
wxCHECK_RET(wxEventLoopBase::GetActive() == m_tempEventLoop, "current event loop must not be changed during "
|
|
"ProgressDialog lifetime");
|
|
|
|
wxEventLoopBase::SetActive(NULL);
|
|
delete m_tempEventLoop;
|
|
}
|
|
}
|
|
|
|
void ProgressDialog::DoSetSize(int x, int y, int width, int height, int sizeFlags /*= wxSIZE_AUTO*/)
|
|
{
|
|
if (m_button_cancel != nullptr) { m_button_cancel->SetMinSize(PROGRESSDIALOG_CANCEL_BUTTON_SIZE); }
|
|
|
|
#ifdef __WXMSW__
|
|
//if (m_block_left != nullptr && m_block_right != nullptr) {
|
|
// m_block_left->SetPosition(wxPoint(0, 0));
|
|
// m_block_right->SetPosition(wxPoint(PROGRESSDIALOG_GAUGE_SIZE.x - 2, 0));
|
|
//}
|
|
#endif
|
|
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
|
|
}
|
|
|
|
void ProgressDialog::DisableOtherWindows()
|
|
{
|
|
if (HasPDFlag(wxPD_APP_MODAL)) {
|
|
#if defined(__WXOSX__)
|
|
if (m_parentTop) m_parentTop->Disable();
|
|
m_winDisabler = NULL;
|
|
#else
|
|
m_winDisabler = new wxWindowDisabler(this);
|
|
#endif
|
|
} else {
|
|
if (m_parentTop) m_parentTop->Disable();
|
|
m_winDisabler = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
void ProgressDialog::ReenableOtherWindows()
|
|
{
|
|
if (HasPDFlag(wxPD_APP_MODAL)) {
|
|
#if defined(__WXOSX__)
|
|
if (m_parentTop) m_parentTop->Enable();
|
|
#else
|
|
wxDELETE(m_winDisabler);
|
|
#endif
|
|
} else {
|
|
if (m_parentTop) m_parentTop->Enable();
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// private functions
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void ProgressDialog::EnableSkip(bool enable)
|
|
{
|
|
if (HasPDFlag(wxPD_CAN_SKIP)) {
|
|
if (m_btnSkip) m_btnSkip->Enable(enable);
|
|
}
|
|
}
|
|
|
|
void ProgressDialog::EnableAbort(bool enable)
|
|
{
|
|
if (HasPDFlag(wxPD_CAN_ABORT)) {
|
|
if (m_btnAbort) m_btnAbort->Enable(enable);
|
|
}
|
|
}
|
|
|
|
void ProgressDialog::EnableClose()
|
|
{
|
|
if (HasPDFlag(wxPD_CAN_ABORT)) {
|
|
if (m_btnAbort) {
|
|
m_btnAbort->Enable();
|
|
m_btnAbort->SetLabel(wxGetTranslation("Close"));
|
|
}
|
|
}
|
|
}
|
|
|
|
void ProgressDialog::UpdateMessage(const wxString &newmsg)
|
|
{
|
|
if (!newmsg.empty() && newmsg != m_msg->GetLabel()) {
|
|
const wxSize sizeOld = m_msg->GetSize();
|
|
|
|
FormatString(newmsg);
|
|
Fit();
|
|
// m_msg->SetLabel(newmsg);
|
|
|
|
if (m_msg->GetSize().x > sizeOld.x) {
|
|
// Resize the dialog to fit its new, longer contents instead of
|
|
// just truncating it.
|
|
Fit();
|
|
}
|
|
|
|
// allow the window to repaint:
|
|
// NOTE: since we yield only for UI events with this call, there
|
|
// should be no side-effects
|
|
wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT);
|
|
}
|
|
}
|
|
}} // namespace Slic3r::GUI
|