Compare commits

..

58 commits

Author SHA1 Message Date
4883b617fd Change project structure and update copyright years. 2021-05-20 22:46:59 +02:00
e98a5e9d26 Add the FindCorrade module to modules directory. 2021-05-14 19:51:07 +02:00
768bcd1e5f Update the CMakeLists. 2021-05-14 19:50:31 +02:00
896c48290d Update Corrade to latest version. 2021-05-14 19:39:34 +02:00
34cba84362 MainFrame: reduce proportion of the general info. 2021-05-13 22:49:01 +02:00
3cb897ccda EvtMainFrame: Add some extra safety, just in case. 2021-05-12 20:39:48 +02:00
0ce8046728 Bump version number. 2021-05-12 20:27:03 +02:00
13b2614af0 Add a way to edit credits. 2021-05-12 20:21:35 +02:00
171fee333f EvtMainFrame: fix a function signature. 2021-05-12 15:11:05 +02:00
1d7c08b3ca Add a viewer/editor for the research inventory. 2021-05-12 13:53:51 +02:00
32c193a53b MainFrame: change size constraints. 2021-05-11 19:29:25 +02:00
ae2a613879 Profile: move locators to their own header. 2021-05-11 19:28:26 +02:00
a310669839 Bump version number. 2021-05-11 14:54:42 +02:00
f532803d56 Add a way to change the story progression state. 2021-05-11 14:54:33 +02:00
9ebd418ed2 MainFrame: fix the rename event. 2021-05-11 14:53:41 +02:00
3c8e82da96 EvtMainFrame: make the PMC rename button safer. 2021-05-11 14:52:52 +02:00
640f378357 EvtMainFrame: remove an extra line. 2021-05-11 14:51:54 +02:00
3c64f59a8c Expose the company renaming feature. 2021-05-11 14:51:33 +02:00
0ccc232afa Remove the screenshot management feature.
I really wasn't satisfied with it, to be honest.
2021-05-10 21:20:19 +02:00
5256b11a46 Add support for the very first progress state. 2021-05-10 20:33:44 +02:00
bb283b0603 Bump version up. 2021-05-10 19:58:02 +02:00
7eceaf329e Fix values for StoryProgress and LastMissionId.
They aren't bad per se, they're just off.
2021-05-10 19:54:46 +02:00
aa5d61ac04 Bump version up. 2021-05-10 19:01:51 +02:00
a58ad3d330 Change the initial warning message. 2021-05-10 18:39:28 +02:00
76de8c0bee Finish mapping StoryProgress. 2021-05-10 18:11:25 +02:00
7cd1f9aa4e Update the about text. 2021-04-20 15:56:08 +02:00
5c4a3e8d16 Start mapping story progress. 2021-04-20 15:55:41 +02:00
d56b2cc4c2 Use a scope guard for more safety. 2021-04-20 15:55:06 +02:00
97eb69922f Move the last mission ID map to its own header. 2021-04-20 15:54:07 +02:00
f3b14fbffe MainFrame: improve readability and add challenges.
Also, hunting grounds are now known as "hunts".
2021-03-11 14:19:43 +01:00
9925fc7f03 MainFrame: fix layout. 2021-03-11 14:18:43 +01:00
036475e4c6 Update version information. 2021-03-05 15:03:01 +01:00
5b23303a48 MainFrame: add logic to unsafe mode checkbox. 2021-03-05 14:56:28 +01:00
0b1ecc52f5 MainFrame: update a button's {dis,en}abled logic. 2021-03-05 14:24:27 +01:00
20c35c8d8e MainFrame: upgrade the default profile logic. 2021-03-05 14:20:19 +01:00
9c74f672dd MainFrame: re-enable the warning on launch.
Also add an extra line about the pre-release stuff.
2021-03-05 14:20:09 +01:00
0d386a70d8 MainFrame: add unsafe checkbox.
It doesn't do anything yet, though.
2021-03-05 14:18:06 +01:00
e799f1be04 CMakeLists: fix a logic issue. 2020-10-05 12:53:04 +02:00
8a5d9c4231 Prepare for pre-release 1. 2020-10-05 11:05:52 +02:00
cebae7d072 Additional safety in fileUpdateEvent. 2020-10-05 10:36:23 +02:00
4c0f1b8ce5 Added an experimental way to rename the company. 2020-10-05 10:36:08 +02:00
932052ab0a Profile: forgot to mark two functions as const. 2020-10-05 08:41:23 +02:00
0b846be139 Prepare the 2.0.0 pre-release version. 2020-10-05 08:36:27 +02:00
3d04ac4a12 Added the last two available levels to the map. 2020-10-05 08:32:59 +02:00
d38606b574 Add two more values. 2020-10-05 00:55:08 +02:00
016b549d7a Profile: simplify the credits formula.
IntProperty is a 32-bit signed integer according to research.
2020-10-04 20:11:32 +02:00
b2c5c6a69f Update the profile stats when the file is modified. 2020-10-02 12:56:22 +02:00
eb08de1a30 MainFrame: rename a symbol. 2020-10-02 12:55:52 +02:00
685bc59540 MassManager: return empty_string by ref instead of a temp object. 2020-10-02 12:55:31 +02:00
4e1a74e03e MainFrame: make code a bit more readable. 2020-10-02 12:54:38 +02:00
a24422adcc MainFrame: increase sleep time in fileUpdateEvent().
This should make file access a tiny bit safer.
2020-10-02 12:53:55 +02:00
e77b56383a Made the strings more readable. 2020-09-30 22:49:42 +02:00
a06ea2caa4 Finish re{writing} the MASS manager. 2020-09-30 16:27:26 +02:00
d7fa2abafb Profile: reimplement the backup feature. 2020-09-30 16:26:34 +02:00
fdf72544fb Fixed an assert.
It didn't appear in release, but it could have bitten me in the ass at
some point.
2020-09-30 16:26:15 +02:00
854a7bbcca Add the ability to not use the Corrade submodule.
Also add a version check, just in case.
2020-09-21 13:48:22 +02:00
34d938548a Update Corrade to 2020.06. 2020-09-08 23:26:37 +02:00
9ddea11b6e Some early work on classes. 2020-09-01 16:14:43 +02:00
35 changed files with 5821 additions and 2637 deletions

View file

@ -1,5 +1,5 @@
# wxMASSManager
# Copyright (C) 2020 Guillaume Jacquemin
# Copyright (C) 2020-2021 Guillaume Jacquemin
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -18,68 +18,23 @@ cmake_minimum_required(VERSION 3.5)
project(wxMASSManager LANGUAGES CXX)
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/modules/" ${CMAKE_MODULE_PATH})
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(BUILD_STATIC ON CACHE BOOL "" FORCE)
set(WITH_INTERCONNECT OFF CACHE BOOL "" FORCE)
set(WITH_PLUGINMANAGER OFF CACHE BOOL "" FORCE)
set(WITH_TESTSUITE OFF CACHE BOOL "" FORCE)
add_subdirectory(corrade)
option(USE_CORRADE_SUBMODULE "Use Corrade from the Git submodule. If set to OFF, make sure you have Corrade 2020.06 or later installed to a path CMake can search in." ON)
find_package(Corrade REQUIRED Containers Utility)
if(USE_CORRADE_SUBMODULE)
set(BUILD_STATIC ON CACHE BOOL "" FORCE)
set(BUILD_STATIC_PIC ON CACHE BOOL "" FORCE)
set(BUILD_STATIC_UNIQUE_GLOBALS OFF CACHE BOOL "" FORCE)
include_directories(SYSTEM "C:/msys64/mingw64/lib/wx/include/msw-unicode-static-3.0")
include_directories(SYSTEM "C:/msys64/mingw64/include/wx-3.0")
set(WITH_INTERCONNECT OFF CACHE BOOL "" FORCE)
set(WITH_PLUGINMANAGER OFF CACHE BOOL "" FORCE)
set(WITH_TESTSUITE OFF CACHE BOOL "" FORCE)
add_subdirectory(corrade EXCLUDE_FROM_ALL)
endif()
set_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS ON)
add_executable(wxMASSManager WIN32
main.cpp
GUI/MainFrame.fbp
GUI/MainFrame.h
GUI/MainFrame.cpp
GUI/EvtMainFrame.h
GUI/EvtMainFrame.cpp
GUI/NameChangeDialog.fbp
GUI/NameChangeDialog.h
GUI/NameChangeDialog.cpp
GUI/EvtNameChangeDialog.h
GUI/EvtNameChangeDialog.cpp
MassManager/MassManager.h
MassManager/MassManager.cpp
resource.rc)
target_compile_options(wxMASSManager PRIVATE -D_FILE_OFFSET_BITS=64 -D__WXMSW__ -fpermissive)
target_link_options(wxMASSManager PRIVATE -static -static-libgcc -static-libstdc++ -pipe -Wl,--subsystem,windows -mwindows)
target_link_libraries(wxMASSManager PRIVATE
Corrade::Containers
Corrade::Utility
wx_mswu_adv-3.0
wx_mswu_core-3.0
wx_baseu-3.0
wxregexu-3.0
wxexpat-3.0
wxtiff-3.0
wxjpeg-3.0
wxpng-3.0
wxzlib-3.0
rpcrt4
oleaut32
ole32
uuid
lzma
jbig
winspool
winmm
shell32
comctl32
comdlg32
advapi32
wsock32
gdi32
oleacc
wtsapi32)
add_subdirectory(src)

View file

@ -1,624 +0,0 @@
// wxMASSManager
// Copyright (C) 2020 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <wx/filedlg.h>
#include <wx/msgdlg.h>
#include <wx/numdlg.h>
#include <wx/regex.h>
#include <wx/scrolwin.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Utility/Directory.h>
#include "EvtNameChangeDialog.h"
#include "EvtMainFrame.h"
using namespace Corrade;
EvtMainFrame::EvtMainFrame(wxWindow* parent): MainFrame(parent) {
SetIcon(wxIcon("MAINICON"));
warningMessage(wxString::FromUTF8("Before you start using this app, a few things you should know:\n\n"
"For this application to work properly, Steam Cloud syncing needs to be disabled for the game.\nTo disable it, right-click the game in your Steam library, click \"Properties\", go to the \"Updates\" tab, and uncheck \"Enable Steam Cloud synchronization for M.A.S.S. Builder\".\n\n"
"DISCLAIMER: The developer of this application (Guillaume Jacquemin) isn't associated with Vermillion Digital, and both parties cannot be held responsible for data loss or corruption this app might cause. PLEASE USE AT YOUR OWN RISK!\n\n"
"Last but not least, this application is released under the terms of the GNU General Public Licence version 3. Please see the COPYING file for more details."));
if(!_manager.ready()) {
errorMessage("There was an issue initialising the manager:\n\n" + _manager.lastError());
return;
}
initialiseListView();
isGameRunning();
_installedListView->Connect(wxEVT_LIST_ITEM_SELECTED, wxListEventHandler(EvtMainFrame::installedSelectionEvent), nullptr, this);
_installedListView->Connect(wxEVT_LIST_ITEM_DESELECTED, wxListEventHandler(EvtMainFrame::installedSelectionEvent), nullptr, this);
_installedListView->Connect(wxEVT_LIST_BEGIN_DRAG, wxListEventHandler(EvtMainFrame::listColumnDragEvent), nullptr, this);
_installedListView->Connect(wxEVT_LIST_COL_BEGIN_DRAG, wxListEventHandler(EvtMainFrame::listColumnDragEvent), nullptr, this);
_watcher.Connect(wxEVT_FSWATCHER, wxFileSystemWatcherEventHandler(EvtMainFrame::fileUpdateEvent), nullptr, this);
_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()));
if(_manager.hasDemoUnits()) {
int result = wxMessageBox("M.A.S.S.es from the demo version of the game were found.\n\n"
"Do you want to move them to the staging area ?\n"
"WARNING: M.A.S.S.es from the demo version will keep parts you haven't unlocked in the main game, so you might get an advantage if you haven't progressed to that point.",
"Question", wxCENTRE|wxYES_NO|wxICON_QUESTION, this);
if(result == wxYES) {
_manager.addDemoUnitsToStaging();
}
}
std::vector<std::string> v = _manager.initialiseStagingArea();
for(const std::string& s : v) {
_stagingList->Append(s);
}
_watcher.AddTree(wxFileName(Utility::Directory::toNativeSeparators(_manager.stagingAreaDirectory()), wxPATH_WIN),
wxFSW_EVENT_CREATE|wxFSW_EVENT_DELETE|wxFSW_EVENT_MODIFY|wxFSW_EVENT_RENAME, "*.sav");
_gameCheckTimer.Start(3000);
if(!_manager.findScreenshotDirectory()) {
warningMessage("Screenshot manager not ready:\n\n" + _manager.lastError());
_screenshotsPanel->Disable();
return;
}
_manager.loadScreenshots();
_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.
_screenshotsList->SetImageList(&_screenshotThumbs, wxIMAGE_LIST_NORMAL);
updateScreenshotList();
}
EvtMainFrame::~EvtMainFrame() {
_installedListView->Disconnect(wxEVT_LIST_ITEM_SELECTED, wxListEventHandler(EvtMainFrame::installedSelectionEvent), nullptr, this);
_installedListView->Disconnect(wxEVT_LIST_ITEM_DESELECTED, wxListEventHandler(EvtMainFrame::installedSelectionEvent), nullptr, this);
_installedListView->Disconnect(wxEVT_LIST_BEGIN_DRAG, wxListEventHandler(EvtMainFrame::listColumnDragEvent), nullptr, this);
_installedListView->Disconnect(wxEVT_LIST_COL_BEGIN_DRAG, wxListEventHandler(EvtMainFrame::listColumnDragEvent), nullptr, this);
_watcher.Disconnect(wxEVT_FSWATCHER, wxFileSystemWatcherEventHandler(EvtMainFrame::fileUpdateEvent), nullptr, this);
}
bool EvtMainFrame::ready() {
return _manager.ready();
}
void EvtMainFrame::importMassEvent(wxCommandEvent&) {
const static std::string error_prefix = "Importing failed:\n\n";
long selected_hangar = _installedListView->GetFirstSelected();
HangarState hangar_state = _manager.hangarState(selected_hangar);
int staged_selection = _stagingList->GetSelection();
int confirmation;
if(hangar_state == HangarState::Filled) {
confirmation = wxMessageBox(wxString::Format("Hangar %.2d is already occupied by the M.A.S.S. named \"%s\". Are you sure you want to import the M.A.S.S. named \"%s\" to this hangar ?",
selected_hangar + 1, *(_manager.massName(selected_hangar)), _manager.stagedMassName(staged_selection)),
"Question", wxYES_NO|wxCENTRE|wxICON_QUESTION, this);
}
else {
confirmation = wxMessageBox(wxString::Format("Are you sure you want to import the M.A.S.S. named \"%s\" to hangar %.2d ?", _manager.stagedMassName(staged_selection), selected_hangar + 1),
"Question", wxYES_NO|wxCENTRE|wxICON_QUESTION, this);
}
if(confirmation == wxNO) {
return;
}
switch(_manager.gameState()) {
case GameState::Unknown:
errorMessage(error_prefix + "For security reasons, importing is disabled if the game's status is unknown.");
break;
case GameState::NotRunning:
if(!_manager.importMass(staged_selection, selected_hangar)) {
errorMessage(error_prefix + _manager.lastError());
}
break;
case GameState::Running:
errorMessage(error_prefix + "Importing a M.A.S.S. is disabled while the game is running.");
break;
}
}
void EvtMainFrame::exportMassEvent(wxCommandEvent&) {
const static std::string error_prefix = "Export failed:\n\n";
long slot = _installedListView->GetFirstSelected();
if(!_manager.exportMass(slot)) {
errorMessage(error_prefix + _manager.lastError());
}
}
void EvtMainFrame::moveMassEvent(wxCommandEvent&) {
const static std::string error_prefix = "Move failed:\n\n";
long source_slot = _installedListView->GetFirstSelected();
long choice = wxGetNumberFromUser(wxString::Format("Which hangar do you want to move the M.A.S.S. named \"%s\" to ?\nNotes:\n"
"- If the destination hangar is the same as the source, nothing will happen.\n"
"- If the destination already contains a M.A.S.S., the two will be swapped.\n"
"- If the destination contains invalid data, it will be cleared first.",
*(_manager.massName(source_slot))),
"Slot", "Choose a slot", source_slot + 1, 1, 32, this);
if(choice == -1 || choice == source_slot) {
return;
}
switch(_manager.gameState()) {
case GameState::Unknown:
errorMessage(error_prefix + "For security reasons, moving a M.A.S.S. is disabled if the game's status is unknown.");
break;
case GameState::NotRunning:
if(!_manager.moveMass(source_slot, choice - 1)) {
errorMessage(error_prefix + _manager.lastError());
}
break;
case GameState::Running:
errorMessage(error_prefix + "Moving a M.A.S.S. is disabled while the game is running.");
break;
}
}
void EvtMainFrame::deleteMassEvent(wxCommandEvent&) {
const static std::string error_prefix = "Deletion failed:\n\n";
if(wxMessageBox(wxString::Format("Are you sure you want to delete the data in hangar %.2d ? This operation cannot be undone.", _installedListView->GetFirstSelected() + 1),
"Are you sure ?", wxYES_NO|wxCENTRE|wxICON_QUESTION, this) == wxNO) {
return;
}
switch(_manager.gameState()) {
case GameState::Unknown:
errorMessage(error_prefix + "For security reasons, deleting a M.A.S.S. is disabled if the game's status is unknown.");
break;
case GameState::NotRunning:
if(!_manager.deleteMass(_installedListView->GetFirstSelected())) {
errorMessage(error_prefix + _manager.lastError());
}
break;
case GameState::Running:
errorMessage(error_prefix + "Deleting a M.A.S.S. is disabled while the game is running.");
break;
}
}
void EvtMainFrame::renameMassEvent(wxCommandEvent&) {
const static std::string error_prefix = "Rename failed:\n\n";
EvtNameChangeDialog dialog{this};
dialog.setName(*(_manager.massName(_installedListView->GetFirstSelected())));
int result = dialog.ShowModal();
if(result == wxID_OK) {
switch(_manager.gameState()) {
case GameState::Unknown:
errorMessage(error_prefix + "For security reasons, renaming a M.A.S.S. is disabled if the game's status is unknown.");
break;
case GameState::NotRunning:
if(!_manager.renameMass(_installedListView->GetFirstSelected(), dialog.getName())) {
errorMessage(error_prefix + _manager.lastError());
}
break;
case GameState::Running:
errorMessage(error_prefix + "Renaming a M.A.S.S. is disabled while the game is running.");
break;
}
}
}
void EvtMainFrame::backupSavesEvent(wxCommandEvent&) {
const static std::string error_prefix = "Backup failed:\n\n";
wxString current_timestamp = wxDateTime::Now().Format("%Y-%m-%d_%H-%M-%S");
wxFileDialog save_dialog{this, "Choose output location", _manager.saveDirectory(),
wxString::Format("backup_%s_%s.zip", _manager.steamId(), current_timestamp), "Zip archive (*zip)|*zip",
wxFD_SAVE|wxFD_OVERWRITE_PROMPT};
if(save_dialog.ShowModal() == wxID_CANCEL) {
return;
}
if(!_manager.backupSaves(save_dialog.GetPath().ToStdString())) {
errorMessage(error_prefix + _manager.lastError());
}
}
void EvtMainFrame::openSaveDirEvent(wxCommandEvent&) {
wxExecute("explorer.exe " + Utility::Directory::toNativeSeparators(_manager.saveDirectory()));
}
void EvtMainFrame::stagingSelectionEvent(wxCommandEvent&) {
updateCommandsState();
}
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) {
_manager.deleteStagedMass(selection);
}
}
void EvtMainFrame::openStagingDirEvent(wxCommandEvent&) {
wxExecute("explorer.exe " + Utility::Directory::toNativeSeparators(_manager.stagingAreaDirectory()));
}
void EvtMainFrame::installedSelectionEvent(wxListEvent&) {
updateCommandsState();
}
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();
if(event_type == wxFSW_EVENT_MODIFY && _lastWatcherEventType == wxFSW_EVENT_RENAME) {
_lastWatcherEventType = event_type;
return;
}
wxMilliSleep(50);
if(event.GetPath().GetPath(wxPATH_GET_VOLUME, wxPATH_WIN) == Utility::Directory::toNativeSeparators(_manager.saveDirectory())) {
unitFileEventHandler(event_type, event_file, event);
}
else if(event.GetPath().GetPath(wxPATH_GET_VOLUME, wxPATH_WIN) == Utility::Directory::toNativeSeparators(_manager.stagingAreaDirectory())) {
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);
}
_lastWatcherEventType = event_type;
updateCommandsState();
}
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));
}
_installedListView->SetColumnWidth(0, wxLIST_AUTOSIZE_USEHEADER);
_installedListView->SetColumnWidth(1, wxLIST_AUTOSIZE_USEHEADER);
refreshListView();
getActiveSlot();
}
void EvtMainFrame::isGameRunning() {
GameState state = _manager.checkGameState();
switch(state) {
case GameState::Unknown:
_gameStatus->SetLabel("unknown");
_gameStatus->SetForegroundColour(wxColour("orange"));
break;
case GameState::NotRunning:
_gameStatus->SetLabel("not running");
_gameStatus->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_CAPTIONTEXT));
break;
case GameState::Running:
_gameStatus->SetLabel("running");
_gameStatus->SetForegroundColour(wxColour("red"));
break;
}
updateCommandsState();
}
void EvtMainFrame::refreshListView() {
for(int i = 0; i < 32; i++) {
refreshHangar(i);
}
updateCommandsState();
}
void EvtMainFrame::getActiveSlot() {
char slot = _manager.activeSlot();
if(slot != -1) {
wxFont tmp_font = _installedListView->GetItemFont(slot);
tmp_font.SetWeight(wxFONTWEIGHT_NORMAL);
_installedListView->SetItemFont(slot, tmp_font);
}
slot = _manager.getActiveSlot();
if(slot != -1) {
_installedListView->SetItemFont(slot, _installedListView->GetItemFont(slot).Bold());
}
}
void EvtMainFrame::updateCommandsState() {
long selection = _installedListView->GetFirstSelected();
int staged_selection = _stagingList->GetSelection();
GameState game_state = _manager.gameState();
HangarState hangar_state = _manager.hangarState(selection);
_importButton->Enable(selection != -1 && staged_selection != -1 && game_state != GameState::Running);
_exportButton->Enable(selection != -1);
_moveButton->Enable(selection != -1 && game_state != GameState::Running && hangar_state != HangarState::Empty && hangar_state != HangarState::Invalid);
_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) {
if(slot < 0 && slot >= 32) {
return;
}
_manager.refreshHangar(slot);
switch(_manager.hangarState(slot)) {
case HangarState::Empty:
_installedListView->SetItem(slot, 1, "<Empty>");
break;
case HangarState::Invalid:
_installedListView->SetItem(slot, 1, "<Invalid>");
break;
case HangarState::Filled:
_installedListView->SetItem(slot, 1, *(_manager.massName(slot)));
break;
}
}
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);
}
void EvtMainFrame::warningMessage(const wxString& message) {
wxMessageBox(message, "Warning", wxOK|wxCENTRE|wxICON_WARNING, this);
}
void EvtMainFrame::errorMessage(const wxString& message) {
wxMessageBox(message, "Error", wxOK|wxCENTRE|wxICON_ERROR, this);
}

View file

@ -1,259 +0,0 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Oct 26 2018)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "MainFrame.h"
///////////////////////////////////////////////////////////////////////////
MainFrame::MainFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxSize( -1,600 ), wxDefaultSize );
wxBoxSizer* bSizerMain;
bSizerMain = new wxBoxSizer( wxVERTICAL );
_mainPanel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizerMainPanel;
bSizerMainPanel = new wxBoxSizer( wxVERTICAL );
_managerNotebook = new wxNotebook( _mainPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
_massPanel = new wxPanel( _managerNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizerMassPanel;
bSizerMassPanel = new wxBoxSizer( wxHORIZONTAL );
wxStaticBoxSizer* sbSizerInstalled;
sbSizerInstalled = new wxStaticBoxSizer( new wxStaticBox( _massPanel, wxID_ANY, wxT("Installed M.A.S.S.es") ), wxVERTICAL );
_installedListView = new wxListView(_massPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_HRULES);
_installedListView->AppendColumn("Hangar", wxLIST_FORMAT_LEFT);
_installedListView->AppendColumn("M.A.S.S. name", wxLIST_FORMAT_LEFT);
sbSizerInstalled->Add( _installedListView, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
wxStaticBoxSizer* sbSizerButtons;
sbSizerButtons = new wxStaticBoxSizer( new wxStaticBox( sbSizerInstalled->GetStaticBox(), wxID_ANY, wxT("Hangar actions") ), wxHORIZONTAL );
_moveButton = new wxButton( sbSizerButtons->GetStaticBox(), wxID_ANY, wxT("Move"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerButtons->Add( _moveButton, 1, wxALL|wxEXPAND, 5 );
_deleteButton = new wxButton( sbSizerButtons->GetStaticBox(), wxID_ANY, wxT("Delete"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerButtons->Add( _deleteButton, 1, wxALL|wxEXPAND, 5 );
_renameButton = new wxButton( sbSizerButtons->GetStaticBox(), wxID_ANY, wxT("Rename"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerButtons->Add( _renameButton, 1, wxALL|wxEXPAND, 5 );
sbSizerInstalled->Add( sbSizerButtons, 0, wxEXPAND, 5 );
wxBoxSizer* bSizerSecondRow;
bSizerSecondRow = new wxBoxSizer( wxHORIZONTAL );
_zipButton = new wxButton( sbSizerInstalled->GetStaticBox(), wxID_ANY, wxT("Backup save files"), wxDefaultPosition, wxDefaultSize, 0 );
bSizerSecondRow->Add( _zipButton, 2, wxALL|wxEXPAND, 5 );
_openSaveDirButton = new wxButton( sbSizerInstalled->GetStaticBox(), wxID_ANY, wxT("Open save directory"), wxDefaultPosition, wxDefaultSize, 0 );
bSizerSecondRow->Add( _openSaveDirButton, 2, wxEXPAND|wxALL, 5 );
sbSizerInstalled->Add( bSizerSecondRow, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
bSizerMassPanel->Add( sbSizerInstalled, 1, wxEXPAND|wxALL, 5 );
wxBoxSizer* bSizerImportExport;
bSizerImportExport = new wxBoxSizer( wxVERTICAL );
_importButton = new wxButton( _massPanel, wxID_ANY, wxT("Import"), wxDefaultPosition, wxDefaultSize, 0 );
_importButton->SetBitmap( wxArtProvider::GetBitmap( wxART_GO_BACK, wxART_BUTTON ) );
bSizerImportExport->Add( _importButton, 1, wxALL|wxEXPAND, 5 );
_exportButton = new wxButton( _massPanel, wxID_ANY, wxT("Export"), wxDefaultPosition, wxDefaultSize, 0 );
_exportButton->SetBitmap( wxArtProvider::GetBitmap( wxART_GO_FORWARD, wxART_BUTTON ) );
_exportButton->SetBitmapPosition( wxRIGHT );
bSizerImportExport->Add( _exportButton, 0, wxALL|wxEXPAND, 5 );
bSizerMassPanel->Add( bSizerImportExport, 0, wxALIGN_CENTER_VERTICAL, 5 );
wxStaticBoxSizer* sbSizerStagingArea;
sbSizerStagingArea = new wxStaticBoxSizer( new wxStaticBox( _massPanel, wxID_ANY, wxT("Staging area") ), wxVERTICAL );
_stagingList = new wxListBox( sbSizerStagingArea->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_NEEDED_SB|wxLB_SINGLE );
sbSizerStagingArea->Add( _stagingList, 1, wxALL|wxEXPAND, 5 );
_deleteStagedButton = new wxButton( sbSizerStagingArea->GetStaticBox(), wxID_ANY, wxT("Delete staged M.A.S.S."), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerStagingArea->Add( _deleteStagedButton, 0, wxALL|wxEXPAND, 5 );
_stagingAreaButton = new wxButton( sbSizerStagingArea->GetStaticBox(), wxID_ANY, wxT("Open staging area directory"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerStagingArea->Add( _stagingAreaButton, 0, wxALL|wxEXPAND, 5 );
bSizerMassPanel->Add( sbSizerStagingArea, 1, wxEXPAND|wxALL, 5 );
_massPanel->SetSizer( bSizerMassPanel );
_massPanel->Layout();
bSizerMassPanel->Fit( _massPanel );
_managerNotebook->AddPage( _massPanel, wxT("M.A.S.S.es"), false );
_screenshotsPanel = new wxPanel( _managerNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizerScreenshotsPanel;
bSizerScreenshotsPanel = new wxBoxSizer( wxHORIZONTAL );
_screenshotsList = new wxListCtrl( _screenshotsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_ALIGN_TOP|wxLC_AUTOARRANGE|wxLC_ICON|wxLC_SINGLE_SEL );
bSizerScreenshotsPanel->Add( _screenshotsList, 1, wxALL|wxEXPAND, 5 );
wxBoxSizer* bSizerScreenshotCommands;
bSizerScreenshotCommands = new wxBoxSizer( wxVERTICAL );
wxStaticBoxSizer* sbSizerSorting;
sbSizerSorting = new wxStaticBoxSizer( new wxStaticBox( _screenshotsPanel, wxID_ANY, wxT("Sorting") ), wxVERTICAL );
wxBoxSizer* bSizerSortType;
bSizerSortType = new wxBoxSizer( wxHORIZONTAL );
_nameRadio = new wxRadioButton( sbSizerSorting->GetStaticBox(), wxID_ANY, wxT("Filename"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
_nameRadio->SetValue( true );
bSizerSortType->Add( _nameRadio, 1, wxALL, 5 );
_creationDateRadio = new wxRadioButton( sbSizerSorting->GetStaticBox(), wxID_ANY, wxT("Creation date"), wxDefaultPosition, wxDefaultSize, 0 );
bSizerSortType->Add( _creationDateRadio, 1, wxALL, 5 );
sbSizerSorting->Add( bSizerSortType, 1, wxEXPAND, 5 );
wxBoxSizer* bSizerSortOrder;
bSizerSortOrder = new wxBoxSizer( wxHORIZONTAL );
_ascendingRadio = new wxRadioButton( sbSizerSorting->GetStaticBox(), wxID_ANY, wxT("Ascending"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
_ascendingRadio->SetValue( true );
bSizerSortOrder->Add( _ascendingRadio, 1, wxALL, 5 );
_descendingRadio = new wxRadioButton( sbSizerSorting->GetStaticBox(), wxID_ANY, wxT("Descending"), wxDefaultPosition, wxDefaultSize, 0 );
bSizerSortOrder->Add( _descendingRadio, 1, wxALL, 5 );
sbSizerSorting->Add( bSizerSortOrder, 1, wxEXPAND, 5 );
bSizerScreenshotCommands->Add( sbSizerSorting, 0, wxEXPAND|wxALL, 5 );
_viewScreenshotButton = new wxButton( _screenshotsPanel, wxID_ANY, wxT("View"), wxDefaultPosition, wxDefaultSize, 0 );
bSizerScreenshotCommands->Add( _viewScreenshotButton, 0, wxALL|wxEXPAND, 5 );
_deleteScreenshotButton = new wxButton( _screenshotsPanel, wxID_ANY, wxT("Delete"), wxDefaultPosition, wxDefaultSize, 0 );
bSizerScreenshotCommands->Add( _deleteScreenshotButton, 0, wxALL|wxEXPAND, 5 );
_screenshotDirButton = new wxButton( _screenshotsPanel, wxID_ANY, wxT("Open directory"), wxDefaultPosition, wxDefaultSize, 0 );
bSizerScreenshotCommands->Add( _screenshotDirButton, 0, wxALL|wxEXPAND, 5 );
bSizerScreenshotsPanel->Add( bSizerScreenshotCommands, 0, wxEXPAND, 5 );
_screenshotsPanel->SetSizer( bSizerScreenshotsPanel );
_screenshotsPanel->Layout();
bSizerScreenshotsPanel->Fit( _screenshotsPanel );
_managerNotebook->AddPage( _screenshotsPanel, wxT("Photo mode shots"), false );
bSizerMainPanel->Add( _managerNotebook, 1, wxEXPAND, 5 );
_riskLabel = new wxStaticText( _mainPanel, wxID_ANY, wxT("USE THIS TOOL AT YOUR OWN RISK!"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL );
_riskLabel->Wrap( -1 );
_riskLabel->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
_riskLabel->SetForegroundColour( wxColour( 255, 0, 0 ) );
bSizerMainPanel->Add( _riskLabel, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP|wxRIGHT|wxLEFT, 5 );
wxBoxSizer* bSizerGameStatus;
bSizerGameStatus = new wxBoxSizer( wxHORIZONTAL );
_gameStatusLabel = new wxStaticText( _mainPanel, wxID_ANY, wxT("Game status:"), wxDefaultPosition, wxDefaultSize, 0 );
_gameStatusLabel->Wrap( -1 );
bSizerGameStatus->Add( _gameStatusLabel, 1, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxEXPAND|wxTOP|wxBOTTOM|wxLEFT, 5 );
_gameStatus = new wxStaticText( _mainPanel, wxID_ANY, wxT("not running"), wxDefaultPosition, wxDefaultSize, 0 );
_gameStatus->Wrap( -1 );
_gameStatus->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
_gameStatus->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_CAPTIONTEXT ) );
bSizerGameStatus->Add( _gameStatus, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
bSizerMainPanel->Add( bSizerGameStatus, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
_aboutText = new wxStaticText( _mainPanel, wxID_ANY, wxT("This version of the application was tested on M.A.S.S. Builder early access version 0.4.5.\nIt may or may not work with other versions of the game.\nMade for the M.A.S.S. Builder community by Guillaume Jacquemin."), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL );
_aboutText->Wrap( -1 );
bSizerMainPanel->Add( _aboutText, 0, wxEXPAND|wxRIGHT|wxLEFT|wxALIGN_CENTER_HORIZONTAL, 5 );
_githubLink = new wxHyperlinkCtrl( _mainPanel, wxID_ANY, wxT("https://github.com/williamjcm/wxMASSManager"), wxT("https://github.com/williamjcm/wxMASSManager"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
bSizerMainPanel->Add( _githubLink, 0, wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
_mainPanel->SetSizer( bSizerMainPanel );
_mainPanel->Layout();
bSizerMainPanel->Fit( _mainPanel );
bSizerMain->Add( _mainPanel, 1, wxEXPAND, 5 );
this->SetSizer( bSizerMain );
this->Layout();
bSizerMain->Fit( this );
_gameCheckTimer.SetOwner( this, wxID_ANY );
this->Centre( wxBOTH );
// Connect Events
_moveButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::moveMassEvent ), NULL, this );
_deleteButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::deleteMassEvent ), NULL, this );
_renameButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::renameMassEvent ), NULL, this );
_zipButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::backupSavesEvent ), NULL, this );
_openSaveDirButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::openSaveDirEvent ), NULL, this );
_importButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::importMassEvent ), NULL, this );
_exportButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::exportMassEvent ), NULL, this );
_stagingList->Connect( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( MainFrame::stagingSelectionEvent ), NULL, this );
_deleteStagedButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::deleteStagedEvent ), NULL, this );
_stagingAreaButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::openStagingDirEvent ), NULL, this );
_screenshotsList->Connect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( MainFrame::viewScreenshotEvent ), NULL, this );
_screenshotsList->Connect( wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler( MainFrame::screenshotListSelectionEvent ), NULL, this );
_screenshotsList->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( MainFrame::screenshotListSelectionEvent ), NULL, this );
_nameRadio->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( MainFrame::screenshotFilenameSortingEvent ), NULL, this );
_creationDateRadio->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( MainFrame::screenshotCreationDateSortingEvent ), NULL, this );
_ascendingRadio->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( MainFrame::screenshotAscendingSortingEvent ), NULL, this );
_descendingRadio->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( MainFrame::screenshotDescendingSortingEvent ), NULL, this );
_viewScreenshotButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::viewScreenshotEvent ), NULL, this );
_deleteScreenshotButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::deleteScreenshotEvent ), NULL, this );
_screenshotDirButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::openScreenshotDirEvent ), NULL, this );
this->Connect( wxID_ANY, wxEVT_TIMER, wxTimerEventHandler( MainFrame::gameCheckTimerEvent ) );
}
MainFrame::~MainFrame()
{
// Disconnect Events
_moveButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::moveMassEvent ), NULL, this );
_deleteButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::deleteMassEvent ), NULL, this );
_renameButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::renameMassEvent ), NULL, this );
_zipButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::backupSavesEvent ), NULL, this );
_openSaveDirButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::openSaveDirEvent ), NULL, this );
_importButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::importMassEvent ), NULL, this );
_exportButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::exportMassEvent ), NULL, this );
_stagingList->Disconnect( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( MainFrame::stagingSelectionEvent ), NULL, this );
_deleteStagedButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::deleteStagedEvent ), NULL, this );
_stagingAreaButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::openStagingDirEvent ), NULL, this );
_screenshotsList->Disconnect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( MainFrame::viewScreenshotEvent ), NULL, this );
_screenshotsList->Disconnect( wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler( MainFrame::screenshotListSelectionEvent ), NULL, this );
_screenshotsList->Disconnect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( MainFrame::screenshotListSelectionEvent ), NULL, this );
_nameRadio->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( MainFrame::screenshotFilenameSortingEvent ), NULL, this );
_creationDateRadio->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( MainFrame::screenshotCreationDateSortingEvent ), NULL, this );
_ascendingRadio->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( MainFrame::screenshotAscendingSortingEvent ), NULL, this );
_descendingRadio->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( MainFrame::screenshotDescendingSortingEvent ), NULL, this );
_viewScreenshotButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::viewScreenshotEvent ), NULL, this );
_deleteScreenshotButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::deleteScreenshotEvent ), NULL, this );
_screenshotDirButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::openScreenshotDirEvent ), NULL, this );
this->Disconnect( wxID_ANY, wxEVT_TIMER, wxTimerEventHandler( MainFrame::gameCheckTimerEvent ) );
}

View file

@ -1,743 +0,0 @@
// wxMASSManager
// Copyright (C) 2020 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <cstring>
#include <algorithm>
#include <wx/filename.h>
#include <wx/regex.h>
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
#include <shlobj.h>
#include <wtsapi32.h>
#include <Corrade/Containers/Array.h>
#include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/FormatStl.h>
#include <Corrade/Utility/String.h>
#include <Corrade/Utility/Unicode.h>
#include "MassManager.h"
constexpr unsigned char mass_name_locator[] = { 'N', 'a', 'm', 'e', '_', '4', '5', '_', 'A', '0', '3', '7', 'C', '5', 'D', '5', '4', 'E', '5', '3', '4', '5', '6', '4', '0', '7', 'B', 'D', 'F', '0', '9', '1', '3', '4', '4', '5', '2', '9', 'B', 'B', '\0', 0x0C, '\0', '\0', '\0', 'S', 't', 'r', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'y', '\0' };
constexpr unsigned char steamid_locator[] = { 'A', 'c', 'c', 'o', 'u', 'n', 't', '\0', 0x0C, '\0', '\0', '\0', 'S', 't', 'r', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'y', '\0' };
constexpr unsigned char active_slot_locator[] = { 'A', 'c', 't', 'i', 'v', 'e', 'F', 'r', 'a', 'm', 'e', 'S', 'l', 'o', 't', '\0', 0x0C, '\0', '\0', '\0', 'I', 'n', 't', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'y', '\0' };
constexpr unsigned char credits_locator[] = { 'C', 'r', 'e', 'd', 'i', 't', '\0', 0x0C, '\0', '\0', '\0', 'I', 'n', 't', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'y', '\0' };
MassManager::MassManager() {
_ready = findSaveDirectory() && findSteamId();
if(!_ready) {
return;
}
std::string executable_location = Utility::Directory::path(Utility::Directory::executableLocation());
_stagingAreaDirectory = Utility::Directory::join(executable_location, "staging");
_profileSaveName = Utility::formatString("Profile{}.sav", _steamId);
for(int i = 0; i < 32; ++i) {
_hangars[i]._filename = Utility::formatString("Unit{:.2d}{}.sav", i, _steamId);
refreshHangar(i);
}
}
auto MassManager::ready() -> bool {
return _ready;
}
auto MassManager::lastError() -> std::string const& {
return _lastError;
}
auto MassManager::hasDemoUnits() -> bool {
using Utility::Directory::Flag;
std::vector<std::string> list = Utility::Directory::list(_saveDirectory, Flag::SkipSpecial|Flag::SkipDirectories|Flag::SkipDotAndDotDot);
for(const std::string& file : list) {
if(Utility::String::beginsWith(file, "DemoUnit") && Utility::String::endsWith(file, ".sav")) {
return true;
}
}
return false;
}
void MassManager::addDemoUnitsToStaging() {
using Utility::Directory::Flag;
std::vector<std::string> list = Utility::Directory::list(_saveDirectory, Flag::SkipSpecial|Flag::SkipDirectories|Flag::SkipDotAndDotDot);
auto predicate = [](const std::string& name)->bool{
return !(Utility::String::endsWith(name, ".sav") && Utility::String::beginsWith(name, "DemoUnit"));
};
list.erase(std::remove_if(list.begin(), list.end(), predicate), list.end());
for(const std::string& file : list) {
Utility::Directory::move(Utility::Directory::join(_saveDirectory, file),
Utility::Directory::join(_stagingAreaDirectory, file));
}
}
auto MassManager::saveDirectory() -> std::string const& {
return _saveDirectory;
}
auto MassManager::stagingAreaDirectory() -> std::string const& {
return _stagingAreaDirectory;
}
auto MassManager::screenshotDirectory() -> std::string const& {
return _screenshotDirectory;
}
auto MassManager::steamId() -> std::string const& {
return _steamId;
}
auto MassManager::profileSaveName() -> std::string const& {
return _profileSaveName;
}
auto MassManager::checkGameState() -> GameState {
WTS_PROCESS_INFOW* process_infos = nullptr;
unsigned long process_count = 0;
if(WTSEnumerateProcessesW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &process_infos, &process_count)) {
for(unsigned long i = 0; i <