Compare commits
2 commits
Author | SHA1 | Date | |
---|---|---|---|
Rafael | 20de3627d5 | ||
13b6d614fc |
33
.ci/app.rc
Normal file
33
.ci/app.rc
Normal file
|
@ -0,0 +1,33 @@
|
|||
IDI_ICON1 ICON DISCARDABLE "5sync.ico"
|
||||
#define RT_MANIFEST 24
|
||||
#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
|
||||
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "gta5view.exe.manifest"
|
||||
#include <windows.h>
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION MAJOR_VER, MINOR_VER, PATCH_VER, INT_BUILD_VER
|
||||
PRODUCTVERSION MAJOR_VER, MINOR_VER, PATCH_VER, INT_BUILD_VER
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x0809, 1200
|
||||
END
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Syping"
|
||||
VALUE "FileDescription", "gta5view"
|
||||
VALUE "FileVersion", "MAJOR_VER.MINOR_VER.PATCH_VERSTR_BUILD_VER"
|
||||
VALUE "InternalName", "gta5view"
|
||||
VALUE "LegalCopyright", "Copyright © 2016-2023 Syping"
|
||||
VALUE "OriginalFilename", "gta5view.exe"
|
||||
VALUE "ProductName", "gta5view"
|
||||
VALUE "ProductVersion", "MAJOR_VER.MINOR_VER.PATCH_VERSTR_BUILD_VER"
|
||||
END
|
||||
END
|
||||
END
|
72
.ci/ci.sh
Executable file
72
.ci/ci.sh
Executable file
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
if [ $(git name-rev --tags --name-only $(git rev-parse HEAD)) == "undefined" ]; then
|
||||
export APPLICATION_VERSION=$(lua -e 'for line in io.lines("config.h") do local m = string.match(line, "#define GTA5SYNC_APPVER \"(.+)\"$"); if m then print(m); os.exit(0) end end')
|
||||
else
|
||||
export APPLICATION_VERSION=$(git name-rev --tags --name-only $(git rev-parse HEAD))
|
||||
fi
|
||||
export PACKAGE_VERSION=$(grep -oE '^[^\-]*' <<< $APPLICATION_VERSION)
|
||||
export PACKAGE_BUILD=$(grep -oP '\-\K.+' <<< $APPLICATION_VERSION)
|
||||
export EXECUTABLE_VERSION=${PACKAGE_VERSION}${PACKAGE_BUILD}${EXECUTABLE_TAG}
|
||||
|
||||
export APPLICATION_MAJOR_VERSION=$(cut -d. -f1 <<< $APPLICATION_VERSION)
|
||||
export APPLICATION_MINOR_VERSION=$(cut -d. -f2 <<< $APPLICATION_VERSION)
|
||||
export APPLICATION_PATCH_VERSION=$(cut -d. -f3 <<< $APPLICATION_VERSION)
|
||||
|
||||
if [ "${PACKAGE_BUILD}" == "" ]; then
|
||||
export PACKAGE_BUILD=1
|
||||
else
|
||||
export APPLICATION_BUILD_INT_VERSION=$(grep -oE '[1-9]*$' <<< $PACKAGE_BUILD)
|
||||
export APPLICATION_BUILD_STR_VERSION=-${PACKAGE_BUILD}
|
||||
fi
|
||||
|
||||
cat ".ci/app.rc" | sed \
|
||||
-e "s/MAJOR_VER/$APPLICATION_MAJOR_VERSION/g" \
|
||||
-e "s/MINOR_VER/$APPLICATION_MINOR_VERSION/g" \
|
||||
-e "s/PATCH_VER/$APPLICATION_PATCH_VERSION/g" \
|
||||
-e "s/INT_BUILD_VER/0/g" \
|
||||
-e "s/STR_BUILD_VER/$APPLICATION_BUILD_STR_VERSION/g" \
|
||||
-e "s/STR_BUILD_VER/$APPLICATION_BUILD_STR_VERSION/g" \
|
||||
> "res/app.rc"
|
||||
|
||||
if [ "${BUILD_TYPE}" == "ALPHA" ]; then
|
||||
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Alpha"
|
||||
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Alpha\\\\\\\""
|
||||
elif [ "${BUILD_TYPE}" == "Alpha" ]; then
|
||||
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Alpha"
|
||||
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Alpha\\\\\\\""
|
||||
elif [ "${BUILD_TYPE}" == "BETA" ]; then
|
||||
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Beta"
|
||||
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Beta\\\\\\\""
|
||||
elif [ "${BUILD_TYPE}" == "Beta" ]; then
|
||||
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Beta"
|
||||
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Beta\\\\\\\""
|
||||
elif [ "${BUILD_TYPE}" == "DEV" ]; then
|
||||
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Developer"
|
||||
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Developer\\\\\\\""
|
||||
elif [ "${BUILD_TYPE}" == "Development" ]; then
|
||||
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Developer"
|
||||
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Developer\\\\\\\""
|
||||
elif [ "${BUILD_TYPE}" == "DAILY" ]; then
|
||||
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Daily Build"
|
||||
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Daily Build\\\\\\\""
|
||||
elif [ "${BUILD_TYPE}" == "Daily" ]; then
|
||||
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Daily Build"
|
||||
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Daily Build\\\\\\\""
|
||||
elif [ "${BUILD_TYPE}" == "RC" ]; then
|
||||
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Release Candidate"
|
||||
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Release Candidate\\\\\\\""
|
||||
elif [ "${BUILD_TYPE}" == "Release Candidate" ]; then
|
||||
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Release Candidate"
|
||||
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Release Candidate\\\\\\\""
|
||||
elif [ "${BUILD_TYPE}" == "REL" ]; then
|
||||
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Release"
|
||||
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Release\\\\\\\""
|
||||
elif [ "${BUILD_TYPE}" == "Release" ]; then
|
||||
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Release"
|
||||
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Release\\\\\\\""
|
||||
fi
|
||||
|
||||
export PROJECT_DIR=$(pwd)
|
||||
|
||||
.ci/${BUILD_SCRIPT}
|
38
.ci/debian_build.sh
Executable file
38
.ci/debian_build.sh
Executable file
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Creating folders
|
||||
cd ${PROJECT_DIR} && \
|
||||
echo "gta5view build version is ${APPLICATION_VERSION}" && \
|
||||
mkdir -p build && \
|
||||
mkdir -p assets && \
|
||||
chmod -x res/gta5sync_*.qm res/*.desktop res/*gta5view*.png && \
|
||||
cd build && \
|
||||
mkdir -p qt5 && \
|
||||
cd qt5 && \
|
||||
echo "Grand Theft Auto V Snapmatic and Savegame viewer/editor" > ./description-pak && \
|
||||
cd .. && \
|
||||
|
||||
# Set compiler
|
||||
export CC=clang && \
|
||||
export CXX=clang++ && \
|
||||
|
||||
# Prepare checkinstall step
|
||||
mkdir -p /usr/share/gta5view && \
|
||||
|
||||
# Starting build
|
||||
cd qt5 && \
|
||||
cmake \
|
||||
"-DCMAKE_INSTALL_PREFIX=/usr" \
|
||||
"${CMAKE_BUILD_TYPE}" \
|
||||
"-DFORCE_QT_VERSION=5" \
|
||||
"-DGTA5VIEW_BUILDCODE=${PACKAGE_CODE}" \
|
||||
"-DGTA5VIEW_APPVER=${APPLICATION_VERSION}" \
|
||||
"-DGTA5VIEW_COMMIT=${APPLICATION_COMMIT}" \
|
||||
"-DWITH_DONATE=ON" \
|
||||
"-DWITH_TELEMETRY=ON" \
|
||||
"-DDONATE_ADDRESSES=$(cat ${PROJECT_DIR}/.ci/donate.txt)" \
|
||||
"-DTELEMETRY_WEBURL=https://dev.syping.de/gta5view-userstats/" \
|
||||
"-DQCONF_BUILD=ON" \
|
||||
../../ && \
|
||||
make -j 4 && \
|
||||
checkinstall -D --default --nodoc --install=no --pkgname=gta5view --pkgversion=${PACKAGE_VERSION} --pkgrelease=${PACKAGE_BUILD} --pkggroup=utility --maintainer="Syping \<dpkg@syping.de\>" --requires=libqt5core5a,libqt5gui5,libqt5network5,libqt5svg5,libqt5widgets5,qttranslations5-l10n --conflicts=gta5view-qt4,gta5view-qt5 --replaces=gta5view-qt4,gta5view-qt5 --pakdir=${PROJECT_DIR}/assets
|
8
.ci/debian_ci.sh
Executable file
8
.ci/debian_ci.sh
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Install packages
|
||||
.ci/debian_install.sh && \
|
||||
|
||||
# Build gta5view
|
||||
.ci/debian_build.sh && \
|
||||
cd ${PROJECT_DIR}
|
15
.ci/debian_docker.sh
Executable file
15
.ci/debian_docker.sh
Executable file
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
if [ "${DOCKER_USER}" != "" ]; then
|
||||
DOCKER_IMAGE=${DOCKER_USER}/debian:${DEBIAN_VERSION}
|
||||
else
|
||||
DOCKER_IMAGE=debian:${DEBIAN_VERSION}
|
||||
fi
|
||||
PROJECT_DIR_DOCKER=/gta5view
|
||||
|
||||
cd ${PROJECT_DIR} && \
|
||||
docker pull ${DOCKER_IMAGE} && \
|
||||
docker run --rm \
|
||||
-v "${PROJECT_DIR}:${PROJECT_DIR_DOCKER}" \
|
||||
${DOCKER_IMAGE} \
|
||||
/bin/bash -c "export PROJECT_DIR=${PROJECT_DIR_DOCKER} && export QT_SELECT=${QT_SELECT} && export APPLICATION_VERSION=${APPLICATION_VERSION} && export APPLICATION_COMMIT=${APPLICATION_COMMIT} && export BUILD_TYPE=${BUILD_TYPE} && export APT_INSTALL=${APT_INSTALL} && export QMAKE_FLAGS_QT4=${QMAKE_FLAGS_QT4} && export QMAKE_FLAGS_QT5=${QMAKE_FLAGS_QT5} && export CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} && export QMAKE_BUILD_TYPE=${QMAKE_BUILD_TYPE} && export PACKAGE_VERSION=${PACKAGE_VERSION} && export PACKAGE_BUILD=${PACKAGE_BUILD} && export PACKAGE_CODE=${PACKAGE_CODE} && export EXECUTABLE_VERSION=${EXECUTABLE_VERSION} && export EXECUTABLE_ARCH=${EXECUTABLE_ARCH} && cd ${PROJECT_DIR_DOCKER} && .ci/debian_install.sh && .ci/debian_build.sh"
|
13
.ci/debian_install.sh
Executable file
13
.ci/debian_install.sh
Executable file
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Source OS Release
|
||||
source /etc/os-release
|
||||
|
||||
# When Debian add backports
|
||||
if [ "${ID}" == "debian" ]; then
|
||||
echo "deb http://deb.debian.org/debian ${VERSION_CODENAME}-backports main" >> /etc/apt/sources.list
|
||||
fi
|
||||
|
||||
# Install packages
|
||||
apt-get update -qq && \
|
||||
apt-get install -qq ${APT_INSTALL} checkinstall cmake dpkg-dev fakeroot g++ gcc qtbase5-dev qt5-qmake qttranslations5-l10n libqt5svg5-dev
|
1763
.ci/dropbox_uploader.sh
Executable file
1763
.ci/dropbox_uploader.sh
Executable file
File diff suppressed because it is too large
Load diff
364
.ci/gta5view.nsi
Normal file
364
.ci/gta5view.nsi
Normal file
|
@ -0,0 +1,364 @@
|
|||
######################################################################
|
||||
|
||||
!define APP_NAME "gta5view"
|
||||
!define APP_EXT ".g5e"
|
||||
!define COMP_NAME "Syping"
|
||||
!define WEB_SITE "https://gta5view.syping.de/"
|
||||
!define VERSION "1.10.2.0"
|
||||
!define COPYRIGHT "Copyright © 2016-2022 Syping"
|
||||
!define DESCRIPTION "Open Source Snapmatic and Savegame viewer/editor for GTA V"
|
||||
!define INSTALLER_NAME "gta5view_setup.exe"
|
||||
!define MAIN_APP_EXE "gta5view.exe"
|
||||
!define INSTALL_TYPE "SetShellVarContext all"
|
||||
!define REG_ROOT "HKLM"
|
||||
!define REG_APP_PATH "Software\Microsoft\Windows\CurrentVersion\App Paths\${MAIN_APP_EXE}"
|
||||
!define UNINSTALL_PATH "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}"
|
||||
!define LICENSE_TXT "../LICENSE"
|
||||
|
||||
######################################################################
|
||||
|
||||
VIProductVersion "${VERSION}"
|
||||
VIAddVersionKey "ProductName" "${APP_NAME}"
|
||||
VIAddVersionKey "ProductVersion" "${VERSION}"
|
||||
VIAddVersionKey "CompanyName" "${COMP_NAME}"
|
||||
VIAddVersionKey "LegalCopyright" "${COPYRIGHT}"
|
||||
VIAddVersionKey "FileDescription" "${DESCRIPTION}"
|
||||
VIAddVersionKey "FileVersion" "${VERSION}"
|
||||
|
||||
######################################################################
|
||||
|
||||
!include "x64.nsh"
|
||||
SetCompressor LZMA
|
||||
Name "${APP_NAME}"
|
||||
Caption "${APP_NAME}"
|
||||
OutFile "${INSTALLER_NAME}"
|
||||
#BrandingText "${APP_NAME}"
|
||||
XPStyle on
|
||||
Unicode true
|
||||
InstallDirRegKey "${REG_ROOT}" "${REG_APP_PATH}" ""
|
||||
InstallDir "$PROGRAMFILES64\Syping\gta5view"
|
||||
|
||||
######################################################################
|
||||
|
||||
!include "MUI2.nsh"
|
||||
|
||||
!define MUI_ABORTWARNING
|
||||
!define MUI_UNABORTWARNING
|
||||
|
||||
!define MUI_LANGDLL_REGISTRY_ROOT "${REG_ROOT}"
|
||||
!define MUI_LANGDLL_REGISTRY_KEY "${UNINSTALL_PATH}"
|
||||
!define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language"
|
||||
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
|
||||
!ifdef LICENSE_TXT
|
||||
!insertmacro MUI_PAGE_LICENSE "${LICENSE_TXT}"
|
||||
!endif
|
||||
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
|
||||
!ifdef REG_START_MENU
|
||||
!define MUI_STARTMENUPAGE_NODISABLE
|
||||
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "gta5view"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "${REG_ROOT}"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_KEY "${UNINSTALL_PATH}"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${REG_START_MENU}"
|
||||
!insertmacro MUI_PAGE_STARTMENU Application $SM_Folder
|
||||
!endif
|
||||
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
|
||||
!define MUI_FINISHPAGE_RUN "$INSTDIR\${MAIN_APP_EXE}"
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
!insertmacro MUI_UNPAGE_FINISH
|
||||
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
!insertmacro MUI_LANGUAGE "French"
|
||||
!insertmacro MUI_LANGUAGE "German"
|
||||
!insertmacro MUI_LANGUAGE "Korean"
|
||||
!insertmacro MUI_LANGUAGE "Russian"
|
||||
!insertmacro MUI_LANGUAGE "Ukrainian"
|
||||
!insertmacro MUI_LANGUAGE "TradChinese"
|
||||
|
||||
!insertmacro MUI_RESERVEFILE_LANGDLL
|
||||
|
||||
######################################################################
|
||||
|
||||
Function .onInit
|
||||
!insertmacro MUI_LANGDLL_DISPLAY
|
||||
!ifdef WIN32
|
||||
MessageBox MB_OK|MB_ICONSTOP "Windows 32-Bit is not supported anymore!"
|
||||
Quit
|
||||
!endif
|
||||
SetRegView 64
|
||||
FunctionEnd
|
||||
|
||||
######################################################################
|
||||
|
||||
Section -MainProgram
|
||||
${INSTALL_TYPE}
|
||||
SetOverwrite ifnewer
|
||||
SetOutPath "$INSTDIR"
|
||||
File "../build/gta5view.exe"
|
||||
File "/opt/llvm-mingw/x86_64-w64-mingw32/bin/libc++.dll"
|
||||
File "/opt/llvm-mingw/x86_64-w64-mingw32/bin/libunwind.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/openssl/bin/libcrypto-1_1-x64.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/openssl/bin/libssl-1_1-x64.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/bin/Qt5Core.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/bin/Qt5Gui.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/bin/Qt5Network.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/bin/Qt5Svg.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/bin/Qt5Widgets.dll"
|
||||
SetOutPath "$INSTDIR\lang"
|
||||
File "../build/gta5sync_en_US.qm"
|
||||
File "../build/gta5sync_de.qm"
|
||||
File "../build/gta5sync_fr.qm"
|
||||
File "../build/gta5sync_ko.qm"
|
||||
File "../build/gta5sync_ru.qm"
|
||||
File "../build/gta5sync_uk.qm"
|
||||
File "../build/gta5sync_zh_TW.qm"
|
||||
File "../build/qtbase_en_GB.qm"
|
||||
File "../res/qt5/qtbase_de.qm"
|
||||
File "../res/qt5/qtbase_fr.qm"
|
||||
File "../res/qt5/qtbase_ko.qm"
|
||||
File "../res/qt5/qtbase_ru.qm"
|
||||
File "../res/qt5/qtbase_uk.qm"
|
||||
File "../res/qt5/qtbase_zh_TW.qm"
|
||||
SetOutPath "$INSTDIR\resources"
|
||||
File "../res/add.svgz"
|
||||
File "../res/avatararea.png"
|
||||
File "../res/avatarareaimport.png"
|
||||
File "../res/back.svgz"
|
||||
File "../res/flag-de.png"
|
||||
File "../res/flag-fr.png"
|
||||
File "../res/flag-gb.png"
|
||||
File "../res/flag-kr.png"
|
||||
File "../res/flag-ru.png"
|
||||
File "../res/flag-tw.png"
|
||||
File "../res/flag-ua.png"
|
||||
File "../res/flag-us.png"
|
||||
File "../res/gta5view-16.png"
|
||||
File "../res/gta5view-24.png"
|
||||
File "../res/gta5view-32.png"
|
||||
File "../res/gta5view-40.png"
|
||||
File "../res/gta5view-48.png"
|
||||
File "../res/gta5view-64.png"
|
||||
File "../res/gta5view-96.png"
|
||||
File "../res/gta5view-128.png"
|
||||
File "../res/gta5view-256.png"
|
||||
File "../res/mapcayoperico.jpg"
|
||||
File "../res/mappreview.jpg"
|
||||
File "../res/next.svgz"
|
||||
File "../res/pointmaker-8.png"
|
||||
File "../res/pointmaker-16.png"
|
||||
File "../res/pointmaker-24.png"
|
||||
File "../res/pointmaker-32.png"
|
||||
File "../res/savegame.svgz"
|
||||
File "../res/watermark_1b.png"
|
||||
File "../res/watermark_2b.png"
|
||||
File "../res/watermark_2r.png"
|
||||
SetOutPath "$INSTDIR\imageformats"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/plugins/imageformats/qgif.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/plugins/imageformats/qicns.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/plugins/imageformats/qico.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/plugins/imageformats/qjpeg.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/plugins/imageformats/qsvg.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/plugins/imageformats/qtga.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/plugins/imageformats/qtiff.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/plugins/imageformats/qwbmp.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/plugins/imageformats/qwebp.dll"
|
||||
SetOutPath "$INSTDIR\platforms"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/plugins/platforms/qwindows.dll"
|
||||
SetOutPath "$INSTDIR\styles"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/plugins/styles/qcleanlooksstyle.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/plugins/styles/qplastiquestyle.dll"
|
||||
File "/usr/local/lib/x86_64-w64-mingw32/qt5/plugins/styles/qwindowsvistastyle.dll"
|
||||
SectionEnd
|
||||
|
||||
######################################################################
|
||||
|
||||
Section -Icons_Reg
|
||||
SetOutPath "$INSTDIR"
|
||||
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||
|
||||
!ifdef REG_START_MENU
|
||||
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
|
||||
CreateDirectory "$SMPROGRAMS\$SM_Folder"
|
||||
CreateShortCut "$SMPROGRAMS\$SM_Folder\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}"
|
||||
CreateShortCut "$SMPROGRAMS\$SM_Folder\Uninstall ${APP_NAME}.lnk" "$INSTDIR\uninstall.exe"
|
||||
|
||||
!ifdef WEB_SITE
|
||||
WriteIniStr "$INSTDIR\${APP_NAME} website.url" "InternetShortcut" "URL" "${WEB_SITE}"
|
||||
CreateShortCut "$SMPROGRAMS\$SM_Folder\gta5view Website.lnk" "$INSTDIR\${APP_NAME} website.url"
|
||||
!endif
|
||||
!insertmacro MUI_STARTMENU_WRITE_END
|
||||
!endif
|
||||
|
||||
!ifndef REG_START_MENU
|
||||
CreateDirectory "$SMPROGRAMS\gta5view"
|
||||
CreateShortCut "$SMPROGRAMS\gta5view\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}"
|
||||
CreateShortCut "$SMPROGRAMS\gta5view\Uninstall ${APP_NAME}.lnk" "$INSTDIR\uninstall.exe"
|
||||
|
||||
!ifdef WEB_SITE
|
||||
WriteIniStr "$INSTDIR\${APP_NAME} website.url" "InternetShortcut" "URL" "${WEB_SITE}"
|
||||
CreateShortCut "$SMPROGRAMS\gta5view\gta5view Website.lnk" "$INSTDIR\${APP_NAME} website.url"
|
||||
!endif
|
||||
!endif
|
||||
|
||||
WriteRegStr ${REG_ROOT} "${REG_APP_PATH}" "" "$INSTDIR\${MAIN_APP_EXE}"
|
||||
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayName" "${APP_NAME}"
|
||||
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "UninstallString" "$INSTDIR\uninstall.exe"
|
||||
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayIcon" "$INSTDIR\${MAIN_APP_EXE}"
|
||||
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayVersion" "${VERSION}"
|
||||
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "Publisher" "${COMP_NAME}"
|
||||
|
||||
!ifdef WEB_SITE
|
||||
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "URLInfoAbout" "${WEB_SITE}"
|
||||
!endif
|
||||
SectionEnd
|
||||
|
||||
######################################################################
|
||||
|
||||
Section -ShellAssoc
|
||||
WriteRegStr ${REG_ROOT} "Software\Classes\${APP_NAME}\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE},0"
|
||||
WriteRegStr ${REG_ROOT} "Software\Classes\${APP_NAME}\shell\open\command" "" '"$INSTDIR\${MAIN_APP_EXE}" "%1"'
|
||||
WriteRegStr ${REG_ROOT} "Software\Classes\${APP_EXT}" "" "${APP_NAME}"
|
||||
WriteRegStr ${REG_ROOT} "Software\Classes\${APP_EXT}" "Content Type" "application/x-gta5view-export"
|
||||
System::Call 'SHELL32::SHChangeNotify(i0x8000000,i0,p0,p0)'
|
||||
SectionEnd
|
||||
|
||||
######################################################################
|
||||
|
||||
Section -un.ShellAssoc
|
||||
ClearErrors
|
||||
ReadRegStr $0 ${REG_ROOT} "Software\Classes\${APP_EXT}" ""
|
||||
DeleteRegKey ${REG_ROOT} "Software\Classes\${APP_NAME}"
|
||||
${IfNot} ${Errors}
|
||||
${AndIf} $0 == "${APP_NAME}"
|
||||
DeleteRegValue ${REG_ROOT} "Software\Classes\${APP_EXT}" ""
|
||||
DeleteRegKey /IfEmpty ${REG_ROOT} "Software\Classes\${APP_EXT}"
|
||||
${EndIf}
|
||||
System::Call 'SHELL32::SHChangeNotify(i0x8000000,i0,p0,p0)'
|
||||
SectionEnd
|
||||
|
||||
######################################################################
|
||||
|
||||
Section Uninstall
|
||||
${INSTALL_TYPE}
|
||||
Delete "$INSTDIR\gta5view.exe"
|
||||
Delete "$INSTDIR\libc++.dll"
|
||||
Delete "$INSTDIR\libunwind.dll"
|
||||
Delete "$INSTDIR\libcrypto-1_1-x64.dll"
|
||||
Delete "$INSTDIR\libssl-1_1-x64.dll"
|
||||
Delete "$INSTDIR\Qt5Core.dll"
|
||||
Delete "$INSTDIR\Qt5Gui.dll"
|
||||
Delete "$INSTDIR\Qt5Network.dll"
|
||||
Delete "$INSTDIR\Qt5Svg.dll"
|
||||
Delete "$INSTDIR\Qt5Widgets.dll"
|
||||
Delete "$INSTDIR\lang\gta5sync_en_US.qm"
|
||||
Delete "$INSTDIR\lang\gta5sync_de.qm"
|
||||
Delete "$INSTDIR\lang\gta5sync_fr.qm"
|
||||
Delete "$INSTDIR\lang\gta5sync_ko.qm"
|
||||
Delete "$INSTDIR\lang\gta5sync_ru.qm"
|
||||
Delete "$INSTDIR\lang\gta5sync_uk.qm"
|
||||
Delete "$INSTDIR\lang\gta5sync_zh_TW.qm"
|
||||
Delete "$INSTDIR\lang\qtbase_en_GB.qm"
|
||||
Delete "$INSTDIR\lang\qtbase_de.qm"
|
||||
Delete "$INSTDIR\lang\qtbase_fr.qm"
|
||||
Delete "$INSTDIR\lang\qtbase_ko.qm"
|
||||
Delete "$INSTDIR\lang\qtbase_ru.qm"
|
||||
Delete "$INSTDIR\lang\qtbase_uk.qm"
|
||||
Delete "$INSTDIR\lang\qtbase_zh_TW.qm"
|
||||
Delete "$INSTDIR\resources\add.svgz"
|
||||
Delete "$INSTDIR\resources\avatararea.png"
|
||||
Delete "$INSTDIR\resources\avatarareaimport.png"
|
||||
Delete "$INSTDIR\resources\back.svgz"
|
||||
Delete "$INSTDIR\resources\flag-de.png"
|
||||
Delete "$INSTDIR\resources\flag-fr.png"
|
||||
Delete "$INSTDIR\resources\flag-gb.png"
|
||||
Delete "$INSTDIR\resources\flag-kr.png"
|
||||
Delete "$INSTDIR\resources\flag-ru.png"
|
||||
Delete "$INSTDIR\resources\flag-tw.png"
|
||||
Delete "$INSTDIR\resources\flag-ua.png"
|
||||
Delete "$INSTDIR\resources\flag-us.png"
|
||||
Delete "$INSTDIR\resources\gta5view-16.png"
|
||||
Delete "$INSTDIR\resources\gta5view-24.png"
|
||||
Delete "$INSTDIR\resources\gta5view-32.png"
|
||||
Delete "$INSTDIR\resources\gta5view-40.png"
|
||||
Delete "$INSTDIR\resources\gta5view-48.png"
|
||||
Delete "$INSTDIR\resources\gta5view-64.png"
|
||||
Delete "$INSTDIR\resources\gta5view-96.png"
|
||||
Delete "$INSTDIR\resources\gta5view-128.png"
|
||||
Delete "$INSTDIR\resources\gta5view-256.png"
|
||||
Delete "$INSTDIR\resources\mapcayoperico.jpg"
|
||||
Delete "$INSTDIR\resources\mappreview.jpg"
|
||||
Delete "$INSTDIR\resources\next.svgz"
|
||||
Delete "$INSTDIR\resources\pointmaker-8.png"
|
||||
Delete "$INSTDIR\resources\pointmaker-16.png"
|
||||
Delete "$INSTDIR\resources\pointmaker-24.png"
|
||||
Delete "$INSTDIR\resources\pointmaker-32.png"
|
||||
Delete "$INSTDIR\resources\savegame.svgz"
|
||||
Delete "$INSTDIR\resources\watermark_1b.png"
|
||||
Delete "$INSTDIR\resources\watermark_2b.png"
|
||||
Delete "$INSTDIR\resources\watermark_2r.png"
|
||||
Delete "$INSTDIR\imageformats\qgif.dll"
|
||||
Delete "$INSTDIR\imageformats\qicns.dll"
|
||||
Delete "$INSTDIR\imageformats\qico.dll"
|
||||
Delete "$INSTDIR\imageformats\qjpeg.dll"
|
||||
Delete "$INSTDIR\imageformats\qsvg.dll"
|
||||
Delete "$INSTDIR\imageformats\qtga.dll"
|
||||
Delete "$INSTDIR\imageformats\qtiff.dll"
|
||||
Delete "$INSTDIR\imageformats\qwbmp.dll"
|
||||
Delete "$INSTDIR\imageformats\qwebp.dll"
|
||||
Delete "$INSTDIR\platforms\qwindows.dll"
|
||||
Delete "$INSTDIR\styles\qcleanlooksstyle.dll"
|
||||
Delete "$INSTDIR\styles\qplastiquestyle.dll"
|
||||
Delete "$INSTDIR\styles\qwindowsvistastyle.dll"
|
||||
RmDir "$INSTDIR\lang"
|
||||
RmDir "$INSTDIR\imageformats"
|
||||
RmDir "$INSTDIR\platforms"
|
||||
RmDir "$INSTDIR\styles"
|
||||
|
||||
Delete "$INSTDIR\uninstall.exe"
|
||||
!ifdef WEB_SITE
|
||||
Delete "$INSTDIR\${APP_NAME} website.url"
|
||||
!endif
|
||||
|
||||
RmDir "$INSTDIR"
|
||||
|
||||
!ifdef REG_START_MENU
|
||||
!insertmacro MUI_STARTMENU_GETFOLDER "Application" $SM_Folder
|
||||
Delete "$SMPROGRAMS\$SM_Folder\${APP_NAME}.lnk"
|
||||
Delete "$SMPROGRAMS\$SM_Folder\Uninstall ${APP_NAME}.lnk"
|
||||
!ifdef WEB_SITE
|
||||
Delete "$SMPROGRAMS\$SM_Folder\gta5view Website.lnk"
|
||||
!endif
|
||||
RmDir "$SMPROGRAMS\$SM_Folder"
|
||||
!endif
|
||||
|
||||
!ifndef REG_START_MENU
|
||||
Delete "$SMPROGRAMS\gta5view\${APP_NAME}.lnk"
|
||||
Delete "$SMPROGRAMS\gta5view\Uninstall ${APP_NAME}.lnk"
|
||||
!ifdef WEB_SITE
|
||||
Delete "$SMPROGRAMS\gta5view\gta5view Website.lnk"
|
||||
!endif
|
||||
RmDir "$SMPROGRAMS\gta5view"
|
||||
!endif
|
||||
|
||||
DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}"
|
||||
DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}"
|
||||
SectionEnd
|
||||
|
||||
######################################################################
|
||||
|
||||
Function un.onInit
|
||||
!insertmacro MUI_UNGETLANGUAGE
|
||||
SetRegView 64
|
||||
FunctionEnd
|
||||
|
||||
######################################################################
|
24
.ci/osx_build.sh
Executable file
24
.ci/osx_build.sh
Executable file
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Creating folders
|
||||
cd ${PROJECT_DIR} && \
|
||||
echo "gta5view build version is ${APPLICATION_VERSION}" && \
|
||||
echo "gta5view image name is gta5view-osx_${APPLICATION_VERSION}.dmg" && \
|
||||
mkdir -p build && \
|
||||
mkdir -p assets && \
|
||||
cd build && \
|
||||
|
||||
/usr/local/bin/cmake \
|
||||
"-DCMAKE_PREFIX_PATH=/usr/local/opt/qt" \
|
||||
"${CMAKE_BUILD_TYPE}" \
|
||||
"-DGTA5VIEW_BUILDCODE=${PACKAGE_CODE}" \
|
||||
"-DGTA5VIEW_APPVER=${APPLICATION_VERSION}" \
|
||||
"-DGTA5VIEW_COMMIT=${APPLICATION_COMMIT}" \
|
||||
"-DWITH_DONATE=ON" \
|
||||
"-DWITH_TELEMETRY=ON" \
|
||||
"-DDONATE_ADDRESSES=$(cat ${PROJECT_DIR}/.ci/donate.txt)" \
|
||||
"-DTELEMETRY_WEBURL=https://dev.syping.de/gta5view-userstats/" \
|
||||
../ && \
|
||||
make -j 4 && \
|
||||
/usr/local/opt/qt/bin/macdeployqt gta5view.app -dmg && \
|
||||
cp -Rf gta5view.dmg ../assets/gta5view-osx_${APPLICATION_VERSION}.dmg
|
8
.ci/osx_ci.sh
Executable file
8
.ci/osx_ci.sh
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Install packages
|
||||
.ci/osx_install.sh && \
|
||||
|
||||
# Build gta5view
|
||||
.ci/osx_build.sh && \
|
||||
cd ${PROJECT_DIR}
|
4
.ci/osx_install.sh
Executable file
4
.ci/osx_install.sh
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Install packages
|
||||
brew upgrade cmake qt
|
28
.ci/windows_build.sh
Executable file
28
.ci/windows_build.sh
Executable file
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Prepare environment variable
|
||||
export GTA5VIEW_EXECUTABLE=gta5view-${EXECUTABLE_VERSION}${EXECUTABLE_ARCH}.exe && \
|
||||
|
||||
# Creating folders
|
||||
cd ${PROJECT_DIR} && \
|
||||
echo "gta5view build version is ${APPLICATION_VERSION}" && \
|
||||
echo "gta5view executable is ${GTA5VIEW_EXECUTABLE}" && \
|
||||
mkdir -p build && \
|
||||
mkdir -p assets && \
|
||||
|
||||
# Starting build
|
||||
cd build && \
|
||||
mingw64-qt-cmake \
|
||||
"${CMAKE_BUILD_TYPE}" \
|
||||
"-DGTA5VIEW_BUILDCODE=${PACKAGE_CODE}" \
|
||||
"-DGTA5VIEW_APPVER=${APPLICATION_VERSION}" \
|
||||
"-DGTA5VIEW_COMMIT=${APPLICATION_COMMIT}" \
|
||||
"-DWITH_DONATE=ON" \
|
||||
"-DWITH_TELEMETRY=ON" \
|
||||
"-DDONATE_ADDRESSES=$(cat ${PROJECT_DIR}/.ci/donate.txt)" \
|
||||
"-DTELEMETRY_WEBURL=https://dev.syping.de/gta5view-userstats/" \
|
||||
.. && \
|
||||
make -j 4 && \
|
||||
x86_64-w64-mingw32-strip -s gta5view.exe && \
|
||||
cp -Rf *.exe ${PROJECT_DIR}/assets/${GTA5VIEW_EXECUTABLE} && \
|
||||
cd ${PROJECT_DIR}/assets
|
25
.ci/windows_docker.sh
Executable file
25
.ci/windows_docker.sh
Executable file
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
DOCKER_IMAGE=sypingauto/gta5view-build:1.10-static
|
||||
PROJECT_DIR_DOCKER=/gta5view
|
||||
|
||||
cd ${PROJECT_DIR} && \
|
||||
docker pull ${DOCKER_IMAGE} && \
|
||||
docker run --rm \
|
||||
-v "${PROJECT_DIR}:${PROJECT_DIR_DOCKER}" \
|
||||
${DOCKER_IMAGE} \
|
||||
/bin/bash -c "export PROJECT_DIR=${PROJECT_DIR_DOCKER} && export QT_SELECT=${QT_SELECT} && export APPLICATION_VERSION=${APPLICATION_VERSION} && export APPLICATION_COMMIT=${APPLICATION_COMMIT} && export BUILD_TYPE=${BUILD_TYPE} && export QMAKE_FLAGS_QT4=${QMAKE_FLAGS_QT4} && export QMAKE_FLAGS_QT5=${QMAKE_FLAGS_QT5} && export CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} && export QMAKE_BUILD_TYPE=${QMAKE_BUILD_TYPE} && export PACKAGE_VERSION=${PACKAGE_VERSION} && export PACKAGE_BUILD=${PACKAGE_BUILD} && export PACKAGE_CODE=${PACKAGE_CODE} && export EXECUTABLE_VERSION=${EXECUTABLE_VERSION} && export EXECUTABLE_ARCH=${EXECUTABLE_ARCH} && cd ${PROJECT_DIR_DOCKER} && .ci/windows_build.sh" && \
|
||||
|
||||
# Prepare environment variable
|
||||
export GTA5VIEW_EXECUTABLE=gta5view-${EXECUTABLE_VERSION}${EXECUTABLE_ARCH}.exe && \
|
||||
|
||||
# Upload Assets to Dropbox
|
||||
if [ "${PACKAGE_CODE}" == "gta5-mods" ]; then
|
||||
${PROJECT_DIR}/.ci/dropbox_uploader.sh mkdir gta5-mods/${PACKAGE_VERSION}
|
||||
${PROJECT_DIR}/.ci/dropbox_uploader.sh upload ${PROJECT_DIR}/assets/${GTA5VIEW_EXECUTABLE} gta5-mods/${PACKAGE_VERSION}/${GTA5VIEW_EXECUTABLE} && \
|
||||
rm -rf ${GTA5VIEW_EXECUTABLE}
|
||||
elif [ "${PACKAGE_CODE}" == "gtainside" ]; then
|
||||
${PROJECT_DIR}/.ci/dropbox_uploader.sh mkdir gtainside/${PACKAGE_VERSION}
|
||||
${PROJECT_DIR}/.ci/dropbox_uploader.sh upload ${PROJECT_DIR}/assets/${GTA5VIEW_EXECUTABLE} gtainside/${PACKAGE_VERSION}/${GTA5VIEW_EXECUTABLE} && \
|
||||
rm -rf ${GTA5VIEW_EXECUTABLE}
|
||||
fi
|
29
.ci/wininstall_build.sh
Executable file
29
.ci/wininstall_build.sh
Executable file
|
@ -0,0 +1,29 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Creating folders
|
||||
cd ${PROJECT_DIR} && \
|
||||
echo "gta5view build version is ${APPLICATION_VERSION}" && \
|
||||
mkdir -p build && \
|
||||
mkdir -p assets && \
|
||||
|
||||
# Starting build
|
||||
cd build && \
|
||||
mingw64-qt-cmake \
|
||||
"${CMAKE_BUILD_TYPE}" \
|
||||
"-DGTA5VIEW_BUILDCODE=${PACKAGE_CODE}" \
|
||||
"-DGTA5VIEW_APPVER=${APPLICATION_VERSION}" \
|
||||
"-DGTA5VIEW_COMMIT=${APPLICATION_COMMIT}" \
|
||||
"-DWITH_DONATE=ON" \
|
||||
"-DWITH_TELEMETRY=ON" \
|
||||
"-DDONATE_ADDRESSES=$(cat ${PROJECT_DIR}/.ci/donate.txt)" \
|
||||
"-DTELEMETRY_WEBURL=https://dev.syping.de/gta5view-userstats/" \
|
||||
"-DQCONF_BUILD=ON" \
|
||||
"-DGTA5VIEW_INLANG=RUNDIR:SEPARATOR:lang" \
|
||||
"-DGTA5VIEW_LANG=RUNDIR:SEPARATOR:lang" \
|
||||
"-DGTA5VIEW_PLUG=RUNDIR:SEPARATOR:plugins" \
|
||||
.. && \
|
||||
make -j 4 && \
|
||||
x86_64-w64-mingw32-strip -s gta5view.exe && \
|
||||
cd ${PROJECT_DIR}/assets && \
|
||||
makensis "-XTarget amd64-unicode" -NOCD ${PROJECT_DIR}/.ci/gta5view.nsi && \
|
||||
mv -f gta5view_setup.exe gta5view-${EXECUTABLE_VERSION}_setup.exe
|
11
.ci/wininstall_docker.sh
Executable file
11
.ci/wininstall_docker.sh
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
DOCKER_IMAGE=sypingauto/gta5view-build:1.10-shared
|
||||
PROJECT_DIR_DOCKER=/gta5view
|
||||
|
||||
cd ${PROJECT_DIR} && \
|
||||
docker pull ${DOCKER_IMAGE} && \
|
||||
docker run --rm \
|
||||
-v "${PROJECT_DIR}:${PROJECT_DIR_DOCKER}" \
|
||||
${DOCKER_IMAGE} \
|
||||
/bin/bash -c "export PROJECT_DIR=${PROJECT_DIR_DOCKER} && export QT_SELECT=${QT_SELECT} && export APPLICATION_VERSION=${APPLICATION_VERSION} && export APPLICATION_COMMIT=${APPLICATION_COMMIT} && export BUILD_TYPE=${BUILD_TYPE} && export QMAKE_FLAGS_QT4=${QMAKE_FLAGS_QT4} && export QMAKE_FLAGS_QT5=${QMAKE_FLAGS_QT5} && export CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} && export QMAKE_BUILD_TYPE=${QMAKE_BUILD_TYPE} && export PACKAGE_VERSION=${PACKAGE_VERSION} && export PACKAGE_BUILD=${PACKAGE_BUILD} && export PACKAGE_CODE=${PACKAGE_CODE} && export EXECUTABLE_VERSION=${EXECUTABLE_VERSION} && export EXECUTABLE_ARCH=${EXECUTABLE_ARCH} && cd ${PROJECT_DIR_DOCKER} && .ci/wininstall_build.sh"
|
36
.drone.yml
Normal file
36
.drone.yml
Normal file
|
@ -0,0 +1,36 @@
|
|||
kind: pipeline
|
||||
type: docker
|
||||
|
||||
environment:
|
||||
BUILD_TYPE: "REL"
|
||||
|
||||
steps:
|
||||
- name: Windows Installer
|
||||
image: sypingauto/gta5view-build:1.10-shared
|
||||
environment:
|
||||
BUILD_SCRIPT: "wininstall_build.sh"
|
||||
QT_SELECT: "qt5-x86_64-w64-mingw32"
|
||||
TCA_PASS:
|
||||
from_secret: tca_pass
|
||||
commands:
|
||||
- .drone/drone.sh
|
||||
volumes:
|
||||
- name: gta5view
|
||||
path: /srv/gta5view
|
||||
- name: Windows Portable
|
||||
image: sypingauto/gta5view-build:1.10-static
|
||||
environment:
|
||||
BUILD_SCRIPT: "windows_build.sh"
|
||||
QT_SELECT: "qt5-x86_64-w64-mingw32"
|
||||
TCA_PASS:
|
||||
from_secret: tca_pass
|
||||
commands:
|
||||
- .drone/drone.sh
|
||||
volumes:
|
||||
- name: gta5view
|
||||
path: /srv/gta5view
|
||||
|
||||
volumes:
|
||||
- name: gta5view
|
||||
host:
|
||||
path: /srv/gta5view
|
BIN
.drone/TelemetryClassAuthenticator.cpp.enc
Normal file
BIN
.drone/TelemetryClassAuthenticator.cpp.enc
Normal file
Binary file not shown.
33
.drone/drone.sh
Executable file
33
.drone/drone.sh
Executable file
|
@ -0,0 +1,33 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Cleanup previous Drone build
|
||||
if [ -d "assets" ]; then
|
||||
rm -rf assets
|
||||
fi
|
||||
if [ -d "build" ]; then
|
||||
rm -rf build
|
||||
fi
|
||||
|
||||
# Decrypt Telemetry Authenticator
|
||||
rm -rf tmext/TelemetryClassAuthenticator.cpp && \
|
||||
openssl aes-256-cbc -k ${TCA_PASS} -in .drone/TelemetryClassAuthenticator.cpp.enc -out tmext/TelemetryClassAuthenticator.cpp -d -pbkdf2
|
||||
|
||||
# Check if build is not tagged
|
||||
if [ "${DRONE_TAG}" == "" ]; then
|
||||
export EXECUTABLE_TAG=-$(git rev-parse --short HEAD)
|
||||
else
|
||||
export EXECUTABLE_TAG=
|
||||
fi
|
||||
|
||||
# Check if package code is not set
|
||||
if [ "${PACKAGE_CODE}" == "" ]; then
|
||||
export PACKAGE_CODE=Drone
|
||||
fi
|
||||
|
||||
# Init Application Commit Hash
|
||||
export APPLICATION_COMMIT=$(git rev-parse --short HEAD)
|
||||
|
||||
# Start CI script and copying assets into gta5view directory
|
||||
.ci/ci.sh && \
|
||||
mkdir -p /srv/gta5view/${APPLICATION_COMMIT} && \
|
||||
cp -Rf assets/* /srv/gta5view/${APPLICATION_COMMIT}/
|
22
.flatpak/de.syping.gta5view.yaml
Normal file
22
.flatpak/de.syping.gta5view.yaml
Normal file
|
@ -0,0 +1,22 @@
|
|||
app-id: de.syping.gta5view
|
||||
runtime: org.kde.Platform
|
||||
runtime-version: '5.15-21.08'
|
||||
sdk: org.kde.Sdk
|
||||
command: gta5view
|
||||
finish-args:
|
||||
- --share=network
|
||||
- --share=ipc
|
||||
- --socket=fallback-x11
|
||||
- --socket=wayland
|
||||
- --device=dri
|
||||
modules:
|
||||
- name: gta5view
|
||||
buildsystem: cmake-ninja
|
||||
config-opts:
|
||||
- -DFLATPAK_BUILD=ON
|
||||
- -DQCONF_BUILD=ON
|
||||
- -DGTA5VIEW_BUILDCODE=Flatpak
|
||||
- -DGTA5VIEW_BUILDTYPE=Release
|
||||
sources:
|
||||
- type: dir
|
||||
path: ../
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -27,8 +27,7 @@
|
|||
*.out
|
||||
*.app
|
||||
|
||||
# Qt project user files
|
||||
CMakeLists.txt.user
|
||||
# Qt project user file
|
||||
*.pro.user
|
||||
|
||||
# Gettext translation files
|
||||
|
|
31
.gitlab-ci.yml
Normal file
31
.gitlab-ci.yml
Normal file
|
@ -0,0 +1,31 @@
|
|||
stages:
|
||||
- build
|
||||
|
||||
variables:
|
||||
BUILD_TYPE: "REL"
|
||||
|
||||
Windows Installer:
|
||||
stage: build
|
||||
image: sypingauto/gta5view-build:1.10-shared
|
||||
variables:
|
||||
BUILD_SCRIPT: "wininstall_build.sh"
|
||||
QT_SELECT: "qt5-x86_64-w64-mingw32"
|
||||
script:
|
||||
- .gitlab/gitlab.sh
|
||||
artifacts:
|
||||
name: "gta5view-$CI_COMMIT_REF_NAME-${CI_COMMIT_SHA:0:8}_setup"
|
||||
paths:
|
||||
- "gta5view-*.exe"
|
||||
|
||||
Windows Portable:
|
||||
stage: build
|
||||
image: sypingauto/gta5view-build:1.10-static
|
||||
variables:
|
||||
BUILD_SCRIPT: "windows_build.sh"
|
||||
QT_SELECT: "qt5-x86_64-w64-mingw32"
|
||||
script:
|
||||
- .gitlab/gitlab.sh
|
||||
artifacts:
|
||||
name: "gta5view-$CI_COMMIT_REF_NAME-${CI_COMMIT_SHA:0:8}_portable"
|
||||
paths:
|
||||
- "gta5view-*.exe"
|
BIN
.gitlab/TelemetryClassAuthenticator.cpp.enc
Normal file
BIN
.gitlab/TelemetryClassAuthenticator.cpp.enc
Normal file
Binary file not shown.
24
.gitlab/gitlab.sh
Executable file
24
.gitlab/gitlab.sh
Executable file
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Decrypt Telemetry Authenticator
|
||||
rm -rf tmext/TelemetryClassAuthenticator.cpp && \
|
||||
openssl aes-256-cbc -k ${tca_pass} -in .gitlab/TelemetryClassAuthenticator.cpp.enc -out tmext/TelemetryClassAuthenticator.cpp -d
|
||||
|
||||
# Check if build is not tagged
|
||||
if [ "${CI_COMMIT_TAG}" == "" ]; then
|
||||
export EXECUTABLE_TAG=-$(git rev-parse --short HEAD)
|
||||
else
|
||||
export EXECUTABLE_TAG=
|
||||
fi
|
||||
|
||||
# Check if package code is not set
|
||||
if [ "${PACKAGE_CODE}" == "" ]; then
|
||||
export PACKAGE_CODE=GitLab
|
||||
fi
|
||||
|
||||
# Init Application Commit Hash
|
||||
export APPLICATION_COMMIT=$(git rev-parse --short HEAD)
|
||||
|
||||
# Start CI script and copying assets into base directory
|
||||
.ci/ci.sh && \
|
||||
cp -Rf assets/* ./
|
6
.gitmodules
vendored
6
.gitmodules
vendored
|
@ -1,6 +0,0 @@
|
|||
[submodule "src/libragephoto"]
|
||||
path = src/libragephoto
|
||||
url = https://github.com/Syping/libragephoto.git
|
||||
[submodule "src/json"]
|
||||
path = src/json
|
||||
url = https://github.com/boostorg/json.git
|
50
.travis.yml
Normal file
50
.travis.yml
Normal file
|
@ -0,0 +1,50 @@
|
|||
dist: bionic
|
||||
sudo: required
|
||||
|
||||
language: cpp
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
env:
|
||||
global:
|
||||
- BUILD_TYPE=REL
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- env:
|
||||
- BUILD_SCRIPT=debian_docker.sh
|
||||
- RELEASE_LABEL="Debian 64-Bit Package"
|
||||
- DEBIAN_VERSION=buster
|
||||
- DOCKER_USER=amd64
|
||||
- APT_INSTALL=clang
|
||||
- env:
|
||||
- BUILD_SCRIPT=windows_docker.sh
|
||||
- QT_SELECT=qt5-x86_64-w64-mingw32
|
||||
- RELEASE_LABEL="Windows 64-Bit Portable"
|
||||
- env:
|
||||
- BUILD_SCRIPT=wininstall_docker.sh
|
||||
- QT_SELECT=qt5-x86_64-w64-mingw32
|
||||
- RELEASE_LABEL="Windows 64-Bit Installer"
|
||||
- os: osx
|
||||
osx_image: xcode14.2
|
||||
env:
|
||||
- BUILD_SCRIPT=osx_ci.sh
|
||||
- RELEASE_LABEL="Mac OS X 64-Bit Disk Image"
|
||||
|
||||
before_install:
|
||||
- ".travis/source.sh"
|
||||
|
||||
script:
|
||||
- ".travis/travis.sh"
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: o7VneEz1aHfdVwZvOZLfopf6uJWNrFsZaBvunTmXFzpmNFhlNS1qwqgMUkIA2yBRbZ3wIzVs4vfwIHv7W9yE/PqK+AYL+R8+AwKGrwlgT4HqJNuk6VM/LNJ6GwT/qkQuaoOVw29bUjmzzgIRdHmw53SlJv6Hh1VE8HphlTT//aex6nCfcFhUZ0BETdZDWz5FSHwL3NalUoqfKfQrJeky5RXzCyCANQC2tKt0bV46GaWIgWrDo2KCTNqPtRWWf5GDmnkXE5IYRMQ3mXvO9iYh0v5Y2jo4PiXGUiFUU6Z3aAWFAiPdGclrBO697cf3lCTzDMhuCETR153qFYsLShUlFf61ITAmCeHAWETjZDri0lmPONo3GoNB6alGfYEA51qw14kXakrTpICtTJj7gw/gtUYOabW6hrzmieNzMBIy62RikDPjyakFnuwW2qNHRlD65e0jYv+6nCpb6E+OV16Ysh1zhV2vTfpfzVmSuyu2J+ELqXD3OZCXRSPpDIih9UQ8335p8FBji6jHORcgym/TRgdgRmENibh8tLzWp+UjpWHuWfcpvZgOskjfwU0iDMCayMJ7tDpOhXHcAhDRnd6XRIiOJ5YZCzflj2nEwmt3YUd7DwXS/AU+WHOmcNQBjXBxF/FJa35XXcy3HKJM5TTKqtph3medo30us5yXHeG6NNg=
|
||||
label: ${RELEASE_LABEL}
|
||||
file_glob: true
|
||||
file: assets/*
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
BIN
.travis/TelemetryClassAuthenticator.cpp.enc
Normal file
BIN
.travis/TelemetryClassAuthenticator.cpp.enc
Normal file
Binary file not shown.
1
.travis/dropbox_uploader.enc
Normal file
1
.travis/dropbox_uploader.enc
Normal file
|
@ -0,0 +1 @@
|
|||
Poァ鏖<EFBFBD>劾ラ<作1x」%几<>ャネw|RtZv<>kホ銓顴Z肄2チ廁湮ォ`<1A>ム,4vヨマ・@<>ヲeハ・~U$+<2B><><EFBFBD><1A><牾&蓬熙
|
5
.travis/source.sh
Executable file
5
.travis/source.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
rm -rf tmext/TelemetryClassAuthenticator.cpp && \
|
||||
openssl aes-256-cbc -K $encrypted_db000a5d87d6_key -iv $encrypted_db000a5d87d6_iv -in .travis/TelemetryClassAuthenticator.cpp.enc -out tmext/TelemetryClassAuthenticator.cpp -d && \
|
||||
openssl aes-256-cbc -K $encrypted_d57e7d2f8877_key -iv $encrypted_d57e7d2f8877_iv -in .travis/dropbox_uploader.enc -out ~/.dropbox_uploader -d
|
27
.travis/travis.sh
Executable file
27
.travis/travis.sh
Executable file
|
@ -0,0 +1,27 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Install lua
|
||||
if [ "${TRAVIS_OS_NAME}" == "osx" ]; then
|
||||
brew install lua
|
||||
else
|
||||
sudo apt-get update -qq && \
|
||||
sudo apt-get install -qq lua5.2
|
||||
fi
|
||||
|
||||
# Check if build is not tagged
|
||||
if [ "${TRAVIS_TAG}" == "" ]; then
|
||||
export EXECUTABLE_TAG=-$(git rev-parse --short HEAD)
|
||||
else
|
||||
export EXECUTABLE_TAG=
|
||||
fi
|
||||
|
||||
# Check if package code is not set
|
||||
if [ "${PACKAGE_CODE}" == "" ]; then
|
||||
export PACKAGE_CODE=GitHub
|
||||
fi
|
||||
|
||||
# Init Application Commit Hash
|
||||
export APPLICATION_COMMIT=$(git rev-parse --short HEAD)
|
||||
|
||||
# Start CI script
|
||||
.ci/ci.sh
|
8
.travis/ubuntu_travis.sh
Executable file
8
.travis/ubuntu_travis.sh
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Install packages
|
||||
sudo .ci/debian_install.sh && \
|
||||
|
||||
# Build gta5view
|
||||
sudo .ci/debian_build.sh && \
|
||||
cd ${PROJECT_DIR}
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2016-2023 Syping
|
||||
* Copyright (C) 2016-2021 Syping
|
||||
*
|
||||
* 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
|
||||
|
@ -29,7 +29,11 @@ AboutDialog::AboutDialog(QWidget *parent) :
|
|||
ui(new Ui::AboutDialog)
|
||||
{
|
||||
// Set Window Flags
|
||||
#if QT_VERSION >= 0x050900
|
||||
setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
#else
|
||||
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||
#endif
|
||||
|
||||
// Build Strings
|
||||
QString appVersion = QApplication::applicationVersion();
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2016-2023 Syping
|
||||
* Copyright (C) 2016-2021 Syping
|
||||
*
|
||||
* 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
|
||||
|
@ -51,25 +51,21 @@ QString AppEnv::getBuildCode()
|
|||
|
||||
// Folder Stuff
|
||||
|
||||
QString AppEnv::getGTAVFolder(bool *ok)
|
||||
QString AppEnv::getGameFolder(bool *ok)
|
||||
{
|
||||
QDir dir;
|
||||
QString GTAV_FOLDER = QString::fromUtf8(qgetenv("GTAV_FOLDER"));
|
||||
if (!GTAV_FOLDER.isEmpty()) {
|
||||
if (GTAV_FOLDER != "") {
|
||||
dir.setPath(GTAV_FOLDER);
|
||||
if (dir.exists()) {
|
||||
if (ok)
|
||||
if (ok != NULL)
|
||||
*ok = true;
|
||||
qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8());
|
||||
return dir.absolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
// TODO: Try to locate the Steam Proton GTA V folder
|
||||
const QString GTAV_defaultFolder = StandardPaths::documentsLocation() % "/Rockstar Games/GTA V";
|
||||
#else
|
||||
const QString GTAV_defaultFolder = StandardPaths::documentsLocation() % "/Rockstar Games/GTA V";
|
||||
#endif
|
||||
QString GTAV_returnFolder = GTAV_defaultFolder;
|
||||
|
||||
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||
|
@ -78,100 +74,48 @@ QString AppEnv::getGTAVFolder(bool *ok)
|
|||
GTAV_returnFolder = settings.value("dir", GTAV_defaultFolder).toString();
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup("GameDirectory");
|
||||
settings.beginGroup("GTA V");
|
||||
forceDir = settings.value("ForceCustom", forceDir).toBool();
|
||||
GTAV_returnFolder = settings.value("Directory", GTAV_returnFolder).toString();
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
|
||||
if (forceDir) {
|
||||
dir.setPath(GTAV_returnFolder);
|
||||
if (dir.exists()) {
|
||||
if (ok)
|
||||
if (ok != 0)
|
||||
*ok = true;
|
||||
qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8());
|
||||
return dir.absolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
dir.setPath(GTAV_defaultFolder);
|
||||
if (dir.exists()) {
|
||||
if (ok)
|
||||
if (ok != 0)
|
||||
*ok = true;
|
||||
qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8());
|
||||
return dir.absolutePath();
|
||||
}
|
||||
|
||||
if (!forceDir) {
|
||||
dir.setPath(GTAV_returnFolder);
|
||||
if (dir.exists()) {
|
||||
if (ok)
|
||||
if (ok != 0)
|
||||
*ok = true;
|
||||
qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8());
|
||||
return dir.absolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
if (ok != 0)
|
||||
*ok = false;
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString AppEnv::getRDR2Folder(bool *ok)
|
||||
bool AppEnv::setGameFolder(QString gameFolder)
|
||||
{
|
||||
QDir dir;
|
||||
QString RDR2_FOLDER = QString::fromUtf8(qgetenv("RDR2_FOLDER"));
|
||||
if (!RDR2_FOLDER.isEmpty()) {
|
||||
dir.setPath(RDR2_FOLDER);
|
||||
if (dir.exists()) {
|
||||
if (ok)
|
||||
*ok = true;
|
||||
return dir.absolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
// TODO: Try to locate the Steam Proton RDR 2 folder
|
||||
const QString RDR2_defaultFolder = StandardPaths::documentsLocation() % "/Rockstar Games/Red Dead Redemption 2";
|
||||
#else
|
||||
const QString RDR2_defaultFolder = StandardPaths::documentsLocation() % "/Rockstar Games/Red Dead Redemption 2";
|
||||
#endif
|
||||
QString RDR2_returnFolder = RDR2_defaultFolder;
|
||||
|
||||
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||
settings.beginGroup("GameDirectory");
|
||||
settings.beginGroup("RDR 2");
|
||||
bool forceDir = settings.value("ForceCustom", false).toBool();
|
||||
RDR2_returnFolder = settings.value("Directory", RDR2_defaultFolder).toString();
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
|
||||
if (forceDir) {
|
||||
dir.setPath(RDR2_returnFolder);
|
||||
if (dir.exists()) {
|
||||
if (ok)
|
||||
*ok = true;
|
||||
return dir.absolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
dir.setPath(RDR2_defaultFolder);
|
||||
dir.setPath(gameFolder);
|
||||
if (dir.exists()) {
|
||||
if (ok)
|
||||
*ok = true;
|
||||
return dir.absolutePath();
|
||||
qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!forceDir) {
|
||||
dir.setPath(RDR2_returnFolder);
|
||||
if (dir.exists()) {
|
||||
if (ok)
|
||||
*ok = true;
|
||||
return dir.absolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
*ok = false;
|
||||
return QString();
|
||||
return false;
|
||||
}
|
||||
|
||||
QString AppEnv::getExLangFolder()
|
||||
|
@ -223,7 +167,33 @@ QString AppEnv::getShareFolder()
|
|||
|
||||
QByteArray AppEnv::getUserAgent()
|
||||
{
|
||||
#if QT_VERSION >= 0x050400
|
||||
#ifdef Q_OS_WIN
|
||||
QString kernelVersion = QSysInfo::kernelVersion();
|
||||
const QStringList &kernelVersionList = kernelVersion.split(".");
|
||||
if (kernelVersionList.length() > 2) {
|
||||
kernelVersion = kernelVersionList.at(0) % "." % kernelVersionList.at(1);
|
||||
}
|
||||
QString runArch = QSysInfo::buildCpuArchitecture();
|
||||
if (runArch == "x86_64") {
|
||||
runArch = "Win64; x64";
|
||||
}
|
||||
else if (runArch == "i686") {
|
||||
const QString &curArch = QSysInfo::currentCpuArchitecture();
|
||||
if (curArch == "x86_64") {
|
||||
runArch = "WOW64";
|
||||
}
|
||||
else if (curArch == "i686") {
|
||||
runArch = "Win32; x86";
|
||||
}
|
||||
}
|
||||
return QString("Mozilla/5.0 (Windows NT %1; %2) %3/%4").arg(kernelVersion, runArch, GTA5SYNC_APPSTR, GTA5SYNC_APPVER).toUtf8();
|
||||
#else
|
||||
return QString("Mozilla/5.0 (%1; %2) %3/%4").arg(QSysInfo::kernelType(), QSysInfo::kernelVersion(), GTA5SYNC_APPSTR, GTA5SYNC_APPVER).toUtf8();
|
||||
#endif
|
||||
#else
|
||||
return QString("Mozilla/5.0 %1/%2").arg(GTA5SYNC_APPSTR, GTA5SYNC_APPVER).toUtf8();
|
||||
#endif
|
||||
}
|
||||
|
||||
QUrl AppEnv::getCrewFetchingUrl(QString crewID)
|
||||
|
@ -243,7 +213,7 @@ QUrl AppEnv::getPlayerFetchingUrl(QString crewID, int pageNumber)
|
|||
|
||||
// Game Stuff
|
||||
|
||||
GameVersion AppEnv::getGTAVVersion()
|
||||
GameVersion AppEnv::getGameVersion()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
QString argumentValue;
|
||||
|
@ -292,7 +262,7 @@ GameVersion AppEnv::getGTAVVersion()
|
|||
#endif
|
||||
}
|
||||
|
||||
GameLanguage AppEnv::getGTAVLanguage(GameVersion gameVersion)
|
||||
GameLanguage AppEnv::getGameLanguage(GameVersion gameVersion)
|
||||
{
|
||||
if (gameVersion == GameVersion::SocialClubVersion) {
|
||||
#ifdef Q_OS_WIN
|
||||
|
@ -399,11 +369,77 @@ QString AppEnv::gameLanguageToString(GameLanguage gameLanguage)
|
|||
}
|
||||
}
|
||||
|
||||
bool AppEnv::setGameLanguage(GameVersion gameVersion, GameLanguage gameLanguage)
|
||||
{
|
||||
bool socialClubVersion = false;
|
||||
bool steamVersion = false;
|
||||
if (gameVersion == GameVersion::SocialClubVersion) {
|
||||
socialClubVersion = true;
|
||||
}
|
||||
else if (gameVersion == GameVersion::SteamVersion) {
|
||||
steamVersion = true;
|
||||
}
|
||||
else if (gameVersion == GameVersion::BothVersions) {
|
||||
socialClubVersion = true;
|
||||
steamVersion = true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
if (socialClubVersion) {
|
||||
#ifdef Q_OS_WIN
|
||||
QString argumentValue;
|
||||
#ifdef _WIN64
|
||||
argumentValue = "\\WOW6432Node";
|
||||
#endif
|
||||
QSettings registrySettingsSc(QString("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\Rockstar Games\\Grand Theft Auto V").arg(argumentValue), QSettings::NativeFormat);
|
||||
if (gameLanguage != GameLanguage::Undefined) {
|
||||
registrySettingsSc.setValue("Language", gameLanguageToString(gameLanguage));
|
||||
}
|
||||
else {
|
||||
registrySettingsSc.remove("Language");
|
||||
}
|
||||
registrySettingsSc.sync();
|
||||
if (registrySettingsSc.status() != QSettings::NoError) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(gameLanguage)
|
||||
#endif
|
||||
}
|
||||
if (steamVersion) {
|
||||
#ifdef Q_OS_WIN
|
||||
QString argumentValue;
|
||||
#ifdef _WIN64
|
||||
argumentValue = "\\WOW6432Node";
|
||||
#endif
|
||||
QSettings registrySettingsSteam(QString("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\Rockstar Games\\Grand Theft Auto V Steam").arg(argumentValue), QSettings::NativeFormat);
|
||||
if (gameLanguage != GameLanguage::Undefined) {
|
||||
registrySettingsSteam.setValue("Language", gameLanguageToString(gameLanguage));
|
||||
}
|
||||
else {
|
||||
registrySettingsSteam.remove("Language");
|
||||
}
|
||||
registrySettingsSteam.sync();
|
||||
if (registrySettingsSteam.status() != QSettings::NoError) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(gameLanguage)
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Screen Stuff
|
||||
|
||||
qreal AppEnv::screenRatio()
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
qreal dpi = QApplication::primaryScreen()->logicalDotsPerInch();
|
||||
#else
|
||||
qreal dpi = QApplication::desktop()->logicalDpiX();
|
||||
#endif
|
||||
#ifdef Q_OS_MAC
|
||||
return (dpi / 72);
|
||||
#else
|
||||
|
@ -413,5 +449,9 @@ qreal AppEnv::screenRatio()
|
|||
|
||||
qreal AppEnv::screenRatioPR()
|
||||
{
|
||||
#if QT_VERSION >= 0x050600
|
||||
return QApplication::primaryScreen()->devicePixelRatio();
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2016-2023 Syping
|
||||
* Copyright (C) 2016-2021 Syping
|
||||
*
|
||||
* 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
|
||||
|
@ -35,8 +35,8 @@ public:
|
|||
static QString getBuildCode();
|
||||
|
||||
// Folder Stuff
|
||||
static QString getGTAVFolder(bool *ok = 0);
|
||||
static QString getRDR2Folder(bool *ok = 0);
|
||||
static QString getGameFolder(bool *ok = 0);
|
||||
static bool setGameFolder(QString gameFolder);
|
||||
static QString getExLangFolder();
|
||||
static QString getInLangFolder();
|
||||
static QString getImagesFolder();
|
||||
|
@ -50,10 +50,11 @@ public:
|
|||
static QUrl getPlayerFetchingUrl(QString crewID, int pageNumber);
|
||||
|
||||
// Game Stuff
|
||||
static GameVersion getGTAVVersion();
|
||||
static GameLanguage getGTAVLanguage(GameVersion gameVersion);
|
||||
static GameVersion getGameVersion();
|
||||
static GameLanguage getGameLanguage(GameVersion gameVersion);
|
||||
static GameLanguage gameLanguageFromString(QString gameLanguage);
|
||||
static QString gameLanguageToString(GameLanguage gameLanguage);
|
||||
static bool setGameLanguage(GameVersion gameVersion, GameLanguage gameLanguage);
|
||||
|
||||
// Screen Stuff
|
||||
static qreal screenRatio();
|
253
CMakeLists.txt
253
CMakeLists.txt
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.7)
|
||||
|
||||
project(gta5view VERSION 1.11.0 LANGUAGES C CXX)
|
||||
project(gta5view LANGUAGES C CXX)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
|
@ -8,7 +8,7 @@ set(CMAKE_AUTOUIC ON)
|
|||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17 CACHE STRING "gta5view C++ standard")
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(FORCE_QT_VERSION "" CACHE STRING "Force Qt Version")
|
||||
|
@ -20,9 +20,6 @@ endif()
|
|||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Network Svg Widgets REQUIRED)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS LinguistTools QUIET)
|
||||
|
||||
set(RAGEPHOTO_STATIC ON CACHE BOOL "Build libragephoto as static library")
|
||||
add_subdirectory(src/libragephoto)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND GTA5VIEW_LIBS
|
||||
dwmapi
|
||||
|
@ -41,7 +38,7 @@ if(APPLE)
|
|||
res/gta5view.icns
|
||||
)
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME gta5view)
|
||||
set(MACOSX_BUNDLE_BUNDLE_VERSION ${gta5view_VERSION})
|
||||
set(MACOSX_BUNDLE_BUNDLE_VERSION 1.10.2)
|
||||
set(MACOSX_BUNDLE_ICON_FILE gta5view.icns)
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER de.syping.gta5view)
|
||||
set_source_files_properties(res/gta5view.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||
|
@ -53,107 +50,111 @@ list(APPEND GTA5VIEW_DEFINES
|
|||
)
|
||||
|
||||
set(GTA5VIEW_SOURCES
|
||||
src/main.cpp
|
||||
src/AboutDialog.cpp
|
||||
src/AppEnv.cpp
|
||||
src/CrewDatabase.cpp
|
||||
src/DatabaseThread.cpp
|
||||
src/ExportDialog.cpp
|
||||
src/ExportThread.cpp
|
||||
src/GlobalString.cpp
|
||||
src/IconLoader.cpp
|
||||
src/ImportDialog.cpp
|
||||
src/JsonEditorDialog.cpp
|
||||
src/MapLocationDialog.cpp
|
||||
src/OptionsDialog.cpp
|
||||
src/PictureDialog.cpp
|
||||
src/PictureExport.cpp
|
||||
src/PictureWidget.cpp
|
||||
src/PlayerListDialog.cpp
|
||||
src/ProfileDatabase.cpp
|
||||
src/ProfileInterface.cpp
|
||||
src/ProfileLoader.cpp
|
||||
src/ProfileWidget.cpp
|
||||
src/SavegameCopy.cpp
|
||||
src/SavegameData.cpp
|
||||
src/SavegameDialog.cpp
|
||||
src/SavegameWidget.cpp
|
||||
src/SnapmaticEditor.cpp
|
||||
src/SnapmaticJson.cpp
|
||||
src/SnapmaticPicture.cpp
|
||||
src/SnapmaticWidget.cpp
|
||||
src/StandardPaths.cpp
|
||||
src/StringParser.cpp
|
||||
src/TranslationClass.cpp
|
||||
src/UserInterface.cpp
|
||||
src/pcg/pcg_basic.c
|
||||
src/uimod/JSHighlighter.cpp
|
||||
src/uimod/UiModLabel.cpp
|
||||
src/uimod/UiModWidget.cpp
|
||||
main.cpp
|
||||
AboutDialog.cpp
|
||||
AppEnv.cpp
|
||||
CrewDatabase.cpp
|
||||
DatabaseThread.cpp
|
||||
ExportDialog.cpp
|
||||
ExportThread.cpp
|
||||
GlobalString.cpp
|
||||
IconLoader.cpp
|
||||
ImportDialog.cpp
|
||||
JsonEditorDialog.cpp
|
||||
MapLocationDialog.cpp
|
||||
OptionsDialog.cpp
|
||||
PictureDialog.cpp
|
||||
PictureExport.cpp
|
||||
PictureWidget.cpp
|
||||
PlayerListDialog.cpp
|
||||
ProfileDatabase.cpp
|
||||
ProfileInterface.cpp
|
||||
ProfileLoader.cpp
|
||||
ProfileWidget.cpp
|
||||
RagePhoto.cpp
|
||||
SavegameCopy.cpp
|
||||
SavegameData.cpp
|
||||
SavegameDialog.cpp
|
||||
SavegameWidget.cpp
|
||||
SidebarGenerator.cpp
|
||||
SnapmaticEditor.cpp
|
||||
SnapmaticPicture.cpp
|
||||
SnapmaticWidget.cpp
|
||||
StandardPaths.cpp
|
||||
StringParser.cpp
|
||||
TranslationClass.cpp
|
||||
UserInterface.cpp
|
||||
anpro/imagecropper.cpp
|
||||
pcg/pcg_basic.c
|
||||
uimod/JSHighlighter.cpp
|
||||
uimod/UiModLabel.cpp
|
||||
uimod/UiModWidget.cpp
|
||||
)
|
||||
|
||||
set(GTA5VIEW_HEADERS
|
||||
src/config.h
|
||||
src/AboutDialog.h
|
||||
src/AppEnv.h
|
||||
src/CrewDatabase.h
|
||||
src/DatabaseThread.h
|
||||
src/ExportDialog.h
|
||||
src/ExportThread.h
|
||||
src/GlobalString.h
|
||||
src/IconLoader.h
|
||||
src/ImportDialog.h
|
||||
src/JsonEditorDialog.h
|
||||
src/MapLocationDialog.h
|
||||
src/OptionsDialog.h
|
||||
src/PictureDialog.h
|
||||
src/PictureExport.h
|
||||
src/PictureWidget.h
|
||||
src/PlayerListDialog.h
|
||||
src/ProfileDatabase.h
|
||||
src/ProfileInterface.h
|
||||
src/ProfileLoader.h
|
||||
src/ProfileWidget.h
|
||||
src/SavegameCopy.h
|
||||
src/SavegameData.h
|
||||
src/SavegameDialog.h
|
||||
src/SavegameWidget.h
|
||||
src/SnapmaticEditor.h
|
||||
src/SnapmaticJson.h
|
||||
src/SnapmaticPicture.h
|
||||
src/SnapmaticWidget.h
|
||||
src/StandardPaths.h
|
||||
src/StringParser.h
|
||||
src/TranslationClass.h
|
||||
src/UserInterface.h
|
||||
src/pcg/pcg_basic.h
|
||||
src/uimod/JSHighlighter.h
|
||||
src/uimod/UiModLabel.h
|
||||
src/uimod/UiModWidget.h
|
||||
config.h
|
||||
wrapper.h
|
||||
AboutDialog.h
|
||||
AppEnv.h
|
||||
CrewDatabase.h
|
||||
DatabaseThread.h
|
||||
ExportDialog.h
|
||||
ExportThread.h
|
||||
GlobalString.h
|
||||
IconLoader.h
|
||||
ImportDialog.h
|
||||
JsonEditorDialog.h
|
||||
MapLocationDialog.h
|
||||
OptionsDialog.h
|
||||
PictureDialog.h
|
||||
PictureExport.h
|
||||
PictureWidget.h
|
||||
PlayerListDialog.h
|
||||
ProfileDatabase.h
|
||||
ProfileInterface.h
|
||||
ProfileLoader.h
|
||||
ProfileWidget.h
|
||||
RagePhoto.h
|
||||
SavegameCopy.h
|
||||
SavegameData.h
|
||||
SavegameDialog.h
|
||||
SavegameWidget.h
|
||||
SidebarGenerator.h
|
||||
SnapmaticEditor.h
|
||||
SnapmaticPicture.h
|
||||
SnapmaticWidget.h
|
||||
StandardPaths.h
|
||||
StringParser.h
|
||||
TranslationClass.h
|
||||
UserInterface.h
|
||||
anpro/imagecropper.h
|
||||
pcg/pcg_basic.h
|
||||
uimod/JSHighlighter.h
|
||||
uimod/UiModLabel.h
|
||||
uimod/UiModWidget.h
|
||||
)
|
||||
|
||||
set(GTA5VIEW_INCLUDEDIR
|
||||
src
|
||||
src/anpro
|
||||
src/pcg
|
||||
src/uimod
|
||||
anpro
|
||||
pcg
|
||||
uimod
|
||||
)
|
||||
|
||||
set(GTA5VIEW_FORMS
|
||||
src/AboutDialog.ui
|
||||
src/ExportDialog.ui
|
||||
src/ImportDialog.ui
|
||||
src/JsonEditorDialog.ui
|
||||
src/MapLocationDialog.ui
|
||||
src/OptionsDialog.ui
|
||||
src/PictureDialog.ui
|
||||
src/PlayerListDialog.ui
|
||||
src/ProfileInterface.ui
|
||||
src/SavegameDialog.ui
|
||||
src/SavegameWidget.ui
|
||||
src/SnapmaticEditor.ui
|
||||
src/SnapmaticWidget.ui
|
||||
src/UserInterface.ui
|
||||
AboutDialog.ui
|
||||
ExportDialog.ui
|
||||
ImportDialog.ui
|
||||
JsonEditorDialog.ui
|
||||
MapLocationDialog.ui
|
||||
OptionsDialog.ui
|
||||
PictureDialog.ui
|
||||
PlayerListDialog.ui
|
||||
ProfileInterface.ui
|
||||
SavegameDialog.ui
|
||||
SavegameWidget.ui
|
||||
SnapmaticEditor.ui
|
||||
SnapmaticWidget.ui
|
||||
UserInterface.ui
|
||||
)
|
||||
|
||||
set(GTA5VIEW_TRANSLATIONS
|
||||
|
@ -168,6 +169,7 @@ set(GTA5VIEW_TRANSLATIONS
|
|||
|
||||
list(APPEND GTA5VIEW_RESOURCES
|
||||
res/global.qrc
|
||||
res/template.qrc
|
||||
)
|
||||
set_property(SOURCE res/global.qrc PROPERTY AUTORCC_OPTIONS "-threshold;0;-compress;9")
|
||||
|
||||
|
@ -216,45 +218,14 @@ if(FLATPAK_BUILD)
|
|||
)
|
||||
endif()
|
||||
|
||||
option(RAGEPHOTO_ABI_WRAPPER "Use libragephoto's ABI wrapper" OFF)
|
||||
if(RAGEPHOTO_ABI_WRAPPER)
|
||||
set(RAGEPHOTO_C_API ON CACHE BOOL "Build libragephoto with C API support" FORCE)
|
||||
list(APPEND GTA5VIEW_DEFINES
|
||||
-DRAGEPHOTO_USE_ABI_WRAPPER
|
||||
)
|
||||
endif()
|
||||
|
||||
option(WITH_BOOST "Use linked Boost library" OFF)
|
||||
if(WITH_BOOST)
|
||||
find_package(Boost REQUIRED
|
||||
COMPONENTS json
|
||||
)
|
||||
list(APPEND GTA5VIEW_LIBS
|
||||
Boost::json
|
||||
)
|
||||
list(APPEND GTA5VIEW_DEFINES
|
||||
-DGTA5SYNC_BOOST
|
||||
)
|
||||
list(APPEND GTA5VIEW_INCLUDEDIR
|
||||
${Boost_INCLUDE_DIRS}
|
||||
)
|
||||
else()
|
||||
list(APPEND GTA5VIEW_DEFINES
|
||||
-DBOOST_JSON_STANDALONE
|
||||
)
|
||||
list(APPEND GTA5VIEW_INCLUDEDIR
|
||||
src/json/include
|
||||
)
|
||||
endif()
|
||||
|
||||
option(WITH_DONATE "Donate menu option and donation dialog" OFF)
|
||||
if(WITH_DONATE)
|
||||
set(DONATE_ADDRESSES "" CACHE STRING "Donation addresses")
|
||||
list(APPEND GTA5VIEW_HEADERS
|
||||
src/anpro/QrCode.h
|
||||
anpro/QrCode.h
|
||||
)
|
||||
list(APPEND GTA5VIEW_SOURCES
|
||||
src/anpro/QrCode.cpp
|
||||
anpro/QrCode.cpp
|
||||
)
|
||||
list(APPEND GTA5VIEW_DEFINES
|
||||
-DGTA5SYNC_DONATE
|
||||
|
@ -273,10 +244,10 @@ option(WITH_MOTD "Developer message system directed to users" OFF)
|
|||
if(WITH_MOTD)
|
||||
set(MOTD_WEBURL "" CACHE STRING "Messages WebURL")
|
||||
list(APPEND GTA5VIEW_HEADERS
|
||||
src/MessageThread.h
|
||||
MessageThread.h
|
||||
)
|
||||
list(APPEND GTA5VIEW_SOURCES
|
||||
src/MessageThread.cpp
|
||||
MessageThread.cpp
|
||||
)
|
||||
list(APPEND GTA5VIEW_DEFINES
|
||||
-DGTA5SYNC_MOTD
|
||||
|
@ -296,15 +267,15 @@ if(WITH_TELEMETRY)
|
|||
set(TELEMETRY_REGURL "" CACHE STRING "Telemetry RegURL")
|
||||
set(TELEMETRY_WEBURL "" CACHE STRING "Telemetry WebURL")
|
||||
list(APPEND GTA5VIEW_HEADERS
|
||||
src/TelemetryClass.h
|
||||
src/tmext/TelemetryClassAuthenticator.h
|
||||
TelemetryClass.h
|
||||
tmext/TelemetryClassAuthenticator.h
|
||||
)
|
||||
list(APPEND GTA5VIEW_SOURCES
|
||||
src/TelemetryClass.cpp
|
||||
src/tmext/TelemetryClassAuthenticator.cpp
|
||||
TelemetryClass.cpp
|
||||
tmext/TelemetryClassAuthenticator.cpp
|
||||
)
|
||||
list(APPEND GTA5VIEW_INCLUDEDIR
|
||||
src/tmext
|
||||
tmext
|
||||
)
|
||||
list(APPEND GTA5VIEW_DEFINES
|
||||
-DGTA5SYNC_TELEMETRY
|
||||
|
@ -380,7 +351,7 @@ if(LINGUIST_FOUND AND QCONF_BUILD)
|
|||
endif()
|
||||
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.16.0")
|
||||
target_precompile_headers(gta5view PRIVATE src/config.h)
|
||||
target_precompile_headers(gta5view PRIVATE config.h)
|
||||
endif()
|
||||
|
||||
if(Qt5Core_VERSION VERSION_GREATER_EQUAL "5.14.0")
|
||||
|
@ -388,8 +359,8 @@ if(Qt5Core_VERSION VERSION_GREATER_EQUAL "5.14.0")
|
|||
endif()
|
||||
|
||||
target_compile_definitions(gta5view PRIVATE ${GTA5VIEW_DEFINES})
|
||||
target_include_directories(gta5view PRIVATE ${GTA5VIEW_INCLUDEDIR} ${RAGEPHOTO_INCLUDE_DIRS})
|
||||
target_link_libraries(gta5view PRIVATE Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Svg Qt${QT_VERSION_MAJOR}::Widgets ragephoto ${GTA5VIEW_LIBS})
|
||||
target_include_directories(gta5view PRIVATE ${GTA5VIEW_INCLUDEDIR})
|
||||
target_link_libraries(gta5view PRIVATE Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Svg Qt${QT_VERSION_MAJOR}::Widgets ${GTA5VIEW_LIBS})
|
||||
|
||||
install(TARGETS gta5view DESTINATION bin)
|
||||
install(FILES res/de.syping.gta5view.desktop DESTINATION share/applications)
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include "config.h"
|
||||
#include <QStringBuilder>
|
||||
#include <QApplication>
|
||||
#include <QSaveFile>
|
||||
#include <QFileInfo>
|
||||
#include <QFile>
|
||||
|
||||
|
@ -36,56 +35,131 @@
|
|||
#include <QDesktopWidget>
|
||||
#endif
|
||||
|
||||
ExportThread::ExportThread(QHash<ProfileWidget*,QString> profileMap, QString exportDirectory, bool pictureCopyEnabled, bool pictureExportEnabled, int exportCount, QObject *parent) : QThread(parent),
|
||||
ExportThread::ExportThread(QMap<ProfileWidget*,QString> profileMap, QString exportDirectory, bool pictureCopyEnabled, bool pictureExportEnabled, int exportCount, QObject *parent) : QThread(parent),
|
||||
profileMap(profileMap), exportDirectory(exportDirectory), pictureCopyEnabled(pictureCopyEnabled), pictureExportEnabled(pictureExportEnabled), exportCount(exportCount)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ExportThread::run()
|
||||
{
|
||||
size_t intExportProgress = 0;
|
||||
for (ProfileWidget *widget : profileMap.keys()) {
|
||||
if (widget->isSelected()) {
|
||||
if (widget->getWidgetType() == "SnapmaticWidget") {
|
||||
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||
|
||||
// Picture Settings
|
||||
// Quality Settings
|
||||
settings.beginGroup("Pictures");
|
||||
int defaultQuality = 100;
|
||||
QSize defExportSize = SnapmaticPicture::getSnapmaticResolution();
|
||||
int customQuality = settings.value("CustomQuality", defaultQuality).toInt();
|
||||
if (customQuality < 1 || customQuality > 100)
|
||||
{
|
||||
customQuality = 100;
|
||||
}
|
||||
bool useCustomQuality = settings.value("CustomQualityEnabled", false).toBool();
|
||||
|
||||
// Size Settings
|
||||
QSize cusExportSize = settings.value("CustomSize", defExportSize).toSize();
|
||||
if (cusExportSize.width() > 3840)
|
||||
{
|
||||
cusExportSize.setWidth(3840);
|
||||
}
|
||||
else if (cusExportSize.height() > 2160)
|
||||
{
|
||||
cusExportSize.setHeight(2160);
|
||||
}
|
||||
if (cusExportSize.width() < 1)
|
||||
{
|
||||
cusExportSize.setWidth(1);
|
||||
}
|
||||
else if (cusExportSize.height() < 1)
|
||||
{
|
||||
cusExportSize.setHeight(1);
|
||||
}
|
||||
QString sizeMode = settings.value("ExportSizeMode", "Default").toString();
|
||||
Qt::AspectRatioMode aspectRatio = (Qt::AspectRatioMode)settings.value("AspectRatio", Qt::KeepAspectRatio).toInt();
|
||||
settings.endGroup();
|
||||
// End Picture Settings
|
||||
|
||||
int intExportProgress = 0;
|
||||
for (ProfileWidget *widget : profileMap.keys())
|
||||
{
|
||||
if (widget->isSelected())
|
||||
{
|
||||
if (widget->getWidgetType() == "SnapmaticWidget")
|
||||
{
|
||||
SnapmaticWidget *picWidget = qobject_cast<SnapmaticWidget*>(widget);
|
||||
SnapmaticPicture *picture = picWidget->getPicture();
|
||||
|
||||
if (pictureExportEnabled) {
|
||||
if (pictureExportEnabled)
|
||||
{
|
||||
QString exportFileName = PictureExport::getPictureFileName(picture);
|
||||
if (!exportFileName.endsWith(".jpg"))
|
||||
if (exportFileName.right(4) != ".jpg" && exportFileName.right(4) != ".png")
|
||||
{
|
||||
exportFileName += ".jpg";
|
||||
}
|
||||
|
||||
intExportProgress++;
|
||||
emit exportStringUpdate(ProfileInterface::tr("Export file %1 of %2 files").arg(QString::number(intExportProgress), QString::number(exportCount)));
|
||||
emit exportProgressUpdate(intExportProgress);
|
||||
|
||||
bool isSaved = false;
|
||||
QSaveFile exportFile(exportDirectory % "/" % exportFileName);
|
||||
if (exportFile.open(QIODevice::WriteOnly)) {
|
||||
exportFile.write(picture->getPictureStream());
|
||||
isSaved = exportFile.commit();
|
||||
// Scale Picture
|
||||
QImage exportPicture = picture->getImage();
|
||||
if (sizeMode == "Desktop")
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
qreal screenRatioPR = AppEnv::screenRatioPR();
|
||||
QRect desktopResolution = QApplication::primaryScreen()->geometry();
|
||||
int desktopSizeWidth = qRound((double)desktopResolution.width() * screenRatioPR);
|
||||
int desktopSizeHeight = qRound((double)desktopResolution.height() * screenRatioPR);
|
||||
#else
|
||||
QRect desktopResolution = QApplication::desktop()->screenGeometry();
|
||||
int desktopSizeWidth = desktopResolution.width();
|
||||
int desktopSizeHeight = desktopResolution.height();
|
||||
#endif
|
||||
exportPicture = exportPicture.scaled(desktopSizeWidth, desktopSizeHeight, aspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
else if (sizeMode == "Custom")
|
||||
{
|
||||
exportPicture = exportPicture.scaled(cusExportSize, aspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
|
||||
bool isSaved;
|
||||
if (useCustomQuality)
|
||||
{
|
||||
isSaved = exportPicture.save(exportDirectory % "/" % exportFileName, "JPEG", customQuality);
|
||||
}
|
||||
else
|
||||
{
|
||||
isSaved = exportPicture.save(exportDirectory % "/" % exportFileName, "JPEG", 100);
|
||||
}
|
||||
|
||||
if (!isSaved)
|
||||
{
|
||||
failedExportPictures += exportFileName;
|
||||
}
|
||||
}
|
||||
if (pictureCopyEnabled) {
|
||||
if (pictureCopyEnabled)
|
||||
{
|
||||
QString exportFileName = PictureExport::getPictureFileName(picture);
|
||||
if (!exportFileName.endsWith(".g5e"))
|
||||
if (exportFileName.right(4) != ".g5e")
|
||||
{
|
||||
exportFileName += ".g5e";
|
||||
}
|
||||
|
||||
intExportProgress++;
|
||||
emit exportStringUpdate(ProfileInterface::tr("Export file %1 of %2 files").arg(QString::number(intExportProgress), QString::number(exportCount)));
|
||||
emit exportProgressUpdate(intExportProgress);
|
||||
|
||||
QString exportFilePath = exportDirectory % "/" % exportFileName;
|
||||
if (QFile::exists(exportFilePath))
|
||||
QFile::remove(exportFilePath);
|
||||
if (QFile::exists(exportFilePath)) {QFile::remove(exportFilePath);}
|
||||
if (!picture->exportPicture(exportDirectory % "/" % exportFileName, SnapmaticFormat::G5E_Format))
|
||||
{
|
||||
failedCopyPictures += exportFileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (widget->getWidgetType() == "SavegameWidget") {
|
||||
else if (widget->getWidgetType() == "SavegameWidget")
|
||||
{
|
||||
SavegameWidget *sgdWidget = qobject_cast<SavegameWidget*>(widget);
|
||||
SavegameData *savegame = sgdWidget->getSavegame();
|
||||
|
||||
|
@ -98,10 +172,11 @@ void ExportThread::run()
|
|||
emit exportProgressUpdate(intExportProgress);
|
||||
|
||||
QString exportFilePath = exportDirectory % "/" % exportFileName;
|
||||
if (QFile::exists(exportFilePath))
|
||||
QFile::remove(exportFilePath);
|
||||
if (QFile::exists(exportFilePath)) {QFile::remove(exportFilePath);}
|
||||
if (!QFile::copy(originalFileName, exportFilePath))
|
||||
{
|
||||
failedSavegames += exportFileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2016-2023 Syping
|
||||
* Copyright (C) 2016-2017 Syping
|
||||
*
|
||||
* 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
|
||||
|
@ -29,7 +29,7 @@ class ExportThread : public QThread
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ExportThread(QHash<ProfileWidget*,QString> profileMap, QString exportDirectory, bool pictureCopyEnabled, bool pictureExportEnabled, int exportCount, QObject *parent = 0);
|
||||
explicit ExportThread(QMap<ProfileWidget*,QString> profileMap, QString exportDirectory, bool pictureCopyEnabled, bool pictureExportEnabled, int exportCount, QObject *parent = 0);
|
||||
QStringList getFailedSavegames();
|
||||
QStringList getFailedCopyPictures();
|
||||
QStringList getFailedExportPictures();
|
||||
|
@ -38,7 +38,7 @@ protected:
|
|||
void run();
|
||||
|
||||
private:
|
||||
QHash<ProfileWidget*,QString> profileMap;
|
||||
QMap <ProfileWidget*, QString> profileMap;
|
||||
QString exportDirectory;
|
||||
bool pictureCopyEnabled;
|
||||
bool pictureExportEnabled;
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2017-2023 Syping
|
||||
* Copyright (C) 2017-2022 Syping
|
||||
*
|
||||
* 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,8 +18,10 @@
|
|||
|
||||
#include "ui_ImportDialog.h"
|
||||
#include "SnapmaticPicture.h"
|
||||
#include "SidebarGenerator.h"
|
||||
#include "StandardPaths.h"
|
||||
#include "ImportDialog.h"
|
||||
#include "imagecropper.h"
|
||||
#include "AppEnv.h"
|
||||
#include "config.h"
|
||||
#include <QStringBuilder>
|
||||
|
@ -47,7 +49,11 @@ ImportDialog::ImportDialog(QString profileName, QWidget *parent) :
|
|||
ui(new Ui::ImportDialog)
|
||||
{
|
||||
// Set Window Flags
|
||||
#if QT_VERSION >= 0x050900
|
||||
setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
#else
|
||||
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||
#endif
|
||||
|
||||
ui->setupUi(this);
|
||||
ui->cmdOK->setDefault(true);
|
||||
|
@ -82,12 +88,12 @@ ImportDialog::ImportDialog(QString profileName, QWidget *parent) :
|
|||
ui->cmdBackgroundWipe->setVisible(false);
|
||||
|
||||
// Snapmatic Resolution
|
||||
ui->cbResolution->addItem("GTA V (536p)", QSize(960, 536));
|
||||
ui->cbResolution->addItem("FiveM (1072p)", QSize(1920, 1072));
|
||||
ui->cbResolution->addItem("RDR 2 (1080p)", QSize(1920, 1080));
|
||||
ui->cbResolution->addItem("HD (720p)", QSize(1280, 720));
|
||||
ui->cbResolution->addItem("WQHD (1440p)", QSize(2560, 1440));
|
||||
ui->cbResolution->addItem("4K/UHD (2160p)", QSize(3840, 2160));
|
||||
snapmaticResolution = SnapmaticPicture::getSnapmaticResolution();
|
||||
ui->cbResolution->addItem("GTA V", snapmaticResolution);
|
||||
ui->cbResolution->addItem("FiveM", QSize(1920, 1072));
|
||||
ui->cbResolution->addItem("1280x720", QSize(1280, 720));
|
||||
ui->cbResolution->addItem("1920x1080", QSize(1920, 1080));
|
||||
ui->cbResolution->addItem("2560x1440", QSize(2560, 1440));
|
||||
|
||||
// Set Import Settings
|
||||
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||
|
@ -119,10 +125,11 @@ ImportDialog::ImportDialog(QString profileName, QWidget *parent) :
|
|||
#endif
|
||||
|
||||
// Options menu
|
||||
optionsMenu.addAction(tr("&Import new Picture..."), this, &ImportDialog::importNewPicture);
|
||||
optionsMenu.addAction(tr("&Import new Picture..."), this, SLOT(importNewPicture()));
|
||||
optionsMenu.addAction(tr("&Crop Picture..."), this, SLOT(cropPicture()));
|
||||
optionsMenu.addSeparator();
|
||||
optionsMenu.addAction(tr("&Load Settings..."), this, &ImportDialog::loadImportSettings);
|
||||
optionsMenu.addAction(tr("&Save Settings..."), this, &ImportDialog::saveImportSettings);
|
||||
optionsMenu.addAction(tr("&Load Settings..."), this, SLOT(loadImportSettings()));
|
||||
optionsMenu.addAction(tr("&Save Settings..."), this, SLOT(saveImportSettings()));
|
||||
ui->cmdOptions->setMenu(&optionsMenu);
|
||||
|
||||
const QSize windowSize = sizeHint();
|
||||
|
@ -368,7 +375,7 @@ void ImportDialog::processSettings(QString settingsProfile, bool setDefault)
|
|||
ui->cbForceAvatarColour->setChecked(settings.value("ForceAvatarColour", false).toBool());
|
||||
ui->cbUnlimited->setChecked(settings.value("UnlimitedBuffer", false).toBool());
|
||||
ui->cbImportAsIs->setChecked(settings.value("ImportAsIs", false).toBool());
|
||||
const QVariant data = settings.value("Resolution", QSize(960, 536));
|
||||
const QVariant data = settings.value("Resolution", SnapmaticPicture::getSnapmaticResolution());
|
||||
#if QT_VERSION >= 0x060000
|
||||
if (data.typeId() == QMetaType::QSize)
|
||||
#else
|
||||
|
@ -428,7 +435,7 @@ void ImportDialog::saveSettings(QString settingsProfile)
|
|||
settings.setValue("Resolution", data);
|
||||
}
|
||||
else {
|
||||
settings.setValue("Resolution", QSize(960, 536));
|
||||
settings.setValue("Resolution", SnapmaticPicture::getSnapmaticResolution());
|
||||
}
|
||||
settings.setValue("UnlimitedBuffer", ui->cbUnlimited->isChecked());
|
||||
settings.setValue("ImportAsIs", ui->cbImportAsIs->isChecked());
|
||||
|
@ -437,6 +444,72 @@ void ImportDialog::saveSettings(QString settingsProfile)
|
|||
settings.endGroup();
|
||||
}
|
||||
|
||||
void ImportDialog::cropPicture()
|
||||
{
|
||||
qreal screenRatio = AppEnv::screenRatio();
|
||||
|
||||
QDialog cropDialog(this);
|
||||
#if QT_VERSION >= 0x050000
|
||||
cropDialog.setObjectName(QStringLiteral("CropDialog"));
|
||||
#else
|
||||
cropDialog.setObjectName(QString::fromUtf8("CropDialog"));
|
||||
#endif
|
||||
cropDialog.setWindowTitle(tr("Crop Picture..."));
|
||||
cropDialog.setWindowFlags(cropDialog.windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||
cropDialog.setModal(true);
|
||||
|
||||
QVBoxLayout cropLayout;
|
||||
#if QT_VERSION >= 0x050000
|
||||
cropLayout.setObjectName(QStringLiteral("CropLayout"));
|
||||
#else
|
||||
cropLayout.setObjectName(QString::fromUtf8("CropLayout"));
|
||||
#endif
|
||||
cropLayout.setContentsMargins(0, 0, 0, 0);
|
||||
cropLayout.setSpacing(0);
|
||||
cropDialog.setLayout(&cropLayout);
|
||||
|
||||
ImageCropper imageCropper(&cropDialog);
|
||||
#if QT_VERSION >= 0x050000
|
||||
imageCropper.setObjectName(QStringLiteral("ImageCropper"));
|
||||
#else
|
||||
imageCropper.setObjectName(QString::fromUtf8("ImageCropper"));
|
||||
#endif
|
||||
imageCropper.setBackgroundColor(Qt::black);
|
||||
imageCropper.setCroppingRectBorderColor(QColor(255, 255, 255, 127));
|
||||
imageCropper.setImage(QPixmap::fromImage(origImage, Qt::AutoColor));
|
||||
imageCropper.setProportion(QSize(1, 1));
|
||||
imageCropper.setFixedSize(workImage.size());
|
||||
cropLayout.addWidget(&imageCropper);
|
||||
|
||||
QHBoxLayout buttonLayout;
|
||||
#if QT_VERSION >= 0x050000
|
||||
cropLayout.setObjectName(QStringLiteral("ButtonLayout"));
|
||||
#else
|
||||
cropLayout.setObjectName(QString::fromUtf8("ButtonLayout"));
|
||||
#endif
|
||||
cropLayout.addLayout(&buttonLayout);
|
||||
|
||||
QPushButton cropButton(&cropDialog);
|
||||
#if QT_VERSION >= 0x050000
|
||||
cropButton.setObjectName(QStringLiteral("CropButton"));
|
||||
#else
|
||||
cropButton.setObjectName(QString::fromUtf8("CropButton"));
|
||||
#endif
|
||||
cropButton.setMinimumSize(0, 40 * screenRatio);
|
||||
cropButton.setText(tr("&Crop"));
|
||||
cropButton.setToolTip(tr("Crop Picture"));
|
||||
QObject::connect(&cropButton, SIGNAL(clicked(bool)), &cropDialog, SLOT(accept()));
|
||||
|
||||
buttonLayout.addWidget(&cropButton);
|
||||
|
||||
cropDialog.show();
|
||||
cropDialog.setFixedSize(cropDialog.sizeHint());
|
||||
if (cropDialog.exec() == QDialog::Accepted) {
|
||||
QImage *croppedImage = new QImage(imageCropper.cropImage().toImage());
|
||||
setImage(croppedImage);
|
||||
}
|
||||
}
|
||||
|
||||
void ImportDialog::importNewPicture()
|
||||
{
|
||||
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||
|
@ -450,7 +523,7 @@ fileDialogPreOpen: //Work?
|
|||
fileDialog.setViewMode(QFileDialog::Detail);
|
||||
fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
|
||||
fileDialog.setOption(QFileDialog::DontUseNativeDialog, dontUseNativeDialog);
|
||||
fileDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||
fileDialog.setWindowTitle(QApplication::translate("ProfileInterface", "Import..."));
|
||||
fileDialog.setLabelText(QFileDialog::Accept, QApplication::translate("ProfileInterface", "Import"));
|
||||
|
||||
|
@ -464,6 +537,10 @@ fileDialogPreOpen: //Work?
|
|||
filters << QApplication::translate("ProfileInterface", "All image files (%1)").arg(imageFormatsStr.trimmed());
|
||||
filters << QApplication::translate("ProfileInterface", "All files (**)");
|
||||
fileDialog.setNameFilters(filters);
|
||||
|
||||
QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls());
|
||||
|
||||
fileDialog.setSidebarUrls(sidebarUrls);
|
||||
fileDialog.setDirectory(settings.value(profileName % "+Directory", StandardPaths::documentsLocation()).toString());
|
||||
fileDialog.restoreGeometry(settings.value(profileName % "+Geometry", "").toByteArray());
|
||||
|
||||
|
@ -756,7 +833,7 @@ fileDialogPreOpen:
|
|||
fileDialog.setViewMode(QFileDialog::Detail);
|
||||
fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
|
||||
fileDialog.setOption(QFileDialog::DontUseNativeDialog, dontUseNativeDialog);
|
||||
fileDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||
fileDialog.setWindowTitle(QApplication::translate("ProfileInterface", "Import..."));
|
||||
fileDialog.setLabelText(QFileDialog::Accept, QApplication::translate("ProfileInterface", "Import"));
|
||||
|
||||
|
@ -770,6 +847,10 @@ fileDialogPreOpen:
|
|||
filters << QApplication::translate("ProfileInterface", "All image files (%1)").arg(imageFormatsStr.trimmed());
|
||||
filters << QApplication::translate("ProfileInterface", "All files (**)");
|
||||
fileDialog.setNameFilters(filters);
|
||||
|
||||
QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls());
|
||||
|
||||
fileDialog.setSidebarUrls(sidebarUrls);
|
||||
fileDialog.setDirectory(settings.value("Directory", StandardPaths::documentsLocation()).toString());
|
||||
fileDialog.restoreGeometry(settings.value("Geometry", "").toByteArray());
|
||||
|
||||
|
@ -868,7 +949,7 @@ void ImportDialog::on_cbResolution_currentIndexChanged(int index)
|
|||
#endif
|
||||
{
|
||||
const QSize dataSize = data.toSize();
|
||||
if (dataSize == QSize(960, 536)) {
|
||||
if (dataSize == SnapmaticPicture::getSnapmaticResolution()) {
|
||||
ui->cbAvatar->setEnabled(true);
|
||||
snapmaticResolution = dataSize;
|
||||
reworkImage();
|
|
@ -45,6 +45,7 @@ public:
|
|||
private slots:
|
||||
void processImage();
|
||||
void reworkImage();
|
||||
void cropPicture();
|
||||
void importNewPicture();
|
||||
void loadImportSettings();
|
||||
void saveImportSettings();
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2017-2023 Syping
|
||||
* Copyright (C) 2017-2021 Syping
|
||||
*
|
||||
* 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
|
||||
|
@ -19,14 +19,12 @@
|
|||
#include "JsonEditorDialog.h"
|
||||
#include "ui_JsonEditorDialog.h"
|
||||
#include "SnapmaticEditor.h"
|
||||
#include "SnapmaticJson.h"
|
||||
#include "AppEnv.h"
|
||||
#include "config.h"
|
||||
#include <QStringBuilder>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QMessageBox>
|
||||
#include <QFile>
|
||||
|
||||
#if QT_VERSION >= 0x050200
|
||||
#include <QFontDatabase>
|
||||
|
@ -41,8 +39,12 @@ JsonEditorDialog::JsonEditorDialog(SnapmaticPicture *picture, QWidget *parent) :
|
|||
ui(new Ui::JsonEditorDialog)
|
||||
{
|
||||
// Set Window Flags
|
||||
#if QT_VERSION >= 0x050900
|
||||
setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
setWindowFlag(Qt::WindowMinMaxButtonsHint, true);
|
||||
#else
|
||||
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint^Qt::WindowMinMaxButtonsHint);
|
||||
#endif
|
||||
|
||||
ui->setupUi(this);
|
||||
ui->cmdClose->setDefault(true);
|
||||
|
@ -64,9 +66,16 @@ JsonEditorDialog::JsonEditorDialog(SnapmaticPicture *picture, QWidget *parent) :
|
|||
ui->cmdSave->setIcon(QIcon::fromTheme("gtk-save"));
|
||||
}
|
||||
|
||||
jsonCode = picture->getJsonStdStr();
|
||||
jsonCode = picture->getJsonStr();
|
||||
|
||||
#if QT_VERSION >= 0x050200
|
||||
ui->txtJSON->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
|
||||
#else
|
||||
QFont jsonFont = ui->txtJSON->font();
|
||||
jsonFont.setStyleHint(QFont::Monospace);
|
||||
jsonFont.setFixedPitch(true);
|
||||
ui->txtJSON->setFont(jsonFont);
|
||||
#endif
|
||||
QFontMetrics fontMetrics(ui->txtJSON->font());
|
||||
#if QT_VERSION >= 0x050B00
|
||||
ui->txtJSON->setTabStopDistance(fontMetrics.horizontalAdvance(" "));
|
||||
|
@ -74,14 +83,9 @@ JsonEditorDialog::JsonEditorDialog(SnapmaticPicture *picture, QWidget *parent) :
|
|||
ui->txtJSON->setTabStopWidth(fontMetrics.width(" "));
|
||||
#endif
|
||||
|
||||
ui->txtJSON->setStyleSheet("QPlainTextEdit{background-color:rgb(46,47,48);color:rgb(238,231,172);}");
|
||||
|
||||
boost::json::error_code ec;
|
||||
const boost::json::value jsonValue = boost::json::parse(jsonCode, ec);
|
||||
if (jsonValue.is_object()) {
|
||||
const boost::json::object jsonObject = jsonValue.get_object();
|
||||
ui->txtJSON->setPlainText(QString::fromUtf8(SnapmaticJson::serialize(jsonObject, true).c_str()));
|
||||
}
|
||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonCode.toUtf8());
|
||||
ui->txtJSON->setStyleSheet("QPlainTextEdit{background-color: rgb(46, 47, 48); color: rgb(238, 231, 172);}");
|
||||
ui->txtJSON->setPlainText(QString::fromUtf8(jsonDocument.toJson(QJsonDocument::Indented)).trimmed());
|
||||
jsonHl = new JSHighlighter(ui->txtJSON->document());
|
||||
|
||||
// DPI calculation
|
||||
|
@ -100,7 +104,7 @@ JsonEditorDialog::JsonEditorDialog(SnapmaticPicture *picture, QWidget *parent) :
|
|||
ui->lineJSON->setMaximumHeight(qRound(1 * screenRatio));
|
||||
ui->lineJSON->setLineWidth(qRound(1 * screenRatio));
|
||||
}
|
||||
resize(450 * screenRatio, 560 * screenRatio);
|
||||
resize(450 * screenRatio, 550 * screenRatio);
|
||||
}
|
||||
|
||||
JsonEditorDialog::~JsonEditorDialog()
|
||||
|
@ -111,12 +115,11 @@ JsonEditorDialog::~JsonEditorDialog()
|
|||
|
||||
void JsonEditorDialog::closeEvent(QCloseEvent *ev)
|
||||
{
|
||||
const QString jsonPatched = QString(ui->txtJSON->toPlainText()).replace("\t", "");
|
||||
boost::json::error_code ec;
|
||||
const boost::json::value jsonNew = boost::json::parse(jsonPatched.toUtf8().constData(), ec);
|
||||
const boost::json::value jsonOriginal = boost::json::parse(jsonCode, ec);
|
||||
const std::string newCode = SnapmaticJson::serialize(jsonNew);
|
||||
const std::string originalCode = SnapmaticJson::serialize(jsonOriginal);
|
||||
QString jsonPatched = QString(ui->txtJSON->toPlainText()).replace("\t", " ");
|
||||
QJsonDocument jsonNew = QJsonDocument::fromJson(jsonPatched.toUtf8());
|
||||
QJsonDocument jsonOriginal = QJsonDocument::fromJson(jsonCode.toUtf8());
|
||||
QString originalCode = QString::fromUtf8(jsonOriginal.toJson(QJsonDocument::Compact));
|
||||
QString newCode = QString::fromUtf8(jsonNew.toJson(QJsonDocument::Compact));
|
||||
if (newCode != originalCode) {
|
||||
QMessageBox::StandardButton button = QMessageBox::warning(this, SnapmaticEditor::tr("Snapmatic Properties"), SnapmaticEditor::tr("<h4>Unsaved changes detected</h4>You want to save the JSON content before you quit?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Cancel);
|
||||
if (button == QMessageBox::Yes) {
|
||||
|
@ -141,13 +144,12 @@ void JsonEditorDialog::closeEvent(QCloseEvent *ev)
|
|||
|
||||
bool JsonEditorDialog::saveJsonContent()
|
||||
{
|
||||
const QString jsonPatched = QString(ui->txtJSON->toPlainText()).replace("\t", "");
|
||||
boost::json::error_code ec;
|
||||
const boost::json::value jsonNew = boost::json::parse(jsonPatched.toUtf8().constData(), ec);
|
||||
if (jsonNew.is_object()) {
|
||||
const boost::json::value jsonOriginal = boost::json::parse(jsonCode, ec);
|
||||
const std::string newCode = SnapmaticJson::serialize(jsonNew);
|
||||
const std::string originalCode = SnapmaticJson::serialize(jsonOriginal);
|
||||
QString jsonPatched = QString(ui->txtJSON->toPlainText()).replace("\t", " ");
|
||||
QJsonDocument jsonNew = QJsonDocument::fromJson(jsonPatched.toUtf8());
|
||||
if (!jsonNew.isEmpty()) {
|
||||
QJsonDocument jsonOriginal = QJsonDocument::fromJson(jsonCode.toUtf8());
|
||||
QString originalCode = QString::fromUtf8(jsonOriginal.toJson(QJsonDocument::Compact));
|
||||
QString newCode = QString::fromUtf8(jsonNew.toJson(QJsonDocument::Compact));
|
||||
if (newCode != originalCode) {
|
||||
QString currentFilePath = smpic->getPictureFilePath();
|
||||
QString originalFilePath = smpic->getOriginalPictureFilePath();
|
||||
|
@ -192,7 +194,7 @@ bool JsonEditorDialog::saveJsonContent()
|
|||
QJsonDocument jsonDocument;
|
||||
QJsonObject jsonObject;
|
||||
jsonObject["Type"] = "JSONEdited";
|
||||
jsonObject["EditedSize"] = QString::number(smpic->getPictureSize());
|
||||
jsonObject["EditedSize"] = QString::number(smpic->getContentMaxLength());
|
||||
#if QT_VERSION >= 0x060000
|
||||
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
|
||||
#else
|
|
@ -47,7 +47,7 @@ signals:
|
|||
void codeUpdated(QString jsonCode);
|
||||
|
||||
private:
|
||||
std::string jsonCode;
|
||||
QString jsonCode;
|
||||
JSHighlighter *jsonHl;
|
||||
SnapmaticPicture *smpic;
|
||||
Ui::JsonEditorDialog *ui;
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2017-2023 Syping
|
||||
* Copyright (C) 2017-2021 Syping
|
||||
*
|
||||
* 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
|
||||
|
@ -29,7 +29,11 @@ MapLocationDialog::MapLocationDialog(double x, double y, QWidget *parent) :
|
|||
ui(new Ui::MapLocationDialog)
|
||||
{
|
||||
// Set Window Flags
|
||||
#if QT_VERSION >= 0x050900
|
||||
setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
#else
|
||||
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||
#endif
|
||||
|
||||
ui->setupUi(this);
|
||||
ui->cmdDone->setVisible(false);
|
|
@ -21,6 +21,7 @@
|
|||
#include "TranslationClass.h"
|
||||
#include "StandardPaths.h"
|
||||
#include "UserInterface.h"
|
||||
#include "wrapper.h"
|
||||
#include "AppEnv.h"
|
||||
#include "config.h"
|
||||
#include <QStringBuilder>
|
||||
|
@ -55,15 +56,41 @@ OptionsDialog::OptionsDialog(ProfileDatabase *profileDB, QWidget *parent) :
|
|||
ui(new Ui::OptionsDialog)
|
||||
{
|
||||
// Set Window Flags
|
||||
#if QT_VERSION >= 0x050900
|
||||
setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
#else
|
||||
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||
#endif
|
||||
|
||||
// Setup User Interface
|
||||
ui->setupUi(this);
|
||||
ui->tabWidget->setCurrentIndex(0);
|
||||
ui->labPicCustomRes->setVisible(false);
|
||||
ui->cmdCancel->setDefault(true);
|
||||
ui->cmdCancel->setFocus();
|
||||
|
||||
#if QT_VERSION >= 0x050000
|
||||
qreal screenRatioPR = AppEnv::screenRatioPR();
|
||||
QRect desktopResolution = QApplication::primaryScreen()->geometry();
|
||||
int desktopSizeWidth = qRound((double)desktopResolution.width() * screenRatioPR);
|
||||
int desktopSizeHeight = qRound((double)desktopResolution.height() * screenRatioPR);
|
||||
#else
|
||||
QRect desktopResolution = QApplication::desktop()->screenGeometry(this);
|
||||
int desktopSizeWidth = desktopResolution.width();
|
||||
int desktopSizeHeight = desktopResolution.height();
|
||||
#endif
|
||||
aspectRatio = Qt::KeepAspectRatio;
|
||||
defExportSize = SnapmaticPicture::getSnapmaticResolution();
|
||||
cusExportSize = defExportSize;
|
||||
defaultQuality = 100;
|
||||
customQuality = 100;
|
||||
contentMode = 0;
|
||||
settings = new QSettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||
|
||||
percentString = ui->labPicQuality->text();
|
||||
ui->labPicQuality->setText(percentString.arg(QString::number(defaultQuality)));
|
||||
ui->rbPicDesktopRes->setText(ui->rbPicDesktopRes->text().arg(QString::number(desktopSizeWidth), QString::number(desktopSizeHeight)));
|
||||
ui->rbPicDefaultRes->setText(ui->rbPicDefaultRes->text().arg(QString::number(defExportSize.width()), QString::number(defExportSize.height())));
|
||||
|
||||
// Set Icon for OK Button
|
||||
if (QIcon::hasThemeIcon("dialog-ok")) {
|
||||
|
@ -86,15 +113,15 @@ OptionsDialog::OptionsDialog(ProfileDatabase *profileDB, QWidget *parent) :
|
|||
ui->cmdCopyStatsID->setIcon(QIcon::fromTheme("edit-copy"));
|
||||
}
|
||||
|
||||
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||
setupTreeWidget();
|
||||
setupLanguageBox(&settings);
|
||||
setupRadioButtons(&settings);
|
||||
setupDefaultProfile(&settings);
|
||||
setupCustomGameFolder(&settings);
|
||||
setupInterfaceSettings(&settings);
|
||||
setupStatisticsSettings(&settings);
|
||||
setupSnapmaticPictureViewer(&settings);
|
||||
setupLanguageBox();
|
||||
setupRadioButtons();
|
||||
setupDefaultProfile();
|
||||
setupPictureSettings();
|
||||
setupCustomGTAFolder();
|
||||
setupInterfaceSettings();
|
||||
setupStatisticsSettings();
|
||||
setupSnapmaticPictureViewer();
|
||||
setupWindowsGameSettings();
|
||||
|
||||
#ifndef Q_QS_ANDROID
|
||||
|
@ -110,6 +137,7 @@ OptionsDialog::OptionsDialog(ProfileDatabase *profileDB, QWidget *parent) :
|
|||
|
||||
OptionsDialog::~OptionsDialog()
|
||||
{
|
||||
delete settings;
|
||||
qDeleteAll(playerItems.begin(), playerItems.end());
|
||||
playerItems.clear();
|
||||
delete ui;
|
||||
|
@ -141,7 +169,7 @@ void OptionsDialog::setupTreeWidget()
|
|||
}
|
||||
}
|
||||
|
||||
void OptionsDialog::setupLanguageBox(QSettings *settings)
|
||||
void OptionsDialog::setupLanguageBox()
|
||||
{
|
||||
settings->beginGroup("Interface");
|
||||
currentLanguage = settings->value("Language", "System").toString();
|
||||
|
@ -152,7 +180,7 @@ void OptionsDialog::setupLanguageBox(QSettings *settings)
|
|||
"System in context of System default"));
|
||||
#ifdef Q_OS_WIN
|
||||
QString cbAutoStr;
|
||||
if (AppEnv::getGTAVLanguage(AppEnv::getGTAVVersion()) != GameLanguage::Undefined) {
|
||||
if (AppEnv::getGameLanguage(AppEnv::getGameVersion()) != GameLanguage::Undefined) {
|
||||
cbAutoStr = tr("%1 (Game language)", "Next closest language compared to the Game settings").arg(tr("Auto", "Automatic language choice."));
|
||||
}
|
||||
else {
|
||||
|
@ -185,7 +213,12 @@ void OptionsDialog::setupLanguageBox(QSettings *settings)
|
|||
ui->cbLanguage->addItem(cbLangStr, lang);
|
||||
}
|
||||
if (currentLanguage == lang) {
|
||||
#if QT_VERSION >= 0x050000
|
||||
ui->cbLanguage->setCurrentText(cbLangStr);
|
||||
#else
|
||||
int indexOfLang = ui->cbLanguage->findText(cbLangStr);
|
||||
ui->cbLanguage->setCurrentIndex(indexOfLang);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,7 +270,7 @@ void OptionsDialog::setupLanguageBox(QSettings *settings)
|
|||
ui->labCurrentAreaLanguage->setText(tr("Current: %1").arg(currentLocale.nativeLanguageName() % " (" % currentLocale.nativeCountryName() % ") [" % aCurrentAreaLanguage % "]"));
|
||||
}
|
||||
|
||||
void OptionsDialog::setupRadioButtons(QSettings *settings)
|
||||
void OptionsDialog::setupRadioButtons()
|
||||
{
|
||||
bool contentModeOk;
|
||||
settings->beginGroup("Profile");
|
||||
|
@ -269,7 +302,7 @@ void OptionsDialog::setupRadioButtons(QSettings *settings)
|
|||
}
|
||||
}
|
||||
|
||||
void OptionsDialog::setupInterfaceSettings(QSettings *settings)
|
||||
void OptionsDialog::setupInterfaceSettings()
|
||||
{
|
||||
settings->beginGroup("Startup");
|
||||
const QString currentStyle = QApplication::style()->objectName();
|
||||
|
@ -317,25 +350,24 @@ void OptionsDialog::on_cmdOK_clicked()
|
|||
|
||||
void OptionsDialog::applySettings()
|
||||
{
|
||||
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||
settings.beginGroup("Interface");
|
||||
settings->beginGroup("Interface");
|
||||
#if QT_VERSION >= 0x050000
|
||||
settings.setValue("Language", ui->cbLanguage->currentData());
|
||||
settings.setValue("AreaLanguage", ui->cbAreaLanguage->currentData());
|
||||
settings->setValue("Language", ui->cbLanguage->currentData());
|
||||
settings->setValue("AreaLanguage", ui->cbAreaLanguage->currentData());
|
||||
#else
|
||||
settings->setValue("Language", ui->cbLanguage->itemData(ui->cbLanguage->currentIndex()));
|
||||
settings->setValue("AreaLanguage", ui->cbAreaLanguage->itemData(ui->cbAreaLanguage->currentIndex()));
|
||||
#endif
|
||||
#ifdef Q_OS_WIN
|
||||
#if QT_VERSION >= 0x050200
|
||||
settings.setValue("NavigationBar", ui->cbSnapmaticNavigationBar->isChecked());
|
||||
settings->setValue("NavigationBar", ui->cbSnapmaticNavigationBar->isChecked());
|
||||
#endif
|
||||
#else
|
||||
settings.setValue("NavigationBar", ui->cbSnapmaticNavigationBar->isChecked());
|
||||
settings->setValue("NavigationBar", ui->cbSnapmaticNavigationBar->isChecked());
|
||||
#endif
|
||||
settings.endGroup();
|
||||
settings->endGroup();
|
||||
|
||||
settings.beginGroup("Profile");
|
||||
settings->beginGroup("Profile");
|
||||
int newContentMode = 20;
|
||||
if (ui->rbModern->isChecked()) {
|
||||
newContentMode = 20;
|
||||
|
@ -346,76 +378,66 @@ void OptionsDialog::applySettings()
|
|||
if (ui->cbDoubleclick->isChecked()) {
|
||||
newContentMode++;
|
||||
}
|
||||
settings.setValue("ContentMode", newContentMode);
|
||||
#if QT_VERSION >= 0x060000
|
||||
if (ui->cbProfiles->currentData().typeId() == QMetaType::QString)
|
||||
settings->setValue("ContentMode", newContentMode);
|
||||
#if QT_VERSION >= 0x050000
|
||||
settings->setValue("Default", ui->cbProfiles->currentData());
|
||||
#else
|
||||
if (ui->cbProfiles->currentData().type() == QVariant::String)
|
||||
settings->setValue("Default", ui->cbProfiles->itemData(ui->cbProfiles->currentIndex()));
|
||||
#endif
|
||||
{
|
||||
settings.setValue("Default", ui->cbProfiles->currentData());
|
||||
settings.remove("DefaultGame");
|
||||
}
|
||||
#if QT_VERSION >= 0x060000
|
||||
if (ui->cbProfiles->currentData().typeId() == QMetaType::QStringList)
|
||||
#else
|
||||
if (ui->cbProfiles->currentData().type() == QVariant::StringList)
|
||||
#endif
|
||||
{
|
||||
const QStringList dataList = ui->cbProfiles->currentData().toStringList();
|
||||
if (dataList.length() == 2) {
|
||||
settings.setValue("Default", dataList.at(0));
|
||||
settings.setValue("DefaultGame", dataList.at(1));
|
||||
}
|
||||
else {
|
||||
settings.setValue("Default", QVariant());
|
||||
settings.remove("DefaultGame");
|
||||
}
|
||||
}
|
||||
settings.endGroup();
|
||||
settings->endGroup();
|
||||
|
||||
const bool forceCustomFolder = ui->cbForceCustomFolder->isChecked();
|
||||
const bool forceCustomFolder_RDR2 = ui->cbForceCustomFolder_RDR2->isChecked();
|
||||
settings.beginGroup("GameDirectory");
|
||||
settings.beginGroup("GTA V");
|
||||
settings.setValue("Directory", ui->txtFolder->text());
|
||||
settings.setValue("ForceCustom", forceCustomFolder);
|
||||
settings.endGroup();
|
||||
settings.beginGroup("RDR 2");
|
||||
settings.setValue("Directory", ui->txtFolder_RDR2->text());
|
||||
settings.setValue("ForceCustom", forceCustomFolder_RDR2);
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
settings->beginGroup("Pictures");
|
||||
if (ui->cbPicCustomQuality->isChecked()) {
|
||||
settings->setValue("CustomQuality", ui->hsPicQuality->value());
|
||||
}
|
||||
settings->setValue("CustomQualityEnabled", ui->cbPicCustomQuality->isChecked());
|
||||
QString sizeMode = "Default";
|
||||
if (ui->rbPicDesktopRes->isChecked()) {
|
||||
sizeMode = "Desktop";
|
||||
}
|
||||
else if (ui->rbPicCustomRes->isChecked()) {
|
||||
sizeMode = "Custom";
|
||||
settings->setValue("CustomSize", QSize(ui->sbPicExportWidth->value(), ui->sbPicExportHeight->value()));
|
||||
}
|
||||
settings->setValue("ExportSizeMode", sizeMode);
|
||||
settings->setValue("AspectRatio", aspectRatio);
|
||||
settings->endGroup();
|
||||
|
||||
const bool defaultStyle = ui->cbDefaultStyle->isChecked();
|
||||
settings.beginGroup("Startup");
|
||||
bool forceCustomFolder = ui->cbForceCustomFolder->isChecked();
|
||||
settings->beginGroup("dir");
|
||||
settings->setValue("dir", ui->txtFolder->text());
|
||||
settings->setValue("force", forceCustomFolder);
|
||||
settings->endGroup();
|
||||
|
||||
bool defaultStyle = ui->cbDefaultStyle->isChecked();
|
||||
settings->beginGroup("Startup");
|
||||
if (!defaultStyle) {
|
||||
QString newStyle = ui->cbStyleList->currentText();
|
||||
settings.setValue("CustomStyle", true);
|
||||
settings.setValue("AppStyle", newStyle);
|
||||
settings->setValue("CustomStyle", true);
|
||||
settings->setValue("AppStyle", newStyle);
|
||||
QApplication::setStyle(QStyleFactory::create(newStyle));
|
||||
}
|
||||
else {
|
||||
settings.setValue("CustomStyle", false);
|
||||
settings->setValue("CustomStyle", false);
|
||||
}
|
||||
const bool defaultFont = ui->cbDefaultFont->isChecked();
|
||||
bool defaultFont = ui->cbDefaultFont->isChecked();
|
||||
if (!defaultFont) {
|
||||
QFont newFont = ui->cbFont->currentFont();
|
||||
settings.setValue("CustomFont", true);
|
||||
settings.setValue("AppFont", newFont);
|
||||
settings->setValue("CustomFont", true);
|
||||
settings->setValue("AppFont", newFont);
|
||||
QApplication::setFont(newFont);
|
||||
}
|
||||
else {
|
||||
settings.setValue("CustomFont", false);
|
||||
settings->setValue("CustomFont", false);
|
||||
}
|
||||
settings.endGroup();
|
||||
settings->endGroup();
|
||||
|
||||
#ifdef GTA5SYNC_TELEMETRY
|
||||
settings.beginGroup("Telemetry");
|
||||
settings.setValue("PushAppConf", ui->cbAppConfigStats->isChecked());
|
||||
settings.setValue("PushUsageData", ui->cbUsageData->isChecked());
|
||||
if (!Telemetry->isStateForced()) { settings.setValue("IsEnabled", ui->cbParticipateStats->isChecked()); }
|
||||
settings.endGroup();
|
||||
settings->beginGroup("Telemetry");
|
||||
settings->setValue("PushAppConf", ui->cbAppConfigStats->isChecked());
|
||||
settings->setValue("PushUsageData", ui->cbUsageData->isChecked());
|
||||
if (!Telemetry->isStateForced()) { settings->setValue("IsEnabled", ui->cbParticipateStats->isChecked()); }
|
||||
settings->endGroup();
|
||||
Telemetry->refresh();
|
||||
Telemetry->work();
|
||||
if (ui->cbUsageData->isChecked() && Telemetry->canPush()) {
|
||||
|
@ -432,8 +454,13 @@ void OptionsDialog::applySettings()
|
|||
}
|
||||
#endif
|
||||
|
||||
const bool languageChanged = ui->cbLanguage->currentData().toString() != currentLanguage;
|
||||
const bool languageAreaChanged = ui->cbAreaLanguage->currentData().toString() != currentAreaLanguage;
|
||||
#if QT_VERSION >= 0x050000
|
||||
bool languageChanged = ui->cbLanguage->currentData().toString() != currentLanguage;
|
||||
bool languageAreaChanged = ui->cbAreaLanguage->currentData().toString() != currentAreaLanguage;
|
||||
#else
|
||||
bool languageChanged = ui->cbLanguage->itemData(ui->cbLanguage->currentIndex()).toString() != currentLanguage;
|
||||
bool languageAreaChanged = ui->cbAreaLanguage->itemData(ui->cbLanguage->currentIndex()).toString() != currentAreaLanguage;
|
||||
#endif
|
||||
if (languageChanged) {
|
||||
Translator->unloadTranslation(qApp);
|
||||
Translator->initUserLanguage();
|
||||
|
@ -443,36 +470,109 @@ void OptionsDialog::applySettings()
|
|||
Translator->initUserLanguage();
|
||||
}
|
||||
|
||||
settings.sync();
|
||||
settings->sync();
|
||||
emit settingsApplied(newContentMode, languageChanged);
|
||||
|
||||
if ((forceCustomFolder && ui->txtFolder->text() != currentCFolder) || (forceCustomFolder != currentFFolder && forceCustomFolder) || (forceCustomFolder_RDR2 && ui->txtFolder_RDR2->text() != currentCFolderR) || (forceCustomFolder_RDR2 != currentFFolderR && forceCustomFolder_RDR2)) {
|
||||
if ((forceCustomFolder && ui->txtFolder->text() != currentCFolder) || (forceCustomFolder != currentFFolder && forceCustomFolder)) {
|
||||
QMessageBox::information(this, tr("%1", "%1").arg(GTA5SYNC_APPSTR), tr("The new Custom Folder will initialise after you restart %1.").arg(GTA5SYNC_APPSTR));
|
||||
}
|
||||
}
|
||||
|
||||
void OptionsDialog::setupDefaultProfile(QSettings *settings)
|
||||
void OptionsDialog::setupDefaultProfile()
|
||||
{
|
||||
settings->beginGroup("Profile");
|
||||
defaultProfile = settings->value("Default", QString()).toString();
|
||||
defaultGame = settings->value("DefaultGame", QStringLiteral("GTA V")).toString();
|
||||
defaultProfile = settings->value("Default", "").toString();
|
||||
settings->endGroup();
|
||||
|
||||
QString cbNoneStr = tr("No Profile", "No Profile, as default");
|
||||
ui->cbProfiles->addItem(cbNoneStr, QString());
|
||||
ui->cbProfiles->addItem(cbNoneStr, "");
|
||||
}
|
||||
|
||||
void OptionsDialog::commitProfiles(const QStringList &profiles, const QString &game)
|
||||
void OptionsDialog::commitProfiles(const QStringList &profiles)
|
||||
{
|
||||
for (const QString &profile : profiles) {
|
||||
ui->cbProfiles->addItem(tr("%2: %1").arg(profile, game), QStringList() << profile << game);
|
||||
if (defaultGame == game && defaultProfile == profile) {
|
||||
ui->cbProfiles->setCurrentText(tr("%2: %1").arg(profile, game));
|
||||
ui->cbProfiles->addItem(tr("Profile: %1").arg(profile), profile);
|
||||
if (defaultProfile == profile) {
|
||||
#if QT_VERSION >= 0x050000
|
||||
ui->cbProfiles->setCurrentText(tr("Profile: %1").arg(profile));
|
||||
#else
|
||||
int indexOfProfile = ui->cbProfiles->findText(tr("Profile: %1").arg(profile));
|
||||
ui->cbProfiles->setCurrentIndex(indexOfProfile);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OptionsDialog::setupStatisticsSettings(QSettings *settings)
|
||||
void OptionsDialog::on_rbPicCustomRes_toggled(bool checked)
|
||||
{
|
||||
ui->labPicCustomRes->setEnabled(checked);
|
||||
ui->sbPicExportWidth->setEnabled(checked);
|
||||
ui->sbPicExportHeight->setEnabled(checked);
|
||||
ui->labPicXDescription->setEnabled(checked);
|
||||
}
|
||||
|
||||
void OptionsDialog::on_cbPicCustomQuality_toggled(bool checked)
|
||||
{
|
||||
ui->hsPicQuality->setEnabled(checked);
|
||||
ui->labPicQuality->setEnabled(checked);
|
||||
ui->labPicQualityDescription->setEnabled(checked);
|
||||
}
|
||||
|
||||
void OptionsDialog::on_hsPicQuality_valueChanged(int value)
|
||||
{
|
||||
customQuality = value;
|
||||
ui->labPicQuality->setText(percentString.arg(QString::number(value)));
|
||||
}
|
||||
|
||||
void OptionsDialog::setupPictureSettings()
|
||||
{
|
||||
settings->beginGroup("Pictures");
|
||||
|
||||
// Quality Settings
|
||||
customQuality = settings->value("CustomQuality", defaultQuality).toInt();
|
||||
if (customQuality < 1 || customQuality > 100) {
|
||||
customQuality = 100;
|
||||
}
|
||||
ui->hsPicQuality->setValue(customQuality);
|
||||
ui->cbPicCustomQuality->setChecked(settings->value("CustomQualityEnabled", false).toBool());
|
||||
|
||||
// Size Settings
|
||||
cusExportSize = settings->value("CustomSize", defExportSize).toSize();
|
||||
if (cusExportSize.width() > 3840) {
|
||||
cusExportSize.setWidth(3840);
|
||||
}
|
||||
else if (cusExportSize.height() > 2160) {
|
||||
cusExportSize.setHeight(2160);
|
||||
}
|
||||
if (cusExportSize.width() < 1) {
|
||||
cusExportSize.setWidth(1);
|
||||
}
|
||||
else if (cusExportSize.height() < 1) {
|
||||
cusExportSize.setHeight(1);
|
||||
}
|
||||
ui->sbPicExportWidth->setValue(cusExportSize.width());
|
||||
ui->sbPicExportHeight->setValue(cusExportSize.height());
|
||||
|
||||
QString sizeMode = settings->value("ExportSizeMode", "Default").toString();
|
||||
if (sizeMode == "Desktop") {
|
||||
ui->rbPicDesktopRes->setChecked(true);
|
||||
}
|
||||
else if (sizeMode == "Custom") {
|
||||
ui->rbPicCustomRes->setChecked(true);
|
||||
}
|
||||
else {
|
||||
ui->rbPicDefaultRes->setChecked(true);
|
||||
}
|
||||
|
||||
aspectRatio = (Qt::AspectRatioMode)settings->value("AspectRatio", Qt::KeepAspectRatio).toInt();
|
||||
if (aspectRatio == Qt::IgnoreAspectRatio) {
|
||||
ui->cbIgnoreAspectRatio->setChecked(true);
|
||||
}
|
||||
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
void OptionsDialog::setupStatisticsSettings()
|
||||
{
|
||||
#ifdef GTA5SYNC_TELEMETRY
|
||||
ui->cbParticipateStats->setText(tr("Participate in %1 User Statistics").arg(GTA5SYNC_APPSTR));
|
||||
|
@ -558,36 +658,32 @@ void OptionsDialog::setupWindowsGameSettings()
|
|||
#endif
|
||||
}
|
||||
|
||||
void OptionsDialog::setupCustomGameFolder(QSettings *settings)
|
||||
void OptionsDialog::on_cbIgnoreAspectRatio_toggled(bool checked)
|
||||
{
|
||||
bool ok_GTAV, ok_RDR2;
|
||||
const QString defaultGameFolder = AppEnv::getGTAVFolder(&ok_GTAV);
|
||||
const QString defaultGameFolderR = AppEnv::getRDR2Folder(&ok_RDR2);
|
||||
settings->beginGroup("dir");
|
||||
currentCFolder = settings->value("dir", QString()).toString();
|
||||
currentFFolder = settings->value("force", false).toBool();
|
||||
settings->endGroup();
|
||||
settings->beginGroup("GameDirectory");
|
||||
settings->beginGroup("GTA V");
|
||||
currentCFolder = settings->value("Directory", currentCFolder).toString();
|
||||
currentFFolder = settings->value("ForceCustom", currentFFolder).toBool();
|
||||
settings->endGroup();
|
||||
settings->beginGroup("RDR 2");
|
||||
currentCFolderR = settings->value("Directory", QString()).toString();
|
||||
currentFFolderR = settings->value("ForceCustom", false).toBool();
|
||||
settings->endGroup();
|
||||
settings->endGroup();
|
||||
if (currentCFolder.isEmpty() && ok_GTAV)
|
||||
currentCFolder = defaultGameFolder;
|
||||
if (currentCFolderR.isEmpty() && ok_RDR2)
|
||||
currentCFolderR = defaultGameFolderR;
|
||||
ui->txtFolder->setText(currentCFolder);
|
||||
ui->cbForceCustomFolder->setChecked(currentFFolder);
|
||||
ui->txtFolder_RDR2->setText(currentCFolderR);
|
||||
ui->cbForceCustomFolder_RDR2->setChecked(currentFFolderR);
|
||||
if (checked) {
|
||||
aspectRatio = Qt::IgnoreAspectRatio;
|
||||
}
|
||||
else {
|
||||
aspectRatio = Qt::KeepAspectRatio;
|
||||
}
|
||||
}
|
||||
|
||||
void OptionsDialog::setupSnapmaticPictureViewer(QSettings *settings)
|
||||
void OptionsDialog::setupCustomGTAFolder()
|
||||
{
|
||||
bool ok;
|
||||
QString defaultGameFolder = AppEnv::getGameFolder(&ok);
|
||||
settings->beginGroup("dir");
|
||||
currentCFolder = settings->value("dir", "").toString();
|
||||
currentFFolder = settings->value("force", false).toBool();
|
||||
if (currentCFolder == "" && ok) {
|
||||
currentCFolder = defaultGameFolder;
|
||||
}
|
||||
ui->txtFolder->setText(currentCFolder);
|
||||
ui->cbForceCustomFolder->setChecked(currentFFolder);
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
void OptionsDialog::setupSnapmaticPictureViewer()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
#if QT_VERSION >= 0x050200
|
||||
|
@ -608,19 +704,11 @@ void OptionsDialog::setupSnapmaticPictureViewer(QSettings *settings)
|
|||
void OptionsDialog::on_cmdExploreFolder_clicked()
|
||||
{
|
||||
const QString GTAV_Folder = QFileDialog::getExistingDirectory(this, UserInterface::tr("Select GTA V Folder..."), StandardPaths::documentsLocation(), QFileDialog::ShowDirsOnly);
|
||||
if (!GTAV_Folder.isEmpty() && QDir(GTAV_Folder).exists()) {
|
||||
if (QDir(GTAV_Folder).exists()) {
|
||||
ui->txtFolder->setText(GTAV_Folder);
|
||||
}
|
||||
}
|
||||
|
||||
void OptionsDialog::on_cmdExploreFolder_RDR2_clicked()
|
||||
{
|
||||
const QString RDR2_Folder = QFileDialog::getExistingDirectory(this, UserInterface::tr("Select RDR 2 Folder..."), StandardPaths::documentsLocation(), QFileDialog::ShowDirsOnly);
|
||||
if (!RDR2_Folder.isEmpty() && QDir(RDR2_Folder).exists()) {
|
||||
ui->txtFolder_RDR2->setText(RDR2_Folder);
|
||||
}
|
||||
}
|
||||
|
||||
void OptionsDialog::on_cbDefaultStyle_toggled(bool checked)
|
||||
{
|
||||
ui->cbStyleList->setDisabled(checked);
|
|
@ -36,13 +36,16 @@ class OptionsDialog : public QDialog
|
|||
|
||||
public:
|
||||
explicit OptionsDialog(ProfileDatabase *profileDB, QWidget *parent = 0);
|
||||
void commitProfiles(const QStringList &profiles, const QString &game);
|
||||
void commitProfiles(const QStringList &profiles);
|
||||
~OptionsDialog();
|
||||
|
||||
private slots:
|
||||
void on_cmdOK_clicked();
|
||||
void on_rbPicCustomRes_toggled(bool checked);
|
||||
void on_cbPicCustomQuality_toggled(bool checked);
|
||||
void on_hsPicQuality_valueChanged(int value);
|
||||
void on_cbIgnoreAspectRatio_toggled(bool checked);
|
||||
void on_cmdExploreFolder_clicked();
|
||||
void on_cmdExploreFolder_RDR2_clicked();
|
||||
void on_cbDefaultStyle_toggled(bool checked);
|
||||
void on_cbDefaultFont_toggled(bool checked);
|
||||
void on_cmdCopyStatsID_clicked();
|
||||
|
@ -60,22 +63,25 @@ private:
|
|||
QString currentAreaLanguage;
|
||||
QString currentLanguage;
|
||||
QString currentCFolder;
|
||||
QString currentCFolderR;
|
||||
QString defaultProfile;
|
||||
QString defaultGame;
|
||||
QString percentString;
|
||||
QSettings *settings;
|
||||
bool withoutPlayers;
|
||||
bool currentFFolder;
|
||||
bool currentFFolderR;
|
||||
int contentMode;
|
||||
int customQuality;
|
||||
int defaultQuality;
|
||||
QSize defExportSize;
|
||||
QSize cusExportSize;
|
||||
void setupTreeWidget();
|
||||
void setupLanguageBox(QSettings *settings);
|
||||
void setupRadioButtons(QSettings *settings);
|
||||
void setupDefaultProfile(QSettings *settings);
|
||||
void setupCustomGameFolder(QSettings *settings);
|
||||
void setupInterfaceSettings(QSettings *settings);
|
||||
void setupStatisticsSettings(QSettings *settings);
|
||||
void setupSnapmaticPictureViewer(QSettings *settings);
|
||||
void setupLanguageBox();
|
||||
void setupRadioButtons();
|
||||
void setupDefaultProfile();
|
||||
void setupPictureSettings();
|
||||
void setupCustomGTAFolder();
|
||||
void setupInterfaceSettings();
|
||||
void setupStatisticsSettings();
|
||||
void setupSnapmaticPictureViewer();
|
||||
void setupWindowsGameSettings();
|
||||
void applySettings();
|
||||
};
|
|
@ -102,36 +102,6 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gbDefaultFolder_RDR2">
|
||||
<property name="title">
|
||||
<string>Custom RDR 2 Folder</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="vlCustomRDR2Folder">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbForceCustomFolder_RDR2">
|
||||
<property name="text">
|
||||
<string>Force using Custom Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="hlDefaultFolder_RDR2">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="txtFolder_RDR2"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="cmdExploreFolder_RDR2">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="vsProfile">
|
||||
<property name="orientation">
|
||||
|
@ -152,6 +122,181 @@
|
|||
<string>Pictures</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="vlTabPictures">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gbPicResolution">
|
||||
<property name="title">
|
||||
<string>Export Size</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="vlGbPicRes">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbPicDefaultRes">
|
||||
<property name="text">
|
||||
<string>Default: %1x%2</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbPicDesktopRes">
|
||||
<property name="text">
|
||||
<string>Screen Resolution: %1x%2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="hlCustomRes">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbPicCustomRes">
|
||||
<property name="text">
|
||||
<string>Custom Size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labPicCustomRes">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Custom Size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="sbPicExportWidth">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>3840</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>960</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labPicXDescription">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>x</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="sbPicExportHeight">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>2160</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>536</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="hsPicCustomSize">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="hlAspectRatio">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbIgnoreAspectRatio">
|
||||
<property name="text">
|
||||
<string>Ignore Aspect Ratio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gbPicQuality">
|
||||
<property name="title">
|
||||
<string>Export Quality</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="vlHlPicQuality">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbPicCustomQuality">
|
||||
<property name="text">
|
||||
<string>Enable Custom Quality</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="hlPicQuality">
|
||||
<item>
|
||||
<widget class="QLabel" name="labPicQualityDescription">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Quality:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="hsPicQuality">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labPicQuality">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>%1%</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gbSnapmaticPictureViewer">
|
||||
<property name="title">
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2016-2023 Syping
|
||||
* Copyright (C) 2016-2021 Syping
|
||||
*
|
||||
* 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
|
||||
|
@ -20,9 +20,11 @@
|
|||
#include "PictureWidget.h"
|
||||
#include "ProfileDatabase.h"
|
||||
#include "ui_PictureDialog.h"
|
||||
#include "SidebarGenerator.h"
|
||||
#include "MapLocationDialog.h"
|
||||
#include "JsonEditorDialog.h"
|
||||
#include "SnapmaticEditor.h"
|
||||
#include "StandardPaths.h"
|
||||
#include "PictureExport.h"
|
||||
#include "ImportDialog.h"
|
||||
#include "StringParser.h"
|
||||
|
@ -84,7 +86,7 @@
|
|||
#define crewID QString::number(picture->getSnapmaticProperties().crewID)
|
||||
#define picArea picture->getSnapmaticProperties().location.area
|
||||
#define picPath picture->getPictureFilePath()
|
||||
#define picTitl picture->getPictureTitle().toHtmlEscaped()
|
||||
#define picTitl StringParser::escapeString(picture->getPictureTitle())
|
||||
#define plyrsList picture->getSnapmaticProperties().playersList
|
||||
#if QT_VERSION >= 0x060000
|
||||
#define created QLocale().toString(picture->getSnapmaticProperties().createdDateTime, QLocale::ShortFormat)
|
||||
|
@ -125,8 +127,21 @@ PictureDialog::PictureDialog(bool primaryWindow, ProfileDatabase *profileDB, Cre
|
|||
void PictureDialog::setupPictureDialog()
|
||||
{
|
||||
// Set Window Flags
|
||||
#if QT_VERSION >= 0x050900
|
||||
setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
setWindowFlag(Qt::CustomizeWindowHint, true);
|
||||
#else
|
||||
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint^Qt::CustomizeWindowHint);
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
// for stupid Window Manager like GNOME
|
||||
#if QT_VERSION >= 0x050900
|
||||
setWindowFlag(Qt::Dialog, false);
|
||||
setWindowFlag(Qt::Window, true);
|
||||
#else
|
||||
setWindowFlags(windowFlags()^Qt::Dialog^Qt::Window);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Setup User Interface
|
||||
ui->setupUi(this);
|
||||
|
@ -141,8 +156,8 @@ void PictureDialog::setupPictureDialog()
|
|||
smpic = nullptr;
|
||||
crewStr = "";
|
||||
|
||||
// Set default Snapmatic resolution (960x536)
|
||||
const QSize snapmaticResolution = QSize(960, 536);
|
||||
// Get Snapmatic Resolution
|
||||
const QSize snapmaticResolution = SnapmaticPicture::getSnapmaticResolution();
|
||||
|
||||
// Avatar area
|
||||
qreal screenRatio = AppEnv::screenRatio();
|
||||
|
@ -168,26 +183,27 @@ void PictureDialog::setupPictureDialog()
|
|||
|
||||
// Manage menu
|
||||
manageMenu = new QMenu(this);
|
||||
manageMenu->addAction(tr("Export as &Picture..."), this, &PictureDialog::exportSnapmaticPicture);
|
||||
exportPhotoAction = manageMenu->addAction(tr("Export as &RAGE Photo..."), this, &PictureDialog::copySnapmaticPicture);
|
||||
manageMenu->addAction(tr("Export as &Picture..."), this, SLOT(exportSnapmaticPicture()));
|
||||
manageMenu->addAction(tr("Export as &Snapmatic..."), this, SLOT(copySnapmaticPicture()));
|
||||
manageMenu->addSeparator();
|
||||
manageMenu->addAction(tr("&Edit Properties..."), this, &PictureDialog::editSnapmaticProperties);
|
||||
manageMenu->addAction(tr("&Overwrite Image..."), this, &PictureDialog::editSnapmaticImage);
|
||||
manageMenu->addAction(tr("&Edit Properties..."), this, SLOT(editSnapmaticProperties()));
|
||||
manageMenu->addAction(tr("&Overwrite Image..."), this, SLOT(editSnapmaticImage()));
|
||||
manageMenu->addSeparator();
|
||||
openViewerAction = manageMenu->addAction(tr("Open &Map Viewer..."), this, &PictureDialog::openPreviewMap);
|
||||
openViewerAction->setEnabled(false);
|
||||
QAction *openViewerAction = manageMenu->addAction(tr("Open &Map Viewer..."), this, SLOT(openPreviewMap()));
|
||||
openViewerAction->setShortcut(Qt::Key_M);
|
||||
manageMenu->addAction(tr("Open &JSON Editor..."), this, &PictureDialog::editSnapmaticRawJson);
|
||||
manageMenu->addAction(tr("Open &JSON Editor..."), this, SLOT(editSnapmaticRawJson()));
|
||||
ui->cmdManage->setMenu(manageMenu);
|
||||
|
||||
// Global map
|
||||
globalMap = GlobalString::getGlobalMap();
|
||||
|
||||
// Set Icon for Close Button
|
||||
if (QIcon::hasThemeIcon("dialog-close"))
|
||||
if (QIcon::hasThemeIcon("dialog-close")) {
|
||||
ui->cmdClose->setIcon(QIcon::fromTheme("dialog-close"));
|
||||
else if (QIcon::hasThemeIcon("gtk-close"))
|
||||
}
|
||||
else if (QIcon::hasThemeIcon("gtk-close")) {
|
||||
ui->cmdClose->setIcon(QIcon::fromTheme("gtk-close"));
|
||||
}
|
||||
|
||||
installEventFilter(this);
|
||||
|
||||
|
@ -218,10 +234,17 @@ void PictureDialog::closeEvent(QCloseEvent *ev)
|
|||
void PictureDialog::addPreviousNextButtons()
|
||||
{
|
||||
QToolBar *uiToolbar = new QToolBar("Picture Toolbar", this);
|
||||
#if QT_VERSION < 0x050600
|
||||
qreal screenRatio = AppEnv::screenRatio();
|
||||
if (screenRatio != 1) {
|
||||
QSize iconSize = uiToolbar->iconSize();
|
||||
uiToolbar->setIconSize(QSize(iconSize.width() * screenRatio, iconSize.height() * screenRatio));
|
||||
}
|
||||
#endif
|
||||
uiToolbar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
uiToolbar->setObjectName("UiToolbar");
|
||||
uiToolbar->addAction(QIcon(AppEnv::getImagesFolder() % "/back.svgz"), "", this, &PictureDialog::previousPictureRequestedSlot);
|
||||
uiToolbar->addAction(QIcon(AppEnv::getImagesFolder() % "/next.svgz"), "", this, &PictureDialog::nextPictureRequestedSlot);
|
||||
uiToolbar->addAction(QIcon(AppEnv::getImagesFolder() % "/back.svgz"), "", this, SLOT(previousPictureRequestedSlot()));
|
||||
uiToolbar->addAction(QIcon(AppEnv::getImagesFolder() % "/next.svgz"), "", this, SLOT(nextPictureRequestedSlot()));
|
||||
#ifdef Q_OS_MAC
|
||||
#if QT_VERSION >= 0x050000
|
||||
uiToolbar->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
@ -233,7 +256,7 @@ void PictureDialog::addPreviousNextButtons()
|
|||
|
||||
void PictureDialog::adaptDialogSize()
|
||||
{
|
||||
int newDialogHeight = (536 * AppEnv::screenRatio()) + ui->jsonFrame->heightForWidth(width());
|
||||
int newDialogHeight = (SnapmaticPicture::getSnapmaticResolution().height() * AppEnv::screenRatio()) + ui->jsonFrame->heightForWidth(width());
|
||||
if (naviEnabled)
|
||||
newDialogHeight = newDialogHeight + layout()->menuBar()->height();
|
||||
const QSize windowSize(width(), newDialogHeight);
|
||||
|
@ -250,8 +273,9 @@ void PictureDialog::styliseDialog()
|
|||
MARGINS margins = {0, 0, qRound(layout()->menuBar()->height() * AppEnv::screenRatioPR()), 0};
|
||||
HRESULT hr = S_OK;
|
||||
hr = DwmExtendFrameIntoClientArea(reinterpret_cast<HWND>(winId()), &margins);
|
||||
if (SUCCEEDED(hr))
|
||||
if (SUCCEEDED(hr)) {
|
||||
setStyleSheet("PictureDialog{background:transparent}");
|
||||
}
|
||||
}
|
||||
else {
|
||||
MARGINS margins = {0, 0, 0, 0};
|
||||
|
@ -259,8 +283,9 @@ void PictureDialog::styliseDialog()
|
|||
bool colorOk = false;
|
||||
QSettings dwmRegistry("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\DWM", QSettings::NativeFormat);
|
||||
QRgb color = dwmRegistry.value("ColorizationColor").toUInt(&colorOk);
|
||||
if (colorOk)
|
||||
if (colorOk) {
|
||||
setStyleSheet(QString("PictureDialog{background:%1}").arg(QColor::fromRgba(color).name()));
|
||||
}
|
||||
else {
|
||||
HRESULT hr = S_OK;
|
||||
BOOL isOpaqueBlend;
|
||||
|
@ -288,8 +313,9 @@ bool PictureDialog::nativeEvent(const QByteArray &eventType, void *message, long
|
|||
#endif
|
||||
{
|
||||
MSG *msg = reinterpret_cast<MSG*>(message);
|
||||
if (msg->message == 0x031e || msg->message == 0x0320)
|
||||
if (msg->message == 0x031e || msg->message == 0x0320) {
|
||||
styliseDialog();
|
||||
}
|
||||
return QWidget::nativeEvent(eventType, message, result);
|
||||
}
|
||||
#endif
|
||||
|
@ -333,23 +359,23 @@ bool PictureDialog::eventFilter(QObject *obj, QEvent *ev)
|
|||
case Qt::Key_2:
|
||||
if (overlayEnabled) {
|
||||
overlayEnabled = false;
|
||||
if (!previewMode)
|
||||
renderPicture();
|
||||
if (!previewMode) renderPicture();
|
||||
}
|
||||
else {
|
||||
overlayEnabled = true;
|
||||
if (!previewMode)
|
||||
renderPicture();
|
||||
if (!previewMode) renderPicture();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_M:
|
||||
openPreviewMap();
|
||||
returnValue = true;
|
||||
break;
|
||||
#if QT_VERSION >= 0x050300
|
||||
case Qt::Key_Exit:
|
||||
ui->cmdClose->click();
|
||||
returnValue = true;
|
||||
break;
|
||||
#endif
|
||||
case Qt::Key_Enter: case Qt::Key_Return:
|
||||
on_labPicture_mouseDoubleClicked(Qt::LeftButton);
|
||||
returnValue = true;
|
||||
|
@ -361,6 +387,7 @@ bool PictureDialog::eventFilter(QObject *obj, QEvent *ev)
|
|||
}
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
#if QT_VERSION >= 0x050000
|
||||
if (obj != ui->labPicture && naviEnabled) {
|
||||
if (ev->type() == QEvent::MouseButtonPress) {
|
||||
QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(ev);
|
||||
|
@ -374,8 +401,9 @@ bool PictureDialog::eventFilter(QObject *obj, QEvent *ev)
|
|||
if (ev->type() == QEvent::MouseButtonRelease) {
|
||||
QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(ev);
|
||||
if (mouseEvent->pos().y() <= layout()->menuBar()->height()) {
|
||||
if (mouseEvent->button() == Qt::LeftButton)
|
||||
if (mouseEvent->button() == Qt::LeftButton) {
|
||||
dragStart = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dragStart && ev->type() == QEvent::MouseMove) {
|
||||
|
@ -389,6 +417,7 @@ bool PictureDialog::eventFilter(QObject *obj, QEvent *ev)
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
return returnValue;
|
||||
|
@ -444,8 +473,9 @@ void PictureDialog::renderOverlayPicture()
|
|||
preferedRect.setHeight(71 * screenRatio * screenRatioPR);
|
||||
overlaySpace.setHeight(80 * screenRatio * screenRatioPR);
|
||||
}
|
||||
else
|
||||
else {
|
||||
overlaySpace.setHeight(overlaySpace.height() + 6 * screenRatio * screenRatioPR);
|
||||
}
|
||||
|
||||
QImage overlayImage(overlaySpace.size(), QImage::Format_ARGB32_Premultiplied);
|
||||
overlayImage.fill(Qt::transparent);
|
||||
|
@ -456,10 +486,12 @@ void PictureDialog::renderOverlayPicture()
|
|||
overlayPainter.drawText(preferedRect, Qt::AlignLeft | hOverlay | Qt::TextDontClip | Qt::TextWordWrap, overlayText);
|
||||
overlayPainter.end();
|
||||
|
||||
if (overlaySpace.width() < 194 * screenRatio * screenRatioPR)
|
||||
if (overlaySpace.width() < 194 * screenRatio * screenRatioPR) {
|
||||
overlaySpace.setWidth(200 * screenRatio * screenRatioPR);
|
||||
else
|
||||
}
|
||||
else {
|
||||
overlaySpace.setWidth(overlaySpace.width() + 6 * screenRatio * screenRatioPR);
|
||||
}
|
||||
|
||||
QImage overlayBorderImage(overlaySpace.width(), overlaySpace.height(), QImage::Format_ARGB6666_Premultiplied);
|
||||
overlayBorderImage.fill(QColor(15, 15, 15, 162));
|
||||
|
@ -475,8 +507,8 @@ void PictureDialog::renderOverlayPicture()
|
|||
void PictureDialog::setSnapmaticPicture(SnapmaticPicture *picture, bool readOk, bool _indexed, int _index)
|
||||
{
|
||||
if (smpic != nullptr) {
|
||||
QObject::disconnect(smpic, &SnapmaticPicture::updated, this, &PictureDialog::updated);
|
||||
QObject::disconnect(smpic, &SnapmaticPicture::customSignal, this, &PictureDialog::customSignal);
|
||||
QObject::disconnect(smpic, SIGNAL(updated()), this, SLOT(updated()));
|
||||
QObject::disconnect(smpic, SIGNAL(customSignal(QString)), this, SLOT(customSignal(QString)));
|
||||
}
|
||||
snapmaticPicture = QImage();
|
||||
indexed = _indexed;
|
||||
|
@ -486,45 +518,29 @@ void PictureDialog::setSnapmaticPicture(SnapmaticPicture *picture, bool readOk,
|
|||
QMessageBox::warning(this, tr("Snapmatic Picture Viewer"), tr("Failed at %1").arg(picture->getLastStep()));
|
||||
return;
|
||||
}
|
||||
setWindowTitle(windowTitleStr.arg(picture->getPictureTitle()));
|
||||
if (picture->isPicOk()) {
|
||||
snapmaticPicture = picture->getImage();
|
||||
renderPicture();
|
||||
ui->cmdManage->setEnabled(true);
|
||||
if (smpic->getSnapmaticFormat() == SnapmaticFormat::PGTA5_Format)
|
||||
exportPhotoAction->setText(tr("Export as >A V Snapmatic..."));
|
||||
else if (smpic->getSnapmaticFormat() == SnapmaticFormat::G5E_Format)
|
||||
exportPhotoAction->setText(tr("Export as >A V Snapmatic..."));
|
||||
else if (smpic->getSnapmaticFormat() == SnapmaticFormat::PRDR3_Format)
|
||||
exportPhotoAction->setText(tr("Export as &RDR 2 Photo..."));
|
||||
else
|
||||
exportPhotoAction->setText(tr("Export as &RAGE Photo..."));
|
||||
}
|
||||
else {
|
||||
exportPhotoAction->setText(tr("Export as &RAGE Photo..."));
|
||||
}
|
||||
if (picture->isJsonOk()) {
|
||||
crewStr = crewDB->getCrewName(crewID);
|
||||
if (globalMap.contains(picArea))
|
||||
if (globalMap.contains(picArea)) {
|
||||
picAreaStr = globalMap.value(picArea);
|
||||
else
|
||||
}
|
||||
else {
|
||||
picAreaStr = picArea;
|
||||
}
|
||||
setWindowTitle(windowTitleStr.arg(picTitl));
|
||||
ui->labJSON->setText(jsonDrawString.arg(locX, locY, locZ, generatePlayersString(), generateCrewString(), picTitl, picAreaStr, created));
|
||||
if (smpic->getSnapmaticFormat() == SnapmaticFormat::PGTA5_Format)
|
||||
openViewerAction->setEnabled(true);
|
||||
else if (smpic->getSnapmaticFormat() == SnapmaticFormat::G5E_Format)
|
||||
openViewerAction->setEnabled(true);
|
||||
else
|
||||
openViewerAction->setEnabled(false);
|
||||
QTimer::singleShot(0, this, &PictureDialog::adaptDialogSize);
|
||||
QTimer::singleShot(0, this, SLOT(adaptDialogSize()));
|
||||
}
|
||||
else {
|
||||
ui->labJSON->setText(jsonDrawString.arg("0", "0", "0", tr("No Players"), tr("No Crew"), tr("Unknown Location")));
|
||||
openViewerAction->setEnabled(false);
|
||||
QTimer::singleShot(0, this, &PictureDialog::adaptDialogSize);
|
||||
QTimer::singleShot(0, this, SLOT(adaptDialogSize()));
|
||||
}
|
||||
QObject::connect(smpic, &SnapmaticPicture::updated, this, &PictureDialog::updated);
|
||||
QObject::connect(smpic, &SnapmaticPicture::customSignal, this, &PictureDialog::customSignal);
|
||||
QObject::connect(smpic, SIGNAL(updated()), this, SLOT(updated()));
|
||||
QObject::connect(smpic, SIGNAL(customSignal(QString)), this, SLOT(customSignal(QString)));
|
||||
emit newPictureCommited(snapmaticPicture);
|
||||
}
|
||||
|
||||
|
@ -552,18 +568,21 @@ void PictureDialog::renderPicture()
|
|||
{
|
||||
const qreal screenRatio = AppEnv::screenRatio();
|
||||
const qreal screenRatioPR = AppEnv::screenRatioPR();
|
||||
const QSize snapmaticResolution = QSize(960, 536);
|
||||
const QSize snapmaticResolution(SnapmaticPicture::getSnapmaticResolution());
|
||||
const QSize renderResolution(snapmaticResolution.width() * screenRatio * screenRatioPR, snapmaticResolution.height() * screenRatio * screenRatioPR);
|
||||
QPixmap shownImagePixmap(renderResolution);
|
||||
shownImagePixmap.fill(Qt::black);
|
||||
QPainter shownImagePainter(&shownImagePixmap);
|
||||
const QImage renderImage = snapmaticPicture.scaled(renderResolution, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
if (renderImage.width() < renderResolution.width())
|
||||
if (renderImage.width() < renderResolution.width()) {
|
||||
shownImagePainter.drawImage((renderResolution.width() - renderImage.width()) / 2, 0, renderImage, Qt::AutoColor);
|
||||
else if (renderImage.height() < renderResolution.height())
|
||||
}
|
||||
else if (renderImage.height() < renderResolution.height()) {
|
||||
shownImagePainter.drawImage(0, (renderResolution.height() - renderImage.height()) / 2, renderImage, Qt::AutoColor);
|
||||
else
|
||||
}
|
||||
else {
|
||||
shownImagePainter.drawImage(0, 0, renderImage, Qt::AutoColor);
|
||||
}
|
||||
if (previewMode) {
|
||||
QFont shownImagePainterFont;
|
||||
shownImagePainterFont.setPixelSize(12 * screenRatio * screenRatioPR);
|
||||
|
@ -572,10 +591,13 @@ void PictureDialog::renderPicture()
|
|||
shownImagePainter.setFont(shownImagePainterFont);
|
||||
shownImagePainter.drawText(QRect(3 * screenRatio * screenRatioPR, 3 * screenRatio * screenRatioPR, 140 * screenRatio * screenRatioPR, snapmaticResolution.height() * screenRatio * screenRatioPR), Qt::AlignLeft | Qt::TextWordWrap, tr("Avatar Preview Mode\nPress 1 for Default View"));
|
||||
}
|
||||
else if (overlayEnabled)
|
||||
else if (overlayEnabled) {
|
||||
shownImagePainter.drawImage(3 * screenRatio * screenRatioPR, 3 * screenRatio * screenRatioPR, overlayTempImage, Qt::AutoColor);
|
||||
}
|
||||
shownImagePainter.end();
|
||||
#if QT_VERSION >= 0x050600
|
||||
shownImagePixmap.setDevicePixelRatio(screenRatioPR);
|
||||
#endif
|
||||
ui->labPicture->setPixmap(shownImagePixmap);
|
||||
}
|
||||
|
||||
|
@ -586,7 +608,7 @@ void PictureDialog::crewNameUpdated()
|
|||
if (crewIDStr == crewStr) {
|
||||
crewStr = crewDB->getCrewName(crewIDStr);
|
||||
ui->labJSON->setText(jsonDrawString.arg(locX, locY, locZ, generatePlayersString(), generateCrewString(), picTitl, picAreaStr, created));
|
||||
QTimer::singleShot(0, this, &PictureDialog::adaptDialogSize);
|
||||
QTimer::singleShot(0, this, SLOT(adaptDialogSize()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -595,7 +617,7 @@ void PictureDialog::playerNameUpdated()
|
|||
SnapmaticPicture *picture = smpic; // used by macro
|
||||
if (plyrsList.count() >= 1) {
|
||||
ui->labJSON->setText(jsonDrawString.arg(locX, locY, locZ, generatePlayersString(), generateCrewString(), picTitl, picAreaStr, created));
|
||||
QTimer::singleShot(0, this, &PictureDialog::adaptDialogSize);
|
||||
QTimer::singleShot(0, this, SLOT(adaptDialogSize()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -604,10 +626,12 @@ QString PictureDialog::generateCrewString()
|
|||
SnapmaticPicture *picture = smpic; // used by macro
|
||||
const QString crewIDStr = crewID; // save operation time
|
||||
if (crewIDStr != "0" && !crewIDStr.isEmpty()) {
|
||||
if (crewIDStr != crewStr)
|
||||
if (crewIDStr != crewStr) {
|
||||
return QString("<a href=\"https://socialclub.rockstargames.com/crew/" % QString(crewStr).replace(" ", "_") % "/" % crewIDStr % "\">" % crewStr % "</a>");
|
||||
else
|
||||
}
|
||||
else {
|
||||
return QString(crewIDStr);
|
||||
}
|
||||
}
|
||||
return tr("No Crew");
|
||||
}
|
||||
|
@ -637,10 +661,12 @@ QString PictureDialog::generatePlayersString()
|
|||
|
||||
void PictureDialog::exportSnapmaticPicture()
|
||||
{
|
||||
if (rqFullscreen && fullscreenWidget != nullptr)
|
||||
if (rqFullscreen && fullscreenWidget != nullptr) {
|
||||
PictureExport::exportAsPicture(fullscreenWidget, smpic);
|
||||
else
|
||||
}
|
||||
else {
|
||||
PictureExport::exportAsPicture(this, smpic);
|
||||
}
|
||||
}
|
||||
|
||||
void PictureDialog::copySnapmaticPicture()
|
||||
|
@ -661,28 +687,35 @@ void PictureDialog::on_labPicture_mouseDoubleClicked(Qt::MouseButton button)
|
|||
#else
|
||||
QRect desktopRect = QApplication::desktop()->screenGeometry(this);
|
||||
#endif
|
||||
PictureWidget pictureWidget(this);
|
||||
pictureWidget.setObjectName("PictureWidget");
|
||||
pictureWidget.setWindowFlag(Qt::FramelessWindowHint, true);
|
||||
pictureWidget.setWindowFlag(Qt::MaximizeUsingFullscreenGeometryHint, true);
|
||||
pictureWidget.setWindowTitle(windowTitle());
|
||||
pictureWidget.setStyleSheet("QLabel#pictureLabel{background-color:black;}");
|
||||
pictureWidget.setImage(smpic->getImage(), desktopRect);
|
||||
pictureWidget.setModal(true);
|
||||
PictureWidget *pictureWidget = new PictureWidget(this); // Work!
|
||||
pictureWidget->setObjectName("PictureWidget");
|
||||
#if QT_VERSION >= 0x050900
|
||||
pictureWidget->setWindowFlag(Qt::FramelessWindowHint, true);
|
||||
pictureWidget->setWindowFlag(Qt::MaximizeUsingFullscreenGeometryHint, true);
|
||||
#elif QT_VERSION >= 0x050600
|
||||
pictureWidget->setWindowFlags(pictureWidget->windowFlags()^Qt::FramelessWindowHint^Qt::MaximizeUsingFullscreenGeometryHint);
|
||||
#else
|
||||
pictureWidget->setWindowFlags(pictureWidget->windowFlags()^Qt::FramelessWindowHint);
|
||||
#endif
|
||||
pictureWidget->setWindowTitle(windowTitle());
|
||||
pictureWidget->setStyleSheet("QLabel#pictureLabel{background-color:black;}");
|
||||
pictureWidget->setImage(smpic->getImage(), desktopRect);
|
||||
pictureWidget->setModal(true);
|
||||
|
||||
fullscreenWidget = &pictureWidget;
|
||||
QObject::connect(this, &PictureDialog::newPictureCommited, &pictureWidget, QOverload<QImage>::of(&PictureWidget::setImage));
|
||||
QObject::connect(&pictureWidget, &PictureWidget::nextPictureRequested, this, &PictureDialog::dialogNextPictureRequested);
|
||||
QObject::connect(&pictureWidget, &PictureWidget::previousPictureRequested, this, &PictureDialog::dialogPreviousPictureRequested);
|
||||
fullscreenWidget = pictureWidget;
|
||||
QObject::connect(this, SIGNAL(newPictureCommited(QImage)), pictureWidget, SLOT(setImage(QImage)));
|
||||
QObject::connect(pictureWidget, SIGNAL(nextPictureRequested()), this, SLOT(dialogNextPictureRequested()));
|
||||
QObject::connect(pictureWidget, SIGNAL(previousPictureRequested()), this, SLOT(dialogPreviousPictureRequested()));
|
||||
|
||||
pictureWidget.move(desktopRect.x(), desktopRect.y());
|
||||
pictureWidget.resize(desktopRect.width(), desktopRect.height());
|
||||
pictureWidget.showFullScreen();
|
||||
pictureWidget.setFocus();
|
||||
pictureWidget.raise();
|
||||
pictureWidget.exec();
|
||||
pictureWidget->move(desktopRect.x(), desktopRect.y());
|
||||
pictureWidget->resize(desktopRect.width(), desktopRect.height());
|
||||
pictureWidget->showFullScreen();
|
||||
pictureWidget->setFocus();
|
||||
pictureWidget->raise();
|
||||
pictureWidget->exec();
|
||||
|
||||
fullscreenWidget = nullptr;
|
||||
fullscreenWidget = nullptr; // Work!
|
||||
delete pictureWidget; // Work!
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -752,7 +785,7 @@ void PictureDialog::openPreviewMap()
|
|||
QJsonObject jsonObject;
|
||||
jsonObject["Type"] = "LocationEdited";
|
||||
jsonObject["ExtraFlags"] = "Viewer";
|
||||
jsonObject["EditedSize"] = QString::number(picture->getPictureSize());
|
||||
jsonObject["EditedSize"] = QString::number(picture->getContentMaxLength());
|
||||
#if QT_VERSION >= 0x060000
|
||||
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
|
||||
#else
|
||||
|
@ -780,7 +813,11 @@ void PictureDialog::editSnapmaticProperties()
|
|||
snapmaticEditor->setWindowIcon(windowIcon());
|
||||
snapmaticEditor->setSnapmaticPicture(picture);
|
||||
snapmaticEditor->setModal(true);
|
||||
#ifndef Q_OS_ANDROID
|
||||
snapmaticEditor->show();
|
||||
#else
|
||||
snapmaticEditor->showMaximized();
|
||||
#endif
|
||||
snapmaticEditor->exec();
|
||||
delete snapmaticEditor;
|
||||
}
|
||||
|
@ -801,7 +838,6 @@ void PictureDialog::editSnapmaticImage()
|
|||
importDialog->setModal(true);
|
||||
importDialog->exec();
|
||||
if (importDialog->isImportAgreed()) {
|
||||
const QSize previousSize = smpic->getPictureResolution();
|
||||
const QByteArray previousPicture = smpic->getPictureStream();
|
||||
bool success = smpic->setImage(importDialog->image(), importDialog->isUnlimitedBuffer());
|
||||
if (success) {
|
||||
|
@ -812,7 +848,7 @@ void PictureDialog::editSnapmaticImage()
|
|||
QFile::copy(currentFilePath, backupFileName);
|
||||
}
|
||||
if (!smpic->exportPicture(currentFilePath)) {
|
||||
smpic->setPictureStream(previousPicture, previousSize.width(), previousSize.height());
|
||||
smpic->setPictureStream(previousPicture);
|
||||
QMessageBox::warning(this, QApplication::translate("ImageEditorDialog", "Snapmatic Image Editor"), QApplication::translate("ImageEditorDialog", "Patching of Snapmatic Image failed because of I/O Error"));
|
||||
return;
|
||||
}
|
||||
|
@ -827,7 +863,7 @@ void PictureDialog::editSnapmaticImage()
|
|||
QJsonObject jsonObject;
|
||||
jsonObject["Type"] = "ImageEdited";
|
||||
jsonObject["ExtraFlags"] = "Viewer";
|
||||
jsonObject["EditedSize"] = QString::number(smpic->getPictureSize());
|
||||
jsonObject["EditedSize"] = QString::number(smpic->getContentMaxLength());
|
||||
#if QT_VERSION >= 0x060000
|
||||
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
|
||||
#else
|
||||
|
@ -858,7 +894,11 @@ void PictureDialog::editSnapmaticRawJson()
|
|||
}
|
||||
jsonEditor->setWindowIcon(windowIcon());
|
||||
jsonEditor->setModal(true);
|
||||
#ifndef Q_OS_ANDROID
|
||||
jsonEditor->show();
|
||||
#else
|
||||
jsonEditor->showMaximized();
|
||||
#endif
|
||||
jsonEditor->exec();
|
||||
delete jsonEditor;
|
||||
}
|
||||
|
@ -867,19 +907,21 @@ void PictureDialog::updated()
|
|||
{
|
||||
SnapmaticPicture *picture = smpic; // used by macro
|
||||
crewStr = crewDB->getCrewName(crewID);
|
||||
if (globalMap.contains(picArea))
|
||||
if (globalMap.contains(picArea)) {
|
||||
picAreaStr = globalMap[picArea];
|
||||
else
|
||||
}
|
||||
else {
|
||||
picAreaStr = picArea;
|
||||
}
|
||||
setWindowTitle(windowTitleStr.arg(picTitl));
|
||||
ui->labJSON->setText(jsonDrawString.arg(locX, locY, locZ, generatePlayersString(), generateCrewString(), picTitl, picAreaStr, created));
|
||||
QTimer::singleShot(0, this, &PictureDialog::adaptDialogSize);
|
||||
QTimer::singleShot(0, this, SLOT(adaptDialogSize()));
|
||||
}
|
||||
|
||||
void PictureDialog::customSignal(QString signal)
|
||||
{
|
||||
SnapmaticPicture *picture = smpic; // used by macro
|
||||
if (signal == QStringLiteral("PictureUpdated")) {
|
||||
if (signal == "PictureUpdated") {
|
||||
snapmaticPicture = picture->getImage();
|
||||
renderPicture();
|
||||
}
|
|
@ -124,8 +124,6 @@ private:
|
|||
int avatarLocX;
|
||||
int avatarLocY;
|
||||
int avatarSize;
|
||||
QAction *exportPhotoAction;
|
||||
QAction *openViewerAction;
|
||||
QMenu *manageMenu;
|
||||
#ifdef Q_OS_WIN
|
||||
#if QT_VERSION >= 0x050000
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2016-2023 Syping
|
||||
* Copyright (C) 2016-2020 Syping
|
||||
*
|
||||
* 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
|
||||
|
@ -21,14 +21,22 @@
|
|||
#include "PictureExport.h"
|
||||
#include "PictureDialog.h"
|
||||
#include "StandardPaths.h"
|
||||
#include "SidebarGenerator.h"
|
||||
#include <QStringBuilder>
|
||||
#include <QApplication>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include <QSettings>
|
||||
#include <QDebug>
|
||||
|
||||
#if QT_VERSION < 0x050000
|
||||
#include <QDesktopWidget>
|
||||
#endif
|
||||
|
||||
#if QT_VERSION >= 0x050000
|
||||
#include <QSaveFile>
|
||||
#include <QScreen>
|
||||
#include <QDebug>
|
||||
#endif
|
||||
|
||||
PictureExport::PictureExport()
|
||||
{
|
||||
|
@ -41,6 +49,30 @@ void PictureExport::exportAsPicture(QWidget *parent, SnapmaticPicture *picture)
|
|||
// Picture Settings
|
||||
// Quality Settings
|
||||
settings.beginGroup("Pictures");
|
||||
int defaultQuality = 100;
|
||||
QSize defExportSize = SnapmaticPicture::getSnapmaticResolution();
|
||||
int customQuality = settings.value("CustomQuality", defaultQuality).toInt();
|
||||
if (customQuality < 1 || customQuality > 100) {
|
||||
customQuality = 100;
|
||||
}
|
||||
bool useCustomQuality = settings.value("CustomQualityEnabled", false).toBool();
|
||||
|
||||
// Size Settings
|
||||
QSize cusExportSize = settings.value("CustomSize", defExportSize).toSize();
|
||||
if (cusExportSize.width() > 3840) {
|
||||
cusExportSize.setWidth(3840);
|
||||
}
|
||||
else if (cusExportSize.height() > 2160) {
|
||||
cusExportSize.setHeight(2160);
|
||||
}
|
||||
if (cusExportSize.width() < 1) {
|
||||
cusExportSize.setWidth(1);
|
||||
}
|
||||
else if (cusExportSize.height() < 1) {
|
||||
cusExportSize.setHeight(1);
|
||||
}
|
||||
QString sizeMode = settings.value("ExportSizeMode", "Default").toString();
|
||||
Qt::AspectRatioMode aspectRatio = (Qt::AspectRatioMode)settings.value("AspectRatio", Qt::KeepAspectRatio).toInt();
|
||||
QString defaultExportFormat = settings.value("DefaultExportFormat", ".jpg").toString();
|
||||
settings.endGroup();
|
||||
// End Picture Settings
|
||||
|
@ -57,7 +89,7 @@ fileDialogPreSave: //Work?
|
|||
fileDialog.setOption(QFileDialog::DontUseNativeDialog, dontUseNativeDialog);
|
||||
fileDialog.setOption(QFileDialog::DontConfirmOverwrite, true);
|
||||
fileDialog.setDefaultSuffix("suffix");
|
||||
fileDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||
fileDialog.setWindowTitle(PictureDialog::tr("Export as Picture..."));
|
||||
fileDialog.setLabelText(QFileDialog::Accept, PictureDialog::tr("Export"));
|
||||
|
||||
|
@ -65,6 +97,10 @@ fileDialogPreSave: //Work?
|
|||
filters << PictureDialog::tr("JPEG Graphics (*.jpg *.jpeg)");
|
||||
filters << PictureDialog::tr("Portable Network Graphics (*.png)");
|
||||
fileDialog.setNameFilters(filters);
|
||||
|
||||
QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls());
|
||||
|
||||
fileDialog.setSidebarUrls(sidebarUrls);
|
||||
fileDialog.setDirectory(settings.value("Directory", StandardPaths::picturesLocation()).toString());
|
||||
fileDialog.restoreGeometry(settings.value(parent->objectName() % "+Geometry", "").toByteArray());
|
||||
|
||||
|
@ -77,13 +113,16 @@ fileDialogPreSave: //Work?
|
|||
QString saveFileFormat;
|
||||
QString selectedFile = selectedFiles.at(0);
|
||||
|
||||
if (selectedFile.endsWith(".jpg") || selectedFile.endsWith(".jpeg")) {
|
||||
if (selectedFile.right(4) == ".jpg") {
|
||||
saveFileFormat = "JPEG";
|
||||
}
|
||||
else if (selectedFile.endsWith(".png")) {
|
||||
else if (selectedFile.right(4) == ".jpeg") {
|
||||
saveFileFormat = "JPEG";
|
||||
}
|
||||
else if (selectedFile.right(4) == ".png") {
|
||||
saveFileFormat = "PNG";
|
||||
}
|
||||
else if (selectedFile.endsWith(".suffix")) {
|
||||
else if (selectedFile.right(7) == ".suffix") {
|
||||
if (fileDialog.selectedNameFilter() == "JPEG picture (*.jpg)") {
|
||||
selectedFile.replace(".suffix", ".jpg");
|
||||
}
|
||||
|
@ -101,23 +140,49 @@ fileDialogPreSave: //Work?
|
|||
}
|
||||
}
|
||||
|
||||
// Scale Picture
|
||||
QImage exportPicture = picture->getImage();
|
||||
if (sizeMode == "Desktop") {
|
||||
#if QT_VERSION >= 0x050000
|
||||
qreal screenRatioPR = AppEnv::screenRatioPR();
|
||||
QRect desktopResolution = QApplication::primaryScreen()->geometry();
|
||||
int desktopSizeWidth = qRound((double)desktopResolution.width() * screenRatioPR);
|
||||
int desktopSizeHeight = qRound((double)desktopResolution.height() * screenRatioPR);
|
||||
#else
|
||||
QRect desktopResolution = QApplication::desktop()->screenGeometry();
|
||||
int desktopSizeWidth = desktopResolution.width();
|
||||
int desktopSizeHeight = desktopResolution.height();
|
||||
#endif
|
||||
exportPicture = exportPicture.scaled(desktopSizeWidth, desktopSizeHeight, aspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
else if (sizeMode == "Custom") {
|
||||
exportPicture = exportPicture.scaled(cusExportSize, aspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
|
||||
int errorId = 0;
|
||||
bool isSaved = false;
|
||||
QSaveFile picFile(selectedFile);
|
||||
if (picFile.open(QIODevice::WriteOnly)) {
|
||||
isSaved = exportPicture.save(&picFile, saveFileFormat.toStdString().c_str(), 100);
|
||||
#if QT_VERSION >= 0x050000
|
||||
QSaveFile *picFile = new QSaveFile(selectedFile);
|
||||
#else
|
||||
QFile *picFile = new QFile(selectedFile);
|
||||
#endif
|
||||
if (picFile->open(QIODevice::WriteOnly)) {
|
||||
isSaved = exportPicture.save(picFile, saveFileFormat.toStdString().c_str(), useCustomQuality ? customQuality : defaultQuality);
|
||||
#if QT_VERSION >= 0x050000
|
||||
if (isSaved) {
|
||||
isSaved = picFile.commit();
|
||||
isSaved = picFile->commit();
|
||||
}
|
||||
else {
|
||||
errorId = 1;
|
||||
}
|
||||
#else
|
||||
picFile->close();
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
errorId = 2;
|
||||
}
|
||||
delete picFile;
|
||||
|
||||
if (!isSaved) {
|
||||
switch (errorId) {
|
||||
|
@ -166,7 +231,7 @@ fileDialogPreSave: //Work?
|
|||
fileDialog.setOption(QFileDialog::DontUseNativeDialog, dontUseNativeDialog);
|
||||
fileDialog.setOption(QFileDialog::DontConfirmOverwrite, true);
|
||||
fileDialog.setDefaultSuffix(".rem");
|
||||
fileDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||
fileDialog.setWindowTitle(PictureDialog::tr("Export as Snapmatic..."));
|
||||
fileDialog.setLabelText(QFileDialog::Accept, PictureDialog::tr("Export"));
|
||||
|
||||
|
@ -177,6 +242,10 @@ fileDialogPreSave: //Work?
|
|||
#endif
|
||||
filters << PictureDialog::tr("Snapmatic pictures (PGTA*)");
|
||||
fileDialog.setNameFilters(filters);
|
||||
|
||||
QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls());
|
||||
|
||||
fileDialog.setSidebarUrls(sidebarUrls);
|
||||
fileDialog.setDirectory(settings.value("Directory", StandardPaths::documentsLocation()).toString());
|
||||
fileDialog.restoreGeometry(settings.value(parent->objectName() % "+Geometry", "").toByteArray());
|
||||
fileDialog.selectFile(QString(picture->getExportPictureFileName() % ".g5e"));
|
||||
|
@ -187,14 +256,14 @@ fileDialogPreSave: //Work?
|
|||
QString selectedFile = selectedFiles.at(0);
|
||||
bool isAutoExt = false;
|
||||
#ifndef GTA5SYNC_FLATPAK
|
||||
if (selectedFile.endsWith(".auto")) {
|
||||
if (selectedFile.right(5) == ".auto") {
|
||||
isAutoExt = true;
|
||||
QString dirPath = QFileInfo(selectedFile).dir().path();
|
||||
QString stockFileName = sgdFileInfo.fileName();
|
||||
selectedFile = dirPath % "/" % stockFileName;
|
||||
}
|
||||
#endif
|
||||
if (selectedFile.endsWith(".rem")) {
|
||||
if (selectedFile.right(4) == ".rem") {
|
||||
selectedFile.remove(selectedFile.length() - 4, 4);
|
||||
}
|
||||
|
||||
|
@ -204,7 +273,7 @@ fileDialogPreSave: //Work?
|
|||
}
|
||||
}
|
||||
|
||||
if (selectedFile.endsWith(".g5e")) {
|
||||
if (selectedFile.right(4) == ".g5e") {
|
||||
bool isExported = picture->exportPicture(selectedFile, SnapmaticFormat::G5E_Format);
|
||||
if (!isExported) {
|
||||
QMessageBox::warning(parent, PictureDialog::tr("Export as Snapmatic"), PictureDialog::tr("Failed to export current Snapmatic picture"));
|
||||
|
@ -212,7 +281,7 @@ fileDialogPreSave: //Work?
|
|||
}
|
||||
}
|
||||
else {
|
||||
bool isCopied = picture->exportPicture(selectedFile, SnapmaticFormat::PGTA5_Format);
|
||||
bool isCopied = picture->exportPicture(selectedFile, SnapmaticFormat::PGTA_Format);
|
||||
if (!isCopied) {
|
||||
QMessageBox::warning(parent, PictureDialog::tr("Export as Snapmatic"), PictureDialog::tr("Failed to export current Snapmatic picture"));
|
||||
goto fileDialogPreSave; //Work?
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2016-2023 Syping
|
||||
* Copyright (C) 2016-2021 Syping
|
||||
*
|
||||
* 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,6 +18,7 @@
|
|||
|
||||
#include "PlayerListDialog.h"
|
||||
#include "ui_PlayerListDialog.h"
|
||||
#include "wrapper.h"
|
||||
#include "AppEnv.h"
|
||||
#include <QStringBuilder>
|
||||
#include <QFontMetrics>
|
||||
|
@ -32,7 +33,11 @@ PlayerListDialog::PlayerListDialog(QStringList players, ProfileDatabase *profile
|
|||
ui(new Ui::PlayerListDialog)
|
||||
{
|
||||
// Set Window Flags
|
||||
#if QT_VERSION >= 0x050900
|
||||
setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
#else
|
||||
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||
#endif
|
||||
|
||||
listUpdated = false;
|
||||
ui->setupUi(this);
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2016-2023 Syping
|
||||
* Copyright (C) 2016-2021 Syping
|
||||
*
|
||||
* 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
|
||||
|
@ -24,6 +24,7 @@
|
|||
#include "ProfileDatabase.h"
|
||||
#include "DatabaseThread.h"
|
||||
#include "SavegameWidget.h"
|
||||
#include "ProfileLoader.h"
|
||||
#include "ProfileWidget.h"
|
||||
#include "ExportThread.h"
|
||||
#include "SavegameData.h"
|
||||
|
@ -48,7 +49,7 @@ class ProfileInterface : public QWidget
|
|||
Q_OBJECT
|
||||
public:
|
||||
explicit ProfileInterface(ProfileDatabase *profileDB, CrewDatabase *crewDB, DatabaseThread *threadDB, QWidget *parent = 0);
|
||||
void setProfileFolder(QString folder, QString profile, quint32 defaultPhotoFormat);
|
||||
void setProfileFolder(QString folder, QString profile);
|
||||
void settingsApplied(int contentMode, bool languageChanged);
|
||||
void setupProfileInterface();
|
||||
void massTool(MassTool tool);
|
||||
|
@ -89,8 +90,10 @@ private slots:
|
|||
void dialogNextPictureRequested(QWidget *dialog);
|
||||
void dialogPreviousPictureRequested(QWidget *dialog);
|
||||
void on_saProfileContent_dropped(const QMimeData *mimeData);
|
||||
#if QT_VERSION >= 0x050000
|
||||
void directoryChanged(const QString &path);
|
||||
void directoryScanned(QVector<QString> savegameFiles, QVector<QString> snapmaticPics);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *watched, QEvent *event);
|
||||
|
@ -101,13 +104,16 @@ private:
|
|||
DatabaseThread *threadDB;
|
||||
Ui::ProfileInterface *ui;
|
||||
|
||||
ProfileLoader *profileLoader;
|
||||
ProfileWidget *previousWidget;
|
||||
QList<SavegameData*> savegames;
|
||||
QList<SnapmaticPicture*> pictures;
|
||||
QHash<ProfileWidget*,QString> widgets;
|
||||
QMap<ProfileWidget*,QString> widgets;
|
||||
#if QT_VERSION >= 0x050000
|
||||
QFileSystemWatcher fileSystemWatcher;
|
||||
QVector<QString> savegameFiles;
|
||||
QVector<QString> snapmaticPics;
|
||||
#endif
|
||||
QSpacerItem *saSpacerItem;
|
||||
QStringList fixedPictures;
|
||||
QString enabledPicStr;
|
||||
|
@ -115,7 +121,6 @@ private:
|
|||
QString profileName;
|
||||
QString loadingStr;
|
||||
QString language;
|
||||
quint32 photoFormat;
|
||||
pcg32_random_t rng;
|
||||
bool contextMenuOpened;
|
||||
bool isProfileLoaded;
|
||||
|
@ -129,6 +134,7 @@ private:
|
|||
bool importImage(QImage *snapmaticImage, QDateTime importDateTime);
|
||||
bool importFilesProgress(QStringList selectedFiles);
|
||||
bool importSnapmaticPicture(SnapmaticPicture *picture, bool warn = true);
|
||||
bool importSavegameData(SavegameData *savegame, QString sgdPath, bool warn = true);
|
||||
void pictureLoaded(SnapmaticPicture *picture, bool inserted);
|
||||
void savegameLoaded(SavegameData *savegame, QString savegamePath, bool inserted);
|
||||
void savegameDeleted(SavegameWidget *sgdWidget, bool isRemoteEmited = false);
|
||||
|
@ -137,7 +143,7 @@ private:
|
|||
void insertSnapmaticIPI(QWidget *widget);
|
||||
void insertSavegameIPI(QWidget *widget);
|
||||
void sortingProfileInterface();
|
||||
quint32 getRandomUid();
|
||||
int getRandomUid();
|
||||
|
||||
signals:
|
||||
void profileLoaded();
|
|
@ -20,6 +20,7 @@
|
|||
#include "ProfileLoader.h"
|
||||
#include "SavegameData.h"
|
||||
#include "CrewDatabase.h"
|
||||
#include "wrapper.h"
|
||||
#include <QStringBuilder>
|
||||
#include <QVector>
|
||||
#include <QString>
|
||||
|
@ -28,9 +29,9 @@
|
|||
#include <QDir>
|
||||
#include <QList>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include "sys/types.h"
|
||||
#include "sys/stat.h"
|
||||
#include "dirent.h"
|
||||
#endif
|
||||
|
||||
ProfileLoader::ProfileLoader(QString profileFolder, CrewDatabase *crewDB, QObject *parent) : QThread(parent), profileFolder(profileFolder), crewDB(crewDB)
|
||||
|
@ -45,18 +46,40 @@ void ProfileLoader::run()
|
|||
QVector<QString> savegameFiles;
|
||||
QVector<QString> snapmaticPics;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QDir dir(profileFolder);
|
||||
const QStringList files = dir.entryList(QDir::Files);
|
||||
for (const QString &fileName : files) {
|
||||
if ((fileName.startsWith("SGTA5") || fileName.startsWith("SRDR3")) && !fileName.endsWith(".bak")) {
|
||||
if (fileName.startsWith("SGTA5") && !fileName.endsWith(".bak")) {
|
||||
savegameFiles << fileName;
|
||||
maximumV++;
|
||||
}
|
||||
if ((fileName.startsWith("PGTA5") || fileName.startsWith("PRDR3")) && !fileName.endsWith(".bak")) {
|
||||
if (fileName.startsWith("PGTA5") && !fileName.endsWith(".bak")) {
|
||||
snapmaticPics << fileName;
|
||||
maximumV++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
DIR *dirp = opendir(profileFolder.toUtf8().constData());
|
||||
struct dirent *dp;
|
||||
while ((dp = readdir(dirp)) != 0) {
|
||||
const QString fileName = QString::fromUtf8(dp->d_name);
|
||||
const QString filePath = profileFolder % "/" % fileName;
|
||||
struct stat fileStat;
|
||||
stat(filePath.toUtf8().constData(), &fileStat);
|
||||
if (S_ISREG(fileStat.st_mode) != 0) {
|
||||
if (fileName.startsWith("SGTA5") && !fileName.endsWith(".bak")) {
|
||||
savegameFiles << fileName;
|
||||
maximumV++;
|
||||
}
|
||||
if (fileName.startsWith("PGTA5") && !fileName.endsWith(".bak")) {
|
||||
snapmaticPics << fileName;
|
||||
maximumV++;
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dirp);
|
||||
#endif
|
||||
|
||||
// Directory successfully scanned
|
||||
emit directoryScanned(savegameFiles, snapmaticPics);
|
||||
|
@ -78,8 +101,8 @@ void ProfileLoader::run()
|
|||
SnapmaticPicture *picture = new SnapmaticPicture(picturePath);
|
||||
if (picture->readingPicture(true)) {
|
||||
if (picture->isFormatSwitched()) {
|
||||
picture->setSnapmaticFormat(SnapmaticFormat::PGTA5_Format);
|
||||
if (picture->exportPicture(picturePath, SnapmaticFormat::PGTA5_Format)) {
|
||||
picture->setSnapmaticFormat(SnapmaticFormat::PGTA_Format);
|
||||
if (picture->exportPicture(picturePath, SnapmaticFormat::PGTA_Format)) {
|
||||
emit pictureFixed(picture);
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ Open Source Snapmatic and Savegame viewer/editor for GTA V
|
|||
|
||||
# Note: Install Docker Community Edition and Git before continuing
|
||||
docker pull sypingauto/gta5view-build:1.10-static
|
||||
git clone --recurse-submodules https://gitlab.com/Syping/gta5view
|
||||
git clone https://gitlab.com/Syping/gta5view
|
||||
docker run --rm -v "$PWD/gta5view:/gta5view" -it sypingauto/gta5view-build:1.10-static
|
||||
mingw64-qt-cmake -B /gta5view/build /gta5view
|
||||
cmake --build /gta5view/build
|
||||
|
@ -23,7 +23,7 @@ Open Source Snapmatic and Savegame viewer/editor for GTA V
|
|||
#### Build gta5view for Debian/Ubuntu
|
||||
|
||||
sudo apt-get install cmake git gcc g++ libqt5svg5-dev make qtbase5-dev qttranslations5-l10n
|
||||
git clone --recurse-submodules https://gitlab.com/Syping/gta5view
|
||||
git clone https://gitlab.com/Syping/gta5view
|
||||
cmake -B gta5view-build gta5view
|
||||
cmake --build gta5view-build
|
||||
sudo cmake --install gta5view-build
|
||||
|
@ -31,7 +31,7 @@ Open Source Snapmatic and Savegame viewer/editor for GTA V
|
|||
#### Build gta5view for Arch/Manjaro
|
||||
|
||||
sudo pacman -S cmake gcc git make qt5-base qt5-svg qt5-tools qt5-translations
|
||||
git clone --recurse-submodules https://gitlab.com/Syping/gta5view
|
||||
git clone https://gitlab.com/Syping/gta5view
|
||||
cmake -B gta5view-build gta5view
|
||||
cmake --build gta5view-build
|
||||
sudo cmake --install gta5view-build
|
||||
|
@ -39,7 +39,7 @@ Open Source Snapmatic and Savegame viewer/editor for GTA V
|
|||
#### Build gta5view for Fedora/RHEL
|
||||
|
||||
sudo dnf install cmake git gcc gcc-c++ make qt5-qtbase-devel qt5-qtsvg-devel qt5-qttranslations
|
||||
git clone --recurse-submodules https://gitlab.com/Syping/gta5view
|
||||
git clone https://gitlab.com/Syping/gta5view
|
||||
cmake -B gta5view-build gta5view
|
||||
cmake --build gta5view-build
|
||||
sudo cmake --install gta5view-build
|
||||
|
|
893
RagePhoto.cpp
Normal file
893
RagePhoto.cpp
Normal file
|
@ -0,0 +1,893 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2020-2022 Syping
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "RagePhoto.h"
|
||||
#include <QJsonDocument>
|
||||
#include <QBuffer>
|
||||
#include <QFile>
|
||||
#if QT_VERSION < 0x060000
|
||||
#include <QTextCodec>
|
||||
#else
|
||||
#include <QStringEncoder>
|
||||
#include <QStringDecoder>
|
||||
#endif
|
||||
#ifdef RAGEPHOTO_BENCHMARK
|
||||
#include <QFileInfo>
|
||||
#include <chrono>
|
||||
#endif
|
||||
|
||||
inline quint32 joaatFromSI(const char *data, size_t size)
|
||||
{
|
||||
quint32 val = 0xE47AB81CUL;
|
||||
for (size_t i = 0; i != size; i++) {
|
||||
val += data[i];
|
||||
val += (val << 10);
|
||||
val ^= (val >> 6);
|
||||
}
|
||||
val += (val << 3);
|
||||
val ^= (val >> 11);
|
||||
val += (val << 15);
|
||||
return val;
|
||||
}
|
||||
|
||||
RagePhoto::RagePhoto()
|
||||
{
|
||||
p_photoFormat = PhotoFormat::Undefined;
|
||||
p_isLoaded = false;
|
||||
p_inputMode = -1;
|
||||
}
|
||||
|
||||
RagePhoto::RagePhoto(const QByteArray &data) : p_fileData(data)
|
||||
{
|
||||
p_photoFormat = PhotoFormat::Undefined;
|
||||
p_isLoaded = false;
|
||||
p_inputMode = 0;
|
||||
}
|
||||
|
||||
RagePhoto::RagePhoto(const QString &filePath) : p_filePath(filePath)
|
||||
{
|
||||
p_photoFormat = PhotoFormat::Undefined;
|
||||
p_isLoaded = false;
|
||||
p_inputMode = 1;
|
||||
}
|
||||
|
||||
RagePhoto::RagePhoto(QIODevice *ioDevice) : p_ioDevice(ioDevice)
|
||||
{
|
||||
p_photoFormat = PhotoFormat::Undefined;
|
||||
p_isLoaded = false;
|
||||
p_inputMode = 2;
|
||||
}
|
||||
|
||||
bool RagePhoto::isLoaded()
|
||||
{
|
||||
return p_isLoaded;
|
||||
}
|
||||
|
||||
bool RagePhoto::load()
|
||||
{
|
||||
if (p_inputMode == -1)
|
||||
return false;
|
||||
|
||||
if (p_isLoaded)
|
||||
clear();
|
||||
|
||||
if (p_inputMode == 1) {
|
||||
QFile pictureFile(p_filePath);
|
||||
if (pictureFile.open(QIODevice::ReadOnly)) {
|
||||
p_fileData = pictureFile.readAll();
|
||||
}
|
||||
pictureFile.close();
|
||||
}
|
||||
else if (p_inputMode == 2) {
|
||||
if (!p_ioDevice->isOpen()) {
|
||||
if (!p_ioDevice->open(QIODevice::ReadOnly))
|
||||
return false;
|
||||
}
|
||||
p_fileData = p_ioDevice->readAll();
|
||||
}
|
||||
|
||||
QBuffer dataBuffer(&p_fileData);
|
||||
dataBuffer.open(QIODevice::ReadOnly);
|
||||
|
||||
#ifdef RAGEPHOTO_BENCHMARK
|
||||
auto benchmark_parse_start = std::chrono::high_resolution_clock::now();
|
||||
#endif
|
||||
|
||||
char uInt32Buffer[4];
|
||||
qint64 size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
quint32 format = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
if (format == static_cast<quint32>(PhotoFormat::GTA5)) {
|
||||
char photoHeader[256];
|
||||
size = dataBuffer.read(photoHeader, 256);
|
||||
if (size != 256) {
|
||||
return false;
|
||||
}
|
||||
for (const QChar &photoChar : utf16LEToString(photoHeader, 256)) {
|
||||
if (photoChar.isNull())
|
||||
break;
|
||||
p_photoString += photoChar;
|
||||
}
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_headerSum = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_endOfFile = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_jsonOffset = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_titlOffset = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_descOffset = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
char markerBuffer[4];
|
||||
size = dataBuffer.read(markerBuffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
if (strncmp(markerBuffer, "JPEG", 4) != 0)
|
||||
return false;
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_photoBuffer = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
quint32 t_photoSize = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
char *photoData = static_cast<char*>(malloc(t_photoSize));
|
||||
if (!photoData)
|
||||
return false;
|
||||
size = dataBuffer.read(photoData, t_photoSize);
|
||||
if (size != t_photoSize) {
|
||||
free(photoData);
|
||||
return false;
|
||||
}
|
||||
p_photoData = QByteArray(photoData, t_photoSize);
|
||||
free(photoData);
|
||||
|
||||
dataBuffer.seek(p_jsonOffset + 264);
|
||||
size = dataBuffer.read(markerBuffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
if (strncmp(markerBuffer, "JSON", 4) != 0)
|
||||
return false;
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_jsonBuffer = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
char *jsonBytes = static_cast<char*>(malloc(p_jsonBuffer));
|
||||
if (!jsonBytes)
|
||||
return false;
|
||||
size = dataBuffer.read(jsonBytes, p_jsonBuffer);
|
||||
if (size != p_jsonBuffer) {
|
||||
free(jsonBytes);
|
||||
return false;
|
||||
}
|
||||
quint32 i;
|
||||
for (i = 0; i != p_jsonBuffer; i++) {
|
||||
if (jsonBytes[i] == '\x00')
|
||||
break;
|
||||
}
|
||||
p_jsonData = QByteArray(jsonBytes, i);
|
||||
free(jsonBytes);
|
||||
QJsonDocument t_jsonDocument = QJsonDocument::fromJson(p_jsonData);
|
||||
if (t_jsonDocument.isNull())
|
||||
return false;
|
||||
p_jsonObject = t_jsonDocument.object();
|
||||
|
||||
dataBuffer.seek(p_titlOffset + 264);
|
||||
size = dataBuffer.read(markerBuffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
if (strncmp(markerBuffer, "TITL", 4) != 0)
|
||||
return false;
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_titlBuffer = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
char *titlBytes = static_cast<char*>(malloc(p_titlBuffer));
|
||||
if (!titlBytes)
|
||||
return false;
|
||||
size = dataBuffer.read(titlBytes, p_titlBuffer);
|
||||
if (size != p_titlBuffer){
|
||||
free(titlBytes);
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i != p_titlBuffer; i++) {
|
||||
if (titlBytes[i] == '\x00')
|
||||
break;
|
||||
}
|
||||
p_titleString = QString::fromUtf8(titlBytes, i);
|
||||
free(titlBytes);
|
||||
|
||||
dataBuffer.seek(p_descOffset + 264);
|
||||
size = dataBuffer.read(markerBuffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
if (strncmp(markerBuffer, "DESC", 4) != 0)
|
||||
return false;
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_descBuffer = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
char *descBytes = static_cast<char*>(malloc(p_descBuffer));
|
||||
if (!descBytes)
|
||||
return false;
|
||||
size = dataBuffer.read(descBytes, p_descBuffer);
|
||||
if (size != p_descBuffer) {
|
||||
free(descBytes);
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i != p_descBuffer; i++) {
|
||||
if (descBytes[i] == '\x00')
|
||||
break;
|
||||
}
|
||||
p_descriptionString = QString::fromUtf8(descBytes, i);
|
||||
free(descBytes);
|
||||
|
||||
dataBuffer.seek(p_endOfFile + 260);
|
||||
size = dataBuffer.read(markerBuffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
if (strncmp(markerBuffer, "JEND", 4) != 0)
|
||||
return false;
|
||||
|
||||
#ifdef RAGEPHOTO_BENCHMARK
|
||||
auto benchmark_parse_end = std::chrono::high_resolution_clock::now();
|
||||
auto benchmark_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(benchmark_parse_end - benchmark_parse_start);
|
||||
if (p_inputMode == 1) {
|
||||
QTextStream(stdout) << QFileInfo(p_filePath).fileName() << ": " << benchmark_ns.count() << "ns" << Qt::endl;
|
||||
}
|
||||
else {
|
||||
QTextStream(stdout) << "PGTA5" << p_jsonObject.value("uid").toInt() << ": " << benchmark_ns.count() << "ns" << Qt::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (p_photoFormat != PhotoFormat::G5EX)
|
||||
p_photoFormat = PhotoFormat::GTA5;
|
||||
|
||||
p_fileData.clear();
|
||||
p_isLoaded = true;
|
||||
return true;
|
||||
}
|
||||
else if (format == static_cast<quint32>(PhotoFormat::G5EX)) {
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
format = charToUInt32LE(uInt32Buffer);
|
||||
if (format == static_cast<quint32>(ExportFormat::G5E3P)) {
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
quint32 compressedSize = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
char *compressedPhotoHeader = static_cast<char*>(malloc(compressedSize));
|
||||
if (!compressedPhotoHeader)
|
||||
return false;
|
||||
size = dataBuffer.read(compressedPhotoHeader, compressedSize);
|
||||
if (size != compressedSize) {
|
||||
free(compressedPhotoHeader);
|
||||
return false;
|
||||
}
|
||||
QByteArray t_photoHeader = QByteArray::fromRawData(compressedPhotoHeader, compressedSize);
|
||||
t_photoHeader = qUncompress(t_photoHeader);
|
||||
free(compressedPhotoHeader);
|
||||
if (t_photoHeader.isEmpty())
|
||||
return false;
|
||||
p_photoString = QString::fromUtf8(t_photoHeader);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_headerSum = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_photoBuffer = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
compressedSize = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
char *compressedPhoto = static_cast<char*>(malloc(compressedSize));
|
||||
if (!compressedPhoto)
|
||||
return false;
|
||||
size = dataBuffer.read(compressedPhoto, compressedSize);
|
||||
if (size != compressedSize) {
|
||||
free(compressedPhoto);
|
||||
return false;
|
||||
}
|
||||
QByteArray t_photoData = QByteArray::fromRawData(compressedPhoto, compressedSize);
|
||||
p_photoData = qUncompress(t_photoData);
|
||||
free(compressedPhoto);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_jsonOffset = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_jsonBuffer = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
compressedSize = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
char *compressedJson = static_cast<char*>(malloc(compressedSize));
|
||||
if (!compressedJson)
|
||||
return false;
|
||||
size = dataBuffer.read(compressedJson, compressedSize);
|
||||
if (size != compressedSize) {
|
||||
free(compressedJson);
|
||||
return false;
|
||||
}
|
||||
QByteArray t_jsonBytes = QByteArray::fromRawData(compressedJson, compressedSize);
|
||||
p_jsonData = qUncompress(t_jsonBytes);
|
||||
free(compressedJson);
|
||||
if (p_jsonData.isEmpty())
|
||||
return false;
|
||||
QJsonDocument t_jsonDocument = QJsonDocument::fromJson(p_jsonData);
|
||||
if (t_jsonDocument.isNull())
|
||||
return false;
|
||||
p_jsonObject = t_jsonDocument.object();
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_titlOffset = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_titlBuffer = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
compressedSize = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
char *compressedTitl = static_cast<char*>(malloc(compressedSize));
|
||||
if (!compressedTitl)
|
||||
return false;
|
||||
size = dataBuffer.read(compressedTitl, compressedSize);
|
||||
if (size != compressedSize) {
|
||||
free(compressedTitl);
|
||||
return false;
|
||||
}
|
||||
QByteArray t_titlBytes = QByteArray::fromRawData(compressedTitl, compressedSize);
|
||||
t_titlBytes = qUncompress(t_titlBytes);
|
||||
free(compressedTitl);
|
||||
p_titleString = QString::fromUtf8(t_titlBytes);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_descOffset = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_descBuffer = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
compressedSize = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
char *compressedDesc = static_cast<char*>(malloc(compressedSize));
|
||||
if (!compressedDesc)
|
||||
return false;
|
||||
size = dataBuffer.read(compressedDesc, compressedSize);
|
||||
if (size != compressedSize) {
|
||||
free(compressedDesc);
|
||||
return false;
|
||||
}
|
||||
QByteArray t_descBytes = QByteArray::fromRawData(compressedDesc, compressedSize);
|
||||
t_descBytes = qUncompress(t_descBytes);
|
||||
free(compressedDesc);
|
||||
p_descriptionString = QString::fromUtf8(t_descBytes);
|
||||
|
||||
size = dataBuffer.read(uInt32Buffer, 4);
|
||||
if (size != 4)
|
||||
return false;
|
||||
p_endOfFile = charToUInt32LE(uInt32Buffer);
|
||||
|
||||
#ifdef RAGEPHOTO_BENCHMARK
|
||||
auto benchmark_parse_end = std::chrono::high_resolution_clock::now();
|
||||
auto benchmark_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(benchmark_parse_end - benchmark_parse_start);
|
||||
if (p_inputMode == 1) {
|
||||
QTextStream(stdout) << QFileInfo(p_filePath).fileName() << ": " << benchmark_ns.count() << "ns" << Qt::endl;
|
||||
}
|
||||
else {
|
||||
QTextStream(stdout) << "PGTA5" << p_jsonObject.value("uid").toInt() << ": " << benchmark_ns.count() << "ns" << Qt::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
p_photoFormat = PhotoFormat::G5EX;
|
||||
|
||||
p_fileData.clear();
|
||||
p_isLoaded = true;
|
||||
return true;
|
||||
}
|
||||
else if (format == static_cast<quint32>(ExportFormat::G5E2P)) {
|
||||
p_photoFormat = PhotoFormat::G5EX;
|
||||
p_fileData = qUncompress(dataBuffer.readAll());
|
||||
if (p_fileData.isEmpty())
|
||||
return false;
|
||||
p_inputMode = 0;
|
||||
return load();
|
||||
}
|
||||
else if (format == static_cast<quint32>(ExportFormat::G5E1P)) {
|
||||
#if QT_VERSION >= 0x050A00
|
||||
size = dataBuffer.skip(1);
|
||||
if (size != 1)
|
||||
return false;
|
||||
#else
|
||||
if (!dataBuffer.seek(dataBuffer.pos() + 1))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
char length[1];
|
||||
size = dataBuffer.read(length, 1);
|
||||
if (size != 1)
|
||||
return false;
|
||||
int i_length = QByteArray::number(static_cast<int>(length[0]), 16).toInt() + 6;
|
||||
|
||||
#if QT_VERSION >= 0x050A00
|
||||
size = dataBuffer.skip(i_length);
|
||||
if (size != i_length)
|
||||
return false;
|
||||
#else
|
||||
if (!dataBuffer.seek(dataBuffer.pos() + i_length))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
p_photoFormat = PhotoFormat::G5EX;
|
||||
p_fileData = qUncompress(dataBuffer.readAll());
|
||||
if (p_fileData.isEmpty())
|
||||
return false;
|
||||
p_inputMode = 0;
|
||||
return load();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void RagePhoto::clear()
|
||||
{
|
||||
p_photoFormat = PhotoFormat::Undefined;
|
||||
p_jsonObject = QJsonObject();
|
||||
p_descriptionString.clear();
|
||||
p_jsonData.clear();
|
||||
p_photoData.clear();
|
||||
p_photoString.clear();
|
||||
p_titleString.clear();
|
||||
p_headerSum = 0;
|
||||
p_isLoaded = false;
|
||||
}
|
||||
|
||||
void RagePhoto::setDescription(const QString &description)
|
||||
{
|
||||
p_descriptionString = description;
|
||||
}
|
||||
|
||||
void RagePhoto::setFileData(const QByteArray &data)
|
||||
{
|
||||
p_fileData = data;
|
||||
p_inputMode = 0;
|
||||
}
|
||||
|
||||
void RagePhoto::setFilePath(const QString &filePath)
|
||||
{
|
||||
p_filePath = filePath;
|
||||
p_inputMode = 1;
|
||||
}
|
||||
|
||||
void RagePhoto::setIODevice(QIODevice *ioDevice)
|
||||
{
|
||||
p_ioDevice = ioDevice;
|
||||
p_inputMode = 2;
|
||||
}
|
||||
|
||||
bool RagePhoto::setJsonData(const QByteArray &data)
|
||||
{
|
||||
QJsonDocument t_jsonDocument = QJsonDocument::fromJson(data);
|
||||
if (t_jsonDocument.isNull())
|
||||
return false;
|
||||
p_jsonObject = t_jsonDocument.object();
|
||||
// serializer band-aid
|
||||
QJsonObject t_jsonObject = p_jsonObject;
|
||||
t_jsonObject["sign"] = "__gta5view.sign";
|
||||
t_jsonDocument.setObject(t_jsonObject);
|
||||
p_jsonData = t_jsonDocument.toJson(QJsonDocument::Compact);
|
||||
char sign_char[24];
|
||||
sprintf(sign_char, "%llu", (0x100000000000000ULL | joaatFromSI(p_photoData.constData(), p_photoData.size())));
|
||||
p_jsonData.replace("\"__gta5view.sign\"", sign_char);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RagePhoto::setPhotoBuffer(quint32 size, bool moveOffsets)
|
||||
{
|
||||
if (size < static_cast<quint32>(p_photoData.size()))
|
||||
return false;
|
||||
p_photoBuffer = size;
|
||||
if (moveOffsets) {
|
||||
p_jsonOffset = size + 28;
|
||||
p_titlOffset = p_jsonOffset + p_jsonBuffer + 8;
|
||||
p_descOffset = p_titlOffset + p_titlBuffer + 8;
|
||||
p_endOfFile = p_descOffset + p_descBuffer + 12;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RagePhoto::setPhotoData(const QByteArray &data)
|
||||
{
|
||||
quint32 size = data.size();
|
||||
if (size > p_photoBuffer)
|
||||
return false;
|
||||
p_photoData = data;
|
||||
// serializer band-aid
|
||||
setJsonData(p_jsonData);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RagePhoto::setPhotoData(const char *data, int size)
|
||||
{
|
||||
if (static_cast<quint32>(size) > p_photoBuffer)
|
||||
return false;
|
||||
p_photoData = QByteArray(data, size);
|
||||
// serializer band-aid
|
||||
setJsonData(p_jsonData);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RagePhoto::setPhotoFormat(PhotoFormat photoFormat)
|
||||
{
|
||||
p_photoFormat = photoFormat;
|
||||
}
|
||||
|
||||
void RagePhoto::setTitle(const QString &title)
|
||||
{
|
||||
p_titleString = title;
|
||||
}
|
||||
|
||||
const QByteArray RagePhoto::jsonData(JsonFormat jsonFormat)
|
||||
{
|
||||
if (jsonFormat == JsonFormat::Compact) {
|
||||
return QJsonDocument(p_jsonObject).toJson(QJsonDocument::Compact);
|
||||
}
|
||||
else if (jsonFormat == JsonFormat::Indented) {
|
||||
return QJsonDocument(p_jsonObject).toJson(QJsonDocument::Indented);
|
||||
}
|
||||
else {
|
||||
return p_jsonData;
|
||||
}
|
||||
}
|
||||
|
||||
const QJsonObject RagePhoto::jsonObject()
|
||||
{
|
||||
return p_jsonObject;
|
||||
}
|
||||
|
||||
const QByteArray RagePhoto::photoData()
|
||||
{
|
||||
return p_photoData;
|
||||
}
|
||||
|
||||
const QString RagePhoto::description()
|
||||
{
|
||||
return p_descriptionString;
|
||||
}
|
||||
|
||||
const QString RagePhoto::photoString()
|
||||
{
|
||||
return p_photoString;
|
||||
}
|
||||
|
||||
const QString RagePhoto::title()
|
||||
{
|
||||
return p_titleString;
|
||||
}
|
||||
|
||||
quint32 RagePhoto::photoBuffer()
|
||||
{
|
||||
return p_photoBuffer;
|
||||
}
|
||||
|
||||
quint32 RagePhoto::photoSize()
|
||||
{
|
||||
return p_photoData.size();
|
||||
}
|
||||
|
||||
RagePhoto::PhotoFormat RagePhoto::photoFormat()
|
||||
{
|
||||
return p_photoFormat;
|
||||
}
|
||||
|
||||
QByteArray RagePhoto::save(PhotoFormat photoFormat)
|
||||
{
|
||||
QByteArray data;
|
||||
QBuffer dataBuffer(&data);
|
||||
dataBuffer.open(QIODevice::WriteOnly);
|
||||
save(&dataBuffer, photoFormat);
|
||||
return data;
|
||||
}
|
||||
|
||||
void RagePhoto::save(QIODevice *ioDevice, PhotoFormat photoFormat)
|
||||
{
|
||||
// serializer band-aid
|
||||
setJsonData(p_jsonData);
|
||||
|
||||
if (photoFormat == PhotoFormat::G5EX) {
|
||||
char uInt32Buffer[4];
|
||||
quint32 format = static_cast<quint32>(PhotoFormat::G5EX);
|
||||
uInt32ToCharLE(format, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
format = static_cast<quint32>(ExportFormat::G5E3P);
|
||||
uInt32ToCharLE(format, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
QByteArray compressedData = qCompress(p_photoString.toUtf8(), 9);
|
||||
quint32 compressedSize = compressedData.size();
|
||||
uInt32ToCharLE(compressedSize, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
ioDevice->write(compressedData);
|
||||
|
||||
uInt32ToCharLE(p_headerSum, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
uInt32ToCharLE(p_photoBuffer, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
compressedData = qCompress(p_photoData, 9);
|
||||
compressedSize = compressedData.size();
|
||||
uInt32ToCharLE(compressedSize, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
ioDevice->write(compressedData);
|
||||
|
||||
uInt32ToCharLE(p_jsonOffset, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
uInt32ToCharLE(p_jsonBuffer, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
compressedData = qCompress(p_jsonData, 9);
|
||||
compressedSize = compressedData.size();
|
||||
uInt32ToCharLE(compressedSize, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
ioDevice->write(compressedData);
|
||||
|
||||
uInt32ToCharLE(p_titlOffset, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
uInt32ToCharLE(p_titlBuffer, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
compressedData = qCompress(p_titleString.toUtf8(), 9);
|
||||
compressedSize = compressedData.size();
|
||||
uInt32ToCharLE(compressedSize, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
ioDevice->write(compressedData);
|
||||
|
||||
uInt32ToCharLE(p_descOffset, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
uInt32ToCharLE(p_descBuffer, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
compressedData = qCompress(p_descriptionString.toUtf8(), 9);
|
||||
compressedSize = compressedData.size();
|
||||
uInt32ToCharLE(compressedSize, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
ioDevice->write(compressedData);
|
||||
|
||||
uInt32ToCharLE(p_endOfFile, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
}
|
||||
else if (photoFormat == PhotoFormat::GTA5) {
|
||||
char uInt32Buffer[4];
|
||||
quint32 format = static_cast<quint32>(PhotoFormat::GTA5);
|
||||
uInt32ToCharLE(format, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
QByteArray photoHeader = stringToUtf16LE(p_photoString);
|
||||
if (photoHeader.startsWith("\xFF\xFE")) {
|
||||
photoHeader.remove(0, 2);
|
||||
}
|
||||
qint64 photoHeaderSize = photoHeader.size();
|
||||
if (photoHeaderSize > 256) {
|
||||
photoHeader = photoHeader.left(256);
|
||||
photoHeaderSize = 256;
|
||||
}
|
||||
ioDevice->write(photoHeader);
|
||||
for (qint64 size = photoHeaderSize; size < 256; size++) {
|
||||
ioDevice->write("\x00", 1);
|
||||
}
|
||||
|
||||
uInt32ToCharLE(p_headerSum, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
uInt32ToCharLE(p_endOfFile, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
uInt32ToCharLE(p_jsonOffset, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
uInt32ToCharLE(p_titlOffset, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
uInt32ToCharLE(p_descOffset, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
ioDevice->write("JPEG", 4);
|
||||
|
||||
uInt32ToCharLE(p_photoBuffer, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
quint32 t_photoSize = p_photoData.size();
|
||||
uInt32ToCharLE(t_photoSize, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
ioDevice->write(p_photoData);
|
||||
for (qint64 size = t_photoSize; size < p_photoBuffer; size++) {
|
||||
ioDevice->write("\x00", 1);
|
||||
}
|
||||
|
||||
ioDevice->seek(p_jsonOffset + 264);
|
||||
ioDevice->write("JSON", 4);
|
||||
|
||||
uInt32ToCharLE(p_jsonBuffer, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
qint64 dataSize = p_jsonData.size();
|
||||
ioDevice->write(p_jsonData);
|
||||
for (qint64 size = dataSize; size < p_jsonBuffer; size++) {
|
||||
ioDevice->write("\x00", 1);
|
||||
}
|
||||
|
||||
ioDevice->seek(p_titlOffset + 264);
|
||||
ioDevice->write("TITL", 4);
|
||||
|
||||
uInt32ToCharLE(p_titlBuffer, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
QByteArray data = p_titleString.toUtf8();
|
||||
dataSize = data.size();
|
||||
ioDevice->write(data);
|
||||
for (qint64 size = dataSize; size < p_titlBuffer; size++) {
|
||||
ioDevice->write("\x00", 1);
|
||||
}
|
||||
|
||||
ioDevice->seek(p_descOffset + 264);
|
||||
ioDevice->write("DESC", 4);
|
||||
|
||||
uInt32ToCharLE(p_descBuffer, uInt32Buffer);
|
||||
ioDevice->write(uInt32Buffer, 4);
|
||||
|
||||
data = p_descriptionString.toUtf8();
|
||||
dataSize = data.size();
|
||||
ioDevice->write(data);
|
||||
for (qint64 size = dataSize; size < p_descBuffer; size++) {
|
||||
ioDevice->write("\x00", 1);
|
||||
}
|
||||
|
||||
ioDevice->seek(p_endOfFile + 260);
|
||||
ioDevice->write("JEND", 4);
|
||||
}
|
||||
}
|
||||
|
||||
RagePhoto* RagePhoto::loadFile(const QString &filePath)
|
||||
{
|
||||
RagePhoto *ragePhoto = new RagePhoto(filePath);
|
||||
ragePhoto->load();
|
||||
return ragePhoto;
|
||||
}
|
||||
|
||||
quint32 RagePhoto::charToUInt32BE(char *x)
|
||||
{
|
||||
return (static_cast<unsigned char>(x[0]) << 24 |
|
||||
static_cast<unsigned char>(x[1]) << 16 |
|
||||
static_cast<unsigned char>(x[2]) << 8 |
|
||||
static_cast<unsigned char>(x[3]));
|
||||
}
|
||||
|
||||
quint32 RagePhoto::charToUInt32LE(char *x)
|
||||
{
|
||||
return (static_cast<unsigned char>(x[3]) << 24 |
|
||||
static_cast<unsigned char>(x[2]) << 16 |
|
||||
static_cast<unsigned char>(x[1]) << 8 |
|
||||
static_cast<unsigned char>(x[0]));
|
||||
}
|
||||
|
||||
void RagePhoto::uInt32ToCharBE(quint32 x, char *y)
|
||||
{
|
||||
y[0] = x >> 24;
|
||||
y[1] = x >> 16;
|
||||
y[2] = x >> 8;
|
||||
y[3] = x;
|
||||
}
|
||||
|
||||
void RagePhoto::uInt32ToCharLE(quint32 x, char *y)
|
||||
{
|
||||
y[0] = x;
|
||||
y[1] = x >> 8;
|
||||
y[2] = x >> 16;
|
||||
y[3] = x >> 24;
|
||||
}
|
||||
|
||||
const QByteArray RagePhoto::stringToUtf16LE(const QString &string)
|
||||
{
|
||||
#if QT_VERSION >= 0x060000
|
||||
return QStringEncoder(QStringEncoder::Utf16LE)(string);
|
||||
#else
|
||||
return QTextCodec::codecForName("UTF-16LE")->fromUnicode(string);
|
||||
#endif
|
||||
}
|
||||
|
||||
const QString RagePhoto::utf16LEToString(const QByteArray &data)
|
||||
{
|
||||
#if QT_VERSION >= 0x060000
|
||||
return QStringDecoder(QStringDecoder::Utf16LE)(data);
|
||||
#else
|
||||
return QTextCodec::codecForName("UTF-16LE")->toUnicode(data);
|
||||
#endif
|
||||
}
|
||||
|
||||
const QString RagePhoto::utf16LEToString(const char *data, int size)
|
||||
{
|
||||
#if QT_VERSION >= 0x060000
|
||||
return QStringDecoder(QStringDecoder::Utf16LE)(QByteArray::fromRawData(data, size));
|
||||
#else
|
||||
return QTextCodec::codecForName("UTF-16LE")->toUnicode(data, size);
|
||||
#endif
|
||||
}
|
110
RagePhoto.h
Normal file
110
RagePhoto.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2020 Syping
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef RAGEPHOTO_H
|
||||
#define RAGEPHOTO_H
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QIODevice>
|
||||
#include <QObject>
|
||||
|
||||
class RagePhoto : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class JsonFormat : quint8 {
|
||||
Original = 0,
|
||||
Compact = 1,
|
||||
Indented = 2,
|
||||
};
|
||||
enum class ExportFormat : quint32 {
|
||||
G5E1P = 0x454C0010U,
|
||||
G5E2P = 0x01000032U,
|
||||
G5E2S = 0x02000032U,
|
||||
G5E3P = 0x01000033U,
|
||||
G5E3S = 0x02000033U,
|
||||
Undefined = 0,
|
||||
};
|
||||
enum class PhotoFormat : quint32 {
|
||||
G5EX = 0x45354700U,
|
||||
GTA5 = 0x01000000U,
|
||||
RDR2 = 0x04000000U,
|
||||
Undefined = 0,
|
||||
};
|
||||
explicit RagePhoto();
|
||||
explicit RagePhoto(const QByteArray &data);
|
||||
explicit RagePhoto(const QString &filePath);
|
||||
explicit RagePhoto(QIODevice *ioDevice);
|
||||
bool isLoaded();
|
||||
bool load();
|
||||
void clear();
|
||||
void setDescription(const QString &description);
|
||||
void setFileData(const QByteArray &data);
|
||||
void setFilePath(const QString &filePath);
|
||||
void setIODevice(QIODevice *ioDevice);
|
||||
bool setJsonData(const QByteArray &data);
|
||||
bool setPhotoBuffer(quint32 size, bool moveOffsets = true);
|
||||
bool setPhotoData(const QByteArray &data);
|
||||
bool setPhotoData(const char *data, int size);
|
||||
void setPhotoFormat(PhotoFormat photoFormat);
|
||||
void setTitle(const QString &title);
|
||||
const QJsonObject jsonObject();
|
||||
const QByteArray jsonData(JsonFormat jsonFormat = JsonFormat::Original);
|
||||
const QByteArray photoData();
|
||||
const QString description();
|
||||
const QString photoString();
|
||||
const QString title();
|
||||
quint32 photoBuffer();
|
||||
quint32 photoSize();
|
||||
PhotoFormat photoFormat();
|
||||
QByteArray save(PhotoFormat photoFormat);
|
||||
void save(QIODevice *ioDevice, PhotoFormat photoFormat);
|
||||
static RagePhoto* loadFile(const QString &filePath);
|
||||
|
||||
private:
|
||||
inline quint32 charToUInt32BE(char *x);
|
||||
inline quint32 charToUInt32LE(char *x);
|
||||
inline void uInt32ToCharBE(quint32 x, char *y);
|
||||
inline void uInt32ToCharLE(quint32 x, char *y);
|
||||
inline const QByteArray stringToUtf16LE(const QString &string);
|
||||
inline const QString utf16LEToString(const QByteArray &data);
|
||||
inline const QString utf16LEToString(const char *data, int size);
|
||||
PhotoFormat p_photoFormat;
|
||||
QJsonObject p_jsonObject;
|
||||
QByteArray p_fileData;
|
||||
QByteArray p_jsonData;
|
||||
QByteArray p_photoData;
|
||||
QIODevice *p_ioDevice;
|
||||
QString p_descriptionString;
|
||||
QString p_filePath;
|
||||
QString p_photoString;
|
||||
QString p_titleString;
|
||||
quint32 p_descBuffer;
|
||||
quint32 p_descOffset;
|
||||
quint32 p_endOfFile;
|
||||
quint32 p_headerSum;
|
||||
quint32 p_jsonBuffer;
|
||||
quint32 p_jsonOffset;
|
||||
quint32 p_photoBuffer;
|
||||
quint32 p_titlBuffer;
|
||||
quint32 p_titlOffset;
|
||||
bool p_isLoaded;
|
||||
int p_inputMode;
|
||||
};
|
||||
|
||||
#endif // RAGEPHOTO_H
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2016-2023 Syping
|
||||
* Copyright (C) 2016-2017 Syping
|
||||
*
|
||||
* 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
|
||||
|
@ -16,6 +16,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "SidebarGenerator.h"
|
||||
#include "SavegameWidget.h"
|
||||
#include "StandardPaths.h"
|
||||
#include "SavegameCopy.h"
|
||||
|
@ -27,6 +28,7 @@
|
|||
|
||||
SavegameCopy::SavegameCopy()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SavegameCopy::copySavegame(QWidget *parent, QString sgdPath)
|
||||
|
@ -46,47 +48,54 @@ fileDialogPreSave: //Work?
|
|||
fileDialog.setOption(QFileDialog::DontUseNativeDialog, dontUseNativeDialog);
|
||||
fileDialog.setOption(QFileDialog::DontConfirmOverwrite, true);
|
||||
fileDialog.setDefaultSuffix("");
|
||||
fileDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||
fileDialog.setWindowTitle(SavegameWidget::tr(("Export Savegame...")));
|
||||
fileDialog.setLabelText(QFileDialog::Accept, SavegameWidget::tr("Export"));
|
||||
|
||||
QStringList filters;
|
||||
const QString fileName = sgdFileInfo.fileName();
|
||||
if (fileName.startsWith("SGTA5"))
|
||||
filters << SavegameWidget::tr("GTA V Savegames files (%1)").arg("SGTA5*");
|
||||
else if (fileName.startsWith("SRDR3"))
|
||||
filters << SavegameWidget::tr("RDR 2 Savegames files (%1)").arg("SRDR3*");
|
||||
filters << SavegameWidget::tr("All files (%1)").arg("**");
|
||||
filters << SavegameWidget::tr("Savegame files (SGTA*)");
|
||||
filters << SavegameWidget::tr("All files (**)");
|
||||
fileDialog.setNameFilters(filters);
|
||||
|
||||
QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls());
|
||||
|
||||
fileDialog.setSidebarUrls(sidebarUrls);
|
||||
fileDialog.setDirectory(settings.value("Directory", StandardPaths::picturesLocation()).toString());
|
||||
fileDialog.restoreGeometry(settings.value(parent->objectName() % "+Geometry", "").toByteArray());
|
||||
fileDialog.selectFile(sgdFileInfo.fileName());
|
||||
|
||||
if (fileDialog.exec()) {
|
||||
if (fileDialog.exec())
|
||||
{
|
||||
QStringList selectedFiles = fileDialog.selectedFiles();
|
||||
if (selectedFiles.length() == 1) {
|
||||
if (selectedFiles.length() == 1)
|
||||
{
|
||||
QString selectedFile = selectedFiles.at(0);
|
||||
|
||||
if (QFile::exists(selectedFile)) {
|
||||
if (QMessageBox::Yes == QMessageBox::warning(parent, SavegameWidget::tr("Export Savegame"), SavegameWidget::tr("Overwrite %1 with current Savegame?").arg("\""+selectedFile+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)) {
|
||||
if (!QFile::remove(selectedFile)) {
|
||||
if (QFile::exists(selectedFile))
|
||||
{
|
||||
if (QMessageBox::Yes == QMessageBox::warning(parent, SavegameWidget::tr("Export Savegame"), SavegameWidget::tr("Overwrite %1 with current Savegame?").arg("\""+selectedFile+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes))
|
||||
{
|
||||
if (!QFile::remove(selectedFile))
|
||||
{
|
||||
QMessageBox::warning(parent, SavegameWidget::tr("Export Savegame"), SavegameWidget::tr("Failed to overwrite %1 with current Savegame").arg("\""+selectedFile+"\""));
|
||||
goto fileDialogPreSave; //Work?
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
goto fileDialogPreSave; //Work?
|
||||
}
|
||||
}
|
||||
|
||||
bool isCopied = QFile::copy(sgdPath, selectedFile);
|
||||
if (!isCopied) {
|
||||
if (!isCopied)
|
||||
{
|
||||
QMessageBox::warning(parent, SavegameWidget::tr("Export Savegame"), SavegameWidget::tr("Failed to export current Savegame"));
|
||||
goto fileDialogPreSave; //Work?
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(parent, SavegameWidget::tr("Export Savegame"), SavegameWidget::tr("No valid file is selected"));
|
||||
goto fileDialogPreSave; //Work?
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2016-2023 Syping
|
||||
* Copyright (C) 2016-2017 Syping
|
||||
*
|
||||
* 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
|
||||
|
@ -17,6 +17,7 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include "SnapmaticPicture.h"
|
||||
#include "StringParser.h"
|
||||
#include "SavegameData.h"
|
||||
#include <QStringBuilder>
|
||||
#include <QByteArray>
|
||||
|
@ -24,8 +25,7 @@
|
|||
#include <QFile>
|
||||
|
||||
#define savegameHeaderLength 260
|
||||
#define verificationValue_GTA5 QByteArray::fromHex("00000001")
|
||||
#define verificationValue_RDR2 QByteArray::fromHex("00000004")
|
||||
#define verificationValue QByteArray::fromHex("00000001")
|
||||
|
||||
SavegameData::SavegameData(const QString &fileName, QObject *parent) : QObject(parent), savegameFileName(fileName)
|
||||
{
|
||||
|
@ -58,10 +58,13 @@ bool SavegameData::readingSavegame()
|
|||
return false;
|
||||
}
|
||||
QByteArray savegameHeaderLine = saveFile->read(savegameHeaderLength);
|
||||
if (savegameHeaderLine.startsWith(verificationValue_GTA5) || savegameHeaderLine.startsWith(verificationValue_RDR2)) {
|
||||
if (savegameHeaderLine.left(4) == verificationValue)
|
||||
{
|
||||
savegameStr = getSavegameDataString(savegameHeaderLine);
|
||||
if (savegameStr.length() >= 1)
|
||||
{
|
||||
savegameOk = true;
|
||||
}
|
||||
}
|
||||
saveFile->close();
|
||||
saveFile->deleteLater();
|
||||
|
@ -72,25 +75,23 @@ bool SavegameData::readingSavegame()
|
|||
QString SavegameData::getSavegameDataString(const QByteArray &savegameHeader)
|
||||
{
|
||||
QByteArray savegameBytes = savegameHeader.left(savegameHeaderLength);
|
||||
char split_byte = 0x00;
|
||||
if (savegameHeader.startsWith(verificationValue_GTA5))
|
||||
split_byte = 0x01;
|
||||
else if (savegameHeader.startsWith(verificationValue_RDR2))
|
||||
split_byte = 0x04;
|
||||
QList<QByteArray> savegameBytesList = savegameBytes.split(split_byte);
|
||||
QList<QByteArray> savegameBytesList = savegameBytes.split(char(0x01));
|
||||
savegameBytes = savegameBytesList.at(1);
|
||||
savegameBytesList.clear();
|
||||
return SnapmaticPicture::parseTitleString(savegameBytes);
|
||||
return SnapmaticPicture::parseTitleString(savegameBytes, savegameBytes.length());
|
||||
}
|
||||
|
||||
bool SavegameData::readingSavegameFromFile(const QString &fileName)
|
||||
{
|
||||
if (fileName != "") {
|
||||
if (fileName != "")
|
||||
{
|
||||
savegameFileName = fileName;
|
||||
return readingSavegame();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SavegameData::isSavegameOk()
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2016-2023 Syping
|
||||
* Copyright (C) 2016-2018 Syping
|
||||
*
|
||||
* 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
|
||||
|
@ -28,7 +28,11 @@ SavegameDialog::SavegameDialog(QWidget *parent) :
|
|||
ui(new Ui::SavegameDialog)
|
||||
{
|
||||
// Set Window Flags
|
||||
#if QT_VERSION >= 0x050900
|
||||
setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
#else
|
||||
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||
#endif
|
||||
|
||||
// Setup User Interface
|
||||
ui->setupUi(this);
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2016-2023 Syping
|
||||
* Copyright (C) 2016-2021 Syping
|
||||
*
|
||||
* 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,6 +18,7 @@
|
|||
|
||||
#include "SavegameWidget.h"
|
||||
#include "ui_SavegameWidget.h"
|
||||
#include "SidebarGenerator.h"
|
||||
#include "SavegameDialog.h"
|
||||
#include "StandardPaths.h"
|
||||
#include "SavegameData.h"
|
||||
|
@ -96,19 +97,27 @@ void SavegameWidget::renderString(const QString &savegameString, const QString &
|
|||
QString savegameName = tr("WRONG FORMAT");
|
||||
QString savegameDate = tr("WRONG FORMAT");
|
||||
QStringList savegameNDL = QString(savegameString).split(" - ");
|
||||
if (savegameNDL.length() >= 2) {
|
||||
if (savegameNDL.length() >= 2)
|
||||
{
|
||||
savegameDate = savegameNDL.at(savegameNDL.length() - 1);
|
||||
savegameName = QString(savegameString).remove(savegameString.length() - savegameDate.length() - 3, savegameDate.length() + 3);
|
||||
}
|
||||
int savegameNumber = QString(fileName).remove(0, 5).toInt(&validNumber) + 1;
|
||||
if (validNumber) {
|
||||
int savegameNumber = QString(fileName).remove(0,5).toInt(&validNumber) + 1;
|
||||
if (validNumber)
|
||||
{
|
||||
if (savegameNumber == 16)
|
||||
{
|
||||
ui->labSavegameStr->setText(labelAutosaveStr.arg(savegameDate, savegameName));
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->labSavegameStr->setText(labelSaveStr.arg(savegameDate, savegameName, QString::number(savegameNumber)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->labSavegameStr->setText(labelSaveStr.arg(savegameDate, savegameName, tr("UNKNOWN")));
|
||||
}
|
||||
}
|
||||
|
||||
void SavegameWidget::retranslate()
|
||||
|
@ -128,15 +137,18 @@ void SavegameWidget::on_cmdCopy_clicked()
|
|||
void SavegameWidget::on_cmdDelete_clicked()
|
||||
{
|
||||
int uchoice = QMessageBox::question(this, tr("Delete Savegame"), tr("Are you sure to delete %1 from your savegames?").arg("\""+sgdStr+"\""), QMessageBox::No | QMessageBox::Yes, QMessageBox::No);
|
||||
if (uchoice == QMessageBox::Yes) {
|
||||
if (!QFile::exists(sgdPath)) {
|
||||
if (uchoice == QMessageBox::Yes)
|
||||
{
|
||||
if (!QFile::exists(sgdPath))
|
||||
{
|
||||
emit savegameDeleted();
|
||||
#ifdef GTA5SYNC_TELEMETRY
|
||||
QSettings telemetrySettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||
telemetrySettings.beginGroup("Telemetry");
|
||||
bool pushUsageData = telemetrySettings.value("PushUsageData", false).toBool();
|
||||
telemetrySettings.endGroup();
|
||||
if (pushUsageData && Telemetry->canPush()) {
|
||||
if (pushUsageData && Telemetry->canPush())
|
||||
{
|
||||
QJsonDocument jsonDocument;
|
||||
QJsonObject jsonObject;
|
||||
jsonObject["Type"] = "DeleteSuccess";
|
||||
|
@ -151,13 +163,15 @@ void SavegameWidget::on_cmdDelete_clicked()
|
|||
}
|
||||
#endif
|
||||
}
|
||||
else if (QFile::remove(sgdPath)) {
|
||||
else if (QFile::remove(sgdPath))
|
||||
{
|
||||
#ifdef GTA5SYNC_TELEMETRY
|
||||
QSettings telemetrySettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
|
||||
telemetrySettings.beginGroup("Telemetry");
|
||||
bool pushUsageData = telemetrySettings.value("PushUsageData", false).toBool();
|
||||
telemetrySettings.endGroup();
|
||||
if (pushUsageData && Telemetry->canPush()) {
|
||||
if (pushUsageData && Telemetry->canPush())
|
||||
{
|
||||
QJsonDocument jsonDocument;
|
||||
QJsonObject jsonObject;
|
||||
jsonObject["Type"] = "DeleteSuccess";
|
||||
|
@ -174,17 +188,25 @@ void SavegameWidget::on_cmdDelete_clicked()
|
|||
emit savegameDeleted();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, tr("Delete Savegame"), tr("Failed at deleting %1 from your savegames").arg("\""+sgdStr+"\""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SavegameWidget::on_cmdView_clicked()
|
||||
{
|
||||
SavegameDialog savegameDialog(this);
|
||||
savegameDialog.setSavegameData(sgdata, sgdPath, true);
|
||||
savegameDialog.setModal(true);
|
||||
savegameDialog.show();
|
||||
savegameDialog.exec();
|
||||
SavegameDialog *savegameDialog = new SavegameDialog(this);
|
||||
savegameDialog->setSavegameData(sgdata, sgdPath, true);
|
||||
savegameDialog->setModal(true);
|
||||
#ifdef Q_OS_ANDROID
|
||||
// Android ...
|
||||
savegameDialog->showMaximized();
|
||||
#else
|
||||
savegameDialog->show();
|
||||
#endif
|
||||
savegameDialog->exec();
|
||||
delete savegameDialog;
|
||||
}
|
||||
|
||||
void SavegameWidget::mousePressEvent(QMouseEvent *ev)
|
||||
|
@ -195,20 +217,31 @@ void SavegameWidget::mousePressEvent(QMouseEvent *ev)
|
|||
void SavegameWidget::mouseReleaseEvent(QMouseEvent *ev)
|
||||
{
|
||||
ProfileWidget::mouseReleaseEvent(ev);
|
||||
if (ui->cbSelected->isVisible()) {
|
||||
if (ui->cbSelected->isVisible())
|
||||
{
|
||||
if (rect().contains(ev->pos()) && ev->button() == Qt::LeftButton)
|
||||
{
|
||||
ui->cbSelected->setChecked(!ui->cbSelected->isChecked());
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
const int contentMode = getContentMode();
|
||||
if ((contentMode == 0 || contentMode == 10 || contentMode == 20) && rect().contains(ev->pos()) && ev->button() == Qt::LeftButton) {
|
||||
if ((contentMode == 0 || contentMode == 10 || contentMode == 20) && rect().contains(ev->pos()) && ev->button() == Qt::LeftButton)
|
||||
{
|
||||
if (ev->modifiers().testFlag(Qt::ShiftModifier))
|
||||
{
|
||||
ui->cbSelected->setChecked(!ui->cbSelected->isChecked());
|
||||
}
|
||||
else
|
||||
{
|
||||
on_cmdView_clicked();
|
||||
}
|
||||
}
|
||||
else if (!ui->cbSelected->isVisible() && (contentMode == 1 || contentMode == 11 || contentMode == 21) && ev->button() == Qt::LeftButton && ev->modifiers().testFlag(Qt::ShiftModifier))
|
||||
{
|
||||
ui->cbSelected->setChecked(!ui->cbSelected->isChecked());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,7 +251,9 @@ void SavegameWidget::mouseDoubleClickEvent(QMouseEvent *ev)
|
|||
|
||||
const int contentMode = getContentMode();
|
||||
if (!ui->cbSelected->isVisible() && (contentMode == 1 || contentMode == 11 || contentMode == 21) && ev->button() == Qt::LeftButton)
|
||||
{
|
||||
on_cmdView_clicked();
|
||||
}
|
||||
}
|
||||
|
||||
void SavegameWidget::setSelected(bool isSelected)
|
||||
|
@ -239,9 +274,13 @@ void SavegameWidget::contextMenuEvent(QContextMenuEvent *ev)
|
|||
void SavegameWidget::on_cbSelected_stateChanged(int arg1)
|
||||
{
|
||||
if (arg1 == Qt::Checked)
|
||||
{
|
||||
emit widgetSelected();
|
||||
}
|
||||
else if (arg1 == Qt::Unchecked)
|
||||
{
|
||||
emit widgetDeselected();
|
||||
}
|
||||
}
|
||||
|
||||
bool SavegameWidget::isSelected()
|
||||
|
@ -271,5 +310,5 @@ SavegameData* SavegameWidget::getSavegame()
|
|||
|
||||
QString SavegameWidget::getWidgetType()
|
||||
{
|
||||
return QStringLiteral("SavegameWidget");
|
||||
return "SavegameWidget";
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2016-2023 Syping
|
||||
* Copyright (C) 2016-2017 Syping
|
||||
*
|
||||
* 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
|
||||
|
@ -44,17 +44,15 @@ public:
|
|||
void retranslate();
|
||||
~SavegameWidget();
|
||||
|
||||
public slots:
|
||||
private slots:
|
||||
void on_cmdView_clicked();
|
||||
void on_cmdCopy_clicked();
|
||||
void on_cmdDelete_clicked();
|
||||
void on_cbSelected_stateChanged(int arg1);
|
||||
void savegameSelected();
|
||||
void selectAllWidgets();
|
||||
void deselectAllWidgets();
|
||||
|
||||
private slots:
|
||||
void on_cbSelected_stateChanged(int arg1);
|
||||
|
||||
protected:
|
||||
void mouseDoubleClickEvent(QMouseEvent *ev);
|
||||
void mouseReleaseEvent(QMouseEvent *ev);
|
61
SidebarGenerator.cpp
Normal file
61
SidebarGenerator.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2016-2017 Syping
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "SidebarGenerator.h"
|
||||
#include "StandardPaths.h"
|
||||
#include "AppEnv.h"
|
||||
#include <QList>
|
||||
#include <QUrl>
|
||||
#include <QDir>
|
||||
|
||||
SidebarGenerator::SidebarGenerator()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QList<QUrl> SidebarGenerator::generateSidebarUrls(QList<QUrl> sidebarUrls)
|
||||
{
|
||||
QDir dir;
|
||||
|
||||
dir.setPath(StandardPaths::picturesLocation());
|
||||
if (dir.exists())
|
||||
{
|
||||
sidebarUrls += QUrl::fromLocalFile(dir.absolutePath());
|
||||
}
|
||||
|
||||
dir.setPath(StandardPaths::documentsLocation());
|
||||
if (dir.exists())
|
||||
{
|
||||
sidebarUrls += QUrl::fromLocalFile(dir.absolutePath());
|
||||
}
|
||||
|
||||
bool gameFolderExists;
|
||||
QString gameFolder = AppEnv::getGameFolder(&gameFolderExists);
|
||||
if (gameFolderExists)
|
||||
{
|
||||
sidebarUrls += QUrl::fromLocalFile(gameFolder);
|
||||
}
|
||||
|
||||
dir.setPath(StandardPaths::desktopLocation());
|
||||
if (dir.exists())
|
||||
{
|
||||
sidebarUrls += QUrl::fromLocalFile(dir.absolutePath());
|
||||
}
|
||||
|
||||
return sidebarUrls;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* gta5view Grand Theft Auto V Profile Viewer
|
||||
* Copyright (C) 2023 Syping
|
||||
* Copyright (C) 2016-2017 Syping
|
||||
*
|
||||
* 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
|
||||
|
@ -16,18 +16,17 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SNAPMATICJSON_H
|
||||
#define SNAPMATICJSON_H
|
||||
#ifndef Q_MOC_RUN
|
||||
#ifndef SIDEBARGENERATOR_H
|
||||
#define SIDEBARGENERATOR_H
|
||||
|
||||
#include <boost/json.hpp>
|
||||
#include <QList>
|
||||
#include <QUrl>
|
||||
|
||||
class SnapmaticJson
|
||||
class SidebarGenerator
|
||||
{
|
||||
public:
|
||||
static std::string serialize(const boost::json::value &jv, bool do_indent = false);
|
||||
boost::json::object jsonObject;
|
||||
SidebarGenerator();
|
||||
static QList<QUrl> generateSidebarUrls(QList<QUrl> sidebarUrls);
|
||||
};
|
||||
|
||||
#endif // Q_MOC_RUN
|
||||
#endif // SNAPMATICJSON_H
|
||||
#endif // SIDEBARGENERATOR_H
|
|
@ -21,6 +21,7 @@
|
|||
#include "SnapmaticPicture.h"
|
||||
#include "PlayerListDialog.h"
|
||||
#include "StringParser.h"
|
||||
#include "wrapper.h"
|
||||
#include "AppEnv.h"
|
||||
#include "config.h"
|
||||
#include <QStringBuilder>
|
||||
|
@ -41,7 +42,11 @@ SnapmaticEditor::SnapmaticEditor(CrewDatabase *crewDB, ProfileDatabase *profileD
|
|||
ui(new Ui::SnapmaticEditor)
|
||||
{
|
||||
// Set Window Flags
|
||||
#if QT_VERSION >= 0x050900
|
||||
setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
#else
|
||||
setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
|
||||
#endif
|
||||
|
||||
ui->setupUi(this);
|
||||
ui->cmdCancel->setDefault(true);
|
||||
|
@ -231,7 +236,7 @@ void SnapmaticEditor::setSnapmaticTitle(const QString &title)
|
|||
snapmaticTitle = title;
|
||||
}
|
||||
QString editStr = QString("<a href=\"g5e://edittitle\" style=\"text-decoration: none;\">%1</a>").arg(tr("Edit"));
|
||||
QString titleStr = tr("Title: %1 (%2)").arg(snapmaticTitle.toHtmlEscaped(), editStr);
|
||||
QString titleStr = tr("Title: %1 (%2)").arg(StringParser::escapeString(snapmaticTitle), editStr);
|
||||
ui->labTitle->setText(titleStr);
|
||||
if (SnapmaticPicture::verifyTitle(snapmaticTitle)) {
|
||||
ui->labAppropriate->setText(tr("Appropriate: %1").arg(QString("<span style=\"color: green\">%1</span>").arg(tr("Yes", "Yes, should work fine"))));
|
||||
|
@ -239,21 +244,25 @@ void SnapmaticEditor::setSnapmaticTitle(const QString &title)
|
|||
else {
|
||||
ui->labAppropriate->setText(tr("Appropriate: %1").arg(QString("<span style=\"color: red\">%1</span>").arg(tr("No", "No, could lead to issues"))));
|
||||
}
|
||||
#ifndef Q_OS_ANDROID
|
||||
ui->gbValues->resize(ui->gbValues->width(), ui->gbValues->heightForWidth(ui->gbValues->width()));
|
||||
ui->frameWidget->resize(ui->gbValues->width(), ui->frameWidget->heightForWidth(ui->frameWidget->width()));
|
||||
if (heightForWidth(width()) > height())
|
||||
resize(width(), heightForWidth(width()));
|
||||
#endif
|
||||
}
|
||||
|
||||
void SnapmaticEditor::setSnapmaticCrew(const QString &crew)
|
||||
{
|
||||
QString editStr = QString("<a href=\"g5e://editcrew\" style=\"text-decoration: none;\">%1</a>").arg(tr("Edit"));
|
||||
QString crewStr = tr("Crew: %1 (%2)").arg(crew.toHtmlEscaped(), editStr);
|
||||
QString crewStr = tr("Crew: %1 (%2)").arg(StringParser::escapeString(crew), editStr);
|
||||
ui->labCrew->setText(crewStr);
|
||||
#ifndef Q_OS_ANDROID
|
||||
ui->gbValues->resize(ui->gbValues->width(), ui->gbValues->heightForWidth(ui->gbValues->width()));
|
||||
ui->frameWidget->resize(ui->gbValues->width(), ui->frameWidget->heightForWidth(ui->frameWidget->width()));
|
||||
if (heightForWidth(width()) > height())
|
||||
resize(width(), heightForWidth(width()));
|
||||
#endif
|
||||
}
|
||||
|
||||
QString SnapmaticEditor::returnCrewName(int crewID_)
|
||||
|
@ -306,7 +315,7 @@ void SnapmaticEditor::on_cmdApply_clicked()
|
|||
QJsonDocument jsonDocument;
|
||||
QJsonObject jsonObject;
|
||||
jsonObject["Type"] = "PropertyEdited";
|
||||
jsonObject["EditedSize"] = QString::number(smpic->getPictureSize());
|
||||
jsonObject["EditedSize"] = QString::number(smpic->getContentMaxLength());
|
||||
#if QT_VERSION >= 0x060000
|
||||
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
|
||||
#else
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue