Compare commits

..

No commits in common. "master" and "snapshot-358" have entirely different histories.

181 changed files with 9232 additions and 8812 deletions

36
.github/build.sh vendored
View File

@ -70,13 +70,12 @@ if [[ -z ${BSH_NO_PACKAGES-} ]]; then
;; ;;
windows) windows)
if [[ $BSH_BUILD_PLATFORM-$BSH_HOST_LIBC == windows-mingw ]]; then if [[ $BSH_BUILD_PLATFORM-$BSH_HOST_LIBC == windows-mingw ]]; then
pacman -S --noconfirm --needed mingw-w64-ucrt-x86_64-gcc pacman -Syu --noconfirm --needed mingw-w64-ucrt-x86_64-gcc
if [[ $BSH_STATIC_DYNAMIC == static ]]; then if [[ $BSH_STATIC_DYNAMIC == static ]]; then
pacman -S --noconfirm --needed mingw-w64-ucrt-x86_64-{cmake,7zip,jq} patch pacman -S --noconfirm --needed mingw-w64-ucrt-x86_64-{cmake,7zip} patch
else else
pacman -S --noconfirm --needed mingw-w64-ucrt-x86_64-{pkgconf,bzip2,luajit,jsoncpp,curl,SDL2,libpng,meson,fftw,jq} pacman -S --noconfirm --needed mingw-w64-ucrt-x86_64-{pkgconf,bzip2,luajit,jsoncpp,curl,SDL2,libpng,meson,fftw}
fi fi
export PKG_CONFIG=$(which pkg-config.exe)
fi fi
;; ;;
linux) linux)
@ -199,7 +198,7 @@ meson_configure+=$'\t'-Dapp_exe=$APP_EXE
meson_configure+=$'\t'-Dapp_id=$APP_ID meson_configure+=$'\t'-Dapp_id=$APP_ID
meson_configure+=$'\t'-Dapp_data=$APP_DATA meson_configure+=$'\t'-Dapp_data=$APP_DATA
meson_configure+=$'\t'-Dapp_vendor=$APP_VENDOR meson_configure+=$'\t'-Dapp_vendor=$APP_VENDOR
meson_configure+=$'\t'-Dstrip=false meson_configure+=$'\t'-Db_strip=false
meson_configure+=$'\t'-Db_staticpic=false meson_configure+=$'\t'-Db_staticpic=false
meson_configure+=$'\t'-Dmod_id=$MOD_ID meson_configure+=$'\t'-Dmod_id=$MOD_ID
case $BSH_HOST_ARCH-$BSH_HOST_PLATFORM-$BSH_HOST_LIBC-$BSH_DEBUG_RELEASE in case $BSH_HOST_ARCH-$BSH_HOST_PLATFORM-$BSH_HOST_LIBC-$BSH_DEBUG_RELEASE in
@ -219,9 +218,23 @@ if [[ $PACKAGE_MODE == nolua ]]; then
fi fi
if [[ $PACKAGE_MODE == backendvs ]]; then if [[ $PACKAGE_MODE == backendvs ]]; then
meson_configure+=$'\t'-Dbackend=vs meson_configure+=$'\t'-Dbackend=vs
# meson 1.2.3 configures vs projects that bring their own manifest, which conflicts with ours echo "NOTE: patching CREATEPROCESS_MANIFEST_RESOURCE_ID out of powder-res.template.rc"
# TODO: remove this patch once https://github.com/mesonbuild/meson/pull/12472 makes it into a release that we can use echo "TODO: remove this patch once https://github.com/mesonbuild/meson/pull/12472 makes it into a release"
meson_configure+=$'\t'-Dwindows_utf8cp=false echo "TODO: also remove the relevant note from the building guide"
git apply <<PATCH
diff --git a/resources/powder-res.template.rc b/resources/powder-res.template.rc
index 1dc26c78..2094049f 100644
--- a/resources/powder-res.template.rc
+++ b/resources/powder-res.template.rc
@@ -7,7 +7,6 @@
IDI_ICON ICON DISCARDABLE "@ICON_EXE_ICO@"
IDI_DOC_ICON ICON DISCARDABLE "@ICON_CPS_ICO@"
-CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "@WINUTF8_XML@"
VS_VERSION_INFO VERSIONINFO
FILEVERSION @DISPLAY_VERSION_MAJOR@,@DISPLAY_VERSION_MINOR@,0,@BUILD_NUM@
PATCH
fi fi
if [[ $BSH_STATIC_DYNAMIC == static ]]; then if [[ $BSH_STATIC_DYNAMIC == static ]]; then
meson_configure+=$'\t'-Dstatic=prebuilt meson_configure+=$'\t'-Dstatic=prebuilt
@ -290,19 +303,12 @@ if [[ $RELEASE_TYPE == snapshot ]] && [[ $MOD_ID != 0 ]]; then
fi fi
if [[ $RELEASE_TYPE == snapshot ]] || [[ $MOD_ID != 0 ]]; then if [[ $RELEASE_TYPE == snapshot ]] || [[ $MOD_ID != 0 ]]; then
meson_configure+=$'\t'-Dupdate_server=starcatcher.us/TPT meson_configure+=$'\t'-Dupdate_server=starcatcher.us/TPT
if [[ $BSH_HOST_PLATFORM == emscripten ]]; then
meson_configure+=$'\t'-Dserver=tptserv.starcatcher.us
meson_configure+=$'\t'-Dstatic_server=tptserv.starcatcher.us/Static
fi
fi fi
if [[ $RELEASE_TYPE != dev ]]; then if [[ $RELEASE_TYPE != dev ]]; then
meson_configure+=$'\t'-Dignore_updates=false meson_configure+=$'\t'-Dignore_updates=false
fi fi
if [[ "$BSH_HOST_PLATFORM-$BSH_HOST_LIBC" == "windows-mingw" ]]; then if [[ "$BSH_HOST_PLATFORM-$BSH_HOST_LIBC" == "windows-mingw" ]]; then
meson_configure+=$'\t'--cross-file=.github/mingw-ghactions.ini meson_configure+=$'\t'--cross-file=.github/mingw-ghactions.ini
# there is some mingw bug that only ever manifests on ghactions which makes MakeIco.exe use tons of memory and fail
# TODO: remove this hack once we figure out how to fix that
meson_configure+=$'\t'-Dwindows_icons=false
fi fi
if [[ $BSH_DEBUG_RELEASE-$BSH_STATIC_DYNAMIC == release-static ]]; then if [[ $BSH_DEBUG_RELEASE-$BSH_STATIC_DYNAMIC == release-static ]]; then
meson_configure+=$'\t'-Db_lto=true meson_configure+=$'\t'-Db_lto=true

10
.github/force-msys2-bash.sh vendored Executable file
View File

@ -0,0 +1,10 @@
set -euo pipefail
IFS=$'\t\n'
echo 'C:\msys64\ucrt64\bin' >> tmp
echo 'C:\msys64\usr\bin' >> tmp
cat $GITHUB_PATH >> tmp
mv tmp $GITHUB_PATH
echo "MSYSTEM=UCRT64" >> $GITHUB_ENV
echo "PKG_CONFIG="'C:\msys64\ucrt64\bin\pkg-config.exe' >> $GITHUB_ENV

9
.github/prepare.py vendored
View File

@ -114,7 +114,7 @@ for arch, platform, libc, statdyn, bplatform, runso
( 'x86_64', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 0 ), # priority = 0: static debug build ( 'x86_64', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 0 ), # priority = 0: static debug build
( 'x86_64', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', True, True, '.pdb', None,'x86_64-win-msvc-static', 'release', 10 ), ( 'x86_64', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', True, True, '.pdb', None,'x86_64-win-msvc-static', 'release', 10 ),
( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 10 ), ( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 10 ),
# ( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, 'backendvs', None, 'debug', 0 ), # priority = 0: backend=vs build ( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, 'backendvs', None, 'debug', 0 ), # priority = 0: backend=vs build
( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'release', 10 ), ( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'release', 10 ),
( 'x86', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 0 ), # priority = 0: static debug build ( 'x86', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 0 ), # priority = 0: static debug build
( 'x86', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', True, True, '.pdb', None, 'i686-win-msvc-static', 'release', 10 ), ( 'x86', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', True, True, '.pdb', None, 'i686-win-msvc-static', 'release', 10 ),
@ -173,10 +173,6 @@ for arch, platform, libc, statdyn, bplatform, runso
debug_asset_path = f'{app_name_slug}-{arch}.AppImage.dbg' debug_asset_path = f'{app_name_slug}-{arch}.AppImage.dbg'
debug_asset_name = f'{app_name_slug}-{arch}.AppImage.dbg' debug_asset_name = f'{app_name_slug}-{arch}.AppImage.dbg'
starcatcher_name = f'powder-{release_name}-{starcatcher}{suffix}' starcatcher_name = f'powder-{release_name}-{starcatcher}{suffix}'
msys2_bash = (bplatform == 'windows' and libc == 'mingw')
shell = 'bash'
if msys2_bash:
shell = 'msys2 {0}'
build_matrix.append({ build_matrix.append({
'bsh_build_platform': bplatform, # part of the unique portion of the matrix 'bsh_build_platform': bplatform, # part of the unique portion of the matrix
'bsh_host_arch': arch, # part of the unique portion of the matrix 'bsh_host_arch': arch, # part of the unique portion of the matrix
@ -185,7 +181,7 @@ for arch, platform, libc, statdyn, bplatform, runso
'bsh_static_dynamic': statdyn, # part of the unique portion of the matrix 'bsh_static_dynamic': statdyn, # part of the unique portion of the matrix
'bsh_debug_release': dbgrel, # part of the unique portion of the matrix 'bsh_debug_release': dbgrel, # part of the unique portion of the matrix
'runs_on': runson, 'runs_on': runson,
'force_msys2_bash': msys2_bash and 'yes' or 'no', 'force_msys2_bash': (bplatform == 'windows' and libc == 'mingw') and 'yes' or 'no',
'package_suffix': suffix, 'package_suffix': suffix,
'package_mode': mode, 'package_mode': mode,
'publish': publish and 'yes' or 'no', 'publish': publish and 'yes' or 'no',
@ -196,7 +192,6 @@ for arch, platform, libc, statdyn, bplatform, runso
'debug_asset_path': debug_asset_path, 'debug_asset_path': debug_asset_path,
'debug_asset_name': debug_asset_name, 'debug_asset_name': debug_asset_name,
'job_name': job_name, 'job_name': job_name,
'shell': shell,
}) })
if publish: if publish:
publish_matrix.append({ publish_matrix.append({

View File

@ -13,8 +13,6 @@ chmod 660 ~/.netrc
mountpoint=ftpmnt mountpoint=ftpmnt
mkdir $mountpoint mkdir $mountpoint
curlftpfs "$PUBLISH_HOSTPORT" $mountpoint -o ssl,ciphers='ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-GCM-SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256' curlftpfs "$PUBLISH_HOSTPORT" $mountpoint -o ssl,ciphers='ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-GCM-SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256'
if [[ -z ${PUBLISH_ACCESSCHECK-} ]]; then
cp $PUBLISH_FILENAME $mountpoint/${PUBLISH_DIRECTORY:-.}/ cp $PUBLISH_FILENAME $mountpoint/${PUBLISH_DIRECTORY:-.}/
fi
fusermount -u $mountpoint fusermount -u $mountpoint
rmdir $mountpoint rmdir $mountpoint

3
.github/vs-env.sh vendored
View File

@ -24,8 +24,5 @@ IFS=$'\t\n'
for i in $(MSYS_NO_PATHCONV=1 cmd /c "$vs_install_dir\\VC\\Auxiliary\\Build\\vcvarsall.bat" $VS_ENV_PARAMS \& env \& exit /b); do for i in $(MSYS_NO_PATHCONV=1 cmd /c "$vs_install_dir\\VC\\Auxiliary\\Build\\vcvarsall.bat" $VS_ENV_PARAMS \& env \& exit /b); do
set +e set +e
export "$i" 2>/dev/null export "$i" 2>/dev/null
echo $i | grep ERROR
set -e set -e
done done
cl

View File

@ -31,8 +31,8 @@ jobs:
do_publish: ${{ steps.prepare.outputs.do_publish }} do_publish: ${{ steps.prepare.outputs.do_publish }}
steps: steps:
- run: git config --global core.autocrlf false - run: git config --global core.autocrlf false
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- uses: actions/setup-python@v5 - uses: actions/setup-python@v4
with: with:
python-version: '3.10' python-version: '3.10'
- run: python -m pip install meson==1.2.3 ninja # TODO: go back to using latest meson once https://github.com/mesonbuild/meson/pull/12544 is live - run: python -m pip install meson==1.2.3 ninja # TODO: go back to using latest meson once https://github.com/mesonbuild/meson/pull/12544 is live
@ -41,13 +41,6 @@ jobs:
env: env:
PUBLISH_HOSTPORT: ${{ secrets.STARCATCHER_PUBLISH_HOSTPORT }} PUBLISH_HOSTPORT: ${{ secrets.STARCATCHER_PUBLISH_HOSTPORT }}
GITHUB_REF: ${{ github.ref }} GITHUB_REF: ${{ github.ref }}
- if: steps.prepare.outputs.do_publish == 'yes'
run: sudo apt update && sudo apt install curlftpfs && bash -c './.github/starcatcher-publish.sh'
env:
PUBLISH_HOSTPORT: ${{ secrets.STARCATCHER_PUBLISH_HOSTPORT }}
PUBLISH_USERNAME: ${{ secrets.STARCATCHER_PUBLISH_USERNAME }}
PUBLISH_PASSWORD: ${{ secrets.STARCATCHER_PUBLISH_PASSWORD }}
PUBLISH_ACCESSCHECK: yes
- if: steps.prepare.outputs.do_release == 'yes' - if: steps.prepare.outputs.do_release == 'yes'
id: create_release id: create_release
env: env:
@ -61,46 +54,15 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: ${{ fromJSON(needs.prepare.outputs.build_matrix) }} matrix: ${{ fromJSON(needs.prepare.outputs.build_matrix) }}
defaults:
run:
shell: ${{ matrix.shell }}
steps: steps:
- if: matrix.force_msys2_bash == 'yes'
uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
path-type: strict
cache: true
# this list doesn't have to mirror the one in build.sh perfectly
# but the packages listed here get cached properly and take less time to install
install: >-
git
curl
mingw-w64-ucrt-x86_64-gcc
mingw-w64-ucrt-x86_64-pkgconf
mingw-w64-ucrt-x86_64-bzip2
mingw-w64-ucrt-x86_64-luajit
mingw-w64-ucrt-x86_64-jsoncpp
mingw-w64-ucrt-x86_64-curl
mingw-w64-ucrt-x86_64-SDL2
mingw-w64-ucrt-x86_64-libpng
mingw-w64-ucrt-x86_64-meson
mingw-w64-ucrt-x86_64-python
mingw-w64-ucrt-x86_64-python-pip
mingw-w64-ucrt-x86_64-fftw
mingw-w64-ucrt-x86_64-cmake
mingw-w64-ucrt-x86_64-7zip
mingw-w64-ucrt-x86_64-jq
patch
- run: git config --global core.autocrlf false - run: git config --global core.autocrlf false
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- if: matrix.force_msys2_bash != 'yes' - if: matrix.force_msys2_bash == 'yes'
uses: actions/setup-python@v5 run: bash -c './.github/force-msys2-bash.sh'
- uses: actions/setup-python@v4
with: with:
python-version: '3.10' python-version: '3.10'
- if: matrix.force_msys2_bash != 'yes' - run: python -m pip install meson==1.2.3 ninja # TODO: go back to using latest meson once https://github.com/mesonbuild/meson/pull/12544 is live
run: python -m pip install meson==1.2.3 ninja # TODO: go back to using latest meson once https://github.com/mesonbuild/meson/pull/12544 is live
- if: matrix.bsh_build_platform == 'darwin' - if: matrix.bsh_build_platform == 'darwin'
run: brew install bash coreutils run: brew install bash coreutils
- run: bash -c './.github/build.sh' - run: bash -c './.github/build.sh'
@ -136,12 +98,12 @@ jobs:
ASSET_PATH: build/${{ matrix.debug_asset_path }} ASSET_PATH: build/${{ matrix.debug_asset_path }}
ASSET_NAME: ${{ matrix.debug_asset_name }} ASSET_NAME: ${{ matrix.debug_asset_name }}
run: bash -c './.github/upload-release-asset.sh' run: bash -c './.github/upload-release-asset.sh'
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v3
if: matrix.artifact == 'yes' if: matrix.artifact == 'yes'
with: with:
path: build/${{ matrix.asset_path }} path: build/${{ matrix.asset_path }}
name: ${{ matrix.asset_name }} name: ${{ matrix.asset_name }}
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v3
if: matrix.artifact == 'yes' && matrix.separate_debug == 'yes' if: matrix.artifact == 'yes' && matrix.separate_debug == 'yes'
with: with:
path: build/${{ matrix.debug_asset_path }} path: build/${{ matrix.debug_asset_path }}
@ -155,8 +117,8 @@ jobs:
if: needs.prepare.outputs.do_publish == 'yes' if: needs.prepare.outputs.do_publish == 'yes'
steps: steps:
- run: git config --global core.autocrlf false - run: git config --global core.autocrlf false
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v3
with: with:
name: ${{ matrix.asset_name }} name: ${{ matrix.asset_name }}
- run: mv ${{ matrix.asset_path }} ${{ matrix.starcatcher_name }} - run: mv ${{ matrix.asset_path }} ${{ matrix.starcatcher_name }}
@ -173,7 +135,7 @@ jobs:
if: needs.prepare.outputs.do_publish == 'yes' if: needs.prepare.outputs.do_publish == 'yes'
steps: steps:
- run: git config --global core.autocrlf false - run: git config --global core.autocrlf false
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- run: ./.github/starcatcher-release.sh - run: ./.github/starcatcher-release.sh
env: env:
RELEASE_NAME: ${{ needs.prepare.outputs.release_name }} RELEASE_NAME: ${{ needs.prepare.outputs.release_name }}

View File

@ -1,4 +1,4 @@
The Powder Toy - April 2024 The Powder Toy - January 2023
========================== ==========================
Get the latest version [from the Powder Toy website](https://powdertoy.co.uk/Download.html). Get the latest version [from the Powder Toy website](https://powdertoy.co.uk/Download.html).
@ -108,7 +108,6 @@ Controls
| Shift + R | Horizontal mirror for selected area when pasting stamps | | Shift + R | Horizontal mirror for selected area when pasting stamps |
| Ctrl + Shift + R | Vertical mirror for selected area when pasting stamps | | Ctrl + Shift + R | Vertical mirror for selected area when pasting stamps |
| R | Rotate selected area counterclockwise when pasting stamps | | R | Rotate selected area counterclockwise when pasting stamps |
| F11 | Toggle fullscreen |
Command Line Command Line
--------------------------------------------------------------------------- ---------------------------------------------------------------------------

View File

@ -55,7 +55,6 @@ lldb_server=${LLDB_SERVER:-$default_lldb_server}
lldb_server_port=${LLDB_SERVER_PORT:-9998} lldb_server_port=${LLDB_SERVER_PORT:-9998}
jdb_port=${JDB_PORT:-13456} jdb_port=${JDB_PORT:-13456}
lldb_client=${LLDB_CLIENT:-$default_lldb_client} lldb_client=${LLDB_CLIENT:-$default_lldb_client}
meson=${MESON:-meson}
adb=${ADB:-adb} adb=${ADB:-adb}
jdb=${JDB:-jdb} jdb=${JDB:-jdb}
@ -114,11 +113,6 @@ Naturally, replace bagelsbagels with an appropriate password.
HELP HELP
exit 1 exit 1
fi fi
>&2 echo "[+] meson compiling android/$app_exe.apk"
if ! $meson compile sign-apk; then
>&2 echo "[-] failed"
return 1
fi
>&2 echo "[+] adb installing android/$app_exe.apk" >&2 echo "[+] adb installing android/$app_exe.apk"
if ! $adb install android/$app_exe.apk; then if ! $adb install android/$app_exe.apk; then
>&2 echo "[-] failed" >&2 echo "[-] failed"

View File

@ -376,22 +376,6 @@ if host_platform == 'emscripten'
'-o', app_exe + '.js', # so we get a .wasm, and a .js '-o', app_exe + '.js', # so we get a .wasm, and a .js
] ]
endif endif
if get_option('export_lua_symbols')
if is_static and lua_variant != 'none' and not project_export_dynamic
if host_platform == 'windows'
error('Lua symbols are currently impossible to export correctly on Windows')
elif c_compiler.has_link_argument('-Wl,--export-dynamic-symbol')
project_link_args += [
'-Wl,--export-dynamic-symbol=lua_*',
'-Wl,--export-dynamic-symbol=luaL_*',
'-Wl,--export-dynamic-symbol=luaopen_*',
]
else
warning('your linker does not support -Wl,--export-dynamic-symbol so Meson will be instructed to export all symbols in order to enable loading Lua shared modules, which may blow up the size of the resulting binary')
project_export_dynamic = true
endif
endif
endif
if get_option('build_powder') if get_option('build_powder')
powder_deps += project_deps + [ powder_deps += project_deps + [

View File

@ -40,42 +40,42 @@ option(
'display_version_major', 'display_version_major',
type: 'integer', type: 'integer',
min: 0, min: 0,
value: 98, value: 97,
description: 'Major component of the display version, should more or less map to the MINOR version in semantic versioning' description: 'Major component of the display version, should more or less map to the MINOR version in semantic versioning'
) )
option( option(
'display_version_minor', 'display_version_minor',
type: 'integer', type: 'integer',
min: 0, min: 0,
value: 2, value: 0,
description: 'Minor component of the display version, should more or less map to the PATCH version in semantic versioning' description: 'Minor component of the display version, should more or less map to the PATCH version in semantic versioning'
) )
option( option(
'build_num', 'build_num',
type: 'integer', type: 'integer',
min: 0, min: 0,
value: 365, value: 358,
description: 'Build number, should be strictly monotonously increasing across public releases' description: 'Build number, should be strictly monotonously increasing across public releases'
) )
option( option(
'upstream_version_major', 'upstream_version_major',
type: 'integer', type: 'integer',
min: 0, min: 0,
value: 98, value: 97,
description: 'Major component of the upstream display version, mod owners should not change this but merge upstream changes to it' description: 'Major component of the upstream display version, mod owners should not change this but merge upstream changes to it'
) )
option( option(
'upstream_version_minor', 'upstream_version_minor',
type: 'integer', type: 'integer',
min: 0, min: 0,
value: 2, value: 0,
description: 'Minor component of the upstream display version, mod owners should not change this but merge upstream changes to it' description: 'Minor component of the upstream display version, mod owners should not change this but merge upstream changes to it'
) )
option( option(
'upstream_build_num', 'upstream_build_num',
type: 'integer', type: 'integer',
min: 0, min: 0,
value: 365, value: 358,
description: 'Upstream build number, mod owners should not change this but merge upstream changes to it' description: 'Upstream build number, mod owners should not change this but merge upstream changes to it'
) )
option( option(
@ -293,21 +293,3 @@ option(
value: 'auto', value: 'auto',
description: 'Show blue error screen upon unhandled signals and exceptions' description: 'Show blue error screen upon unhandled signals and exceptions'
) )
option(
'windows_icons',
type: 'boolean',
value: true,
description: 'Add icon resources to the executable on Windows'
)
option(
'windows_utf8cp',
type: 'boolean',
value: true,
description: 'Ask Windows nicely for UTF-8 as the codepage'
)
option(
'export_lua_symbols',
type: 'boolean',
value: false,
description: 'Export Lua symbols to enable loading of Lua shared modules'
)

View File

@ -1,137 +1,67 @@
#include <cstdint>
#include <cstring>
#include <fstream> #include <fstream>
#include <iostream>
#include <string>
#include <vector> #include <vector>
#include <cstdint>
static void writeU32LE(uint8_t *dest, uint32_t value)
{
dest[0] = uint8_t( value & 0xFF);
dest[1] = uint8_t((value >> 8) & 0xFF);
dest[2] = uint8_t((value >> 16) & 0xFF);
dest[3] = uint8_t((value >> 24) & 0xFF);
}
static uint32_t readU32BE(const uint8_t *src)
{
return uint32_t(src[3]) |
(uint32_t(src[2]) << 8) |
(uint32_t(src[1]) << 16) |
(uint32_t(src[0]) << 24);
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
if (argc < 3) if (argc < 3)
{ {
std::cerr << "usage: " << argv[0] << " OUTPUT INPUT..." << std::endl; return 1;
exit(1); }
auto *outputIcoPath = argv[1];
std::ofstream outputIco(outputIcoPath, std::ios::binary);
if (!outputIco)
{
return 2;
} }
auto images = argc - 2; auto images = argc - 2;
if (images > 255) std::vector<char> header(22 + images * 16);
auto *incondir = &header[0];
*reinterpret_cast<uint16_t *>(&incondir[0]) = 0; // reserved
*reinterpret_cast<uint16_t *>(&incondir[2]) = 1; // icon
*reinterpret_cast<uint16_t *>(&incondir[4]) = uint16_t(images);
std::vector<char> allData;
for (auto i = 0; i < images; ++i)
{ {
std::cerr << "too many images specified" << std::endl; auto *inputAnyPath = argv[i + 2];
exit(1); std::ifstream inputAny(inputAnyPath, std::ios::binary);
} std::vector<char> data;
std::string outputPath = argv[1]; while (true)
std::ofstream output(outputPath, std::ios::binary);
auto outputFailure = [&outputPath](std::string action) {
std::cerr << "failed to " << action << " " << outputPath << ": " << strerror(errno) << std::endl;
exit(1);
};
if (!output)
{ {
outputFailure("open"); char ch;
} inputAny.read(&ch, 1);
std::vector<char> header(6 + images * 16, 0); if (inputAny.eof())
auto writeHeader = [&header, &output, &outputFailure]() {
output.seekp(0, std::ios_base::beg);
output.write(&header[0], header.size());
if (!output)
{ {
outputFailure("write"); break;
} }
}; if (!inputAny)
writeHeader(); // make space for header
auto *headerU8 = reinterpret_cast<uint8_t *>(&header[0]);
headerU8[2] = 1;
headerU8[4] = images;
for (auto image = 0; image < images; ++image)
{ {
std::string inputPath = argv[2 + image]; return 3;
std::ifstream input(inputPath, std::ios::binary); }
auto inputFailure = [&inputPath](std::string action) { data.push_back(ch);
std::cerr << "failed to " << action << " " << inputPath << ": " << strerror(errno) << std::endl; }
exit(1); if (*reinterpret_cast<uint64_t *>(&data[0]) != UINT64_C(0x0A1A0A0D474E5089)) // png magic
};
auto imageFailure = [&inputPath](std::string failure) {
std::cerr << "failed to process " << inputPath << ": " << failure << std::endl;
exit(1);
};
if (!input)
{ {
inputFailure("open"); return 5;
} }
std::vector<char> buf; auto width = uint8_t(data[19]);
input.seekg(0, std::ios_base::end); auto height = uint8_t(data[23]);
buf.resize(input.tellg()); auto *incondirentry = &header[6 + i * 16];
input.seekg(0, std::ios_base::beg); *reinterpret_cast<uint8_t *>(&incondirentry[0]) = width;
input.read(&buf[0], buf.size()); *reinterpret_cast<uint8_t *>(&incondirentry[1]) = height;
if (!input) *reinterpret_cast<uint8_t *>(&incondirentry[2]) = 0; // no color palette
*reinterpret_cast<uint8_t *>(&incondirentry[3]) = 0; // reserved
*reinterpret_cast<uint16_t *>(&incondirentry[4]) = 1; // 1 color plane
*reinterpret_cast<uint16_t *>(&incondirentry[6]) = 32; // 32 bits per pixel
*reinterpret_cast<uint32_t *>(&incondirentry[8]) = uint32_t(data.size()); // data size
*reinterpret_cast<uint32_t *>(&incondirentry[12]) = uint32_t(header.size() + allData.size()); // data offset
allData.insert(allData.end(), data.begin(), data.end());
}
outputIco.write(&header[0], header.size());
outputIco.write(&allData[0], allData.size());
if (!outputIco)
{ {
inputFailure("read"); return 4;
} }
auto *bufU8 = reinterpret_cast<uint8_t *>(&buf[0]);
if (buf.size() < 0x21 ||
readU32BE(&bufU8[0]) != UINT32_C(0x89504E47) ||
readU32BE(&bufU8[4]) != UINT32_C(0x0D0A1A0A) ||
bufU8[0x18] != 8 ||
bufU8[0x19] != 6)
{
imageFailure("not a 32bpp RGBA PNG");
}
auto writeOffset = output.tellp();
output.write(&buf[0], buf.size());
if (!output)
{
outputFailure("write");
}
auto width = readU32BE(&bufU8[0x10]);
auto height = readU32BE(&bufU8[0x14]);
if (width == 256)
{
width = 0;
}
if (width > 255)
{
imageFailure("width exceeds U8 limit");
}
if (height == 256)
{
height = 0;
}
if (height > 255)
{
imageFailure("height exceeds U8 limit");
}
auto *entryU8 = headerU8 + 6 + image * 16;
entryU8[0] = width;
entryU8[1] = height;
entryU8[4] = 1;
entryU8[6] = 32;
if (buf.size() > UINT32_MAX)
{
imageFailure("data size exceeds U32 limit");
}
writeU32LE(&entryU8[8], uint32_t(buf.size()));
if (writeOffset > UINT32_MAX)
{
std::cerr << "output data size exceeds U32 limit" << std::endl;
exit(1);
}
writeU32LE(&entryU8[12], uint32_t(writeOffset));
}
writeHeader(); // actually write it out
return 0; return 0;
} }

View File

@ -32,16 +32,6 @@ else
endif endif
if host_platform == 'windows' if host_platform == 'windows'
windows_icons = get_option('windows_icons')
windows_utf8cp = get_option('windows_utf8cp')
rc_conf_depends = []
rc_conf_depend_files = [
'resource.h',
]
icon_exe_ico_path = ''
icon_cps_ico_path = ''
winutf8_xml_path = ''
if windows_icons
make_ico = executable('makeico', sources: 'MakeIco.cpp', native: true) make_ico = executable('makeico', sources: 'MakeIco.cpp', native: true)
generated_win_icos = {} generated_win_icos = {}
win_icos = { win_icos = {
@ -62,35 +52,26 @@ if host_platform == 'windows'
command: command, command: command,
) } ) }
endforeach endforeach
rc_conf_depends += [
generated_win_icos['icon_exe'],
generated_win_icos['icon_cps'],
]
icon_exe_ico_path = join_paths(meson.current_build_dir(), 'icon_exe.ico')
icon_cps_ico_path = join_paths(meson.current_build_dir(), 'icon_cps.ico')
endif
if windows_utf8cp
rc_conf_depend_files += [
'winutf8.xml',
]
winutf8_xml_path = join_paths(meson.current_source_dir(), 'winutf8.xml')
endif
rc_conf_data = configuration_data() rc_conf_data = configuration_data()
rc_conf_data.merge_from(conf_data) rc_conf_data.merge_from(conf_data)
rc_conf_data.set('HAVE_ICONS', windows_icons ? 1 : 0)
rc_conf_data.set('HAVE_UTF8CP', windows_utf8cp ? 1 : 0)
rc_conf_data.set('RESOUCE_H', join_paths(meson.current_source_dir(), 'resource.h')) rc_conf_data.set('RESOUCE_H', join_paths(meson.current_source_dir(), 'resource.h'))
rc_conf_data.set('WINUTF8_XML', winutf8_xml_path) rc_conf_data.set('WINUTF8_XML', join_paths(meson.current_source_dir(), 'winutf8.xml'))
rc_conf_data.set('ICON_EXE_ICO', icon_exe_ico_path) rc_conf_data.set('ICON_EXE_ICO', join_paths(meson.current_build_dir(), 'icon_exe.ico'))
rc_conf_data.set('ICON_CPS_ICO', icon_cps_ico_path) rc_conf_data.set('ICON_CPS_ICO', join_paths(meson.current_build_dir(), 'icon_cps.ico'))
powder_files += windows_mod.compile_resources( powder_files += windows_mod.compile_resources(
configure_file( configure_file(
input: 'powder-res.template.rc', input: 'powder-res.template.rc',
output: 'powder-res.rc', output: 'powder-res.rc',
configuration: rc_conf_data, configuration: rc_conf_data,
), ),
depends: rc_conf_depends, depends: [
depend_files: rc_conf_depend_files, generated_win_icos['icon_exe'],
generated_win_icos['icon_cps'],
],
depend_files: [
'resource.h',
'winutf8.xml',
],
) )
elif host_platform == 'darwin' elif host_platform == 'darwin'
configure_file( configure_file(

View File

@ -5,15 +5,9 @@
#include <winver.h> #include <winver.h>
#include <ntdef.h> #include <ntdef.h>
#define HAVE_ICONS @HAVE_ICONS@
#define HAVE_UTF8CP @HAVE_UTF8CP@
#if HAVE_ICONS
IDI_ICON ICON DISCARDABLE "@ICON_EXE_ICO@" IDI_ICON ICON DISCARDABLE "@ICON_EXE_ICO@"
IDI_DOC_ICON ICON DISCARDABLE "@ICON_CPS_ICO@" IDI_DOC_ICON ICON DISCARDABLE "@ICON_CPS_ICO@"
#endif
#if HAVE_UTF8CP
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "@WINUTF8_XML@" CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "@WINUTF8_XML@"
#endif
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION @DISPLAY_VERSION_MAJOR@,@DISPLAY_VERSION_MINOR@,0,@BUILD_NUM@ FILEVERSION @DISPLAY_VERSION_MAJOR@,@DISPLAY_VERSION_MINOR@,0,@BUILD_NUM@

View File

@ -51,11 +51,6 @@ inline int isign(float i)
return 0; return 0;
} }
inline int iabs(int i)
{
return i * isign(i);
}
inline unsigned clamp_flt(float f, float min, float max) inline unsigned clamp_flt(float f, float min, float max)
{ {
if (f<min) if (f<min)

View File

@ -445,20 +445,19 @@ int Main(int argc, char *argv[])
engine.Begin(); engine.Begin();
engine.SetFastQuit(prefs.Get("FastQuit", true)); engine.SetFastQuit(prefs.Get("FastQuit", true));
engine.TouchUI = prefs.Get("TouchUI", DEFAULT_TOUCH_UI); engine.TouchUI = prefs.Get("TouchUI", DEFAULT_TOUCH_UI);
engine.windowFrameOps = windowFrameOps;
SDLOpen();
if (Client::Ref().IsFirstRun() && FORCE_WINDOW_FRAME_OPS == forceWindowFrameOpsNone) if (Client::Ref().IsFirstRun() && FORCE_WINDOW_FRAME_OPS == forceWindowFrameOpsNone)
{ {
auto guessed = GuessBestScale(); auto guessed = GuessBestScale();
if (engine.windowFrameOps.scale != guessed) if (windowFrameOps.scale != guessed)
{ {
engine.windowFrameOps.scale = guessed; windowFrameOps.scale = guessed;
prefs.Set("Scale", windowFrameOps.scale); prefs.Set("Scale", windowFrameOps.scale);
showLargeScreenDialog = true; showLargeScreenDialog = true;
} }
} }
engine.windowFrameOps = windowFrameOps;
SDLOpen();
bool enableBluescreen = USE_BLUESCREEN && !true_arg(arguments["disable-bluescreen"]); bool enableBluescreen = USE_BLUESCREEN && !true_arg(arguments["disable-bluescreen"]);
if (enableBluescreen) if (enableBluescreen)

View File

@ -75,7 +75,7 @@ int main(int argc, char * argv[])
} }
else else
{ {
std::cerr << "path to font.bz2 not supplied" << std::endl; std::cerr << "path to font.cpp not supplied" << std::endl;
Platform::Exit(1); Platform::Exit(1);
} }

View File

@ -22,8 +22,6 @@ int main(int argc, char *argv[])
auto inputFilename = ByteString(argv[1]); auto inputFilename = ByteString(argv[1]);
auto outputFilename = ByteString(argv[2]) + ".png"; auto outputFilename = ByteString(argv[2]) + ".png";
auto simulationData = std::make_unique<SimulationData>();
std::vector<char> fileData; std::vector<char> fileData;
if (!Platform::ReadFile(fileData, inputFilename)) if (!Platform::ReadFile(fileData, inputFilename))
{ {
@ -42,6 +40,7 @@ int main(int argc, char *argv[])
throw e; throw e;
} }
auto simulationData = std::make_unique<SimulationData>();
Simulation * sim = new Simulation(); Simulation * sim = new Simulation();
Renderer * ren = new Renderer(sim); Renderer * ren = new Renderer(sim);
@ -64,7 +63,6 @@ int main(int argc, char *argv[])
} }
else else
{ {
ren->clearScreen();
int w = Graphics::TextSize("Save file invalid").X + 15, x = (XRES-w)/2, y = (YRES-24)/2; int w = Graphics::TextSize("Save file invalid").X + 15, x = (XRES-w)/2, y = (YRES-24)/2;
ren->DrawRect(RectSized(Vec2{ x, y }, Vec2{ w, 24 }), 0xC0C0C0_rgb); ren->DrawRect(RectSized(Vec2{ x, y }, Vec2{ w, 24 }), 0xC0C0C0_rgb);
ren->BlendText({ x+8, y+8 }, "Save file invalid", 0xC0C0F0_rgb .WithAlpha(255)); ren->BlendText({ x+8, y+8 }, "Save file invalid", 0xC0C0F0_rgb .WithAlpha(255));

View File

@ -349,7 +349,7 @@ static void EventProcess(const SDL_Event &event)
mousey = event.button.y; mousey = event.button.y;
} }
mouseButton = event.button.button; mouseButton = event.button.button;
engine.onMouseDown(mousex, mousey, mouseButton); engine.onMouseClick(mousex, mousey, mouseButton);
mouseDown = true; mouseDown = true;
if constexpr (!DEBUG) if constexpr (!DEBUG)
@ -365,7 +365,7 @@ static void EventProcess(const SDL_Event &event)
mousey = event.button.y; mousey = event.button.y;
} }
mouseButton = event.button.button; mouseButton = event.button.button;
engine.onMouseUp(mousex, mousey, mouseButton); engine.onMouseUnclick(mousex, mousey, mouseButton);
mouseDown = false; mouseDown = false;
if constexpr (!DEBUG) if constexpr (!DEBUG)

View File

@ -42,13 +42,10 @@ constexpr float AIR_PLOSS = 0.9999f;
constexpr int NGOL = 24; constexpr int NGOL = 24;
enum DefaultBrushes constexpr int CIRCLE_BRUSH = 0;
{ constexpr int SQUARE_BRUSH = 1;
BRUSH_CIRCLE, constexpr int TRI_BRUSH = 2;
BRUSH_SQUARE, constexpr int BRUSH_NUM = 3;
BRUSH_TRIANGLE,
NUM_DEFAULTBRUSHES,
};
//Photon constants //Photon constants
constexpr int SURF_RANGE = 10; constexpr int SURF_RANGE = 10;

View File

@ -3,6 +3,7 @@
#include "client/http/StartupRequest.h" #include "client/http/StartupRequest.h"
#include "ClientListener.h" #include "ClientListener.h"
#include "Format.h" #include "Format.h"
#include "MD5.h"
#include "client/GameSave.h" #include "client/GameSave.h"
#include "client/SaveFile.h" #include "client/SaveFile.h"
#include "client/SaveInfo.h" #include "client/SaveInfo.h"
@ -117,7 +118,7 @@ void Client::Tick()
{ {
if (versionCheckRequest->StatusCode() == 618) if (versionCheckRequest->StatusCode() == 618)
{ {
AddServerNotification({ "Failed to load SSL certificates", ByteString::Build(SCHEME, SERVER, "/FAQ.html") }); AddServerNotification({ "Failed to load SSL certificates", ByteString(SCHEME) + "powdertoy.co.uk/FAQ.html" });
} }
try try
{ {
@ -377,6 +378,7 @@ void Client::RescanStamps()
newStampIDs.push_back(stampID); newStampIDs.push_back(stampID);
} }
} }
auto oldCount = newStampIDs.size();
auto stampIDsSet = std::set<ByteString>(stampIDs.begin(), stampIDs.end()); auto stampIDsSet = std::set<ByteString>(stampIDs.begin(), stampIDs.end());
for (auto &stampID : stampFilesSet) for (auto &stampID : stampFilesSet)
{ {
@ -388,6 +390,8 @@ void Client::RescanStamps()
} }
if (changed) if (changed)
{ {
// Move newly discovered stamps to front.
std::rotate(newStampIDs.begin(), newStampIDs.begin() + oldCount, newStampIDs.end());
stampIDs = newStampIDs; stampIDs = newStampIDs;
WriteStamps(); WriteStamps();
} }

View File

@ -51,18 +51,9 @@ GameSave::GameSave(const std::vector<char> &data, bool newWantAuthors)
void GameSave::MapPalette() void GameSave::MapPalette()
{ {
int partMap[PT_NUM]; int partMap[PT_NUM];
bool ignoreMissingErrors[PT_NUM];
for(int i = 0; i < PT_NUM; i++) for(int i = 0; i < PT_NUM; i++)
{ {
partMap[i] = i; partMap[i] = i;
ignoreMissingErrors[i] = false;
}
if (version <= Version(98, 2))
{
ignoreMissingErrors[PT_ICEI] = true;
ignoreMissingErrors[PT_SNOW] = true;
ignoreMissingErrors[PT_RSST] = true;
ignoreMissingErrors[PT_RSSS] = true;
} }
auto &sd = SimulationData::CRef(); auto &sd = SimulationData::CRef();
@ -99,14 +90,12 @@ void GameSave::MapPalette()
} }
} }
} }
auto paletteLookup = [this, &partMap](int type, bool ignoreMissingErrors) { auto paletteLookup = [this, &partMap](int type) {
if (type > 0 && type < PT_NUM) if (type > 0 && type < PT_NUM)
{ {
auto carriedType = partMap[type]; auto carriedType = partMap[type];
if (!carriedType) // type is not 0 so this shouldn't be 0 either if (!carriedType) // type is not 0 so this shouldn't be 0 either
{ {
if (ignoreMissingErrors)
return type;
missingElements.ids.insert(type); missingElements.ids.insert(type);
} }
type = carriedType; type = carriedType;
@ -124,7 +113,7 @@ void GameSave::MapPalette()
{ {
continue; continue;
} }
tempPart.type = paletteLookup(tempPart.type, false); tempPart.type = paletteLookup(tempPart.type);
for (auto index : possiblyCarriesType) for (auto index : possiblyCarriesType)
{ {
if (elements[tempPart.type].CarriesTypeIn & (1U << index)) if (elements[tempPart.type].CarriesTypeIn & (1U << index))
@ -132,7 +121,7 @@ void GameSave::MapPalette()
auto *prop = reinterpret_cast<int *>(reinterpret_cast<char *>(&tempPart) + properties[index].Offset); auto *prop = reinterpret_cast<int *>(reinterpret_cast<char *>(&tempPart) + properties[index].Offset);
auto carriedType = *prop & int(pmapmask); auto carriedType = *prop & int(pmapmask);
auto extra = *prop >> pmapbits; auto extra = *prop >> pmapbits;
carriedType = paletteLookup(carriedType, ignoreMissingErrors[tempPart.type]); carriedType = paletteLookup(carriedType);
*prop = PMAP(extra, carriedType); *prop = PMAP(extra, carriedType);
} }
} }
@ -2347,14 +2336,6 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
{ {
RESTRICTVERSION(97, 0); RESTRICTVERSION(97, 0);
} }
if (particles[i].type == PT_RSST || particles[i].type == PT_RSSS)
{
RESTRICTVERSION(98, 0);
}
if (particles[i].type == PT_ETRD && (particles[i].tmp || particles[i].tmp2))
{
RESTRICTVERSION(98, 0);
}
//Get the pmap entry for the next particle in the same position //Get the pmap entry for the next particle in the same position
i = partsPosLink[i]; i = partsPosLink[i];

231
src/client/MD5.cpp Normal file
View File

@ -0,0 +1,231 @@
// based on public-domain code from Colin Plumb (1993)
#include "MD5.h"
#include <cstring>
static unsigned getu32(const unsigned char *addr)
{
return (((((unsigned long)addr[3] << 8) | addr[2]) << 8) | addr[1]) << 8 | addr[0];
}
static void putu32(unsigned data, unsigned char *addr)
{
addr[0] = (unsigned char)data;
addr[1] = (unsigned char)(data >> 8);
addr[2] = (unsigned char)(data >> 16);
addr[3] = (unsigned char)(data >> 24);
}
void md5_init(struct md5_context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
void md5_update(struct md5_context *ctx, unsigned char const *buf, unsigned len)
{
unsigned t;
// update bit count
t = ctx->bits[0];
if ((ctx->bits[0] = (t + ((unsigned)len << 3)) & 0xffffffff) < t)
ctx->bits[1]++; // carry
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f;
// use leading data to top up the buffer
if (t)
{
unsigned char *p = ctx->in + t;
t = 64-t;
if (len < t)
{
memcpy(p, buf, len);
return;
}
memcpy(p, buf, t);
md5_transform(ctx->buf, ctx->in);
buf += t;
len -= t;
}
// following 64-byte chunks
while (len >= 64)
{
memcpy(ctx->in, buf, 64);
md5_transform(ctx->buf, ctx->in);
buf += 64;
len -= 64;
}
// save rest of bytes for later
memcpy(ctx->in, buf, len);
}
void md5_final(unsigned char digest[16], struct md5_context *ctx)
{
unsigned count;
unsigned char *p;
// #bytes mod64
count = (ctx->bits[0] >> 3) & 0x3F;
// first char of padding = 0x80
p = ctx->in + count;
*p++ = 0x80;
// calculate # of bytes to pad
count = 64 - 1 - count;
// Pad out to 56 mod 64
if (count < 8)
{
// we need to finish a whole block before padding
memset(p, 0, count);
md5_transform(ctx->buf, ctx->in);
memset(ctx->in, 0, 56);
}
else
{
// just pad to 56 bytes
memset(p, 0, count-8);
}
// append length & final transform
putu32(ctx->bits[0], ctx->in + 56);
putu32(ctx->bits[1], ctx->in + 60);
md5_transform(ctx->buf, ctx->in);
putu32(ctx->buf[0], digest);
putu32(ctx->buf[1], digest + 4);
putu32(ctx->buf[2], digest + 8);
putu32(ctx->buf[3], digest + 12);
memset(&ctx, 0, sizeof(ctx));
}
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x )
void md5_transform(unsigned buf[4], const unsigned char inraw[64])
{
unsigned a, b, c, d;
unsigned in[16];
int i;
for (i = 0; i < 16; ++i)
in[i] = getu32 (inraw + 4 * i);
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
static char hexChars[] = "0123456789abcdef";
void md5_ascii(char *result, unsigned char const *buf, unsigned len)
{
struct md5_context md5;
unsigned char hash[16];
int i;
if (len==0)
len = strlen((char *)buf);
md5_init(&md5);
md5_update(&md5, buf, len);
md5_final(hash, &md5);
for (i=0; i<16; i++)
{
result[i*2] = hexChars[(hash[i]>>4)&0xF];
result[i*2+1] = hexChars[hash[i]&0x0F];
}
result[32] = 0;
}

15
src/client/MD5.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
struct md5_context
{
unsigned buf[4];
unsigned bits[2];
unsigned char in[64];
};
void md5_init(struct md5_context *context);
void md5_update(struct md5_context *context, unsigned char const *buf, unsigned len);
void md5_final(unsigned char digest[16], struct md5_context *context);
void md5_transform(unsigned buf[4], const unsigned char in[64]);
void md5_ascii(char *result, unsigned char const *buf, unsigned len);

View File

@ -14,13 +14,4 @@ namespace http
sortByVotes, sortByVotes,
sortByDate, sortByDate,
}; };
enum Period
{
allSaves,
todaySaves,
weekSaves,
monthSaves,
yearSaves,
};
} }

View File

@ -1,4 +1,3 @@
#include <ctime>
#include "SearchSavesRequest.h" #include "SearchSavesRequest.h"
#include "Config.h" #include "Config.h"
#include "client/Client.h" #include "client/Client.h"
@ -7,7 +6,7 @@
namespace http namespace http
{ {
static ByteString Url(int start, int count, ByteString query, Period period, Sort sort, Category category) static ByteString Url(int start, int count, ByteString query, Sort sort, Category category)
{ {
ByteStringBuilder builder; ByteStringBuilder builder;
builder << SCHEME << SERVER << "/Browse.json?Start=" << start << "&Count=" << count; builder << SCHEME << SERVER << "/Browse.json?Start=" << start << "&Count=" << count;
@ -18,38 +17,6 @@ namespace http
} }
query += str; query += str;
}; };
time_t currentTime = time(NULL);
if(period)
{
switch (period)
{
case todaySaves:
currentTime -= 60*60*24; // One day
break;
case weekSaves:
currentTime -= 60*60*24*7; // One week
break;
case monthSaves:
currentTime -= 60*60*24*31; // One month
break;
case yearSaves:
currentTime -= 60*60*24*365; // One year
break;
default:
break;
}
struct tm currentTimeData = *localtime(&currentTime);
ByteStringBuilder afterQuery;
afterQuery << "after:" << currentTimeData.tm_year+1900 << "-" <<
(currentTimeData.tm_mon < 9 ? "0" : "") << currentTimeData.tm_mon+1 << "-" <<
(currentTimeData.tm_mday < 10 ? "0" : "") << currentTimeData.tm_mday;
appendToQuery(afterQuery.Build());
}
switch (sort) switch (sort)
{ {
case sortByDate: case sortByDate:
@ -81,7 +48,7 @@ namespace http
return builder.Build(); return builder.Build();
} }
SearchSavesRequest::SearchSavesRequest(int start, int count, ByteString query, Period period, Sort sort, Category category) : APIRequest(Url(start, count, query, period, sort, category), authUse, false) SearchSavesRequest::SearchSavesRequest(int start, int count, ByteString query, Sort sort, Category category) : APIRequest(Url(start, count, query, sort, category), authUse, false)
{ {
} }

View File

@ -8,7 +8,7 @@ namespace http
class SearchSavesRequest : public APIRequest class SearchSavesRequest : public APIRequest
{ {
public: public:
SearchSavesRequest(int start, int count, ByteString query, Period period, Sort sort, Category category); SearchSavesRequest(int start, int count, ByteString query, Sort sort, Category category);
std::pair<int, std::vector<std::unique_ptr<SaveInfo>>> Finish(); std::pair<int, std::vector<std::unique_ptr<SaveInfo>>> Finish();
}; };

View File

@ -52,10 +52,6 @@ namespace http
return; return;
} }
auto &info = versions[key]; auto &info = versions[key];
if (info.isNull())
{
return;
}
auto getOr = [&info](ByteString key, int defaultValue) -> int { auto getOr = [&info](ByteString key, int defaultValue) -> int {
if (!info.isMember(key)) if (!info.isMember(key))
{ {
@ -63,7 +59,7 @@ namespace http
} }
return info[key].asInt(); return info[key].asInt();
}; };
auto build = getOr(key == "Snapshot" ? "Snapshot" : "Build", 0); auto build = getOr(key == "Snapshot" ? "Snapshot" : "Build", -1);
if (!updateAvailableFunc(build)) if (!updateAvailableFunc(build))
{ {
return; return;
@ -72,8 +68,8 @@ namespace http
channel, channel,
ByteString::Build(SCHEME, alternate ? UPDATESERVER : SERVER, info["File"].asString()), ByteString::Build(SCHEME, alternate ? UPDATESERVER : SERVER, info["File"].asString()),
ByteString(info["Changelog"].asString()).FromUtf8(), ByteString(info["Changelog"].asString()).FromUtf8(),
getOr("Major", 0), getOr("Major", -1),
getOr("Minor", 0), getOr("Minor", -1),
build, build,
}; };
}; };

View File

@ -1,4 +1,5 @@
client_files = files( client_files = files(
'MD5.cpp',
'SaveFile.cpp', 'SaveFile.cpp',
'SaveInfo.cpp', 'SaveInfo.cpp',
'ThumbnailRendererTask.cpp', 'ThumbnailRendererTask.cpp',

View File

@ -112,14 +112,6 @@ struct Vec2
); );
} }
Vec2<T> Min(Vec2<T> other) const
{
return Vec2<T>(
std::min(X, other.X),
std::min(Y, other.Y)
);
}
// Return a rectangle starting at origin, whose dimensions match this vector // Return a rectangle starting at origin, whose dimensions match this vector
template<typename S = T, typename = std::enable_if_t<std::is_integral_v<S>>> template<typename S = T, typename = std::enable_if_t<std::is_integral_v<S>>>
constexpr inline Rect<T> OriginRect() const constexpr inline Rect<T> OriginRect() const

View File

@ -58,7 +58,7 @@ bool ReadFile(std::vector<char> &fileData, ByteString filename)
if (f) f.seekg(0, std::ios::end); if (f) f.seekg(0, std::ios::end);
if (f) fileData.resize(f.tellg()); if (f) fileData.resize(f.tellg());
if (f) f.seekg(0); if (f) f.seekg(0);
if (f && fileData.size()) f.read(&fileData[0], fileData.size()); if (f) f.read(&fileData[0], fileData.size());
if (!f) if (!f)
{ {
std::cerr << "ReadFile: " << filename << ": " << strerror(errno) << std::endl; std::cerr << "ReadFile: " << filename << ": " << strerror(errno) << std::endl;

View File

@ -6,9 +6,6 @@
#include "Config.h" #include "Config.h"
#include <cstring> #include <cstring>
#include <ctime> #include <ctime>
#ifdef __FreeBSD__
# include <sys/sysctl.h>
#endif
namespace Platform namespace Platform
{ {
@ -28,28 +25,9 @@ long unsigned int GetTime()
} }
ByteString ExecutableNameFirstApprox() ByteString ExecutableNameFirstApprox()
{
if (Stat("/proc/self/exe"))
{ {
return "/proc/self/exe"; return "/proc/self/exe";
} }
#ifdef __FreeBSD__
{
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = -1;
std::array<char, 1000> buf;
size_t cb = buf.size();
if (!sysctl(mib, 4, &buf[0], &cb, NULL, 0))
{
return ByteString(&buf[0], &buf[0] + cb);
}
}
#endif
return "";
}
bool CanUpdate() bool CanUpdate()
{ {

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
#include "common/String.h" #include "common/String.h"
#include <cstdint>
#include <string> #include <string>
#include <vector> #include <vector>
#include <optional> #include <optional>

View File

@ -16,11 +16,6 @@ elif host_platform == 'linux'
stacktrace_files = files('Execinfo.cpp') stacktrace_files = files('Execinfo.cpp')
# export symbols so backtrace_symbols works, see above # export symbols so backtrace_symbols works, see above
bluescreen_export_symbols = true bluescreen_export_symbols = true
if host_machine.system() in [ 'freebsd' ]
project_deps += [
c_compiler.find_library('execinfo'),
]
endif
else else
stacktrace_files = files('Null.cpp') stacktrace_files = files('Null.cpp')
endif endif

View File

@ -183,8 +183,6 @@ void Renderer::render_parts()
gfctx.pipeSubcallTpart = nullptr; gfctx.pipeSubcallTpart = nullptr;
int deca, decr, decg, decb, cola, colr, colg, colb, firea, firer, fireg, fireb, pixel_mode, q, i, t, nx, ny, x, y; int deca, decr, decg, decb, cola, colr, colg, colb, firea, firer, fireg, fireb, pixel_mode, q, i, t, nx, ny, x, y;
int orbd[4] = {0, 0, 0, 0}, orbl[4] = {0, 0, 0, 0}; int orbd[4] = {0, 0, 0, 0}, orbl[4] = {0, 0, 0, 0};
int drawing_budget = 1000000; //Serves as an upper bound for costly effects such as SPARK, FLARE and LFLARE
if(!sim) if(!sim)
return; return;
auto *parts = sim->parts; auto *parts = sim->parts;
@ -635,7 +633,7 @@ void Renderer::render_parts()
{ {
auto flicker = float(gfctx.rng()%20); auto flicker = float(gfctx.rng()%20);
auto gradv = 4*sim->parts[i].life + flicker; auto gradv = 4*sim->parts[i].life + flicker;
for (x = 0; (gradv>0.5) && (drawing_budget > 0); x++) { for (x = 0; gradv>0.5; x++) {
auto col = RGBA<uint8_t>( auto col = RGBA<uint8_t>(
std::min(0xFF, colr * int(gradv) / 255), std::min(0xFF, colr * int(gradv) / 255),
std::min(0xFF, colg * int(gradv) / 255), std::min(0xFF, colg * int(gradv) / 255),
@ -646,7 +644,6 @@ void Renderer::render_parts()
AddPixel({ nx, ny+x }, col); AddPixel({ nx, ny+x }, col);
AddPixel({ nx, ny-x }, col); AddPixel({ nx, ny-x }, col);
gradv = gradv/1.5f; gradv = gradv/1.5f;
drawing_budget--;
} }
} }
if(pixel_mode & PMODE_FLARE) if(pixel_mode & PMODE_FLARE)
@ -663,13 +660,12 @@ void Renderer::render_parts()
BlendPixel({ nx-1, ny-1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv))); BlendPixel({ nx-1, ny-1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
BlendPixel({ nx+1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv))); BlendPixel({ nx+1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
BlendPixel({ nx-1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv))); BlendPixel({ nx-1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
for (x = 1; (gradv>0.5) && (drawing_budget > 0); x++) { for (x = 1; gradv>0.5; x++) {
AddPixel({ nx+x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv))); AddPixel({ nx+x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
AddPixel({ nx-x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv))); AddPixel({ nx-x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
AddPixel({ nx, ny+x }, RGBA<uint8_t>(colr, colg, colb, int(gradv))); AddPixel({ nx, ny+x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
AddPixel({ nx, ny-x }, RGBA<uint8_t>(colr, colg, colb, int(gradv))); AddPixel({ nx, ny-x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
gradv = gradv/1.2f; gradv = gradv/1.2f;
drawing_budget--;
} }
} }
if(pixel_mode & PMODE_LFLARE) if(pixel_mode & PMODE_LFLARE)
@ -686,13 +682,12 @@ void Renderer::render_parts()
BlendPixel({ nx-1, ny-1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv))); BlendPixel({ nx-1, ny-1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
BlendPixel({ nx+1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv))); BlendPixel({ nx+1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
BlendPixel({ nx-1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv))); BlendPixel({ nx-1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
for (x = 1; (gradv>0.5) && (drawing_budget > 0); x++) { for (x = 1; gradv>0.5; x++) {
AddPixel({ nx+x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv))); AddPixel({ nx+x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
AddPixel({ nx-x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv))); AddPixel({ nx-x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
AddPixel({ nx, ny+x }, RGBA<uint8_t>(colr, colg, colb, int(gradv))); AddPixel({ nx, ny+x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
AddPixel({ nx, ny-x }, RGBA<uint8_t>(colr, colg, colb, int(gradv))); AddPixel({ nx, ny-x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
gradv = gradv/1.01f; gradv = gradv/1.01f;
drawing_budget--;
} }
} }
if (pixel_mode & EFFECT_GRAVIN) if (pixel_mode & EFFECT_GRAVIN)

View File

@ -41,8 +41,6 @@ class Renderer: public RasterDrawMethods<Renderer>
friend struct RasterDrawMethods<Renderer>; friend struct RasterDrawMethods<Renderer>;
float fireIntensity = 1;
public: public:
Vec2<int> Size() const Vec2<int> Size() const
{ {
@ -99,10 +97,6 @@ public:
void DrawSigns(); void DrawSigns();
void render_gravlensing(const Video &source); void render_gravlensing(const Video &source);
void render_fire(); void render_fire();
float GetFireIntensity() const
{
return fireIntensity;
}
void prepare_alpha(int size, float intensity); void prepare_alpha(int size, float intensity);
void render_parts(); void render_parts();
void draw_grav_zones(); void draw_grav_zones();

View File

@ -11,6 +11,7 @@ constexpr auto VIDYRES = WINDOWH;
void Renderer::RenderBegin() void Renderer::RenderBegin()
{ {
draw_air();
draw_grav(); draw_grav();
DrawWalls(); DrawWalls();
render_parts(); render_parts();
@ -141,10 +142,9 @@ float glow_alphaf[11][11];
float blur_alphaf[7][7]; float blur_alphaf[7][7];
void Renderer::prepare_alpha(int size, float intensity) void Renderer::prepare_alpha(int size, float intensity)
{ {
fireIntensity = intensity;
//TODO: implement size //TODO: implement size
int x,y,i,j; int x,y,i,j;
float multiplier = 255.0f*fireIntensity; float multiplier = 255.0f*intensity;
memset(temp, 0, sizeof(temp)); memset(temp, 0, sizeof(temp));
for (x=0; x<CELL; x++) for (x=0; x<CELL; x++)

View File

@ -6,7 +6,6 @@
#include <SDL.h> #include <SDL.h>
#include "gui/interface/Textbox.h" #include "gui/interface/Textbox.h"
#include "gui/interface/ScrollPanel.h"
#include "gui/interface/Label.h" #include "gui/interface/Label.h"
#include "gui/game/Tool.h" #include "gui/game/Tool.h"
#include "gui/game/Menu.h" #include "gui/game/Menu.h"
@ -53,9 +52,6 @@ ElementSearchActivity::ElementSearchActivity(GameController * gameController, st
AddComponent(okButton); AddComponent(okButton);
AddComponent(closeButton); AddComponent(closeButton);
scrollPanel = new ui::ScrollPanel(searchField->Position + Vec2{ 1, searchField->Size.Y+9 }, { searchField->Size.X - 2, Size.Y-(searchField->Position.Y+searchField->Size.Y+6)-23 });
AddComponent(scrollPanel);
searchTools(""); searchTools("");
} }
@ -63,12 +59,12 @@ void ElementSearchActivity::searchTools(String query)
{ {
firstResult = NULL; firstResult = NULL;
for (auto &toolButton : toolButtons) { for (auto &toolButton : toolButtons) {
scrollPanel->RemoveChild(toolButton); RemoveComponent(toolButton);
delete toolButton; delete toolButton;
} }
toolButtons.clear(); toolButtons.clear();
ui::Point viewPosition = { 1, 1 }; ui::Point viewPosition = searchField->Position + ui::Point(2+0, searchField->Size.Y+2+8);
ui::Point current = ui::Point(0, 0); ui::Point current = ui::Point(0, 0);
String queryLower = query.ToLower(); String queryLower = query.ToLower();
@ -182,7 +178,7 @@ void ElementSearchActivity::searchTools(String query)
} }
toolButtons.push_back(tempButton); toolButtons.push_back(tempButton);
scrollPanel->AddChild(tempButton); AddComponent(tempButton);
current.X += 31; current.X += 31;
@ -190,13 +186,10 @@ void ElementSearchActivity::searchTools(String query)
current.X = 0; current.X = 0;
current.Y += 19; current.Y += 19;
} }
}
if (current.X == 0) if(current.Y + viewPosition.Y + 18 > Size.Y-23)
{ break;
current.Y -= 19;
} }
scrollPanel->InnerSize = ui::Point(scrollPanel->Size.X, current.Y + 20);
} }
void ElementSearchActivity::SetActiveTool(int selectionState, Tool * tool) void ElementSearchActivity::SetActiveTool(int selectionState, Tool * tool)
@ -223,7 +216,8 @@ void ElementSearchActivity::OnDraw()
g->DrawRect(RectSized(Position, Size), 0xFFFFFF_rgb); g->DrawRect(RectSized(Position, Size), 0xFFFFFF_rgb);
g->BlendRect( g->BlendRect(
RectSized(Position + scrollPanel->Position - Vec2{ 1, 1 }, scrollPanel->Size + Vec2{ 2, 2 }), RectSized(Position + searchField->Position + Vec2{ 0, searchField->Size.Y+8 },
{ searchField->Size.X, Size.Y-(searchField->Position.Y+searchField->Size.Y+8)-23 }),
0xFFFFFF_rgb .WithAlpha(180)); 0xFFFFFF_rgb .WithAlpha(180));
if (toolTipPresence && toolTip.length()) if (toolTipPresence && toolTip.length())
{ {

View File

@ -10,7 +10,6 @@ class GameController;
namespace ui namespace ui
{ {
class ScrollPanel;
class Textbox; class Textbox;
} }
@ -21,7 +20,6 @@ class ElementSearchActivity: public WindowActivity
std::vector<Tool*> tools; std::vector<Tool*> tools;
ui::Textbox * searchField; ui::Textbox * searchField;
std::vector<ToolButton*> toolButtons; std::vector<ToolButton*> toolButtons;
ui::ScrollPanel *scrollPanel = nullptr;
String toolTip; String toolTip;
int toolTipPresence; int toolTipPresence;
bool shiftPressed; bool shiftPressed;

View File

@ -39,7 +39,7 @@ class LoadFilesTask: public Task
bool doWork() override bool doWork() override
{ {
std::vector<ByteString> files = Platform::DirectorySearch(directory, search, { ".cps" }); std::vector<ByteString> files = Platform::DirectorySearch(directory, search, { ".cps" });
std::sort(files.rbegin(), files.rend(), [](ByteString a, ByteString b) { return a.ToLower() > b.ToLower(); }); std::sort(files.rbegin(), files.rend(), [](ByteString a, ByteString b) { return a.ToLower() < b.ToLower(); });
notifyProgress(-1); notifyProgress(-1);
for(std::vector<ByteString>::iterator iter = files.begin(), end = files.end(); iter != end; ++iter) for(std::vector<ByteString>::iterator iter = files.begin(), end = files.end(); iter != end; ++iter)

View File

@ -52,14 +52,6 @@ void Brush::InitOutline()
void Brush::SetRadius(ui::Point newRadius) void Brush::SetRadius(ui::Point newRadius)
{ {
if (newRadius.X < 0)
newRadius.X = 0;
if (newRadius.Y < 0)
newRadius.Y = 0;
if (newRadius.X > 200)
newRadius.X = 200;
if (newRadius.Y > 200)
newRadius.Y = 200;
radius = newRadius; radius = newRadius;
InitOutline(); InitOutline();
} }
@ -75,6 +67,14 @@ void Brush::AdjustSize(int delta, bool logarithmic, bool keepX, bool keepY)
newSize = oldSize + ui::Point(delta * std::max(oldSize.X / 5, 1), delta * std::max(oldSize.Y / 5, 1)); newSize = oldSize + ui::Point(delta * std::max(oldSize.X / 5, 1), delta * std::max(oldSize.Y / 5, 1));
else else
newSize = oldSize + ui::Point(delta, delta); newSize = oldSize + ui::Point(delta, delta);
if (newSize.X < 0)
newSize.X = 0;
if (newSize.Y < 0)
newSize.Y = 0;
if (newSize.X > 200)
newSize.X = 200;
if (newSize.Y > 200)
newSize.Y = 200;
if (keepY) if (keepY)
SetRadius(ui::Point(newSize.X, oldSize.Y)); SetRadius(ui::Point(newSize.X, oldSize.Y));

View File

@ -90,7 +90,7 @@ GameController::GameController():
gameView->SetDebugHUD(GlobalPrefs::Ref().Get("Renderer.DebugMode", false)); gameView->SetDebugHUD(GlobalPrefs::Ref().Get("Renderer.DebugMode", false));
commandInterface = CommandInterface::Create(this, gameModel); CommandInterface::Create(this, gameModel);
Client::Ref().AddListener(this); Client::Ref().AddListener(this);
@ -146,7 +146,7 @@ GameController::~GameController()
{ {
delete *iter; delete *iter;
} }
commandInterface.reset(); delete commandInterface;
delete gameModel; delete gameModel;
if (gameView->CloseActiveWindow()) if (gameView->CloseActiveWindow())
{ {
@ -552,7 +552,7 @@ bool GameController::MouseUp(int x, int y, unsigned button, MouseupReason reason
} }
break; break;
case sign::Type::Thread: case sign::Type::Thread:
Platform::OpenURI(ByteString::Build(SCHEME, SERVER, "/Discussions/Thread/View.html?Thread=", str.Substr(3, si.first - 3).ToUtf8())); Platform::OpenURI(ByteString::Build(SCHEME, "powdertoy.co.uk/Discussions/Thread/View.html?Thread=", str.Substr(3, si.first - 3).ToUtf8()));
break; break;
case sign::Type::Search: case sign::Type::Search:
OpenSearch(str.Substr(3, si.first - 3)); OpenSearch(str.Substr(3, si.first - 3));
@ -785,7 +785,7 @@ void GameController::ResetSpark()
void GameController::SwitchGravity() void GameController::SwitchGravity()
{ {
gameModel->GetSimulation()->gravityMode = (gameModel->GetSimulation()->gravityMode + 1) % NUM_GRAVMODES; gameModel->GetSimulation()->gravityMode = (gameModel->GetSimulation()->gravityMode + 1) % NUM_GRAV_MODES;
switch (gameModel->GetSimulation()->gravityMode) switch (gameModel->GetSimulation()->gravityMode)
{ {
@ -806,23 +806,23 @@ void GameController::SwitchGravity()
void GameController::SwitchAir() void GameController::SwitchAir()
{ {
gameModel->GetSimulation()->air->airMode = (gameModel->GetSimulation()->air->airMode + 1) % NUM_AIRMODES; gameModel->GetSimulation()->air->airMode = (gameModel->GetSimulation()->air->airMode + 1) % NUM_AIR_MODES;
switch (gameModel->GetSimulation()->air->airMode) switch (gameModel->GetSimulation()->air->airMode)
{ {
case AIR_ON: case AIR_ON:
gameModel->SetInfoTip("Air: On"); gameModel->SetInfoTip("Air: On");
break; break;
case AIR_PRESSUREOFF: case AIR_PRESSURE_OFF:
gameModel->SetInfoTip("Air: Pressure Off"); gameModel->SetInfoTip("Air: Pressure Off");
break; break;
case AIR_VELOCITYOFF: case AIR_VELOCITY_OFF:
gameModel->SetInfoTip("Air: Velocity Off"); gameModel->SetInfoTip("Air: Velocity Off");
break; break;
case AIR_OFF: case AIR_OFF:
gameModel->SetInfoTip("Air: Off"); gameModel->SetInfoTip("Air: Off");
break; break;
case AIR_NOUPDATE: case AIR_NO_UPDATE:
gameModel->SetInfoTip("Air: No Update"); gameModel->SetInfoTip("Air: No Update");
break; break;
} }
@ -1031,7 +1031,7 @@ int GameController::GetEdgeMode()
void GameController::SetEdgeMode(int edgeMode) void GameController::SetEdgeMode(int edgeMode)
{ {
if (edgeMode < 0 || edgeMode >= NUM_EDGEMODES) if (edgeMode < 0 || edgeMode >= NUM_EDGE_MODES)
edgeMode = 0; edgeMode = 0;
gameModel->SetEdgeMode(edgeMode); gameModel->SetEdgeMode(edgeMode);
@ -1111,12 +1111,9 @@ void GameController::SetActiveTool(int toolSelection, Tool * tool)
gameModel->SetLastTool(tool); gameModel->SetLastTool(tool);
for(int i = 0; i < 3; i++) for(int i = 0; i < 3; i++)
{ {
auto *activeTool = gameModel->GetActiveTool(i); if(gameModel->GetActiveTool(i) == gameModel->GetMenuList().at(SC_WALL)->GetToolList().at(WL_GRAV))
if (activeTool && activeTool->Identifier == "DEFAULT_WL_GRVTY")
{
gameModel->GetRenderer()->gravityZonesEnabled = true; gameModel->GetRenderer()->gravityZonesEnabled = true;
} }
}
if (tool->Identifier == "DEFAULT_UI_PROPERTY") if (tool->Identifier == "DEFAULT_UI_PROPERTY")
{ {
static_cast<PropertyTool *>(tool)->OpenWindow(gameModel->GetSimulation(), nullptr); static_cast<PropertyTool *>(tool)->OpenWindow(gameModel->GetSimulation(), nullptr);
@ -1389,7 +1386,7 @@ void GameController::OpenOptions()
void GameController::ShowConsole() void GameController::ShowConsole()
{ {
if (!console) if (!console)
console = new ConsoleController(NULL, commandInterface.get()); console = new ConsoleController(NULL, commandInterface);
if (console->GetView() != ui::Engine::Ref().GetWindow()) if (console->GetView() != ui::Engine::Ref().GetWindow())
ui::Engine::Ref().ShowWindow(console->GetView()); ui::Engine::Ref().ShowWindow(console->GetView());
} }

View File

@ -1,5 +1,4 @@
#pragma once #pragma once
#include "lua/CommandInterfacePtr.h"
#include "client/ClientListener.h" #include "client/ClientListener.h"
#include "client/StartupInfo.h" #include "client/StartupInfo.h"
#include "gui/interface/Point.h" #include "gui/interface/Point.h"
@ -29,6 +28,7 @@ class LocalBrowserController;
class SearchController; class SearchController;
class PreviewController; class PreviewController;
class RenderController; class RenderController;
class CommandInterface;
class VideoBuffer; class VideoBuffer;
class Tool; class Tool;
class Menu; class Menu;
@ -39,8 +39,6 @@ class TagsController;
class ConsoleController; class ConsoleController;
class GameController: public ClientListener class GameController: public ClientListener
{ {
CommandInterfacePtr commandInterface;
private: private:
bool firstTick; bool firstTick;
int foundSignID; int foundSignID;
@ -128,7 +126,6 @@ public:
int GetEdgeMode(); int GetEdgeMode();
void SetEdgeMode(int edgeMode); void SetEdgeMode(int edgeMode);
void SetDebugFlags(unsigned int flags) { debugFlags = flags; } void SetDebugFlags(unsigned int flags) { debugFlags = flags; }
unsigned int GetDebugFlags() const { return debugFlags; }
void SetActiveMenu(int menuID); void SetActiveMenu(int menuID);
std::vector<Menu*> GetMenuList(); std::vector<Menu*> GetMenuList();
int GetNumMenus(bool onlyEnabled); int GetNumMenus(bool onlyEnabled);

View File

@ -54,16 +54,16 @@ GameModel::GameModel():
colour(255, 0, 0, 255), colour(255, 0, 0, 255),
edgeMode(EDGE_VOID), edgeMode(EDGE_VOID),
ambientAirTemp(R_TEMP + 273.15f), ambientAirTemp(R_TEMP + 273.15f),
decoSpace(DECOSPACE_SRGB) decoSpace(0)
{ {
sim = new Simulation(); sim = new Simulation();
sim->useLuaCallbacks = true; sim->useLuaCallbacks = true;
ren = new Renderer(sim); ren = new Renderer(sim);
activeTools = &regularToolset[0]; activeTools = regularToolset;
std::fill(decoToolset.begin(), decoToolset.end(), nullptr); std::fill(decoToolset, decoToolset+4, (Tool*)NULL);
std::fill(regularToolset.begin(), regularToolset.end(), nullptr); std::fill(regularToolset, regularToolset+4, (Tool*)NULL);
//Default render prefs //Default render prefs
ren->SetRenderMode({ ren->SetRenderMode({
@ -93,7 +93,7 @@ GameModel::GameModel():
ren->decorations_enable = prefs.Get("Renderer.Decorations", true); ren->decorations_enable = prefs.Get("Renderer.Decorations", true);
//Load config into simulation //Load config into simulation
edgeMode = prefs.Get("Simulation.EdgeMode", NUM_EDGEMODES, EDGE_VOID); edgeMode = prefs.Get("Simulation.EdgeMode", (int)EDGE_VOID);
sim->SetEdgeMode(edgeMode); sim->SetEdgeMode(edgeMode);
ambientAirTemp = float(R_TEMP) + 273.15f; ambientAirTemp = float(R_TEMP) + 273.15f;
{ {
@ -104,9 +104,9 @@ GameModel::GameModel():
} }
} }
sim->air->ambientAirTemp = ambientAirTemp; sim->air->ambientAirTemp = ambientAirTemp;
decoSpace = prefs.Get("Simulation.DecoSpace", NUM_DECOSPACES, DECOSPACE_SRGB); decoSpace = prefs.Get("Simulation.DecoSpace", 0); // TODO: DecoSpace enum
sim->SetDecoSpace(decoSpace); sim->SetDecoSpace(decoSpace);
int ngrav_enable = prefs.Get("Simulation.NewtonianGravity", NUM_GRAVMODES, GRAV_VERTICAL); int ngrav_enable = prefs.Get("Simulation.NewtonianGravity", 0); // TODO: NewtonianGravity enum
if (ngrav_enable) if (ngrav_enable)
sim->grav->start_grav_async(); sim->grav->start_grav_async();
sim->aheat_enable = prefs.Get("Simulation.AmbientHeat", 0); // TODO: AmbientHeat enum sim->aheat_enable = prefs.Get("Simulation.AmbientHeat", 0); // TODO: AmbientHeat enum
@ -228,7 +228,7 @@ void GameModel::BuildMenus()
if(activeMenu != -1) if(activeMenu != -1)
lastMenu = activeMenu; lastMenu = activeMenu;
std::array<ByteString, NUM_TOOLINDICES> activeToolIdentifiers; ByteString activeToolIdentifiers[4];
if(regularToolset[0]) if(regularToolset[0])
activeToolIdentifiers[0] = regularToolset[0]->Identifier; activeToolIdentifiers[0] = regularToolset[0]->Identifier;
if(regularToolset[1]) if(regularToolset[1])
@ -881,17 +881,17 @@ void GameModel::SetActiveMenu(int menuID)
if(menuID == SC_DECO) if(menuID == SC_DECO)
{ {
if(activeTools != &decoToolset[0]) if(activeTools != decoToolset)
{ {
activeTools = &decoToolset[0]; activeTools = decoToolset;
notifyActiveToolsChanged(); notifyActiveToolsChanged();
} }
} }
else else
{ {
if(activeTools != &regularToolset[0]) if(activeTools != regularToolset)
{ {
activeTools = &regularToolset[0]; activeTools = regularToolset;
notifyActiveToolsChanged(); notifyActiveToolsChanged();
} }
} }
@ -1712,7 +1712,7 @@ void GameModel::BeforeSim()
{ {
if (!sim->sys_pause || sim->framerender) if (!sim->sys_pause || sim->framerender)
{ {
CommandInterface::Ref().HandleEvent(BeforeSimEvent{}); commandInterface->HandleEvent(BeforeSimEvent{});
} }
sim->BeforeSim(); sim->BeforeSim();
} }
@ -1720,5 +1720,5 @@ void GameModel::BeforeSim()
void GameModel::AfterSim() void GameModel::AfterSim()
{ {
sim->AfterSim(); sim->AfterSim();
CommandInterface::Ref().HandleEvent(AfterSimEvent{}); commandInterface->HandleEvent(AfterSimEvent{});
} }

View File

@ -6,9 +6,6 @@
#include <deque> #include <deque>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <array>
constexpr auto NUM_TOOLINDICES = 4;
class Menu; class Menu;
class Tool; class Tool;
@ -75,8 +72,8 @@ private:
std::unique_ptr<SaveFile> currentFile; std::unique_ptr<SaveFile> currentFile;
Tool * lastTool; Tool * lastTool;
Tool ** activeTools; Tool ** activeTools;
std::array<Tool *, NUM_TOOLINDICES> decoToolset; Tool * decoToolset[4];
std::array<Tool *, NUM_TOOLINDICES> regularToolset; Tool * regularToolset[4];
User currentUser; User currentUser;
float toolStrength; float toolStrength;
std::deque<HistoryEntry> history; std::deque<HistoryEntry> history;
@ -195,10 +192,6 @@ public:
Brush &GetBrush(); Brush &GetBrush();
Brush *GetBrushByID(int i); Brush *GetBrushByID(int i);
int GetBrushID(); int GetBrushID();
int BrushListSize() const
{
return int(brushList.size());
}
void SetBrushID(int i); void SetBrushID(int i);
void SetVote(int direction); void SetVote(int direction);

View File

@ -87,7 +87,7 @@ public:
} }
} }
} }
void OnMouseClick(int x, int y, unsigned int button) override void OnMouseUnclick(int x, int y, unsigned int button) override
{ {
if(isButtonDown) if(isButtonDown)
{ {
@ -96,7 +96,7 @@ public:
else if(rightDown) else if(rightDown)
DoRightAction(); DoRightAction();
} }
ui::Button::OnMouseClick(x, y, button); ui::Button::OnMouseUnclick(x, y, button);
} }
void OnMouseHover(int x, int y) override void OnMouseHover(int x, int y) override
@ -120,19 +120,16 @@ public:
toolTip = newToolTip1; toolTip = newToolTip1;
toolTip2 = newToolTip2; toolTip2 = newToolTip2;
} }
void OnMouseDown(int x, int y, unsigned int button) override void OnMouseClick(int x, int y, unsigned int button) override
{
ui::Button::OnMouseDown(x, y, button);
if (MouseDownInside)
{ {
ui::Button::OnMouseClick(x, y, button);
rightDown = false; rightDown = false;
leftDown = false; leftDown = false;
if(x - Position.X >= splitPosition) if(x >= splitPosition)
rightDown = true; rightDown = true;
else if(x - Position.X < splitPosition) else if(x < splitPosition)
leftDown = true; leftDown = true;
} }
}
void DoRightAction() void DoRightAction()
{ {
if(!Enabled) if(!Enabled)
@ -1055,21 +1052,14 @@ void GameView::updateToolButtonScroll()
{ {
for (auto *button : toolButtons) for (auto *button : toolButtons)
{ {
auto inside = button->Position.X < x && button->Position.X + button->Size.X > x; if (button->Position.X < x && button->Position.X + button->Size.X > x)
if (inside && !button->MouseInside)
{
button->MouseInside = true;
button->OnMouseEnter(x, y); button->OnMouseEnter(x, y);
} else
if (!inside && button->MouseInside)
{
button->MouseInside = false;
button->OnMouseLeave(x, y); button->OnMouseLeave(x, y);
} }
} }
} }
} }
}
void GameView::OnMouseMove(int x, int y, int dx, int dy) void GameView::OnMouseMove(int x, int y, int dx, int dy)
{ {
@ -2134,7 +2124,6 @@ void GameView::OnDraw()
auto &sd = SimulationData::Ref(); auto &sd = SimulationData::Ref();
std::unique_lock lk(sd.elementGraphicsMx); std::unique_lock lk(sd.elementGraphicsMx);
ren->clearScreen(); ren->clearScreen();
ren->draw_air();
c->BeforeSimDraw(); c->BeforeSimDraw();
ren->RenderBegin(); ren->RenderBegin();
ren->SetSample(c->PointTranslate(currentMouse)); ren->SetSample(c->PointTranslate(currentMouse));

View File

@ -76,7 +76,7 @@ inline ByteString IntroText()
} }
else else
{ {
sb << "\bgTo use online features such as saving, you need to register at: \brhttps://" << SERVER << "/Register.html\n"; sb << "\bgTo use online features such as saving, you need to register at: \brhttps://powdertoy.co.uk/Register.html\n";
} }
sb << "\n\bt" << VersionInfo(); sb << "\n\bt" << VersionInfo();
return sb.Build(); return sb.Build();

View File

@ -16,15 +16,12 @@ ToolButton::ToolButton(ui::Point position, ui::Point size, String text, ByteStri
Component::TextPosition(buttonDisplayText); Component::TextPosition(buttonDisplayText);
} }
void ToolButton::OnMouseDown(int x, int y, unsigned int button) void ToolButton::OnMouseClick(int x, int y, unsigned int button)
{
if (MouseDownInside)
{ {
isButtonDown = true; isButtonDown = true;
} }
}
void ToolButton::OnMouseClick(int x, int y, unsigned int button) void ToolButton::OnMouseUnclick(int x, int y, unsigned int button)
{ {
if(isButtonDown) if(isButtonDown)
{ {

View File

@ -9,7 +9,7 @@ class ToolButton: public ui::Button
ByteString toolIdentifier; ByteString toolIdentifier;
public: public:
ToolButton(ui::Point position, ui::Point size, String text, ByteString toolIdentifier, String toolTip = String()); ToolButton(ui::Point position, ui::Point size, String text, ByteString toolIdentifier, String toolTip = String());
void OnMouseDown(int x, int y, unsigned int button) override; void OnMouseUnclick(int x, int y, unsigned int button) override;
void OnMouseUp(int x, int y, unsigned int button) override; void OnMouseUp(int x, int y, unsigned int button) override;
void OnMouseClick(int x, int y, unsigned int button) override; void OnMouseClick(int x, int y, unsigned int button) override;
void Draw(const ui::Point& screenPos) override; void Draw(const ui::Point& screenPos) override;

View File

@ -51,7 +51,7 @@ void AvatarButton::Draw(const Point& screenPos)
} }
} }
void AvatarButton::OnMouseClick(int x, int y, unsigned int button) void AvatarButton::OnMouseUnclick(int x, int y, unsigned int button)
{ {
if(button != 1) if(button != 1)
{ {
@ -70,21 +70,18 @@ void AvatarButton::OnContextMenuAction(int item)
//Do nothing //Do nothing
} }
void AvatarButton::OnMouseDown(int x, int y, unsigned int button) void AvatarButton::OnMouseClick(int x, int y, unsigned int button)
{
if (MouseDownInside)
{ {
if(button == SDL_BUTTON_RIGHT) if(button == SDL_BUTTON_RIGHT)
{ {
if(menu) if(menu)
menu->Show(GetContainerPos() + ui::Point(x, y)); menu->Show(GetScreenPos() + ui::Point(x, y));
} }
else else
{ {
isButtonDown = true; isButtonDown = true;
} }
} }
}
void AvatarButton::OnMouseEnter(int x, int y) void AvatarButton::OnMouseEnter(int x, int y)
{ {

View File

@ -30,7 +30,7 @@ public:
virtual ~AvatarButton() = default; virtual ~AvatarButton() = default;
void OnMouseClick(int x, int y, unsigned int button) override; void OnMouseClick(int x, int y, unsigned int button) override;
void OnMouseDown(int x, int y, unsigned int button) override; void OnMouseUnclick(int x, int y, unsigned int button) override;
void OnMouseEnter(int x, int y) override; void OnMouseEnter(int x, int y) override;
void OnMouseLeave(int x, int y) override; void OnMouseLeave(int x, int y) override;

View File

@ -86,7 +86,7 @@ void Button::Draw(const Point& screenPos)
if (Enabled) if (Enabled)
{ {
if ((isButtonDown && MouseDownInside) || (isTogglable && toggle)) if (isButtonDown || (isTogglable && toggle))
{ {
textColour = Appearance.TextActive; textColour = Appearance.TextActive;
borderColour = Appearance.BorderActive; borderColour = Appearance.BorderActive;
@ -140,7 +140,7 @@ void Button::Draw(const Point& screenPos)
} }
} }
void Button::OnMouseClick(int x, int y, unsigned int button) void Button::OnMouseUnclick(int x, int y, unsigned int button)
{ {
if(button == 1) if(button == 1)
{ {
@ -171,9 +171,7 @@ void Button::OnMouseUp(int x, int y, unsigned int button)
isAltButtonDown = false; isAltButtonDown = false;
} }
void Button::OnMouseDown(int x, int y, unsigned int button) void Button::OnMouseClick(int x, int y, unsigned int button)
{
if (MouseDownInside)
{ {
if(!Enabled) if(!Enabled)
return; return;
@ -186,7 +184,6 @@ void Button::OnMouseDown(int x, int y, unsigned int button)
isAltButtonDown = true; isAltButtonDown = true;
} }
} }
}
void Button::OnMouseEnter(int x, int y) void Button::OnMouseEnter(int x, int y)
{ {

View File

@ -18,7 +18,7 @@ public:
virtual ~Button() = default; virtual ~Button() = default;
void OnMouseClick(int x, int y, unsigned int button) override; void OnMouseClick(int x, int y, unsigned int button) override;
void OnMouseDown(int x, int y, unsigned int button) override; void OnMouseUnclick(int x, int y, unsigned int button) override;
void OnMouseUp(int x, int y, unsigned int button) override; void OnMouseUp(int x, int y, unsigned int button) override;
void OnMouseEnter(int x, int y) override; void OnMouseEnter(int x, int y) override;

View File

@ -124,21 +124,17 @@ void Component::SetParent(Panel* new_parent)
this->_parent = new_parent; this->_parent = new_parent;
} }
Point Component::GetContainerPos() Point Component::GetScreenPos()
{ {
Point newPos(0,0); Point newPos(0,0);
if(GetParentWindow()) if(GetParentWindow())
newPos += GetParentWindow()->Position; newPos += GetParentWindow()->Position;
if(GetParent()) if(GetParent())
newPos += GetParent()->Position + GetParent()->ViewportPosition; newPos += GetParent()->Position + GetParent()->ViewportPosition;
newPos += Position;
return newPos; return newPos;
} }
Point Component::GetScreenPos()
{
return GetContainerPos() + Position;
}
Graphics * Component::GetGraphics() Graphics * Component::GetGraphics()
{ {
return parentstate_->GetGraphics(); return parentstate_->GetGraphics();
@ -189,7 +185,11 @@ void Component::OnMouseHover(int localx, int localy)
{ {
} }
void Component::OnMouseMoved(int localx, int localy) void Component::OnMouseMoved(int localx, int localy, int dx, int dy)
{
}
void Component::OnMouseMovedInside(int localx, int localy, int dx, int dy)
{ {
} }
@ -201,6 +201,10 @@ void Component::OnMouseLeave(int localx, int localy)
{ {
} }
void Component::OnMouseUnclick(int localx, int localy, unsigned button)
{
}
void Component::OnMouseUp(int x, int y, unsigned button) void Component::OnMouseUp(int x, int y, unsigned button)
{ {
} }

View File

@ -43,8 +43,6 @@ namespace ui
bool Enabled; bool Enabled;
bool Visible; bool Visible;
bool DoesTextInput; bool DoesTextInput;
bool MouseInside;
bool MouseDownInside;
ui::Appearance Appearance; ui::Appearance Appearance;
//virtual void SetAppearance(ui::Appearance); //virtual void SetAppearance(ui::Appearance);
@ -53,7 +51,6 @@ namespace ui
void Refresh(); void Refresh();
Point GetContainerPos();
Point GetScreenPos(); Point GetScreenPos();
/* See the parent of this component. /* See the parent of this component.
@ -97,8 +94,20 @@ namespace ui
// Params: // Params:
// localx: Local mouse X position. // localx: Local mouse X position.
// localy: Local mouse Y position. // localy: Local mouse Y position.
// dx: Mouse X delta.
// dy: Mouse Y delta.
/// ///
virtual void OnMouseMoved(int localx, int localy); virtual void OnMouseMoved(int localx, int localy, int dx, int dy);
///
// Called: When the mouse moves.
// Params:
// localx: Local mouse X position.
// localy: Local mouse Y position.
// dx: Mouse X delta.
// dy: Mouse Y delta.
///
virtual void OnMouseMovedInside(int localx, int localy, int dx, int dy);
/// ///
// Called: When the mouse moves on top of the item. // Called: When the mouse moves on top of the item.
@ -137,7 +146,7 @@ namespace ui
virtual void OnMouseUp(int x, int y, unsigned button); virtual void OnMouseUp(int x, int y, unsigned button);
/// ///
// Called: When a mouse button is pressed and then released on top of the item. // Called: When a mouse button is pressed on top of the item.
// Params: // Params:
// x: X position of the mouse. // x: X position of the mouse.
// y: Y position of the mouse. // y: Y position of the mouse.
@ -145,6 +154,15 @@ namespace ui
/// ///
virtual void OnMouseClick(int localx, int localy, unsigned button); virtual void OnMouseClick(int localx, int localy, unsigned button);
///
// Called: When a mouse button is released on top of the item.
// Params:
// x: X position of the mouse.
// y: Y position of the mouse.
// button: The button that is being released.
///
virtual void OnMouseUnclick(int localx, int localy, unsigned button);
/// ///
// Called: When the mouse wheel moves/changes. // Called: When the mouse wheel moves/changes.
// Params: // Params:

View File

@ -133,7 +133,7 @@ void DirectionSelector::Draw(const ui::Point& screenPos)
g->BlendEllipse(center + value.offset, { handleRadius, handleRadius }, borderColor); g->BlendEllipse(center + value.offset, { handleRadius, handleRadius }, borderColor);
} }
void DirectionSelector::OnMouseMoved(int x, int y) void DirectionSelector::OnMouseMoved(int x, int y, int dx, int dy)
{ {
if (mouseDown) if (mouseDown)
{ {
@ -142,14 +142,11 @@ void DirectionSelector::OnMouseMoved(int x, int y)
CheckHovering(x, y); CheckHovering(x, y);
} }
void DirectionSelector::OnMouseDown(int x, int y, unsigned button) void DirectionSelector::OnMouseClick(int x, int y, unsigned button)
{
if (MouseDownInside)
{ {
mouseDown = true; mouseDown = true;
SetPositionAbs({ x - Position.X, y - Position.Y }); SetPositionAbs({ x, y });
CheckHovering(x - Position.X, y - Position.Y); CheckHovering(x, y);
}
} }
void DirectionSelector::OnMouseUp(int x, int y, unsigned button) void DirectionSelector::OnMouseUp(int x, int y, unsigned button)

View File

@ -78,8 +78,8 @@ public:
void SetValues(float x, float y); void SetValues(float x, float y);
void Draw(const ui::Point& screenPos) override; void Draw(const ui::Point& screenPos) override;
void OnMouseMoved(int x, int y) override; void OnMouseMoved(int x, int y, int dx, int dy) override;
void OnMouseDown(int x, int y, unsigned int button) override; void OnMouseClick(int x, int y, unsigned int button) override;
void OnMouseUp(int x, int y, unsigned button) override; void OnMouseUp(int x, int y, unsigned button) override;
inline void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override { altDown = alt; } inline void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override { altDown = alt; }
inline void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override { altDown = alt; } inline void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override { altDown = alt; }

View File

@ -15,8 +15,7 @@ class DropDownWindow : public ui::Window
public: public:
DropDownWindow(DropDown * dropDown): DropDownWindow(DropDown * dropDown):
Window(dropDown->GetScreenPos() + ui::Point(-1, -1 - (dropDown->optionIndex*16 < dropDown->GetScreenPos().Y ? dropDown->optionIndex*16 : 0)), Window(dropDown->GetScreenPos() + ui::Point(-1, -1 - dropDown->optionIndex * 16), ui::Point(dropDown->Size.X+2, 2+dropDown->options.size()*16)),
ui::Point(dropDown->Size.X+2, 2+dropDown->options.size()*16)),
dropDown(dropDown), dropDown(dropDown),
appearance(dropDown->Appearance) appearance(dropDown->Appearance)
{ {

View File

@ -83,8 +83,6 @@ void Engine::ShowWindow(Window * window)
{ {
window->Position.Y = (g->Size().Y - window->Size.Y) / 2; window->Position.Y = (g->Size().Y - window->Size.Y) / 2;
} }
window->Size = window->Size.Min(g->Size());
window->Position = window->Position.Clamp(RectBetween<int>({0, 0}, g->Size()));
/*if(window->Position.Y > 0) /*if(window->Position.Y > 0)
{ {
windowTargetPosition = window->Position; windowTargetPosition = window->Position;
@ -270,14 +268,14 @@ void Engine::onTextEditing(String text, int start)
} }
} }
void Engine::onMouseDown(int x, int y, unsigned button) void Engine::onMouseClick(int x, int y, unsigned button)
{ {
mouseb_ |= button; mouseb_ |= button;
if (state_ && !ignoreEvents) if (state_ && !ignoreEvents)
state_->DoMouseDown(x, y, button); state_->DoMouseDown(x, y, button);
} }
void Engine::onMouseUp(int x, int y, unsigned button) void Engine::onMouseUnclick(int x, int y, unsigned button)
{ {
mouseb_ &= ~button; mouseb_ &= ~button;
if (state_ && !ignoreEvents) if (state_ && !ignoreEvents)

View File

@ -30,8 +30,8 @@ namespace ui
void initialMouse(int x, int y); void initialMouse(int x, int y);
void onMouseMove(int x, int y); void onMouseMove(int x, int y);
void onMouseDown(int x, int y, unsigned button); void onMouseClick(int x, int y, unsigned button);
void onMouseUp(int x, int y, unsigned button); void onMouseUnclick(int x, int y, unsigned button);
void onMouseWheel(int x, int y, int delta); void onMouseWheel(int x, int y, int delta);
void onKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt); void onKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
void onKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt); void onKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);

View File

@ -88,29 +88,26 @@ void Label::OnContextMenuAction(int item)
} }
} }
void Label::OnMouseDown(int x, int y, unsigned button) void Label::OnMouseClick(int x, int y, unsigned button)
{
if (MouseDownInside)
{ {
if(button == SDL_BUTTON_RIGHT) if(button == SDL_BUTTON_RIGHT)
{ {
if (menu) if (menu)
{ {
menu->Show(GetContainerPos() + ui::Point(x, y)); menu->Show(GetScreenPos() + ui::Point(x, y));
} }
} }
else else
{ {
selecting = true; selecting = true;
auto tp = textPosition - Vec2{ scrollX, 0 }; auto tp = textPosition - Vec2{ scrollX, 0 };
selectionIndex0 = textWrapper.Point2Index(x - Position.X - tp.X, y - Position.Y - tp.Y); selectionIndex0 = textWrapper.Point2Index(x - tp.X, y - tp.Y);
selectionIndexL = selectionIndex0; selectionIndexL = selectionIndex0;
selectionIndexH = selectionIndex0; selectionIndexH = selectionIndex0;
updateSelection(); updateSelection();
} }
} }
}
void Label::copySelection() void Label::copySelection()
{ {
@ -146,7 +143,7 @@ void Label::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bo
} }
} }
void Label::OnMouseMoved(int localx, int localy) void Label::OnMouseMoved(int localx, int localy, int dx, int dy)
{ {
if (selecting) if (selecting)
{ {

View File

@ -58,9 +58,9 @@ namespace ui
void SetTextColour(Colour textColour) { this->textColour = textColour; } void SetTextColour(Colour textColour) { this->textColour = textColour; }
void OnContextMenuAction(int item) override; void OnContextMenuAction(int item) override;
virtual void OnMouseDown(int x, int y, unsigned button) override; virtual void OnMouseClick(int x, int y, unsigned button) override;
void OnMouseUp(int x, int y, unsigned button) override; void OnMouseUp(int x, int y, unsigned button) override;
void OnMouseMoved(int localx, int localy) override; void OnMouseMoved(int localx, int localy, int dx, int dy) override;
void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override; void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override;
void Draw(const Point& screenPos) override; void Draw(const Point& screenPos) override;
void Tick(float dt) override; void Tick(float dt) override;

View File

@ -10,7 +10,8 @@ using namespace ui;
Panel::Panel(Point position, Point size): Panel::Panel(Point position, Point size):
Component(position, size), Component(position, size),
InnerSize(size), InnerSize(size),
ViewportPosition(0, 0) ViewportPosition(0, 0),
mouseInside(false)
{ {
} }
@ -26,8 +27,6 @@ void Panel::AddChild(Component* c)
{ {
c->SetParent(this); c->SetParent(this);
c->SetParentWindow(this->GetParentWindow()); c->SetParentWindow(this->GetParentWindow());
c->MouseInside = false;
c->MouseDownInside = false;
} }
int Panel::GetChildCount() int Panel::GetChildCount()
@ -109,15 +108,8 @@ void Panel::OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl,
void Panel::OnMouseClick(int localx, int localy, unsigned button) void Panel::OnMouseClick(int localx, int localy, unsigned button)
{ {
XOnMouseClick(localx, localy, button); bool childclicked = false;
}
void Panel::OnMouseDown(int x, int y, unsigned button)
{
if (MouseDownInside)
{
auto localx = x - Position.X;
auto localy = y - Position.Y;
//check if clicked a child //check if clicked a child
for(int i = children.size()-1; i >= 0 ; --i) for(int i = children.size()-1; i >= 0 ; --i)
{ {
@ -130,19 +122,29 @@ void Panel::OnMouseDown(int x, int y, unsigned button)
localx < children[i]->Position.X + ViewportPosition.X + children[i]->Size.X && localx < children[i]->Position.X + ViewportPosition.X + children[i]->Size.X &&
localy < children[i]->Position.Y + ViewportPosition.Y + children[i]->Size.Y ) localy < children[i]->Position.Y + ViewportPosition.Y + children[i]->Size.Y )
{ {
childclicked = true;
GetParentWindow()->FocusComponent(children[i]); GetParentWindow()->FocusComponent(children[i]);
children[i]->MouseDownInside = true; children[i]->OnMouseClick(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, button);
break; break;
} }
} }
} }
//if a child wasn't clicked, send click to ourself
if(!childclicked)
{
XOnMouseClick(localx, localy, button);
GetParentWindow()->FocusComponent(this);
}
}
void Panel::OnMouseDown(int x, int y, unsigned button)
{
XOnMouseDown(x, y, button); XOnMouseDown(x, y, button);
for (size_t i = 0; i < children.size(); ++i) for (size_t i = 0; i < children.size(); ++i)
{ {
if(children[i]->Enabled) if(children[i]->Enabled)
children[i]->OnMouseDown(x - Position.X - ViewportPosition.X, y - Position.Y - ViewportPosition.Y, button); children[i]->OnMouseDown(x, y, button);
}
} }
} }
@ -153,14 +155,12 @@ void Panel::OnMouseHover(int localx, int localy)
{ {
if (children[i]->Enabled) if (children[i]->Enabled)
{ {
auto px = children[i]->Position.X + ViewportPosition.X; if( localx >= children[i]->Position.X &&
auto py = children[i]->Position.Y + ViewportPosition.Y; localy >= children[i]->Position.Y &&
if( localx >= px && localx < children[i]->Position.X + children[i]->Size.X &&
localy >= py && localy < children[i]->Position.Y + children[i]->Size.Y )
localx < px + children[i]->Size.X &&
localy < py + children[i]->Size.Y )
{ {
children[i]->OnMouseHover(localx - px, localy - py); children[i]->OnMouseHover(localx - children[i]->Position.X, localy - children[i]->Position.Y);
break; break;
} }
} }
@ -170,26 +170,25 @@ void Panel::OnMouseHover(int localx, int localy)
XOnMouseHover(localx, localy); XOnMouseHover(localx, localy);
} }
void Panel::OnMouseMoved(int localx, int localy) void Panel::OnMouseMoved(int localx, int localy, int dx, int dy)
{ {
PropagateMouseMove(); XOnMouseMoved(localx, localy, dx, dy);
XOnMouseMoved(localx, localy);
for (size_t i = 0; i < children.size(); ++i) for (size_t i = 0; i < children.size(); ++i)
{ {
if(children[i]->Enabled) if(children[i]->Enabled)
children[i]->OnMouseMoved(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y); children[i]->OnMouseMoved(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, dx, dy);
} }
} }
void Panel::PropagateMouseMove() void Panel::OnMouseMovedInside(int localx, int localy, int dx, int dy)
{ {
auto localx = ui::Engine::Ref().GetMouseX() - GetScreenPos().X; mouseInside = true;
auto localy = ui::Engine::Ref().GetMouseY() - GetScreenPos().Y;
for (size_t i = 0; i < children.size(); ++i) for (size_t i = 0; i < children.size(); ++i)
{ {
if (children[i]->Enabled) if (children[i]->Enabled)
{ {
Point local (localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y); Point local (localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y)
, prevlocal (local.X - dx, local.Y - dy);
// mouse currently inside? // mouse currently inside?
if( local.X >= 0 && if( local.X >= 0 &&
@ -197,12 +196,14 @@ void Panel::PropagateMouseMove()
local.X < children[i]->Size.X && local.X < children[i]->Size.X &&
local.Y < children[i]->Size.Y ) local.Y < children[i]->Size.Y )
{ {
children[i]->OnMouseMoved(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y); children[i]->OnMouseMovedInside(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, dx, dy);
// was the mouse outside? // was the mouse outside?
if (!children[i]->MouseInside) if(!(prevlocal.X >= 0 &&
prevlocal.Y >= 0 &&
prevlocal.X < children[i]->Size.X &&
prevlocal.Y < children[i]->Size.Y ) )
{ {
children[i]->MouseInside = true;
children[i]->OnMouseEnter(local.X, local.Y); children[i]->OnMouseEnter(local.X, local.Y);
} }
} }
@ -210,59 +211,71 @@ void Panel::PropagateMouseMove()
else else
{ {
// was the mouse inside? // was the mouse inside?
if (children[i]->MouseInside) if( prevlocal.X >= 0 &&
prevlocal.Y >= 0 &&
prevlocal.X < children[i]->Size.X &&
prevlocal.Y < children[i]->Size.Y )
{ {
children[i]->MouseInside = false;
children[i]->OnMouseLeave(local.X, local.Y); children[i]->OnMouseLeave(local.X, local.Y);
} }
} }
} }
} }
// always allow hover on parent (?)
XOnMouseMovedInside(localx, localy, dx, dy);
} }
void Panel::OnMouseEnter(int localx, int localy) void Panel::OnMouseEnter(int localx, int localy)
{ {
mouseInside = true;
XOnMouseEnter(localx, localy); XOnMouseEnter(localx, localy);
} }
void Panel::OnMouseLeave(int localx, int localy) void Panel::OnMouseLeave(int localx, int localy)
{ {
mouseInside = false;
XOnMouseLeave(localx, localy); XOnMouseLeave(localx, localy);
} }
void Panel::OnMouseUp(int x, int y, unsigned button) void Panel::OnMouseUnclick(int localx, int localy, unsigned button)
{ {
auto localx = x - Position.X; bool childunclicked = false;
auto localy = y - Position.Y;
//check if clicked a child //check if clicked a child
for(int i = children.size()-1; i >= 0 ; --i) for(int i = children.size()-1; i >= 0 ; --i)
{ {
//child must be enabled //child must be unlocked
if(children[i]->Enabled) if(children[i]->Enabled)
{ {
//is mouse inside? //is mouse inside?
if( children[i]->MouseDownInside && if( localx >= children[i]->Position.X + ViewportPosition.X &&
localx >= children[i]->Position.X + ViewportPosition.X &&
localy >= children[i]->Position.Y + ViewportPosition.Y && localy >= children[i]->Position.Y + ViewportPosition.Y &&
localx < children[i]->Position.X + ViewportPosition.X + children[i]->Size.X && localx < children[i]->Position.X + ViewportPosition.X + children[i]->Size.X &&
localy < children[i]->Position.Y + ViewportPosition.Y + children[i]->Size.Y ) localy < children[i]->Position.Y + ViewportPosition.Y + children[i]->Size.Y )
{ {
children[i]->OnMouseClick(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, button); childunclicked = true;
children[i]->OnMouseUnclick(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, button);
break; break;
} }
} }
} }
for (auto *child : children)
//if a child wasn't clicked, send click to ourself
if (!childunclicked)
{ {
child->MouseDownInside = false; XOnMouseUnclick(localx, localy, button);
}
} }
void Panel::OnMouseUp(int x, int y, unsigned button)
{
XOnMouseUp(x, y, button); XOnMouseUp(x, y, button);
for (size_t i = 0; i < children.size(); ++i) for (size_t i = 0; i < children.size(); ++i)
{ {
if (children[i]->Enabled) if (children[i]->Enabled)
children[i]->OnMouseUp(x - Position.X - ViewportPosition.X, y - Position.Y - ViewportPosition.Y, button); children[i]->OnMouseUp(x, y, button);
} }
} }
@ -329,7 +342,11 @@ void Panel::XOnMouseHover(int localx, int localy)
{ {
} }
void Panel::XOnMouseMoved(int localx, int localy) void Panel::XOnMouseMoved(int localx, int localy, int dx, int dy)
{
}
void Panel::XOnMouseMovedInside(int localx, int localy, int dx, int dy)
{ {
} }
@ -341,6 +358,10 @@ void Panel::XOnMouseLeave(int localx, int localy)
{ {
} }
void Panel::XOnMouseUnclick(int localx, int localy, unsigned button)
{
}
void Panel::XOnMouseUp(int x, int y, unsigned button) void Panel::XOnMouseUp(int x, int y, unsigned button)
{ {
} }

View File

@ -51,12 +51,14 @@ namespace ui
void Draw(const Point& screenPos) override; void Draw(const Point& screenPos) override;
void OnMouseHover(int localx, int localy) override; void OnMouseHover(int localx, int localy) override;
void OnMouseMoved(int localx, int localy) override; void OnMouseMoved(int localx, int localy, int dx, int dy) override;
void OnMouseMovedInside(int localx, int localy, int dx, int dy) override;
void OnMouseEnter(int localx, int localy) override; void OnMouseEnter(int localx, int localy) override;
void OnMouseLeave(int localx, int localy) override; void OnMouseLeave(int localx, int localy) override;
void OnMouseDown(int x, int y, unsigned button) override; void OnMouseDown(int x, int y, unsigned button) override;
void OnMouseUp(int x, int y, unsigned button) override; void OnMouseUp(int x, int y, unsigned button) override;
void OnMouseClick(int localx, int localy, unsigned button) override; void OnMouseClick(int localx, int localy, unsigned button) override;
void OnMouseUnclick(int localx, int localy, unsigned button) override;
void OnMouseWheel(int localx, int localy, int d) override; void OnMouseWheel(int localx, int localy, int d) override;
void OnMouseWheelInside(int localx, int localy, int d) override; void OnMouseWheelInside(int localx, int localy, int d) override;
void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override; void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override;
@ -65,6 +67,7 @@ namespace ui
protected: protected:
// child components // child components
std::vector<ui::Component*> children; std::vector<ui::Component*> children;
bool mouseInside;
// Overridable. Called by XComponent::Tick() // Overridable. Called by XComponent::Tick()
virtual void XTick(float dt); virtual void XTick(float dt);
@ -77,7 +80,10 @@ namespace ui
virtual void XOnMouseHover(int localx, int localy); virtual void XOnMouseHover(int localx, int localy);
// Overridable. Called by XComponent::OnMouseMoved() // Overridable. Called by XComponent::OnMouseMoved()
virtual void XOnMouseMoved(int localx, int localy); virtual void XOnMouseMoved(int localx, int localy, int dx, int dy);
// Overridable. Called by XComponent::OnMouseMovedInside()
virtual void XOnMouseMovedInside(int localx, int localy, int dx, int dy);
// Overridable. Called by XComponent::OnMouseEnter() // Overridable. Called by XComponent::OnMouseEnter()
virtual void XOnMouseEnter(int localx, int localy); virtual void XOnMouseEnter(int localx, int localy);
@ -94,6 +100,9 @@ namespace ui
// Overridable. Called by XComponent::OnMouseClick() // Overridable. Called by XComponent::OnMouseClick()
virtual void XOnMouseClick(int localx, int localy, unsigned button); virtual void XOnMouseClick(int localx, int localy, unsigned button);
// Overridable. Called by XComponent::OnMouseUnclick()
virtual void XOnMouseUnclick(int localx, int localy, unsigned button);
// Overridable. Called by XComponent::OnMouseWheel() // Overridable. Called by XComponent::OnMouseWheel()
virtual void XOnMouseWheel(int localx, int localy, int d); virtual void XOnMouseWheel(int localx, int localy, int d);
@ -105,8 +114,6 @@ namespace ui
// Overridable. Called by XComponent::OnKeyRelease() // Overridable. Called by XComponent::OnKeyRelease()
virtual void XOnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt); virtual void XOnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
void PropagateMouseMove();
}; };
} }

View File

@ -64,11 +64,9 @@ void RichLabel::SetText(String newText)
regions = newRegions; regions = newRegions;
} }
void RichLabel::OnMouseDown(int x, int y, unsigned button) void RichLabel::OnMouseClick(int x, int y, unsigned button)
{ {
if (MouseDownInside) int cursorPosition = displayTextWrapper.Point2Index(x - textPosition.X, y - textPosition.Y).raw_index;
{
int cursorPosition = displayTextWrapper.Point2Index(x - Position.X - textPosition.X, y - Position.Y - textPosition.Y).raw_index;
for (auto const &region : regions) for (auto const &region : regions)
{ {
if (region.begin <= cursorPosition && region.end > cursorPosition) if (region.begin <= cursorPosition && region.end > cursorPosition)
@ -80,6 +78,5 @@ void RichLabel::OnMouseDown(int x, int y, unsigned button)
} }
} }
} }
} Label::OnMouseClick(x, y, button);
Label::OnMouseDown(x, y, button);
} }

View File

@ -24,6 +24,6 @@ namespace ui
RichLabel(Point position, Point size, String text); RichLabel(Point position, Point size, String text);
void SetText(String newText) override; void SetText(String newText) override;
void OnMouseDown(int x, int y, unsigned button) override; void OnMouseClick(int x, int y, unsigned button) override;
}; };
} }

View File

@ -262,7 +262,7 @@ void SaveButton::Draw(const Point& screenPos)
} }
} }
void SaveButton::OnMouseClick(int x, int y, unsigned int button) void SaveButton::OnMouseUnclick(int x, int y, unsigned int button)
{ {
if(button != 1) if(button != 1)
{ {
@ -333,14 +333,12 @@ void SaveButton::OnContextMenuAction(int item)
} }
} }
void SaveButton::OnMouseDown(int x, int y, unsigned int button) void SaveButton::OnMouseClick(int x, int y, unsigned int button)
{
if (MouseDownInside)
{ {
if(button == SDL_BUTTON_RIGHT) if(button == SDL_BUTTON_RIGHT)
{ {
if(menu) if(menu)
menu->Show(GetContainerPos() + ui::Point(x, y)); menu->Show(GetScreenPos() + ui::Point(x, y));
} }
else else
{ {
@ -353,20 +351,18 @@ void SaveButton::OnMouseDown(int x, int y, unsigned int button)
} }
} }
}
void SaveButton::OnMouseMoved(int x, int y) void SaveButton::OnMouseMovedInside(int x, int y, int dx, int dy)
{
isMouseInsideAuthor = false;
isMouseInsideHistory = false;
if (MouseInside)
{ {
if(y > Size.Y-11) if(y > Size.Y-11)
isMouseInsideAuthor = true; isMouseInsideAuthor = true;
else
isMouseInsideAuthor = false;
if (y > Size.Y-29 && y < Size.Y - 18 && x > 0 && x < 9) if(showVotes && y > Size.Y-29 && y < Size.Y - 18 && x > 0 && x < 9)
isMouseInsideHistory = true; isMouseInsideHistory = true;
} else
isMouseInsideHistory = false;
} }
void SaveButton::OnMouseEnter(int x, int y) void SaveButton::OnMouseEnter(int x, int y)

View File

@ -48,12 +48,12 @@ public:
virtual ~SaveButton(); virtual ~SaveButton();
void OnMouseClick(int x, int y, unsigned int button) override; void OnMouseClick(int x, int y, unsigned int button) override;
void OnMouseDown(int x, int y, unsigned int button) override; void OnMouseUnclick(int x, int y, unsigned int button) override;
void OnMouseEnter(int x, int y) override; void OnMouseEnter(int x, int y) override;
void OnMouseLeave(int x, int y) override; void OnMouseLeave(int x, int y) override;
void OnMouseMoved(int x, int y) override; void OnMouseMovedInside(int x, int y, int dx, int dy) override;
void AddContextMenu(int menuType); void AddContextMenu(int menuType);
void OnContextMenuAction(int item) override; void OnContextMenuAction(int item) override;

View File

@ -1,9 +1,8 @@
#include "ScrollPanel.h" #include "ScrollPanel.h"
#include "Engine.h" #include "Engine.h"
#include "graphics/Graphics.h" #include "graphics/Graphics.h"
#include "Misc.h"
#include "PowderToySDL.h"
#include "Window.h"
#include <algorithm> #include <algorithm>
using namespace ui; using namespace ui;
@ -71,56 +70,28 @@ void ScrollPanel::Draw(const Point& screenPos)
} }
} }
void ScrollPanel::XOnMouseDown(int x, int y, unsigned int button) void ScrollPanel::XOnMouseClick(int x, int y, unsigned int button)
{ {
if (MouseDownInside)
{
CancelPanning();
if (isMouseInsideScrollbar) if (isMouseInsideScrollbar)
{ {
scrollbarSelected = true; scrollbarSelected = true;
scrollbarInitialYOffset = int(offsetY); scrollbarInitialYOffset = int(offsetY);
} }
initialOffsetY = offsetY; scrollbarInitialYClick = y;
scrollbarInitialYClick = y - Position.Y;
scrollbarClickLocation = 100; scrollbarClickLocation = 100;
} }
}
void ScrollPanel::CancelPanning()
{
panning = false;
panHistory = {};
yScrollVel = 0;
}
void ScrollPanel::XOnMouseUp(int x, int y, unsigned int button) void ScrollPanel::XOnMouseUp(int x, int y, unsigned int button)
{ {
scrollbarSelected = false; scrollbarSelected = false;
auto oldPanHistory = panHistory;
CancelPanning();
{
auto it = oldPanHistory.end();
while (it != oldPanHistory.begin() && *(it - 1))
{
--it;
}
if (it < oldPanHistory.end())
{
auto offsetYDiff = oldPanHistory.back()->offsetY - (*it)->offsetY;
auto tickDiff = oldPanHistory.back()->ticks - (*it)->ticks;
yScrollVel += offsetYDiff / tickDiff * (1000.f / Engine::Ref().GetFps());
}
}
isMouseInsideScrollbarArea = false; isMouseInsideScrollbarArea = false;
scrollbarClickLocation = 0; scrollbarClickLocation = 0;
} }
void ScrollPanel::XOnMouseMoved(int x, int y) void ScrollPanel::XOnMouseMoved(int x, int y, int dx, int dy)
{ {
if(maxOffset.Y>0 && InnerSize.Y>0) if(maxOffset.Y>0 && InnerSize.Y>0)
{ {
auto oldViewportPositionY = ViewportPosition.Y;
float scrollHeight = float(Size.Y)*(float(Size.Y)/float(InnerSize.Y)); float scrollHeight = float(Size.Y)*(float(Size.Y)/float(InnerSize.Y));
float scrollPos = 0; float scrollPos = 0;
if (-ViewportPosition.Y>0) if (-ViewportPosition.Y>0)
@ -142,19 +113,6 @@ void ScrollPanel::XOnMouseMoved(int x, int y)
offsetY = float(scrollbarInitialYOffset); offsetY = float(scrollbarInitialYOffset);
} }
} }
else if (MouseDownInside)
{
Vec2<int> mouseAt{ x, y };
if (Engine::Ref().TouchUI && iabs(scrollbarInitialYClick - mouseAt.Y) > PanOffsetThreshold)
{
panning = true;
for (auto *child : children)
{
child->MouseDownInside = false;
}
GetParentWindow()->FocusComponent(NULL);
}
}
if (x > (Size.X-scrollBarWidth) && x < (Size.X-scrollBarWidth)+scrollBarWidth) if (x > (Size.X-scrollBarWidth) && x < (Size.X-scrollBarWidth)+scrollBarWidth)
{ {
@ -164,31 +122,11 @@ void ScrollPanel::XOnMouseMoved(int x, int y)
} }
else else
isMouseInsideScrollbar = false; isMouseInsideScrollbar = false;
if (oldViewportPositionY != ViewportPosition.Y)
{
PropagateMouseMove();
}
} }
} }
void ScrollPanel::XTick(float dt) void ScrollPanel::XTick(float dt)
{ {
auto oldViewportPositionY = ViewportPosition.Y;
if (panning)
{
auto scrollY = initialOffsetY + scrollbarInitialYClick - (Engine::Ref().GetMouseY() - GetScreenPos().Y);
ViewportPosition.Y = -scrollY;
offsetY = float(scrollY);
PanPoint p{ offsetY, GetTicks() };
if (!(panHistory.back() && panHistory.back()->ticks == p.ticks))
{
std::copy(panHistory.begin() + 1, panHistory.end(), panHistory.begin());
panHistory.back() = p;
}
}
if (xScrollVel > 7.0f) xScrollVel = 7.0f; if (xScrollVel > 7.0f) xScrollVel = 7.0f;
if (xScrollVel < -7.0f) xScrollVel = -7.0f; if (xScrollVel < -7.0f) xScrollVel = -7.0f;
if (xScrollVel > -0.5f && xScrollVel < 0.5) if (xScrollVel > -0.5f && xScrollVel < 0.5)
@ -245,9 +183,9 @@ void ScrollPanel::XTick(float dt)
} }
} }
if (MouseInside && scrollBarWidth < 6) if (mouseInside && scrollBarWidth < 6)
scrollBarWidth++; scrollBarWidth++;
else if (!MouseInside && scrollBarWidth > 0 && !scrollbarSelected) else if (!mouseInside && scrollBarWidth > 0 && !scrollbarSelected)
scrollBarWidth--; scrollBarWidth--;
if (isMouseInsideScrollbarArea && scrollbarClickLocation && !scrollbarSelected) if (isMouseInsideScrollbarArea && scrollbarClickLocation && !scrollbarSelected)
@ -267,9 +205,4 @@ void ScrollPanel::XTick(float dt)
offsetY += scrollbarClickLocation*scrollHeight/10; offsetY += scrollbarClickLocation*scrollHeight/10;
ViewportPosition.Y -= int(scrollbarClickLocation*scrollHeight/10); ViewportPosition.Y -= int(scrollbarClickLocation*scrollHeight/10);
} }
if (oldViewportPositionY != ViewportPosition.Y)
{
PropagateMouseMove();
}
} }

View File

@ -1,14 +1,11 @@
#pragma once #pragma once
#include "Panel.h" #include "Panel.h"
#include <optional>
#include <array>
namespace ui namespace ui
{ {
class ScrollPanel: public Panel class ScrollPanel: public Panel
{ {
void CancelPanning();
protected: protected:
int scrollBarWidth; int scrollBarWidth;
Point maxOffset; Point maxOffset;
@ -22,16 +19,6 @@ namespace ui
int scrollbarInitialYOffset; int scrollbarInitialYOffset;
int scrollbarInitialYClick; int scrollbarInitialYClick;
int scrollbarClickLocation; int scrollbarClickLocation;
int initialOffsetY;
bool panning = false;
static constexpr int PanOffsetThreshold = 10;
static constexpr int PanHistorySize = 5;
struct PanPoint
{
float offsetY;
unsigned int ticks;
};
std::array<std::optional<PanPoint>, PanHistorySize> panHistory;
public: public:
ScrollPanel(Point position, Point size); ScrollPanel(Point position, Point size);
@ -41,8 +28,8 @@ namespace ui
void Draw(const Point& screenPos) override; void Draw(const Point& screenPos) override;
void XTick(float dt) override; void XTick(float dt) override;
void XOnMouseWheelInside(int localx, int localy, int d) override; void XOnMouseWheelInside(int localx, int localy, int d) override;
void XOnMouseDown(int localx, int localy, unsigned int button) override; void XOnMouseClick(int localx, int localy, unsigned int button) override;
void XOnMouseUp(int x, int y, unsigned int button) override; void XOnMouseUp(int x, int y, unsigned int button) override;
void XOnMouseMoved(int localx, int localy) override; void XOnMouseMoved(int localx, int localy, int dx, int dy) override;
}; };
} }

View File

@ -40,7 +40,7 @@ void Slider::updatePosition(int position)
} }
} }
void Slider::OnMouseMoved(int x, int y) void Slider::OnMouseMoved(int x, int y, int dx, int dy)
{ {
if(isMouseDown) if(isMouseDown)
{ {
@ -48,13 +48,10 @@ void Slider::OnMouseMoved(int x, int y)
} }
} }
void Slider::OnMouseDown(int x, int y, unsigned button) void Slider::OnMouseClick(int x, int y, unsigned button)
{
if (MouseDownInside)
{ {
isMouseDown = true; isMouseDown = true;
updatePosition(x - Position.X); updatePosition(x);
}
} }
void Slider::OnMouseUp(int x, int y, unsigned button) void Slider::OnMouseUp(int x, int y, unsigned button)

View File

@ -24,8 +24,8 @@ public:
Slider(Point position, Point size, int steps); Slider(Point position, Point size, int steps);
virtual ~Slider() = default; virtual ~Slider() = default;
void OnMouseMoved(int x, int y) override; void OnMouseMoved(int x, int y, int dx, int dy) override;
void OnMouseDown(int x, int y, unsigned button) override; void OnMouseClick(int x, int y, unsigned button) override;
void OnMouseUp(int x, int y, unsigned button) override; void OnMouseUp(int x, int y, unsigned button) override;
void Draw(const Point& screenPos) override; void Draw(const Point& screenPos) override;
void SetColour(Colour col1, Colour col2); void SetColour(Colour col1, Colour col2);

View File

@ -569,21 +569,18 @@ void Textbox::OnTextEditing(String text)
updateSelection(); updateSelection();
} }
void Textbox::OnMouseDown(int x, int y, unsigned button) void Textbox::OnMouseClick(int x, int y, unsigned button)
{
if (MouseDownInside)
{ {
if (button != SDL_BUTTON_RIGHT) if (button != SDL_BUTTON_RIGHT)
{ {
StopTextEditing(); StopTextEditing();
mouseDown = true; mouseDown = true;
auto tp = textPosition - Vec2{ scrollX, 0 }; auto tp = textPosition - Vec2{ scrollX, 0 };
auto index = textWrapper.Point2Index(x-Position.X-tp.X, y-Position.Y-tp.Y); auto index = textWrapper.Point2Index(x-tp.X, y-tp.Y);
cursor = index.raw_index; cursor = index.raw_index;
resetCursorPosition(); resetCursorPosition();
} }
} Label::OnMouseClick(x, y, button);
Label::OnMouseDown(x, y, button);
} }
void Textbox::OnMouseUp(int x, int y, unsigned button) void Textbox::OnMouseUp(int x, int y, unsigned button)
@ -592,7 +589,7 @@ void Textbox::OnMouseUp(int x, int y, unsigned button)
Label::OnMouseUp(x, y, button); Label::OnMouseUp(x, y, button);
} }
void Textbox::OnMouseMoved(int localx, int localy) void Textbox::OnMouseMoved(int localx, int localy, int dx, int dy)
{ {
if(mouseDown) if(mouseDown)
{ {
@ -601,7 +598,7 @@ void Textbox::OnMouseMoved(int localx, int localy)
cursor = index.raw_index; cursor = index.raw_index;
resetCursorPosition(); resetCursorPosition();
} }
Label::OnMouseMoved(localx, localy); Label::OnMouseMoved(localx, localy, dx, dy);
} }
void Textbox::OnDefocus() void Textbox::OnDefocus()

View File

@ -53,9 +53,9 @@ public:
void Tick(float dt) override; void Tick(float dt) override;
void OnContextMenuAction(int item) override; void OnContextMenuAction(int item) override;
void OnMouseDown(int x, int y, unsigned button) override; void OnMouseClick(int x, int y, unsigned button) override;
void OnMouseUp(int x, int y, unsigned button) override; void OnMouseUp(int x, int y, unsigned button) override;
void OnMouseMoved(int localx, int localy) override; void OnMouseMoved(int localx, int localy, int dx, int dy) override;
void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override; void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override;
void OnVKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt); void OnVKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override; void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override;

View File

@ -43,17 +43,12 @@ void Window::AddComponent(Component* c)
if (c->GetParentWindow() == NULL) if (c->GetParentWindow() == NULL)
{ {
c->SetParentWindow(this); c->SetParentWindow(this);
c->MouseInside = false;
c->MouseDownInside = false;
Components.push_back(c); Components.push_back(c);
if (Engine::Ref().GetMouseX() > Position.X + c->Position.X && Engine::Ref().GetMouseX() < Position.X + c->Position.X + c->Size.X && if (Engine::Ref().GetMouseX() > Position.X + c->Position.X && Engine::Ref().GetMouseX() < Position.X + c->Position.X + c->Size.X &&
Engine::Ref().GetMouseY() > Position.Y + c->Position.Y && Engine::Ref().GetMouseY() < Position.Y + c->Position.Y + c->Size.Y) Engine::Ref().GetMouseY() > Position.Y + c->Position.Y && Engine::Ref().GetMouseY() < Position.Y + c->Position.Y + c->Size.Y)
{
c->MouseInside = true;
c->OnMouseEnter(Engine::Ref().GetMouseX() - (Position.X + c->Position.X), Engine::Ref().GetMouseY() - (Position.Y + c->Position.Y)); c->OnMouseEnter(Engine::Ref().GetMouseX() - (Position.X + c->Position.X), Engine::Ref().GetMouseY() - (Position.Y + c->Position.Y));
} }
}
else else
{ {
//Component already in a window //Component already in a window
@ -445,7 +440,7 @@ void Window::DoMouseDown(int x_, int y_, unsigned button)
FocusComponent(Components[i]); FocusComponent(Components[i]);
if (!DEBUG || !debugMode) if (!DEBUG || !debugMode)
{ {
Components[i]->MouseDownInside = true; Components[i]->OnMouseClick(x - Components[i]->Position.X, y - Components[i]->Position.Y, button);
} }
clickState = true; clickState = true;
break; break;
@ -490,17 +485,21 @@ void Window::DoMouseMove(int x_, int y_, int dx, int dy)
Point local(x - Components[i]->Position.X, y - Components[i]->Position.Y); Point local(x - Components[i]->Position.X, y - Components[i]->Position.Y);
Point a(local.X - dx, local.Y - dy); Point a(local.X - dx, local.Y - dy);
Components[i]->OnMouseMoved(local.X, local.Y); Components[i]->OnMouseMoved(local.X, local.Y, dx, dy);
if (local.X >= 0 && if (local.X >= 0 &&
local.Y >= 0 && local.Y >= 0 &&
local.X < Components[i]->Size.X && local.X < Components[i]->Size.X &&
local.Y < Components[i]->Size.Y && !halt) local.Y < Components[i]->Size.Y && !halt)
{ {
Components[i]->OnMouseMovedInside(local.X, local.Y, dx, dy);
// entering? // entering?
if (!Components[i]->MouseInside) if (!(a.X >= 0 &&
a.Y >= 0 &&
a.X < Components[i]->Size.X &&
a.Y < Components[i]->Size.Y ))
{ {
Components[i]->MouseInside = true;
Components[i]->OnMouseEnter(local.X, local.Y); Components[i]->OnMouseEnter(local.X, local.Y);
} }
if (Components[i]->Enabled) if (Components[i]->Enabled)
@ -509,9 +508,11 @@ void Window::DoMouseMove(int x_, int y_, int dx, int dy)
else if (!halt) else if (!halt)
{ {
// leaving? // leaving?
if (Components[i]->MouseInside) if (a.X >= 0 &&
a.Y >= 0 &&
a.X < Components[i]->Size.X &&
a.Y < Components[i]->Size.Y )
{ {
Components[i]->MouseInside = false;
Components[i]->OnMouseLeave(local.X, local.Y); Components[i]->OnMouseLeave(local.X, local.Y);
} }
@ -536,17 +537,13 @@ void Window::DoMouseUp(int x_, int y_, unsigned button)
{ {
if (Components[i]->Enabled && Components[i]->Visible) if (Components[i]->Enabled && Components[i]->Visible)
{ {
if (Components[i]->MouseDownInside && x >= Components[i]->Position.X && y >= Components[i]->Position.Y && x < Components[i]->Position.X + Components[i]->Size.X && y < Components[i]->Position.Y + Components[i]->Size.Y) if (x >= Components[i]->Position.X && y >= Components[i]->Position.Y && x < Components[i]->Position.X + Components[i]->Size.X && y < Components[i]->Position.Y + Components[i]->Size.Y)
{ {
Components[i]->OnMouseClick(x - Components[i]->Position.X, y - Components[i]->Position.Y, button); Components[i]->OnMouseUnclick(x - Components[i]->Position.X, y - Components[i]->Position.Y, button);
break; break;
} }
} }
} }
for (auto *component : Components)
{
component->MouseDownInside = false;
}
//on mouse up //on mouse up
for (int i = Components.size() - 1; i >= 0 && !halt; --i) for (int i = Components.size() - 1; i >= 0 && !halt; --i)

View File

@ -59,8 +59,6 @@ void LocalBrowserModel::OpenSave(int index)
{ {
stamp = std::move(savesList[index]); stamp = std::move(savesList[index]);
savesList.clear(); savesList.clear();
notifyPageChanged();
notifySavesListChanged();
} }
bool LocalBrowserModel::GetMoveToFront() bool LocalBrowserModel::GetMoveToFront()

View File

@ -1,6 +1,5 @@
#include "LoginModel.h" #include "LoginModel.h"
#include "LoginView.h" #include "LoginView.h"
#include "Config.h"
#include "client/Client.h" #include "client/Client.h"
#include "client/http/LoginRequest.h" #include "client/http/LoginRequest.h"
#include "client/http/LogoutRequest.h" #include "client/http/LogoutRequest.h"
@ -9,7 +8,7 @@ void LoginModel::Login(ByteString username, ByteString password)
{ {
if (username.Contains("@")) if (username.Contains("@"))
{ {
statusText = String::Build("Use your Powder Toy account to log in, not your email. If you don't have a Powder Toy account, you can create one at https://", SERVER, "/Register.html"); statusText = "Use your Powder Toy account to log in, not your email. If you don't have a Powder Toy account, you can create one at https://powdertoy.co.uk/Register.html";
loginStatus = loginIdle; loginStatus = loginIdle;
notifyStatusChanged(); notifyStatusChanged();
return; return;

View File

@ -8,7 +8,6 @@
#include "graphics/Renderer.h" #include "graphics/Renderer.h"
#include "gui/Style.h" #include "gui/Style.h"
#include "simulation/ElementDefs.h" #include "simulation/ElementDefs.h"
#include "simulation/SimulationData.h"
#include "client/Client.h" #include "client/Client.h"
#include "gui/dialogues/ConfirmPrompt.h" #include "gui/dialogues/ConfirmPrompt.h"
#include "gui/dialogues/InformationMessage.h" #include "gui/dialogues/InformationMessage.h"
@ -76,13 +75,13 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340))
auto *checkbox = new ui::Checkbox(ui::Point(8 + indent * 15, currentY), ui::Point(1, 16), text, ""); auto *checkbox = new ui::Checkbox(ui::Point(8 + indent * 15, currentY), ui::Point(1, 16), text, "");
autoWidth(checkbox, 0); autoWidth(checkbox, 0);
checkbox->SetActionCallback({ action }); checkbox->SetActionCallback({ action });
scrollPanel->AddChild(checkbox);
currentY += 14; currentY += 14;
if (info.size()) if (info.size())
{ {
addLabel(indent, info); addLabel(indent, info);
} }
currentY += 4; currentY += 4;
scrollPanel->AddChild(checkbox);
return checkbox; return checkbox;
}; };
auto addDropDown = [this, &currentY, &autoWidth](String info, std::vector<std::pair<String, int>> options, std::function<void ()> action) { auto addDropDown = [this, &currentY, &autoWidth](String info, std::vector<std::pair<String, int>> options, std::function<void ()> action) {
@ -121,11 +120,11 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340))
c->SetWaterEqualisation(waterEqualisation->GetChecked()); c->SetWaterEqualisation(waterEqualisation->GetChecked());
}); });
airMode = addDropDown("Air simulation mode", { airMode = addDropDown("Air simulation mode", {
{ "On", AIR_ON }, { "On", 0 },
{ "Pressure off", AIR_PRESSUREOFF }, { "Pressure off", 1 },
{ "Velocity off", AIR_VELOCITYOFF }, { "Velocity off", 2 },
{ "Off", AIR_OFF }, { "Off", 3 },
{ "No update", AIR_NOUPDATE }, { "No update", 4 },
}, [this] { }, [this] {
c->SetAirMode(airMode->GetOption().second); c->SetAirMode(airMode->GetOption().second);
}); });
@ -137,11 +136,10 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340))
ambientAirTemp->SetDefocusCallback({ [this] { ambientAirTemp->SetDefocusCallback({ [this] {
UpdateAirTemp(ambientAirTemp->GetText(), true); UpdateAirTemp(ambientAirTemp->GetText(), true);
}}); }});
ambientAirTemp->SetLimit(9);
scrollPanel->AddChild(ambientAirTemp); scrollPanel->AddChild(ambientAirTemp);
ambientAirTempPreview = new ui::Button(ui::Point(Size.X-31, currentY), ui::Point(16, 16), "", "Preview"); ambientAirTempPreview = new ui::Button(ui::Point(Size.X-31, currentY), ui::Point(16, 16), "", "Preview");
scrollPanel->AddChild(ambientAirTempPreview); scrollPanel->AddChild(ambientAirTempPreview);
auto *label = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-105, 16), "Ambient air temperature"); auto *label = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-96, 16), "Ambient air temperature");
label->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; label->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
label->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; label->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
scrollPanel->AddChild(label); scrollPanel->AddChild(label);
@ -212,10 +210,10 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340))
} }
}; };
gravityMode = addDropDown("Gravity simulation mode", { gravityMode = addDropDown("Gravity simulation mode", {
{ "Vertical", GRAV_VERTICAL }, { "Vertical", 0 },
{ "Off", GRAV_OFF }, { "Off", 1 },
{ "Radial", GRAV_RADIAL }, { "Radial", 2 },
{ "Custom", GRAV_CUSTOM }, { "Custom", 3 },
}, [this] { }, [this] {
c->SetGravityMode(gravityMode->GetOption().second); c->SetGravityMode(gravityMode->GetOption().second);
if (gravityMode->GetOption().second == 3) if (gravityMode->GetOption().second == 3)
@ -224,9 +222,9 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340))
} }
}); });
edgeMode = addDropDown("Edge mode", { edgeMode = addDropDown("Edge mode", {
{ "Void", EDGE_VOID }, { "Void", 0 },
{ "Solid", EDGE_SOLID }, { "Solid", 1 },
{ "Loop", EDGE_LOOP }, { "Loop", 2 },
}, [this] { }, [this] {
c->SetEdgeMode(edgeMode->GetOption().second); c->SetEdgeMode(edgeMode->GetOption().second);
}); });
@ -319,10 +317,10 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340))
currentY += 4; // and then undo the undo currentY += 4; // and then undo the undo
} }
decoSpace = addDropDown("Colour space used by decoration tools", { decoSpace = addDropDown("Colour space used by decoration tools", {
{ "sRGB", DECOSPACE_SRGB }, { "sRGB", 0 },
{ "Linear", DECOSPACE_LINEAR }, { "Linear", 1 },
{ "Gamma 2.2", DECOSPACE_GAMMA22 }, { "Gamma 2.2", 2 },
{ "Gamma 1.8", DECOSPACE_GAMMA18 }, { "Gamma 1.8", 3 },
}, [this] { }, [this] {
c->SetDecoSpace(decoSpace->GetOption().second); c->SetDecoSpace(decoSpace->GetOption().second);
}); });

View File

@ -147,7 +147,7 @@ void PreviewModel::OnSaveReady()
{ {
auto gameSave = std::make_unique<GameSave>(*saveData); auto gameSave = std::make_unique<GameSave>(*saveData);
if (gameSave->fromNewerVersion) if (gameSave->fromNewerVersion)
new ErrorMessage("This save is from a newer version", String::Build("Please update TPT in game or at https://", SERVER)); new ErrorMessage("This save is from a newer version", "Please update TPT in game or at https://powdertoy.co.uk");
saveInfo->SetGameSave(std::move(gameSave)); saveInfo->SetGameSave(std::move(gameSave));
} }
catch(ParseException &e) catch(ParseException &e)

View File

@ -111,9 +111,9 @@ PreviewView::PreviewView(std::unique_ptr<VideoBuffer> newSavePreview):
AddComponent(missingElementsButton); AddComponent(missingElementsButton);
if(showAvatars) if(showAvatars)
saveNameLabel = new ui::Label(ui::Point(39, (YRES/2)+4), ui::Point(265, 16), ""); saveNameLabel = new ui::Label(ui::Point(39, (YRES/2)+4), ui::Point(180, 16), "");
else else
saveNameLabel = new ui::Label(ui::Point(5, (YRES/2)+4), ui::Point(300, 16), ""); saveNameLabel = new ui::Label(ui::Point(5, (YRES/2)+4), ui::Point(200, 16), "");
saveNameLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; saveNameLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
saveNameLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; saveNameLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(saveNameLabel); AddComponent(saveNameLabel);
@ -129,9 +129,9 @@ PreviewView::PreviewView(std::unique_ptr<VideoBuffer> newSavePreview):
AddComponent(saveDescriptionLabel); AddComponent(saveDescriptionLabel);
if(showAvatars) if(showAvatars)
authorDateLabel = new ui::Label(ui::Point(39, (YRES/2)+4+15), ui::Point(200, 16), ""); authorDateLabel = new ui::Label(ui::Point(39, (YRES/2)+4+15), ui::Point(180, 16), "");
else else
authorDateLabel = new ui::Label(ui::Point(5, (YRES/2)+4+15), ui::Point(220, 16), ""); authorDateLabel = new ui::Label(ui::Point(5, (YRES/2)+4+15), ui::Point(200, 16), "");
authorDateLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; authorDateLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
authorDateLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; authorDateLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(authorDateLabel); AddComponent(authorDateLabel);
@ -148,7 +148,7 @@ PreviewView::PreviewView(std::unique_ptr<VideoBuffer> newSavePreview):
AddComponent(avatarButton); AddComponent(avatarButton);
} }
viewsLabel = new ui::Label(ui::Point((XRES/2)-88, (YRES/2)+4+15), ui::Point(88, 16), ""); viewsLabel = new ui::Label(ui::Point((XRES/2)-80, (YRES/2)+4+15), ui::Point(80, 16), "");
viewsLabel->Appearance.HorizontalAlign = ui::Appearance::AlignRight; viewsLabel->Appearance.HorizontalAlign = ui::Appearance::AlignRight;
viewsLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; viewsLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(viewsLabel); AddComponent(viewsLabel);
@ -644,7 +644,6 @@ void PreviewView::NotifyCommentBoxEnabledChanged(PreviewModel * sender)
} }); } });
addCommentBox->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; addCommentBox->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
addCommentBox->SetMultiline(true); addCommentBox->SetMultiline(true);
addCommentBox->SetLimit(1000);
AddComponent(addCommentBox); AddComponent(addCommentBox);
submitCommentButton = new ui::Button(ui::Point(Size.X-40, Size.Y-19), ui::Point(40, 19), "Submit"); submitCommentButton = new ui::Button(ui::Point(Size.X-40, Size.Y-19), ui::Point(40, 19), "Submit");
submitCommentButton->SetActionCallback({ [this] { submitComment(); } }); submitCommentButton->SetActionCallback({ [this] { submitComment(); } });

View File

@ -70,7 +70,7 @@ void ProfileActivity::setUserInfo(UserInfo newInfo)
int currentY = 5; int currentY = 5;
// username label // username label
ui::Label * title = new ui::Label(ui::Point(4, currentY), ui::Point(Size.X-8-(40+16+75), 15), info.username.FromUtf8()); ui::Label * title = new ui::Label(ui::Point(4, currentY), ui::Point(Size.X-8-(40+8+75), 15), info.username.FromUtf8());
title->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; title->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
scrollPanel->AddChild(title); scrollPanel->AddChild(title);
@ -90,13 +90,13 @@ void ProfileActivity::setUserInfo(UserInfo newInfo)
currentY += 23; currentY += 23;
// age // age
ui::Label * ageTitle = new ui::Label(ui::Point(4, currentY), ui::Point(23, 15), "Age:"); ui::Label * ageTitle = new ui::Label(ui::Point(4, currentY), ui::Point(18, 15), "Age:");
ageTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; ageTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
ageTitle->SetTextColour(ui::Colour(180, 180, 180)); ageTitle->SetTextColour(ui::Colour(180, 180, 180));
scrollPanel->AddChild(ageTitle); scrollPanel->AddChild(ageTitle);
// can't figure out how to tell a null from a 0 in the json library we use // can't figure out how to tell a null from a 0 in the json library we use
ui::Label *age = new ui::Label(ui::Point(5+ageTitle->Size.X, currentY), ui::Point(Size.X-ageTitle->Size.X-56, 15), info.age ? String::Build(info.age) : "\bgNot Provided"); ui::Label *age = new ui::Label(ui::Point(8+ageTitle->Size.X, currentY), ui::Point(40, 15), info.age ? String::Build(info.age) : "\bgNot Provided");
age->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; age->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
scrollPanel->AddChild(age); scrollPanel->AddChild(age);
currentY += 2+age->Size.Y; currentY += 2+age->Size.Y;
@ -108,25 +108,20 @@ void ProfileActivity::setUserInfo(UserInfo newInfo)
scrollPanel->AddChild(locationTitle); scrollPanel->AddChild(locationTitle);
if (editable) if (editable)
{ location = new ui::Textbox(ui::Point(8+locationTitle->Size.X, currentY), ui::Point(Size.X-locationTitle->Size.X-16, 17), info.location);
location = new ui::Textbox(ui::Point(5+locationTitle->Size.X, currentY), ui::Point(Size.X-locationTitle->Size.X-16, 17), info.location);
((ui::Textbox*)location)->SetLimit(40);
}
else else
{ location = new ui::Label(ui::Point(4+locationTitle->Size.X, currentY), ui::Point(Size.X-locationTitle->Size.X-14, 17), info.location);
location = new ui::Label(ui::Point(5+locationTitle->Size.X, currentY), ui::Point(Size.X-locationTitle->Size.X-14, 17), info.location);
}
location->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; location->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
scrollPanel->AddChild(location); scrollPanel->AddChild(location);
currentY += 2+location->Size.Y; currentY += 2+location->Size.Y;
// website // website
ui::Label * websiteTitle = new ui::Label(ui::Point(1, currentY), ui::Point(42, 15), "Website:"); ui::Label * websiteTitle = new ui::Label(ui::Point(4, currentY), ui::Point(38, 15), "Website:");
websiteTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; websiteTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
websiteTitle->SetTextColour(ui::Colour(180, 180, 180)); websiteTitle->SetTextColour(ui::Colour(180, 180, 180));
scrollPanel->AddChild(websiteTitle); scrollPanel->AddChild(websiteTitle);
ui::Label *website = new ui::Label(ui::Point(2+websiteTitle->Size.X, currentY), ui::Point(Size.X-websiteTitle->Size.X-16, 15), info.website.FromUtf8()); ui::Label *website = new ui::Label(ui::Point(8+websiteTitle->Size.X, currentY), ui::Point(Size.X-websiteTitle->Size.X-16, 15), info.website.FromUtf8());
website->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; website->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
scrollPanel->AddChild(website); scrollPanel->AddChild(website);
currentY += 2+website->Size.Y; currentY += 2+website->Size.Y;
@ -139,34 +134,34 @@ void ProfileActivity::setUserInfo(UserInfo newInfo)
currentY += savesTitle->Size.Y; currentY += savesTitle->Size.Y;
// saves count // saves count
ui::Label * saveCountTitle = new ui::Label(ui::Point(12, currentY), ui::Point(32, 15), "Count:"); ui::Label * saveCountTitle = new ui::Label(ui::Point(12, currentY), ui::Point(30, 15), "Count:");
saveCountTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; saveCountTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
saveCountTitle->SetTextColour(ui::Colour(180, 180, 180)); saveCountTitle->SetTextColour(ui::Colour(180, 180, 180));
scrollPanel->AddChild(saveCountTitle); scrollPanel->AddChild(saveCountTitle);
ui::Label *savesCount = new ui::Label(ui::Point(13+saveCountTitle->Size.X, currentY), ui::Point(Size.X-saveCountTitle->Size.X-24, 15), String::Build(info.saveCount)); ui::Label *savesCount = new ui::Label(ui::Point(12+saveCountTitle->Size.X, currentY), ui::Point(Size.X-saveCountTitle->Size.X-16, 15), String::Build(info.saveCount));
savesCount->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; savesCount->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
scrollPanel->AddChild(savesCount); scrollPanel->AddChild(savesCount);
currentY += savesCount->Size.Y; currentY += savesCount->Size.Y;
// average score // average score
ui::Label * averageScoreTitle = new ui::Label(ui::Point(12, currentY), ui::Point(72, 15), "Average Score:"); ui::Label * averageScoreTitle = new ui::Label(ui::Point(12, currentY), ui::Point(70, 15), "Average Score:");
averageScoreTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; averageScoreTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
averageScoreTitle->SetTextColour(ui::Colour(180, 180, 180)); averageScoreTitle->SetTextColour(ui::Colour(180, 180, 180));
scrollPanel->AddChild(averageScoreTitle); scrollPanel->AddChild(averageScoreTitle);
ui::Label *averageScore = new ui::Label(ui::Point(13+averageScoreTitle->Size.X, currentY), ui::Point(Size.X-averageScoreTitle->Size.X-24, 15), String::Build(info.averageScore)); ui::Label *averageScore = new ui::Label(ui::Point(12+averageScoreTitle->Size.X, currentY), ui::Point(Size.X-averageScoreTitle->Size.X-16, 15), String::Build(info.averageScore));
averageScore->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; averageScore->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
scrollPanel->AddChild(averageScore); scrollPanel->AddChild(averageScore);
currentY += averageScore->Size.Y; currentY += averageScore->Size.Y;
// highest score // highest score
ui::Label * highestScoreTitle = new ui::Label(ui::Point(12, currentY), ui::Point(71, 15), "Highest Score:"); ui::Label * highestScoreTitle = new ui::Label(ui::Point(12, currentY), ui::Point(69, 15), "Highest Score:");
highestScoreTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; highestScoreTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
highestScoreTitle->SetTextColour(ui::Colour(180, 180, 180)); highestScoreTitle->SetTextColour(ui::Colour(180, 180, 180));
scrollPanel->AddChild(highestScoreTitle); scrollPanel->AddChild(highestScoreTitle);
ui::Label *highestScore = new ui::Label(ui::Point(13+highestScoreTitle->Size.X, currentY), ui::Point(Size.X-highestScoreTitle->Size.X-24, 15), String::Build(info.highestScore)); ui::Label *highestScore = new ui::Label(ui::Point(12+highestScoreTitle->Size.X, currentY), ui::Point(Size.X-highestScoreTitle->Size.X-16, 15), String::Build(info.highestScore));
highestScore->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; highestScore->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
scrollPanel->AddChild(highestScore); scrollPanel->AddChild(highestScore);
currentY += 2+highestScore->Size.Y; currentY += 2+highestScore->Size.Y;

View File

@ -79,7 +79,6 @@ ServerSaveActivity::ServerSaveActivity(std::unique_ptr<SaveInfo> newSave, OnUplo
nameField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; nameField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
nameField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; nameField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
nameField->SetActionCallback({ [this] { CheckName(nameField->GetText()); } }); nameField->SetActionCallback({ [this] { CheckName(nameField->GetText()); } });
nameField->SetLimit(50);
AddComponent(nameField); AddComponent(nameField);
FocusComponent(nameField); FocusComponent(nameField);

View File

@ -136,32 +136,6 @@ void SearchController::SetPageRelative(int offset)
searchModel->UpdateSaveList(page, searchModel->GetLastQuery()); searchModel->UpdateSaveList(page, searchModel->GetLastQuery());
} }
void SearchController::ChangePeriod(int period)
{
switch(period)
{
case 0:
searchModel->SetPeriod(http::allSaves);
break;
case 1:
searchModel->SetPeriod(http::todaySaves);
break;
case 2:
searchModel->SetPeriod(http::weekSaves);
break;
case 3:
searchModel->SetPeriod(http::monthSaves);
break;
case 4:
searchModel->SetPeriod(http::yearSaves);
break;
default:
searchModel->SetPeriod(http::allSaves);
}
searchModel->UpdateSaveList(1, searchModel->GetLastQuery());
}
void SearchController::ChangeSort() void SearchController::ChangeSort()
{ {
if(searchModel->GetSort() == http::sortByDate) if(searchModel->GetSort() == http::sortByDate)

View File

@ -37,7 +37,6 @@ public:
void Refresh(); void Refresh();
void SetPage(int page); void SetPage(int page);
void SetPageRelative(int offset); void SetPageRelative(int offset);
void ChangePeriod(int period);
void ChangeSort(); void ChangeSort();
void ShowOwn(bool show); void ShowOwn(bool show);
void ShowFavourite(bool show); void ShowFavourite(bool show);

View File

@ -11,7 +11,6 @@
#include <cmath> #include <cmath>
SearchModel::SearchModel(): SearchModel::SearchModel():
currentPeriod(http::allSaves),
currentSort(http::sortByVotes), currentSort(http::sortByVotes),
currentPage(1), currentPage(1),
resultCount(0), resultCount(0),
@ -31,11 +30,11 @@ bool SearchModel::GetShowTags()
return showTags; return showTags;
} }
void SearchModel::BeginSearchSaves(int start, int count, String query, http::Period period, http::Sort sort, http::Category category) void SearchModel::BeginSearchSaves(int start, int count, String query, http::Sort sort, http::Category category)
{ {
lastError = ""; lastError = "";
resultCount = 0; resultCount = 0;
searchSaves = std::make_unique<http::SearchSavesRequest>(start, count, query.ToUtf8(), period, sort, category); searchSaves = std::make_unique<http::SearchSavesRequest>(start, count, query.ToUtf8(), sort, category);
searchSaves->Start(); searchSaves->Start();
} }
@ -96,7 +95,7 @@ bool SearchModel::UpdateSaveList(int pageNumber, String query)
//resultCount = 0; //resultCount = 0;
currentPage = pageNumber; currentPage = pageNumber;
if(pageNumber == 1 && !showOwn && !showFavourite && currentPeriod == http::allSaves && currentSort == http::sortByVotes && query == "") if(pageNumber == 1 && !showOwn && !showFavourite && currentSort == http::sortByVotes && query == "")
SetShowTags(true); SetShowTags(true);
else else
SetShowTags(false); SetShowTags(false);
@ -121,7 +120,7 @@ bool SearchModel::UpdateSaveList(int pageNumber, String query)
{ {
category = http::categoryMyOwn; category = http::categoryMyOwn;
} }
BeginSearchSaves((currentPage-1)*20, 20, lastQuery, currentPeriod, currentSort, category); BeginSearchSaves((currentPage-1)*20, 20, lastQuery, currentSort, category);
return true; return true;
} }
return false; return false;
@ -179,7 +178,6 @@ void SearchModel::AddObserver(SearchView * observer)
observers.push_back(observer); observers.push_back(observer);
observer->NotifySaveListChanged(this); observer->NotifySaveListChanged(this);
observer->NotifyPageChanged(this); observer->NotifyPageChanged(this);
observer->NotifyPeriodChanged(this);
observer->NotifySortChanged(this); observer->NotifySortChanged(this);
observer->NotifyShowOwnChanged(this); observer->NotifyShowOwnChanged(this);
observer->NotifyTagListChanged(this); observer->NotifyTagListChanged(this);
@ -260,15 +258,6 @@ void SearchModel::notifyPageChanged()
} }
} }
void SearchModel::notifyPeriodChanged()
{
for (size_t i = 0; i < observers.size(); i++)
{
SearchView* cObserver = observers[i];
cObserver->NotifyPeriodChanged(this);
}
}
void SearchModel::notifySortChanged() void SearchModel::notifySortChanged()
{ {
for (size_t i = 0; i < observers.size(); i++) for (size_t i = 0; i < observers.size(); i++)
@ -307,7 +296,7 @@ void SearchModel::notifySelectedChanged()
int SearchModel::GetPageCount() int SearchModel::GetPageCount()
{ {
if (!showOwn && !showFavourite && currentPeriod == http::allSaves && currentSort == http::sortByVotes && lastQuery == "") if (!showOwn && !showFavourite && currentSort == http::sortByVotes && lastQuery == "")
return std::max(1, (int)(ceil(resultCount/20.0f))+1); //add one for front page (front page saves are repeated twice) return std::max(1, (int)(ceil(resultCount/20.0f))+1); //add one for front page (front page saves are repeated twice)
else else
return std::max(1, (int)(ceil(resultCount/20.0f))); return std::max(1, (int)(ceil(resultCount/20.0f)));

View File

@ -18,7 +18,7 @@ class SearchModel
{ {
private: private:
std::unique_ptr<http::SearchSavesRequest> searchSaves; std::unique_ptr<http::SearchSavesRequest> searchSaves;
void BeginSearchSaves(int start, int count, String query, http::Period period, http::Sort sort, http::Category category); void BeginSearchSaves(int start, int count, String query, http::Sort sort, http::Category category);
std::vector<std::unique_ptr<SaveInfo>> EndSearchSaves(); std::vector<std::unique_ptr<SaveInfo>> EndSearchSaves();
void BeginGetTags(int start, int count, String query); void BeginGetTags(int start, int count, String query);
@ -26,7 +26,6 @@ private:
std::unique_ptr<http::SearchTagsRequest> getTags; std::unique_ptr<http::SearchTagsRequest> getTags;
std::unique_ptr<SaveInfo> loadedSave; std::unique_ptr<SaveInfo> loadedSave;
http::Period currentPeriod;
http::Sort currentSort; http::Sort currentSort;
String lastQuery; String lastQuery;
String lastError; String lastError;
@ -43,7 +42,6 @@ private:
void notifyTagListChanged(); void notifyTagListChanged();
void notifySelectedChanged(); void notifySelectedChanged();
void notifyPageChanged(); void notifyPageChanged();
void notifyPeriodChanged();
void notifySortChanged(); void notifySortChanged();
void notifyShowOwnChanged(); void notifyShowOwnChanged();
void notifyShowFavouriteChanged(); void notifyShowFavouriteChanged();
@ -63,8 +61,6 @@ public:
int GetPageCount(); int GetPageCount();
int GetPageNum() { return currentPage; } int GetPageNum() { return currentPage; }
String GetLastQuery() { return lastQuery; } String GetLastQuery() { return lastQuery; }
void SetPeriod(http::Period period) { if(!searchSaves) { currentPeriod = period; } notifyPeriodChanged(); }
http::Period GetPeriod() { return currentPeriod; }
void SetSort(http::Sort sort) { if(!searchSaves) { currentSort = sort; } notifySortChanged(); } void SetSort(http::Sort sort) { if(!searchSaves) { currentSort = sort; } notifySortChanged(); }
http::Sort GetSort() { return currentSort; } http::Sort GetSort() { return currentSort; }
void SetShowOwn(bool show) { if(!searchSaves) { if(show!=showOwn) { showOwn = show; } } notifyShowOwnChanged(); } void SetShowOwn(bool show) { if(!searchSaves) { if(show!=showOwn) { showOwn = show; } } notifyShowOwnChanged(); }

View File

@ -9,7 +9,6 @@
#include "gui/interface/RichLabel.h" #include "gui/interface/RichLabel.h"
#include "gui/interface/Textbox.h" #include "gui/interface/Textbox.h"
#include "gui/interface/Spinner.h" #include "gui/interface/Spinner.h"
#include "gui/interface/DropDown.h"
#include "PowderToySDL.h" #include "PowderToySDL.h"
#include "graphics/Graphics.h" #include "graphics/Graphics.h"
#include "SimulationConfig.h" #include "SimulationConfig.h"
@ -44,25 +43,13 @@ SearchView::SearchView():
AddComponent(pageCountLabel); AddComponent(pageCountLabel);
AddComponent(pageTextbox); AddComponent(pageTextbox);
searchField = new ui::Textbox(ui::Point(60, 10), ui::Point(WINDOWW-283, 17), "", "[search]"); searchField = new ui::Textbox(ui::Point(60, 10), ui::Point(WINDOWW-238, 17), "", "[search]");
searchField->Appearance.icon = IconSearch; searchField->Appearance.icon = IconSearch;
searchField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; searchField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
searchField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; searchField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
searchField->SetActionCallback({ [this] { doSearch(); } }); searchField->SetActionCallback({ [this] { doSearch(); } });
searchField->SetLimit(100);
FocusComponent(searchField); FocusComponent(searchField);
dateRange = new ui::DropDown(ui::Point(WINDOWW-185, 10), ui::Point(36, 17));
dateRange->SetActionCallback({ [this] { c->ChangePeriod(dateRange->GetOption().second); } });
dateRange->AddOption({"All", 0});
dateRange->AddOption({"Day", 1});
dateRange->AddOption({"Week", 2});
dateRange->AddOption({"Month", 3});
dateRange->AddOption({"Year", 4});
dateRange->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
dateRange->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(dateRange);
sortButton = new ui::Button(ui::Point(WINDOWW-140, 10), ui::Point(61, 17), "Sort"); sortButton = new ui::Button(ui::Point(WINDOWW-140, 10), ui::Point(61, 17), "Sort");
sortButton->SetIcon(IconVoteSort); sortButton->SetIcon(IconVoteSort);
sortButton->SetTogglable(true); sortButton->SetTogglable(true);
@ -214,11 +201,6 @@ void SearchView::Search(String query)
c->DoSearch(query, true); c->DoSearch(query, true);
} }
void SearchView::NotifyPeriodChanged(SearchModel * sender)
{
dateRange->SetOption(sender->GetPeriod());
}
void SearchView::NotifySortChanged(SearchModel * sender) void SearchView::NotifySortChanged(SearchModel * sender)
{ {
if(sender->GetSort() == http::sortByVotes) if(sender->GetSort() == http::sortByVotes)
@ -507,7 +489,7 @@ void SearchView::NotifySaveListChanged(SearchModel * sender)
loadingSpinner->Visible = false; loadingSpinner->Visible = false;
if (!errorLabel) if (!errorLabel)
{ {
errorLabel = new ui::Label(ui::Point(0, (WINDOWH/2)-6), ui::Point(WINDOWW, 12), "Error"); errorLabel = new ui::Label(ui::Point((WINDOWW/2)-100, (WINDOWH/2)-6), ui::Point(200, 12), "Error");
AddComponent(errorLabel); AddComponent(errorLabel);
} }
if (!sender->GetSavesLoaded()) if (!sender->GetSavesLoaded())

View File

@ -11,7 +11,6 @@ namespace ui
class Label; class Label;
class Spinner; class Spinner;
class Textbox; class Textbox;
class DropDown;
} }
class SearchModel; class SearchModel;
@ -33,7 +32,6 @@ private:
ui::Label * pageCountLabel; ui::Label * pageCountLabel;
ui::Label * tagsLabel; ui::Label * tagsLabel;
ui::RichLabel * motdLabel = nullptr; ui::RichLabel * motdLabel = nullptr;
ui::DropDown * dateRange;
ui::Button * sortButton; ui::Button * sortButton;
ui::Button * ownButton; ui::Button * ownButton;
ui::Spinner * loadingSpinner; ui::Spinner * loadingSpinner;
@ -54,7 +52,6 @@ public:
void NotifySaveListChanged(SearchModel * sender); void NotifySaveListChanged(SearchModel * sender);
void NotifySelectedChanged(SearchModel * sender); void NotifySelectedChanged(SearchModel * sender);
void NotifyPageChanged(SearchModel * sender); void NotifyPageChanged(SearchModel * sender);
void NotifyPeriodChanged(SearchModel * sender);
void NotifySortChanged(SearchModel * sender); void NotifySortChanged(SearchModel * sender);
void NotifyShowOwnChanged(SearchModel * sender); void NotifyShowOwnChanged(SearchModel * sender);
void NotifyShowFavouriteChanged(SearchModel * sender); void NotifyShowFavouriteChanged(SearchModel * sender);

View File

@ -30,7 +30,6 @@ TagsView::TagsView():
tagInput->Appearance.icon = IconTag; tagInput->Appearance.icon = IconTag;
tagInput->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; tagInput->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tagInput->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; tagInput->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
tagInput->SetLimit(16);
AddComponent(tagInput); AddComponent(tagInput);
FocusComponent(tagInput); FocusComponent(tagInput);

View File

@ -151,7 +151,7 @@ void UpdateActivity::NotifyError(Task * sender)
new ConfirmPrompt("Autoupdate failed", sb.Build(), { [this] { new ConfirmPrompt("Autoupdate failed", sb.Build(), { [this] {
if constexpr (!USE_UPDATESERVER) if constexpr (!USE_UPDATESERVER)
{ {
Platform::OpenURI(ByteString::Build(SCHEME, SERVER, "/Download.html")); Platform::OpenURI(ByteString(SCHEME) + "powdertoy.co.uk/Download.html");
} }
Exit(); Exit();
}, [this] { Exit(); } }); }, [this] { Exit(); } });

View File

@ -1,26 +1,37 @@
#include "CommandInterface.h" #include "CommandInterface.h"
#include <cstring>
#include <cstddef>
#include <cassert>
#include "Misc.h" #include "Misc.h"
#include "gui/game/GameModel.h" #include "gui/game/GameModel.h"
#include "simulation/Particle.h" #include "simulation/Particle.h"
#include "Format.h"
#include "simulation/Simulation.h"
#include "simulation/Air.h"
#include "simulation/ElementClasses.h"
#include "gui/game/GameController.h"
#include "gui/game/GameModel.h"
#include "gui/interface/Engine.h"
#include "common/tpt-compat.h"
#include <cassert>
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <deque>
CommandInterface::CommandInterface(GameController *newGameController, GameModel *newGameModel) CommandInterface *commandInterface = nullptr;
CommandInterface::CommandInterface(GameController * c, GameModel * m)
{ {
this->m = newGameModel; assert(!commandInterface);
this->c = newGameController; commandInterface = this;
this->m = m;
this->c = c;
}
CommandInterface::~CommandInterface()
{
commandInterface = nullptr;
}
int CommandInterface::Command(String command)
{
lastError = "No interpreter";
return -1;
}
String CommandInterface::FormatCommand(String command)
{
return command;
} }
void CommandInterface::Log(LogType type, String message) void CommandInterface::Log(LogType type, String message)
@ -70,592 +81,3 @@ String CommandInterface::GetLastError()
{ {
return lastError; return lastError;
} }
int CommandInterface::PlainCommand(String command)
{
lastError = "";
std::deque<String> words;
std::deque<AnyType> commandWords;
int retCode = -1;
//Split command into words, put them on the stack
for(String word : command.PartitionBy(' '))
words.push_back(word);
while(!words.empty())
{
try
{
commandWords.push_back(eval(&words));
}
catch (GeneralException & e)
{
retCode = -1;
lastError = e.GetExceptionMessage();
break;
}
}
if(commandWords.size())
{
retCode = 0;
lastError = ((StringType)commandWords.front()).Value();
}
//Evaluate
return retCode;
}
ValueType CommandInterface::testType(String word)
{
size_t i = 0;
String::value_type const *rawWord = word.c_str();
//Function
if (word == "set")
return TypeFunction;
else if (word == "create")
return TypeFunction;
else if (word == "delete")
return TypeFunction;
else if (word == "kill")
return TypeFunction;
else if (word == "load")
return TypeFunction;
else if (word == "reset")
return TypeFunction;
else if (word == "bubble")
return TypeFunction;
else if (word == "quit")
return TypeFunction;
//Basic type
for (i = 0; i < word.length(); i++)
{
if (!(rawWord[i] >= '0' && rawWord[i] <= '9') && !(rawWord[i] == '-' && !i))
{
if (rawWord[i] == '.' && rawWord[i+1])
goto parseFloat;
else if (rawWord[i] == ',' && rawWord[i+1] >= '0' && rawWord[i+1] <= '9')
goto parsePoint;
else if ((rawWord[i] == '#' || (i && rawWord[i-1] == '0' && rawWord[i] == 'x')) &&
((rawWord[i+1] >= '0' && rawWord[i+1] <= '9')
|| (rawWord[i+1] >= 'a' && rawWord[i+1] <= 'f')
|| (rawWord[i+1] >= 'A' && rawWord[i+1] <= 'F')))
goto parseNumberHex;
else
goto parseString;
}
}
return TypeNumber;
parseFloat:
for (i++; i < word.length(); i++)
if (!((rawWord[i] >= '0' && rawWord[i] <= '9')))
{
goto parseString;
}
return TypeFloat;
parseNumberHex:
for (i++; i < word.length(); i++)
if (!((rawWord[i] >= '0' && rawWord[i] <= '9') || (rawWord[i] >= 'a' && rawWord[i] <= 'f') || (rawWord[i] >= 'A' && rawWord[i] <= 'F')))
{
goto parseString;
}
return TypeNumber;
parsePoint:
for (i++; i < word.length(); i++)
if (!(rawWord[i] >= '0' && rawWord[i] <= '9'))
{
goto parseString;
}
return TypePoint;
parseString:
return TypeString;
}
int CommandInterface::parseNumber(String str)
{
String::value_type const *stringData = str.c_str();
char cc;
int base = 10;
int currentNumber = 0;
if (stringData[0] == '#')
{
stringData++;
base = 16;
}
else if (stringData[0] == '0' && stringData[1] == 'x')
{
stringData+=2;
base = 16;
}
if (base == 16)
{
while ((cc = *(stringData++)))
{
currentNumber *= base;
if (cc >= '0' && cc <= '9')
currentNumber += cc - '0';
else if (cc >= 'a' && cc <= 'f')
currentNumber += (cc - 'a') + 10;
else if (cc >= 'A' && cc <= 'F')
currentNumber += (cc - 'A') + 10;
else
break;
}
}
else
{
try
{
return str.ToNumber<int>();
}
catch (std::exception & e)
{
throw GeneralException(ByteString(e.what()).FromUtf8());
}
}
return currentNumber;
}
AnyType CommandInterface::eval(std::deque<String> * words)
{
if(words->size() < 1)
return AnyType(TypeNull, ValueValue());
String word = words->front(); words->pop_front();
ValueType wordType = testType(word);
switch(wordType)
{
case TypeFunction:
if(word == "set")
return tptS_set(words);
else if(word == "create")
return tptS_create(words);
else if(word == "delete" || word == "kill")
return tptS_delete(words);
else if(word == "load")
return tptS_load(words);
else if(word == "reset")
return tptS_reset(words);
else if(word == "bubble")
return tptS_bubble(words);
else if(word == "quit")
return tptS_quit(words);
break;
case TypeNumber:
return NumberType(parseNumber(word));
case TypeFloat:
return FloatType(atof(word.ToUtf8().c_str()));
case TypePoint:
{
int x, y;
if(String::Split comma = word.SplitNumber(x))
if(comma.After().BeginsWith(","))
if(comma.After().Substr(1).SplitNumber(y))
return PointType(x, y);
return PointType(0, 0);
}
case TypeString:
return StringType(word);
default:
break;
}
return StringType(word);
}
String CommandInterface::PlainFormatCommand(String command)
{
std::deque<String> words;
std::deque<AnyType> commandWords;
String outputData;
//Split command into words, put them on the stack
for(String word : command.PartitionBy(' ', true))
words.push_back(word);
while(!words.empty())
{
ValueType cType = testType(words.front());
switch(cType)
{
case TypeFunction:
outputData += "\bt";
break;
case TypeNumber:
case TypePoint:
outputData += "\bo";
break;
case TypeString:
outputData += "\bg";
break;
default:
outputData += "\bw";
break;
}
outputData += words.front() + " ";
words.pop_front();
}
return outputData;
}
AnyType CommandInterface::tptS_set(std::deque<String> * words)
{
auto &sd = SimulationData::CRef();
//Arguments from stack
StringType property = eval(words);
AnyType selector = eval(words);
AnyType value = eval(words);
Simulation * sim = m->GetSimulation();
unsigned char * partsBlock = (unsigned char*)&sim->parts[0];
int returnValue = 0;
FormatType propertyFormat;
int propertyOffset = GetPropertyOffset(property.Value().ToUtf8(), propertyFormat);
if (propertyOffset == -1)
throw GeneralException("Invalid property");
//Selector
int newValue = 0;
float newValuef = 0.0f;
if (property.Value() == "temp")
{
// convert non-string temperature values to strings to format::StringToTemperature can take care of them
switch (value.GetType())
{
case TypeNumber:
value = StringType(String::Build(((NumberType)value).Value()));
break;
case TypeFloat:
value = StringType(String::Build(((FloatType)value).Value()));
break;
default:
break;
}
}
if (value.GetType() == TypeNumber)
{
newValuef = float(newValue = ((NumberType)value).Value());
}
else if (value.GetType() == TypeFloat)
{
newValue = int(newValuef = ((FloatType)value).Value());
}
else if(value.GetType() == TypeString)
{
if (property.Value() == "temp")
{
try
{
newValuef = format::StringToTemperature(((StringType)value).Value(), c->GetTemperatureScale());
}
catch (const std::exception &ex)
{
throw GeneralException("Invalid value for assignment");
}
}
else
{
newValue = sd.GetParticleType(((StringType)value).Value().ToUtf8());
if (newValue < 0 || newValue >= PT_NUM)
{
// TODO: add element CAKE to invalidate this
if (((StringType)value).Value().ToUpper() == "CAKE")
throw GeneralException("Cake is a lie, not an element");
throw GeneralException("Invalid element");
}
}
}
else
throw GeneralException("Invalid value for assignment");
if (property.Value() == "type" && (newValue < 0 || newValue >= PT_NUM || !sd.elements[newValue].Enabled))
throw GeneralException("Invalid element");
if (selector.GetType() == TypePoint || selector.GetType() == TypeNumber)
{
int partIndex = -1;
if(selector.GetType() == TypePoint)
{
ui::Point tempPoint = ((PointType)selector).Value();
if(tempPoint.X<0 || tempPoint.Y<0 || tempPoint.Y >= YRES || tempPoint.X >= XRES)
throw GeneralException("Invalid position");
}
else
partIndex = ((NumberType)selector).Value();
if(partIndex<0 || partIndex>=NPART || sim->parts[partIndex].type==0)
throw GeneralException("Invalid particle");
switch(propertyFormat)
{
case FormatInt:
*((int*)(partsBlock+(partIndex*sizeof(Particle))+propertyOffset)) = newValue;
break;
case FormatFloat:
*((float*)(partsBlock+(partIndex*sizeof(Particle))+propertyOffset)) = newValuef;
break;
case FormatElement:
sim->part_change_type(partIndex, int(sim->parts[partIndex].x + 0.5f), int(sim->parts[partIndex].y + 0.5f), newValue);
break;
default:
break;
}
returnValue = 1;
}
else if (selector.GetType() == TypeString && ((StringType)selector).Value() == "all")
{
switch(propertyFormat)
{
case FormatInt:
{
for(int j = 0; j < NPART; j++)
if(sim->parts[j].type)
{
returnValue++;
*((int*)(partsBlock+(j*sizeof(Particle))+propertyOffset)) = newValue;
}
}
break;
case FormatFloat:
{
for(int j = 0; j < NPART; j++)
if(sim->parts[j].type)
{
returnValue++;
*((float*)(partsBlock+(j*sizeof(Particle))+propertyOffset)) = newValuef;
}
}
break;
case FormatElement:
{
for (int j = 0; j < NPART; j++)
if (sim->parts[j].type)
{
returnValue++;
sim->part_change_type(j, int(sim->parts[j].x + 0.5f), int(sim->parts[j].y + 0.5f), newValue);
}
}
break;
default:
break;
}
}
else if(selector.GetType() == TypeString || selector.GetType() == TypeNumber)
{
int type = 0;
if (selector.GetType() == TypeNumber)
type = ((NumberType)selector).Value();
else if (selector.GetType() == TypeString)
type = sd.GetParticleType(((StringType)selector).Value().ToUtf8());
if (type<0 || type>=PT_NUM)
throw GeneralException("Invalid particle type");
if (type==0)
throw GeneralException("Cannot set properties of particles that do not exist");
switch(propertyFormat)
{
case FormatInt:
{
for (int j = 0; j < NPART; j++)
if (sim->parts[j].type == type)
{
returnValue++;
*((int*)(partsBlock+(j*sizeof(Particle))+propertyOffset)) = newValue;
}
}
break;
case FormatFloat:
{
for (int j = 0; j < NPART; j++)
if (sim->parts[j].type == type)
{
returnValue++;
*((float*)(partsBlock+(j*sizeof(Particle))+propertyOffset)) = newValuef;
}
}
break;
case FormatElement:
{
for (int j = 0; j < NPART; j++)
if (sim->parts[j].type == type)
{
returnValue++;
sim->part_change_type(j, int(sim->parts[j].x + 0.5f), int(sim->parts[j].y + 0.5f), newValue);
}
}
break;
default:
break;
}
}
else
throw GeneralException("Invalid selector");
return NumberType(returnValue);
}
AnyType CommandInterface::tptS_create(std::deque<String> * words)
{
auto &sd = SimulationData::CRef();
//Arguments from stack
AnyType createType = eval(words);
PointType position = eval(words);
Simulation * sim = m->GetSimulation();
int type;
if(createType.GetType() == TypeNumber)
type = ((NumberType)createType).Value();
else if(createType.GetType() == TypeString)
type = sd.GetParticleType(((StringType)createType).Value().ToUtf8());
else
throw GeneralException("Invalid type");
if(type == -1)
throw GeneralException("Invalid particle type");
ui::Point tempPoint = position.Value();
if(tempPoint.X<0 || tempPoint.Y<0 || tempPoint.Y >= YRES || tempPoint.X >= XRES)
throw GeneralException("Invalid position");
int v = -1;
if (ID(type))
{
v = ID(type);
type = TYP(type);
}
int returnValue = sim->create_part(-1, tempPoint.X, tempPoint.Y, type, v);
return NumberType(returnValue);
}
AnyType CommandInterface::tptS_delete(std::deque<String> * words)
{
//Arguments from stack
AnyType partRef = eval(words);
Simulation * sim = m->GetSimulation();
if(partRef.GetType() == TypePoint)
{
ui::Point deletePoint = ((PointType)partRef).Value();
if(deletePoint.X<0 || deletePoint.Y<0 || deletePoint.Y >= YRES || deletePoint.X >= XRES)
throw GeneralException("Invalid position");
sim->delete_part(deletePoint.X, deletePoint.Y);
}
else if(partRef.GetType() == TypeNumber)
{
int partIndex = ((NumberType)partRef).Value();
if(partIndex < 0 || partIndex >= NPART)
throw GeneralException("Invalid particle index");
sim->kill_part(partIndex);
}
else
throw GeneralException("Invalid particle reference");
return NumberType(0);
}
AnyType CommandInterface::tptS_load(std::deque<String> * words)
{
//Arguments from stack
NumberType saveID = eval(words);
if (saveID.Value() > 0)
{
c->OpenSavePreview(saveID.Value(), 0, savePreviewNormal);
return NumberType(0);
}
else
throw GeneralException("Invalid save ID");
}
AnyType CommandInterface::tptS_bubble(std::deque<String> * words)
{
//Arguments from stack
PointType bubblePosA = eval(words);
ui::Point bubblePos = bubblePosA.Value();
if(bubblePos.X<0 || bubblePos.Y<0 || bubblePos.Y >= YRES || bubblePos.X >= XRES)
throw GeneralException("Invalid position");
Simulation * sim = m->GetSimulation();
int first, rem1, rem2;
first = sim->create_part(-1, bubblePos.X+18, bubblePos.Y, PT_SOAP);
rem1 = first;
for (int i = 1; i<=30; i++)
{
rem2 = sim->create_part(-1, int(bubblePos.X+18*cosf(i/5.0)+0.5f), int(bubblePos.Y+18*sinf(i/5.0)+0.5f), PT_SOAP);
sim->parts[rem1].ctype = 7;
sim->parts[rem1].tmp = rem2;
sim->parts[rem2].tmp2 = rem1;
rem1 = rem2;
}
sim->parts[rem1].ctype = 7;
sim->parts[rem1].tmp = first;
sim->parts[first].tmp2 = rem1;
sim->parts[first].ctype = 7;
return NumberType(0);
}
AnyType CommandInterface::tptS_reset(std::deque<String> * words)
{
auto &sd = SimulationData::CRef();
//Arguments from stack
StringType reset = eval(words);
String resetStr = reset.Value();
Simulation * sim = m->GetSimulation();
if (resetStr == "pressure")
{
for (int nx = 0; nx < XCELLS; nx++)
for (int ny = 0; ny < YCELLS; ny++)
{
sim->air->pv[ny][nx] = 0;
}
}
else if (resetStr == "velocity")
{
for (int nx = 0; nx < XCELLS; nx++)
for (int ny = 0; ny < YCELLS; ny++)
{
sim->air->vx[ny][nx] = 0;
sim->air->vy[ny][nx] = 0;
}
}
else if (resetStr == "sparks")
{
c->ResetSpark();
}
else if (resetStr == "temp")
{
for (int i = 0; i < NPART; i++)
{
if (sim->parts[i].type)
{
sim->parts[i].temp = sd.elements[sim->parts[i].type].DefaultProperties.temp;
}
}
}
else
{
throw GeneralException("Unknown reset command");
}
return NumberType(0);
}
AnyType CommandInterface::tptS_quit(std::deque<String> * words)
{
ui::Engine::Ref().Exit();
return NumberType(0);
}

View File

@ -1,58 +1,41 @@
#pragma once #pragma once
#include "CommandInterfacePtr.h"
#include "common/ExplicitSingleton.h"
#include "common/String.h" #include "common/String.h"
#include "gui/game/GameControllerEvents.h" #include "gui/game/GameControllerEvents.h"
#include "TPTSTypes.h"
#include <deque>
class GameModel; class GameModel;
class GameController; class GameController;
class Tool; class Tool;
class CommandInterface : public ExplicitSingleton<CommandInterface> class CommandInterface
{ {
protected: protected:
String lastError; String lastError;
GameModel * m; GameModel * m;
GameController * c; GameController * c;
CommandInterface(GameController * c, GameModel * m);
int PlainCommand(String command);
String PlainFormatCommand(String command);
public: public:
CommandInterface(GameController *newGameController, GameModel *newGameModel);
enum LogType { LogError, LogWarning, LogNotice }; enum LogType { LogError, LogWarning, LogNotice };
enum FormatType { FormatInt, FormatString, FormatChar, FormatFloat, FormatElement }; enum FormatType { FormatInt, FormatString, FormatChar, FormatFloat, FormatElement };
int GetPropertyOffset(ByteString key, FormatType & format); int GetPropertyOffset(ByteString key, FormatType & format);
void Log(LogType type, String message); void Log(LogType type, String message);
//void AttachGameModel(GameModel * m); //void AttachGameModel(GameModel * m);
void OnTick(); virtual void OnTick() { }
void Init(); virtual void Init() { }
bool HandleEvent(const GameControllerEvent &event); virtual bool HandleEvent(const GameControllerEvent &event) { return true; }
int Command(String command); virtual int Command(String command);
String FormatCommand(String command); virtual String FormatCommand(String command);
void SetLastError(String err) void SetLastError(String err)
{ {
lastError = err; lastError = err;
} }
String GetLastError(); String GetLastError();
virtual ~CommandInterface();
AnyType eval(std::deque<String> * words); static CommandInterface *Create(GameController * c, GameModel * m);
int parseNumber(String str);
AnyType tptS_set(std::deque<String> * words);
AnyType tptS_create(std::deque<String> * words);
AnyType tptS_delete(std::deque<String> * words);
AnyType tptS_load(std::deque<String> * words);
AnyType tptS_reset(std::deque<String> * words);
AnyType tptS_bubble(std::deque<String> * words);
AnyType tptS_quit(std::deque<String> * words);
ValueType testType(String word);
static CommandInterfacePtr Create(GameController *newGameController, GameModel *newGameModel);
}; };
extern CommandInterface *commandInterface;

View File

@ -1,9 +0,0 @@
#pragma once
#include <memory>
class CommandInterface;
struct CommandInterfaceDeleter
{
void operator ()(CommandInterface *ptr) const;
};
using CommandInterfacePtr = std::unique_ptr<CommandInterface, CommandInterfaceDeleter>;

1200
src/lua/LegacyLuaAPI.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
#include "LuaScriptInterface.h" #include "LuaScriptInterface.h"
#include "gui/interface/Button.h" #include "gui/interface/Button.h"
const char LuaButton::className[] = "button"; const char LuaButton::className[] = "Button";
#define method(class, name) {#name, &class::name} #define method(class, name) {#name, &class::name}
Luna<LuaButton>::RegType LuaButton::methods[] = { Luna<LuaButton>::RegType LuaButton::methods[] = {
@ -15,53 +15,53 @@ Luna<LuaButton>::RegType LuaButton::methods[] = {
{0, 0} {0, 0}
}; };
LuaButton::LuaButton(lua_State *L) : LuaButton::LuaButton(lua_State * l) :
LuaComponent(L) LuaComponent(l)
{ {
int posX = luaL_optinteger(L, 1, 0); int posX = luaL_optinteger(l, 1, 0);
int posY = luaL_optinteger(L, 2, 0); int posY = luaL_optinteger(l, 2, 0);
int sizeX = luaL_optinteger(L, 3, 10); int sizeX = luaL_optinteger(l, 3, 10);
int sizeY = luaL_optinteger(L, 4, 10); int sizeY = luaL_optinteger(l, 4, 10);
String text = tpt_lua_optString(L, 5, ""); String text = tpt_lua_optString(l, 5, "");
String toolTip = tpt_lua_optString(L, 6, ""); String toolTip = tpt_lua_optString(l, 6, "");
button = new ui::Button(ui::Point(posX, posY), ui::Point(sizeX, sizeY), text, toolTip); button = new ui::Button(ui::Point(posX, posY), ui::Point(sizeX, sizeY), text, toolTip);
component = button; component = button;
button->SetActionCallback({ [this] { triggerAction(); } }); button->SetActionCallback({ [this] { triggerAction(); } });
} }
int LuaButton::enabled(lua_State *L) int LuaButton::enabled(lua_State * l)
{ {
int args = lua_gettop(L); int args = lua_gettop(l);
if(args) if(args)
{ {
luaL_checktype(L, 1, LUA_TBOOLEAN); luaL_checktype(l, 1, LUA_TBOOLEAN);
button->Enabled = lua_toboolean(L, 1); button->Enabled = lua_toboolean(l, 1);
return 0; return 0;
} }
else else
{ {
lua_pushboolean(L, button->Enabled); lua_pushboolean(l, button->Enabled);
return 1; return 1;
} }
} }
int LuaButton::action(lua_State *L) int LuaButton::action(lua_State * l)
{ {
return actionFunction.CheckAndAssignArg1(L); return actionFunction.CheckAndAssignArg1(l);
} }
int LuaButton::text(lua_State *L) int LuaButton::text(lua_State * l)
{ {
int args = lua_gettop(L); int args = lua_gettop(l);
if(args) if(args)
{ {
button->SetText(tpt_lua_checkString(L, 1)); button->SetText(tpt_lua_checkString(l, 1));
return 0; return 0;
} }
else else
{ {
tpt_lua_pushString(L, button->GetText()); tpt_lua_pushString(l, button->GetText());
return 1; return 1;
} }
} }
@ -70,11 +70,11 @@ void LuaButton::triggerAction()
{ {
if(actionFunction) if(actionFunction)
{ {
lua_rawgeti(L, LUA_REGISTRYINDEX, actionFunction); lua_rawgeti(l, LUA_REGISTRYINDEX, actionFunction);
lua_rawgeti(L, LUA_REGISTRYINDEX, owner_ref); lua_rawgeti(l, LUA_REGISTRYINDEX, owner_ref);
if (tpt_lua_pcall(L, 1, 0, 0, eventTraitNone)) if (tpt_lua_pcall(l, 1, 0, 0, eventTraitNone))
{ {
ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1));
} }
} }
} }

View File

@ -15,13 +15,13 @@ class LuaButton: public LuaComponent
ui::Button * button; ui::Button * button;
LuaComponentCallback actionFunction; LuaComponentCallback actionFunction;
void triggerAction(); void triggerAction();
int action(lua_State *L); int action(lua_State * l);
int text(lua_State *L); int text(lua_State * l);
int enabled(lua_State *L); int enabled(lua_State * l);
public: public:
static const char className[]; static const char className[];
static Luna<LuaButton>::RegType methods[]; static Luna<LuaButton>::RegType methods[];
LuaButton(lua_State *L); LuaButton(lua_State * l);
~LuaButton(); ~LuaButton();
}; };

View File

@ -1,64 +0,0 @@
#include "LuaScriptInterface.h"
#include "bzip2/bz2wrap.h"
static int compress(lua_State *L)
{
auto src = tpt_lua_checkByteString(L, 1);
auto maxSize = size_t(luaL_optinteger(L, 2, 0));
std::vector<char> dest;
auto result = BZ2WCompress(dest, src.data(), src.size(), maxSize);
#define RETURN_ERR(str) lua_pushnil(L); lua_pushinteger(L, int(result)); lua_pushliteral(L, str); return 3
switch (result)
{
case BZ2WCompressOk: break;
case BZ2WCompressNomem: RETURN_ERR("out of memory");
case BZ2WCompressLimit: RETURN_ERR("size limit exceeded");
}
#undef RETURN_ERR
tpt_lua_pushByteString(L, ByteString(dest.begin(), dest.end()));
return 1;
}
static int decompress(lua_State *L)
{
auto src = tpt_lua_checkByteString(L, 1);
auto maxSize = size_t(luaL_optinteger(L, 2, 0));
std::vector<char> dest;
auto result = BZ2WDecompress(dest, src.data(), src.size(), maxSize);
#define RETURN_ERR(str) lua_pushnil(L); lua_pushinteger(L, int(result)); lua_pushliteral(L, str); return 3
switch (result)
{
case BZ2WDecompressOk: break;
case BZ2WDecompressNomem: RETURN_ERR("out of memory");
case BZ2WDecompressLimit: RETURN_ERR("size limit exceeded");
case BZ2WDecompressType:
case BZ2WDecompressBad:
case BZ2WDecompressEof: RETURN_ERR("corrupted stream");
}
#undef RETURN_ERR
tpt_lua_pushByteString(L, ByteString(dest.begin(), dest.end()));
return 1;
}
void LuaBz2::Open(lua_State *L)
{
static const luaL_Reg reg[] = {
#define LFUNC(v) { #v, v }
LFUNC(compress),
LFUNC(decompress),
#undef LFUNC
{ NULL, NULL }
};
lua_newtable(L);
luaL_register(L, NULL, reg);
#define LCONSTAS(k, v) lua_pushinteger(L, int(v)); lua_setfield(L, -2, k)
LCONSTAS("COMPRESS_NOMEM" , BZ2WCompressNomem );
LCONSTAS("COMPRESS_LIMIT" , BZ2WCompressLimit );
LCONSTAS("DECOMPRESS_NOMEM", BZ2WDecompressNomem);
LCONSTAS("DECOMPRESS_LIMIT", BZ2WDecompressLimit);
LCONSTAS("DECOMPRESS_TYPE" , BZ2WDecompressType );
LCONSTAS("DECOMPRESS_BAD" , BZ2WDecompressBad );
LCONSTAS("DECOMPRESS_EOF" , BZ2WDecompressEof );
#undef LCONSTAS
lua_setglobal(L, "bz2");
}

View File

@ -2,7 +2,7 @@
#include "LuaScriptInterface.h" #include "LuaScriptInterface.h"
#include "gui/interface/Checkbox.h" #include "gui/interface/Checkbox.h"
const char LuaCheckbox::className[] = "checkbox"; const char LuaCheckbox::className[] = "Checkbox";
#define method(class, name) {#name, &class::name} #define method(class, name) {#name, &class::name}
Luna<LuaCheckbox>::RegType LuaCheckbox::methods[] = { Luna<LuaCheckbox>::RegType LuaCheckbox::methods[] = {
@ -15,51 +15,51 @@ Luna<LuaCheckbox>::RegType LuaCheckbox::methods[] = {
{0, 0} {0, 0}
}; };
LuaCheckbox::LuaCheckbox(lua_State *L) : LuaCheckbox::LuaCheckbox(lua_State * l) :
LuaComponent(L) LuaComponent(l)
{ {
int posX = luaL_optinteger(L, 1, 0); int posX = luaL_optinteger(l, 1, 0);
int posY = luaL_optinteger(L, 2, 0); int posY = luaL_optinteger(l, 2, 0);
int sizeX = luaL_optinteger(L, 3, 10); int sizeX = luaL_optinteger(l, 3, 10);
int sizeY = luaL_optinteger(L, 4, 10); int sizeY = luaL_optinteger(l, 4, 10);
String text = tpt_lua_optString(L, 5, ""); String text = tpt_lua_optString(l, 5, "");
checkbox = new ui::Checkbox(ui::Point(posX, posY), ui::Point(sizeX, sizeY), text, ""); checkbox = new ui::Checkbox(ui::Point(posX, posY), ui::Point(sizeX, sizeY), text, "");
component = checkbox; component = checkbox;
checkbox->SetActionCallback({ [this] { triggerAction(); } }); checkbox->SetActionCallback({ [this] { triggerAction(); } });
} }
int LuaCheckbox::checked(lua_State *L) int LuaCheckbox::checked(lua_State * l)
{ {
int args = lua_gettop(L); int args = lua_gettop(l);
if(args) if(args)
{ {
checkbox->SetChecked(lua_toboolean(L, 1)); checkbox->SetChecked(lua_toboolean(l, 1));
return 0; return 0;
} }
else else
{ {
lua_pushboolean(L, checkbox->GetChecked()); lua_pushboolean(l, checkbox->GetChecked());
return 1; return 1;
} }
} }
int LuaCheckbox::action(lua_State *L) int LuaCheckbox::action(lua_State * l)
{ {
return actionFunction.CheckAndAssignArg1(L); return actionFunction.CheckAndAssignArg1(l);
} }
int LuaCheckbox::text(lua_State *L) int LuaCheckbox::text(lua_State * l)
{ {
int args = lua_gettop(L); int args = lua_gettop(l);
if(args) if(args)
{ {
checkbox->SetText(tpt_lua_checkString(L, 1)); checkbox->SetText(tpt_lua_checkString(l, 1));
return 0; return 0;
} }
else else
{ {
tpt_lua_pushString(L, checkbox->GetText()); tpt_lua_pushString(l, checkbox->GetText());
return 1; return 1;
} }
} }
@ -68,12 +68,12 @@ void LuaCheckbox::triggerAction()
{ {
if(actionFunction) if(actionFunction)
{ {
lua_rawgeti(L, LUA_REGISTRYINDEX, actionFunction); lua_rawgeti(l, LUA_REGISTRYINDEX, actionFunction);
lua_rawgeti(L, LUA_REGISTRYINDEX, owner_ref); lua_rawgeti(l, LUA_REGISTRYINDEX, owner_ref);
lua_pushboolean(L, checkbox->GetChecked()); lua_pushboolean(l, checkbox->GetChecked());
if (tpt_lua_pcall(L, 2, 0, 0, eventTraitNone)) if (tpt_lua_pcall(l, 2, 0, 0, eventTraitNone))
{ {
ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1));
} }
} }
} }

View File

@ -15,13 +15,13 @@ class LuaCheckbox: public LuaComponent
ui::Checkbox * checkbox; ui::Checkbox * checkbox;
LuaComponentCallback actionFunction; LuaComponentCallback actionFunction;
void triggerAction(); void triggerAction();
int action(lua_State *L); int action(lua_State * l);
int checked(lua_State *L); int checked(lua_State * l);
int text(lua_State *L); int text(lua_State * l);
public: public:
static const char className[]; static const char className[];
static Luna<LuaCheckbox>::RegType methods[]; static Luna<LuaCheckbox>::RegType methods[];
LuaCheckbox(lua_State *L); LuaCheckbox(lua_State * l);
~LuaCheckbox(); ~LuaCheckbox();
}; };

View File

@ -8,7 +8,9 @@ int luaL_typerror(lua_State *L, int narg, const char *tname)
return luaL_argerror(L, narg, msg); return luaL_argerror(L, narg, msg);
} }
void luaL_register(lua_State *L, const char *libname, const luaL_Reg *l) void luaL_register (lua_State *L,
const char *libname,
const luaL_Reg *l)
{ {
if (libname) if (libname)
{ {
@ -18,7 +20,18 @@ void luaL_register(lua_State *L, const char *libname, const luaL_Reg *l)
} }
luaL_setfuncs(L, l, 0); luaL_setfuncs(L, l, 0);
} }
void tpt_lua_setmainthread(lua_State *L)
{
}
void tpt_lua_getmainthread(lua_State *L)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD);
}
#else #else
# ifndef lua_pushglobaltable // * Thank you moonjit # ifndef lua_pushglobaltable // * Thank you moonjit
// Implement function added in lua 5.2 that we now use // Implement function added in lua 5.2 that we now use
void lua_pushglobaltable(lua_State *L) void lua_pushglobaltable(lua_State *L)
@ -26,4 +39,42 @@ void lua_pushglobaltable(lua_State *L)
lua_pushvalue(L, LUA_GLOBALSINDEX); lua_pushvalue(L, LUA_GLOBALSINDEX);
} }
# endif # endif
void tpt_lua_setmainthread(lua_State *L)
{
lua_pushthread(L);
lua_setfield(L, LUA_REGISTRYINDEX, "tpt_lua_mainthread");
}
void tpt_lua_getmainthread(lua_State *L)
{
lua_getfield(L, LUA_REGISTRYINDEX, "tpt_lua_mainthread");
}
#endif #endif
// Useful helper function, mainly used for logging
int luaL_tostring(lua_State *L, int n)
{
luaL_checkany(L, n);
switch (lua_type(L, n))
{
case LUA_TNUMBER:
lua_tostring(L, n);
lua_pushvalue(L, n);
break;
case LUA_TSTRING:
lua_pushvalue(L, n);
break;
case LUA_TBOOLEAN:
lua_pushstring(L, (lua_toboolean(L, n) ? "true" : "false"));
break;
case LUA_TNIL:
lua_pushliteral(L, "nil");
break;
default:
lua_pushfstring(L, "%s: %p", luaL_typename(L, n), lua_topointer(L, n));
break;
}
return 1;
}

View File

@ -9,6 +9,9 @@ extern "C"
#include <lauxlib.h> #include <lauxlib.h>
#include <lualib.h> #include <lualib.h>
LUALIB_API void tpt_lua_setmainthread(lua_State *L);
LUALIB_API void tpt_lua_getmainthread(lua_State *L);
#if LUA_VERSION_NUM >= 502 #if LUA_VERSION_NUM >= 502
void luaL_register(lua_State *L, const char *libname, const luaL_Reg *l); void luaL_register(lua_State *L, const char *libname, const luaL_Reg *l);
#define lua_strlen(L,i) lua_rawlen(L, (i)) #define lua_strlen(L,i) lua_rawlen(L, (i))
@ -22,6 +25,7 @@ LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
LUALIB_API void (lua_pushglobaltable) (lua_State *L); LUALIB_API void (lua_pushglobaltable) (lua_State *L);
# endif # endif
#endif #endif
int luaL_tostring(lua_State *L, int n);
#ifdef __cplusplus #ifdef __cplusplus
} }

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