diff --git a/src/slic3r/GUI/ImageGrid.cpp b/src/slic3r/GUI/ImageGrid.cpp index eff08335d..e552783a3 100644 --- a/src/slic3r/GUI/ImageGrid.cpp +++ b/src/slic3r/GUI/ImageGrid.cpp @@ -5,6 +5,7 @@ #include "I18N.hpp" #include "GUI_App.hpp" #include "GUI.hpp" +#include "MsgDialog.hpp" #include @@ -127,11 +128,12 @@ void Slic3r::GUI::ImageGrid::Rescale() void Slic3r::GUI::ImageGrid::Select(size_t index) { + if (m_selecting) { + m_file_sys->ToggleSelect(index); + Refresh(); + return; + } if (m_file_sys->GetGroupMode() == PrinterFileSystem::G_NONE) { - if (m_selecting) { - m_file_sys->ToggleSelect(index); - Refresh(); - } return; } index = m_file_sys->EnterSubGroup(index); @@ -145,6 +147,13 @@ void Slic3r::GUI::ImageGrid::Select(size_t index) void Slic3r::GUI::ImageGrid::DoAction(size_t index, int action) { if (action == 0) { + if (m_file_sys->GetSelectCount() > 1) { + MessageDialog dlg(this, + wxString::Format(_L("You are going to delete %u files. Are you sure to continue?"), m_file_sys->GetSelectCount()), + _L("Delete files"), wxYES_NO | wxICON_WARNING); + if (dlg.ShowModal() != wxID_YES) + return; + } m_file_sys->DeleteFiles(index); } else if (action == 1) { if (index != -1) { @@ -152,7 +161,9 @@ void Slic3r::GUI::ImageGrid::DoAction(size_t index, int action) if (file.IsDownload() && file.progress >= -1) { if (file.progress >= 100) { if (!m_file_sys->DownloadCheckFile(index)) { - wxMessageBox(wxString::Format(_L("File '%s' was lost! Please download it again."), from_u8(file.name)), _L("Error"), wxOK); + MessageDialog(this, + wxString::Format(_L("File '%s' was lost! Please download it again."), from_u8(file.name)), + _L("Error"), wxOK).ShowModal(); Refresh(); return; } @@ -176,7 +187,9 @@ void Slic3r::GUI::ImageGrid::DoAction(size_t index, int action) if (file.IsDownload() && file.progress >= -1) { if (file.progress >= 100) { if (!m_file_sys->DownloadCheckFile(index)) { - wxMessageBox(wxString::Format(_L("File '%s' was lost! Please download it again."), from_u8(file.name)), _L("Error"), wxOK); + MessageDialog(this, + wxString::Format(_L("File '%s' was lost! Please download it again."), from_u8(file.name)), + _L("Error"), wxOK).ShowModal(); Refresh(); return; } @@ -465,6 +478,8 @@ wxBitmap Slic3r::GUI::ImageGrid::createCircleBitmap(wxSize size, int borderWidth return bmp; } +static constexpr wchar_t const *TIME_FORMATS[] = {_T("%Y-%m-%d"), _T("%Y-%m"), _T("%Y")}; + /* * Here we do the actual rendering. I put it in a separate * method so that it can work no matter what type of DC @@ -495,7 +510,6 @@ void ImageGrid::render(wxDC& dc) // Draw line spacing at top if (off.y > 0) dc.DrawRectangle({0, 0, size.x, off.y}); - constexpr wchar_t const * formats[] = {_T("%Y-%m-%d"), _T("%Y-%m"), _T("%Y")}; size_t start = index; size_t end = index; size_t hit_image = m_selecting ? size_t(-1) : m_hit_type == HIT_ITEM ? m_hit_item : m_hit_type == HIT_ACTION ? m_hit_item / 4 :size_t(-1); @@ -506,65 +520,7 @@ void ImageGrid::render(wxDC& dc) wxPoint pt{off.x, off.y}; end = (index + m_col_count) < m_file_sys->GetCount() ? index + m_col_count : m_file_sys->GetCount(); while (index < end) { - auto & file = m_file_sys->GetFile(index); - // Draw thumbnail - if (file.thumbnail.IsOk()) { - float hs = (float) m_image_size.GetWidth() / file.thumbnail.GetWidth(); - float vs = (float) m_image_size.GetHeight() / file.thumbnail.GetHeight(); - dc.SetUserScale(hs, vs); - dc.DrawBitmap(file.thumbnail, {(int) (pt.x / hs), (int) (pt.y / vs)}); - dc.SetUserScale(1, 1); - if (m_file_sys->GetGroupMode() != PrinterFileSystem::G_NONE) { - dc.DrawBitmap(m_mask, pt); - } - } - bool show_download_state_always = true; - // Draw checked icon - if (m_selecting && !show_download_state_always) - dc.DrawBitmap(file.IsSelect() ? m_checked_icon.bmp() : m_unchecked_icon.bmp(), - pt + wxPoint{10, m_image_size.GetHeight() - m_checked_icon.GetBmpHeight() - 10}); - // can't handle alpha - // dc.GradientFillLinear({pt.x, pt.y, m_image_size.GetWidth(), 60}, wxColour(0x6F, 0x6F, 0x6F, 0x99), wxColour(0x6F, 0x6F, 0x6F, 0), wxBOTTOM); - else if (m_file_sys->GetGroupMode() == PrinterFileSystem::G_NONE) { - wxString nonHoverText; - wxString secondAction = _L("Download"); - wxString thirdAction; - int states = 0; - // Draw download progress - if (file.IsDownload()) { - if (file.progress == -1) { - secondAction = _L("Cancel"); - nonHoverText = _L("Download waiting..."); - } else if (file.progress < 0) { - secondAction = _L("Retry"); - nonHoverText = _L("Download failed"); - states = StateColor::Checked; - } else if (file.progress >= 100) { - secondAction = _L("Play"); - thirdAction = _L("Open Folder"); - nonHoverText = _L("Download finished"); - } else { - secondAction = _L("Cancel"); - nonHoverText = wxString::Format(_L("Downloading %d%%..."), file.progress); - thirdAction = wxString::Format(L"%d%%...", file.progress); - } - } - // Draw buttons on hovered item - wxRect rect{pt.x, pt.y + m_image_size.y - m_buttons_background.GetHeight(), m_image_size.GetWidth(), m_buttons_background.GetHeight()}; - if (hit_image == index) { - renderButtons(dc, {_L("Delete"), (wxChar const *) secondAction, thirdAction.IsEmpty() ? nullptr : (wxChar const *) thirdAction, nullptr}, rect, - m_hit_type == HIT_ACTION ? m_hit_item & 3 : -1, states); - } else if (!nonHoverText.IsEmpty()) { - renderButtons(dc, {(wxChar const *) nonHoverText, nullptr}, rect, -1, states); - } - if (m_selecting && show_download_state_always) - dc.DrawBitmap(file.IsSelect() ? m_checked_icon.bmp() : m_unchecked_icon.bmp(), - pt + wxPoint{10, m_image_size.GetHeight() - m_checked_icon.GetBmpHeight() - 10}); - } else { - dc.SetTextForeground(*wxWHITE); // time text color - auto date = wxDateTime((time_t) file.time).Format(_L(formats[m_file_sys->GetGroupMode()])); - dc.DrawText(date, pt + wxPoint{24, 16}); - } + renderContent(dc, pt, index, hit_image == index); // Draw colume spacing at right dc.DrawRectangle({pt.x + m_image_size.GetWidth(), pt.y, m_cell_size.GetWidth() - m_image_size.GetWidth(), m_image_size.GetHeight()}); ++index; @@ -583,8 +539,8 @@ void ImageGrid::render(wxDC& dc) dc.DrawRectangle({off.x, 0}, m_mask.GetSize()); auto & file1 = m_file_sys->GetFile(start); auto & file2 = m_file_sys->GetFile(end - 1); - auto date1 = wxDateTime((time_t) file1.time).Format(_L(formats[m_file_sys->GetGroupMode()])); - auto date2 = wxDateTime((time_t) file2.time).Format(_L(formats[m_file_sys->GetGroupMode()])); + auto date1 = wxDateTime((time_t) file1.time).Format(_L(TIME_FORMATS[m_file_sys->GetGroupMode()])); + auto date2 = wxDateTime((time_t) file2.time).Format(_L(TIME_FORMATS[m_file_sys->GetGroupMode()])); dc.SetFont(Label::Head_16); dc.SetTextForeground(StateColor::darkModeColorFor("#262E30")); dc.DrawText(date1 + " - " + date2, wxPoint{off.x, 2}); @@ -605,6 +561,68 @@ void ImageGrid::render(wxDC& dc) } } +void Slic3r::GUI::ImageGrid::renderContent(wxDC &dc, wxPoint const &pt, int index, bool hit) +{ + bool selected = false; + auto &file = m_file_sys->GetFile(index, selected); + // Draw thumbnail + if (file.thumbnail.IsOk()) { + float hs = (float) m_image_size.GetWidth() / file.thumbnail.GetWidth(); + float vs = (float) m_image_size.GetHeight() / file.thumbnail.GetHeight(); + dc.SetUserScale(hs, vs); + dc.DrawBitmap(file.thumbnail, {(int) (pt.x / hs), (int) (pt.y / vs)}); + dc.SetUserScale(1, 1); + if (m_file_sys->GetGroupMode() != PrinterFileSystem::G_NONE) { + dc.DrawBitmap(m_mask, pt); + } + } + bool show_download_state_always = true; + // Draw checked icon + if (m_selecting && !show_download_state_always) + dc.DrawBitmap(selected ? m_checked_icon.bmp() : m_unchecked_icon.bmp(), pt + wxPoint{10, m_image_size.GetHeight() - m_checked_icon.GetBmpHeight() - 10}); + // can't handle alpha + // dc.GradientFillLinear({pt.x, pt.y, m_border_size.GetWidth(), 60}, wxColour(0x6F, 0x6F, 0x6F, 0x99), wxColour(0x6F, 0x6F, 0x6F, 0), wxBOTTOM); + else if (m_file_sys->GetGroupMode() == PrinterFileSystem::G_NONE) { + wxString nonHoverText; + wxString secondAction = _L("Download"); + wxString thirdAction; + int states = 0; + // Draw download progress + if (file.IsDownload()) { + if (file.progress == -1) { + secondAction = _L("Cancel"); + nonHoverText = _L("Download waiting..."); + } else if (file.progress < 0) { + secondAction = _L("Retry"); + nonHoverText = _L("Download failed"); + states = StateColor::Checked; + } else if (file.progress >= 100) { + secondAction = _L("Play"); + thirdAction = _L("Open Folder"); + nonHoverText = _L("Download finished"); + } else { + secondAction = _L("Cancel"); + nonHoverText = wxString::Format(_L("Downloading %d%%..."), file.progress); + thirdAction = wxString::Format(L"%d%%...", file.progress); + } + } + // Draw buttons on hovered item + wxRect rect{pt.x, pt.y + m_image_size.GetHeight() - m_buttons_background.GetHeight(), m_image_size.GetWidth(), m_buttons_background.GetHeight()}; + if (hit) { + renderButtons(dc, {_L("Delete"), (wxChar const *) secondAction, thirdAction.IsEmpty() ? nullptr : (wxChar const *) thirdAction, nullptr}, rect, + m_hit_type == HIT_ACTION ? m_hit_item & 3 : -1, states); + } else if (!nonHoverText.IsEmpty()) { + renderButtons(dc, {(wxChar const *) nonHoverText, nullptr}, rect, -1, states); + } + } else { + dc.SetTextForeground(*wxWHITE); // time text color + auto date = wxDateTime((time_t) file.time).Format(_L(TIME_FORMATS[m_file_sys->GetGroupMode()])); + dc.DrawText(date, pt + wxPoint{24, 16}); + } + if (m_selecting && show_download_state_always) + dc.DrawBitmap(selected ? m_checked_icon.bmp() : m_unchecked_icon.bmp(), pt + wxPoint{10, m_image_size.GetHeight() - m_checked_icon.GetBmpHeight() - 10}); +} + void Slic3r::GUI::ImageGrid::renderButtons(wxDC &dc, wxStringList const &texts, wxRect const &rect2, size_t hit, int states) { // Draw background diff --git a/src/slic3r/GUI/ImageGrid.h b/src/slic3r/GUI/ImageGrid.h index 8aef8a5e9..0aa97b008 100644 --- a/src/slic3r/GUI/ImageGrid.h +++ b/src/slic3r/GUI/ImageGrid.h @@ -76,6 +76,8 @@ protected: void render(wxDC &dc); + void renderContent(wxDC &dc, wxPoint const &pt, int index, bool hit); + void renderButtons(wxDC &dc, wxStringList const &texts, wxRect const &rect, size_t hit, int states); void renderText(wxDC &dc, wxString const & text, wxRect const & rect, int states); diff --git a/src/slic3r/GUI/Printer/PrinterFileSystem.cpp b/src/slic3r/GUI/Printer/PrinterFileSystem.cpp index 97c506dad..8915e5f78 100644 --- a/src/slic3r/GUI/Printer/PrinterFileSystem.cpp +++ b/src/slic3r/GUI/Printer/PrinterFileSystem.cpp @@ -78,6 +78,7 @@ void PrinterFileSystem::SetGroupMode(GroupMode mode) return; this->m_group_mode = mode; m_lock_start = m_lock_end = 0; + UpdateGroupSelect(); SendChangedEvent(EVT_MODE_CHANGED); } @@ -131,6 +132,7 @@ void PrinterFileSystem::ListAllFiles() } } BuildGroups(); + UpdateGroupSelect(); m_status = Status::ListReady; SendChangedEvent(EVT_STATUS_CHANGED, m_status); SendChangedEvent(EVT_FILE_CHANGED); @@ -253,7 +255,28 @@ size_t PrinterFileSystem::GetIndexAtTime(boost::uint32_t time) void PrinterFileSystem::ToggleSelect(size_t index) { - if (index < m_file_list.size()) { + if (m_group_mode != G_NONE) { + size_t beg = m_group_mode == G_YEAR ? m_group_month[m_group_year[index]] : m_group_month[index]; + size_t end_month = m_group_mode == G_YEAR ? ((index + 1) < m_group_year.size() ? m_group_year[index + 1] : m_group_month.size()) : index + 1; + size_t end = end_month < m_group_month.size() ? m_group_month[end_month] : m_file_list.size(); + if ((m_group_flags[index] & FF_SELECT) == 0) { + for (int i = beg; i < end; ++i) { + if ((m_file_list[i].flags & FF_SELECT) == 0) { + m_file_list[i].flags |= FF_SELECT; + ++m_select_count; + } + } + m_group_flags[index] |= FF_SELECT; + } else { + for (int i = beg; i < end; ++i) { + if (m_file_list[i].flags & FF_SELECT) { + m_file_list[i].flags &= ~FF_SELECT; + --m_select_count; + } + } + m_group_flags[index] &= ~FF_SELECT; + } + } else if (index < m_file_list.size()) { m_file_list[index].flags ^= FF_SELECT; if (m_file_list[index].flags & FF_SELECT) ++m_select_count; @@ -268,9 +291,11 @@ void PrinterFileSystem::SelectAll(bool select) if (select) { for (auto &f : m_file_list) f.flags |= FF_SELECT; m_select_count = m_file_list.size(); + for (auto &s : m_group_flags) s |= FF_SELECT; } else { for (auto &f : m_file_list) f.flags &= ~FF_SELECT; m_select_count = 0; + for (auto &s : m_group_flags) s &= ~FF_SELECT; } SendChangedEvent(EVT_SELECT_CHANGED, m_select_count); } @@ -289,6 +314,17 @@ PrinterFileSystem::File const &PrinterFileSystem::GetFile(size_t index) { if (m_group_mode == G_NONE) return m_file_list[index]; + if (m_group_mode == G_YEAR) index = m_group_year[index]; + return m_file_list[m_group_month[index]]; +} + +PrinterFileSystem::File const &PrinterFileSystem::GetFile(size_t index, bool &select) +{ + if (m_group_mode == G_NONE) { + select = m_file_list[index].IsSelect(); + return m_file_list[index]; + } + select = m_group_flags[index] & FF_SELECT; if (m_group_mode == G_YEAR) index = m_group_year[index]; return m_file_list[m_group_month[index]]; @@ -380,6 +416,26 @@ void PrinterFileSystem::BuildGroups() } } +void PrinterFileSystem::UpdateGroupSelect() +{ + m_group_flags.clear(); + int beg = 0; + if (m_group_mode != G_NONE) { + auto group = m_group_mode == G_YEAR ? m_group_year : m_group_month; + if (m_group_mode == G_YEAR) + for (auto &g : group) g = m_group_month[g]; + m_group_flags.resize(group.size(), FF_SELECT); + for (int i = 0; i < m_file_list.size(); ++i) { + if ((m_file_list[i].flags & FF_SELECT) == 0) { + auto iter = std::upper_bound(group.begin(), group.end(), i); + m_group_flags[iter - group.begin() - 1] &= ~FF_SELECT; + if (iter == group.end()) break; + i = *iter - 1; // start from next group + } + } + } +} + void PrinterFileSystem::DeleteFilesContinue() { std::vector indexes; @@ -584,9 +640,14 @@ void PrinterFileSystem::FileRemoved(size_t index, std::string const &name) size_t index2 = removeFromGroup(m_group_month, index, m_file_list.size()); if (index2 < m_group_month.size()) { int index3 = removeFromGroup(m_group_year, index, m_group_month.size()); - if (index3 < m_group_year.size()) + if (index3 < m_group_year.size()) { m_group_year.erase(m_group_year.begin() + index3); + if (m_group_mode == G_YEAR) + m_group_flags.erase(m_group_flags.begin() + index2); + } m_group_month.erase(m_group_month.begin() + index2); + if (m_group_mode == G_MONTH) + m_group_flags.erase(m_group_flags.begin() + index2); } m_file_list.erase(m_file_list.begin() + index); } diff --git a/src/slic3r/GUI/Printer/PrinterFileSystem.h b/src/slic3r/GUI/Printer/PrinterFileSystem.h index 775721621..66e41f2d6 100644 --- a/src/slic3r/GUI/Printer/PrinterFileSystem.h +++ b/src/slic3r/GUI/Printer/PrinterFileSystem.h @@ -146,6 +146,8 @@ public: File const &GetFile(size_t index); + File const &GetFile(size_t index, bool &select); + enum Status { Initializing, Connecting, @@ -170,6 +172,8 @@ public: private: void BuildGroups(); + void UpdateGroupSelect(); + void DeleteFilesContinue(); void DownloadNextFile(); @@ -266,6 +270,7 @@ protected: FileList m_file_list2; std::vector m_group_year; std::vector m_group_month; + std::vector m_group_flags; private: size_t m_select_count = 0;