Compare commits
58 commits
Author | SHA1 | Date | |
---|---|---|---|
4883b617fd | |||
e98a5e9d26 | |||
768bcd1e5f | |||
896c48290d | |||
34cba84362 | |||
3cb897ccda | |||
0ce8046728 | |||
13b2614af0 | |||
171fee333f | |||
1d7c08b3ca | |||
32c193a53b | |||
ae2a613879 | |||
a310669839 | |||
f532803d56 | |||
9ebd418ed2 | |||
3c8e82da96 | |||
640f378357 | |||
3c64f59a8c | |||
0ccc232afa | |||
5256b11a46 | |||
bb283b0603 | |||
7eceaf329e | |||
aa5d61ac04 | |||
a58ad3d330 | |||
76de8c0bee | |||
7cd1f9aa4e | |||
5c4a3e8d16 | |||
d56b2cc4c2 | |||
97eb69922f | |||
f3b14fbffe | |||
9925fc7f03 | |||
036475e4c6 | |||
5b23303a48 | |||
0b1ecc52f5 | |||
20c35c8d8e | |||
9c74f672dd | |||
0d386a70d8 | |||
e799f1be04 | |||
8a5d9c4231 | |||
cebae7d072 | |||
4c0f1b8ce5 | |||
932052ab0a | |||
0b846be139 | |||
3d04ac4a12 | |||
d38606b574 | |||
016b549d7a | |||
b2c5c6a69f | |||
eb08de1a30 | |||
685bc59540 | |||
4e1a74e03e | |||
a24422adcc | |||
e77b56383a | |||
a06ea2caa4 | |||
d7fa2abafb | |||
fdf72544fb | |||
854a7bbcca | |||
34d938548a | |||
9ddea11b6e |
35 changed files with 5821 additions and 2637 deletions
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 ) );
|
||||
|
||||
}
|
|
@ -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 < |