diff --git a/GUI/EvtMainFrame.cpp b/GUI/EvtMainFrame.cpp index 1a3cff6..40d8484 100644 --- a/GUI/EvtMainFrame.cpp +++ b/GUI/EvtMainFrame.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -54,7 +55,9 @@ EvtMainFrame::EvtMainFrame(wxWindow* parent): MainFrame(parent) { _watcher.AddTree(wxFileName(Utility::Directory::toNativeSeparators(_manager.saveDirectory()), wxPATH_WIN), wxFSW_EVENT_CREATE|wxFSW_EVENT_DELETE|wxFSW_EVENT_MODIFY|wxFSW_EVENT_RENAME, wxString::Format("*%s.sav", _manager.steamId())); _watcher.AddTree(wxFileName(Utility::Directory::toNativeSeparators(_manager.stagingAreaDirectory()), wxPATH_WIN), - wxFSW_EVENT_CREATE|wxFSW_EVENT_DELETE|wxFSW_EVENT_MODIFY|wxFSW_EVENT_RENAME, wxString::Format("*.sav")); + wxFSW_EVENT_CREATE|wxFSW_EVENT_DELETE|wxFSW_EVENT_MODIFY|wxFSW_EVENT_RENAME, "*.sav"); + _watcher.AddTree(wxFileName(Utility::Directory::toNativeSeparators(_manager.screenshotDirectory()), wxPATH_WIN), + wxFSW_EVENT_CREATE|wxFSW_EVENT_DELETE, "*.png"); // Not monitoring wxFSW_EVENT_{MODIFY,RENAME}, because they're a massive pain to handle. Ugh. std::vector v = _manager.initialiseStagingArea(); for(const std::string& s : v) { @@ -62,6 +65,10 @@ EvtMainFrame::EvtMainFrame(wxWindow* parent): MainFrame(parent) { } _gameCheckTimer.Start(3000); + + _screenshotsList->SetImageList(&_screenshotThumbs, wxIMAGE_LIST_NORMAL); + + updateScreenshotList(); } EvtMainFrame::~EvtMainFrame() { @@ -230,6 +237,11 @@ void EvtMainFrame::stagingSelectionEvent(wxCommandEvent&) { } void EvtMainFrame::deleteStagedEvent(wxCommandEvent&) { + if(wxMessageBox("Are you sure you want to delete the selected M.A.S.S. ? This operation cannot be undone.", + "Are you sure ?", wxYES_NO|wxCENTRE|wxICON_QUESTION, this) == wxNO) { + return; + } + int selection = _stagingList->GetSelection(); if(selection != wxNOT_FOUND) { @@ -249,6 +261,55 @@ void EvtMainFrame::listColumnDragEvent(wxListEvent& event) { event.Veto(); } +void EvtMainFrame::screenshotListSelectionEvent(wxListEvent&) { + updateCommandsState(); +} + +void EvtMainFrame::screenshotFilenameSortingEvent(wxCommandEvent&) { + _manager.sortScreenshots(SortType::Filename); + updateScreenshotList(); +} + +void EvtMainFrame::screenshotCreationDateSortingEvent(wxCommandEvent&) { + _manager.sortScreenshots(SortType::CreationDate); + updateScreenshotList(); +} + +void EvtMainFrame::screenshotAscendingSortingEvent(wxCommandEvent&) { + _manager.sortScreenshots(SortOrder::Ascending); + updateScreenshotList(); +} + +void EvtMainFrame::screenshotDescendingSortingEvent(wxCommandEvent&) { + _manager.sortScreenshots(SortOrder::Descending); + updateScreenshotList(); +} + +void EvtMainFrame::viewScreenshotEvent(wxCommandEvent&) { + viewScreenshot(); +} + +void EvtMainFrame::viewScreenshotEvent(wxListEvent&) { + viewScreenshot(); +} + +void EvtMainFrame::deleteScreenshotEvent(wxCommandEvent&) { + if(wxMessageBox("Are you sure you want to delete the selected screenshot ? This operation cannot be undone.", + "Are you sure ?", wxYES_NO|wxCENTRE|wxICON_QUESTION, this) == wxNO) { + return; + } + + long selection = _screenshotsList->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + + if(selection != -1) { + _manager.deleteScreenshot(selection); + } +} + +void EvtMainFrame::openScreenshotDirEvent(wxCommandEvent&) { + wxExecute("explorer.exe " + Utility::Directory::toNativeSeparators(_manager.screenshotDirectory())); +} + void EvtMainFrame::fileUpdateEvent(wxFileSystemWatcherEvent& event) { int event_type = event.GetChangeType(); wxString event_file = event.GetPath().GetFullName(); @@ -261,93 +322,13 @@ void EvtMainFrame::fileUpdateEvent(wxFileSystemWatcherEvent& event) { wxMilliSleep(50); if(event.GetPath().GetPath(wxPATH_GET_VOLUME, wxPATH_WIN) == Utility::Directory::toNativeSeparators(_manager.saveDirectory())) { - wxRegEx regex; - - switch (event_type) { - case wxFSW_EVENT_CREATE: - case wxFSW_EVENT_DELETE: - regex.Compile(wxString::Format("Unit([0-3][0-9])%s\\.sav", _manager.steamId()), wxRE_ADVANCED); - if(regex.Matches(event_file)) { - long slot; - - if(regex.GetMatch(event_file, 1).ToLong(&slot) && slot >= 0 && slot < 32) { - refreshHangar(slot); - } - } - break; - case wxFSW_EVENT_MODIFY: - if(_lastWatcherEventType == wxFSW_EVENT_RENAME) { - break; - } - if(event_file == _manager.profileSaveName()) { - getActiveSlot(); - } - else { - regex.Compile(wxString::Format("Unit([0-3][0-9])%s\\.sav", _manager.steamId()), wxRE_ADVANCED); - if(regex.Matches(event_file)) { - long slot; - - if(regex.GetMatch(event_file, 1).ToLong(&slot) && slot >= 0 && slot < 32) { - refreshHangar(slot); - } - } - } - break; - case wxFSW_EVENT_RENAME: - wxString new_name = event.GetNewPath().GetFullName(); - - long slot; - if(regex.Compile(wxString::Format("Unit([0-3][0-9])%s\\.sav\\.tmp", _manager.steamId()), wxRE_ADVANCED), regex.Matches(new_name)) { - if(regex.GetMatch(new_name, 1).ToLong(&slot) && slot >= 0 && slot < 32) { - refreshHangar(slot); - } - } - else if(regex.Compile(wxString::Format("Unit([0-3][0-9])%s\\.sav", _manager.steamId()), wxRE_ADVANCED), regex.Matches(new_name)) { - if(regex.GetMatch(new_name, 1).ToLong(&slot) && slot >= 0 && slot < 32) { - refreshHangar(slot); - if(regex.Matches(event_file)) { - if(regex.GetMatch(event_file, 1).ToLong(&slot) && slot >= 0 && slot < 32) { - refreshHangar(slot); - } - } - } - } - break; - } + unitFileEventHandler(event_type, event_file, event); } else if(event.GetPath().GetPath(wxPATH_GET_VOLUME, wxPATH_WIN) == Utility::Directory::toNativeSeparators(_manager.stagingAreaDirectory())) { - int index; - - switch(event_type) { - case wxFSW_EVENT_CREATE: - index = _manager.updateStagedMass(event_file.ToUTF8().data()); - if(index != -1) { - _stagingList->Insert(wxString::Format("%s (%s)", _manager.stagedMassName(index), event_file), index); - } - break; - case wxFSW_EVENT_DELETE: - index = _manager.removeStagedMass(event_file.ToUTF8().data()); - if(index != -1) { - _stagingList->Delete(index); - } - break; - case wxFSW_EVENT_MODIFY: - index = _manager.updateStagedMass(event_file.ToUTF8().data()); - if(index != -1) { - _stagingList->SetString(index, wxString::Format("%s (%s)", _manager.stagedMassName(index), event_file)); - } - break; - case wxFSW_EVENT_RENAME: - index = _manager.removeStagedMass(event_file.ToUTF8().data()); - if(index != -1) { - _stagingList->Delete(index); - } - index = _manager.updateStagedMass(event.GetNewPath().GetFullName().ToUTF8().data()); - if(index != -1) { - _stagingList->Insert(wxString::Format("%s (%s)", _manager.stagedMassName(index), event.GetNewPath().GetFullName()), index); - } - break; - } + stagingFileEventHandler(event_type, event_file, event); + } + else if(event.GetPath().GetPath(wxPATH_GET_VOLUME, wxPATH_WIN) == Utility::Directory::toNativeSeparators(_manager.screenshotDirectory())) { + screenshotFileEventHandler(event_type, event_file, event); } _lastWatcherEventType = event_type; @@ -359,17 +340,125 @@ void EvtMainFrame::gameCheckTimerEvent(wxTimerEvent&) { isGameRunning(); } +void EvtMainFrame::unitFileEventHandler(int event_type, const wxString& event_file, const wxFileSystemWatcherEvent& event) { + wxRegEx regex; + + switch (event_type) { + case wxFSW_EVENT_CREATE: + case wxFSW_EVENT_DELETE: + regex.Compile(wxString::Format("Unit([0-3][0-9])%s\\.sav", _manager.steamId()), wxRE_ADVANCED); + if(regex.Matches(event_file)) { + long slot; + + if(regex.GetMatch(event_file, 1).ToLong(&slot) && slot >= 0 && slot < 32) { + refreshHangar(slot); + } + } + break; + case wxFSW_EVENT_MODIFY: + if(_lastWatcherEventType == wxFSW_EVENT_RENAME) { + break; + } + if(event_file == _manager.profileSaveName()) { + getActiveSlot(); + } + else { + regex.Compile(wxString::Format("Unit([0-3][0-9])%s\\.sav", _manager.steamId()), wxRE_ADVANCED); + if(regex.Matches(event_file)) { + long slot; + + if(regex.GetMatch(event_file, 1).ToLong(&slot) && slot >= 0 && slot < 32) { + refreshHangar(slot); + } + } + } + break; + case wxFSW_EVENT_RENAME: + wxString new_name = event.GetNewPath().GetFullName(); + + long slot; + if(regex.Compile(wxString::Format("Unit([0-3][0-9])%s\\.sav\\.tmp", _manager.steamId()), wxRE_ADVANCED), regex.Matches(new_name)) { + if(regex.GetMatch(new_name, 1).ToLong(&slot) && slot >= 0 && slot < 32) { + refreshHangar(slot); + } + } + else if(regex.Compile(wxString::Format("Unit([0-3][0-9])%s\\.sav", _manager.steamId()), wxRE_ADVANCED), regex.Matches(new_name)) { + if(regex.GetMatch(new_name, 1).ToLong(&slot) && slot >= 0 && slot < 32) { + refreshHangar(slot); + if(regex.Matches(event_file)) { + if(regex.GetMatch(event_file, 1).ToLong(&slot) && slot >= 0 && slot < 32) { + refreshHangar(slot); + } + } + } + } + break; + } +} + +void EvtMainFrame::stagingFileEventHandler(int event_type, const wxString& event_file, const wxFileSystemWatcherEvent& event) { + int index; + + switch(event_type) { + case wxFSW_EVENT_CREATE: + index = _manager.updateStagedMass(event_file.ToUTF8().data()); + if(index != -1) { + _stagingList->Insert(wxString::Format("%s (%s)", _manager.stagedMassName(index), event_file), index); + } + break; + case wxFSW_EVENT_DELETE: + index = _manager.removeStagedMass(event_file.ToUTF8().data()); + if(index != -1) { + _stagingList->Delete(index); + } + break; + case wxFSW_EVENT_MODIFY: + index = _manager.updateStagedMass(event_file.ToUTF8().data()); + if(index != -1) { + _stagingList->SetString(index, wxString::Format("%s (%s)", _manager.stagedMassName(index), event_file)); + } + break; + case wxFSW_EVENT_RENAME: + index = _manager.removeStagedMass(event_file.ToUTF8().data()); + if(index != -1) { + _stagingList->Delete(index); + } + index = _manager.updateStagedMass(event.GetNewPath().GetFullName().ToUTF8().data()); + if(index != -1) { + _stagingList->Insert(wxString::Format("%s (%s)", _manager.stagedMassName(index), event.GetNewPath().GetFullName()), index); + } + break; + } +} + +void EvtMainFrame::screenshotFileEventHandler(int event_type, const wxString& event_file) { + int index = -1; + + switch(event_type) { + case wxFSW_EVENT_CREATE: + _manager.updateScreenshot(event_file.ToUTF8().data()); + updateScreenshotList(); + break; + case wxFSW_EVENT_DELETE: + index = _screenshotsList->FindItem(-1, event_file, true); + if(index != -1) { + _manager.removeScreenshot(index); + _screenshotsList->DeleteItem(index); + } + break; + } +} + void EvtMainFrame::initialiseListView() { for(long i = 0; i < 32; i++) { _installedListView->InsertItem(i, wxString::Format("%.2i", i + 1)); } - getActiveSlot(); - _installedListView->SetColumnWidth(0, wxLIST_AUTOSIZE_USEHEADER); _installedListView->SetColumnWidth(1, wxLIST_AUTOSIZE_USEHEADER); refreshListView(); + getActiveSlot(); } void EvtMainFrame::isGameRunning() { @@ -404,9 +493,11 @@ void EvtMainFrame::refreshListView() { void EvtMainFrame::getActiveSlot() { char slot = _manager.activeSlot(); - wxFont tmp_font = _installedListView->GetItemFont(slot); - tmp_font.SetWeight(wxFONTWEIGHT_NORMAL); - _installedListView->SetItemFont(slot, tmp_font); + if(slot != -1) { + wxFont tmp_font = _installedListView->GetItemFont(slot); + tmp_font.SetWeight(wxFONTWEIGHT_NORMAL); + _installedListView->SetItemFont(slot, tmp_font); + } slot = _manager.getActiveSlot(); @@ -427,6 +518,10 @@ void EvtMainFrame::updateCommandsState() { _deleteButton->Enable(selection != -1 && game_state != GameState::Running && hangar_state != HangarState::Empty); _renameButton->Enable(selection != -1 && game_state != GameState::Running && hangar_state != HangarState::Empty); _deleteStagedButton->Enable(staged_selection != -1); + + long screenshot_selection = _screenshotsList->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + _viewScreenshotButton->Enable(screenshot_selection != -1); + _deleteScreenshotButton->Enable(screenshot_selection != -1); } void EvtMainFrame::refreshHangar(int slot) { @@ -449,6 +544,52 @@ void EvtMainFrame::refreshHangar(int slot) { } } +void EvtMainFrame::updateScreenshotList() { + _screenshotsList->DeleteAllItems(); + _screenshotThumbs.RemoveAll(); + + int index = 0; + for(const Screenshot& s : _manager.screenshots()) { + _screenshotsList->InsertItem(index, + wxString::Format("%s\n%s", wxString::FromUTF8(s._filename.c_str()), s._creationDate.Format("%d/%m/%Y %H:%M:%S")), + _screenshotThumbs.Add(s._thumbnail)); + + ++index; + } +} + +void EvtMainFrame::viewScreenshot() { + long selection = _screenshotsList->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if(selection == -1) { + return; + } + + wxBitmap image(Utility::Directory::toNativeSeparators(Utility::Directory::join(_manager.screenshotDirectory(), _manager.screenshots().at(selection)._filename)), wxBITMAP_TYPE_PNG); + + wxDialog view_dialog; + view_dialog.Create(this, wxID_ANY, "Screenshot viewer", wxDefaultPosition, wxSize{1024, 576}, wxCAPTION|wxCLOSE_BOX|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSYSTEM_MENU); + + wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); + wxScrolledWindow* scroller = new wxScrolledWindow(&view_dialog, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL|wxHSCROLL); + scroller->SetScrollRate(5, 5); + + wxBoxSizer* scroller_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticBitmap* screenshot = new wxStaticBitmap(scroller, wxID_ANY, image); + scroller_sizer->Add(screenshot, 1, wxEXPAND, 5); + + scroller->SetSizer(scroller_sizer); + scroller->Layout(); + scroller_sizer->FitInside(scroller); + sizer->Add(scroller, 1, wxEXPAND, 5); + + view_dialog.SetSizer(sizer); + view_dialog.Layout(); + sizer->FitInside(&view_dialog); + view_dialog.Centre(); + + view_dialog.ShowModal(); +} + void EvtMainFrame::infoMessage(const wxString& message) { wxMessageBox(message, "Information", wxOK|wxCENTRE|wxICON_INFORMATION, this); } diff --git a/GUI/EvtMainFrame.h b/GUI/EvtMainFrame.h index 9bfb90e..90a2c5c 100644 --- a/GUI/EvtMainFrame.h +++ b/GUI/EvtMainFrame.h @@ -20,6 +20,7 @@ #include #include +#include #include "../MassManager/MassManager.h" @@ -33,6 +34,7 @@ class EvtMainFrame: public MainFrame { auto ready() -> bool; protected: + // M.A.S.S.-related events void importEvent(wxCommandEvent&); void exportEvent(wxCommandEvent&); void moveEvent(wxCommandEvent&); @@ -45,10 +47,27 @@ class EvtMainFrame: public MainFrame { void stagingButtonEvent(wxCommandEvent&); void installedSelectionEvent(wxListEvent&); void listColumnDragEvent(wxListEvent&); + + // Screenshot events + void screenshotListSelectionEvent(wxListEvent&); + void screenshotFilenameSortingEvent(wxCommandEvent&); + void screenshotCreationDateSortingEvent(wxCommandEvent&); + void screenshotAscendingSortingEvent(wxCommandEvent&); + void screenshotDescendingSortingEvent(wxCommandEvent&); + void viewScreenshotEvent(wxCommandEvent&); + void viewScreenshotEvent(wxListEvent&); + void deleteScreenshotEvent(wxCommandEvent&); + void openScreenshotDirEvent(wxCommandEvent&); + + // General events void fileUpdateEvent(wxFileSystemWatcherEvent& event); void gameCheckTimerEvent(wxTimerEvent&); private: + void unitFileEventHandler(int event_type, const wxString& event_file, const wxFileSystemWatcherEvent& event); + void stagingFileEventHandler(int event_type, const wxString& event_file, const wxFileSystemWatcherEvent& event); + void screenshotFileEventHandler(int event_type, const wxString& event_file); + void initialiseListView(); void isGameRunning(); void refreshListView(); @@ -56,6 +75,9 @@ class EvtMainFrame: public MainFrame { void updateCommandsState(); void refreshHangar(int slot); + void updateScreenshotList(); + void viewScreenshot(); + void infoMessage(const wxString& message); void warningMessage(const wxString& message); void errorMessage(const wxString& message); @@ -64,6 +86,8 @@ class EvtMainFrame: public MainFrame { wxFileSystemWatcher _watcher; int _lastWatcherEventType = 0; + + wxImageList _screenshotThumbs{160, 160, true, 0}; }; #endif // __EvtMainFrame__