Compare commits

..

No commits in common. "1.10.x" and "1.8.x" have entirely different histories.

164 changed files with 24421 additions and 10915 deletions

View File

@ -24,7 +24,7 @@ BEGIN
VALUE "FileDescription", "gta5view"
VALUE "FileVersion", "MAJOR_VER.MINOR_VER.PATCH_VERSTR_BUILD_VER"
VALUE "InternalName", "gta5view"
VALUE "LegalCopyright", "Copyright © 2016-2023 Syping"
VALUE "LegalCopyright", "Copyright © 2016-2020 Syping"
VALUE "OriginalFilename", "gta5view.exe"
VALUE "ProductName", "gta5view"
VALUE "ProductVersion", "MAJOR_VER.MINOR_VER.PATCH_VERSTR_BUILD_VER"

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/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')
@ -16,7 +16,7 @@ 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_INT_VERSION=$(grep -oE "[1-9]*$" <<< $PACKAGE_BUILD)
export APPLICATION_BUILD_STR_VERSION=-${PACKAGE_BUILD}
fi
@ -30,41 +30,41 @@ cat ".ci/app.rc" | sed \
> "res/app.rc"
if [ "${BUILD_TYPE}" == "ALPHA" ]; then
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Alpha"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Alpha\\\\\\\""
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE_ALPHA=TRUE"
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\\\\\\\""
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE_ALPHA=TRUE"
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\\\\\\\""
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE_BETA=TRUE"
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\\\\\\\""
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE_BETA=TRUE"
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\\\\\\\""
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE_DEV=TRUE"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE_DEV"
elif [ "${BUILD_TYPE}" == "Development" ]; then
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Developer"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Developer\\\\\\\""
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE_DEV=TRUE"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE_DEV"
elif [ "${BUILD_TYPE}" == "DAILY" ]; then
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Daily Build"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Daily Build\\\\\\\""
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE_DAILY=TRUE"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE_DAILY"
elif [ "${BUILD_TYPE}" == "Daily" ]; then
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Daily Build"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Daily Build\\\\\\\""
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE_DAILY=TRUE"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE_DAILY"
elif [ "${BUILD_TYPE}" == "RC" ]; then
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Release Candidate"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Release Candidate\\\\\\\""
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE_RC=TRUE"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE_RC"
elif [ "${BUILD_TYPE}" == "Release Candidate" ]; then
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Release Candidate"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Release Candidate\\\\\\\""
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE_RC=TRUE"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE_RC"
elif [ "${BUILD_TYPE}" == "REL" ]; then
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Release"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Release\\\\\\\""
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE_REL=TRUE"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE_REL"
elif [ "${BUILD_TYPE}" == "Release" ]; then
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE=Release"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE=\\\\\\\"Release\\\\\\\""
export CMAKE_BUILD_TYPE="-DGTA5VIEW_BUILDTYPE_REL=TRUE"
export QMAKE_BUILD_TYPE="DEFINES+=GTA5SYNC_BUILDTYPE_REL"
fi
export PROJECT_DIR=$(pwd)

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
# Creating folders
cd ${PROJECT_DIR} && \
@ -7,6 +7,10 @@ mkdir -p build && \
mkdir -p assets && \
chmod -x res/gta5sync_*.qm res/*.desktop res/*gta5view*.png && \
cd build && \
mkdir -p qt4 && \
cd qt4 && \
echo "Grand Theft Auto V Snapmatic and Savegame viewer/editor" > ./description-pak && \
cd .. && \
mkdir -p qt5 && \
cd qt5 && \
echo "Grand Theft Auto V Snapmatic and Savegame viewer/editor" > ./description-pak && \
@ -23,16 +27,18 @@ mkdir -p /usr/share/gta5view && \
cd qt5 && \
cmake \
"-DCMAKE_INSTALL_PREFIX=/usr" \
"${CMAKE_BUILD_TYPE}" \
"-DFORCE_QT_VERSION=5" \
${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" \
../../ && \
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
checkinstall -D --default --nodoc --install=no --pkgname=gta5view-qt5 --pkgversion=${PACKAGE_VERSION} --pkgrelease=${PACKAGE_BUILD} --pkggroup=utility --maintainer="Syping \<dpkg@syping.de\>" --requires=libqt5core5a,libqt5gui5,libqt5network5,libqt5svg5,libqt5widgets5,qttranslations5-l10n --conflicts=gta5view,gta5view-qt4 --replaces=gta5view,gta5view-qt4 --pakdir=${PROJECT_DIR}/assets && \
cd .. && \
cd qt4 && \
qmake -qt=4 GTA5SYNC_PREFIX=/usr QMAKE_CXXFLAGS+=-std=gnu++11 ${QMAKE_FLAGS_QT4} ${QMAKE_BUILD_TYPE} "DEFINES+=GTA5SYNC_BUILDCODE=\\\\\\\"${PACKAGE_CODE}\\\\\\\"" "DEFINES+=GTA5SYNC_APPVER=\\\\\\\"${APPLICATION_VERSION}\\\\\\\"" DEFINES+=GTA5SYNC_QCONF ../../gta5view.pro && \
make -j 4 && \
checkinstall -D --default --nodoc --install=no --pkgname=gta5view-qt4 --pkgversion=${PACKAGE_VERSION} --pkgrelease=${PACKAGE_BUILD} --pkggroup=utility --maintainer="Syping \<dpkg@syping.de\>" --requires=libqtcore4,libqtgui4,libqt4-network,libqt4-svg,qtcore4-l10n --conflicts=gta5view,gta5view-qt5 --replaces=gta5view,gta5view-qt5 --pakdir=${PROJECT_DIR}/assets

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
# Install packages
.ci/debian_install.sh && \

View File

@ -1,15 +1,15 @@
#!/usr/bin/env bash
#!/bin/bash
if [ "${DOCKER_USER}" != "" ]; then
DOCKER_IMAGE=${DOCKER_USER}/debian:${DEBIAN_VERSION}
DOCKER_IMAGE=${DOCKER_USER}/debian:${DEBIAN_VERSION}
else
DOCKER_IMAGE=debian:${DEBIAN_VERSION}
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"
-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"

View File

@ -1,13 +1,5 @@
#!/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
#!/bin/bash
# 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
apt-get install -qq ${APT_INSTALL} checkinstall cmake dpkg-dev fakeroot g++ gcc qtbase5-dev qt5-qmake qttranslations5-l10n libqt4-dev libqt5svg5-dev

View File

@ -1 +0,0 @@
btc:187NSQSPzdMpQDGhxZAuw4AhZ7LgoAPV7D,eth:0x19d71DfCa86104d37a13D3c5d419936421CDC569,ltc:LKr6yvBoMMGmcxViS8Kc1A2sDjVSWTXn4m,xmr:43TB3ZMP5nk1pu5EQXRGPzdTKvmFEBGgccX3tNhRknLLiUYQ7z7dNedVHEA6WrWdByZv1isvFmjSGhCF7ddx3eRxFdm5Fzz

View File

@ -1,12 +1,11 @@
######################################################################
!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 VERSION "1.8.0.0"
!define COPYRIGHT "Copyright © 2016-2020 Syping"
!define DESCRIPTION "Grand Theft Auto V Savegame and Snapmatic Viewer/Editor"
!define INSTALLER_NAME "gta5view_setup.exe"
!define MAIN_APP_EXE "gta5view.exe"
!define INSTALL_TYPE "SetShellVarContext all"
@ -114,6 +113,7 @@ 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"
File "/usr/local/lib/x86_64-w64-mingw32/qt5/bin/Qt5WinExtras.dll"
SetOutPath "$INSTDIR\lang"
File "../build/gta5sync_en_US.qm"
File "../build/gta5sync_de.qm"
@ -123,45 +123,12 @@ 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"
File "../res/qtbase_de.qm"
File "../res/qtbase_fr.qm"
File "../res/qtbase_ko.qm"
File "../res/qtbase_ru.qm"
File "../res/qtbase_uk.qm"
File "../res/qtbase_zh_TW.qm"
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"
@ -224,30 +191,6 @@ 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"
@ -260,6 +203,7 @@ Delete "$INSTDIR\Qt5Gui.dll"
Delete "$INSTDIR\Qt5Network.dll"
Delete "$INSTDIR\Qt5Svg.dll"
Delete "$INSTDIR\Qt5Widgets.dll"
Delete "$INSTDIR\Qt5WinExtras.dll"
Delete "$INSTDIR\lang\gta5sync_en_US.qm"
Delete "$INSTDIR\lang\gta5sync_de.qm"
Delete "$INSTDIR\lang\gta5sync_fr.qm"
@ -274,38 +218,6 @@ 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"

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
# Creating folders
cd ${PROJECT_DIR} && \
@ -8,17 +8,7 @@ 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/" \
../ && \
/usr/local/opt/qt/bin/qmake ${QMAKE_FLAGS_QT5} ${QMAKE_BUILD_TYPE} "DEFINES+=GTA5SYNC_BUILDCODE=\\\\\\\"${PACKAGE_CODE}\\\\\\\"" "DEFINES+=GTA5SYNC_APPVER=\\\\\\\"${APPLICATION_VERSION}\\\\\\\"" "DEFINES+=GTA5SYNC_COMMIT=\\\\\\\"${APPLICATION_COMMIT}\\\\\\\"" DEFINES+=GTA5SYNC_TELEMETRY "DEFINES+=GTA5SYNC_TELEMETRY_WEBURL=\\\\\\\"https://dev.syping.de/gta5view-userstats/\\\\\\\"" ../gta5view.pro && \
make -j 4 && \
/usr/local/opt/qt/bin/macdeployqt gta5view.app -dmg && \
cp -Rf gta5view.dmg ../assets/gta5view-osx_${APPLICATION_VERSION}.dmg

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
# Install packages
.ci/osx_install.sh && \

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
# Install packages
brew upgrade cmake qt
brew upgrade qt

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
# Prepare environment variable
export GTA5VIEW_EXECUTABLE=gta5view-${EXECUTABLE_VERSION}${EXECUTABLE_ARCH}.exe && \
@ -13,13 +13,11 @@ mkdir -p assets && \
# Starting build
cd build && \
mingw64-qt-cmake \
"${CMAKE_BUILD_TYPE}" \
${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 && \

View File

@ -1,25 +1,25 @@
#!/usr/bin/env bash
#!/bin/bash
DOCKER_IMAGE=sypingauto/gta5view-build:1.10-static
DOCKER_IMAGE=sypingauto/gta5view-build:1.8-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" && \
-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}
${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}
${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

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
# Creating folders
cd ${PROJECT_DIR} && \
@ -9,13 +9,11 @@ mkdir -p assets && \
# Starting build
cd build && \
mingw64-qt-cmake \
"${CMAKE_BUILD_TYPE}" \
${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" \
@ -25,5 +23,5 @@ mingw64-qt-cmake \
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 && \
makensis -NOCD ${PROJECT_DIR}/.ci/gta5view.nsi && \
mv -f gta5view_setup.exe gta5view-${EXECUTABLE_VERSION}_setup.exe

View File

@ -1,11 +1,11 @@
#!/usr/bin/env bash
#!/bin/bash
DOCKER_IMAGE=sypingauto/gta5view-build:1.10-shared
DOCKER_IMAGE=sypingauto/gta5view-build:1.8-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"
-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"

View File

@ -6,7 +6,7 @@ environment:
steps:
- name: Windows Installer
image: sypingauto/gta5view-build:1.10-shared
image: sypingauto/gta5view-build:1.8-shared
environment:
BUILD_SCRIPT: "wininstall_build.sh"
QT_SELECT: "qt5-x86_64-w64-mingw32"
@ -18,7 +18,7 @@ steps:
- name: gta5view
path: /srv/gta5view
- name: Windows Portable
image: sypingauto/gta5view-build:1.10-static
image: sypingauto/gta5view-build:1.8-static
environment:
BUILD_SCRIPT: "windows_build.sh"
QT_SELECT: "qt5-x86_64-w64-mingw32"

View File

@ -1,6 +1,6 @@
app-id: de.syping.gta5view
runtime: org.kde.Platform
runtime-version: '5.15-21.08'
runtime-version: '5.15'
sdk: org.kde.Sdk
command: gta5view
finish-args:
@ -15,8 +15,6 @@ modules:
config-opts:
- -DFLATPAK_BUILD=ON
- -DQCONF_BUILD=ON
- -DGTA5VIEW_BUILDCODE=Flatpak
- -DGTA5VIEW_BUILDTYPE=Release
sources:
- type: dir
path: ../

View File

@ -6,7 +6,7 @@ variables:
Windows Installer:
stage: build
image: sypingauto/gta5view-build:1.10-shared
image: sypingauto/gta5view-build:1.8-shared
variables:
BUILD_SCRIPT: "wininstall_build.sh"
QT_SELECT: "qt5-x86_64-w64-mingw32"
@ -19,7 +19,7 @@ Windows Installer:
Windows Portable:
stage: build
image: sypingauto/gta5view-build:1.10-static
image: sypingauto/gta5view-build:1.8-static
variables:
BUILD_SCRIPT: "windows_build.sh"
QT_SELECT: "qt5-x86_64-w64-mingw32"

View File

@ -3,9 +3,9 @@ sudo: required
language: cpp
services:
service:
- docker
env:
global:
- BUILD_TYPE=REL
@ -15,19 +15,28 @@ matrix:
- env:
- BUILD_SCRIPT=debian_docker.sh
- RELEASE_LABEL="Debian 64-Bit Package"
- DEBIAN_VERSION=buster
- DEBIAN_VERSION=stretch
- 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=windows_docker.sh
- QT_SELECT=qt5-x86_64-w64-mingw32
- RELEASE_LABEL="Windows 64-Bit Portable for gta5-mods"
- PACKAGE_CODE=gta5-mods
- env:
- BUILD_SCRIPT=windows_docker.sh
- QT_SELECT=qt5-x86_64-w64-mingw32
- RELEASE_LABEL="Windows 64-Bit Portable for gtainside"
- PACKAGE_CODE=gtainside
- 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"

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 Syping
* Copyright (C) 2016-2019 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,47 +29,48 @@ 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();
const char* literalBuildType = GTA5SYNC_BUILDTYPE;
const QString buildType = tr(literalBuildType);
const QString projectBuild = AppEnv::getBuildDateTime();
const QString buildStr = GTA5SYNC_BUILDSTRING;
QString appVersion = qApp->applicationVersion();
QString buildType = tr(GTA5SYNC_BUILDTYPE);
buildType.replace("_", " ");
QString projectBuild = AppEnv::getBuildDateTime();
QString buildStr = GTA5SYNC_BUILDSTRING;
#ifndef GTA5SYNC_BUILDTYPE_REL
#ifdef GTA5SYNC_COMMIT
if ((strcmp(literalBuildType, REL_BUILDTYPE) != 0) && !appVersion.contains("-"))
appVersion = appVersion % "-" % GTA5SYNC_COMMIT;
if (!appVersion.contains("-")) { appVersion = appVersion % "-" % GTA5SYNC_COMMIT; }
#endif
#endif
// Translator Comments
//: Translated by translator, example Translated by Syping
const QString translatedByStr = tr("Translated by %1");
QString translatedByStr = tr("Translated by %1");
//: Insert your name here and profile here in following scheme, First Translator,First Profile\\nSecond Translator\\nThird Translator,Second Profile
const QString translatorVal = tr("TRANSLATOR");
QString translatorVal = tr("TRANSLATOR");
QStringList translatorContent;
if (translatorVal != "TRANSLATOR") {
if (translatorVal != "TRANSLATOR")
{
const QStringList translatorList = translatorVal.split('\n');
for (const QString &translatorStr : translatorList) {
for (const QString &translatorStr : translatorList)
{
QStringList translatorStrList = translatorStr.split(',');
const QString translatorName = translatorStrList.at(0);
QString translatorName = translatorStrList.at(0);
translatorStrList.removeFirst();
QString translatorProfile = translatorStrList.join(QString());
if (!translatorProfile.isEmpty()) {
if (!translatorProfile.isEmpty())
{
translatorContent += QString("<a href=\"%1\">%2</a>").arg(translatorProfile, translatorName);
}
else {
else
{
translatorContent += translatorName;
}
}
}
// Project Description
const QString projectDes = tr("A project for viewing Grand Theft Auto V Snapmatic<br/>\nPictures and Savegames");
QString projectDes = tr("A project for viewing Grand Theft Auto V Snapmatic<br/>\nPictures and Savegames");
// Copyright Description
QString copyrightDes1 = tr("Copyright &copy; <a href=\"%1\">%2</a> %3");
@ -77,34 +78,40 @@ AboutDialog::AboutDialog(QWidget *parent) :
QString copyrightDes2 = tr("%1 is licensed under <a href=\"https://www.gnu.org/licenses/gpl-3.0.html#content\">GNU GPLv3</a>");
copyrightDes2 = copyrightDes2.arg(GTA5SYNC_APPSTR);
QString copyrightDesA;
if (!translatorContent.isEmpty()) {
if (!translatorContent.isEmpty())
{
copyrightDesA = copyrightDes1 % "<br/>" % translatedByStr.arg(translatorContent.join(", ")) % "<br/>" % copyrightDes2;
}
else {
else
{
copyrightDesA = copyrightDes1 % "<br/>" % copyrightDes2;
}
// Setup User Interface
ui->setupUi(this);
aboutStr = ui->labAbout->text();
titleStr = windowTitle();
titleStr = this->windowTitle();
ui->labAbout->setText(aboutStr.arg(GTA5SYNC_APPSTR, projectDes, appVersion % " (" % buildType % ")", projectBuild, buildStr, qVersion(), copyrightDesA));
setWindowTitle(titleStr.arg(GTA5SYNC_APPSTR));
this->setWindowTitle(titleStr.arg(GTA5SYNC_APPSTR));
// 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"));
}
// DPI calculation
qreal screenRatio = AppEnv::screenRatio();
if (!translatorContent.isEmpty()) {
if (!translatorContent.isEmpty())
{
resize(375 * screenRatio, 270 * screenRatio);
}
else {
else
{
resize(375 * screenRatio, 260 * screenRatio);
}
}
@ -116,11 +123,13 @@ AboutDialog::~AboutDialog()
void AboutDialog::on_labAbout_linkActivated(const QString &link)
{
if (link.left(12) == "g5e://about?") {
if (link.left(12) == "g5e://about?")
{
QStringList aboutStrList = QString(link).remove(0, 12).split(":");
QMessageBox::information(this, QString::fromUtf8(QByteArray::fromBase64(aboutStrList.at(0).toUtf8())), QString::fromUtf8(QByteArray::fromBase64(aboutStrList.at(1).toUtf8())));
}
else {
else
{
QDesktopServices::openUrl(QUrl(link));
}
}

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -28,6 +28,7 @@ class AboutDialog;
class AboutDialog : public QDialog
{
Q_OBJECT
public:
explicit AboutDialog(QWidget *parent = 0);
~AboutDialog();

View File

@ -26,7 +26,7 @@
</sizepolicy>
</property>
<property name="text">
<string>&lt;span style=&quot;font-weight:600&quot;&gt;%1&lt;/span&gt;&lt;br/&gt;
<string>&lt;span style=&quot; font-weight:600;&quot;&gt;%1&lt;/span&gt;&lt;br/&gt;
&lt;br/&gt;
%2&lt;br/&gt;
&lt;br/&gt;

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -33,8 +33,12 @@
#include <QDesktopWidget>
#endif
#include <iostream>
using namespace std;
AppEnv::AppEnv()
{
}
// Build Stuff
@ -55,17 +59,18 @@ QString AppEnv::getGameFolder(bool *ok)
{
QDir dir;
QString GTAV_FOLDER = QString::fromUtf8(qgetenv("GTAV_FOLDER"));
if (GTAV_FOLDER != "") {
if (GTAV_FOLDER != "")
{
dir.setPath(GTAV_FOLDER);
if (dir.exists()) {
if (ok != NULL)
*ok = true;
if (dir.exists())
{
if (ok != NULL) *ok = true;
qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8());
return dir.absolutePath();
}
}
const QString GTAV_defaultFolder = StandardPaths::documentsLocation() % "/Rockstar Games/GTA V";
QString GTAV_defaultFolder = StandardPaths::documentsLocation() % QDir::separator() % "Rockstar Games" % QDir::separator() % "GTA V";
QString GTAV_returnFolder = GTAV_defaultFolder;
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
@ -74,44 +79,46 @@ QString AppEnv::getGameFolder(bool *ok)
GTAV_returnFolder = settings.value("dir", GTAV_defaultFolder).toString();
settings.endGroup();
if (forceDir) {
if (forceDir)
{
dir.setPath(GTAV_returnFolder);
if (dir.exists()) {
if (ok != 0)
*ok = true;
if (dir.exists())
{
if (ok != 0) *ok = true;
qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8());
return dir.absolutePath();
}
}
dir.setPath(GTAV_defaultFolder);
if (dir.exists()) {
if (ok != 0)
*ok = true;
if (dir.exists())
{
if (ok != 0) *ok = true;
qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8());
return dir.absolutePath();
}
if (!forceDir) {
if (!forceDir)
{
dir.setPath(GTAV_returnFolder);
if (dir.exists()) {
if (ok != 0)
*ok = true;
if (dir.exists())
{
if (ok != 0) *ok = true;
qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8());
return dir.absolutePath();
}
}
if (ok != 0)
*ok = false;
return QString();
if (ok != 0) *ok = false;
return "";
}
bool AppEnv::setGameFolder(QString gameFolder)
{
QDir dir;
dir.setPath(gameFolder);
if (dir.exists()) {
if (dir.exists())
{
qputenv("GTAV_FOLDER", dir.absolutePath().toUtf8());
return true;
}
@ -129,13 +136,13 @@ QString AppEnv::getInLangFolder()
#ifdef GTA5SYNC_INLANG
return StringParser::convertBuildedString(GTA5SYNC_INLANG);
#else
return StringParser::convertBuildedString(GTA5SYNC_SHARE % QLatin1String("/APPNAME:/translations"));
return StringParser::convertBuildedString(GTA5SYNC_SHARE % QLatin1String("SEPARATOR:APPNAME:SEPARATOR:translations"));
#endif
#else
#ifdef GTA5SYNC_INLANG
return StringParser::convertBuildedString(GTA5SYNC_INLANG);
#else
return QLatin1String(":/tr");
return QString(":/tr");
#endif
#endif
}
@ -145,24 +152,6 @@ QString AppEnv::getPluginsFolder()
return StringParser::convertBuildedString(GTA5SYNC_PLUG);
}
QString AppEnv::getImagesFolder()
{
#if defined(GTA5SYNC_QCONF) && defined(GTA5SYNC_CMAKE)
#ifdef Q_OS_WIN
return StringParser::convertBuildedString(GTA5SYNC_SHARE % QLatin1String("/resources"));
#else
return StringParser::convertBuildedString(GTA5SYNC_SHARE % QLatin1String("/APPNAME:/resources"));
#endif
#else
return QLatin1String(":/img");
#endif
}
QString AppEnv::getShareFolder()
{
return StringParser::convertBuildedString(GTA5SYNC_SHARE);
}
// Web Stuff
QByteArray AppEnv::getUserAgent()
@ -171,19 +160,24 @@ QByteArray AppEnv::getUserAgent()
#ifdef Q_OS_WIN
QString kernelVersion = QSysInfo::kernelVersion();
const QStringList &kernelVersionList = kernelVersion.split(".");
if (kernelVersionList.length() > 2) {
if (kernelVersionList.length() > 2)
{
kernelVersion = kernelVersionList.at(0) % "." % kernelVersionList.at(1);
}
QString runArch = QSysInfo::buildCpuArchitecture();
if (runArch == "x86_64") {
if (runArch == "x86_64")
{
runArch = "Win64; x64";
}
else if (runArch == "i686") {
else if (runArch == "i686")
{
const QString &curArch = QSysInfo::currentCpuArchitecture();
if (curArch == "x86_64") {
if (curArch == "x86_64")
{
runArch = "WOW64";
}
else if (curArch == "i686") {
else if (curArch == "i686")
{
runArch = "Win32; x86";
}
}
@ -196,6 +190,11 @@ QByteArray AppEnv::getUserAgent()
#endif
}
// QUrl AppEnv::getCrewFetchingUrl(QString crewID)
// {
// return QUrl(QString("https://socialclub.rockstargames.com/reference/crewfeed/%1").arg(crewID));
// }
QUrl AppEnv::getCrewFetchingUrl(QString crewID)
{
return QUrl(QString("https://socialclub.rockstargames.com/crew/%1/%1").arg(crewID));
@ -224,7 +223,8 @@ GameVersion AppEnv::getGameVersion()
QString installFolderSc = registrySettingsSc.value("InstallFolder", "").toString();
QDir installFolderScDir(installFolderSc);
bool scVersionInstalled = false;
if (!installFolderSc.isEmpty() && installFolderScDir.exists()) {
if (!installFolderSc.isEmpty() && installFolderScDir.exists())
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "gameVersionFoundSocialClubVersion";
#endif
@ -233,28 +233,34 @@ GameVersion AppEnv::getGameVersion()
QSettings registrySettingsSteam(QString("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\Rockstar Games\\GTAV").arg(argumentValue), QSettings::NativeFormat);
QString installFolderSteam = registrySettingsSteam.value("installfoldersteam", "").toString();
if (installFolderSteam.right(5) == "\\GTAV") {
if (installFolderSteam.right(5) == "\\GTAV")
{
installFolderSteam = installFolderSteam.remove(installFolderSteam.length() - 5, 5);
}
QDir installFolderSteamDir(installFolderSteam);
bool steamVersionInstalled = false;
if (!installFolderSteam.isEmpty() && installFolderSteamDir.exists()) {
if (!installFolderSteam.isEmpty() && installFolderSteamDir.exists())
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "gameVersionFoundSteamVersion";
#endif
steamVersionInstalled = true;
}
if (scVersionInstalled && steamVersionInstalled) {
if (scVersionInstalled && steamVersionInstalled)
{
return GameVersion::BothVersions;
}
else if (scVersionInstalled) {
else if (scVersionInstalled)
{
return GameVersion::SocialClubVersion;
}
else if (steamVersionInstalled) {
else if (steamVersionInstalled)
{
return GameVersion::SteamVersion;
}
else {
else
{
return GameVersion::NoVersion;
}
#else
@ -264,7 +270,8 @@ GameVersion AppEnv::getGameVersion()
GameLanguage AppEnv::getGameLanguage(GameVersion gameVersion)
{
if (gameVersion == GameVersion::SocialClubVersion) {
if (gameVersion == GameVersion::SocialClubVersion)
{
#ifdef Q_OS_WIN
QString argumentValue;
#ifdef _WIN64
@ -277,7 +284,8 @@ GameLanguage AppEnv::getGameLanguage(GameVersion gameVersion)
return GameLanguage::Undefined;
#endif
}
else if (gameVersion == GameVersion::SteamVersion) {
else if (gameVersion == GameVersion::SteamVersion)
{
#ifdef Q_OS_WIN
QString argumentValue;
#ifdef _WIN64
@ -290,81 +298,128 @@ GameLanguage AppEnv::getGameLanguage(GameVersion gameVersion)
return GameLanguage::Undefined;
#endif
}
return GameLanguage::Undefined;
else
{
return GameLanguage::Undefined;
}
}
GameLanguage AppEnv::gameLanguageFromString(QString gameLanguage)
{
if (gameLanguage == "en-US") {
if (gameLanguage == "en-US")
{
return GameLanguage::English;
}
else if (gameLanguage == "fr-FR") {
else if (gameLanguage == "fr-FR")
{
return GameLanguage::French;
}
else if (gameLanguage == "it-IT") {
else if (gameLanguage == "it-IT")
{
return GameLanguage::Italian;
}
else if (gameLanguage == "de-DE") {
else if (gameLanguage == "de-DE")
{
return GameLanguage::German;
}
else if (gameLanguage == "es-ES") {
else if (gameLanguage == "es-ES")
{
return GameLanguage::Spanish;
}
else if (gameLanguage == "es-MX") {
else if (gameLanguage == "es-MX")
{
return GameLanguage::Mexican;
}
else if (gameLanguage == "pt-BR") {
else if (gameLanguage == "pt-BR")
{
return GameLanguage::Brasilian;
}
else if (gameLanguage == "ru-RU") {
else if (gameLanguage == "ru-RU")
{
return GameLanguage::Russian;
}
else if (gameLanguage == "pl-PL") {
else if (gameLanguage == "pl-PL")
{
return GameLanguage::Polish;
}
else if (gameLanguage == "ja-JP") {
else if (gameLanguage == "ja-JP")
{
return GameLanguage::Japanese;
}
else if (gameLanguage == "zh-CHS") {
else if (gameLanguage == "zh-CHS")
{
return GameLanguage::SChinese;
}
else if (gameLanguage == "zh-CHT") {
else if (gameLanguage == "zh-CHT")
{
return GameLanguage::TChinese;
}
else if (gameLanguage == "ko-KR") {
return GameLanguage::Korean;
else if (gameLanguage == "ko-KR")
{
return GameLanguage::Koreana;
}
else
{
return GameLanguage::Undefined;
}
return GameLanguage::Undefined;
}
QString AppEnv::gameLanguageToString(GameLanguage gameLanguage)
{
switch (gameLanguage) {
case GameLanguage::English:
if (gameLanguage == GameLanguage::English)
{
return "en-US";
case GameLanguage::French:
}
else if (gameLanguage == GameLanguage::French)
{
return "fr-FR";
case GameLanguage::Italian:
}
else if (gameLanguage == GameLanguage::Italian)
{
return "it-IT";
case GameLanguage::German:
}
else if (gameLanguage == GameLanguage::German)
{
return "de-DE";
case GameLanguage::Spanish:
}
else if (gameLanguage == GameLanguage::Spanish)
{
return "es-ES";
case GameLanguage::Mexican:
}
else if (gameLanguage == GameLanguage::Mexican)
{
return "es-MX";
case GameLanguage::Brasilian:
}
else if (gameLanguage == GameLanguage::Brasilian)
{
return "pt-BR";
case GameLanguage::Polish:
}
else if (gameLanguage == GameLanguage::Russian)
{
return "ru-RU";
}
else if (gameLanguage == GameLanguage::Polish)
{
return "pl-PL";
case GameLanguage::Japanese:
}
else if (gameLanguage == GameLanguage::Japanese)
{
return "ja-JP";
case GameLanguage::SChinese:
}
else if (gameLanguage == GameLanguage::SChinese)
{
return "zh-CHS";
case GameLanguage::TChinese:
}
else if (gameLanguage == GameLanguage::TChinese)
{
return "zh-CHT";
case GameLanguage::Korean:
}
else if (gameLanguage == GameLanguage::Koreana)
{
return "ko-KR";
default:
}
else
{
return "Undefinied";
}
}
@ -373,55 +428,67 @@ bool AppEnv::setGameLanguage(GameVersion gameVersion, GameLanguage gameLanguage)
{
bool socialClubVersion = false;
bool steamVersion = false;
if (gameVersion == GameVersion::SocialClubVersion) {
if (gameVersion == GameVersion::SocialClubVersion)
{
socialClubVersion = true;
}
else if (gameVersion == GameVersion::SteamVersion) {
else if (gameVersion == GameVersion::SteamVersion)
{
steamVersion = true;
}
else if (gameVersion == GameVersion::BothVersions) {
else if (gameVersion == GameVersion::BothVersions)
{
socialClubVersion = true;
steamVersion = true;
}
else {
else
{
return false;
}
if (socialClubVersion) {
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) {
if (gameLanguage != GameLanguage::Undefined)
{
registrySettingsSc.setValue("Language", gameLanguageToString(gameLanguage));
}
else {
else
{
registrySettingsSc.remove("Language");
}
registrySettingsSc.sync();
if (registrySettingsSc.status() != QSettings::NoError) {
if (registrySettingsSc.status() != QSettings::NoError)
{
return false;
}
#else
Q_UNUSED(gameLanguage)
#endif
}
if (steamVersion) {
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) {
if (gameLanguage != GameLanguage::Undefined)
{
registrySettingsSteam.setValue("Language", gameLanguageToString(gameLanguage));
}
else {
else
{
registrySettingsSteam.remove("Language");
}
registrySettingsSteam.sync();
if (registrySettingsSteam.status() != QSettings::NoError) {
if (registrySettingsSteam.status() != QSettings::NoError)
{
return false;
}
#else

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -23,7 +23,7 @@
#include <QUrl>
enum class GameVersion : int { NoVersion = 0, SocialClubVersion = 1, SteamVersion = 2, BothVersions = 3 };
enum class GameLanguage : int { Undefined = 0, English = 1, French = 2, Italian = 3, German = 4, Spanish = 5, Mexican = 6, Brasilian = 7, Russian = 8, Polish = 9, Japanese = 10, SChinese = 11, TChinese = 12, Korean = 13 };
enum class GameLanguage : int { Undefined = 0, English = 1, French = 2, Italian = 3, German = 4, Spanish = 5, Mexican = 6, Brasilian = 7, Russian = 8, Polish = 9, Japanese = 10, SChinese = 11, TChinese = 12, Koreana = 13 };
class AppEnv
{
@ -39,9 +39,7 @@ public:
static bool setGameFolder(QString gameFolder);
static QString getExLangFolder();
static QString getInLangFolder();
static QString getImagesFolder();
static QString getPluginsFolder();
static QString getShareFolder();
// Web Stuff
static QByteArray getUserAgent();

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.7)
cmake_minimum_required(VERSION 3.5)
project(gta5view LANGUAGES C CXX)
@ -11,18 +11,13 @@ set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(FORCE_QT_VERSION "" CACHE STRING "Force Qt Version")
if(FORCE_QT_VERSION)
set(QT_VERSION_MAJOR ${FORCE_QT_VERSION})
else()
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
endif()
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Network Svg Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS LinguistTools QUIET)
find_package(Qt5 COMPONENTS Network Svg Widgets REQUIRED)
find_package(Qt5 COMPONENTS LinguistTools QUIET)
if(WIN32)
find_package(Qt5 COMPONENTS WinExtras REQUIRED)
list(APPEND GTA5VIEW_LIBS
dwmapi
Qt5::WinExtras
)
list(APPEND GTA5VIEW_DEFINES
-DUNICODE
@ -33,20 +28,11 @@ if(WIN32)
res/app.rc
)
endif()
if(APPLE)
list(APPEND GTA5VIEW_RESOURCES
res/gta5view.icns
)
set(MACOSX_BUNDLE_BUNDLE_NAME gta5view)
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")
endif()
list(APPEND GTA5VIEW_DEFINES
-DGTA5SYNC_CMAKE
-DGTA5SYNC_PROJECT
-DSNAPMATIC_NODEFAULT
)
set(GTA5VIEW_SOURCES
@ -71,7 +57,6 @@ set(GTA5VIEW_SOURCES
ProfileInterface.cpp
ProfileLoader.cpp
ProfileWidget.cpp
RagePhoto.cpp
SavegameCopy.cpp
SavegameData.cpp
SavegameDialog.cpp
@ -93,7 +78,6 @@ set(GTA5VIEW_SOURCES
set(GTA5VIEW_HEADERS
config.h
wrapper.h
AboutDialog.h
AppEnv.h
CrewDatabase.h
@ -114,7 +98,6 @@ set(GTA5VIEW_HEADERS
ProfileInterface.h
ProfileLoader.h
ProfileWidget.h
RagePhoto.h
SavegameCopy.h
SavegameData.h
SavegameDialog.h
@ -157,36 +140,26 @@ set(GTA5VIEW_FORMS
UserInterface.ui
)
set(GTA5VIEW_TRANSLATIONS
res/gta5sync_de.ts
res/gta5sync_en_US.ts
res/gta5sync_fr.ts
res/gta5sync_ko.ts
res/gta5sync_ru.ts
res/gta5sync_uk.ts
res/gta5sync_zh_TW.ts
)
list(APPEND GTA5VIEW_RESOURCES
res/app.qrc
res/global.qrc
res/template.qrc
)
set_property(SOURCE res/global.qrc PROPERTY AUTORCC_OPTIONS "-threshold;0;-compress;9")
if(Qt5LinguistTools_FOUND)
qt5_add_translation(GTA5VIEW_QMFILES
${GTA5VIEW_TRANSLATIONS}
res/qt5/qtbase_en_GB.ts
qt5_add_translation(GTA5VIEW_TRANSLATIONS
res/gta5sync_de.ts
res/gta5sync_en_US.ts
res/gta5sync_fr.ts
res/gta5sync_ko.ts
res/gta5sync_ru.ts
res/gta5sync_uk.ts
res/gta5sync_zh_TW.ts
res/qtbase_en_GB.ts
)
set(LINGUIST_FOUND TRUE)
elseif(Qt6LinguistTools_FOUND)
qt6_add_translation(GTA5VIEW_QMFILES
${GTA5VIEW_TRANSLATIONS}
res/qt6/qtbase_en_GB.ts
)
set(LINGUIST_FOUND TRUE)
add_custom_target(translations DEPENDS ${GTA5VIEW_TRANSLATIONS})
else()
set(GTA5VIEW_QMFILES
set(GTA5VIEW_TRANSLATIONS
res/gta5sync_de.qm
res/gta5sync_en_US.qm
res/gta5sync_fr.qm
@ -194,7 +167,7 @@ else()
res/gta5sync_ru.qm
res/gta5sync_uk.qm
res/gta5sync_zh_TW.qm
res/qt${QT_VERSION_MAJOR}/qtbase_en_GB.qm
res/qtbase_en_GB.qm
)
endif()
@ -205,44 +178,22 @@ if(QCONF_BUILD)
)
else()
list(APPEND GTA5VIEW_RESOURCES
res/img.qrc
res/tr_g5p.qrc
res/qt${QT_VERSION_MAJOR}/tr_qt.qrc
res/tr_qt5.qrc
)
endif()
option(FLATPAK_BUILD "Flatpak modifications and optimisations" OFF)
option(FLATPAK_BUILD "Flatpak modifications and identifications" OFF)
if(FLATPAK_BUILD)
list(APPEND GTA5VIEW_DEFINES
"-DGTA5SYNC_BUILDCODE=\"Flatpak\""
"-DGTA5SYNC_BUILDTYPE=\"Flatpak\""
-DGTA5SYNC_FLATPAK
)
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
anpro/QrCode.h
)
list(APPEND GTA5VIEW_SOURCES
anpro/QrCode.cpp
)
list(APPEND GTA5VIEW_DEFINES
-DGTA5SYNC_DONATE
)
list(APPEND GTA5VIEW_RESOURCES
res/donate.qrc
)
if(DONATE_ADDRESSES)
list(APPEND GTA5VIEW_DEFINES
"-DGTA5SYNC_DONATE_ADDRESSES=\"${DONATE_ADDRESSES}\""
)
endif()
endif()
option(WITH_MOTD "Developer message system directed to users" OFF)
if(WITH_MOTD)
set(MOTD_WEBURL "" CACHE STRING "Messages WebURL")
list(APPEND GTA5VIEW_HEADERS
MessageThread.h
)
@ -261,11 +212,6 @@ endif()
option(WITH_TELEMETRY "Hardware survey and basic telemetry system" OFF)
if(WITH_TELEMETRY)
set(TELEMETRY_AUTHID "" CACHE STRING "Telemetry AuthID")
set(TELEMETRY_AUTHPW "" CACHE STRING "Telemetry AuthPW")
set(TELEMETRY_PUSHURL "" CACHE STRING "Telemetry PushURL")
set(TELEMETRY_REGURL "" CACHE STRING "Telemetry RegURL")
set(TELEMETRY_WEBURL "" CACHE STRING "Telemetry WebURL")
list(APPEND GTA5VIEW_HEADERS
TelemetryClass.h
tmext/TelemetryClassAuthenticator.h
@ -314,6 +260,37 @@ if(GTA5VIEW_BUILDTYPE)
list(APPEND GTA5VIEW_DEFINES
"-DGTA5SYNC_BUILDTYPE=\"${GTA5VIEW_BUILDTYPE}\""
)
else()
if(GTA5VIEW_BUILDTYPE_ALPHA)
list(APPEND GTA5VIEW_DEFINES
-DGTA5SYNC_BUILDTYPE_ALPHA
)
endif()
if(GTA5VIEW_BUILDTYPE_BETA)
list(APPEND GTA5VIEW_DEFINES
-DGTA5SYNC_BUILDTYPE_BETA
)
endif()
if(GTA5VIEW_BUILDTYPE_DEV)
list(APPEND GTA5VIEW_DEFINES
-DGTA5SYNC_BUILDTYPE_DEV
)
endif()
if(GTA5VIEW_BUILDTYPE_DAILY)
list(APPEND GTA5VIEW_DEFINES
-DGTA5SYNC_BUILDTYPE_DAILY
)
endif()
if(GTA5VIEW_BUILDTYPE_RC)
list(APPEND GTA5VIEW_DEFINES
-DGTA5SYNC_BUILDTYPE_RC
)
endif()
if(GTA5VIEW_BUILDTYPE_REL)
list(APPEND GTA5VIEW_DEFINES
-DGTA5SYNC_BUILDTYPE_REL
)
endif()
endif()
if(GTA5VIEW_COMMIT)
list(APPEND GTA5VIEW_DEFINES
@ -345,8 +322,7 @@ add_executable(gta5view
${GTA5VIEW_RESOURCES}
)
if(LINGUIST_FOUND AND QCONF_BUILD)
add_custom_target(translations DEPENDS ${GTA5VIEW_QMFILES})
if(Qt5LinguistTools_FOUND AND QCONF_BUILD)
add_dependencies(gta5view translations)
endif()
@ -360,12 +336,11 @@ endif()
target_compile_definitions(gta5view PRIVATE ${GTA5VIEW_DEFINES})
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})
target_link_libraries(gta5view PRIVATE Qt5::Network Qt5::Svg Qt5::Widgets ${GTA5VIEW_LIBS})
install(TARGETS gta5view DESTINATION bin)
install(FILES res/de.syping.gta5view.desktop DESTINATION share/applications)
install(FILES res/de.syping.gta5view.metainfo.xml DESTINATION share/metainfo)
install(FILES res/de.syping.gta5view.xml DESTINATION share/mime/packages)
install(FILES res/gta5view-16.png DESTINATION share/icons/hicolor/16x16/apps RENAME de.syping.gta5view.png)
install(FILES res/gta5view-24.png DESTINATION share/icons/hicolor/24x24/apps RENAME de.syping.gta5view.png)
install(FILES res/gta5view-32.png DESTINATION share/icons/hicolor/32x32/apps RENAME de.syping.gta5view.png)
@ -375,8 +350,7 @@ install(FILES res/gta5view-96.png DESTINATION share/icons/hicolor/96x96/apps REN
install(FILES res/gta5view-128.png DESTINATION share/icons/hicolor/128x128/apps RENAME de.syping.gta5view.png)
install(FILES res/gta5view-256.png DESTINATION share/icons/hicolor/256x256/apps RENAME de.syping.gta5view.png)
install(FILES res/gta5view-512.png DESTINATION share/icons/hicolor/512x512/apps RENAME de.syping.gta5view.png)
install(FILES res/de.syping.gta5view.png DESTINATION share/pixmaps)
if(QCONF_BUILD)
include(res/img.cmake)
install(FILES ${GTA5VIEW_IMGFILES} DESTINATION share/gta5view/resources)
install(FILES ${GTA5VIEW_QMFILES} DESTINATION share/gta5view/translations)
install(FILES ${GTA5VIEW_TRANSLATIONS} DESTINATION share/gta5view/translations)
endif()

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -46,7 +46,8 @@ void DatabaseThread::run()
QObject::connect(this, SIGNAL(threadTerminated()), &threadLoop, SLOT(quit()));
while (threadRunning) {
while (threadRunning)
{
QTimer::singleShot(300000, &threadLoop, SLOT(quit()));
threadLoop.exec();
}
@ -54,8 +55,10 @@ void DatabaseThread::run()
void DatabaseThread::scanCrewReference(const QStringList &crewList, const int &requestDelay)
{
for (const QString &crewID : crewList) {
if (threadRunning && crewID != QLatin1String("0")) {
for (QString crewID : crewList)
{
if (threadRunning && crewID != QLatin1String("0"))
{
QNetworkAccessManager *netManager = new QNetworkAccessManager();
QNetworkRequest netRequest(AppEnv::getCrewFetchingUrl(crewID));
#if QT_VERSION >= 0x050600
@ -73,36 +76,40 @@ void DatabaseThread::scanCrewReference(const QStringList &crewList, const int &r
QEventLoop *downloadLoop = new QEventLoop();
QObject::connect(netReply, SIGNAL(finished()), downloadLoop, SLOT(quit()));
if (!continueLastCrew)
QObject::connect(this, SIGNAL(threadTerminated()), downloadLoop, SLOT(quit()));
if (!continueLastCrew) { QObject::connect(this, SIGNAL(threadTerminated()), downloadLoop, SLOT(quit())); }
QTimer::singleShot(30000, downloadLoop, SLOT(quit()));
downloadLoop->exec();
downloadLoop->disconnect();
delete downloadLoop;
if (netReply->isFinished()) {
if (netReply->isFinished())
{
QString crewName;
QByteArray crewHtml = netReply->readAll();
QStringList crewHtmlSplit1 = QString::fromUtf8(crewHtml).split("<title>Rockstar Games Social Club - Crew : ");
if (crewHtmlSplit1.length() >= 2) {
if (crewHtmlSplit1.length() >= 2)
{
QStringList crewHtmlSplit2 = QString(crewHtmlSplit1.at(1)).split("</title>");
if (crewHtmlSplit2.length() >= 1) {
if (crewHtmlSplit2.length() >= 1)
{
crewName = crewHtmlSplit2.at(0);
}
}
if (!crewName.isEmpty()) {
if (!crewName.isEmpty())
{
emit crewNameFound(crewID.toInt(), crewName);
}
}
else {
else
{
netReply->abort();
}
if (threadRunning) {
if (threadRunning)
{
QEventLoop *waitingLoop = new QEventLoop();
QTimer::singleShot(requestDelay, waitingLoop, SLOT(quit()));
if (!continueLastCrew)
QObject::connect(this, SIGNAL(threadTerminated()), waitingLoop, SLOT(quit()));
if (!continueLastCrew) { QObject::connect(this, SIGNAL(threadTerminated()), waitingLoop, SLOT(quit())); }
waitingLoop->exec();
waitingLoop->disconnect();
delete waitingLoop;
@ -116,14 +123,17 @@ void DatabaseThread::scanCrewReference(const QStringList &crewList, const int &r
void DatabaseThread::scanCrewMembersList(const QStringList &crewList, const int &maxPages, const int &requestDelay)
{
for (const QString &crewID : crewList) {
if (threadRunning && crewID != QLatin1String("0")) {
for (QString crewID : crewList)
{
if (threadRunning && crewID != QLatin1String("0"))
{
int currentFail = 0;
int currentPage = 0;
int foundPlayers = 0;
int totalPlayers = 1000;
while(foundPlayers < totalPlayers && currentPage < maxPages && (continueLastCrew ? true : threadRunning)) {
while(foundPlayers < totalPlayers && currentPage < maxPages && (continueLastCrew ? true : threadRunning))
{
QNetworkAccessManager *netManager = new QNetworkAccessManager();
QNetworkRequest netRequest(AppEnv::getPlayerFetchingUrl(crewID, currentPage));
#if QT_VERSION >= 0x050600
@ -141,14 +151,14 @@ void DatabaseThread::scanCrewMembersList(const QStringList &crewList, const int
QEventLoop *downloadLoop = new QEventLoop();
QObject::connect(netReply, SIGNAL(finished()), downloadLoop, SLOT(quit()));
if (!continueLastCrew)
QObject::connect(this, SIGNAL(threadTerminated()), downloadLoop, SLOT(quit()));
if (!continueLastCrew) { QObject::connect(this, SIGNAL(threadTerminated()), downloadLoop, SLOT(quit())); }
QTimer::singleShot(30000, downloadLoop, SLOT(quit()));
downloadLoop->exec();
downloadLoop->disconnect();
delete downloadLoop;
if (netReply->isFinished()) {
if (netReply->isFinished())
{
QByteArray crewJson = netReply->readAll();
QJsonDocument crewDocument = QJsonDocument::fromJson(crewJson);
QJsonObject crewObject = crewDocument.object();
@ -156,25 +166,32 @@ void DatabaseThread::scanCrewMembersList(const QStringList &crewList, const int
if (crewMap.contains("Total")) { totalPlayers = crewMap["Total"].toInt(); }
if (crewMap.contains("Members")) {
if (crewMap.contains("Members"))
{
const QList<QVariant> memberList = crewMap["Members"].toList();
for (const QVariant &memberVariant : memberList) {
for (QVariant memberVariant : memberList)
{
QMap<QString, QVariant> memberMap = memberVariant.toMap();
if (memberMap.contains("RockstarId") && memberMap.contains("Name")) {
if (memberMap.contains("RockstarId") && memberMap.contains("Name"))
{
int RockstarId = memberMap["RockstarId"].toInt();
QString memberName = memberMap["Name"].toString();
if (!memberName.isEmpty() && RockstarId != 0) {
if (!memberName.isEmpty() && RockstarId != 0)
{
foundPlayers++;
emit playerNameFound(RockstarId, memberName);
}
}
}
}
currentPage++;
}
else {
else
{
currentFail++;
if (currentFail == maxLoadFails) {
if (currentFail == maxLoadFails)
{
currentFail = 0;
currentPage++;
}
@ -183,7 +200,8 @@ void DatabaseThread::scanCrewMembersList(const QStringList &crewList, const int
delete netReply;
delete netManager;
if (foundPlayers < totalPlayers && currentPage < maxPages && (continueLastCrew ? true : threadRunning)) {
if (foundPlayers < totalPlayers && currentPage < maxPages && (continueLastCrew ? true : threadRunning))
{
QEventLoop *waitingLoop = new QEventLoop();
QTimer::singleShot(requestDelay, waitingLoop, SLOT(quit()));
if (!continueLastCrew) { QObject::connect(this, SIGNAL(threadTerminated()), waitingLoop, SLOT(quit())); }
@ -198,8 +216,10 @@ void DatabaseThread::scanCrewMembersList(const QStringList &crewList, const int
void DatabaseThread::deleteCompatibleCrews(QStringList *crewList)
{
for (const QString &crewNID : *crewList) {
if (crewDB->isCompatibleCrew(crewNID)) {
for (QString crewNID : *crewList)
{
if (crewDB->isCompatibleCrew(crewNID))
{
crewList->removeAll(crewNID);
}
}
@ -208,8 +228,10 @@ void DatabaseThread::deleteCompatibleCrews(QStringList *crewList)
QStringList DatabaseThread::deleteCompatibleCrews(const QStringList &crewList)
{
QStringList crewListR = crewList;
for (const QString &crewNID : crewListR) {
if (crewDB->isCompatibleCrew(crewNID)) {
for (QString crewNID : crewListR)
{
if (crewDB->isCompatibleCrew(crewNID))
{
crewListR.removeAll(crewNID);
}
}

View File

@ -49,7 +49,7 @@ void ExportThread::run()
// Quality Settings
settings.beginGroup("Pictures");
int defaultQuality = 100;
QSize defExportSize = SnapmaticPicture::getSnapmaticResolution();
QSize defExportSize = QSize(960, 536);
int customQuality = settings.value("CustomQuality", defaultQuality).toInt();
if (customQuality < 1 || customQuality > 100)
{

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -28,6 +28,7 @@
GlobalString::GlobalString()
{
}
QMap<QString, QString> GlobalString::getGlobalMap()
@ -38,7 +39,8 @@ QMap<QString, QString> GlobalString::getGlobalMap()
globalFile.setIniCodec("UTF-8");
#endif
globalFile.beginGroup("Global");
for (const QString &globalStr : globalFile.childKeys()) {
for (const QString &globalStr : globalFile.childKeys())
{
globalMap[globalStr] = globalFile.value(globalStr, globalStr).toString();
}
globalFile.endGroup();
@ -54,9 +56,9 @@ QString GlobalString::getString(QString valueStr, bool *ok)
#endif
globalFile.beginGroup("Global");
QStringList globalStrList = globalFile.childKeys();
if (globalStrList.contains(valueStr)) {
if (ok != nullptr)
*ok = true;
if (globalStrList.contains(valueStr))
{
if (ok != nullptr) *ok = true;
globalString = globalFile.value(valueStr, valueStr).toString();
}
globalFile.endGroup();
@ -67,14 +69,10 @@ QString GlobalString::getLanguageFile()
{
QString language = getLanguage();
QString languageFile = ":/global/global." % language % ".ini";
#if QT_VERSION >= 0x050200
if (!QFileInfo::exists(languageFile))
languageFile = ":/global/global.en.ini";
#else
if (!QFileInfo(languageFile).exists())
{
languageFile = ":/global/global.en.ini";
#endif
}
return languageFile;
}

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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,45 +17,34 @@
*****************************************************************************/
#include "IconLoader.h"
#include "AppEnv.h"
#include <QStringBuilder>
#include <QIcon>
IconLoader::IconLoader()
{
}
QIcon IconLoader::loadingAppIcon()
{
QIcon appIcon;
#if defined(GTA5SYNC_QCONF) && defined(GTA5SYNC_CMAKE)
#ifdef Q_OS_WIN
const QString pattern = AppEnv::getImagesFolder() % QLatin1String("/gta5view-%1.png");
#else
const QString pattern = AppEnv::getShareFolder() % QLatin1String("/icons/hicolor/%1x%1/apps/de.syping.gta5view.png");
#endif
#else
const QString pattern = AppEnv::getImagesFolder() % QLatin1String("/gta5view-%1.png");
#endif
appIcon.addFile(pattern.arg("16"), QSize(16, 16));
appIcon.addFile(pattern.arg("24"), QSize(24, 24));
appIcon.addFile(pattern.arg("32"), QSize(32, 32));
appIcon.addFile(pattern.arg("40"), QSize(40, 40));
appIcon.addFile(pattern.arg("48"), QSize(48, 48));
appIcon.addFile(pattern.arg("64"), QSize(64, 64));
appIcon.addFile(pattern.arg("96"), QSize(96, 96));
appIcon.addFile(pattern.arg("128"), QSize(128, 128));
appIcon.addFile(pattern.arg("256"), QSize(256, 256));
appIcon.addFile(":/img/gta5view-16.png", QSize(16, 16));
appIcon.addFile(":/img/gta5view-24.png", QSize(24, 24));
appIcon.addFile(":/img/gta5view-32.png", QSize(32, 32));
appIcon.addFile(":/img/gta5view-40.png", QSize(40, 40));
appIcon.addFile(":/img/gta5view-48.png", QSize(48, 48));
appIcon.addFile(":/img/gta5view-64.png", QSize(64, 64));
appIcon.addFile(":/img/gta5view-96.png", QSize(96, 96));
appIcon.addFile(":/img/gta5view-128.png", QSize(128, 128));
appIcon.addFile(":/img/gta5view-256.png", QSize(256, 256));
return appIcon;
}
QIcon IconLoader::loadingPointmakerIcon()
{
QIcon pointmakerIcon;
const QString pattern = AppEnv::getImagesFolder() % QLatin1String("/pointmaker-%1.png");
pointmakerIcon.addFile(pattern.arg("8"), QSize(8, 8));
pointmakerIcon.addFile(pattern.arg("16"), QSize(16, 16));
pointmakerIcon.addFile(pattern.arg("24"), QSize(24, 24));
pointmakerIcon.addFile(pattern.arg("32"), QSize(32, 32));
pointmakerIcon.addFile(":/img/pointmaker-8.png", QSize(8, 8));
pointmakerIcon.addFile(":/img/pointmaker-16.png", QSize(16, 16));
pointmakerIcon.addFile(":/img/pointmaker-24.png", QSize(24, 24));
pointmakerIcon.addFile(":/img/pointmaker-32.png", QSize(32, 32));
return pointmakerIcon;
}

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2017-2022 Syping
* Copyright (C) 2017-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
@ -16,11 +16,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include "ImportDialog.h"
#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"
@ -40,6 +39,8 @@
#include <QRgb>
// IMAGES VALUES
#define snapmaticResolutionW 960
#define snapmaticResolutionH 536
#define snapmaticAvatarResolution 470
#define snapmaticAvatarPlacementW 145
#define snapmaticAvatarPlacementH 66
@ -49,11 +50,7 @@ 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);
@ -63,22 +60,26 @@ ImportDialog::ImportDialog(QString profileName, QWidget *parent) :
watermarkAvatar = true;
watermarkPicture = false;
insideAvatarZone = false;
avatarAreaImage = QImage(AppEnv::getImagesFolder() % "/avatarareaimport.png");
avatarAreaImage = QImage(":/img/avatarareaimport.png");
selectedColour = QColor::fromRgb(0, 0, 0, 255);
// Set Icon for OK Button
if (QIcon::hasThemeIcon("dialog-ok")) {
if (QIcon::hasThemeIcon("dialog-ok"))
{
ui->cmdOK->setIcon(QIcon::fromTheme("dialog-ok"));
}
else if (QIcon::hasThemeIcon("gtk-ok")) {
else if (QIcon::hasThemeIcon("gtk-ok"))
{
ui->cmdOK->setIcon(QIcon::fromTheme("gtk-ok"));
}
// Set Icon for Cancel Button
if (QIcon::hasThemeIcon("dialog-cancel")) {
if (QIcon::hasThemeIcon("dialog-cancel"))
{
ui->cmdCancel->setIcon(QIcon::fromTheme("dialog-cancel"));
}
else if (QIcon::hasThemeIcon("gtk-cancel")) {
else if (QIcon::hasThemeIcon("gtk-cancel"))
{
ui->cmdCancel->setIcon(QIcon::fromTheme("gtk-cancel"));
}
@ -87,14 +88,6 @@ ImportDialog::ImportDialog(QString profileName, QWidget *parent) :
ui->labBackgroundImage->setText(tr("Background Image:"));
ui->cmdBackgroundWipe->setVisible(false);
// Snapmatic Resolution
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);
settings.beginGroup("Import");
@ -112,157 +105,123 @@ ImportDialog::ImportDialog(QString profileName, QWidget *parent) :
#ifndef Q_OS_MAC
ui->vlButtom->setContentsMargins(9 * screenRatio, 6 * screenRatio, 9 * screenRatio, 9 * screenRatio);
#else
#if QT_VERSION >= 0x060000
if (QApplication::style()->objectName() == "macos") {
#else
if (QApplication::style()->objectName() == "macintosh") {
#endif
if (QApplication::style()->objectName() == "macintosh")
{
ui->vlButtom->setContentsMargins(9 * screenRatio, 9 * screenRatio, 9 * screenRatio, 9 * screenRatio);
}
else {
else
{
ui->vlButtom->setContentsMargins(9 * screenRatio, 6 * screenRatio, 9 * screenRatio, 9 * screenRatio);
}
#endif
// Options menu
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, SLOT(loadImportSettings()));
optionsMenu.addAction(tr("&Save Settings..."), this, SLOT(saveImportSettings()));
ui->cmdOptions->setMenu(&optionsMenu);
optionsMenu = new QMenu(this);
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, SLOT(loadImportSettings()));
optionsMenu->addAction(tr("&Save Settings..."), this, SLOT(saveImportSettings()));
ui->cmdOptions->setMenu(optionsMenu);
const QSize windowSize = sizeHint();
setMinimumSize(windowSize);
setMaximumSize(windowSize);
setMaximumSize(sizeHint());
setMinimumSize(sizeHint());
setFixedSize(sizeHint());
}
ImportDialog::~ImportDialog()
{
delete optionsMenu;
delete ui;
}
void ImportDialog::processImage()
{
if (workImage.isNull())
return;
if (workImage.isNull()) return;
QImage snapmaticImage = workImage;
QPixmap snapmaticPixmap(snapmaticResolution);
QPixmap snapmaticPixmap(snapmaticResolutionW, snapmaticResolutionH);
snapmaticPixmap.fill(selectedColour);
QPainter snapmaticPainter(&snapmaticPixmap);
qreal screenRatioPR = AppEnv::screenRatioPR();
if (!backImage.isNull()) {
if (!ui->cbStretch->isChecked()) {
if (!backImage.isNull())
{
if (!ui->cbStretch->isChecked())
{
int diffWidth = 0;
int diffHeight = 0;
if (backImage.width() != snapmaticResolution.width()) {
diffWidth = snapmaticResolution.width() - backImage.width();
if (backImage.width() != snapmaticResolutionW)
{
diffWidth = snapmaticResolutionW - backImage.width();
diffWidth = diffWidth / 2;
}
else if (backImage.height() != snapmaticResolution.height()) {
diffHeight = snapmaticResolution.height() - backImage.height();
else if (backImage.height() != snapmaticResolutionH)
{
diffHeight = snapmaticResolutionH - backImage.height();
diffHeight = diffHeight / 2;
}
snapmaticPainter.drawImage(0 + diffWidth, 0 + diffHeight, backImage);
}
else {
snapmaticPainter.drawImage(0, 0, QImage(backImage).scaled(snapmaticResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
else
{
snapmaticPainter.drawImage(0, 0, QImage(backImage).scaled(snapmaticResolutionW, snapmaticResolutionH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
if (ui->cbAvatar->isChecked() && ui->cbForceAvatarColour->isChecked()) {
if (ui->cbAvatar->isChecked() && ui->cbForceAvatarColour->isChecked())
{
snapmaticPainter.fillRect(snapmaticAvatarPlacementW, snapmaticAvatarPlacementH, snapmaticAvatarResolution, snapmaticAvatarResolution, selectedColour);
}
}
if (insideAvatarZone) {
if (insideAvatarZone)
{
// Avatar mode
int diffWidth = 0;
int diffHeight = 0;
if (ui->cbIgnore->isChecked()) {
snapmaticImage = snapmaticImage.scaled(snapmaticAvatarResolution, snapmaticAvatarResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
else if (ui->cbBorderless->isChecked()) {
snapmaticImage = snapmaticImage.scaled(snapmaticAvatarResolution, snapmaticAvatarResolution, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
if (snapmaticImage.width() > snapmaticAvatarResolution) {
int diffWidth = snapmaticImage.width() - snapmaticAvatarResolution;
diffWidth = diffWidth / 2;
QImage croppedImage(snapmaticAvatarResolution, snapmaticAvatarResolution, QImage::Format_ARGB32);
croppedImage.fill(Qt::transparent);
QPainter croppedPainter(&croppedImage);
croppedPainter.drawImage(0 - diffWidth, 0, snapmaticImage);
croppedPainter.end();
snapmaticImage = croppedImage;
}
else if (snapmaticImage.height() > snapmaticAvatarResolution) {
int diffHeight = snapmaticImage.height() - snapmaticAvatarResolution;
diffHeight = diffHeight / 2;
QImage croppedImage(snapmaticAvatarResolution, snapmaticAvatarResolution, QImage::Format_ARGB32);
croppedImage.fill(Qt::transparent);
QPainter croppedPainter(&croppedImage);
croppedPainter.drawImage(0, 0 - diffHeight, snapmaticImage);
croppedPainter.end();
snapmaticImage = croppedImage;
}
}
else {
if (!ui->cbIgnore->isChecked())
{
snapmaticImage = snapmaticImage.scaled(snapmaticAvatarResolution, snapmaticAvatarResolution, Qt::KeepAspectRatio, Qt::SmoothTransformation);
if (snapmaticImage.width() > snapmaticImage.height()) {
if (snapmaticImage.width() > snapmaticImage.height())
{
diffHeight = snapmaticAvatarResolution - snapmaticImage.height();
diffHeight = diffHeight / 2;
}
else if (snapmaticImage.width() < snapmaticImage.height()) {
else if (snapmaticImage.width() < snapmaticImage.height())
{
diffWidth = snapmaticAvatarResolution - snapmaticImage.width();
diffWidth = diffWidth / 2;
}
}
else
{
snapmaticImage = snapmaticImage.scaled(snapmaticAvatarResolution, snapmaticAvatarResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
snapmaticPainter.drawImage(snapmaticAvatarPlacementW + diffWidth, snapmaticAvatarPlacementH + diffHeight, snapmaticImage);
if (ui->cbWatermark->isChecked())
processWatermark(&snapmaticPainter);
if (ui->cbWatermark->isChecked()) { processWatermark(&snapmaticPainter); }
imageTitle = tr("Custom Avatar", "Custom Avatar Description in SC, don't use Special Character!");
}
else {
else
{
// Picture mode
int diffWidth = 0;
int diffHeight = 0;
if (ui->cbIgnore->isChecked()) {
snapmaticImage = snapmaticImage.scaled(snapmaticResolution, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
else if (ui->cbBorderless->isChecked()) {
snapmaticImage = snapmaticImage.scaled(snapmaticResolution, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
if (snapmaticImage.width() > snapmaticResolution.width()) {
int diffWidth = snapmaticImage.width() - snapmaticResolution.width();
diffWidth = diffWidth / 2;
QImage croppedImage(snapmaticResolution, QImage::Format_ARGB32);
croppedImage.fill(Qt::transparent);
QPainter croppedPainter(&croppedImage);
croppedPainter.drawImage(0 - diffWidth, 0, snapmaticImage);
croppedPainter.end();
snapmaticImage = croppedImage;
}
else if (snapmaticImage.height() > snapmaticResolution.height()) {
int diffHeight = snapmaticImage.height() - snapmaticResolution.height();
diffHeight = diffHeight / 2;
QImage croppedImage(snapmaticResolution, QImage::Format_ARGB32);
croppedImage.fill(Qt::transparent);
QPainter croppedPainter(&croppedImage);
croppedPainter.drawImage(0, 0 - diffHeight, snapmaticImage);
croppedPainter.end();
snapmaticImage = croppedImage;
}
}
else {
snapmaticImage = snapmaticImage.scaled(snapmaticResolution, Qt::KeepAspectRatio, Qt::SmoothTransformation);
if (snapmaticImage.width() != snapmaticResolution.width()) {
diffWidth = snapmaticResolution.width() - snapmaticImage.width();
if (!ui->cbIgnore->isChecked())
{
snapmaticImage = snapmaticImage.scaled(snapmaticResolutionW, snapmaticResolutionH, Qt::KeepAspectRatio, Qt::SmoothTransformation);
if (snapmaticImage.width() != snapmaticResolutionW)
{
diffWidth = snapmaticResolutionW - snapmaticImage.width();
diffWidth = diffWidth / 2;
}
else if (snapmaticImage.height() != snapmaticResolution.height()) {
diffHeight = snapmaticResolution.height() - snapmaticImage.height();
else if (snapmaticImage.height() != snapmaticResolutionH)
{
diffHeight = snapmaticResolutionH - snapmaticImage.height();
diffHeight = diffHeight / 2;
}
}
else
{
snapmaticImage = snapmaticImage.scaled(snapmaticResolutionW, snapmaticResolutionH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
snapmaticPainter.drawImage(0 + diffWidth, 0 + diffHeight, snapmaticImage);
if (ui->cbWatermark->isChecked())
processWatermark(&snapmaticPainter);
if (ui->cbWatermark->isChecked()) { processWatermark(&snapmaticPainter); }
imageTitle = tr("Custom Picture", "Custom Picture Description in SC, don't use Special Character!");
}
snapmaticPainter.end();
@ -273,136 +232,94 @@ void ImportDialog::processImage()
ui->labPicture->setPixmap(snapmaticPixmap.scaled(snapmaticResolutionLW * screenRatioPR, snapmaticResolutionLH * screenRatioPR, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
void ImportDialog::reworkImage()
{
workImage = QImage();
if (origImage.width() == origImage.height()) {
if (ui->cbResolution->currentIndex() == 0) {
insideAvatarZone = true;
ui->cbAvatar->setChecked(true);
}
else {
insideAvatarZone = false;
ui->cbAvatar->setChecked(false);
}
if (origImage.height() > snapmaticResolution.height()) {
workImage = origImage.scaled(snapmaticResolution.height(), snapmaticResolution.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
else {
workImage = origImage;
}
}
else if (origImage.width() > snapmaticResolution.width() && origImage.width() > origImage.height()) {
insideAvatarZone = false;
ui->cbAvatar->setChecked(false);
workImage = origImage.scaledToWidth(snapmaticResolution.width(), Qt::SmoothTransformation);
}
else if (origImage.height() > snapmaticResolution.height() && origImage.height() > origImage.width()) {
insideAvatarZone = false;
ui->cbAvatar->setChecked(false);
workImage = origImage.scaledToHeight(snapmaticResolution.height(), Qt::SmoothTransformation);
}
else {
insideAvatarZone = false;
ui->cbAvatar->setChecked(false);
workImage = origImage;
}
processImage();
}
void ImportDialog::processWatermark(QPainter *snapmaticPainter)
{
bool blackWatermark = false;
bool redWatermark = false;
if (selectedColour.red() > 127) {
if (selectedColour.green() > 127 || selectedColour.blue() > 127) {
if (selectedColour.red() > 127)
{
if (selectedColour.green() > 127 || selectedColour.blue() > 127)
{
redWatermark = true;
}
}
else {
else
{
redWatermark = true;
}
if (selectedColour.lightness() > 127) {
if (selectedColour.lightness() > 127)
{
blackWatermark = true;
}
// draw watermark
if (redWatermark) {
const QImage viewWatermark = QImage(AppEnv::getImagesFolder() % "/watermark_2r.png");
snapmaticPainter->drawImage(snapmaticResolution.width() - viewWatermark.width(), 0, viewWatermark);
if (redWatermark)
{
snapmaticPainter->drawImage(0, 0, QImage(":/img/watermark_2r.png"));
}
else
{
QImage viewWatermark = QImage(AppEnv::getImagesFolder() % "/watermark_2b.png");
if (!blackWatermark) {
QImage viewWatermark = QImage(":/img/watermark_2b.png");
if (!blackWatermark)
{
viewWatermark.invertPixels(QImage::InvertRgb);
}
snapmaticPainter->drawImage(snapmaticResolution.width() - viewWatermark.width(), 0, viewWatermark);
snapmaticPainter->drawImage(0, 0, viewWatermark);
}
QImage textWatermark = QImage(AppEnv::getImagesFolder() % "/watermark_1b.png");
if (!blackWatermark) {
QImage textWatermark = QImage(":/img/watermark_1b.png");
if (!blackWatermark)
{
textWatermark.invertPixels(QImage::InvertRgb);
}
snapmaticPainter->drawImage(snapmaticResolution.width() - textWatermark.width(), 0, textWatermark);
snapmaticPainter->drawImage(0, 0, textWatermark);
}
void ImportDialog::processSettings(QString settingsProfile, bool setDefault)
{
QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
settings.beginGroup("Import");
if (setDefault) {
if (setDefault)
{
settings.setValue("Profile", settingsProfile);
}
if (settingsProfile == "Default") {
if (settingsProfile == "Default")
{
watermarkAvatar = true;
watermarkPicture = false;
selectedColour = QColor::fromRgb(0, 0, 0, 255);
backImage = QImage();
ui->cbBorderless->setChecked(false);
ui->cbStretch->setChecked(false);
ui->cbForceAvatarColour->setChecked(false);
ui->cbUnlimited->setChecked(false);
ui->cbImportAsIs->setChecked(false);
ui->cbResolution->setCurrentIndex(0);
}
else {
else
{
settings.beginGroup(settingsProfile);
watermarkAvatar = settings.value("WatermarkAvatar", true).toBool();
watermarkPicture = settings.value("WatermarkPicture", false).toBool();
backImage = qvariant_cast<QImage>(settings.value("BackgroundImage", QImage()));
selectedColour = qvariant_cast<QColor>(settings.value("SelectedColour", QColor::fromRgb(0, 0, 0, 255)));
ui->cbBorderless->setChecked(settings.value("BorderlessImage", false).toBool());
ui->cbStretch->setChecked(settings.value("BackgroundStretch", false).toBool());
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", SnapmaticPicture::getSnapmaticResolution());
#if QT_VERSION >= 0x060000
if (data.typeId() == QMetaType::QSize)
#else
if (data.type() == QVariant::Size)
#endif
{
int index = ui->cbResolution->findData(data);
if (index != -1) {
ui->cbResolution->setCurrentIndex(index);
}
}
settings.endGroup();
}
if (!workImage.isNull()) {
if (ui->cbAvatar->isChecked()) {
if (!workImage.isNull())
{
if (ui->cbAvatar->isChecked())
{
ui->cbWatermark->setChecked(watermarkAvatar);
}
else {
else
{
ui->cbWatermark->setChecked(watermarkPicture);
}
}
ui->labColour->setText(tr("Background Colour: <span style=\"color: %1\">%1</span>").arg(selectedColour.name()));
if (!backImage.isNull()) {
if (!backImage.isNull())
{
ui->labBackgroundImage->setText(tr("Background Image: %1").arg(tr("Storage", "Background Image: Storage")));
ui->cmdBackgroundWipe->setVisible(true);
}
else {
else
{
ui->labBackgroundImage->setText(tr("Background Image:"));
ui->cmdBackgroundWipe->setVisible(false);
}
@ -418,27 +335,8 @@ void ImportDialog::saveSettings(QString settingsProfile)
settings.setValue("WatermarkPicture", watermarkPicture);
settings.setValue("BackgroundImage", backImage);
settings.setValue("SelectedColour", selectedColour);
settings.setValue("BorderlessImage", ui->cbBorderless->isChecked());
settings.setValue("BackgroundStretch", ui->cbStretch->isChecked());
settings.setValue("ForceAvatarColour", ui->cbForceAvatarColour->isChecked());
#if QT_VERSION >= 0x050000
const QVariant data = ui->cbResolution->currentData();
#else
const QVariant data = ui->cbResolution->itemData(ui->cbResolution->currentIndex());
#endif
#if QT_VERSION >= 0x060000
if (data.typeId() == QMetaType::QSize)
#else
if (data.type() == QVariant::Size)
#endif
{
settings.setValue("Resolution", data);
}
else {
settings.setValue("Resolution", SnapmaticPicture::getSnapmaticResolution());
}
settings.setValue("UnlimitedBuffer", ui->cbUnlimited->isChecked());
settings.setValue("ImportAsIs", ui->cbImportAsIs->isChecked());
settings.endGroup();
settings.setValue("Profile", settingsProfile);
settings.endGroup();
@ -504,7 +402,8 @@ void ImportDialog::cropPicture()
cropDialog.show();
cropDialog.setFixedSize(cropDialog.sizeHint());
if (cropDialog.exec() == QDialog::Accepted) {
if (cropDialog.exec() == QDialog::Accepted)
{
QImage *croppedImage = new QImage(imageCropper.cropImage().toImage());
setImage(croppedImage);
}
@ -529,7 +428,8 @@ fileDialogPreOpen: //Work?
// Getting readable Image formats
QString imageFormatsStr = " ";
for (const QByteArray &imageFormat : QImageReader::supportedImageFormats()) {
for (QByteArray imageFormat : QImageReader::supportedImageFormats())
{
imageFormatsStr += QString("*.") % QString::fromUtf8(imageFormat).toLower() % " ";
}
@ -544,14 +444,17 @@ fileDialogPreOpen: //Work?
fileDialog.setDirectory(settings.value(profileName % "+Directory", StandardPaths::documentsLocation()).toString());
fileDialog.restoreGeometry(settings.value(profileName % "+Geometry", "").toByteArray());
if (fileDialog.exec()) {
if (fileDialog.exec())
{
QStringList selectedFiles = fileDialog.selectedFiles();
if (selectedFiles.length() == 1) {
if (selectedFiles.length() == 1)
{
QString selectedFile = selectedFiles.at(0);
QString selectedFileName = QFileInfo(selectedFile).fileName();
QFile snapmaticFile(selectedFile);
if (!snapmaticFile.open(QFile::ReadOnly)) {
if (!snapmaticFile.open(QFile::ReadOnly))
{
QMessageBox::warning(this, QApplication::translate("ProfileInterface", "Import"), QApplication::translate("ProfileInterface", "Can't import %1 because file can't be open").arg("\""+selectedFileName+"\""));
goto fileDialogPreOpen;
}
@ -559,7 +462,8 @@ fileDialogPreOpen: //Work?
QImageReader snapmaticImageReader;
snapmaticImageReader.setDecideFormatFromContent(true);
snapmaticImageReader.setDevice(&snapmaticFile);
if (!snapmaticImageReader.read(importImage)) {
if (!snapmaticImageReader.read(importImage))
{
QMessageBox::warning(this, QApplication::translate("ProfileInterface", "Import"), QApplication::translate("ProfileInterface", "Can't import %1 because file can't be parsed properly").arg("\""+selectedFileName+"\""));
delete importImage;
goto fileDialogPreOpen;
@ -576,38 +480,45 @@ fileDialogPreOpen: //Work?
void ImportDialog::loadImportSettings()
{
if (settingsLocked) {
if (settingsLocked)
{
QMessageBox::information(this, tr("Load Settings..."), tr("Please import a new picture first"));
return;
}
bool ok;
QStringList profileList;
profileList << tr("Default", "Default as Default Profile")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("1")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("2")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("3")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("4")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("5");
<< tr("Profile %1", "Profile %1 as Profile 1").arg("1")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("2")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("3")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("4")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("5");
QString sProfile = QInputDialog::getItem(this, tr("Load Settings..."), tr("Please select your settings profile"), profileList, 0, false, &ok, windowFlags());
if (ok) {
if (ok)
{
QString pProfile;
if (sProfile == tr("Default", "Default as Default Profile")) {
if (sProfile == tr("Default", "Default as Default Profile"))
{
pProfile = "Default";
}
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("1")) {
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("1"))
{
pProfile = "Profile 1";
}
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("2")) {
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("2"))
{
pProfile = "Profile 2";
}
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("3")) {
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("3"))
{
pProfile = "Profile 3";
}
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("4"))
{
pProfile = "Profile 4";
}
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("5")) {
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("5"))
{
pProfile = "Profile 5";
}
processSettings(pProfile, true);
@ -617,33 +528,40 @@ void ImportDialog::loadImportSettings()
void ImportDialog::saveImportSettings()
{
if (settingsLocked) {
if (settingsLocked)
{
QMessageBox::information(this, tr("Save Settings..."), tr("Please import a new picture first"));
return;
}
bool ok;
QStringList profileList;
profileList << tr("Profile %1", "Profile %1 as Profile 1").arg("1")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("2")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("3")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("4")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("5");
<< tr("Profile %1", "Profile %1 as Profile 1").arg("2")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("3")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("4")
<< tr("Profile %1", "Profile %1 as Profile 1").arg("5");
QString sProfile = QInputDialog::getItem(this, tr("Save Settings..."), tr("Please select your settings profile"), profileList, 0, false, &ok, windowFlags());
if (ok) {
if (ok)
{
QString pProfile;
if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("1")) {
if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("1"))
{
pProfile = "Profile 1";
}
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("2")) {
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("2"))
{
pProfile = "Profile 2";
}
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("3")) {
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("3"))
{
pProfile = "Profile 3";
}
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("4")) {
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("4"))
{
pProfile = "Profile 4";
}
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("5")) {
else if (sProfile == tr("Profile %1", "Profile %1 as Profile 1").arg("5"))
{
pProfile = "Profile 5";
}
saveSettings(pProfile);
@ -652,49 +570,44 @@ void ImportDialog::saveImportSettings()
QImage ImportDialog::image()
{
if (ui->cbImportAsIs->isChecked()) {
return origImage;
}
else {
return newImage;
}
return newImage;
}
void ImportDialog::setImage(QImage *image_)
{
origImage = *image_;
workImage = QImage();
if (image_->width() == image_->height()) {
if (ui->cbResolution->currentIndex() == 0) {
insideAvatarZone = true;
ui->cbAvatar->setChecked(true);
}
else {
insideAvatarZone = false;
ui->cbAvatar->setChecked(false);
}
if (image_->height() > snapmaticResolution.height()) {
workImage = image_->scaled(snapmaticResolution.height(), snapmaticResolution.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
if (image_->width() == image_->height())
{
insideAvatarZone = true;
ui->cbAvatar->setChecked(true);
if (image_->height() > snapmaticResolutionH)
{
workImage = image_->scaled(snapmaticResolutionH, snapmaticResolutionH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
delete image_;
}
else {
else
{
workImage = *image_;
delete image_;
}
}
else if (image_->width() > snapmaticResolution.width() && image_->width() > image_->height()) {
else if (image_->width() > snapmaticResolutionW && image_->width() > image_->height())
{
insideAvatarZone = false;
ui->cbAvatar->setChecked(false);
workImage = image_->scaledToWidth(snapmaticResolution.width(), Qt::SmoothTransformation);
workImage = image_->scaledToWidth(snapmaticResolutionW, Qt::SmoothTransformation);
delete image_;
}
else if (image_->height() > snapmaticResolution.height() && image_->height() > image_->width()) {
else if (image_->height() > snapmaticResolutionH && image_->height() > image_->width())
{
insideAvatarZone = false;
ui->cbAvatar->setChecked(false);
workImage = image_->scaledToHeight(snapmaticResolution.height(), Qt::SmoothTransformation);
workImage = image_->scaledToHeight(snapmaticResolutionH, Qt::SmoothTransformation);
delete image_;
}
else {
else
{
insideAvatarZone = false;
ui->cbAvatar->setChecked(false);
workImage = *image_;
@ -706,15 +619,18 @@ void ImportDialog::setImage(QImage *image_)
void ImportDialog::lockSettings(bool lock)
{
ui->gbAdvanced->setDisabled(lock);
if (ui->cbImportAsIs->isChecked()) {
ui->gbBackground->setDisabled(true);
ui->gbSettings->setDisabled(true);
}
else {
ui->gbBackground->setDisabled(lock);
ui->gbSettings->setDisabled(lock);
}
ui->cbAvatar->setDisabled(lock);
ui->cbForceAvatarColour->setDisabled(lock);
ui->cbIgnore->setDisabled(lock);
ui->cbStretch->setDisabled(lock);
ui->cbWatermark->setDisabled(lock);
ui->cmdBackgroundChange->setDisabled(lock);
ui->cmdBackgroundWipe->setDisabled(lock);
ui->cmdColourChange->setDisabled(lock);
ui->labBackgroundImage->setDisabled(lock);
ui->labColour->setDisabled(lock);
ui->gbSettings->setDisabled(lock);
ui->gbBackground->setDisabled(lock);
ui->cmdOK->setDisabled(lock);
settingsLocked = lock;
}
@ -736,11 +652,6 @@ bool ImportDialog::isImportAgreed()
return importAgreed;
}
bool ImportDialog::isUnlimitedBuffer()
{
return ui->cbUnlimited->isChecked();
}
bool ImportDialog::areSettingsLocked()
{
return settingsLocked;
@ -748,27 +659,21 @@ bool ImportDialog::areSettingsLocked()
QString ImportDialog::getImageTitle()
{
if (ui->cbImportAsIs->isChecked()) {
return tr("Custom Picture", "Custom Picture Description in SC, don't use Special Character!");
}
else {
return imageTitle;
}
return imageTitle;
}
void ImportDialog::on_cbIgnore_toggled(bool checked)
{
ui->cbBorderless->setDisabled(checked);
Q_UNUSED(checked)
processImage();
}
void ImportDialog::on_cbAvatar_toggled(bool checked)
{
if (ui->cbResolution->currentIndex() != 0)
return;
if (!workImage.isNull() && workImage.width() == workImage.height() && !checked) {
if (QMessageBox::No == QMessageBox::warning(this, tr("Snapmatic Avatar Zone"), tr("Are you sure to use a square image outside of the Avatar Zone?\nWhen you want to use it as Avatar the image will be detached!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No)) {
if (!workImage.isNull() && workImage.width() == workImage.height() && !checked)
{
if (QMessageBox::No == QMessageBox::warning(this, tr("Snapmatic Avatar Zone"), tr("Are you sure to use a square image outside of the Avatar Zone?\nWhen you want to use it as Avatar the image will be detached!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No))
{
ui->cbAvatar->setChecked(true);
insideAvatarZone = true;
return;
@ -776,10 +681,12 @@ void ImportDialog::on_cbAvatar_toggled(bool checked)
}
insideAvatarZone = ui->cbAvatar->isChecked();
watermarkBlock = true;
if (insideAvatarZone) {
if (insideAvatarZone)
{
ui->cbWatermark->setChecked(watermarkAvatar);
}
else {
else
{
ui->cbWatermark->setChecked(watermarkPicture);
}
watermarkBlock = false;
@ -799,9 +706,11 @@ void ImportDialog::on_cmdOK_clicked()
void ImportDialog::on_labPicture_labelPainted()
{
if (insideAvatarZone) {
if (insideAvatarZone)
{
QImage avatarAreaFinalImage(avatarAreaImage);
if (selectedColour.lightness() > 127) {
if (selectedColour.lightness() > 127)
{
avatarAreaFinalImage.setColor(1, qRgb(0, 0, 0));
}
QPainter labelPainter(ui->labPicture);
@ -813,7 +722,8 @@ void ImportDialog::on_labPicture_labelPainted()
void ImportDialog::on_cmdColourChange_clicked()
{
QColor newSelectedColour = QColorDialog::getColor(selectedColour, this, tr("Select Colour..."));
if (newSelectedColour.isValid()) {
if (newSelectedColour.isValid())
{
selectedColour = newSelectedColour;
ui->labColour->setText(tr("Background Colour: <span style=\"color: %1\">%1</span>").arg(selectedColour.name()));
processImage();
@ -839,7 +749,8 @@ fileDialogPreOpen:
// Getting readable Image formats
QString imageFormatsStr = " ";
for (const QByteArray &imageFormat : QImageReader::supportedImageFormats()) {
for (QByteArray imageFormat : QImageReader::supportedImageFormats())
{
imageFormatsStr += QString("*.") % QString::fromUtf8(imageFormat).toLower() % " ";
}
@ -854,14 +765,17 @@ fileDialogPreOpen:
fileDialog.setDirectory(settings.value("Directory", StandardPaths::documentsLocation()).toString());
fileDialog.restoreGeometry(settings.value("Geometry", "").toByteArray());
if (fileDialog.exec()) {
if (fileDialog.exec())
{
QStringList selectedFiles = fileDialog.selectedFiles();
if (selectedFiles.length() == 1) {
if (selectedFiles.length() == 1)
{
QString selectedFile = selectedFiles.at(0);
QString selectedFileName = QFileInfo(selectedFile).fileName();
QFile snapmaticFile(selectedFile);
if (!snapmaticFile.open(QFile::ReadOnly)) {
if (!snapmaticFile.open(QFile::ReadOnly))
{
QMessageBox::warning(this, QApplication::translate("ProfileInterface", "Import"), QApplication::translate("ProfileInterface", "Can't import %1 because file can't be open").arg("\""+selectedFileName+"\""));
goto fileDialogPreOpen;
}
@ -869,11 +783,12 @@ fileDialogPreOpen:
QImageReader snapmaticImageReader;
snapmaticImageReader.setDecideFormatFromContent(true);
snapmaticImageReader.setDevice(&snapmaticFile);
if (!snapmaticImageReader.read(&importImage)) {
if (!snapmaticImageReader.read(&importImage))
{
QMessageBox::warning(this, QApplication::translate("ProfileInterface", "Import"), QApplication::translate("ProfileInterface", "Can't import %1 because file can't be parsed properly").arg("\""+selectedFileName+"\""));
goto fileDialogPreOpen;
}
backImage = importImage.scaled(snapmaticResolution, Qt::KeepAspectRatio, Qt::SmoothTransformation);
backImage = importImage.scaled(snapmaticResolutionW, snapmaticResolutionH, Qt::KeepAspectRatio, Qt::SmoothTransformation);
backgroundPath = selectedFile;
ui->labBackgroundImage->setText(tr("Background Image: %1").arg(tr("File", "Background Image: File")));
ui->cmdBackgroundWipe->setVisible(true);
@ -909,66 +824,16 @@ void ImportDialog::on_cbForceAvatarColour_toggled(bool checked)
void ImportDialog::on_cbWatermark_toggled(bool checked)
{
if (!watermarkBlock) {
if (insideAvatarZone) {
if (!watermarkBlock)
{
if (insideAvatarZone)
{
watermarkAvatar = checked;
}
else {
else
{
watermarkPicture = checked;
}
processImage();
}
}
void ImportDialog::on_cbBorderless_toggled(bool checked)
{
ui->cbIgnore->setDisabled(checked);
processImage();
}
void ImportDialog::on_cbImportAsIs_toggled(bool checked)
{
ui->cbResolution->setDisabled(checked);
ui->labResolution->setDisabled(checked);
ui->gbBackground->setDisabled(checked);
ui->gbSettings->setDisabled(checked);
}
void ImportDialog::on_cbResolution_currentIndexChanged(int index)
{
Q_UNUSED(index)
#if QT_VERSION >= 0x050000
const QVariant data = ui->cbResolution->currentData();
#else
const QVariant data = ui->cbResolution->itemData(ui->cbResolution->currentIndex());
#endif
#if QT_VERSION >= 0x060000
if (data.typeId() == QMetaType::QSize)
#else
if (data.type() == QVariant::Size)
#endif
{
const QSize dataSize = data.toSize();
if (dataSize == SnapmaticPicture::getSnapmaticResolution()) {
ui->cbAvatar->setEnabled(true);
snapmaticResolution = dataSize;
reworkImage();
}
else {
if (!workImage.isNull() && workImage.width() == workImage.height() && ui->cbAvatar->isChecked()) {
if (QMessageBox::No == QMessageBox::warning(this, tr("Snapmatic Avatar Zone"), tr("Are you sure to use a square image outside of the Avatar Zone?\nWhen you want to use it as Avatar the image will be detached!"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No)) {
ui->cbResolution->setCurrentIndex(0);
ui->cbAvatar->setChecked(true);
insideAvatarZone = true;
return;
}
}
ui->cbAvatar->setChecked(false);
ui->cbAvatar->setDisabled(true);
insideAvatarZone = false;
ui->cbWatermark->setChecked(watermarkPicture);
snapmaticResolution = dataSize;
reworkImage();
}
}
}

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2017-2021 Syping
* Copyright (C) 2017-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
@ -39,12 +39,10 @@ public:
void lockSettings(bool lock);
void enableOverwriteMode();
bool isImportAgreed();
bool isUnlimitedBuffer();
bool areSettingsLocked();
private slots:
void processImage();
void reworkImage();
void cropPicture();
void importNewPicture();
void loadImportSettings();
@ -60,9 +58,6 @@ private slots:
void on_cbStretch_toggled(bool checked);
void on_cbForceAvatarColour_toggled(bool checked);
void on_cbWatermark_toggled(bool checked);
void on_cbBorderless_toggled(bool checked);
void on_cbImportAsIs_toggled(bool checked);
void on_cbResolution_currentIndexChanged(int index);
private:
QString profileName;
@ -75,8 +70,7 @@ private:
QImage origImage;
QImage newImage;
QColor selectedColour;
QMenu optionsMenu;
QSize snapmaticResolution;
QMenu *optionsMenu;
bool insideAvatarZone;
bool watermarkPicture;
bool watermarkAvatar;

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>516</width>
<height>673</height>
<height>512</height>
</rect>
</property>
<property name="minimumSize">
@ -85,32 +85,47 @@
</property>
<layout class="QVBoxLayout" name="vlSettings">
<item>
<layout class="QGridLayout" name="glPicture">
<item row="0" column="1">
<widget class="QCheckBox" name="cbIgnore">
<property name="text">
<string>Ignore Aspect Ratio</string>
</property>
</widget>
</item>
<item row="0" column="0">
<layout class="QHBoxLayout" name="hlCheckboxesTop">
<item>
<widget class="QCheckBox" name="cbAvatar">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Avatar</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="cbWatermark">
<item>
<widget class="QCheckBox" name="cbIgnore">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Watermark</string>
<string>Ignore Aspect Ratio</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="cbBorderless">
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="hlCheckboxesButtom">
<item>
<widget class="QCheckBox" name="cbWatermark">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Crop to Aspect Ratio</string>
<string>Watermark</string>
</property>
</widget>
</item>
@ -126,8 +141,8 @@
</property>
<layout class="QVBoxLayout" name="vlBackground">
<item>
<layout class="QGridLayout" name="glBackground">
<item row="0" column="0">
<layout class="QHBoxLayout" name="hlColour">
<item>
<layout class="QHBoxLayout" name="hlColourManage">
<item>
<widget class="QLabel" name="labColour">
@ -159,7 +174,7 @@
<string>Select background colour</string>
</property>
<property name="text">
<string notr="true">...</string>
<string>...</string>
</property>
</widget>
</item>
@ -180,24 +195,7 @@
</item>
</layout>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="cbStretch">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Ignore Aspect Ratio</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="cbForceAvatarColour">
<property name="text">
<string>Force Colour in Avatar Zone</string>
</property>
</widget>
</item>
<item row="0" column="1">
<item>
<layout class="QHBoxLayout" name="hlBackgroundManage">
<item>
<widget class="QLabel" name="labBackgroundImage">
@ -229,7 +227,7 @@
<string>Select background image</string>
</property>
<property name="text">
<string notr="true">...</string>
<string>...</string>
</property>
</widget>
</item>
@ -239,7 +237,7 @@
<string>Remove background image</string>
</property>
<property name="text">
<string notr="true">X</string>
<string>X</string>
</property>
</widget>
</item>
@ -262,61 +260,25 @@
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gbAdvanced">
<property name="title">
<string>Advanced</string>
</property>
<layout class="QVBoxLayout" name="vlAdvanced">
<item>
<layout class="QGridLayout" name="glAdvanced">
<item row="1" column="0">
<widget class="QCheckBox" name="cbUnlimited">
<property name="toolTip">
<string>Avoid compression and expand buffer instead, improves picture quality, but may break Snapmatic</string>
</property>
<layout class="QHBoxLayout" name="hlBackground">
<item>
<widget class="QCheckBox" name="cbForceAvatarColour">
<property name="text">
<string>Unlimited Buffer</string>
<string>Force Colour in Avatar Zone</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="cbImportAsIs">
<property name="toolTip">
<string>Import as-is, don't change the picture at all, guaranteed to break Snapmatic unless you know what you doing</string>
<item>
<widget class="QCheckBox" name="cbStretch">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Import as-is</string>
<string>Ignore Aspect Ratio</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<layout class="QHBoxLayout" name="hlResolution">
<item>
<widget class="QLabel" name="labResolution">
<property name="text">
<string>Resolution:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbResolution">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Snapmatic resolution</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2017-2021 Syping
* Copyright (C) 2017-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,6 +28,7 @@
#if QT_VERSION >= 0x050200
#include <QFontDatabase>
#include <QDebug>
#endif
#ifdef GTA5SYNC_TELEMETRY
@ -39,30 +40,29 @@ 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);
ui->cmdClose->setFocus();
// 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"));
}
// Set Icon for Save Button
if (QIcon::hasThemeIcon("document-save")) {
if (QIcon::hasThemeIcon("document-save"))
{
ui->cmdSave->setIcon(QIcon::fromTheme("document-save"));
}
else if (QIcon::hasThemeIcon("gtk-save")) {
else if (QIcon::hasThemeIcon("gtk-save"))
{
ui->cmdSave->setIcon(QIcon::fromTheme("gtk-save"));
}
@ -99,7 +99,8 @@ JsonEditorDialog::JsonEditorDialog(SnapmaticPicture *picture, QWidget *parent) :
ui->hlButtons->setContentsMargins(9 * screenRatio, 0, 9 * screenRatio, 0);
ui->vlInterface->setContentsMargins(0, 0, 0, 9 * screenRatio);
#endif
if (screenRatio > 1) {
if (screenRatio > 1)
{
ui->lineJSON->setMinimumHeight(qRound(1 * screenRatio));
ui->lineJSON->setMaximumHeight(qRound(1 * screenRatio));
ui->lineJSON->setLineWidth(qRound(1 * screenRatio));
@ -120,22 +121,28 @@ void JsonEditorDialog::closeEvent(QCloseEvent *ev)
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) {
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) {
if (saveJsonContent()) {
if (button == QMessageBox::Yes)
{
if (saveJsonContent())
{
ev->accept();
}
else {
else
{
ev->ignore();
}
return;
}
else if (button == QMessageBox::No) {
else if (button == QMessageBox::No)
{
ev->accept();
return;
}
else {
else
{
ev->ignore();
return;
}
@ -146,38 +153,47 @@ bool JsonEditorDialog::saveJsonContent()
{
QString jsonPatched = QString(ui->txtJSON->toPlainText()).replace("\t", " ");
QJsonDocument jsonNew = QJsonDocument::fromJson(jsonPatched.toUtf8());
if (!jsonNew.isEmpty()) {
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) {
if (newCode != originalCode)
{
QString currentFilePath = smpic->getPictureFilePath();
QString originalFilePath = smpic->getOriginalPictureFilePath();
QString backupFileName = originalFilePath % ".bak";
if (!QFile::exists(backupFileName)) {
if (!QFile::exists(backupFileName))
{
QFile::copy(currentFilePath, backupFileName);
}
smpic->setJsonStr(newCode, true);
if (!smpic->isJsonOk()) {
if (!smpic->isJsonOk())
{
QString lastStep = smpic->getLastStep(false);
QString readableError;
if (lastStep.contains("JSONINCOMPLETE") && lastStep.contains("JSONERROR")) {
if (lastStep.contains("JSONINCOMPLETE") && lastStep.contains("JSONERROR"))
{
readableError = SnapmaticPicture::tr("JSON is incomplete and malformed");
}
else if (lastStep.contains("JSONINCOMPLETE")) {
else if (lastStep.contains("JSONINCOMPLETE"))
{
readableError = SnapmaticPicture::tr("JSON is incomplete");
}
else if (lastStep.contains("JSONERROR")) {
else if (lastStep.contains("JSONERROR"))
{
readableError = SnapmaticPicture::tr("JSON is malformed");
}
else {
else
{
readableError = tr("JSON Error");
}
QMessageBox::warning(this, SnapmaticEditor::tr("Snapmatic Properties"), SnapmaticEditor::tr("Patching of Snapmatic Properties failed because of %1").arg(readableError));
smpic->setJsonStr(originalCode, true);
return false;
}
if (!smpic->exportPicture(currentFilePath)) {
if (!smpic->exportPicture(currentFilePath))
{
QMessageBox::warning(this, SnapmaticEditor::tr("Snapmatic Properties"), SnapmaticEditor::tr("Patching of Snapmatic Properties failed because of I/O Error"));
smpic->setJsonStr(originalCode, true);
return false;
@ -190,16 +206,13 @@ bool JsonEditorDialog::saveJsonContent()
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"] = "JSONEdited";
jsonObject["EditedSize"] = QString::number(smpic->getContentMaxLength());
#if QT_VERSION >= 0x060000
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
#else
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
#endif
jsonDocument.setObject(jsonObject);
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
}
@ -208,7 +221,8 @@ bool JsonEditorDialog::saveJsonContent()
}
return true;
}
else {
else
{
QMessageBox::warning(this, SnapmaticEditor::tr("Snapmatic Properties"), SnapmaticEditor::tr("Patching of Snapmatic Properties failed because of JSON Error"));
return false;
}
@ -222,5 +236,7 @@ void JsonEditorDialog::on_cmdClose_clicked()
void JsonEditorDialog::on_cmdSave_clicked()
{
if (saveJsonContent())
{
close();
}
}

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2017-2021 Syping
* Copyright (C) 2017-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
@ -20,8 +20,8 @@
#include "ui_MapLocationDialog.h"
#include "IconLoader.h"
#include "AppEnv.h"
#include <QStringBuilder>
#include <QPainter>
#include <QDebug>
#include <QStyle>
MapLocationDialog::MapLocationDialog(double x, double y, QWidget *parent) :
@ -29,11 +29,7 @@ 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);
@ -49,10 +45,12 @@ MapLocationDialog::MapLocationDialog(double x, double y, QWidget *parent) :
ui->vlMapDialog->setSpacing(widgetMargin);
setMinimumSize(500 * screenRatio, 600 * screenRatio);
setMaximumSize(500 * screenRatio, 600 * screenRatio);
setFixedSize(500 * screenRatio, 600 * screenRatio);
setMouseTracking(true);
zoomPercent = 100;
changeMode = false;
propUpdate = false;
drawPointOnMap(xpos_old, ypos_old);
}
MapLocationDialog::~MapLocationDialog()
@ -68,220 +66,6 @@ void MapLocationDialog::drawPointOnMap(double xpos_d, double ypos_d)
repaint();
}
void MapLocationDialog::setCayoPerico(bool isCayoPerico)
{
qreal screenRatio = AppEnv::screenRatio();
p_isCayoPerico = isCayoPerico;
if (isCayoPerico) {
setMinimumSize(500 * screenRatio, 500 * screenRatio);
setMaximumSize(500 * screenRatio, 500 * screenRatio);
ui->hlMapDialog->removeItem(ui->vlMapDialog);
ui->hlMapDialog->insertLayout(0, ui->vlMapDialog);
ui->hlMapDialog->removeItem(ui->vlPosLayout);
ui->hlMapDialog->addLayout(ui->vlPosLayout);
ui->labPos->setAlignment(Qt::AlignRight);
mapImage = QImage(AppEnv::getImagesFolder() % "/mapcayoperico.jpg");
}
else {
mapImage = QImage(AppEnv::getImagesFolder() % "/mappreview.jpg");
}
drawPointOnMap(xpos_old, ypos_old);
}
void MapLocationDialog::updatePosFromEvent(double x, double y)
{
QSize mapPixelSize = size();
double x_per = x / mapPixelSize.width(); // get X %
double y_per = y / mapPixelSize.height(); // get Y %
double x_pos, y_pos;
if (p_isCayoPerico) {
x_pos = x_per * 2340; // 2340 is 100% for X (Cayo Perico)
y_pos = y_per * -2340; // -2340 is 100% for Y (Cayo Perico)
x_pos = x_pos + 3560; // +3560 gets corrected for X (Cayo Perico)
y_pos = y_pos - 3980; // -3980 gets corrected for Y (Cayo Perico)
}
else {
x_pos = x_per * 10000; // 10000 is 100% for X (Los Santos)
y_pos = y_per * -12000; // -12000 is 100% for Y (Los Santos)
x_pos = x_pos - 4000; // -4000 gets corrected for X (Los Santos)
y_pos = y_pos + 8000; // +8000 gets corrected for Y (Los Santos)
}
drawPointOnMap(x_pos, y_pos);
}
void MapLocationDialog::paintEvent(QPaintEvent *ev)
{
QPainter painter(this);
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
// Screen Ratio
qreal screenRatio = AppEnv::screenRatio();
qreal screenRatioPR = AppEnv::screenRatioPR();
// Paint Map
const double zoomLevel = static_cast<double>(zoomPercent) / 100;
const QSize mapImageSize = mapImage.size();
const QPointF mapImageMid(static_cast<double>(mapImageSize.width()) / 2, static_cast<double>(mapImageSize.height()) / 2);
const QSizeF srcImageSize(static_cast<double>(mapImageSize.width()) / zoomLevel , static_cast<double>(mapImageSize.height()) / zoomLevel);
const QPointF mapImageTopLeft(mapImageMid.x() - (srcImageSize.width() / 2), mapImageMid.y() - (srcImageSize.height() / 2));
const QPointF mapImageBottomRight(mapImageMid.x() + (srcImageSize.width() / 2), mapImageMid.y() + (srcImageSize.height() / 2));
painter.drawImage(QRect(QPoint(0, 0), size()), mapImage, QRectF(mapImageTopLeft, mapImageBottomRight));
// Paint Marker
QSize mapPixelSize = size();
int pointMarkerSize = 8 * screenRatio;
int pointMarkerHalfSize = pointMarkerSize / 2;
double xpos_mp, ypos_mp;
if (p_isCayoPerico) {
double xpos_per = xpos_new - 3560; // correct X in reserve
double ypos_per = ypos_new + 3980; // correct y in reserve
xpos_per = xpos_per / 2340; // divide 100% for X
ypos_per = ypos_per / -2340; // divide 100% for Y
xpos_mp = xpos_per * mapPixelSize.width(); // locate window width pos
ypos_mp = ypos_per * mapPixelSize.height(); // locate window height pos
}
else {
double xpos_per = xpos_new + 4000; // correct X in reserve
double ypos_per = ypos_new - 8000; // correct y in reserve
xpos_per = xpos_per / 10000; // divide 100% for X
ypos_per = ypos_per / -12000; // divide 100% for Y
xpos_mp = xpos_per * mapPixelSize.width(); // locate window width pos
ypos_mp = ypos_per * mapPixelSize.height(); // locate window height pos
}
QPointF pointMarkerPos(xpos_mp, ypos_mp);
if (screenRatioPR != 1) {
pointMarkerPos.setX(pointMarkerPos.x() - pointMarkerHalfSize + screenRatioPR);
pointMarkerPos.setY(pointMarkerPos.y() - pointMarkerHalfSize + screenRatioPR);
}
else {
pointMarkerPos.setX(pointMarkerPos.x() - pointMarkerHalfSize);
pointMarkerPos.setY(pointMarkerPos.y() - pointMarkerHalfSize);
}
QPixmap mapMarkerPixmap = IconLoader::loadingPointmakerIcon().pixmap(QSize(pointMarkerSize, pointMarkerSize));
painter.drawPixmap(pointMarkerPos, mapMarkerPixmap);
QDialog::paintEvent(ev);
}
void MapLocationDialog::mouseMoveEvent(QMouseEvent *ev)
{
if (changeMode && ev->buttons() & Qt::LeftButton) {
#if QT_VERSION >= 0x060000
const QPointF localPos = ev->position();
#elif QT_VERSION >= 0x050000
const QPointF localPos = ev->localPos();
#else
const QPointF localPos = ev->posF();
#endif
#ifdef Q_OS_WIN
qreal screenRatioPR = AppEnv::screenRatioPR();
if (screenRatioPR != 1) {
updatePosFromEvent(localPos.x() - screenRatioPR, localPos.y() - screenRatioPR);
}
else {
updatePosFromEvent(localPos.x(), localPos.y());
}
#else
updatePosFromEvent(localPos.x(), localPos.y());
#endif
}
else if (dragStart && ev->buttons() & Qt::LeftButton) {
#if QT_VERSION >= 0x060000
const QPointF dragNewPosition = ev->position();
#elif QT_VERSION >= 0x050000
const QPointF dragNewPosition = ev->localPos();
#else
const QPointF dragNewPosition = ev->posF();
#endif
mapDiffPosition = dragNewPosition - dragPosition + mapDiffPosition;
dragPosition = dragNewPosition;
}
}
void MapLocationDialog::mousePressEvent(QMouseEvent *ev)
{
if (!changeMode && ev->button() == Qt::LeftButton) {
#if QT_VERSION >= 0x060000
dragPosition = ev->position();
#elif QT_VERSION >= 0x050000
dragPosition = ev->localPos();
#else
dragPosition = ev->posF();
#endif
dragStart = true;
}
}
void MapLocationDialog::mouseReleaseEvent(QMouseEvent *ev)
{
if (changeMode && ev->button() == Qt::LeftButton) {
#if QT_VERSION >= 0x060000
const QPointF localPos = ev->position();
#elif QT_VERSION >= 0x050000
const QPointF localPos = ev->localPos();
#else
const QPointF localPos = ev->posF();
#endif
#ifdef Q_OS_WIN
qreal screenRatioPR = AppEnv::screenRatioPR();
if (screenRatioPR != 1) {
updatePosFromEvent(localPos.x() - screenRatioPR, localPos.y() - screenRatioPR);
}
else {
updatePosFromEvent(localPos.x(), localPos.y());
}
#else
updatePosFromEvent(localPos.x(), localPos.y());
#endif
}
else if (dragStart && ev->button() == Qt::LeftButton) {
dragStart = false;
}
}
void MapLocationDialog::wheelEvent(QWheelEvent *ev)
{
#ifdef GTA5SYNC_EXPERIMENTAL
#if QT_VERSION >= 0x050000
const QPoint numPixels = ev->pixelDelta();
const QPoint numDegrees = ev->angleDelta();
#else
QPoint numDegrees;
if (ev->orientation() == Qt::Horizontal) {
numDegrees.setX(ev->delta());
}
else {
numDegrees.setY(ev->delta());
}
#endif
#if QT_VERSION >= 0x050000
if (!numPixels.isNull()) {
if (numPixels.y() < 0 && zoomPercent != 100) {
zoomPercent = zoomPercent - 10;
repaint();
}
else if (numPixels.y() > 0 && zoomPercent != 400) {
zoomPercent = zoomPercent + 10;
repaint();
}
return;
}
#endif
if (!numDegrees.isNull()) {
if (numDegrees.y() < 0 && zoomPercent != 100) {
zoomPercent = zoomPercent - 10;
repaint();
}
else if (numDegrees.y() > 0 && zoomPercent != 400) {
zoomPercent = zoomPercent + 10;
repaint();
}
}
#else
Q_UNUSED(ev)
#endif
}
void MapLocationDialog::on_cmdChange_clicked()
{
qreal screenRatio = AppEnv::screenRatio();
@ -301,14 +85,124 @@ void MapLocationDialog::on_cmdDone_clicked()
{
ui->cmdDone->setVisible(false);
ui->cmdChange->setVisible(true);
if (xpos_new != xpos_old || ypos_new != ypos_old) {
if (xpos_new != xpos_old || ypos_new != ypos_old)
{
ui->cmdApply->setVisible(true);
ui->cmdRevert->setVisible(true);
}
setCursor(Qt::ArrowCursor);
changeMode = false;
}
#if QT_VERSION >= 0x060000
void MapLocationDialog::updatePosFromEvent(double x, double y)
{
QSize mapPixelSize = size();
double xpos_ad = x;
double ypos_ad = mapPixelSize.height() - y;
double xrat = 10000 / (double)mapPixelSize.width();
double yrat = 12000 / (double)mapPixelSize.height();
double xpos_rv = xrat * xpos_ad;
double ypos_rv = yrat * ypos_ad;
double xpos_fp = xpos_rv - 4000;
double ypos_fp = ypos_rv - 4000;
drawPointOnMap(xpos_fp, ypos_fp);
}
#else
void MapLocationDialog::updatePosFromEvent(int x, int y)
{
QSize mapPixelSize = size();
int xpos_ad = x;
int ypos_ad = mapPixelSize.height() - y;
double xrat = 10000 / (double)mapPixelSize.width();
double yrat = 12000 / (double)mapPixelSize.height();
double xpos_rv = xrat * xpos_ad;
double ypos_rv = yrat * ypos_ad;
double xpos_fp = xpos_rv - 4000;
double ypos_fp = ypos_rv - 4000;
drawPointOnMap(xpos_fp, ypos_fp);
}
#endif
void MapLocationDialog::paintEvent(QPaintEvent *ev)
{
QPainter painter(this);
qreal screenRatio = AppEnv::screenRatio();
qreal screenRatioPR = AppEnv::screenRatioPR();
// Paint Map
QSize mapPixelSize = QSize(width() * screenRatioPR, height() * screenRatioPR);
painter.drawPixmap(0, 0, width(), height(), QPixmap(":/img/mappreview.jpg").scaled(mapPixelSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
// Paint Marker
int pointMarkerSize = 8 * screenRatio;
int pointMarkerHalfSize = pointMarkerSize / 2;
long xpos_ms = qRound(xpos_new);
long ypos_ms = qRound(ypos_new);
double xpos_ma = xpos_ms + 4000;
double ypos_ma = ypos_ms + 4000;
double xrat = (double)width() / 10000;
double yrat = (double)height() / 12000;
long xpos_mp = qRound(xpos_ma * xrat);
long ypos_mp = qRound(ypos_ma * yrat);
long xpos_pr;
long ypos_pr;
if (screenRatioPR != 1) {
#ifdef Q_OS_WIN
xpos_pr = xpos_mp - pointMarkerHalfSize;
ypos_pr = ypos_mp + pointMarkerHalfSize;
#else
xpos_pr = xpos_mp - pointMarkerHalfSize + screenRatioPR;
ypos_pr = ypos_mp + pointMarkerHalfSize - screenRatioPR;
#endif
}
else {
xpos_pr = xpos_mp - pointMarkerHalfSize;
ypos_pr = ypos_mp + pointMarkerHalfSize;
}
QPixmap mapMarkerPixmap = IconLoader::loadingPointmakerIcon().pixmap(QSize(pointMarkerSize, pointMarkerSize));
painter.drawPixmap(xpos_pr, height() - ypos_pr, pointMarkerSize, pointMarkerSize, mapMarkerPixmap);
QDialog::paintEvent(ev);
}
void MapLocationDialog::mouseMoveEvent(QMouseEvent *ev)
{
if (!changeMode) { ev->ignore(); }
else if (ev->buttons() & Qt::LeftButton)
{
#if QT_VERSION >= 0x060000
updatePosFromEvent(ev->position().x(), ev->position().y());
#else
updatePosFromEvent(ev->x(), ev->y());
#endif
ev->accept();
}
else
{
ev->ignore();
}
}
void MapLocationDialog::mouseReleaseEvent(QMouseEvent *ev)
{
if (!changeMode) { ev->ignore(); }
else if (ev->button() == Qt::LeftButton)
{
#if QT_VERSION >= 0x060000
updatePosFromEvent(ev->position().x(), ev->position().y());
#else
updatePosFromEvent(ev->x(), ev->y());
#endif
ev->accept();
}
else
{
ev->ignore();
}
}
void MapLocationDialog::on_cmdApply_clicked()
{
propUpdate = true;

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2017-2021 Syping
* Copyright (C) 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
@ -33,7 +33,6 @@ class MapLocationDialog : public QDialog
public:
explicit MapLocationDialog(double x, double y, QWidget *parent = 0);
void drawPointOnMap(double x, double y);
void setCayoPerico(bool isCayoPerico);
bool propUpdated();
double getXpos();
double getYpos();
@ -42,31 +41,27 @@ public:
protected:
void paintEvent(QPaintEvent *ev);
void mouseMoveEvent(QMouseEvent *ev);
void mousePressEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
void wheelEvent(QWheelEvent *ev);
private slots:
void on_cmdApply_clicked();
void on_cmdDone_clicked();
void on_cmdClose_clicked();
void on_cmdApply_clicked();
void on_cmdChange_clicked();
void on_cmdRevert_clicked();
#if QT_VERSION >= 0x060000
void updatePosFromEvent(double x, double y);
#else
void updatePosFromEvent(int x, int y);
#endif
void on_cmdClose_clicked();
private:
int zoomPercent;
double xpos_old;
double ypos_old;
double xpos_new;
double ypos_new;
bool dragStart;
bool propUpdate;
bool changeMode;
bool p_isCayoPerico;
QImage mapImage;
QPointF dragPosition;
QPointF mapDiffPosition;
Ui::MapLocationDialog *ui;
};

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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,7 +21,6 @@
#include "TranslationClass.h"
#include "StandardPaths.h"
#include "UserInterface.h"
#include "wrapper.h"
#include "AppEnv.h"
#include "config.h"
#include <QStringBuilder>
@ -30,7 +29,6 @@
#include <QApplication>
#include <QJsonObject>
#include <QFileDialog>
#include <QFontDialog>
#include <QMessageBox>
#include <QStringList>
#include <QClipboard>
@ -56,11 +54,7 @@ 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);
@ -80,7 +74,7 @@ OptionsDialog::OptionsDialog(ProfileDatabase *profileDB, QWidget *parent) :
int desktopSizeHeight = desktopResolution.height();
#endif
aspectRatio = Qt::KeepAspectRatio;
defExportSize = SnapmaticPicture::getSnapmaticResolution();
defExportSize = QSize(960, 536);
cusExportSize = defExportSize;
defaultQuality = 100;
customQuality = 100;
@ -93,26 +87,25 @@ OptionsDialog::OptionsDialog(ProfileDatabase *profileDB, QWidget *parent) :
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")) {
if (QIcon::hasThemeIcon("dialog-ok"))
{
ui->cmdOK->setIcon(QIcon::fromTheme("dialog-ok"));
}
else if (QIcon::hasThemeIcon("gtk-ok")) {
else if (QIcon::hasThemeIcon("gtk-ok"))
{
ui->cmdOK->setIcon(QIcon::fromTheme("gtk-ok"));
}
// Set Icon for Cancel Button
if (QIcon::hasThemeIcon("dialog-cancel")) {
if (QIcon::hasThemeIcon("dialog-cancel"))
{
ui->cmdCancel->setIcon(QIcon::fromTheme("dialog-cancel"));
}
else if (QIcon::hasThemeIcon("gtk-cancel")) {
else if (QIcon::hasThemeIcon("gtk-cancel"))
{
ui->cmdCancel->setIcon(QIcon::fromTheme("gtk-cancel"));
}
// Set Icon for Copy Button
if (QIcon::hasThemeIcon("edit-copy")) {
ui->cmdCopyStatsID->setIcon(QIcon::fromTheme("edit-copy"));
}
setupTreeWidget();
setupLanguageBox();
setupRadioButtons();
@ -130,8 +123,6 @@ OptionsDialog::OptionsDialog(ProfileDatabase *profileDB, QWidget *parent) :
resize(435 * screenRatio, 405 * screenRatio);
#endif
ui->rbModern->setText(ui->rbModern->text().arg(GTA5SYNC_APPSTR));
ui->rbClassic->setText(ui->rbClassic->text().arg(GTA5SYNC_APPSTR));
setWindowTitle(windowTitle().arg(GTA5SYNC_APPSTR));
}
@ -147,11 +138,15 @@ void OptionsDialog::setupTreeWidget()
{
const QStringList players = profileDB->getPlayers();
if (players.length() != 0) {
for (auto it = players.constBegin(); it != players.constEnd(); it++) {
QStringList::const_iterator it = players.constBegin();
QStringList::const_iterator end = players.constEnd();
while (it != end)
{
bool ok;
int playerID = it->toInt(&ok);
if (ok) {
const QString playerName = profileDB->getPlayerName(playerID);
if (ok)
{
QString playerName = profileDB->getPlayerName(playerID);
QStringList playerTreeViewList;
playerTreeViewList += *it;
@ -161,6 +156,7 @@ void OptionsDialog::setupTreeWidget()
ui->twPlayers->addTopLevelItem(playerItem);
playerItems += playerItem;
}
it++;
}
ui->twPlayers->sortItems(1, Qt::AscendingOrder);
}
@ -176,18 +172,20 @@ void OptionsDialog::setupLanguageBox()
currentAreaLanguage = settings->value("AreaLanguage", "Auto").toString();
settings->endGroup();
const QString cbSysStr = tr("%1 (Language priority)", "First language a person can talk with a different person/application. \"Native\" or \"Not Native\".").arg(tr("System",
QString cbSysStr = tr("%1 (Language priority)", "First language a person can talk with a different person/application. \"Native\" or \"Not Native\".").arg(tr("System",
"System in context of System default"));
#ifdef Q_OS_WIN
QString cbAutoStr;
if (AppEnv::getGameLanguage(AppEnv::getGameVersion()) != 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 {
else
{
cbAutoStr = tr("%1 (Closest to Interface)", "Next closest language compared to the Interface").arg(tr("Auto", "Automatic language choice."));
}
#else
const QString cbAutoStr = tr("%1 (Closest to Interface)", "Next closest language compared to the Interface").arg(tr("Auto", "Automatic language choice."));
QString cbAutoStr = tr("%1 (Closest to Interface)", "Next closest language compared to the Interface").arg(tr("Auto", "Automatic language choice."));
#endif
ui->cbLanguage->addItem(cbSysStr, "System");
ui->cbAreaLanguage->addItem(cbAutoStr, "Auto");
@ -201,18 +199,15 @@ void OptionsDialog::setupLanguageBox()
availableLanguages.removeDuplicates();
availableLanguages.sort();
for (const QString &lang : qAsConst(availableLanguages)) {
for (QString lang : availableLanguages)
{
QLocale langLocale(lang);
const QString cbLangStr = langLocale.nativeLanguageName() % " (" % langLocale.nativeCountryName() % ") [" % lang % "]";
const QString langIconPath = AppEnv::getImagesFolder() % "/flag-" % TranslationClass::getCountryCode(langLocale) % ".png";
QString cbLangStr = langLocale.nativeLanguageName() % " (" % langLocale.nativeCountryName() % ") [" % lang % "]";
QString langIconStr = "flag-" % TranslationClass::getCountryCode(langLocale);
if (QFile::exists(langIconPath)) {
ui->cbLanguage->addItem(QIcon(langIconPath), cbLangStr, lang);
}
else {
ui->cbLanguage->addItem(cbLangStr, lang);
}
if (currentLanguage == lang) {
ui->cbLanguage->addItem(QIcon::fromTheme(langIconStr), cbLangStr, lang);
if (currentLanguage == lang)
{
#if QT_VERSION >= 0x050000
ui->cbLanguage->setCurrentText(cbLangStr);
#else
@ -223,8 +218,7 @@ void OptionsDialog::setupLanguageBox()
}
QString aCurrentLanguage = QString("en_GB");
if (Translator->isLanguageLoaded())
aCurrentLanguage = Translator->getCurrentLanguage();
if (Translator->isLanguageLoaded()) { aCurrentLanguage = Translator->getCurrentLanguage(); }
QLocale currentLocale = QLocale(aCurrentLanguage);
ui->labCurrentLanguage->setText(tr("Current: %1").arg(currentLocale.nativeLanguageName() % " (" % currentLocale.nativeCountryName() % ") [" % aCurrentLanguage % "]"));
@ -233,21 +227,27 @@ void OptionsDialog::setupLanguageBox()
availableLanguages.removeDuplicates();
availableLanguages.sort();
for (const QString &lang : qAsConst(availableLanguages)) {
for (QString lang : availableLanguages)
{
// correcting Language Location if possible
QString aLang = lang;
if (QFile::exists(":/global/global." % lang % ".loc")) {
if (QFile::exists(":/global/global." % lang % ".loc"))
{
QFile locFile(":/global/global." % lang % ".loc");
if (locFile.open(QFile::ReadOnly)) {
if (locFile.open(QFile::ReadOnly))
{
aLang = QString::fromUtf8(locFile.readLine()).trimmed();
locFile.close();
}
}
QLocale langLocale(aLang);
const QString cbLangStr = langLocale.nativeLanguageName() % " (" % langLocale.nativeCountryName() % ") [" % aLang % "]";
ui->cbAreaLanguage->addItem(cbLangStr, lang);
if (currentAreaLanguage == lang) {
QString cbLangStr = langLocale.nativeLanguageName() % " (" % langLocale.nativeCountryName() % ") [" % aLang % "]";
QString langIconStr = "flag-" % TranslationClass::getCountryCode(langLocale);
ui->cbAreaLanguage->addItem(QIcon::fromTheme(langIconStr), cbLangStr, lang);
if (currentAreaLanguage == lang)
{
#if QT_VERSION >= 0x050000
ui->cbAreaLanguage->setCurrentText(cbLangStr);
#else
@ -258,10 +258,12 @@ void OptionsDialog::setupLanguageBox()
}
QString aCurrentAreaLanguage = Translator->getCurrentAreaLanguage();
if (QFile::exists(":/global/global." % aCurrentAreaLanguage % ".loc")) {
if (QFile::exists(":/global/global." % aCurrentAreaLanguage % ".loc"))
{
qDebug() << "locFile found";
QFile locFile(":/global/global." % aCurrentAreaLanguage % ".loc");
if (locFile.open(QFile::ReadOnly)) {
if (locFile.open(QFile::ReadOnly))
{
aCurrentAreaLanguage = QString::fromUtf8(locFile.readLine()).trimmed();
locFile.close();
}
@ -277,26 +279,18 @@ void OptionsDialog::setupRadioButtons()
contentMode = settings->value("ContentMode", 0).toInt(&contentModeOk);
settings->endGroup();
if (contentModeOk) {
switch (contentMode) {
if (contentModeOk)
{
switch (contentMode)
{
case 0:
case 20:
ui->rbModern->setChecked(true);
ui->cbDoubleclick->setChecked(false);
ui->rbOpenWithSC->setChecked(true);
break;
case 1:
ui->rbOpenWithDC->setChecked(true);
break;
case 2:
case 21:
ui->rbModern->setChecked(true);
ui->cbDoubleclick->setChecked(true);
break;
case 10:
ui->rbClassic->setChecked(true);
ui->cbDoubleclick->setChecked(false);
break;
case 11:
ui->rbClassic->setChecked(true);
ui->cbDoubleclick->setChecked(true);
ui->rbSelectWithSC->setChecked(true);
break;
}
}
@ -305,40 +299,55 @@ void OptionsDialog::setupRadioButtons()
void OptionsDialog::setupInterfaceSettings()
{
settings->beginGroup("Startup");
const QString currentStyle = QApplication::style()->objectName();
const QString appStyle = settings->value("AppStyle", currentStyle).toString();
bool alwaysUseMessageFont = settings->value("AlwaysUseMessageFont", false).toBool();
ui->cbAlwaysUseMessageFont->setChecked(alwaysUseMessageFont);
#ifdef Q_OS_WIN
if (QSysInfo::windowsVersion() >= 0x0080)
{
ui->gbFont->setVisible(false);
ui->cbAlwaysUseMessageFont->setVisible(false);
}
#else
ui->gbFont->setVisible(false);
ui->cbAlwaysUseMessageFont->setVisible(false);
#endif
QString currentStyle = QApplication::style()->objectName();
QString appStyle = settings->value("AppStyle", currentStyle).toString();
bool customStyle = settings->value("CustomStyle", false).toBool();
const QStringList availableStyles = QStyleFactory::keys();
ui->cbStyleList->addItems(availableStyles);
if (availableStyles.contains(appStyle, Qt::CaseInsensitive)) {
if (availableStyles.contains(appStyle, Qt::CaseInsensitive))
{
// use 'for' for select to be sure it's case insensitive
int currentIndex = 0;
for (const QString &currentStyleFF : availableStyles) {
if (currentStyleFF.toLower() == appStyle.toLower()) {
for (QString currentStyleFF : availableStyles)
{
if (currentStyleFF.toLower() == appStyle.toLower())
{
ui->cbStyleList->setCurrentIndex(currentIndex);
}
currentIndex++;
}
}
else {
if (availableStyles.contains(currentStyle, Qt::CaseInsensitive)) {
else
{
if (availableStyles.contains(currentStyle, Qt::CaseInsensitive))
{
int currentIndex = 0;
for (const QString &currentStyleFF : availableStyles) {
if (currentStyleFF.toLower() == currentStyle.toLower()) {
for (QString currentStyleFF : availableStyles)
{
if (currentStyleFF.toLower() == currentStyle.toLower())
{
ui->cbStyleList->setCurrentIndex(currentIndex);
}
currentIndex++;
}
}
}
ui->cbDefaultStyle->setChecked(!customStyle);
ui->cbStyleList->setEnabled(customStyle);
const QFont currentFont = QApplication::font();
const QFont appFont = qvariant_cast<QFont>(settings->value("AppFont", currentFont));
bool customFont = settings->value("CustomFont", false).toBool();
ui->cbDefaultFont->setChecked(!customFont);
ui->cbFont->setEnabled(customFont);
ui->cbFont->setCurrentFont(appFont);
if (customStyle)
{
ui->cbDefaultStyle->setChecked(false);
}
settings->endGroup();
}
@ -368,15 +377,18 @@ void OptionsDialog::applySettings()
settings->endGroup();
settings->beginGroup("Profile");
int newContentMode = 20;
if (ui->rbModern->isChecked()) {
newContentMode = 20;
int newContentMode = 0;
if (ui->rbOpenWithSC->isChecked())
{
newContentMode = 0;
}
else if (ui->rbClassic->isChecked()) {
newContentMode = 10;
else if (ui->rbOpenWithDC->isChecked())
{
newContentMode = 1;
}
if (ui->cbDoubleclick->isChecked()) {
newContentMode++;
else if (ui->rbSelectWithSC->isChecked())
{
newContentMode = 2;
}
settings->setValue("ContentMode", newContentMode);
#if QT_VERSION >= 0x050000
@ -387,15 +399,18 @@ void OptionsDialog::applySettings()
settings->endGroup();
settings->beginGroup("Pictures");
if (ui->cbPicCustomQuality->isChecked()) {
if (ui->cbPicCustomQuality->isChecked())
{
settings->setValue("CustomQuality", ui->hsPicQuality->value());
}
settings->setValue("CustomQualityEnabled", ui->cbPicCustomQuality->isChecked());
QString sizeMode = "Default";
if (ui->rbPicDesktopRes->isChecked()) {
if (ui->rbPicDesktopRes->isChecked())
{
sizeMode = "Desktop";
}
else if (ui->rbPicCustomRes->isChecked()) {
else if (ui->rbPicCustomRes->isChecked())
{
sizeMode = "Custom";
settings->setValue("CustomSize", QSize(ui->sbPicExportWidth->value(), ui->sbPicExportHeight->value()));
}
@ -411,25 +426,18 @@ void OptionsDialog::applySettings()
bool defaultStyle = ui->cbDefaultStyle->isChecked();
settings->beginGroup("Startup");
if (!defaultStyle) {
if (!defaultStyle)
{
QString newStyle = ui->cbStyleList->currentText();
settings->setValue("CustomStyle", true);
settings->setValue("AppStyle", newStyle);
QApplication::setStyle(QStyleFactory::create(newStyle));
}
else {
else
{
settings->setValue("CustomStyle", false);
}
bool defaultFont = ui->cbDefaultFont->isChecked();
if (!defaultFont) {
QFont newFont = ui->cbFont->currentFont();
settings->setValue("CustomFont", true);
settings->setValue("AppFont", newFont);
QApplication::setFont(newFont);
}
else {
settings->setValue("CustomFont", false);
}
settings->setValue("AlwaysUseMessageFont", ui->cbAlwaysUseMessageFont->isChecked());
settings->endGroup();
#ifdef GTA5SYNC_TELEMETRY
@ -440,15 +448,12 @@ void OptionsDialog::applySettings()
settings->endGroup();
Telemetry->refresh();
Telemetry->work();
if (ui->cbUsageData->isChecked() && Telemetry->canPush()) {
if (ui->cbUsageData->isChecked() && Telemetry->canPush())
{
QJsonDocument jsonDocument;
QJsonObject jsonObject;
jsonObject["Type"] = "SettingsUpdated";
#if QT_VERSION >= 0x060000
jsonObject["UpdateTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
#else
jsonObject["UpdateTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
#endif
jsonDocument.setObject(jsonObject);
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
}
@ -461,19 +466,22 @@ void OptionsDialog::applySettings()
bool languageChanged = ui->cbLanguage->itemData(ui->cbLanguage->currentIndex()).toString() != currentLanguage;
bool languageAreaChanged = ui->cbAreaLanguage->itemData(ui->cbLanguage->currentIndex()).toString() != currentAreaLanguage;
#endif
if (languageChanged) {
if (languageChanged)
{
Translator->unloadTranslation(qApp);
Translator->initUserLanguage();
Translator->loadTranslation(qApp);
}
else if (languageAreaChanged) {
else if (languageAreaChanged)
{
Translator->initUserLanguage();
}
settings->sync();
emit settingsApplied(newContentMode, languageChanged);
if ((forceCustomFolder && ui->txtFolder->text() != currentCFolder) || (forceCustomFolder != currentFFolder && forceCustomFolder)) {
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));
}
}
@ -490,9 +498,11 @@ void OptionsDialog::setupDefaultProfile()
void OptionsDialog::commitProfiles(const QStringList &profiles)
{
for (const QString &profile : profiles) {
for (QString profile : profiles)
{
ui->cbProfiles->addItem(tr("Profile: %1").arg(profile), profile);
if (defaultProfile == profile) {
if (defaultProfile == profile)
{
#if QT_VERSION >= 0x050000
ui->cbProfiles->setCurrentText(tr("Profile: %1").arg(profile));
#else
@ -530,7 +540,8 @@ void OptionsDialog::setupPictureSettings()
// Quality Settings
customQuality = settings->value("CustomQuality", defaultQuality).toInt();
if (customQuality < 1 || customQuality > 100) {
if (customQuality < 1 || customQuality > 100)
{
customQuality = 100;
}
ui->hsPicQuality->setValue(customQuality);
@ -538,34 +549,42 @@ void OptionsDialog::setupPictureSettings()
// Size Settings
cusExportSize = settings->value("CustomSize", defExportSize).toSize();
if (cusExportSize.width() > 3840) {
if (cusExportSize.width() > 3840)
{
cusExportSize.setWidth(3840);
}
else if (cusExportSize.height() > 2160) {
else if (cusExportSize.height() > 2160)
{
cusExportSize.setHeight(2160);
}
if (cusExportSize.width() < 1) {
if (cusExportSize.width() < 1)
{
cusExportSize.setWidth(1);
}
else if (cusExportSize.height() < 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") {
if (sizeMode == "Desktop")
{
ui->rbPicDesktopRes->setChecked(true);
}
else if (sizeMode == "Custom") {
else if (sizeMode == "Custom")
{
ui->rbPicCustomRes->setChecked(true);
}
else {
else
{
ui->rbPicDefaultRes->setChecked(true);
}
aspectRatio = (Qt::AspectRatioMode)settings->value("AspectRatio", Qt::KeepAspectRatio).toInt();
if (aspectRatio == Qt::IgnoreAspectRatio) {
if (aspectRatio == Qt::IgnoreAspectRatio)
{
ui->cbIgnoreAspectRatio->setChecked(true);
}
@ -584,14 +603,17 @@ void OptionsDialog::setupStatisticsSettings()
ui->cbUsageData->setChecked(settings->value("PushUsageData", false).toBool());
settings->endGroup();
if (Telemetry->isStateForced()) {
if (Telemetry->isStateForced())
{
ui->cbParticipateStats->setEnabled(false);
}
if (Telemetry->isRegistered()) {
if (Telemetry->isRegistered())
{
ui->labParticipationID->setText(tr("Participation ID: %1").arg(Telemetry->getRegisteredID()));
}
else {
else
{
ui->labParticipationID->setText(tr("Participation ID: %1").arg(tr("Not registered")));
ui->cmdCopyStatsID->setVisible(false);
}
@ -605,49 +627,62 @@ void OptionsDialog::setupWindowsGameSettings()
#ifdef GTA5SYNC_GAME
GameVersion gameVersion = AppEnv::getGameVersion();
#ifdef Q_OS_WIN
if (gameVersion != GameVersion::NoVersion) {
if (gameVersion == GameVersion::SocialClubVersion) {
if (gameVersion != GameVersion::NoVersion)
{
if (gameVersion == GameVersion::SocialClubVersion)
{
ui->gbSteam->setDisabled(true);
ui->labSocialClubFound->setText(tr("Found: %1").arg(QString("<span style=\"color: green\">%1</span>").arg(tr("Yes"))));
ui->labSteamFound->setText(tr("Found: %1").arg(QString("<span style=\"color: red\">%1</span>").arg(tr("No"))));
if (AppEnv::getGameLanguage(GameVersion::SocialClubVersion) != GameLanguage::Undefined) {
if (AppEnv::getGameLanguage(GameVersion::SocialClubVersion) != GameLanguage::Undefined)
{
ui->labSocialClubLanguage->setText(tr("Language: %1").arg(QLocale(AppEnv::gameLanguageToString(AppEnv::getGameLanguage(GameVersion::SocialClubVersion))).nativeLanguageName()));
}
else {
else
{
ui->labSocialClubLanguage->setText(tr("Language: %1").arg(tr("OS defined")));
}
ui->labSteamLanguage->setVisible(false);
}
else if (gameVersion == GameVersion::SteamVersion) {
else if (gameVersion == GameVersion::SteamVersion)
{
ui->gbSocialClub->setDisabled(true);
ui->labSocialClubFound->setText(tr("Found: %1").arg(QString("<span style=\"color: red\">%1</span>").arg(tr("No"))));
ui->labSteamFound->setText(tr("Found: %1").arg(QString("<span style=\"color: green\">%1</span>").arg(tr("Yes"))));
ui->labSocialClubLanguage->setVisible(false);
if (AppEnv::getGameLanguage(GameVersion::SteamVersion) != GameLanguage::Undefined) {
if (AppEnv::getGameLanguage(GameVersion::SteamVersion) != GameLanguage::Undefined)
{
ui->labSteamLanguage->setText(tr("Language: %1").arg(QLocale(AppEnv::gameLanguageToString(AppEnv::getGameLanguage(GameVersion::SteamVersion))).nativeLanguageName()));
}
else {
else
{
ui->labSteamLanguage->setText(tr("Language: %1").arg(tr("Steam defined")));
}
}
else {
else
{
ui->labSocialClubFound->setText(tr("Found: %1").arg(QString("<span style=\"color: green\">%1</span>").arg(tr("Yes"))));
ui->labSteamFound->setText(tr("Found: %1").arg(QString("<span style=\"color: green\">%1</span>").arg(tr("Yes"))));
if (AppEnv::getGameLanguage(GameVersion::SocialClubVersion) != GameLanguage::Undefined) {
if (AppEnv::getGameLanguage(GameVersion::SocialClubVersion) != GameLanguage::Undefined)
{
ui->labSocialClubLanguage->setText(tr("Language: %1").arg(QLocale(AppEnv::gameLanguageToString(AppEnv::getGameLanguage(GameVersion::SocialClubVersion))).nativeLanguageName()));
}
else {
else
{
ui->labSocialClubLanguage->setText(tr("Language: %1").arg(tr("OS defined")));
}
if (AppEnv::getGameLanguage(GameVersion::SteamVersion) != GameLanguage::Undefined) {
if (AppEnv::getGameLanguage(GameVersion::SteamVersion) != GameLanguage::Undefined)
{
ui->labSteamLanguage->setText(tr("Language: %1").arg(QLocale(AppEnv::gameLanguageToString(AppEnv::getGameLanguage(GameVersion::SteamVersion))).nativeLanguageName()));
}
else {
else
{
ui->labSteamLanguage->setText(tr("Language: %1").arg(tr("Steam defined")));
}
}
}
else {
else
{
ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabGame));
}
#else
@ -660,10 +695,12 @@ void OptionsDialog::setupWindowsGameSettings()
void OptionsDialog::on_cbIgnoreAspectRatio_toggled(bool checked)
{
if (checked) {
if (checked)
{
aspectRatio = Qt::IgnoreAspectRatio;
}
else {
else
{
aspectRatio = Qt::KeepAspectRatio;
}
}
@ -675,7 +712,8 @@ void OptionsDialog::setupCustomGTAFolder()
settings->beginGroup("dir");
currentCFolder = settings->value("dir", "").toString();
currentFFolder = settings->value("force", false).toBool();
if (currentCFolder == "" && ok) {
if (currentCFolder == "" && ok)
{
currentCFolder = defaultGameFolder;
}
ui->txtFolder->setText(currentCFolder);
@ -703,8 +741,9 @@ void OptionsDialog::setupSnapmaticPictureViewer()
void OptionsDialog::on_cmdExploreFolder_clicked()
{
const QString GTAV_Folder = QFileDialog::getExistingDirectory(this, UserInterface::tr("Select GTA V Folder..."), StandardPaths::documentsLocation(), QFileDialog::ShowDirsOnly);
if (QDir(GTAV_Folder).exists()) {
QString GTAV_Folder = QFileDialog::getExistingDirectory(this, UserInterface::tr("Select GTA V Folder..."), StandardPaths::documentsLocation(), QFileDialog::ShowDirsOnly);
if (QFileInfo(GTAV_Folder).exists())
{
ui->txtFolder->setText(GTAV_Folder);
}
}
@ -712,14 +751,6 @@ void OptionsDialog::on_cmdExploreFolder_clicked()
void OptionsDialog::on_cbDefaultStyle_toggled(bool checked)
{
ui->cbStyleList->setDisabled(checked);
ui->labStyle->setDisabled(checked);
}
void OptionsDialog::on_cbDefaultFont_toggled(bool checked)
{
ui->cbFont->setDisabled(checked);
ui->cmdFont->setDisabled(checked);
ui->labFont->setDisabled(checked);
}
void OptionsDialog::on_cmdCopyStatsID_clicked()
@ -728,18 +759,3 @@ void OptionsDialog::on_cmdCopyStatsID_clicked()
QApplication::clipboard()->setText(Telemetry->getRegisteredID());
#endif
}
void OptionsDialog::on_cbFont_currentFontChanged(const QFont &font)
{
ui->cbFont->setFont(font);
}
void OptionsDialog::on_cmdFont_clicked()
{
bool ok;
const QFont font = QFontDialog::getFont(&ok, ui->cbFont->currentFont(), this);
if (ok) {
ui->cbFont->setCurrentFont(font);
ui->cbFont->setFont(font);
}
}

View File

@ -47,10 +47,7 @@ private slots:
void on_cbIgnoreAspectRatio_toggled(bool checked);
void on_cmdExploreFolder_clicked();
void on_cbDefaultStyle_toggled(bool checked);
void on_cbDefaultFont_toggled(bool checked);
void on_cmdCopyStatsID_clicked();
void on_cbFont_currentFontChanged(const QFont &font);
void on_cmdFont_clicked();
signals:
void settingsApplied(int contentMode, bool languageChanged);

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>435</width>
<height>524</height>
<height>474</height>
</rect>
</property>
<property name="windowTitle">
@ -34,9 +34,9 @@
</property>
<layout class="QVBoxLayout" name="vlProfileContentMode">
<item>
<widget class="QRadioButton" name="rbModern">
<widget class="QRadioButton" name="rbOpenWithSC">
<property name="text">
<string notr="true">%1 1.9+</string>
<string>Open with Singleclick</string>
</property>
<property name="checked">
<bool>true</bool>
@ -44,16 +44,16 @@
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbClassic">
<widget class="QRadioButton" name="rbOpenWithDC">
<property name="text">
<string notr="true">%1 1.0-1.8</string>
<string>Open with Doubleclick</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbDoubleclick">
<widget class="QRadioButton" name="rbSelectWithSC">
<property name="text">
<string>Open with Doubleclick</string>
<string>Select with Singleclick</string>
</property>
</widget>
</item>
@ -660,9 +660,6 @@
<layout class="QHBoxLayout" name="hlStyle">
<item>
<widget class="QLabel" name="labStyle">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Style:</string>
</property>
@ -693,52 +690,12 @@
</property>
<layout class="QVBoxLayout" name="vlFont">
<item>
<widget class="QCheckBox" name="cbDefaultFont">
<widget class="QCheckBox" name="cbAlwaysUseMessageFont">
<property name="text">
<string>Use Default Font (Restart)</string>
</property>
<property name="checked">
<bool>true</bool>
<string>Always use Message Font (Windows 2003 and earlier)</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="hlFont">
<item>
<widget class="QLabel" name="labFont">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Font:</string>
</property>
</widget>
</item>
<item>
<widget class="QFontComboBox" name="cbFont">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="cmdFont">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string notr="true">...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -38,15 +38,12 @@
#endif
#ifdef Q_OS_WIN
#if QT_VERSION >= 0x050000
#include "dwmapi.h"
#if QT_VERSION >= 0x050200
#include <QtWinExtras/QtWin>
#include <QtWinExtras/QWinEvent>
#endif
#endif
#ifdef Q_OS_MAC
#include <QStyleFactory>
#endif
#include <QStringBuilder>
#include <QJsonDocument>
#include <QApplication>
@ -66,7 +63,6 @@
#include <QPicture>
#include <QBitmap>
#include <QBuffer>
#include <QTimer>
#include <QImage>
#include <QDebug>
#include <QList>
@ -127,20 +123,10 @@ 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
// for stupid Window Manager (GNOME 3 should feel triggered)
setWindowFlags(windowFlags()^Qt::Dialog^Qt::Window);
#endif
#endif
// Setup User Interface
@ -157,16 +143,18 @@ void PictureDialog::setupPictureDialog()
crewStr = "";
// Get Snapmatic Resolution
const QSize snapmaticResolution = SnapmaticPicture::getSnapmaticResolution();
QSize snapmaticResolution = SnapmaticPicture::getSnapmaticResolution();
// Avatar area
qreal screenRatio = AppEnv::screenRatio();
qreal screenRatioPR = AppEnv::screenRatioPR();
if (screenRatio != 1 || screenRatioPR != 1) {
avatarAreaPicture = QImage(AppEnv::getImagesFolder() % "/avatararea.png").scaledToHeight(snapmaticResolution.height() * screenRatio * screenRatioPR, Qt::FastTransformation);
if (screenRatio != 1 || screenRatioPR != 1)
{
avatarAreaPicture = QImage(":/img/avatararea.png").scaledToHeight(snapmaticResolution.height() * screenRatio * screenRatioPR, Qt::FastTransformation);
}
else {
avatarAreaPicture = QImage(AppEnv::getImagesFolder() % "/avatararea.png");
else
{
avatarAreaPicture = QImage(":/img/avatararea.png");
}
avatarLocX = 145;
avatarLocY = 66;
@ -197,15 +185,21 @@ void PictureDialog::setupPictureDialog()
// Global map
globalMap = GlobalString::getGlobalMap();
// Event connects
connect(ui->labJSON, SIGNAL(resized(QSize)), this, SLOT(adaptNewDialogSize(QSize)));
// 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);
installEventFilter(ui->labPicture);
// DPI calculation
ui->hlButtons->setSpacing(6 * screenRatio);
@ -214,13 +208,38 @@ void PictureDialog::setupPictureDialog()
ui->jsonLayout->setContentsMargins(4 * screenRatio, 10 * screenRatio, 4 * screenRatio, 4 * screenRatio);
// Pre-adapt window for DPI
const QSize windowSize(snapmaticResolution.width() * screenRatio, snapmaticResolution.height() * screenRatio);
setMinimumSize(windowSize);
setMaximumSize(windowSize);
setFixedWidth(snapmaticResolution.width() * screenRatio);
setFixedHeight(snapmaticResolution.height() * screenRatio);
}
PictureDialog::~PictureDialog()
{
#ifdef Q_OS_WIN
#if QT_VERSION >= 0x050200
if (naviEnabled)
{
for (QObject *obj : layout()->menuBar()->children())
{
delete obj;
}
delete layout()->menuBar();
}
#endif
#else
if (naviEnabled)
{
for (QObject *obj : layout()->menuBar()->children())
{
delete obj;
}
delete layout()->menuBar();
}
#endif
for (QObject *obj : manageMenu->children())
{
delete obj;
}
delete manageMenu;
delete ui;
}
@ -228,11 +247,24 @@ void PictureDialog::closeEvent(QCloseEvent *ev)
{
Q_UNUSED(ev)
if (primaryWindow)
{
emit endDatabaseThread();
}
}
void PictureDialog::addPreviousNextButtons()
{
#ifdef Q_OS_WIN
#if QT_VERSION >= 0x050200
QToolBar *uiToolbar = new QToolBar("Picture Toolbar", this);
uiToolbar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
uiToolbar->setObjectName("UiToolbar");
uiToolbar->addAction(QIcon(":/img/back.svgz"), "", this, SLOT(previousPictureRequestedSlot()));
uiToolbar->addAction(QIcon(":/img/next.svgz"), "", this, SLOT(nextPictureRequestedSlot()));
layout()->setMenuBar(uiToolbar);
naviEnabled = true;
#endif
#else
QToolBar *uiToolbar = new QToolBar("Picture Toolbar", this);
#if QT_VERSION < 0x050600
qreal screenRatio = AppEnv::screenRatio();
@ -243,83 +275,68 @@ void PictureDialog::addPreviousNextButtons()
#endif
uiToolbar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
uiToolbar->setObjectName("UiToolbar");
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"));
#endif
#endif
uiToolbar->addAction(QIcon(":/img/back.svgz"), "", this, SLOT(previousPictureRequestedSlot()));
uiToolbar->addAction(QIcon(":/img/next.svgz"), "", this, SLOT(nextPictureRequestedSlot()));
layout()->setMenuBar(uiToolbar);
naviEnabled = true;
#endif
}
void PictureDialog::adaptDialogSize()
void PictureDialog::adaptNewDialogSize(QSize newLabelSize)
{
int newDialogHeight = (SnapmaticPicture::getSnapmaticResolution().height() * AppEnv::screenRatio()) + ui->jsonFrame->heightForWidth(width());
if (naviEnabled)
newDialogHeight = newDialogHeight + layout()->menuBar()->height();
const QSize windowSize(width(), newDialogHeight);
setMinimumSize(windowSize);
setMaximumSize(windowSize);
Q_UNUSED(newLabelSize)
#if QT_VERSION >= 0x050F00
int newDialogHeight = SnapmaticPicture::getSnapmaticResolution().height();
#else
int newDialogHeight = (ui->labPicture->pixmap()->height() / AppEnv::screenRatioPR());
#endif
newDialogHeight = newDialogHeight + ui->jsonFrame->height();
if (naviEnabled) newDialogHeight = newDialogHeight + layout()->menuBar()->height();
setMaximumSize(width(), newDialogHeight);
setMinimumSize(width(), newDialogHeight);
setFixedHeight(newDialogHeight);
ui->labPicture->updateGeometry();
ui->jsonFrame->updateGeometry();
updateGeometry();
}
void PictureDialog::styliseDialog()
{
#ifdef Q_OS_WIN
BOOL isEnabled;
DwmIsCompositionEnabled(&isEnabled);
if (isEnabled == TRUE) {
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)) {
setStyleSheet("PictureDialog{background:transparent}");
}
#if QT_VERSION >= 0x050200
if (QtWin::isCompositionEnabled())
{
QPalette palette;
QtWin::extendFrameIntoClientArea(this, 0, qRound(layout()->menuBar()->height() * AppEnv::screenRatioPR()), 0, 0);
ui->jsonFrame->setStyleSheet(QString("QFrame { background: %1; }").arg(palette.window().color().name()));
setStyleSheet("PictureDialog { background: transparent; }");
}
else {
MARGINS margins = {0, 0, 0, 0};
DwmExtendFrameIntoClientArea(reinterpret_cast<HWND>(winId()), &margins);
bool colorOk = false;
QSettings dwmRegistry("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\DWM", QSettings::NativeFormat);
QRgb color = dwmRegistry.value("ColorizationColor").toUInt(&colorOk);
if (colorOk) {
setStyleSheet(QString("PictureDialog{background:%1}").arg(QColor::fromRgba(color).name()));
}
else {
HRESULT hr = S_OK;
BOOL isOpaqueBlend;
DWORD colorization;
hr = DwmGetColorizationColor(&colorization, &isOpaqueBlend);
if (SUCCEEDED(hr) && isOpaqueBlend == FALSE) {
color = colorization;
setStyleSheet(QString("PictureDialog{background:%1}").arg(QColor::fromRgba(color).name()));
}
else {
setStyleSheet("PictureDialog{background:palette(window)}");
}
}
else
{
QPalette palette;
QtWin::resetExtendedFrame(this);
ui->jsonFrame->setStyleSheet(QString("QFrame { background: %1; }").arg(palette.window().color().name()));
setStyleSheet(QString("PictureDialog { background: %1; }").arg(QtWin::realColorizationColor().name()));
}
ui->jsonFrame->setStyleSheet("QFrame{background:palette(window)}");
#endif
#endif
}
#ifdef Q_OS_WIN
#if QT_VERSION >= 0x050000
#if QT_VERSION >= 0x060000
bool PictureDialog::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
#else
bool PictureDialog::nativeEvent(const QByteArray &eventType, void *message, long *result)
#endif
bool PictureDialog::event(QEvent *event)
{
MSG *msg = reinterpret_cast<MSG*>(message);
if (msg->message == 0x031e || msg->message == 0x0320) {
styliseDialog();
#ifdef Q_OS_WIN
#if QT_VERSION >= 0x050200
if (naviEnabled)
{
if (event->type() == QWinEvent::CompositionChange || event->type() == QWinEvent::ColorizationChange)
{
styliseDialog();
}
}
return QWidget::nativeEvent(eventType, message, result);
#endif
#endif
return QDialog::event(event);
}
#endif
#endif
void PictureDialog::nextPictureRequestedSlot()
{
@ -334,10 +351,12 @@ void PictureDialog::previousPictureRequestedSlot()
bool PictureDialog::eventFilter(QObject *obj, QEvent *ev)
{
bool returnValue = false;
if (obj == this || obj == ui->labPicture) {
if (ev->type() == QEvent::KeyPress) {
if (obj == this || obj == ui->labPicture)
{
if (ev->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = dynamic_cast<QKeyEvent*>(ev);
switch (keyEvent->key()) {
switch (keyEvent->key()){
case Qt::Key_Left:
emit previousPictureRequested();
returnValue = true;
@ -347,21 +366,25 @@ bool PictureDialog::eventFilter(QObject *obj, QEvent *ev)
returnValue = true;
break;
case Qt::Key_1:
if (previewMode) {
if (previewMode)
{
previewMode = false;
renderPicture();
}
else {
else
{
previewMode = true;
renderPicture();
}
break;
case Qt::Key_2:
if (overlayEnabled) {
if (overlayEnabled)
{
overlayEnabled = false;
if (!previewMode) renderPicture();
}
else {
else
{
overlayEnabled = true;
if (!previewMode) renderPicture();
}
@ -387,30 +410,40 @@ 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) {
#if QT_VERSION >= 0x050200
if (obj != ui->labPicture && naviEnabled)
{
if (ev->type() == QEvent::MouseButtonPress)
{
QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(ev);
if (mouseEvent->pos().y() <= layout()->menuBar()->height()) {
if (mouseEvent->button() == Qt::LeftButton) {
if (mouseEvent->pos().y() <= layout()->menuBar()->height())
{
if (mouseEvent->button() == Qt::LeftButton)
{
dragPosition = mouseEvent->pos();
dragStart = true;
}
}
}
if (ev->type() == QEvent::MouseButtonRelease) {
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->pos().y() <= layout()->menuBar()->height())
{
if (mouseEvent->button() == Qt::LeftButton)
{
dragStart = false;
}
}
}
if (dragStart && ev->type() == QEvent::MouseMove) {
if (ev->type() == QEvent::MouseMove && dragStart)
{
QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(ev);
if (mouseEvent->pos().y() <= layout()->menuBar()->height()) {
if (mouseEvent->buttons() & Qt::LeftButton) {
const QPoint diff = mouseEvent->pos() - dragPosition;
if (mouseEvent->pos().y() <= layout()->menuBar()->height())
{
if (mouseEvent->buttons() & Qt::LeftButton)
{
QPoint diff = mouseEvent->pos() - dragPosition;
move(QPoint(pos() + diff));
updateGeometry();
}
@ -468,12 +501,14 @@ void PictureDialog::renderOverlayPicture()
QRect overlaySpace = fontMetrics.boundingRect(preferedRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextDontClip | Qt::TextWordWrap, overlayText);
int hOverlay = Qt::AlignTop;
if (overlaySpace.height() < 74 * screenRatio * screenRatioPR) {
if (overlaySpace.height() < 74 * screenRatio * screenRatioPR)
{
hOverlay = Qt::AlignVCenter;
preferedRect.setHeight(71 * screenRatio * screenRatioPR);
overlaySpace.setHeight(80 * screenRatio * screenRatioPR);
}
else {
else
{
overlaySpace.setHeight(overlaySpace.height() + 6 * screenRatio * screenRatioPR);
}
@ -486,10 +521,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);
}
@ -506,7 +543,8 @@ void PictureDialog::renderOverlayPicture()
void PictureDialog::setSnapmaticPicture(SnapmaticPicture *picture, bool readOk, bool _indexed, int _index)
{
if (smpic != nullptr) {
if (smpic != nullptr)
{
QObject::disconnect(smpic, SIGNAL(updated()), this, SLOT(updated()));
QObject::disconnect(smpic, SIGNAL(customSignal(QString)), this, SLOT(customSignal(QString)));
}
@ -514,30 +552,35 @@ void PictureDialog::setSnapmaticPicture(SnapmaticPicture *picture, bool readOk,
indexed = _indexed;
index = _index;
smpic = picture;
if (!readOk) {
if (!readOk)
{
QMessageBox::warning(this, tr("Snapmatic Picture Viewer"), tr("Failed at %1").arg(picture->getLastStep()));
return;
}
if (picture->isPicOk()) {
if (picture->isPicOk())
{
snapmaticPicture = picture->getImage();
renderPicture();
ui->cmdManage->setEnabled(true);
}
if (picture->isJsonOk()) {
if (picture->isJsonOk())
{
crewStr = crewDB->getCrewName(crewID);
if (globalMap.contains(picArea)) {
picAreaStr = globalMap.value(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, SLOT(adaptDialogSize()));
}
else {
else
{
ui->labJSON->setText(jsonDrawString.arg("0", "0", "0", tr("No Players"), tr("No Crew"), tr("Unknown Location")));
QTimer::singleShot(0, this, SLOT(adaptDialogSize()));
QMessageBox::warning(this,tr("Snapmatic Picture Viewer"),tr("Failed at %1").arg(picture->getLastStep()));
}
QObject::connect(smpic, SIGNAL(updated()), this, SLOT(updated()));
QObject::connect(smpic, SIGNAL(customSignal(QString)), this, SLOT(customSignal(QString)));
@ -566,58 +609,76 @@ void PictureDialog::setSnapmaticPicture(SnapmaticPicture *picture)
void PictureDialog::renderPicture()
{
const qreal screenRatio = AppEnv::screenRatio();
const qreal screenRatioPR = AppEnv::screenRatioPR();
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()) {
shownImagePainter.drawImage((renderResolution.width() - renderImage.width()) / 2, 0, renderImage, Qt::AutoColor);
}
else if (renderImage.height() < renderResolution.height()) {
shownImagePainter.drawImage(0, (renderResolution.height() - renderImage.height()) / 2, renderImage, Qt::AutoColor);
}
else {
shownImagePainter.drawImage(0, 0, renderImage, Qt::AutoColor);
}
if (previewMode) {
QFont shownImagePainterFont;
shownImagePainterFont.setPixelSize(12 * screenRatio * screenRatioPR);
shownImagePainter.drawImage(0, 0, avatarAreaPicture);
shownImagePainter.setPen(QColor::fromRgb(255, 255, 255, 255));
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) {
shownImagePainter.drawImage(3 * screenRatio * screenRatioPR, 3 * screenRatio * screenRatioPR, overlayTempImage, Qt::AutoColor);
}
shownImagePainter.end();
qreal screenRatio = AppEnv::screenRatio();
qreal screenRatioPR = AppEnv::screenRatioPR();
if (!previewMode)
{
if (overlayEnabled)
{
QSize snapmaticResolution = SnapmaticPicture::getSnapmaticResolution();
QPixmap shownImagePixmap(snapmaticResolution.width() * screenRatio * screenRatioPR, snapmaticResolution.height() * screenRatio * screenRatioPR);
shownImagePixmap.fill(Qt::transparent);
QPainter shownImagePainter(&shownImagePixmap);
shownImagePainter.drawImage(0, 0, snapmaticPicture.scaled(snapmaticResolution.width() * screenRatio * screenRatioPR, snapmaticResolution.height() * screenRatio * screenRatioPR, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
shownImagePainter.drawImage(3 * screenRatio * screenRatioPR, 3 * screenRatio * screenRatioPR, overlayTempImage);
shownImagePainter.end();
#if QT_VERSION >= 0x050600
shownImagePixmap.setDevicePixelRatio(screenRatioPR);
shownImagePixmap.setDevicePixelRatio(screenRatioPR);
#endif
ui->labPicture->setPixmap(shownImagePixmap);
ui->labPicture->setPixmap(shownImagePixmap);
}
else
{
QSize snapmaticResolution = SnapmaticPicture::getSnapmaticResolution();
QPixmap shownImagePixmap(snapmaticResolution.width() * screenRatio * screenRatioPR, snapmaticResolution.height() * screenRatio * screenRatioPR);
shownImagePixmap.fill(Qt::transparent);
QPainter shownImagePainter(&shownImagePixmap);
shownImagePainter.drawImage(0, 0, snapmaticPicture.scaled(snapmaticResolution.width() * screenRatio * screenRatioPR, snapmaticResolution.height() * screenRatio * screenRatioPR, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
shownImagePainter.end();
#if QT_VERSION >= 0x050600
shownImagePixmap.setDevicePixelRatio(screenRatioPR);
#endif
ui->labPicture->setPixmap(shownImagePixmap);
}
}
else
{
// Generating Avatar Preview
QSize snapmaticResolution = SnapmaticPicture::getSnapmaticResolution();
QPixmap avatarPixmap(snapmaticResolution.width() * screenRatio * screenRatioPR, snapmaticResolution.height() * screenRatio * screenRatioPR);
QPainter snapPainter(&avatarPixmap);
QFont snapPainterFont;
snapPainterFont.setPixelSize(12 * screenRatio * screenRatioPR);
snapPainter.drawImage(0, 0, snapmaticPicture.scaled(snapmaticResolution.width() * screenRatio * screenRatioPR, snapmaticResolution.height() * screenRatio * screenRatioPR, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
snapPainter.drawImage(0, 0, avatarAreaPicture);
snapPainter.setPen(QColor::fromRgb(255, 255, 255, 255));
snapPainter.setFont(snapPainterFont);
snapPainter.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"));
snapPainter.end();
#if QT_VERSION >= 0x050600
avatarPixmap.setDevicePixelRatio(screenRatioPR);
#endif
ui->labPicture->setPixmap(avatarPixmap);
}
}
void PictureDialog::crewNameUpdated()
{
SnapmaticPicture *picture = smpic; // used by macro
QString crewIDStr = crewID;
if (crewIDStr == crewStr) {
if (crewIDStr == crewStr)
{
crewStr = crewDB->getCrewName(crewIDStr);
ui->labJSON->setText(jsonDrawString.arg(locX, locY, locZ, generatePlayersString(), generateCrewString(), picTitl, picAreaStr, created));
QTimer::singleShot(0, this, SLOT(adaptDialogSize()));
}
}
void PictureDialog::playerNameUpdated()
{
SnapmaticPicture *picture = smpic; // used by macro
if (plyrsList.count() >= 1) {
if (plyrsList.count() >= 1)
{
ui->labJSON->setText(jsonDrawString.arg(locX, locY, locZ, generatePlayersString(), generateCrewString(), picTitl, picAreaStr, created));
QTimer::singleShot(0, this, SLOT(adaptDialogSize()));
}
}
@ -625,7 +686,8 @@ QString PictureDialog::generateCrewString()
{
SnapmaticPicture *picture = smpic; // used by macro
const QString crewIDStr = crewID; // save operation time
if (crewIDStr != "0" && !crewIDStr.isEmpty()) {
if (crewIDStr != "0" && !crewIDStr.isEmpty())
{
if (crewIDStr != crewStr) {
return QString("<a href=\"https://socialclub.rockstargames.com/crew/" % QString(crewStr).replace(" ", "_") % "/" % crewIDStr % "\">" % crewStr % "</a>");
}
@ -641,8 +703,10 @@ QString PictureDialog::generatePlayersString()
SnapmaticPicture *picture = smpic; // used by macro
const QStringList playersList = plyrsList; // save operation time
QString plyrsStr;
if (playersList.length() >= 1) {
for (const QString &player : playersList) {
if (playersList.length() >= 1)
{
for (const QString &player : playersList)
{
const QString playerName = profileDB->getPlayerName(player);
if (player != playerName) {
plyrsStr += ", <a href=\"https://socialclub.rockstargames.com/member/" % playerName % "/" % player % "\">" % playerName % "</a>";
@ -653,7 +717,8 @@ QString PictureDialog::generatePlayersString()
}
plyrsStr.remove(0, 2);
}
else {
else
{
plyrsStr = tr("No Players");
}
return plyrsStr;
@ -661,27 +726,32 @@ 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()
{
if (rqFullscreen && fullscreenWidget != nullptr) {
if (rqFullscreen && fullscreenWidget != nullptr)
{
PictureExport::exportAsSnapmatic(fullscreenWidget, smpic);
}
else {
else
{
PictureExport::exportAsSnapmatic(this, smpic);
}
}
void PictureDialog::on_labPicture_mouseDoubleClicked(Qt::MouseButton button)
{
if (button == Qt::LeftButton) {
if (button == Qt::LeftButton)
{
#if QT_VERSION >= 0x060000
QRect desktopRect = QApplication::screenAt(pos())->geometry();
#else
@ -689,17 +759,14 @@ void PictureDialog::on_labPicture_mouseDoubleClicked(Qt::MouseButton button)
#endif
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
#if 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->setStyleSheet("QLabel#pictureLabel{background-color: black;}");
pictureWidget->setImage(snapmaticPicture, desktopRect);
pictureWidget->setModal(true);
fullscreenWidget = pictureWidget;
@ -709,6 +776,11 @@ void PictureDialog::on_labPicture_mouseDoubleClicked(Qt::MouseButton button)
pictureWidget->move(desktopRect.x(), desktopRect.y());
pictureWidget->resize(desktopRect.width(), desktopRect.height());
#ifdef Q_OS_WIN
#if QT_VERSION >= 0x050200
QtWin::markFullscreenWindow(pictureWidget, true);
#endif
#endif
pictureWidget->showFullScreen();
pictureWidget->setFocus();
pictureWidget->raise();
@ -737,15 +809,15 @@ int PictureDialog::getIndex()
void PictureDialog::openPreviewMap()
{
SnapmaticPicture *picture = smpic;
SnapmaticProperties currentProperties = picture->getSnapmaticProperties();
MapLocationDialog *mapLocDialog;
if (rqFullscreen && fullscreenWidget != nullptr) {
mapLocDialog = new MapLocationDialog(currentProperties.location.x, currentProperties.location.y, fullscreenWidget);
if (rqFullscreen && fullscreenWidget != nullptr)
{
mapLocDialog = new MapLocationDialog(picture->getSnapmaticProperties().location.x, picture->getSnapmaticProperties().location.y, fullscreenWidget);
}
else {
mapLocDialog = new MapLocationDialog(currentProperties.location.x, currentProperties.location.y, this);
else
{
mapLocDialog = new MapLocationDialog(picture->getSnapmaticProperties().location.x, picture->getSnapmaticProperties().location.y, this);
}
mapLocDialog->setCayoPerico(currentProperties.location.isCayoPerico);
mapLocDialog->setWindowIcon(windowIcon());
mapLocDialog->setModal(true);
#ifndef Q_OS_ANDROID
@ -754,43 +826,45 @@ void PictureDialog::openPreviewMap()
mapLocDialog->showMaximized();
#endif
mapLocDialog->exec();
if (mapLocDialog->propUpdated()) {
if (mapLocDialog->propUpdated())
{
// Update Snapmatic Properties
currentProperties.location.x = mapLocDialog->getXpos();
currentProperties.location.y = mapLocDialog->getYpos();
currentProperties.location.z = 0;
SnapmaticProperties localSpJson = picture->getSnapmaticProperties();
localSpJson.location.x = mapLocDialog->getXpos();
localSpJson.location.y = mapLocDialog->getYpos();
localSpJson.location.z = 0;
// Update Snapmatic Picture
QString currentFilePath = picture->getPictureFilePath();
QString originalFilePath = picture->getOriginalPictureFilePath();
QString backupFileName = originalFilePath % ".bak";
if (!QFile::exists(backupFileName)) {
if (!QFile::exists(backupFileName))
{
QFile::copy(currentFilePath, backupFileName);
}
SnapmaticProperties fallbackProperties = picture->getSnapmaticProperties();
picture->setSnapmaticProperties(currentProperties);
if (!picture->exportPicture(currentFilePath)) {
picture->setSnapmaticProperties(localSpJson);
if (!picture->exportPicture(currentFilePath))
{
QMessageBox::warning(this, SnapmaticEditor::tr("Snapmatic Properties"), SnapmaticEditor::tr("Patching of Snapmatic Properties failed because of I/O Error"));
picture->setSnapmaticProperties(fallbackProperties);
}
else {
else
{
updated();
#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"] = "LocationEdited";
jsonObject["ExtraFlags"] = "Viewer";
jsonObject["EditedSize"] = QString::number(picture->getContentMaxLength());
#if QT_VERSION >= 0x060000
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
#else
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
#endif
jsonDocument.setObject(jsonObject);
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
}
@ -804,10 +878,12 @@ void PictureDialog::editSnapmaticProperties()
{
SnapmaticPicture *picture = smpic;
SnapmaticEditor *snapmaticEditor;
if (rqFullscreen && fullscreenWidget != nullptr) {
if (rqFullscreen && fullscreenWidget != nullptr)
{
snapmaticEditor = new SnapmaticEditor(crewDB, profileDB, fullscreenWidget);
}
else {
else
{
snapmaticEditor = new SnapmaticEditor(crewDB, profileDB, this);
}
snapmaticEditor->setWindowIcon(windowIcon());
@ -826,10 +902,12 @@ void PictureDialog::editSnapmaticImage()
{
QImage *currentImage = new QImage(smpic->getImage());
ImportDialog *importDialog;
if (rqFullscreen && fullscreenWidget != nullptr) {
if (rqFullscreen && fullscreenWidget != nullptr)
{
importDialog = new ImportDialog(profileName, fullscreenWidget);
}
else {
else
{
importDialog = new ImportDialog(profileName, this);
}
importDialog->setWindowIcon(windowIcon());
@ -837,17 +915,21 @@ void PictureDialog::editSnapmaticImage()
importDialog->enableOverwriteMode();
importDialog->setModal(true);
importDialog->exec();
if (importDialog->isImportAgreed()) {
if (importDialog->isImportAgreed())
{
const QByteArray previousPicture = smpic->getPictureStream();
bool success = smpic->setImage(importDialog->image(), importDialog->isUnlimitedBuffer());
if (success) {
bool success = smpic->setImage(importDialog->image());
if (success)
{
QString currentFilePath = smpic->getPictureFilePath();
QString originalFilePath = smpic->getOriginalPictureFilePath();
QString backupFileName = originalFilePath % ".bak";
if (!QFile::exists(backupFileName)) {
if (!QFile::exists(backupFileName))
{
QFile::copy(currentFilePath, backupFileName);
}
if (!smpic->exportPicture(currentFilePath)) {
if (!smpic->exportPicture(currentFilePath))
{
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;
@ -858,23 +940,21 @@ void PictureDialog::editSnapmaticImage()
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"] = "ImageEdited";
jsonObject["ExtraFlags"] = "Viewer";
jsonObject["EditedSize"] = QString::number(smpic->getContentMaxLength());
#if QT_VERSION >= 0x060000
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
#else
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
#endif
jsonDocument.setObject(jsonObject);
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
}
#endif
}
else {
else
{
QMessageBox::warning(this, QApplication::translate("ImageEditorDialog", "Snapmatic Image Editor"), QApplication::translate("ImageEditorDialog", "Patching of Snapmatic Image failed because of Image Error"));
return;
}
@ -886,10 +966,12 @@ void PictureDialog::editSnapmaticRawJson()
{
SnapmaticPicture *picture = smpic;
JsonEditorDialog *jsonEditor;
if (rqFullscreen && fullscreenWidget != nullptr) {
if (rqFullscreen && fullscreenWidget != nullptr)
{
jsonEditor = new JsonEditorDialog(picture, fullscreenWidget);
}
else {
else
{
jsonEditor = new JsonEditorDialog(picture, this);
}
jsonEditor->setWindowIcon(windowIcon());
@ -907,21 +989,23 @@ 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, SLOT(adaptDialogSize()));
}
void PictureDialog::customSignal(QString signal)
{
SnapmaticPicture *picture = smpic; // used by macro
if (signal == "PictureUpdated") {
if (signal == "PictureUpdated")
{
snapmaticPicture = picture->getImage();
renderPicture();
}

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -54,11 +54,11 @@ public:
~PictureDialog();
public slots:
void adaptDialogSize();
void crewNameUpdated();
void playerNameUpdated();
void dialogNextPictureRequested();
void dialogPreviousPictureRequested();
void adaptNewDialogSize(QSize newLabelSize);
void exportCustomContextMenuRequested(const QPoint &pos);
private slots:
@ -89,13 +89,7 @@ protected:
void closeEvent(QCloseEvent *ev);
bool eventFilter(QObject *obj, QEvent *ev);
void mousePressEvent(QMouseEvent *ev);
#ifdef Q_OS_WIN
#if QT_VERSION >= 0x060000
bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result);
#elif QT_VERSION >= 0x050000
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
#endif
#endif
bool event(QEvent *event);
private:
QString generateCrewString();
@ -126,7 +120,7 @@ private:
int avatarSize;
QMenu *manageMenu;
#ifdef Q_OS_WIN
#if QT_VERSION >= 0x050000
#if QT_VERSION >= 0x050200
QPoint dragPosition;
bool dragStart;
#endif

View File

@ -48,6 +48,19 @@
</property>
</widget>
</item>
<item>
<spacer name="vsJSONUpper">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QFrame" name="jsonFrame">
<property name="frameShape">
@ -98,10 +111,10 @@
</sizepolicy>
</property>
<property name="text">
<string>&lt;span style=&quot;font-weight:600&quot;&gt;Title: &lt;/span&gt;%6&lt;br/&gt;
&lt;span style=&quot;font-weight:600&quot;&gt;Location: &lt;/span&gt;%7 (%1, %2, %3)&lt;br/&gt;
&lt;span style=&quot;font-weight:600&quot;&gt;Players: &lt;/span&gt;%4 (Crew %5)&lt;br/&gt;
&lt;span style=&quot;font-weight:600&quot;&gt;Created: &lt;/span&gt;%8</string>
<string>&lt;span style=&quot; font-weight:600;&quot;&gt;Title: &lt;/span&gt;%6&lt;br/&gt;
&lt;span style=&quot; font-weight:600;&quot;&gt;Location: &lt;/span&gt;%7 (%1, %2, %3)&lt;br/&gt;
&lt;span style=&quot; font-weight:600;&quot;&gt;Players: &lt;/span&gt;%4 (Crew %5)&lt;br/&gt;
&lt;span style=&quot; font-weight:600;&quot;&gt;Created: &lt;/span&gt;%8</string>
</property>
<property name="wordWrap">
<bool>true</bool>

View File

@ -40,6 +40,7 @@
PictureExport::PictureExport()
{
}
void PictureExport::exportAsPicture(QWidget *parent, SnapmaticPicture *picture)
@ -50,25 +51,30 @@ void PictureExport::exportAsPicture(QWidget *parent, SnapmaticPicture *picture)
// Quality Settings
settings.beginGroup("Pictures");
int defaultQuality = 100;
QSize defExportSize = SnapmaticPicture::getSnapmaticResolution();
QSize defExportSize = QSize(960, 536);
int customQuality = settings.value("CustomQuality", defaultQuality).toInt();
if (customQuality < 1 || customQuality > 100) {
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) {
if (cusExportSize.width() > 3840)
{
cusExportSize.setWidth(3840);
}
else if (cusExportSize.height() > 2160) {
else if (cusExportSize.height() > 2160)
{
cusExportSize.setHeight(2160);
}
if (cusExportSize.width() < 1) {
if (cusExportSize.width() < 1)
{
cusExportSize.setWidth(1);
}
else if (cusExportSize.height() < 1) {
else if (cusExportSize.height() < 1)
{
cusExportSize.setHeight(1);
}
QString sizeMode = settings.value("ExportSizeMode", "Default").toString();
@ -107,42 +113,54 @@ fileDialogPreSave: //Work?
QString newPictureFileName = getPictureFileName(picture) % defaultExportFormat;
fileDialog.selectFile(newPictureFileName);
if (fileDialog.exec()) {
if (fileDialog.exec())
{
QStringList selectedFiles = fileDialog.selectedFiles();
if (selectedFiles.length() == 1) {
if (selectedFiles.length() == 1)
{
QString saveFileFormat;
QString selectedFile = selectedFiles.at(0);
if (selectedFile.right(4) == ".jpg") {
if (selectedFile.right(4) == ".jpg")
{
saveFileFormat = "JPEG";
}
else if (selectedFile.right(4) == ".jpeg") {
else if (selectedFile.right(4) == ".jpeg")
{
saveFileFormat = "JPEG";
}
else if (selectedFile.right(4) == ".png") {
else if (selectedFile.right(4) == ".png")
{
saveFileFormat = "PNG";
}
else if (selectedFile.right(7) == ".suffix") {
if (fileDialog.selectedNameFilter() == "JPEG picture (*.jpg)") {
else if (selectedFile.right(7) == ".suffix")
{
if (fileDialog.selectedNameFilter() == "JPEG picture (*.jpg)")
{
selectedFile.replace(".suffix", ".jpg");
}
else if (fileDialog.selectedNameFilter() == "Portable Network Graphics (*.png)") {
else if (fileDialog.selectedNameFilter() == "Portable Network Graphics (*.png)")
{
selectedFile.replace(".suffix", ".png");
}
else {
else
{
selectedFile.replace(".suffix", ".jpg");
}
}
if (QFile::exists(selectedFile)) {
if (QMessageBox::No == QMessageBox::warning(parent, PictureDialog::tr("Export as Picture"), PictureDialog::tr("Overwrite %1 with current Snapmatic picture?").arg("\""+selectedFile+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)) {
if (QFile::exists(selectedFile))
{
if (QMessageBox::No == QMessageBox::warning(parent, PictureDialog::tr("Export as Picture"), PictureDialog::tr("Overwrite %1 with current Snapmatic picture?").arg("\""+selectedFile+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes))
{
goto fileDialogPreSave; //Work?
}
}
// Scale Picture
QImage exportPicture = picture->getImage();
if (sizeMode == "Desktop") {
if (sizeMode == "Desktop")
{
#if QT_VERSION >= 0x050000
qreal screenRatioPR = AppEnv::screenRatioPR();
QRect desktopResolution = QApplication::primaryScreen()->geometry();
@ -155,7 +173,8 @@ fileDialogPreSave: //Work?
#endif
exportPicture = exportPicture.scaled(desktopSizeWidth, desktopSizeHeight, aspectRatio, Qt::SmoothTransformation);
}
else if (sizeMode == "Custom") {
else if (sizeMode == "Custom")
{
exportPicture = exportPicture.scaled(cusExportSize, aspectRatio, Qt::SmoothTransformation);
}
@ -166,26 +185,32 @@ fileDialogPreSave: //Work?
#else
QFile *picFile = new QFile(selectedFile);
#endif
if (picFile->open(QIODevice::WriteOnly)) {
if (picFile->open(QIODevice::WriteOnly))
{
isSaved = exportPicture.save(picFile, saveFileFormat.toStdString().c_str(), useCustomQuality ? customQuality : defaultQuality);
#if QT_VERSION >= 0x050000
if (isSaved) {
if (isSaved)
{
isSaved = picFile->commit();
}
else {
else
{
errorId = 1;
}
#else
picFile->close();
#endif
}
else {
else
{
errorId = 2;
}
delete picFile;
if (!isSaved) {
switch (errorId) {
if (!isSaved)
{
switch (errorId)
{
case 0:
QMessageBox::warning(parent, PictureDialog::tr("Export as Picture"), PictureDialog::tr("Failed to export the picture because the system occurred a write failure"));
break;
@ -201,7 +226,8 @@ fileDialogPreSave: //Work?
goto fileDialogPreSave; //Work?
}
}
else {
else
{
QMessageBox::warning(parent, PictureDialog::tr("Export as Picture"), PictureDialog::tr("No valid file is selected"));
goto fileDialogPreSave; //Work?
}
@ -237,9 +263,7 @@ fileDialogPreSave: //Work?
QStringList filters;
filters << PictureDialog::tr("GTA V Export (*.g5e)");
#ifndef GTA5SYNC_FLATPAK
filters << PictureDialog::tr("GTA V Raw Export (*.auto)");
#endif
filters << PictureDialog::tr("Snapmatic pictures (PGTA*)");
fileDialog.setNameFilters(filters);
@ -250,48 +274,58 @@ fileDialogPreSave: //Work?
fileDialog.restoreGeometry(settings.value(parent->objectName() % "+Geometry", "").toByteArray());
fileDialog.selectFile(QString(picture->getExportPictureFileName() % ".g5e"));
if (fileDialog.exec()) {
if (fileDialog.exec())
{
QStringList selectedFiles = fileDialog.selectedFiles();
if (selectedFiles.length() == 1) {
if (selectedFiles.length() == 1)
{
QString selectedFile = selectedFiles.at(0);
bool isAutoExt = false;
#ifndef GTA5SYNC_FLATPAK
if (selectedFile.right(5) == ".auto") {
if (selectedFile.right(5) == ".auto")
{
isAutoExt = true;
QString dirPath = QFileInfo(selectedFile).dir().path();
QString stockFileName = sgdFileInfo.fileName();
selectedFile = dirPath % "/" % stockFileName;
}
#endif
if (selectedFile.right(4) == ".rem") {
else if (selectedFile.right(4) == ".rem")
{
selectedFile.remove(selectedFile.length() - 4, 4);
}
if (QFile::exists(selectedFile)) {
if (QMessageBox::No == QMessageBox::warning(parent, PictureDialog::tr("Export as Snapmatic"), PictureDialog::tr("Overwrite %1 with current Snapmatic picture?").arg("\""+selectedFile+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)) {
if (QFile::exists(selectedFile))
{
if (QMessageBox::No == QMessageBox::warning(parent, PictureDialog::tr("Export as Snapmatic"), PictureDialog::tr("Overwrite %1 with current Snapmatic picture?").arg("\""+selectedFile+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes))
{
goto fileDialogPreSave; //Work?
}
}
if (selectedFile.right(4) == ".g5e") {
if (selectedFile.right(4) == ".g5e")
{
bool isExported = picture->exportPicture(selectedFile, SnapmaticFormat::G5E_Format);
if (!isExported) {
if (!isExported)
{
QMessageBox::warning(parent, PictureDialog::tr("Export as Snapmatic"), PictureDialog::tr("Failed to export current Snapmatic picture"));
goto fileDialogPreSave; //Work?
}
}
else {
else
{
bool isCopied = picture->exportPicture(selectedFile, SnapmaticFormat::PGTA_Format);
if (!isCopied) {
if (!isCopied)
{
QMessageBox::warning(parent, PictureDialog::tr("Export as Snapmatic"), PictureDialog::tr("Failed to export current Snapmatic picture"));
goto fileDialogPreSave; //Work?
}
else {
else
{
if (isAutoExt) QMessageBox::information(parent, PictureDialog::tr("Export as Snapmatic"), PictureDialog::tr("Exported Snapmatic to \"%1\" because of using the .auto extension.").arg(selectedFile));
}
}
}
else {
else
{
QMessageBox::warning(parent, PictureDialog::tr("Export as Snapmatic"), PictureDialog::tr("No valid file is selected"));
goto fileDialogPreSave; //Work?
}

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2020 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
@ -19,12 +19,16 @@
#include "PictureDialog.h"
#include "PictureWidget.h"
#include "UiModLabel.h"
#include "AppEnv.h"
#include <QApplication>
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QPixmap>
#include <QEvent>
#include <QDebug>
#if QT_VERSION < 0x060000
#include <QDesktopWidget>
#endif
PictureWidget::PictureWidget(QWidget *parent) : QDialog(parent)
{
@ -43,6 +47,9 @@ PictureWidget::PictureWidget(QWidget *parent) : QDialog(parent)
QObject::connect(pictureLabel, SIGNAL(mouseDoubleClicked(Qt::MouseButton)), this, SLOT(pictureDoubleClicked(Qt::MouseButton)));
QObject::connect(pictureLabel, SIGNAL(customContextMenuRequested(QPoint)), parent, SLOT(exportCustomContextMenuRequested(QPoint)));
#if QT_VERSION < 0x060000
QObject::connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(updateWindowSize(int)));
#endif
setLayout(widgetLayout);
}
@ -56,10 +63,12 @@ PictureWidget::~PictureWidget()
bool PictureWidget::eventFilter(QObject *obj, QEvent *ev)
{
if (obj == this) {
if (ev->type() == QEvent::KeyPress) {
if (obj == this)
{
if (ev->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = (QKeyEvent*)ev;
switch (keyEvent->key()) {
switch (keyEvent->key()){
case Qt::Key_Left:
emit previousPictureRequested();
break;
@ -74,29 +83,41 @@ bool PictureWidget::eventFilter(QObject *obj, QEvent *ev)
void PictureWidget::pictureDoubleClicked(Qt::MouseButton button)
{
if (button == Qt::LeftButton) {
if (button == Qt::LeftButton)
{
close();
}
}
void PictureWidget::setImage(QImage image_, QRect rec)
{
const qreal screenRatioPR = AppEnv::screenRatioPR();
image = image_;
QPixmap pixmap = QPixmap::fromImage(image.scaled(rec.width() * screenRatioPR, rec.height() * screenRatioPR, Qt::KeepAspectRatio, Qt::SmoothTransformation));
#if QT_VERSION >= 0x050600
pixmap.setDevicePixelRatio(AppEnv::screenRatioPR());
#endif
pictureLabel->setPixmap(pixmap);
pictureLabel->setPixmap(QPixmap::fromImage(image.scaled(rec.width(), rec.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation)));
}
void PictureWidget::setImage(QImage image_)
{
const qreal screenRatioPR = AppEnv::screenRatioPR();
image = image_;
QPixmap pixmap = QPixmap::fromImage(image.scaled(geometry().width() * screenRatioPR, geometry().height() * screenRatioPR, Qt::KeepAspectRatio, Qt::SmoothTransformation));
#if QT_VERSION >= 0x050600
pixmap.setDevicePixelRatio(screenRatioPR);
#endif
pictureLabel->setPixmap(pixmap);
pictureLabel->setPixmap(QPixmap::fromImage(image.scaled(geometry().width(), geometry().height(), Qt::KeepAspectRatio, Qt::SmoothTransformation)));
}
void PictureWidget::updateWindowSize(int screenID)
{
#if QT_VERSION >= 0x060000
Q_UNUSED(screenID)
QRect desktopRect = QApplication::screenAt(pos())->geometry();
move(desktopRect.x(), desktopRect.y());
resize(desktopRect.width(), desktopRect.height());
showFullScreen();
pictureLabel->setPixmap(QPixmap::fromImage(image.scaled(desktopRect.width(), desktopRect.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation)));
#else
if (screenID == QApplication::desktop()->screenNumber(this))
{
QRect desktopRect = QApplication::desktop()->screenGeometry(this);
move(desktopRect.x(), desktopRect.y());
resize(desktopRect.width(), desktopRect.height());
showFullScreen();
pictureLabel->setPixmap(QPixmap::fromImage(image.scaled(desktopRect.width(), desktopRect.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation)));
}
#endif
}

View File

@ -46,6 +46,7 @@ private:
private slots:
void pictureDoubleClicked(Qt::MouseButton button);
void updateWindowSize(int screenID);
signals:
void nextPictureRequested();

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -18,9 +18,7 @@
#include "PlayerListDialog.h"
#include "ui_PlayerListDialog.h"
#include "wrapper.h"
#include "AppEnv.h"
#include <QStringBuilder>
#include <QFontMetrics>
#include <QInputDialog>
#include <QMessageBox>
@ -33,11 +31,7 @@ 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);
@ -45,32 +39,40 @@ PlayerListDialog::PlayerListDialog(QStringList players, ProfileDatabase *profile
ui->cmdCancel->setFocus();
// Set Icon for Apply Button
if (QIcon::hasThemeIcon("dialog-ok-apply")) {
if (QIcon::hasThemeIcon("dialog-ok-apply"))
{
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-ok-apply"));
}
else if (QIcon::hasThemeIcon("dialog-apply")) {
else if (QIcon::hasThemeIcon("dialog-apply"))
{
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-apply"));
}
else if (QIcon::hasThemeIcon("gtk-apply")) {
else if (QIcon::hasThemeIcon("gtk-apply"))
{
ui->cmdApply->setIcon(QIcon::fromTheme("gtk-apply"));
}
else if (QIcon::hasThemeIcon("dialog-ok")) {
else if (QIcon::hasThemeIcon("dialog-ok"))
{
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-ok"));
}
else if (QIcon::hasThemeIcon("gtk-ok")) {
else if (QIcon::hasThemeIcon("gtk-ok"))
{
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-ok"));
}
// Set Icon for Cancel Button
if (QIcon::hasThemeIcon("dialog-cancel")) {
if (QIcon::hasThemeIcon("dialog-cancel"))
{
ui->cmdCancel->setIcon(QIcon::fromTheme("dialog-cancel"));
}
else if (QIcon::hasThemeIcon("gtk-cancel")) {
else if (QIcon::hasThemeIcon("gtk-cancel"))
{
ui->cmdCancel->setIcon(QIcon::fromTheme("gtk-cancel"));
}
// Set Icon for Manage Buttons
if (QIcon::hasThemeIcon("go-previous") && QIcon::hasThemeIcon("go-next") && QIcon::hasThemeIcon("list-add")) {
if (QIcon::hasThemeIcon("go-previous") && QIcon::hasThemeIcon("go-next") && QIcon::hasThemeIcon("list-add"))
{
#if QT_VERSION < 0x050600
qreal screenRatio = AppEnv::screenRatio();
if (screenRatio != 1) {
@ -85,7 +87,8 @@ PlayerListDialog::PlayerListDialog(QStringList players, ProfileDatabase *profile
ui->cmdMakeSe->setIcon(QIcon::fromTheme("go-next"));
ui->cmdMakeAd->setIcon(QIcon::fromTheme("list-add"));
}
else {
else
{
#if QT_VERSION < 0x050600
qreal screenRatio = AppEnv::screenRatio();
if (screenRatio != 1) {
@ -96,9 +99,9 @@ PlayerListDialog::PlayerListDialog(QStringList players, ProfileDatabase *profile
ui->cmdMakeAd->setIconSize(iconSize);
}
#endif
ui->cmdMakeAv->setIcon(QIcon(AppEnv::getImagesFolder() % "/back.svgz"));
ui->cmdMakeSe->setIcon(QIcon(AppEnv::getImagesFolder() % "/next.svgz"));
ui->cmdMakeAd->setIcon(QIcon(AppEnv::getImagesFolder() % "/add.svgz"));
ui->cmdMakeAv->setIcon(QIcon(":/img/back.svgz"));
ui->cmdMakeSe->setIcon(QIcon(":/img/next.svgz"));
ui->cmdMakeAd->setIcon(QIcon(":/img/add.svgz"));
}
buildInterface();
@ -109,10 +112,12 @@ PlayerListDialog::PlayerListDialog(QStringList players, ProfileDatabase *profile
PlayerListDialog::~PlayerListDialog()
{
for (QObject *object : ui->listAvPlayers->children()) {
for (QObject *object : ui->listAvPlayers->children())
{
delete object;
}
for (QObject *object : ui->listSePlayers->children()) {
for (QObject *object : ui->listSePlayers->children())
{
delete object;
}
delete ui;
@ -126,13 +131,16 @@ void PlayerListDialog::on_cmdCancel_clicked()
void PlayerListDialog::buildInterface()
{
const QStringList dbPlayers = profileDB->getPlayers();
for (const QString &sePlayer : qAsConst(players)) {
for (QString sePlayer : players)
{
QListWidgetItem *playerItem = new QListWidgetItem(profileDB->getPlayerName(sePlayer));
playerItem->setData(Qt::UserRole, sePlayer);
ui->listSePlayers->addItem(playerItem);
}
for (const QString &dbPlayer : dbPlayers) {
if (!players.contains(dbPlayer)) {
for (QString dbPlayer : dbPlayers)
{
if (!players.contains(dbPlayer))
{
QListWidgetItem *playerItem = new QListWidgetItem(profileDB->getPlayerName(dbPlayer));
playerItem->setData(Qt::UserRole, dbPlayer);
ui->listAvPlayers->addItem(playerItem);
@ -143,7 +151,8 @@ void PlayerListDialog::buildInterface()
void PlayerListDialog::on_cmdMakeAv_clicked()
{
for (QListWidgetItem *item : ui->listSePlayers->selectedItems()) {
for (QListWidgetItem *item : ui->listSePlayers->selectedItems())
{
QString playerName = item->text();
int playerID = item->data(Qt::UserRole).toInt();
delete item;
@ -157,11 +166,13 @@ void PlayerListDialog::on_cmdMakeAv_clicked()
void PlayerListDialog::on_cmdMakeSe_clicked()
{
int maxPlayers = 30;
if (maxPlayers < ui->listSePlayers->count() + ui->listAvPlayers->selectedItems().count()) {
if (maxPlayers < ui->listSePlayers->count() + ui->listAvPlayers->selectedItems().count())
{
QMessageBox::warning(this, tr("Add Players..."), tr("Failed to add more Players because the limit of Players are %1!").arg(QString::number(maxPlayers)));
return;
}
for (QListWidgetItem *item : ui->listAvPlayers->selectedItems()) {
for (QListWidgetItem *item : ui->listAvPlayers->selectedItems())
{
QString playerName = item->text();
int playerID = item->data(Qt::UserRole).toInt();
delete item;
@ -175,12 +186,15 @@ void PlayerListDialog::on_cmdMakeAd_clicked()
{
bool playerOk;
int playerID = QInputDialog::getInt(this, tr("Add Player..."), tr("Enter Social Club Player ID"), 1, 1, 214783647, 1, &playerOk, windowFlags());
if (playerOk) {
for (int i = 0; i < ui->listAvPlayers->count(); ++i) {
if (playerOk)
{
for (int i = 0; i < ui->listAvPlayers->count(); ++i)
{
QListWidgetItem *item = ui->listAvPlayers->item(i);
QString itemPlayerName = item->text();
int itemPlayerID = item->data(Qt::UserRole).toInt();
if (itemPlayerID == playerID) {
if (itemPlayerID == playerID)
{
delete item;
QListWidgetItem *playerItem = new QListWidgetItem(itemPlayerName);
playerItem->setData(Qt::UserRole, playerID);
@ -188,7 +202,8 @@ void PlayerListDialog::on_cmdMakeAd_clicked()
return;
}
}
for (int i = 0; i < ui->listSePlayers->count(); ++i) {
for (int i = 0; i < ui->listSePlayers->count(); ++i)
{
QListWidgetItem *item = ui->listSePlayers->item(i);
int itemPlayerID = item->data(Qt::UserRole).toInt();
if (itemPlayerID == playerID)
@ -206,7 +221,8 @@ void PlayerListDialog::on_cmdMakeAd_clicked()
void PlayerListDialog::on_cmdApply_clicked()
{
players.clear();
for (int i = 0; i < ui->listSePlayers->count(); ++i) {
for (int i = 0; i < ui->listSePlayers->count(); ++i)
{
players += ui->listSePlayers->item(i)->data(Qt::UserRole).toString();
}
emit playerListUpdated(players);

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -30,7 +30,6 @@
#include "SavegameData.h"
#include "CrewDatabase.h"
#include "pcg_basic.h"
#include <QFileSystemWatcher>
#include <QProgressDialog>
#include <QSpacerItem>
#include <QDateTime>
@ -53,6 +52,8 @@ public:
void settingsApplied(int contentMode, bool languageChanged);
void setupProfileInterface();
void massTool(MassTool tool);
void disableSelected();
void enableSelected();
int selectedWidgets();
void retranslateUi();
~ProfileInterface();
@ -63,11 +64,8 @@ public slots:
void hoverProfileWidgetCheck();
void selectAllWidgets();
void deselectAllWidgets();
void disableSelected();
void enableSelected();
void exportSelected();
void deleteSelected();
void deleteSelectedR();
void updatePalette();
void importFiles();
@ -83,17 +81,9 @@ private slots:
void profileLoaded_p();
void profileWidgetSelected();
void profileWidgetDeselected();
void massToolQualify();
void massToolPlayers();
void massToolCrew();
void massToolTitle();
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);
@ -109,11 +99,6 @@ private:
QList<SavegameData*> savegames;
QList<SnapmaticPicture*> pictures;
QMap<ProfileWidget*,QString> widgets;
#if QT_VERSION >= 0x050000
QFileSystemWatcher fileSystemWatcher;
QVector<QString> savegameFiles;
QVector<QString> snapmaticPics;
#endif
QSpacerItem *saSpacerItem;
QStringList fixedPictures;
QString enabledPicStr;
@ -139,7 +124,6 @@ private:
void savegameLoaded(SavegameData *savegame, QString savegamePath, bool inserted);
void savegameDeleted(SavegameWidget *sgdWidget, bool isRemoteEmited = false);
void pictureDeleted(SnapmaticWidget *picWidget, bool isRemoteEmited = false);
void deleteSelectedL(bool isRemoteEmited = false);
void insertSnapmaticIPI(QWidget *widget);
void insertSavegameIPI(QWidget *widget);
void sortingProfileInterface();

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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,99 +16,80 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include "SnapmaticPicture.h"
#include "ProfileLoader.h"
#include "SnapmaticPicture.h"
#include "SavegameData.h"
#include "CrewDatabase.h"
#include "wrapper.h"
#include <QStringBuilder>
#include <QVector>
#include <QStringList>
#include <QString>
#include <QFile>
#ifdef Q_OS_WIN
#include <QDir>
#include <QThread>
#include <QList>
#else
#include "sys/types.h"
#include "sys/stat.h"
#include "dirent.h"
#endif
#include <QFile>
#include <QDir>
ProfileLoader::ProfileLoader(QString profileFolder, CrewDatabase *crewDB, QObject *parent) : QThread(parent), profileFolder(profileFolder), crewDB(crewDB)
{
}
void ProfileLoader::run()
{
int curFile = 1;
int maximumV = 0;
QVector<int> crewList;
QVector<QString> savegameFiles;
QVector<QString> snapmaticPics;
QDir profileDir;
QList<int> crewList;
profileDir.setPath(profileFolder);
#ifdef Q_OS_WIN
QDir dir(profileFolder);
const QStringList files = dir.entryList(QDir::Files);
for (const QString &fileName : files) {
if (fileName.startsWith("SGTA5") && !fileName.endsWith(".bak")) {
savegameFiles << fileName;
maximumV++;
}
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
// Seek pictures and savegames
profileDir.setNameFilters(QStringList("SGTA*"));
QStringList SavegameFiles = profileDir.entryList(QDir::Files | QDir::NoDot, QDir::NoSort);
QStringList BackupFiles = SavegameFiles.filter(".bak", Qt::CaseInsensitive);
profileDir.setNameFilters(QStringList("PGTA*"));
QStringList SnapmaticPics = profileDir.entryList(QDir::Files | QDir::NoDot, QDir::NoSort);
BackupFiles += SnapmaticPics.filter(".bak", Qt::CaseInsensitive);
// Directory successfully scanned
emit directoryScanned(savegameFiles, snapmaticPics);
SavegameFiles.removeDuplicates();
SnapmaticPics.removeDuplicates();
for (QString BackupFile : BackupFiles)
{
SavegameFiles.removeAll(BackupFile);
SnapmaticPics.removeAll(BackupFile);
}
int maximumV = SavegameFiles.length() + SnapmaticPics.length();
// Loading pictures and savegames
emit loadingProgress(curFile, maximumV);
for (const QString &SavegameFile : qAsConst(savegameFiles)) {
for (QString SavegameFile : SavegameFiles)
{
emit loadingProgress(curFile, maximumV);
const QString sgdPath = profileFolder % "/" % SavegameFile;
QString sgdPath = profileFolder % "/" % SavegameFile;
SavegameData *savegame = new SavegameData(sgdPath);
if (savegame->readingSavegame()) {
if (savegame->readingSavegame())
{
emit savegameLoaded(savegame, sgdPath);
}
curFile++;
}
for (const QString &SnapmaticPic : qAsConst(snapmaticPics)) {
for (QString SnapmaticPic : SnapmaticPics)
{
emit loadingProgress(curFile, maximumV);
const QString picturePath = profileFolder % "/" % SnapmaticPic;
QString picturePath = profileFolder % "/" % SnapmaticPic;
SnapmaticPicture *picture = new SnapmaticPicture(picturePath);
if (picture->readingPicture(true)) {
if (picture->isFormatSwitched()) {
if (picture->readingPicture(true, true, true))
{
if (picture->isFormatSwitched())
{
picture->setSnapmaticFormat(SnapmaticFormat::PGTA_Format);
if (picture->exportPicture(picturePath, SnapmaticFormat::PGTA_Format)) {
if (picture->exportPicture(picturePath, SnapmaticFormat::PGTA_Format))
{
emit pictureFixed(picture);
}
}
emit pictureLoaded(picture);
int crewNumber = picture->getSnapmaticProperties().crewID;
if (!crewList.contains(crewNumber)) {
if (!crewList.contains(crewNumber))
{
crewList += crewNumber;
}
}
@ -117,7 +98,8 @@ void ProfileLoader::run()
// adding found crews
crewDB->setAddingCrews(true);
for (int crewID : qAsConst(crewList)) {
for (int crewID : crewList)
{
crewDB->addCrew(crewID);
}
crewDB->setAddingCrews(false);
@ -125,9 +107,10 @@ void ProfileLoader::run()
void ProfileLoader::preloaded()
{
}
void ProfileLoader::loaded()
{
}
}

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -48,7 +48,6 @@ signals:
void pictureFixed(SnapmaticPicture *picture);
void savegameLoaded(SavegameData *savegame, QString savegamePath);
void loadingProgress(int value, int maximum);
void directoryScanned(QVector<QString> savegameFiles, QVector<QString> snapmaticPics);
};
#endif // PROFILELOADER_H

View File

@ -1,5 +1,5 @@
## gta5view
Open Source Snapmatic and Savegame viewer/editor for GTA V
Grand Theft Auto V Savegame and Snapmatic viewer/editor
- View Snapmatics with the ability to disable them in-game
- Edit Snapmatic pictures and properties in multiple ways
@ -14,32 +14,40 @@ Open Source Snapmatic and Savegame viewer/editor for GTA V
#### Build gta5view for Windows
# Note: Install Docker Community Edition and Git before continuing
docker pull sypingauto/gta5view-build:1.10-static
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
git clone https://gitlab.com/Syping/gta5view && cd gta5view
docker pull sypingauto/gta5view-build:1.8-static
docker run --rm -v ${PWD}:/gta5view -it sypingauto/gta5view-build:1.8-static
cd /gta5view && mkdir -p build && cd build
mingw64-qt-cmake ../
make -j $(nproc --all)
#### Build gta5view for Debian/Ubuntu
sudo apt-get install cmake git gcc g++ libqt5svg5-dev make qtbase5-dev qttranslations5-l10n
git clone https://gitlab.com/Syping/gta5view
cmake -B gta5view-build gta5view
cmake --build gta5view-build
sudo cmake --install gta5view-build
git clone https://gitlab.com/Syping/gta5view && cd gta5view
mkdir -p build && cd build
cmake ../
make -j $(nproc --all)
sudo make install
#### Build gta5view for Arch/Manjaro
sudo pacman -S cmake gcc git make qt5-base qt5-svg qt5-tools qt5-translations
git clone https://gitlab.com/Syping/gta5view
cmake -B gta5view-build gta5view
cmake --build gta5view-build
sudo cmake --install gta5view-build
git clone https://gitlab.com/Syping/gta5view && cd gta5view
mkdir -p build && cd build
cmake ../
make -j $(nproc --all)
sudo make install
#### Build gta5view for Fedora/RHEL
#### Build gta5view for Fedora
sudo dnf install cmake git gcc gcc-c++ make qt5-qtbase-devel qt5-qtsvg-devel qt5-qttranslations
git clone https://gitlab.com/Syping/gta5view
cmake -B gta5view-build gta5view
cmake --build gta5view-build
sudo cmake --install gta5view-build
git clone https://gitlab.com/Syping/gta5view && cd gta5view
mkdir -p build && cd build
cmake ../
make -j $(nproc --all)
sudo make install
#### Download Binary Releases
Go to [gta5view release](https://github.com/SyDevTeam/gta5view/releases) and download the .exe file for Windows, .deb file for Debian/Ubuntu and .dmg file for OS X.

View File

@ -1,893 +0,0 @@
/*****************************************************************************
* 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
}

View File

@ -1,110 +0,0 @@
/*****************************************************************************
* 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

View File

@ -28,11 +28,7 @@ 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);

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>400</width>
<height>112</height>
<height>105</height>
</rect>
</property>
<property name="windowTitle">
@ -20,7 +20,7 @@
<item>
<widget class="QLabel" name="labSavegameText">
<property name="text">
<string>&lt;span style=&quot;font-weight:600&quot;&gt;Savegame&lt;/span&gt;&lt;br&gt;&lt;br&gt;%1</string>
<string>&lt;span style=&quot; font-weight:600;&quot;&gt;Savegame&lt;/span&gt;&lt;br&gt;&lt;br&gt;%1</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -25,7 +25,6 @@
#include "SavegameCopy.h"
#include "AppEnv.h"
#include "config.h"
#include <QStringBuilder>
#include <QFileDialog>
#include <QMessageBox>
#include <QSettings>
@ -60,7 +59,7 @@ SavegameWidget::SavegameWidget(QWidget *parent) :
ui->labSavegamePic->setFixedSize(48 * screenRatio, 27 * screenRatio);
ui->labSavegamePic->setScaledContents(true);
ui->labSavegamePic->setPixmap(QPixmap(AppEnv::getImagesFolder() % "/savegame.svgz"));
ui->labSavegamePic->setPixmap(QPixmap(":/img/savegame.svgz"));
QString exportSavegameStr = tr("Export Savegame...");
Q_UNUSED(exportSavegameStr)
@ -153,11 +152,7 @@ void SavegameWidget::on_cmdDelete_clicked()
QJsonObject jsonObject;
jsonObject["Type"] = "DeleteSuccess";
jsonObject["ExtraFlags"] = "Savegame";
#if QT_VERSION >= 0x060000
jsonObject["DeletedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
#else
jsonObject["DeletedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
#endif
jsonDocument.setObject(jsonObject);
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
}
@ -176,11 +171,7 @@ void SavegameWidget::on_cmdDelete_clicked()
QJsonObject jsonObject;
jsonObject["Type"] = "DeleteSuccess";
jsonObject["ExtraFlags"] = "Savegame";
#if QT_VERSION >= 0x060000
jsonObject["DeletedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
#else
jsonObject["DeletedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
#endif
jsonDocument.setObject(jsonObject);
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
}
@ -226,8 +217,7 @@ void SavegameWidget::mouseReleaseEvent(QMouseEvent *ev)
}
else
{
const int contentMode = getContentMode();
if ((contentMode == 0 || contentMode == 10 || contentMode == 20) && rect().contains(ev->pos()) && ev->button() == Qt::LeftButton)
if (getContentMode() == 0 && rect().contains(ev->pos()) && ev->button() == Qt::LeftButton)
{
if (ev->modifiers().testFlag(Qt::ShiftModifier))
{
@ -238,7 +228,7 @@ void SavegameWidget::mouseReleaseEvent(QMouseEvent *ev)
on_cmdView_clicked();
}
}
else if (!ui->cbSelected->isVisible() && (contentMode == 1 || contentMode == 11 || contentMode == 21) && ev->button() == Qt::LeftButton && ev->modifiers().testFlag(Qt::ShiftModifier))
else if (!ui->cbSelected->isVisible() && getContentMode() == 1 && ev->button() == Qt::LeftButton && ev->modifiers().testFlag(Qt::ShiftModifier))
{
ui->cbSelected->setChecked(!ui->cbSelected->isChecked());
}
@ -249,8 +239,7 @@ void SavegameWidget::mouseDoubleClickEvent(QMouseEvent *ev)
{
ProfileWidget::mouseDoubleClickEvent(ev);
const int contentMode = getContentMode();
if (!ui->cbSelected->isVisible() && (contentMode == 1 || contentMode == 11 || contentMode == 21) && ev->button() == Qt::LeftButton)
if (!ui->cbSelected->isVisible() && getContentMode() == 1 && ev->button() == Qt::LeftButton)
{
on_cmdView_clicked();
}

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -21,7 +21,6 @@
#include "SnapmaticPicture.h"
#include "PlayerListDialog.h"
#include "StringParser.h"
#include "wrapper.h"
#include "AppEnv.h"
#include "config.h"
#include <QStringBuilder>
@ -42,38 +41,41 @@ 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);
ui->cmdCancel->setFocus();
// Set Icon for Apply Button
if (QIcon::hasThemeIcon("dialog-ok-apply")) {
if (QIcon::hasThemeIcon("dialog-ok-apply"))
{
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-ok-apply"));
}
else if (QIcon::hasThemeIcon("dialog-apply")) {
else if (QIcon::hasThemeIcon("dialog-apply"))
{
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-apply"));
}
else if (QIcon::hasThemeIcon("gtk-apply")) {
else if (QIcon::hasThemeIcon("gtk-apply"))
{
ui->cmdApply->setIcon(QIcon::fromTheme("gtk-apply"));
}
else if (QIcon::hasThemeIcon("dialog-ok")) {
else if (QIcon::hasThemeIcon("dialog-ok"))
{
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-ok"));
}
else if (QIcon::hasThemeIcon("gtk-ok")) {
else if (QIcon::hasThemeIcon("gtk-ok"))
{
ui->cmdApply->setIcon(QIcon::fromTheme("dialog-ok"));
}
// Set Icon for Cancel Button
if (QIcon::hasThemeIcon("dialog-cancel")) {
if (QIcon::hasThemeIcon("dialog-cancel"))
{
ui->cmdCancel->setIcon(QIcon::fromTheme("dialog-cancel"));
}
else if (QIcon::hasThemeIcon("gtk-cancel")) {
else if (QIcon::hasThemeIcon("gtk-cancel"))
{
ui->cmdCancel->setIcon(QIcon::fromTheme("gtk-cancel"));
}
@ -94,18 +96,27 @@ SnapmaticEditor::~SnapmaticEditor()
void SnapmaticEditor::selfie_toggled(bool checked)
{
isSelfie = checked;
if (checked)
{
isSelfie = true;
}
else
{
isSelfie = false;
}
}
void SnapmaticEditor::mugshot_toggled(bool checked)
{
if (checked) {
if (checked)
{
isMugshot = true;
ui->cbDirector->setEnabled(false);
ui->cbDirector->setChecked(false);
}
else {
else
{
isMugshot = false;
ui->cbDirector->setEnabled(true);
}
@ -113,12 +124,14 @@ void SnapmaticEditor::mugshot_toggled(bool checked)
void SnapmaticEditor::editor_toggled(bool checked)
{
if (checked) {
if (checked)
{
isEditor = true;
ui->cbDirector->setEnabled(false);
ui->cbDirector->setChecked(false);
}
else {
else
{
isEditor = false;
ui->cbDirector->setEnabled(true);
}
@ -126,7 +139,8 @@ void SnapmaticEditor::editor_toggled(bool checked)
void SnapmaticEditor::on_rbSelfie_toggled(bool checked)
{
if (checked) {
if (checked)
{
mugshot_toggled(false);
editor_toggled(false);
selfie_toggled(true);
@ -135,7 +149,8 @@ void SnapmaticEditor::on_rbSelfie_toggled(bool checked)
void SnapmaticEditor::on_rbMugshot_toggled(bool checked)
{
if (checked) {
if (checked)
{
selfie_toggled(false);
editor_toggled(false);
mugshot_toggled(true);
@ -144,7 +159,8 @@ void SnapmaticEditor::on_rbMugshot_toggled(bool checked)
void SnapmaticEditor::on_rbEditor_toggled(bool checked)
{
if (checked) {
if (checked)
{
selfie_toggled(false);
mugshot_toggled(false);
editor_toggled(true);
@ -153,7 +169,8 @@ void SnapmaticEditor::on_rbEditor_toggled(bool checked)
void SnapmaticEditor::on_rbCustom_toggled(bool checked)
{
if (checked) {
if (checked)
{
selfie_toggled(false);
mugshot_toggled(false);
editor_toggled(false);
@ -172,16 +189,20 @@ void SnapmaticEditor::setSnapmaticPicture(SnapmaticPicture *picture)
playersList = snapmaticProperties.playersList;
ui->cbDirector->setChecked(snapmaticProperties.isFromDirector);
ui->cbMeme->setChecked(snapmaticProperties.isMeme);
if (isSelfie) {
if (isSelfie)
{
ui->rbSelfie->setChecked(true);
}
else if (isMugshot) {
else if (isMugshot)
{
ui->rbMugshot->setChecked(true);
}
else if (isEditor) {
else if (isEditor)
{
ui->rbEditor->setChecked(true);
}
else {
else
{
ui->rbCustom->setChecked(true);
}
setSnapmaticCrew(returnCrewName(crewID));
@ -191,7 +212,8 @@ void SnapmaticEditor::setSnapmaticPicture(SnapmaticPicture *picture)
void SnapmaticEditor::insertPlayerNames(QStringList *players)
{
for (int i = 0; i < players->size(); ++i) {
for (int i = 0; i < players->size(); ++i)
{
players->replace(i, profileDB->getPlayerName(players->at(i)));
}
}
@ -207,48 +229,54 @@ void SnapmaticEditor::setSnapmaticPlayers(const QStringList &players)
{
QString editStr = QString("<a href=\"g5e://editplayers\" style=\"text-decoration: none;\">%1</a>").arg(tr("Edit"));
QString playersStr;
if (players.length() != 1) {
if (players.length() != 1)
{
playersStr = tr("Players: %1 (%2)", "Multiple Player are inserted here");
}
else {
else
{
playersStr = tr("Player: %1 (%2)", "One Player is inserted here");
}
if (players.length() != 0) {
if (players.length() != 0)
{
ui->labPlayers->setText(playersStr.arg(players.join(", "), editStr));
}
else {
else
{
ui->labPlayers->setText(playersStr.arg(QApplication::translate("PictureDialog", "No Players"), editStr));
}
#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()));
if (heightForWidth(width()) > height()) { resize(width(), heightForWidth(width())); }
#endif
}
void SnapmaticEditor::setSnapmaticTitle(const QString &title)
{
if (title.length() > 39) {
if (title.length() > 39)
{
snapmaticTitle = title.left(39);
}
else {
else
{
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(StringParser::escapeString(snapmaticTitle), editStr);
ui->labTitle->setText(titleStr);
if (SnapmaticPicture::verifyTitle(snapmaticTitle)) {
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"))));
}
else {
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()));
if (heightForWidth(width()) > height()) { resize(width(), heightForWidth(width())); }
#endif
}
@ -260,8 +288,7 @@ void SnapmaticEditor::setSnapmaticCrew(const QString &crew)
#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()));
if (heightForWidth(width()) > height()) { resize(width(), heightForWidth(width())); }
#endif
}
@ -277,7 +304,8 @@ void SnapmaticEditor::on_cmdCancel_clicked()
void SnapmaticEditor::on_cmdApply_clicked()
{
if (ui->cbQualify->isChecked()) {
if (ui->cbQualify->isChecked())
{
qualifyAvatar();
}
snapmaticProperties.crewID = crewID;
@ -287,23 +315,27 @@ void SnapmaticEditor::on_cmdApply_clicked()
snapmaticProperties.isFromDirector = ui->cbDirector->isChecked();
snapmaticProperties.isMeme = ui->cbMeme->isChecked();
snapmaticProperties.playersList = playersList;
if (smpic) {
if (smpic)
{
QString currentFilePath = smpic->getPictureFilePath();
QString originalFilePath = smpic->getOriginalPictureFilePath();
QString backupFileName = originalFilePath % ".bak";
if (!QFile::exists(backupFileName)) {
if (!QFile::exists(backupFileName))
{
QFile::copy(currentFilePath, backupFileName);
}
SnapmaticProperties fallbackProperties = smpic->getSnapmaticProperties();
QString fallbackTitle = smpic->getPictureTitle();
smpic->setSnapmaticProperties(snapmaticProperties);
smpic->setPictureTitle(snapmaticTitle);
if (!smpic->exportPicture(currentFilePath)) {
if (!smpic->exportPicture(currentFilePath))
{
QMessageBox::warning(this, tr("Snapmatic Properties"), tr("Patching of Snapmatic Properties failed because of I/O Error"));
smpic->setSnapmaticProperties(fallbackProperties);
smpic->setPictureTitle(fallbackTitle);
}
else {
else
{
smpic->updateStrings();
smpic->emitUpdate();
#ifdef GTA5SYNC_TELEMETRY
@ -311,16 +343,13 @@ void SnapmaticEditor::on_cmdApply_clicked()
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"] = "PropertyEdited";
jsonObject["EditedSize"] = QString::number(smpic->getContentMaxLength());
#if QT_VERSION >= 0x060000
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
#else
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
#endif
jsonDocument.setObject(jsonObject);
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
}
@ -340,7 +369,8 @@ void SnapmaticEditor::qualifyAvatar()
void SnapmaticEditor::on_cbQualify_toggled(bool checked)
{
if (checked) {
if (checked)
{
ui->cbMeme->setEnabled(false);
ui->cbDirector->setEnabled(false);
ui->rbCustom->setEnabled(false);
@ -348,13 +378,15 @@ void SnapmaticEditor::on_cbQualify_toggled(bool checked)
ui->rbEditor->setEnabled(false);
ui->rbMugshot->setEnabled(false);
}
else {
else
{
ui->cbMeme->setEnabled(true);
ui->rbCustom->setEnabled(true);
ui->rbSelfie->setEnabled(true);
ui->rbEditor->setEnabled(true);
ui->rbMugshot->setEnabled(true);
if (ui->rbSelfie->isChecked() || ui->rbCustom->isChecked()) {
if (ui->rbSelfie->isChecked() || ui->rbCustom->isChecked())
{
ui->cbDirector->setEnabled(true);
}
}
@ -362,7 +394,8 @@ void SnapmaticEditor::on_cbQualify_toggled(bool checked)
void SnapmaticEditor::on_labPlayers_linkActivated(const QString &link)
{
if (link == "g5e://editplayers") {
if (link == "g5e://editplayers")
{
PlayerListDialog *playerListDialog = new PlayerListDialog(playersList, profileDB, this);
connect(playerListDialog, SIGNAL(playerListUpdated(QStringList)), this, SLOT(playerListUpdated(QStringList)));
playerListDialog->setModal(true);
@ -374,10 +407,12 @@ void SnapmaticEditor::on_labPlayers_linkActivated(const QString &link)
void SnapmaticEditor::on_labTitle_linkActivated(const QString &link)
{
if (link == "g5e://edittitle") {
if (link == "g5e://edittitle")
{
bool ok;
QString newTitle = QInputDialog::getText(this, tr("Snapmatic Title"), tr("New Snapmatic title:"), QLineEdit::Normal, snapmaticTitle, &ok, windowFlags());
if (ok && !newTitle.isEmpty()) {
if (ok && !newTitle.isEmpty())
{
setSnapmaticTitle(newTitle);
}
}
@ -385,33 +420,39 @@ void SnapmaticEditor::on_labTitle_linkActivated(const QString &link)
void SnapmaticEditor::on_labCrew_linkActivated(const QString &link)
{
if (link == "g5e://editcrew") {
if (link == "g5e://editcrew")
{
bool ok;
int indexNum = 0;
QStringList itemList;
QStringList crewList = crewDB->getCrews();
if (!crewList.contains(QLatin1String("0"))) {
if (!crewList.contains(QLatin1String("0")))
{
crewList += QLatin1String("0");
}
crewList.sort();
for (const QString &crew : crewList) {
for (QString crew : crewList)
{
itemList += QString("%1 (%2)").arg(crew, returnCrewName(crew.toInt()));
}
if (crewList.contains(QString::number(crewID))) {
if (crewList.contains(QString::number(crewID)))
{
indexNum = crewList.indexOf(QString::number(crewID));
}
QString newCrew = QInputDialog::getItem(this, tr("Snapmatic Crew"), tr("New Snapmatic crew:"), itemList, indexNum, true, &ok, windowFlags());
if (ok && !newCrew.isEmpty()) {
if (newCrew.contains(" "))
newCrew = newCrew.split(" ").at(0);
if (newCrew.length() > 10)
return;
for (const QChar &crewChar : qAsConst(newCrew)) {
if (!crewChar.isNumber()) {
if (ok && !newCrew.isEmpty())
{
if (newCrew.contains(" ")) newCrew = newCrew.split(" ").at(0);
if (newCrew.length() > 10) return;
for (QChar crewChar : newCrew)
{
if (!crewChar.isNumber())
{
return;
}
}
if (!crewList.contains(newCrew)) {
if (!crewList.contains(newCrew))
{
crewDB->addCrew(crewID);
}
crewID = newCrew.toInt();

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5spv Grand Theft Auto Snapmatic Picture Viewer
* Copyright (C) 2016-2020 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
@ -19,7 +19,6 @@
#ifndef SNAPMATICPICTURE_H
#define SNAPMATICPICTURE_H
#include "RagePhoto.h"
#include <QStringList>
#include <QDateTime>
#include <QObject>
@ -35,7 +34,6 @@ struct SnapmaticProperties {
double x;
double y;
double z;
bool isCayoPerico;
};
int uid;
int crewID;
@ -59,15 +57,17 @@ public:
~SnapmaticPicture();
void reset();
bool preloadFile();
bool readingPictureFromFile(const QString &fileName, bool cacheEnabled = false);
bool readingPicture(bool cacheEnabled = false);
bool readingPictureFromFile(const QString &fileName, bool writeEnabled = true, bool cacheEnabled = false, bool fastLoad = true, bool lowRamMode = false);
bool readingPicture(bool writeEnabled = true, bool cacheEnabled = false, bool fastLoad = true, bool lowRamMode = false);
bool isPicOk(); // Please use isPictureOk instead
void clearCache();
QImage getImage();
QImage getImage(bool fastLoad = false);
QByteArray getPictureStream();
QString getLastStep(bool readable = true);
QString getPictureStr();
QString getPictureHead();
QString getPictureTitl();
QString getPictureDesc();
QString getPictureSortStr();
QString getPictureFileName();
QString getPictureFilePath();
@ -75,7 +75,7 @@ public:
QString getOriginalPictureFileName();
QString getOriginalPictureFilePath();
int getContentMaxLength();
bool setImage(const QImage &picture, bool eXtendMode = false);
bool setImage(const QImage &picture);
bool setPictureTitl(const QString &newTitle); // Please use setPictureTitle instead
bool setPictureStream(const QByteArray &streamArray);
void updateStrings();
@ -106,6 +106,7 @@ public:
QString getPictureJson() { return getJsonStr(); }
QString getPictureTitle() { return getPictureTitl(); }
QString getPictureString() { return getPictureStr(); }
QString getPictureDescription() { return getPictureDesc(); }
bool setJsonString(const QString &jsonString, bool updateProperties = false) { return setJsonStr(jsonString, updateProperties); } // Please use setPictureJson instead
bool setPictureJson(const QString &json, bool updateProperties = false) { return setJsonStr(json, updateProperties); }
bool setPictureTitle(const QString &title) { return setPictureTitl(title); }
@ -121,6 +122,10 @@ public:
// PREDEFINED PROPERTIES
static QSize getSnapmaticResolution();
// SNAPMATIC DEFAULTS
bool isSnapmaticDefaultsEnforced();
void setSnapmaticDefaultsEnforced(bool enforced);
// SNAPMATIC FORMAT
SnapmaticFormat getSnapmaticFormat();
void setSnapmaticFormat(SnapmaticFormat format);
@ -134,32 +139,44 @@ public:
static QString convertDrawStringForLog(const QString &inputStr);
static QString convertLogStringForDraw(const QString &inputStr);
// RAGEPHOTO
RagePhoto* ragePhoto();
private:
QString getSnapmaticHeaderString(const QByteArray &snapmaticHeader);
QString getSnapmaticJSONString(const QByteArray &jsonBytes);
QString getSnapmaticTIDEString(const QByteArray &tideBytes);
QImage cachePicture;
QString picExportFileName;
QString picFileName;
QString picFilePath;
QString pictureHead;
QString pictureStr;
QString lastStep;
QString sortStr;
QString titlStr;
QString descStr;
bool picOk;
bool lowRamMode;
bool writeEnabled;
bool cacheEnabled;
bool isLoadedInRAM;
bool isCustomFormat;
bool isFormatSwitch;
bool isModernFormat;
bool careSnapDefault;
int jpegRawContentSize;
int jpegRawContentSizeE;
// PICTURE STREAM
QByteArray rawPicContent;
// JSON
void parseJsonContent();
bool jsonOk;
QString jsonStr;
SnapmaticProperties localProperties;
// VERIFY CONTENT
static bool verifyTitleChar(const QChar &titleChar);
// RAGEPHOTO
RagePhoto p_ragePhoto;
signals:
void customSignal(QString signal);
void preloaded();

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -31,9 +31,9 @@
#include "config.h"
#include <QStringBuilder>
#include <QMessageBox>
#include <QPainter>
#include <QPixmap>
#include <QTimer>
#include <QDebug>
#include <QMenu>
#include <QFile>
@ -76,33 +76,19 @@ void SnapmaticWidget::setSnapmaticPicture(SnapmaticPicture *picture)
QObject::connect(picture, SIGNAL(updated()), this, SLOT(snapmaticUpdated()));
QObject::connect(picture, SIGNAL(customSignal(QString)), this, SLOT(customSignal(QString)));
const qreal screenRatio = AppEnv::screenRatio();
const qreal screenRatioPR = AppEnv::screenRatioPR();
const QSize renderResolution(48 * screenRatio * screenRatioPR, 27 * screenRatio * screenRatioPR);
qreal screenRatio = AppEnv::screenRatio();
qreal screenRatioPR = AppEnv::screenRatioPR();
ui->labPicture->setFixedSize(48 * screenRatio, 27 * screenRatio);
ui->labPicture->setScaledContents(true);
QPixmap renderPixmap(renderResolution);
renderPixmap.fill(Qt::transparent);
QPainter renderPainter(&renderPixmap);
const QImage originalImage = picture->getImage();
const QImage renderImage = originalImage.scaled(renderResolution, Qt::KeepAspectRatio, Qt::SmoothTransformation); // Stack smash
if (renderImage.width() < renderResolution.width()) {
renderPainter.drawImage((renderResolution.width() - renderImage.width()) / 2, 0, renderImage, Qt::AutoColor);
}
else if (renderImage.height() < renderResolution.height()) {
renderPainter.drawImage(0, (renderResolution.height() - renderImage.height()) / 2, renderImage, Qt::AutoColor);
}
else {
renderPainter.drawImage(0, 0, renderImage, Qt::AutoColor);
}
renderPainter.end();
QPixmap SnapmaticPixmap = QPixmap::fromImage(picture->getImage().scaled(ui->labPicture->width() * screenRatioPR, ui->labPicture->height() * screenRatioPR, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::AutoColor);
#if QT_VERSION >= 0x050600
renderPixmap.setDevicePixelRatio(screenRatioPR);
SnapmaticPixmap.setDevicePixelRatio(screenRatioPR);
#endif
ui->labPicStr->setText(smpic->getPictureStr() % "\n" % smpic->getPictureTitl());
ui->labPicture->setPixmap(renderPixmap);
ui->labPicture->setPixmap(SnapmaticPixmap);
picture->clearCache();
@ -116,7 +102,8 @@ void SnapmaticWidget::snapmaticUpdated()
void SnapmaticWidget::customSignal(QString signal)
{
if (signal == "PictureUpdated") {
if (signal == "PictureUpdated")
{
QPixmap SnapmaticPixmap = QPixmap::fromImage(smpic->getImage().scaled(ui->labPicture->width(), ui->labPicture->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::AutoColor);
ui->labPicture->setPixmap(SnapmaticPixmap);
}
@ -146,8 +133,7 @@ void SnapmaticWidget::on_cmdView_clicked()
QObject::connect(picDialog, SIGNAL(previousPictureRequested()), this, SLOT(dialogPreviousPictureRequested()));
// add previous next buttons
if (navigationBar)
picDialog->addPreviousNextButtons();
if (navigationBar) picDialog->addPreviousNextButtons();
// show picture dialog
#ifdef Q_OS_ANDROID
@ -176,38 +162,37 @@ void SnapmaticWidget::on_cmdExport_clicked()
void SnapmaticWidget::on_cmdDelete_clicked()
{
if (deletePicture())
emit pictureDeleted();
if (deletePicture()) emit pictureDeleted();
}
bool SnapmaticWidget::deletePicture()
{
int uchoice = QMessageBox::question(this, tr("Delete picture"), tr("Are you sure to delete %1 from your Snapmatic pictures?").arg("\""+smpic->getPictureTitle()+"\""), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (uchoice == QMessageBox::Yes) {
if (smpic->deletePictureFile()) {
if (uchoice == QMessageBox::Yes)
{
if (smpic->deletePictureFile())
{
#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";
jsonObject["ExtraFlags"] = "Snapmatic";
jsonObject["DeletedSize"] = QString::number(smpic->getContentMaxLength());
#if QT_VERSION >= 0x060000
jsonObject["DeletedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
#else
jsonObject["DeletedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
#endif
jsonDocument.setObject(jsonObject);
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
}
#endif
return true;
}
else {
else
{
QMessageBox::warning(this, tr("Delete picture"), tr("Failed at deleting %1 from your Snapmatic pictures").arg("\""+smpic->getPictureTitle()+"\""));
}
}
@ -222,22 +207,28 @@ void SnapmaticWidget::mousePressEvent(QMouseEvent *ev)
void SnapmaticWidget::mouseReleaseEvent(QMouseEvent *ev)
{
ProfileWidget::mouseReleaseEvent(ev);
if (ui->cbSelected->isVisible()) {
if (rect().contains(ev->pos()) && ev->button() == Qt::LeftButton) {
if (ui->cbSelected->isVisible())
{
if (rect().contains(ev->pos()) && ev->button() == Qt::LeftButton)
{
ui->cbSelected->setChecked(!ui->cbSelected->isChecked());
}
}
else {
const int contentMode = getContentMode();
if ((contentMode == 0 || contentMode == 10 || contentMode == 20) && rect().contains(ev->pos()) && ev->button() == Qt::LeftButton) {
if (ev->modifiers().testFlag(Qt::ShiftModifier)) {
else
{
if (getContentMode() == 0 && rect().contains(ev->pos()) && ev->button() == Qt::LeftButton)
{
if (ev->modifiers().testFlag(Qt::ShiftModifier))
{
ui->cbSelected->setChecked(!ui->cbSelected->isChecked());
}
else {
else
{
on_cmdView_clicked();
}
}
else if (!ui->cbSelected->isVisible() && (contentMode == 1 || contentMode == 11 || contentMode == 21) && ev->button() == Qt::LeftButton && ev->modifiers().testFlag(Qt::ShiftModifier)) {
else if (!ui->cbSelected->isVisible() && getContentMode() == 1 && ev->button() == Qt::LeftButton && ev->modifiers().testFlag(Qt::ShiftModifier))
{
ui->cbSelected->setChecked(!ui->cbSelected->isChecked());
}
}
@ -247,8 +238,8 @@ void SnapmaticWidget::mouseDoubleClickEvent(QMouseEvent *ev)
{
ProfileWidget::mouseDoubleClickEvent(ev);
const int contentMode = getContentMode();
if (!ui->cbSelected->isVisible() && (contentMode == 1 || contentMode == 11 || contentMode == 21) && ev->button() == Qt::LeftButton) {
if (!ui->cbSelected->isVisible() && getContentMode() == 1 && ev->button() == Qt::LeftButton)
{
on_cmdView_clicked();
}
}
@ -280,27 +271,32 @@ void SnapmaticWidget::dialogPreviousPictureRequested()
void SnapmaticWidget::on_cbSelected_stateChanged(int arg1)
{
if (arg1 == Qt::Checked) {
if (arg1 == Qt::Checked)
{
emit widgetSelected();
}
else if (arg1 == Qt::Unchecked) {
else if (arg1 == Qt::Unchecked)
{
emit widgetDeselected();
}
}
void SnapmaticWidget::adjustTextColor()
{
if (isHidden()) {
if (isHidden())
{
ui->labPicStr->setStyleSheet(QString("QLabel{color: rgb(%1, %2, %3);}").arg(QString::number(highlightHiddenColor.red()), QString::number(highlightHiddenColor.green()), QString::number(highlightHiddenColor.blue())));
}
else {
else
{
ui->labPicStr->setStyleSheet("");
}
}
bool SnapmaticWidget::makePictureHidden()
{
if (smpic->setPictureHidden()) {
if (smpic->setPictureHidden())
{
adjustTextColor();
return true;
}
@ -309,7 +305,8 @@ bool SnapmaticWidget::makePictureHidden()
bool SnapmaticWidget::makePictureVisible()
{
if (smpic->setPictureVisible()) {
if (smpic->setPictureVisible())
{
adjustTextColor();
return true;
}
@ -319,13 +316,17 @@ bool SnapmaticWidget::makePictureVisible()
void SnapmaticWidget::makePictureHiddenSlot()
{
if (!makePictureHidden())
{
QMessageBox::warning(this, QApplication::translate("UserInterface", "Hide In-game"), QApplication::translate("SnapmaticWidget", "Failed to hide %1 In-game from your Snapmatic pictures").arg("\""+smpic->getPictureTitle()+"\""));
}
}
void SnapmaticWidget::makePictureVisibleSlot()
{
if (!makePictureVisible())
{
QMessageBox::warning(this, QApplication::translate("UserInterface", "Show In-game"), QApplication::translate("SnapmaticWidget", "Failed to show %1 In-game from your Snapmatic pictures").arg("\""+smpic->getPictureTitle()+"\""));
}
}
void SnapmaticWidget::editSnapmaticProperties()
@ -355,17 +356,21 @@ void SnapmaticWidget::editSnapmaticImage()
importDialog->enableOverwriteMode();
importDialog->setModal(true);
importDialog->exec();
if (importDialog->isImportAgreed()) {
if (importDialog->isImportAgreed())
{
const QByteArray previousPicture = smpic->getPictureStream();
bool success = smpic->setImage(importDialog->image(), importDialog->isUnlimitedBuffer());
if (success) {
bool success = smpic->setImage(importDialog->image());
if (success)
{
QString currentFilePath = smpic->getPictureFilePath();
QString originalFilePath = smpic->getOriginalPictureFilePath();
QString backupFileName = originalFilePath % ".bak";
if (!QFile::exists(backupFileName)) {
if (!QFile::exists(backupFileName))
{
QFile::copy(currentFilePath, backupFileName);
}
if (!smpic->exportPicture(currentFilePath)) {
if (!smpic->exportPicture(currentFilePath))
{
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;
@ -376,23 +381,21 @@ void SnapmaticWidget::editSnapmaticImage()
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"] = "ImageEdited";
jsonObject["ExtraFlags"] = "Interface";
jsonObject["EditedSize"] = QString::number(smpic->getContentMaxLength());
#if QT_VERSION >= 0x060000
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
#else
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
#endif
jsonDocument.setObject(jsonObject);
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
}
#endif
}
else {
else
{
QMessageBox::warning(this, QApplication::translate("ImageEditorDialog", "Snapmatic Image Editor"), QApplication::translate("ImageEditorDialog", "Patching of Snapmatic Image failed because of Image Error"));
return;
}
@ -403,48 +406,48 @@ void SnapmaticWidget::editSnapmaticImage()
void SnapmaticWidget::openMapViewer()
{
SnapmaticPicture *picture = smpic;
SnapmaticProperties currentProperties = picture->getSnapmaticProperties();
MapLocationDialog *mapLocDialog = new MapLocationDialog(currentProperties.location.x, currentProperties.location.y, this);
mapLocDialog->setCayoPerico(currentProperties.location.isCayoPerico);
MapLocationDialog *mapLocDialog = new MapLocationDialog(picture->getSnapmaticProperties().location.x, picture->getSnapmaticProperties().location.y, this);
mapLocDialog->setModal(true);
mapLocDialog->show();
mapLocDialog->exec();
if (mapLocDialog->propUpdated()) {
if (mapLocDialog->propUpdated())
{
// Update Snapmatic Properties
currentProperties.location.x = mapLocDialog->getXpos();
currentProperties.location.y = mapLocDialog->getYpos();
currentProperties.location.z = 0;
SnapmaticProperties localSpJson = picture->getSnapmaticProperties();
localSpJson.location.x = mapLocDialog->getXpos();
localSpJson.location.y = mapLocDialog->getYpos();
localSpJson.location.z = 0;
// Update Snapmatic Picture
QString currentFilePath = picture->getPictureFilePath();
QString originalFilePath = picture->getOriginalPictureFilePath();
QString backupFileName = originalFilePath % ".bak";
if (!QFile::exists(backupFileName)) {
if (!QFile::exists(backupFileName))
{
QFile::copy(currentFilePath, backupFileName);
}
SnapmaticProperties fallbackProperties = picture->getSnapmaticProperties();
picture->setSnapmaticProperties(currentProperties);
if (!picture->exportPicture(currentFilePath)) {
picture->setSnapmaticProperties(localSpJson);
if (!picture->exportPicture(currentFilePath))
{
QMessageBox::warning(this, SnapmaticEditor::tr("Snapmatic Properties"), SnapmaticEditor::tr("Patching of Snapmatic Properties failed because of I/O Error"));
picture->setSnapmaticProperties(fallbackProperties);
}
#ifdef GTA5SYNC_TELEMETRY
else {
else
{
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"] = "LocationEdited";
jsonObject["ExtraFlags"] = "Interface";
jsonObject["EditedSize"] = QString::number(picture->getContentMaxLength());
#if QT_VERSION >= 0x060000
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
#else
jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toTime_t());
#endif
jsonDocument.setObject(jsonObject);
Telemetry->push(TelemetryCategory::PersonalData, jsonDocument);
}

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -23,6 +23,11 @@
#include <QDesktopServices>
#endif
StandardPaths::StandardPaths()
{
}
QString StandardPaths::applicationsLocation()
{
#if QT_VERSION >= 0x050000
@ -43,9 +48,7 @@ QString StandardPaths::cacheLocation()
QString StandardPaths::dataLocation()
{
#if QT_VERSION >= 0x060000
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
#elif QT_VERSION >= 0x050000
#if QT_VERSION >= 0x050000
return QStandardPaths::writableLocation(QStandardPaths::DataLocation);
#else
return QDesktopServices::storageLocation(QDesktopServices::DataLocation);

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -24,6 +24,7 @@
class StandardPaths
{
public:
StandardPaths();
static QString applicationsLocation();
static QString cacheLocation();
static QString dataLocation();

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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,9 +17,7 @@
*****************************************************************************/
#include "StringParser.h"
#include "config.h"
#include <QTextDocument>
#include <QApplication>
#include <QLibraryInfo>
#include <QByteArray>
#include <QFileInfo>
@ -27,6 +25,16 @@
#include <QList>
#include <QDir>
#ifdef GTA5SYNC_PROJECT
#include <QApplication>
#include "config.h"
#endif
StringParser::StringParser()
{
}
QString StringParser::escapeString(const QString &toEscape)
{
#if QT_VERSION >= 0x050000
@ -36,6 +44,7 @@ QString StringParser::escapeString(const QString &toEscape)
#endif
}
#ifdef GTA5SYNC_PROJECT
QString StringParser::convertBuildedString(const QString &buildedStr)
{
QString outputStr = buildedStr;
@ -52,3 +61,4 @@ QString StringParser::convertBuildedString(const QString &buildedStr)
outputStr.replace("SEPARATOR:", QDir::separator());
return outputStr;
}
#endif

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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
@ -25,8 +25,11 @@
class StringParser
{
public:
StringParser();
static QString escapeString(const QString &toEscape);
#ifdef GTA5SYNC_PROJECT
static QString convertBuildedString(const QString &buildedStr);
#endif
};
#endif // STRINGPARSER_H

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2017-2021 Syping
* Copyright (C) 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
@ -48,23 +48,22 @@ void TranslationClass::initUserLanguage()
void TranslationClass::loadTranslation(QApplication *app)
{
if (isLangLoaded) {
unloadTranslation(app);
}
else {
currentLangIndex = 0;
}
const QString exLangPath = AppEnv::getExLangFolder();
const QString inLangPath = AppEnv::getInLangFolder();
if (userLanguage == "en" || userLanguage == "en_GB") {
if (isLangLoaded) { unloadTranslation(app); }
else { currentLangIndex = 0; }
QString exLangPath = AppEnv::getExLangFolder();
QString inLangPath = AppEnv::getInLangFolder();
if (userLanguage == "en" || userLanguage == "en_GB")
{
currentLanguage = "en_GB";
if (loadQtTranslation_p(exLangPath, &exQtTranslator)) {
if (loadQtTranslation_p(exLangPath, &exQtTranslator))
{
app->installTranslator(&exQtTranslator);
}
else if (loadQtTranslation_p(inLangPath, &inQtTranslator)) {
else if (loadQtTranslation_p(inLangPath, &inQtTranslator))
{
app->installTranslator(&inQtTranslator);
}
#if QT_VERSION >= 0x060000
#if QT_VERSION <= 0x060000
QLocale::setDefault(QLocale(currentLanguage));
#else
QLocale::setDefault(currentLanguage);
@ -78,28 +77,33 @@ void TranslationClass::loadTranslation(QApplication *app)
bool externalEnglishMode = false;
bool loadInternalLang = false;
bool trLoadSuccess = false;
if (isUserLanguageSystem_p()) {
if (isUserLanguageSystem_p())
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadExSystemLanguage";
#endif
trLoadSuccess = loadSystemTranslation_p(exLangPath, &exAppTranslator);
}
else {
else
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadExUserLanguage";
#endif
trLoadSuccess = loadUserTranslation_p(exLangPath, &exAppTranslator);
if (!trLoadSuccess) {
if (!trLoadSuccess)
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadInUserLanguage";
#endif
trLoadSuccess = loadUserTranslation_p(inLangPath, &inAppTranslator);
if (!trLoadSuccess) {
if (!trLoadSuccess)
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadUserLanguageFailed";
#endif
}
else {
else
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadUserLanguageSuccess";
#endif
@ -107,16 +111,18 @@ void TranslationClass::loadTranslation(QApplication *app)
isLangLoaded = true;
}
}
else {
else
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadUserLanguageSuccess";
#endif
isLangLoaded = true;
}
}
if (trLoadSuccess) {
// Don't install the language until we know we not have a better language for the user
if (currentLangIndex != 0 || isEnglishMode) {
if (trLoadSuccess)
{
if (currentLangIndex != 0 || isEnglishMode) // Don't install the language until we know we not have a better language for the user
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "externalLanguageReady" << currentLanguage;
#endif
@ -124,23 +130,28 @@ void TranslationClass::loadTranslation(QApplication *app)
externalLanguageStr = currentLanguage;
externalLanguageReady = true;
}
else {
else
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "installTranslation";
#endif
if (loadInternalLang) {
if (loadInternalLang)
{
app->installTranslator(&inAppTranslator);
}
else {
else
{
app->installTranslator(&exAppTranslator);
}
if (loadQtTranslation_p(exLangPath, &exQtTranslator)) {
if (loadQtTranslation_p(exLangPath, &exQtTranslator))
{
app->installTranslator(&exQtTranslator);
}
else if (loadQtTranslation_p(inLangPath, &inQtTranslator)) {
else if (loadQtTranslation_p(inLangPath, &inQtTranslator))
{
app->installTranslator(&inQtTranslator);
}
#if QT_VERSION >= 0x060000
#if QT_VERSION <= 0x060000
QLocale::setDefault(QLocale(currentLanguage));
#else
QLocale::setDefault(currentLanguage);
@ -148,7 +159,8 @@ void TranslationClass::loadTranslation(QApplication *app)
isLangLoaded = true;
}
}
if (externalLanguageReady) {
if (externalLanguageReady)
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadInSystemLanguage";
#endif
@ -158,38 +170,44 @@ void TranslationClass::loadTranslation(QApplication *app)
qDebug() << "externalLangIndex" << externalLangIndex << "internalLangIndex" << currentLangIndex;
qDebug() << "externalEnglishMode" << externalEnglishMode << "internalEnglishMode" << isEnglishMode;
#endif
if ((trLoadSuccess && externalLangIndex > currentLangIndex) || (trLoadSuccess && externalEnglishMode && !isEnglishMode)) {
if ((trLoadSuccess && externalLangIndex > currentLangIndex) || (trLoadSuccess && externalEnglishMode && !isEnglishMode))
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "installInternalTranslation";
#endif
app->installTranslator(&inAppTranslator);
if (loadQtTranslation_p(exLangPath, &exQtTranslator)) {
if (loadQtTranslation_p(exLangPath, &exQtTranslator))
{
app->installTranslator(&exQtTranslator);
}
else if (loadQtTranslation_p(inLangPath, &inQtTranslator)) {
else if (loadQtTranslation_p(inLangPath, &inQtTranslator))
{
app->installTranslator(&inQtTranslator);
}
#if QT_VERSION >= 0x060000
#if QT_VERSION <= 0x060000
QLocale::setDefault(QLocale(currentLanguage));
#else
QLocale::setDefault(currentLanguage);
#endif
isLangLoaded = true;
}
else {
else
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "installExternalTranslation";
#endif
isEnglishMode = externalEnglishMode;
currentLanguage = externalLanguageStr;
app->installTranslator(&exAppTranslator);
if (loadQtTranslation_p(exLangPath, &exQtTranslator)) {
if (loadQtTranslation_p(exLangPath, &exQtTranslator))
{
app->installTranslator(&exQtTranslator);
}
else if (loadQtTranslation_p(inLangPath, &inQtTranslator)) {
else if (loadQtTranslation_p(inLangPath, &inQtTranslator))
{
app->installTranslator(&inQtTranslator);
}
#if QT_VERSION >= 0x060000
#if QT_VERSION <= 0x060000
QLocale::setDefault(QLocale(currentLanguage));
#else
QLocale::setDefault(currentLanguage);
@ -197,41 +215,48 @@ void TranslationClass::loadTranslation(QApplication *app)
isLangLoaded = true;
}
}
else if (!isLangLoaded) {
else if (!isLangLoaded)
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadInSystemLanguage";
#endif
trLoadSuccess = loadSystemTranslation_p(inLangPath, &inAppTranslator);
if (trLoadSuccess) {
if (trLoadSuccess)
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "installInternalTranslation";
#endif
app->installTranslator(&inAppTranslator);
if (loadQtTranslation_p(exLangPath, &exQtTranslator)) {
if (loadQtTranslation_p(exLangPath, &exQtTranslator))
{
app->installTranslator(&exQtTranslator);
}
else if (loadQtTranslation_p(inLangPath, &inQtTranslator)) {
else if (loadQtTranslation_p(inLangPath, &inQtTranslator))
{
app->installTranslator(&inQtTranslator);
}
#if QT_VERSION >= 0x060000
#if QT_VERSION <= 0x060000
QLocale::setDefault(QLocale(currentLanguage));
#else
QLocale::setDefault(currentLanguage);
#endif
isLangLoaded = true;
}
else if (!trLoadSuccess) {
else if (!trLoadSuccess)
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "fallbackToDefaultApplicationLanguage";
#endif
currentLanguage = "en_GB";
if (loadQtTranslation_p(exLangPath, &exQtTranslator)) {
if (loadQtTranslation_p(exLangPath, &exQtTranslator))
{
app->installTranslator(&exQtTranslator);
}
else if (loadQtTranslation_p(inLangPath, &inQtTranslator)) {
else if (loadQtTranslation_p(inLangPath, &inQtTranslator))
{
app->installTranslator(&inQtTranslator);
}
#if QT_VERSION >= 0x060000
#if QT_VERSION <= 0x060000
QLocale::setDefault(QLocale(currentLanguage));
#else
QLocale::setDefault(currentLanguage);
@ -241,31 +266,33 @@ void TranslationClass::loadTranslation(QApplication *app)
}
#else // New qconf loading method
bool trLoadSuccess;
if (isUserLanguageSystem_p()) {
if (isUserLanguageSystem_p())
{
trLoadSuccess = loadSystemTranslation_p(inLangPath, &inAppTranslator);
}
else {
else
{
trLoadSuccess = loadUserTranslation_p(inLangPath, &inAppTranslator);
}
if (!trLoadSuccess && !isUserLanguageSystem_p()) {
if (!trLoadSuccess && !isUserLanguageSystem_p())
{
trLoadSuccess = loadSystemTranslation_p(inLangPath, &inAppTranslator);
}
if (trLoadSuccess) {
if (trLoadSuccess)
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "installTranslation" << currentLanguage;
#endif
app->installTranslator(&inAppTranslator);
if (loadQtTranslation_p(exLangPath, &exQtTranslator)) {
if (loadQtTranslation_p(exLangPath, &exQtTranslator))
{
app->installTranslator(&exQtTranslator);
}
else if (loadQtTranslation_p(inLangPath, &inQtTranslator)) {
else if (loadQtTranslation_p(inLangPath, &inQtTranslator))
{
app->installTranslator(&inQtTranslator);
}
#if QT_VERSION >= 0x060000
QLocale::setDefault(QLocale(currentLanguage));
#else
QLocale::setDefault(currentLanguage);
#endif
isLangLoaded = true;
}
#endif
@ -277,7 +304,8 @@ QStringList TranslationClass::listTranslations(const QString &langPath)
langDir.setNameFilters(QStringList("gta5sync_*.qm"));
langDir.setPath(langPath);
QStringList availableLanguages;
for (const QString &lang : langDir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::NoSort)) {
for (QString lang : langDir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::NoSort))
{
availableLanguages << QString(lang).remove("gta5sync_").remove(".qm");
}
return availableLanguages;
@ -289,7 +317,8 @@ QStringList TranslationClass::listAreaTranslations()
langDir.setNameFilters(QStringList("global.*.ini"));
langDir.setPath(":/global");
QStringList availableLanguages;
for (const QString &lang : langDir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::NoSort)) {
for (QString lang : langDir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::NoSort))
{
availableLanguages << QString(lang).remove("global.").remove(".ini");
}
return availableLanguages;
@ -301,17 +330,21 @@ bool TranslationClass::loadSystemTranslation_p(const QString &langPath, QTransla
qDebug() << "loadSystemTranslation_p";
#endif
int currentLangCounter = 0;
for (const QString &languageName : QLocale::system().uiLanguages()) {
for (QString languageName : QLocale::system().uiLanguages())
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguage" << languageName;
#endif
const QStringList langList = QString(languageName).replace("-","_").split("_");
if (langList.length() == 2) {
QStringList langList = QString(languageName).replace("-","_").split("_");
if (langList.length() == 2)
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFile" << QString(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm");
#endif
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm")) {
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm")) {
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm"))
{
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm"))
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFileSuccess" << QString(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm");
#endif
@ -324,8 +357,10 @@ bool TranslationClass::loadSystemTranslation_p(const QString &langPath, QTransla
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFile" << QString(langPath % "/gta5sync_" % langList.at(0) % ".qm");
#endif
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % ".qm")) {
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % ".qm")) {
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
{
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFileSuccess" << QString(langPath % "/gta5sync_" % langList.at(0) % ".qm");
#endif
@ -334,7 +369,8 @@ bool TranslationClass::loadSystemTranslation_p(const QString &langPath, QTransla
currentLangIndex = currentLangCounter;
return true;
}
else if (langList.at(0) == "en") {
else if (langList.at(0) == "en")
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "languageEnglishMode index" << currentLangCounter;
#endif
@ -344,7 +380,8 @@ bool TranslationClass::loadSystemTranslation_p(const QString &langPath, QTransla
return true;
}
}
else if (langList.at(0) == "en") {
else if (langList.at(0) == "en")
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "languageEnglishMode index" << currentLangCounter;
#endif
@ -354,12 +391,15 @@ bool TranslationClass::loadSystemTranslation_p(const QString &langPath, QTransla
return true;
}
}
else if (langList.length() == 1) {
else if (langList.length() == 1)
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFile" << QString(langPath % "/gta5sync_" % langList.at(0) % ".qm");
#endif
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % ".qm")) {
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % ".qm")) {
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
{
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFileSuccess" << QString(langPath % "/gta5sync_" % langList.at(0) % ".qm");
#endif
@ -383,14 +423,17 @@ bool TranslationClass::loadUserTranslation_p(const QString &langPath, QTranslato
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadUserTranslation_p";
#endif
const QString languageName = userLanguage;
const QStringList langList = QString(languageName).replace("-","_").split("_");
if (langList.length() == 2) {
QString languageName = userLanguage;
QStringList langList = QString(languageName).replace("-","_").split("_");
if (langList.length() == 2)
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFile" << QString(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm");
#endif
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm")) {
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm")) {
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm"))
{
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm"))
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFileSuccess" << QString(langPath % "/gta5sync_" % langList.at(0) % "_" % langList.at(1) % ".qm");
#endif
@ -401,8 +444,10 @@ bool TranslationClass::loadUserTranslation_p(const QString &langPath, QTranslato
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFile" << QString(langPath % "/gta5sync_" % langList.at(0) % ".qm");
#endif
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % ".qm")) {
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % ".qm")) {
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
{
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFileSuccess" << QString(langPath % "/gta5sync_" % langList.at(0) % ".qm");
#endif
@ -411,12 +456,15 @@ bool TranslationClass::loadUserTranslation_p(const QString &langPath, QTranslato
}
}
}
else if (langList.length() == 1) {
else if (langList.length() == 1)
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFile" << QString(langPath % "/gta5sync_" % langList.at(0) % ".qm");
#endif
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % ".qm")) {
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % ".qm")) {
if (QFile::exists(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
{
if (appTranslator->load(langPath % "/gta5sync_" % langList.at(0) % ".qm"))
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFileSuccess" << QString(langPath % "/gta5sync_" % langList.at(0) % ".qm");
#endif
@ -433,14 +481,17 @@ bool TranslationClass::loadQtTranslation_p(const QString &langPath, QTranslator
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadQtTranslation_p" << currentLanguage;
#endif
const QString languageName = currentLanguage;
const QStringList langList = QString(languageName).replace("-","_").split("_");
if (langList.length() == 2) {
QString languageName = currentLanguage;
QStringList langList = QString(languageName).replace("-","_").split("_");
if (langList.length() == 2)
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFile" << QString(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % "_" % langList.at(1) % ".qm");
#endif
if (QFile::exists(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % "_" % langList.at(1) % ".qm")) {
if (qtTranslator->load(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % "_" % langList.at(1) % ".qm")) {
if (QFile::exists(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % "_" % langList.at(1) % ".qm"))
{
if (qtTranslator->load(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % "_" % langList.at(1) % ".qm"))
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFileSuccess" << QString(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % "_" % langList.at(1) % ".qm");
#endif
@ -450,8 +501,10 @@ bool TranslationClass::loadQtTranslation_p(const QString &langPath, QTranslator
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFile" << QString(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm");
#endif
if (QFile::exists(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm")) {
if (qtTranslator->load(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm")) {
if (QFile::exists(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm"))
{
if (qtTranslator->load(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm"))
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFileSuccess" << QString(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm");
#endif
@ -459,12 +512,15 @@ bool TranslationClass::loadQtTranslation_p(const QString &langPath, QTranslator
}
}
}
else if (langList.length() == 1) {
else if (langList.length() == 1)
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFile" << QString(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm");
#endif
if (QFile::exists(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm")) {
if (qtTranslator->load(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm")) {
if (QFile::exists(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm"))
{
if (qtTranslator->load(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm"))
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "loadLanguageFileSuccess" << QString(langPath % QDir::separator() % QtBaseTranslationFormat % langList.at(0) % ".qm");
#endif
@ -483,44 +539,49 @@ bool TranslationClass::isUserLanguageSystem_p()
QString TranslationClass::getCurrentAreaLanguage()
{
const QStringList areaTranslations = listAreaTranslations();
if (userAreaLanguage == "Auto" || userAreaLanguage.trimmed().isEmpty()) {
const GameLanguage gameLanguage = AppEnv::getGameLanguage(AppEnv::getGameVersion());
if (gameLanguage == GameLanguage::Undefined) {
if (userAreaLanguage == "Auto" || userAreaLanguage.trimmed().isEmpty())
{
GameLanguage gameLanguage = AppEnv::getGameLanguage(AppEnv::getGameVersion());
if (gameLanguage == GameLanguage::Undefined)
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "autoAreaLanguageModeInterface";
#endif
QString langCode = QString(currentLanguage).replace("-", "_");
if (areaTranslations.contains(langCode)) {
if (areaTranslations.contains(langCode))
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "autoAreaLanguageSelected" << langCode;
#endif
return langCode;
}
else if (langCode.contains("_")) {
else if (langCode.contains("_"))
{
langCode = langCode.split("_").at(0);
if (!areaTranslations.contains(langCode))
goto outputDefaultLanguage;
if (!areaTranslations.contains(langCode)) goto outputDefaultLanguage;
#ifdef GTA5SYNC_DEBUG
qDebug() << "autoAreaLanguageSelected" << langCode;
#endif
return langCode;
}
}
else {
else
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "autoAreaLanguageModeGame";
#endif
QString langCode = AppEnv::gameLanguageToString(gameLanguage).replace("-", "_");
if (areaTranslations.contains(langCode)) {
if (areaTranslations.contains(langCode))
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "autoAreaLanguageSelected" << langCode;
#endif
return langCode;
}
else if (langCode.contains("_")) {
else if (langCode.contains("_"))
{
langCode = langCode.split("_").at(0);
if (!areaTranslations.contains(langCode))
goto outputDefaultLanguage;
if (!areaTranslations.contains(langCode)) goto outputDefaultLanguage;
#ifdef GTA5SYNC_DEBUG
qDebug() << "autoAreaLanguageSelected" << langCode;
#endif
@ -528,16 +589,17 @@ QString TranslationClass::getCurrentAreaLanguage()
}
}
}
else if (areaTranslations.contains(userAreaLanguage)) {
else if (areaTranslations.contains(userAreaLanguage))
{
#ifdef GTA5SYNC_DEBUG
qDebug() << "userAreaLanguageSelected" << userAreaLanguage;
#endif
return userAreaLanguage;
}
else if (userAreaLanguage.contains("_")) {
const QString langCode = QString(userAreaLanguage).replace("-", "_").split("_").at(0);
if (!areaTranslations.contains(langCode))
goto outputDefaultLanguage;
else if (userAreaLanguage.contains("_"))
{
QString langCode = QString(userAreaLanguage).replace("-", "_").split("_").at(0);
if (!areaTranslations.contains(langCode)) goto outputDefaultLanguage;
#ifdef GTA5SYNC_DEBUG
qDebug() << "userAreaLanguageSelected" << langCode;
#endif
@ -562,7 +624,8 @@ bool TranslationClass::isLanguageLoaded()
void TranslationClass::unloadTranslation(QApplication *app)
{
if (isLangLoaded) {
if (isLangLoaded)
{
#ifndef GTA5SYNC_QCONF
app->removeTranslator(&exAppTranslator);
app->removeTranslator(&exQtTranslator);
@ -585,21 +648,30 @@ void TranslationClass::unloadTranslation(QApplication *app)
QString TranslationClass::getCountryCode(QLocale::Country country)
{
const QList<QLocale> locales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, country);
if (!locales.isEmpty()) {
const QStringList localeStrList = locales.at(0).name().split("_");
if (localeStrList.length() >= 2) {
return localeStrList.at(1).toLower();
}
QList<QLocale> locales = QLocale::matchingLocales(QLocale::AnyLanguage,
QLocale::AnyScript,
country);
if (locales.isEmpty()) return QString();
QStringList localeStrList = locales.at(0).name().split("_");
if (localeStrList.length() >= 2)
{
return localeStrList.at(1).toLower();
}
else
{
return QString();
}
return QString();
}
QString TranslationClass::getCountryCode(QLocale locale)
{
QStringList localeStrList = locale.name().split("_");
if (localeStrList.length() >= 2) {
if (localeStrList.length() >= 2)
{
return localeStrList.at(1).toLower();
}
return QString();
else
{
return QString();
}
}

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 Syping
* Copyright (C) 2016-2019 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
@ -46,25 +46,15 @@
#include <QDir>
#include <QMap>
#ifdef GTA5SYNC_DONATE
#ifdef GTA5SYNC_DONATE_ADDRESSES
#include <QSvgRenderer>
#include <QClipboard>
#include <QPainter>
#include "QrCode.h"
using namespace qrcodegen;
#endif
#endif
#ifdef GTA5SYNC_MOTD
UserInterface::UserInterface(ProfileDatabase *profileDB, CrewDatabase *crewDB, DatabaseThread *threadDB, MessageThread *threadMessage, QWidget *parent) :
QMainWindow(parent), profileDB(profileDB), crewDB(crewDB), threadDB(threadDB), threadMessage(threadMessage),
ui(new Ui::UserInterface)
#else
#else
UserInterface::UserInterface(ProfileDatabase *profileDB, CrewDatabase *crewDB, DatabaseThread *threadDB, QWidget *parent) :
QMainWindow(parent), profileDB(profileDB), crewDB(crewDB), threadDB(threadDB),
ui(new Ui::UserInterface)
#endif
#endif
{
ui->setupUi(this);
contentMode = 0;
@ -73,244 +63,113 @@ UserInterface::UserInterface(ProfileDatabase *profileDB, CrewDatabase *crewDB, D
ui->menuProfile->setEnabled(false);
ui->actionSelect_profile->setEnabled(false);
ui->actionAbout_gta5sync->setIcon(IconLoader::loadingAppIcon());
#ifdef Q_OS_MAC
ui->actionAbout_gta5sync->setText(QApplication::translate("MAC_APPLICATION_MENU", "About %1").arg(GTA5SYNC_APPSTR));
ui->actionOptions->setText(QApplication::translate("MAC_APPLICATION_MENU", "Preferences..."));
#else
ui->actionAbout_gta5sync->setText(tr("&About %1").arg(GTA5SYNC_APPSTR));
#endif
ui->cmdClose->setToolTip(ui->cmdClose->toolTip().arg(GTA5SYNC_APPSTR));
defaultWindowTitle = tr("%2 - %1").arg("%1", GTA5SYNC_APPSTR);
setWindowTitle(defaultWindowTitle.arg(tr("Select Profile")));
QString appVersion = QApplication::applicationVersion();
const char* literalBuildType = GTA5SYNC_BUILDTYPE;
this->setWindowTitle(defaultWindowTitle.arg(tr("Select Profile")));
QString appVersion = GTA5SYNC_APPVER;
#ifndef GTA5SYNC_BUILDTYPE_REL
#ifdef GTA5SYNC_COMMIT
if ((strcmp(literalBuildType, REL_BUILDTYPE) != 0) && !appVersion.contains("-"))
appVersion = appVersion % "-" % GTA5SYNC_COMMIT;
if (!appVersion.contains("-")) { appVersion = appVersion % "-" % GTA5SYNC_COMMIT; }
#endif
#endif
ui->labVersion->setText(QString("%1 %2").arg(GTA5SYNC_APPSTR, appVersion));
// 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"));
}
// Set Icon for Reload Button
if (QIcon::hasThemeIcon("view-refresh")) {
if (QIcon::hasThemeIcon("view-refresh"))
{
ui->cmdReload->setIcon(QIcon::fromTheme("view-refresh"));
}
else if (QIcon::hasThemeIcon("reload")) {
else if (QIcon::hasThemeIcon("reload"))
{
ui->cmdReload->setIcon(QIcon::fromTheme("reload"));
}
// Set Icon for Choose GTA V Folder Menu Item
if (QIcon::hasThemeIcon("document-open-folder")) {
if (QIcon::hasThemeIcon("document-open-folder"))
{
ui->actionSelect_GTA_Folder->setIcon(QIcon::fromTheme("document-open-folder"));
}
else if (QIcon::hasThemeIcon("gtk-directory")) {
else if (QIcon::hasThemeIcon("gtk-directory"))
{
ui->actionSelect_GTA_Folder->setIcon(QIcon::fromTheme("gtk-directory"));
}
// Set Icon for Open File Menu Item
if (QIcon::hasThemeIcon("document-open")) {
if (QIcon::hasThemeIcon("document-open"))
{
ui->actionOpen_File->setIcon(QIcon::fromTheme("document-open"));
}
// Set Icon for Close Profile Menu Item
if (QIcon::hasThemeIcon("dialog-close")) {
if (QIcon::hasThemeIcon("dialog-close"))
{
ui->actionSelect_profile->setIcon(QIcon::fromTheme("dialog-close"));
}
else if (QIcon::hasThemeIcon("gtk-close")) {
else if (QIcon::hasThemeIcon("gtk-close"))
{
ui->actionSelect_profile->setIcon(QIcon::fromTheme("gtk-close"));
}
// Set Icon for Exit Menu Item
if (QIcon::hasThemeIcon("application-exit")) {
if (QIcon::hasThemeIcon("application-exit"))
{
#ifndef Q_OS_MACOS // Setting icon for exit/quit lead to a crash in Mac OS X
ui->actionExit->setIcon(QIcon::fromTheme("application-exit"));
#endif
}
// Set Icon for Preferences Menu Item
if (QIcon::hasThemeIcon("preferences-system")) {
if (QIcon::hasThemeIcon("preferences-system"))
{
#ifndef Q_OS_MACOS // Setting icon for preferences/settings/options lead to a crash in Mac OS X
ui->actionOptions->setIcon(QIcon::fromTheme("preferences-system"));
#endif
}
else if (QIcon::hasThemeIcon("configure")) {
else if (QIcon::hasThemeIcon("configure"))
{
#ifndef Q_OS_MACOS // Setting icon for preferences/settings/options lead to a crash in Mac OS X
ui->actionOptions->setIcon(QIcon::fromTheme("configure"));
#endif
}
// Set Icon for Profile Import Menu Item
if (QIcon::hasThemeIcon("document-import")) {
if (QIcon::hasThemeIcon("document-import"))
{
ui->action_Import->setIcon(QIcon::fromTheme("document-import"));
}
else if (QIcon::hasThemeIcon("document-open")) {
else if (QIcon::hasThemeIcon("document-open"))
{
ui->action_Import->setIcon(QIcon::fromTheme("document-open"));
}
// Set Icon for Profile Export Menu Item
if (QIcon::hasThemeIcon("document-export")) {
if (QIcon::hasThemeIcon("document-export"))
{
ui->actionExport_selected->setIcon(QIcon::fromTheme("document-export"));
}
else if (QIcon::hasThemeIcon("document-save")) {
else if (QIcon::hasThemeIcon("document-save"))
{
ui->actionExport_selected->setIcon(QIcon::fromTheme("document-save"));
}
// Set Icon for Profile Remove Menu Item
if (QIcon::hasThemeIcon("remove")) {
if (QIcon::hasThemeIcon("remove"))
{
ui->actionDelete_selected->setIcon(QIcon::fromTheme("remove"));
}
#ifdef GTA5SYNC_DONATE
#ifdef GTA5SYNC_DONATE_ADDRESSES
donateAction = new QAction(tr("&Donate"), this);
if (QIcon::hasThemeIcon("help-donate")) {
donateAction->setIcon(QIcon::fromTheme("help-donate"));
}
else if (QIcon::hasThemeIcon("taxes-finances")) {
donateAction->setIcon(QIcon::fromTheme("taxes-finances"));
}
else {
donateAction->setIcon(QIcon(":/img/donate.svgz"));
}
ui->menuHelp->insertAction(ui->actionAbout_gta5sync, donateAction);
QObject::connect(donateAction, &QAction::triggered, this, [=](){
QDialog *donateDialog = new QDialog(this);
donateDialog->setWindowTitle(QString("%1 - %2").arg(GTA5SYNC_APPSTR, tr("Donate")));
#if QT_VERSION >= 0x050900
donateDialog->setWindowFlag(Qt::WindowContextHelpButtonHint, false);
#else
donateDialog->setWindowFlags(donateDialog->windowFlags()^Qt::WindowContextHelpButtonHint);
#endif
QVBoxLayout *donateLayout = new QVBoxLayout;
donateDialog->setLayout(donateLayout);
QLabel *methodsLabel = new QLabel(QString("<b>%1</b>").arg(tr("Donation methods").toHtmlEscaped()), donateDialog);
methodsLabel->setWordWrap(true);
donateLayout->addWidget(methodsLabel);
QHBoxLayout *currencyLayout = new QHBoxLayout;
donateLayout->addLayout(currencyLayout);
const QStringList addressList = QString::fromUtf8(GTA5SYNC_DONATE_ADDRESSES).split(',');
for (const QString &address : addressList) {
const QStringList addressList = address.split(':');
if (addressList.length() == 2) {
const QString currency = addressList.at(0);
const QString address = addressList.at(1);
QString currencyStr = currency;
const QString strPath = QString(":/donate/%1.str").arg(currency);
if (QFile::exists(strPath)) {
QFile strFile(strPath);
if (strFile.open(QIODevice::ReadOnly)) {
currencyStr = QString::fromUtf8(strFile.readAll());
strFile.close();
}
}
const QString iconPath = QString(":/donate/%1.svgz").arg(currency);
QPushButton *currencyButton = new QPushButton(currencyStr, donateDialog);
currencyButton->setToolTip(currencyStr);
if (QFile::exists(iconPath)) {
currencyButton->setIconSize(QSize(32, 32));
currencyButton->setIcon(QIcon(iconPath));
}
currencyLayout->addWidget(currencyButton);
QObject::connect(currencyButton, &QPushButton::pressed, donateDialog, [=](){
QDialog *addressDialog = new QDialog(donateDialog);
addressDialog->setWindowTitle(currencyStr);
#if QT_VERSION >= 0x050900
addressDialog->setWindowFlag(Qt::WindowContextHelpButtonHint, false);
#else
addressDialog->setWindowFlags(donateDialog->windowFlags()^Qt::WindowContextHelpButtonHint);
#endif
QVBoxLayout *addressLayout = new QVBoxLayout;
addressDialog->setLayout(addressLayout);
QLabel *addressLabel = new QLabel(address, addressDialog);
addressLabel->setAlignment(Qt::AlignCenter);
addressLabel->setTextFormat(Qt::PlainText);
addressLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
addressLayout->addWidget(addressLabel);
QHBoxLayout *qrLayout = new QHBoxLayout;
qrLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
QrCode qr = QrCode::encodeText(address.toUtf8().constData(), QrCode::Ecc::MEDIUM);
const std::string svgString = qr.toSvgString(0);
QSvgRenderer svgRenderer(QByteArray::fromRawData(svgString.c_str(), svgString.size()));
qreal screenRatioPR = AppEnv::screenRatioPR();
const QSize widgetSize = QSize(200, 200);
const QSize pixmapSize = widgetSize * screenRatioPR;
QPixmap qrPixmap(pixmapSize);
qrPixmap.fill(Qt::white);
QPainter qrPainter(&qrPixmap);
svgRenderer.render(&qrPainter, QRectF(QPointF(0, 0), pixmapSize));
qrPainter.end();
#if QT_VERSION >= 0x050600
qrPixmap.setDevicePixelRatio(screenRatioPR);
#endif
QLabel *qrLabel = new QLabel(addressDialog);
qrLabel->setFixedSize(widgetSize);
qrLabel->setPixmap(qrPixmap);
qrLayout->addWidget(qrLabel);
qrLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
addressLayout->addLayout(qrLayout);
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
QPushButton *copyAddressButton = new QPushButton(tr("&Copy"), addressDialog);
if (QIcon::hasThemeIcon("edit-copy")) {
copyAddressButton->setIcon(QIcon::fromTheme("edit-copy"));
}
QObject::connect(copyAddressButton, &QPushButton::pressed, addressDialog, [=](){
QApplication::clipboard()->setText(address);
});
buttonLayout->addWidget(copyAddressButton);
QPushButton *closeButton = new QPushButton(tr("&Close"), addressDialog);
if (QIcon::hasThemeIcon("dialog-close")) {
closeButton->setIcon(QIcon::fromTheme("dialog-close"));
}
else if (QIcon::hasThemeIcon("gtk-close")) {
closeButton->setIcon(QIcon::fromTheme("gtk-close"));
}
closeButton->setDefault(true);
buttonLayout->addWidget(closeButton);
buttonLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
addressLayout->addLayout(buttonLayout);
QObject::connect(closeButton, &QPushButton::clicked, addressDialog, &QDialog::accept);
QObject::connect(addressDialog, &QDialog::finished, addressDialog, &QDialog::deleteLater);
QTimer::singleShot(0, addressDialog, [=](){
addressDialog->setFocus();
});
addressDialog->open();
addressDialog->setFixedSize(addressDialog->size());
});
}
}
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
QPushButton *closeButton = new QPushButton(donateDialog);
closeButton->setText(tr("&Close"));
if (QIcon::hasThemeIcon("dialog-close")) {
closeButton->setIcon(QIcon::fromTheme("dialog-close"));
}
else if (QIcon::hasThemeIcon("gtk-close")) {
closeButton->setIcon(QIcon::fromTheme("gtk-close"));
}
closeButton->setDefault(true);
buttonLayout->addWidget(closeButton);
donateLayout->addLayout(buttonLayout);
QObject::connect(closeButton, &QPushButton::clicked, donateDialog, &QDialog::accept);
QObject::connect(donateDialog, &QDialog::finished, donateDialog, &QDialog::deleteLater);
QTimer::singleShot(0, donateDialog, [=](){
donateDialog->setFocus();
});
donateDialog->open();
donateDialog->setFixedSize(donateDialog->size());
});
#endif
#endif
// DPI calculation
qreal screenRatio = AppEnv::screenRatio();
#ifndef Q_QS_ANDROID
@ -327,22 +186,29 @@ void UserInterface::setupDirEnv(bool showFolderDialog)
bool folderExists;
GTAV_Folder = AppEnv::getGameFolder(&folderExists);
if (folderExists) {
if (folderExists)
{
QDir::setCurrent(GTAV_Folder);
}
else if (showFolderDialog) {
GTAV_Folder = QFileDialog::getExistingDirectory(this, tr("Select GTA V Folder..."), StandardPaths::documentsLocation(), QFileDialog::ShowDirsOnly);
if (QDir(GTAV_Folder).exists()) {
folderExists = true;
QDir::setCurrent(GTAV_Folder);
AppEnv::setGameFolder(GTAV_Folder);
else
{
if (showFolderDialog)
{
GTAV_Folder = QFileDialog::getExistingDirectory(this, tr("Select GTA V Folder..."), StandardPaths::documentsLocation(), QFileDialog::ShowDirsOnly);
if (QFileInfo(GTAV_Folder).exists())
{
folderExists = true;
QDir::setCurrent(GTAV_Folder);
AppEnv::setGameFolder(GTAV_Folder);
// First time folder selection save
settings.beginGroup("dir");
if (settings.value("dir", "").toString().isEmpty()) {
settings.setValue("dir", GTAV_Folder);
// First time folder selection save
settings.beginGroup("dir");
if (settings.value("dir", "").toString().isEmpty())
{
settings.setValue("dir", GTAV_Folder);
}
settings.endGroup();
}
settings.endGroup();
}
}
@ -350,15 +216,15 @@ void UserInterface::setupDirEnv(bool showFolderDialog)
settings.beginGroup("Profile");
QString defaultProfile = settings.value("Default", "").toString();
contentMode = settings.value("ContentMode", 0).toInt();
if (contentMode == 1) {
contentMode = 21;
}
else if (contentMode != 10 && contentMode != 11 && contentMode != 20 && contentMode != 21) {
contentMode = 20;
bool contentModeOk;
contentMode = settings.value("ContentMode", 0).toInt(&contentModeOk);
if (contentMode != 0 && contentMode != 1 && contentMode != 2)
{
contentMode = 0;
}
if (folderExists) {
if (folderExists)
{
QDir GTAV_ProfilesDir;
GTAV_ProfilesFolder = GTAV_Folder % "/Profiles";
GTAV_ProfilesDir.setPath(GTAV_ProfilesFolder);
@ -366,14 +232,17 @@ void UserInterface::setupDirEnv(bool showFolderDialog)
GTAV_Profiles = GTAV_ProfilesDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::NoSort);
setupProfileUi();
if (GTAV_Profiles.length() == 1) {
if (GTAV_Profiles.length() == 1)
{
openProfile(GTAV_Profiles.at(0));
}
else if(GTAV_Profiles.contains(defaultProfile)) {
else if(GTAV_Profiles.contains(defaultProfile))
{
openProfile(defaultProfile);
}
}
else {
else
{
GTAV_Profiles = QStringList();
setupProfileUi();
}
@ -383,7 +252,8 @@ void UserInterface::setupDirEnv(bool showFolderDialog)
void UserInterface::setupProfileUi()
{
qreal screenRatio = AppEnv::screenRatio();
if (GTAV_Profiles.isEmpty()) {
if (GTAV_Profiles.isEmpty())
{
QPushButton *changeDirBtn = new QPushButton(tr("Select &GTA V Folder..."), ui->swSelection);
changeDirBtn->setObjectName("cmdChangeDir");
changeDirBtn->setMinimumSize(0, 40 * screenRatio);
@ -393,7 +263,8 @@ void UserInterface::setupProfileUi()
QObject::connect(changeDirBtn, SIGNAL(clicked(bool)), this, SLOT(changeFolder_clicked()));
}
else for (const QString &GTAV_Profile : GTAV_Profiles) {
else for (QString GTAV_Profile : GTAV_Profiles)
{
QPushButton *profileBtn = new QPushButton(GTAV_Profile, ui->swSelection);
profileBtn->setObjectName(GTAV_Profile);
profileBtn->setMinimumSize(0, 40 * screenRatio);
@ -413,7 +284,8 @@ void UserInterface::changeFolder_clicked()
void UserInterface::on_cmdReload_clicked()
{
for (QPushButton *profileBtn : profileBtns) {
for (QPushButton *profileBtn : profileBtns)
{
ui->vlButtons->removeWidget(profileBtn);
delete profileBtn;
}
@ -439,15 +311,16 @@ void UserInterface::openProfile(const QString &profileName_)
profileUI->setupProfileInterface();
QObject::connect(profileUI, SIGNAL(profileClosed()), this, SLOT(closeProfile()));
QObject::connect(profileUI, SIGNAL(profileLoaded()), this, SLOT(profileLoaded()));
setWindowTitle(defaultWindowTitle.arg(profileName));
this->setWindowTitle(defaultWindowTitle.arg(profileName));
}
void UserInterface::closeProfile()
{
if (profileOpen) {
if (profileOpen)
{
closeProfile_p();
}
setWindowTitle(defaultWindowTitle.arg(tr("Select Profile")));
this->setWindowTitle(defaultWindowTitle.arg(tr("Select Profile")));
}
void UserInterface::closeProfile_p()
@ -475,8 +348,11 @@ void UserInterface::closeEvent(QCloseEvent *ev)
UserInterface::~UserInterface()
{
if (profileOpen)
{
closeProfile_p();
for (QPushButton *profileBtn : profileBtns) {
}
for (QPushButton *profileBtn : profileBtns)
{
delete profileBtn;
}
profileBtns.clear();
@ -485,7 +361,7 @@ UserInterface::~UserInterface()
void UserInterface::on_actionExit_triggered()
{
close();
this->close();
}
void UserInterface::on_actionSelect_profile_triggered()
@ -523,25 +399,33 @@ void UserInterface::profileLoaded()
void UserInterface::on_actionSelect_all_triggered()
{
if (profileOpen)
{
profileUI->selectAllWidgets();
}
}
void UserInterface::on_actionDeselect_all_triggered()
{
if (profileOpen)
{
profileUI->deselectAllWidgets();
}
}
void UserInterface::on_actionExport_selected_triggered()
{
if (profileOpen)
{
profileUI->exportSelected();
}
}
void UserInterface::on_actionDelete_selected_triggered()
{
if (profileOpen)
{
profileUI->deleteSelected();
}
}
void UserInterface::on_actionOptions_triggered()
@ -566,7 +450,9 @@ void UserInterface::on_actionOptions_triggered()
void UserInterface::on_action_Import_triggered()
{
if (profileOpen)
{
profileUI->importFiles();
}
}
void UserInterface::on_actionOpen_File_triggered()
@ -580,11 +466,7 @@ fileDialogPreOpen:
fileDialog.setViewMode(QFileDialog::Detail);
fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
fileDialog.setOption(QFileDialog::DontUseNativeDialog, false);
#if QT_VERSION >= 0x050900
fileDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
#else
fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint);
#endif
fileDialog.setWindowTitle(tr("Open File..."));
QStringList filters;
@ -601,9 +483,11 @@ fileDialogPreOpen:
fileDialog.setDirectory(settings.value("OpenDialogDirectory", StandardPaths::documentsLocation()).toString());
fileDialog.restoreGeometry(settings.value("OpenDialogGeometry","").toByteArray());
if (fileDialog.exec()) {
if (fileDialog.exec())
{
QStringList selectedFiles = fileDialog.selectedFiles();
if (selectedFiles.length() == 1) {
if (selectedFiles.length() == 1)
{
QString selectedFile = selectedFiles.at(0);
if (!openFile(selectedFile, true)) goto fileDialogPreOpen;
}
@ -617,61 +501,68 @@ fileDialogPreOpen:
bool UserInterface::openFile(QString selectedFile, bool warn)
{
QString selectedFileName = QFileInfo(selectedFile).fileName();
if (QFile::exists(selectedFile)) {
if (selectedFileName.left(4) == "PGTA" || selectedFileName.right(4) == ".g5e") {
if (QFile::exists(selectedFile))
{
if (selectedFileName.left(4) == "PGTA" || selectedFileName.right(4) == ".g5e")
{
SnapmaticPicture *picture = new SnapmaticPicture(selectedFile);
if (picture->readingPicture()) {
if (picture->readingPicture())
{
openSnapmaticFile(picture);
delete picture;
return true;
}
else {
if (warn)
QMessageBox::warning(this, tr("Open File"), ProfileInterface::tr("Failed to read Snapmatic picture"));
else
{
if (warn) QMessageBox::warning(this, tr("Open File"), ProfileInterface::tr("Failed to read Snapmatic picture"));
delete picture;
return false;
}
}
else if (selectedFileName.left(4) == "SGTA") {
else if (selectedFileName.left(4) == "SGTA")
{
SavegameData *savegame = new SavegameData(selectedFile);
if (savegame->readingSavegame()) {
if (savegame->readingSavegame())
{
openSavegameFile(savegame);
delete savegame;
return true;
}
else {
if (warn)
QMessageBox::warning(this, tr("Open File"), ProfileInterface::tr("Failed to read Savegame file"));
else
{
if (warn) QMessageBox::warning(this, tr("Open File"), ProfileInterface::tr("Failed to read Savegame file"));
delete savegame;
return false;
}
}
else {
else
{
SnapmaticPicture *picture = new SnapmaticPicture(selectedFile);
SavegameData *savegame = new SavegameData(selectedFile);
if (picture->readingPicture()) {
if (picture->readingPicture())
{
delete savegame;
openSnapmaticFile(picture);
delete picture;
return true;
}
else if (savegame->readingSavegame()) {
else if (savegame->readingSavegame())
{
delete picture;
openSavegameFile(savegame);
delete savegame;
return true;
}
else {
else
{
delete savegame;
delete picture;
if (warn)
QMessageBox::warning(this, tr("Open File"), tr("Can't open %1 because of not valid file format").arg("\""+selectedFileName+"\""));
if (warn) QMessageBox::warning(this, tr("Open File"), tr("Can't open %1 because of not valid file format").arg("\""+selectedFileName+"\""));
return false;
}
}
}
if (warn)
QMessageBox::warning(this, tr("Open File"), ProfileInterface::tr("No valid file is selected"));
if (warn) QMessageBox::warning(this, tr("Open File"), ProfileInterface::tr("No valid file is selected"));
return false;
}
@ -682,8 +573,7 @@ void UserInterface::openSnapmaticFile(SnapmaticPicture *picture)
picDialog.setModal(true);
int crewID = picture->getSnapmaticProperties().crewID;
if (crewID != 0)
crewDB->addCrew(crewID);
if (crewID != 0) { crewDB->addCrew(crewID); }
QObject::connect(threadDB, SIGNAL(crewNameUpdated()), &picDialog, SLOT(crewNameUpdated()));
QObject::connect(threadDB, SIGNAL(playerNameUpdated()), &picDialog, SLOT(playerNameUpdated()));
@ -716,11 +606,13 @@ void UserInterface::openSavegameFile(SavegameData *savegame)
void UserInterface::settingsApplied(int _contentMode, bool languageChanged)
{
if (languageChanged) {
if (languageChanged)
{
retranslateUi();
}
contentMode = _contentMode;
if (profileOpen) {
if (profileOpen)
{
profileUI->settingsApplied(contentMode, languageChanged);
}
}
@ -754,11 +646,7 @@ void UserInterface::showMessages(const QStringList messages)
{
QDialog *messageDialog = new QDialog(this);
messageDialog->setWindowTitle(tr("%1 - Messages").arg(GTA5SYNC_APPSTR));
#if QT_VERSION >= 0x050900
messageDialog->setWindowFlag(Qt::WindowContextHelpButtonHint, false);
#else
messageDialog->setWindowFlags(messageDialog->windowFlags()^Qt::WindowContextHelpButtonHint);
#endif
QVBoxLayout *messageLayout = new QVBoxLayout;
messageDialog->setLayout(messageLayout);
QStackedWidget *stackWidget = new QStackedWidget(messageDialog);
@ -777,8 +665,8 @@ void UserInterface::showMessages(const QStringList messages)
nextButton->setIcon(QIcon::fromTheme("go-next"));
}
else {
backButton->setIcon(QIcon(AppEnv::getImagesFolder() % "/back.svgz"));
nextButton->setIcon(QIcon(AppEnv::getImagesFolder() % "/next.svgz"));
backButton->setIcon(QIcon(":/img/back.svgz"));
nextButton->setIcon(QIcon(":/img/next.svgz"));
}
backButton->setEnabled(false);
if (stackWidget->count() <= 1) {
@ -829,9 +717,7 @@ void UserInterface::showMessages(const QStringList messages)
});
QObject::connect(closeButton, &QPushButton::clicked, messageDialog, &QDialog::accept);
QObject::connect(messageDialog, &QDialog::finished, messageDialog, &QDialog::deleteLater);
QTimer::singleShot(0, closeButton, [=](){
closeButton->setFocus();
});
QTimer::singleShot(0, closeButton, SLOT(setFocus()));
messageDialog->show();
}
@ -847,8 +733,10 @@ void UserInterface::updateCacheId(uint cacheId)
void UserInterface::on_actionSelect_GTA_Folder_triggered()
{
QString GTAV_Folder_Temp = QFileDialog::getExistingDirectory(this, tr("Select GTA V Folder..."), StandardPaths::documentsLocation(), QFileDialog::ShowDirsOnly);
if (QDir(GTAV_Folder_Temp).exists()) {
if (profileOpen) {
if (QFileInfo(GTAV_Folder_Temp).exists())
{
if (profileOpen)
{
closeProfile_p();
}
GTAV_Folder = GTAV_Folder_Temp;
@ -861,41 +749,37 @@ void UserInterface::on_actionSelect_GTA_Folder_triggered()
void UserInterface::on_action_Enable_In_game_triggered()
{
if (profileOpen)
{
profileUI->enableSelected();
}
}
void UserInterface::on_action_Disable_In_game_triggered()
{
if (profileOpen)
{
profileUI->disableSelected();
}
}
void UserInterface::retranslateUi()
{
ui->retranslateUi(this);
#ifdef GTA5SYNC_DONATE
#ifdef GTA5SYNC_DONATE_ADDRESSES
donateAction->setText(tr("&Donate"));
#endif
#endif
#ifdef Q_OS_MAC
ui->actionAbout_gta5sync->setText(QApplication::translate("MAC_APPLICATION_MENU", "About %1").arg(GTA5SYNC_APPSTR));
ui->actionOptions->setText(QApplication::translate("MAC_APPLICATION_MENU", "Preferences..."));
#else
ui->actionAbout_gta5sync->setText(tr("&About %1").arg(GTA5SYNC_APPSTR));
#endif
QString appVersion = QApplication::applicationVersion();
const char* literalBuildType = GTA5SYNC_BUILDTYPE;
QString appVersion = GTA5SYNC_APPVER;
#ifndef GTA5SYNC_BUILDTYPE_REL
#ifdef GTA5SYNC_COMMIT
if ((strcmp(literalBuildType, REL_BUILDTYPE) != 0) && !appVersion.contains("-"))
appVersion = appVersion % "-" % GTA5SYNC_COMMIT;
if (!appVersion.contains("-")) { appVersion = appVersion % "-" % GTA5SYNC_COMMIT; }
#endif
#endif
ui->labVersion->setText(QString("%1 %2").arg(GTA5SYNC_APPSTR, appVersion));
if (profileOpen) {
setWindowTitle(defaultWindowTitle.arg(profileName));
if (profileOpen)
{
this->setWindowTitle(defaultWindowTitle.arg(profileName));
}
else {
setWindowTitle(defaultWindowTitle.arg(tr("Select Profile")));
else
{
this->setWindowTitle(defaultWindowTitle.arg(tr("Select Profile")));
}
}

View File

@ -90,11 +90,6 @@ private:
DatabaseThread *threadDB;
#ifdef GTA5SYNC_MOTD
MessageThread *threadMessage;
#endif
#ifdef GTA5SYNC_DONATE
#ifdef GTA5SYNC_DONATE_ADDRESSES
QAction *donateAction;
#endif
#endif
Ui::UserInterface *ui;
ProfileInterface *profileUI;

View File

@ -1,862 +0,0 @@
/*
* QR Code generator library (C++)
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
* - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* - The Software is provided "as is", without warranty of any kind, express or
* implied, including but not limited to the warranties of merchantability,
* fitness for a particular purpose and noninfringement. In no event shall the
* authors or copyright holders be liable for any claim, damages or other
* liability, whether in an action of contract, tort or otherwise, arising from,
* out of or in connection with the Software or the use or other dealings in the
* Software.
*/
#include <algorithm>
#include <climits>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <stdexcept>
#include <utility>
#include "QrCode.h"
using std::int8_t;
using std::uint8_t;
using std::size_t;
using std::vector;
namespace qrcodegen {
QrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) :
modeBits(mode) {
numBitsCharCount[0] = cc0;
numBitsCharCount[1] = cc1;
numBitsCharCount[2] = cc2;
}
int QrSegment::Mode::getModeBits() const {
return modeBits;
}
int QrSegment::Mode::numCharCountBits(int ver) const {
return numBitsCharCount[(ver + 7) / 17];
}
const QrSegment::Mode QrSegment::Mode::NUMERIC (0x1, 10, 12, 14);
const QrSegment::Mode QrSegment::Mode::ALPHANUMERIC(0x2, 9, 11, 13);
const QrSegment::Mode QrSegment::Mode::BYTE (0x4, 8, 16, 16);
const QrSegment::Mode QrSegment::Mode::KANJI (0x8, 8, 10, 12);
const QrSegment::Mode QrSegment::Mode::ECI (0x7, 0, 0, 0);
QrSegment QrSegment::makeBytes(const vector<uint8_t> &data) {
if (data.size() > static_cast<unsigned int>(INT_MAX))
throw std::length_error("Data too long");
BitBuffer bb;
for (uint8_t b : data)
bb.appendBits(b, 8);
return QrSegment(Mode::BYTE, static_cast<int>(data.size()), std::move(bb));
}
QrSegment QrSegment::makeNumeric(const char *digits) {
BitBuffer bb;
int accumData = 0;
int accumCount = 0;
int charCount = 0;
for (; *digits != '\0'; digits++, charCount++) {
char c = *digits;
if (c < '0' || c > '9')
throw std::domain_error("String contains non-numeric characters");
accumData = accumData * 10 + (c - '0');
accumCount++;
if (accumCount == 3) {
bb.appendBits(static_cast<uint32_t>(accumData), 10);
accumData = 0;
accumCount = 0;
}
}
if (accumCount > 0) // 1 or 2 digits remaining
bb.appendBits(static_cast<uint32_t>(accumData), accumCount * 3 + 1);
return QrSegment(Mode::NUMERIC, charCount, std::move(bb));
}
QrSegment QrSegment::makeAlphanumeric(const char *text) {
BitBuffer bb;
int accumData = 0;
int accumCount = 0;
int charCount = 0;
for (; *text != '\0'; text++, charCount++) {
const char *temp = std::strchr(ALPHANUMERIC_CHARSET, *text);
if (temp == nullptr)
throw std::domain_error("String contains unencodable characters in alphanumeric mode");
accumData = accumData * 45 + static_cast<int>(temp - ALPHANUMERIC_CHARSET);
accumCount++;
if (accumCount == 2) {
bb.appendBits(static_cast<uint32_t>(accumData), 11);
accumData = 0;
accumCount = 0;
}
}
if (accumCount > 0) // 1 character remaining
bb.appendBits(static_cast<uint32_t>(accumData), 6);
return QrSegment(Mode::ALPHANUMERIC, charCount, std::move(bb));
}
vector<QrSegment> QrSegment::makeSegments(const char *text) {
// Select the most efficient segment encoding automatically
vector<QrSegment> result;
if (*text == '\0'); // Leave result empty
else if (isNumeric(text))
result.push_back(makeNumeric(text));
else if (isAlphanumeric(text))
result.push_back(makeAlphanumeric(text));
else {
vector<uint8_t> bytes;
for (; *text != '\0'; text++)
bytes.push_back(static_cast<uint8_t>(*text));
result.push_back(makeBytes(bytes));
}
return result;
}
QrSegment QrSegment::makeEci(long assignVal) {
BitBuffer bb;
if (assignVal < 0)
throw std::domain_error("ECI assignment value out of range");
else if (assignVal < (1 << 7))
bb.appendBits(static_cast<uint32_t>(assignVal), 8);
else if (assignVal < (1 << 14)) {
bb.appendBits(2, 2);
bb.appendBits(static_cast<uint32_t>(assignVal), 14);
} else if (assignVal < 1000000L) {
bb.appendBits(6, 3);
bb.appendBits(static_cast<uint32_t>(assignVal), 21);
} else
throw std::domain_error("ECI assignment value out of range");
return QrSegment(Mode::ECI, 0, std::move(bb));
}
QrSegment::QrSegment(Mode md, int numCh, const std::vector<bool> &dt) :
mode(md),
numChars(numCh),
data(dt) {
if (numCh < 0)
throw std::domain_error("Invalid value");
}
QrSegment::QrSegment(Mode md, int numCh, std::vector<bool> &&dt) :
mode(md),
numChars(numCh),
data(std::move(dt)) {
if (numCh < 0)
throw std::domain_error("Invalid value");
}
int QrSegment::getTotalBits(const vector<QrSegment> &segs, int version) {
int result = 0;
for (const QrSegment &seg : segs) {
int ccbits = seg.mode.numCharCountBits(version);
if (seg.numChars >= (1L << ccbits))
return -1; // The segment's length doesn't fit the field's bit width
if (4 + ccbits > INT_MAX - result)
return -1; // The sum will overflow an int type
result += 4 + ccbits;
if (seg.data.size() > static_cast<unsigned int>(INT_MAX - result))
return -1; // The sum will overflow an int type
result += static_cast<int>(seg.data.size());
}
return result;
}
bool QrSegment::isAlphanumeric(const char *text) {
for (; *text != '\0'; text++) {
if (std::strchr(ALPHANUMERIC_CHARSET, *text) == nullptr)
return false;
}
return true;
}
bool QrSegment::isNumeric(const char *text) {
for (; *text != '\0'; text++) {
char c = *text;
if (c < '0' || c > '9')
return false;
}
return true;
}
QrSegment::Mode QrSegment::getMode() const {
return mode;
}
int QrSegment::getNumChars() const {
return numChars;
}
const std::vector<bool> &QrSegment::getData() const {
return data;
}
const char *QrSegment::ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
int QrCode::getFormatBits(Ecc ecl) {
switch (ecl) {
case Ecc::LOW : return 1;
case Ecc::MEDIUM : return 0;
case Ecc::QUARTILE: return 3;
case Ecc::HIGH : return 2;
default: throw std::logic_error("Assertion error");
}
}
QrCode QrCode::encodeText(const char *text, Ecc ecl) {
vector<QrSegment> segs = QrSegment::makeSegments(text);
return encodeSegments(segs, ecl);
}
QrCode QrCode::encodeBinary(const vector<uint8_t> &data, Ecc ecl) {
vector<QrSegment> segs{QrSegment::makeBytes(data)};
return encodeSegments(segs, ecl);
}
QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
int minVersion, int maxVersion, int mask, bool boostEcl) {
if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
throw std::invalid_argument("Invalid value");
// Find the minimal version number to use
int version, dataUsedBits;
for (version = minVersion; ; version++) {
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
dataUsedBits = QrSegment::getTotalBits(segs, version);
if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
break; // This version number is found to be suitable
if (version >= maxVersion) { // All versions in the range could not fit the given data
std::ostringstream sb;
if (dataUsedBits == -1)
sb << "Segment too long";
else {
sb << "Data length = " << dataUsedBits << " bits, ";
sb << "Max capacity = " << dataCapacityBits << " bits";
}
throw data_too_long(sb.str());
}
}
if (dataUsedBits == -1)
throw std::logic_error("Assertion error");
// Increase the error correction level while the data still fits in the current version number
for (Ecc newEcl : vector<Ecc>{Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) { // From low to high
if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
ecl = newEcl;
}
// Concatenate all segments to create the data bit string
BitBuffer bb;
for (const QrSegment &seg : segs) {
bb.appendBits(static_cast<uint32_t>(seg.getMode().getModeBits()), 4);
bb.appendBits(static_cast<uint32_t>(seg.getNumChars()), seg.getMode().numCharCountBits(version));
bb.insert(bb.end(), seg.getData().begin(), seg.getData().end());
}
if (bb.size() != static_cast<unsigned int>(dataUsedBits))
throw std::logic_error("Assertion error");
// Add terminator and pad up to a byte if applicable
size_t dataCapacityBits = static_cast<size_t>(getNumDataCodewords(version, ecl)) * 8;
if (bb.size() > dataCapacityBits)
throw std::logic_error("Assertion error");
bb.appendBits(0, std::min(4, static_cast<int>(dataCapacityBits - bb.size())));
bb.appendBits(0, (8 - static_cast<int>(bb.size() % 8)) % 8);
if (bb.size() % 8 != 0)
throw std::logic_error("Assertion error");
// Pad with alternating bytes until data capacity is reached
for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
bb.appendBits(padByte, 8);
// Pack bits into bytes in big endian
vector<uint8_t> dataCodewords(bb.size() / 8);
for (size_t i = 0; i < bb.size(); i++)
dataCodewords[i >> 3] |= (bb.at(i) ? 1 : 0) << (7 - (i & 7));
// Create the QR Code object
return QrCode(version, ecl, dataCodewords, mask);
}
QrCode::QrCode(int ver, Ecc ecl, const vector<uint8_t> &dataCodewords, int msk) :
// Initialize fields and check arguments
version(ver),
errorCorrectionLevel(ecl) {
if (ver < MIN_VERSION || ver > MAX_VERSION)
throw std::domain_error("Version value out of range");
if (msk < -1 || msk > 7)
throw std::domain_error("Mask value out of range");
size = ver * 4 + 17;
size_t sz = static_cast<size_t>(size);
modules = vector<vector<bool> >(sz, vector<bool>(sz)); // Initially all white
isFunction = vector<vector<bool> >(sz, vector<bool>(sz));
// Compute ECC, draw modules
drawFunctionPatterns();
const vector<uint8_t> allCodewords = addEccAndInterleave(dataCodewords);
drawCodewords(allCodewords);
// Do masking
if (msk == -1) { // Automatically choose best mask
long minPenalty = LONG_MAX;
for (int i = 0; i < 8; i++) {
applyMask(i);
drawFormatBits(i);
long penalty = getPenaltyScore();
if (penalty < minPenalty) {
msk = i;
minPenalty = penalty;
}
applyMask(i); // Undoes the mask due to XOR
}
}
if (msk < 0 || msk > 7)
throw std::logic_error("Assertion error");
this->mask = msk;
applyMask(msk); // Apply the final choice of mask
drawFormatBits(msk); // Overwrite old format bits
isFunction.clear();
isFunction.shrink_to_fit();
}
int QrCode::getVersion() const {
return version;
}
int QrCode::getSize() const {
return size;
}
QrCode::Ecc QrCode::getErrorCorrectionLevel() const {
return errorCorrectionLevel;
}
int QrCode::getMask() const {
return mask;
}
bool QrCode::getModule(int x, int y) const {
return 0 <= x && x < size && 0 <= y && y < size && module(x, y);
}
std::string QrCode::toSvgString(int border) const {
if (border < 0)
throw std::domain_error("Border must be non-negative");
if (border > INT_MAX / 2 || border * 2 > INT_MAX - size)
throw std::overflow_error("Border too large");
std::ostringstream sb;
sb << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
sb << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n";
sb << "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 ";
sb << (size + border * 2) << " " << (size + border * 2) << "\" stroke=\"none\">\n";
sb << "\t<rect width=\"100%\" height=\"100%\" fill=\"#FFFFFF\"/>\n";
sb << "\t<path d=\"";
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
if (getModule(x, y)) {
if (x != 0 || y != 0)
sb << " ";
sb << "M" << (x + border) << "," << (y + border) << "h1v1h-1z";
}
}
}
sb << "\" fill=\"#000000\"/>\n";
sb << "</svg>\n";
return sb.str();
}
void QrCode::drawFunctionPatterns() {
// Draw horizontal and vertical timing patterns
for (int i = 0; i < size; i++) {
setFunctionModule(6, i, i % 2 == 0);
setFunctionModule(i, 6, i % 2 == 0);
}
// Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
drawFinderPattern(3, 3);
drawFinderPattern(size - 4, 3);
drawFinderPattern(3, size - 4);
// Draw numerous alignment patterns
const vector<int> alignPatPos = getAlignmentPatternPositions();
size_t numAlign = alignPatPos.size();
for (size_t i = 0; i < numAlign; i++) {
for (size_t j = 0; j < numAlign; j++) {
// Don't draw on the three finder corners
if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)))
drawAlignmentPattern(alignPatPos.at(i), alignPatPos.at(j));
}
}
// Draw configuration data
drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
drawVersion();
}
void QrCode::drawFormatBits(int msk) {
// Calculate error correction code and pack bits
int data = getFormatBits(errorCorrectionLevel) << 3 | msk; // errCorrLvl is uint2, msk is uint3
int rem = data;
for (int i = 0; i < 10; i++)
rem = (rem << 1) ^ ((rem >> 9) * 0x537);
int bits = (data << 10 | rem) ^ 0x5412; // uint15
if (bits >> 15 != 0)
throw std::logic_error("Assertion error");
// Draw first copy
for (int i = 0; i <= 5; i++)
setFunctionModule(8, i, getBit(bits, i));
setFunctionModule(8, 7, getBit(bits, 6));
setFunctionModule(8, 8, getBit(bits, 7));
setFunctionModule(7, 8, getBit(bits, 8));
for (int i = 9; i < 15; i++)
setFunctionModule(14 - i, 8, getBit(bits, i));
// Draw second copy
for (int i = 0; i < 8; i++)
setFunctionModule(size - 1 - i, 8, getBit(bits, i));
for (int i = 8; i < 15; i++)
setFunctionModule(8, size - 15 + i, getBit(bits, i));
setFunctionModule(8, size - 8, true); // Always black
}
void QrCode::drawVersion() {
if (version < 7)
return;
// Calculate error correction code and pack bits
int rem = version; // version is uint6, in the range [7, 40]
for (int i = 0; i < 12; i++)
rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
long bits = static_cast<long>(version) << 12 | rem; // uint18
if (bits >> 18 != 0)
throw std::logic_error("Assertion error");
// Draw two copies
for (int i = 0; i < 18; i++) {
bool bit = getBit(bits, i);
int a = size - 11 + i % 3;
int b = i / 3;
setFunctionModule(a, b, bit);
setFunctionModule(b, a, bit);
}
}
void QrCode::drawFinderPattern(int x, int y) {
for (int dy = -4; dy <= 4; dy++) {
for (int dx = -4; dx <= 4; dx++) {
int dist = std::max(std::abs(dx), std::abs(dy)); // Chebyshev/infinity norm
int xx = x + dx, yy = y + dy;
if (0 <= xx && xx < size && 0 <= yy && yy < size)
setFunctionModule(xx, yy, dist != 2 && dist != 4);
}
}
}
void QrCode::drawAlignmentPattern(int x, int y) {
for (int dy = -2; dy <= 2; dy++) {
for (int dx = -2; dx <= 2; dx++)
setFunctionModule(x + dx, y + dy, std::max(std::abs(dx), std::abs(dy)) != 1);
}
}
void QrCode::setFunctionModule(int x, int y, bool isBlack) {
size_t ux = static_cast<size_t>(x);
size_t uy = static_cast<size_t>(y);
modules .at(uy).at(ux) = isBlack;
isFunction.at(uy).at(ux) = true;
}
bool QrCode::module(int x, int y) const {
return modules.at(static_cast<size_t>(y)).at(static_cast<size_t>(x));
}
vector<uint8_t> QrCode::addEccAndInterleave(const vector<uint8_t> &data) const {
if (data.size() != static_cast<unsigned int>(getNumDataCodewords(version, errorCorrectionLevel)))
throw std::invalid_argument("Invalid argument");
// Calculate parameter numbers
int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast<int>(errorCorrectionLevel)][version];
int blockEccLen = ECC_CODEWORDS_PER_BLOCK [static_cast<int>(errorCorrectionLevel)][version];
int rawCodewords = getNumRawDataModules(version) / 8;
int numShortBlocks = numBlocks - rawCodewords % numBlocks;
int shortBlockLen = rawCodewords / numBlocks;
// Split data into blocks and append ECC to each block
vector<vector<uint8_t> > blocks;
const vector<uint8_t> rsDiv = reedSolomonComputeDivisor(blockEccLen);
for (int i = 0, k = 0; i < numBlocks; i++) {
vector<uint8_t> dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)));
k += static_cast<int>(dat.size());
const vector<uint8_t> ecc = reedSolomonComputeRemainder(dat, rsDiv);
if (i < numShortBlocks)
dat.push_back(0);
dat.insert(dat.end(), ecc.cbegin(), ecc.cend());
blocks.push_back(std::move(dat));
}
// Interleave (not concatenate) the bytes from every block into a single sequence
vector<uint8_t> result;
for (size_t i = 0; i < blocks.at(0).size(); i++) {
for (size_t j = 0; j < blocks.size(); j++) {
// Skip the padding byte in short blocks
if (i != static_cast<unsigned int>(shortBlockLen - blockEccLen) || j >= static_cast<unsigned int>(numShortBlocks))
result.push_back(blocks.at(j).at(i));
}
}
if (result.size() != static_cast<unsigned int>(rawCodewords))
throw std::logic_error("Assertion error");
return result;
}
void QrCode::drawCodewords(const vector<uint8_t> &data) {
if (data.size() != static_cast<unsigned int>(getNumRawDataModules(version) / 8))
throw std::invalid_argument("Invalid argument");
size_t i = 0; // Bit index into the data
// Do the funny zigzag scan
for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
if (right == 6)
right = 5;
for (int vert = 0; vert < size; vert++) { // Vertical counter
for (int j = 0; j < 2; j++) {
size_t x = static_cast<size_t>(right - j); // Actual x coordinate
bool upward = ((right + 1) & 2) == 0;
size_t y = static_cast<size_t>(upward ? size - 1 - vert : vert); // Actual y coordinate
if (!isFunction.at(y).at(x) && i < data.size() * 8) {
modules.at(y).at(x) = getBit(data.at(i >> 3), 7 - static_cast<int>(i & 7));
i++;
}
// If this QR Code has any remainder bits (0 to 7), they were assigned as
// 0/false/white by the constructor and are left unchanged by this method
}
}
}
if (i != data.size() * 8)
throw std::logic_error("Assertion error");
}
void QrCode::applyMask(int msk) {
if (msk < 0 || msk > 7)
throw std::domain_error("Mask value out of range");
size_t sz = static_cast<size_t>(size);
for (size_t y = 0; y < sz; y++) {
for (size_t x = 0; x < sz; x++) {
bool invert;
switch (msk) {
case 0: invert = (x + y) % 2 == 0; break;
case 1: invert = y % 2 == 0; break;
case 2: invert = x % 3 == 0; break;
case 3: invert = (x + y) % 3 == 0; break;
case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
case 5: invert = x * y % 2 + x * y % 3 == 0; break;
case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
default: throw std::logic_error("Assertion error");
}
modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x));
}
}
}
long QrCode::getPenaltyScore() const {
long result = 0;
// Adjacent modules in row having same color, and finder-like patterns
for (int y = 0; y < size; y++) {
bool runColor = false;
int runX = 0;
std::array<int,7> runHistory = {};
for (int x = 0; x < size; x++) {
if (module(x, y) == runColor) {
runX++;
if (runX == 5)
result += PENALTY_N1;
else if (runX > 5)
result++;
} else {
finderPenaltyAddHistory(runX, runHistory);
if (!runColor)
result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
runColor = module(x, y);
runX = 1;
}
}
result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3;
}
// Adjacent modules in column having same color, and finder-like patterns
for (int x = 0; x < size; x++) {
bool runColor = false;
int runY = 0;
std::array<int,7> runHistory = {};
for (int y = 0; y < size; y++) {
if (module(x, y) == runColor) {
runY++;
if (runY == 5)
result += PENALTY_N1;
else if (runY > 5)
result++;
} else {
finderPenaltyAddHistory(runY, runHistory);
if (!runColor)
result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
runColor = module(x, y);
runY = 1;
}
}
result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3;
}
// 2*2 blocks of modules having same color
for (int y = 0; y < size - 1; y++) {
for (int x = 0; x < size - 1; x++) {
bool color = module(x, y);
if ( color == module(x + 1, y) &&
color == module(x, y + 1) &&
color == module(x + 1, y + 1))
result += PENALTY_N2;
}
}
// Balance of black and white modules
int black = 0;
for (const vector<bool> &row : modules) {
for (bool color : row) {
if (color)
black++;
}
}
int total = size * size; // Note that size is odd, so black/total != 1/2
// Compute the smallest integer k >= 0 such that (45-5k)% <= black/total <= (55+5k)%
int k = static_cast<int>((std::abs(black * 20L - total * 10L) + total - 1) / total) - 1;
result += k * PENALTY_N4;
return result;
}
vector<int> QrCode::getAlignmentPatternPositions() const {
if (version == 1)
return vector<int>();
else {
int numAlign = version / 7 + 2;
int step = (version == 32) ? 26 :
(version*4 + numAlign*2 + 1) / (numAlign*2 - 2) * 2;
vector<int> result;
for (int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step)
result.insert(result.begin(), pos);
result.insert(result.begin(), 6);
return result;
}
}
int QrCode::getNumRawDataModules(int ver) {
if (ver < MIN_VERSION || ver > MAX_VERSION)
throw std::domain_error("Version number out of range");
int result = (16 * ver + 128) * ver + 64;
if (ver >= 2) {
int numAlign = ver / 7 + 2;
result -= (25 * numAlign - 10) * numAlign - 55;
if (ver >= 7)
result -= 36;
}
if (!(208 <= result && result <= 29648))
throw std::logic_error("Assertion error");
return result;
}
int QrCode::getNumDataCodewords(int ver, Ecc ecl) {
return getNumRawDataModules(ver) / 8
- ECC_CODEWORDS_PER_BLOCK [static_cast<int>(ecl)][ver]
* NUM_ERROR_CORRECTION_BLOCKS[static_cast<int>(ecl)][ver];
}
vector<uint8_t> QrCode::reedSolomonComputeDivisor(int degree) {
if (degree < 1 || degree > 255)
throw std::domain_error("Degree out of range");
// Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.
// For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
vector<uint8_t> result(static_cast<size_t>(degree));
result.at(result.size() - 1) = 1; // Start off with the monomial x^0
// Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
// and drop the highest monomial term which is always 1x^degree.
// Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
uint8_t root = 1;
for (int i = 0; i < degree; i++) {
// Multiply the current product by (x - r^i)
for (size_t j = 0; j < result.size(); j++) {
result.at(j) = reedSolomonMultiply(result.at(j), root);
if (j + 1 < result.size())
result.at(j) ^= result.at(j + 1);
}
root = reedSolomonMultiply(root, 0x02);
}
return result;
}
vector<uint8_t> QrCode::reedSolomonComputeRemainder(const vector<uint8_t> &data, const vector<uint8_t> &divisor) {
vector<uint8_t> result(divisor.size());
for (uint8_t b : data) { // Polynomial division
uint8_t factor = b ^ result.at(0);
result.erase(result.begin());
result.push_back(0);
for (size_t i = 0; i < result.size(); i++)
result.at(i) ^= reedSolomonMultiply(divisor.at(i), factor);
}
return result;
}
uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) {
// Russian peasant multiplication
int z = 0;
for (int i = 7; i >= 0; i--) {
z = (z << 1) ^ ((z >> 7) * 0x11D);
z ^= ((y >> i) & 1) * x;
}
if (z >> 8 != 0)
throw std::logic_error("Assertion error");
return static_cast<uint8_t>(z);
}
int QrCode::finderPenaltyCountPatterns(const std::array<int,7> &runHistory) const {
int n = runHistory.at(1);
if (n > size * 3)
throw std::logic_error("Assertion error");
bool core = n > 0 && runHistory.at(2) == n && runHistory.at(3) == n * 3 && runHistory.at(4) == n && runHistory.at(5) == n;
return (core && runHistory.at(0) >= n * 4 && runHistory.at(6) >= n ? 1 : 0)
+ (core && runHistory.at(6) >= n * 4 && runHistory.at(0) >= n ? 1 : 0);
}
int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array<int,7> &runHistory) const {
if (currentRunColor) { // Terminate black run
finderPenaltyAddHistory(currentRunLength, runHistory);
currentRunLength = 0;
}
currentRunLength += size; // Add white border to final run
finderPenaltyAddHistory(currentRunLength, runHistory);
return finderPenaltyCountPatterns(runHistory);
}
void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array<int,7> &runHistory) const {
if (runHistory.at(0) == 0)
currentRunLength += size; // Add white border to initial run
std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end());
runHistory.at(0) = currentRunLength;
}
bool QrCode::getBit(long x, int i) {
return ((x >> i) & 1) != 0;
}
/*---- Tables of constants ----*/
const int QrCode::PENALTY_N1 = 3;
const int QrCode::PENALTY_N2 = 3;
const int QrCode::PENALTY_N3 = 40;
const int QrCode::PENALTY_N4 = 10;
const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = {
// Version: (note that index 0 is for padding, and is set to an illegal value)
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
{-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low
{-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium
{-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile
{-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High
};
const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
// Version: (note that index 0 is for padding, and is set to an illegal value)
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
{-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low
{-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium
{-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile
{-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High
};
data_too_long::data_too_long(const std::string &msg) :
std::length_error(msg) {}
BitBuffer::BitBuffer()
: std::vector<bool>() {}
void BitBuffer::appendBits(std::uint32_t val, int len) {
if (len < 0 || len > 31 || val >> len != 0)
throw std::domain_error("Value out of range");
for (int i = len - 1; i >= 0; i--) // Append bit by bit
this->push_back(((val >> i) & 1) != 0);
}
}

View File

@ -1,556 +0,0 @@
/*
* QR Code generator library (C++)
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
* - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* - The Software is provided "as is", without warranty of any kind, express or
* implied, including but not limited to the warranties of merchantability,
* fitness for a particular purpose and noninfringement. In no event shall the
* authors or copyright holders be liable for any claim, damages or other
* liability, whether in an action of contract, tort or otherwise, arising from,
* out of or in connection with the Software or the use or other dealings in the
* Software.
*/
#pragma once
#include <array>
#include <cstdint>
#include <stdexcept>
#include <string>
#include <vector>
namespace qrcodegen {
/*
* A segment of character/binary/control data in a QR Code symbol.
* Instances of this class are immutable.
* The mid-level way to create a segment is to take the payload data
* and call a static factory function such as QrSegment::makeNumeric().
* The low-level way to create a segment is to custom-make the bit buffer
* and call the QrSegment() constructor with appropriate values.
* This segment class imposes no length restrictions, but QR Codes have restrictions.
* Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
* Any segment longer than this is meaningless for the purpose of generating QR Codes.
*/
class QrSegment final {
/*---- Public helper enumeration ----*/
/*
* Describes how a segment's data bits are interpreted. Immutable.
*/
public: class Mode final {
/*-- Constants --*/
public: static const Mode NUMERIC;
public: static const Mode ALPHANUMERIC;
public: static const Mode BYTE;
public: static const Mode KANJI;
public: static const Mode ECI;
/*-- Fields --*/
// The mode indicator bits, which is a uint4 value (range 0 to 15).
private: int modeBits;
// Number of character count bits for three different version ranges.
private: int numBitsCharCount[3];
/*-- Constructor --*/
private: Mode(int mode, int cc0, int cc1, int cc2);
/*-- Methods --*/
/*
* (Package-private) Returns the mode indicator bits, which is an unsigned 4-bit value (range 0 to 15).
*/
public: int getModeBits() const;
/*
* (Package-private) Returns the bit width of the character count field for a segment in
* this mode in a QR Code at the given version number. The result is in the range [0, 16].
*/
public: int numCharCountBits(int ver) const;
};
/*---- Static factory functions (mid level) ----*/
/*
* Returns a segment representing the given binary data encoded in
* byte mode. All input byte vectors are acceptable. Any text string
* can be converted to UTF-8 bytes and encoded as a byte mode segment.
*/
public: static QrSegment makeBytes(const std::vector<std::uint8_t> &data);
/*
* Returns a segment representing the given string of decimal digits encoded in numeric mode.
*/
public: static QrSegment makeNumeric(const char *digits);
/*
* Returns a segment representing the given text string encoded in alphanumeric mode.
* The characters allowed are: 0 to 9, A to Z (uppercase only), space,
* dollar, percent, asterisk, plus, hyphen, period, slash, colon.
*/
public: static QrSegment makeAlphanumeric(const char *text);
/*
* Returns a list of zero or more segments to represent the given text string. The result
* may use various segment modes and switch modes to optimize the length of the bit stream.
*/
public: static std::vector<QrSegment> makeSegments(const char *text);
/*
* Returns a segment representing an Extended Channel Interpretation
* (ECI) designator with the given assignment value.
*/
public: static QrSegment makeEci(long assignVal);
/*---- Public static helper functions ----*/
/*
* Tests whether the given string can be encoded as a segment in alphanumeric mode.
* A string is encodable iff each character is in the following set: 0 to 9, A to Z
* (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
*/
public: static bool isAlphanumeric(const char *text);
/*
* Tests whether the given string can be encoded as a segment in numeric mode.
* A string is encodable iff each character is in the range 0 to 9.
*/
public: static bool isNumeric(const char *text);
/*---- Instance fields ----*/
/* The mode indicator of this segment. Accessed through getMode(). */
private: Mode mode;
/* The length of this segment's unencoded data. Measured in characters for
* numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
* Always zero or positive. Not the same as the data's bit length.
* Accessed through getNumChars(). */
private: int numChars;
/* The data bits of this segment. Accessed through getData(). */
private: std::vector<bool> data;
/*---- Constructors (low level) ----*/
/*
* Creates a new QR Code segment with the given attributes and data.
* The character count (numCh) must agree with the mode and the bit buffer length,
* but the constraint isn't checked. The given bit buffer is copied and stored.
*/
public: QrSegment(Mode md, int numCh, const std::vector<bool> &dt);
/*
* Creates a new QR Code segment with the given parameters and data.
* The character count (numCh) must agree with the mode and the bit buffer length,
* but the constraint isn't checked. The given bit buffer is moved and stored.
*/
public: QrSegment(Mode md, int numCh, std::vector<bool> &&dt);
/*---- Methods ----*/
/*
* Returns the mode field of this segment.
*/
public: Mode getMode() const;
/*
* Returns the character count field of this segment.
*/
public: int getNumChars() const;
/*
* Returns the data bits of this segment.
*/
public: const std::vector<bool> &getData() const;
// (Package-private) Calculates the number of bits needed to encode the given segments at
// the given version. Returns a non-negative number if successful. Otherwise returns -1 if a
// segment has too many characters to fit its length field, or the total bits exceeds INT_MAX.
public: static int getTotalBits(const std::vector<QrSegment> &segs, int version);
/*---- Private constant ----*/
/* The set of all legal characters in alphanumeric mode, where
* each character value maps to the index in the string. */
private: static const char *ALPHANUMERIC_CHARSET;
};
/*
* A QR Code symbol, which is a type of two-dimension barcode.
* Invented by Denso Wave and described in the ISO/IEC 18004 standard.
* Instances of this class represent an immutable square grid of black and white cells.
* The class provides static factory functions to create a QR Code from text or binary data.
* The class covers the QR Code Model 2 specification, supporting all versions (sizes)
* from 1 to 40, all 4 error correction levels, and 4 character encoding modes.
*
* Ways to create a QR Code object:
* - High level: Take the payload data and call QrCode::encodeText() or QrCode::encodeBinary().
* - Mid level: Custom-make the list of segments and call QrCode::encodeSegments().
* - Low level: Custom-make the array of data codeword bytes (including
* segment headers and final padding, excluding error correction codewords),
* supply the appropriate version number, and call the QrCode() constructor.
* (Note that all ways require supplying the desired error correction level.)
*/
class QrCode final {
/*---- Public helper enumeration ----*/
/*
* The error correction level in a QR Code symbol.
*/
public: enum class Ecc {
LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords
MEDIUM , // The QR Code can tolerate about 15% erroneous codewords
QUARTILE, // The QR Code can tolerate about 25% erroneous codewords
HIGH , // The QR Code can tolerate about 30% erroneous codewords
};
// Returns a value in the range 0 to 3 (unsigned 2-bit integer).
private: static int getFormatBits(Ecc ecl);
/*---- Static factory functions (high level) ----*/
/*
* Returns a QR Code representing the given Unicode text string at the given error correction level.
* As a conservative upper bound, this function is guaranteed to succeed for strings that have 2953 or fewer
* UTF-8 code units (not Unicode code points) if the low error correction level is used. The smallest possible
* QR Code version is automatically chosen for the output. The ECC level of the result may be higher than
* the ecl argument if it can be done without increasing the version.
*/
public: static QrCode encodeText(const char *text, Ecc ecl);
/*
* Returns a QR Code representing the given binary data at the given error correction level.
* This function always encodes using the binary segment mode, not any text mode. The maximum number of
* bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
* The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
*/
public: static QrCode encodeBinary(const std::vector<std::uint8_t> &data, Ecc ecl);
/*---- Static factory functions (mid level) ----*/
/*
* Returns a QR Code representing the given segments with the given encoding parameters.
* The smallest possible QR Code version within the given range is automatically
* chosen for the output. Iff boostEcl is true, then the ECC level of the result
* may be higher than the ecl argument if it can be done without increasing the
* version. The mask number is either between 0 to 7 (inclusive) to force that
* mask, or -1 to automatically choose an appropriate mask (which may be slow).
* This function allows the user to create a custom sequence of segments that switches
* between modes (such as alphanumeric and byte) to encode text in less space.
* This is a mid-level API; the high-level API is encodeText() and encodeBinary().
*/
public: static QrCode encodeSegments(const std::vector<QrSegment> &segs, Ecc ecl,
int minVersion=1, int maxVersion=40, int mask=-1, bool boostEcl=true); // All optional parameters
/*---- Instance fields ----*/
// Immutable scalar parameters:
/* The version number of this QR Code, which is between 1 and 40 (inclusive).
* This determines the size of this barcode. */
private: int version;
/* The width and height of this QR Code, measured in modules, between
* 21 and 177 (inclusive). This is equal to version * 4 + 17. */
private: int size;
/* The error correction level used in this QR Code. */
private: Ecc errorCorrectionLevel;
/* The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive).
* Even if a QR Code is created with automatic masking requested (mask = -1),
* the resulting object still has a mask value between 0 and 7. */
private: int mask;
// Private grids of modules/pixels, with dimensions of size*size:
// The modules of this QR Code (false = white, true = black).
// Immutable after constructor finishes. Accessed through getModule().
private: std::vector<std::vector<bool> > modules;
// Indicates function modules that are not subjected to masking. Discarded when constructor finishes.
private: std::vector<std::vector<bool> > isFunction;
/*---- Constructor (low level) ----*/
/*
* Creates a new QR Code with the given version number,
* error correction level, data codeword bytes, and mask number.
* This is a low-level API that most users should not use directly.
* A mid-level API is the encodeSegments() function.
*/
public: QrCode(int ver, Ecc ecl, const std::vector<std::uint8_t> &dataCodewords, int msk);
/*---- Public instance methods ----*/
/*
* Returns this QR Code's version, in the range [1, 40].
*/
public: int getVersion() const;
/*
* Returns this QR Code's size, in the range [21, 177].
*/
public: int getSize() const;
/*
* Returns this QR Code's error correction level.
*/
public: Ecc getErrorCorrectionLevel() const;
/*
* Returns this QR Code's mask, in the range [0, 7].
*/
public: int getMask() const;
/*
* Returns the color of the module (pixel) at the given coordinates, which is false
* for white or true for black. The top left corner has the coordinates (x=0, y=0).
* If the given coordinates are out of bounds, then false (white) is returned.
*/
public: bool getModule(int x, int y) const;
/*
* Returns a string of SVG code for an image depicting this QR Code, with the given number
* of border modules. The string always uses Unix newlines (\n), regardless of the platform.
*/
public: std::string toSvgString(int border) const;
/*---- Private helper methods for constructor: Drawing function modules ----*/
// Reads this object's version field, and draws and marks all function modules.
private: void drawFunctionPatterns();
// Draws two copies of the format bits (with its own error correction code)
// based on the given mask and this object's error correction level field.
private: void drawFormatBits(int msk);
// Draws two copies of the version bits (with its own error correction code),
// based on this object's version field, iff 7 <= version <= 40.
private: void drawVersion();
// Draws a 9*9 finder pattern including the border separator,
// with the center module at (x, y). Modules can be out of bounds.
private: void drawFinderPattern(int x, int y);
// Draws a 5*5 alignment pattern, with the center module
// at (x, y). All modules must be in bounds.
private: void drawAlignmentPattern(int x, int y);
// Sets the color of a module and marks it as a function module.
// Only used by the constructor. Coordinates must be in bounds.
private: void setFunctionModule(int x, int y, bool isBlack);
// Returns the color of the module at the given coordinates, which must be in range.
private: bool module(int x, int y) const;
/*---- Private helper methods for constructor: Codewords and masking ----*/
// Returns a new byte string representing the given data with the appropriate error correction
// codewords appended to it, based on this object's version and error correction level.
private: std::vector<std::uint8_t> addEccAndInterleave(const std::vector<std::uint8_t> &data) const;
// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
// data area of this QR Code. Function modules need to be marked off before this is called.
private: void drawCodewords(const std::vector<std::uint8_t> &data);
// XORs the codeword modules in this QR Code with the given mask pattern.
// The function modules must be marked and the codeword bits must be drawn
// before masking. Due to the arithmetic of XOR, calling applyMask() with
// the same mask value a second time will undo the mask. A final well-formed
// QR Code needs exactly one (not zero, two, etc.) mask applied.
private: void applyMask(int msk);
// Calculates and returns the penalty score based on state of this QR Code's current modules.
// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
private: long getPenaltyScore() const;
/*---- Private helper functions ----*/
// Returns an ascending list of positions of alignment patterns for this version number.
// Each position is in the range [0,177), and are used on both the x and y axes.
// This could be implemented as lookup table of 40 variable-length lists of unsigned bytes.
private: std::vector<int> getAlignmentPatternPositions() const;
// Returns the number of data bits that can be stored in a QR Code of the given version number, after
// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
private: static int getNumRawDataModules(int ver);
// Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
// QR Code of the given version number and error correction level, with remainder bits discarded.
// This stateless pure function could be implemented as a (40*4)-cell lookup table.
private: static int getNumDataCodewords(int ver, Ecc ecl);
// Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be
// implemented as a lookup table over all possible parameter values, instead of as an algorithm.
private: static std::vector<std::uint8_t> reedSolomonComputeDivisor(int degree);
// Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials.
private: static std::vector<std::uint8_t> reedSolomonComputeRemainder(const std::vector<std::uint8_t> &data, const std::vector<std::uint8_t> &divisor);
// Returns the product of the two given field elements modulo GF(2^8/0x11D).
// All inputs are valid. This could be implemented as a 256*256 lookup table.
private: static std::uint8_t reedSolomonMultiply(std::uint8_t x, std::uint8_t y);
// Can only be called immediately after a white run is added, and
// returns either 0, 1, or 2. A helper function for getPenaltyScore().
private: int finderPenaltyCountPatterns(const std::array<int,7> &runHistory) const;
// Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore().
private: int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array<int,7> &runHistory) const;
// Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().
private: void finderPenaltyAddHistory(int currentRunLength, std::array<int,7> &runHistory) const;
// Returns true iff the i'th bit of x is set to 1.
private: static bool getBit(long x, int i);
/*---- Constants and tables ----*/
// The minimum version number supported in the QR Code Model 2 standard.
public: static constexpr int MIN_VERSION = 1;
// The maximum version number supported in the QR Code Model 2 standard.
public: static constexpr int MAX_VERSION = 40;
// For use in getPenaltyScore(), when evaluating which mask is best.
private: static const int PENALTY_N1;
private: static const int PENALTY_N2;
private: static const int PENALTY_N3;
private: static const int PENALTY_N4;
private: static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][41];
private: static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41];
};
/*---- Public exception class ----*/
/*
* Thrown when the supplied data does not fit any QR Code version. Ways to handle this exception include:
* - Decrease the error correction level if it was greater than Ecc::LOW.
* - If the encodeSegments() function was called with a maxVersion argument, then increase
* it if it was less than QrCode::MAX_VERSION. (This advice does not apply to the other
* factory functions because they search all versions up to QrCode::MAX_VERSION.)
* - Split the text data into better or optimal segments in order to reduce the number of bits required.
* - Change the text or binary data to be shorter.
* - Change the text to fit the character set of a particular segment mode (e.g. alphanumeric).
* - Propagate the error upward to the caller/user.
*/
class data_too_long : public std::length_error {
public: explicit data_too_long(const std::string &msg);
};
/*
* An appendable sequence of bits (0s and 1s). Mainly used by QrSegment.
*/
class BitBuffer final : public std::vector<bool> {
/*---- Constructor ----*/
// Creates an empty bit buffer (length 0).
public: BitBuffer();
/*---- Method ----*/
// Appends the given number of low-order bits of the given value
// to this buffer. Requires 0 <= len <= 31 and val < 2^len.
public: void appendBits(std::uint32_t val, int len);
};
}

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 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,13 +21,6 @@
#if __cplusplus
#include <QString>
#define REL_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Release")
#define RC_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Release Candidate")
#define BETA_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Beta")
#define ALPHA_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Alpha")
#define DEV_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Developer")
#define DAILY_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Daily Build")
#define CUSTOM_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Custom")
#endif
#ifndef GTA5SYNC_APPVENDOR
@ -35,7 +28,7 @@
#endif
#ifndef GTA5SYNC_APPVENDORLINK
#define GTA5SYNC_APPVENDORLINK "g5e://about?U3lwaW5n:R2l0TGFiOiA8YSBocmVmPSJodHRwczovL2dpdGxhYi5jb20vU3lwaW5nIj5TeXBpbmc8L2E+PGJyLz5HaXRIdWI6IDxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9TeXBpbmciPlN5cGluZzwvYT48YnIvPlNvY2lhbCBDbHViOiA8YSBocmVmPSJodHRwczovL3NvY2lhbGNsdWIucm9ja3N0YXJnYW1lcy5jb20vbWVtYmVyL1N5cGluZy80NjMwMzA1NiI+U3lwaW5nPC9hPg"
#define GTA5SYNC_APPVENDORLINK "g5e://about?U3lwaW5n:R2l0TGFiOiA8YSBocmVmPSJodHRwczovL2dpdGxhYi5jb20vU3lwaW5nIj5TeXBpbmc8L2E+PGJyLz5HaXRIdWI6IDxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9TeXBpbmciPlN5cGluZzwvYT48YnIvPlNvY2lhbCBDbHViOiA8YSBocmVmPSJodHRwczovL3NvY2lhbGNsdWIucm9ja3N0YXJnYW1lcy5jb20vbWVtYmVyL1N5cGluZy80NjMwMzA1NiI+U3lwaW5nPC9hPg=="
#endif
#ifndef GTA5SYNC_APPSTR
@ -47,14 +40,50 @@
#endif
#ifndef GTA5SYNC_COPYRIGHT
#define GTA5SYNC_COPYRIGHT "2016-2023"
#define GTA5SYNC_COPYRIGHT "2016-2020"
#endif
#ifndef GTA5SYNC_APPVER
#define GTA5SYNC_APPVER "1.10.2"
#define GTA5SYNC_APPVER "1.8.0"
#endif
#if __cplusplus
#ifdef GTA5SYNC_BUILDTYPE_REL
#ifndef GTA5SYNC_BUILDTYPE
#define GTA5SYNC_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Release")
#endif
#endif
#ifdef GTA5SYNC_BUILDTYPE_RC
#ifndef GTA5SYNC_BUILDTYPE
#define GTA5SYNC_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Release Candidate")
#endif
#endif
#ifdef GTA5SYNC_BUILDTYPE_DAILY
#ifndef GTA5SYNC_BUILDTYPE
#define GTA5SYNC_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Daily Build")
#endif
#endif
#ifdef GTA5SYNC_BUILDTYPE_DEV
#ifndef GTA5SYNC_BUILDTYPE
#define GTA5SYNC_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Developer")
#endif
#endif
#ifdef GTA5SYNC_BUILDTYPE_BETA
#ifndef GTA5SYNC_BUILDTYPE
#define GTA5SYNC_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Beta")
#endif
#endif
#ifdef GTA5SYNC_BUILDTYPE_ALPHA
#ifndef GTA5SYNC_BUILDTYPE
#define GTA5SYNC_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Alpha")
#endif
#endif
#ifndef GTA5SYNC_BUILDTYPE
#define GTA5SYNC_BUILDTYPE QT_TRANSLATE_NOOP("AboutDialog", "Custom")
#endif
@ -65,11 +94,7 @@
#ifdef GTA5SYNC_QCONF
#ifndef GTA5SYNC_SHARE
#ifdef Q_OS_WIN
#define GTA5SYNC_SHARE "RUNDIR:"
#else
#define GTA5SYNC_SHARE "RUNDIR:/../share"
#endif
#define GTA5SYNC_SHARE "RUNDIR:SEPARATOR:..SEPARATOR:share"
#endif
#ifndef GTA5SYNC_LANG
#define GTA5SYNC_LANG "QCONFLANG:"
@ -87,10 +112,10 @@
#define GTA5SYNC_SHARE "RUNDIR:"
#endif
#ifndef GTA5SYNC_LANG
#define GTA5SYNC_LANG "SHAREDDIR:/lang"
#define GTA5SYNC_LANG "SHAREDDIR:SEPARATOR:lang"
#endif
#ifndef GTA5SYNC_PLUG
#define GTA5SYNC_PLUG "RUNDIR:/plugins"
#define GTA5SYNC_PLUG "RUNDIR:SEPARATOR:plugins"
#endif
#endif

View File

@ -1,6 +1,6 @@
#/*****************************************************************************
#* gta5view Grand Theft Auto V Profile Viewer
#* Copyright (C) 2015-2021 Syping
#* Copyright (C) 2015-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
@ -19,14 +19,13 @@
QT += core gui network svg
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 4): win32: LIBS += -ldwmapi
greaterThan(QT_MAJOR_VERSION, 4): greaterThan(QT_MINOR_VERSION, 1): win32: QT += winextras
DEPLOYMENT.display_name = gta5view
TARGET = gta5view
TEMPLATE = app
HEADERS += config.h \
wrapper.h
HEADERS += config.h
PRECOMPILED_HEADER += config.h
SOURCES += main.cpp \
@ -51,7 +50,6 @@ SOURCES += main.cpp \
ProfileInterface.cpp \
ProfileLoader.cpp \
ProfileWidget.cpp \
RagePhoto.cpp \
SavegameCopy.cpp \
SavegameData.cpp \
SavegameDialog.cpp \
@ -94,7 +92,6 @@ HEADERS += \
ProfileInterface.h \
ProfileLoader.h \
ProfileWidget.h \
RagePhoto.h \
SavegameCopy.h \
SavegameData.h \
SavegameDialog.h \
@ -144,8 +141,7 @@ TRANSLATIONS += \
res/gta5sync_zh_TW.ts
RESOURCES += \
res/img.qrc \
res/template.qrc \
res/app.qrc \
res/tr_g5p.qrc
DISTFILES += \
@ -179,6 +175,7 @@ INCLUDEPATH += ./anpro ./pcg ./tmext ./uimod
DEFINES += GTA5SYNC_QMAKE # We using qmake do we?
DEFINES += GTA5SYNC_PROJECT # Enable exclusive gta5sync/gta5view functions
DEFINES += SNAPMATIC_NODEFAULT # Not assisting at proper usage of SnapmaticPicture class
# WINDOWS ONLY
@ -187,7 +184,7 @@ win32: CONFIG -= embed_manifest_exe
contains(DEFINES, GTA5SYNC_TELEMETRY): win32: LIBS += -ld3d9 # Required for getting information about GPU
# MAC OS X ONLY
macx: ICON = res/gta5view.icns
macx: ICON = res/5sync.icns
# QT4 ONLY STUFF
@ -209,21 +206,17 @@ isEqual(QT_MAJOR_VERSION, 4): SOURCES += qjson4/QJsonArray.cpp \
qjson4/QJsonValueRef.cpp \
qjson4/QJsonParser.cpp
isEqual(QT_MAJOR_VERSION, 4): RESOURCES += res/qt4/tr_qt.qrc
isEqual(QT_MAJOR_VERSION, 4): RESOURCES += res/tr_qt4.qrc
isEqual(QT_MAJOR_VERSION, 4): GTA5SYNC_RCC = $$[QT_INSTALL_BINS]/rcc
# QT5 ONLY STUFF
isEqual(QT_MAJOR_VERSION, 5): RESOURCES += res/qt5/tr_qt.qrc
isEqual(QT_MAJOR_VERSION, 5): RESOURCES += res/tr_qt5.qrc
# QT5+ ONLY STUFF
greaterThan(QT_MAJOR_VERSION, 4): GTA5SYNC_RCC = $$[QT_HOST_BINS]/rcc
# QT6 ONLY STUFF
isEqual(QT_MAJOR_VERSION, 6): RESOURCES += res/qt6/tr_qt.qrc
# RESOURCE COMPILATION
system($$GTA5SYNC_RCC -threshold 0 -compress 9 $$PWD/res/global.qrc -o $$OUT_PWD/qrc_global.cpp) {
@ -246,9 +239,8 @@ INSTALLS += target pixmaps appfiles
# QCONF BASED BUILD STUFF
contains(DEFINES, GTA5SYNC_QCONF) {
isEqual(QT_MAJOR_VERSION, 4): RESOURCES -= res/qt4/tr_qt.qrc
isEqual(QT_MAJOR_VERSION, 5): RESOURCES -= res/qt5/tr_qt.qrc
isEqual(QT_MAJOR_VERSION, 6): RESOURCES -= res/qt6/tr_qt.qrc
isEqual(QT_MAJOR_VERSION, 4): RESOURCES -= res/tr_qt4.qrc
isEqual(QT_MAJOR_VERSION, 5): RESOURCES -= res/tr_qt5.qrc
!contains(DEFINES, GTA5SYNC_QCONF_IN) {
RESOURCES -= res/tr_g5p.qrc
langfiles.path = $$GTA5SYNC_PREFIX/share/gta5view/translations

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2021 Syping
* Copyright (C) 2016-2019 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
@ -49,6 +49,7 @@
#include <QLayout>
#include <QObject>
#include <QString>
#include <QDebug>
#include <QFont>
#include <QFile>
@ -93,30 +94,28 @@ int main(int argc, char *argv[])
settings.sync();
#endif
bool isFirstStart = settings.value("IsFirstStart", true).toBool();
bool customStyle = settings.value("CustomStyle", false).toBool();
if (customStyle) {
const QString appStyle = settings.value("AppStyle", "Default").toString();
if (QStyleFactory::keys().contains(appStyle, Qt::CaseInsensitive)) {
QString appStyle = settings.value("AppStyle", "Default").toString();
if (customStyle)
{
if (QStyleFactory::keys().contains(appStyle, Qt::CaseInsensitive))
{
a.setStyle(QStyleFactory::create(appStyle));
}
}
#ifdef Q_OS_WIN
#if QT_VERSION >= 0x060000
a.setFont(QApplication::font("QMenu"));
#elif QT_VERSION >= 0x050400
if (QSysInfo::windowsVersion() >= 0x0080) {
#if QT_VERSION >= 0x050400
bool alwaysUseMessageFont = settings.value("AlwaysUseMessageFont", false).toBool();
if (QSysInfo::windowsVersion() >= 0x0080 || alwaysUseMessageFont)
{
a.setFont(QApplication::font("QMenu"));
}
#endif
#endif
bool customFont = settings.value("CustomFont", false).toBool();
if (customFont) {
const QFont appFont = qvariant_cast<QFont>(settings.value("AppFont", a.font()));
a.setFont(appFont);
}
QStringList applicationArgs = a.arguments();
QString selectedAction;
QString arg1;
@ -130,10 +129,28 @@ int main(int argc, char *argv[])
Telemetry->work();
#endif
if (!applicationArgs.contains("--skip-firststart"))
{
if (isFirstStart)
{
QMessageBox::StandardButton button = QMessageBox::information(nullptr, QString("%1 %2").arg(GTA5SYNC_APPSTR, GTA5SYNC_APPVER), QApplication::tr("<h4>Welcome to %1!</h4>You want to configure %1 before you start using it?").arg(GTA5SYNC_APPSTR), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (button == QMessageBox::Yes)
{
ProfileDatabase profileDB;
OptionsDialog optionsDialog(&profileDB);
optionsDialog.setWindowIcon(IconLoader::loadingAppIcon());
optionsDialog.show();
optionsDialog.exec();
}
settings.setValue("IsFirstStart", false);
}
}
#ifdef GTA5SYNC_TELEMETRY
bool telemetryWindowLaunched = settings.value("PersonalUsageDataWindowLaunched", false).toBool();
bool pushUsageData = settings.value("PushUsageData", false).toBool();
if (!telemetryWindowLaunched && !pushUsageData) {
if (!telemetryWindowLaunched && !pushUsageData)
{
QDialog *telemetryDialog = new QDialog();
telemetryDialog->setObjectName(QStringLiteral("TelemetryDialog"));
telemetryDialog->setWindowTitle(QString("%1 %2").arg(GTA5SYNC_APPSTR, GTA5SYNC_APPVER));
@ -165,7 +182,8 @@ int main(int argc, char *argv[])
telemetryDialog->setFixedSize(telemetryDialog->sizeHint());
telemetryDialog->exec();
QObject::disconnect(telemetryButton, SIGNAL(clicked(bool)), telemetryDialog, SLOT(close()));
if (telemetryCheckBox->isChecked()) {
if (telemetryCheckBox->isChecked())
{
QSettings telemetrySettings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR);
telemetrySettings.beginGroup("Telemetry");
telemetrySettings.setValue("PushUsageData", true);
@ -181,35 +199,43 @@ int main(int argc, char *argv[])
#endif
settings.endGroup();
for (const QString &currentArg : applicationArgs) {
for (QString currentArg : applicationArgs)
{
QString reworkedArg;
if (currentArg.left(9) == "-showpic=" && selectedAction == "") {
reworkedArg = QString(currentArg).remove(0,9);
if (currentArg.left(9) == "-showpic=" && selectedAction == "")
{
reworkedArg = currentArg.remove(0,9);
arg1 = reworkedArg;
selectedAction = "showpic";
}
else if (currentArg.left(9) == "-showsgd=" && selectedAction == "") {
reworkedArg = QString(currentArg).remove(0,9);
else if (currentArg.left(9) == "-showsgd=" && selectedAction == "")
{
reworkedArg = currentArg.remove(0,9);
arg1 = reworkedArg;
selectedAction = "showsgd";
}
else if (selectedAction == "") {
else if (selectedAction == "")
{
QFile argumentFile(currentArg);
QFileInfo argumentFileInfo(argumentFile);
if (argumentFile.exists()) {
if (argumentFile.exists())
{
QString argumentFileName = argumentFileInfo.fileName();
QString argumentFileType = argumentFileName.left(4);
QString argumentFileExt = argumentFileName.right(4);
if (argumentFileType == "PGTA" || argumentFileExt == ".g5e") {
if (argumentFileType == "PGTA" || argumentFileExt == ".g5e")
{
arg1 = currentArg;
selectedAction = "showpic";
}
else if (argumentFileType == "SGTA") {
else if (argumentFileType == "SGTA")
{
arg1 = currentArg;
selectedAction = "showsgd";
}
else if (argumentFileType == "MISR") {
else if (argumentFileType == "MISR")
{
arg1 = currentArg;
selectedAction = "showsgd";
}
@ -217,7 +243,8 @@ int main(int argc, char *argv[])
}
}
if (selectedAction == "showpic") {
if (selectedAction == "showpic")
{
CrewDatabase crewDB;
ProfileDatabase profileDB;
DatabaseThread threadDB(&crewDB);
@ -230,10 +257,8 @@ int main(int argc, char *argv[])
picDialog.setWindowFlags(picDialog.windowFlags()^Qt::Dialog^Qt::Window);
int crewID = picture.getSnapmaticProperties().crewID;
if (crewID != 0)
crewDB.addCrew(crewID);
if (!readOk)
return 1;
if (crewID != 0) { crewDB.addCrew(crewID); }
if (!readOk) { return 1; }
QObject::connect(&threadDB, SIGNAL(crewNameFound(int, QString)), &crewDB, SLOT(setCrewName(int, QString)));
QObject::connect(&threadDB, SIGNAL(crewNameUpdated()), &picDialog, SLOT(crewNameUpdated()));
@ -247,7 +272,8 @@ int main(int argc, char *argv[])
return a.exec();
}
else if (selectedAction == "showsgd") {
else if (selectedAction == "showsgd")
{
SavegameDialog savegameDialog;
SavegameData savegame;
@ -256,8 +282,7 @@ int main(int argc, char *argv[])
savegameDialog.setSavegameData(&savegame, arg1, readOk);
savegameDialog.setWindowFlags(savegameDialog.windowFlags()^Qt::Dialog^Qt::Window);
if (!readOk)
return 1;
if (!readOk) { return 1; }
a.setQuitOnLastWindowClosed(true);
savegameDialog.show();

Binary file not shown.

View File

@ -4,14 +4,7 @@
<file>avatararea.png</file>
<file>avatarareaimport.png</file>
<file>back.svgz</file>
<file>flag-de.png</file>
<file>flag-fr.png</file>
<file>flag-gb.png</file>
<file>flag-kr.png</file>
<file>flag-ru.png</file>
<file>flag-tw.png</file>
<file>flag-ua.png</file>
<file>flag-us.png</file>
<file>empty1x16.png</file>
<file>gta5view-16.png</file>
<file>gta5view-24.png</file>
<file>gta5view-32.png</file>
@ -21,7 +14,6 @@
<file>gta5view-96.png</file>
<file>gta5view-128.png</file>
<file>gta5view-256.png</file>
<file>mapcayoperico.jpg</file>
<file>mappreview.jpg</file>
<file>next.svgz</file>
<file>pointmaker-8.png</file>
@ -33,4 +25,7 @@
<file>watermark_2b.png</file>
<file>watermark_2r.png</file>
</qresource>
<qresource prefix="/template">
<file>template.g5e</file>
</qresource>
</RCC>

View File

@ -4,8 +4,8 @@ IDI_ICON1 ICON DISCARDABLE "5sync.ico"
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "gta5view.exe.manifest"
#include <windows.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1, 10, 2, 0
PRODUCTVERSION 1, 10, 2, 0
FILEVERSION 1, 8, 0, 0
PRODUCTVERSION 1, 8, 0, 0
FILEFLAGSMASK 0x3fL
FILEFLAGS 0
FILEOS VOS_NT_WINDOWS32
@ -22,12 +22,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Syping"
VALUE "FileDescription", "gta5view"
VALUE "FileVersion", "1.10.2"
VALUE "FileVersion", "1.8.0"
VALUE "InternalName", "gta5view"
VALUE "LegalCopyright", "Copyright © 2016-2023 Syping"
VALUE "LegalCopyright", "Copyright © 2016-2020 Syping"
VALUE "OriginalFilename", "gta5view.exe"
VALUE "ProductName", "gta5view"
VALUE "ProductVersion", "1.10.2"
VALUE "ProductVersion", "1.8.0"
END
END
END

Binary file not shown.

View File

@ -1 +0,0 @@
Bitcoin

Binary file not shown.

View File

@ -3,11 +3,8 @@ Type=Application
Name=gta5view
Comment=Open and edit GTA V profiles
Comment[de]=GTA V Profile öffnen und bearbeiten
Comment[ko]=GTA V
Comment[ru]=Просмотрщик и редактор профилей GTA V
Comment[zh_TW]= GTA V
Categories=Qt;Utility;FileTools;
TryExec=gta5view
Exec=gta5view %f
Categories=Qt;Utility;
Exec=gta5view
Icon=de.syping.gta5view
MimeType=application/x-gta5view-export;
Terminal=false
StartupNotify=false

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2021 Syping -->
<!-- Copyright 2020 Syping -->
<component type="desktop-application">
<id>de.syping.gta5view</id>
<launchable type="desktop-id">de.syping.gta5view.desktop</launchable>
@ -10,14 +10,11 @@
<summary>Open and edit GTA V profiles</summary>
<summary xml:lang="de">GTA V Profile öffnen und bearbeiten</summary>
<summary xml:lang="ko">GTA V 프로필을 열고 편집</summary>
<summary xml:lang="ru">Просмотрщик и редактор профилей GTA V</summary>
<summary xml:lang="zh-TW">打開與編輯 GTA V 個人檔案</summary>
<icon type="remote">https://img.syping.de/gta5view/gta5view.png</icon>
<description>
<p>Open Source Snapmatic and Savegame viewer/editor for GTA V</p>
<p>Open Source Snapmatic picture and Savegame viewer/editor for GTA V</p>
<p>Features</p>
<ul>
<li>View Snapmatics with the ability to disable them in-game</li>
@ -34,13 +31,7 @@
<developer_name>Syping</developer_name>
<releases>
<release date="2023-03-15" version="1.10.2"/>
<release date="2021-06-17" version="1.10.1"/>
<release date="2021-05-27" version="1.10.0"/>
<release date="2021-03-22" version="1.9.2"/>
<release date="2020-12-16" version="1.9.1"/>
<release date="2020-11-30" version="1.9.0"/>
<release date="2020-10-11" version="1.8.0"/>
<release date="2020-10-11" version="1.8.0" />
</releases>
<screenshots>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/x-gta5view-export">
<comment>gta5view Export</comment>
<glob pattern="*.g5e"/>
<generic-icon name="de.syping.gta5view"/>
</mime-type>
</mime-info>

View File

@ -1,15 +0,0 @@
<RCC>
<qresource prefix="/donate">
<file>btc.str</file>
<file>btc.svgz</file>
<file>eth.str</file>
<file>eth.svgz</file>
<file>ltc.str</file>
<file>ltc.svgz</file>
<file>xmr.str</file>
<file>xmr.svgz</file>
</qresource>
<qresource prefix="/img">
<file>donate.svgz</file>
</qresource>
</RCC>

Binary file not shown.

BIN
res/empty1x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 B

View File

@ -1 +0,0 @@
Ethereum

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -42,7 +42,6 @@ HAWICK="Hawick"
HEART="Heart Attacks Beach"
HORS="Vinewood-Rennbahn"
HUMLAB="Humane Labs and Research"
ISHEIST="Cayo Perico"
JAIL="Bolingbroke-Strafanstalt"
KOREAT="Little Seoul"
LACT="Land-Act-Stausee"

View File

@ -42,7 +42,6 @@ HAWICK="Hawick"
HEART="Heart Attacks Beach"
HORS="Vinewood Racetrack"
HUMLAB="Humane Labs and Research"
ISHEIST="Cayo Perico"
JAIL="Bolingbroke Penitentiary"
KOREAT="Little Seoul"
LACT="Land Act Reservoir"

View File

@ -42,7 +42,6 @@ HAWICK="Hawick"
HEART="Heart Attacks Beach"
HORS="Circuito de Vinewood"
HUMLAB="Laboratorios Humane"
ISHEIST="Cayo Perico"
JAIL="Penitenciaría de Bolingbroke"
KOREAT="Little Seoul"
LACT="Embalse de Land Act"

View File

@ -42,7 +42,6 @@ HAWICK="Hawick"
HEART="Heart Attacks Beach"
HORS="Circuito de Vinewood"
HUMLAB="Humane Labs and Research"
ISHEIST="Cayo Perico"
JAIL="Penitenciaría de Bolingbroke"
KOREAT="Little Seoul"
LACT="Presa de Land Act"

View File

@ -41,7 +41,6 @@ HAWICK="Hawick"
HEART="Heart Attacks Beach"
HORS="Hippodrome de Vinewood"
HUMLAB="Laboratoires Humane"
ISHEIST="Cayo Perico"
JAIL="Pénitencier de Bolingbroke"
KOREAT="Little Seoul"
LACT="Land Act Reservoir"

View File

@ -42,7 +42,6 @@ HAWICK="Hawick"
HEART="Heart Attacks Beach"
HORS="Vinewood Racetrack"
HUMLAB="Laboratori di ricerca Humane"
ISHEIST="Cayo Perico"
JAIL="Bolingbroke Penitentiary"
KOREAT="Little Seoul"
LACT="Land Act Reservoir"

Some files were not shown because too many files have changed in this diff Show More