diff --git a/.github/workflows/dev-desktop-builds.yml b/.github/workflows/dev-desktop-builds.yml
index 2391c0c534..dcd2ba47d9 100644
--- a/.github/workflows/dev-desktop-builds.yml
+++ b/.github/workflows/dev-desktop-builds.yml
@@ -1,279 +1,285 @@
-name: "Build Material Maker"
+# name: "Build Material Maker"
-on:
- push:
- branches: [master]
- pull_request:
- branches: [master]
- workflow_dispatch:
- inputs:
- artifacts:
- description: "Generate artifacts"
- type: boolean
- required: true
- default: "false"
- sign_macos:
- description: "Sign macOS version"
- type: boolean
- required: true
- default: "false"
- gen_doc:
- description: "Generate documentation"
- type: boolean
- required: true
- default: "true"
- steam:
- description: "Generate Steam version"
- type: boolean
- required: true
- default: "false"
- steam_deploy:
- description: "Upload Steam version"
- type: boolean
- required: true
- default: "false"
+# on:
+# push:
+# branches: [master]
+# pull_request:
+# branches: [master]
+# workflow_dispatch:
+# inputs:
+# artifacts:
+# description: "Generate artifacts"
+# type: boolean
+# required: true
+# default: false
+# sign_macos:
+# description: "Sign macOS version"
+# type: boolean
+# required: true
+# default: false
+# android_release:
+# description: "Generate Android release"
+# type: boolean
+# required: true
+# default: false
+# gen_doc:
+# description: "Generate documentation"
+# type: boolean
+# required: true
+# default: true
+# steam:
+# description: "Generate Steam version"
+# type: boolean
+# required: true
+# default: false
+# steam_deploy:
+# description: "Upload Steam version"
+# type: boolean
+# required: true
+# default: false
-env:
- GODOT_VERSION: 4.7.2
- GODOT_SUB: stable
- GODOT_DOWNLOAD_DIR: https://github.com/godotengine/godot-builds/releases/download/4.7.2-stable
- EXPORT_NAME: material_maker
- MM_RELEASE: 1_8
- EXPORT_TARGET_SUFFIX: "${{ github.event.inputs.steam == 'true' && ' Steam' || '' }}"
- PACKAGE_SUFFIX: "${{ github.event.inputs.steam == 'true' && '_steam' || '' }}"
+# env:
+# GODOT_VERSION: 4.8
+# GODOT_SUB: beta1
+# GODOT_DOWNLOAD_DIR: https://github.com/godotengine/godot-builds/releases/download/4.8-beta1
+# EXPORT_NAME: material_maker
+# MM_RELEASE: 1_7
+# EXPORT_TARGET_SUFFIX: "${{ github.event.inputs.steam == 'true' && ' Steam' || '' }}"
+# PACKAGE_SUFFIX: "${{ github.event.inputs.steam == 'true' && '_steam' || '' }}"
-jobs:
- export_windows_linux:
- name: Export Windows and Linux 🗔
- runs-on: ubuntu-latest
- steps:
- - name: Checkout 🛎️
- uses: actions/checkout@v1
- with:
- submodules: true
- - name: Setup 💻
- run: |
- cp -f material_maker/theme/default_theme_icons.svg material_maker/theme/default_theme_icons_export.svg
- wget -q ${GODOT_DOWNLOAD_DIR}/Godot_v${GODOT_VERSION}-${GODOT_SUB}_linux.x86_64.zip
- unzip Godot_v${GODOT_VERSION}-${GODOT_SUB}_linux.x86_64.zip
- wget -q ${GODOT_DOWNLOAD_DIR}/Godot_v${GODOT_VERSION}-${GODOT_SUB}_export_templates.tpz
- unzip -a Godot_v${GODOT_VERSION}-${GODOT_SUB}_export_templates.tpz
- mkdir -v -p ~/.local/share/godot/export_templates/${GODOT_VERSION}.${GODOT_SUB}
- mv ./templates/* ~/.local/share/godot/export_templates/${GODOT_VERSION}.${GODOT_SUB}
- mkdir -v -p build/${EXPORT_NAME}_${MM_RELEASE}_windows build/${EXPORT_NAME}_${MM_RELEASE}_linux
- - name: Generate Documentation
- if: ${{ github.event.inputs.gen_doc == 'true' }}
- uses: ammaraskar/sphinx-action@master
- with:
- docs-folder: "material_maker/doc"
- - name: Windows Build 🗔
- run: |
- ./Godot_v${GODOT_VERSION}-${GODOT_SUB}_linux.x86_64 --headless -v --export-release "Windows${EXPORT_TARGET_SUFFIX}" ./build/${EXPORT_NAME}_${MM_RELEASE}_windows/$EXPORT_NAME.exe
- - name: Linux Build 🐧
- run: |
- ./Godot_v${GODOT_VERSION}-${GODOT_SUB}_linux.x86_64 --headless -v --export-release "Linux/X11${EXPORT_TARGET_SUFFIX}" ./build/${EXPORT_NAME}_${MM_RELEASE}_linux/$EXPORT_NAME.x86_64
- - name: Copy Material Maker data 📁
- run: |
- cp -R ./addons/material_maker/nodes ./build/${EXPORT_NAME}_${MM_RELEASE}_windows
- cp -R ./material_maker/environments ./build/${EXPORT_NAME}_${MM_RELEASE}_windows
- cp -R ./material_maker/examples ./build/${EXPORT_NAME}_${MM_RELEASE}_windows
- cp -R ./material_maker/library ./build/${EXPORT_NAME}_${MM_RELEASE}_windows
- cp -R ./material_maker/meshes ./build/${EXPORT_NAME}_${MM_RELEASE}_windows
- cp -R ./material_maker/misc/export ./build/${EXPORT_NAME}_${MM_RELEASE}_windows
- cp -R ./material_maker/doc/_build/html ./build/${EXPORT_NAME}_${MM_RELEASE}_windows/doc || :
- cp -R ./addons/material_maker/nodes ./build/${EXPORT_NAME}_${MM_RELEASE}_linux
- cp -R ./material_maker/environments ./build/${EXPORT_NAME}_${MM_RELEASE}_linux
- cp -R ./material_maker/examples ./build/${EXPORT_NAME}_${MM_RELEASE}_linux
- cp -R ./material_maker/library ./build/${EXPORT_NAME}_${MM_RELEASE}_linux
- cp -R ./material_maker/meshes ./build/${EXPORT_NAME}_${MM_RELEASE}_linux
- cp -R ./material_maker/misc/export ./build/${EXPORT_NAME}_${MM_RELEASE}_linux
- cp -R ./material_maker/doc/_build/html ./build/${EXPORT_NAME}_${MM_RELEASE}_linux/doc || :
- - name: Create archives 📁
- run: |
- cd build
- zip -r ${EXPORT_NAME}_${MM_RELEASE}_windows${PACKAGE_SUFFIX}.zip ${EXPORT_NAME}_${MM_RELEASE}_windows
- tar zcvf ${EXPORT_NAME}_${MM_RELEASE}_linux${PACKAGE_SUFFIX}.tar.gz ${EXPORT_NAME}_${MM_RELEASE}_linux
- - name: Upload Documentation 🚀
- if: ${{ github.event.inputs.gen_doc == 'true' && github.event.inputs.artifacts == 'true' }}
- uses: actions/upload-artifact@v6
- with:
- name: documentation
- path: ./material_maker/doc/_build/html
- - name: Upload Windows Artifact 🚀
- if: ${{ github.event.inputs.steam == 'false' && github.event.inputs.artifacts == 'true' }}
- uses: actions/upload-artifact@v6
- with:
- name: windows_snapshot
- path: build/${{ env.EXPORT_NAME }}_${{ env.MM_RELEASE }}_windows${{ env.PACKAGE_SUFFIX }}.zip
- - name: Upload Windows Artifact (Steam) 🚀
- if: ${{ github.event.inputs.steam == 'true' }}
- uses: actions/upload-artifact@v6
- with:
- name: windows_snapshot
- path: build/${{ env.EXPORT_NAME }}_${{ env.MM_RELEASE }}_windows
- - name: Upload Linux Artifact 🚀
- if: ${{ github.event.inputs.steam == 'false' && github.event.inputs.artifacts == 'true' }}
- uses: actions/upload-artifact@v6
- with:
- name: linux_snapshot
- path: build/${{ env.EXPORT_NAME }}_${{ env.MM_RELEASE }}_linux${{ env.PACKAGE_SUFFIX }}.tar.gz
- - name: Upload Linux Artifact (Steam) 🚀
- if: ${{ github.event.inputs.steam == 'true' }}
- uses: actions/upload-artifact@v6
- with:
- name: linux_snapshot
- path: build/${{ env.EXPORT_NAME }}_${{ env.MM_RELEASE }}_linux
- export_macos:
- name: Mac Export 🍎
- needs: export_windows_linux
- runs-on: macos-26
- steps:
- - name: Checkout 🛎️
- uses: actions/checkout@v1
- with:
- submodules: true
- - name: Setup environment 🔧
- run: |
- cp -f material_maker/theme/default_theme_icons.svg material_maker/theme/default_theme_icons_export.svg
- export GODOT_VERSION=${GODOT_VERSION}
- export EXPORT_NAME=material_maker
- - name: Install the Apple certificate and provisioning profile
- if: ${{ github.event.inputs.sign_macos == 'true' }}
- env:
- BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
- P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
- BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
- KEYCHAIN_PASSWORD: "${{ secrets.KEYCHAIN_PASSWORD }}"
- run: |
- # create variables
- CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
- PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
- KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
+# jobs:
+# export_windows_linux:
+# name: Export Windows and Linux 🗔
+# runs-on: ubuntu-latest
+# steps:
+# - name: Checkout 🛎️
+# uses: actions/checkout@v1
+# with:
+# submodules: true
+# - name: Setup 💻
+# run: |
+# cp -f material_maker/theme/default_theme_icons.svg material_maker/theme/default_theme_icons_export.svg
+# wget -q ${GODOT_DOWNLOAD_DIR}/Godot_v${GODOT_VERSION}-${GODOT_SUB}_linux.x86_64.zip
+# unzip Godot_v${GODOT_VERSION}-${GODOT_SUB}_linux.x86_64.zip
+# wget -q ${GODOT_DOWNLOAD_DIR}/Godot_v${GODOT_VERSION}-${GODOT_SUB}_export_templates.tpz
+# unzip -a Godot_v${GODOT_VERSION}-${GODOT_SUB}_export_templates.tpz
+# mkdir -v -p ~/.local/share/godot/export_templates/${GODOT_VERSION}.${GODOT_SUB}
+# mv ./templates/* ~/.local/share/godot/export_templates/${GODOT_VERSION}.${GODOT_SUB}
+# mkdir -v -p build/${EXPORT_NAME}_${MM_RELEASE}_windows build/${EXPORT_NAME}_${MM_RELEASE}_linux
+# - name: Generate Documentation
+# if: ${{ github.event.inputs.gen_doc == 'true' }}
+# uses: ammaraskar/sphinx-action@master
+# with:
+# docs-folder: "material_maker/doc"
+# - name: Windows Build 🗔
+# run: |
+# ./Godot_v${GODOT_VERSION}-${GODOT_SUB}_linux.x86_64 --headless -v --export-release "Windows${EXPORT_TARGET_SUFFIX}" ./build/${EXPORT_NAME}_${MM_RELEASE}_windows/$EXPORT_NAME.exe
+# - name: Linux Build 🐧
+# run: |
+# ./Godot_v${GODOT_VERSION}-${GODOT_SUB}_linux.x86_64 --headless -v --export-release "Linux/X11${EXPORT_TARGET_SUFFIX}" ./build/${EXPORT_NAME}_${MM_RELEASE}_linux/$EXPORT_NAME.x86_64
+# - name: Copy Material Maker data 📁
+# run: |
+# cp -R ./addons/material_maker/nodes ./build/${EXPORT_NAME}_${MM_RELEASE}_windows
+# cp -R ./material_maker/environments ./build/${EXPORT_NAME}_${MM_RELEASE}_windows
+# cp -R ./material_maker/examples ./build/${EXPORT_NAME}_${MM_RELEASE}_windows
+# cp -R ./material_maker/library ./build/${EXPORT_NAME}_${MM_RELEASE}_windows
+# cp -R ./material_maker/meshes ./build/${EXPORT_NAME}_${MM_RELEASE}_windows
+# cp -R ./material_maker/misc/export ./build/${EXPORT_NAME}_${MM_RELEASE}_windows
+# cp -R ./material_maker/doc/_build/html ./build/${EXPORT_NAME}_${MM_RELEASE}_windows/doc || :
+# cp -R ./addons/material_maker/nodes ./build/${EXPORT_NAME}_${MM_RELEASE}_linux
+# cp -R ./material_maker/environments ./build/${EXPORT_NAME}_${MM_RELEASE}_linux
+# cp -R ./material_maker/examples ./build/${EXPORT_NAME}_${MM_RELEASE}_linux
+# cp -R ./material_maker/library ./build/${EXPORT_NAME}_${MM_RELEASE}_linux
+# cp -R ./material_maker/meshes ./build/${EXPORT_NAME}_${MM_RELEASE}_linux
+# cp -R ./material_maker/misc/export ./build/${EXPORT_NAME}_${MM_RELEASE}_linux
+# cp -R ./material_maker/doc/_build/html ./build/${EXPORT_NAME}_${MM_RELEASE}_linux/doc || :
+# - name: Create archives 📁
+# run: |
+# cd build
+# zip -r ${EXPORT_NAME}_${MM_RELEASE}_windows${PACKAGE_SUFFIX}.zip ${EXPORT_NAME}_${MM_RELEASE}_windows
+# tar zcvf ${EXPORT_NAME}_${MM_RELEASE}_linux${PACKAGE_SUFFIX}.tar.gz ${EXPORT_NAME}_${MM_RELEASE}_linux
+# - name: Upload Documentation 🚀
+# if: ${{ github.event.inputs.gen_doc == 'true' && github.event.inputs.artifacts == 'true' }}
+# uses: actions/upload-artifact@v6
+# with:
+# name: documentation
+# path: ./material_maker/doc/_build/html
+# - name: Upload Windows Artifact 🚀
+# if: ${{ github.event.inputs.steam == 'false' && github.event.inputs.artifacts == 'true' }}
+# uses: actions/upload-artifact@v6
+# with:
+# name: windows_snapshot
+# path: build/${{ env.EXPORT_NAME }}_${{ env.MM_RELEASE }}_windows${{ env.PACKAGE_SUFFIX }}.zip
+# - name: Upload Windows Artifact (Steam) 🚀
+# if: ${{ github.event.inputs.steam == 'true' }}
+# uses: actions/upload-artifact@v6
+# with:
+# name: windows_snapshot
+# path: build/${{ env.EXPORT_NAME }}_${{ env.MM_RELEASE }}_windows
+# - name: Upload Linux Artifact 🚀
+# if: ${{ github.event.inputs.steam == 'false' && github.event.inputs.artifacts == 'true' }}
+# uses: actions/upload-artifact@v6
+# with:
+# name: linux_snapshot
+# path: build/${{ env.EXPORT_NAME }}_${{ env.MM_RELEASE }}_linux${{ env.PACKAGE_SUFFIX }}.tar.gz
+# - name: Upload Linux Artifact (Steam) 🚀
+# if: ${{ github.event.inputs.steam == 'true' }}
+# uses: actions/upload-artifact@v6
+# with:
+# name: linux_snapshot
+# path: build/${{ env.EXPORT_NAME }}_${{ env.MM_RELEASE }}_linux
+# export_macos:
+# name: Mac Export 🍎
+# needs: export_windows_linux
+# runs-on: macos-26
+# steps:
+# - name: Checkout 🛎️
+# uses: actions/checkout@v1
+# with:
+# submodules: true
+# - name: Setup environment 🔧
+# run: |
+# cp -f material_maker/theme/default_theme_icons.svg material_maker/theme/default_theme_icons_export.svg
+# export GODOT_VERSION=${GODOT_VERSION}
+# export EXPORT_NAME=material_maker
+# - name: Install the Apple certificate and provisioning profile
+# if: ${{ github.event.inputs.sign_macos == 'true' }}
+# env:
+# BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
+# P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
+# BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
+# KEYCHAIN_PASSWORD: "${{ secrets.KEYCHAIN_PASSWORD }}"
+# run: |
+# # create variables
+# CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
+# PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
+# KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
- # import certificate and provisioning profile from secrets
- echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode --output $CERTIFICATE_PATH
- echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode --output $PP_PATH
+# # import certificate and provisioning profile from secrets
+# echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode --output $CERTIFICATE_PATH
+# echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode --output $PP_PATH
- # create temporary keychain
- security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
- security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
- security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
+# # create temporary keychain
+# security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
+# security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
+# security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
- # import certificate to keychain
- security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
- security list-keychain -d user -s $KEYCHAIN_PATH
+# # import certificate to keychain
+# security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
+# security list-keychain -d user -s $KEYCHAIN_PATH
- # apply provisioning profile
- mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
- cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
- - name: Download and extract Godot and export templates 💾
- run: |
- wget ${GODOT_DOWNLOAD_DIR}/Godot_v${GODOT_VERSION}-${GODOT_SUB}_macos.universal.zip
- unzip -a Godot_v${GODOT_VERSION}-${GODOT_SUB}_macos.universal.zip
- wget ${GODOT_DOWNLOAD_DIR}/Godot_v${GODOT_VERSION}-${GODOT_SUB}_export_templates.tpz
- unzip -a Godot_v${GODOT_VERSION}-${GODOT_SUB}_export_templates.tpz
- mkdir -v -p "/Users/runner/Library/Application Support/Godot/export_templates/${GODOT_VERSION}.${GODOT_SUB}"
- mv ./templates/* "/Users/runner/Library/Application Support/Godot/export_templates/${GODOT_VERSION}.${GODOT_SUB}"
- - name: Mac Build 🔧
- run: |
- chown runner Godot.app/Contents/MacOS/Godot
- chmod +x Godot.app/Contents/MacOS/Godot
- mkdir -v -p ./build/mac
- Godot.app/Contents/MacOS/Godot --headless -v --export-release "Mac OSX${EXPORT_TARGET_SUFFIX}" ./build/mac/material_maker.zip
- - name: Make application executable 🔧
- run: |
- unzip -a ./build/mac/material_maker.zip -d ./build/mac
- chmod +x "./build/mac/Material Maker.app/Contents/MacOS/Material Maker"
- rm ./build/mac/material_maker.zip
- - name: Get documentation 🚀
- if: ${{ github.event.inputs.gen_doc == 'true' && github.event.inputs.artifacts == 'true' }}
- uses: actions/download-artifact@v8
- with:
- name: documentation
- path: doc
- - name: Copy data folder 📁
- run: |
- cp -R ./addons/material_maker/nodes "./build/mac/Material Maker.app/Contents/MacOS"
- cp -R ./material_maker/environments "./build/mac/Material Maker.app/Contents/MacOS"
- cp -R ./material_maker/examples "./build/mac/Material Maker.app/Contents/MacOS"
- cp -R ./material_maker/library "./build/mac/Material Maker.app/Contents/MacOS"
- cp -R ./material_maker/meshes "./build/mac/Material Maker.app/Contents/MacOS"
- cp -R ./material_maker/misc/export "./build/mac/Material Maker.app/Contents/MacOS"
- cp -R ./doc "./build/mac/Material Maker.app/Contents/MacOS/doc" || :
- - name: Ad-hoc signing ✍️
- if: ${{ github.event.inputs.sign_macos != 'true' }}
- run: |
- codesign -s - --force --deep "./build/mac/Material Maker.app"
- - name: Signing ✍️
- if: ${{ github.event.inputs.sign_macos == 'true' }}
- run: |
- codesign -s "Rodolphe Suescun" --force --timestamp --options runtime --deep "./build/mac/Material Maker.app"
- - name: Create DMG archive 🔧
- if: ${{ github.event.inputs.steam == 'false' }}
- run: |
- brew untap aws/tap || true
- brew install imagemagick
- cp ./.github/workflows/create-dmg-bg.sh .
- chmod +x create-dmg-bg.sh
- ./create-dmg-bg.sh ./splash_screen/backgrounds/pavel_oliva_vintage_luggage.png ./bg.png
- #hdiutil create -srcfolder ./build/mac -fs HFS+ -volname material_maker material_maker_${MM_RELEASE}${PACKAGE_SUFFIX}.dmg
- wget https://github.com/create-dmg/create-dmg/archive/refs/tags/v1.2.2.zip
- unzip v1.2.2.zip
- create-dmg-1.2.2/create-dmg --volname "Material Maker" --icon-size 128 --background ./bg.png --window-size 540 330 --icon "Material Maker.app" 158 125 --app-drop-link 384 125 --hide-extension "Material Maker.app" ./build/mac/material_maker_${MM_RELEASE}${PACKAGE_SUFFIX}.dmg ./build/mac
- ls
- - name: Notarizing ✍️
- if: ${{ github.event.inputs.steam == 'false' && github.event.inputs.sign_macos == 'true' }}
- env:
- APPLE_ID: ${{ secrets.APPLE_ID }}
- NOTARYTOOL_APP_PASSWORD: ${{ secrets.NOTARYTOOL_APP_PASSWORD }}
- APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
- run: |
- xcrun notarytool submit ./build/mac/material_maker_${MM_RELEASE}${PACKAGE_SUFFIX}.dmg --apple-id $APPLE_ID --password $NOTARYTOOL_APP_PASSWORD --team-id $APPLE_TEAM_ID --wait
- xcrun stapler staple -v ./build/mac/material_maker_${MM_RELEASE}${PACKAGE_SUFFIX}.dmg
- - name: Upload Mac OSX Artifact 🚀
- if: ${{ github.event.inputs.steam == 'false' && github.event.inputs.artifacts == 'true' }}
- uses: actions/upload-artifact@v6
- with:
- name: macos_snapshot
- path: ./build/mac/material_maker_${{ env.MM_RELEASE }}${{ env.PACKAGE_SUFFIX }}.dmg
- - name: Upload Mac OSX Artifact (Steam) 🚀
- if: ${{ github.event.inputs.steam == 'true' }}
- uses: actions/upload-artifact@v6
- with:
- name: macos_snapshot
- path: ./build/mac
- deploy_to_steam:
- name: Steam deploy 🎮
- runs-on: ubuntu-latest
- needs: export_macos
- if: ${{ github.event.inputs.steam_deploy == 'true' }}
- steps:
- - name: Get Windows build 🚀
- uses: actions/download-artifact@v8
- with:
- name: windows_snapshot
- path: build/windows
- - name: Get Linux build 🚀
- uses: actions/download-artifact@v8
- with:
- name: linux_snapshot
- path: build/linux
- - name: Get Macos build 🚀
- uses: actions/download-artifact@v8
- with:
- name: macos_snapshot
- path: build/macos
- - name: Prepare packages 🔧
- run: |
- find .
- - uses: game-ci/steam-deploy@v3
- with:
- username: ${{ secrets.STEAM_USERNAME }}
- configVdf: ${{ secrets.STEAM_CONFIG_VDF}}
- appId: 4110830
- buildDescription: v${{ env.MM_RELEASE }}_${{ github.sha }}
- rootPath: build
- depot1Path: windows
- depot2Path: macos
- depot3Path: linux
- releaseBranch: prerelease
+# # apply provisioning profile
+# mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
+# cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
+# - name: Download and extract Godot and export templates 💾
+# run: |
+# wget ${GODOT_DOWNLOAD_DIR}/Godot_v${GODOT_VERSION}-${GODOT_SUB}_macos.arm64.zip
+# unzip -a Godot_v${GODOT_VERSION}-${GODOT_SUB}_macos.arm64.zip
+# wget ${GODOT_DOWNLOAD_DIR}/Godot_v${GODOT_VERSION}-${GODOT_SUB}_export_templates.tpz
+# unzip -a Godot_v${GODOT_VERSION}-${GODOT_SUB}_export_templates.tpz
+# mkdir -v -p "/Users/runner/Library/Application Support/Godot/export_templates/${GODOT_VERSION}.${GODOT_SUB}"
+# mv ./templates/* "/Users/runner/Library/Application Support/Godot/export_templates/${GODOT_VERSION}.${GODOT_SUB}"
+# - name: Mac Build 🔧
+# run: |
+# chown runner Godot.app/Contents/MacOS/Godot
+# chmod +x Godot.app/Contents/MacOS/Godot
+# mkdir -v -p ./build/mac
+# Godot.app/Contents/MacOS/Godot --headless -v --export-release "Mac OSX${EXPORT_TARGET_SUFFIX}" ./build/mac/material_maker.zip
+# - name: Make application executable 🔧
+# run: |
+# unzip -a ./build/mac/material_maker.zip -d ./build/mac
+# chmod +x "./build/mac/Material Maker.app/Contents/MacOS/Material Maker"
+# rm ./build/mac/material_maker.zip
+# - name: Get documentation 🚀
+# if: ${{ github.event.inputs.gen_doc == 'true' && github.event.inputs.artifacts == 'true' }}
+# uses: actions/download-artifact@v8
+# with:
+# name: documentation
+# path: doc
+# - name: Copy data folder 📁
+# run: |
+# cp -R ./addons/material_maker/nodes "./build/mac/Material Maker.app/Contents/MacOS"
+# cp -R ./material_maker/environments "./build/mac/Material Maker.app/Contents/MacOS"
+# cp -R ./material_maker/examples "./build/mac/Material Maker.app/Contents/MacOS"
+# cp -R ./material_maker/library "./build/mac/Material Maker.app/Contents/MacOS"
+# cp -R ./material_maker/meshes "./build/mac/Material Maker.app/Contents/MacOS"
+# cp -R ./material_maker/misc/export "./build/mac/Material Maker.app/Contents/MacOS"
+# cp -R ./doc "./build/mac/Material Maker.app/Contents/MacOS/doc" || :
+# - name: Ad-hoc signing ✍️
+# if: ${{ github.event.inputs.sign_macos != 'true' }}
+# run: |
+# codesign -s - --force --deep "./build/mac/Material Maker.app"
+# - name: Signing ✍️
+# if: ${{ github.event.inputs.sign_macos == 'true' }}
+# run: |
+# codesign -s "Rodolphe Suescun" --force --timestamp --options runtime --deep "./build/mac/Material Maker.app"
+# - name: Create DMG archive 🔧
+# if: ${{ github.event.inputs.steam == 'false' }}
+# run: |
+# brew untap aws/tap || true
+# brew install imagemagick
+# cp ./.github/workflows/create-dmg-bg.sh .
+# chmod +x create-dmg-bg.sh
+# ./create-dmg-bg.sh ./splash_screen/backgrounds/pavel_oliva_vintage_luggage.png ./bg.png
+# #hdiutil create -srcfolder ./build/mac -fs HFS+ -volname material_maker material_maker_${MM_RELEASE}${PACKAGE_SUFFIX}.dmg
+# wget https://github.com/create-dmg/create-dmg/archive/refs/tags/v1.2.2.zip
+# unzip v1.2.2.zip
+# create-dmg-1.2.2/create-dmg --volname "Material Maker" --icon-size 128 --background ./bg.png --window-size 540 330 --icon "Material Maker.app" 158 125 --app-drop-link 384 125 --hide-extension "Material Maker.app" ./build/mac/material_maker_${MM_RELEASE}${PACKAGE_SUFFIX}.dmg ./build/mac
+# ls
+# - name: Notarizing ✍️
+# if: ${{ github.event.inputs.steam == 'false' && github.event.inputs.sign_macos == 'true' }}
+# env:
+# APPLE_ID: ${{ secrets.APPLE_ID }}
+# NOTARYTOOL_APP_PASSWORD: ${{ secrets.NOTARYTOOL_APP_PASSWORD }}
+# APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
+# run: |
+# xcrun notarytool submit ./build/mac/material_maker_${MM_RELEASE}${PACKAGE_SUFFIX}.dmg --apple-id $APPLE_ID --password $NOTARYTOOL_APP_PASSWORD --team-id $APPLE_TEAM_ID --wait
+# xcrun stapler staple -v ./build/mac/material_maker_${MM_RELEASE}${PACKAGE_SUFFIX}.dmg
+# - name: Upload Mac OSX Artifact 🚀
+# if: ${{ github.event.inputs.steam == 'false' && github.event.inputs.artifacts == 'true' }}
+# uses: actions/upload-artifact@v6
+# with:
+# name: macos_snapshot
+# path: ./build/mac/material_maker_${{ env.MM_RELEASE }}${{ env.PACKAGE_SUFFIX }}.dmg
+# - name: Upload Mac OSX Artifact (Steam) 🚀
+# if: ${{ github.event.inputs.steam == 'true' }}
+# uses: actions/upload-artifact@v6
+# with:
+# name: macos_snapshot
+# path: ./build/mac
+
+# deploy_to_steam:
+# name: Steam deploy 🎮
+# runs-on: ubuntu-latest
+# needs: export_macos
+# if: ${{ github.event.inputs.steam_deploy == 'true' }}
+# steps:
+# - name: Get Windows build 🚀
+# uses: actions/download-artifact@v8
+# with:
+# name: windows_snapshot
+# path: build/windows
+# - name: Get Linux build 🚀
+# uses: actions/download-artifact@v8
+# with:
+# name: linux_snapshot
+# path: build/linux
+# - name: Get Macos build 🚀
+# uses: actions/download-artifact@v8
+# with:
+# name: macos_snapshot
+# path: build/macos
+# - name: Prepare packages 🔧
+# run: |
+# find .
+# - uses: game-ci/steam-deploy@v3
+# with:
+# username: ${{ secrets.STEAM_USERNAME }}
+# configVdf: ${{ secrets.STEAM_CONFIG_VDF}}
+# appId: 4110830
+# buildDescription: v1.7
+# rootPath: build
+# depot1Path: windows
+# depot2Path: macos
+# depot3Path: linux
+# releaseBranch: prerelease
diff --git a/addons/flexible_layout/flexible_dragger.gd b/addons/flexible_layout/flexible_dragger.gd
index 1c53f2ba2a..314fed500a 100644
--- a/addons/flexible_layout/flexible_dragger.gd
+++ b/addons/flexible_layout/flexible_dragger.gd
@@ -5,12 +5,24 @@ var dragging : bool = false
var flex_split : WeakRef
var dragger_index : int
var vertical : bool
+var half_grip_size : int
+
+var touch_dragger : TouchDragger
func _init():
set_meta("flexlayout", true)
+func _ready() -> void:
+ if mm_globals.get_config("touch_optimization"):
+ touch_dragger = TouchDragger.new()
+ touch_dragger.name = "TouchDragger"
+ add_child(touch_dragger)
+ mouse_entered.disconnect($TextureRect.show)
+ mouse_exited.disconnect($TextureRect.hide)
+
func set_split(s, i : int, v : bool):
flex_split = weakref(s)
+ half_grip_size = flex_split.get_ref().grip_size * 0.5
dragger_index = i
vertical = v
if vertical:
@@ -20,10 +32,14 @@ func set_split(s, i : int, v : bool):
mouse_default_cursor_shape = Control.CURSOR_HSPLIT
$TextureRect.texture = get_theme_icon("grabber", "HSplitContainer")
+ if mm_globals.get_config("touch_optimization"):
+ touch_dragger.setup()
+ mouse_filter = Control.MOUSE_FILTER_IGNORE
+
var drag_limits : Vector2i
var drag_position : int
-func _on_gui_input(event):
+func _on_gui_input(event : InputEvent, is_touch_dragger_input : bool = false):
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
dragging = event.pressed
@@ -34,15 +50,30 @@ func _on_gui_input(event):
drag_limits = flex_split.get_ref().start_flexlayout_drag(dragger_index, drag_position)
elif event is InputEventMouseMotion:
if dragging:
+ accept_event()
if vertical:
- drag_position = position.y+event.position.y-5
+ drag_position = position.y+event.position.y - half_grip_size
+
+ if is_touch_dragger_input:
+ drag_position -= touch_dragger.get_drag_offset()
+
var new_position_y = clampi(drag_position, drag_limits.x, drag_limits.y)
if position.y != new_position_y:
position.y = new_position_y
flex_split.get_ref().drag(dragger_index, position.y)
+
+ if is_touch_dragger_input:
+ touch_dragger.update_position(new_position_y)
else:
- drag_position = position.x+event.position.x-5
+ drag_position = position.x+event.position.x - half_grip_size
+
+ if is_touch_dragger_input:
+ drag_position -= touch_dragger.get_drag_offset()
+
var new_position_x = clampi(drag_position, drag_limits.x, drag_limits.y)
if position.x != new_position_x:
position.x = new_position_x
flex_split.get_ref().drag(dragger_index, position.x)
+
+ if is_touch_dragger_input:
+ touch_dragger.update_position(new_position_x)
diff --git a/addons/flexible_layout/flexible_dragger.tscn b/addons/flexible_layout/flexible_dragger.tscn
index deef46f076..e2016a3abf 100644
--- a/addons/flexible_layout/flexible_dragger.tscn
+++ b/addons/flexible_layout/flexible_dragger.tscn
@@ -1,18 +1,16 @@
-[gd_scene load_steps=2 format=3 uid="uid://cucx3oayvvxhu"]
+[gd_scene format=3 uid="uid://cucx3oayvvxhu"]
-[ext_resource type="Script" path="res://addons/flexible_layout/flexible_dragger.gd" id="1_3i5mx"]
+[ext_resource type="Script" uid="uid://dgwcni3ebvc8s" path="res://addons/flexible_layout/flexible_dragger.gd" id="1_3i5mx"]
-[node name="Dragger" type="HBoxContainer"]
-anchors_preset = 8
+[node name="Dragger" type="HBoxContainer" unique_id=1107978390]
+anchors_preset = -1
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
-grow_horizontal = 2
-grow_vertical = 2
script = ExtResource("1_3i5mx")
-[node name="TextureRect" type="TextureRect" parent="."]
+[node name="TextureRect" type="TextureRect" parent="." unique_id=1116440276]
visible = false
layout_mode = 2
size_flags_horizontal = 6
diff --git a/addons/flexible_layout/flexible_dragger_touch.gd b/addons/flexible_layout/flexible_dragger_touch.gd
new file mode 100644
index 0000000000..c2f63226f8
--- /dev/null
+++ b/addons/flexible_layout/flexible_dragger_touch.gd
@@ -0,0 +1,94 @@
+class_name TouchDragger
+extends Control
+
+var is_pressed : bool = false
+
+static var sb_normal : StyleBoxFlat
+static var sb_pressed : StyleBoxFlat
+
+func _ready() -> void:
+ set_notify_transform(true)
+ gui_input.connect(get_parent()._on_gui_input.bind(true))
+
+ mouse_filter = Control.MOUSE_FILTER_STOP
+ size_flags_horizontal = Control.SIZE_SHRINK_CENTER
+ size_flags_vertical = Control.SIZE_SHRINK_CENTER
+ top_level = true
+
+ init_styleboxes()
+
+func _draw() -> void:
+ if sb_pressed and sb_normal:
+ draw_style_box(sb_pressed if is_pressed else sb_normal, Rect2(Vector2.ZERO, size))
+
+func _gui_input(event : InputEvent) -> void:
+ if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
+ is_pressed = event.pressed
+ queue_redraw()
+
+func _notification(what : int) -> void:
+ match what:
+ NOTIFICATION_THEME_CHANGED:
+ update_theme_colors()
+ NOTIFICATION_TRANSFORM_CHANGED:
+ update_dragger_global_pos()
+
+func update_stylebox_colors(base_color : Color, border : Color,
+ normal_opacity : float, pressed_opacity : float) -> void:
+ sb_normal.bg_color = base_color
+ sb_normal.bg_color.a = normal_opacity
+ sb_normal.border_color = border
+
+ sb_pressed.bg_color = base_color
+ sb_pressed.bg_color.a = pressed_opacity
+ sb_pressed.border_color = border
+
+func init_styleboxes() -> void:
+ if not sb_normal:
+ sb_normal = StyleBoxFlat.new()
+ sb_normal.set_border_width_all(2)
+ sb_normal.set_corner_radius_all(5)
+ sb_normal.border_blend = true
+ sb_normal.corner_detail = 4
+
+ if not sb_pressed:
+ sb_pressed = sb_normal.duplicate(true)
+
+func setup() -> void:
+ show()
+ if get_parent().vertical:
+ mouse_default_cursor_shape = Control.CURSOR_VSPLIT
+ custom_minimum_size = Vector2(52, 16)
+ else:
+ mouse_default_cursor_shape = Control.CURSOR_HSPLIT
+ custom_minimum_size = Vector2(16, 52)
+ update_theme_colors()
+ update_dragger_global_pos.call_deferred()
+
+func update_dragger_global_pos() -> void:
+ global_position = get_parent().global_position + (get_parent().size - size) * 0.5
+
+func update_position(v : float) -> void:
+ if get_parent().vertical:
+ position.y = v
+ else:
+ position.x = v
+ queue_redraw()
+
+func get_drag_offset() -> int:
+ return mini(custom_minimum_size.x, custom_minimum_size.y) / 2
+
+func update_theme_colors() -> void:
+ if not sb_normal or not sb_pressed:
+ init_styleboxes()
+ match ThemeUtils.current_theme:
+ ThemeUtils.CUSTOM_THEME:
+ update_stylebox_colors(ThemeUtils.base_color.lightened(0.3),
+ ThemeUtils.base_color.darkened(0.2), 0.25, 0.8)
+ ThemeUtils.DARK_THEME:
+ update_stylebox_colors(Color.WHITE, Color.BLACK, 0.25, 0.8)
+ ThemeUtils.LIGHT_THEME:
+ update_stylebox_colors(Color.BLACK, Color.WHITE, 0.6, 0.25)
+ ThemeUtils.CLASSIC_THEME:
+ update_stylebox_colors(Color("506396ff"), Color("768ac2ff"), .25, .8)
+ queue_redraw()
diff --git a/addons/flexible_layout/flexible_dragger_touch.gd.uid b/addons/flexible_layout/flexible_dragger_touch.gd.uid
new file mode 100644
index 0000000000..65e38f5042
--- /dev/null
+++ b/addons/flexible_layout/flexible_dragger_touch.gd.uid
@@ -0,0 +1 @@
+uid://dgeyah0cwww2p
diff --git a/addons/flexible_layout/flexible_layout.gd b/addons/flexible_layout/flexible_layout.gd
index 1b6a85e2bc..7ce37adc88 100644
--- a/addons/flexible_layout/flexible_layout.gd
+++ b/addons/flexible_layout/flexible_layout.gd
@@ -109,7 +109,8 @@ class FlexSplit:
var draggers : Array[Control] = []
const DRAGGER_SCENE = preload("res://addons/flexible_layout/flexible_dragger.tscn")
-
+ var grip_size : int = 4 if mm_globals.get_config("touch_optimization") else 10
+
func _init(p : FlexNode, fl : FlexLayout):
super._init(p, fl, "FlexSplit")
@@ -122,13 +123,13 @@ class FlexSplit:
func get_minimum_size() -> Vector2i:
var s : Vector2i
if vertical:
- s = Vector2i(0, (10*children.size()-1))
+ s = Vector2i(0, (grip_size*children.size()-1))
for c in children:
var ms : Vector2i = c.get_minimum_size()
s.x = max(s.x, ms.x)
s.y += ms.y
else:
- s = Vector2i(10*(children.size()-1), 0)
+ s = Vector2i(grip_size*(children.size()-1), 0)
for c in children:
var ms : Vector2i = c.get_minimum_size()
s.x += ms.x
@@ -185,7 +186,6 @@ class FlexSplit:
func layout(r : Rect2):
#print("Layout FlexSplit (%d children) - %s" % [ children.size(), str(r) ])
- var grip_size : int = 10
rect = r
var children_count : int = children.size()
var draggers_count : int = draggers.size()
@@ -240,19 +240,19 @@ class FlexSplit:
var min_c1_size : Vector2i = c1.get_minimum_size()
var min_c2_size : Vector2i = c2.get_minimum_size()
if vertical:
- return Vector2i(c1.rect.position.y+min_c1_size.y, c2.rect.position.y+c2.rect.size.y-min_c2_size.y-10)
+ return Vector2i(c1.rect.position.y+min_c1_size.y, c2.rect.position.y+c2.rect.size.y-min_c2_size.y-grip_size)
else:
- return Vector2i(c1.rect.position.x+min_c1_size.x, c2.rect.position.x+c2.rect.size.x-min_c2_size.x-10)
+ return Vector2i(c1.rect.position.x+min_c1_size.x, c2.rect.position.x+c2.rect.size.x-min_c2_size.x-grip_size)
func drag(dragger_index : int, p : int):
var c1 = children[dragger_index]
var c2 = children[dragger_index+1]
if vertical:
c1.layout(Rect2(c1.rect.position, Vector2(c1.rect.size.x, p-c1.rect.position.y)))
- c2.layout(Rect2(c2.rect.position.x, p+10, c1.rect.size.x, c2.rect.position.y+c2.rect.size.y-(p+10)))
+ c2.layout(Rect2(c2.rect.position.x, p+grip_size, c1.rect.size.x, c2.rect.position.y+c2.rect.size.y-(p+grip_size)))
else:
c1.layout(Rect2(c1.rect.position, Vector2(p-c1.rect.position.x, c1.rect.size.y)))
- c2.layout(Rect2(p+10, c2.rect.position.y, c2.rect.position.x+c2.rect.size.x-(p+10), c1.rect.size.y))
+ c2.layout(Rect2(p+grip_size, c2.rect.position.y, c2.rect.position.x+c2.rect.size.x-(p+grip_size), c1.rect.size.y))
class FlexTab:
diff --git a/addons/flexible_layout/flexible_tab.gd b/addons/flexible_layout/flexible_tab.gd
index ff7390b371..c69e155848 100644
--- a/addons/flexible_layout/flexible_tab.gd
+++ b/addons/flexible_layout/flexible_tab.gd
@@ -24,13 +24,17 @@ func get_flex_layout():
func update():
%Close.texture_normal = get_theme_icon("close", "MM_FlexibleTab")
%Close.modulate = get_theme_color("font_selected_color", "MM_FlexibleTab")
- %Undock.texture_normal = get_theme_icon("undock", "MM_FlexibleTab")
- %Undock.modulate = get_theme_color("font_selected_color", "MM_FlexibleTab")
+
+ if not OS.get_name() == "Android":
+ %Undock.texture_normal = get_theme_icon("undock", "MM_FlexibleTab")
+ %Undock.modulate = get_theme_color("font_selected_color", "MM_FlexibleTab")
+
if not updating:
updating = true
var is_current: bool = (get_index() == get_parent().get_parent().current)
add_theme_stylebox_override("panel", get_theme_stylebox("tab_selected" if is_current else "tab_unselected", "MM_FlexibleTab"))
- %Undock.visible = is_current and get_flex_layout().main_control.allow_undock
+ if not OS.get_name() == "Android":
+ %Undock.visible = is_current and get_flex_layout().main_control.allow_undock
%Close.visible = is_current
%Label.add_theme_color_override("font_color", get_theme_color("font_selected_color" if is_current else "font_unselected_color", "MM_FlexibleTab") )
updating = false
diff --git a/addons/godotsteam/godotsteam.gdextension b/addons/godotsteam/godotsteam.gdextension
index ee29ceb7ac..c649b9996b 100644
--- a/addons/godotsteam/godotsteam.gdextension
+++ b/addons/godotsteam/godotsteam.gdextension
@@ -14,9 +14,14 @@ linux.debug.x86_32 = "res://addons/godotsteam/linux32/libgodotsteam.linux.templa
linux.release.x86_64 = "res://addons/godotsteam/linux64/libgodotsteam.linux.template_release.x86_64.so"
linux.release.x86_32 = "res://addons/godotsteam/linux32/libgodotsteam.linux.template_release.x86_32.so"
+ios.debug.arm64 = { }
+ios.release.arm64 = { }
+
[dependencies]
macos.universal = { "res://addons/godotsteam/osx/libsteam_api.dylib": "" }
windows.x86_64 = { "res://addons/godotsteam/win64/steam_api64.dll": "" }
windows.x86_32 = { "res://addons/godotsteam/win32/steam_api.dll": "" }
linux.x86_64 = { "res://addons/godotsteam/linux64/libsteam_api.so": "" }
linux.x86_32 = { "res://addons/godotsteam/linux32/libsteam_api.so": "" }
+
+ios.arm64 = { }
diff --git a/addons/material_maker/engine/nodes/gen_sdf.gd b/addons/material_maker/engine/nodes/gen_sdf.gd
index b9e25eb7f6..c8521462c1 100644
--- a/addons/material_maker/engine/nodes/gen_sdf.gd
+++ b/addons/material_maker/engine/nodes/gen_sdf.gd
@@ -188,8 +188,8 @@ func _deserialize(data : Dictionary) -> void:
func edit(node, tab : String = "") -> void:
if scene != null:
- var edit_window = load("res://material_maker/windows/sdf_builder/sdf_builder.tscn").instantiate()
- node.get_parent().add_child(edit_window)
+ var edit_window : Window = load("res://material_maker/windows/sdf_builder/sdf_builder.tscn").instantiate()
+ mm_globals.main_window.add_dialog(edit_window)
edit_window.set_node_parameter_defs(node_parameters)
edit_window.set_sdf_scene(scene)
edit_window.connect("node_changed", Callable(node, "update_sdf_generator"))
diff --git a/addons/material_maker/engine/nodes/gen_shader.gd b/addons/material_maker/engine/nodes/gen_shader.gd
index 7363eda319..ecd9152605 100644
--- a/addons/material_maker/engine/nodes/gen_shader.gd
+++ b/addons/material_maker/engine/nodes/gen_shader.gd
@@ -822,8 +822,13 @@ func do_edit(node, edit_window_scene : PackedScene, tab : String = "") -> void:
edit_window.title = "%s - %s" % [material, edit_window.title]
edit_window.get_window().content_scale_factor = mm_globals.ui_scale_factor()
edit_window.get_window().min_size = Vector2(950, 450) * edit_window.get_window().content_scale_factor
- edit_window.hide()
- edit_window.popup_centered()
+
+ if OS.get_name() == "Android":
+ mm_touch.make_dialog_fullscreen.call_deferred(edit_window, true)
+ else:
+ edit_window.hide()
+ edit_window.popup_centered()
+
if tab != "":
edit_window.show_tab(tab)
diff --git a/addons/material_maker/engine/paths.gd b/addons/material_maker/engine/paths.gd
index 855334c391..b3be1473d5 100644
--- a/addons/material_maker/engine/paths.gd
+++ b/addons/material_maker/engine/paths.gd
@@ -6,9 +6,13 @@ const WEBSITE_ADDRESS : String = "https://www.materialmaker.org"
const STD_GENDEF_PATH = "res://addons/material_maker/nodes"
+const DOC_ADDRESS : String = "https://rodzill4.github.io/material-maker/doc"
+
static func get_resource_dir() -> String:
if Engine.is_editor_hint():
return ProjectSettings.globalize_path("res://material_maker")
+ if OS.get_name() == "Android":
+ return "user:/"
return OS.get_executable_path().get_base_dir()
static func get_nodes_paths() -> Array:
diff --git a/export_presets.cfg b/export_presets.cfg
index 686352a3a5..d7769ebc85 100644
--- a/export_presets.cfg
+++ b/export_presets.cfg
@@ -1,14 +1,21 @@
+[runnable_presets]
+
+"Windows Desktop"="Windows"
+Linux="Linux/X11"
+macOS="Mac OSX"
+Android="Android"
+Web="Web"
+
[preset.0]
name="Windows"
platform="Windows Desktop"
-runnable=true
dedicated_server=false
custom_features=""
export_filter="exclude"
export_files=PackedStringArray("res://addons/godotsteam/godotsteam.gdextension", "res://addons/gut/cli/change_project_warnings.gd", "res://addons/gut/cli/gut_cli.gd", "res://addons/gut/cli/optparse.gd", "res://addons/gut/fonts/AnonymousPro-Bold.ttf", "res://addons/gut/fonts/AnonymousPro-BoldItalic.ttf", "res://addons/gut/fonts/AnonymousPro-Italic.ttf", "res://addons/gut/fonts/AnonymousPro-Regular.ttf", "res://addons/gut/fonts/CourierPrime-Bold.ttf", "res://addons/gut/fonts/CourierPrime-BoldItalic.ttf", "res://addons/gut/fonts/CourierPrime-Italic.ttf", "res://addons/gut/fonts/CourierPrime-Regular.ttf", "res://addons/gut/fonts/LobsterTwo-Bold.ttf", "res://addons/gut/fonts/LobsterTwo-BoldItalic.ttf", "res://addons/gut/fonts/LobsterTwo-Italic.ttf", "res://addons/gut/fonts/LobsterTwo-Regular.ttf", "res://addons/gut/gui/about.gd", "res://addons/gut/gui/about.tscn", "res://addons/gut/gui/arrow.png", "res://addons/gut/gui/EditorRadioButton.tres", "res://addons/gut/gui/editor_globals.gd", "res://addons/gut/gui/GutBottomPanel.gd", "res://addons/gut/gui/GutBottomPanel.tscn", "res://addons/gut/gui/GutControl.gd", "res://addons/gut/gui/GutControl.tscn", "res://addons/gut/gui/GutEditorWindow.gd", "res://addons/gut/gui/GutEditorWindow.tscn", "res://addons/gut/gui/GutLogo.tscn", "res://addons/gut/gui/GutRunner.gd", "res://addons/gut/gui/GutRunner.tscn", "res://addons/gut/gui/GutSceneTheme.tres", "res://addons/gut/gui/gut_config_gui.gd", "res://addons/gut/gui/gut_gui.gd", "res://addons/gut/gui/gut_logo.gd", "res://addons/gut/gui/gut_user_preferences.gd", "res://addons/gut/gui/MinGui.tscn", "res://addons/gut/gui/NormalGui.tscn", "res://addons/gut/gui/option_maker.gd", "res://addons/gut/gui/OutputText.gd", "res://addons/gut/gui/OutputText.tscn", "res://addons/gut/gui/panel_controls.gd", "res://addons/gut/gui/play.png", "res://addons/gut/gui/ResizeHandle.gd", "res://addons/gut/gui/ResizeHandle.tscn", "res://addons/gut/gui/ResultsTree.gd", "res://addons/gut/gui/ResultsTree.tscn", "res://addons/gut/gui/RunAtCursor.gd", "res://addons/gut/gui/RunAtCursor.tscn", "res://addons/gut/gui/RunExternally.gd", "res://addons/gut/gui/RunExternally.tscn", "res://addons/gut/gui/RunResults.gd", "res://addons/gut/gui/RunResults.tscn", "res://addons/gut/gui/run_from_editor.gd", "res://addons/gut/gui/run_from_editor.tscn", "res://addons/gut/gui/Settings.tscn", "res://addons/gut/gui/ShellOutOptions.gd", "res://addons/gut/gui/ShellOutOptions.tscn", "res://addons/gut/gui/ShortcutButton.gd", "res://addons/gut/gui/ShortcutButton.tscn", "res://addons/gut/gui/ShortcutDialog.gd", "res://addons/gut/gui/ShortcutDialog.tscn", "res://addons/gut/images/eyey.png", "res://addons/gut/images/Folder.svg", "res://addons/gut/images/green.png", "res://addons/gut/images/GutIconV2_base.png", "res://addons/gut/images/GutIconV2_no_shine.png", "res://addons/gut/images/HSplitContainer.svg", "res://addons/gut/images/red.png", "res://addons/gut/images/Script.svg", "res://addons/gut/images/VSplitContainer.svg", "res://addons/gut/images/yellow.png", "res://addons/gut/autofree.gd", "res://addons/gut/awaiter.gd", "res://addons/gut/collected_script.gd", "res://addons/gut/collected_test.gd", "res://addons/gut/comparator.gd", "res://addons/gut/compare_result.gd", "res://addons/gut/diff_formatter.gd", "res://addons/gut/diff_tool.gd", "res://addons/gut/doubler.gd", "res://addons/gut/double_tools.gd", "res://addons/gut/dynamic_gdscript.gd", "res://addons/gut/editor_caret_context_notifier.gd", "res://addons/gut/error_tracker.gd", "res://addons/gut/get_editor_interface.gd", "res://addons/gut/gut.gd", "res://addons/gut/GutScene.gd", "res://addons/gut/GutScene.tscn", "res://addons/gut/gut_cmdln.gd", "res://addons/gut/gut_config.gd", "res://addons/gut/gut_fonts.gd", "res://addons/gut/gut_loader.gd", "res://addons/gut/gut_loader_the_scene.tscn", "res://addons/gut/gut_menu.gd", "res://addons/gut/gut_plugin.gd", "res://addons/gut/gut_to_move.gd", "res://addons/gut/gut_tracked_error.gd", "res://addons/gut/gut_vscode_debugger.gd", "res://addons/gut/hook_script.gd", "res://addons/gut/icon.png", "res://addons/gut/inner_class_registry.gd", "res://addons/gut/input_factory.gd", "res://addons/gut/input_sender.gd", "res://addons/gut/junit_xml_export.gd", "res://addons/gut/lazy_loader.gd", "res://addons/gut/logger.gd", "res://addons/gut/method_maker.gd", "res://addons/gut/one_to_many.gd", "res://addons/gut/orphan_counter.gd", "res://addons/gut/parameter_factory.gd", "res://addons/gut/parameter_handler.gd", "res://addons/gut/printers.gd", "res://addons/gut/result_exporter.gd", "res://addons/gut/script_parser.gd", "res://addons/gut/signal_watcher.gd", "res://addons/gut/source_code_pro.fnt", "res://addons/gut/spy.gd", "res://addons/gut/strutils.gd", "res://addons/gut/stubber.gd", "res://addons/gut/stub_params.gd", "res://addons/gut/summary.gd", "res://addons/gut/test.gd", "res://addons/gut/test_collector.gd", "res://addons/gut/thing_counter.gd", "res://addons/gut/UserFileViewer.gd", "res://addons/gut/UserFileViewer.tscn", "res://addons/gut/utils.gd", "res://addons/gut/version_conversion.gd", "res://addons/gut/version_numbers.gd", "res://addons/gut/warnings_manager.gd", "res://demo/demo.tscn", "res://demo/object.tscn")
include_filter="*.tmpl"
-exclude_filter="*.ptex,*.mmn,*.mmg"
+exclude_filter="*.ptex,*.mmn,*.mmg, no_export/*"
export_path="../../rodz_labs/releases/mm_1_5/material_maker_1_5_windows/material_maker.exe"
patches=PackedStringArray()
patch_delta_encoding=false
@@ -79,13 +86,12 @@ texture_format/etc2=true
name="Linux/X11"
platform="Linux"
-runnable=true
dedicated_server=false
custom_features=""
export_filter="exclude"
export_files=PackedStringArray("res://addons/godotsteam/godotsteam.gdextension", "res://addons/gut/cli/change_project_warnings.gd", "res://addons/gut/cli/gut_cli.gd", "res://addons/gut/cli/optparse.gd", "res://addons/gut/fonts/AnonymousPro-Bold.ttf", "res://addons/gut/fonts/AnonymousPro-BoldItalic.ttf", "res://addons/gut/fonts/AnonymousPro-Italic.ttf", "res://addons/gut/fonts/AnonymousPro-Regular.ttf", "res://addons/gut/fonts/CourierPrime-Bold.ttf", "res://addons/gut/fonts/CourierPrime-BoldItalic.ttf", "res://addons/gut/fonts/CourierPrime-Italic.ttf", "res://addons/gut/fonts/CourierPrime-Regular.ttf", "res://addons/gut/fonts/LobsterTwo-Bold.ttf", "res://addons/gut/fonts/LobsterTwo-BoldItalic.ttf", "res://addons/gut/fonts/LobsterTwo-Italic.ttf", "res://addons/gut/fonts/LobsterTwo-Regular.ttf", "res://addons/gut/gui/about.gd", "res://addons/gut/gui/about.tscn", "res://addons/gut/gui/arrow.png", "res://addons/gut/gui/EditorRadioButton.tres", "res://addons/gut/gui/editor_globals.gd", "res://addons/gut/gui/GutBottomPanel.gd", "res://addons/gut/gui/GutBottomPanel.tscn", "res://addons/gut/gui/GutControl.gd", "res://addons/gut/gui/GutControl.tscn", "res://addons/gut/gui/GutEditorWindow.gd", "res://addons/gut/gui/GutEditorWindow.tscn", "res://addons/gut/gui/GutLogo.tscn", "res://addons/gut/gui/GutRunner.gd", "res://addons/gut/gui/GutRunner.tscn", "res://addons/gut/gui/GutSceneTheme.tres", "res://addons/gut/gui/gut_config_gui.gd", "res://addons/gut/gui/gut_gui.gd", "res://addons/gut/gui/gut_logo.gd", "res://addons/gut/gui/gut_user_preferences.gd", "res://addons/gut/gui/MinGui.tscn", "res://addons/gut/gui/NormalGui.tscn", "res://addons/gut/gui/option_maker.gd", "res://addons/gut/gui/OutputText.gd", "res://addons/gut/gui/OutputText.tscn", "res://addons/gut/gui/panel_controls.gd", "res://addons/gut/gui/play.png", "res://addons/gut/gui/ResizeHandle.gd", "res://addons/gut/gui/ResizeHandle.tscn", "res://addons/gut/gui/ResultsTree.gd", "res://addons/gut/gui/ResultsTree.tscn", "res://addons/gut/gui/RunAtCursor.gd", "res://addons/gut/gui/RunAtCursor.tscn", "res://addons/gut/gui/RunExternally.gd", "res://addons/gut/gui/RunExternally.tscn", "res://addons/gut/gui/RunResults.gd", "res://addons/gut/gui/RunResults.tscn", "res://addons/gut/gui/run_from_editor.gd", "res://addons/gut/gui/run_from_editor.tscn", "res://addons/gut/gui/Settings.tscn", "res://addons/gut/gui/ShellOutOptions.gd", "res://addons/gut/gui/ShellOutOptions.tscn", "res://addons/gut/gui/ShortcutButton.gd", "res://addons/gut/gui/ShortcutButton.tscn", "res://addons/gut/gui/ShortcutDialog.gd", "res://addons/gut/gui/ShortcutDialog.tscn", "res://addons/gut/images/eyey.png", "res://addons/gut/images/Folder.svg", "res://addons/gut/images/green.png", "res://addons/gut/images/GutIconV2_base.png", "res://addons/gut/images/GutIconV2_no_shine.png", "res://addons/gut/images/HSplitContainer.svg", "res://addons/gut/images/red.png", "res://addons/gut/images/Script.svg", "res://addons/gut/images/VSplitContainer.svg", "res://addons/gut/images/yellow.png", "res://addons/gut/autofree.gd", "res://addons/gut/awaiter.gd", "res://addons/gut/collected_script.gd", "res://addons/gut/collected_test.gd", "res://addons/gut/comparator.gd", "res://addons/gut/compare_result.gd", "res://addons/gut/diff_formatter.gd", "res://addons/gut/diff_tool.gd", "res://addons/gut/doubler.gd", "res://addons/gut/double_tools.gd", "res://addons/gut/dynamic_gdscript.gd", "res://addons/gut/editor_caret_context_notifier.gd", "res://addons/gut/error_tracker.gd", "res://addons/gut/get_editor_interface.gd", "res://addons/gut/gut.gd", "res://addons/gut/GutScene.gd", "res://addons/gut/GutScene.tscn", "res://addons/gut/gut_cmdln.gd", "res://addons/gut/gut_config.gd", "res://addons/gut/gut_fonts.gd", "res://addons/gut/gut_loader.gd", "res://addons/gut/gut_loader_the_scene.tscn", "res://addons/gut/gut_menu.gd", "res://addons/gut/gut_plugin.gd", "res://addons/gut/gut_to_move.gd", "res://addons/gut/gut_tracked_error.gd", "res://addons/gut/gut_vscode_debugger.gd", "res://addons/gut/hook_script.gd", "res://addons/gut/icon.png", "res://addons/gut/inner_class_registry.gd", "res://addons/gut/input_factory.gd", "res://addons/gut/input_sender.gd", "res://addons/gut/junit_xml_export.gd", "res://addons/gut/lazy_loader.gd", "res://addons/gut/logger.gd", "res://addons/gut/method_maker.gd", "res://addons/gut/one_to_many.gd", "res://addons/gut/orphan_counter.gd", "res://addons/gut/parameter_factory.gd", "res://addons/gut/parameter_handler.gd", "res://addons/gut/printers.gd", "res://addons/gut/result_exporter.gd", "res://addons/gut/script_parser.gd", "res://addons/gut/signal_watcher.gd", "res://addons/gut/source_code_pro.fnt", "res://addons/gut/spy.gd", "res://addons/gut/strutils.gd", "res://addons/gut/stubber.gd", "res://addons/gut/stub_params.gd", "res://addons/gut/summary.gd", "res://addons/gut/test.gd", "res://addons/gut/test_collector.gd", "res://addons/gut/thing_counter.gd", "res://addons/gut/UserFileViewer.gd", "res://addons/gut/UserFileViewer.tscn", "res://addons/gut/utils.gd", "res://addons/gut/version_conversion.gd", "res://addons/gut/version_numbers.gd", "res://addons/gut/warnings_manager.gd", "res://demo/demo.tscn", "res://demo/object.tscn")
include_filter="*.tmpl"
-exclude_filter="*.ptex,*.mmn,*.mmg"
+exclude_filter="*.ptex,*.mmn,*.mmg, no_export/*"
export_path="../material_maker.x86_64"
patches=PackedStringArray()
patch_delta_encoding=false
@@ -131,13 +137,12 @@ texture_format/etc2=false
name="Mac OSX"
platform="macOS"
-runnable=true
dedicated_server=false
custom_features=""
export_filter="exclude"
export_files=PackedStringArray("res://addons/godotsteam/godotsteam.gdextension", "res://addons/gut/cli/change_project_warnings.gd", "res://addons/gut/cli/gut_cli.gd", "res://addons/gut/cli/optparse.gd", "res://addons/gut/fonts/AnonymousPro-Bold.ttf", "res://addons/gut/fonts/AnonymousPro-BoldItalic.ttf", "res://addons/gut/fonts/AnonymousPro-Italic.ttf", "res://addons/gut/fonts/AnonymousPro-Regular.ttf", "res://addons/gut/fonts/CourierPrime-Bold.ttf", "res://addons/gut/fonts/CourierPrime-BoldItalic.ttf", "res://addons/gut/fonts/CourierPrime-Italic.ttf", "res://addons/gut/fonts/CourierPrime-Regular.ttf", "res://addons/gut/fonts/LobsterTwo-Bold.ttf", "res://addons/gut/fonts/LobsterTwo-BoldItalic.ttf", "res://addons/gut/fonts/LobsterTwo-Italic.ttf", "res://addons/gut/fonts/LobsterTwo-Regular.ttf", "res://addons/gut/gui/about.gd", "res://addons/gut/gui/about.tscn", "res://addons/gut/gui/arrow.png", "res://addons/gut/gui/EditorRadioButton.tres", "res://addons/gut/gui/editor_globals.gd", "res://addons/gut/gui/GutBottomPanel.gd", "res://addons/gut/gui/GutBottomPanel.tscn", "res://addons/gut/gui/GutControl.gd", "res://addons/gut/gui/GutControl.tscn", "res://addons/gut/gui/GutEditorWindow.gd", "res://addons/gut/gui/GutEditorWindow.tscn", "res://addons/gut/gui/GutLogo.tscn", "res://addons/gut/gui/GutRunner.gd", "res://addons/gut/gui/GutRunner.tscn", "res://addons/gut/gui/GutSceneTheme.tres", "res://addons/gut/gui/gut_config_gui.gd", "res://addons/gut/gui/gut_gui.gd", "res://addons/gut/gui/gut_logo.gd", "res://addons/gut/gui/gut_user_preferences.gd", "res://addons/gut/gui/MinGui.tscn", "res://addons/gut/gui/NormalGui.tscn", "res://addons/gut/gui/option_maker.gd", "res://addons/gut/gui/OutputText.gd", "res://addons/gut/gui/OutputText.tscn", "res://addons/gut/gui/panel_controls.gd", "res://addons/gut/gui/play.png", "res://addons/gut/gui/ResizeHandle.gd", "res://addons/gut/gui/ResizeHandle.tscn", "res://addons/gut/gui/ResultsTree.gd", "res://addons/gut/gui/ResultsTree.tscn", "res://addons/gut/gui/RunAtCursor.gd", "res://addons/gut/gui/RunAtCursor.tscn", "res://addons/gut/gui/RunExternally.gd", "res://addons/gut/gui/RunExternally.tscn", "res://addons/gut/gui/RunResults.gd", "res://addons/gut/gui/RunResults.tscn", "res://addons/gut/gui/run_from_editor.gd", "res://addons/gut/gui/run_from_editor.tscn", "res://addons/gut/gui/Settings.tscn", "res://addons/gut/gui/ShellOutOptions.gd", "res://addons/gut/gui/ShellOutOptions.tscn", "res://addons/gut/gui/ShortcutButton.gd", "res://addons/gut/gui/ShortcutButton.tscn", "res://addons/gut/gui/ShortcutDialog.gd", "res://addons/gut/gui/ShortcutDialog.tscn", "res://addons/gut/images/eyey.png", "res://addons/gut/images/Folder.svg", "res://addons/gut/images/green.png", "res://addons/gut/images/GutIconV2_base.png", "res://addons/gut/images/GutIconV2_no_shine.png", "res://addons/gut/images/HSplitContainer.svg", "res://addons/gut/images/red.png", "res://addons/gut/images/Script.svg", "res://addons/gut/images/VSplitContainer.svg", "res://addons/gut/images/yellow.png", "res://addons/gut/autofree.gd", "res://addons/gut/awaiter.gd", "res://addons/gut/collected_script.gd", "res://addons/gut/collected_test.gd", "res://addons/gut/comparator.gd", "res://addons/gut/compare_result.gd", "res://addons/gut/diff_formatter.gd", "res://addons/gut/diff_tool.gd", "res://addons/gut/doubler.gd", "res://addons/gut/double_tools.gd", "res://addons/gut/dynamic_gdscript.gd", "res://addons/gut/editor_caret_context_notifier.gd", "res://addons/gut/error_tracker.gd", "res://addons/gut/get_editor_interface.gd", "res://addons/gut/gut.gd", "res://addons/gut/GutScene.gd", "res://addons/gut/GutScene.tscn", "res://addons/gut/gut_cmdln.gd", "res://addons/gut/gut_config.gd", "res://addons/gut/gut_fonts.gd", "res://addons/gut/gut_loader.gd", "res://addons/gut/gut_loader_the_scene.tscn", "res://addons/gut/gut_menu.gd", "res://addons/gut/gut_plugin.gd", "res://addons/gut/gut_to_move.gd", "res://addons/gut/gut_tracked_error.gd", "res://addons/gut/gut_vscode_debugger.gd", "res://addons/gut/hook_script.gd", "res://addons/gut/icon.png", "res://addons/gut/inner_class_registry.gd", "res://addons/gut/input_factory.gd", "res://addons/gut/input_sender.gd", "res://addons/gut/junit_xml_export.gd", "res://addons/gut/lazy_loader.gd", "res://addons/gut/logger.gd", "res://addons/gut/method_maker.gd", "res://addons/gut/one_to_many.gd", "res://addons/gut/orphan_counter.gd", "res://addons/gut/parameter_factory.gd", "res://addons/gut/parameter_handler.gd", "res://addons/gut/printers.gd", "res://addons/gut/result_exporter.gd", "res://addons/gut/script_parser.gd", "res://addons/gut/signal_watcher.gd", "res://addons/gut/source_code_pro.fnt", "res://addons/gut/spy.gd", "res://addons/gut/strutils.gd", "res://addons/gut/stubber.gd", "res://addons/gut/stub_params.gd", "res://addons/gut/summary.gd", "res://addons/gut/test.gd", "res://addons/gut/test_collector.gd", "res://addons/gut/thing_counter.gd", "res://addons/gut/UserFileViewer.gd", "res://addons/gut/UserFileViewer.tscn", "res://addons/gut/utils.gd", "res://addons/gut/version_conversion.gd", "res://addons/gut/version_numbers.gd", "res://addons/gut/warnings_manager.gd", "res://demo/demo.tscn", "res://demo/object.tscn")
include_filter="*.tmpl"
-exclude_filter="*.ptex,*.mmn,*.mmg"
+exclude_filter="*.ptex,*.mmn,*.mmg, no_export/*"
export_path="../material_maker_macosx.dmg.zip"
patches=PackedStringArray()
patch_delta_encoding=false
@@ -397,7 +402,6 @@ application/min_macos_version="10.12"
name="Windows Steam"
platform="Windows Desktop"
-runnable=false
dedicated_server=false
custom_features=""
export_filter="exclude"
@@ -474,13 +478,12 @@ texture_format/etc2=true
name="Linux/X11 Steam"
platform="Linux"
-runnable=false
dedicated_server=false
custom_features=""
export_filter="exclude"
export_files=PackedStringArray("res://addons/gut/cli/change_project_warnings.gd", "res://addons/gut/cli/gut_cli.gd", "res://addons/gut/cli/optparse.gd", "res://addons/gut/fonts/AnonymousPro-Bold.ttf", "res://addons/gut/fonts/AnonymousPro-BoldItalic.ttf", "res://addons/gut/fonts/AnonymousPro-Italic.ttf", "res://addons/gut/fonts/AnonymousPro-Regular.ttf", "res://addons/gut/fonts/CourierPrime-Bold.ttf", "res://addons/gut/fonts/CourierPrime-BoldItalic.ttf", "res://addons/gut/fonts/CourierPrime-Italic.ttf", "res://addons/gut/fonts/CourierPrime-Regular.ttf", "res://addons/gut/fonts/LobsterTwo-Bold.ttf", "res://addons/gut/fonts/LobsterTwo-BoldItalic.ttf", "res://addons/gut/fonts/LobsterTwo-Italic.ttf", "res://addons/gut/fonts/LobsterTwo-Regular.ttf", "res://addons/gut/gui/about.gd", "res://addons/gut/gui/about.tscn", "res://addons/gut/gui/arrow.png", "res://addons/gut/gui/EditorRadioButton.tres", "res://addons/gut/gui/editor_globals.gd", "res://addons/gut/gui/GutBottomPanel.gd", "res://addons/gut/gui/GutBottomPanel.tscn", "res://addons/gut/gui/GutControl.gd", "res://addons/gut/gui/GutControl.tscn", "res://addons/gut/gui/GutEditorWindow.gd", "res://addons/gut/gui/GutEditorWindow.tscn", "res://addons/gut/gui/GutLogo.tscn", "res://addons/gut/gui/GutRunner.gd", "res://addons/gut/gui/GutRunner.tscn", "res://addons/gut/gui/GutSceneTheme.tres", "res://addons/gut/gui/gut_config_gui.gd", "res://addons/gut/gui/gut_gui.gd", "res://addons/gut/gui/gut_logo.gd", "res://addons/gut/gui/gut_user_preferences.gd", "res://addons/gut/gui/MinGui.tscn", "res://addons/gut/gui/NormalGui.tscn", "res://addons/gut/gui/option_maker.gd", "res://addons/gut/gui/OutputText.gd", "res://addons/gut/gui/OutputText.tscn", "res://addons/gut/gui/panel_controls.gd", "res://addons/gut/gui/play.png", "res://addons/gut/gui/ResizeHandle.gd", "res://addons/gut/gui/ResizeHandle.tscn", "res://addons/gut/gui/ResultsTree.gd", "res://addons/gut/gui/ResultsTree.tscn", "res://addons/gut/gui/RunAtCursor.gd", "res://addons/gut/gui/RunAtCursor.tscn", "res://addons/gut/gui/RunExternally.gd", "res://addons/gut/gui/RunExternally.tscn", "res://addons/gut/gui/RunResults.gd", "res://addons/gut/gui/RunResults.tscn", "res://addons/gut/gui/run_from_editor.gd", "res://addons/gut/gui/run_from_editor.tscn", "res://addons/gut/gui/Settings.tscn", "res://addons/gut/gui/ShellOutOptions.gd", "res://addons/gut/gui/ShellOutOptions.tscn", "res://addons/gut/gui/ShortcutButton.gd", "res://addons/gut/gui/ShortcutButton.tscn", "res://addons/gut/gui/ShortcutDialog.gd", "res://addons/gut/gui/ShortcutDialog.tscn", "res://addons/gut/images/eyey.png", "res://addons/gut/images/Folder.svg", "res://addons/gut/images/green.png", "res://addons/gut/images/GutIconV2_base.png", "res://addons/gut/images/GutIconV2_no_shine.png", "res://addons/gut/images/HSplitContainer.svg", "res://addons/gut/images/red.png", "res://addons/gut/images/Script.svg", "res://addons/gut/images/VSplitContainer.svg", "res://addons/gut/images/yellow.png", "res://addons/gut/autofree.gd", "res://addons/gut/awaiter.gd", "res://addons/gut/collected_script.gd", "res://addons/gut/collected_test.gd", "res://addons/gut/comparator.gd", "res://addons/gut/compare_result.gd", "res://addons/gut/diff_formatter.gd", "res://addons/gut/diff_tool.gd", "res://addons/gut/doubler.gd", "res://addons/gut/double_tools.gd", "res://addons/gut/dynamic_gdscript.gd", "res://addons/gut/editor_caret_context_notifier.gd", "res://addons/gut/error_tracker.gd", "res://addons/gut/get_editor_interface.gd", "res://addons/gut/gut.gd", "res://addons/gut/GutScene.gd", "res://addons/gut/GutScene.tscn", "res://addons/gut/gut_cmdln.gd", "res://addons/gut/gut_config.gd", "res://addons/gut/gut_fonts.gd", "res://addons/gut/gut_loader.gd", "res://addons/gut/gut_loader_the_scene.tscn", "res://addons/gut/gut_menu.gd", "res://addons/gut/gut_plugin.gd", "res://addons/gut/gut_to_move.gd", "res://addons/gut/gut_tracked_error.gd", "res://addons/gut/gut_vscode_debugger.gd", "res://addons/gut/hook_script.gd", "res://addons/gut/icon.png", "res://addons/gut/inner_class_registry.gd", "res://addons/gut/input_factory.gd", "res://addons/gut/input_sender.gd", "res://addons/gut/junit_xml_export.gd", "res://addons/gut/lazy_loader.gd", "res://addons/gut/logger.gd", "res://addons/gut/method_maker.gd", "res://addons/gut/one_to_many.gd", "res://addons/gut/orphan_counter.gd", "res://addons/gut/parameter_factory.gd", "res://addons/gut/parameter_handler.gd", "res://addons/gut/printers.gd", "res://addons/gut/result_exporter.gd", "res://addons/gut/script_parser.gd", "res://addons/gut/signal_watcher.gd", "res://addons/gut/source_code_pro.fnt", "res://addons/gut/spy.gd", "res://addons/gut/strutils.gd", "res://addons/gut/stubber.gd", "res://addons/gut/stub_params.gd", "res://addons/gut/summary.gd", "res://addons/gut/test.gd", "res://addons/gut/test_collector.gd", "res://addons/gut/thing_counter.gd", "res://addons/gut/UserFileViewer.gd", "res://addons/gut/UserFileViewer.tscn", "res://addons/gut/utils.gd", "res://addons/gut/version_conversion.gd", "res://addons/gut/version_numbers.gd", "res://addons/gut/warnings_manager.gd", "res://demo/demo.tscn", "res://demo/object.tscn")
include_filter="*.tmpl"
-exclude_filter="*.ptex,*.mmn,*.mmg"
+exclude_filter="*.ptex,*.mmn,*.mmg, no_export/*"
export_path=""
patches=PackedStringArray()
patch_delta_encoding=false
@@ -526,7 +529,6 @@ texture_format/etc2=false
name="Mac OSX Steam"
platform="macOS"
-runnable=false
dedicated_server=false
custom_features=""
export_filter="exclude"
@@ -792,7 +794,6 @@ application/min_macos_version="10.12"
name="Windows Demo"
platform="Windows Desktop"
-runnable=false
dedicated_server=false
custom_features=""
export_filter="resources"
@@ -869,13 +870,13 @@ texture_format/etc2=true
name="Android"
platform="Android"
-runnable=true
dedicated_server=false
custom_features=""
-export_filter="all_resources"
-include_filter="*.json,*.mmg,*.mmt,addons/material_maker/nodes/*,material_maker/library/*.json"
-exclude_filter=""
-export_path="./material_maker.apk"
+export_filter="exclude"
+export_files=PackedStringArray("res://addons/godotsteam/godotsteam.gdextension", "res://addons/gut/cli/change_project_warnings.gd", "res://addons/gut/cli/gut_cli.gd", "res://addons/gut/cli/optparse.gd", "res://addons/gut/fonts/AnonymousPro-Bold.ttf", "res://addons/gut/fonts/AnonymousPro-BoldItalic.ttf", "res://addons/gut/fonts/AnonymousPro-Italic.ttf", "res://addons/gut/fonts/AnonymousPro-Regular.ttf", "res://addons/gut/fonts/CourierPrime-Bold.ttf", "res://addons/gut/fonts/CourierPrime-BoldItalic.ttf", "res://addons/gut/fonts/CourierPrime-Italic.ttf", "res://addons/gut/fonts/CourierPrime-Regular.ttf", "res://addons/gut/fonts/LobsterTwo-Bold.ttf", "res://addons/gut/fonts/LobsterTwo-BoldItalic.ttf", "res://addons/gut/fonts/LobsterTwo-Italic.ttf", "res://addons/gut/fonts/LobsterTwo-Regular.ttf", "res://addons/gut/gui/about.gd", "res://addons/gut/gui/about.tscn", "res://addons/gut/gui/arrow.png", "res://addons/gut/gui/EditorRadioButton.tres", "res://addons/gut/gui/editor_globals.gd", "res://addons/gut/gui/GutBottomPanel.gd", "res://addons/gut/gui/GutBottomPanel.tscn", "res://addons/gut/gui/GutControl.gd", "res://addons/gut/gui/GutControl.tscn", "res://addons/gut/gui/GutEditorWindow.gd", "res://addons/gut/gui/GutEditorWindow.tscn", "res://demo/object.tscn", "res://addons/gut/gui/GutRunner.gd", "res://addons/gut/gui/GutRunner.tscn", "res://addons/gut/gui/GutSceneTheme.tres", "res://addons/gut/gui/gut_config_gui.gd", "res://addons/gut/gui/gut_gui.gd", "res://addons/gut/gui/gut_logo.gd", "res://addons/gut/gui/gut_user_preferences.gd", "res://addons/gut/gui/MinGui.tscn", "res://addons/gut/gui/NormalGui.tscn", "res://addons/gut/gui/option_maker.gd", "res://addons/gut/gui/OutputText.gd", "res://addons/gut/gui/OutputText.tscn", "res://addons/gut/gui/panel_controls.gd", "res://addons/gut/gui/play.png", "res://addons/gut/gui/ResizeHandle.gd", "res://addons/gut/gui/ResizeHandle.tscn", "res://addons/gut/gui/ResultsTree.gd", "res://addons/gut/gui/ResultsTree.tscn", "res://addons/gut/gui/RunAtCursor.gd", "res://addons/gut/gui/RunAtCursor.tscn", "res://addons/gut/gui/RunExternally.gd", "res://addons/gut/gui/RunExternally.tscn", "res://addons/gut/gui/RunResults.gd", "res://addons/gut/gui/RunResults.tscn", "res://addons/gut/gui/run_from_editor.gd", "res://addons/gut/gui/run_from_editor.tscn", "res://addons/gut/gui/Settings.tscn", "res://addons/gut/gui/ShellOutOptions.gd", "res://addons/gut/gui/ShellOutOptions.tscn", "res://addons/gut/gui/ShortcutButton.gd", "res://addons/gut/gui/ShortcutButton.tscn", "res://addons/gut/gui/ShortcutDialog.gd", "res://addons/gut/gui/ShortcutDialog.tscn", "res://addons/gut/images/eyey.png", "res://addons/gut/images/Folder.svg", "res://addons/gut/images/green.png", "res://addons/gut/images/GutIconV2_base.png", "res://addons/gut/images/GutIconV2_no_shine.png", "res://addons/gut/images/HSplitContainer.svg", "res://addons/gut/images/red.png", "res://addons/gut/images/Script.svg", "res://addons/gut/images/VSplitContainer.svg", "res://addons/gut/images/yellow.png", "res://addons/gut/autofree.gd", "res://addons/gut/awaiter.gd", "res://addons/gut/collected_script.gd", "res://addons/gut/collected_test.gd", "res://addons/gut/comparator.gd", "res://addons/gut/compare_result.gd", "res://addons/gut/diff_formatter.gd", "res://addons/gut/diff_tool.gd", "res://addons/gut/doubler.gd", "res://addons/gut/double_tools.gd", "res://addons/gut/dynamic_gdscript.gd", "res://addons/gut/editor_caret_context_notifier.gd", "res://addons/gut/error_tracker.gd", "res://addons/gut/get_editor_interface.gd", "res://addons/gut/gut.gd", "res://addons/gut/GutScene.gd", "res://addons/gut/GutScene.tscn", "res://addons/gut/gut_cmdln.gd", "res://addons/gut/gut_config.gd", "res://addons/gut/gut_fonts.gd", "res://addons/gut/gut_loader.gd", "res://addons/gut/gut_loader_the_scene.tscn", "res://addons/gut/gut_menu.gd", "res://addons/gut/gut_plugin.gd", "res://addons/gut/gut_to_move.gd", "res://addons/gut/gut_tracked_error.gd", "res://addons/gut/gut_vscode_debugger.gd", "res://addons/gut/hook_script.gd", "res://addons/gut/icon.png", "res://addons/gut/inner_class_registry.gd", "res://addons/gut/input_factory.gd", "res://addons/gut/input_sender.gd", "res://addons/gut/junit_xml_export.gd", "res://addons/gut/lazy_loader.gd", "res://addons/gut/logger.gd", "res://addons/gut/method_maker.gd", "res://addons/gut/one_to_many.gd", "res://addons/gut/orphan_counter.gd", "res://addons/gut/parameter_factory.gd", "res://addons/gut/parameter_handler.gd", "res://addons/gut/printers.gd", "res://addons/gut/result_exporter.gd", "res://addons/gut/script_parser.gd", "res://addons/gut/signal_watcher.gd", "res://addons/gut/source_code_pro.fnt", "res://addons/gut/spy.gd", "res://addons/gut/strutils.gd", "res://addons/gut/stubber.gd", "res://addons/gut/stub_params.gd", "res://addons/gut/summary.gd", "res://addons/gut/test.gd", "res://addons/gut/test_collector.gd", "res://addons/gut/thing_counter.gd", "res://addons/gut/UserFileViewer.gd", "res://addons/gut/UserFileViewer.tscn", "res://addons/gut/utils.gd", "res://addons/gut/version_conversion.gd", "res://addons/gut/version_numbers.gd", "res://addons/gut/warnings_manager.gd", "res://demo/demo.tscn", "res://test/test_doc_completion.gd", "res://addons/gut/gui/GutLogo.tscn", "res://material_maker/theme/test_graphedit.tscn", "res://material_maker/locale/generate_po_template.gd", "res://material_maker/panels/preview_3d/meshes/bricks.tres", "res://material_maker/panels/preview_3d/meshes/bricks_albedo.png", "res://material_maker/panels/preview_3d/meshes/bricks_normal.png", "res://material_maker/panels/preview_3d/meshes/bricks_orm.png", "res://material_maker/panels/preview_3d/meshes/bricks_heightmap.png", "res://scripts/fixup.gd", "res://addons/flexible_layout/test.tscn", "res://addons/flexible_layout/test.gd", "res://addons/material_maker/map_generator/test.gd", "res://addons/material_maker/map_generator/test.tscn", "res://start.gd", "res://start.tscn", "res://addons/material_maker/import_plugin/ptex_import.gd", "res://addons/material_maker/import_plugin/ptex_spatial_material.gd", "res://addons/material_maker/import_plugin/tesselated.gdshader", "res://material_maker/theme/optimize_theme.gd")
+include_filter="*.json,*.mmg,*.mmt,addons/material_maker/nodes/*,material_maker/library/*.json,material_maker/examples/*.ptex"
+exclude_filter="no_export/*"
+export_path="../../../../../Downloads/material-maker.apk"
patches=PackedStringArray()
patch_delta_encoding=false
patch_delta_compression_level_zstd=19
@@ -901,25 +902,25 @@ gradle_build/export_format=0
gradle_build/min_sdk=""
gradle_build/target_sdk=""
gradle_build/custom_theme_attributes={}
-architectures/armeabi-v7a=true
+architectures/armeabi-v7a=false
architectures/arm64-v8a=true
architectures/x86=false
-architectures/x86_64=false
-version/code=2
-version/name="1.5"
+architectures/x86_64=true
+version/code=1
+version/name="1.7"
package/unique_name="org.rodzlabs.materialmaker"
-package/name=""
+package/name="Material Maker"
package/signed=true
-package/app_category=2
+package/app_category=3
package/retain_data_on_uninstall=false
package/exclude_from_recents=false
package/show_in_android_tv=false
package/show_in_app_library=true
package/show_as_launcher_app=false
-launcher_icons/main_192x192=""
-launcher_icons/adaptive_foreground_432x432=""
-launcher_icons/adaptive_background_432x432=""
-launcher_icons/adaptive_monochrome_432x432=""
+launcher_icons/main_192x192="res://no_export/android/android_legacy_icon.webp"
+launcher_icons/adaptive_foreground_432x432="res://no_export/android/adaptive_foreground.svg"
+launcher_icons/adaptive_background_432x432="res://no_export/android/adaptive_background.svg"
+launcher_icons/adaptive_monochrome_432x432="res://no_export/android/adaptive_monochrome.svg"
graphics/opengl_debug=false
shader_baker/enabled=false
xr_features/xr_mode=0
@@ -931,11 +932,12 @@ screen/support_normal=true
screen/support_large=true
screen/support_xlarge=true
screen/background_color=Color(0, 0, 0, 1)
+splash_screen/disable_godot_boot_splash=true
+splash_screen/icon=""
+splash_screen/branding_image=""
+splash_screen/background_color=Color(0, 0, 0, 1)
user_data_backup/allow=false
command_line/extra_args=""
-apk_expansion/enable=false
-apk_expansion/SALT=""
-apk_expansion/public_key=""
permissions/custom_permissions=PackedStringArray()
permissions/access_checkin_properties=false
permissions/access_coarse_location=false
@@ -1010,7 +1012,7 @@ permissions/location_hardware=false
permissions/manage_accounts=false
permissions/manage_app_tokens=false
permissions/manage_documents=false
-permissions/manage_external_storage=false
+permissions/manage_external_storage=true
permissions/manage_media=false
permissions/master_clear=false
permissions/media_content_control=false
@@ -1025,7 +1027,7 @@ permissions/process_outgoing_calls=false
permissions/read_calendar=false
permissions/read_call_log=false
permissions/read_contacts=false
-permissions/read_external_storage=true
+permissions/read_external_storage=false
permissions/read_frame_buffer=false
permissions/read_history_bookmarks=false
permissions/read_input_state=false
@@ -1080,7 +1082,7 @@ permissions/write_apn_settings=false
permissions/write_calendar=false
permissions/write_call_log=false
permissions/write_contacts=false
-permissions/write_external_storage=true
+permissions/write_external_storage=false
permissions/write_gservices=false
permissions/write_history_bookmarks=false
permissions/write_profile=false
@@ -1090,15 +1092,244 @@ permissions/write_sms=false
permissions/write_social_stream=false
permissions/write_sync_settings=false
permissions/write_user_dictionary=false
+apk_expansion/enable=false
+apk_expansion/SALT=""
+apk_expansion/public_key=""
xr_features/hand_tracking=0
xr_features/hand_tracking_frequency=0
xr_features/passthrough=0
[preset.8]
+name="Android AAB"
+platform="Android"
+dedicated_server=false
+custom_features=""
+export_filter="exclude"
+export_files=PackedStringArray("res://addons/godotsteam/godotsteam.gdextension", "res://addons/gut/cli/change_project_warnings.gd", "res://addons/gut/cli/gut_cli.gd", "res://addons/gut/cli/optparse.gd", "res://addons/gut/fonts/AnonymousPro-Bold.ttf", "res://addons/gut/fonts/AnonymousPro-BoldItalic.ttf", "res://addons/gut/fonts/AnonymousPro-Italic.ttf", "res://addons/gut/fonts/AnonymousPro-Regular.ttf", "res://addons/gut/fonts/CourierPrime-Bold.ttf", "res://addons/gut/fonts/CourierPrime-BoldItalic.ttf", "res://addons/gut/fonts/CourierPrime-Italic.ttf", "res://addons/gut/fonts/CourierPrime-Regular.ttf", "res://addons/gut/fonts/LobsterTwo-Bold.ttf", "res://addons/gut/fonts/LobsterTwo-BoldItalic.ttf", "res://addons/gut/fonts/LobsterTwo-Italic.ttf", "res://addons/gut/fonts/LobsterTwo-Regular.ttf", "res://addons/gut/gui/about.gd", "res://addons/gut/gui/about.tscn", "res://addons/gut/gui/arrow.png", "res://addons/gut/gui/EditorRadioButton.tres", "res://addons/gut/gui/editor_globals.gd", "res://addons/gut/gui/GutBottomPanel.gd", "res://addons/gut/gui/GutBottomPanel.tscn", "res://addons/gut/gui/GutControl.gd", "res://addons/gut/gui/GutControl.tscn", "res://addons/gut/gui/GutEditorWindow.gd", "res://addons/gut/gui/GutEditorWindow.tscn", "res://demo/object.tscn", "res://addons/gut/gui/GutRunner.gd", "res://addons/gut/gui/GutRunner.tscn", "res://addons/gut/gui/GutSceneTheme.tres", "res://addons/gut/gui/gut_config_gui.gd", "res://addons/gut/gui/gut_gui.gd", "res://addons/gut/gui/gut_logo.gd", "res://addons/gut/gui/gut_user_preferences.gd", "res://addons/gut/gui/MinGui.tscn", "res://addons/gut/gui/NormalGui.tscn", "res://addons/gut/gui/option_maker.gd", "res://addons/gut/gui/OutputText.gd", "res://addons/gut/gui/OutputText.tscn", "res://addons/gut/gui/panel_controls.gd", "res://addons/gut/gui/play.png", "res://addons/gut/gui/ResizeHandle.gd", "res://addons/gut/gui/ResizeHandle.tscn", "res://addons/gut/gui/ResultsTree.gd", "res://addons/gut/gui/ResultsTree.tscn", "res://addons/gut/gui/RunAtCursor.gd", "res://addons/gut/gui/RunAtCursor.tscn", "res://addons/gut/gui/RunExternally.gd", "res://addons/gut/gui/RunExternally.tscn", "res://addons/gut/gui/RunResults.gd", "res://addons/gut/gui/RunResults.tscn", "res://addons/gut/gui/run_from_editor.gd", "res://addons/gut/gui/run_from_editor.tscn", "res://addons/gut/gui/Settings.tscn", "res://addons/gut/gui/ShellOutOptions.gd", "res://addons/gut/gui/ShellOutOptions.tscn", "res://addons/gut/gui/ShortcutButton.gd", "res://addons/gut/gui/ShortcutButton.tscn", "res://addons/gut/gui/ShortcutDialog.gd", "res://addons/gut/gui/ShortcutDialog.tscn", "res://addons/gut/images/eyey.png", "res://addons/gut/images/Folder.svg", "res://addons/gut/images/green.png", "res://addons/gut/images/GutIconV2_base.png", "res://addons/gut/images/GutIconV2_no_shine.png", "res://addons/gut/images/HSplitContainer.svg", "res://addons/gut/images/red.png", "res://addons/gut/images/Script.svg", "res://addons/gut/images/VSplitContainer.svg", "res://addons/gut/images/yellow.png", "res://addons/gut/autofree.gd", "res://addons/gut/awaiter.gd", "res://addons/gut/collected_script.gd", "res://addons/gut/collected_test.gd", "res://addons/gut/comparator.gd", "res://addons/gut/compare_result.gd", "res://addons/gut/diff_formatter.gd", "res://addons/gut/diff_tool.gd", "res://addons/gut/doubler.gd", "res://addons/gut/double_tools.gd", "res://addons/gut/dynamic_gdscript.gd", "res://addons/gut/editor_caret_context_notifier.gd", "res://addons/gut/error_tracker.gd", "res://addons/gut/get_editor_interface.gd", "res://addons/gut/gut.gd", "res://addons/gut/GutScene.gd", "res://addons/gut/GutScene.tscn", "res://addons/gut/gut_cmdln.gd", "res://addons/gut/gut_config.gd", "res://addons/gut/gut_fonts.gd", "res://addons/gut/gut_loader.gd", "res://addons/gut/gut_loader_the_scene.tscn", "res://addons/gut/gut_menu.gd", "res://addons/gut/gut_plugin.gd", "res://addons/gut/gut_to_move.gd", "res://addons/gut/gut_tracked_error.gd", "res://addons/gut/gut_vscode_debugger.gd", "res://addons/gut/hook_script.gd", "res://addons/gut/icon.png", "res://addons/gut/inner_class_registry.gd", "res://addons/gut/input_factory.gd", "res://addons/gut/input_sender.gd", "res://addons/gut/junit_xml_export.gd", "res://addons/gut/lazy_loader.gd", "res://addons/gut/logger.gd", "res://addons/gut/method_maker.gd", "res://addons/gut/one_to_many.gd", "res://addons/gut/orphan_counter.gd", "res://addons/gut/parameter_factory.gd", "res://addons/gut/parameter_handler.gd", "res://addons/gut/printers.gd", "res://addons/gut/result_exporter.gd", "res://addons/gut/script_parser.gd", "res://addons/gut/signal_watcher.gd", "res://addons/gut/source_code_pro.fnt", "res://addons/gut/spy.gd", "res://addons/gut/strutils.gd", "res://addons/gut/stubber.gd", "res://addons/gut/stub_params.gd", "res://addons/gut/summary.gd", "res://addons/gut/test.gd", "res://addons/gut/test_collector.gd", "res://addons/gut/thing_counter.gd", "res://addons/gut/UserFileViewer.gd", "res://addons/gut/UserFileViewer.tscn", "res://addons/gut/utils.gd", "res://addons/gut/version_conversion.gd", "res://addons/gut/version_numbers.gd", "res://addons/gut/warnings_manager.gd", "res://demo/demo.tscn", "res://test/test_doc_completion.gd", "res://addons/gut/gui/GutLogo.tscn", "res://material_maker/theme/test_graphedit.tscn", "res://material_maker/locale/generate_po_template.gd", "res://material_maker/panels/preview_3d/meshes/bricks.tres", "res://material_maker/panels/preview_3d/meshes/bricks_albedo.png", "res://material_maker/panels/preview_3d/meshes/bricks_normal.png", "res://material_maker/panels/preview_3d/meshes/bricks_orm.png", "res://material_maker/panels/preview_3d/meshes/bricks_heightmap.png", "res://scripts/fixup.gd", "res://addons/flexible_layout/test.tscn", "res://addons/flexible_layout/test.gd", "res://addons/material_maker/map_generator/test.gd", "res://addons/material_maker/map_generator/test.tscn", "res://start.gd", "res://start.tscn", "res://addons/material_maker/import_plugin/ptex_import.gd", "res://addons/material_maker/import_plugin/ptex_spatial_material.gd", "res://addons/material_maker/import_plugin/tesselated.gdshader", "res://material_maker/theme/optimize_theme.gd")
+include_filter="*.json,*.mmg,*.mmt,addons/material_maker/nodes/*,material_maker/library/*.json,material_maker/examples/*.ptex"
+exclude_filter="no_export/*"
+export_path="./material-maker.aab"
+patches=PackedStringArray()
+patch_delta_encoding=false
+patch_delta_compression_level_zstd=19
+patch_delta_min_reduction=0.1
+patch_delta_include_filters="*"
+patch_delta_exclude_filters=""
+encryption_include_filters=""
+encryption_exclude_filters=""
+seed=0
+encrypt_pck=false
+encrypt_directory=false
+script_export_mode=2
+
+[preset.8.options]
+
+custom_template/debug=""
+custom_template/release=""
+gradle_build/use_gradle_build=true
+gradle_build/gradle_build_directory=""
+gradle_build/android_source_template=""
+gradle_build/compress_native_libraries=false
+gradle_build/export_format=1
+gradle_build/min_sdk=""
+gradle_build/target_sdk=""
+gradle_build/custom_theme_attributes={}
+architectures/armeabi-v7a=false
+architectures/arm64-v8a=true
+architectures/x86=false
+architectures/x86_64=true
+version/code=1
+version/name="1.7"
+package/unique_name="org.rodzlabs.materialmaker"
+package/name="Material Maker"
+package/signed=true
+package/app_category=3
+package/retain_data_on_uninstall=false
+package/exclude_from_recents=false
+package/show_in_android_tv=false
+package/show_in_app_library=true
+package/show_as_launcher_app=false
+launcher_icons/main_192x192="res://no_export/android/android_legacy_icon.webp"
+launcher_icons/adaptive_foreground_432x432="res://no_export/android/adaptive_foreground.svg"
+launcher_icons/adaptive_background_432x432="res://no_export/android/adaptive_background.svg"
+launcher_icons/adaptive_monochrome_432x432="res://no_export/android/adaptive_monochrome.svg"
+graphics/opengl_debug=false
+shader_baker/enabled=false
+xr_features/xr_mode=0
+gesture/swipe_to_dismiss=false
+screen/immersive_mode=true
+screen/edge_to_edge=false
+screen/support_small=true
+screen/support_normal=true
+screen/support_large=true
+screen/support_xlarge=true
+screen/background_color=Color(0, 0, 0, 1)
+splash_screen/disable_godot_boot_splash=true
+splash_screen/icon=""
+splash_screen/branding_image=""
+splash_screen/background_color=Color(0, 0, 0, 1)
+user_data_backup/allow=false
+command_line/extra_args=""
+permissions/custom_permissions=PackedStringArray()
+permissions/access_checkin_properties=false
+permissions/access_coarse_location=false
+permissions/access_fine_location=false
+permissions/access_location_extra_commands=false
+permissions/access_media_location=false
+permissions/access_mock_location=false
+permissions/access_network_state=false
+permissions/access_surface_flinger=false
+permissions/access_wifi_state=false
+permissions/account_manager=false
+permissions/add_voicemail=false
+permissions/authenticate_accounts=false
+permissions/battery_stats=false
+permissions/bind_accessibility_service=false
+permissions/bind_appwidget=false
+permissions/bind_device_admin=false
+permissions/bind_input_method=false
+permissions/bind_nfc_service=false
+permissions/bind_notification_listener_service=false
+permissions/bind_print_service=false
+permissions/bind_remoteviews=false
+permissions/bind_text_service=false
+permissions/bind_vpn_service=false
+permissions/bind_wallpaper=false
+permissions/bluetooth=false
+permissions/bluetooth_admin=false
+permissions/bluetooth_privileged=false
+permissions/brick=false
+permissions/broadcast_package_removed=false
+permissions/broadcast_sms=false
+permissions/broadcast_sticky=false
+permissions/broadcast_wap_push=false
+permissions/call_phone=false
+permissions/call_privileged=false
+permissions/camera=false
+permissions/capture_audio_output=false
+permissions/capture_secure_video_output=false
+permissions/capture_video_output=false
+permissions/change_component_enabled_state=false
+permissions/change_configuration=false
+permissions/change_network_state=false
+permissions/change_wifi_multicast_state=false
+permissions/change_wifi_state=false
+permissions/clear_app_cache=false
+permissions/clear_app_user_data=false
+permissions/control_location_updates=false
+permissions/delete_cache_files=false
+permissions/delete_packages=false
+permissions/device_power=false
+permissions/diagnostic=false
+permissions/disable_keyguard=false
+permissions/dump=false
+permissions/expand_status_bar=false
+permissions/factory_test=false
+permissions/flashlight=false
+permissions/force_back=false
+permissions/get_accounts=false
+permissions/get_package_size=false
+permissions/get_tasks=false
+permissions/get_top_activity_info=false
+permissions/global_search=false
+permissions/hardware_test=false
+permissions/inject_events=false
+permissions/install_location_provider=false
+permissions/install_packages=false
+permissions/install_shortcut=false
+permissions/internal_system_window=false
+permissions/internet=true
+permissions/kill_background_processes=false
+permissions/location_hardware=false
+permissions/manage_accounts=false
+permissions/manage_app_tokens=false
+permissions/manage_documents=false
+permissions/manage_external_storage=true
+permissions/manage_media=false
+permissions/master_clear=false
+permissions/media_content_control=false
+permissions/modify_audio_settings=false
+permissions/modify_phone_state=false
+permissions/mount_format_filesystems=false
+permissions/mount_unmount_filesystems=false
+permissions/nfc=false
+permissions/persistent_activity=false
+permissions/post_notifications=false
+permissions/process_outgoing_calls=false
+permissions/read_calendar=false
+permissions/read_call_log=false
+permissions/read_contacts=false
+permissions/read_external_storage=false
+permissions/read_frame_buffer=false
+permissions/read_history_bookmarks=false
+permissions/read_input_state=false
+permissions/read_logs=false
+permissions/read_media_audio=false
+permissions/read_media_images=false
+permissions/read_media_video=false
+permissions/read_media_visual_user_selected=false
+permissions/read_phone_state=false
+permissions/read_profile=false
+permissions/read_sms=false
+permissions/read_social_stream=false
+permissions/read_sync_settings=false
+permissions/read_sync_stats=false
+permissions/read_user_dictionary=false
+permissions/reboot=false
+permissions/receive_boot_completed=false
+permissions/receive_mms=false
+permissions/receive_sms=false
+permissions/receive_wap_push=false
+permissions/record_audio=false
+permissions/reorder_tasks=false
+permissions/restart_packages=false
+permissions/send_respond_via_message=false
+permissions/send_sms=false
+permissions/set_activity_watcher=false
+permissions/set_alarm=false
+permissions/set_always_finish=false
+permissions/set_animation_scale=false
+permissions/set_debug_app=false
+permissions/set_orientation=false
+permissions/set_pointer_speed=false
+permissions/set_preferred_applications=false
+permissions/set_process_limit=false
+permissions/set_time=false
+permissions/set_time_zone=false
+permissions/set_wallpaper=false
+permissions/set_wallpaper_hints=false
+permissions/signal_persistent_processes=false
+permissions/status_bar=false
+permissions/subscribed_feeds_read=false
+permissions/subscribed_feeds_write=false
+permissions/system_alert_window=false
+permissions/transmit_ir=false
+permissions/uninstall_shortcut=false
+permissions/update_device_stats=false
+permissions/use_credentials=false
+permissions/use_sip=false
+permissions/vibrate=false
+permissions/wake_lock=false
+permissions/write_apn_settings=false
+permissions/write_calendar=false
+permissions/write_call_log=false
+permissions/write_contacts=false
+permissions/write_external_storage=false
+permissions/write_gservices=false
+permissions/write_history_bookmarks=false
+permissions/write_profile=false
+permissions/write_secure_settings=false
+permissions/write_settings=false
+permissions/write_sms=false
+permissions/write_social_stream=false
+permissions/write_sync_settings=false
+permissions/write_user_dictionary=false
+
+[preset.9]
+
name="Web"
platform="Web"
-runnable=true
dedicated_server=false
custom_features=""
export_filter="all_resources"
@@ -1118,7 +1349,7 @@ encrypt_pck=false
encrypt_directory=false
script_export_mode=2
-[preset.8.options]
+[preset.9.options]
custom_template/debug=""
custom_template/release=""
@@ -1143,3 +1374,271 @@ progressive_web_app/icon_512x512=""
progressive_web_app/background_color=Color(0, 0, 0, 1)
threads/emscripten_pool_size=8
threads/godot_pool_size=4
+
+[preset.9]
+
+name="iOS"
+platform="iOS"
+dedicated_server=false
+custom_features=""
+export_filter="exclude"
+export_files=PackedStringArray("res://addons/gut/cli/change_project_warnings.gd", "res://addons/gut/cli/gut_cli.gd", "res://addons/gut/cli/optparse.gd", "res://addons/gut/fonts/AnonymousPro-Bold.ttf", "res://addons/gut/fonts/AnonymousPro-BoldItalic.ttf", "res://addons/gut/fonts/AnonymousPro-Italic.ttf", "res://addons/gut/fonts/AnonymousPro-Regular.ttf", "res://addons/gut/fonts/CourierPrime-Bold.ttf", "res://addons/gut/fonts/CourierPrime-BoldItalic.ttf", "res://addons/gut/fonts/CourierPrime-Italic.ttf", "res://addons/gut/fonts/CourierPrime-Regular.ttf", "res://addons/gut/fonts/LobsterTwo-Bold.ttf", "res://addons/gut/fonts/LobsterTwo-BoldItalic.ttf", "res://addons/gut/fonts/LobsterTwo-Italic.ttf", "res://addons/gut/fonts/LobsterTwo-Regular.ttf", "res://addons/gut/gui/about.gd", "res://addons/gut/gui/about.tscn", "res://addons/gut/gui/arrow.png", "res://addons/gut/gui/EditorRadioButton.tres", "res://addons/gut/gui/editor_globals.gd", "res://addons/gut/gui/GutBottomPanel.gd", "res://addons/gut/gui/GutBottomPanel.tscn", "res://addons/gut/gui/GutControl.gd", "res://addons/gut/gui/GutControl.tscn", "res://addons/gut/gui/GutEditorWindow.gd", "res://addons/gut/gui/GutEditorWindow.tscn", "res://addons/gut/gui/GutLogo.tscn", "res://addons/gut/gui/GutRunner.gd", "res://addons/gut/gui/GutRunner.tscn", "res://addons/gut/gui/GutSceneTheme.tres", "res://addons/gut/gui/gut_config_gui.gd", "res://addons/gut/gui/gut_gui.gd", "res://addons/gut/gui/gut_logo.gd", "res://addons/gut/gui/gut_user_preferences.gd", "res://addons/gut/gui/MinGui.tscn", "res://addons/gut/gui/NormalGui.tscn", "res://addons/gut/gui/option_maker.gd", "res://addons/gut/gui/OutputText.gd", "res://addons/gut/gui/OutputText.tscn", "res://addons/gut/gui/panel_controls.gd", "res://addons/gut/gui/play.png", "res://addons/gut/gui/ResizeHandle.gd", "res://addons/gut/gui/ResizeHandle.tscn", "res://addons/gut/gui/ResultsTree.gd", "res://addons/gut/gui/ResultsTree.tscn", "res://addons/gut/gui/RunAtCursor.gd", "res://addons/gut/gui/RunAtCursor.tscn", "res://addons/gut/gui/RunExternally.gd", "res://addons/gut/gui/RunExternally.tscn", "res://addons/gut/gui/RunResults.gd", "res://addons/gut/gui/RunResults.tscn", "res://addons/gut/gui/run_from_editor.gd", "res://addons/gut/gui/run_from_editor.tscn", "res://addons/gut/gui/Settings.tscn", "res://addons/gut/gui/ShellOutOptions.gd", "res://addons/gut/gui/ShellOutOptions.tscn", "res://addons/gut/gui/ShortcutButton.gd", "res://addons/gut/gui/ShortcutButton.tscn", "res://addons/gut/gui/ShortcutDialog.gd", "res://addons/gut/gui/ShortcutDialog.tscn", "res://addons/gut/images/eyey.png", "res://addons/gut/images/Folder.svg", "res://addons/gut/images/green.png", "res://addons/gut/images/GutIconV2_base.png", "res://addons/gut/images/GutIconV2_no_shine.png", "res://addons/gut/images/HSplitContainer.svg", "res://addons/gut/images/red.png", "res://addons/gut/images/Script.svg", "res://addons/gut/images/VSplitContainer.svg", "res://addons/gut/images/yellow.png", "res://addons/gut/autofree.gd", "res://addons/gut/awaiter.gd", "res://addons/gut/collected_script.gd", "res://addons/gut/collected_test.gd", "res://addons/gut/comparator.gd", "res://addons/gut/compare_result.gd", "res://addons/gut/diff_formatter.gd", "res://addons/gut/diff_tool.gd", "res://addons/gut/doubler.gd", "res://addons/gut/double_tools.gd", "res://addons/gut/dynamic_gdscript.gd", "res://addons/gut/editor_caret_context_notifier.gd", "res://addons/gut/error_tracker.gd", "res://addons/gut/get_editor_interface.gd", "res://addons/gut/gut.gd", "res://addons/gut/GutScene.gd", "res://addons/gut/GutScene.tscn", "res://addons/gut/gut_cmdln.gd", "res://addons/gut/gut_config.gd", "res://addons/gut/gut_fonts.gd", "res://addons/gut/gut_loader.gd", "res://addons/gut/gut_loader_the_scene.tscn", "res://addons/gut/gut_menu.gd", "res://addons/gut/gut_plugin.gd", "res://addons/gut/gut_to_move.gd", "res://addons/gut/gut_tracked_error.gd", "res://addons/gut/gut_vscode_debugger.gd", "res://addons/gut/hook_script.gd", "res://addons/gut/icon.png", "res://addons/gut/inner_class_registry.gd", "res://addons/gut/input_factory.gd", "res://addons/gut/input_sender.gd", "res://addons/gut/junit_xml_export.gd", "res://addons/gut/lazy_loader.gd", "res://addons/gut/logger.gd", "res://addons/gut/method_maker.gd", "res://addons/gut/one_to_many.gd", "res://addons/gut/orphan_counter.gd", "res://addons/gut/parameter_factory.gd", "res://addons/gut/parameter_handler.gd", "res://addons/gut/printers.gd", "res://addons/gut/result_exporter.gd", "res://addons/gut/script_parser.gd", "res://addons/gut/signal_watcher.gd", "res://addons/gut/source_code_pro.fnt", "res://addons/gut/spy.gd", "res://addons/gut/strutils.gd", "res://addons/gut/stubber.gd", "res://addons/gut/stub_params.gd", "res://addons/gut/summary.gd", "res://addons/gut/test.gd", "res://addons/gut/test_collector.gd", "res://addons/gut/thing_counter.gd", "res://addons/gut/UserFileViewer.gd", "res://addons/gut/UserFileViewer.tscn", "res://addons/gut/utils.gd", "res://addons/gut/version_conversion.gd", "res://addons/gut/version_numbers.gd", "res://addons/gut/warnings_manager.gd", "res://demo/demo.tscn", "res://demo/object.tscn")
+include_filter="*.tmpl"
+exclude_filter="*.ptex,*.mmn,*.mmg"
+export_path=""
+patches=PackedStringArray()
+patch_delta_encoding=false
+patch_delta_compression_level_zstd=19
+patch_delta_min_reduction=0.1
+patch_delta_include_filters="*"
+patch_delta_exclude_filters=""
+encryption_include_filters=""
+encryption_exclude_filters=""
+seed=0
+encrypt_pck=false
+encrypt_directory=false
+script_export_mode=2
+
+[preset.9.options]
+
+custom_template/debug=""
+custom_template/release=""
+architectures/arm64=true
+application/app_store_team_id=""
+application/export_method_debug=1
+application/code_sign_identity_debug=""
+application/code_sign_identity_release=""
+application/provisioning_profile_specifier_debug=""
+application/provisioning_profile_specifier_release=""
+application/export_method_release=0
+application/bundle_identifier="com.rodzill4.materialmaker"
+application/signature=""
+application/short_version=""
+application/version=""
+application/additional_plist_content=""
+application/icon_interpolation=4
+application/export_project_only=false
+application/delete_old_export_files_unconditionally=false
+modules/camera=false
+entitlements/increased_memory_limit=false
+entitlements/game_center=false
+entitlements/push_notifications="Disabled"
+entitlements/additional=""
+capabilities/access_wifi=true
+capabilities/performance_gaming_tier=false
+capabilities/performance_a12=false
+capabilities/additional=PackedStringArray()
+shader_baker/enabled=false
+user_data/accessible_from_files_app=true
+user_data/accessible_from_itunes_sharing=true
+privacy/camera_usage_description=""
+privacy/camera_usage_description_localized={}
+privacy/microphone_usage_description=""
+privacy/microphone_usage_description_localized={}
+privacy/photolibrary_usage_description=""
+privacy/photolibrary_usage_description_localized={}
+privacy/file_timestamp_access_reasons=3
+privacy/system_boot_time_access_reasons=1
+privacy/disk_space_access_reasons=3
+privacy/active_keyboard_access_reasons=0
+privacy/user_defaults_access_reasons=0
+privacy/tracking_enabled=false
+privacy/tracking_domains=PackedStringArray()
+privacy/collected_data/name/collected=false
+privacy/collected_data/name/linked_to_user=false
+privacy/collected_data/name/used_for_tracking=false
+privacy/collected_data/name/collection_purposes=0
+privacy/collected_data/email_address/collected=false
+privacy/collected_data/email_address/linked_to_user=false
+privacy/collected_data/email_address/used_for_tracking=false
+privacy/collected_data/email_address/collection_purposes=0
+privacy/collected_data/phone_number/collected=false
+privacy/collected_data/phone_number/linked_to_user=false
+privacy/collected_data/phone_number/used_for_tracking=false
+privacy/collected_data/phone_number/collection_purposes=0
+privacy/collected_data/physical_address/collected=false
+privacy/collected_data/physical_address/linked_to_user=false
+privacy/collected_data/physical_address/used_for_tracking=false
+privacy/collected_data/physical_address/collection_purposes=0
+privacy/collected_data/other_contact_info/collected=false
+privacy/collected_data/other_contact_info/linked_to_user=false
+privacy/collected_data/other_contact_info/used_for_tracking=false
+privacy/collected_data/other_contact_info/collection_purposes=0
+privacy/collected_data/health/collected=false
+privacy/collected_data/health/linked_to_user=false
+privacy/collected_data/health/used_for_tracking=false
+privacy/collected_data/health/collection_purposes=0
+privacy/collected_data/fitness/collected=false
+privacy/collected_data/fitness/linked_to_user=false
+privacy/collected_data/fitness/used_for_tracking=false
+privacy/collected_data/fitness/collection_purposes=0
+privacy/collected_data/payment_info/collected=false
+privacy/collected_data/payment_info/linked_to_user=false
+privacy/collected_data/payment_info/used_for_tracking=false
+privacy/collected_data/payment_info/collection_purposes=0
+privacy/collected_data/credit_info/collected=false
+privacy/collected_data/credit_info/linked_to_user=false
+privacy/collected_data/credit_info/used_for_tracking=false
+privacy/collected_data/credit_info/collection_purposes=0
+privacy/collected_data/other_financial_info/collected=false
+privacy/collected_data/other_financial_info/linked_to_user=false
+privacy/collected_data/other_financial_info/used_for_tracking=false
+privacy/collected_data/other_financial_info/collection_purposes=0
+privacy/collected_data/precise_location/collected=false
+privacy/collected_data/precise_location/linked_to_user=false
+privacy/collected_data/precise_location/used_for_tracking=false
+privacy/collected_data/precise_location/collection_purposes=0
+privacy/collected_data/coarse_location/collected=false
+privacy/collected_data/coarse_location/linked_to_user=false
+privacy/collected_data/coarse_location/used_for_tracking=false
+privacy/collected_data/coarse_location/collection_purposes=0
+privacy/collected_data/sensitive_info/collected=false
+privacy/collected_data/sensitive_info/linked_to_user=false
+privacy/collected_data/sensitive_info/used_for_tracking=false
+privacy/collected_data/sensitive_info/collection_purposes=0
+privacy/collected_data/contacts/collected=false
+privacy/collected_data/contacts/linked_to_user=false
+privacy/collected_data/contacts/used_for_tracking=false
+privacy/collected_data/contacts/collection_purposes=0
+privacy/collected_data/emails_or_text_messages/collected=false
+privacy/collected_data/emails_or_text_messages/linked_to_user=false
+privacy/collected_data/emails_or_text_messages/used_for_tracking=false
+privacy/collected_data/emails_or_text_messages/collection_purposes=0
+privacy/collected_data/photos_or_videos/collected=false
+privacy/collected_data/photos_or_videos/linked_to_user=false
+privacy/collected_data/photos_or_videos/used_for_tracking=false
+privacy/collected_data/photos_or_videos/collection_purposes=0
+privacy/collected_data/audio_data/collected=false
+privacy/collected_data/audio_data/linked_to_user=false
+privacy/collected_data/audio_data/used_for_tracking=false
+privacy/collected_data/audio_data/collection_purposes=0
+privacy/collected_data/gameplay_content/collected=false
+privacy/collected_data/gameplay_content/linked_to_user=false
+privacy/collected_data/gameplay_content/used_for_tracking=false
+privacy/collected_data/gameplay_content/collection_purposes=0
+privacy/collected_data/customer_support/collected=false
+privacy/collected_data/customer_support/linked_to_user=false
+privacy/collected_data/customer_support/used_for_tracking=false
+privacy/collected_data/customer_support/collection_purposes=0
+privacy/collected_data/other_user_content/collected=false
+privacy/collected_data/other_user_content/linked_to_user=false
+privacy/collected_data/other_user_content/used_for_tracking=false
+privacy/collected_data/other_user_content/collection_purposes=0
+privacy/collected_data/browsing_history/collected=false
+privacy/collected_data/browsing_history/linked_to_user=false
+privacy/collected_data/browsing_history/used_for_tracking=false
+privacy/collected_data/browsing_history/collection_purposes=0
+privacy/collected_data/search_history/collected=false
+privacy/collected_data/search_history/linked_to_user=false
+privacy/collected_data/search_history/used_for_tracking=false
+privacy/collected_data/search_history/collection_purposes=0
+privacy/collected_data/user_id/collected=false
+privacy/collected_data/user_id/linked_to_user=false
+privacy/collected_data/user_id/used_for_tracking=false
+privacy/collected_data/user_id/collection_purposes=0
+privacy/collected_data/device_id/collected=false
+privacy/collected_data/device_id/linked_to_user=false
+privacy/collected_data/device_id/used_for_tracking=false
+privacy/collected_data/device_id/collection_purposes=0
+privacy/collected_data/purchase_history/collected=false
+privacy/collected_data/purchase_history/linked_to_user=false
+privacy/collected_data/purchase_history/used_for_tracking=false
+privacy/collected_data/purchase_history/collection_purposes=0
+privacy/collected_data/product_interaction/collected=false
+privacy/collected_data/product_interaction/linked_to_user=false
+privacy/collected_data/product_interaction/used_for_tracking=false
+privacy/collected_data/product_interaction/collection_purposes=0
+privacy/collected_data/advertising_data/collected=false
+privacy/collected_data/advertising_data/linked_to_user=false
+privacy/collected_data/advertising_data/used_for_tracking=false
+privacy/collected_data/advertising_data/collection_purposes=0
+privacy/collected_data/other_usage_data/collected=false
+privacy/collected_data/other_usage_data/linked_to_user=false
+privacy/collected_data/other_usage_data/used_for_tracking=false
+privacy/collected_data/other_usage_data/collection_purposes=0
+privacy/collected_data/crash_data/collected=false
+privacy/collected_data/crash_data/linked_to_user=false
+privacy/collected_data/crash_data/used_for_tracking=false
+privacy/collected_data/crash_data/collection_purposes=0
+privacy/collected_data/performance_data/collected=false
+privacy/collected_data/performance_data/linked_to_user=false
+privacy/collected_data/performance_data/used_for_tracking=false
+privacy/collected_data/performance_data/collection_purposes=0
+privacy/collected_data/other_diagnostic_data/collected=false
+privacy/collected_data/other_diagnostic_data/linked_to_user=false
+privacy/collected_data/other_diagnostic_data/used_for_tracking=false
+privacy/collected_data/other_diagnostic_data/collection_purposes=0
+privacy/collected_data/environment_scanning/collected=false
+privacy/collected_data/environment_scanning/linked_to_user=false
+privacy/collected_data/environment_scanning/used_for_tracking=false
+privacy/collected_data/environment_scanning/collection_purposes=0
+privacy/collected_data/hands/collected=false
+privacy/collected_data/hands/linked_to_user=false
+privacy/collected_data/hands/used_for_tracking=false
+privacy/collected_data/hands/collection_purposes=0
+privacy/collected_data/head/collected=false
+privacy/collected_data/head/linked_to_user=false
+privacy/collected_data/head/used_for_tracking=false
+privacy/collected_data/head/collection_purposes=0
+privacy/collected_data/other_data_types/collected=false
+privacy/collected_data/other_data_types/linked_to_user=false
+privacy/collected_data/other_data_types/used_for_tracking=false
+privacy/collected_data/other_data_types/collection_purposes=0
+icons/icon_1024x1024=""
+icons/icon_1024x1024_dark=""
+icons/icon_1024x1024_tinted=""
+icons/settings_58x58=""
+icons/settings_58x58_dark=""
+icons/settings_58x58_tinted=""
+icons/settings_87x87=""
+icons/settings_87x87_dark=""
+icons/settings_87x87_tinted=""
+icons/notification_40x40=""
+icons/notification_40x40_dark=""
+icons/notification_40x40_tinted=""
+icons/notification_60x60=""
+icons/notification_60x60_dark=""
+icons/notification_60x60_tinted=""
+icons/notification_76x76=""
+icons/notification_76x76_dark=""
+icons/notification_76x76_tinted=""
+icons/notification_114x114=""
+icons/notification_114x114_dark=""
+icons/notification_114x114_tinted=""
+icons/spotlight_80x80=""
+icons/spotlight_80x80_dark=""
+icons/spotlight_80x80_tinted=""
+icons/spotlight_120x120=""
+icons/spotlight_120x120_dark=""
+icons/spotlight_120x120_tinted=""
+icons/iphone_120x120=""
+icons/iphone_120x120_dark=""
+icons/iphone_120x120_tinted=""
+icons/iphone_180x180=""
+icons/iphone_180x180_dark=""
+icons/iphone_180x180_tinted=""
+icons/ipad_167x167=""
+icons/ipad_167x167_dark=""
+icons/ipad_167x167_tinted=""
+icons/ipad_152x152=""
+icons/ipad_152x152_dark=""
+icons/ipad_152x152_tinted=""
+icons/ios_128x128=""
+icons/ios_128x128_dark=""
+icons/ios_128x128_tinted=""
+icons/ios_192x192=""
+icons/ios_192x192_dark=""
+icons/ios_192x192_tinted=""
+icons/ios_136x136=""
+icons/ios_136x136_dark=""
+icons/ios_136x136_tinted=""
+icons/app_store_1024x1024=""
+icons/app_store_1024x1024_dark=""
+icons/app_store_1024x1024_tinted=""
+application/targeted_device_family=1
+application/min_ios_version="14.0"
+storyboard/image_scale_mode=0
+storyboard/custom_image@2x=""
+storyboard/custom_image@3x=""
+storyboard/use_custom_bg_color=false
+storyboard/custom_bg_color=Color(0, 0, 0, 1)
diff --git a/material_maker/darken.gd.uid b/material_maker/darken.gd.uid
index deb559d6f0..30e8d28d6b 100644
--- a/material_maker/darken.gd.uid
+++ b/material_maker/darken.gd.uid
@@ -1 +1 @@
-uid://du7vv67kc65qb
+uid://dydhg5xaf7bjm
diff --git a/material_maker/darken.tscn b/material_maker/darken.tscn
deleted file mode 100644
index 3e59f8ab13..0000000000
--- a/material_maker/darken.tscn
+++ /dev/null
@@ -1,10 +0,0 @@
-[gd_scene load_steps=2 format=3 uid="uid://cmeh4ewlvp7vx"]
-
-[ext_resource type="Script" path="res://material_maker/darken.gd" id="1"]
-
-[node name="Darken" type="ColorRect"]
-anchor_right = 1.0
-anchor_bottom = 1.0
-script = ExtResource("1")
-
-[connection signal="resized" from="." to="." method="_on_resized"]
diff --git a/material_maker/doc/user_interface.rst b/material_maker/doc/user_interface.rst
index 38f1217381..002024ed54 100644
--- a/material_maker/doc/user_interface.rst
+++ b/material_maker/doc/user_interface.rst
@@ -6,6 +6,7 @@ User interface
user_interface_overview
user_interface_shortcuts
+ user_interface_gestures
user_interface_first_steps
user_interface_main_menu
user_interface_panels
diff --git a/material_maker/doc/user_interface_gestures.rst b/material_maker/doc/user_interface_gestures.rst
new file mode 100644
index 0000000000..4030a1c322
--- /dev/null
+++ b/material_maker/doc/user_interface_gestures.rst
@@ -0,0 +1,81 @@
+Touch Gestures
+~~~~~~~~~~~~~~
+
+While not an exhuaustive list, this shows the most
+common touch gestures available in Material Maker for Android.
+
+In general, most desktop inputs can be mapped to
+touch inputs in the following manner:
+
+**Tap**: Left Click, **Double-Tap**: Left Double Click, **Long-Press**: Right Click
+
+Add Node Popup
+++++++++++++++
++-------------------------------------------------------+----------------------------------------------------+
+| One-Finger Drag | Scroll |
++-------------------------------------------------------+----------------------------------------------------+
+| One-Finger Drag | Drag item from list (at icon) |
++-------------------------------------------------------+----------------------------------------------------+
+
+
+Graph Editor
+++++++++++++
++-------------------------------------------------------+----------------------------------------------------+
+| Two-Finger drag | Pan |
++-------------------------------------------------------+----------------------------------------------------+
+| Two-Finger Pinch | Double-Tap + Drag | Zoom in/out |
++-------------------------------------------------------+----------------------------------------------------+
+| Long Tap | Add node menu |
++-------------------------------------------------------+----------------------------------------------------+
+| One-Finger Drag | Box selection |
++-------------------------------------------------------+----------------------------------------------------+
+| Double Tap | Enters subgraph/nodegroup, or exit/go up a level |
+| | in subgraph hierarchy when double-tapping in an |
+| | empty area. |
++-------------------------------------------------------+----------------------------------------------------+
+| Two-Finger Tap | Undo |
++-------------------------------------------------------+----------------------------------------------------+
+| Three-Finger Tap | Redo |
++-------------------------------------------------------+----------------------------------------------------+
+
+Nodes
++++++
++-------------------------------------------------------+----------------------------------------------------+
+| Long Tap | Open expression editor (float parameter) |
++-------------------------------------------------------+----------------------------------------------------+
+
+Reference
++++++++++
++-------------------------------------------------------+----------------------------------------------------+
+| Two-Finger drag | Pan |
++-------------------------------------------------------+----------------------------------------------------+
+| Two-Finger Pinch | Double-Tap + Drag | Zoom in/out |
++-------------------------------------------------------+----------------------------------------------------+
+
+Preview 2D
+++++++++++
++-------------------------------------------------------+----------------------------------------------------+
+| One-Finger Drag | Pan |
++-------------------------------------------------------+----------------------------------------------------+
+| Two-Finger Pinch | Double-Tap + Drag | Zoom in/out |
++-------------------------------------------------------+----------------------------------------------------+
+| Two-Finger Tap | Reset view |
++-------------------------------------------------------+----------------------------------------------------+
+
+Preview 3D
+++++++++++
++-------------------------------------------------------+----------------------------------------------------+
+| One-Finger Drag | Orbit |
++-------------------------------------------------------+----------------------------------------------------+
+| Two-Finger Pinch | Double-Tap + Drag | Zoom in/out |
++-------------------------------------------------------+----------------------------------------------------+
+
+Library
++++++++
++-------------------------------------------------------+----------------------------------------------------+
+| One-Finger Drag | Two-Finger Drag | Scroll / Fast Scroll |
++-------------------------------------------------------+----------------------------------------------------+
+| One-Finger Drag | Drag item from libary panel (at icon) |
++-------------------------------------------------------+----------------------------------------------------+
+| Two-Finger Pinch | Double-Tap + Drag | Zoom in/out |
++-------------------------------------------------------+----------------------------------------------------+
diff --git a/material_maker/environments/environments.json b/material_maker/environments/environments.json
index 26750029d0..ba422d7250 100644
--- a/material_maker/environments/environments.json
+++ b/material_maker/environments/environments.json
@@ -1 +1 @@
-[{"name":"Epping Forest","hdri_url":"https://hdrihaven.com/files/hdris/epping_forest_01_1k.hdr","show_color":false,"color":{"type":"Color","r":0,"g":0,"b":0,"a":1},"sky_energy":1,"ambient_light_color":{"type":"Color","r":1,"g":1,"b":1,"a":1},"ambient_light_energy":0.5,"ambient_light_sky_contribution":0.7,"sun_color":{"type":"Color","r":1,"g":1,"b":1,"a":1},"sun_energy":0,"sun_direction":0,"sun_angle":7.9,"thumbnail":"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"},{"name":"Moonless Golf","hdri_url":"https://hdrihaven.com/files/hdris/moonless_golf_1k.hdr","show_color":false,"color":{"type":"Color","r":0,"g":0,"b":0,"a":1},"sky_energy":1,"ambient_light_color":{"type":"Color","r":0,"g":0,"b":0,"a":1},"ambient_light_energy":1,"ambient_light_sky_contribution":1,"sun_color":{"type":"Color","r":1,"g":0.984375,"b":0,"a":1},"sun_energy":0.5,"sun_direction":130,"sun_angle":10,"thumbnail":"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"},{"name":"Studio","hdri_url":"https://hdrihaven.com/files/hdris/photo_studio_01_1k.hdr","show_color":true,"color":{"type":"Color","r":0.671875,"g":0.671875,"b":0.671875,"a":1},"sky_energy":1,"ambient_light_color":{"type":"Color","r":1,"g":1,"b":1,"a":1},"ambient_light_energy":0.2,"ambient_light_sky_contribution":0.2,"sun_color":{"type":"Color","r":1,"g":1,"b":1,"a":1},"sun_energy":1,"sun_direction":0,"sun_angle":90,"thumbnail":"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"}]
+[{"name":"Epping Forest","hdri_url":"https://hdrihaven.com/files/hdris/epping_forest_01_1k.exr","show_color":false,"color":{"type":"Color","r":0,"g":0,"b":0,"a":1},"sky_energy":1,"ambient_light_color":{"type":"Color","r":1,"g":1,"b":1,"a":1},"ambient_light_energy":0.5,"ambient_light_sky_contribution":0.7,"sun_color":{"type":"Color","r":1,"g":1,"b":1,"a":1},"sun_energy":0,"sun_direction":0,"sun_angle":7.9,"thumbnail":"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"},{"name":"Moonless Golf","hdri_url":"https://hdrihaven.com/files/hdris/moonless_golf_1k.exr","show_color":false,"color":{"type":"Color","r":0,"g":0,"b":0,"a":1},"sky_energy":1,"ambient_light_color":{"type":"Color","r":0,"g":0,"b":0,"a":1},"ambient_light_energy":1,"ambient_light_sky_contribution":1,"sun_color":{"type":"Color","r":1,"g":0.984375,"b":0,"a":1},"sun_energy":0.5,"sun_direction":130,"sun_angle":10,"thumbnail":"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"},{"name":"Studio","hdri_url":"https://hdrihaven.com/files/hdris/photo_studio_01_1k.exr","show_color":true,"color":{"type":"Color","r":0.671875,"g":0.671875,"b":0.671875,"a":1},"sky_energy":1,"ambient_light_color":{"type":"Color","r":1,"g":1,"b":1,"a":1},"ambient_light_energy":0.2,"ambient_light_sky_contribution":0.2,"sun_color":{"type":"Color","r":1,"g":1,"b":1,"a":1},"sun_energy":1,"sun_direction":0,"sun_angle":90,"thumbnail":"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"}]
diff --git a/material_maker/environments/hdris/epping_forest_01_1k.exr b/material_maker/environments/hdris/epping_forest_01_1k.exr
new file mode 100644
index 0000000000..5a25b66a6e
Binary files /dev/null and b/material_maker/environments/hdris/epping_forest_01_1k.exr differ
diff --git a/material_maker/environments/hdris/epping_forest_01_1k.hdr.import b/material_maker/environments/hdris/epping_forest_01_1k.exr.import
similarity index 58%
rename from material_maker/environments/hdris/epping_forest_01_1k.hdr.import
rename to material_maker/environments/hdris/epping_forest_01_1k.exr.import
index b9c8621ebc..17165dad6c 100644
--- a/material_maker/environments/hdris/epping_forest_01_1k.hdr.import
+++ b/material_maker/environments/hdris/epping_forest_01_1k.exr.import
@@ -3,19 +3,21 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://by6042vpo6i1o"
-path="res://.godot/imported/epping_forest_01_1k.hdr-deb5d85b1c0b655387fa44d4d061848a.ctex"
+path.bptc="res://.godot/imported/epping_forest_01_1k.exr-dd265e3a1064f51c25b4469230bf58cd.bptc.ctex"
+path.astc="res://.godot/imported/epping_forest_01_1k.exr-dd265e3a1064f51c25b4469230bf58cd.astc.ctex"
metadata={
-"vram_texture": false
+"imported_formats": ["s3tc_bptc", "etc2_astc"],
+"vram_texture": true
}
[deps]
-source_file="res://material_maker/environments/hdris/epping_forest_01_1k.hdr"
-dest_files=["res://.godot/imported/epping_forest_01_1k.hdr-deb5d85b1c0b655387fa44d4d061848a.ctex"]
+source_file="res://material_maker/environments/hdris/epping_forest_01_1k.exr"
+dest_files=["res://.godot/imported/epping_forest_01_1k.exr-dd265e3a1064f51c25b4469230bf58cd.bptc.ctex", "res://.godot/imported/epping_forest_01_1k.exr-dd265e3a1064f51c25b4469230bf58cd.astc.ctex"]
[params]
-compress/mode=0
+compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
@@ -23,7 +25,7 @@ compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
-mipmaps/generate=false
+mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
diff --git a/material_maker/environments/hdris/epping_forest_01_1k.hdr b/material_maker/environments/hdris/epping_forest_01_1k.hdr
deleted file mode 100644
index 0307bffbb6..0000000000
Binary files a/material_maker/environments/hdris/epping_forest_01_1k.hdr and /dev/null differ
diff --git a/material_maker/environments/hdris/moonless_golf_1k.exr b/material_maker/environments/hdris/moonless_golf_1k.exr
new file mode 100644
index 0000000000..f9733fe607
Binary files /dev/null and b/material_maker/environments/hdris/moonless_golf_1k.exr differ
diff --git a/material_maker/environments/hdris/moonless_golf_1k.hdr.import b/material_maker/environments/hdris/moonless_golf_1k.exr.import
similarity index 67%
rename from material_maker/environments/hdris/moonless_golf_1k.hdr.import
rename to material_maker/environments/hdris/moonless_golf_1k.exr.import
index ec7781b3a9..db085950f2 100644
--- a/material_maker/environments/hdris/moonless_golf_1k.hdr.import
+++ b/material_maker/environments/hdris/moonless_golf_1k.exr.import
@@ -3,8 +3,8 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://bqre7xkdgb655"
-path.bptc="res://.godot/imported/moonless_golf_1k.hdr-9cc5420e458979fa0268bbd265e3a765.bptc.ctex"
-path.astc="res://.godot/imported/moonless_golf_1k.hdr-9cc5420e458979fa0268bbd265e3a765.astc.ctex"
+path.bptc="res://.godot/imported/moonless_golf_1k.exr-dc79b74455e0bb044175d039bc8ecb2e.bptc.ctex"
+path.astc="res://.godot/imported/moonless_golf_1k.exr-dc79b74455e0bb044175d039bc8ecb2e.astc.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
@@ -12,8 +12,8 @@ metadata={
[deps]
-source_file="res://material_maker/environments/hdris/moonless_golf_1k.hdr"
-dest_files=["res://.godot/imported/moonless_golf_1k.hdr-9cc5420e458979fa0268bbd265e3a765.bptc.ctex", "res://.godot/imported/moonless_golf_1k.hdr-9cc5420e458979fa0268bbd265e3a765.astc.ctex"]
+source_file="res://material_maker/environments/hdris/moonless_golf_1k.exr"
+dest_files=["res://.godot/imported/moonless_golf_1k.exr-dc79b74455e0bb044175d039bc8ecb2e.bptc.ctex", "res://.godot/imported/moonless_golf_1k.exr-dc79b74455e0bb044175d039bc8ecb2e.astc.ctex"]
[params]
diff --git a/material_maker/environments/hdris/moonless_golf_1k.hdr b/material_maker/environments/hdris/moonless_golf_1k.hdr
deleted file mode 100644
index cc60dc8624..0000000000
Binary files a/material_maker/environments/hdris/moonless_golf_1k.hdr and /dev/null differ
diff --git a/material_maker/environments/hdris/photo_studio_01_1k.exr b/material_maker/environments/hdris/photo_studio_01_1k.exr
new file mode 100644
index 0000000000..5fdde59957
Binary files /dev/null and b/material_maker/environments/hdris/photo_studio_01_1k.exr differ
diff --git a/material_maker/environments/hdris/photo_studio_01_1k.hdr.import b/material_maker/environments/hdris/photo_studio_01_1k.exr.import
similarity index 60%
rename from material_maker/environments/hdris/photo_studio_01_1k.hdr.import
rename to material_maker/environments/hdris/photo_studio_01_1k.exr.import
index 315f5fd614..bd5e8af18d 100644
--- a/material_maker/environments/hdris/photo_studio_01_1k.hdr.import
+++ b/material_maker/environments/hdris/photo_studio_01_1k.exr.import
@@ -3,19 +3,21 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://ceqyb6morrwwp"
-path="res://.godot/imported/photo_studio_01_1k.hdr-67066106c81aadd61efb3176d5af71b1.ctex"
+path.bptc="res://.godot/imported/photo_studio_01_1k.exr-8c8b30710711710f3cfa9bec036e54ec.bptc.ctex"
+path.astc="res://.godot/imported/photo_studio_01_1k.exr-8c8b30710711710f3cfa9bec036e54ec.astc.ctex"
metadata={
-"vram_texture": false
+"imported_formats": ["s3tc_bptc", "etc2_astc"],
+"vram_texture": true
}
[deps]
-source_file="res://material_maker/environments/hdris/photo_studio_01_1k.hdr"
-dest_files=["res://.godot/imported/photo_studio_01_1k.hdr-67066106c81aadd61efb3176d5af71b1.ctex"]
+source_file="res://material_maker/environments/hdris/photo_studio_01_1k.exr"
+dest_files=["res://.godot/imported/photo_studio_01_1k.exr-8c8b30710711710f3cfa9bec036e54ec.bptc.ctex", "res://.godot/imported/photo_studio_01_1k.exr-8c8b30710711710f3cfa9bec036e54ec.astc.ctex"]
[params]
-compress/mode=0
+compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
diff --git a/material_maker/environments/hdris/photo_studio_01_1k.hdr b/material_maker/environments/hdris/photo_studio_01_1k.hdr
deleted file mode 100644
index 043cc54f95..0000000000
Binary files a/material_maker/environments/hdris/photo_studio_01_1k.hdr and /dev/null differ
diff --git a/material_maker/examples/.gdignore b/material_maker/examples/.gdignore
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/material_maker/examples/mm_icon.png.import b/material_maker/examples/mm_icon.png.import
new file mode 100644
index 0000000000..8dd0c09d14
--- /dev/null
+++ b/material_maker/examples/mm_icon.png.import
@@ -0,0 +1,3 @@
+[remap]
+
+importer="keep"
diff --git a/material_maker/globals.gd b/material_maker/globals.gd
index be003b1229..ba2444b805 100644
--- a/material_maker/globals.gd
+++ b/material_maker/globals.gd
@@ -3,7 +3,15 @@ extends Node
@onready var menu_manager = $MenuManager
-var main_window
+var main_window : MainWindow
+
+@warning_ignore("unused_signal")
+signal preferences_updated
+
+
+const DEFAULT_DARK : int = 0
+const DEFAULT_LIGHT : int = 1
+const CLASSIC : int = 2
var config : ConfigFile = ConfigFile.new()
const DEFAULT_CONFIG : Dictionary = {
@@ -70,17 +78,33 @@ const DEFAULT_CONFIG : Dictionary = {
custom_theme_contrast = 0.8,
ui_3d_preview_generated_mesh = true,
nearest_filter_reference = false,
+ keep_screen_on = true,
+ touch_node_actions = false,
+ touch_optimization = false,
+ touch_full_screen = false,
sub_node_items = [],
}
+const ANDROID_CONFIG : Dictionary[String, Variant] = {
+ node_minimize_button = false,
+ node_close_button = false,
+ touch_node_actions = true,
+ touch_optimization = true,
+ touch_full_screen = true,
+ ui_3d_preview_generated_mesh = false,
+}
-func _enter_tree():
+func _enter_tree() -> void:
config.load("user://mm_config.ini")
for k : String in DEFAULT_CONFIG.keys():
- if ! config.has_section_key("config", k):
+ if not config.has_section_key("config", k):
config.set_value("config", k, DEFAULT_CONFIG[k])
-func _exit_tree():
+ # android-specific defaults
+ if OS.get_name() == "Android" and k in ANDROID_CONFIG:
+ config.set_value("config", k, ANDROID_CONFIG[k])
+
+func _exit_tree() -> void:
config.save("user://mm_config.ini")
# Config
@@ -194,7 +218,7 @@ func popup_menu(menu : PopupMenu, parent : Control):
var content_scale_factor : float = mm_globals.ui_scale_factor()
menu.popup(Rect2(parent.get_local_mouse_position()*content_scale_factor*zoom_fac + parent.get_screen_position(), Vector2(0, 0)))
-func set_tip_text(tip : String, timeout : float = 0.0, priority: int = 0):
+func set_tip_text(tip : String, timeout : float = 0.0, priority: int = 0) -> void:
if main_window:
main_window.set_tip_text(TranslationServer.translate(tip), timeout, priority)
else:
@@ -226,7 +250,13 @@ func propagate_shortcuts(control : Control, event : InputEvent):
do_propagate_shortcuts(control, event)
func get_home_directory() -> String:
- return OS.get_environment("USERPROFILE" if OS.has_feature("windows") else "HOME")
+ match OS.get_name():
+ "Windows":
+ return OS.get_environment("USERPROFILE")
+ "Android":
+ return "/storage/emulated/%s" % [ mm_globals.android_get_user_uid() ]
+ _:
+ return OS.get_environment("HOME")
func get_node_title_from_gen(generator : MMGenBase) -> String:
# Get GraphNode title from generator (in current graph)
@@ -246,3 +276,68 @@ func ui_scale_factor() -> float:
func is_custom_theme() -> bool:
return config.get_value("window", "theme") == "custom"
+
+func get_ui_scale() -> float:
+ var ui_scale = mm_globals.get_config("ui_scale")
+ if ui_scale <= 0:
+ # If scale is set to 0 (auto), scale everything if the display requires it (crude hiDPI support).
+ # This prevents UI elements from being too small on hiDPI displays.
+ return 2 if DisplayServer.screen_get_dpi() >= 192 and DisplayServer.screen_get_size().x >= 2048 else 1
+ return ui_scale
+
+## Returns current theme based on Main Window's theme resource path.
+func current_theme() -> int:
+ var t : String = main_window.theme.resource_path.get_file()
+ match t.trim_suffix(".tres").to_lower():
+ "default dark":
+ return DEFAULT_DARK
+ "default light":
+ return DEFAULT_LIGHT
+ "classic":
+ return CLASSIC
+ _:
+ return DEFAULT_DARK
+
+#region android utilties
+
+## Creates a toast message.
+## [param duration] set to 0 displays the message for a short period of time.
+func android_make_toast(message : String, duration : int = 1) -> void:
+ if mm_touch.android_runtime:
+ var activity : JavaObject = mm_touch.android_runtime.getActivity()
+ var toastCallable = func() -> void:
+ var ToastClass : JavaClass = JavaClassWrapper.wrap("android.widget.Toast")
+ ToastClass.makeText(activity, message, duration).show()
+
+ activity.runOnUiThread(mm_touch.android_runtime.createRunnableFromGodotCallable(toastCallable))
+ else:
+ printerr("Unable to access android runtime")
+
+## Returns the current user's uid (i.e. the '0' in /storage/emulated/0).
+func android_get_user_uid() -> int:
+ if mm_touch.android_runtime:
+ var processClass : JavaClass = JavaClassWrapper.wrap("android.os.Process")
+ var userHandle : JavaClass = JavaClassWrapper.wrap("android.os.UserHandle")
+ return userHandle.getUserId(processClass.myUid())
+ else:
+ printerr("Unable to access android runtime")
+ return -1
+
+func android_move_task_to_back() -> void:
+ if mm_touch.android_runtime:
+ mm_touch.android_runtime.getActivity().moveTaskToBack(true)
+
+func android_open_url(url : String) -> void:
+ # can't open url directly via shell_open
+ var b : Button = Button.new()
+ add_child(b)
+ b.pressed.connect(OS.shell_open.call_deferred.bind(url))
+ b.pressed.connect(b.queue_free)
+ b.modulate.a = 0
+ b.pressed.emit()
+
+func should_dim_fullscreen(window : Window) -> bool:
+ const dim : String = "android_fullscreen_dim"
+ return OS.get_name() == "Android" and window.has_meta(dim) and window.get_meta(dim)
+
+#endregion
diff --git a/material_maker/globals_menu_manager.gd b/material_maker/globals_menu_manager.gd
index af5f2f335b..5dd8bbc460 100644
--- a/material_maker/globals_menu_manager.gd
+++ b/material_maker/globals_menu_manager.gd
@@ -253,7 +253,10 @@ func create_menu(menu_def : Array, object : Object, menu_name : String, menu : M
if s == "Alt":
shortcut |= KEY_MASK_ALT
elif s == "Control":
- shortcut |= KEY_MASK_CTRL
+ if OS.get_name() == "iOS":
+ shortcut |= KEY_MASK_META
+ else:
+ shortcut |= KEY_MASK_CTRL
elif s == "Shift":
shortcut |= KEY_MASK_SHIFT
else:
diff --git a/material_maker/main_window.gd b/material_maker/main_window.gd
index 406d12a4f3..5e6c0b6952 100644
--- a/material_maker/main_window.gd
+++ b/material_maker/main_window.gd
@@ -1,4 +1,4 @@
-
+class_name MainWindow
extends Control
var quitting : bool = false
@@ -24,10 +24,11 @@ var preview_tesselation_detail : int = 256
@onready var node_library_manager = $NodeLibraryManager
@onready var brush_library_manager = $BrushLibraryManager
+@onready var tip_label : RichTextLabel = %Tip
-@onready var projects_panel = $VBoxContainer/Layout/FlexibleLayout/Main
+@onready var projects_panel = %Main
-@onready var layout = $VBoxContainer/Layout
+@onready var layout = %Layout
var library
var preview_2d : Array
var histogram
@@ -67,7 +68,7 @@ const MENU : Array[Dictionary] = [
{ menu="File/Export material", submenu="export_material", not_in_ports=["HTML5"] },
{ menu="File/-" },
{ menu="File/Close", command="close_project", shortcut="Control+Shift+Q" },
- { menu="File/Quit", command="quit", shortcut="Control+Q", not_in_ports=["HTML5"] },
+ { menu="File/Quit", command="quit", shortcut="Control+Q", not_in_ports=["HTML5", "iOS"] },
{ menu="Edit/Undo", command="edit_undo", shortcut="Control+Z" },
{ menu="Edit/Redo", command="edit_redo", shortcut="Control+Shift+Z" },
@@ -131,8 +132,17 @@ enum WinTabletDriver { WININK, WINTAB, DISABLED }
func _enter_tree() -> void:
mm_globals.main_window = self
+ if OS.get_name() == "Android":
+ ready.connect(android_setup_margins)
+ mm_globals.preferences_updated.connect(android_setup_margins)
+
+ if mm_globals.get_config("touch_optimization"):
+ android_setup_status_bar()
func _ready() -> void:
+ if OS.get_name() == "iOS":
+ DirAccess.make_dir_absolute("user://Documents")
+
get_window().borderless = false
get_window().transparent = false
get_window().grab_focus()
@@ -144,26 +154,28 @@ func _ready() -> void:
if mm_globals.get_config("locale") == "":
mm_globals.set_config("locale", TranslationServer.get_locale())
+ mm_globals.preferences_updated.connect(on_config_changed)
on_config_changed()
- # Set a minimum window size to prevent UI elements from collapsing on each other.
- get_window().min_size = Vector2(1024, 600)
+ if OS.get_name() != "Android":
+ # Set a minimum window size to prevent UI elements from collapsing on each other.
+ get_window().min_size = Vector2(1024, 600)
- # Restore the window position/size if values are present in the configuration cache
- if mm_globals.config.has_section_key("window", "screen"):
- get_window().current_screen = mm_globals.config.get_value("window", "screen")
+ # Restore the window position/size if values are present in the configuration cache
+ if mm_globals.config.has_section_key("window", "screen"):
+ get_window().current_screen = mm_globals.config.get_value("window", "screen")
- if mm_globals.config.has_section_key("window", "maximized"):
- get_window().mode = Window.MODE_MAXIMIZED if (mm_globals.config.get_value("window", "maximized")) else Window.MODE_WINDOWED
+ if mm_globals.config.has_section_key("window", "maximized"):
+ get_window().mode = Window.MODE_MAXIMIZED if (mm_globals.config.get_value("window", "maximized")) else Window.MODE_WINDOWED
- if get_window().mode != Window.MODE_MAXIMIZED:
- if mm_globals.config.has_section_key("window", "position"):
- get_window().position = mm_globals.config.get_value("window", "position")
- else:
- get_window().min_size *= get_window().content_scale_factor
- get_window().move_to_center()
- if mm_globals.config.has_section_key("window", "size"):
- get_window().size = mm_globals.config.get_value("window", "size")
+ if get_window().mode != Window.MODE_MAXIMIZED:
+ if mm_globals.config.has_section_key("window", "position"):
+ get_window().position = mm_globals.config.get_value("window", "position")
+ else:
+ get_window().min_size *= get_window().content_scale_factor
+ get_window().move_to_center()
+ if mm_globals.config.has_section_key("window", "size"):
+ get_window().size = mm_globals.config.get_value("window", "size")
# Restore the theme
var theme_name: String = "default dark"
@@ -245,7 +257,6 @@ func _ready() -> void:
DirAccess.remove_absolute(f)
if get_current_graph_edit() == null:
- await get_tree().process_frame
new_material()
size = get_window().size
@@ -258,6 +269,10 @@ func _ready() -> void:
size = get_viewport().size/get_viewport().content_scale_factor
position = Vector2i(0, 0)
+ if OS.get_name() == "Android":
+ # copy image node's default mm_icon.png
+ android_copy_examples("png")
+ tip_label.hide()
var menu_update_requested : bool = false
@@ -273,7 +288,7 @@ func do_update_menus() -> void:
menu_bar_class = mm_globals.menu_manager.MenuBarDisplayServer
else:
menu_bar_class = mm_globals.menu_manager.MenuBarGodot
- var menu_bar = menu_bar_class.new($VBoxContainer/TopBar/Menu)
+ var menu_bar = menu_bar_class.new($MainContainer/VBoxContainer/TopBar/Menu)
mm_globals.menu_manager.create_menus(MENU, self, menu_bar)
menu_update_requested = false
@@ -294,6 +309,7 @@ func _input(event: InputEvent) -> void:
get_window().mode = Window.MODE_MAXIMIZED
func on_config_changed() -> void:
+ DisplayServer.screen_set_keep_on(mm_globals.get_config("keep_screen_on"))
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if (mm_globals.get_config("vsync")) else DisplayServer.VSYNC_DISABLED)
# Convert FPS to microseconds per frame.
# Clamp the FPS to reasonable values to avoid locking up the UI.
@@ -307,12 +323,7 @@ func on_config_changed() -> void:
if OS.get_name() == "macOS":
mm_globals.main_window.update_menus()
- var ui_scale = mm_globals.get_config("ui_scale")
- if ui_scale <= 0:
- # If scale is set to 0 (auto), scale everything if the display requires it (crude hiDPI support).
- # This prevents UI elements from being too small on hiDPI displays.
- ui_scale = 2 if DisplayServer.screen_get_dpi() >= 192 and DisplayServer.screen_get_size().x >= 2048 else 1
- get_viewport().content_scale_factor = ui_scale
+ get_viewport().content_scale_factor = mm_globals.get_ui_scale()
size = get_viewport().size/get_viewport().content_scale_factor
position = Vector2i(0, 0)
#ProjectSettings.set_setting("display/window/stretch/scale", scale)
@@ -348,6 +359,7 @@ func on_config_changed() -> void:
if mm_globals.config.get_value("window", "theme") == "custom":
change_theme("custom")
+
func get_panel(panel_name : String) -> Control:
return layout.get_panel(panel_name)
@@ -659,6 +671,10 @@ func change_theme(theme_name : String) -> void:
_theme.update()
theme = _theme
+
+ if mm_globals.get_config("touch_optimization"):
+ mobile_set_theme_overrides(theme)
+
ThemeUtils.setup_clear_color()
$NodeFactory.on_theme_changed()
@@ -722,15 +738,15 @@ func _on_PanelsPreset_id_pressed(id : int) -> void:
var replace_status : String = await accept_dialog(
"Preset \"%s\" already exists. Do you want to replace it?" % [preset_name], true)
if replace_status == "ok":
- existing_preset.preset = $VBoxContainer/Layout/FlexibleLayout.serialize()
+ existing_preset.preset = $MainContainer/VBoxContainer/Layout/FlexibleLayout.serialize()
else:
var new_preset : Dictionary = {
"name": preset_name,
- "preset": $VBoxContainer/Layout/FlexibleLayout.serialize()
+ "preset": $MainContainer/VBoxContainer/Layout/FlexibleLayout.serialize()
}
layout.presets.push_back(new_preset)
_:
- $VBoxContainer/Layout/FlexibleLayout.init(layout.presets[id].preset)
+ $MainContainer/VBoxContainer/Layout/FlexibleLayout.init(layout.presets[id].preset)
update_menus()
func create_menu_create(menu : MMMenuManager.MenuBase) -> void:
@@ -916,11 +932,13 @@ func quit() -> void:
quitting = false
return
if mm_globals.get_config("confirm_close_project"):
- var result = await $VBoxContainer/Layout/FlexibleLayout/Main/Projects.check_save_tabs()
+ var result = await $MainContainer/VBoxContainer/Layout/FlexibleLayout/Main/Projects.check_save_tabs()
if !result:
quitting = false
return
await mm_renderer.stop_rendering_thread()
+ if OS.get_name() == "Android":
+ mm_globals.android_move_task_to_back()
dim_window()
get_tree().quit()
quitting = false
@@ -1112,10 +1130,10 @@ func view_reset_zoom() -> void:
graph_edit.zoom = 1
func view_reset_panels() -> void:
- $VBoxContainer/Layout.reset_panels()
+ $MainContainer/VBoxContainer/Layout.reset_panels()
func toggle_side_panels() -> void:
- $VBoxContainer/Layout.toggle_side_panels()
+ $MainContainer/VBoxContainer/Layout.toggle_side_panels()
func get_selected_nodes() -> Array:
var graph_edit : MMGraphEdit = get_current_graph_edit()
@@ -1231,7 +1249,7 @@ func _on_PaintEnvironment_id_pressed(id) -> void:
func environment_editor() -> Node:
var env_editor : Node = load("res://material_maker/windows/environment_editor/environment_editor.tscn").instantiate()
- add_child(env_editor)
+ add_dialog(env_editor)
return env_editor
# -----------------------------------------------------------------------
@@ -1239,6 +1257,9 @@ func environment_editor() -> Node:
# -----------------------------------------------------------------------
func get_doc_dir() -> String:
+ if OS.get_name() == "Android":
+ return MMPaths.DOC_ADDRESS
+
var base_dir = MMPaths.get_resource_dir().replace("\\", "/")
# In release builds, documentation is expected to be located in
# a subdirectory of the program directory
@@ -1252,6 +1273,9 @@ func get_doc_dir() -> String:
return ""
func show_doc() -> void:
+ if OS.get_name() == "Android":
+ mm_globals.android_open_url(MMPaths.DOC_ADDRESS)
+ return
var doc_dir = get_doc_dir()
if doc_dir != "":
OS.shell_open(doc_dir+"/index.html")
@@ -1259,39 +1283,54 @@ func show_doc() -> void:
func show_doc_is_disabled() -> bool:
+ if OS.get_name() == "Android":
+ return false
return get_doc_dir() == ""
func show_library_item_doc() -> void:
var doc_dir : String = get_doc_dir()
if doc_dir != "":
var doc_name = library.get_selected_item_doc_name()
+ var doc_path : String = doc_dir+"/node_"+doc_name+".html"
+
+ if OS.get_name() == "Android":
+ if library.get_selected_item_name() == "" or not library.is_inside_tree():
+ mm_globals.android_make_toast("Please select an item in the libary panel.")
+ else:
+ var path : String = android_process_doc_path(doc_dir, doc_name)
+ mm_globals.android_open_url(path)
+ return
+
while doc_name != "":
- var doc_path : String = doc_dir+"/node_"+doc_name+".html"
if FileAccess.file_exists(doc_path):
OS.shell_open(doc_path)
break
doc_name = doc_name.left(doc_name.rfind("_"))
func show_library_item_doc_is_disabled() -> bool:
+ if OS.get_name() == "Android":
+ return false
return get_doc_dir() == "" or !library.is_inside_tree() or library.get_selected_item_doc_name() == ""
func bug_report() -> void:
OS.shell_open("https://github.com/RodZill4/godot-procedural-textures/issues")
func about() -> void:
- var about_box = preload("res://material_maker/windows/about/about.tscn").instantiate()
- add_child(about_box)
- about_box.hide()
- about_box.popup_centered()
+ var about_box : Window = preload("res://material_maker/windows/about/about.tscn").instantiate()
+ add_dialog(about_box)
func show_example_projects() -> void:
- var base_dir : String = MMPaths.get_resource_dir().replace("\\", "/")
- var release_examples_path : String = base_dir.path_join("examples")
- var devel_examples_path : String = ProjectSettings.globalize_path("res://material_maker/examples")
- for p in [ release_examples_path, devel_examples_path ]:
- if DirAccess.dir_exists_absolute(p):
- OS.shell_open(p)
- return
+ if OS.get_name() == "Android":
+ android_copy_examples()
+ android_load_example_project()
+ else:
+ var base_dir : String = MMPaths.get_resource_dir().replace("\\", "/")
+ var release_examples_path : String = base_dir.path_join("examples")
+ var devel_examples_path : String = ProjectSettings.globalize_path("res://material_maker/examples")
+ for p in [ release_examples_path, devel_examples_path ]:
+ if DirAccess.dir_exists_absolute(p):
+ OS.shell_open(p)
+ return
# Preview
@@ -1518,8 +1557,8 @@ func set_tip_text(tip : String, timeout : float = 0.0, priority: int = 0):
tip = tip.replace("#RIGHT", "[img]res://material_maker/icons/right_arrow.tres[/img]")
if priority >= tip_priority:
tip_priority = priority
- $VBoxContainer/StatusBar/HBox/Tip.text = tip
- var tip_timer : Timer = $VBoxContainer/StatusBar/HBox/Tip/Timer
+ tip_label.text = tip
+ var tip_timer : Timer = tip_label.get_node("Timer")
tip_timer.stop()
if timeout > 0.0:
tip_timer.one_shot = true
@@ -1528,15 +1567,20 @@ func set_tip_text(tip : String, timeout : float = 0.0, priority: int = 0):
func _on_Tip_Timer_timeout():
tip_priority = 0
- $VBoxContainer/StatusBar/HBox/Tip.text = ""
+ tip_label.text = ""
# Add dialog
-func add_dialog(dialog : Window):
- if mm_globals.get_config("dialog_dim_background"):
- var background : ColorRect = load("res://material_maker/darken.tscn").instantiate()
- add_child(background)
- dialog.tree_exited.connect(background.queue_free)
+func add_dialog(dialog : Window) -> void:
+ var opaque_dim : bool = mm_globals.should_dim_fullscreen(dialog)
+ if opaque_dim or mm_globals.get_config("dialog_dim_background"):
+ var bg : ColorRect = ColorRect.new()
+ bg.set_anchors_and_offsets_preset(PRESET_FULL_RECT)
+ bg.color = theme.get_stylebox("panel", "Panel").bg_color
+ bg.color.a = 1.0 if opaque_dim else 0.8
+
+ get_tree().root.add_child(bg)
+ dialog.tree_exited.connect(bg.queue_free)
add_child(dialog)
# Accept dialog
@@ -1575,3 +1619,136 @@ func draw_children(p, x):
func _draw_debug():
draw_children(self, get_global_mouse_position())
+
+#region mobile-specific setups
+
+func android_setup_margins() -> void:
+ # offset by MM_MainBackground stylebox content margins
+ if not mm_globals.get_config("touch_full_screen"):
+ $MainContainer.add_theme_constant_override("margin_left",
+ maxi(mm_touch.cutout_margins(SIDE_LEFT) - 10, 0))
+ $MainContainer.add_theme_constant_override("margin_right",
+ maxi(mm_touch.cutout_margins(SIDE_RIGHT) - 10, 0))
+ else:
+ $MainContainer.remove_theme_constant_override("margin_right")
+ $MainContainer.remove_theme_constant_override("margin_left")
+
+func android_setup_status_bar() -> void:
+ # move status bar items to menu bar
+ var status_bar_hbox : HBoxContainer = $MainContainer/VBoxContainer/StatusBar/HBox
+ var menu_bar_hbox : HBoxContainer = $MainContainer/VBoxContainer/TopBar/Menu
+
+ status_bar_hbox.owner = null
+ status_bar_hbox.reparent(menu_bar_hbox.get_parent())
+ status_bar_hbox.owner = self
+
+ var status_spacer : Control = Control.new()
+ status_spacer.name = "StatusBarSpacer"
+ status_bar_hbox.add_child(status_spacer)
+
+ var menu_spacer : Control = Control.new()
+ menu_spacer.name = "MenuBarSpacer"
+ menu_bar_hbox.add_child(menu_spacer)
+ menu_bar_hbox.move_child(menu_spacer, 0)
+
+ android_update_spacers(menu_spacer, status_spacer)
+ mm_globals.preferences_updated.connect(
+ android_update_spacers.bind(menu_spacer, status_spacer))
+
+ await status_bar_hbox.ready
+ status_bar_hbox.get_node("Tip").hide()
+ $MainContainer/VBoxContainer/StatusBar.hide()
+
+func android_update_spacers(menu : Control, status : Control) -> void:
+ android_update_spacer_margins(status, SIDE_RIGHT, CORNER_BOTTOM_RIGHT)
+ android_update_spacer_margins(menu, SIDE_LEFT, CORNER_TOP_RIGHT)
+
+func android_update_spacer_margins(spacer : Control,
+ side : Side, corner : Corner) -> void:
+ var corner_reach : float = 0.0
+
+ # avoid screen corners
+ var r : float = mm_touch.corner_radius(corner)
+ if r > 0.0:
+ var h : float = 36.0 # window title_height theme constant
+ corner_reach = sqrt(maxf((r) ** 2.0 - (r-h) ** 2.0, 0.0))
+ corner_reach /= mm_globals.get_ui_scale()
+
+ if mm_globals.get_config("touch_full_screen"):
+ DisplayServer.get_display_cutouts()
+ spacer.custom_minimum_size.x = corner_reach
+ else:
+ # account for main container's already-applied margins
+ spacer.custom_minimum_size.x = maxf(corner_reach - mm_touch.cutout_margins(side), 0.0)
+
+func mobile_set_theme_overrides(t : Theme) -> void:
+ const vh_scroll_width : int = 10
+ var sv : StyleBoxFlat = t.get_stylebox("scroll", "VScrollBar")
+ sv.set_border_width(SIDE_LEFT, vh_scroll_width)
+ sv.set_border_width(SIDE_RIGHT, vh_scroll_width)
+
+ var sh : StyleBoxFlat = t.get_stylebox("scroll", "HScrollBar")
+ sh.set_border_width(SIDE_TOP, vh_scroll_width)
+ sh.set_border_width(SIDE_BOTTOM, vh_scroll_width)
+
+ t.set_constant("v_separation", "PopupMenu", 16)
+ t.set_constant("v_separation", "ItemList", 16)
+ t.set_constant("resize_margin", "Window", 32)
+
+ t.set_stylebox("pressed", "Button", t.get_stylebox("hover_pressed", "Button"))
+ t.set_stylebox("hover", "Button", t.get_stylebox("normal", "Button"))
+
+func android_copy_examples(ext : String = "ptex") -> void:
+ # copy example projects from exported examples
+ var base : String = "res://material_maker/examples/"
+ var examples : String = "user://examples/"
+ DirAccess.make_dir_absolute("user://examples/")
+ var dir : DirAccess = DirAccess.open(base)
+ dir.list_dir_begin()
+ var arr : PackedStringArray
+ while true:
+ var f : String = dir.get_next()
+ arr.push_back(f)
+ if f.is_empty():
+ break
+ if f.get_extension() == ext and not FileAccess.file_exists(examples.path_join(f)):
+ dir.copy(base.path_join(f), examples.path_join(f))
+ dir.list_dir_end()
+
+func android_load_example_project() -> void:
+ const fd : String = "res://material_maker/windows/file_dialog/file_dialog.tscn"
+ var dialog : FileDialog = preload(fd).instantiate()
+ dialog.access = FileDialog.ACCESS_USERDATA
+ dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILES
+ dialog.current_dir = "examples"
+ dialog.add_filter("*.ptex;Procedural Textures File")
+ var files = await dialog.select_files()
+ if files.size() > 0:
+ do_load_project(files[0])
+
+func android_process_doc_path(doc_dir : String, doc_name : String) -> String:
+ const maps : Dictionary[String, String] = {
+ "miscellaneous_reroute": "reroute_nodes",
+ "miscellaneous": "miscellaneous_nodes",
+ "workflow": "nodes_workflow",
+ "transform": "nodes_transform",
+ "filter": "nodes_filter",
+ "noise": "nodes_noise",
+ "pattern": "nodes_pattern",
+ "3d": "nodes_3d",
+ "simple": "nodes_simple",
+ }
+
+ const prefix : Dictionary[String, String] = {
+ "miscellaneous_aperture": "aperture_nodes"
+ }
+
+ for p in prefix.keys():
+ if doc_name.begins_with(p):
+ return doc_dir.path_join(prefix[p]+".html")
+
+ if maps.has(doc_name):
+ return doc_dir.path_join(maps[doc_name]+".html")
+ return doc_dir+"/node_"+doc_name+".html"
+
+#endregion
diff --git a/material_maker/main_window.tscn b/material_maker/main_window.tscn
index ebdc776254..b5ce0c2dac 100644
--- a/material_maker/main_window.tscn
+++ b/material_maker/main_window.tscn
@@ -102,10 +102,10 @@ filter_clip = true
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
-offset_left = -160.0
-offset_top = -21.0
-offset_right = 430.0
-offset_bottom = 311.0
+offset_left = -54.99
+offset_top = 18.19
+offset_right = 535.01
+offset_bottom = 350.19
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
@@ -139,29 +139,35 @@ config_section = "brush_lib"
[node name="EnvironmentManager" parent="." unique_id=2064810205 instance=ExtResource("13")]
-[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=257055939]
+[node name="MainContainer" type="MarginContainer" parent="." unique_id=1229937872]
+layout_mode = 2
+
+[node name="VBoxContainer" type="VBoxContainer" parent="MainContainer" unique_id=257055939]
+unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
-[node name="TopBar" type="HBoxContainer" parent="VBoxContainer" unique_id=1671198557]
+[node name="TopBar" type="HBoxContainer" parent="MainContainer/VBoxContainer" unique_id=1671198557]
layout_mode = 2
-[node name="Menu" type="HBoxContainer" parent="VBoxContainer/TopBar" unique_id=1359206080]
+[node name="Menu" type="HBoxContainer" parent="MainContainer/VBoxContainer/TopBar" unique_id=1359206080]
layout_mode = 2
size_flags_horizontal = 3
-[node name="Layout" type="HBoxContainer" parent="VBoxContainer" unique_id=1034731775]
+[node name="Layout" type="HBoxContainer" parent="MainContainer/VBoxContainer" unique_id=1034731775]
+unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
script = ExtResource("2")
-[node name="FlexibleLayout" parent="VBoxContainer/Layout" unique_id=2116126116 instance=ExtResource("6_ygla4")]
+[node name="FlexibleLayout" parent="MainContainer/VBoxContainer/Layout" unique_id=2116126116 instance=ExtResource("6_ygla4")]
layout_mode = 2
size_flags_horizontal = 3
allow_undock = true
-[node name="Main" parent="VBoxContainer/Layout/FlexibleLayout" unique_id=1335562493 instance=ExtResource("7_ih0ps")]
+[node name="Main" parent="MainContainer/VBoxContainer/Layout/FlexibleLayout" unique_id=1335562493 instance=ExtResource("7_ih0ps")]
+unique_name_in_owner = true
layout_mode = 0
anchors_preset = 0
anchor_right = 0.0
@@ -173,13 +179,13 @@ offset_bottom = 32.0
grow_horizontal = 1
grow_vertical = 1
-[node name="ConsoleResizer" type="Control" parent="VBoxContainer" unique_id=2025564150]
+[node name="ConsoleResizer" type="Control" parent="MainContainer/VBoxContainer" unique_id=2025564150]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 10)
layout_mode = 2
mouse_default_cursor_shape = 9
-[node name="ResizerBar" type="PanelContainer" parent="VBoxContainer/ConsoleResizer" unique_id=606354979]
+[node name="ResizerBar" type="PanelContainer" parent="MainContainer/VBoxContainer/ConsoleResizer" unique_id=606354979]
custom_minimum_size = Vector2(0, 4)
layout_mode = 1
anchors_preset = 14
@@ -192,28 +198,29 @@ size_flags_horizontal = 4
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_2cpsi")
-[node name="Console" type="HBoxContainer" parent="VBoxContainer" unique_id=9505509]
+[node name="Console" type="HBoxContainer" parent="MainContainer/VBoxContainer" unique_id=9505509]
unique_name_in_owner = true
visible = false
custom_minimum_size = Vector2(0, 100)
layout_mode = 2
script = ExtResource("8_1tb00")
-[node name="RichTextLabel" type="RichTextLabel" parent="VBoxContainer/Console" unique_id=223286998]
+[node name="RichTextLabel" type="RichTextLabel" parent="MainContainer/VBoxContainer/Console" unique_id=223286998]
custom_minimum_size = Vector2(0, 100)
layout_mode = 2
size_flags_horizontal = 3
bbcode_enabled = true
scroll_following = true
-[node name="StatusBar" type="PanelContainer" parent="VBoxContainer" unique_id=1997079745]
+[node name="StatusBar" type="PanelContainer" parent="MainContainer/VBoxContainer" unique_id=1997079745]
layout_mode = 2
theme_type_variation = &"MM_StatusBarBackground"
-[node name="HBox" type="HBoxContainer" parent="VBoxContainer/StatusBar" unique_id=860693887]
+[node name="HBox" type="HBoxContainer" parent="MainContainer/VBoxContainer/StatusBar" unique_id=860693887]
layout_mode = 2
-[node name="Tip" type="RichTextLabel" parent="VBoxContainer/StatusBar/HBox" unique_id=2056192730]
+[node name="Tip" type="RichTextLabel" parent="MainContainer/VBoxContainer/StatusBar/HBox" unique_id=2056192730]
+unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 4
@@ -221,9 +228,9 @@ bbcode_enabled = true
fit_content = true
scroll_active = false
-[node name="Timer" type="Timer" parent="VBoxContainer/StatusBar/HBox/Tip" unique_id=654728135]
+[node name="Timer" type="Timer" parent="MainContainer/VBoxContainer/StatusBar/HBox/Tip" unique_id=654728135]
-[node name="UndoRedoLabel" type="Label" parent="VBoxContainer/StatusBar/HBox" unique_id=984075942]
+[node name="UndoRedoLabel" type="Label" parent="MainContainer/VBoxContainer/StatusBar/HBox" unique_id=984075942]
unique_name_in_owner = true
visible = false
layout_mode = 2
@@ -231,14 +238,14 @@ size_flags_horizontal = 4
text = "Undo/Redo action added"
script = SubResource("6")
-[node name="AnimationPlayer" type="AnimationPlayer" parent="VBoxContainer/StatusBar/HBox/UndoRedoLabel" unique_id=955898904]
+[node name="AnimationPlayer" type="AnimationPlayer" parent="MainContainer/VBoxContainer/StatusBar/HBox/UndoRedoLabel" unique_id=955898904]
libraries/ = SubResource("AnimationLibrary_kxf7t")
-[node name="ConsoleControls" type="HBoxContainer" parent="VBoxContainer/StatusBar/HBox" unique_id=365066398]
+[node name="ConsoleControls" type="HBoxContainer" parent="MainContainer/VBoxContainer/StatusBar/HBox" unique_id=365066398]
layout_mode = 2
alignment = 2
-[node name="ClearConsoleButton" type="TextureButton" parent="VBoxContainer/StatusBar/HBox/ConsoleControls" unique_id=416342385]
+[node name="ClearConsoleButton" type="TextureButton" parent="MainContainer/VBoxContainer/StatusBar/HBox/ConsoleControls" unique_id=416342385]
unique_name_in_owner = true
modulate = Color(1, 1, 1, 0.49803922)
custom_minimum_size = Vector2(20, 20)
@@ -248,7 +255,7 @@ size_flags_vertical = 4
tooltip_text = "Clear console"
stretch_mode = 0
-[node name="ConsoleButton" type="TextureButton" parent="VBoxContainer/StatusBar/HBox/ConsoleControls" unique_id=1288312618]
+[node name="ConsoleButton" type="TextureButton" parent="MainContainer/VBoxContainer/StatusBar/HBox/ConsoleControls" unique_id=1288312618]
unique_name_in_owner = true
modulate = Color(1, 1, 1, 0.49803922)
custom_minimum_size = Vector2(20, 20)
@@ -259,41 +266,41 @@ size_flags_vertical = 4
tooltip_text = "Show console"
stretch_mode = 0
-[node name="VSeparator1" type="VSeparator" parent="VBoxContainer/StatusBar/HBox" unique_id=398470012]
+[node name="VSeparator1" type="VSeparator" parent="MainContainer/VBoxContainer/StatusBar/HBox" unique_id=398470012]
layout_mode = 2
-[node name="Share" parent="VBoxContainer/StatusBar/HBox" unique_id=798130657 instance=ExtResource("12")]
+[node name="Share" parent="MainContainer/VBoxContainer/StatusBar/HBox" unique_id=798130657 instance=ExtResource("12")]
unique_name_in_owner = true
layout_mode = 2
-[node name="VSeparator2" type="VSeparator" parent="VBoxContainer/StatusBar/HBox" unique_id=46983986]
+[node name="VSeparator2" type="VSeparator" parent="MainContainer/VBoxContainer/StatusBar/HBox" unique_id=46983986]
layout_mode = 2
-[node name="ClipBoardAnalyzer" type="HBoxContainer" parent="VBoxContainer/StatusBar/HBox" unique_id=500957646]
+[node name="ClipBoardAnalyzer" type="HBoxContainer" parent="MainContainer/VBoxContainer/StatusBar/HBox" unique_id=500957646]
layout_mode = 2
script = SubResource("9")
-[node name="Clipboard" type="TextureRect" parent="VBoxContainer/StatusBar/HBox/ClipBoardAnalyzer" unique_id=1605541228]
+[node name="Clipboard" type="TextureRect" parent="MainContainer/VBoxContainer/StatusBar/HBox/ClipBoardAnalyzer" unique_id=1605541228]
visible = false
layout_mode = 2
size_flags_vertical = 4
mouse_filter = 2
texture = SubResource("8")
-[node name="Contents" type="TextureRect" parent="VBoxContainer/StatusBar/HBox/ClipBoardAnalyzer" unique_id=795860269]
+[node name="Contents" type="TextureRect" parent="MainContainer/VBoxContainer/StatusBar/HBox/ClipBoardAnalyzer" unique_id=795860269]
layout_mode = 2
size_flags_vertical = 4
mouse_filter = 2
texture = ExtResource("15")
-[node name="Timer" type="Timer" parent="VBoxContainer/StatusBar/HBox/ClipBoardAnalyzer" unique_id=358487496]
+[node name="Timer" type="Timer" parent="MainContainer/VBoxContainer/StatusBar/HBox/ClipBoardAnalyzer" unique_id=358487496]
wait_time = 0.5
autostart = true
-[node name="VSeparator3" type="VSeparator" parent="VBoxContainer/StatusBar/HBox" unique_id=1220214490]
+[node name="VSeparator3" type="VSeparator" parent="MainContainer/VBoxContainer/StatusBar/HBox" unique_id=1220214490]
layout_mode = 2
-[node name="RenderCounter" parent="VBoxContainer/StatusBar/HBox" unique_id=57795798 instance=ExtResource("11")]
+[node name="RenderCounter" parent="MainContainer/VBoxContainer/StatusBar/HBox" unique_id=57795798 instance=ExtResource("11")]
layout_mode = 2
[node name="NodeFactory" type="Node" parent="." unique_id=738541505]
@@ -302,13 +309,13 @@ script = ExtResource("9")
[node name="AddNodePopup" parent="." unique_id=142473620 instance=ExtResource("7")]
visible = false
-[connection signal="layout_changed" from="VBoxContainer/Layout/FlexibleLayout" to="." method="update_menus"]
-[connection signal="gui_input" from="VBoxContainer/ConsoleResizer" to="VBoxContainer/Console" method="_on_console_resizer_gui_input"]
-[connection signal="gui_input" from="VBoxContainer/ConsoleResizer/ResizerBar" to="VBoxContainer/Console" method="_on_console_resizer_gui_input"]
-[connection signal="meta_clicked" from="VBoxContainer/Console/RichTextLabel" to="VBoxContainer/Console" method="_on_rich_text_label_meta_clicked"]
-[connection signal="meta_hover_ended" from="VBoxContainer/Console/RichTextLabel" to="VBoxContainer/Console" method="_on_rich_text_label_meta_hover_ended"]
-[connection signal="meta_hover_started" from="VBoxContainer/Console/RichTextLabel" to="VBoxContainer/Console" method="_on_rich_text_label_meta_hover_started"]
-[connection signal="timeout" from="VBoxContainer/StatusBar/HBox/Tip/Timer" to="." method="_on_Tip_Timer_timeout"]
-[connection signal="pressed" from="VBoxContainer/StatusBar/HBox/ConsoleControls/ClearConsoleButton" to="VBoxContainer/Console" method="clear"]
-[connection signal="pressed" from="VBoxContainer/StatusBar/HBox/ConsoleControls/ConsoleButton" to="VBoxContainer/Console" method="toggle"]
-[connection signal="timeout" from="VBoxContainer/StatusBar/HBox/ClipBoardAnalyzer/Timer" to="VBoxContainer/StatusBar/HBox/ClipBoardAnalyzer" method="_on_Timer_timeout"]
+[connection signal="layout_changed" from="MainContainer/VBoxContainer/Layout/FlexibleLayout" to="." method="update_menus"]
+[connection signal="gui_input" from="MainContainer/VBoxContainer/ConsoleResizer" to="MainContainer/VBoxContainer/Console" method="_on_console_resizer_gui_input"]
+[connection signal="gui_input" from="MainContainer/VBoxContainer/ConsoleResizer/ResizerBar" to="MainContainer/VBoxContainer/Console" method="_on_console_resizer_gui_input"]
+[connection signal="meta_clicked" from="MainContainer/VBoxContainer/Console/RichTextLabel" to="MainContainer/VBoxContainer/Console" method="_on_rich_text_label_meta_clicked"]
+[connection signal="meta_hover_ended" from="MainContainer/VBoxContainer/Console/RichTextLabel" to="MainContainer/VBoxContainer/Console" method="_on_rich_text_label_meta_hover_ended"]
+[connection signal="meta_hover_started" from="MainContainer/VBoxContainer/Console/RichTextLabel" to="MainContainer/VBoxContainer/Console" method="_on_rich_text_label_meta_hover_started"]
+[connection signal="timeout" from="MainContainer/VBoxContainer/StatusBar/HBox/Tip/Timer" to="." method="_on_Tip_Timer_timeout"]
+[connection signal="pressed" from="MainContainer/VBoxContainer/StatusBar/HBox/ConsoleControls/ClearConsoleButton" to="MainContainer/VBoxContainer/Console" method="clear"]
+[connection signal="pressed" from="MainContainer/VBoxContainer/StatusBar/HBox/ConsoleControls/ConsoleButton" to="MainContainer/VBoxContainer/Console" method="toggle"]
+[connection signal="timeout" from="MainContainer/VBoxContainer/StatusBar/HBox/ClipBoardAnalyzer/Timer" to="MainContainer/VBoxContainer/StatusBar/HBox/ClipBoardAnalyzer" method="_on_Timer_timeout"]
diff --git a/material_maker/nodes/base.gd b/material_maker/nodes/base.gd
index ec8a871170..8ce5a90eb8 100644
--- a/material_maker/nodes/base.gd
+++ b/material_maker/nodes/base.gd
@@ -331,15 +331,7 @@ func _on_gui_input(event) -> void:
doubleclicked = true
if event.button_index == MOUSE_BUTTON_RIGHT:
accept_event()
- var menu : PopupMenu = create_context_menu()
- if menu != null:
- if menu.get_item_count() != 0:
- add_child(menu)
- menu.popup_hide.connect(menu.queue_free)
- menu.id_pressed.connect(self._on_menu_id_pressed)
- mm_globals.popup_menu(menu, self)
- else:
- menu.free()
+ show_context_menu()
elif doubleclicked:
doubleclicked = false
if generator is MMGenGraph:
@@ -421,6 +413,17 @@ func create_context_menu() -> PopupMenu:
menu.add_item(tr("Propagate changes"), MENU_PROPAGATE_CHANGES)
return menu
+func show_context_menu() -> void:
+ var menu : PopupMenu = create_context_menu()
+ if menu != null:
+ if menu.get_item_count() != 0:
+ add_child(menu)
+ menu.popup_hide.connect(menu.queue_free)
+ menu.id_pressed.connect(self._on_menu_id_pressed)
+ mm_globals.popup_menu(menu, self)
+ else:
+ menu.free()
+
func _on_menu_id_pressed(id : int) -> void:
match id:
MENU_PROPAGATE_CHANGES:
diff --git a/material_maker/nodes/debug/debug.gd b/material_maker/nodes/debug/debug.gd
index a5fd1d00e1..0aa56645eb 100644
--- a/material_maker/nodes/debug/debug.gd
+++ b/material_maker/nodes/debug/debug.gd
@@ -1,3 +1,4 @@
+class_name MMGraphDebug
extends MMGraphNodeBase
func _ready():
diff --git a/material_maker/nodes/generic/generic.tscn b/material_maker/nodes/generic/generic.tscn
index b6e7ae52bd..d93efbbef4 100644
--- a/material_maker/nodes/generic/generic.tscn
+++ b/material_maker/nodes/generic/generic.tscn
@@ -5,7 +5,6 @@
[node name="Generic" type="GraphNode" unique_id=1189007728]
offset_right = 95.0
offset_bottom = 29.0
-scaling_menus = true
title = "Generic"
script = ExtResource("1")
diff --git a/material_maker/nodes/minimal.gd b/material_maker/nodes/minimal.gd
index d26a2eca0a..3b858d9ed6 100644
--- a/material_maker/nodes/minimal.gd
+++ b/material_maker/nodes/minimal.gd
@@ -13,7 +13,7 @@ const CLOSE_ICON : Texture2D = preload("res://material_maker/icons/close.tres")
func _ready() -> void:
- scaling_menus = true
+ scaling_menus = false
position_offset_changed.connect(self._on_offset_changed)
if buttons == null:
buttons = HBoxContainer.new()
diff --git a/material_maker/nodes/portal/portal.gd b/material_maker/nodes/portal/portal.gd
index 59ba9e23b6..1c3e682b7b 100644
--- a/material_maker/nodes/portal/portal.gd
+++ b/material_maker/nodes/portal/portal.gd
@@ -10,7 +10,7 @@ var is_editing : bool = false
var syncing_io : bool = false
var is_navigating_source : bool = false
-const label_y_offset : float = 35.0
+const LABEL_Y_OFFSET : float = 35.0
func _ready() -> void:
super._ready()
@@ -41,7 +41,7 @@ func _draw() -> void:
if generator.horizontal_label:
label_draw_pos += Vector2(31.0 if is_portal_in() else (-label_size.x - 31.0), 5.0)
else:
- label_draw_pos -= Vector2(label_size.x * 0.5, label_y_offset)
+ label_draw_pos -= Vector2(label_size.x * 0.5, LABEL_Y_OFFSET)
draw_string_outline(LABEL_FONT, label_draw_pos, get_link(), HORIZONTAL_ALIGNMENT_CENTER, -1, label_font_size, 5, Color.BLACK)
draw_string(LABEL_FONT, label_draw_pos, get_link(), HORIZONTAL_ALIGNMENT_CENTER, -1, label_font_size, label_color)
@@ -299,6 +299,19 @@ func set_color(c : Color) -> void:
queue_redraw()
get_parent().send_changed_signal()
+func get_rect_with_link() -> Rect2:
+ var label_size : Vector2 = LABEL_FONT.get_string_size(
+ get_link(), HORIZONTAL_ALIGNMENT_CENTER)
+ var label_width_half = label_size.x * 0.5
+ var r : Rect2 = Rect2(Vector2.ZERO, size)
+ if generator.horizontal_label:
+ r = r.grow_side(SIDE_RIGHT if is_portal_in() else SIDE_LEFT, label_size.x + 31.0)
+ else:
+ r = r.grow_side(SIDE_LEFT, label_width_half)
+ r = r.grow_side(SIDE_RIGHT, label_width_half)
+ r = r.grow_side(SIDE_TOP, LABEL_Y_OFFSET)
+ return r
+
#region portal link edit
## Replaces all links from [param from_link] to [param new_link].
@@ -317,7 +330,7 @@ func replace_links(new_link : String, from_link : String) -> void:
p.on_parameter_changed("link", new_link)
func edit_box_set_position(edit : LineEdit) -> void:
- var y_offset : float = label_y_offset + 21.0
+ var y_offset : float = LABEL_Y_OFFSET + 21.0
var g : MMGraphEdit = get_parent()
if g == null:
edit.queue_free()
diff --git a/material_maker/nodes/reroute/reroute.gd b/material_maker/nodes/reroute/reroute.gd
index 4c752c7ea0..e13173b6c0 100644
--- a/material_maker/nodes/reroute/reroute.gd
+++ b/material_maker/nodes/reroute/reroute.gd
@@ -1,3 +1,4 @@
+class_name MMGraphReroute
extends MMGraphNodeMinimal
diff --git a/material_maker/nodes/switch/switch.gd b/material_maker/nodes/switch/switch.gd
index 8aacfaf32d..aeaae37542 100644
--- a/material_maker/nodes/switch/switch.gd
+++ b/material_maker/nodes/switch/switch.gd
@@ -1,3 +1,4 @@
+class_name MMGraphSwitch
extends MMGraphNodeGeneric
var fixed_lines : int = 0
diff --git a/material_maker/panels/graph_edit/graph_actions_menu.gd b/material_maker/panels/graph_edit/graph_actions_menu.gd
new file mode 100644
index 0000000000..cc28b82f9e
--- /dev/null
+++ b/material_maker/panels/graph_edit/graph_actions_menu.gd
@@ -0,0 +1,41 @@
+extends PanelContainer
+
+var graph : MMGraphEdit
+
+func _ready() -> void:
+ if OS.get_name() != "Android":
+ hide()
+
+func _on_knife_tool_toggled(toggled_on : bool) -> void:
+ if not graph:
+ graph = mm_globals.main_window.get_current_graph_edit()
+ if toggled_on:
+ if not graph.cut_drag_finished.is_connected(reset_knife_action_button):
+ graph.cut_drag_finished.connect(reset_knife_action_button)
+ should_hide_selection_rect(true)
+ should_disable_graph_elements(true)
+ graph.drag_cut_line.clear()
+ else:
+ reset_knife_action_button()
+ graph.valid_drag_cut_entry = toggled_on
+
+func reset_knife_action_button() -> void:
+ $HBox/KnifeTool.hide()
+ $HBox/KnifeTool.show.call_deferred()
+ $HBox/KnifeTool.set_pressed_no_signal(false)
+ should_disable_graph_elements(false)
+ should_hide_selection_rect(false)
+
+func should_hide_selection_rect(is_hide : bool) -> void:
+ if is_hide:
+ graph.add_theme_color_override("selection_fill", Color.TRANSPARENT)
+ graph.add_theme_color_override("selection_stroke", Color.TRANSPARENT)
+ else:
+ graph.remove_theme_color_override("selection_fill")
+ graph.remove_theme_color_override("selection_stroke")
+
+func should_disable_graph_elements(disable : bool) -> void:
+ for x in graph.get_children():
+ if x is GraphElement:
+ x.modulate.a = 0.5 if disable else 1.0
+ x.selectable = not disable
diff --git a/material_maker/panels/graph_edit/graph_actions_menu.gd.uid b/material_maker/panels/graph_edit/graph_actions_menu.gd.uid
new file mode 100644
index 0000000000..ec6fe17ee0
--- /dev/null
+++ b/material_maker/panels/graph_edit/graph_actions_menu.gd.uid
@@ -0,0 +1 @@
+uid://c7hvi7bvtgwbd
diff --git a/material_maker/panels/graph_edit/graph_edit.gd b/material_maker/panels/graph_edit/graph_edit.gd
index f47e33fa8c..bee953a6d8 100644
--- a/material_maker/panels/graph_edit/graph_edit.gd
+++ b/material_maker/panels/graph_edit/graph_edit.gd
@@ -16,7 +16,7 @@ class Preview:
var node_factory = null
-var save_path := "": set = set_save_path
+var save_path : String = "": set = set_save_path
var need_save : bool = false
var save_crash_recovery_path = ""
var need_save_crash_recovery : bool = false
@@ -68,11 +68,17 @@ var is_dragging_connection : bool = false:
is_dragging_connection = v
set_process_if_necessary()
+var has_double_tap : bool = false
+
+var node_actions_panel : NodeActionsPanel
+
signal save_path_changed
signal graph_changed
signal view_updated
signal preview_changed
+## Emitted when connections are cut using the knife tool.
+signal cut_drag_finished
func _ready() -> void:
OS.low_processor_usage_mode = true
@@ -82,6 +88,13 @@ func _ready() -> void:
add_valid_connection_type(42, t)
node_popup.about_to_popup.connect(func(): valid_drag_cut_entry = false)
+ if mm_globals.get_config("touch_node_actions"):
+ node_actions_panel = NodeActionsPanel.new(self)
+
+ if mm_globals.get_config("touch_optimization"):
+ $GraphUI/ButtonReroll.hide()
+ $GraphUI/ButtonShowTree.hide()
+
func _exit_tree():
remove_crash_recovery_file()
@@ -130,8 +143,24 @@ func process_port_click(pressed : bool):
port_click_port_index = -1
return
-
func _input(event : InputEvent) -> void:
+ if DisplayServer.is_touchscreen_available():
+ if event.get("position") and get_rect().has_point(
+ make_input_local(event).position):
+ if OS.get_name() == "Android":
+ if event is InputEventPanGesture:
+ scroll_offset += event.delta
+ if is_dragging_connection:
+ force_connection_drag_end()
+ accept_event()
+ elif OS.get_name() == "iOS":
+ if event is InputEventScreenDrag and event.index == 1:
+ scroll_offset -= event.relative
+ force_selection_end()
+ if is_dragging_connection:
+ force_connection_drag_end()
+ accept_event()
+
# Handle node grab
if has_grab:
var selected_nodes := get_selected_nodes()
@@ -175,7 +204,7 @@ func _input(event : InputEvent) -> void:
if event.unicode >= KEY_0 and event.unicode <= KEY_9 and event.pressed:
grab_focus()
-func _gui_input(event) -> void:
+func _gui_input(event : InputEvent) -> void:
if (
event.is_action_pressed("ui_library_popup")
and not Input.is_key_pressed(KEY_CTRL)
@@ -187,21 +216,7 @@ func _gui_input(event) -> void:
node_popup.position = Vector2i(get_screen_transform()*get_local_mouse_position())
node_popup.show_popup()
elif event.is_action_released("ui_cut_drag"):
- var conns : Array[Dictionary]
- for p in len(drag_cut_line) - 1:
- var rect : Rect2
- rect.position = drag_cut_line[p]
- rect.end = drag_cut_line[p + 1]
- conns = get_connections_intersecting_with_rect(rect.abs())
- if conns.size():
- connections_to_cut.append_array(conns)
- if connections_to_cut.size():
- on_cut_connections(connections_to_cut)
- connections_to_cut.clear()
- Input.set_custom_mouse_cursor(null)
- drag_cut_line.clear()
- conns.clear()
- queue_redraw()
+ do_cut_drag()
elif event.is_action_released("ui_lasso_select", true):
for node in get_children():
if node is GraphElement:
@@ -378,7 +393,29 @@ func _gui_input(event) -> void:
Input.set_custom_mouse_cursor(null)
lasso_points.clear()
queue_redraw()
-
+ elif event is InputEventScreenTouch:
+ if not event.pressed:
+ if mm_touch.last_touch_duration_msec < 150:
+ cut_drag_finished.emit()
+ valid_drag_cut_entry = false
+ if mm_touch.last_touch_duration_msec < 80:
+ if event.index == 1:
+ mm_globals.main_window.edit_undo()
+ elif event.index == 2:
+ mm_globals.main_window.edit_redo()
+ elif valid_drag_cut_entry and event.index == 0:
+ do_cut_drag()
+ valid_drag_cut_entry = false
+ elif event is InputEventScreenDrag and event.index == 0 and valid_drag_cut_entry:
+ # actions menu knife gesture
+ if is_dragging_connection:
+ force_connection_drag_end()
+ drag_cut_line.append(get_local_mouse_position())
+ queue_redraw()
+ else:
+ if not valid_drag_cut_entry:
+ drag_cut_line.clear()
+ queue_redraw()
func get_padded_node_rect(graph_node:GraphNode) -> Rect2:
var rect : Rect2 = graph_node.get_global_rect()
@@ -591,7 +628,7 @@ func set_need_save(ns = true) -> void:
update_tab_title()
need_save_crash_recovery = true
-func set_save_path(path: String) -> void:
+func set_save_path(path : String) -> void:
if path != save_path:
remove_crash_recovery_file()
need_save_crash_recovery = false
@@ -703,7 +740,7 @@ func new_material(init_nodes = {nodes=[{name="Material", type="material",paramet
add_child(top_generator)
move_child(top_generator, 0)
update_view(top_generator)
- center_view()
+ center_view.call_deferred()
set_save_path("")
set_need_save(false)
@@ -1643,7 +1680,6 @@ func add_reroute_under_mouse() -> void:
var next : Dictionary = generator.serialize()
undoredo_create_step("Reroute on connection", generator.get_hier_name(), prev, next)
-
func add_reroute_to_input(node : MMGraphNodeMinimal, port_index : int) -> void:
var prev = generator.serialize()
var new_connections = []
@@ -2039,6 +2075,34 @@ func _on_button_reroll_pressed() -> void:
func _on_button_reroll_mouse_entered() -> void:
mm_globals.set_tip_text("#LMB: Reroll all nodes, Shift+#LMB: Reroll selected nodes")
+func do_cut_drag() -> void:
+ var conns : Array[Dictionary]
+ for p in len(drag_cut_line) - 1:
+ var rect : Rect2
+ rect.position = drag_cut_line[p]
+ rect.end = drag_cut_line[p + 1]
+ conns = get_connections_intersecting_with_rect(rect.abs())
+ if conns.size():
+ connections_to_cut.append_array(conns)
+ if connections_to_cut.size():
+ on_cut_connections(connections_to_cut)
+ connections_to_cut.clear()
+ Input.set_custom_mouse_cursor(null)
+ drag_cut_line.clear()
+ conns.clear()
+ queue_redraw()
+ cut_drag_finished.emit()
+
+#region mobile-specific
+
+func force_selection_end() -> void:
+ var e : InputEventMouseButton = InputEventMouseButton.new()
+ e.pressed = false
+ e.button_index = MOUSE_BUTTON_LEFT
+ e.position = get_local_mouse_position()
+ Input.parse_input_event(e)
+
+#endregion
func align_start() -> void:
var nodes : Array = get_selected_nodes()
var min_offset : float = INF
diff --git a/material_maker/panels/graph_edit/graph_edit.tscn b/material_maker/panels/graph_edit/graph_edit.tscn
index 59333b1487..489e982315 100644
--- a/material_maker/panels/graph_edit/graph_edit.tscn
+++ b/material_maker/panels/graph_edit/graph_edit.tscn
@@ -23,14 +23,12 @@ atlas = ExtResource("2")
region = Rect2(0, 48, 16, 16)
[node name="GraphEdit" type="GraphEdit" unique_id=909518343 groups=["mm_graphedit"]]
-anchors_preset = 15
+anchors_preset = -1
anchor_right = 1.0
anchor_bottom = 1.0
offset_top = -1.0
offset_right = 1529.0
offset_bottom = 1193.0
-grow_horizontal = 2
-grow_vertical = 2
grid_pattern = 1
snapping_distance = 24
right_disconnects = true
diff --git a/material_maker/panels/graph_edit/node_actions_panel.gd b/material_maker/panels/graph_edit/node_actions_panel.gd
new file mode 100644
index 0000000000..f79257bd3d
--- /dev/null
+++ b/material_maker/panels/graph_edit/node_actions_panel.gd
@@ -0,0 +1,360 @@
+class_name NodeActionsPanel
+extends PanelContainer
+
+## floating panel for node titlebar actions, mainly for touch.
+
+static var sb_selection : StyleBoxFlat
+
+const BUTTON_SIZE : Vector2 = Vector2(16, 16)
+const H_PAD : int = 16
+const AREA_PAD : int = 24
+const PADDING : Vector2 = Vector2(AREA_PAD + H_PAD, -AREA_PAD)
+const AVOID_PAD : int = 12
+
+var parent : MMGraphEdit
+var selection_area : Rect2
+
+var is_updating : bool = false
+var is_theme_updating : bool = false
+
+var selected_nodes : Array
+
+var container : VBoxContainer
+var buttons : Dictionary[String, ActionButton]
+
+func _init(graph : MMGraphEdit) -> void:
+ name = "NodeActionsPanel"
+ parent = graph
+ parent.add_child(self)
+ scale = Vector2(2.5, 2.5)
+ top_level = true
+
+func _ready() -> void:
+ hide()
+ init_stylebox()
+ setup_signals()
+
+ container = VBoxContainer.new()
+ add_child(container)
+ create_buttons()
+
+ theme_type_variation = "MM_PanelMenuSubPanel"
+
+func _notification(what : int) -> void:
+ if what == NOTIFICATION_THEME_CHANGED:
+ if not is_node_ready():
+ await ready
+ update_button_icons()
+ update_stylebox()
+
+func _input(event : InputEvent) -> void:
+ if is_visible_in_tree() and event is InputEventPanGesture and event.delta.length():
+ hide_panel()
+
+func viewport_focus_changed(c : Control) -> void:
+ if visible and c.owner and c.owner.get_script() in [GradientPopup, GradientEdit]:
+ hide_panel()
+
+func setup_signals() -> void:
+ get_viewport().gui_focus_changed.connect(viewport_focus_changed)
+ parent.node_selected.connect(should_panel_update.unbind(1))
+ parent.scroll_offset_changed.connect(should_panel_update.unbind(1))
+ parent.node_deselected.connect(hide_panel.unbind(1))
+ parent.begin_node_move.connect(hide_panel)
+ parent.connection_drag_started.connect(hide_panel.unbind(3))
+ parent.draw.connect(draw_selection_area)
+
+class ActionButton extends Button:
+ ## Emitted when button is right clicked (long pressed for touch)
+ signal on_show_popup
+
+ func _gui_input(event : InputEvent) -> void:
+ if event is InputEventMouseButton and event.pressed:
+ if event.button_index == MOUSE_BUTTON_RIGHT:
+ on_show_popup.emit()
+
+ func disconnect_actions() -> void:
+ for s in [ pressed, on_show_popup ]:
+ for connection in s.get_connections():
+ if s.is_connected(connection.callable):
+ s.disconnect(connection.callable)
+
+ func connect_actions(pressed_callback : Callable = Callable(),
+ popup_callback : Callable = Callable()) -> void:
+ disconnect_actions()
+ if visible:
+ if pressed_callback != Callable() and not pressed.is_connected(pressed_callback):
+ pressed.connect(pressed_callback)
+ if popup_callback != Callable() and not on_show_popup.is_connected(popup_callback):
+ on_show_popup.connect(popup_callback)
+
+#region panel creation/update
+
+func input_released() -> void:
+ while Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
+ if visible and Input.is_key_pressed(KEY_SHIFT):
+ hide()
+ await get_tree().process_frame
+ await get_tree().process_frame
+
+func create_panel() -> void:
+ if not is_node_ready():
+ return
+ await input_released()
+
+ selected_nodes = parent.get_selected_nodes()
+ if selected_nodes.is_empty():
+ return hide_panel()
+
+ for button : ActionButton in container.get_children():
+ button.show()
+
+ var nodes_rect : Rect2 = Rect2(0, 0, -1, -1)
+ for n in selected_nodes:
+ if nodes_rect.size == Vector2(-1, -1):
+ nodes_rect = calc_node_rect(n)
+ else:
+ nodes_rect = nodes_rect.merge(calc_node_rect(n))
+
+ if not n.tree_exiting.is_connected(should_panel_update):
+ n.tree_exiting.connect(should_panel_update)
+
+ global_position = nodes_rect.get_support(Vector2(1, -1)) + parent.global_position
+
+ if selected_nodes.size() == 1:
+ selection_area = Rect2()
+ global_position.x += AREA_PAD
+
+ var node : GraphElement = selected_nodes[0]
+ var gen : MMGenBase = node.generator
+
+ if is_node_simple(node):
+ buttons.minimize.hide()
+ buttons.randomize.hide()
+ buttons.generic.hide()
+ buttons.custom.hide()
+
+ if node is MMGraphSwitch:
+ buttons.custom.show()
+ buttons.custom.connect_actions(node_switch_edit.bind(node))
+
+ if should_node_panel_center(node):
+ var local_p : Vector2 = node.position
+ local_p.x += node.size.x * 0.5 * parent.zoom - size.x - 6.0
+ local_p.y += (node.size.y + H_PAD) * parent.zoom
+ global_position = parent.global_position + local_p
+ else:
+ buttons.close.visible = should_close_visible(gen)
+ buttons.randomize.visible = should_random_visible(gen)
+ buttons.generic.visible = should_generic_visible(gen)
+ buttons.custom.visible = should_custom_visible(gen)
+
+ buttons.randomize.connect_actions(node.on_randomness_pressed, node.randomness_button_create_popup)
+ buttons.generic.connect_actions(node.on_generic_pressed, node.generic_button_create_popup)
+ buttons.custom.connect_actions(node.edit_generator, node.custom_button_create_popup)
+
+ elif selected_nodes.size() > 1:
+ selection_area = nodes_rect
+ global_position += PADDING
+
+ buttons.close.visible = node_selection_can_be_deleted()
+ buttons.randomize.visible = node_selection_has_randomness()
+ buttons.generic.visible = false
+ buttons.custom.visible = false
+
+ buttons.randomize.connect_actions(randomize_selected_nodes)
+
+ size = get_combined_minimum_size()
+
+ avoid_intersecting_popups()
+ set_top_level()
+ show_panel()
+
+func is_node_simple(node : GraphElement) -> bool:
+ return node.get_script() in [ MMGraphPortal, MMGraphReroute,
+ MMGraphCommentLine, MMGraphSwitch, MMGraphComment,
+ MMGraphDebug, MMGraphNodeRemote ]
+
+func should_node_panel_center(node : GraphElement) -> bool:
+ return node.get_script() in [ MMGraphPortal, MMGraphReroute,
+ MMGraphCommentLine ]
+
+func set_top_level() -> void:
+ # have panel visible only within graph bounds
+ var prev : Vector2 = global_position
+ var graph_rect : Rect2 = parent.get_global_rect()
+ var panel_rect : Rect2 = get_global_rect()
+
+ # account for graph scrollbars width/height
+ var wh : int = -get_theme_stylebox("scroll").border_width_left * 2.0 - 6.0
+ graph_rect = graph_rect.grow_individual(0.0, 0.0, wh, wh)
+
+ # avoid covering subgraph menu and graph menubar
+ var graph_menu : ScrollContainer = mm_globals.main_window.projects_panel.get_node("MenuBar")
+ var intersect_subgraph_ui : bool = parent.subgraph_ui.get_global_rect().intersects(panel_rect)
+ var intersect_graph_menu : bool = graph_menu.get_global_rect().intersects(panel_rect)
+
+ top_level = graph_rect.encloses(panel_rect) and not (intersect_subgraph_ui or intersect_graph_menu)
+ global_position = prev
+
+var _gradient_edits : Array[Node]
+
+func avoid_intersecting_popups() -> void:
+ # avoid intersecting with GradientEdit's popup
+ if selected_nodes.size() != 1 or not selected_nodes[0]:
+ return
+ var node : GraphElement = selected_nodes[0]
+ var popup : GradientPopup
+
+ var edits : Array[Node] = node.find_children("*", "GradientEdit", true, false)
+ if edits.hash() != _gradient_edits.hash():
+ _gradient_edits = edits
+
+ for edit in _gradient_edits:
+ if edit and is_instance_valid(edit.popup):
+ popup = edit.popup
+ break
+
+ if not popup:
+ return
+ var panel_r : Rect2 = get_global_rect()
+ var popup_r : Rect2 = popup.get_global_rect()
+ if panel_r.intersects(popup_r):
+ global_position.y = popup_r.position.y - panel_r.size.y - AVOID_PAD
+
+func should_panel_update() -> void:
+ if is_updating:
+ return
+ is_updating = true
+ create_panel.call_deferred()
+
+func show_panel() -> void:
+ show()
+ move_to_front()
+ parent.queue_redraw()
+ is_updating = false
+
+func hide_panel() -> void:
+ hide()
+ selection_area = Rect2()
+ parent.queue_redraw()
+ is_updating = false
+
+func calc_node_rect(n : GraphElement) -> Rect2:
+ if n is MMGraphPortal:
+ var r : Rect2 = n.get_rect_with_link()
+ return Rect2(r.position * parent.zoom + n.position,
+ r.size * parent.zoom)
+ return Rect2(n.position, n.size * parent.zoom)
+
+#endregion
+
+#region generator conditionals/functions
+
+func node_switch_edit(node : MMGraphSwitch) -> void:
+ node.generator.toggle_editable()
+ node.update_node()
+
+func node_selection_has_generic() -> bool:
+ for node in selected_nodes:
+ if should_generic_visible(node.generator):
+ return true
+ return false
+
+func node_selection_has_randomness() -> bool:
+ for node in selected_nodes:
+ if should_random_visible(node.generator):
+ return true
+ return false
+
+func node_selection_can_be_deleted() -> bool:
+ for node in selected_nodes:
+ if should_close_visible(node.generator):
+ return true
+ return false
+
+func randomize_selected_nodes() -> void:
+ parent.undoredo.start_group()
+ for node in selected_nodes:
+ if should_random_visible(node.generator):
+ node.on_randomness_pressed()
+ parent.undoredo.end_group()
+
+func should_close_visible(g : MMGenBase) -> bool:
+ return g and g.can_be_deleted()
+
+func should_random_visible(g : MMGenBase) -> bool:
+ return g and g.has_randomness()
+
+func should_generic_visible(g : MMGenBase) -> bool:
+ return g and g.has_method("is_generic") and g.is_generic()
+
+func should_custom_visible(g : MMGenBase) -> bool:
+ return g and g.model == null and (g is MMGenShader or g is MMGenGraph)
+
+#endregion
+
+#region area stylebox draw/update
+
+func init_stylebox() -> void:
+ if not sb_selection:
+ sb_selection = StyleBoxFlat.new()
+ sb_selection.set_border_width_all(2)
+ sb_selection.set_corner_radius_all(4)
+ sb_selection.corner_detail = 4
+
+func update_stylebox() -> void:
+ if not sb_selection:
+ init_stylebox()
+
+ match ThemeUtils.current_theme:
+ ThemeUtils.CUSTOM_THEME:
+ sb_selection.bg_color = ThemeUtils.base_color.darkened(0.5)
+ sb_selection.border_color = ThemeUtils.base_color.lightened(0.2)
+ ThemeUtils.CLASSIC_THEME:
+ sb_selection.bg_color = Color(0.22, 0.255, 0.36, 1.0)
+ sb_selection.border_color = Color(0.377, 0.482, 0.65, 1.0)
+ ThemeUtils.DARK_THEME:
+ sb_selection.bg_color = Color(0.14, 0.14, 0.14, 1.0)
+ sb_selection.border_color = Color(0.355, 0.355, 0.355, 1.0)
+ ThemeUtils.LIGHT_THEME:
+ sb_selection.bg_color = Color(0.62, 0.62, 0.62, 1.0)
+ sb_selection.border_color = Color(0.33, 0.33, 0.33, 1.0)
+
+func draw_selection_area() -> void:
+ if selection_area.size != Vector2.ZERO and sb_selection and visible:
+ var ci : RID = parent.get_canvas_item()
+ sb_selection.draw(ci, selection_area.grow(AREA_PAD))
+
+#endregion
+
+#region button init/setup
+
+func create_buttons() -> void:
+ buttons.close = create_button(parent.remove_selection)
+ buttons.minimize = create_button(parent.minimize_selection)
+ buttons.randomize = create_button()
+ buttons.generic = create_button()
+ buttons.custom = create_button()
+
+func update_button_icons() -> void:
+ buttons.close.icon = get_theme_icon("delete_2x", "MM_Icons")
+ buttons.minimize.icon = get_theme_icon("minimize", "MM_Icons")
+ buttons.randomize.icon = get_theme_icon("randomize", "MM_Icons")
+ buttons.generic.icon = get_theme_icon("generic_size", "MM_Icons")
+ buttons.custom.icon = get_theme_icon("draw_2x", "MM_Icons")
+
+ buttons.randomize.add_theme_color_override("icon_normal_color", Color.WHITE)
+
+func create_button(pressed_callback : Callable = Callable()) -> ActionButton:
+ var button : ActionButton = ActionButton.new()
+ button.custom_minimum_size = BUTTON_SIZE
+ button.flat = true
+ button.expand_icon = true
+ button.add_theme_color_override("icon_hover_color", Color.WHITE)
+ if pressed_callback != Callable():
+ button.pressed.connect(pressed_callback)
+ container.add_child(button)
+ return button
+
+#endregion
diff --git a/material_maker/panels/graph_edit/node_actions_panel.gd.uid b/material_maker/panels/graph_edit/node_actions_panel.gd.uid
new file mode 100644
index 0000000000..405c05dc74
--- /dev/null
+++ b/material_maker/panels/graph_edit/node_actions_panel.gd.uid
@@ -0,0 +1 @@
+uid://dcre4rccoc1fw
diff --git a/material_maker/panels/library/library.gd b/material_maker/panels/library/library.gd
index 3ecf3f1efa..3f5b89fa51 100644
--- a/material_maker/panels/library/library.gd
+++ b/material_maker/panels/library/library.gd
@@ -49,6 +49,15 @@ func _ready() -> void:
init_expanded_items()
update_tree()
update_theme()
+
+ if mm_globals.get_config("touch_optimization"):
+ var web_btn : Button = Button.new()
+ web_btn.name = "GetFromWebsite"
+ web_btn.pressed.connect(_on_GetFromWebsite_pressed)
+ $Library/Filter.add_child(web_btn)
+ $Library/Filter.move_child(web_btn, 1)
+ $Library/GetFromWebsite.hide()
+
func _notification(what: int) -> void:
if what == NOTIFICATION_THEME_CHANGED:
@@ -59,6 +68,8 @@ func _notification(what: int) -> void:
button.icon = get_theme_icon("section_" + s.to_lower(), "MM_Icons")
update_category_button_styleboxes(button, s)
update_theme()
+ if mm_globals.get_config("touch_optimization"):
+ $Library/Filter.get_node("GetFromWebsite").icon = get_theme_icon("download", "MM_Icons")
func update_theme() -> void:
libraries_button.icon = get_theme_icon("settings", "MM_Icons")
diff --git a/material_maker/panels/library/library.tscn b/material_maker/panels/library/library.tscn
index 3b9143afcc..8bfece0610 100644
--- a/material_maker/panels/library/library.tscn
+++ b/material_maker/panels/library/library.tscn
@@ -90,8 +90,10 @@ item_5/id = 5
[connection signal="text_changed" from="Library/Filter/Filter" to="." method="_on_Filter_text_changed"]
[connection signal="about_to_popup" from="Library/Filter/Libraries" to="." method="_on_Libraries_about_to_show"]
+[connection signal="gui_input" from="Library/Tree" to="Library/Tree" method="_on_gui_input"]
[connection signal="item_collapsed" from="Library/Tree" to="." method="_on_Tree_item_collapsed"]
[connection signal="item_mouse_selected" from="Library/Tree" to="." method="_on_tree_item_mouse_selected"]
+[connection signal="ready" from="Library/Tree" to="Library/Tree" method="_on_ready"]
[connection signal="pressed" from="Library/GetFromWebsite" to="." method="_on_GetFromWebsite_pressed"]
[connection signal="about_to_popup" from="ItemMenu" to="Library" method="_on_PopupMenu_about_to_show"]
[connection signal="index_pressed" from="ItemMenu" to="." method="_on_PopupMenu_index_pressed"]
diff --git a/material_maker/panels/library/library_tree.gd b/material_maker/panels/library/library_tree.gd
index 6cc8e56139..df7457ffa5 100644
--- a/material_maker/panels/library/library_tree.gd
+++ b/material_maker/panels/library/library_tree.gd
@@ -2,7 +2,16 @@ extends Tree
@export var supports_drag : bool = true
-var scroll_position = 0.0
+var force_drag_started : bool
+
+var tree_scrollbar : VScrollBar
+
+func _on_ready() -> void:
+ for node in get_children(true):
+ if node is VScrollBar:
+ tree_scrollbar = node
+ if mm_globals.get_config("touch_optimization"):
+ %Tree.add_theme_constant_override("v_separation", 4)
func get_last_item(parent : TreeItem):
while true:
@@ -13,7 +22,7 @@ func get_last_item(parent : TreeItem):
return parent
parent = items.back()
-func _draw():
+func _draw() -> void:
if get_root() == null:
return
var last_tree_item = get_last_item(get_root())
@@ -33,14 +42,37 @@ func _draw():
draw_rect(Rect2(1, rect.position.y, 4, last_rect.position.y-rect.position.y+last_rect.size.y), color)
item = item.get_next()
-func _get_drag_data(_position):
- if !supports_drag:
+func _get_drag_data(_position) -> Variant:
+ var _data_preview : Dictionary = _get_data_preview()
+ if _data_preview.is_empty():
return null
+ else:
+ set_drag_preview(_data_preview.preview)
+ return _data_preview.data
+
+func _on_gui_input(event : InputEvent) -> void:
+ if not force_drag_started:
+ if event is InputEventScreenDrag and event.index == 0:
+ var icon_rect : Rect2 = get_item_area_rect(get_selected(), 1)
+ icon_rect = icon_rect.grow_individual(6, 0, 6, 0)
+ if icon_rect.has_point(get_local_mouse_position()):
+ ## 1-finger item drag from library
+ _force_drag()
+ accept_event()
+ elif event is InputEventScreenTouch and event.index == 0:
+ if not event.pressed and mm_touch.last_touch_duration_msec > 120:
+ deselect_all()
+
+ if OS.get_name() == "Android" and event is InputEventPanGesture:
+ tree_scrollbar.value += event.delta.y * 2.0
+ accept_event()
+
+func _get_data_preview() -> Dictionary:
var selected_item = get_selected()
if selected_item != null:
var data = selected_item.get_metadata(0)
if data == null:
- return null
+ return {}
var preview : Control
var preview_texture = selected_item.get_icon(1)
if preview_texture != null:
@@ -55,6 +87,22 @@ func _get_drag_data(_position):
else:
preview = Label.new()
preview.text = data.tree_item
- set_drag_preview(preview)
- return data
- return null
+
+ if mm_globals.get_config("touch_optimization"):
+ var offset : Vector2 = Vector2.ZERO
+ preview.scale = Vector2(1.5, 1.5)
+ offset = preview_texture.get_size() if preview_texture else preview.size
+ preview.offset_transform_enabled = true
+ preview.offset_transform_position = -offset * 0.5
+
+ return { "preview": preview, "data": data }
+ return {}
+
+func _force_drag() -> void:
+ if force_drag_started:
+ return
+ force_drag_started = true
+ var drag_data = _get_data_preview()
+ if not drag_data.is_empty():
+ force_drag(drag_data.data, drag_data.preview)
+ force_drag_started = false
diff --git a/material_maker/panels/preview_2d/control_point.gd b/material_maker/panels/preview_2d/control_point.gd
index 701dd7a0c7..8f76c07a94 100644
--- a/material_maker/panels/preview_2d/control_point.gd
+++ b/material_maker/panels/preview_2d/control_point.gd
@@ -19,6 +19,8 @@ var parent_control_node = null
var children_control_nodes = []
func _ready() -> void:
+ if mm_globals.get_config("touch_optimization"):
+ custom_minimum_size = size * 1.5
if parent_control != "":
parent_control_node = get_parent().get_node(parent_control)
if parent_control_node != null:
diff --git a/material_maker/panels/preview_2d/control_point.tscn b/material_maker/panels/preview_2d/control_point.tscn
index 0084844371..1fe7fbaaea 100644
--- a/material_maker/panels/preview_2d/control_point.tscn
+++ b/material_maker/panels/preview_2d/control_point.tscn
@@ -5,6 +5,7 @@
[node name="Point" type="TextureRect"]
mouse_filter = 0
mouse_default_cursor_shape = 13
+stretch_mode = 3
script = ExtResource("1")
[connection signal="gui_input" from="." to="." method="_on_Point_gui_input"]
diff --git a/material_maker/panels/preview_2d/export_menu.gd b/material_maker/panels/preview_2d/export_menu.gd
index 5d4efb1f6d..52c41694ae 100644
--- a/material_maker/panels/preview_2d/export_menu.gd
+++ b/material_maker/panels/preview_2d/export_menu.gd
@@ -113,7 +113,7 @@ func get_export_resolution() -> Vector2i:
func _on_image_pressed() -> void:
- var path: String = %ExportFolder.text
+ var path : String = %ExportFolder.text
var file_name: String = %ExportFile.text
if file_name:
diff --git a/material_maker/panels/preview_2d/preview_2d_panel.gd b/material_maker/panels/preview_2d/preview_2d_panel.gd
index b533ba1640..2f2a8478dd 100644
--- a/material_maker/panels/preview_2d/preview_2d_panel.gd
+++ b/material_maker/panels/preview_2d/preview_2d_panel.gd
@@ -57,6 +57,9 @@ var checker_brightness: int = 1:
material.set_shader_parameter("background_color_2", color_b)
mm_globals.set_config("preview"+config_var_suffix+"_checker_brightness", checker_brightness)
+const MIN_ZOOM : float = 0.005
+const MAX_ZOOM : float = 5.0
+
const POSTPROCESS_OPTIONS : Array = [
{ name="None", function="preview_2d(uv)" },
{ name="Lowres 32x32", function="preview_2d((floor(uv*32.0)+vec2(0.5))/32.0)" },
@@ -259,6 +262,7 @@ func on_resized() -> void:
var dragging : bool = false
var zooming : bool = false
+var magnifying : bool = false
func _input(event):
if event.is_pressed():
@@ -275,9 +279,9 @@ func _on_gui_input(event):
if event.pressed:
match event.button_index:
MOUSE_BUTTON_WHEEL_DOWN:
- new_scale = min(new_scale*1.05, 5.0)
+ new_scale = min(new_scale*1.05, MAX_ZOOM)
MOUSE_BUTTON_WHEEL_UP:
- new_scale = max(new_scale*0.95, 0.005)
+ new_scale = max(new_scale*0.95, MIN_ZOOM)
MOUSE_BUTTON_MIDDLE:
dragging = true
MOUSE_BUTTON_LEFT:
@@ -292,13 +296,21 @@ func _on_gui_input(event):
if dragging:
new_center = center-event.relative*view_scale/multiplier
elif zooming:
- new_scale = clamp(new_scale*(1.0+0.01*event.relative.y), 0.005, 5.0)
- elif event is InputEventPanGesture:
- new_center = center-event.delta*10.0*view_scale/multiplier
+ new_scale = clamp(new_scale*(1.0+0.01*event.relative.y), MIN_ZOOM, MAX_ZOOM)
elif event is InputEventMagnifyGesture:
- new_scale = clamp(new_scale/event.factor, 0.005, 5.0)
+ magnifying = true
+ new_scale = clampf(new_scale / event.factor, MIN_ZOOM, MAX_ZOOM)
+ elif event is InputEventScreenTouch and event.index == 1:
+ # two-finger tap: center view
+ if not event.pressed and mm_touch.last_touch_duration_msec < 80:
+ reset_view.call_deferred()
+ elif event is InputEventScreenDrag and event.index == 0:
+ new_center = center-event.relative * view_scale/multiplier
+ else:
+ magnifying = false
if new_scale != view_scale:
- new_center = center+offset_from_center*(view_scale-new_scale)/multiplier
+ if not magnifying:
+ new_center = center+offset_from_center*(view_scale-new_scale)/multiplier
view_scale = new_scale
need_update = true
if new_center != center:
diff --git a/material_maker/panels/preview_2d/preview_2d_panel.tscn b/material_maker/panels/preview_2d/preview_2d_panel.tscn
index 08467621f2..28f86f2c6b 100644
--- a/material_maker/panels/preview_2d/preview_2d_panel.tscn
+++ b/material_maker/panels/preview_2d/preview_2d_panel.tscn
@@ -1,4 +1,4 @@
-[gd_scene load_steps=30 format=3 uid="uid://b7x7yqgsurxhv"]
+[gd_scene format=3 uid="uid://b7x7yqgsurxhv"]
[ext_resource type="Texture2D" uid="uid://c0j4px4n72di5" path="res://material_maker/icons/icons.tres" id="1"]
[ext_resource type="PackedScene" uid="uid://est6pi7xbptp" path="res://material_maker/panels/preview_2d/control_point.tscn" id="2"]
@@ -19,7 +19,7 @@
[ext_resource type="Script" uid="uid://pielyrq85378" path="res://material_maker/panels/preview_2d/two_icon_toggle_button.gd" id="17_07kc5"]
[ext_resource type="FontFile" uid="uid://lro0qdrhfytt" path="res://material_maker/theme/font_rubik/Rubik-Light.ttf" id="18_kn37y"]
-[sub_resource type="Shader" id="Shader_0mwcg"]
+[sub_resource type="Shader" id="Shader_r76ng"]
resource_local_to_scene = true
code = "shader_type canvas_item;
@@ -47,9 +47,9 @@ void fragment() {
}
"
-[sub_resource type="ShaderMaterial" id="2"]
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_63a3x"]
resource_local_to_scene = true
-shader = SubResource("Shader_0mwcg")
+shader = SubResource("Shader_r76ng")
shader_parameter/preview_2d_size = Vector2(100, 100)
shader_parameter/preview_2d_scale = 1.655
shader_parameter/preview_2d_center = Vector2(0.46, 0.56)
@@ -95,15 +95,14 @@ keycode = 69
[sub_resource type="Shortcut" id="Shortcut_llf02"]
events = [SubResource("InputEventKey_rhw4u")]
-[node name="Preview2D" node_paths=PackedStringArray("shortcut_context") instance=ExtResource("3")]
-material = SubResource("2")
+[node name="Preview2D" unique_id=415203794 node_paths=PackedStringArray("shortcut_context") instance=ExtResource("3")]
+material = SubResource("ShaderMaterial_63a3x")
custom_minimum_size = Vector2(100, 100)
+anchors_preset = -1
offset_left = 8.0
offset_top = -5.0
offset_right = 481.0
offset_bottom = 414.0
-grow_horizontal = 2
-grow_vertical = 2
shortcut_context = NodePath(".")
color = Color(1, 1, 1, 0)
script = ExtResource("4")
@@ -165,21 +164,21 @@ void fragment() {
}
"
-[node name="Guides" type="Control" parent="." index="0"]
+[node name="Guides" type="Control" parent="." index="0" unique_id=1437580332]
anchors_preset = 0
anchor_right = 1.0
anchor_bottom = 1.0
mouse_filter = 2
script = ExtResource("5")
-[node name="Axes" type="Control" parent="." index="1"]
+[node name="Axes" type="Control" parent="." index="1" unique_id=1769337482]
visible = false
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
script = ExtResource("3_r76ng")
-[node name="PolygonEditor" parent="." index="2" instance=ExtResource("4_gd40d")]
+[node name="PolygonEditor" parent="." index="2" unique_id=1840385301 instance=ExtResource("4_gd40d")]
visible = false
layout_mode = 1
offset_right = 0.0
@@ -187,25 +186,25 @@ offset_bottom = 0.0
draw_area = false
auto_rescale = false
-[node name="SplinesEditor" parent="." index="3" instance=ExtResource("5_5hlfo")]
+[node name="SplinesEditor" parent="." index="3" unique_id=1375481755 instance=ExtResource("5_5hlfo")]
visible = false
layout_mode = 1
draw_area = false
draw_control_lines = true
-[node name="PixelsEditor" parent="." index="4" instance=ExtResource("6_m4663")]
+[node name="PixelsEditor" parent="." index="4" unique_id=362722278 instance=ExtResource("6_m4663")]
visible = false
layout_mode = 1
draw_area = false
alpha = 0.5
-[node name="LatticeEditor" parent="." index="5" instance=ExtResource("7_u2w4r")]
+[node name="LatticeEditor" parent="." index="5" unique_id=1404568824 instance=ExtResource("7_u2w4r")]
visible = false
layout_mode = 1
offset_right = 0.0
offset_bottom = 0.0
-[node name="P1" parent="." index="6" instance=ExtResource("2")]
+[node name="P1" parent="." index="6" unique_id=1765205436 instance=ExtResource("2")]
visible = false
self_modulate = Color(1, 0.466667, 0, 1)
layout_mode = 0
@@ -215,7 +214,7 @@ offset_right = 37.0
offset_bottom = 61.0
texture = SubResource("3")
-[node name="P2" parent="." index="7" instance=ExtResource("2")]
+[node name="P2" parent="." index="7" unique_id=1580629670 instance=ExtResource("2")]
visible = false
self_modulate = Color(0, 0.505882, 1, 1)
layout_mode = 0
@@ -225,7 +224,7 @@ offset_right = 37.0
offset_bottom = 61.0
texture = SubResource("3")
-[node name="P11" parent="." index="8" instance=ExtResource("2")]
+[node name="P11" parent="." index="8" unique_id=1205963807 instance=ExtResource("2")]
visible = false
self_modulate = Color(0, 0.505882, 1, 1)
layout_mode = 0
@@ -237,7 +236,7 @@ texture = SubResource("3")
parent_control = "P1"
apply_local_transform = true
-[node name="RadiusP11" parent="." index="9" instance=ExtResource("2")]
+[node name="RadiusP11" parent="." index="9" unique_id=1589820436 instance=ExtResource("2")]
visible = false
self_modulate = Color(1, 0.631373, 0, 1)
layout_mode = 0
@@ -250,7 +249,7 @@ texture = SubResource("4")
parent_control = "P11"
control_type = 2
-[node name="P12" parent="." index="10" instance=ExtResource("2")]
+[node name="P12" parent="." index="10" unique_id=249875203 instance=ExtResource("2")]
visible = false
self_modulate = Color(0, 0.505882, 1, 1)
layout_mode = 0
@@ -262,7 +261,7 @@ texture = SubResource("3")
parent_control = "P1"
apply_local_transform = true
-[node name="P3" parent="." index="11" instance=ExtResource("2")]
+[node name="P3" parent="." index="11" unique_id=1688060177 instance=ExtResource("2")]
visible = false
self_modulate = Color(0, 1, 0.380392, 1)
layout_mode = 0
@@ -272,7 +271,7 @@ offset_right = 21.0
offset_bottom = 45.0
texture = SubResource("4")
-[node name="Rect1" parent="." index="12" instance=ExtResource("2")]
+[node name="Rect1" parent="." index="12" unique_id=844748247 instance=ExtResource("2")]
visible = false
self_modulate = Color(1, 0.631373, 0, 1)
layout_mode = 0
@@ -285,7 +284,7 @@ parent_control = "P1"
control_type = 1
apply_local_transform = true
-[node name="Radius1" parent="." index="13" instance=ExtResource("2")]
+[node name="Radius1" parent="." index="13" unique_id=1399381492 instance=ExtResource("2")]
visible = false
self_modulate = Color(1, 0.631373, 0, 1)
layout_mode = 0
@@ -298,7 +297,7 @@ texture = SubResource("4")
parent_control = "P1"
control_type = 2
-[node name="Radius2" parent="." index="14" instance=ExtResource("2")]
+[node name="Radius2" parent="." index="14" unique_id=1594322313 instance=ExtResource("2")]
visible = false
self_modulate = Color(0, 0.505882, 1, 1)
layout_mode = 0
@@ -311,7 +310,7 @@ texture = SubResource("4")
parent_control = "P2"
control_type = 2
-[node name="Radius11" parent="." index="15" instance=ExtResource("2")]
+[node name="Radius11" parent="." index="15" unique_id=1948264432 instance=ExtResource("2")]
visible = false
self_modulate = Color(1, 0.631373, 0, 1)
layout_mode = 0
@@ -324,7 +323,7 @@ texture = SubResource("4")
parent_control = "Radius1"
control_type = 2
-[node name="Scale1" parent="." index="16" instance=ExtResource("2")]
+[node name="Scale1" parent="." index="16" unique_id=1543136436 instance=ExtResource("2")]
visible = false
self_modulate = Color(1, 0.631373, 0, 1)
layout_mode = 0
@@ -337,7 +336,7 @@ texture = SubResource("4")
parent_control = "P1"
control_type = 3
-[node name="RotateScale1" parent="." index="17" instance=ExtResource("2")]
+[node name="RotateScale1" parent="." index="17" unique_id=1073873848 instance=ExtResource("2")]
visible = false
self_modulate = Color(1, 0.631373, 0, 1)
layout_mode = 0
@@ -350,7 +349,7 @@ texture = SubResource("4")
parent_control = "P1"
control_type = 4
-[node name="Angle1" parent="." index="18" instance=ExtResource("2")]
+[node name="Angle1" parent="." index="18" unique_id=56837712 instance=ExtResource("2")]
visible = false
self_modulate = Color(1, 0.631373, 0, 1)
layout_mode = 0
@@ -363,7 +362,7 @@ texture = SubResource("4")
parent_control = "P1"
control_type = 2
-[node name="Angle2" parent="." index="19" instance=ExtResource("2")]
+[node name="Angle2" parent="." index="19" unique_id=1272609448 instance=ExtResource("2")]
visible = false
self_modulate = Color(1, 0.631373, 0, 1)
layout_mode = 0
@@ -376,7 +375,7 @@ texture = SubResource("4")
parent_control = "P1"
control_type = 2
-[node name="Accumulate" type="SubViewport" parent="." index="20"]
+[node name="Accumulate" type="SubViewport" parent="." index="20" unique_id=68447703]
disable_3d = true
handle_input_locally = false
gui_snap_controls_to_pixels = false
@@ -384,12 +383,12 @@ size = Vector2i(2, 2)
render_target_clear_mode = 1
render_target_update_mode = 1
-[node name="Iteration" type="ColorRect" parent="Accumulate" index="0"]
+[node name="Iteration" type="ColorRect" parent="Accumulate" index="0" unique_id=824547017]
material = SubResource("6")
offset_right = 40.0
offset_bottom = 40.0
-[node name="MenuBar" type="ScrollContainer" parent="." index="21"]
+[node name="MenuBar" type="ScrollContainer" parent="." index="21" unique_id=1082056955]
unique_name_in_owner = true
clip_contents = false
layout_mode = 1
@@ -402,21 +401,21 @@ theme_type_variation = &"MM_PanelMenuBackground"
horizontal_scroll_mode = 3
vertical_scroll_mode = 0
-[node name="HBox" type="HFlowContainer" parent="MenuBar" index="0"]
+[node name="HBox" type="HFlowContainer" parent="MenuBar" index="0" unique_id=182327461]
layout_mode = 2
size_flags_horizontal = 3
mouse_filter = 2
-[node name="MainMenu" type="PanelContainer" parent="MenuBar/HBox" index="0"]
+[node name="MainMenu" type="PanelContainer" parent="MenuBar/HBox" index="0" unique_id=398954274]
layout_mode = 2
size_flags_vertical = 0
theme_type_variation = &"MM_PanelMenuBar"
-[node name="HBox" type="HBoxContainer" parent="MenuBar/HBox/MainMenu" index="0"]
+[node name="HBox" type="HBoxContainer" parent="MenuBar/HBox/MainMenu" index="0" unique_id=2074778138]
layout_mode = 2
theme_type_variation = &"MM_PanelMenuBar"
-[node name="ResetViewButton" type="Button" parent="MenuBar/HBox/MainMenu/HBox" index="0"]
+[node name="ResetViewButton" type="Button" parent="MenuBar/HBox/MainMenu/HBox" index="0" unique_id=798283184]
unique_name_in_owner = true
custom_minimum_size = Vector2(25, 25)
layout_mode = 2
@@ -428,7 +427,7 @@ icon_alignment = 1
script = ExtResource("10_83edi")
icon_name = "reset_view"
-[node name="ViewMenu" type="Button" parent="MenuBar/HBox/MainMenu/HBox" index="1" node_paths=PackedStringArray("shortcut_context")]
+[node name="ViewMenu" type="Button" parent="MenuBar/HBox/MainMenu/HBox" index="1" unique_id=1038944622 node_paths=PackedStringArray("shortcut_context")]
custom_minimum_size = Vector2(40, 25)
layout_mode = 2
tooltip_text = "View"
@@ -439,7 +438,7 @@ button_mask = 3
script = ExtResource("12_nrhap")
icon_name = "view"
-[node name="ViewMenuPanel" type="PanelContainer" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu" index="0"]
+[node name="ViewMenuPanel" type="PanelContainer" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu" index="0" unique_id=1472687647]
top_level = true
layout_mode = 0
offset_left = 493.0
@@ -449,20 +448,20 @@ offset_bottom = 145.0
theme_type_variation = &"MM_PanelMenuSubPanel"
script = ExtResource("13_5w2hy")
-[node name="VBox" type="GridContainer" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel" index="0"]
+[node name="VBox" type="GridContainer" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel" index="0" unique_id=1223609843]
layout_mode = 2
columns = 2
-[node name="Control" type="Control" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="0"]
+[node name="Control" type="Control" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="0" unique_id=92161024]
visible = false
layout_mode = 2
-[node name="ViewModeLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="1"]
+[node name="ViewModeLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="1" unique_id=663479758]
layout_mode = 2
theme_type_variation = &"MM_PanelMenuSubPanelLabel"
text = "View"
-[node name="ViewMode" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="2" instance=ExtResource("12_4017l")]
+[node name="ViewMode" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="2" unique_id=1232097209 instance=ExtResource("12_4017l")]
unique_name_in_owner = true
layout_mode = 2
selected = 0
@@ -474,12 +473,12 @@ popup/item_1/id = 1
popup/item_2/text = "Clamp"
popup/item_2/id = 2
-[node name="PostProcessingLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="3"]
+[node name="PostProcessingLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="3" unique_id=1208707070]
layout_mode = 2
theme_type_variation = &"MM_PanelMenuSubPanelLabel"
text = "Filter"
-[node name="PostProcessing" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="4" instance=ExtResource("12_4017l")]
+[node name="PostProcessing" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="4" unique_id=1278149163 instance=ExtResource("12_4017l")]
unique_name_in_owner = true
layout_mode = 2
selected = 0
@@ -497,15 +496,15 @@ popup/item_4/id = 4
popup/item_5/text = "Lowres 512x512"
popup/item_5/id = 5
-[node name="GuidesLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="5"]
+[node name="GuidesLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="5" unique_id=2077812196]
layout_mode = 2
theme_type_variation = &"MM_PanelMenuSubPanelLabel"
text = "Guides"
-[node name="BoxContainer" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="6"]
+[node name="BoxContainer" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="6" unique_id=1545146403]
layout_mode = 2
-[node name="Guides" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox/BoxContainer" index="0" instance=ExtResource("12_4017l")]
+[node name="Guides" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox/BoxContainer" index="0" unique_id=481345934 instance=ExtResource("12_4017l")]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
@@ -520,7 +519,7 @@ popup/item_2/id = 2
popup/item_3/text = "Grid"
popup/item_3/id = 3
-[node name="CustomGridSize" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox/BoxContainer" index="1" instance=ExtResource("14_qr76f")]
+[node name="CustomGridSize" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox/BoxContainer" index="1" unique_id=49865437 instance=ExtResource("14_qr76f")]
unique_name_in_owner = true
layout_mode = 2
value = 10.0
@@ -529,20 +528,20 @@ max_value = 32.0
step = 1.0
float_only = true
-[node name="GuidesColor" type="ColorPickerButton" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox/BoxContainer" index="2"]
+[node name="GuidesColor" type="ColorPickerButton" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox/BoxContainer" index="2" unique_id=119437571]
unique_name_in_owner = true
custom_minimum_size = Vector2(32, 0)
layout_mode = 2
-[node name="AlphaLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="7"]
+[node name="AlphaLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="7" unique_id=1462781046]
layout_mode = 2
theme_type_variation = &"MM_PanelMenuSubPanelLabel"
text = "Alpha"
-[node name="BoxContainer2" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="8"]
+[node name="BoxContainer2" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox" index="8" unique_id=513106806]
layout_mode = 2
-[node name="CheckerBrightness" type="OptionButton" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox/BoxContainer2" index="0"]
+[node name="CheckerBrightness" type="OptionButton" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox/BoxContainer2" index="0" unique_id=830063006]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Transparency checkers brightness"
@@ -555,7 +554,7 @@ popup/item_1/id = 1
popup/item_2/text = "Dark"
popup/item_2/id = 2
-[node name="CheckerSize" type="OptionButton" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox/BoxContainer2" index="1"]
+[node name="CheckerSize" type="OptionButton" parent="MenuBar/HBox/MainMenu/HBox/ViewMenu/ViewMenuPanel/VBox/BoxContainer2" index="1" unique_id=1281944466]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Transparency checkers size"
@@ -568,7 +567,7 @@ popup/item_1/id = 1
popup/item_2/text = "Large"
popup/item_2/id = 2
-[node name="ExportMenu" type="Button" parent="MenuBar/HBox/MainMenu/HBox" index="2" node_paths=PackedStringArray("shortcut_context")]
+[node name="ExportMenu" type="Button" parent="MenuBar/HBox/MainMenu/HBox" index="2" unique_id=372091705 node_paths=PackedStringArray("shortcut_context")]
unique_name_in_owner = true
custom_minimum_size = Vector2(40, 25)
layout_mode = 2
@@ -580,7 +579,7 @@ button_mask = 3
script = ExtResource("12_nrhap")
icon_name = "export"
-[node name="ExportMenuPanel" type="PanelContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu" index="0"]
+[node name="ExportMenuPanel" type="PanelContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu" index="0" unique_id=1894299873]
top_level = true
custom_minimum_size = Vector2(320, 0)
layout_mode = 0
@@ -591,50 +590,50 @@ offset_bottom = 380.0
theme_type_variation = &"MM_PanelMenuSubPanel"
script = ExtResource("16_0fl4g")
-[node name="VBox" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel" index="0"]
+[node name="VBox" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel" index="0" unique_id=56797128]
layout_mode = 2
vertical = true
-[node name="Grid" type="GridContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox" index="0"]
+[node name="Grid" type="GridContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox" index="0" unique_id=951766683]
layout_mode = 2
columns = 2
-[node name="ExportFolderLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="0"]
+[node name="ExportFolderLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="0" unique_id=222750042]
layout_mode = 2
theme_type_variation = &"MM_PanelMenuSubPanelLabel"
text = "Folder"
-[node name="ExportFolder" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="1"]
+[node name="ExportFolder" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="1" unique_id=445756125]
layout_mode = 2
theme_override_constants/separation = 2
-[node name="ExportFolder" type="LineEdit" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ExportFolder" index="0"]
+[node name="ExportFolder" type="LineEdit" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ExportFolder" index="0" unique_id=1924452745]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 15
-[node name="ExportFolderButton" type="Button" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ExportFolder" index="1"]
+[node name="ExportFolderButton" type="Button" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ExportFolder" index="1" unique_id=1318426978]
unique_name_in_owner = true
custom_minimum_size = Vector2(25, 25)
layout_mode = 2
icon_alignment = 1
-[node name="ExportFileLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="2"]
+[node name="ExportFileLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="2" unique_id=1748884565]
layout_mode = 2
size_flags_vertical = 0
theme_type_variation = &"MM_PanelMenuSubPanelLabel"
text = "File Name"
-[node name="ExportFile" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="3"]
+[node name="ExportFile" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="3" unique_id=2132902207]
layout_mode = 2
theme_override_constants/separation = 2
vertical = true
-[node name="BoxContainer" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ExportFile" index="0"]
+[node name="BoxContainer" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ExportFile" index="0" unique_id=183570309]
layout_mode = 2
-[node name="ExportFile" type="LineEdit" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ExportFile/BoxContainer" index="0"]
+[node name="ExportFile" type="LineEdit" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ExportFile/BoxContainer" index="0" unique_id=1326714374]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
@@ -644,7 +643,7 @@ You can use $project, $node, $idx and $resolution to make the file-name auto-adj
theme_override_font_sizes/font_size = 15
text = "$project_$node"
-[node name="FileType" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ExportFile/BoxContainer" index="1" instance=ExtResource("12_4017l")]
+[node name="FileType" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ExportFile/BoxContainer" index="1" unique_id=854524278 instance=ExtResource("12_4017l")]
unique_name_in_owner = true
layout_mode = 2
selected = 0
@@ -654,22 +653,22 @@ popup/item_0/id = 0
popup/item_1/text = ".exr"
popup/item_1/id = 1
-[node name="ExportFileResultLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ExportFile" index="1"]
+[node name="ExportFileResultLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ExportFile" index="1" unique_id=1095061228]
unique_name_in_owner = true
layout_mode = 2
theme_type_variation = &"MM_PanelMenuSubPanelLabel"
theme_override_fonts/font = SubResource("FontVariation_wkuuo")
-[node name="ResolutionLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="4"]
+[node name="ResolutionLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="4" unique_id=888000205]
layout_mode = 2
theme_type_variation = &"MM_PanelMenuSubPanelLabel"
text = "Resolution"
-[node name="ResolutionSection" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="5"]
+[node name="ResolutionSection" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="5" unique_id=1471406219]
unique_name_in_owner = true
layout_mode = 2
-[node name="Resolution" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ResolutionSection" index="0" instance=ExtResource("12_4017l")]
+[node name="Resolution" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ResolutionSection" index="0" unique_id=98709583 instance=ExtResource("12_4017l")]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
@@ -694,12 +693,12 @@ popup/item_7/id = 7
popup/item_8/text = "Custom"
popup/item_8/id = 8
-[node name="CustomResolutionSection" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ResolutionSection" index="1"]
+[node name="CustomResolutionSection" type="BoxContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ResolutionSection" index="1" unique_id=143731711]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
-[node name="CustomResolutionX" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ResolutionSection/CustomResolutionSection" index="0" instance=ExtResource("14_qr76f")]
+[node name="CustomResolutionX" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ResolutionSection/CustomResolutionSection" index="0" unique_id=1990106158 instance=ExtResource("14_qr76f")]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
@@ -710,11 +709,11 @@ max_value = 2048.0
step = 1.0
float_only = true
-[node name="x" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ResolutionSection/CustomResolutionSection" index="1"]
+[node name="x" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ResolutionSection/CustomResolutionSection" index="1" unique_id=1904246614]
layout_mode = 2
text = "x"
-[node name="CustomResolutionY" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ResolutionSection/CustomResolutionSection" index="2" instance=ExtResource("14_qr76f")]
+[node name="CustomResolutionY" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/ResolutionSection/CustomResolutionSection" index="2" unique_id=120110795 instance=ExtResource("14_qr76f")]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
@@ -725,42 +724,42 @@ max_value = 2048.0
step = 1.0
float_only = true
-[node name="ExportLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="6"]
+[node name="ExportLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="6" unique_id=300852845]
layout_mode = 2
theme_type_variation = &"MM_PanelMenuSubPanelLabel"
text = "Export"
-[node name="BoxContainer" type="GridContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="7"]
+[node name="BoxContainer" type="GridContainer" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid" index="7" unique_id=827077119]
layout_mode = 2
size_flags_horizontal = 3
columns = 2
-[node name="Image" type="Button" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/BoxContainer" index="0"]
+[node name="Image" type="Button" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/BoxContainer" index="0" unique_id=1455711006]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
shortcut = SubResource("Shortcut_llf02")
text = "Image"
-[node name="Reference" type="Button" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/BoxContainer" index="1"]
+[node name="Reference" type="Button" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/BoxContainer" index="1" unique_id=432697365]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "To Reference"
-[node name="Animation" type="Button" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/BoxContainer" index="2"]
+[node name="Animation" type="Button" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/BoxContainer" index="2" unique_id=115406925]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "Animation"
-[node name="TAA_Render" type="Button" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/BoxContainer" index="3"]
+[node name="TAA_Render" type="Button" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox/Grid/BoxContainer" index="3" unique_id=816810603]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "TAA Render"
-[node name="ExportNotificationLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox" index="1"]
+[node name="ExportNotificationLabel" type="Label" parent="MenuBar/HBox/MainMenu/HBox/ExportMenu/ExportMenuPanel/VBox" index="1" unique_id=1573873066]
unique_name_in_owner = true
visible = false
layout_mode = 2
@@ -769,7 +768,7 @@ theme_override_colors/font_color = Color(0.52, 0.52, 0.52, 1)
theme_override_fonts/font = SubResource("FontVariation_wkuuo")
autowrap_mode = 1
-[node name="PreviewLocked" type="Button" parent="MenuBar/HBox/MainMenu/HBox" index="3"]
+[node name="PreviewLocked" type="Button" parent="MenuBar/HBox/MainMenu/HBox" index="3" unique_id=1901034297]
unique_name_in_owner = true
custom_minimum_size = Vector2(25, 25)
layout_mode = 2
@@ -780,7 +779,7 @@ script = ExtResource("17_07kc5")
icon_normal_name = "lock_unlocked"
icon_pressed_name = "lock_locked"
-[node name="ComplexParameters" type="OptionButton" parent="MenuBar/HBox/MainMenu/HBox" index="4"]
+[node name="ComplexParameters" type="OptionButton" parent="MenuBar/HBox/MainMenu/HBox" index="4" unique_id=1709215385]
unique_name_in_owner = true
visible = false
layout_mode = 2
@@ -788,7 +787,9 @@ layout_mode = 2
[connection signal="gui_input" from="." to="." method="_on_gui_input"]
[connection signal="mouse_entered" from="." to="." method="_on_Preview2D_mouse_entered"]
[connection signal="unhandled_event" from="PolygonEditor" to="." method="_on_gui_input"]
-[connection signal="gui_input" from="PolygonEditor/@Control@42512" to="PolygonEditor/@Control@42512" method="_on_ControlPoint_gui_input"]
+[connection signal="gui_input" from="PolygonEditor/ControlPoint" to="PolygonEditor/ControlPoint" method="_on_ControlPoint_gui_input"]
+[connection signal="mouse_entered" from="PolygonEditor/ControlPoint" to="PolygonEditor/ControlPoint" method="_on_mouse_entered"]
+[connection signal="mouse_exited" from="PolygonEditor/ControlPoint" to="PolygonEditor/ControlPoint" method="_on_mouse_exited"]
[connection signal="unhandled_event" from="SplinesEditor" to="." method="_on_gui_input"]
[connection signal="unhandled_event" from="PixelsEditor" to="." method="_on_gui_input"]
[connection signal="unhandled_event" from="LatticeEditor" to="." method="_on_gui_input"]
diff --git a/material_maker/panels/preview_3d/preview_3d_panel.tscn b/material_maker/panels/preview_3d/preview_3d_panel.tscn
index 2aa9757625..d94fa08832 100644
--- a/material_maker/panels/preview_3d/preview_3d_panel.tscn
+++ b/material_maker/panels/preview_3d/preview_3d_panel.tscn
@@ -45,16 +45,15 @@ reflected_light_source = 2
environment = SubResource("Environment_qxxdb")
camera_attributes = SubResource("CameraAttributesPractical_g4ldw")
-[sub_resource type="ButtonGroup" id="ButtonGroup_j6uuq"]
+[sub_resource type="ButtonGroup" id="ButtonGroup_jy7sc"]
[node name="Preview3D" unique_id=308580129 instance=ExtResource("1")]
custom_minimum_size = Vector2(250, 200)
+anchors_preset = -1
offset_left = -1.0
offset_top = -2.0
offset_right = 248.0
offset_bottom = 253.0
-grow_horizontal = 2
-grow_vertical = 2
script = ExtResource("3")
click_material = SubResource("2")
@@ -97,16 +96,16 @@ layout_mode = 2
size_flags_horizontal = 3
[node name="Speed_Pause" parent="MainMenu/HBox/ModelMenu/ModelMenuPanel/VBoxContainer/Model/RotationSpeeds" parent_id_path=PackedInt32Array(530040303) index="0" unique_id=1158744206]
-button_group = SubResource("ButtonGroup_j6uuq")
+button_group = SubResource("ButtonGroup_jy7sc")
[node name="Speed_Slow" parent="MainMenu/HBox/ModelMenu/ModelMenuPanel/VBoxContainer/Model/RotationSpeeds" parent_id_path=PackedInt32Array(530040303) index="1" unique_id=1454681268]
-button_group = SubResource("ButtonGroup_j6uuq")
+button_group = SubResource("ButtonGroup_jy7sc")
[node name="Speed_Medium" parent="MainMenu/HBox/ModelMenu/ModelMenuPanel/VBoxContainer/Model/RotationSpeeds" parent_id_path=PackedInt32Array(530040303) index="2" unique_id=1024390903]
-button_group = SubResource("ButtonGroup_j6uuq")
+button_group = SubResource("ButtonGroup_jy7sc")
[node name="Speed_Fast" parent="MainMenu/HBox/ModelMenu/ModelMenuPanel/VBoxContainer/Model/RotationSpeeds" parent_id_path=PackedInt32Array(530040303) index="3" unique_id=1976754458]
-button_group = SubResource("ButtonGroup_j6uuq")
+button_group = SubResource("ButtonGroup_jy7sc")
[connection signal="mouse_entered" from="." to="." method="_on_Preview3D_mouse_entered"]
[connection signal="resized" from="." to="." method="_on_resized"]
diff --git a/material_maker/panels/preview_3d/preview_3d_scene.tscn b/material_maker/panels/preview_3d/preview_3d_scene.tscn
index c845553aa7..56cb0805da 100644
--- a/material_maker/panels/preview_3d/preview_3d_scene.tscn
+++ b/material_maker/panels/preview_3d/preview_3d_scene.tscn
@@ -1,8 +1,7 @@
-[gd_scene load_steps=10 format=3 uid="uid://dpulty2lkvcht"]
+[gd_scene format=3 uid="uid://dpulty2lkvcht"]
[ext_resource type="PackedScene" uid="uid://cxcw0mi4sfl2x" path="res://material_maker/panels/preview_3d/preview_objects.tscn" id="2"]
[ext_resource type="PackedScene" uid="uid://dw4wghi1pn4qr" path="res://material_maker/windows/environment_editor/camera_controller.tscn" id="2_g4ldw"]
-[ext_resource type="Texture2D" uid="uid://bqre7xkdgb655" path="res://material_maker/environments/hdris/moonless_golf_1k.hdr" id="2_ks6fo"]
[sub_resource type="Animation" id="3"]
loop_mode = 1
@@ -24,8 +23,11 @@ _data = {
&"rotate": SubResource("3")
}
+[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_w6dyo"]
+load_path = "res://.godot/imported/moonless_golf_1k.hdr-9cc5420e458979fa0268bbd265e3a765.bptc.ctex"
+
[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_40ogr"]
-panorama = ExtResource("2_ks6fo")
+panorama = SubResource("CompressedTexture2D_w6dyo")
[sub_resource type="Sky" id="Sky_wye7d"]
sky_material = SubResource("PanoramaSkyMaterial_40ogr")
@@ -39,31 +41,29 @@ reflected_light_source = 2
[sub_resource type="CameraAttributesPractical" id="CameraAttributesPractical_g4ldw"]
-[node name="Preview3dScene" type="Node3D"]
+[node name="Preview3dScene" type="Node3D" unique_id=368054269]
-[node name="ObjectsPivot" type="Node3D" parent="."]
+[node name="ObjectsPivot" type="Node3D" parent="." unique_id=900793287]
-[node name="Objects" parent="ObjectsPivot" instance=ExtResource("2")]
+[node name="Objects" parent="ObjectsPivot" unique_id=1124287291 instance=ExtResource("2")]
-[node name="CameraController" parent="." instance=ExtResource("2_g4ldw")]
+[node name="CameraController" parent="." unique_id=610403260 instance=ExtResource("2_g4ldw")]
camera_path = NodePath("../Camera3D")
-[node name="Camera3D" type="Camera3D" parent="."]
+[node name="Camera3D" type="Camera3D" parent="." unique_id=1210778811]
transform = Transform3D(1, 0, 0, 0, 0.766044, 0.642788, 0, -0.642788, 0.766044, 0, 2.57115, 3.06418)
current = true
fov = 50.0
-[node name="ObjectRotate" type="AnimationPlayer" parent="."]
-libraries = {
-&"": SubResource("AnimationLibrary_sxr5g")
-}
+[node name="ObjectRotate" type="AnimationPlayer" parent="." unique_id=2024899918]
+libraries/ = SubResource("AnimationLibrary_sxr5g")
-[node name="Sun" type="DirectionalLight3D" parent="."]
+[node name="Sun" type="DirectionalLight3D" parent="." unique_id=1498759412]
shadow_enabled = true
shadow_bias = 0.03
directional_shadow_mode = 0
directional_shadow_max_distance = 5.0
-[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
+[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=502695456]
environment = SubResource("Environment_qxxdb")
camera_attributes = SubResource("CameraAttributesPractical_g4ldw")
diff --git a/material_maker/panels/reference/reference_panel.gd b/material_maker/panels/reference/reference_panel.gd
index eade101bbe..5ff2576b4b 100644
--- a/material_maker/panels/reference/reference_panel.gd
+++ b/material_maker/panels/reference/reference_panel.gd
@@ -43,6 +43,12 @@ func _ready():
%GradientSlot.toggled.connect(_on_slot_toggled.bind(%GradientSlot))
+ if DisplayServer.is_touchscreen_available():
+ %PasteImageButton.hide()
+ %CheckClipboardImage.stop()
+ %CheckClipboardImage.queue_free()
+ $Empty/Label.text = "Add reference image to get started"
+
## This is magically called by the main window :)
func on_drop_image_file(file_name: String) -> void:
@@ -167,7 +173,7 @@ func _on_image_resized() -> void:
%Image.material.set_shader_parameter("canvas_size", %Image.get_size())
-func _on_image_gui_input(event: InputEvent) -> void:
+func _on_image_gui_input(event : InputEvent) -> void:
if opened_images.is_empty():
return
@@ -177,8 +183,8 @@ func _on_image_gui_input(event: InputEvent) -> void:
handle_movement(event)
-func handle_movement(event: InputEvent) -> void:
- var m: ShaderMaterial = %Image.material
+func handle_movement(event : InputEvent) -> void:
+ var m : ShaderMaterial = %Image.material
var canvas_size : Vector2 = %Image.get_size()
var image_size : Vector2 = m.get_shader_parameter("image_size")
@@ -212,9 +218,12 @@ func handle_movement(event: InputEvent) -> void:
elif event is InputEventMouseMotion:
if is_dragging:
new_center = m.get_shader_parameter("center")-event.relative*image_scale/multiplier
-
elif is_zooming:
new_scale = clamp(new_scale*(1.0+0.01*event.relative.y), 0.005, 3)
+ elif event is InputEventMagnifyGesture:
+ new_scale = clamp(new_scale / event.factor, 0.005, 3)
+ elif event is InputEventScreenDrag and event.index == 0:
+ new_center = m.get_shader_parameter("center")-event.relative*image_scale/multiplier
if new_scale != image_scale:
m.set_shader_parameter("scale", new_scale)
diff --git a/material_maker/panels/reference/reference_panel.tscn b/material_maker/panels/reference/reference_panel.tscn
index 4877a5f569..5c992f6fce 100644
--- a/material_maker/panels/reference/reference_panel.tscn
+++ b/material_maker/panels/reference/reference_panel.tscn
@@ -40,13 +40,11 @@ allow_unpress = true
[node name="ReferencePanel" type="Panel" unique_id=329764457]
clip_children = 2
-anchors_preset = 15
+anchors_preset = -1
anchor_right = 1.0
anchor_bottom = 1.0
offset_right = 171.0
offset_bottom = 237.0
-grow_horizontal = 2
-grow_vertical = 2
theme_type_variation = &"MM_PanelBackground"
script = ExtResource("1")
@@ -126,6 +124,7 @@ tooltip_text = "Remove Image"
icon_alignment = 1
[node name="CheckClipboardImage" type="Timer" parent="MenuBar/HBox/MainMenu/HBox" unique_id=2067403748]
+unique_name_in_owner = true
autostart = true
[node name="ViewMenu" type="PanelContainer" parent="MenuBar/HBox" unique_id=2108939916]
diff --git a/material_maker/projects_panel.tscn b/material_maker/projects_panel.tscn
index 84beac16a5..57b07afa01 100644
--- a/material_maker/projects_panel.tscn
+++ b/material_maker/projects_panel.tscn
@@ -11,14 +11,15 @@
[ext_resource type="Script" uid="uid://bxwor0k6svci8" path="res://material_maker/panels/graph_edit/graph_view_menu.gd" id="8_nl2qi"]
[ext_resource type="Script" uid="uid://pqxjwlcff5ko" path="res://material_maker/panels/graph_edit/graph_align_menu.gd" id="8_r5hxx"]
[ext_resource type="ButtonGroup" uid="uid://biv6we3po8wbb" path="res://material_maker/line_style_btn_group.tres" id="10_lbgjg"]
+[ext_resource type="Script" uid="uid://c7hvi7bvtgwbd" path="res://material_maker/panels/graph_edit/graph_actions_menu.gd" id="12_qnupl"]
-[sub_resource type="Shader" id="Shader_r5hxx"]
+[sub_resource type="Shader" id="Shader_qnupl"]
resource_local_to_scene = true
code = "shader_type canvas_item;"
-[sub_resource type="ShaderMaterial" id="ShaderMaterial_qnupl"]
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_uk6aw"]
resource_local_to_scene = true
-shader = SubResource("Shader_r5hxx")
+shader = SubResource("Shader_qnupl")
[sub_resource type="InputEventKey" id="InputEventKey_r5hxx"]
device = -1
@@ -75,7 +76,7 @@ theme_type_variation = &"MM_ProjectsBackground"
[node name="Preview2D" parent="BackgroundPreviews" unique_id=650291010 instance=ExtResource("2_oiaqi")]
visible = false
-material = SubResource("ShaderMaterial_qnupl")
+material = SubResource("ShaderMaterial_uk6aw")
layout_mode = 1
offset_right = 64.0
offset_bottom = 64.0
@@ -419,7 +420,27 @@ icon_alignment = 1
script = ExtResource("7_qnupl")
icon_name = "arrange_nodes"
-[node name="AlignMenu" type="PanelContainer" parent="MenuBar/HBox" unique_id=254250138]
+[node name="ActionsMenu" type="PanelContainer" parent="MenuBar/HBox" unique_id=1156734553]
+layout_mode = 2
+size_flags_vertical = 0
+theme_type_variation = &"MM_PanelMenuBar"
+script = ExtResource("12_qnupl")
+
+[node name="HBox" type="HBoxContainer" parent="MenuBar/HBox/ActionsMenu" unique_id=1846468046]
+layout_mode = 2
+theme_type_variation = &"MM_PanelMenuBar"
+
+[node name="KnifeTool" type="Button" parent="MenuBar/HBox/ActionsMenu/HBox" unique_id=409994758]
+custom_minimum_size = Vector2(25, 25)
+layout_mode = 2
+tooltip_text = "Knife tool"
+toggle_mode = true
+shortcut_in_tooltip = false
+icon_alignment = 1
+script = ExtResource("7_qnupl")
+icon_name = "knife"
+
+[node name="AlignMenu" type="PanelContainer" parent="MenuBar/HBox" unique_id=243111021]
layout_mode = 2
size_flags_vertical = 0
theme_type_variation = &"MM_PanelMenuBar"
@@ -531,6 +552,7 @@ Scroll to zoom the 3D Preview."
[connection signal="value_changed" from="MenuBar/HBox/MainGraphMenuBar/HBox/ViewMenu/ViewMenuPanel/VBoxContainer/VBoxContainer2/Thickness/LineThickness" to="MenuBar/HBox/MainGraphMenuBar/HBox/ViewMenu/ViewMenuPanel" method="_on_line_thickness_value_changed"]
[connection signal="value_changed" from="MenuBar/HBox/MainGraphMenuBar/HBox/ViewMenu/ViewMenuPanel/VBoxContainer/VBoxContainer2/Curvature/LineCurvature" to="MenuBar/HBox/MainGraphMenuBar/HBox/ViewMenu" method="_on_line_curvature_value_changed"]
[connection signal="value_changed" from="MenuBar/HBox/MainGraphMenuBar/HBox/ViewMenu/ViewMenuPanel/VBoxContainer/VBoxContainer2/Curvature/LineCurvature" to="MenuBar/HBox/MainGraphMenuBar/HBox/ViewMenu/ViewMenuPanel" method="_on_line_curvature_value_changed"]
+[connection signal="toggled" from="MenuBar/HBox/ActionsMenu/HBox/KnifeTool" to="MenuBar/HBox/ActionsMenu" method="_on_knife_tool_toggled"]
[connection signal="pressed" from="MenuBar/HBox/AlignMenu/HBox/AlignStart" to="MenuBar/HBox/AlignMenu" method="_on_align_start_pressed"]
[connection signal="pressed" from="MenuBar/HBox/AlignMenu/HBox/AlignTop" to="MenuBar/HBox/AlignMenu" method="_on_align_top_pressed"]
[connection signal="pressed" from="MenuBar/HBox/AlignMenu/HBox/AlignEnd" to="MenuBar/HBox/AlignMenu" method="_on_align_end_pressed"]
diff --git a/material_maker/theme/classic_base.tres b/material_maker/theme/classic_base.tres
index edbf134c3b..ee2f470bd1 100644
--- a/material_maker/theme/classic_base.tres
+++ b/material_maker/theme/classic_base.tres
@@ -441,7 +441,7 @@ atlas = ExtResource("1_fw8f4")
region = Rect2(112, 224, 16, 16)
metadata/scale = 2.0
-[sub_resource type="AtlasTexture" id="AtlasTexture_rgi6n"]
+[sub_resource type="AtlasTexture" id="AtlasTexture_0v3cv"]
atlas = ExtResource("1_fw8f4")
region = Rect2(32, 240, 16, 16)
filter_clip = true
@@ -452,7 +452,7 @@ metadata/recolor = true
atlas = ExtResource("1_fw8f4")
region = Rect2(64, 160, 16, 16)
-[sub_resource type="AtlasTexture" id="AtlasTexture_0v3cv"]
+[sub_resource type="AtlasTexture" id="AtlasTexture_l3428"]
atlas = ExtResource("1_fw8f4")
region = Rect2(112, 48, 16, 16)
filter_clip = true
@@ -463,10 +463,28 @@ metadata/recolor = true
atlas = ExtResource("1_fw8f4")
region = Rect2(32, 16, 16, 16)
+[sub_resource type="AtlasTexture" id="AtlasTexture_rgi6n"]
+atlas = ExtResource("1_fw8f4")
+region = Rect2(32, 16, 16, 16)
+metadata/scale = 2.0
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_jtuhu"]
+atlas = ExtResource("1_fw8f4")
+region = Rect2(0, 64, 16, 16)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_l22ac"]
+atlas = ExtResource("1_fw8f4")
+region = Rect2(96, 240, 16, 16)
+
[sub_resource type="AtlasTexture" id="AtlasTexture_oy0ko"]
atlas = ExtResource("1_fw8f4")
region = Rect2(64, 0, 16, 16)
+[sub_resource type="AtlasTexture" id="AtlasTexture_omlq7"]
+atlas = ExtResource("1_fw8f4")
+region = Rect2(63, 0, 16, 16)
+metadata/scale = 2.0
+
[sub_resource type="AtlasTexture" id="AtlasTexture_2gawd"]
atlas = ExtResource("1_fw8f4")
region = Rect2(112, 16, 16, 16)
@@ -497,11 +515,24 @@ metadata/scale = 2.0
atlas = ExtResource("1_fw8f4")
region = Rect2(112, 128, 16, 16)
+[sub_resource type="AtlasTexture" id="AtlasTexture_n4y2n"]
+atlas = ExtResource("1_fw8f4")
+region = Rect2(32, 80, 16, 16)
+margin = Rect2(-2, -2, -4, -4)
+metadata/scale = 2.0
+
[sub_resource type="AtlasTexture" id="AtlasTexture_pbgus"]
atlas = ExtResource("1_fw8f4")
region = Rect2(16, 240, 16, 16)
metadata/scale = 3.0
+[sub_resource type="AtlasTexture" id="AtlasTexture_7b7js"]
+atlas = ExtResource("1_fw8f4")
+region = Rect2(48, 240, 16, 16)
+filter_clip = true
+metadata/scale = 2.0
+metadata/recolor = true
+
[sub_resource type="AtlasTexture" id="AtlasTexture_c7xvc"]
atlas = ExtResource("1_fw8f4")
region = Rect2(80, 32, 16, 16)
@@ -520,6 +551,11 @@ region = Rect2(0, 240, 16, 16)
filter_clip = true
metadata/scale = 3.0
+[sub_resource type="AtlasTexture" id="AtlasTexture_fh3ks"]
+atlas = ExtResource("1_fw8f4")
+region = Rect2(80, 240, 16, 16)
+metadata/scale = 2.0
+
[sub_resource type="AtlasTexture" id="AtlasTexture_dsr33"]
atlas = ExtResource("1_fw8f4")
region = Rect2(64, 64, 16, 16)
@@ -536,6 +572,12 @@ region = Rect2(64, 80, 16, 16)
atlas = ExtResource("1_fw8f4")
region = Rect2(48, 80, 16, 16)
+[sub_resource type="AtlasTexture" id="AtlasTexture_l6nwy"]
+atlas = ExtResource("1_fw8f4")
+region = Rect2(96, 64, 16, 16)
+metadata/recolor = true
+metadata/scale = 2.0
+
[sub_resource type="AtlasTexture" id="AtlasTexture_lsxnf"]
atlas = ExtResource("1_fw8f4")
region = Rect2(96, 128, 16, 16)
@@ -1215,11 +1257,15 @@ MM_Icons/icons/arrow_right = SubResource("AtlasTexture_r3xak")
MM_Icons/icons/arrow_updown = SubResource("AtlasTexture_dnklm")
MM_Icons/icons/category_ascending = SubResource("AtlasTexture_50kh2")
MM_Icons/icons/category_descending = SubResource("AtlasTexture_ivx1c")
-MM_Icons/icons/clean = SubResource("AtlasTexture_rgi6n")
+MM_Icons/icons/clean = SubResource("AtlasTexture_0v3cv")
MM_Icons/icons/color_picker = SubResource("AtlasTexture_7ns35")
-MM_Icons/icons/console = SubResource("AtlasTexture_0v3cv")
+MM_Icons/icons/console = SubResource("AtlasTexture_l3428")
MM_Icons/icons/delete = SubResource("AtlasTexture_agwde")
+MM_Icons/icons/delete_2x = SubResource("AtlasTexture_rgi6n")
+MM_Icons/icons/download = SubResource("AtlasTexture_jtuhu")
+MM_Icons/icons/drag_hint = SubResource("AtlasTexture_l22ac")
MM_Icons/icons/draw = SubResource("AtlasTexture_oy0ko")
+MM_Icons/icons/draw_2x = SubResource("AtlasTexture_omlq7")
MM_Icons/icons/dropdown = SubResource("AtlasTexture_2gawd")
MM_Icons/icons/environment = SubResource("AtlasTexture_x8swe")
MM_Icons/icons/export = SubResource("AtlasTexture_5e0gw")
@@ -1227,15 +1273,19 @@ MM_Icons/icons/folder = SubResource("AtlasTexture_rqlqa")
MM_Icons/icons/frequency_ascending = SubResource("AtlasTexture_6kl5u")
MM_Icons/icons/frequency_descending = SubResource("AtlasTexture_ya45l")
MM_Icons/icons/function = SubResource("AtlasTexture_jxpkm")
+MM_Icons/icons/generic_size = SubResource("AtlasTexture_n4y2n")
MM_Icons/icons/internet = SubResource("AtlasTexture_pbgus")
+MM_Icons/icons/knife = SubResource("AtlasTexture_7b7js")
MM_Icons/icons/link = SubResource("AtlasTexture_c7xvc")
MM_Icons/icons/lock_locked = SubResource("AtlasTexture_m27ao")
MM_Icons/icons/lock_unlocked = SubResource("AtlasTexture_asgc8")
MM_Icons/icons/logo = SubResource("AtlasTexture_mnfe7")
+MM_Icons/icons/minimize = SubResource("AtlasTexture_fh3ks")
MM_Icons/icons/model = SubResource("AtlasTexture_dsr33")
MM_Icons/icons/paste_image = SubResource("AtlasTexture_64fc4")
MM_Icons/icons/pin_pinned = SubResource("AtlasTexture_du4od")
MM_Icons/icons/pin_unpinned = SubResource("AtlasTexture_nkmvd")
+MM_Icons/icons/randomize = SubResource("AtlasTexture_l6nwy")
MM_Icons/icons/reset_view = SubResource("AtlasTexture_lsxnf")
MM_Icons/icons/section_3d = SubResource("AtlasTexture_vbdqj")
MM_Icons/icons/section_filter = SubResource("AtlasTexture_h5b0q")
diff --git a/material_maker/theme/default.tres b/material_maker/theme/default.tres
index 67966383ed..fb0ae8add3 100644
--- a/material_maker/theme/default.tres
+++ b/material_maker/theme/default.tres
@@ -497,6 +497,11 @@ filter_clip = true
metadata/scale = 2.0
metadata/recolor = true
+[sub_resource type="AtlasTexture" id="AtlasTexture_qnupl"]
+atlas = ExtResource("1_s43fy")
+region = Rect2(48, 0, 16, 16)
+metadata/scale = 2.0
+
[sub_resource type="AtlasTexture" id="AtlasTexture_j13i3"]
atlas = ExtResource("1_s43fy")
region = Rect2(64, 160, 16, 16)
@@ -521,7 +526,7 @@ region = Rect2(32, 192, 16, 16)
atlas = ExtResource("1_s43fy")
region = Rect2(64, 192, 16, 16)
-[sub_resource type="AtlasTexture" id="AtlasTexture_npn74"]
+[sub_resource type="AtlasTexture" id="AtlasTexture_ov3t0"]
atlas = ExtResource("1_s43fy")
region = Rect2(112, 48, 16, 16)
filter_clip = true
@@ -532,10 +537,24 @@ metadata/recolor = true
atlas = ExtResource("1_s43fy")
region = Rect2(32, 16, 16, 16)
+[sub_resource type="AtlasTexture" id="AtlasTexture_u5byk"]
+atlas = ExtResource("1_s43fy")
+region = Rect2(32, 16, 16, 16)
+metadata/scale = 2.0
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_w255t"]
+atlas = ExtResource("1_s43fy")
+region = Rect2(96, 240, 16, 16)
+
[sub_resource type="AtlasTexture" id="AtlasTexture_oy0ko"]
atlas = ExtResource("1_s43fy")
region = Rect2(64, 0, 16, 16)
+[sub_resource type="AtlasTexture" id="AtlasTexture_omlq7"]
+atlas = ExtResource("1_s43fy")
+region = Rect2(63, 0, 16, 16)
+metadata/scale = 2.0
+
[sub_resource type="AtlasTexture" id="AtlasTexture_2gawd"]
atlas = ExtResource("1_s43fy")
region = Rect2(112, 16, 16, 16)
@@ -544,6 +563,11 @@ region = Rect2(112, 16, 16, 16)
atlas = ExtResource("1_s43fy")
region = Rect2(80, 64, 16, 16)
+[sub_resource type="AtlasTexture" id="AtlasTexture_6yetl"]
+atlas = ExtResource("1_s43fy")
+region = Rect2(48, 240, 16, 16)
+metadata/scale = 1.0
+
[sub_resource type="AtlasTexture" id="AtlasTexture_bn15y"]
atlas = ExtResource("1_s43fy")
region = Rect2(16, 0, 16, 16)
@@ -552,7 +576,7 @@ region = Rect2(16, 0, 16, 16)
atlas = ExtResource("1_s43fy")
region = Rect2(0, 32, 16, 16)
-[sub_resource type="AtlasTexture" id="AtlasTexture_xdmf6"]
+[sub_resource type="AtlasTexture" id="AtlasTexture_ooua1"]
atlas = ExtResource("1_s43fy")
region = Rect2(64, 224, 16, 16)
metadata/scale = 2.0
@@ -566,6 +590,12 @@ metadata/scale = 2.0
atlas = ExtResource("1_s43fy")
region = Rect2(112, 128, 16, 16)
+[sub_resource type="AtlasTexture" id="AtlasTexture_8an74"]
+atlas = ExtResource("1_s43fy")
+region = Rect2(32, 80, 16, 16)
+margin = Rect2(-2, -2, -4, -4)
+metadata/scale = 2.0
+
[sub_resource type="AtlasTexture" id="AtlasTexture_pkv4t"]
atlas = ExtResource("1_s43fy")
region = Rect2(0, 128, 16, 16)
@@ -575,6 +605,13 @@ atlas = ExtResource("1_s43fy")
region = Rect2(16, 240, 16, 16)
metadata/scale = 3.0
+[sub_resource type="AtlasTexture" id="AtlasTexture_npn74"]
+atlas = ExtResource("1_s43fy")
+region = Rect2(64, 240, 16, 16)
+filter_clip = true
+metadata/scale = 2.0
+metadata/recolor = true
+
[sub_resource type="AtlasTexture" id="AtlasTexture_8uenv"]
atlas = ExtResource("1_s43fy")
region = Rect2(80, 32, 16, 16)
@@ -596,6 +633,11 @@ metadata/scale = 3.0
atlas = ExtResource("1_s43fy")
region = Rect2(16, 128, 16, 16)
+[sub_resource type="AtlasTexture" id="AtlasTexture_xdmf6"]
+atlas = ExtResource("1_s43fy")
+region = Rect2(80, 240, 16, 16)
+metadata/scale = 2.0
+
[sub_resource type="AtlasTexture" id="AtlasTexture_dsr33"]
atlas = ExtResource("1_s43fy")
region = Rect2(64, 64, 16, 16)
@@ -612,6 +654,12 @@ region = Rect2(64, 80, 16, 16)
atlas = ExtResource("1_s43fy")
region = Rect2(48, 80, 16, 16)
+[sub_resource type="AtlasTexture" id="AtlasTexture_l6nwy"]
+atlas = ExtResource("1_s43fy")
+region = Rect2(96, 64, 16, 16)
+metadata/recolor = true
+metadata/scale = 2.0
+
[sub_resource type="AtlasTexture" id="AtlasTexture_c58nb"]
atlas = ExtResource("1_s43fy")
region = Rect2(96, 192, 16, 16)
@@ -688,15 +736,6 @@ region = Rect2(96, 16, 16, 16)
atlas = ExtResource("1_s43fy")
region = Rect2(48, 16, 16, 16)
-[sub_resource type="AtlasTexture" id="AtlasTexture_6yetl"]
-atlas = ExtResource("1_s43fy")
-region = Rect2(48, 240, 16, 16)
-metadata/scale = 1.0
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_l6nwy"]
-atlas = ExtResource("1_s43fy")
-region = Rect2(64, 240, 16, 16)
-
[sub_resource type="AtlasTexture" id="AtlasTexture_en6gw"]
atlas = ExtResource("1_s43fy")
region = Rect2(0, 0, 16, 16)
@@ -1462,33 +1501,43 @@ MM_Icons/icons/camera = SubResource("AtlasTexture_cscp3")
MM_Icons/icons/category_ascending = SubResource("AtlasTexture_ha0qk")
MM_Icons/icons/category_descending = SubResource("AtlasTexture_4tel2")
MM_Icons/icons/clean = SubResource("AtlasTexture_888jp")
+MM_Icons/icons/close = SubResource("AtlasTexture_qnupl")
MM_Icons/icons/color_picker = SubResource("AtlasTexture_j13i3")
MM_Icons/icons/connection_bezier = SubResource("AtlasTexture_rqjp3")
MM_Icons/icons/connection_diagonal = SubResource("AtlasTexture_8tn7x")
MM_Icons/icons/connection_direct = SubResource("AtlasTexture_pfiqs")
MM_Icons/icons/connection_manhattan = SubResource("AtlasTexture_pfsii")
MM_Icons/icons/connection_rounded = SubResource("AtlasTexture_1lfk8")
-MM_Icons/icons/console = SubResource("AtlasTexture_npn74")
+MM_Icons/icons/console = SubResource("AtlasTexture_ov3t0")
MM_Icons/icons/delete = SubResource("AtlasTexture_agwde")
+MM_Icons/icons/delete_2x = SubResource("AtlasTexture_u5byk")
+MM_Icons/icons/download = SubResource("AtlasTexture_n4y2n")
+MM_Icons/icons/drag_hint = SubResource("AtlasTexture_w255t")
MM_Icons/icons/draw = SubResource("AtlasTexture_oy0ko")
+MM_Icons/icons/draw_2x = SubResource("AtlasTexture_omlq7")
MM_Icons/icons/dropdown = SubResource("AtlasTexture_2gawd")
MM_Icons/icons/environment = SubResource("AtlasTexture_x8swe")
+MM_Icons/icons/expand = SubResource("AtlasTexture_6yetl")
MM_Icons/icons/export = SubResource("AtlasTexture_bn15y")
MM_Icons/icons/folder = SubResource("AtlasTexture_rqlqa")
-MM_Icons/icons/frequency_ascending = SubResource("AtlasTexture_xdmf6")
+MM_Icons/icons/frequency_ascending = SubResource("AtlasTexture_ooua1")
MM_Icons/icons/frequency_descending = SubResource("AtlasTexture_5jxva")
MM_Icons/icons/function = SubResource("AtlasTexture_0jwmb")
+MM_Icons/icons/generic_size = SubResource("AtlasTexture_8an74")
MM_Icons/icons/grid = SubResource("AtlasTexture_pkv4t")
MM_Icons/icons/internet = SubResource("AtlasTexture_bp85t")
+MM_Icons/icons/knife = SubResource("AtlasTexture_npn74")
MM_Icons/icons/link = SubResource("AtlasTexture_8uenv")
MM_Icons/icons/lock_locked = SubResource("AtlasTexture_m27ao")
MM_Icons/icons/lock_unlocked = SubResource("AtlasTexture_asgc8")
MM_Icons/icons/logo = SubResource("AtlasTexture_5e0gw")
MM_Icons/icons/minimap = SubResource("AtlasTexture_ld0tj")
+MM_Icons/icons/minimize = SubResource("AtlasTexture_xdmf6")
MM_Icons/icons/model = SubResource("AtlasTexture_dsr33")
MM_Icons/icons/paste_image = SubResource("AtlasTexture_dqlpm")
MM_Icons/icons/pin_pinned = SubResource("AtlasTexture_du4od")
MM_Icons/icons/pin_unpinned = SubResource("AtlasTexture_nkmvd")
+MM_Icons/icons/randomize = SubResource("AtlasTexture_l6nwy")
MM_Icons/icons/reset = SubResource("AtlasTexture_c58nb")
MM_Icons/icons/reset_view = SubResource("AtlasTexture_w0re2")
MM_Icons/icons/section_3d = SubResource("AtlasTexture_to270")
diff --git a/material_maker/theme/default_theme_icons.svg b/material_maker/theme/default_theme_icons.svg
index d7ec1d960a..eb673403ca 100644
--- a/material_maker/theme/default_theme_icons.svg
+++ b/material_maker/theme/default_theme_icons.svg
@@ -8,7 +8,7 @@
version="1.1"
id="svg1"
inkscape:version="1.4.4 (dcaf3e7, 2026-05-05)"
- sodipodi:docname="default_theme_icons.svg"
+ sodipodi:docname="master.svg"
inkscape:export-filename="new_theme_icons.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
@@ -28,15 +28,15 @@
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="true"
- inkscape:zoom="8"
- inkscape:cx="41.125"
- inkscape:cy="210.5625"
+ inkscape:zoom="5.6568543"
+ inkscape:cx="45.608387"
+ inkscape:cy="221.58959"
inkscape:window-width="1152"
inkscape:window-height="981"
inkscape:window-x="0"
inkscape:window-y="38"
inkscape:window-maximized="0"
- inkscape:current-layer="g44"
+ inkscape:current-layer="g234"
showguides="true"> bool:
while progress_window != null:
await get_tree().process_frame
environment_textures[index].erase("hdri")
+ if OS.get_name() == "Android" and android_set_hdr(index, url):
+ return true
if set_hdr(index, base_dir+"/environments/hdris/"+url.get_file()):
return true
if set_hdr(index, "res://material_maker/environments/hdris/"+url.get_file()):
@@ -202,7 +204,7 @@ func read_hdr(index : int, url : String) -> bool:
func _physics_process(_delta) -> void:
progress_window.set_progress(float($HTTPRequest.get_downloaded_bytes())/float($HTTPRequest.get_body_size()))
-func set_hdr(index, hdr_path) -> bool:
+func set_hdr(index : int, hdr_path : String) -> bool:
if not FileAccess.file_exists(hdr_path):
return false
print("Setting hdr "+hdr_path)
@@ -262,3 +264,13 @@ func do_update_thumbnail() -> void:
emit_signal("thumbnail_updated", index, t)
thumbnail_update_list = []
rendering = false
+
+func android_set_hdr(index : int, hdr_path : String) -> bool:
+ var res : String = "res://material_maker/environments/hdris"
+ for f in DirAccess.get_files_at(res):
+ var file_name : String = f.trim_suffix(".import")
+ if file_name == hdr_path.get_file():
+ print("Setting hdr "+ res.path_join(file_name))
+ environment_textures[index].hdri = load(res.path_join(file_name))
+ return true
+ return false
diff --git a/material_maker/tools/share/share_button.gd b/material_maker/tools/share/share_button.gd
index d95ca44de9..35be912138 100644
--- a/material_maker/tools/share/share_button.gd
+++ b/material_maker/tools/share/share_button.gd
@@ -195,8 +195,8 @@ func _notification(what : int) -> void:
setup_icons()
func setup_icons() -> void:
- $SendButton.texture_normal = owner.get_theme_icon("internet", "MM_Icons")
- $ConnectButton.texture_normal = owner.get_theme_icon("logo", "MM_Icons")
+ $SendButton.texture_normal = mm_globals.main_window.get_theme_icon("internet", "MM_Icons")
+ $ConnectButton.texture_normal = mm_globals.main_window.get_theme_icon("logo", "MM_Icons")
$SendButton.texture_disabled = $SendButton.texture_normal
$ConnectButton.texture_disabled = $ConnectButton.texture_normal
diff --git a/material_maker/touch.gd b/material_maker/touch.gd
new file mode 100644
index 0000000000..768bc1ecb9
--- /dev/null
+++ b/material_maker/touch.gd
@@ -0,0 +1,219 @@
+class_name MMTouch
+extends Node
+
+## basic touch handling and android utilities
+
+var _display_corner_radii : PackedInt32Array = PackedInt32Array([0, 0, 0, 0])
+var _dispalay_cutout_margins : PackedInt32Array = PackedInt32Array([0, 0, 0, 0])
+
+var android_runtime : JNISingleton
+
+var long_press_timer : Timer
+
+# workaround for godot issue #123454 for Android 16
+var last_go_back_request : int = 0
+
+func _ready() -> void:
+ if OS.get_name() not in ["iOS", "Android"]:
+ set_process_input(false)
+ else:
+ if OS.get_name() == "Android":
+ android_runtime = Engine.get_singleton("AndroidRuntime")
+ _display_corner_radii = _get_corner_radius()
+ _dispalay_cutout_margins = _get_cutout_margins()
+ elif OS.get_name() == "iOS":
+ long_press_timer = Timer.new()
+ long_press_timer.wait_time = 0.45
+ long_press_timer.autostart = false
+ long_press_timer.timeout.connect(_emulate_right_click)
+ add_child(long_press_timer)
+
+var _touch_start : int = -1
+
+## Duration between touch down/up events in milliseconds.
+var last_touch_duration_msec : int = -1
+
+## Time since last touch down event in milliseconds.
+var time_since_touch_down : int = -1:
+ get: return Time.get_ticks_msec() - _touch_start
+
+var last_touch_position : Vector2
+
+func _input(event : InputEvent) -> void:
+ if event is InputEventScreenTouch:
+ if event.pressed:
+ _touch_start = Time.get_ticks_msec()
+ long_press_timer.start()
+ last_touch_position = event.position
+ elif not event.pressed:
+ last_touch_duration_msec = Time.get_ticks_msec() - _touch_start
+ long_press_timer.stop()
+ else:
+ long_press_timer.stop()
+
+func _emulate_right_click() -> void:
+ var rmb : InputEventMouseButton = InputEventMouseButton.new()
+ rmb.pressed = true
+ rmb.position = last_touch_position * mm_globals.get_ui_scale()
+ rmb.global_position = last_touch_position * mm_globals.get_ui_scale()
+ rmb.button_index = MOUSE_BUTTON_RIGHT
+ rmb.button_mask = MOUSE_BUTTON_MASK_RIGHT
+ get_viewport().push_input(rmb, true)
+ await get_tree().process_frame
+ rmb.pressed = false
+ get_viewport().push_input(rmb, true)
+
+func _notification(what : int) -> void:
+ match what:
+ NOTIFICATION_APPLICATION_PAUSED:
+ mm_globals.config.save("user://mm_config.ini")
+ NOTIFICATION_WM_GO_BACK_REQUEST:
+ if _get_android_version() >= 36:
+ if Time.get_ticks_msec() - last_go_back_request < 125:
+ return
+ last_go_back_request = Time.get_ticks_msec()
+
+ var main_window : MainWindow = mm_globals.main_window
+ var exclude : PackedStringArray = PackedStringArray(["AddNodePopup"])
+ var windows : Array[Window]
+
+ if main_window:
+ windows.append(_first_window_child(main_window, exclude))
+ windows.append(_first_window_child(main_window.get_current_graph_edit(), exclude))
+
+ # ask window to quit
+ for window in windows:
+ if window:
+ window.close_requested.emit()
+ return
+
+ # exit app when no other dialogs are shown
+ main_window.quit()
+
+## Get display corner radius per corner.
+func corner_radius(corner : Corner, scale : float = mm_globals.get_ui_scale()) -> int:
+ return ceili(_display_corner_radii[corner] / scale)
+
+## Get cutout margins per side.
+func cutout_margins(side : Side, scale : float = mm_globals.get_ui_scale()) -> int:
+ return ceili(_dispalay_cutout_margins[side] / scale)
+
+func make_dialog_fullscreen(window : Window, show : bool = false) -> void:
+ window.borderless = true
+ window.size = mm_globals.main_window.size
+ window.min_size = Vector2.ZERO
+ window.position = Vector2.ZERO
+ # offset by MM_MainBackground stylebox content margins
+ window.position.x += maxi(0, calc_margins(Side.SIDE_LEFT) - 10)
+ window.size.x -= (window.position.x + calc_margins(Side.SIDE_RIGHT))
+ if show:
+ window.show()
+
+## Get display safe margins accounting for cutouts and corner radii.
+## [param side] can be either Side.SIDE_LEFT or Side.SIDE_RIGHT
+func calc_margins(side : Side, scale : float = mm_globals.get_ui_scale()) -> int:
+ var top : int = cutout_margins(SIDE_TOP, scale)
+ var bottom : int = cutout_margins(SIDE_BOTTOM, scale)
+ match side:
+ Side.SIDE_LEFT:
+ var top_left : int = _inset(corner_radius(CORNER_TOP_LEFT, scale), top)
+ var bottom_left : int = _inset(corner_radius(CORNER_BOTTOM_LEFT, scale), bottom)
+ return maxi(maxi(top_left, bottom_left), cutout_margins(SIDE_LEFT, scale))
+ Side.SIDE_RIGHT:
+ var top_right : int = _inset(corner_radius(CORNER_TOP_RIGHT, scale), top)
+ var bottom_right : int = _inset(corner_radius(CORNER_BOTTOM_RIGHT, scale), bottom)
+ return maxi(maxi(top_right, bottom_right), cutout_margins(SIDE_RIGHT, scale))
+ return 0
+
+func setup_margins(container : MarginContainer, margin_offset_left : int,
+ margin_ofset_right : int = margin_offset_left) -> void:
+ container.add_theme_constant_override("margin_left",
+ maxi(0, calc_margins(Side.SIDE_LEFT) + margin_offset_left))
+ container.add_theme_constant_override("margin_right",
+ maxi(0, calc_margins(Side.SIDE_RIGHT) + margin_ofset_right))
+
+## Allows a control to show its tooltip when tapped.
+func handle_tap_show_tooltip(c : Control) -> void:
+ if not c.gui_input.is_connected(_control_tap_show_tooltip.bind(c)):
+ c.gui_input.connect(_control_tap_show_tooltip.bind(c))
+
+func _first_window_child(node : Node, exclude_list : PackedStringArray) -> Window:
+ if node != null:
+ for w in node.get_children():
+ if w is Window and w.name not in exclude_list:
+ return w
+ return null
+
+func _inset(radius : int, y : int) -> int:
+ return ceili(radius - sqrt(radius ** 2 - (y - radius) ** 2)) if y < radius else 0
+
+func _get_corner_radius() -> PackedInt32Array:
+ # github.com/godotengine/godot-proposals/issues/14056#issuecomment-3816832522
+ var result : PackedInt32Array = PackedInt32Array([0, 0, 0, 0])
+ if not android_runtime:
+ return result
+ var version : JavaClass = JavaClassWrapper.wrap("android.os.Build$VERSION")
+
+ # Available only on Android 12 and later
+ if version.SDK_INT < 31:
+ return result
+
+ var insets : JavaObject = android_runtime.getActivity().getWindow().getDecorView().getRootWindowInsets()
+ var RoundedCorner : JavaClass = JavaClassWrapper.wrap("android.view.RoundedCorner")
+
+ var topLeft : JavaObject = insets.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT)
+ var topRight : JavaObject = insets.getRoundedCorner(RoundedCorner.POSITION_TOP_RIGHT)
+ var bottomRight : JavaObject = insets.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT)
+ var bottomLeft : JavaObject = insets.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT)
+
+ if is_instance_valid(topLeft):
+ result[Corner.CORNER_TOP_LEFT] = topLeft.getRadius()
+ if is_instance_valid(topRight):
+ result[Corner.CORNER_TOP_RIGHT] = topRight.getRadius()
+ if is_instance_valid(bottomRight):
+ result[Corner.CORNER_BOTTOM_RIGHT] = bottomRight.getRadius()
+ if is_instance_valid(bottomLeft):
+ result[Corner.CORNER_BOTTOM_LEFT] = bottomLeft.getRadius()
+ return result
+
+func _get_cutout_margins() -> PackedInt32Array:
+ var result : PackedInt32Array = PackedInt32Array([0, 0, 0, 0])
+ var safe_area : Rect2i = DisplayServer.get_display_safe_area()
+ var screen_size : Vector2i = DisplayServer.screen_get_size()
+ result[SIDE_LEFT] = safe_area.position.x
+ result[SIDE_TOP] = safe_area.position.y
+ result[SIDE_RIGHT] = screen_size.x - safe_area.end.x
+ result[SIDE_BOTTOM] = screen_size.y - safe_area.end.y
+ return result
+
+func _get_android_version() -> int:
+ if not android_runtime:
+ return -1
+ return JavaClassWrapper.wrap("android.os.Build$VERSION").SDK_INT
+
+func _control_tap_show_tooltip(e : InputEvent, c : Control) -> void:
+ if e is InputEventScreenTouch and e.pressed and e.index == 0:
+ _show_tooltip(c.get_global_mouse_position(), c.tooltip_text)
+
+func _show_tooltip(at : Vector2, text : String) -> void:
+ if get_tree().root.has_node("TouchTooltipPanel"):
+ get_tree().root.get_node("TouchTooltipPanel").queue_free()
+ const margin : Vector2i = Vector2i(24, 24)
+ var main_window : MainWindow = get_node("/root/MainWindow")
+
+ var tool_tip_panel : PopupPanel = PopupPanel.new()
+ tool_tip_panel.name = "TouchTooltipPanel"
+ tool_tip_panel.theme = main_window.theme
+ tool_tip_panel.theme_type_variation = "TooltipPanel"
+
+ var label : Label = Label.new()
+ label.text = text
+
+ tool_tip_panel.add_child(label)
+ tool_tip_panel.size = Vector2.ZERO
+ get_tree().root.add_child(tool_tip_panel)
+ var tsize : Vector2i = tool_tip_panel.get_contents_minimum_size()
+ var vsize : Vector2i = get_viewport().get_visible_rect().size
+ tool_tip_panel.position = at.clamp(margin, vsize - tsize - margin)
+ tool_tip_panel.popup()
+ tool_tip_panel.popup_hide.connect(tool_tip_panel.queue_free)
diff --git a/material_maker/touch.gd.uid b/material_maker/touch.gd.uid
new file mode 100644
index 0000000000..74b55faf0e
--- /dev/null
+++ b/material_maker/touch.gd.uid
@@ -0,0 +1 @@
+uid://uyvqjubc7arn
diff --git a/material_maker/widgets/curve_edit/control_point.gd b/material_maker/widgets/curve_edit/control_point.gd
index 58b17c8037..ce3f7407a9 100644
--- a/material_maker/widgets/curve_edit/control_point.gd
+++ b/material_maker/widgets/curve_edit/control_point.gd
@@ -15,10 +15,13 @@ signal moved(index)
signal removed(index)
signal selected(index)
-func _ready():
- pass # Replace with function body.
+func _ready() -> void:
+ if mm_globals.get_config("touch_optimization"):
+ offset_transform_scale = Vector2(2.5, 2.5)
+ offset_transform_visual_only = false
+ offset_transform_enabled = true
-func _draw():
+func _draw() -> void:
var current_theme : Theme = mm_globals.main_window.theme
var color : Color = current_theme.get_color("font_color", "Label")
var selected_color : Color = current_theme.get_color("icon_pressed_color", "Button")
@@ -29,8 +32,7 @@ func _draw():
draw_rect(Rect2(Vector2.ZERO, custom_minimum_size), color.inverted(), false)
if hovering or moving:
draw_rect(Rect2(-custom_minimum_size * 0.5, custom_minimum_size * 2.0), color, false, 1.0)
- draw_rect(Rect2(-custom_minimum_size*0.5-Vector2(1.0,1.0),
- custom_minimum_size*2.0+Vector2(2.0,2.0)), color.inverted(), false, 1.0)
+ draw_rect(Rect2(-custom_minimum_size * 0.5, custom_minimum_size * 2.0).grow(1.0), color.inverted(), false, 1.0)
func initialize(p : MMCurve.Point) -> void:
position = get_parent().transform_point(p.p)-OFFSET
@@ -61,7 +63,7 @@ func _on_ControlPoint_gui_input(event):
elif event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
emit_signal("removed", get_index())
elif moving and event is InputEventMouseMotion:
- var new_pos : Vector2 = position + event.relative
+ var new_pos : Vector2 = position + event.relative * offset_transform_scale
if event.is_command_or_control_pressed():
if get_parent().axes_density > 1.0:
var snap : float = 1.0 / (get_parent().axes_density - 1.0)
diff --git a/material_maker/widgets/curve_edit/slope_point.gd b/material_maker/widgets/curve_edit/slope_point.gd
index 54061ebcca..a9400c7397 100644
--- a/material_maker/widgets/curve_edit/slope_point.gd
+++ b/material_maker/widgets/curve_edit/slope_point.gd
@@ -8,16 +8,20 @@ var is_selected : bool = false
const OFFSET = -Vector2(0, 0)
-func _ready():
- pass # Replace with function body.
+func _ready() -> void:
+ if OS.get_name() == "Android":
+ offset_transform_scale = Vector2(2.5, 2.5)
+ offset_transform_visual_only = false
+ offset_transform_enabled = true
-func _draw():
+func _draw() -> void:
var current_theme : Theme = mm_globals.main_window.theme
var color : Color = current_theme.get_color("font_color", "Label")
var selected_color : Color = current_theme.get_color("icon_pressed_color", "Button")
- draw_circle(custom_minimum_size*0.5, 3.0, selected_color if is_selected else color)
+ var adjusted_scale : float = offset_transform_scale.x
+ draw_circle(custom_minimum_size*0.5, 3.0 / adjusted_scale, selected_color if is_selected else color)
if hovering or is_selected:
- draw_circle(custom_minimum_size*0.5, 6.0, color, false, 0.5, true)
+ draw_circle(custom_minimum_size*0.5, 6.0 / adjusted_scale, color, false, 0.5 / adjusted_scale, true)
func _on_ControlPoint_gui_input(event : InputEvent):
if event is InputEventMouseButton:
diff --git a/material_maker/widgets/file_picker_button/file_picker_button.gd b/material_maker/widgets/file_picker_button/file_picker_button.gd
index 8194903d73..c67bd192af 100644
--- a/material_maker/widgets/file_picker_button/file_picker_button.gd
+++ b/material_maker/widgets/file_picker_button/file_picker_button.gd
@@ -23,11 +23,13 @@ func add_filter(f : String) -> void:
filters.append(f)
func _on_Control_pressed() -> void:
- var dialog = preload("res://material_maker/windows/file_dialog/file_dialog.tscn").instantiate()
- dialog.min_size = Vector2i(500, 500)
- dialog.access = FileDialog.ACCESS_FILESYSTEM
- dialog.file_mode = mode
- dialog.current_dir = path.get_base_dir()
+ var dialog : FileDialog = preload("res://material_maker/windows/file_dialog/file_dialog.tscn").instantiate()
+ if not OS.get_name() == "Android":
+ dialog.min_size = Vector2i(500, 500)
+ dialog.access = FileDialog.ACCESS_FILESYSTEM
+ dialog.file_mode = mode
+ if path:
+ dialog.current_dir = path.get_base_dir()
for f in filters:
dialog.add_filter(f)
var files = await dialog.select_files()
diff --git a/material_maker/widgets/float_edit/float_edit.gd b/material_maker/widgets/float_edit/float_edit.gd
index 649faf89bd..239372f0b2 100644
--- a/material_maker/widgets/float_edit/float_edit.gd
+++ b/material_maker/widgets/float_edit/float_edit.gd
@@ -362,6 +362,8 @@ func _exit_tree() -> void:
mm_globals.set_config("ui_field_sensitivity", sensitivity)
func _handle_sensitivity_adjustment(event : InputEvent) -> void:
+ if OS.get_name() == "Android":
+ return
if mode == Modes.SLIDING:
adjust_increment = 0.05 if event.alt_pressed else 0.1
if event is InputEventMouseButton:
diff --git a/material_maker/widgets/gradient_editor/gradient_edit.gd b/material_maker/widgets/gradient_editor/gradient_edit.gd
index 5aecc63b1f..3f345da059 100644
--- a/material_maker/widgets/gradient_editor/gradient_edit.gd
+++ b/material_maker/widgets/gradient_editor/gradient_edit.gd
@@ -127,12 +127,13 @@ func select_color(cursor : GradientEditCursor) -> void:
if mm_globals.has_config("color_picker_shape"):
color_picker.picker_shape = mm_globals.get_config("color_picker_shape")
- # find and focus/highlight hex code
- for node in color_picker.get_child(0,true).get_child(0,true).get_children(true):
- for hex in node.get_children(true):
- if hex is LineEdit:
- hex.grab_focus()
- hex.select_all()
+ if OS.get_name() != "Android":
+ # find and focus/highlight hex code
+ for node in color_picker.get_child(0,true).get_child(0,true).get_children(true):
+ for hex in node.get_children(true):
+ if hex is LineEdit:
+ hex.grab_focus()
+ hex.select_all()
var content_scale_factor : float = mm_globals.ui_scale_factor()
color_picker_popup.content_scale_factor = content_scale_factor
@@ -279,7 +280,6 @@ func _on_popup_button_toggled(toggled_on: bool) -> void:
update_popup_position()
set_notify_transform(true)
-
else:
if is_instance_valid(popup):
popup.close()
diff --git a/material_maker/widgets/gradient_editor/gradient_popup.gd b/material_maker/widgets/gradient_editor/gradient_popup.gd
index de6ec7edc0..2d3b02493d 100644
--- a/material_maker/widgets/gradient_editor/gradient_popup.gd
+++ b/material_maker/widgets/gradient_editor/gradient_popup.gd
@@ -1,3 +1,4 @@
+class_name GradientPopup
extends Control
signal updated(value, merge_undos)
diff --git a/material_maker/widgets/image_picker_button/image_picker_button.gd b/material_maker/widgets/image_picker_button/image_picker_button.gd
index 6e3940334c..8abddd87b6 100644
--- a/material_maker/widgets/image_picker_button/image_picker_button.gd
+++ b/material_maker/widgets/image_picker_button/image_picker_button.gd
@@ -52,7 +52,7 @@ func get_filetime(file_path : String) -> int:
return 0
func open_image_dialog() -> void:
- var dialog = preload("res://material_maker/windows/file_dialog/file_dialog.tscn").instantiate()
+ var dialog = load("res://material_maker/windows/file_dialog/file_dialog.tscn").instantiate()
if image_path:
dialog.current_dir = image_path.get_base_dir()
if FileAccess.file_exists(image_path):
diff --git a/material_maker/widgets/pixels_edit/pixels_editor.gd b/material_maker/widgets/pixels_edit/pixels_editor.gd
index f9e9869a7e..74301ac8b2 100644
--- a/material_maker/widgets/pixels_edit/pixels_editor.gd
+++ b/material_maker/widgets/pixels_edit/pixels_editor.gd
@@ -33,6 +33,7 @@ func _ready() -> void:
if get_parent().has_method("add_menu_bar"):
menu_bar.get_parent().remove_child(menu_bar)
get_parent().add_menu_bar(menu_bar, self)
+
func is_mouse_in_canvas() -> bool:
return Rect2(draw_offset, draw_size).has_point(get_local_mouse_position())
@@ -61,6 +62,10 @@ func set_pixels(p : MMPixels) -> void:
queue_redraw()
update_color_buttons()
+func color_button_gui_input(event : InputEvent, button : ColorPickerButton) -> void:
+ if event is InputEventScreenTouch:
+ button.accept_event()
+
func update_color_buttons() -> void:
if not is_visible_in_tree():
return
@@ -85,6 +90,9 @@ func update_color_buttons() -> void:
color_button.toggle_mode = true
color_button.button_mask = MOUSE_BUTTON_MASK_RIGHT
colors.add_child(color_button)
+ if OS.get_name() == "Android":
+ color_button.custom_minimum_size = Vector2i(32, 32)
+ color_button.gui_input.connect(color_button_gui_input.bind(color_button))
color_button.focus_entered.connect(self.set_current_color.bind(button_count))
color_button.color_changed.connect(self.set_palette_color.bind(button_count))
button_count += 1
diff --git a/material_maker/widgets/polygon_edit/control_point.gd b/material_maker/widgets/polygon_edit/control_point.gd
index 72bc5da513..bc73e82e34 100644
--- a/material_maker/widgets/polygon_edit/control_point.gd
+++ b/material_maker/widgets/polygon_edit/control_point.gd
@@ -14,7 +14,13 @@ signal moved(index)
signal selected(index, control_pressed, shift_pressed)
signal removed(index)
-func _draw():
+func _ready() -> void:
+ if mm_globals.get_config("touch_optimization"):
+ offset_transform_enabled = true
+ offset_transform_visual_only = false
+ offset_transform_scale = Vector2(2.5, 2.5)
+
+func _draw() -> void:
var current_theme : Theme = mm_globals.main_window.theme
var moving_color : Color = current_theme.get_color("icon_pressed_color", "Button")
var color : Color = Color(1.0, 0.0, 0.0) if is_selected else current_theme.get_color("font_color", "Label")
@@ -26,8 +32,8 @@ func _draw():
draw_rect(Rect2(Vector2(0, 0), custom_minimum_size), color.inverted(), false)
if is_moving or hovered:
draw_rect(Rect2(-custom_minimum_size*0.5, custom_minimum_size*2.0), current_theme.get_color("font_color", "Label"), false, 1.0)
- draw_rect(Rect2(-custom_minimum_size*0.5-Vector2(1.0,1.0),
- custom_minimum_size*2.0+Vector2(2.0,2.0)), current_theme.get_color("font_color", "Label").inverted(), false, 1.0)
+ draw_rect(Rect2(-custom_minimum_size*0.5, custom_minimum_size*2.0).grow(1.0),
+ current_theme.get_color("font_color", "Label").inverted(), false, 1.0)
func initialize(p : Vector2, e : Control = null) -> void:
editor = e if e != null else get_parent()
@@ -62,7 +68,7 @@ func _on_ControlPoint_gui_input(event):
elif event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
removed.emit(get_index())
elif is_moving and event is InputEventMouseMotion:
- var new_pos : Vector2 = position + event.relative
+ var new_pos : Vector2 = position + event.relative * offset_transform_scale.x
if event.is_command_or_control_pressed():
var value : Vector2
var parent = get_parent().owner
diff --git a/material_maker/widgets/render_counter/render_counter.gd b/material_maker/widgets/render_counter/render_counter.gd
index ec0b853748..a481629d12 100644
--- a/material_maker/widgets/render_counter/render_counter.gd
+++ b/material_maker/widgets/render_counter/render_counter.gd
@@ -53,6 +53,9 @@ func _ready() -> void:
# GPU RAM tooltip
$GpuRam.tooltip_text = "Adapter: %s\nVendor: %s" % [ RenderingServer.get_video_adapter_name(), RenderingServer.get_video_adapter_vendor() ]
+ if OS.get_name() == "Android":
+ mm_touch.handle_tap_show_tooltip($GpuRam)
+
func on_counter_change(count : int, pending : int) -> void:
if pending == 0:
$ProgressBar.max_value = 1
diff --git a/material_maker/widgets/tabs/tabs.gd b/material_maker/widgets/tabs/tabs.gd
index 2bf69f0646..4259e170ad 100644
--- a/material_maker/widgets/tabs/tabs.gd
+++ b/material_maker/widgets/tabs/tabs.gd
@@ -123,11 +123,6 @@ func _on_Tabs_tab_changed(tab) -> void:
current_tab = tab
func _on_Projects_resized() -> void:
- $TabBar.anchor_left = 0
- $TabBar.anchor_right = 0
- $TabBar.anchor_top = 0
- $TabBar.anchor_bottom = 0
- $TabBar.size.x = size.x
if current_tab >= 0:
var node = get_child(current_tab)
node.position = Vector2(0, $TabBar.size.y)
diff --git a/material_maker/windows/about/about.gd b/material_maker/windows/about/about.gd
index ce871db70c..ad3100c17c 100644
--- a/material_maker/windows/about/about.gd
+++ b/material_maker/windows/about/about.gd
@@ -154,6 +154,12 @@ func _ready() -> void:
continue
patrons_list.add_item(p)
+ if OS.get_name() == "Android":
+ mm_touch.make_dialog_fullscreen(self, true)
+ else:
+ hide()
+ popup_centered()
+
func _name_control_gui_input(event : InputEvent, url : String) -> void:
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
open_url(url)
diff --git a/material_maker/windows/about/about.tscn b/material_maker/windows/about/about.tscn
index 9008425d1c..9efb30af73 100644
--- a/material_maker/windows/about/about.tscn
+++ b/material_maker/windows/about/about.tscn
@@ -52,6 +52,7 @@ title = "About Material Maker"
position = Vector2i(0, 36)
size = Vector2i(600, 500)
script = ExtResource("1")
+metadata/android_fullscreen_dim = true
[node name="BG" type="ColorRect" parent="."]
anchors_preset = 15
diff --git a/material_maker/windows/add_node_popup/add_node_popup.gd b/material_maker/windows/add_node_popup/add_node_popup.gd
index e989868ea0..9317af1bda 100644
--- a/material_maker/windows/add_node_popup/add_node_popup.gd
+++ b/material_maker/windows/add_node_popup/add_node_popup.gd
@@ -13,12 +13,24 @@ var qc_slot : int
var qc_slot_type : int
var qc_is_output : bool
+## Whether a drag has initiated from item's icon.
+var dragging_from_icon : bool = false
+const ICON_DRAG_MARGIN : int = 12
+
@onready var library_manager = get_node("/root/MainWindow/NodeLibraryManager")
func get_current_graph():
return get_parent().get_current_graph_edit()
func _ready() -> void:
+ if mm_globals.get_config("touch_optimization"):
+ %List.add_theme_constant_override("v_separation", 4)
+ $PanelContainer.custom_minimum_size.y = 325
+ size.y = 325
+ %List.icon_scale = 1.5
+ for i in $PanelContainer/VBoxContainer/Buttons.get_children():
+ i.custom_minimum_size *= 1.25
+
filter.connect("text_changed", Callable(self, "update_list"))
filter.connect("text_submitted", Callable(self, "filter_entered"))
%List.set_drag_forwarding(get_list_drag_data, Callable(), Callable())
@@ -162,6 +174,10 @@ func check_quick_connect(obj : Dictionary) -> bool:
return true
func update_list(filter_text : String = "") -> void:
+ var isize : Vector2i = %List.fixed_icon_size
+ var empty : Image = Image.create_empty(isize.x, isize.y, false, Image.FORMAT_RGBA8)
+ var placeholder_icon = ImageTexture.create_from_image(empty)
+
filter_text = filter_text.to_lower()
%List.clear()
var idx : int = 0
@@ -184,7 +200,8 @@ func update_list(filter_text : String = "") -> void:
var _name : String = obj.display_name
_name = obj.tree_item# + "("+str(i.quality)+")" + " ("+str(i.idx)+")"
- %List.add_item(_name, i.icon)
+ var icon : ImageTexture = i.icon if i.icon else placeholder_icon
+ %List.add_item(_name, icon)
%List.set_item_custom_fg_color(idx, color)
%List.set_item_metadata(idx, i)
%List.set_item_tooltip_enabled(idx, false)
@@ -206,26 +223,69 @@ func _on_filter_gui_input(event: InputEvent) -> void:
%List.grab_focus()
%List.select(1)
+var click_start : int
-func _on_list_gui_input(event: InputEvent) -> void:
+func _on_list_gui_input(event : InputEvent) -> void:
if event.is_action("ui_up"):
if not %List.item_count or %List.is_selected(0):
%Filter.grab_focus()
- if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and not event.pressed:
- var idx: int = %List.get_item_at_position(%List.get_local_mouse_position(), true)
- if idx != -1:
- _on_list_item_activated(idx)
-
-
-func get_list_drag_data(m_position : Vector2):
+ if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
+ if event.pressed:
+ click_start = Time.get_ticks_msec()
+ else:
+ # releasing a pan gesture also triggers a left click release
+ # use click down/up duration to tell them part
+ if Time.get_ticks_msec() - click_start > 150 and\
+ event.device == InputEvent.DEVICE_ID_EMULATION:
+ return
+ activate_item_at_current_position()
+ elif event is InputEventScreenTouch and event.index == 0:
+ var icon_width : float = get_icon_size().x + ICON_DRAG_MARGIN
+ dragging_from_icon = event.pressed and event.position.x < icon_width
+ if event.pressed:
+ %Filter.mouse_filter = Control.MOUSE_FILTER_IGNORE
+ else:
+ %Filter.mouse_filter = Control.MOUSE_FILTER_STOP
+ elif event is InputEventScreenDrag and event.index == 0:
+ # allow drag to only occur on text
+ if event.position.x > get_icon_size().x + ICON_DRAG_MARGIN and not dragging_from_icon:
+ %List.get_v_scroll_bar().value -= event.relative.y
+ %List.accept_event()
+
+func activate_item_at_current_position() -> void:
+ var idx: int = %List.get_item_at_position(%List.get_local_mouse_position(), true)
+ if idx != -1:
+ _on_list_item_activated(idx)
+
+func get_list_drag_data(m_position : Vector2) -> Variant:
var idx : int = %List.get_item_at_position(m_position)
- var data = %List.get_item_metadata(idx)
+ if OS.get_name() == "Android":
+ if m_position.x > get_icon_size().x + ICON_DRAG_MARGIN:
+ return ""
+
+ var preview : Control
+ var data : Dictionary = %List.get_item_metadata(idx)
sub_node_disable_item_drag(data, idx)
- var texture_rect : TextureRect = TextureRect.new()
- texture_rect.texture = data.icon
- texture_rect.scale = Vector2(0.35, 0.35)
- %List.set_drag_preview(texture_rect)
+
+ if data.icon:
+ preview = TextureRect.new()
+ preview.texture = data.icon
+ preview.scale = Vector2(0.35, 0.35)
+ else:
+ preview = Label.new()
+ preview.text = %List.get_item_text(idx)
+
+ if mm_globals.get_config("touch_optimization"):
+ var offset : Vector2
+ preview.scale = Vector2.ONE * (1.5 if preview is Label else 0.8)
+ if preview is TextureRect:
+ offset = preview.texture.get_size() if data.icon else preview.size
+ preview.offset_transform_enabled = true
+ preview.offset_transform_visual_only = false
+ preview.offset_transform_position = -offset * 0.5
+
+ %List.set_drag_preview(preview)
return data.item.tree_item
@@ -249,6 +309,8 @@ func _on_sort_menu_pressed() -> void:
else:
panel.popup(Rect2(panel.get_mouse_position() * content_scale_factor, panel.size))
+func get_icon_size() -> Vector2:
+ return %List.fixed_icon_size * %List.icon_scale
#region sub-node items
diff --git a/material_maker/windows/add_node_popup/quick_button.gd b/material_maker/windows/add_node_popup/quick_button.gd
index b7ede170a4..b1a6df6f93 100644
--- a/material_maker/windows/add_node_popup/quick_button.gd
+++ b/material_maker/windows/add_node_popup/quick_button.gd
@@ -20,6 +20,8 @@ func _ready():
func _can_drop_data(_position, _data):
+ if OS.get_name() == "Android":
+ return _data != ""
return true
@@ -41,10 +43,12 @@ func _drop_data(_position, data):
func _on_gui_input(event):
if !disabled and event is InputEventMouseButton:
- if event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
+ if event.button_index == MOUSE_BUTTON_LEFT and not (event.pressed or event.canceled):
emit_signal("object_selected", library_item.item)
- if event.pressed and event.button_index == MOUSE_BUTTON_RIGHT:
+ elif event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
set_library_item("")
+ if OS.get_name() == "Android":
+ mm_globals.android_make_toast("Item cleared.")
disable()
func enable() -> void:
diff --git a/material_maker/windows/environment_editor/camera_controller.gd b/material_maker/windows/environment_editor/camera_controller.gd
index ae12ea641b..25b963f01b 100644
--- a/material_maker/windows/environment_editor/camera_controller.gd
+++ b/material_maker/windows/environment_editor/camera_controller.gd
@@ -15,9 +15,21 @@ extends Node3D
var mouse_start_position : Vector2
+var world_env : WorldEnvironment
+var parent_vp : SubViewport
+
func _ready():
camera_path = camera_path
+ if has_node("../WorldEnvironment"):
+ world_env = get_node("../WorldEnvironment")
+
+ await get_tree().process_frame
+ for node in [get_parent(), get_parent().get_parent()]:
+ if node is SubViewport:
+ parent_vp = node
+ break
+
func process_event(event : InputEvent, viewport : Viewport = null) -> bool:
if event is InputEventMouseMotion:
if (event.button_mask & MOUSE_BUTTON_MASK_MIDDLE != 0
@@ -32,9 +44,13 @@ func process_event(event : InputEvent, viewport : Viewport = null) -> bool:
return true
elif event.button_mask & MOUSE_BUTTON_MASK_RIGHT != 0:
if event.shift_pressed:
- var world_env : WorldEnvironment = get_node("../WorldEnvironment")
world_env.environment.sky_rotation.y += event.relative.x * 0.001
return false
+ elif event.button_mask & MOUSE_BUTTON_MASK_LEFT != 0:
+ if event.device == InputEvent.DEVICE_ID_EMULATION:
+ camera_rotation2.rotate_x(-0.0125 * event.relative.y)
+ camera_rotation1.rotate_y(-0.0125 * event.relative.x)
+ return true
elif event is InputEventMouseButton:
if not event.is_command_or_control_pressed():
var zoom = 0.0
@@ -60,11 +76,16 @@ func process_event(event : InputEvent, viewport : Viewport = null) -> bool:
var factor : float = 0.01 * camera_position.position.z
camera_target_position.translate(-factor*event.delta.x*camera_position.global_transform.basis.x)
camera_target_position.translate(factor*event.delta.y*camera_position.global_transform.basis.y)
- else:
+ elif OS.get_name() != "Android":
camera_rotation2.rotate_x(-0.05*event.delta.y)
camera_rotation1.rotate_y(-0.05*event.delta.x)
return true
elif event is InputEventMagnifyGesture:
camera_position.position.z /= event.factor
return true
+ elif event is InputEventScreenDrag:
+ if event.index == 0:
+ camera_rotation2.rotate_x(-4.0 * event.relative.y / parent_vp.size.x )
+ camera_rotation1.rotate_y(-4.0 * event.relative.x / parent_vp.size.y )
+ return true
return false
diff --git a/material_maker/windows/environment_editor/camera_controller.tscn b/material_maker/windows/environment_editor/camera_controller.tscn
index 9a82e13ae3..d602922785 100644
--- a/material_maker/windows/environment_editor/camera_controller.tscn
+++ b/material_maker/windows/environment_editor/camera_controller.tscn
@@ -1,14 +1,14 @@
-[gd_scene load_steps=2 format=3 uid="uid://dw4wghi1pn4qr"]
+[gd_scene format=3 uid="uid://dw4wghi1pn4qr"]
[ext_resource type="Script" uid="uid://yamgbb24fo4g" path="res://material_maker/windows/environment_editor/camera_controller.gd" id="1_i358n"]
-[node name="CameraController" type="Node3D"]
+[node name="CameraController" type="Node3D" unique_id=1858284500]
script = ExtResource("1_i358n")
-[node name="CameraRotation1" type="Node3D" parent="."]
+[node name="CameraRotation1" type="Node3D" parent="." unique_id=1698689953]
-[node name="CameraRotation2" type="Node3D" parent="CameraRotation1"]
+[node name="CameraRotation2" type="Node3D" parent="CameraRotation1" unique_id=1440601724]
transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 0, 0)
-[node name="Camera3D" type="RemoteTransform3D" parent="CameraRotation1/CameraRotation2"]
+[node name="Camera3D" type="RemoteTransform3D" parent="CameraRotation1/CameraRotation2" unique_id=929968289]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 4)
diff --git a/material_maker/windows/environment_editor/environment_editor.gd b/material_maker/windows/environment_editor/environment_editor.gd
index 89b81d3e8c..4ddf8346ff 100644
--- a/material_maker/windows/environment_editor/environment_editor.gd
+++ b/material_maker/windows/environment_editor/environment_editor.gd
@@ -32,8 +32,14 @@ func _ready():
v.add_theme_stylebox_override("scroll", grabber_sb)
v.add_theme_constant_override("padding_left", 8)
- hide()
- popup_centered()
+ if OS.get_name() == "Android":
+ min_size = Vector2.ZERO
+ $Main.custom_minimum_size = Vector2.ZERO
+ mm_touch.make_dialog_fullscreen(self, true)
+ else:
+ hide()
+ popup_centered()
+
connect_controls()
environment_manager.environment_updated.connect(self.on_environment_updated)
environment_manager.name_updated.connect(self.on_name_updated)
diff --git a/material_maker/windows/environment_editor/environment_editor.tscn b/material_maker/windows/environment_editor/environment_editor.tscn
index f70cd34574..8725d53299 100644
--- a/material_maker/windows/environment_editor/environment_editor.tscn
+++ b/material_maker/windows/environment_editor/environment_editor.tscn
@@ -9,6 +9,7 @@ oversampling_override = 1.0
position = Vector2i(0, 36)
exclusive = true
script = ExtResource("2")
+metadata/android_fullscreen_dim = true
[node name="Main" type="VBoxContainer" parent="."]
custom_minimum_size = Vector2(800, 500)
diff --git a/material_maker/windows/environment_editor/environment_editor_viewport.tscn b/material_maker/windows/environment_editor/environment_editor_viewport.tscn
index 8606d265e1..f4051935a4 100644
--- a/material_maker/windows/environment_editor/environment_editor_viewport.tscn
+++ b/material_maker/windows/environment_editor/environment_editor_viewport.tscn
@@ -1,7 +1,7 @@
-[gd_scene load_steps=10 format=3 uid="uid://bb76ty33yvxj2"]
+[gd_scene format=3 uid="uid://bb76ty33yvxj2"]
[ext_resource type="PackedScene" uid="uid://cdkj3jrppq51u" path="res://material_maker/windows/environment_editor/environment_editor_scene.tscn" id="1"]
-[ext_resource type="Texture2D" uid="uid://by6042vpo6i1o" path="res://material_maker/environments/hdris/epping_forest_01_1k.hdr" id="1_r627v"]
+[ext_resource type="Texture2D" uid="uid://by6042vpo6i1o" path="res://material_maker/environments/hdris/epping_forest_01_1k.exr" id="1_r627v"]
[ext_resource type="PackedScene" uid="uid://dw4wghi1pn4qr" path="res://material_maker/windows/environment_editor/camera_controller.tscn" id="3_iommd"]
[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_f7v0t"]
diff --git a/material_maker/windows/file_dialog/file_dialog.gd b/material_maker/windows/file_dialog/file_dialog.gd
index ba0fe7d075..2ec7698e66 100644
--- a/material_maker/windows/file_dialog/file_dialog.gd
+++ b/material_maker/windows/file_dialog/file_dialog.gd
@@ -24,6 +24,10 @@ func _fix_context_menu() -> void:
break
func _ready() -> void:
+ if OS.get_name() == "Android":
+ OS.request_permissions()
+ mm_touch.make_dialog_fullscreen(self)
+
_fix_context_menu()
load_fav_recents()
if file_mode == FileMode.FILE_MODE_SAVE_FILE:
@@ -34,7 +38,7 @@ func _ready() -> void:
setup_thumbnail_callbacks()
- use_native_dialog = mm_globals.get_config("ui_use_native_file_dialogs")
+ use_native_dialog = mm_globals.get_config("ui_use_native_file_dialogs") and not OS.get_name() == "Android"
content_scale_factor = mm_globals.ui_scale_factor()
min_size = get_contents_minimum_size().max(Vector2i(750, 500)) * content_scale_factor
@@ -45,8 +49,8 @@ func _ready() -> void:
left_panel = n.get_child(1).get_children()[0]
favorites_list = left_panel.get_child(0).get_child(1)
recents_list = left_panel.get_child(1).get_child(1)
- favorites_list.gui_input.connect(_on_favorites_list_gui_input)
- recents_list.gui_input.connect(_on_recents_list_gui_input)
+ favorites_list.gui_input.connect(_on_recent_faves_list_gui_input.bind(favorites_list))
+ recents_list.gui_input.connect(_on_recent_faves_list_gui_input.bind(recents_list))
# setup display list/thumbnail buttons signals
var thumb_list_btns : HBoxContainer = n.get_child(1).get_child(1).get_child(0).get_child(3)
@@ -55,23 +59,23 @@ func _ready() -> void:
thumbnail_button.pressed.connect(set_thumbnail_mode_callback)
list_button.pressed.connect(set_list_mode_callback)
-func _on_favorites_list_gui_input(event : InputEvent) -> void:
- if event is InputEventKey and event.pressed and event.keycode == KEY_DELETE:
- if not favorites_list.get_selected_items().is_empty():
- var fav = get_favorite_list()
- fav.remove_at(favorites_list.get_selected_items()[0])
- favorites_list.remove_item(favorites_list.get_selected_items()[0])
- set_favorite_list(fav)
- left_panel.accept_event()
-
-func _on_recents_list_gui_input(event : InputEvent) -> void:
+func _on_recent_faves_list_gui_input(event : InputEvent, list : ItemList) -> void:
+ if _should_delete_recents_faves(event) and not list.get_selected_items().is_empty():
+ var list_data = get_recent_list() if list == recents_list else get_favorite_list()
+ list_data.remove_at(list.get_selected_items()[0])
+ list.remove_item(list.get_selected_items()[0])
+ if list == recents_list:
+ set_recent_list(list_data)
+ else:
+ set_favorite_list(list_data)
+ left_panel.accept_event()
+
+func _should_delete_recents_faves(event : InputEvent) -> bool:
if event is InputEventKey and event.pressed and event.keycode == KEY_DELETE:
- if not recents_list.get_selected_items().is_empty():
- var recents = get_recent_list()
- recents.remove_at(recents_list.get_selected_items()[0])
- recents_list.remove_item(recents_list.get_selected_items()[0])
- set_recent_list(recents)
- left_panel.accept_event()
+ return true
+ elif event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_RIGHT:
+ return OS.get_name() == "Android"
+ return false
func _on_FileDialog_file_selected(path) -> void:
emit_signal("return_paths", [ path ])
diff --git a/material_maker/windows/file_dialog/file_dialog.tscn b/material_maker/windows/file_dialog/file_dialog.tscn
index fb97d662d6..22cff28dcc 100644
--- a/material_maker/windows/file_dialog/file_dialog.tscn
+++ b/material_maker/windows/file_dialog/file_dialog.tscn
@@ -10,6 +10,7 @@ ok_button_text = "Open"
file_mode = 0
access = 2
script = ExtResource("1")
+metadata/android_fullscreen_dim = true
[connection signal="canceled" from="." to="." method="_on_FileDialog_popup_hide"]
[connection signal="child_entered_tree" from="." to="." method="_on_child_entered_tree"]
diff --git a/material_maker/windows/material_editor/export_editor.tscn b/material_maker/windows/material_editor/export_editor.tscn
index 5bd2df39a4..feb1fae7de 100644
--- a/material_maker/windows/material_editor/export_editor.tscn
+++ b/material_maker/windows/material_editor/export_editor.tscn
@@ -37,6 +37,7 @@ oversampling_override = 1.0
title = "Material Export Editor"
position = Vector2i(0, 36)
script = ExtResource("2")
+metadata/android_fullscreen_dim = true
[node name="BG" type="ColorRect" parent="."]
anchors_preset = 15
diff --git a/material_maker/windows/node_editor/node_editor.gd b/material_maker/windows/node_editor/node_editor.gd
index f950428e1b..17c696449f 100644
--- a/material_maker/windows/node_editor/node_editor.gd
+++ b/material_maker/windows/node_editor/node_editor.gd
@@ -143,7 +143,8 @@ func _on_Functions_text_changed():
error_label.text = "Syntax error line "+str(globals_error_line+1)+": "+result.msg
func _on_Sizer_minimum_size_changed():
- size = $Sizer.get_combined_minimum_size() + Vector2(4, 4)
+ if OS.get_name() != "Android":
+ size = $Sizer.get_combined_minimum_size() + Vector2(4, 4)
# OK/Apply/Cancel buttons
diff --git a/material_maker/windows/preferences/preference_touch_hint.gd b/material_maker/windows/preferences/preference_touch_hint.gd
new file mode 100644
index 0000000000..607f988890
--- /dev/null
+++ b/material_maker/windows/preferences/preference_touch_hint.gd
@@ -0,0 +1,62 @@
+extends Control
+
+var highlight : StyleBoxFlat
+
+var t : Tween
+
+func _ready() -> void:
+ if not OS.get_name() == "Android":
+ queue_free()
+ return
+ show()
+
+ var panel_sb : StyleBoxFlat = get_theme_stylebox("panel")
+ panel_sb.set_corner_radius_all(3)
+ panel_sb.corner_detail = 3
+ add_theme_stylebox_override("panel", panel_sb)
+
+ highlight = StyleBoxFlat.new()
+ highlight.set_corner_radius_all(4)
+ highlight.corner_detail = 3
+ highlight.bg_color = Color.WEB_GRAY
+ highlight.bg_color.a = 0.1
+ highlight.set_expand_margin_all(4.0)
+
+ var prefs : TabContainer = get_node("../TabContainer")
+ for tab in prefs.get_children():
+ for container in tab.get_child(0).get_children():
+ if container is not Container:
+ continue
+ for control : Control in container.get_children():
+ if control.get_script() in [BoolOption, EnumOption, FloatOption]:
+ control.mouse_entered.connect(_item_mouse_entered.bind(container, control.tooltip_text))
+ control.mouse_exited.connect(_item_mouse_exited.bind(container))
+ container.mouse_entered.connect(_item_mouse_entered.bind(container, control.tooltip_text))
+ container.mouse_exited.connect(_item_mouse_exited.bind(container))
+ break
+
+func setup_tween() -> void:
+ var vs : VScrollBar = $MarginContainer/ScrollContainer.get_v_scroll_bar()
+ if t:
+ t.kill()
+
+ # do not animate scroll if the text still fits
+ if abs(vs.max_value - $MarginContainer/ScrollContainer.size.y) > 5.0:
+ t = create_tween().set_loops()
+ t.tween_interval(1.5)
+ t.tween_property(vs, "ratio", 1.0, 1.5)
+ t.tween_interval(1.5)
+ t.tween_property(vs, "ratio", 0.0, 1.5)
+
+func _item_mouse_entered(c : Container, hint : String) -> void:
+ var hint_lb : Label = $MarginContainer/ScrollContainer/TouchHintLabel
+ highlight.draw.call_deferred(c.get_parent().get_canvas_item(), c.get_rect())
+ hint_lb.text = hint.replacen("\n", " ")
+ setup_tween.call_deferred()
+
+func _item_mouse_exited(c : Container) -> void:
+ c.get_parent().queue_redraw()
+ var hint_lb : Label = $MarginContainer/ScrollContainer/TouchHintLabel
+ hint_lb.text = ""
+ if t:
+ t.kill.call_deferred()
diff --git a/material_maker/windows/preferences/preference_touch_hint.gd.uid b/material_maker/windows/preferences/preference_touch_hint.gd.uid
new file mode 100644
index 0000000000..c36e0989d9
--- /dev/null
+++ b/material_maker/windows/preferences/preference_touch_hint.gd.uid
@@ -0,0 +1 @@
+uid://c8mnypok072xm
diff --git a/material_maker/windows/preferences/preferences.gd b/material_maker/windows/preferences/preferences.gd
index 5c0e5a9900..642a8bf9e6 100644
--- a/material_maker/windows/preferences/preferences.gd
+++ b/material_maker/windows/preferences/preferences.gd
@@ -12,12 +12,16 @@ func edit_preferences(c : ConfigFile) -> void:
config = c
var main_window = mm_globals.main_window
main_window.add_dialog(self)
- config_changed.connect(main_window.on_config_changed)
+ config_changed.connect(mm_globals.preferences_updated.emit)
content_scale_factor = mm_globals.ui_scale_factor()
update_controls(self)
- size *= content_scale_factor
- hide()
- popup_centered(size)
+
+ if OS.get_name() == "Android":
+ mm_touch.make_dialog_fullscreen(self, true)
+ else:
+ size *= content_scale_factor
+ hide()
+ popup_centered(size)
func update_controls(p : Node) -> void:
for c in p.get_children():
@@ -72,3 +76,12 @@ func _on_DownloadLanguage_closed():
func _on_ready() -> void:
%WinTabletDriver.visible = OS.get_name() == "Windows"
%WinTabletDriverSpacer.visible = OS.get_name() == "Windows"
+
+ %GuiSingleWindowMode.visible = OS.get_name() != "Android"
+ %GuiUseNativeFileDialogs.visible = OS.get_name() != "Android"
+ %IdleFPSLimit.visible = OS.get_name() != "Android"
+ %TouchFullScreen.visible = OS.get_name() == "Android"
+
+ if OS.get_name() == "Android":
+ config_changed.connect(mm_touch.make_dialog_fullscreen.bind(self),
+ ConnectFlags.CONNECT_DEFERRED)
diff --git a/material_maker/windows/preferences/preferences.tscn b/material_maker/windows/preferences/preferences.tscn
index 7c381d3cc9..678467b67d 100644
--- a/material_maker/windows/preferences/preferences.tscn
+++ b/material_maker/windows/preferences/preferences.tscn
@@ -17,6 +17,7 @@ position = Vector2i(0, 36)
size = Vector2i(700, 450)
exclusive = true
script = ExtResource("2")
+metadata/android_fullscreen_dim = true
[node name="HSplitContainer" type="HSplitContainer" parent="." unique_id=1807450959]
anchors_preset = 15
@@ -161,6 +162,7 @@ step = 0.01
float_only = true
[node name="GuiUseNativeFileDialogs" type="HBoxContainer" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/General/VBoxContainer" unique_id=912910531]
+unique_name_in_owner = true
layout_mode = 2
[node name="Label" type="Label" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/General/VBoxContainer/GuiUseNativeFileDialogs" unique_id=1637894285]
@@ -195,6 +197,7 @@ flat = false
config_variable = "dialog_dim_background"
[node name="GuiSingleWindowMode" type="HBoxContainer" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/General/VBoxContainer" unique_id=2099467585]
+unique_name_in_owner = true
layout_mode = 2
[node name="Label" type="Label" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/General/VBoxContainer/GuiSingleWindowMode" unique_id=721519803]
@@ -202,7 +205,7 @@ layout_mode = 2
mouse_filter = 1
text = "Single window mode (requires restart)"
-[node name="GuiSingleWindowMode" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/General/VBoxContainer/GuiSingleWindowMode" unique_id=1386250423 instance=ExtResource("1")]
+[node name="SingleWindowMode" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/General/VBoxContainer/GuiSingleWindowMode" unique_id=1386250423 instance=ExtResource("1")]
custom_minimum_size = Vector2(200, 0)
layout_mode = 2
size_flags_horizontal = 10
@@ -211,10 +214,6 @@ text = "On"
flat = false
config_variable = "ui_single_window_mode"
-[node name="Spacer6" type="Control" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/General/VBoxContainer" unique_id=2007307925]
-custom_minimum_size = Vector2(0, 10)
-layout_mode = 2
-
[node name="GuiCustomThemeBase" type="HBoxContainer" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/General/VBoxContainer" unique_id=2087466635]
layout_mode = 2
@@ -357,6 +356,7 @@ unique_name_in_owner = true
layout_mode = 2
[node name="Label" type="Label" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/General/VBoxContainer/WinTabletDriver" unique_id=724900106]
+visible = false
layout_mode = 2
text = "Tablet Driver"
@@ -420,6 +420,7 @@ step = 1.0
float_only = true
[node name="IdleFPSLimit" type="HBoxContainer" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/General/VBoxContainer" unique_id=918523289]
+unique_name_in_owner = true
layout_mode = 2
[node name="Label" type="Label" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/General/VBoxContainer/IdleFPSLimit" unique_id=34014532]
@@ -443,6 +444,24 @@ max_value = 20.0
step = 1.0
float_only = true
+[node name="KeepScreenOn" type="HBoxContainer" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/General/VBoxContainer" unique_id=1389077131]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/General/VBoxContainer/KeepScreenOn" unique_id=1745336321]
+layout_mode = 2
+size_flags_horizontal = 0
+mouse_filter = 1
+text = "Keep Screen On"
+
+[node name="KeepScreenOn" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/General/VBoxContainer/KeepScreenOn" unique_id=760988835 instance=ExtResource("1")]
+custom_minimum_size = Vector2(200, 0)
+layout_mode = 2
+size_flags_horizontal = 10
+tooltip_text = "Whether screen should stay on after a period of inactivity (based on OS settings)"
+text = "On"
+flat = false
+config_variable = "keep_screen_on"
+
[node name="Spacer4" type="Control" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/General/VBoxContainer" unique_id=1280062657]
custom_minimum_size = Vector2(0, 10)
layout_mode = 2
@@ -690,6 +709,94 @@ text = "On"
flat = false
config_variable = "remember_anim_export"
+[node name="Touch" type="ScrollContainer" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer" unique_id=881994305]
+visible = false
+layout_mode = 2
+theme_type_variation = &"MM_PreferenceTab"
+metadata/_tab_index = 4
+
+[node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/Touch" unique_id=276816290]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="TouchNodeActions" type="HBoxContainer" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/Touch/VBoxContainer" unique_id=1309858269]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/Touch/VBoxContainer/TouchNodeActions" unique_id=895456211]
+layout_mode = 2
+text = "Enable node actions panel (requires restart)"
+
+[node name="NodeActions" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/Touch/VBoxContainer/TouchNodeActions" unique_id=307131792 instance=ExtResource("1")]
+custom_minimum_size = Vector2(200, 0)
+layout_mode = 2
+size_flags_horizontal = 10
+tooltip_text = "A touch-friendly panel that provides access to common actions
+(such as delete, minimize, randomize etc.) for selected node(s) in graph panel.
+
+This is enabled by default on Android."
+text = "On"
+flat = false
+config_variable = "touch_node_actions"
+
+[node name="TouchOptimizations" type="HBoxContainer" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/Touch/VBoxContainer" unique_id=315705879]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/Touch/VBoxContainer/TouchOptimizations" unique_id=1640622729]
+layout_mode = 2
+text = "Enable touch optimizations (requires restart)"
+
+[node name="TouchOptimize" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/Touch/VBoxContainer/TouchOptimizations" unique_id=1259798418 instance=ExtResource("1")]
+custom_minimum_size = Vector2(200, 0)
+layout_mode = 2
+size_flags_horizontal = 10
+tooltip_text = "When enabled, this increases the touch area of scrollbars, makes vertical seperation between popup menu items
+larger, enables a touch dragger for panel splits etc. to increase usability on smaller screens.
+
+This is enabled by default on Android."
+text = "On"
+flat = false
+config_variable = "touch_optimization"
+
+[node name="TouchFullScreen" type="HBoxContainer" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/Touch/VBoxContainer" unique_id=860528142]
+unique_name_in_owner = true
+layout_mode = 2
+
+[node name="Label" type="Label" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/Touch/VBoxContainer/TouchFullScreen" unique_id=93076913]
+layout_mode = 2
+text = "Enable full screen"
+
+[node name="FullScreen" parent="HSplitContainer/PreferencesPanel/VBoxContainer/TabContainer/Touch/VBoxContainer/TouchFullScreen" unique_id=1590147791 instance=ExtResource("1")]
+custom_minimum_size = Vector2(200, 0)
+layout_mode = 2
+size_flags_horizontal = 10
+tooltip_text = "When enabled, this extends the window towards screen edges."
+text = "On"
+flat = false
+config_variable = "touch_full_screen"
+
+[node name="PreferenceTouchHint" type="PanelContainer" parent="HSplitContainer/PreferencesPanel/VBoxContainer" unique_id=328849096]
+visible = false
+layout_mode = 2
+theme_type_variation = &"MM_PanelBackground"
+
+[node name="MarginContainer" type="MarginContainer" parent="HSplitContainer/PreferencesPanel/VBoxContainer/PreferenceTouchHint" unique_id=508458780]
+layout_mode = 2
+theme_override_constants/margin_left = 6
+theme_override_constants/margin_top = 6
+theme_override_constants/margin_right = 6
+theme_override_constants/margin_bottom = 6
+
+[node name="ScrollContainer" type="ScrollContainer" parent="HSplitContainer/PreferencesPanel/VBoxContainer/PreferenceTouchHint/MarginContainer" unique_id=1664878493]
+custom_minimum_size = Vector2(0, 60)
+custom_maximum_size = Vector2(-1, 60)
+layout_mode = 2
+
+[node name="TouchHintLabel" type="Label" parent="HSplitContainer/PreferencesPanel/VBoxContainer/PreferenceTouchHint/MarginContainer/ScrollContainer" unique_id=1926624238]
+custom_minimum_size = Vector2(1, 0)
+layout_mode = 2
+size_flags_horizontal = 3
+autowrap_mode = 3
+
[node name="MarginContainer" type="MarginContainer" parent="HSplitContainer/PreferencesPanel/VBoxContainer" unique_id=245791047]
layout_mode = 2
theme_override_constants/margin_top = 4
diff --git a/material_maker/windows/sdf_builder/preview_3d.gd b/material_maker/windows/sdf_builder/preview_3d.gd
index a760959466..210487a99d 100644
--- a/material_maker/windows/sdf_builder/preview_3d.gd
+++ b/material_maker/windows/sdf_builder/preview_3d.gd
@@ -121,7 +121,7 @@ func _on_Preview3D_resized():
viewport.size = size
update_viewport()
-func navigation_input(ev) -> bool:
+func navigation_input(ev : InputEvent) -> bool:
if ! get_global_rect().has_point(get_global_mouse_position()):
return false
if ev is InputEventMouseMotion:
@@ -152,8 +152,27 @@ func navigation_input(ev) -> bool:
if zoom != 0.0:
camera.translate(Vector3(0.0, 0.0, zoom*(1.0 if ev.shift_pressed else 0.1)))
return true
+ elif ev is InputEventScreenDrag and ev.index == 0:
+ # one-finger drag: orbit
+ camera_rotation2.rotate_x(-0.01*ev.relative.y)
+ camera_rotation1.rotate_y(-0.01*ev.relative.x)
+ return true
+ elif ev is InputEventMagnifyGesture:
+ # two-finger pinch: zoom
+ camera.position.z /= ev.factor
+ return true
+ elif ev is InputEventPanGesture:
+ # two-finger pan: offset
+ var factor = camera.position.z
+ camera_position.translate(-factor/size.x*-4.0*ev.delta.x*camera.global_transform.basis.x)
+ camera_position.translate(factor/size.y*-4.0*ev.delta.y*camera.global_transform.basis.y)
+ return true
return false
+func _gui_input(event : InputEvent) -> void:
+ if event is InputEventMagnifyGesture or event is InputEventPanGesture:
+ _on_Background_input_event(null, event, null, null, null)
+
func _on_Background_input_event(_camera, event, _position, _normal, _shape_idx):
if navigation_input(event):
accept_event()
diff --git a/material_maker/windows/sdf_builder/sdf_builder.gd b/material_maker/windows/sdf_builder/sdf_builder.gd
index e618bacfb9..1729cf20b2 100644
--- a/material_maker/windows/sdf_builder/sdf_builder.gd
+++ b/material_maker/windows/sdf_builder/sdf_builder.gd
@@ -31,7 +31,7 @@ signal editor_window_closed
const BUTTON_SHOWN = preload("res://material_maker/icons/eye_open.tres")
const BUTTON_HIDDEN = preload("res://material_maker/icons/eye_closed.tres")
-
+var button_drag_hint : Texture2D
func _ready():
tree.set_hide_root(true)
@@ -45,9 +45,23 @@ func _ready():
await get_tree().process_frame
content_scale_factor = mm_globals.ui_scale_factor()
- min_size = Vector2(800, 400) * content_scale_factor
- size = min_size
- move_to_center()
+
+ if OS.get_name() == "Android":
+ mm_touch.make_dialog_fullscreen(self, true)
+ var top_spacer : Control = Control.new()
+ top_spacer.custom_minimum_size.y = 24
+ $TopContainer.add_child(top_spacer)
+ $TopContainer.move_child(top_spacer, 0)
+ $TopContainer/Main/Tree/AddMenuHint.text = "Tap and hold to add shapes"
+ else:
+ min_size = Vector2(800, 400) * content_scale_factor
+ size = min_size
+ move_to_center()
+ _update_tree_menu_hint_visibility()
+
+func _notification(what : int) -> void:
+ if what == NOTIFICATION_THEME_CHANGED:
+ button_drag_hint = get_theme_icon("drag_hint", "MM_Icons")
func get_next_index() -> int:
next_index += 1
@@ -154,9 +168,9 @@ func update_node_parameters_grid():
if button != null:
button.disabled = true
-func node_parameter_exists_already(name : String, param_index : int) -> bool:
+func node_parameter_exists_already(_name : String, param_index : int) -> bool:
for pi in range($GenSDF.node_parameters.size()):
- if pi != param_index and $GenSDF.node_parameters[pi].name == name:
+ if pi != param_index and $GenSDF.node_parameters[pi].name == _name:
return true
return false
@@ -253,9 +267,13 @@ func add_sdf_item(i : Dictionary, parent_item : TreeItem) -> TreeItem:
var item_type = mm_sdf_builder.item_types[mm_sdf_builder.item_ids[i.type]]
var item_icon = item_type.get("icon")
if item_icon != null:
- item.set_icon(0, item_icon)
+ var icon : Texture2D = item_icon
+ if mm_globals.get_config("touch_optimization"):
+ icon = resize_icon(item_icon, 24)
+ item.set_icon(0, icon)
i.index = get_next_index()
item.add_button(2, BUTTON_HIDDEN if i.has("hidden") and i.hidden else BUTTON_SHOWN, 0)
+ add_mobile_drag_hint_button(item, 1)
item.set_meta("scene", i)
set_sdf_scene(i.children, item)
if i.has("collapsed") and i.collapsed:
@@ -266,6 +284,7 @@ func rebuild_scene(item : TreeItem = tree.get_root()) -> Dictionary:
var scene_list : Array = []
for child in item.get_children():
scene_list.push_back(rebuild_scene(child))
+ _update_tree_menu_hint_visibility()
if item == tree.get_root():
scene = scene_list
return {}
@@ -349,6 +368,11 @@ func _on_menu(id : int, current_item : TreeItem):
MENU_DUMP:
print(current_item.get_meta("scene"))
+func resize_icon(icon : Texture2D, width : int, height = width) -> ImageTexture:
+ var img : Image = icon.get_image()
+ img.resize(width, height)
+ return ImageTexture.create_from_image(img)
+
func _on_menu_add_shape(id : int, current_item : TreeItem):
var shape = mm_sdf_builder.item_types[id]
var shape_name = shape.item_type
@@ -369,24 +393,31 @@ func _on_menu_add_shape(id : int, current_item : TreeItem):
current_item.get_meta("scene").children.push_back(data)
var item_icon = shape.get("icon")
if item_icon != null:
- item.set_icon(0, item_icon)
+ var icon : Texture2D = item_icon
+ if mm_globals.get_config("touch_optimization"):
+ icon = resize_icon(item_icon, 24)
+ item.set_icon(0, icon)
data.index = get_next_index()
item.set_text(0, shape_name)
item.set_meta("scene", data)
item.add_button(2, BUTTON_SHOWN, 0)
+ add_mobile_drag_hint_button(item, 1)
set_preview(scene)
item.select(0)
+ _update_tree_menu_hint_visibility()
func _on_Tree_item_edited():
var item : TreeItem = tree.get_selected()
+ if not item:
+ return
item.set_editable(0, false)
var item_scene : Dictionary = item.get_meta("scene")
- var name : String = item.get_text(0)
- if name == "" or name == item_scene.type:
+ var _name : String = item.get_text(0)
+ if _name == "" or _name == item_scene.type:
item_scene.erase("name")
item.set_text(0, item_scene.type)
else:
- item_scene.name = name
+ item_scene.name = _name
func _on_Tree_item_collapsed(item):
var item_scene : Dictionary = item.get_meta("scene")
@@ -623,16 +654,18 @@ func _on_Tree_item_selected():
preview_3d.setup_controls("n%d" % index)
$GenSDF.set_parameter("index", float(index))
-func _on_tree_button_clicked(item, _column, _id, mouse_button_index):
+func _on_tree_button_clicked(item : Variant, _column : Variant,
+ id : int, mouse_button_index : Variant):
if mouse_button_index != MOUSE_BUTTON_LEFT:
return
var item_scene : Dictionary = item.get_meta("scene")
- if item_scene.has("hidden") and item_scene.hidden:
- item_scene.erase("hidden")
- item.set_button(2, 0, BUTTON_SHOWN)
- else:
- item_scene.hidden = true
- item.set_button(2, 0, BUTTON_HIDDEN)
+ if id == 0:
+ if item_scene.has("hidden") and item_scene.hidden:
+ item_scene.erase("hidden")
+ item.set_button(2, 0, BUTTON_SHOWN)
+ else:
+ item_scene.hidden = true
+ item.set_button(2, 0, BUTTON_HIDDEN)
set_preview(scene)
_on_Tree_item_selected()
@@ -658,16 +691,17 @@ func duplicate_item(item : TreeItem, parent : TreeItem, index : int = -1):
new_item.set_text(0, item.get_text(0))
new_item.set_icon(0, item.get_icon(0))
new_item.add_button(2, item.get_button(2, 0), 0)
+ add_mobile_drag_hint_button(new_item, 1)
new_item.set_meta("scene", item.get_meta("scene"))
for c in item.get_children():
duplicate_item(c, new_item)
return new_item
-func move_item(item, dest, position):
+func move_item(item, dest, target_position):
var source_transform : Transform3D = get_item_transform_3d(item)
var dest_transform : Transform3D = get_item_transform_3d(dest)
var new_transform : Transform3D = dest_transform.affine_inverse()*source_transform
- var new_item : TreeItem = duplicate_item(item, dest, position)
+ var new_item : TreeItem = duplicate_item(item, dest, target_position)
item.get_parent().remove_child(item)
# update copy's transform parameters
rebuild_scene()
@@ -686,8 +720,8 @@ func move_item(item, dest, position):
parameters["n%d_position_z" % index] = new_transform.origin.z
set_node_parameters($GenSDF, parameters)
-func _on_Tree_drop_item(item, dest, position):
- move_item(item, dest, position)
+func _on_Tree_drop_item(item, dest, target_position):
+ move_item(item, dest, target_position)
# OK/Apply/Cancel buttons
@@ -744,3 +778,16 @@ func _input(event):
func _on_VBoxContainer_minimum_size_changed():
min_size = $TopContainer.get_combined_minimum_size()+Vector2(4, 4)
+
+func _update_tree_menu_hint_visibility() -> void:
+ var should_show : bool = tree.get_root().get_child_count() == 0
+ $TopContainer/Main/Tree/AddMenuHint.visible = should_show
+
+#region android specific
+
+func add_mobile_drag_hint_button(item : TreeItem, id : int = -1) -> void:
+ if OS.get_name() == "Android":
+ item.add_button(3, button_drag_hint, id)
+ item.set_icon_modulate(3, Color.RED)
+
+#endregion
diff --git a/material_maker/windows/sdf_builder/sdf_builder.tscn b/material_maker/windows/sdf_builder/sdf_builder.tscn
index c790d96f68..606ef1bb61 100644
--- a/material_maker/windows/sdf_builder/sdf_builder.tscn
+++ b/material_maker/windows/sdf_builder/sdf_builder.tscn
@@ -30,6 +30,7 @@ title = "Easy SDF"
position = Vector2i(0, 36)
exclusive = true
script = ExtResource("3")
+metadata/android_fullscreen_dim = true
[node name="TopContainer" type="VBoxContainer" parent="."]
custom_minimum_size = Vector2(800, 400)
@@ -53,10 +54,27 @@ custom_minimum_size = Vector2(200, 200)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
-columns = 3
+columns = 4
select_mode = 1
+auto_tooltip = false
script = ExtResource("4")
+[node name="AddMenuHint" type="Label" parent="TopContainer/Main/Tree" unique_id=909843201]
+modulate = Color(1, 1, 1, 0.5176471)
+layout_mode = 1
+anchors_preset = 8
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+offset_left = -20.0
+offset_top = -11.5
+offset_right = 20.0
+offset_bottom = 11.5
+grow_horizontal = 2
+grow_vertical = 2
+text = "Right click to add shapes"
+
[node name="Preview2D" parent="TopContainer/Main" instance=ExtResource("2")]
unique_name_in_owner = true
material = SubResource("ShaderMaterial_pgcwv")
diff --git a/material_maker/windows/sdf_builder/sdf_builder_tree.gd b/material_maker/windows/sdf_builder/sdf_builder_tree.gd
index 5ec2a8d188..45eea0d62e 100644
--- a/material_maker/windows/sdf_builder/sdf_builder_tree.gd
+++ b/material_maker/windows/sdf_builder/sdf_builder_tree.gd
@@ -1,5 +1,6 @@
extends Tree
+var tree_scrollbar : VScrollBar
signal drop_item(item, dest, position)
@@ -9,6 +10,47 @@ func _ready():
set_column_custom_minimum_width(1, 28)
set_column_expand(2, false)
set_column_custom_minimum_width(2, 28)
+ set_column_expand(3, false)
+ set_column_custom_minimum_width(3, 32)
+
+ if mm_globals.get_config("touch_optimization"):
+ add_theme_constant_override("v_separation", 12)
+
+ for node in get_children(true):
+ if node is VScrollBar:
+ tree_scrollbar = node
+
+func get_drag_handle_pos(item : TreeItem) -> float:
+ if not item:
+ return 0.0
+ var scroll_w : float = 0.0
+ if tree_scrollbar.visible:
+ scroll_w = tree_scrollbar.size.x
+ var item_w : float = get_item_area_rect(item).size.x
+ return maxf(item_w - scroll_w - 72.0, 0.0)
+
+var dragged_from_handle : bool = false
+
+func _gui_input(event : InputEvent) -> void:
+ if event is InputEventMouseButton:
+ if event.device == InputEvent.DEVICE_ID_EMULATION:
+ accept_event()
+ elif event is InputEventScreenDrag and event.index == 0:
+ var item : TreeItem = get_item_at_position(event.position)
+ if not dragged_from_handle and item and event.position.x < get_drag_handle_pos(item):
+ tree_scrollbar.value -= event.relative.y
+ accept_event()
+ elif event is InputEventScreenTouch and event.index == 0:
+ if event.pressed:
+ var item : TreeItem = get_item_at_position(event.position)
+ if item:
+ item.select(0, false)
+ if event.position.x > get_drag_handle_pos(item):
+ dragged_from_handle = true
+ else:
+ deselect_all()
+ else:
+ dragged_from_handle = false
func get_sdf_item_type(item : TreeItem) -> Object:
if item == null or not item.has_meta("scene"):
@@ -29,11 +71,13 @@ func get_nearest_parent(item : TreeItem, type : String) -> TreeItem:
item = item.get_parent()
return item
-func _get_drag_data(position):
- var item : TreeItem = get_item_at_position(position)
+func _get_drag_data(at_position : Vector2):
+ var item : TreeItem = get_item_at_position(at_position)
if item == null:
return null
else:
+ if at_position.x < get_drag_handle_pos(item):
+ return null
var label = Label.new()
label.text = item.get_text(0)
set_drag_preview(label)
@@ -62,10 +106,10 @@ func get_valid_children_types(parent : TreeItem):
valid_children_types.push_back(parent_type.item_category)
return valid_children_types
-func _can_drop_data(position, data):
+func _can_drop_data(at_position : Vector2, data : Variant):
if data is Dictionary and data.has("item") and data.item is TreeItem:
- var destination : TreeItem = get_item_at_position(position)
- if destination != null and get_drop_section_at_position(position) != 0:
+ var destination : TreeItem = get_item_at_position(at_position)
+ if destination != null and get_drop_section_at_position(at_position) != 0:
destination = destination.get_parent()
if not mm_sdf_builder.scene_get_type(data.item.get_meta("scene")).item_category in get_valid_children_types(destination):
return false
@@ -82,10 +126,10 @@ func get_item_index(item : TreeItem) -> int:
index += 1
return -1
-func _drop_data(position, data):
+func _drop_data(at_position : Vector2, data : Variant):
if data is Dictionary and data.has("item") and data.item is TreeItem:
- var item = get_item_at_position(position)
- match get_drop_section_at_position(position):
+ var item = get_item_at_position(at_position)
+ match get_drop_section_at_position(at_position):
0:
emit_signal("drop_item", data.item, item, -1)
-1:
diff --git a/no_export/android/adaptive_background.svg b/no_export/android/adaptive_background.svg
new file mode 100644
index 0000000000..0dfac893f5
--- /dev/null
+++ b/no_export/android/adaptive_background.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/no_export/android/adaptive_background.svg.import b/no_export/android/adaptive_background.svg.import
new file mode 100644
index 0000000000..4812a947d7
--- /dev/null
+++ b/no_export/android/adaptive_background.svg.import
@@ -0,0 +1,3 @@
+[remap]
+
+importer="skip"
diff --git a/no_export/android/adaptive_foreground.svg b/no_export/android/adaptive_foreground.svg
new file mode 100644
index 0000000000..11adbb3d5d
--- /dev/null
+++ b/no_export/android/adaptive_foreground.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/no_export/android/adaptive_foreground.svg.import b/no_export/android/adaptive_foreground.svg.import
new file mode 100644
index 0000000000..4812a947d7
--- /dev/null
+++ b/no_export/android/adaptive_foreground.svg.import
@@ -0,0 +1,3 @@
+[remap]
+
+importer="skip"
diff --git a/no_export/android/adaptive_monochrome.svg b/no_export/android/adaptive_monochrome.svg
new file mode 100644
index 0000000000..456ae0dbf4
--- /dev/null
+++ b/no_export/android/adaptive_monochrome.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/no_export/android/adaptive_monochrome.svg.import b/no_export/android/adaptive_monochrome.svg.import
new file mode 100644
index 0000000000..4812a947d7
--- /dev/null
+++ b/no_export/android/adaptive_monochrome.svg.import
@@ -0,0 +1,3 @@
+[remap]
+
+importer="skip"
diff --git a/no_export/android/android_legacy_icon.webp b/no_export/android/android_legacy_icon.webp
new file mode 100644
index 0000000000..993b80cafd
Binary files /dev/null and b/no_export/android/android_legacy_icon.webp differ
diff --git a/no_export/android/android_legacy_icon.webp.import b/no_export/android/android_legacy_icon.webp.import
new file mode 100644
index 0000000000..4812a947d7
--- /dev/null
+++ b/no_export/android/android_legacy_icon.webp.import
@@ -0,0 +1,3 @@
+[remap]
+
+importer="skip"
diff --git a/project.godot b/project.godot
index 9b602ebfd4..5eb03560ae 100644
--- a/project.godot
+++ b/project.godot
@@ -20,7 +20,8 @@ config/tags=PackedStringArray("material_maker")
run/main_scene="res://parse_args.tscn"
config/use_custom_user_dir=true
config/custom_user_dir_name="material_maker_2"
-config/features=PackedStringArray("4.7")
+config/quit_on_go_back=false
+config/features=PackedStringArray("4.8")
boot_splash/bg_color=Color(0, 0, 0, 1)
boot_splash/show_image=false
boot_splash/use_filter=false
@@ -35,6 +36,7 @@ driver/driver="Dummy"
[autoload]
+mm_touch="*res://material_maker/touch.gd"
mm_logger="*res://addons/material_maker/engine/logger.gd"
mm_steam="*res://material_maker/steam.gd"
mm_globals="*res://material_maker/globals.tscn"
@@ -60,9 +62,9 @@ window/size/borderless=true
window/size/transparent=true
window/size/window_width_override=1
window/size/window_height_override=1
-window/per_pixel_transparency/allowed=true
window/subwindows/embed_subwindows=false
-window/handheld/orientation.Android="sensor_landscape"
+window/per_pixel_transparency/allowed=true
+window/per_pixel_transparency/allowed.android=false
[editor]
@@ -82,57 +84,257 @@ timers/tooltip_delay_sec=0.1
toggle_fullscreen={
"deadzone": 0.5,
-"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":16777254,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
-, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":16777221,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
-]
+"events": [Object(InputEventKey,
+"resource_local_to_scene": false,
+"resource_name": "",
+"device": 0,
+"window_id": 0,
+"alt_pressed": false,
+"shift_pressed": false,
+"ctrl_pressed": false,
+"meta_pressed": false,
+"pressed": false,
+"keycode": 16777254,
+"physical_keycode": 0,
+"key_label": 0,
+"unicode": 0,
+"location": 0,
+"echo": false,
+"script": null
+), Object(InputEventKey,
+"resource_local_to_scene": false,
+"resource_name": "",
+"device": 0,
+"window_id": 0,
+"alt_pressed": true,
+"shift_pressed": false,
+"ctrl_pressed": false,
+"meta_pressed": false,
+"pressed": false,
+"keycode": 16777221,
+"physical_keycode": 0,
+"key_label": 0,
+"unicode": 0,
+"location": 0,
+"echo": false,
+"script": null
+)]
}
ui_library_popup={
"deadzone": 0.5,
-"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":32,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
-]
+"events": [Object(InputEventKey,
+"resource_local_to_scene": false,
+"resource_name": "",
+"device": 0,
+"window_id": 0,
+"alt_pressed": false,
+"shift_pressed": false,
+"ctrl_pressed": false,
+"meta_pressed": false,
+"pressed": false,
+"keycode": 32,
+"physical_keycode": 0,
+"key_label": 0,
+"unicode": 0,
+"location": 0,
+"echo": false,
+"script": null
+)]
}
ui_hierarchy_up={
"deadzone": 0.5,
-"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":16777220,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
-, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":16777218,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
-]
+"events": [Object(InputEventKey,
+"resource_local_to_scene": false,
+"resource_name": "",
+"device": 0,
+"window_id": 0,
+"alt_pressed": false,
+"shift_pressed": false,
+"ctrl_pressed": false,
+"meta_pressed": false,
+"pressed": false,
+"keycode": 16777220,
+"physical_keycode": 0,
+"key_label": 0,
+"unicode": 0,
+"location": 0,
+"echo": false,
+"script": null
+), Object(InputEventKey,
+"resource_local_to_scene": false,
+"resource_name": "",
+"device": 0,
+"window_id": 0,
+"alt_pressed": false,
+"shift_pressed": true,
+"ctrl_pressed": false,
+"meta_pressed": false,
+"pressed": false,
+"keycode": 16777218,
+"physical_keycode": 0,
+"key_label": 0,
+"unicode": 0,
+"location": 0,
+"echo": false,
+"script": null
+)]
}
ui_hierarchy_down={
"deadzone": 0.5,
-"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":16777218,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
-]
+"events": [Object(InputEventKey,
+"resource_local_to_scene": false,
+"resource_name": "",
+"device": 0,
+"window_id": 0,
+"alt_pressed": false,
+"shift_pressed": false,
+"ctrl_pressed": false,
+"meta_pressed": false,
+"pressed": false,
+"keycode": 16777218,
+"physical_keycode": 0,
+"key_label": 0,
+"unicode": 0,
+"location": 0,
+"echo": false,
+"script": null
+)]
}
ui_toggle_docks={
"deadzone": 0.5,
-"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":true,"pressed":false,"keycode":32,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
-]
+"events": [Object(InputEventKey,
+"resource_local_to_scene": false,
+"resource_name": "",
+"device": 0,
+"window_id": 0,
+"alt_pressed": false,
+"shift_pressed": false,
+"ctrl_pressed": true,
+"meta_pressed": true,
+"pressed": false,
+"keycode": 32,
+"physical_keycode": 0,
+"key_label": 0,
+"unicode": 0,
+"location": 0,
+"echo": false,
+"script": null
+)]
}
ui_previous_tab={
"deadzone": 0.5,
-"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":true,"meta_pressed":true,"pressed":false,"keycode":16777218,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
-]
+"events": [Object(InputEventKey,
+"resource_local_to_scene": false,
+"resource_name": "",
+"device": 0,
+"window_id": 0,
+"alt_pressed": false,
+"shift_pressed": true,
+"ctrl_pressed": true,
+"meta_pressed": true,
+"pressed": false,
+"keycode": 16777218,
+"physical_keycode": 0,
+"key_label": 0,
+"unicode": 0,
+"location": 0,
+"echo": false,
+"script": null
+)]
}
ui_next_tab={
"deadzone": 0.5,
-"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":true,"pressed":false,"keycode":16777218,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
-]
+"events": [Object(InputEventKey,
+"resource_local_to_scene": false,
+"resource_name": "",
+"device": 0,
+"window_id": 0,
+"alt_pressed": false,
+"shift_pressed": false,
+"ctrl_pressed": true,
+"meta_pressed": true,
+"pressed": false,
+"keycode": 16777218,
+"physical_keycode": 0,
+"key_label": 0,
+"unicode": 0,
+"location": 0,
+"echo": false,
+"script": null
+)]
}
ui_cut_drag={
"deadzone": 0.5,
-"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":false,"button_mask":2,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":2,"canceled":false,"pressed":true,"double_click":false,"script":null)
-]
+"events": [Object(InputEventMouseButton,
+"resource_local_to_scene": false,
+"resource_name": "",
+"device": 0,
+"window_id": 0,
+"alt_pressed": false,
+"shift_pressed": false,
+"ctrl_pressed": true,
+"meta_pressed": false,
+"button_mask": 2,
+"position": Vector2(0, 0),
+"global_position": Vector2(0, 0),
+"factor": 1.0,
+"button_index": 2,
+"canceled": false,
+"pressed": true,
+"double_click": false,
+"script": null
+)]
}
ui_lasso_select={
"deadzone": 0.5,
-"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":1,"position":Vector2(391, 10),"global_position":Vector2(407, 91),"factor":1.0,"button_index":1,"canceled":false,"pressed":true,"double_click":false,"script":null)
-]
+"events": [Object(InputEventMouseButton,
+"resource_local_to_scene": false,
+"resource_name": "",
+"device": -1,
+"window_id": 0,
+"alt_pressed": true,
+"shift_pressed": false,
+"ctrl_pressed": false,
+"meta_pressed": false,
+"button_mask": 1,
+"position": Vector2(391, 10),
+"global_position": Vector2(407, 91),
+"factor": 1.0,
+"button_index": 1,
+"canceled": false,
+"pressed": true,
+"double_click": false,
+"script": null
+)]
}
left_click={
"deadzone": 0.2,
-"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":1,"position":Vector2(80, 13),"global_position":Vector2(89, 61),"factor":1.0,"button_index":1,"canceled":false,"pressed":true,"double_click":false,"script":null)
-]
+"events": [Object(InputEventMouseButton,
+"resource_local_to_scene": false,
+"resource_name": "",
+"device": -1,
+"window_id": 0,
+"alt_pressed": false,
+"shift_pressed": false,
+"ctrl_pressed": false,
+"meta_pressed": false,
+"button_mask": 1,
+"position": Vector2(80, 13),
+"global_position": Vector2(89, 61),
+"factor": 1.0,
+"button_index": 1,
+"canceled": false,
+"pressed": true,
+"double_click": false,
+"script": null
+)]
}
+[input_devices]
+
+pointing/android/enable_long_press_as_right_click=true
+pointing/android/enable_pan_and_scale_gestures=true
+
[internationalization]
rendering/root_node_layout_direction=1
@@ -155,6 +357,7 @@ limits/debugger/max_chars_per_second=204800000
[rendering]
+rendering_device/driver.ios="vulkan"
rendering_device/driver.macos="vulkan"
textures/vram_compression/import_etc2_astc=true
shading/overrides/force_lambert_over_burley.mobile=false
diff --git a/splash_screen/splash_screen.gd b/splash_screen/splash_screen.gd
index d721c8da01..25b24c8191 100644
--- a/splash_screen/splash_screen.gd
+++ b/splash_screen/splash_screen.gd
@@ -12,7 +12,7 @@ var mm_scene : PackedScene = null
const BACKGROUNDS_DIR : String = "res://splash_screen/backgrounds/"
-const BACKGROUNDS : Array[Dictionary] = [
+var splash_backgrounds : Array[Dictionary] = [
{ author="Angel", entries=[
{ title="Beanbag Chair", file="angel_beanbag_chair.png" },
{ title="Soft Nurball", file="angel_soft_nurball.png" },
@@ -101,6 +101,8 @@ const ACTIVITY_MESSAGES : Array[String] = [
]
func _enter_tree():
+ if OS.get_name() == "Android":
+ android_filter_splash_screens()
var date : Dictionary = Time.get_date_dict_from_system()
var date_int : int = date.month*33+date.day
var screen : int = 0
@@ -108,32 +110,42 @@ func _enter_tree():
_:
randomize()
var sum : float = 0.0
- for i in BACKGROUNDS.size():
- if BACKGROUNDS[i].has("odds"):
- sum += BACKGROUNDS[i].odds
+ for i in splash_backgrounds.size():
+ if splash_backgrounds[i].has("odds"):
+ sum += splash_backgrounds[i].odds
else:
sum += 1
var value : float = randf_range(0, sum)
sum = 0.0
- for i in BACKGROUNDS.size():
- if BACKGROUNDS[i].has("odds"):
- sum += BACKGROUNDS[i].odds
+ for i in splash_backgrounds.size():
+ if splash_backgrounds[i].has("odds"):
+ sum += splash_backgrounds[i].odds
else:
sum += 1
if sum >= value:
screen = i
break
set_screen(screen)
+
var window : Window = get_window()
- var current_screen_index = window.current_screen
- var ui_scale : int = 2 if DisplayServer.screen_get_dpi() >= 192 and DisplayServer.screen_get_size().x >= 2048 else 1
- window.position = (DisplayServer.screen_get_size(current_screen_index)-Vector2i(ui_scale*size))/2 + DisplayServer.screen_get_position(current_screen_index)
- window.size = ui_scale*size
+ var ui_scale : int = _ui_scale()
window.content_scale_factor = ui_scale
+ if OS.get_name() == "Android":
+ android_setup_margins()
+ android_setup_artwork_details_size()
+ $SplashScreen.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_COVERED
+ else:
+ var current_screen_index = window.current_screen
+ @warning_ignore("integer_division")
+ window.position = (DisplayServer.screen_get_size(current_screen_index)-Vector2i(ui_scale*size))/2 + DisplayServer.screen_get_position(current_screen_index)
+ window.size = ui_scale*size
+
+func _ui_scale() -> int:
+ return 2 if DisplayServer.screen_get_dpi() >= 192 and DisplayServer.screen_get_size().x >= 2048 else 1
func set_screen(bi : int, sub_index = -1) -> void:
background_index = bi
- var background : Dictionary = BACKGROUNDS[background_index]
+ var background : Dictionary = splash_backgrounds[background_index]
var author : String = background.author if background.has("author") else ""
var file : String = background.file if background.has("file") else ""
var title : String = background.title if background.has("title") else ""
@@ -173,6 +185,9 @@ func set_screen(bi : int, sub_index = -1) -> void:
%Title.gui_input.disconnect(c.callable)
func _ready():
+ if OS.get_name() == "Android":
+ android_splash_fade_in()
+ await get_tree().create_timer(0.7).timeout
set_process(false)
resource_path = "res://material_maker/main_window.tscn"
@@ -260,16 +275,16 @@ func _on_secret_button_gui_input(event):
mm_steam.unlock_achievement("ACH_EAGLE_EYE")
func _on_previous_pressed():
- if BACKGROUNDS[background_index].has("entries") and background_subindex > 0:
+ if splash_backgrounds[background_index].has("entries") and background_subindex > 0:
set_screen(background_index, background_subindex-1)
else:
- set_screen(background_index-1 if background_index > 0 else BACKGROUNDS.size()-1, 1000)
+ set_screen(background_index-1 if background_index > 0 else splash_backgrounds.size()-1, 1000)
func _on_next_pressed():
- if BACKGROUNDS[background_index].has("entries") and background_subindex < BACKGROUNDS[background_index].entries.size()-1:
+ if splash_backgrounds[background_index].has("entries") and background_subindex < splash_backgrounds[background_index].entries.size()-1:
set_screen(background_index, background_subindex+1)
else:
- set_screen(background_index+1 if background_index < BACKGROUNDS.size()-1 else 0, 0)
+ set_screen(background_index+1 if background_index < splash_backgrounds.size()-1 else 0, 0)
func _on_title_gui_input(event, url : String):
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
@@ -279,3 +294,61 @@ func _on_title_gui_input(event, url : String):
func _on_url_gui_input(event):
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
OS.shell_open("https://www.materialmaker.org")
+
+#region android-specific
+
+func android_setup_artwork_details_size() -> void:
+ %URL.add_theme_font_size_override("font_size", 14)
+ %Title.add_theme_font_size_override("font_size", 22)
+ %Author.add_theme_font_size_override("font_size", 22)
+
+func android_setup_margins() -> void:
+ await get_tree().process_frame
+ var scale_fac : float = get_window().content_scale_factor
+
+ custom_minimum_size = Vector2.ZERO
+ $SplashScreen.custom_minimum_size = Vector2.ZERO
+ var nine_patch : NinePatchRect = $SplashScreen/TextureRect/LogoExtend
+ var logo : TextureRect = $SplashScreen/TextureRect
+ set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
+
+ var safe_margin_left : int = mm_touch.calc_margins(SIDE_LEFT, scale_fac)
+ var safe_margin_right : int = mm_touch.calc_margins(SIDE_RIGHT, scale_fac)
+
+ # url / artwork details margins
+ $MarginContainer.add_theme_constant_override("margin_left", safe_margin_left)
+ $MarginContainer.add_theme_constant_override("margin_right", safe_margin_right)
+ $MarginContainer.add_theme_constant_override("margin_bottom", 12)
+
+ # keep logo/progress bar within safe area
+ logo.position.x += safe_margin_left
+ nine_patch.position.x -= safe_margin_left
+ nine_patch.patch_margin_left = safe_margin_left + 4
+ progress_bar.position.x -= safe_margin_left
+ progress_bar.size.x += safe_margin_left
+
+func android_filter_splash_screens() -> void:
+ # filter animated shaders
+ var filtered_backgrounds : Array[Dictionary]
+ for group in splash_backgrounds:
+ var entries : Array[Dictionary] = []
+ if group.has("entries"):
+ for e in group.entries:
+ if e.file.get_extension() == "png":
+ entries.append(e)
+ if entries.is_empty():
+ continue
+ group.entries = entries
+ filtered_backgrounds.append(group)
+ splash_backgrounds = filtered_backgrounds
+
+func android_splash_fade_in() -> void:
+ var darken : ColorRect = ColorRect.new()
+ darken.color = Color.BLACK
+ tree_exiting.connect(darken.queue_free)
+ add_child(darken)
+ var t : Tween = get_tree().create_tween()
+ t.set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_OUT)
+ t.tween_property(darken, "color:a", 0.0, 0.6).set_delay(0.5)
+
+#endregion
diff --git a/splash_screen/splash_screen.tscn b/splash_screen/splash_screen.tscn
index cfad1586ef..93e3ac444e 100644
--- a/splash_screen/splash_screen.tscn
+++ b/splash_screen/splash_screen.tscn
@@ -44,8 +44,8 @@ offset_bottom = 40.0
script = ExtResource("1_q7nii")
[node name="SplashScreen" type="TextureRect" parent="." unique_id=1261927513]
-clip_contents = true
custom_minimum_size = Vector2(760, 430)
+clip_contents = true
layout_mode = 2
texture = SubResource("PlaceholderTexture2D_jeaul")
expand_mode = 1
@@ -53,9 +53,17 @@ expand_mode = 1
[node name="TextureRect" type="TextureRect" parent="SplashScreen" unique_id=547599219]
layout_mode = 0
offset_top = 34.0
-offset_right = 500.0
-offset_bottom = 177.0
+offset_right = 503.00006
+offset_bottom = 178.0
+texture = ExtResource("2_uba88")
+
+[node name="LogoExtend" type="NinePatchRect" parent="SplashScreen/TextureRect" unique_id=512569899]
+layout_mode = 1
+anchors_preset = 9
+anchor_bottom = 1.0
+grow_vertical = 2
texture = ExtResource("2_uba88")
+region_rect = Rect2(0, 0, 25, 144)
[node name="MM" type="Label" parent="SplashScreen/TextureRect" unique_id=1234938026]
layout_mode = 0
@@ -139,18 +147,6 @@ anchor_bottom = 1.0
offset_top = 331.0
offset_bottom = 1.0
-[node name="URL" type="Label" parent="SplashScreen" unique_id=710870014]
-unique_name_in_owner = true
-layout_mode = 0
-offset_left = 4.0
-offset_top = 414.0
-offset_right = 134.0
-offset_bottom = 433.0
-mouse_filter = 0
-mouse_default_cursor_shape = 2
-theme_override_font_sizes/font_size = 11
-text = "materialmaker.org"
-
[node name="MarginContainer" type="MarginContainer" parent="." unique_id=986076381]
layout_mode = 2
mouse_filter = 2
@@ -160,10 +156,24 @@ theme_override_constants/margin_bottom = 3
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer" unique_id=383891881]
layout_mode = 2
-size_flags_horizontal = 8
size_flags_vertical = 8
alignment = 2
+[node name="URLSpacer" type="Control" parent="MarginContainer/HBoxContainer" unique_id=1549656315]
+custom_minimum_size = Vector2(2, 0)
+layout_mode = 2
+
+[node name="URL" type="Label" parent="MarginContainer/HBoxContainer" unique_id=710870014]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 2
+size_flags_vertical = 8
+mouse_filter = 0
+mouse_default_cursor_shape = 2
+theme_override_font_sizes/font_size = 11
+text = "materialmaker.org"
+vertical_alignment = 2
+
[node name="Title" type="Label" parent="MarginContainer/HBoxContainer" unique_id=736839233]
unique_name_in_owner = true
layout_mode = 2
@@ -251,6 +261,6 @@ mouse_filter = 2
texture = SubResource("AtlasTexture_587d8")
[connection signal="gui_input" from="SplashScreen/TextureRect/SecretButton" to="." method="_on_secret_button_gui_input"]
-[connection signal="gui_input" from="SplashScreen/URL" to="." method="_on_url_gui_input"]
+[connection signal="gui_input" from="MarginContainer/HBoxContainer/URL" to="." method="_on_url_gui_input"]
[connection signal="pressed" from="BackgroundSelect/Previous" to="." method="_on_previous_pressed"]
[connection signal="pressed" from="BackgroundSelect/Next" to="." method="_on_next_pressed"]