Grassy knoll

This commit is contained in:
2026-03-19 11:35:38 -05:00
parent 42e49b5cd8
commit b5c7c7c8b6
124 changed files with 7319 additions and 119 deletions
@@ -0,0 +1,86 @@
# about.gd
# This file is part of: SimpleGrassTextured
# Copyright (c) 2023 IcterusGames
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@tool
extends AcceptDialog
@export_multiline var message := ""
var icon_itch := "PHN2ZyBoZWlnaHQ9IjMyMy45NiIgd2lkdGg9IjMyMy45NiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCBmaWxsPSIjZmE1YzVjIiBoZWlnaHQ9IjMxMy45NiIgcnk9IjguNjE0MSIgc3Ryb2tlPSIjZDU0YzRjIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMTAiIHdpZHRoPSIzMTMuOTYiIHg9IjUiIHk9IjUiLz48ZyBmaWxsPSIjZmZmIiB0cmFuc2Zvcm09Im1hdHJpeCguOTM3MjEgMCAwIC45MzcyMSA1OC43NTEgMzUuMzM2KSI+PHBhdGggZD0ibS40MzUgMTk3LjI1aDI0LjE0MnY3MS41NTRoLTI0LjE0di03MS41NTZ6bTEyLjIxNy01LjgxN2MtNC4wNyAwLTcuMTk3LTEuMDItOS4zOC0zLjA1NC0yLjE4LTIuMDM2LTMuMjcyLTQuNzUtMy4yNzItOC4xNDUgMC0zLjIgMS4wOS01LjkxNiAzLjI3Mi04LjE0NSAyLjE4My0yLjIzIDUuMzEtMy4zNDUgOS4zOC0zLjM0NSA0LjA3MyAwIDcuMiAxLjExNSA5LjM4IDMuMzQ1IDIuMTgzIDIuMjMgMy4yNzQgNC45NDUgMy4yNzQgOC4xNDQgMCAzLjM5My0xLjA5IDYuMTA4LTMuMjcyIDguMTQ0LTIuMTggMi4wMzUtNS4zMDggMy4wNTQtOS4zOCAzLjA1NG00Ny4xMSA3OC44MTRjLTYuOTggMC0xMi4yNC0xLjg2Ni0xNS43OC01LjYtMy41NC0zLjczMi01LjMxLTguOTQ0LTUuMzEtMTUuNjM0di0zMy44ODRoLTkuNTk2di0xNy44OWg5LjU5N3YtMTcuNDVoMjQuMTQzdjE3LjQ1aDE1LjcwN3YxNy44OWgtMTUuNzF2MzAuMzk2YzAgMi4yMy40NiAzLjgwNiAxLjM4MiA0LjcyOHMyLjM1IDEuMzggNC4yOSAxLjM4YzIuNjE4IDAgNS40NzgtMS4xNjIgOC41OC0zLjQ5bDUuNTI4IDE1Ljg1M2MtMi44MSAxLjk0LTYuMDEgMy40NjgtOS42IDQuNTgzcy04IDEuNjcyLTEzLjIzNCAxLjY3Mm01OC40MyAwYy0xMS4wNTMgMC0xOS43NTUtMy4xNS0yNi4xMDUtOS40NTQtNi4zNTMtNi4zLTkuNTI4LTE1LjQ2NC05LjUyOC0yNy40ODUgMC04LjcyNiAxLjc5NC0xNi4wNDcgNS4zOC0yMS45NiAzLjY4NS02LjExIDguMjkyLTEwLjIzIDEzLjgyLTEyLjM2NCA1LjgxNS0yLjIzIDExLjE5Ny0zLjM0NCAxNi4xNDItMy4zNDQgNi4yMDMgMCAxMS4zOTIgMS4yMzcgMTUuNTYgMy43MSA0LjE3IDIuNDcyIDcuMjQ4IDUuMTYyIDkuMjM2IDguMDdzMy40MTcgNS4xODggNC4yOSA2LjgzN2wtMTYuNzI1IDEwLjc2Yy0xLjU1LTMuMTk4LTMuMjQ4LTUuNzItNS4wOS03LjU2Mi0xLjg0My0xLjg0LTQuMDczLTIuNzYtNi42OS0yLjc2LTMuNjg1IDAtNi41OTMgMS40NTMtOC43MjYgNC4zNi0yLjEzNCAyLjkxLTMuMiA3LjMyLTMuMiAxMy4yMzYgMCA2LjQgMS4yNiAxMS4xMDIgMy43OCAxNC4xMDggMi41MiAzLjAwNSA2LjExIDQuNTA3IDEwLjc2MiA0LjUwNyAzLjY4NCAwIDYuNzYzLS42NzYgOS4yMzctMi4wMzUgMi40Ny0xLjM1NiA0LjgyLTMuMSA3LjA1LTUuMjM1bDcuNzEgMTguMDM0Yy0yLjMyOCAxLjk0LTUuNzcgMy44NTUtMTAuMzI1IDUuNzQ1LTQuNTYgMS44OS0xMC4wODUgMi44MzUtMTYuNTggMi44MzVtMzQuNDctMS40NHYtOTcuMTVoMjQuMjg3djI5LjUyM2MyLjAzNy0xLjQ1NSA0LjUxLTIuNzQgNy40MTctMy44NTQgMi45MS0xLjExNSA2LjQtMS42NzMgMTAuNDczLTEuNjczIDguNTMgMCAxNC45MDcgMi40MjUgMTkuMTI1IDcuMjczczYuMzI2IDExLjY4MyA2LjMyNiAyMC41MDZ2NDUuMzc1aC0yNC4yODZ2LTQyLjQ2N2MwLTQuMDcyLS43NzUtNy4wNTQtMi4zMjctOC45NDRzLTMuNTktMi44MzYtNi4xMS0yLjgzNmMtMi4xMzIgMC00LjEyLjQ4NS01Ljk2MiAxLjQ1NS0xLjg0Ljk2OC0zLjM5NCAxLjk4Ni00LjY1NCAzLjA1MnY0OS43NGgtMjQuMjg2eiIvPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEgLjIxNjI1IDAgMSAyLjI0MzIgLTM4OC4yOSkiPjxwYXRoIGQ9Im0xNjAuMTYgMzUzLjljLTEuMDI3NC0uMDQzMi0yLjE1NzIuMTQ4NTYtMy4zNDU3LjYwMTU2bC0xMDcuMzYgNDAuOTJjLTQuNzU0MiAxLjgxMi04LjU4MiA3LjExMjYtOC41ODIgMTEuODg1djEwNy43N2MtLjAwMDAwMSA0Ljc3MjIgMy44Mjc4IDcuMTUzOCA4LjU4MiA1LjM0MThsLjc5Mjk3LS4zMDI3M2MtLjE5NDUzLS42NDY4OS0uMzA4NTktMS4zNTg2LS4zMDg1OS0yLjE0MjZ2LTEwNy43N2MwLTQuNzcyMiAzLjg0My0xMC4wNzYgOC42MTUyLTExLjg5MWwxMDYuNTctNDAuNTJjLS42Njk0OC0yLjM2MDYtMi41MTctMy43OTAxLTQuOTU1MS0zLjg5MjZ6IiBmaWxsLW9wYWNpdHk9Ii4yMzQ1NyIvPjxwYXRoIGQ9Im01OC41NDkgMzk4LjE5Yy00Ljc3MjIgMS44MTQ2LTguNjE1MiA3LjExOS04LjYxNTIgMTEuODkxdjEwNy43N2MwIDQuNzcyMiAzLjg0MyA3LjE1MiA4LjYxNTIgNS4zMzc0bDEwNy43Ny00MC45OGM0Ljc3MjItMS44MTQ2IDguNjEzMy03LjExNjIgOC42MTMzLTExLjg4OHYtMTA3Ljc3YzAtNC43NzIyLTMuODQxMS03LjE1NDctOC42MTMzLTUuMzRsLTEwNy43NyA0MC45OHptMzAuNDYxIDIzLjE1NC4wMDgtLjAwM2M0Ljk1NzQtMS44ODUgOC40ODI5LS4wMTM0IDkuNzMyNCA0LjM1bDI3LjQtMTAuNDE5YzEuMjQ3My01LjMxMjggNC43NTA5LTkuODU3MyA5LjcwOS0xMS43NDMgNy44NzQ4LTIuOTk0NCAxNi41MzIgMS43OTk4IDE5LjIzNCAxMC42NTNsNi40NTcgMjEuMTM4YzIuNzAzNCA4Ljg1MjgtMS41MzUzIDE4LjU1MS05LjQxMDIgMjEuNTQ1LTYuOTEzMiAyLjYyODctMTQuNDI3LS43NDI2MS0xNy45ODgtNy41OTU1bC00My40MzYgMTYuNTE2Yy0zLjU2MDMgOS41NjA4LTExLjA3NiAxOC42NDctMTcuOTkgMjEuMjc2LTcuODc2MyAyLjk5NS0xMi4xMTItMy40ODA1LTkuNDA4Mi0xNC4zODlsNi40NTctMjYuMDQ5YzIuNzAyNy0xMC45MSAxMS4zNTgtMjIuMjg2IDE5LjIzNC0yNS4yODF6bTE3LjAzNSA3LjU1OTV2OC44MDY2bC03LjA3MDMgMi42ODg1IDYuNzMwNSA1Ljk3OTggNi43MjY2IDUuOTgxMyA2LjczNDQtMTEuMTA0IDYuNzMwNS0xMS4wOTgtNi42MzA5IDIuNTIxNHYtOC44MDI3bC0xMy4yMjEgNS4wMjcyeiIvPjwvZz48L2c+PC9zdmc+"
var icon_patreon_dark := "PHN2ZyB2aWV3Qm94PSIwIDAgMjM0Ljg5IDMzNyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGNsaXBQYXRoIGlkPSJhIj48cGF0aCBkPSJtMCAwaDIzNC44OXYyNTcuMjZoLTIzNC44OXoiLz48L2NsaXBQYXRoPjxwYXRoIGQ9Im0wIDMwNy41NWMwLTEuMzggMS4wMi0yLjMxIDIuNjItMi4zMWg3LjY0YzYuOTMgMCAxMS42NCAzLjgyIDExLjY0IDkuNDJzLTQuNjYgOS41OS0xMS42NCA5LjU5aC0xLjA3Yy0yLjY2IDAtNC4wNCAxLjM4LTQuMDQgMy42djYuMjZjMCAxLjc4LTEuMDIgMi44OS0yLjU4IDIuODlzLTIuNTctMS4xMS0yLjU3LTIuODl6bTUuMTUgNy45NWMwIDIuOCAxLjQyIDQuMTMgNC4xMyA0LjEzaC42N2MzLjgyIDAgNi42Mi0xLjU1IDYuNjItNC45N3MtMi44LTQuOTgtNi42Mi00Ljk4aC0uNjdjLTIuNzEgMC00LjEzIDEuMzMtNC4xMyA0LjEzem0xNi43NSAxOS4wNmMwIDEuNDcgMS4wMiAyLjQ0IDIuNTggMi40NCAxLjAyIDAgMS45NS0uNjcgMi40OS0yLjA0bC45My0yLjQ5Yy43Ni0yIDIuMDktMi45MyAzLjU1LTIuOTNoOC40NGMxLjQ3IDAgMi44LjkzIDMuNTUgMi45M2wuOTMgMi40OWMuNTMgMS4zOCAxLjQ3IDIuMDQgMi40OSAyLjA0IDEuNTUgMCAyLjU4LS45OCAyLjU4LTIuNDQgMC0uNC0uMDktLjg5LS4yNy0xLjM4bC0xMC4wOC0yNi4yYy0uNjItMS42LTIuMDQtMi40LTMuNDItMi40cy0yLjguOC0zLjQyIDIuNGwtMTAuMDggMjYuMmMtLjE4LjQ5LS4yNy45OC0uMjcgMS4zOHptOS44MS0xMS45MWMwLS40OS4xMy0uOTMuMzYtMS42bDEuOTEtNS4yOWMuMzYtMS4wMi45OC0xLjUxIDEuNjktMS41MXMxLjMzLjQ5IDEuNjkgMS41MWwxLjkxIDUuMjljLjIyLjY3LjM2IDEuMTEuMzYgMS42IDAgMS4zMy0uNzYgMi4yNy0yLjc1IDIuMjdoLTIuNGMtMiAwLTIuNzUtLjkzLTIuNzUtMi4yN3ptMTYuMDQtMTUuMDFjMC0xLjQyIDEuMDItMi40IDIuNjctMi40aDIwLjQzYzEuNjQgMCAyLjY3Ljk4IDIuNjcgMi40cy0xLjAyIDIuNC0yLjY3IDIuNGgtMy40MmMtMi43MSAwLTQuMTggMS4zOC00LjE4IDQuNTN2MTkuNWMwIDEuODItMS4wMiAyLjkzLTIuNjIgMi45M3MtMi42Mi0xLjExLTIuNjItMi45M3YtMTkuNWMwLTMuMTUtMS40Ny00LjUzLTQuMTgtNC41M2gtMy40MmMtMS42NCAwLTIuNjctLjk4LTIuNjctMi40em0zMC41NiAyNi40N2MwIDEuNzggMS4wMiAyLjg5IDIuNTggMi44OXMyLjU4LTEuMTEgMi41OC0yLjg5di03LjA2YzAtMiAxLjE1LTIuODQgMi41OC0yLjg0aC4zNmMuOTMgMCAxLjg3LjU4IDIuNDQgMS40Mmw2Ljc1IDkuOWMuNjIuOTMgMS40MiAxLjQ3IDIuNDQgMS40NyAxLjMzIDAgMi40LTEuMTEgMi40LTIuNDQgMC0uNTMtLjE4LTEuMTEtLjU4LTEuNjlsLTQuNDktNi4zMWMtLjUzLS43Ni0uNzUtMS4zOC0uNzUtMS45MSAwLTEuMTEuOTgtMS45MSAyLjEzLTIuNzUgMi4wOS0xLjU1IDQuMzUtMy42IDQuMzUtNy41MSAwLTUuNDYtNC4yNi05LjE1LTExLjI4LTkuMTVoLTguOTNjLTEuNiAwLTIuNTguOTMtMi41OCAyLjMxem01LjE1LTE5LjAxdi0xLjMzYzAtMi44OSAxLjUxLTQuMDkgMy44Mi00LjA5aDIuMjJjMy44MiAwIDYuMjYgMS40MiA2LjI2IDQuNzFzLTIuNTggNC44LTYuNCA0LjhoLTIuMDljLTIuMzEgMC0zLjgyLTEuMi0zLjgyLTQuMDl6bTI0LjIxIDE4Ljkydi0yNi40N2MwLTEuMzguOTgtMi4zMSAyLjU4LTIuMzFoMTYuNzljMS42IDAgMi41OC45MyAyLjU4IDIuMzFzLS45OCAyLjMxLTIuNTggMi4zMWgtMTAuNjJjLTIuMDkgMC0zLjYgMS4yNC0zLjYgMy42di45OGMwIDIuMzUgMS41MSAzLjYgMy42IDMuNmg4LjIyYzEuNiAwIDIuNTguOTMgMi41OCAyLjMxcy0uOTggMi4zMS0yLjU4IDIuMzFoLTcuOTFjLTIuMDkgMC0zLjkxIDEuMjktMy45MSAzLjkxdjEuMjRjMCAyLjYyIDEuODIgMy45MSAzLjkxIDMuOTFoMTAuMzFjMS42IDAgMi41OC45MyAyLjU4IDIuMzFzLS45OCAyLjMxLTIuNTggMi4zMWgtMTYuNzljLTEuNiAwLTIuNTgtLjkzLTIuNTgtMi4zMXptMjUtMTMuMjNjMC05LjU5IDcuMi0xNi4yMSAxNS42My0xNi4yMXMxNS42MyA2LjYyIDE1LjYzIDE2LjIxLTcuMiAxNi4yMS0xNS42MyAxNi4yMS0xNS42My02LjYyLTE1LjYzLTE2LjIxem01Ljg3IDBjMCA2Ljc1IDQgMTEuMDYgOS43NyAxMS4wNnM5Ljc3LTQuMzEgOS43Ny0xMS4wNi00LTExLjA2LTkuNzctMTEuMDYtOS43NyA0LjI2LTkuNzcgMTEuMDZ6bTMxLjU4IDEzLjMyYzAgMS43OCAxLjAyIDIuODkgMi41OCAyLjg5czIuNTgtMS4xMSAyLjU4LTIuODl2LTEzLjU5YzAtMS42NC45OC0yLjQ0IDItMi40NC44IDAgMS40Ni40NCAxLjk1IDEuMjRsOC41MyAxNC4yNmMxLjE1IDEuOTUgMi4yMiAzLjQyIDQuNCAzLjQyczMuNi0xLjUxIDMuNi0zLjk1di0yNS41OGMwLTEuNzgtMS4wMi0yLjg5LTIuNTgtMi44OXMtMi41OCAxLjExLTIuNTggMi44OXYxMy41OWMwIDEuNjQtLjk4IDIuNDQtMiAyLjQ0LS44IDAtMS40Ny0uNDQtMS45NS0xLjI0bC04LjUzLTE0LjI2Yy0xLjE1LTEuOTUtMi4yMi0zLjQyLTQuNC0zLjQycy0zLjYgMS41MS0zLjYgMy45NXoiIGZpbGw9IiMwMTAxMDEiLz48ZyBjbGlwLXBhdGg9InVybCgjYSkiPjxwYXRoIGQ9Im0yMzQuODkgNzcuMjljLS4wNS0zMi44NS0yNS42My01OS43Ny01NS42NC02OS40OC0zNy4yOC0xMi4wNy04Ni40My0xMC4zMi0xMjIuMDMgNi40Ny00My4xNCAyMC4zNi01Ni42OSA2NC45NS01Ny4xOSAxMDkuNDItLjQxIDM2LjU2IDMuMjMgMTMyLjg3IDU3LjU1IDEzMy41NSA0MC4zNi41MSA0Ni4zNy01MS40OSA2NS4wNS03Ni41NCAxMy4yOS0xNy44MiAzMC4zOS0yMi44NSA1MS40NS0yOC4wNyAzNi4yLTguOTYgNjAuODYtMzcuNTIgNjAuODEtNzUuMzZ6IiBmaWxsPSIjMDEwMTAxIi8+PC9nPjwvc3ZnPg=="
var icon_patreon_light := "PHN2ZyB2aWV3Qm94PSIwIDAgMjM0Ljg5IDMzNyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGNsaXBQYXRoIGlkPSJhIj48cGF0aCBkPSJtMCAwaDIzNC44OXYyNTcuMjZoLTIzNC44OXoiLz48L2NsaXBQYXRoPjxwYXRoIGQ9Im0wIDMwNy41NWMwLTEuMzggMS4wMi0yLjMxIDIuNjItMi4zMWg3LjY0YzYuOTMgMCAxMS42NCAzLjgyIDExLjY0IDkuNDJzLTQuNjYgOS41OS0xMS42NCA5LjU5aC0xLjA3Yy0yLjY2IDAtNC4wNCAxLjM4LTQuMDQgMy42djYuMjZjMCAxLjc4LTEuMDIgMi44OS0yLjU4IDIuODlzLTIuNTctMS4xMS0yLjU3LTIuODl6bTUuMTUgNy45NWMwIDIuOCAxLjQyIDQuMTMgNC4xMyA0LjEzaC42N2MzLjgyIDAgNi42Mi0xLjU1IDYuNjItNC45N3MtMi44LTQuOTgtNi42Mi00Ljk4aC0uNjdjLTIuNzEgMC00LjEzIDEuMzMtNC4xMyA0LjEzem0xNi43NSAxOS4wNmMwIDEuNDcgMS4wMiAyLjQ0IDIuNTggMi40NCAxLjAyIDAgMS45NS0uNjcgMi40OS0yLjA0bC45My0yLjQ5Yy43Ni0yIDIuMDktMi45MyAzLjU1LTIuOTNoOC40NGMxLjQ3IDAgMi44LjkzIDMuNTUgMi45M2wuOTMgMi40OWMuNTMgMS4zOCAxLjQ3IDIuMDQgMi40OSAyLjA0IDEuNTUgMCAyLjU4LS45OCAyLjU4LTIuNDQgMC0uNC0uMDktLjg5LS4yNy0xLjM4bC0xMC4wOC0yNi4yYy0uNjItMS42LTIuMDQtMi40LTMuNDItMi40cy0yLjguOC0zLjQyIDIuNGwtMTAuMDggMjYuMmMtLjE4LjQ5LS4yNy45OC0uMjcgMS4zOHptOS44MS0xMS45MWMwLS40OS4xMy0uOTMuMzYtMS42bDEuOTEtNS4yOWMuMzYtMS4wMi45OC0xLjUxIDEuNjktMS41MXMxLjMzLjQ5IDEuNjkgMS41MWwxLjkxIDUuMjljLjIyLjY3LjM2IDEuMTEuMzYgMS42IDAgMS4zMy0uNzYgMi4yNy0yLjc1IDIuMjdoLTIuNGMtMiAwLTIuNzUtLjkzLTIuNzUtMi4yN3ptMTYuMDQtMTUuMDFjMC0xLjQyIDEuMDItMi40IDIuNjctMi40aDIwLjQzYzEuNjQgMCAyLjY3Ljk4IDIuNjcgMi40cy0xLjAyIDIuNC0yLjY3IDIuNGgtMy40MmMtMi43MSAwLTQuMTggMS4zOC00LjE4IDQuNTN2MTkuNWMwIDEuODItMS4wMiAyLjkzLTIuNjIgMi45M3MtMi42Mi0xLjExLTIuNjItMi45M3YtMTkuNWMwLTMuMTUtMS40Ny00LjUzLTQuMTgtNC41M2gtMy40MmMtMS42NCAwLTIuNjctLjk4LTIuNjctMi40em0zMC41NiAyNi40N2MwIDEuNzggMS4wMiAyLjg5IDIuNTggMi44OXMyLjU4LTEuMTEgMi41OC0yLjg5di03LjA2YzAtMiAxLjE1LTIuODQgMi41OC0yLjg0aC4zNmMuOTMgMCAxLjg3LjU4IDIuNDQgMS40Mmw2Ljc1IDkuOWMuNjIuOTMgMS40MiAxLjQ3IDIuNDQgMS40NyAxLjMzIDAgMi40LTEuMTEgMi40LTIuNDQgMC0uNTMtLjE4LTEuMTEtLjU4LTEuNjlsLTQuNDktNi4zMWMtLjUzLS43Ni0uNzUtMS4zOC0uNzUtMS45MSAwLTEuMTEuOTgtMS45MSAyLjEzLTIuNzUgMi4wOS0xLjU1IDQuMzUtMy42IDQuMzUtNy41MSAwLTUuNDYtNC4yNi05LjE1LTExLjI4LTkuMTVoLTguOTNjLTEuNiAwLTIuNTguOTMtMi41OCAyLjMxem01LjE1LTE5LjAxdi0xLjMzYzAtMi44OSAxLjUxLTQuMDkgMy44Mi00LjA5aDIuMjJjMy44MiAwIDYuMjYgMS40MiA2LjI2IDQuNzFzLTIuNTggNC44LTYuNCA0LjhoLTIuMDljLTIuMzEgMC0zLjgyLTEuMi0zLjgyLTQuMDl6bTI0LjIxIDE4Ljkydi0yNi40N2MwLTEuMzguOTgtMi4zMSAyLjU4LTIuMzFoMTYuNzljMS42IDAgMi41OC45MyAyLjU4IDIuMzFzLS45OCAyLjMxLTIuNTggMi4zMWgtMTAuNjJjLTIuMDkgMC0zLjYgMS4yNC0zLjYgMy42di45OGMwIDIuMzUgMS41MSAzLjYgMy42IDMuNmg4LjIyYzEuNiAwIDIuNTguOTMgMi41OCAyLjMxcy0uOTggMi4zMS0yLjU4IDIuMzFoLTcuOTFjLTIuMDkgMC0zLjkxIDEuMjktMy45MSAzLjkxdjEuMjRjMCAyLjYyIDEuODIgMy45MSAzLjkxIDMuOTFoMTAuMzFjMS42IDAgMi41OC45MyAyLjU4IDIuMzFzLS45OCAyLjMxLTIuNTggMi4zMWgtMTYuNzljLTEuNiAwLTIuNTgtLjkzLTIuNTgtMi4zMXptMjUtMTMuMjNjMC05LjU5IDcuMi0xNi4yMSAxNS42My0xNi4yMXMxNS42MyA2LjYyIDE1LjYzIDE2LjIxLTcuMiAxNi4yMS0xNS42MyAxNi4yMS0xNS42My02LjYyLTE1LjYzLTE2LjIxem01Ljg3IDBjMCA2Ljc1IDQgMTEuMDYgOS43NyAxMS4wNnM5Ljc3LTQuMzEgOS43Ny0xMS4wNi00LTExLjA2LTkuNzctMTEuMDYtOS43NyA0LjI2LTkuNzcgMTEuMDZ6bTMxLjU4IDEzLjMyYzAgMS43OCAxLjAyIDIuODkgMi41OCAyLjg5czIuNTgtMS4xMSAyLjU4LTIuODl2LTEzLjU5YzAtMS42NC45OC0yLjQ0IDItMi40NC44IDAgMS40Ni40NCAxLjk1IDEuMjRsOC41MyAxNC4yNmMxLjE1IDEuOTUgMi4yMiAzLjQyIDQuNCAzLjQyczMuNi0xLjUxIDMuNi0zLjk1di0yNS41OGMwLTEuNzgtMS4wMi0yLjg5LTIuNTgtMi44OXMtMi41OCAxLjExLTIuNTggMi44OXYxMy41OWMwIDEuNjQtLjk4IDIuNDQtMiAyLjQ0LS44IDAtMS40Ny0uNDQtMS45NS0xLjI0bC04LjUzLTE0LjI2Yy0xLjE1LTEuOTUtMi4yMi0zLjQyLTQuNC0zLjQycy0zLjYgMS41MS0zLjYgMy45NXoiIGZpbGw9IiNmZmYiLz48ZyBjbGlwLXBhdGg9InVybCgjYSkiPjxwYXRoIGQ9Im0yMzQuODkgNzcuMjljLS4wNS0zMi44NS0yNS42My01OS43Ny01NS42NC02OS40OC0zNy4yOC0xMi4wNy04Ni40My0xMC4zMi0xMjIuMDMgNi40Ny00My4xNCAyMC4zNi01Ni42OSA2NC45NS01Ny4xOSAxMDkuNDItLjQxIDM2LjU2IDMuMjMgMTMyLjg3IDU3LjU1IDEzMy41NSA0MC4zNi41MSA0Ni4zNy01MS40OSA2NS4wNS03Ni41NCAxMy4yOS0xNy44MiAzMC4zOS0yMi44NSA1MS40NS0yOC4wNyAzNi4yLTguOTYgNjAuODYtMzcuNTIgNjAuODEtNzUuMzZ6IiBmaWxsPSIjZmZmIi8+PC9nPjwvc3ZnPg=="
var icon_github_dark := "PHN2ZyBoZWlnaHQ9Ijk2IiB3aWR0aD0iOTgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggY2xpcC1ydWxlPSJldmVub2RkIiBkPSJtNDguODU0IDBjLTI3LjAxNSAwLTQ4Ljg1NCAyMi00OC44NTQgNDkuMjE3IDAgMjEuNzU2IDEzLjk5MyA0MC4xNzIgMzMuNDA1IDQ2LjY5IDIuNDI3LjQ5IDMuMzE2LTEuMDU5IDMuMzE2LTIuMzYyIDAtMS4xNDEtLjA4LTUuMDUyLS4wOC05LjEyNy0xMy41OSAyLjkzNC0xNi40Mi01Ljg2Ny0xNi40Mi01Ljg2Ny0yLjE4NC01LjcwNC01LjQyLTcuMTctNS40Mi03LjE3LTQuNDQ4LTMuMDE1LjMyNC0zLjAxNS4zMjQtMy4wMTUgNC45MzQuMzI2IDcuNTIzIDUuMDUyIDcuNTIzIDUuMDUyIDQuMzY3IDcuNDk2IDExLjQwNCA1LjM3OCAxNC4yMzUgNC4wNzQuNDA0LTMuMTc4IDEuNjk5LTUuMzc4IDMuMDc0LTYuNi0xMC44MzktMS4xNDEtMjIuMjQzLTUuMzc4LTIyLjI0My0yNC4yODMgMC01LjM3OCAxLjk0LTkuNzc4IDUuMDE0LTEzLjItLjQ4NS0xLjIyMi0yLjE4NC02LjI3NS40ODYtMTMuMDM4IDAgMCA0LjEyNS0xLjMwNCAxMy40MjYgNS4wNTJhNDYuOTcgNDYuOTcgMCAwIDEgMTIuMjE0LTEuNjNjNC4xMjUgMCA4LjMzLjU3MSAxMi4yMTMgMS42MyA5LjMwMi02LjM1NiAxMy40MjctNS4wNTIgMTMuNDI3LTUuMDUyIDIuNjcgNi43NjMuOTcgMTEuODE2LjQ4NSAxMy4wMzggMy4xNTUgMy40MjIgNS4wMTUgNy44MjIgNS4wMTUgMTMuMiAwIDE4LjkwNS0xMS40MDQgMjMuMDYtMjIuMzI0IDI0LjI4MyAxLjc4IDEuNTQ4IDMuMzE2IDQuNDgxIDMuMzE2IDkuMTI2IDAgNi42LS4wOCAxMS44OTctLjA4IDEzLjUyNiAwIDEuMzA0Ljg5IDIuODUzIDMuMzE2IDIuMzY0IDE5LjQxMi02LjUyIDMzLjQwNS0yNC45MzUgMzMuNDA1LTQ2LjY5MS4wOC0yNy4yMTctMjEuODM5LTQ5LjIxNy00OC43NzMtNDkuMjE3eiIgZmlsbD0iIzI0MjkyZiIgZmlsbC1ydWxlPSJldmVub2RkIi8+PC9zdmc+"
var icon_github_light := "PHN2ZyB3aWR0aD0iOTgiIGhlaWdodD0iOTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00OC44NTQgMEMyMS44MzkgMCAwIDIyIDAgNDkuMjE3YzAgMjEuNzU2IDEzLjk5MyA0MC4xNzIgMzMuNDA1IDQ2LjY5IDIuNDI3LjQ5IDMuMzE2LTEuMDU5IDMuMzE2LTIuMzYyIDAtMS4xNDEtLjA4LTUuMDUyLS4wOC05LjEyNy0xMy41OSAyLjkzNC0xNi40Mi01Ljg2Ny0xNi40Mi01Ljg2Ny0yLjE4NC01LjcwNC01LjQyLTcuMTctNS40Mi03LjE3LTQuNDQ4LTMuMDE1LjMyNC0zLjAxNS4zMjQtMy4wMTUgNC45MzQuMzI2IDcuNTIzIDUuMDUyIDcuNTIzIDUuMDUyIDQuMzY3IDcuNDk2IDExLjQwNCA1LjM3OCAxNC4yMzUgNC4wNzQuNDA0LTMuMTc4IDEuNjk5LTUuMzc4IDMuMDc0LTYuNi0xMC44MzktMS4xNDEtMjIuMjQzLTUuMzc4LTIyLjI0My0yNC4yODMgMC01LjM3OCAxLjk0LTkuNzc4IDUuMDE0LTEzLjItLjQ4NS0xLjIyMi0yLjE4NC02LjI3NS40ODYtMTMuMDM4IDAgMCA0LjEyNS0xLjMwNCAxMy40MjYgNS4wNTJhNDYuOTcgNDYuOTcgMCAwIDEgMTIuMjE0LTEuNjNjNC4xMjUgMCA4LjMzLjU3MSAxMi4yMTMgMS42MyA5LjMwMi02LjM1NiAxMy40MjctNS4wNTIgMTMuNDI3LTUuMDUyIDIuNjcgNi43NjMuOTcgMTEuODE2LjQ4NSAxMy4wMzggMy4xNTUgMy40MjIgNS4wMTUgNy44MjIgNS4wMTUgMTMuMiAwIDE4LjkwNS0xMS40MDQgMjMuMDYtMjIuMzI0IDI0LjI4MyAxLjc4IDEuNTQ4IDMuMzE2IDQuNDgxIDMuMzE2IDkuMTI2IDAgNi42LS4wOCAxMS44OTctLjA4IDEzLjUyNiAwIDEuMzA0Ljg5IDIuODUzIDMuMzE2IDIuMzY0IDE5LjQxMi02LjUyIDMzLjQwNS0yNC45MzUgMzMuNDA1LTQ2LjY5MUM5Ny43MDcgMjIgNzUuNzg4IDAgNDguODU0IDB6IiBmaWxsPSIjZmZmIi8+PC9zdmc+"
func _ready() -> void:
var config := ConfigFile.new()
config.load("res://addons/simplegrasstextured/plugin.cfg")
%RichTextLabel.text = message.format({"_version_num":config.get_value("plugin", "version")})
name = &"SimpleGrassTexturedHelpAbout"
get_ok_button().custom_minimum_size.x = 100
size.y = 250
await %ItchContainer.draw
var gui_h: int = max(32, %ItchContainer.size.y)
var base_color: Color = EditorInterface.get_base_control().get_theme_color(&"base_color", &"Editor")
if base_color.get_luminance() < 0.5:
_set_icon_button(%ItchContainer, icon_itch, gui_h, 324)
_set_icon_button(%PatreonContainer, icon_patreon_light, gui_h, 360)
_set_icon_button(%GithubContainer, icon_github_light, gui_h, 96)
else:
_set_icon_button(%ItchContainer, icon_itch, gui_h, 324)
_set_icon_button(%PatreonContainer, icon_patreon_dark, gui_h, 360)
_set_icon_button(%GithubContainer, icon_github_dark, gui_h, 96)
func _set_icon_button(container: Container, icon: String, gui_h: int, icon_size: int):
var image := Image.new()
var t_rect: TextureRect
image.load_svg_from_string(Marshalls.base64_to_utf8(icon), gui_h / float(icon_size))
t_rect = TextureRect.new()
t_rect.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
t_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
t_rect.texture = ImageTexture.create_from_image(image)
t_rect.custom_minimum_size.x = gui_h
container.add_child(t_rect)
container.move_child(t_rect, 0)
func _on_canceled() -> void:
queue_free()
func _on_confirmed() -> void:
queue_free()
func _on_itch_button_pressed() -> void:
OS.shell_open("https://icterusgames.itch.io")
func _on_patreon_button_pressed() -> void:
OS.shell_open("https://www.patreon.com/IcterusGames")
func _on_github_button_pressed() -> void:
OS.shell_open("https://github.com/IcterusGames/SimpleGrassTextured")
@@ -0,0 +1 @@
uid://cu72rjuvdnnx
@@ -0,0 +1,187 @@
[gd_scene load_steps=7 format=3 uid="uid://cb8klhv6nwvtl"]
[ext_resource type="Script" uid="uid://cu72rjuvdnnx" path="res://addons/simplegrasstextured/gui/about.gd" id="1_r23hh"]
[ext_resource type="Material" uid="uid://cl74usvfymgvs" path="res://addons/simplegrasstextured/materials/icon.material" id="2_4glo1"]
[ext_resource type="Texture2D" uid="uid://cubr1a55brlfp" path="res://addons/simplegrasstextured/sgt_icon_48.svg" id="3_7w1su"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_hnw4u"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_lwftf"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5fhmg"]
content_margin_left = 5.0
content_margin_top = 5.0
content_margin_right = 5.0
content_margin_bottom = 5.0
draw_center = false
[node name="SimpleGrassTexturedHelpAbout" type="AcceptDialog"]
title = "About"
position = Vector2i(0, 36)
size = Vector2i(644, 475)
visible = true
min_size = Vector2i(520, 200)
max_size = Vector2i(1280, 720)
script = ExtResource("1_r23hh")
message = "Simple Grass Textured Plugin
v. {_version_num}
by IcterusGames
[font_size=7] [/font_size]
[b]Support me on:[/b]"
[node name="MarginContainer" type="MarginContainer" parent="."]
offset_left = 8.0
offset_top = 8.0
offset_right = 636.0
offset_bottom = 426.0
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"]
layout_mode = 2
theme_override_constants/separation = 20
[node name="TextureRect" type="TextureRect" parent="MarginContainer/HBoxContainer"]
material = ExtResource("2_4glo1")
custom_minimum_size = Vector2(48, 48)
layout_mode = 2
texture = ExtResource("3_7w1su")
stretch_mode = 4
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="RichTextLabel" type="RichTextLabel" parent="MarginContainer/HBoxContainer/VBoxContainer"]
unique_name_in_owner = true
custom_minimum_size = Vector2(420, 0)
layout_mode = 2
size_flags_horizontal = 3
theme_override_styles/focus = SubResource("StyleBoxEmpty_hnw4u")
theme_override_styles/normal = SubResource("StyleBoxEmpty_lwftf")
bbcode_enabled = true
text = "Simple Grass Textured Plugin
v. 2.0.8
by IcterusGames
[font_size=7] [/font_size]
[b]Support me on:[/b]"
fit_content = true
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/HBoxContainer/VBoxContainer"]
layout_mode = 2
mouse_filter = 2
theme_override_constants/margin_left = 15
[node name="ItchButton" type="Button" parent="MarginContainer/HBoxContainer/VBoxContainer/MarginContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/HBoxContainer/VBoxContainer/MarginContainer"]
layout_mode = 2
mouse_filter = 2
theme_override_constants/margin_left = 5
theme_override_constants/margin_top = 5
theme_override_constants/margin_right = 5
theme_override_constants/margin_bottom = 5
[node name="ItchContainer" type="HBoxContainer" parent="MarginContainer/HBoxContainer/VBoxContainer/MarginContainer/MarginContainer"]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
[node name="RichTextLabel" type="RichTextLabel" parent="MarginContainer/HBoxContainer/VBoxContainer/MarginContainer/MarginContainer/ItchContainer"]
custom_minimum_size = Vector2(400, 0)
layout_mode = 2
size_flags_vertical = 4
mouse_filter = 2
theme_override_styles/normal = SubResource("StyleBoxFlat_5fhmg")
bbcode_enabled = true
text = "[b]Itch.io[/b]
[url]https://icterusgames.itch.io[url]"
fit_content = true
[node name="MarginContainer2" type="MarginContainer" parent="MarginContainer/HBoxContainer/VBoxContainer"]
layout_mode = 2
mouse_filter = 2
theme_override_constants/margin_left = 15
[node name="PatreonButton" type="Button" parent="MarginContainer/HBoxContainer/VBoxContainer/MarginContainer2"]
layout_mode = 2
size_flags_horizontal = 3
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/HBoxContainer/VBoxContainer/MarginContainer2"]
layout_mode = 2
mouse_filter = 2
theme_override_constants/margin_left = 5
theme_override_constants/margin_top = 5
theme_override_constants/margin_right = 5
theme_override_constants/margin_bottom = 5
[node name="PatreonContainer" type="HBoxContainer" parent="MarginContainer/HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer"]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
[node name="RichTextLabel" type="RichTextLabel" parent="MarginContainer/HBoxContainer/VBoxContainer/MarginContainer2/MarginContainer/PatreonContainer"]
custom_minimum_size = Vector2(400, 0)
layout_mode = 2
size_flags_vertical = 4
mouse_filter = 2
theme_override_styles/normal = SubResource("StyleBoxFlat_5fhmg")
bbcode_enabled = true
text = "[b]Patreon[/b]
[url]https://www.patreon.com/IcterusGames[/url]"
fit_content = true
[node name="RichTextLabel2" type="RichTextLabel" parent="MarginContainer/HBoxContainer/VBoxContainer"]
unique_name_in_owner = true
custom_minimum_size = Vector2(420, 0)
layout_mode = 2
size_flags_horizontal = 3
theme_override_styles/focus = SubResource("StyleBoxEmpty_hnw4u")
theme_override_styles/normal = SubResource("StyleBoxEmpty_lwftf")
bbcode_enabled = true
text = "[font_size=7] [/font_size]
[b]Source code on:[/b]"
fit_content = true
[node name="MarginContainer3" type="MarginContainer" parent="MarginContainer/HBoxContainer/VBoxContainer"]
layout_mode = 2
mouse_filter = 2
theme_override_constants/margin_left = 15
[node name="GithubButton" type="Button" parent="MarginContainer/HBoxContainer/VBoxContainer/MarginContainer3"]
layout_mode = 2
size_flags_horizontal = 3
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/HBoxContainer/VBoxContainer/MarginContainer3"]
layout_mode = 2
mouse_filter = 2
theme_override_constants/margin_left = 5
theme_override_constants/margin_top = 5
theme_override_constants/margin_right = 5
theme_override_constants/margin_bottom = 5
[node name="GithubContainer" type="HBoxContainer" parent="MarginContainer/HBoxContainer/VBoxContainer/MarginContainer3/MarginContainer"]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
[node name="RichTextLabel" type="RichTextLabel" parent="MarginContainer/HBoxContainer/VBoxContainer/MarginContainer3/MarginContainer/GithubContainer"]
custom_minimum_size = Vector2(400, 0)
layout_mode = 2
size_flags_vertical = 4
mouse_filter = 2
theme_override_styles/normal = SubResource("StyleBoxFlat_5fhmg")
bbcode_enabled = true
text = "[b]Github[/b]
[url]https://github.com/IcterusGames/SimpleGrassTextured[/url]"
fit_content = true
[connection signal="canceled" from="." to="." method="_on_canceled"]
[connection signal="confirmed" from="." to="." method="_on_confirmed"]
[connection signal="pressed" from="MarginContainer/HBoxContainer/VBoxContainer/MarginContainer/ItchButton" to="." method="_on_itch_button_pressed"]
[connection signal="pressed" from="MarginContainer/HBoxContainer/VBoxContainer/MarginContainer2/PatreonButton" to="." method="_on_patreon_button_pressed"]
[connection signal="pressed" from="MarginContainer/HBoxContainer/VBoxContainer/MarginContainer3/GithubButton" to="." method="_on_github_button_pressed"]
@@ -0,0 +1,38 @@
# clear_all_confirmation_dialog.gd
# This file is part of: SimpleGrassTextured
# Copyright (c) 2023 IcterusGames
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@tool
extends ConfirmationDialog
func _ready() -> void:
get_ok_button().custom_minimum_size.x = 100
get_cancel_button().custom_minimum_size.x = 100
func _on_confirmed() -> void:
queue_free()
func _on_canceled() -> void:
queue_free()
@@ -0,0 +1 @@
uid://wckg68rm05vd
@@ -0,0 +1,13 @@
[gd_scene load_steps=2 format=3 uid="uid://c1242d1bef7lb"]
[ext_resource type="Script" uid="uid://wckg68rm05vd" path="res://addons/simplegrasstextured/gui/clear_all_confirmation_dialog.gd" id="1_xk6u2"]
[node name="ClearAllConfirmationDialog" type="ConfirmationDialog"]
size = Vector2i(377, 109)
ok_button_text = "Yes"
dialog_text = "Are you sure you want to remove all the grass?"
cancel_button_text = "No"
script = ExtResource("1_xk6u2")
[connection signal="canceled" from="." to="." method="_on_canceled"]
[connection signal="confirmed" from="." to="." method="_on_confirmed"]
@@ -0,0 +1,309 @@
# domain_range.gd
# This file is part of: SimpleGrassTextured
# Copyright (c) 2025 IcterusGames
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@tool
extends Control
signal value_changed(value_min: float, value_max: float)
@export var range_min: float = 0.0
@export var range_max: float = 180.0
@export var step: float = 1.0
@export var value_min: float = 0.0 : set = set_value_min
@export var value_max: float = 45.0 : set = set_value_max
var _ed_scale: float = 1.0
var _slider_area := Rect2()
var _slider_range := Rect2()
var _grabber_min_pos := Vector2.ZERO
var _grabber_max_pos := Vector2.ZERO
var _is_grabbing_min_grab := false
var _is_grabbing_max_grab := false
var _is_grabbing_min_value := false
var _is_grabbing_max_value := false
var _is_editing_min := false
var _is_editing_max := false
var _mouse_over := false
var _mouse_click_pos := Vector2.ONE * 100000
var _mouse_click_rel := Vector2.ZERO
var _mouse_click_value := 0.0
var _mouse_over_grabber_min := false
var _mouse_over_grabber_max := false
@onready var _line_edit: LineEdit = $LineEdit
func _ready() -> void:
theme_changed.connect(_on_theme_changed)
_on_theme_changed()
_update_tooltip()
func _notification(what: int) -> void:
if what == NOTIFICATION_MOUSE_ENTER_SELF:
_mouse_over = true
queue_redraw()
if what == NOTIFICATION_MOUSE_EXIT_SELF:
_mouse_over = false
_mouse_over_grabber_min = false
_mouse_over_grabber_max = false
queue_redraw()
func _gui_input(event: InputEvent) -> void:
if event is InputEventMouseMotion:
_mouse_over_grabber_min = false
_mouse_over_grabber_max = false
if _is_grabbing_max_value:
if event.position.distance_to(_mouse_click_pos) > 8 * _ed_scale:
_mouse_click_pos = Vector2.ONE * 100000
set_value_max(value_max + event.screen_relative.x * step)
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
elif _is_grabbing_min_value:
if event.position.distance_to(_mouse_click_pos) > 8 * _ed_scale:
_mouse_click_pos = Vector2.ONE * 100000
set_value_min(value_min + event.screen_relative.x * step)
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
elif _is_grabbing_max_grab:
_mouse_click_pos = Vector2.ONE * 100000
set_value_max((event.position.x - _mouse_click_rel.x - _slider_area.position.x) / _slider_area.size.x * range_max)
elif _is_grabbing_min_grab:
_mouse_click_pos = Vector2.ONE * 100000
set_value_min((event.position.x - _mouse_click_rel.x - _slider_area.position.x) / _slider_area.size.x * range_max)
if event.position.distance_to(_grabber_max_pos) <= 8 * _ed_scale:
_mouse_over_grabber_max = true
if event.position.distance_to(_grabber_min_pos) <= 8 * _ed_scale:
_mouse_over_grabber_min = true
queue_redraw()
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
if event.pressed:
_mouse_click_pos = event.position
if (event.position.distance_to(_grabber_min_pos) <= 8 * _ed_scale and
event.position.distance_to(_grabber_max_pos) <= 8 * _ed_scale):
if event.position.x < (_grabber_min_pos.x + _grabber_max_pos.x) / 2:
_is_grabbing_min_grab = true
_mouse_click_rel = event.position - _grabber_min_pos
_mouse_click_value = value_min
else:
_is_grabbing_max_grab = true
_mouse_click_rel = event.position - _grabber_max_pos
_mouse_click_value = value_max
elif event.position.distance_to(_grabber_min_pos) <= 8 * _ed_scale:
_is_grabbing_min_grab = true
_mouse_click_rel = event.position - _grabber_min_pos
_mouse_click_value = value_min
elif event.position.distance_to(_grabber_max_pos) <= 8 * _ed_scale:
_is_grabbing_max_grab = true
_mouse_click_rel = event.position - _grabber_max_pos
_mouse_click_value = value_max
elif event.position.x < size.x / 2:
_is_grabbing_min_value = true
_mouse_click_value = value_min
else:
_is_grabbing_max_value = true
_mouse_click_value = value_max
else: # Mouse left released
if _mouse_click_pos.distance_to(event.position) <= 8 * _ed_scale:
_grab_end()
if event.position.x < size.x / 2:
_line_edit.text = str(value_min)
_is_editing_min = true
_is_editing_max = false
else:
_line_edit.text = str(value_max)
_is_editing_min = false
_is_editing_max = true
_line_edit.visible = true
_line_edit.select()
_line_edit.grab_focus()
elif _is_grabbing_max_grab or _is_grabbing_max_value:
_grab_end()
queue_redraw()
elif _is_grabbing_min_grab or _is_grabbing_min_value:
_grab_end()
queue_redraw()
elif event.button_index == MOUSE_BUTTON_RIGHT:
if event.pressed:
if _is_grabbing_max_grab or _is_grabbing_max_value:
_grab_end()
set_value_max(_mouse_click_value)
elif _is_grabbing_min_grab or _is_grabbing_min_value:
_grab_end()
set_value_min(_mouse_click_value)
elif event.button_index == MOUSE_BUTTON_WHEEL_UP or event.button_index == MOUSE_BUTTON_WHEEL_LEFT:
if event.pressed:
if event.position.x < size.x / 2:
set_value_min(value_min + step)
else:
set_value_max(value_max + step)
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN or event.button_index == MOUSE_BUTTON_WHEEL_RIGHT:
if event.pressed:
if event.position.x < size.x / 2:
set_value_min(value_min - step)
else:
set_value_max(value_max - step)
func _draw() -> void:
var sb := get_theme_stylebox(&"normal", &"LineEdit")
var font := get_theme_font(&"font", &"LineEdit")
var font_size := get_theme_font_size(&"font_size", &"LineEdit")
var label_min := "%0.0f" % value_min
var label_max := "%0.0f" % value_max
var label_w_min := font.get_string_size(label_min, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x
var label_w_max := font.get_string_size(label_max, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x
var label_y := (size.y - font.get_height(font_size)) / 2.0 + font.get_ascent(font_size)
var color := get_theme_color(&"font_color", &"LineEdit")
draw_style_box(sb, Rect2(Vector2.ZERO, size))
if has_focus():
var sb_focus = get_theme_stylebox(&"focus", &"LineEdit")
draw_style_box(sb_focus, Rect2(Vector2(), size))
color.a = 0.9
draw_line(Vector2(size.x / 2.0, label_y - 10.0 * _ed_scale), Vector2(size.x / 2.0, label_y), color, max(1.0, _ed_scale))
draw_string(font, Vector2(size.x * 0.25 - label_w_min / 2.0, label_y), label_min, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color)
draw_string(font, Vector2(size.x * 0.75 - label_w_max / 2.0, label_y), label_max, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color)
_slider_area = Rect2(_ed_scale * 6.0, size.y - _ed_scale * 5.0, size.x - _ed_scale * 12.0, _ed_scale * 2.0)
color.a = 0.2
draw_rect(_slider_area, color)
_slider_range = _slider_area
_slider_range.size.x *= (value_max - value_min) / (range_max - range_min)
_slider_range.position.x += value_min / (range_max - range_min) * _slider_area.size.x
color.a = 0.45
draw_rect(_slider_range, color)
_grabber_min_pos = _slider_range.position
_grabber_max_pos = _slider_range.position + Vector2(_slider_range.size.x, 0)
color.a = 0.9
var tex: Texture2D = null
if not _is_grabbing_max_grab:
if _mouse_over_grabber_min or _is_grabbing_min_grab:
tex = get_theme_icon(&"grabber_highlight", &"HSlider")
elif _mouse_over and not _mouse_over_grabber_max:
tex = get_theme_icon(&"grabber", &"HSlider")
if tex:
draw_texture(tex, (_grabber_min_pos - tex.get_size() / 2.0) + Vector2.DOWN)
else:
draw_rect(Rect2(_grabber_min_pos.x - 2 * _ed_scale, _grabber_min_pos.y - 1 * _ed_scale, 4 * _ed_scale, 4 * _ed_scale), color)
tex = null
if not _is_grabbing_min_grab:
if _mouse_over_grabber_max or _is_grabbing_max_grab:
tex = get_theme_icon(&"grabber_highlight", &"HSlider")
elif _mouse_over and not _mouse_over_grabber_min:
tex = get_theme_icon(&"grabber", &"HSlider")
if tex:
draw_texture(tex, (_grabber_max_pos - tex.get_size() / 2.0) + Vector2.DOWN)
else:
draw_rect(Rect2(_grabber_max_pos.x - 2 * _ed_scale, _grabber_max_pos.y - 1 * _ed_scale, 4 * _ed_scale, 4 * _ed_scale), color)
func set_value(v_min: float, v_max: float) -> void:
v_min = max(min(v_min, v_max), range_min)
v_max = min(max(v_min, v_max), range_max)
if v_min != value_min or v_max != value_max:
value_min = v_min
value_max = v_max
value_changed.emit(value_min, value_max)
_update_tooltip()
queue_redraw()
func set_value_min(value: float) -> void:
value = clampf(snappedf(value, step), range_min, value_max)
if value != value_min:
value_min = value
value_changed.emit(value_min, value_max)
_update_tooltip()
queue_redraw()
func set_value_max(value: float) -> void:
value = clampf(snappedf(value, step), value_min, range_max)
if value != value_max:
value_max = value
value_changed.emit(value_min, value_max)
_update_tooltip()
queue_redraw()
func _update_tooltip() -> void:
tooltip_text = "Slope to avoid:\n"
tooltip_text += "Min: %0.*f°\n" %[step_decimals(step), value_min]
tooltip_text += "Max: %0.*f°\n" %[step_decimals(step), value_max]
func _grab_end() -> void:
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
if _is_grabbing_max_value:
Input.warp_mouse(_grabber_max_pos + global_position)
elif _is_grabbing_min_value:
Input.warp_mouse(_grabber_min_pos + global_position)
_is_grabbing_min_grab = false
_is_grabbing_max_grab = false
_is_grabbing_min_value = false
_is_grabbing_max_value = false
func _on_theme_changed() -> void:
var es: int = EditorInterface.get_editor_settings().get_setting("interface/editor/display_scale")
if es == 7:
_ed_scale = EditorInterface.get_editor_settings().get_setting("interface/editor/custom_display_scale")
else:
_ed_scale = [1.0, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0][clamp(es, 0, 6)]
_line_edit.caret_blink = EditorInterface.get_editor_settings().get_setting("text_editor/appearance/caret/caret_blink")
func _on_line_edit_text_submitted(new_text: String) -> void:
var value := range_min
var expression = Expression.new()
if expression.parse(new_text) == OK:
var result = expression.execute()
if not expression.has_execute_failed() and (typeof(result) == TYPE_FLOAT or typeof(result) == TYPE_INT):
value = result
if _is_editing_min:
set_value_min(value)
elif _is_editing_max:
set_value_max(value)
_is_editing_min = false
_is_editing_max = false
_line_edit.visible = false
grab_focus()
func _on_line_edit_focus_exited() -> void:
_line_edit.visible = false
func _on_line_edit_gui_input(event: InputEvent) -> void:
if event is InputEventKey:
if event.keycode == KEY_ESCAPE and event.pressed:
_line_edit.visible = false
grab_focus()
@@ -0,0 +1 @@
uid://dmpm4vrmag0ru
@@ -0,0 +1,28 @@
[gd_scene load_steps=2 format=3 uid="uid://r30ih7dtx1uo"]
[ext_resource type="Script" uid="uid://dmpm4vrmag0ru" path="res://addons/simplegrasstextured/gui/domain_range.gd" id="1_xiopc"]
[node name="DomainRange" type="Control"]
custom_minimum_size = Vector2(80, 0)
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
focus_mode = 2
script = ExtResource("1_xiopc")
[node name="LineEdit" type="LineEdit" parent="."]
visible = false
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
caret_blink = true
[connection signal="focus_exited" from="LineEdit" to="." method="_on_line_edit_focus_exited"]
[connection signal="gui_input" from="LineEdit" to="." method="_on_line_edit_gui_input"]
[connection signal="text_submitted" from="LineEdit" to="." method="_on_line_edit_text_submitted"]
@@ -0,0 +1,212 @@
# global_parameters.gd
# This file is part of: SimpleGrassTextured
# Copyright (c) 2023 IcterusGames
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@tool
extends AcceptDialog
const DEFAULT_WIND_DIR := Vector3.RIGHT
const DEFAULT_WIND_STRENGTH := 0.15
const DEFAULT_WIND_TURBULENCE := 1.0
const DEFAULT_WIND_PATTERN := "res://addons/simplegrasstextured/images/wind_pattern.png"
var _wind_dir_x_slider :EditorSpinSlider
var _wind_dir_y_slider :EditorSpinSlider
var _wind_dir_z_slider :EditorSpinSlider
var _wind_strength_slider :EditorSpinSlider
var _wind_turbulence_slider :EditorSpinSlider
var _wind_pattern :EditorResourcePicker
func _ready() -> void:
name = &"SimpleGrassTexturedGlobalParameters"
size = Vector2.ZERO
_wind_dir_x_slider = _create_slider("X", -1, 1, 0.01)
_wind_dir_y_slider = _create_slider("Y", -1, 1, 0.01)
_wind_dir_z_slider = _create_slider("Z", -1, 1, 0.01)
_wind_strength_slider = _create_slider("", 0, 1, 0.001)
_wind_turbulence_slider = _create_slider("", 0, 20, 0.01)
_wind_pattern = EditorResourcePicker.new()
_wind_pattern.base_type = "Texture"
_wind_pattern.size_flags_horizontal = Control.SIZE_EXPAND_FILL
_wind_dir_x_slider.value_changed.connect(_on_wind_dir_x_value_changed)
_wind_dir_y_slider.value_changed.connect(_on_wind_dir_y_value_changed)
_wind_dir_z_slider.value_changed.connect(_on_wind_dir_z_value_changed)
_wind_strength_slider.value_changed.connect(_on_wind_strength_value_changed)
_wind_turbulence_slider.value_changed.connect(_on_wind_turbulence_value_changed)
_wind_pattern.resource_changed.connect(_on_wind_pattern_resource_changed)
%WindDirHbox.add_child(_wind_dir_x_slider)
%WindDirHbox.add_child(_wind_dir_y_slider)
%WindDirHbox.add_child(_wind_dir_z_slider)
%WindStrengthHBox.add_child(_wind_strength_slider)
%WindTurbulenceHBox.add_child(_wind_turbulence_slider)
%WindPatternHBox.add_child(_wind_pattern)
get_ok_button().custom_minimum_size.x = 100
func _create_slider(label :String, min :float, max :float, step :float) -> EditorSpinSlider:
var slider := EditorSpinSlider.new()
slider.size_flags_horizontal = Control.SIZE_EXPAND_FILL
slider.step = step;
slider.min_value = min
slider.max_value = max
slider.label = label
slider.custom_minimum_size.x = 80
return slider
func disable_button(button :Button, disabled :bool) -> void:
if disabled:
button.disabled = true
button.modulate.a = 0
button.focus_mode = Control.FOCUS_NONE
else:
button.disabled = false
button.modulate.a = 1
button.focus_mode = Control.FOCUS_ALL
func on_theme_changed() -> void:
%DefaultWindDirButton.icon = get_theme_icon(&"Reload", &"EditorIcons")
%DefaultWindStrengthButton.icon = get_theme_icon(&"Reload", &"EditorIcons")
%DefaultWindTurbulenceButton.icon = get_theme_icon(&"Reload", &"EditorIcons")
%DefaultWindPatternButton.icon = get_theme_icon(&"Reload", &"EditorIcons")
func _on_about_to_popup() -> void:
var windir :Vector3 = ProjectSettings.get_setting("shader_globals/sgt_wind_direction").value
_wind_dir_x_slider.value = windir.x
_wind_dir_y_slider.value = windir.y
_wind_dir_z_slider.value = windir.z
_wind_strength_slider.value = ProjectSettings.get_setting("shader_globals/sgt_wind_strength").value
_wind_turbulence_slider.value = ProjectSettings.get_setting("shader_globals/sgt_wind_turbulence").value
_wind_pattern.edited_resource = load(ProjectSettings.get_setting("shader_globals/sgt_wind_pattern").value)
_on_wind_pattern_resource_changed(_wind_pattern.edited_resource)
on_theme_changed()
func _on_wind_dir_x_value_changed(value :float) -> void:
var windir :Vector3 = ProjectSettings.get_setting("shader_globals/sgt_wind_direction", {"value":Vector3.RIGHT}).value
windir.x = value
ProjectSettings.set_setting("shader_globals/sgt_wind_direction", {
"type": "vec3",
"value": windir
})
RenderingServer.global_shader_parameter_set("sgt_wind_direction", windir)
$SaveConfigTimer.start()
get_tree().emit_signal(&"sgt_globals_params_changed")
disable_button(%DefaultWindDirButton, windir == DEFAULT_WIND_DIR)
func _on_wind_dir_y_value_changed(value :float) -> void:
var windir :Vector3 = ProjectSettings.get_setting("shader_globals/sgt_wind_direction", {"value":Vector3.RIGHT}).value
windir.y = value
ProjectSettings.set_setting("shader_globals/sgt_wind_direction", {
"type": "vec3",
"value": windir
})
RenderingServer.global_shader_parameter_set("sgt_wind_direction", windir)
$SaveConfigTimer.start()
get_tree().emit_signal(&"sgt_globals_params_changed")
disable_button(%DefaultWindDirButton, windir == DEFAULT_WIND_DIR)
func _on_wind_dir_z_value_changed(value :float) -> void:
var windir :Vector3 = ProjectSettings.get_setting("shader_globals/sgt_wind_direction", {"value":Vector3.RIGHT}).value
windir.z = value
ProjectSettings.set_setting("shader_globals/sgt_wind_direction", {
"type": "vec3",
"value": windir
})
RenderingServer.global_shader_parameter_set("sgt_wind_direction", windir)
$SaveConfigTimer.start()
get_tree().emit_signal(&"sgt_globals_params_changed")
disable_button(%DefaultWindDirButton, windir == DEFAULT_WIND_DIR)
func _on_wind_strength_value_changed(value :float) -> void:
ProjectSettings.set_setting("shader_globals/sgt_wind_strength", {
"type": "float",
"value": value
})
RenderingServer.global_shader_parameter_set("sgt_wind_strength", value)
$SaveConfigTimer.start()
get_tree().emit_signal(&"sgt_globals_params_changed")
disable_button(%DefaultWindStrengthButton, _wind_strength_slider.value == DEFAULT_WIND_STRENGTH)
func _on_wind_turbulence_value_changed(value :float) -> void:
ProjectSettings.set_setting("shader_globals/sgt_wind_turbulence", {
"type": "float",
"value": value
})
RenderingServer.global_shader_parameter_set("sgt_wind_turbulence", value)
$SaveConfigTimer.start()
get_tree().emit_signal(&"sgt_globals_params_changed")
disable_button(%DefaultWindTurbulenceButton, _wind_turbulence_slider.value == DEFAULT_WIND_TURBULENCE)
func _on_wind_pattern_resource_changed(resource :Resource) -> void:
if resource.resource_path == "":
_wind_pattern.edited_resource = load(DEFAULT_WIND_PATTERN)
_on_wind_pattern_resource_changed(_wind_pattern.edited_resource)
return
ProjectSettings.set_setting("shader_globals/sgt_wind_pattern", {
"type": "sampler2D",
"value": resource.resource_path
})
RenderingServer.global_shader_parameter_set("sgt_wind_pattern", load(resource.resource_path))
$SaveConfigTimer.start()
get_tree().emit_signal(&"sgt_globals_params_changed")
disable_button(%DefaultWindPatternButton, resource.resource_path == DEFAULT_WIND_PATTERN)
func _on_save_config_timer_timeout() -> void:
ProjectSettings.save()
func _on_canceled():
queue_free()
func _on_confirmed() -> void:
ProjectSettings.save()
queue_free()
func _on_default_wind_dir_button_pressed() -> void:
_wind_dir_x_slider.value = DEFAULT_WIND_DIR.x
_wind_dir_y_slider.value = DEFAULT_WIND_DIR.y
_wind_dir_z_slider.value = DEFAULT_WIND_DIR.z
func _on_default_wind_strength_button_pressed() -> void:
_wind_strength_slider.value = DEFAULT_WIND_STRENGTH
func _on_default_wind_turbulence_button_pressed() -> void:
_wind_turbulence_slider.value = DEFAULT_WIND_TURBULENCE
func _on_default_wind_pattern_button_pressed() -> void:
_wind_pattern.edited_resource = load(DEFAULT_WIND_PATTERN)
_on_wind_pattern_resource_changed(_wind_pattern.edited_resource)
@@ -0,0 +1 @@
uid://b1ddeyowx86m3
@@ -0,0 +1,90 @@
[gd_scene load_steps=2 format=3 uid="uid://bbbcb5o176677"]
[ext_resource type="Script" uid="uid://b1ddeyowx86m3" path="res://addons/simplegrasstextured/gui/global_parameters.gd" id="1_f1c1a"]
[node name="SimpleGrassTexturedGlobalParameters" type="AcceptDialog"]
title = "Simple Grass Texture: Global Parameters"
initial_position = 2
size = Vector2i(197, 181)
unresizable = true
script = ExtResource("1_f1c1a")
[node name="MarginContainer" type="MarginContainer" parent="."]
offset_left = 8.0
offset_top = 8.0
offset_right = 441.0
offset_bottom = 164.0
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
[node name="GridContainer" type="GridContainer" parent="MarginContainer"]
layout_mode = 2
theme_override_constants/h_separation = 20
columns = 2
[node name="Label" type="Label" parent="MarginContainer/GridContainer"]
layout_mode = 2
text = "Wind direction:"
[node name="WindDirHbox" type="HBoxContainer" parent="MarginContainer/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
[node name="DefaultWindDirButton" type="Button" parent="MarginContainer/GridContainer/WindDirHbox"]
unique_name_in_owner = true
layout_mode = 2
flat = true
[node name="Label2" type="Label" parent="MarginContainer/GridContainer"]
layout_mode = 2
text = "Wind strength:"
[node name="WindStrengthHBox" type="HBoxContainer" parent="MarginContainer/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
[node name="DefaultWindStrengthButton" type="Button" parent="MarginContainer/GridContainer/WindStrengthHBox"]
unique_name_in_owner = true
layout_mode = 2
flat = true
[node name="Label3" type="Label" parent="MarginContainer/GridContainer"]
layout_mode = 2
text = "Wind turbulence:"
[node name="WindTurbulenceHBox" type="HBoxContainer" parent="MarginContainer/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
[node name="DefaultWindTurbulenceButton" type="Button" parent="MarginContainer/GridContainer/WindTurbulenceHBox"]
unique_name_in_owner = true
layout_mode = 2
flat = true
[node name="Label4" type="Label" parent="MarginContainer/GridContainer"]
layout_mode = 2
text = "Wind pattern:"
[node name="WindPatternHBox" type="HBoxContainer" parent="MarginContainer/GridContainer"]
unique_name_in_owner = true
layout_mode = 2
[node name="DefaultWindPatternButton" type="Button" parent="MarginContainer/GridContainer/WindPatternHBox"]
unique_name_in_owner = true
layout_mode = 2
flat = true
[node name="SaveConfigTimer" type="Timer" parent="."]
wait_time = 5.0
one_shot = true
[connection signal="about_to_popup" from="." to="." method="_on_about_to_popup"]
[connection signal="canceled" from="." to="." method="_on_canceled"]
[connection signal="confirmed" from="." to="." method="_on_confirmed"]
[connection signal="pressed" from="MarginContainer/GridContainer/WindDirHbox/DefaultWindDirButton" to="." method="_on_default_wind_dir_button_pressed"]
[connection signal="pressed" from="MarginContainer/GridContainer/WindStrengthHBox/DefaultWindStrengthButton" to="." method="_on_default_wind_strength_button_pressed"]
[connection signal="pressed" from="MarginContainer/GridContainer/WindTurbulenceHBox/DefaultWindTurbulenceButton" to="." method="_on_default_wind_turbulence_button_pressed"]
[connection signal="pressed" from="MarginContainer/GridContainer/WindPatternHBox/DefaultWindPatternButton" to="." method="_on_default_wind_pattern_button_pressed"]
[connection signal="timeout" from="SaveConfigTimer" to="." method="_on_save_config_timer_timeout"]
@@ -0,0 +1,337 @@
# toolbar.gd
# This file is part of: SimpleGrassTextured
# Copyright (c) 2023 IcterusGames
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@tool
extends Control
enum MENU_SHAPE_ID {
TOOL_SHAPE_SPHERE,
TOOL_SHAPE_CYLINDER,
TOOL_SHAPE_CYLINDER_INF_H,
TOOL_SHAPE_BOX,
TOOL_SHAPE_BOX_INF_H,
}
const DEFAULT_RADIUS := 2.0
const DEFAULT_DENSITY := 25.0
const DEFAULT_SCALE := 1.0
const DEFAULT_ROTATION := 0.0
const DEFAULT_ROTATION_RAND := 1.0
const DEFAULT_DISTANCE := 0.25
var _shortcut_radius_inc := Shortcut.new()
var _shortcut_radius_dec := Shortcut.new()
var _shortcut_density_inc := Shortcut.new()
var _shortcut_density_dec := Shortcut.new()
var _plugin: EditorPlugin = null
var _grass_selected = null
@onready var button_airbrush :Button = %ButtonAirbrush
@onready var button_pencil :Button = %ButtonPencil
@onready var button_eraser :Button = %ButtonEraser
@onready var button_density :Button = %IconDensity
@onready var slider_radius :HSlider = $HSliderRadius
@onready var slider_density :HSlider = $HSliderDensity
@onready var edit_slope_range: Control = %SlopeRange
@onready var edit_scale :EditorSpinSlider
@onready var edit_rotation :EditorSpinSlider
@onready var edit_rotation_rand :EditorSpinSlider
@onready var edit_distance :EditorSpinSlider
@onready var label_stats :Label = $LabelStats
@onready var _label_radius :Label = $HSliderRadius/Label
@onready var _label_density :Label = $HSliderDensity/Label
@onready var _button_more :MenuButton = $ButtonMore
@onready var _airbrush_options: MenuButton = %AirbrushOptions
@onready var _pencil_options: MenuButton = %PencilOptions
@onready var _eraser_options: MenuButton = %EraserOptions
@onready var _tween_radius :Tween = null
@onready var _tween_density :Tween = null
func _ready() -> void:
edit_scale = _create_slider("", 0.01, 10.0, 0.01, DEFAULT_SCALE)
edit_rotation = _create_slider("", 0.0, 360.0, 0.1, DEFAULT_ROTATION)
edit_rotation_rand = _create_slider("", 0.0, 1.0, 0.01, DEFAULT_ROTATION_RAND)
edit_distance = _create_slider("", 0.0, 5.0, 0.01, DEFAULT_DISTANCE)
%ScaleCont.add_child(edit_scale)
%RotationCont.add_child(edit_rotation)
%RotationRandCont.add_child(edit_rotation_rand)
%DistanceCont.add_child(edit_distance)
func _unhandled_input(event :InputEvent) -> void:
if not event.is_pressed():
return
if _shortcut_radius_inc.matches_event(event):
slider_radius.value += 0.1
if _shortcut_radius_dec.matches_event(event):
slider_radius.value -= 0.1
if slider_density.editable and _shortcut_density_inc.matches_event(event):
slider_density.value += 1
if slider_density.editable and _shortcut_density_dec.matches_event(event):
slider_density.value -= 1
func set_plugin(plugin :EditorPlugin) -> void:
_plugin = plugin
theme_changed.connect(_on_theme_changed)
%ButtonMore.set_plugin(plugin)
var config := ConfigFile.new()
config.load("res://addons/simplegrasstextured/plugin.cfg")
%LabelVersion.text = config.get_value("plugin", "version")
button_airbrush.shortcut = plugin.get_custom_setting("SimpleGrassTextured/Shortcuts/airbrush_tool")
button_pencil.shortcut = plugin.get_custom_setting("SimpleGrassTextured/Shortcuts/pencil_tool")
button_eraser.shortcut = plugin.get_custom_setting("SimpleGrassTextured/Shortcuts/eraser_tool")
button_airbrush.gui_input.connect(_on_button_tool_gui_input.bind(button_airbrush, _airbrush_options))
button_pencil.gui_input.connect(_on_button_tool_gui_input.bind(button_pencil, _pencil_options))
button_eraser.gui_input.connect(_on_button_tool_gui_input.bind(button_eraser, _eraser_options))
_shortcut_radius_inc = plugin.get_custom_setting("SimpleGrassTextured/Shortcuts/radius_increment")
_shortcut_radius_dec = plugin.get_custom_setting("SimpleGrassTextured/Shortcuts/radius_decrement")
_shortcut_density_inc = plugin.get_custom_setting("SimpleGrassTextured/Shortcuts/density_increment")
_shortcut_density_dec = plugin.get_custom_setting("SimpleGrassTextured/Shortcuts/density_decrement")
_airbrush_options.get_popup().add_radio_check_item("Cylinder", MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER)
_airbrush_options.get_popup().add_radio_check_item("Box", MENU_SHAPE_ID.TOOL_SHAPE_BOX)
_airbrush_options.get_popup().about_to_popup.connect(_on_tool_options_about_to_popup.bind(_airbrush_options))
_airbrush_options.get_popup().id_pressed.connect(_on_sgt_shape_menu_pressed.bind("airbrush", _airbrush_options.get_popup()))
_pencil_options.get_popup().add_radio_check_item("Cylinder", MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER)
_pencil_options.get_popup().add_radio_check_item("Box", MENU_SHAPE_ID.TOOL_SHAPE_BOX)
_pencil_options.get_popup().about_to_popup.connect(_on_tool_options_about_to_popup.bind(_pencil_options))
_pencil_options.get_popup().id_pressed.connect(_on_sgt_shape_menu_pressed.bind("pencil", _pencil_options.get_popup()))
_eraser_options.get_popup().add_radio_check_item("Sphere", MENU_SHAPE_ID.TOOL_SHAPE_SPHERE)
_eraser_options.get_popup().add_radio_check_item("Cylinder", MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER)
_eraser_options.get_popup().add_radio_check_item("Infinite vertical cylinder", MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER_INF_H)
_eraser_options.get_popup().add_radio_check_item("Box", MENU_SHAPE_ID.TOOL_SHAPE_BOX)
_eraser_options.get_popup().add_radio_check_item("Infinite vertical box", MENU_SHAPE_ID.TOOL_SHAPE_BOX_INF_H)
_eraser_options.get_popup().about_to_popup.connect(_on_tool_options_about_to_popup.bind(_eraser_options))
_eraser_options.get_popup().id_pressed.connect(_on_sgt_shape_menu_pressed.bind("eraser", _eraser_options.get_popup()))
_on_theme_changed()
func set_current_grass(grass) -> void:
_grass_selected = grass
%ButtonMore.set_current_grass(grass)
if _grass_selected == null:
return
for tool_name in _grass_selected.sgt_tool_shape:
match tool_name:
"airbrush":
_update_shape_menu_from_grass(_airbrush_options.get_popup(), _grass_selected.sgt_tool_shape[tool_name])
"pencil":
_update_shape_menu_from_grass(_pencil_options.get_popup(), _grass_selected.sgt_tool_shape[tool_name])
"eraser":
_update_shape_menu_from_grass(_eraser_options.get_popup(), _grass_selected.sgt_tool_shape[tool_name])
func set_density_modulate(color: Color) -> void:
%IconDensity.self_modulate = color
slider_density.modulate = color
func _create_slider(label :String, min_value :float, max_value :float, step :float, value :float = 0.0) -> EditorSpinSlider:
var slider := EditorSpinSlider.new()
slider.size_flags_horizontal = Control.SIZE_EXPAND_FILL
slider.step = step;
slider.min_value = min_value
slider.max_value = max_value
slider.label = label
slider.value = value
slider.custom_minimum_size.x = 75
return slider
func _on_tool_options_about_to_popup(_button_options: MenuButton) -> void:
set_current_grass(_grass_selected)
func _update_shape_menu_from_grass(popupmenu: PopupMenu, plugin_id_shape: int) -> void:
for i in popupmenu.item_count:
popupmenu.set_item_checked(i, false)
var idx := -1
match _plugin.get_tool_shape_name(plugin_id_shape):
"sphere":
idx = popupmenu.get_item_index(MENU_SHAPE_ID.TOOL_SHAPE_SPHERE)
"cylinder":
idx = popupmenu.get_item_index(MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER)
"cylinder_inf_h":
idx = popupmenu.get_item_index(MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER_INF_H)
"box":
idx = popupmenu.get_item_index(MENU_SHAPE_ID.TOOL_SHAPE_BOX)
"box_inf_h":
idx = popupmenu.get_item_index(MENU_SHAPE_ID.TOOL_SHAPE_BOX_INF_H)
_:
idx = -1
if idx == -1:
return
popupmenu.set_item_checked(idx, true)
func _on_sgt_shape_menu_pressed(id: int, tool_name: String, popupmenu: PopupMenu) -> void:
if _grass_selected == null:
return
for i in popupmenu.item_count:
popupmenu.set_item_checked(i, false)
var idx := popupmenu.get_item_index(id)
if idx == -1:
return
popupmenu.set_item_checked(idx, true)
var shape_name := ""
match id:
MENU_SHAPE_ID.TOOL_SHAPE_SPHERE:
shape_name = "sphere"
MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER:
shape_name = "cylinder"
MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER_INF_H:
shape_name = "cylinder_inf_h"
MENU_SHAPE_ID.TOOL_SHAPE_BOX:
shape_name = "box"
MENU_SHAPE_ID.TOOL_SHAPE_BOX_INF_H:
shape_name = "box_inf_h"
_plugin.set_tool_shape(tool_name, shape_name)
_plugin.set_tool(tool_name)
func _on_h_slider_radius_value_changed(value :float) -> void:
if _tween_radius != null:
_tween_radius.kill()
_label_radius.set(&"theme_override_colors/font_outline_color", _label_radius.get_theme_color(&"font_color").inverted())
_tween_radius = _label_radius.create_tween()
_tween_radius.tween_property(_label_radius, ^"modulate", Color.WHITE, 0.1)
_tween_radius.tween_interval(2)
_tween_radius.tween_property(_label_radius, ^"modulate", Color(1,1,1,0), 2)
_label_radius.text = "%0.1f" % value
slider_radius.tooltip_text = "(" + _shortcut_radius_dec.get_as_text() + ") - (" + _shortcut_radius_inc.get_as_text() + ")\n"
slider_radius.tooltip_text += "Radius = %0.1f" % value
func _on_h_slider_density_value_changed(value :float) -> void:
if _tween_density != null:
_tween_density.kill()
_label_density.set(&"theme_override_colors/font_outline_color", _label_density.get_theme_color(&"font_color").inverted())
_tween_density = _label_density.create_tween()
_tween_density.tween_property(_label_density, ^"modulate", Color.WHITE, 0.1)
_tween_density.tween_interval(2)
_tween_density.tween_property(_label_density, ^"modulate", Color(1,1,1,0), 2)
_label_density.text = str(value)
slider_density.tooltip_text = "(" + _shortcut_density_dec.get_as_text() + ") - (" + _shortcut_density_inc.get_as_text() + ")\n"
slider_density.tooltip_text += "Density = %0.0f" % value
func _on_theme_changed() -> void:
%IconScale.icon = get_theme_icon(&"ToolScale", &"EditorIcons")
%IconRotation.icon = get_theme_icon(&"ToolRotate", &"EditorIcons")
%IconRotationRand.icon = get_theme_icon(&"RandomNumberGenerator", &"EditorIcons")
var base_color: Color = EditorInterface.get_base_control().get_theme_color(&"base_color", &"Editor")
if base_color.get_luminance() < 0.5:
button_airbrush.icon = load("res://addons/simplegrasstextured/images/sgt_icon_airbrush.svg")
button_pencil.icon = load("res://addons/simplegrasstextured/images/sgt_icon_pen.svg")
button_eraser.icon = load("res://addons/simplegrasstextured/images/sgt_icon_eraser.svg")
_airbrush_options.icon = load("res://addons/simplegrasstextured/images/sgt_icon_arrow_up.svg")
_pencil_options.icon = load("res://addons/simplegrasstextured/images/sgt_icon_arrow_up.svg")
_eraser_options.icon = load("res://addons/simplegrasstextured/images/sgt_icon_arrow_up.svg")
%IconSlope.icon = load("res://addons/simplegrasstextured/images/sgt_icon_slope.svg")
%IconRadius.icon = load("res://addons/simplegrasstextured/images/sgt_icon_radius.svg")
%IconDensity.icon = load("res://addons/simplegrasstextured/images/sgt_icon_density.svg")
%IconDistance.icon = load("res://addons/simplegrasstextured/images/sgt_icon_distance.svg")
else:
button_airbrush.icon = load("res://addons/simplegrasstextured/images/sgt_icon_airbrush_dark.svg")
button_pencil.icon = load("res://addons/simplegrasstextured/images/sgt_icon_pen_dark.svg")
button_eraser.icon = load("res://addons/simplegrasstextured/images/sgt_icon_eraser_dark.svg")
_airbrush_options.icon = load("res://addons/simplegrasstextured/images/sgt_icon_arrow_up_dark.svg")
_pencil_options.icon = load("res://addons/simplegrasstextured/images/sgt_icon_arrow_up_dark.svg")
_eraser_options.icon = load("res://addons/simplegrasstextured/images/sgt_icon_arrow_up_dark.svg")
%IconSlope.icon = load("res://addons/simplegrasstextured/images/sgt_icon_slope_dark.svg")
%IconRadius.icon = load("res://addons/simplegrasstextured/images/sgt_icon_radius_dark.svg")
%IconDensity.icon = load("res://addons/simplegrasstextured/images/sgt_icon_density_dark.svg")
%IconDistance.icon = load("res://addons/simplegrasstextured/images/sgt_icon_distance_dark.svg")
if _button_more != null:
_button_more.icon = get_theme_icon(&"GuiTabMenuHl", &"EditorIcons")
# Test that the icons size matches with editor UI scale
var _ed_scale := 1.0
var es: int = EditorInterface.get_editor_settings().get_setting("interface/editor/display_scale")
if es == 7:
_ed_scale = EditorInterface.get_editor_settings().get_setting("interface/editor/custom_display_scale")
else:
_ed_scale = [1.0, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0][clamp(es, 0, 6)]
if load("res://addons/simplegrasstextured/images/sgt_icon_density.svg").get_width() != roundi(16 * _ed_scale):
$TimerReimportIcons.start()
func _on_panel_container_gui_input(event) -> void:
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
var win = load("res://addons/simplegrasstextured/gui/about.tscn").instantiate()
get_window().add_child(win)
win.popup_centered()
func _on_icon_slope_pressed() -> void:
edit_slope_range.set_value_min(0)
edit_slope_range.set_value_max(45)
func _on_icon_scale_pressed() -> void:
edit_scale.value = DEFAULT_SCALE
func _on_icon_rotation_pressed() -> void:
edit_rotation.value = DEFAULT_ROTATION
func _on_icon_rotation_rand_pressed() -> void:
edit_rotation_rand.value = DEFAULT_ROTATION_RAND
func _on_icon_distance_pressed() -> void:
edit_distance.value = DEFAULT_DISTANCE
func _on_icon_radius_pressed() -> void:
slider_radius.value = DEFAULT_RADIUS
func _on_icon_radius_2_pressed() -> void:
slider_density.value = DEFAULT_DENSITY
func _on_timer_reimport_icons_timeout() -> void:
if EditorInterface.get_resource_filesystem().is_scanning():
return
$TimerReimportIcons.stop()
EditorInterface.get_resource_filesystem().reimport_files([
"res://addons/simplegrasstextured/sgt_icon.svg",
"res://addons/simplegrasstextured/sgt_icon_48.svg",
"res://addons/simplegrasstextured/images/sgt_icon_density.svg",
"res://addons/simplegrasstextured/images/sgt_icon_distance.svg",
"res://addons/simplegrasstextured/images/sgt_icon_radius.svg",
"res://addons/simplegrasstextured/images/sgt_icon_slope.svg",
"res://addons/simplegrasstextured/images/sgt_icon_airbrush.svg",
"res://addons/simplegrasstextured/images/sgt_icon_pen.svg",
"res://addons/simplegrasstextured/images/sgt_icon_eraser.svg"
])
func _on_button_tool_gui_input(event: InputEvent, tool: Button, button_options: MenuButton) -> void:
if event is InputEventMouseButton:
if event.pressed and event.button_index == MOUSE_BUTTON_RIGHT:
button_options.get_popup().popup(Rect2(tool.global_position + Vector2(tool.size.x, 0), Vector2.ZERO))
@@ -0,0 +1 @@
uid://usxgr64t746m
@@ -0,0 +1,305 @@
[gd_scene load_steps=16 format=3 uid="uid://dsim5cbhc6kwm"]
[ext_resource type="Script" uid="uid://usxgr64t746m" path="res://addons/simplegrasstextured/gui/toolbar.gd" id="1_aa1o6"]
[ext_resource type="Material" uid="uid://cl74usvfymgvs" path="res://addons/simplegrasstextured/materials/icon.material" id="2_p7k4b"]
[ext_resource type="Texture2D" uid="uid://bsmcpupaj02v8" path="res://addons/simplegrasstextured/sgt_icon.svg" id="3_tl64l"]
[ext_resource type="PackedScene" uid="uid://der2mmxtog2mt" path="res://addons/simplegrasstextured/gui/toolbar_menu.tscn" id="4_1u4kn"]
[ext_resource type="Texture2D" uid="uid://c2kunxv5wepih" path="res://addons/simplegrasstextured/images/sgt_icon_airbrush.svg" id="4_weijg"]
[ext_resource type="Texture2D" uid="uid://clm6vd2es8xm7" path="res://addons/simplegrasstextured/images/sgt_icon_radius.svg" id="5_55kgh"]
[ext_resource type="Texture2D" uid="uid://dtal42g10x1ay" path="res://addons/simplegrasstextured/images/sgt_icon_pen.svg" id="5_itpep"]
[ext_resource type="Texture2D" uid="uid://bda52g6s88x5d" path="res://addons/simplegrasstextured/images/sgt_icon_arrow_up.svg" id="5_jg7h4"]
[ext_resource type="Texture2D" uid="uid://brugf6rnck1tk" path="res://addons/simplegrasstextured/images/sgt_icon_eraser.svg" id="6_jg7h4"]
[ext_resource type="Texture2D" uid="uid://tqiak77omdnr" path="res://addons/simplegrasstextured/images/sgt_icon_density.svg" id="6_wboky"]
[ext_resource type="Texture2D" uid="uid://24avwtyvf01r" path="res://addons/simplegrasstextured/images/sgt_icon_slope.svg" id="7_4wrj3"]
[ext_resource type="Texture2D" uid="uid://d28dlfkm62t6e" path="res://addons/simplegrasstextured/images/sgt_icon_distance.svg" id="7_ao3h0"]
[ext_resource type="PackedScene" uid="uid://r30ih7dtx1uo" path="res://addons/simplegrasstextured/gui/domain_range.tscn" id="8_y7yf0"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_6mh15"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_hc7jq"]
[node name="SGTToolbar" type="HFlowContainer"]
anchors_preset = 10
anchor_right = 1.0
offset_bottom = 31.0
grow_horizontal = 2
script = ExtResource("1_aa1o6")
[node name="PanelContainer" type="PanelContainer" parent="."]
custom_minimum_size = Vector2(24, 0)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_styles/panel = SubResource("StyleBoxEmpty_6mh15")
[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer"]
layout_mode = 2
mouse_filter = 2
alignment = 1
[node name="MarginContainer" type="MarginContainer" parent="PanelContainer/VBoxContainer"]
custom_minimum_size = Vector2(24, 0)
layout_mode = 2
mouse_filter = 2
theme_override_constants/margin_bottom = 3
[node name="TextureRect" type="TextureRect" parent="PanelContainer/VBoxContainer/MarginContainer"]
material = ExtResource("2_p7k4b")
custom_minimum_size = Vector2(24, 0)
layout_mode = 2
mouse_filter = 2
texture = ExtResource("3_tl64l")
stretch_mode = 3
[node name="LabelVersion" type="Label" parent="PanelContainer"]
unique_name_in_owner = true
auto_translate_mode = 2
clip_contents = true
layout_mode = 2
size_flags_vertical = 1
localize_numeral_system = false
theme_override_font_sizes/font_size = 7
theme_override_styles/normal = SubResource("StyleBoxEmpty_hc7jq")
text = "2.0.5"
horizontal_alignment = 1
vertical_alignment = 2
[node name="VSeparator" type="VSeparator" parent="."]
layout_mode = 2
[node name="HBoxContainer" type="HBoxContainer" parent="."]
layout_mode = 2
theme_override_constants/separation = 0
[node name="ButtonAirbrush" type="Button" parent="HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Airdraw tool
(right button for more options)"
theme_type_variation = &"FlatButton"
toggle_mode = true
icon = ExtResource("4_weijg")
[node name="AirbrushOptions" type="MenuButton" parent="HBoxContainer"]
unique_name_in_owner = true
visible = false
layout_mode = 2
theme_type_variation = &"FlatMenuButton"
icon = ExtResource("5_jg7h4")
flat = false
[node name="HBoxContainer2" type="HBoxContainer" parent="."]
layout_mode = 2
theme_override_constants/separation = 0
[node name="ButtonPencil" type="Button" parent="HBoxContainer2"]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Pencil tool
(right button for more options)"
theme_type_variation = &"FlatButton"
toggle_mode = true
icon = ExtResource("5_itpep")
[node name="PencilOptions" type="MenuButton" parent="HBoxContainer2"]
unique_name_in_owner = true
visible = false
layout_mode = 2
theme_type_variation = &"FlatMenuButton"
icon = ExtResource("5_jg7h4")
flat = false
[node name="HBoxContainer3" type="HBoxContainer" parent="."]
layout_mode = 2
theme_override_constants/separation = 0
[node name="ButtonEraser" type="Button" parent="HBoxContainer3"]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Eraser tool
(right button for more options)"
theme_type_variation = &"FlatButton"
toggle_mode = true
icon = ExtResource("6_jg7h4")
[node name="EraserOptions" type="MenuButton" parent="HBoxContainer3"]
unique_name_in_owner = true
visible = false
layout_mode = 2
theme_type_variation = &"FlatMenuButton"
icon = ExtResource("5_jg7h4")
flat = false
[node name="ButtonMore" parent="." instance=ExtResource("4_1u4kn")]
unique_name_in_owner = true
layout_mode = 2
theme_type_variation = &"FlatMenuButton"
flat = false
switch_on_hover = true
[node name="VSeparator2" type="VSeparator" parent="."]
layout_mode = 2
[node name="IconRadius" type="Button" parent="."]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
tooltip_text = "Radius"
icon = ExtResource("5_55kgh")
flat = true
[node name="HSliderRadius" type="HSlider" parent="."]
custom_minimum_size = Vector2(100, 0)
layout_mode = 2
size_flags_vertical = 1
tooltip_text = "Radius"
min_value = 0.1
max_value = 10.0
step = 0.1
value = 1.0
[node name="Label" type="Label" parent="HSliderRadius"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 2
horizontal_alignment = 1
vertical_alignment = 1
[node name="Separator" type="Control" parent="."]
custom_minimum_size = Vector2(15, 0)
layout_mode = 2
[node name="IconDensity" type="Button" parent="."]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
tooltip_text = "Density"
icon = ExtResource("6_wboky")
flat = true
[node name="HSliderDensity" type="HSlider" parent="."]
custom_minimum_size = Vector2(100, 0)
layout_mode = 2
size_flags_vertical = 1
tooltip_text = "Density"
min_value = 1.0
max_value = 200.0
value = 1.0
[node name="Label" type="Label" parent="HSliderDensity"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 2
horizontal_alignment = 1
vertical_alignment = 1
[node name="Separator2" type="Control" parent="."]
custom_minimum_size = Vector2(15, 0)
layout_mode = 2
[node name="SlopeCont" type="HBoxContainer" parent="."]
unique_name_in_owner = true
layout_mode = 2
[node name="IconSlope" type="Button" parent="SlopeCont"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
tooltip_text = "Slope"
icon = ExtResource("7_4wrj3")
flat = true
[node name="SlopeRange" parent="SlopeCont" instance=ExtResource("8_y7yf0")]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Slope to avoid:
Min: 0°
Max: 45°
"
[node name="ScaleCont" type="HBoxContainer" parent="."]
unique_name_in_owner = true
layout_mode = 2
[node name="IconScale" type="Button" parent="ScaleCont"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
tooltip_text = "Scale"
flat = true
[node name="Separator3" type="Control" parent="."]
custom_minimum_size = Vector2(15, 0)
layout_mode = 2
[node name="RotationCont" type="HBoxContainer" parent="."]
unique_name_in_owner = true
layout_mode = 2
[node name="IconRotation" type="Button" parent="RotationCont"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
tooltip_text = "Rotation"
flat = true
[node name="RotationRandCont" type="HBoxContainer" parent="."]
unique_name_in_owner = true
layout_mode = 2
[node name="IconRotationRand" type="Button" parent="RotationRandCont"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
tooltip_text = "Rotation randomizer"
flat = true
[node name="Separator4" type="Control" parent="."]
custom_minimum_size = Vector2(15, 0)
layout_mode = 2
[node name="DistanceCont" type="HBoxContainer" parent="."]
unique_name_in_owner = true
layout_mode = 2
[node name="IconDistance" type="Button" parent="DistanceCont"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
tooltip_text = "Minimum distance between grasses"
icon = ExtResource("7_ao3h0")
flat = true
[node name="Separator5" type="Control" parent="."]
custom_minimum_size = Vector2(15, 0)
layout_mode = 2
[node name="LabelStats" type="Label" parent="."]
layout_mode = 2
size_flags_horizontal = 3
text = "Count: 0"
horizontal_alignment = 2
vertical_alignment = 1
[node name="TimerReimportIcons" type="Timer" parent="."]
[connection signal="gui_input" from="PanelContainer" to="." method="_on_panel_container_gui_input"]
[connection signal="pressed" from="IconRadius" to="." method="_on_icon_radius_pressed"]
[connection signal="value_changed" from="HSliderRadius" to="." method="_on_h_slider_radius_value_changed"]
[connection signal="pressed" from="IconDensity" to="." method="_on_icon_radius_2_pressed"]
[connection signal="value_changed" from="HSliderDensity" to="." method="_on_h_slider_density_value_changed"]
[connection signal="pressed" from="SlopeCont/IconSlope" to="." method="_on_icon_slope_pressed"]
[connection signal="pressed" from="ScaleCont/IconScale" to="." method="_on_icon_scale_pressed"]
[connection signal="pressed" from="RotationCont/IconRotation" to="." method="_on_icon_rotation_pressed"]
[connection signal="pressed" from="RotationRandCont/IconRotationRand" to="." method="_on_icon_rotation_rand_pressed"]
[connection signal="pressed" from="DistanceCont/IconDistance" to="." method="_on_icon_distance_pressed"]
[connection signal="timeout" from="TimerReimportIcons" to="." method="_on_timer_reimport_icons_timeout"]
@@ -0,0 +1,266 @@
# toolbar_menu.gd
# This file is part of: SimpleGrassTextured
# Copyright (c) 2023 IcterusGames
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@tool
extends MenuButton
enum MENU_ID {
TOOL_FOLLOW_NORMAL,
TOOL_SHAPE_AIRBRUSH,
TOOL_SHAPE_PENCIL,
TOOL_SHAPE_ERASER,
TOOL_SNAP_TO_TERRAIN,
AUTO_CENTER_POSITION,
CAST_SHADOW,
BAKE_HEIGHT_MAP,
GLOBAL_PARAMETERS,
CLEAR_ALL,
HELP_ABOUT,
RECALCULATE_AABB,
}
enum MENU_SHAPE_ID {
TOOL_SHAPE_SPHERE,
TOOL_SHAPE_CYLINDER,
TOOL_SHAPE_CYLINDER_INF_H,
TOOL_SHAPE_BOX,
TOOL_SHAPE_BOX_INF_H,
}
var _plugin: EditorPlugin = null
var _grass_selected = null
var _tools_menu: PopupMenu = null
var _airbrush_shape_menu: PopupMenu = null
var _pencil_shape_menu: PopupMenu = null
var _eraser_shape_menu: PopupMenu = null
func set_plugin(plugin :EditorPlugin) -> void:
var popup := get_popup()
_plugin = plugin
_airbrush_shape_menu = PopupMenu.new()
_airbrush_shape_menu.name = &"AirbrushShapeMenu"
_airbrush_shape_menu.add_radio_check_item("Cylinder", MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER)
_airbrush_shape_menu.add_radio_check_item("Box", MENU_SHAPE_ID.TOOL_SHAPE_BOX)
_pencil_shape_menu = PopupMenu.new()
_pencil_shape_menu.name = &"PencilShapeMenu"
_pencil_shape_menu.add_radio_check_item("Cylinder", MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER)
_pencil_shape_menu.add_radio_check_item("Box", MENU_SHAPE_ID.TOOL_SHAPE_BOX)
_eraser_shape_menu = PopupMenu.new()
_eraser_shape_menu.name = &"EraserShapeMenu"
_eraser_shape_menu.add_radio_check_item("Sphere", MENU_SHAPE_ID.TOOL_SHAPE_SPHERE)
_eraser_shape_menu.add_radio_check_item("Cylinder", MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER)
_eraser_shape_menu.add_radio_check_item("Infinite vertical cylinder", MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER_INF_H)
_eraser_shape_menu.add_radio_check_item("Box", MENU_SHAPE_ID.TOOL_SHAPE_BOX)
_eraser_shape_menu.add_radio_check_item("Infinite vertical box", MENU_SHAPE_ID.TOOL_SHAPE_BOX_INF_H)
_tools_menu = PopupMenu.new()
_tools_menu.add_child(_airbrush_shape_menu)
_tools_menu.add_child(_pencil_shape_menu)
_tools_menu.add_child(_eraser_shape_menu)
_tools_menu.name = &"ToolsMenu"
_tools_menu.add_check_item("Follow terrain's normal", MENU_ID.TOOL_FOLLOW_NORMAL)
_tools_menu.add_submenu_item("Airbrush shape", "AirbrushShapeMenu")
_tools_menu.add_submenu_item("Pencil shape", "PencilShapeMenu")
_tools_menu.add_submenu_item("Eraser shape", "EraserShapeMenu")
_tools_menu.add_separator()
_tools_menu.add_item("Snap to terrain", MENU_ID.TOOL_SNAP_TO_TERRAIN)
popup.add_child(_tools_menu)
popup.clear()
popup.add_submenu_item("Tools", "ToolsMenu")
popup.add_separator()
popup.add_item("Auto center position", MENU_ID.AUTO_CENTER_POSITION)
popup.add_item("Recalculate custom AABB", MENU_ID.RECALCULATE_AABB)
popup.add_item("Bake height map", MENU_ID.BAKE_HEIGHT_MAP)
popup.add_check_item("Cast shadow", MENU_ID.CAST_SHADOW)
popup.add_item("Global parameters", MENU_ID.GLOBAL_PARAMETERS)
popup.add_separator()
popup.add_item("Clear all", MENU_ID.CLEAR_ALL)
popup.add_separator()
popup.add_item("About SimpleGrassTextured", MENU_ID.HELP_ABOUT)
popup.id_pressed.connect(_on_sgt_menu_button)
_tools_menu.id_pressed.connect(_on_sgt_tools_menu_button)
_airbrush_shape_menu.id_pressed.connect(_on_sgt_shape_menu_pressed.bind("airbrush", _airbrush_shape_menu))
_pencil_shape_menu.id_pressed.connect(_on_sgt_shape_menu_pressed.bind("pencil", _pencil_shape_menu))
_eraser_shape_menu.id_pressed.connect(_on_sgt_shape_menu_pressed.bind("eraser", _eraser_shape_menu))
about_to_popup.connect(_on_about_to_popup)
func set_current_grass(grass_selected) -> void:
_grass_selected = grass_selected
if grass_selected == null:
return
var popup := get_popup()
if grass_selected.cast_shadow == GeometryInstance3D.SHADOW_CASTING_SETTING_OFF:
popup.set_item_checked(popup.get_item_index(MENU_ID.CAST_SHADOW), false)
else:
popup.set_item_checked(popup.get_item_index(MENU_ID.CAST_SHADOW), true)
if _grass_selected.baked_height_map != null:
popup.set_item_text(popup.get_item_index(MENU_ID.BAKE_HEIGHT_MAP), "Bake height map (already baked)")
popup.set_item_disabled(popup.get_item_index(MENU_ID.BAKE_HEIGHT_MAP), true)
else:
popup.set_item_text(popup.get_item_index(MENU_ID.BAKE_HEIGHT_MAP), "Bake height map")
popup.set_item_disabled(popup.get_item_index(MENU_ID.BAKE_HEIGHT_MAP), false)
_tools_menu.set_item_checked(_tools_menu.get_item_index(MENU_ID.TOOL_FOLLOW_NORMAL), _grass_selected.sgt_follow_normal)
for tool_name in _grass_selected.sgt_tool_shape:
match tool_name:
"airbrush":
_update_shape_menu_from_grass(_airbrush_shape_menu, _grass_selected.sgt_tool_shape[tool_name])
"pencil":
_update_shape_menu_from_grass(_pencil_shape_menu, _grass_selected.sgt_tool_shape[tool_name])
"eraser":
_update_shape_menu_from_grass(_eraser_shape_menu, _grass_selected.sgt_tool_shape[tool_name])
func _update_shape_menu_from_grass(popupmenu: PopupMenu, plugin_id_shape: int) -> void:
for i in popupmenu.item_count:
popupmenu.set_item_checked(i, false)
var idx := -1
match _plugin.get_tool_shape_name(plugin_id_shape):
"sphere":
idx = popupmenu.get_item_index(MENU_SHAPE_ID.TOOL_SHAPE_SPHERE)
"cylinder":
idx = popupmenu.get_item_index(MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER)
"cylinder_inf_h":
idx = popupmenu.get_item_index(MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER_INF_H)
"box":
idx = popupmenu.get_item_index(MENU_SHAPE_ID.TOOL_SHAPE_BOX)
"box_inf_h":
idx = popupmenu.get_item_index(MENU_SHAPE_ID.TOOL_SHAPE_BOX_INF_H)
_:
idx = -1
if idx == -1:
return
popupmenu.set_item_checked(idx, true)
func _on_sgt_menu_button(id :int) -> void:
if _grass_selected == null:
return
match id:
MENU_ID.AUTO_CENTER_POSITION:
_plugin.get_undo_redo().create_action(_grass_selected.name + " Auto Center Position")
_plugin.get_undo_redo().add_undo_property(_grass_selected, &"baked_height_map", _grass_selected.baked_height_map)
_plugin.get_undo_redo().add_undo_property(_grass_selected, &"multimesh", _grass_selected.multimesh)
_plugin.get_undo_redo().add_undo_property(_grass_selected, &"global_position", _grass_selected.global_position)
_grass_selected.auto_center_position()
_plugin.get_undo_redo().add_do_property(_grass_selected, &"baked_height_map", _grass_selected.baked_height_map)
_plugin.get_undo_redo().add_do_property(_grass_selected, &"multimesh", _grass_selected.multimesh)
_plugin.get_undo_redo().add_do_property(_grass_selected, &"global_position", _grass_selected.global_position)
_plugin.get_undo_redo().commit_action()
MENU_ID.RECALCULATE_AABB:
_plugin.get_undo_redo().create_action(_grass_selected.name + " Recalculate Custom AABB")
_plugin.get_undo_redo().add_undo_property(_grass_selected, &"custom_aabb", _grass_selected.custom_aabb)
_grass_selected.recalculate_custom_aabb()
_plugin.get_undo_redo().add_do_property(_grass_selected, &"custom_aabb", _grass_selected.custom_aabb)
_plugin.get_undo_redo().commit_action()
MENU_ID.CAST_SHADOW:
_plugin.get_undo_redo().create_action(_grass_selected.name + " Toogle Cast Shadow")
_plugin.get_undo_redo().add_undo_property(_grass_selected, &"cast_shadow", _grass_selected.cast_shadow)
for child in _grass_selected.get_children():
if child.has_meta(&"SimpleGrassTexturedRegion"):
_plugin.get_undo_redo().add_undo_property(child, &"cast_shadow", child.cast_shadow)
if _grass_selected.cast_shadow == GeometryInstance3D.SHADOW_CASTING_SETTING_OFF:
_grass_selected.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_ON
else:
_grass_selected.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
_plugin.get_undo_redo().add_do_property(_grass_selected, &"cast_shadow", _grass_selected.cast_shadow)
for child in _grass_selected.get_children():
if child.has_meta(&"SimpleGrassTexturedRegion"):
child.cast_shadow = _grass_selected.cast_shadow
_plugin.get_undo_redo().add_do_property(child, &"cast_shadow", child.cast_shadow)
_plugin.get_undo_redo().commit_action()
MENU_ID.BAKE_HEIGHT_MAP:
_grass_selected.bake_height_map()
MENU_ID.GLOBAL_PARAMETERS:
var _global_parameters = load("res://addons/simplegrasstextured/gui/global_parameters.tscn").instantiate()
get_window().add_child(_global_parameters)
_global_parameters.popup_centered()
MENU_ID.CLEAR_ALL:
var win = load("res://addons/simplegrasstextured/gui/clear_all_confirmation_dialog.tscn").instantiate()
get_window().add_child(win)
win.confirmed.connect(_on_clear_all_confirmation_dialog_confirmed)
win.popup_centered()
MENU_ID.HELP_ABOUT:
var win = load("res://addons/simplegrasstextured/gui/about.tscn").instantiate()
get_window().add_child(win)
win.popup_centered()
func _on_sgt_tools_menu_button(id :int) -> void:
if _grass_selected == null:
return
match id:
MENU_ID.TOOL_FOLLOW_NORMAL:
var idx := _tools_menu.get_item_index(id)
_tools_menu.set_item_checked(idx, not _tools_menu.is_item_checked(idx))
_grass_selected.sgt_follow_normal = _tools_menu.is_item_checked(idx)
MENU_ID.TOOL_SNAP_TO_TERRAIN:
_plugin.get_undo_redo().create_action(_grass_selected.name + " Snap to terrain")
_plugin.get_undo_redo().add_undo_property(_grass_selected, &"baked_height_map", _grass_selected.baked_height_map)
_plugin.get_undo_redo().add_undo_property(_grass_selected, &"multimesh", _grass_selected.multimesh.duplicate())
_plugin.get_undo_redo().add_undo_property(_grass_selected, &"global_position", _grass_selected.global_position)
_grass_selected.snap_to_terrain()
_plugin.get_undo_redo().add_do_property(_grass_selected, &"baked_height_map", _grass_selected.baked_height_map)
_plugin.get_undo_redo().add_do_property(_grass_selected, &"multimesh", _grass_selected.multimesh)
_plugin.get_undo_redo().add_do_property(_grass_selected, &"global_position", _grass_selected.global_position)
_plugin.get_undo_redo().commit_action()
func _on_sgt_shape_menu_pressed(id: int, tool_name: String, popupmenu: PopupMenu) -> void:
if _grass_selected == null:
return
for i in popupmenu.item_count:
popupmenu.set_item_checked(i, false)
var idx := popupmenu.get_item_index(id)
if idx == -1:
return
popupmenu.set_item_checked(idx, true)
var shape_name := ""
match id:
MENU_SHAPE_ID.TOOL_SHAPE_SPHERE:
shape_name = "sphere"
MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER:
shape_name = "cylinder"
MENU_SHAPE_ID.TOOL_SHAPE_CYLINDER_INF_H:
shape_name = "cylinder_inf_h"
MENU_SHAPE_ID.TOOL_SHAPE_BOX:
shape_name = "box"
MENU_SHAPE_ID.TOOL_SHAPE_BOX_INF_H:
shape_name = "box_inf_h"
_plugin.set_tool_shape(tool_name, shape_name)
func _on_about_to_popup() -> void:
set_current_grass(_grass_selected)
func _on_clear_all_confirmation_dialog_confirmed() -> void:
if _grass_selected == null:
return
_plugin.get_undo_redo().create_action(_grass_selected.name + " Clear All Grass")
_plugin.get_undo_redo().add_undo_property(_grass_selected, &"baked_height_map", _grass_selected.baked_height_map)
_plugin.get_undo_redo().add_undo_property(_grass_selected, &"multimesh", _grass_selected.multimesh)
_grass_selected.clear_all()
_plugin.get_undo_redo().add_do_property(_grass_selected, &"baked_height_map", _grass_selected.baked_height_map)
_plugin.get_undo_redo().add_do_property(_grass_selected, &"multimesh", _grass_selected.multimesh)
_plugin.get_undo_redo().commit_action()
@@ -0,0 +1 @@
uid://bk4wcnwns36qk
@@ -0,0 +1,31 @@
[gd_scene load_steps=2 format=3 uid="uid://der2mmxtog2mt"]
[ext_resource type="Script" uid="uid://bk4wcnwns36qk" path="res://addons/simplegrasstextured/gui/toolbar_menu.gd" id="1_mmgcy"]
[node name="ToolbarMenu" type="MenuButton"]
item_count = 11
popup/item_0/text = "Tools"
popup/item_0/id = 0
popup/item_1/id = -1
popup/item_1/separator = true
popup/item_2/text = "Auto center position"
popup/item_2/id = 1
popup/item_3/text = "Recalculate custom AABB"
popup/item_3/id = 7
popup/item_4/text = "Bake height map"
popup/item_4/checkable = 1
popup/item_4/id = 3
popup/item_5/text = "Cast shadow"
popup/item_5/checkable = 1
popup/item_5/id = 2
popup/item_6/text = "Global parameters"
popup/item_6/id = 4
popup/item_7/id = -1
popup/item_7/separator = true
popup/item_8/text = "Clear all"
popup/item_8/id = 5
popup/item_9/id = -1
popup/item_9/separator = true
popup/item_10/text = "About SimpleGrassTextured"
popup/item_10/id = 6
script = ExtResource("1_mmgcy")
@@ -0,0 +1,33 @@
# toolbar_up.gd
# This file is part of: SimpleGrassTextured
# Copyright (c) 2023 IcterusGames
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@tool
extends Control
func set_plugin(plugin :EditorPlugin) -> void:
$MenuButton.set_plugin(plugin)
func set_current_grass(grass) -> void:
$MenuButton.set_current_grass(grass)
@@ -0,0 +1 @@
uid://cdfq5jjtnlcwg
@@ -0,0 +1,17 @@
[gd_scene load_steps=4 format=3 uid="uid://bfy4swcp2kwpq"]
[ext_resource type="Script" uid="uid://cdfq5jjtnlcwg" path="res://addons/simplegrasstextured/gui/toolbar_up.gd" id="1_h2433"]
[ext_resource type="Texture2D" uid="uid://bsmcpupaj02v8" path="res://addons/simplegrasstextured/sgt_icon.svg" id="3_637xa"]
[ext_resource type="PackedScene" uid="uid://der2mmxtog2mt" path="res://addons/simplegrasstextured/gui/toolbar_menu.tscn" id="3_suvo1"]
[node name="SGTToolbarUp" type="HBoxContainer"]
anchors_preset = 10
anchor_right = 1.0
grow_horizontal = 2
script = ExtResource("1_h2433")
[node name="MenuButton" parent="." instance=ExtResource("3_suvo1")]
layout_mode = 2
text = "SimpleGrassTextured"
icon = ExtResource("3_637xa")
switch_on_hover = true