Compare commits
2 Commits
9fccf98917
...
2a60380258
| Author | SHA1 | Date | |
|---|---|---|---|
| 2a60380258 | |||
| 659c37aa23 |
BIN
asset_src/models/electrics/hologram_projector_floor.blend
Normal file
261
asset_src/models/electrics/hologram_projector_glass.ptex
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
{
|
||||||
|
"connections": [
|
||||||
|
{
|
||||||
|
"from": "colorize",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "Material",
|
||||||
|
"to_port": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": "skewed_uneven_bricks_2",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "make_tileable_square",
|
||||||
|
"to_port": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": "make_tileable_square",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "colorize",
|
||||||
|
"to_port": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": "fbm3",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "make_tileable_square_2",
|
||||||
|
"to_port": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": "make_tileable_square_2",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "math",
|
||||||
|
"to_port": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": "colorize",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "colorize_2",
|
||||||
|
"to_port": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": "colorize_2",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "math",
|
||||||
|
"to_port": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": "math",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "invert",
|
||||||
|
"to_port": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": "invert",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "Material",
|
||||||
|
"to_port": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"label": "Graph",
|
||||||
|
"longdesc": "",
|
||||||
|
"name": "_Node_799",
|
||||||
|
"node_position": {
|
||||||
|
"x": 0.0,
|
||||||
|
"y": 0.0
|
||||||
|
},
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"export_last_target": "Godot/Godot 4 Standard",
|
||||||
|
"export_paths": {
|
||||||
|
"Blender": "D:/Programms/Development/Game-Engines/Godot/Godot 4/Projects/MagicNStuff/asset_src/models/electrics/hologram_projector_glass",
|
||||||
|
"Godot/Godot 4 Standard": "D:/Programms/Development/Game-Engines/Godot/Godot 4/Projects/MagicNStuff/source/src/gameplay/props/electrics/hologram_projector/model/glass"
|
||||||
|
},
|
||||||
|
"name": "Material",
|
||||||
|
"node_position": {
|
||||||
|
"x": 1158.208984375,
|
||||||
|
"y": -289.662231445312
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"albedo_color": {
|
||||||
|
"a": 1.0,
|
||||||
|
"b": 1.0,
|
||||||
|
"g": 1.0,
|
||||||
|
"r": 1.0,
|
||||||
|
"type": "Color"
|
||||||
|
},
|
||||||
|
"ao": 1.0,
|
||||||
|
"depth_scale": 0.5,
|
||||||
|
"emission_energy": 1.0,
|
||||||
|
"flags_transparent": false,
|
||||||
|
"metallic": 1.0,
|
||||||
|
"normal": 1.0,
|
||||||
|
"roughness": 0.7,
|
||||||
|
"size": 8.0,
|
||||||
|
"sss": 1.0
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "material"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "skewed_uneven_bricks_2",
|
||||||
|
"node_position": {
|
||||||
|
"x": -397.5,
|
||||||
|
"y": -289.0
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"bevel": 0.0,
|
||||||
|
"columns": 6.0,
|
||||||
|
"corner": 0.3,
|
||||||
|
"mortar": 0.04,
|
||||||
|
"randomness": 0.0,
|
||||||
|
"round": 0.06,
|
||||||
|
"rows": 6.0
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "skewed_uneven_bricks"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "colorize",
|
||||||
|
"node_position": {
|
||||||
|
"x": 230.500015258789,
|
||||||
|
"y": -271.399993896484
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"gradient": {
|
||||||
|
"interpolation": 1,
|
||||||
|
"points": [
|
||||||
|
{
|
||||||
|
"a": 1.0,
|
||||||
|
"b": 0.30078125,
|
||||||
|
"g": 0.30078125,
|
||||||
|
"pos": 0.0505725190839695,
|
||||||
|
"r": 0.30078125
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a": 1.0,
|
||||||
|
"b": 0.06640625,
|
||||||
|
"g": 0.06640625,
|
||||||
|
"pos": 0.445610687022901,
|
||||||
|
"r": 0.06640625
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Gradient"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "colorize"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fbm3",
|
||||||
|
"node_position": {
|
||||||
|
"x": 68.6030349731445,
|
||||||
|
"y": -5.20602083206177
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"folds": 0.0,
|
||||||
|
"iterations": 5.0,
|
||||||
|
"noise": 1.0,
|
||||||
|
"offset": 0.0,
|
||||||
|
"persistence": 0.5,
|
||||||
|
"scale_x": 16.0,
|
||||||
|
"scale_y": 13.0
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "fbm3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "make_tileable_square",
|
||||||
|
"node_position": {
|
||||||
|
"x": -94.5,
|
||||||
|
"y": -234.0
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"fw": 0.2
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "make_tileable_square"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "math",
|
||||||
|
"node_position": {
|
||||||
|
"x": 639.997985839844,
|
||||||
|
"y": -80.1040115356445
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"clamp": false,
|
||||||
|
"default_in1": 0.0,
|
||||||
|
"default_in2": 0.0,
|
||||||
|
"op": 3.0
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "math"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "make_tileable_square_2",
|
||||||
|
"node_position": {
|
||||||
|
"x": 361.857055664062,
|
||||||
|
"y": 11.725022315979
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"fw": 0.47
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "make_tileable_square"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "colorize_2",
|
||||||
|
"node_position": {
|
||||||
|
"x": 367.584899902344,
|
||||||
|
"y": -176.591888427734
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"gradient": {
|
||||||
|
"interpolation": 0,
|
||||||
|
"points": [
|
||||||
|
{
|
||||||
|
"a": 1.0,
|
||||||
|
"b": 0.48046875,
|
||||||
|
"g": 0.48046875,
|
||||||
|
"pos": 0,
|
||||||
|
"r": 0.48046875
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a": 1.0,
|
||||||
|
"b": 0.48046875,
|
||||||
|
"g": 0.48046875,
|
||||||
|
"pos": 0.173070560815243,
|
||||||
|
"r": 0.48046875
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a": 1.0,
|
||||||
|
"b": 0.13671875,
|
||||||
|
"g": 0.13671875,
|
||||||
|
"pos": 0.173090560815243,
|
||||||
|
"r": 0.13671875
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Gradient"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "colorize"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "invert",
|
||||||
|
"node_position": {
|
||||||
|
"x": 925.055053710938,
|
||||||
|
"y": -112.261871337891
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "invert"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"shortdesc": "",
|
||||||
|
"type": "graph"
|
||||||
|
}
|
||||||
BIN
asset_src/models/electrics/hologram_projector_glass_albedo.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
235
asset_src/models/electrics/hologram_projector_glass_powered.ptex
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
{
|
||||||
|
"connections": [
|
||||||
|
{
|
||||||
|
"from": "skewed_uneven_bricks_2",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "make_tileable_square",
|
||||||
|
"to_port": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": "make_tileable_square",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "colorize",
|
||||||
|
"to_port": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": "colorize",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "greyscale",
|
||||||
|
"to_port": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": "greyscale",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "colorize_2",
|
||||||
|
"to_port": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": "colorize_2",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "Material",
|
||||||
|
"to_port": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": "colorize_2",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "colorize_3",
|
||||||
|
"to_port": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": "colorize_3",
|
||||||
|
"from_port": 0,
|
||||||
|
"to": "Material",
|
||||||
|
"to_port": 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"label": "Graph",
|
||||||
|
"longdesc": "",
|
||||||
|
"name": "_Node_799",
|
||||||
|
"node_position": {
|
||||||
|
"x": 0.0,
|
||||||
|
"y": 0.0
|
||||||
|
},
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"export_last_target": "Godot/Godot 4 Standard",
|
||||||
|
"export_paths": {
|
||||||
|
"Blender": "D:/Programms/Development/Game-Engines/Godot/Godot 4/Projects/MagicNStuff/asset_src/models/electrics/hologram_projector_glass",
|
||||||
|
"Godot/Godot 4 Standard": "D:/Programms/Development/Game-Engines/Godot/Godot 4/Projects/MagicNStuff/source/src/gameplay/props/electrics/hologram_projector/model/glass_active"
|
||||||
|
},
|
||||||
|
"name": "Material",
|
||||||
|
"node_position": {
|
||||||
|
"x": 1588.208984375,
|
||||||
|
"y": -315.662231445312
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"albedo_color": {
|
||||||
|
"a": 1.0,
|
||||||
|
"b": 1.0,
|
||||||
|
"g": 1.0,
|
||||||
|
"r": 1.0,
|
||||||
|
"type": "Color"
|
||||||
|
},
|
||||||
|
"ao": 1.0,
|
||||||
|
"depth_scale": 0.5,
|
||||||
|
"emission_energy": 1.0,
|
||||||
|
"flags_transparent": false,
|
||||||
|
"metallic": 1.0,
|
||||||
|
"normal": 1.0,
|
||||||
|
"roughness": 0.7,
|
||||||
|
"size": 8.0,
|
||||||
|
"sss": 1.0
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "material"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "skewed_uneven_bricks_2",
|
||||||
|
"node_position": {
|
||||||
|
"x": -397.5,
|
||||||
|
"y": -289.0
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"bevel": 0.0,
|
||||||
|
"columns": 6.0,
|
||||||
|
"corner": 0.3,
|
||||||
|
"mortar": 0.04,
|
||||||
|
"randomness": 0.0,
|
||||||
|
"round": 0.06,
|
||||||
|
"rows": 6.0
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "skewed_uneven_bricks"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "colorize",
|
||||||
|
"node_position": {
|
||||||
|
"x": 230.500015258789,
|
||||||
|
"y": -271.399993896484
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"gradient": {
|
||||||
|
"interpolation": 1,
|
||||||
|
"points": [
|
||||||
|
{
|
||||||
|
"a": 1.0,
|
||||||
|
"b": 0.30078125,
|
||||||
|
"g": 0.30078125,
|
||||||
|
"pos": 0.0505725190839695,
|
||||||
|
"r": 0.30078125
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a": 1.0,
|
||||||
|
"b": 0.06640625,
|
||||||
|
"g": 0.06640625,
|
||||||
|
"pos": 0.445610687022901,
|
||||||
|
"r": 0.06640625
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Gradient"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "colorize"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "make_tileable_square",
|
||||||
|
"node_position": {
|
||||||
|
"x": -94.5,
|
||||||
|
"y": -234.0
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"fw": 0.2
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "make_tileable_square"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "greyscale",
|
||||||
|
"node_position": {
|
||||||
|
"x": 787.90380859375,
|
||||||
|
"y": -288.896728515625
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"mode": 2.0
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "greyscale"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "colorize_2",
|
||||||
|
"node_position": {
|
||||||
|
"x": 1020.0,
|
||||||
|
"y": -320.0
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"gradient": {
|
||||||
|
"interpolation": 1,
|
||||||
|
"points": [
|
||||||
|
{
|
||||||
|
"a": 1.0,
|
||||||
|
"b": 1.0,
|
||||||
|
"g": 0.765625,
|
||||||
|
"pos": 0.0,
|
||||||
|
"r": 0.375
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a": 1.0,
|
||||||
|
"b": 0.0,
|
||||||
|
"g": 0.0,
|
||||||
|
"pos": 1.0,
|
||||||
|
"r": 0.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Gradient"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "colorize"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "colorize_3",
|
||||||
|
"node_position": {
|
||||||
|
"x": 1206.23718261719,
|
||||||
|
"y": -251.841186523438
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"gradient": {
|
||||||
|
"interpolation": 0,
|
||||||
|
"points": [
|
||||||
|
{
|
||||||
|
"a": 1.0,
|
||||||
|
"b": 0.0,
|
||||||
|
"g": 0.0,
|
||||||
|
"pos": 0,
|
||||||
|
"r": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a": 1.0,
|
||||||
|
"b": 0.0,
|
||||||
|
"g": 0.0,
|
||||||
|
"pos": 0.611631221374046,
|
||||||
|
"r": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a": 1.0,
|
||||||
|
"b": 1.0,
|
||||||
|
"g": 0.765625,
|
||||||
|
"pos": 0.611651221374046,
|
||||||
|
"r": 0.375
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Gradient"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"type": "colorize"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"seed_int": 0,
|
||||||
|
"shortdesc": "",
|
||||||
|
"type": "graph"
|
||||||
|
}
|
||||||
BIN
asset_src/models/electrics/hologram_projector_glass_rough.exr
Normal file
24
source/addons/StairsCharacter/LICENSE
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
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 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.
|
||||||
|
|
||||||
|
For more information, please refer to <https://unlicense.org>
|
||||||
52
source/addons/StairsCharacter/README.md
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Stairs Character 3D
|
||||||
|
|
||||||
|
A simple class based on Godot's default CharacterBody3D with very simple stair stepping ability.
|
||||||
|
Just call "move_and_stair_step()" instead of "move_and_slide()".
|
||||||
|
|
||||||
|
Only tested with cylinder colliders. Works best with "0.01" collider margin.
|
||||||
|
|
||||||
|
There are a couple signals you can connect to:
|
||||||
|
- on_stair_step (any step, up or down)
|
||||||
|
- on_stair_step_down
|
||||||
|
- on_stair_step_up
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
```gdscript
|
||||||
|
|
||||||
|
extends StairsCharacter3D
|
||||||
|
|
||||||
|
|
||||||
|
const SPEED = 5.0
|
||||||
|
const JUMP_VELOCITY = 4.5
|
||||||
|
|
||||||
|
# Get the gravity from the project settings to be synced with RigidBody nodes.
|
||||||
|
var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity")
|
||||||
|
|
||||||
|
|
||||||
|
func _physics_process(delta: float) -> void:
|
||||||
|
# Add the gravity.
|
||||||
|
if not is_on_floor():
|
||||||
|
velocity.y -= gravity * delta
|
||||||
|
|
||||||
|
# Handle jump.
|
||||||
|
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
|
||||||
|
velocity.y = JUMP_VELOCITY
|
||||||
|
|
||||||
|
# Get the input direction and handle the movement/deceleration.
|
||||||
|
# As good practice, you should replace UI actions with custom gameplay actions.
|
||||||
|
var input_dir := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
|
||||||
|
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
|
||||||
|
if direction:
|
||||||
|
velocity.x = direction.x * SPEED
|
||||||
|
velocity.z = direction.z * SPEED
|
||||||
|
else:
|
||||||
|
velocity.x = move_toward(velocity.x, 0, SPEED)
|
||||||
|
velocity.z = move_toward(velocity.z, 0, SPEED)
|
||||||
|
|
||||||
|
# call move_and_stair_step instead of default move_and_slide
|
||||||
|
move_and_stair_step()
|
||||||
|
```
|
||||||
|
|
||||||
|
# Note
|
||||||
|
This plugin is basically just [Andricraft's GDScript Stairs Character](https://github.com/Andicraft/stairs-character) translated into C++.
|
||||||
|
I made it as a learning exercise for GDExtension.
|
||||||
22
source/addons/StairsCharacter/StairsCharacter.gdextension
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
[configuration]
|
||||||
|
|
||||||
|
entry_symbol = "gdextension_init"
|
||||||
|
compatibility_minimum = 4.3
|
||||||
|
|
||||||
|
[libraries]
|
||||||
|
|
||||||
|
linux.debug.x86_64 = "bin/libStairsCharacter.linux.debug.x86_64.so"
|
||||||
|
linux.release.x86_64 = "bin/libStairsCharacter.linux.release.x86_64.so"
|
||||||
|
linux.debug.arm64 = "bin/libStairsCharacter.linux.debug.arm64.so"
|
||||||
|
linux.release.arm64 = "bin/libStairsCharacter.linux.release.arm64.so"
|
||||||
|
linux.debug.rv64 = "bin/libStairsCharacter.linux.debug.rv64.so"
|
||||||
|
linux.release.rv64 = "bin/libStairsCharacter.linux.release.rv64.so"
|
||||||
|
windows.debug.x86_64 = "bin/libStairsCharacter.windows.debug.x86_64.dll"
|
||||||
|
windows.release.x86_64 = "bin/libStairsCharacter.windows.release.x86_64.dll"
|
||||||
|
macos.debug = "bin/libStairsCharacter.macos.debug.framework"
|
||||||
|
macos.release = "bin/libStairsCharacter.macos.release.framework"
|
||||||
|
android.debug.arm64 = "bin/libStairsCharacter.android.debug.arm64.so"
|
||||||
|
android.release.arm64 = "bin/libStairsCharacter.android.release.arm64.so"
|
||||||
|
|
||||||
|
[icons]
|
||||||
|
StairsCharacter3D = "stairs_character.svg"
|
||||||
@ -0,0 +1 @@
|
|||||||
|
uid://tkege8xp3mnb
|
||||||
1
source/addons/StairsCharacter/stairs_character.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="32" width="32" version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" xml:space="preserve"><style type="text/css">.st0{fill:#cd5c5c;}</style><g stroke-opacity="1" fill-opacity="1"><path class="st0" d="M315.664 0 193.969 32.069v98.468l-86.38 20.729v98.477l-86.381 20.73v117.37L196.337 512l6.388-1.532 288.068-71.995V124.166L315.664 0zM188.487 470.942 50.17 372.883v-68.175l138.317 98.799V470.942zM201.627 386.197 66.192 289.462l58.411-14.02 135.436 96.746L201.627 386.197zM274.868 356.078l-138.317-98.799v-71.778l138.317 98.8V356.078zM288.008 266.992l-135.436-96.746 58.402-14.01 135.446 96.754L288.008 266.992zM361.248 236.881l-138.317-98.8V66.296l138.317 98.808V236.881zM374.388 147.803 238.943 51.057l70.699-19.833 136.193 96.572L374.388 147.803z" fill="black" opacity="1" fill-opacity="1"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 886 B |
43
source/addons/StairsCharacter/stairs_character.svg.import
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://f8rpbcuiicd7"
|
||||||
|
path="res://.godot/imported/stairs_character.svg-a9660f3f5b9588e29c90e9a9aaadbbda.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/StairsCharacter/stairs_character.svg"
|
||||||
|
dest_files=["res://.godot/imported/stairs_character.svg-a9660f3f5b9588e29c90e9a9aaadbbda.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
||||||
17
source/addons/Todo_Manager/ColourPicker.gd
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
@tool
|
||||||
|
extends HBoxContainer
|
||||||
|
|
||||||
|
var colour : Color
|
||||||
|
var title : String:
|
||||||
|
set = set_title
|
||||||
|
var index : int
|
||||||
|
|
||||||
|
@onready var colour_picker := $TODOColourPickerButton
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
$TODOColourPickerButton.color = colour
|
||||||
|
$Label.text = title
|
||||||
|
|
||||||
|
func set_title(value: String) -> void:
|
||||||
|
title = value
|
||||||
|
$Label.text = value
|
||||||
1
source/addons/Todo_Manager/ColourPicker.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://dd033y6smf6jh
|
||||||
44
source/addons/Todo_Manager/Current.gd
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
@tool
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
signal tree_built # used for debugging
|
||||||
|
|
||||||
|
const Todo := preload("res://addons/Todo_Manager/todo_class.gd")
|
||||||
|
const TodoItem := preload("res://addons/Todo_Manager/todoItem_class.gd")
|
||||||
|
|
||||||
|
var _sort_alphabetical := true
|
||||||
|
|
||||||
|
@onready var tree := $Panel/Tree as Tree
|
||||||
|
|
||||||
|
func build_tree(todo_item : TodoItem, patterns : Array, cased_patterns : Array[String]) -> void:
|
||||||
|
tree.clear()
|
||||||
|
var root := tree.create_item()
|
||||||
|
root.set_text(0, "Scripts")
|
||||||
|
var script := tree.create_item(root)
|
||||||
|
script.set_text(0, todo_item.get_short_path() + " -------")
|
||||||
|
script.set_metadata(0, todo_item)
|
||||||
|
for todo in todo_item.todos:
|
||||||
|
var item := tree.create_item(script)
|
||||||
|
var content_header : String = todo.content
|
||||||
|
if "\n" in todo.content:
|
||||||
|
content_header = content_header.split("\n")[0] + "..."
|
||||||
|
item.set_text(0, "(%0) - %1".format([todo.line_number, content_header], "%_"))
|
||||||
|
item.set_tooltip_text(0, todo.content)
|
||||||
|
item.set_metadata(0, todo)
|
||||||
|
for i in range(0, len(cased_patterns)):
|
||||||
|
if cased_patterns[i] == todo.pattern:
|
||||||
|
item.set_custom_color(0, patterns[i][1])
|
||||||
|
emit_signal("tree_built")
|
||||||
|
|
||||||
|
|
||||||
|
func sort_alphabetical(a, b) -> bool:
|
||||||
|
if a.script_path > b.script_path:
|
||||||
|
return true
|
||||||
|
else:
|
||||||
|
return false
|
||||||
|
|
||||||
|
func sort_backwards(a, b) -> bool:
|
||||||
|
if a.script_path < b.script_path:
|
||||||
|
return true
|
||||||
|
else:
|
||||||
|
return false
|
||||||
1
source/addons/Todo_Manager/Current.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://dp4hevwsquax6
|
||||||
336
source/addons/Todo_Manager/Dock.gd
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
@tool
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
#signal tree_built # used for debugging
|
||||||
|
enum { CASE_INSENSITIVE, CASE_SENSITIVE }
|
||||||
|
|
||||||
|
const Project := preload("res://addons/Todo_Manager/Project.gd")
|
||||||
|
const Current := preload("res://addons/Todo_Manager/Current.gd")
|
||||||
|
|
||||||
|
const Todo := preload("res://addons/Todo_Manager/todo_class.gd")
|
||||||
|
const TodoItem := preload("res://addons/Todo_Manager/todoItem_class.gd")
|
||||||
|
const ColourPicker := preload("res://addons/Todo_Manager/UI/ColourPicker.tscn")
|
||||||
|
const PatternEdit := preload("res://addons/Todo_Manager/PatternEdit.gd")
|
||||||
|
const PatternEditScene := preload("res://addons/Todo_Manager/UI/PatternEdit.tscn")
|
||||||
|
const ToggleButton := preload("res://addons/Todo_Manager/UI/ToggleButton.tscn")
|
||||||
|
|
||||||
|
# Pattern array format - [regex, colour, case_sensitivity, enabled]
|
||||||
|
const DEFAULT_PATTERNS := [["\\bTODO\\b", Color("96f1ad"), CASE_INSENSITIVE, true], ["\\bHACK\\b", Color("d5bc70"), CASE_INSENSITIVE, true], ["\\bFIXME\\b", Color("d57070"), CASE_INSENSITIVE, true]]
|
||||||
|
const DEFAULT_SCRIPT_COLOUR := Color("ccced3")
|
||||||
|
const DEFAULT_SCRIPT_NAME := false
|
||||||
|
const DEFAULT_SORT := true
|
||||||
|
|
||||||
|
var plugin : EditorPlugin
|
||||||
|
|
||||||
|
var todo_items : Array
|
||||||
|
|
||||||
|
var script_colour := Color("ccced3")
|
||||||
|
var ignore_paths : Array[String] = []
|
||||||
|
var full_path := false
|
||||||
|
var auto_refresh := true
|
||||||
|
var builtin_enabled := false
|
||||||
|
var _sort_alphabetical := true
|
||||||
|
|
||||||
|
var patterns := [["\\bTODO\\b", Color("96f1ad"), CASE_INSENSITIVE, true], ["\\bHACK\\b", Color("d5bc70"), CASE_INSENSITIVE, true], ["\\bFIXME\\b", Color("d57070"), CASE_INSENSITIVE, true]]
|
||||||
|
|
||||||
|
@onready var tabs := $VBoxContainer/TabContainer as TabContainer
|
||||||
|
@onready var project := $VBoxContainer/TabContainer/Project as Project
|
||||||
|
@onready var current := $VBoxContainer/TabContainer/Current as Current
|
||||||
|
@onready var project_tree := $VBoxContainer/TabContainer/Project/Panel/Tree as Tree
|
||||||
|
@onready var project_toggles_container := $VBoxContainer/TabContainer/Project/TogglesScrollContainer/VBoxContainer as VBoxContainer
|
||||||
|
@onready var current_tree := $VBoxContainer/TabContainer/Current/Panel/Tree as Tree
|
||||||
|
@onready var current_toggles_container := $VBoxContainer/TabContainer/Current/TogglesScrollContainer/VBoxContainer as VBoxContainer
|
||||||
|
@onready var settings_panel := $VBoxContainer/TabContainer/Settings as Panel
|
||||||
|
@onready var colours_container := $VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer3/Colours as VBoxContainer
|
||||||
|
@onready var pattern_container := $VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer4/Patterns as VBoxContainer
|
||||||
|
@onready var ignore_textbox := $VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/IgnorePaths/TextEdit as LineEdit
|
||||||
|
@onready var auto_refresh_button := $VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns/RefreshCheckButton as CheckButton
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
load_config()
|
||||||
|
populate_settings()
|
||||||
|
|
||||||
|
|
||||||
|
func build_tree() -> void:
|
||||||
|
if tabs:
|
||||||
|
add_toggle_buttons()
|
||||||
|
var filtered_patterns = patterns.filter(func (p): return p[3] == true)
|
||||||
|
match tabs.current_tab:
|
||||||
|
0:
|
||||||
|
project.build_tree(todo_items, ignore_paths, filtered_patterns, plugin.cased_patterns, _sort_alphabetical, full_path)
|
||||||
|
create_config_file()
|
||||||
|
1:
|
||||||
|
current.build_tree(get_active_script(), filtered_patterns, plugin.cased_patterns)
|
||||||
|
create_config_file()
|
||||||
|
2:
|
||||||
|
pass
|
||||||
|
_:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
func get_active_script() -> TodoItem:
|
||||||
|
var current_script : Script = plugin.get_editor_interface().get_script_editor().get_current_script()
|
||||||
|
if current_script:
|
||||||
|
var script_path = current_script.resource_path
|
||||||
|
for todo_item in todo_items:
|
||||||
|
if todo_item.script_path == script_path:
|
||||||
|
return todo_item
|
||||||
|
|
||||||
|
# nothing found
|
||||||
|
var todo_item := TodoItem.new(script_path, [])
|
||||||
|
return todo_item
|
||||||
|
else:
|
||||||
|
# not a script
|
||||||
|
var todo_item := TodoItem.new("res://Documentation", [])
|
||||||
|
return todo_item
|
||||||
|
|
||||||
|
|
||||||
|
func go_to_script(script_path: String, line_number : int = 0) -> void:
|
||||||
|
if plugin.get_editor_interface().get_editor_settings().get_setting("text_editor/external/use_external_editor"):
|
||||||
|
var exec_path = plugin.get_editor_interface().get_editor_settings().get_setting("text_editor/external/exec_path")
|
||||||
|
var args := get_exec_flags(exec_path, script_path, line_number)
|
||||||
|
OS.execute(exec_path, args)
|
||||||
|
else:
|
||||||
|
var script := load(script_path)
|
||||||
|
plugin.get_editor_interface().edit_resource(script)
|
||||||
|
plugin.get_editor_interface().get_script_editor().goto_line(line_number - 1)
|
||||||
|
|
||||||
|
|
||||||
|
func get_exec_flags(editor_path : String, script_path : String, line_number : int) -> PackedStringArray:
|
||||||
|
var args : PackedStringArray
|
||||||
|
var script_global_path = ProjectSettings.globalize_path(script_path)
|
||||||
|
|
||||||
|
if editor_path.ends_with("code.cmd") or editor_path.ends_with("code"): ## VS Code
|
||||||
|
args.append(ProjectSettings.globalize_path("res://"))
|
||||||
|
args.append("--goto")
|
||||||
|
args.append(script_global_path + ":" + str(line_number))
|
||||||
|
|
||||||
|
elif editor_path.ends_with("rider64.exe") or editor_path.ends_with("rider"): ## Rider
|
||||||
|
args.append("--line")
|
||||||
|
args.append(str(line_number))
|
||||||
|
args.append(script_global_path)
|
||||||
|
|
||||||
|
else: ## Atom / Sublime
|
||||||
|
args.append(script_global_path + ":" + str(line_number))
|
||||||
|
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
func sort_alphabetical(a, b) -> bool:
|
||||||
|
if a.script_path > b.script_path:
|
||||||
|
return true
|
||||||
|
else:
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func sort_backwards(a, b) -> bool:
|
||||||
|
if a.script_path < b.script_path:
|
||||||
|
return true
|
||||||
|
else:
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func populate_settings() -> void:
|
||||||
|
for i in patterns.size():
|
||||||
|
## Create Colour Pickers
|
||||||
|
var colour_picker: Node = ColourPicker.instantiate()
|
||||||
|
colour_picker.colour = patterns[i][1]
|
||||||
|
colour_picker.title = patterns[i][0]
|
||||||
|
colour_picker.index = i
|
||||||
|
colours_container.add_child(colour_picker)
|
||||||
|
colour_picker.colour_picker.color_changed.connect(change_colour.bind(i))
|
||||||
|
|
||||||
|
## Create Patterns
|
||||||
|
var pattern_edit: PatternEdit = PatternEditScene.instantiate()
|
||||||
|
pattern_edit.text = patterns[i][0]
|
||||||
|
pattern_edit.index = i
|
||||||
|
pattern_container.add_child(pattern_edit)
|
||||||
|
pattern_edit.line_edit.text_changed.connect(change_pattern.bind(i,
|
||||||
|
colour_picker))
|
||||||
|
pattern_edit.remove_button.pressed.connect(remove_pattern.bind(i,
|
||||||
|
pattern_edit, colour_picker))
|
||||||
|
pattern_edit.case_checkbox.button_pressed = patterns[i][2]
|
||||||
|
pattern_edit.case_checkbox.toggled.connect(case_sensitive_pattern.bind(i))
|
||||||
|
|
||||||
|
var pattern_button := $VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer4/Patterns/AddPatternButton
|
||||||
|
$VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer4/Patterns.move_child(pattern_button, 0)
|
||||||
|
|
||||||
|
# path filtering
|
||||||
|
var ignore_paths_field := ignore_textbox
|
||||||
|
if not ignore_paths_field.is_connected("text_changed", _on_ignore_paths_changed):
|
||||||
|
ignore_paths_field.connect("text_changed", _on_ignore_paths_changed)
|
||||||
|
var ignore_paths_text := ""
|
||||||
|
for path in ignore_paths:
|
||||||
|
ignore_paths_text += path + ", "
|
||||||
|
ignore_paths_text = ignore_paths_text.trim_suffix(", ")
|
||||||
|
ignore_paths_field.text = ignore_paths_text
|
||||||
|
|
||||||
|
auto_refresh_button.button_pressed = auto_refresh
|
||||||
|
|
||||||
|
|
||||||
|
func rebuild_settings() -> void:
|
||||||
|
for node in colours_container.get_children():
|
||||||
|
node.queue_free()
|
||||||
|
for node in pattern_container.get_children():
|
||||||
|
if node is Button:
|
||||||
|
continue
|
||||||
|
node.queue_free()
|
||||||
|
populate_settings()
|
||||||
|
|
||||||
|
|
||||||
|
func add_toggle_buttons() -> void:
|
||||||
|
for toggle in project_toggles_container.get_children():
|
||||||
|
toggle.queue_free()
|
||||||
|
for toggle in current_toggles_container.get_children():
|
||||||
|
toggle.queue_free()
|
||||||
|
for pattern in patterns:
|
||||||
|
var toggle : Button = ToggleButton.instantiate()
|
||||||
|
toggle.text = pattern[0].replace('\\b', '')
|
||||||
|
toggle.button_pressed = pattern[3]
|
||||||
|
toggle.connect("toggled", toggle_pattern_enabled.bind(pattern))
|
||||||
|
if tabs.current_tab == 0:
|
||||||
|
project_toggles_container.add_child(toggle)
|
||||||
|
elif tabs.current_tab == 1:
|
||||||
|
current_toggles_container.add_child(toggle)
|
||||||
|
|
||||||
|
#### CONFIG FILE ####
|
||||||
|
func create_config_file() -> void:
|
||||||
|
var config = ConfigFile.new()
|
||||||
|
|
||||||
|
config.set_value("scripts", "full_path", full_path)
|
||||||
|
config.set_value("scripts", "sort_alphabetical", _sort_alphabetical)
|
||||||
|
config.set_value("scripts", "script_colour", script_colour)
|
||||||
|
config.set_value("scripts", "ignore_paths", ignore_paths)
|
||||||
|
|
||||||
|
config.set_value("patterns", "patterns", patterns)
|
||||||
|
|
||||||
|
config.set_value("config", "auto_refresh", auto_refresh)
|
||||||
|
config.set_value("config", "builtin_enabled", builtin_enabled)
|
||||||
|
|
||||||
|
var err = config.save("res://addons/Todo_Manager/todo.cfg")
|
||||||
|
|
||||||
|
|
||||||
|
func load_config() -> void:
|
||||||
|
var config := ConfigFile.new()
|
||||||
|
if config.load("res://addons/Todo_Manager/todo.cfg") == OK:
|
||||||
|
full_path = config.get_value("scripts", "full_path", DEFAULT_SCRIPT_NAME)
|
||||||
|
_sort_alphabetical = config.get_value("scripts", "sort_alphabetical", DEFAULT_SORT)
|
||||||
|
script_colour = config.get_value("scripts", "script_colour", DEFAULT_SCRIPT_COLOUR)
|
||||||
|
ignore_paths = config.get_value("scripts", "ignore_paths", [] as Array[String])
|
||||||
|
patterns = config.get_value("patterns", "patterns", DEFAULT_PATTERNS)
|
||||||
|
fix_missing_values(patterns)
|
||||||
|
auto_refresh = config.get_value("config", "auto_refresh", true)
|
||||||
|
builtin_enabled = config.get_value("config", "builtin_enabled", false)
|
||||||
|
else:
|
||||||
|
create_config_file()
|
||||||
|
|
||||||
|
|
||||||
|
func fix_missing_values(patterns: Array) -> void:
|
||||||
|
for pattern in patterns:
|
||||||
|
if pattern.size() == 2:
|
||||||
|
pattern.append(CASE_INSENSITIVE)
|
||||||
|
if pattern.size() == 3:
|
||||||
|
pattern.append(true)
|
||||||
|
|
||||||
|
|
||||||
|
#### Events ####
|
||||||
|
func _on_SettingsButton_toggled(button_pressed: bool) -> void:
|
||||||
|
settings_panel.visible = button_pressed
|
||||||
|
if button_pressed == false:
|
||||||
|
create_config_file()
|
||||||
|
# plugin.find_tokens_from_path(plugin.script_cache)
|
||||||
|
if auto_refresh:
|
||||||
|
plugin.rescan_files(true)
|
||||||
|
|
||||||
|
func _on_Tree_item_activated() -> void:
|
||||||
|
var item : TreeItem
|
||||||
|
match tabs.current_tab:
|
||||||
|
0:
|
||||||
|
item = project_tree.get_selected()
|
||||||
|
1:
|
||||||
|
item = current_tree.get_selected()
|
||||||
|
if item.get_metadata(0) is Todo:
|
||||||
|
var todo : Todo = item.get_metadata(0)
|
||||||
|
call_deferred("go_to_script", todo.script_path, todo.line_number)
|
||||||
|
else:
|
||||||
|
var todo_item = item.get_metadata(0)
|
||||||
|
call_deferred("go_to_script", todo_item.script_path)
|
||||||
|
|
||||||
|
func _on_FullPathCheckBox_toggled(button_pressed: bool) -> void:
|
||||||
|
full_path = button_pressed
|
||||||
|
|
||||||
|
func _on_ScriptColourPickerButton_color_changed(color: Color) -> void:
|
||||||
|
script_colour = color
|
||||||
|
|
||||||
|
func _on_RescanButton_pressed() -> void:
|
||||||
|
plugin.rescan_files(true)
|
||||||
|
|
||||||
|
func change_colour(colour: Color, index: int) -> void:
|
||||||
|
patterns[index][1] = colour
|
||||||
|
|
||||||
|
func change_pattern(value: String, index: int, this_colour: Node) -> void:
|
||||||
|
patterns[index][0] = value
|
||||||
|
this_colour.title = value
|
||||||
|
plugin.rescan_files(true)
|
||||||
|
|
||||||
|
func remove_pattern(index: int, this: Node, this_colour: Node) -> void:
|
||||||
|
patterns.remove_at(index)
|
||||||
|
this.queue_free()
|
||||||
|
this_colour.queue_free()
|
||||||
|
plugin.rescan_files(true)
|
||||||
|
|
||||||
|
func toggle_pattern_enabled(active: bool, pattern: Array) -> void:
|
||||||
|
pattern[3] = active
|
||||||
|
plugin.rescan_files(true)
|
||||||
|
|
||||||
|
func case_sensitive_pattern(active: bool, index: int) -> void:
|
||||||
|
if active:
|
||||||
|
patterns[index][2] = CASE_SENSITIVE
|
||||||
|
else:
|
||||||
|
patterns[index][2] = CASE_INSENSITIVE
|
||||||
|
plugin.rescan_files(true)
|
||||||
|
|
||||||
|
func _on_DefaultButton_pressed() -> void:
|
||||||
|
patterns = DEFAULT_PATTERNS.duplicate(true)
|
||||||
|
_sort_alphabetical = DEFAULT_SORT
|
||||||
|
script_colour = DEFAULT_SCRIPT_COLOUR
|
||||||
|
full_path = DEFAULT_SCRIPT_NAME
|
||||||
|
rebuild_settings()
|
||||||
|
plugin.rescan_files(true)
|
||||||
|
|
||||||
|
func _on_AlphSortCheckBox_toggled(button_pressed: bool) -> void:
|
||||||
|
_sort_alphabetical = button_pressed
|
||||||
|
plugin.rescan_files(true)
|
||||||
|
|
||||||
|
func _on_AddPatternButton_pressed() -> void:
|
||||||
|
patterns.append(["\\bplaceholder\\b", Color.WHITE, CASE_INSENSITIVE, true])
|
||||||
|
rebuild_settings()
|
||||||
|
|
||||||
|
func _on_RefreshCheckButton_toggled(button_pressed: bool) -> void:
|
||||||
|
auto_refresh = button_pressed
|
||||||
|
|
||||||
|
func _on_Timer_timeout() -> void:
|
||||||
|
plugin.refresh_lock = false
|
||||||
|
|
||||||
|
func _on_ignore_paths_changed(new_text: String) -> void:
|
||||||
|
var text = ignore_textbox.text
|
||||||
|
var split: Array = text.split(',')
|
||||||
|
ignore_paths.clear()
|
||||||
|
for elem in split:
|
||||||
|
if elem == " " || elem == "":
|
||||||
|
continue
|
||||||
|
ignore_paths.push_front(elem.lstrip(' ').rstrip(' '))
|
||||||
|
# validate so no empty string slips through (all paths ignored)
|
||||||
|
var i := 0
|
||||||
|
for path in ignore_paths:
|
||||||
|
if (path == "" || path == " "):
|
||||||
|
ignore_paths.remove_at(i)
|
||||||
|
i += 1
|
||||||
|
plugin.rescan_files(true)
|
||||||
|
|
||||||
|
func _on_TabContainer_tab_changed(tab: int) -> void:
|
||||||
|
build_tree()
|
||||||
|
|
||||||
|
func _on_BuiltInCheckButton_toggled(button_pressed: bool) -> void:
|
||||||
|
builtin_enabled = button_pressed
|
||||||
|
plugin.rescan_files(true)
|
||||||
1
source/addons/Todo_Manager/Dock.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://csgl0vtsudgxh
|
||||||
21
source/addons/Todo_Manager/PatternEdit.gd
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
@tool
|
||||||
|
extends HBoxContainer
|
||||||
|
|
||||||
|
|
||||||
|
var text : String : set = set_text
|
||||||
|
var disabled : bool
|
||||||
|
var index : int
|
||||||
|
|
||||||
|
@onready var line_edit := $LineEdit as LineEdit
|
||||||
|
@onready var remove_button := $RemoveButton as Button
|
||||||
|
@onready var case_checkbox := %CaseSensativeCheckbox as CheckBox
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
line_edit.text = text
|
||||||
|
remove_button.disabled = disabled
|
||||||
|
|
||||||
|
|
||||||
|
func set_text(value: String) -> void:
|
||||||
|
text = value
|
||||||
|
if line_edit:
|
||||||
|
line_edit.text = value
|
||||||
1
source/addons/Todo_Manager/PatternEdit.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://betg01sk02eyy
|
||||||
73
source/addons/Todo_Manager/Project.gd
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
@tool
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
signal tree_built # used for debugging
|
||||||
|
|
||||||
|
const Todo := preload("res://addons/Todo_Manager/todo_class.gd")
|
||||||
|
|
||||||
|
var _sort_alphabetical := true
|
||||||
|
var _full_path := false
|
||||||
|
|
||||||
|
@onready var tree := $Panel/Tree as Tree
|
||||||
|
|
||||||
|
func build_tree(todo_items : Array, ignore_paths : Array, patterns : Array, cased_patterns: Array[String], sort_alphabetical : bool, full_path : bool) -> void:
|
||||||
|
_full_path = full_path
|
||||||
|
tree.clear()
|
||||||
|
if sort_alphabetical:
|
||||||
|
todo_items.sort_custom(Callable(self, "sort_alphabetical"))
|
||||||
|
else:
|
||||||
|
todo_items.sort_custom(Callable(self, "sort_backwards"))
|
||||||
|
var root := tree.create_item()
|
||||||
|
root.set_text(0, "Scripts")
|
||||||
|
for todo_item in todo_items:
|
||||||
|
var ignore := false
|
||||||
|
for ignore_path in ignore_paths:
|
||||||
|
var script_path : String = todo_item.script_path
|
||||||
|
if script_path.begins_with(ignore_path) or script_path.begins_with("res://" + ignore_path) or script_path.begins_with("res:///" + ignore_path):
|
||||||
|
ignore = true
|
||||||
|
break
|
||||||
|
if ignore:
|
||||||
|
continue
|
||||||
|
var script := tree.create_item(root)
|
||||||
|
if full_path:
|
||||||
|
script.set_text(0, todo_item.script_path + " -------")
|
||||||
|
else:
|
||||||
|
script.set_text(0, todo_item.get_short_path() + " -------")
|
||||||
|
script.set_metadata(0, todo_item)
|
||||||
|
for todo in todo_item.todos:
|
||||||
|
var item := tree.create_item(script)
|
||||||
|
var content_header : String = todo.content
|
||||||
|
if "\n" in todo.content:
|
||||||
|
content_header = content_header.split("\n")[0] + "..."
|
||||||
|
item.set_text(0, "(%0) - %1".format([todo.line_number, content_header], "%_"))
|
||||||
|
item.set_tooltip_text(0, todo.content)
|
||||||
|
item.set_metadata(0, todo)
|
||||||
|
for i in range(0, len(cased_patterns)):
|
||||||
|
if cased_patterns[i] == todo.pattern:
|
||||||
|
item.set_custom_color(0, patterns[i][1])
|
||||||
|
emit_signal("tree_built")
|
||||||
|
|
||||||
|
|
||||||
|
func sort_alphabetical(a, b) -> bool:
|
||||||
|
if _full_path:
|
||||||
|
if a.script_path < b.script_path:
|
||||||
|
return true
|
||||||
|
else:
|
||||||
|
return false
|
||||||
|
else:
|
||||||
|
if a.get_short_path() < b.get_short_path():
|
||||||
|
return true
|
||||||
|
else:
|
||||||
|
return false
|
||||||
|
|
||||||
|
func sort_backwards(a, b) -> bool:
|
||||||
|
if _full_path:
|
||||||
|
if a.script_path > b.script_path:
|
||||||
|
return true
|
||||||
|
else:
|
||||||
|
return false
|
||||||
|
else:
|
||||||
|
if a.get_short_path() > b.get_short_path():
|
||||||
|
return true
|
||||||
|
else:
|
||||||
|
return false
|
||||||
1
source/addons/Todo_Manager/Project.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://bnyawhvwojm5g
|
||||||
4
source/addons/Todo_Manager/Test.gd
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
class_name Test extends RefCounted
|
||||||
|
|
||||||
|
var a: String
|
||||||
|
var b: bool
|
||||||
1
source/addons/Todo_Manager/Test.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://den1uk6816qrb
|
||||||
17
source/addons/Todo_Manager/UI/ColourPicker.tscn
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://bie1xn8v1kd66"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dd033y6smf6jh" path="res://addons/Todo_Manager/ColourPicker.gd" id="1"]
|
||||||
|
|
||||||
|
[node name="TODOColour" type="HBoxContainer"]
|
||||||
|
offset_right = 105.0
|
||||||
|
offset_bottom = 31.0
|
||||||
|
script = ExtResource("1")
|
||||||
|
metadata/_edit_use_custom_anchors = false
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="TODOColourPickerButton" type="ColorPickerButton" parent="."]
|
||||||
|
custom_minimum_size = Vector2(40, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 10
|
||||||
365
source/addons/Todo_Manager/UI/Dock.tscn
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
[gd_scene load_steps=6 format=3 uid="uid://b6k0dtftankcx"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://csgl0vtsudgxh" path="res://addons/Todo_Manager/Dock.gd" id="1"]
|
||||||
|
[ext_resource type="Script" uid="uid://bnyawhvwojm5g" path="res://addons/Todo_Manager/Project.gd" id="2"]
|
||||||
|
[ext_resource type="Script" uid="uid://dp4hevwsquax6" path="res://addons/Todo_Manager/Current.gd" id="3"]
|
||||||
|
|
||||||
|
[sub_resource type="ButtonGroup" id="ButtonGroup_kqxcu"]
|
||||||
|
|
||||||
|
[sub_resource type="ButtonGroup" id="ButtonGroup_kltg3"]
|
||||||
|
|
||||||
|
[node name="Dock" type="Control"]
|
||||||
|
custom_minimum_size = Vector2(0, 200)
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
script = ExtResource("1")
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_top = 4.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
metadata/_edit_layout_mode = 1
|
||||||
|
|
||||||
|
[node name="Header" type="HBoxContainer" parent="VBoxContainer"]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="HeaderLeft" type="HBoxContainer" parent="VBoxContainer/Header"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="Title" type="Label" parent="VBoxContainer/Header/HeaderLeft"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Todo Dock:"
|
||||||
|
|
||||||
|
[node name="HeaderRight" type="HBoxContainer" parent="VBoxContainer/Header"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
alignment = 2
|
||||||
|
|
||||||
|
[node name="SettingsButton" type="Button" parent="VBoxContainer/Header/HeaderRight"]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 2
|
||||||
|
toggle_mode = true
|
||||||
|
text = "Settings"
|
||||||
|
|
||||||
|
[node name="TabContainer" type="TabContainer" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
current_tab = 0
|
||||||
|
|
||||||
|
[node name="Project" type="Control" parent="VBoxContainer/TabContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
script = ExtResource("2")
|
||||||
|
metadata/_tab_index = 0
|
||||||
|
|
||||||
|
[node name="Panel" type="Panel" parent="VBoxContainer/TabContainer/Project"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_right = -106.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="Tree" type="Tree" parent="VBoxContainer/TabContainer/Project/Panel"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
hide_root = true
|
||||||
|
|
||||||
|
[node name="TogglesScrollContainer" type="ScrollContainer" parent="VBoxContainer/TabContainer/Project"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 11
|
||||||
|
anchor_left = 1.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = -102.0
|
||||||
|
grow_horizontal = 0
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/TabContainer/Project/TogglesScrollContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
theme_override_constants/separation = 6
|
||||||
|
|
||||||
|
[node name="Current" type="Control" parent="VBoxContainer/TabContainer"]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
script = ExtResource("3")
|
||||||
|
metadata/_tab_index = 1
|
||||||
|
|
||||||
|
[node name="Panel" type="Panel" parent="VBoxContainer/TabContainer/Current"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_right = -106.0
|
||||||
|
|
||||||
|
[node name="Tree" type="Tree" parent="VBoxContainer/TabContainer/Current/Panel"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
hide_folding = true
|
||||||
|
hide_root = true
|
||||||
|
|
||||||
|
[node name="TogglesScrollContainer" type="ScrollContainer" parent="VBoxContainer/TabContainer/Current"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 11
|
||||||
|
anchor_left = 1.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = -102.0
|
||||||
|
grow_horizontal = 0
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/TabContainer/Current/TogglesScrollContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
theme_override_constants/separation = 6
|
||||||
|
|
||||||
|
[node name="Settings" type="Panel" parent="VBoxContainer/TabContainer"]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 2
|
||||||
|
metadata/_tab_index = 2
|
||||||
|
|
||||||
|
[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer/TabContainer/Settings"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="Scripts" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/Scripts"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Scripts:"
|
||||||
|
|
||||||
|
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/Scripts"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 5
|
||||||
|
|
||||||
|
[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="VSeparator" type="VSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Scripts" type="VBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="ScriptName" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptName"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Script Name:"
|
||||||
|
|
||||||
|
[node name="FullPathCheckBox" type="CheckBox" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptName"]
|
||||||
|
layout_mode = 2
|
||||||
|
button_group = SubResource("ButtonGroup_kqxcu")
|
||||||
|
text = "Full path"
|
||||||
|
|
||||||
|
[node name="ShortNameCheckBox" type="CheckBox" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptName"]
|
||||||
|
layout_mode = 2
|
||||||
|
button_pressed = true
|
||||||
|
button_group = SubResource("ButtonGroup_kqxcu")
|
||||||
|
text = "Short name"
|
||||||
|
|
||||||
|
[node name="ScriptSort" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptSort"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Sort Order:"
|
||||||
|
|
||||||
|
[node name="AlphSortCheckBox" type="CheckBox" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptSort"]
|
||||||
|
layout_mode = 2
|
||||||
|
button_pressed = true
|
||||||
|
button_group = SubResource("ButtonGroup_kltg3")
|
||||||
|
text = "Alphabetical"
|
||||||
|
|
||||||
|
[node name="RAlphSortCheckBox" type="CheckBox" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptSort"]
|
||||||
|
layout_mode = 2
|
||||||
|
button_group = SubResource("ButtonGroup_kltg3")
|
||||||
|
text = "Reverse Alphabetical"
|
||||||
|
|
||||||
|
[node name="ScriptColour" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptColour"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Script Colour:"
|
||||||
|
|
||||||
|
[node name="ScriptColourPickerButton" type="ColorPickerButton" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptColour"]
|
||||||
|
custom_minimum_size = Vector2(40, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
color = Color(0.8, 0.807843, 0.827451, 1)
|
||||||
|
|
||||||
|
[node name="IgnorePaths" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/IgnorePaths"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Ignore Paths:"
|
||||||
|
|
||||||
|
[node name="TextEdit" type="LineEdit" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/IgnorePaths"]
|
||||||
|
custom_minimum_size = Vector2(100, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
expand_to_text_length = true
|
||||||
|
|
||||||
|
[node name="Label3" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/IgnorePaths"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "(Separated by commas)"
|
||||||
|
|
||||||
|
[node name="TODOColours" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/TODOColours"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "TODO Colours:"
|
||||||
|
|
||||||
|
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/TODOColours"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="HBoxContainer3" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="VSeparator" type="VSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer3"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Colours" type="VBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer3"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Patterns" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/Patterns"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Patterns:"
|
||||||
|
|
||||||
|
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/Patterns"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="HBoxContainer4" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="VSeparator" type="VSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer4"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Patterns" type="VBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer4"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="AddPatternButton" type="Button" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer4/Patterns"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 0
|
||||||
|
text = "Add"
|
||||||
|
|
||||||
|
[node name="Config" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/Config"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Config:"
|
||||||
|
|
||||||
|
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/Config"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="HBoxContainer5" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="VSeparator" type="VSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Patterns" type="VBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="RefreshCheckButton" type="CheckButton" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 0
|
||||||
|
button_pressed = true
|
||||||
|
text = "Auto Refresh"
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="BuiltInCheckButton" type="CheckButton" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns/HBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Scan Built-in Scripts"
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns/HBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="DefaultButton" type="Button" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 0
|
||||||
|
text = "Reset to default"
|
||||||
|
|
||||||
|
[node name="Timer" type="Timer" parent="."]
|
||||||
|
one_shot = true
|
||||||
|
|
||||||
|
[node name="RescanButton" type="Button" parent="."]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 1
|
||||||
|
anchor_left = 1.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_left = -102.0
|
||||||
|
offset_top = 3.0
|
||||||
|
offset_bottom = 34.0
|
||||||
|
grow_horizontal = 0
|
||||||
|
text = "Rescan Files"
|
||||||
|
flat = true
|
||||||
|
|
||||||
|
[connection signal="toggled" from="VBoxContainer/Header/HeaderRight/SettingsButton" to="." method="_on_SettingsButton_toggled"]
|
||||||
|
[connection signal="tab_changed" from="VBoxContainer/TabContainer" to="." method="_on_TabContainer_tab_changed"]
|
||||||
|
[connection signal="item_activated" from="VBoxContainer/TabContainer/Project/Panel/Tree" to="." method="_on_Tree_item_activated"]
|
||||||
|
[connection signal="item_activated" from="VBoxContainer/TabContainer/Current/Panel/Tree" to="." method="_on_Tree_item_activated"]
|
||||||
|
[connection signal="toggled" from="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptName/FullPathCheckBox" to="." method="_on_FullPathCheckBox_toggled"]
|
||||||
|
[connection signal="toggled" from="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptSort/AlphSortCheckBox" to="." method="_on_AlphSortCheckBox_toggled"]
|
||||||
|
[connection signal="color_changed" from="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptColour/ScriptColourPickerButton" to="." method="_on_ScriptColourPickerButton_color_changed"]
|
||||||
|
[connection signal="pressed" from="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer4/Patterns/AddPatternButton" to="." method="_on_AddPatternButton_pressed"]
|
||||||
|
[connection signal="toggled" from="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns/RefreshCheckButton" to="." method="_on_RefreshCheckButton_toggled"]
|
||||||
|
[connection signal="toggled" from="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns/HBoxContainer/BuiltInCheckButton" to="." method="_on_BuiltInCheckButton_toggled"]
|
||||||
|
[connection signal="pressed" from="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns/DefaultButton" to="." method="_on_DefaultButton_pressed"]
|
||||||
|
[connection signal="timeout" from="Timer" to="." method="_on_Timer_timeout"]
|
||||||
|
[connection signal="pressed" from="RescanButton" to="." method="_on_RescanButton_pressed"]
|
||||||
21
source/addons/Todo_Manager/UI/FlatToggleButton.tres
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[gd_resource type="Theme" load_steps=4 format=3 uid="uid://cignxcqjqfst0"]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_0amm0"]
|
||||||
|
bg_color = Color(1, 1, 1, 0.0784314)
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_juds7"]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_elllf"]
|
||||||
|
bg_color = Color(0.12549, 0.156863, 0.192157, 1)
|
||||||
|
border_width_bottom = 2
|
||||||
|
border_color = Color(0.439216, 0.729412, 0.980392, 1)
|
||||||
|
corner_radius_top_left = 4
|
||||||
|
corner_radius_top_right = 4
|
||||||
|
corner_radius_bottom_right = 4
|
||||||
|
corner_radius_bottom_left = 4
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
Button/colors/font_pressed_color = Color(0.439216, 0.729412, 0.980392, 1)
|
||||||
|
Button/styles/hover = SubResource("StyleBoxFlat_0amm0")
|
||||||
|
Button/styles/normal = SubResource("StyleBoxEmpty_juds7")
|
||||||
|
Button/styles/pressed = SubResource("StyleBoxFlat_elllf")
|
||||||
26
source/addons/Todo_Manager/UI/PatternEdit.tscn
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://bx11sel2q5wli"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://betg01sk02eyy" path="res://addons/Todo_Manager/PatternEdit.gd" id="1_mujq6"]
|
||||||
|
|
||||||
|
[node name="Pattern" type="HBoxContainer"]
|
||||||
|
script = ExtResource("1_mujq6")
|
||||||
|
|
||||||
|
[node name="LineEdit" type="LineEdit" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 0
|
||||||
|
expand_to_text_length = true
|
||||||
|
|
||||||
|
[node name="RemoveButton" type="Button" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "-"
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||||
|
custom_minimum_size = Vector2(20, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 0
|
||||||
|
|
||||||
|
[node name="CaseSensativeCheckbox" type="CheckBox" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 0
|
||||||
|
text = "Case Sensitive"
|
||||||
29
source/addons/Todo_Manager/UI/ToggleButton.tscn
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
[gd_scene load_steps=5 format=3 uid="uid://bq0tjjng7hdvt"]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_5887s"]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_rtgj1"]
|
||||||
|
bg_color = Color(1, 1, 1, 0.0705882)
|
||||||
|
corner_radius_top_left = 4
|
||||||
|
corner_radius_top_right = 4
|
||||||
|
corner_radius_bottom_right = 4
|
||||||
|
corner_radius_bottom_left = 4
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5887s"]
|
||||||
|
bg_color = Color(0.12549, 0.156863, 0.192157, 1)
|
||||||
|
border_width_bottom = 2
|
||||||
|
border_color = Color(0.439216, 0.729412, 0.980392, 1)
|
||||||
|
corner_radius_top_left = 4
|
||||||
|
corner_radius_top_right = 4
|
||||||
|
corner_radius_bottom_right = 4
|
||||||
|
corner_radius_bottom_left = 4
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_f41nr"]
|
||||||
|
|
||||||
|
[node name="Button" type="Button"]
|
||||||
|
theme_override_styles/focus = SubResource("StyleBoxEmpty_5887s")
|
||||||
|
theme_override_styles/hover = SubResource("StyleBoxFlat_rtgj1")
|
||||||
|
theme_override_styles/pressed = SubResource("StyleBoxFlat_5887s")
|
||||||
|
theme_override_styles/normal = SubResource("StyleBoxEmpty_f41nr")
|
||||||
|
toggle_mode = true
|
||||||
|
text = "TODO"
|
||||||
7
source/addons/Todo_Manager/doc/example.gd
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
# TODO: this is a TODO
|
||||||
|
# HACK: this is a HACK
|
||||||
|
# FIXME: this is a FIXME
|
||||||
|
# TODO this works too
|
||||||
|
#Hack any format will do
|
||||||
1
source/addons/Todo_Manager/doc/example.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://dotx67t7w7hhk
|
||||||
BIN
source/addons/Todo_Manager/doc/images/Instruct1.png
Normal file
|
After Width: | Height: | Size: 111 KiB |
40
source/addons/Todo_Manager/doc/images/Instruct1.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://c7v1fdudy4quq"
|
||||||
|
path="res://.godot/imported/Instruct1.png-698c6faa3ef3ac4960807faa3e028bd6.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/Todo_Manager/doc/images/Instruct1.png"
|
||||||
|
dest_files=["res://.godot/imported/Instruct1.png-698c6faa3ef3ac4960807faa3e028bd6.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
source/addons/Todo_Manager/doc/images/Instruct2.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
40
source/addons/Todo_Manager/doc/images/Instruct2.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://b80nmr6b06t21"
|
||||||
|
path="res://.godot/imported/Instruct2.png-4e8664e49d00a397bbd539f7dee976ff.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/Todo_Manager/doc/images/Instruct2.png"
|
||||||
|
dest_files=["res://.godot/imported/Instruct2.png-4e8664e49d00a397bbd539f7dee976ff.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
source/addons/Todo_Manager/doc/images/Instruct3.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
40
source/addons/Todo_Manager/doc/images/Instruct3.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bmpb4ldb5xhm2"
|
||||||
|
path="res://.godot/imported/Instruct3.png-3cc62ed99bf29d90b803cb8eb40881e9.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/Todo_Manager/doc/images/Instruct3.png"
|
||||||
|
dest_files=["res://.godot/imported/Instruct3.png-3cc62ed99bf29d90b803cb8eb40881e9.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
source/addons/Todo_Manager/doc/images/Instruct4.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
40
source/addons/Todo_Manager/doc/images/Instruct4.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dtsgcaefwbblx"
|
||||||
|
path="res://.godot/imported/Instruct4.png-bf5aa1cffc066175cecf9281b0774809.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/Todo_Manager/doc/images/Instruct4.png"
|
||||||
|
dest_files=["res://.godot/imported/Instruct4.png-bf5aa1cffc066175cecf9281b0774809.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
source/addons/Todo_Manager/doc/images/Instruct5.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
40
source/addons/Todo_Manager/doc/images/Instruct5.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bq57uhyrdewef"
|
||||||
|
path="res://.godot/imported/Instruct5.png-001538ed8b5682dcf232de08035aab38.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/Todo_Manager/doc/images/Instruct5.png"
|
||||||
|
dest_files=["res://.godot/imported/Instruct5.png-001538ed8b5682dcf232de08035aab38.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
source/addons/Todo_Manager/doc/images/TODO_Manager_Logo.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cnjwqakk07q5g"
|
||||||
|
path="res://.godot/imported/TODO_Manager_Logo.png-e07d7ec75201c66b732ef87ec1bece15.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/Todo_Manager/doc/images/TODO_Manager_Logo.png"
|
||||||
|
dest_files=["res://.godot/imported/TODO_Manager_Logo.png-e07d7ec75201c66b732ef87ec1bece15.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
source/addons/Todo_Manager/doc/images/TodoExternal.gif
Normal file
|
After Width: | Height: | Size: 243 KiB |
BIN
source/addons/Todo_Manager/doc/images/example1.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
40
source/addons/Todo_Manager/doc/images/example1.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dm4238rk6sken"
|
||||||
|
path="res://.godot/imported/example1.png-6386c332ca46e1e62ea061b956a901cd.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/Todo_Manager/doc/images/example1.png"
|
||||||
|
dest_files=["res://.godot/imported/example1.png-6386c332ca46e1e62ea061b956a901cd.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
source/addons/Todo_Manager/doc/images/example2.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
40
source/addons/Todo_Manager/doc/images/example2.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://b4gc0l6pibggy"
|
||||||
|
path="res://.godot/imported/example2.png-2e3a8f9cd1e178daf22b83dc0513f37a.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/Todo_Manager/doc/images/example2.png"
|
||||||
|
dest_files=["res://.godot/imported/example2.png-2e3a8f9cd1e178daf22b83dc0513f37a.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
7
source/addons/Todo_Manager/plugin.cfg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[plugin]
|
||||||
|
|
||||||
|
name="Todo Manager"
|
||||||
|
description="Dock for managing TODO messages and other notes in your code."
|
||||||
|
author="Peter de Vroom"
|
||||||
|
version="2.5.0"
|
||||||
|
script="plugin.gd"
|
||||||
295
source/addons/Todo_Manager/plugin.gd
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
@tool
|
||||||
|
extends EditorPlugin
|
||||||
|
|
||||||
|
const DockScene := preload("res://addons/Todo_Manager/UI/Dock.tscn")
|
||||||
|
const Dock := preload("res://addons/Todo_Manager/Dock.gd")
|
||||||
|
const Todo := preload("res://addons/Todo_Manager/todo_class.gd")
|
||||||
|
const TodoItem := preload("res://addons/Todo_Manager/todoItem_class.gd")
|
||||||
|
|
||||||
|
var _dockUI : Dock
|
||||||
|
|
||||||
|
class TodoCacheValue:
|
||||||
|
var todos: Array
|
||||||
|
var last_modified_time: int
|
||||||
|
|
||||||
|
func _init(todos: Array, last_modified_time: int):
|
||||||
|
self.todos = todos
|
||||||
|
self.last_modified_time = last_modified_time
|
||||||
|
|
||||||
|
var todo_cache : Dictionary # { key: script_path, value: TodoCacheValue }
|
||||||
|
var remove_queue : Array
|
||||||
|
var combined_pattern : String
|
||||||
|
var cased_patterns : Array[String]
|
||||||
|
|
||||||
|
var refresh_lock := false # makes sure _on_filesystem_changed only triggers once
|
||||||
|
|
||||||
|
|
||||||
|
func _enter_tree() -> void:
|
||||||
|
_dockUI = DockScene.instantiate() as Control
|
||||||
|
add_control_to_bottom_panel(_dockUI, "TODO")
|
||||||
|
get_editor_interface().get_resource_filesystem().connect("filesystem_changed",
|
||||||
|
_on_filesystem_changed)
|
||||||
|
get_editor_interface().get_file_system_dock().connect("file_removed", queue_remove)
|
||||||
|
get_editor_interface().get_script_editor().connect("editor_script_changed",
|
||||||
|
_on_active_script_changed)
|
||||||
|
_dockUI.plugin = self
|
||||||
|
|
||||||
|
var filtered_patterns = _dockUI.patterns.filter(func (p): return p[3] == true)
|
||||||
|
if filtered_patterns.size() > 0:
|
||||||
|
combined_pattern = combine_patterns(filtered_patterns)
|
||||||
|
find_tokens_from_path(find_scripts())
|
||||||
|
_dockUI.build_tree()
|
||||||
|
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
_dockUI.create_config_file()
|
||||||
|
remove_control_from_bottom_panel(_dockUI)
|
||||||
|
_dockUI.free()
|
||||||
|
|
||||||
|
|
||||||
|
func queue_remove(file: String):
|
||||||
|
for i in _dockUI.todo_items.size() - 1:
|
||||||
|
if _dockUI.todo_items[i].script_path == file:
|
||||||
|
_dockUI.todo_items.remove_at(i)
|
||||||
|
|
||||||
|
|
||||||
|
func find_tokens_from_path(scripts: Array[String]) -> void:
|
||||||
|
for script_path in scripts:
|
||||||
|
var file := FileAccess.open(script_path, FileAccess.READ)
|
||||||
|
var contents := file.get_as_text()
|
||||||
|
if script_path.ends_with(".tscn"):
|
||||||
|
handle_built_in_scripts(contents, script_path)
|
||||||
|
else:
|
||||||
|
find_tokens(contents, script_path)
|
||||||
|
|
||||||
|
|
||||||
|
func handle_built_in_scripts(contents: String, resource_path: String):
|
||||||
|
var s := contents.split("sub_resource type=\"GDScript\"")
|
||||||
|
if s.size() <= 1:
|
||||||
|
return
|
||||||
|
for i in range(1, s.size()):
|
||||||
|
var script_components := s[i].split("script/source")
|
||||||
|
var script_name = script_components[0].substr(5, 14)
|
||||||
|
find_tokens(script_components[1], resource_path + "::" + script_name)
|
||||||
|
|
||||||
|
|
||||||
|
func find_tokens(text: String, script_path: String) -> void:
|
||||||
|
var cached_todos = get_cached_todos(script_path)
|
||||||
|
if cached_todos.size() != 0:
|
||||||
|
# var i := 0
|
||||||
|
# for todo_item in _dockUI.todo_items:
|
||||||
|
# if todo_item.script_path == script_path:
|
||||||
|
# _dockUI.todo_items.remove_at(i)
|
||||||
|
# i += 1
|
||||||
|
var todo_item := TodoItem.new(script_path, cached_todos)
|
||||||
|
_dockUI.todo_items.append(todo_item)
|
||||||
|
else:
|
||||||
|
var regex = RegEx.new()
|
||||||
|
# if regex.compile("#\\s*\\bTODO\\b.*|#\\s*\\bHACK\\b.*") == OK:
|
||||||
|
if regex.compile(combined_pattern) == OK:
|
||||||
|
var result : Array[RegExMatch] = regex.search_all(text)
|
||||||
|
if result.is_empty():
|
||||||
|
for i in _dockUI.todo_items.size():
|
||||||
|
if _dockUI.todo_items[i].script_path == script_path:
|
||||||
|
_dockUI.todo_items.remove_at(i)
|
||||||
|
return # No tokens found
|
||||||
|
var match_found : bool
|
||||||
|
var i := 0
|
||||||
|
for todo_item in _dockUI.todo_items:
|
||||||
|
if todo_item.script_path == script_path:
|
||||||
|
match_found = true
|
||||||
|
var updated_todo_item := update_todo_item(todo_item, result, text, script_path)
|
||||||
|
_dockUI.todo_items.remove_at(i)
|
||||||
|
_dockUI.todo_items.insert(i, updated_todo_item)
|
||||||
|
break
|
||||||
|
i += 1
|
||||||
|
if !match_found:
|
||||||
|
_dockUI.todo_items.append(create_todo_item(result, text, script_path))
|
||||||
|
|
||||||
|
|
||||||
|
func create_todo_item(regex_results: Array[RegExMatch], text: String, script_path: String) -> TodoItem:
|
||||||
|
var todo_item = TodoItem.new(script_path, [])
|
||||||
|
todo_item.script_path = script_path
|
||||||
|
var last_line_number := 0
|
||||||
|
var lines := text.split("\n")
|
||||||
|
for r in regex_results:
|
||||||
|
var new_todo : Todo = create_todo(r.get_string(), script_path)
|
||||||
|
new_todo.line_number = get_line_number(r.get_string(), text, last_line_number)
|
||||||
|
# GD Multiline comment
|
||||||
|
var trailing_line := new_todo.line_number
|
||||||
|
var should_break = false
|
||||||
|
while trailing_line < lines.size() and lines[trailing_line].dedent().begins_with("#"):
|
||||||
|
for other_r in regex_results:
|
||||||
|
if lines[trailing_line] in other_r.get_string():
|
||||||
|
should_break = true
|
||||||
|
break
|
||||||
|
if should_break:
|
||||||
|
break
|
||||||
|
|
||||||
|
new_todo.content += "\n" + lines[trailing_line]
|
||||||
|
trailing_line += 1
|
||||||
|
|
||||||
|
last_line_number = new_todo.line_number
|
||||||
|
todo_item.todos.append(new_todo)
|
||||||
|
cache_todos(todo_item.todos, script_path)
|
||||||
|
return todo_item
|
||||||
|
|
||||||
|
|
||||||
|
func update_todo_item(todo_item: TodoItem, regex_results: Array[RegExMatch], text: String, script_path: String) -> TodoItem:
|
||||||
|
todo_item.todos.clear()
|
||||||
|
var lines := text.split("\n")
|
||||||
|
for r in regex_results:
|
||||||
|
var new_todo : Todo = create_todo(r.get_string(), script_path)
|
||||||
|
new_todo.line_number = get_line_number(r.get_string(), text)
|
||||||
|
# GD Multiline comment
|
||||||
|
var trailing_line := new_todo.line_number
|
||||||
|
var should_break = false
|
||||||
|
while trailing_line < lines.size() and lines[trailing_line].dedent().begins_with("#"):
|
||||||
|
for other_r in regex_results:
|
||||||
|
if lines[trailing_line] in other_r.get_string():
|
||||||
|
should_break = true
|
||||||
|
break
|
||||||
|
if should_break:
|
||||||
|
break
|
||||||
|
|
||||||
|
new_todo.content += "\n" + lines[trailing_line]
|
||||||
|
trailing_line += 1
|
||||||
|
todo_item.todos.append(new_todo)
|
||||||
|
return todo_item
|
||||||
|
|
||||||
|
|
||||||
|
func get_line_number(what: String, from: String, start := 0) -> int:
|
||||||
|
what = what.split('\n')[0] # Match first line of multiline C# comments
|
||||||
|
var temp_array := from.split('\n')
|
||||||
|
var lines := Array(temp_array)
|
||||||
|
var line_number# = lines.find(what) + 1
|
||||||
|
for i in range(start, lines.size()):
|
||||||
|
if what in lines[i]:
|
||||||
|
line_number = i + 1 # +1 to account of 0-based array vs 1-based line numbers
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
line_number = 0 # This is an error
|
||||||
|
return line_number
|
||||||
|
|
||||||
|
|
||||||
|
func _on_filesystem_changed() -> void:
|
||||||
|
if !refresh_lock:
|
||||||
|
if _dockUI.auto_refresh:
|
||||||
|
refresh_lock = true
|
||||||
|
_dockUI.get_node("Timer").start()
|
||||||
|
rescan_files(false)
|
||||||
|
|
||||||
|
|
||||||
|
func find_scripts() -> Array[String]:
|
||||||
|
var scripts : Array[String]
|
||||||
|
var directory_queue : Array[String]
|
||||||
|
var dir := DirAccess.open("res://")
|
||||||
|
if dir.get_open_error() == OK:
|
||||||
|
get_dir_contents(dir, scripts, directory_queue)
|
||||||
|
else:
|
||||||
|
printerr("TODO_Manager: There was an error during find_scripts()")
|
||||||
|
|
||||||
|
while not directory_queue.is_empty():
|
||||||
|
if dir.change_dir(directory_queue[0]) == OK:
|
||||||
|
get_dir_contents(dir, scripts, directory_queue)
|
||||||
|
else:
|
||||||
|
printerr("TODO_Manager: There was an error at: " + directory_queue[0])
|
||||||
|
directory_queue.pop_front()
|
||||||
|
|
||||||
|
return scripts
|
||||||
|
|
||||||
|
|
||||||
|
func cache_todos(todos: Array, script_path: String) -> void:
|
||||||
|
var last_modified_time = FileAccess.get_modified_time(script_path)
|
||||||
|
todo_cache[script_path] = TodoCacheValue.new(todos, last_modified_time)
|
||||||
|
|
||||||
|
|
||||||
|
func get_cached_todos(script_path: String) -> Array:
|
||||||
|
if todo_cache.has(script_path) and !script_path.contains("tscn::"):
|
||||||
|
var cached_value: TodoCacheValue = todo_cache[script_path]
|
||||||
|
if cached_value.last_modified_time == FileAccess.get_modified_time(script_path):
|
||||||
|
|
||||||
|
return cached_value.todos
|
||||||
|
return []
|
||||||
|
|
||||||
|
func get_dir_contents(dir: DirAccess, scripts: Array[String], directory_queue: Array[String]) -> void:
|
||||||
|
dir.include_navigational = false
|
||||||
|
dir.include_hidden = false
|
||||||
|
if dir_has_gdignore(dir):
|
||||||
|
return
|
||||||
|
dir.list_dir_begin()
|
||||||
|
var file_name : String = dir.get_next()
|
||||||
|
|
||||||
|
while file_name != "":
|
||||||
|
if dir.current_is_dir():
|
||||||
|
if file_name.begins_with('.'): # Skip folders which should never have scripts
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
directory_queue.append(dir.get_current_dir().path_join(file_name))
|
||||||
|
else:
|
||||||
|
if file_name.ends_with(".gd") or file_name.ends_with(".cs") \
|
||||||
|
or file_name.ends_with(".c") or file_name.ends_with(".cpp") or file_name.ends_with(".h") \
|
||||||
|
or ((file_name.ends_with(".tscn") and _dockUI.builtin_enabled)):
|
||||||
|
scripts.append(dir.get_current_dir().path_join(file_name))
|
||||||
|
file_name = dir.get_next()
|
||||||
|
dir.list_dir_end()
|
||||||
|
|
||||||
|
func dir_has_gdignore(dir: DirAccess) -> bool:
|
||||||
|
var files = dir.get_files()
|
||||||
|
return files.has(".gdignore")
|
||||||
|
|
||||||
|
func rescan_files(clear_cache: bool) -> void:
|
||||||
|
_dockUI.todo_items.clear()
|
||||||
|
if clear_cache:
|
||||||
|
todo_cache.clear()
|
||||||
|
var filtered_patterns = _dockUI.patterns.filter(func (p): return p[3] == true)
|
||||||
|
|
||||||
|
if filtered_patterns.size() > 0:
|
||||||
|
combined_pattern = combine_patterns(filtered_patterns)
|
||||||
|
find_tokens_from_path(find_scripts())
|
||||||
|
_dockUI.build_tree()
|
||||||
|
|
||||||
|
|
||||||
|
func combine_patterns(patterns: Array) -> String:
|
||||||
|
# Case Sensitivity
|
||||||
|
cased_patterns = []
|
||||||
|
for pattern in patterns:
|
||||||
|
if pattern[2] == _dockUI.CASE_INSENSITIVE:
|
||||||
|
cased_patterns.append(pattern[0].insert(0, "((?i)") + ")")
|
||||||
|
else:
|
||||||
|
cased_patterns.append("(" + pattern[0] + ")")
|
||||||
|
|
||||||
|
|
||||||
|
var pattern_string := "((\\/\\*)|(#|\\/\\/))\\s*("
|
||||||
|
for i in range(patterns.size()):
|
||||||
|
if i == 0:
|
||||||
|
pattern_string += cased_patterns[i]
|
||||||
|
else:
|
||||||
|
pattern_string += "|" + cased_patterns[i]
|
||||||
|
pattern_string += ")(?(2)[\\s\\S]*?\\*\\/|.*)"
|
||||||
|
return pattern_string
|
||||||
|
|
||||||
|
|
||||||
|
func create_todo(todo_string: String, script_path: String) -> Todo:
|
||||||
|
var todo := Todo.new()
|
||||||
|
var regex = RegEx.new()
|
||||||
|
for pattern in cased_patterns:
|
||||||
|
if regex.compile(pattern) == OK:
|
||||||
|
var result : RegExMatch = regex.search(todo_string)
|
||||||
|
if result:
|
||||||
|
todo.pattern = pattern
|
||||||
|
todo.title = result.strings[0]
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
printerr("Error compiling " + pattern)
|
||||||
|
|
||||||
|
todo.content = todo_string
|
||||||
|
todo.script_path = script_path
|
||||||
|
return todo
|
||||||
|
|
||||||
|
|
||||||
|
func _on_active_script_changed(script) -> void:
|
||||||
|
if _dockUI:
|
||||||
|
if _dockUI.tabs.current_tab == 1:
|
||||||
|
_dockUI.build_tree()
|
||||||
1
source/addons/Todo_Manager/plugin.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://cgmj81roq24r8
|
||||||
15
source/addons/Todo_Manager/todo.cfg
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[scripts]
|
||||||
|
|
||||||
|
full_path=false
|
||||||
|
sort_alphabetical=true
|
||||||
|
script_colour=Color(0.8, 0.80784315, 0.827451, 1)
|
||||||
|
ignore_paths=Array[String](["res://addons/"])
|
||||||
|
|
||||||
|
[patterns]
|
||||||
|
|
||||||
|
patterns=[["\\bTODO\\b", Color(0.5882353, 0.94509804, 0.6784314, 1), 0, true], ["\\bHACK\\b", Color(0.8352941, 0.7372549, 0.4392157, 1), 0, true], ["\\bFIXME\\b", Color(0.8352941, 0.4392157, 0.4392157, 1), 0, true]]
|
||||||
|
|
||||||
|
[config]
|
||||||
|
|
||||||
|
auto_refresh=true
|
||||||
|
builtin_enabled=false
|
||||||
18
source/addons/Todo_Manager/todoItem_class.gd
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
@tool
|
||||||
|
extends RefCounted
|
||||||
|
|
||||||
|
var script_path : String
|
||||||
|
var todos : Array
|
||||||
|
|
||||||
|
func _init(script_path: String, todos: Array):
|
||||||
|
self.script_path = script_path
|
||||||
|
self.todos = todos
|
||||||
|
|
||||||
|
func get_short_path() -> String:
|
||||||
|
var temp_array := script_path.rsplit('/', false, 1)
|
||||||
|
var short_path : String
|
||||||
|
if not temp_array.size() > 1:
|
||||||
|
short_path = "(!)" + temp_array[0]
|
||||||
|
else:
|
||||||
|
short_path = temp_array[1]
|
||||||
|
return short_path
|
||||||
1
source/addons/Todo_Manager/todoItem_class.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://yao1gny5ka0a
|
||||||
8
source/addons/Todo_Manager/todo_class.gd
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
@tool
|
||||||
|
extends RefCounted
|
||||||
|
|
||||||
|
var pattern : String
|
||||||
|
var title : String
|
||||||
|
var content : String
|
||||||
|
var script_path : String
|
||||||
|
var line_number : int
|
||||||
1
source/addons/Todo_Manager/todo_class.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://cvxelosp5shwf
|
||||||
44
source/addons/godot_3d_cursor/3d_cursor.gd
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
@tool
|
||||||
|
class_name Cursor3D
|
||||||
|
extends Marker3D
|
||||||
|
|
||||||
|
## The size of the 3D Cursor within your scene
|
||||||
|
@export var size_scale: float = 1.0
|
||||||
|
|
||||||
|
@export_group("Label Settings")
|
||||||
|
## This setting decides whether the label with the text '3D Cursor' should
|
||||||
|
## be displayed
|
||||||
|
@export var show_label: bool = true
|
||||||
|
## This setting decides whether the label should scale with the selected size
|
||||||
|
## of the 3D Cursor.
|
||||||
|
@export var scale_affect_label: bool = false
|
||||||
|
|
||||||
|
# The standard scale of the 3D Cursor. This size is chosen because of the
|
||||||
|
# size of the .png used for the cursor. Please don't touch (private var)
|
||||||
|
var _scale: float = 0.25
|
||||||
|
|
||||||
|
## The sprite of the 3D Cursor
|
||||||
|
@onready var sprite_3d: Sprite3D = $Sprite3D
|
||||||
|
## The label of the 3D Cursor
|
||||||
|
@onready var label_3d: Label3D = $Sprite3D/Label3D
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
if not Engine.is_editor_hint():
|
||||||
|
hide()
|
||||||
|
|
||||||
|
# No manual user input allowed on rotation and scale;
|
||||||
|
# Reset any user input to 0 or 1 respectively
|
||||||
|
rotation = Vector3.ZERO
|
||||||
|
scale = Vector3.ONE
|
||||||
|
|
||||||
|
# Show the label if desired
|
||||||
|
label_3d.visible = show_label
|
||||||
|
|
||||||
|
# Set the scale of the 3D Cursor
|
||||||
|
sprite_3d.scale = Vector3(_scale * size_scale, _scale * size_scale, _scale * size_scale)
|
||||||
|
if scale_affect_label:
|
||||||
|
label_3d.scale = Vector3.ONE * 4
|
||||||
|
else:
|
||||||
|
var label_scale = 1 / (_scale * size_scale)
|
||||||
|
label_3d.scale = Vector3(label_scale, label_scale, label_scale)
|
||||||
1
source/addons/godot_3d_cursor/3d_cursor.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://dt04kfvdc21nb
|
||||||
BIN
source/addons/godot_3d_cursor/3d_cursor.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
41
source/addons/godot_3d_cursor/3d_cursor.png.import
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cdqg3y11tiold"
|
||||||
|
path.s3tc="res://.godot/imported/3d_cursor.png-3f509e9f2ec38702e6618d6c6cc63f4d.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/godot_3d_cursor/3d_cursor.png"
|
||||||
|
dest_files=["res://.godot/imported/3d_cursor.png-3f509e9f2ec38702e6618d6c6cc63f4d.s3tc.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=2
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=0
|
||||||
19
source/addons/godot_3d_cursor/3d_cursor.tscn
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://dfpatff4d5okj"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://brmxsn2cjdqw4" path="res://addons/godot_3d_cursor/3d_cursor.png" id="2_mnq4l"]
|
||||||
|
[ext_resource type="Script" uid="uid://dt04kfvdc21nb" path="res://addons/godot_3d_cursor/3d_cursor.gd" id="2_stis0"]
|
||||||
|
|
||||||
|
[node name="3DCursor" type="Marker3D"]
|
||||||
|
script = ExtResource("2_stis0")
|
||||||
|
|
||||||
|
[node name="Sprite3D" type="Sprite3D" parent="."]
|
||||||
|
transform = Transform3D(0.25, 0, 0, 0, 0.25, 0, 0, 0, 0.25, 0, 0, 0)
|
||||||
|
billboard = 1
|
||||||
|
no_depth_test = true
|
||||||
|
texture = ExtResource("2_mnq4l")
|
||||||
|
|
||||||
|
[node name="Label3D" type="Label3D" parent="Sprite3D"]
|
||||||
|
transform = Transform3D(4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 2.4, 0)
|
||||||
|
billboard = 1
|
||||||
|
no_depth_test = true
|
||||||
|
text = "3D Cursor"
|
||||||
228
source/addons/godot_3d_cursor/pie_menu.gd
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
@tool
|
||||||
|
class_name PieMenu
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
## Emitted when the "3D Cursor to Origin" command is invoked through the [PieMenu]
|
||||||
|
signal cursor_to_origin_pressed
|
||||||
|
## Emitted when the "3D Cursor to Selected Object(s)" command is invoked through the [PieMenu]
|
||||||
|
signal cursor_to_selected_objects_pressed
|
||||||
|
## Emitted when the "Selected Object to 3D Cursor" command is invoked through the [PieMenu]
|
||||||
|
signal selected_object_to_cursor_pressed
|
||||||
|
## Emitted when the "Remove 3D Cursor from Scene" command is invoked through the [PieMenu]
|
||||||
|
signal remove_cursor_from_scene_pressed
|
||||||
|
## Emitted when the "Toggle 3D Cursor" command is invoked through the [PieMenu]
|
||||||
|
signal toggle_cursor_pressed
|
||||||
|
|
||||||
|
## The dimmed color for the selection indicator that is used if no button is hovered
|
||||||
|
const _dimmed_selection_indicator_color: Color = Color("8c8c8cFF")
|
||||||
|
|
||||||
|
## The value at which the buttons start to animate/slide if the menu is shown
|
||||||
|
var slide_start: int = 0
|
||||||
|
## The position the buttons animate/slide to
|
||||||
|
var slide_end: int = 100
|
||||||
|
## The radius of the menu. The buttons are aligned around an invisible circle
|
||||||
|
## and this is the corresponding radius.
|
||||||
|
var menu_radius: int = slide_start
|
||||||
|
## The buttons that are "loaded"
|
||||||
|
var buttons: Array[Button] = []
|
||||||
|
|
||||||
|
var _hovered_button: Button
|
||||||
|
var _show_menu_echo: bool = false
|
||||||
|
|
||||||
|
@onready var selection_indicator: Sprite2D = $SelectionIndicator
|
||||||
|
@onready var toggle_3d_cursor: Button = $Toggle3DCursor
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
#var viewport_height: int = get_viewport().size.y
|
||||||
|
#var viewport_width: int = get_viewport().size.x
|
||||||
|
|
||||||
|
# If the menu is shown animate the buttons
|
||||||
|
if visible:
|
||||||
|
menu_radius = lerp(menu_radius, slide_end, 20 * delta)
|
||||||
|
|
||||||
|
# Reset the button positions when the menu is hidden
|
||||||
|
if not visible:
|
||||||
|
menu_radius = slide_start
|
||||||
|
_show_menu_echo = true
|
||||||
|
|
||||||
|
_align_buttons()
|
||||||
|
|
||||||
|
# Load all children from the pie menu
|
||||||
|
var children = get_children()
|
||||||
|
# Get all the children that are buttons if there are no new button return
|
||||||
|
if children.filter(_is_button) == buttons:
|
||||||
|
return
|
||||||
|
|
||||||
|
# If there are new buttons repopulate the buttons list and display them
|
||||||
|
buttons.clear()
|
||||||
|
for button: Button in children.filter(_is_button):
|
||||||
|
buttons.append(button)
|
||||||
|
|
||||||
|
_align_buttons()
|
||||||
|
|
||||||
|
|
||||||
|
func _input(event: InputEvent) -> void:
|
||||||
|
if not is_visible_in_tree():
|
||||||
|
return
|
||||||
|
|
||||||
|
# If the [PieMenu] is opened the selection indicator will rotate according
|
||||||
|
# to the mouse position. If the user hovers over a button the indicator
|
||||||
|
# will change its color to white and a more dimmed color otherwise
|
||||||
|
if event is InputEventMouseMotion:
|
||||||
|
# Calculate the angle of the mouse position to the x axis
|
||||||
|
var rot: float = rad_to_deg(get_local_mouse_position().angle_to(Vector2.RIGHT)) - 45
|
||||||
|
# Apply the rotation to the indicator
|
||||||
|
selection_indicator.rotation_degrees = -rot
|
||||||
|
|
||||||
|
# If the key used to open the [PieMenu] is held down while selecting hovering
|
||||||
|
# over a button the user can invoke the buttons action by releasing the
|
||||||
|
# key (s). This does not work if the key was released prior to hovering
|
||||||
|
# over a button. This functionality is similar to the one in Blender
|
||||||
|
if not event is InputEventKey:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not event.keycode == KEY_S:
|
||||||
|
return
|
||||||
|
|
||||||
|
if event.is_released() and _hovered_button == null:
|
||||||
|
_show_menu_echo = false
|
||||||
|
return
|
||||||
|
|
||||||
|
if _show_menu_echo and event.is_released():
|
||||||
|
_hovered_button.pressed.emit()
|
||||||
|
|
||||||
|
|
||||||
|
## This method should be used in conjuncton with a [Array.filter] method.
|
||||||
|
## It checks whether a node inherits from Button
|
||||||
|
func _is_button(child: Node) -> bool:
|
||||||
|
return child is Button
|
||||||
|
|
||||||
|
|
||||||
|
## This method aligns the available buttons in a circular menu by using
|
||||||
|
## some [sin] and [cos] magic
|
||||||
|
func _align_buttons() -> void:
|
||||||
|
var button_count: int = len(buttons)
|
||||||
|
for i in range(button_count):
|
||||||
|
var button: Button = buttons[i]
|
||||||
|
var theta: float = (i / float(button_count)) * TAU
|
||||||
|
var x: float = (menu_radius * cos(theta))
|
||||||
|
var y: float = (menu_radius * sin(theta)) - button.size.y / 2.0
|
||||||
|
x = x - button.size.x if x < 0 else x
|
||||||
|
button.position = Vector2(x, y)
|
||||||
|
|
||||||
|
|
||||||
|
## Connected to the corresponding UI button this method acts as a repeater
|
||||||
|
## by emitting the corresponding signal classes can listen to via a [PieMenu]
|
||||||
|
## instance
|
||||||
|
func _on_3d_cursor_to_origin_pressed() -> void:
|
||||||
|
hide()
|
||||||
|
cursor_to_origin_pressed.emit()
|
||||||
|
|
||||||
|
## Executes when the "3D Cursor to Origin" button is hovered
|
||||||
|
func _on_3d_cursor_to_origin_mouse_entered() -> void:
|
||||||
|
_hovered_button = $"3DCursorToOrigin"
|
||||||
|
_on_mouse_entered_button()
|
||||||
|
|
||||||
|
## Executes when the "3D Cursor to Origin" button is no longer hovered
|
||||||
|
func _on_3d_cursor_to_origin_mouse_exited() -> void:
|
||||||
|
_hovered_button = null
|
||||||
|
_on_mouse_exited_button()
|
||||||
|
|
||||||
|
|
||||||
|
## Connected to the corresponding UI button this method acts as a repeater
|
||||||
|
## by emitting the corresponding signal classes can listen to via a [PieMenu]
|
||||||
|
## instance
|
||||||
|
func _on_3d_cursor_to_selected_objects_pressed() -> void:
|
||||||
|
hide()
|
||||||
|
cursor_to_selected_objects_pressed.emit()
|
||||||
|
|
||||||
|
## Executes when the "3D Cursor to Selected Object(s)" button is hovered
|
||||||
|
func _on_3d_cursor_to_selected_objects_mouse_entered() -> void:
|
||||||
|
_hovered_button = $"3DCursorToSelectedObjects"
|
||||||
|
_on_mouse_entered_button()
|
||||||
|
|
||||||
|
## Executes when the "3D Cursor to Selected Object(s)" button is no longer hovered
|
||||||
|
func _on_3d_cursor_to_selected_objects_mouse_exited() -> void:
|
||||||
|
_hovered_button = null
|
||||||
|
_on_mouse_exited_button()
|
||||||
|
|
||||||
|
|
||||||
|
## Connected to the corresponding UI button this method acts as a repeater
|
||||||
|
## by emitting the corresponding signal classes can listen to via a [PieMenu]
|
||||||
|
## instance
|
||||||
|
func _on_selected_object_to_3d_cursor_pressed() -> void:
|
||||||
|
hide()
|
||||||
|
selected_object_to_cursor_pressed.emit()
|
||||||
|
|
||||||
|
## Executes when the "Selected Object to 3D Cursor" button is hovered
|
||||||
|
func _on_selected_object_to_3d_cursor_mouse_entered() -> void:
|
||||||
|
_hovered_button = $SelectedObjectTo3DCursor
|
||||||
|
_on_mouse_entered_button()
|
||||||
|
|
||||||
|
## Executes when the "Selected Object to 3D Cursor" button is no longer hovered
|
||||||
|
func _on_selected_object_to_3d_cursor_mouse_exited() -> void:
|
||||||
|
_hovered_button = null
|
||||||
|
_on_mouse_exited_button()
|
||||||
|
|
||||||
|
|
||||||
|
## Connected to the corresponding UI button this method acts as a repeater
|
||||||
|
## by emitting the corresponding signal classes can listen to via a [PieMenu]
|
||||||
|
## instance
|
||||||
|
func _on_remove_3d_cursor_from_scene_pressed() -> void:
|
||||||
|
hide()
|
||||||
|
remove_cursor_from_scene_pressed.emit()
|
||||||
|
|
||||||
|
## Executes when the "Remove 3D Cursor" button is hovered
|
||||||
|
func _on_remove_3d_cursor_from_scene_mouse_entered() -> void:
|
||||||
|
_hovered_button = $Remove3DCursorFromScene
|
||||||
|
_on_mouse_entered_button()
|
||||||
|
|
||||||
|
## Executes when the "Remove 3D Cursor" button is no longer hovered
|
||||||
|
func _on_remove_3d_cursor_from_scene_mouse_exited() -> void:
|
||||||
|
_hovered_button = null
|
||||||
|
_on_mouse_exited_button()
|
||||||
|
|
||||||
|
|
||||||
|
## Connected to the corresponding UI button this method acts as a repeater
|
||||||
|
## by emitting the corresponding signal classes can listen to via a [PieMenu]
|
||||||
|
## instance
|
||||||
|
func _on_toggle_3d_cursor_pressed() -> void:
|
||||||
|
hide()
|
||||||
|
toggle_cursor_pressed.emit()
|
||||||
|
|
||||||
|
## Executes when the "Disable/Enable 3D Cursor" button is hovered
|
||||||
|
func _on_toggle_3d_cursor_mouse_entered() -> void:
|
||||||
|
_hovered_button = toggle_3d_cursor
|
||||||
|
_on_mouse_entered_button()
|
||||||
|
|
||||||
|
## Executes when the "Disable/Enable 3D Cursor" button is hovered
|
||||||
|
func _on_toggle_3d_cursor_mouse_exited() -> void:
|
||||||
|
_hovered_button = null
|
||||||
|
_on_mouse_exited_button()
|
||||||
|
|
||||||
|
|
||||||
|
## This method is executed by every button of the [PieMenu]. It brightens
|
||||||
|
## the color of the selection indicator when a button is hovered.
|
||||||
|
func _on_mouse_entered_button() -> void:
|
||||||
|
selection_indicator.modulate = Color.WHITE
|
||||||
|
|
||||||
|
## This method is executed by every button of the [PieMenu]. It dims the color
|
||||||
|
## of the selection indicator when a button is no longer hovered
|
||||||
|
func _on_mouse_exited_button() -> void:
|
||||||
|
selection_indicator.modulate = _dimmed_selection_indicator_color
|
||||||
|
|
||||||
|
|
||||||
|
## This method is a little helper that is used to prevent some quirky behaviour
|
||||||
|
## with the consumption of events. It checks whether the user clicked on a
|
||||||
|
## button rather than the space around it
|
||||||
|
func hit_any_button() -> bool:
|
||||||
|
var mouse_position: Vector2 = get_global_mouse_position()
|
||||||
|
for button in buttons:
|
||||||
|
if button.get_global_rect().has_point(mouse_position):
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func change_toggle_label(visible: bool) -> void:
|
||||||
|
toggle_3d_cursor.text = ("Disable" if visible else "Enable") + " 3D Cursor"
|
||||||
1
source/addons/godot_3d_cursor/pie_menu.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://dul31m8bwxlxm
|
||||||
119
source/addons/godot_3d_cursor/pie_menu.tscn
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
[gd_scene load_steps=5 format=3 uid="uid://igrlue2n5478"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dul31m8bwxlxm" path="res://addons/godot_3d_cursor/pie_menu.gd" id="1_a7cko"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bhift5k0v2tga" path="res://addons/godot_3d_cursor/selection_ring.png" id="2_k5qvu"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bngw0w7d1nrgv" path="res://addons/godot_3d_cursor/selection_indicator.png" id="3_euipm"]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_s5fna"]
|
||||||
|
bg_color = Color(0.145098, 0.145098, 0.145098, 0.258824)
|
||||||
|
corner_radius_top_left = 20
|
||||||
|
corner_radius_top_right = 20
|
||||||
|
corner_radius_bottom_right = 20
|
||||||
|
corner_radius_bottom_left = 20
|
||||||
|
|
||||||
|
[node name="PieMenu" type="Control"]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
size_flags_horizontal = 4
|
||||||
|
size_flags_vertical = 4
|
||||||
|
script = ExtResource("1_a7cko")
|
||||||
|
|
||||||
|
[node name="Panel" type="Panel" parent="."]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -347.5
|
||||||
|
offset_top = -145.0
|
||||||
|
offset_right = 379.5
|
||||||
|
offset_bottom = 145.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
theme_override_styles/panel = SubResource("StyleBoxFlat_s5fna")
|
||||||
|
|
||||||
|
[node name="3DCursorToSelectedObjects" type="Button" parent="."]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = 100.0
|
||||||
|
offset_top = -15.5
|
||||||
|
offset_right = 347.0
|
||||||
|
offset_bottom = 15.5
|
||||||
|
mouse_default_cursor_shape = 2
|
||||||
|
text = "3D Cursor to Selected Object(s)"
|
||||||
|
|
||||||
|
[node name="Remove3DCursorFromScene" type="Button" parent="."]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = 30.9017
|
||||||
|
offset_top = 79.6054
|
||||||
|
offset_right = 273.902
|
||||||
|
offset_bottom = 110.606
|
||||||
|
mouse_default_cursor_shape = 2
|
||||||
|
text = "Remove 3D Cursor from Scene"
|
||||||
|
|
||||||
|
[node name="SelectedObjectTo3DCursor" type="Button" parent="."]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = -309.902
|
||||||
|
offset_top = 43.2785
|
||||||
|
offset_right = -80.9017
|
||||||
|
offset_bottom = 74.2785
|
||||||
|
mouse_default_cursor_shape = 2
|
||||||
|
text = "Selected Object to 3D Cursor"
|
||||||
|
|
||||||
|
[node name="3DCursorToOrigin" type="Button" parent="."]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -237.902
|
||||||
|
offset_top = -74.2785
|
||||||
|
offset_right = -80.9017
|
||||||
|
offset_bottom = -43.2785
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
size_flags_horizontal = 0
|
||||||
|
mouse_default_cursor_shape = 2
|
||||||
|
text = "3D Cursor to Origin"
|
||||||
|
|
||||||
|
[node name="Toggle3DCursor" type="Button" parent="."]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = 30.9017
|
||||||
|
offset_top = -110.606
|
||||||
|
offset_right = 176.902
|
||||||
|
offset_bottom = -79.6055
|
||||||
|
mouse_default_cursor_shape = 2
|
||||||
|
text = "Disable 3D Cursor"
|
||||||
|
|
||||||
|
[node name="SelectionRing" type="Sprite2D" parent="."]
|
||||||
|
modulate = Color(0.148438, 0.148438, 0.148438, 1)
|
||||||
|
scale = Vector2(0.2, 0.2)
|
||||||
|
texture = ExtResource("2_k5qvu")
|
||||||
|
|
||||||
|
[node name="SelectionIndicator" type="Sprite2D" parent="."]
|
||||||
|
modulate = Color(0.550781, 0.550781, 0.550781, 1)
|
||||||
|
scale = Vector2(0.2, 0.2)
|
||||||
|
texture = ExtResource("3_euipm")
|
||||||
|
|
||||||
|
[connection signal="mouse_entered" from="3DCursorToSelectedObjects" to="." method="_on_3d_cursor_to_selected_objects_mouse_entered"]
|
||||||
|
[connection signal="mouse_exited" from="3DCursorToSelectedObjects" to="." method="_on_3d_cursor_to_selected_objects_mouse_exited"]
|
||||||
|
[connection signal="pressed" from="3DCursorToSelectedObjects" to="." method="_on_3d_cursor_to_selected_objects_pressed"]
|
||||||
|
[connection signal="mouse_entered" from="Remove3DCursorFromScene" to="." method="_on_remove_3d_cursor_from_scene_mouse_entered"]
|
||||||
|
[connection signal="mouse_exited" from="Remove3DCursorFromScene" to="." method="_on_remove_3d_cursor_from_scene_mouse_exited"]
|
||||||
|
[connection signal="pressed" from="Remove3DCursorFromScene" to="." method="_on_remove_3d_cursor_from_scene_pressed"]
|
||||||
|
[connection signal="mouse_entered" from="SelectedObjectTo3DCursor" to="." method="_on_selected_object_to_3d_cursor_mouse_entered"]
|
||||||
|
[connection signal="mouse_exited" from="SelectedObjectTo3DCursor" to="." method="_on_selected_object_to_3d_cursor_mouse_exited"]
|
||||||
|
[connection signal="pressed" from="SelectedObjectTo3DCursor" to="." method="_on_selected_object_to_3d_cursor_pressed"]
|
||||||
|
[connection signal="mouse_entered" from="3DCursorToOrigin" to="." method="_on_3d_cursor_to_origin_mouse_entered"]
|
||||||
|
[connection signal="mouse_exited" from="3DCursorToOrigin" to="." method="_on_3d_cursor_to_origin_mouse_exited"]
|
||||||
|
[connection signal="pressed" from="3DCursorToOrigin" to="." method="_on_3d_cursor_to_origin_pressed"]
|
||||||
|
[connection signal="mouse_entered" from="Toggle3DCursor" to="." method="_on_toggle_3d_cursor_mouse_entered"]
|
||||||
|
[connection signal="mouse_exited" from="Toggle3DCursor" to="." method="_on_toggle_3d_cursor_mouse_exited"]
|
||||||
|
[connection signal="pressed" from="Toggle3DCursor" to="." method="_on_toggle_3d_cursor_pressed"]
|
||||||
7
source/addons/godot_3d_cursor/plugin.cfg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[plugin]
|
||||||
|
|
||||||
|
name="Godot 3D Cursor"
|
||||||
|
description="This plugin for the Godot Engine implements a 3D cursor, offering functionality similar to Blender’s 3D cursor.\n\nNote: Due to certain engine limitations, you must switch to a tab other than 3D (e.g., 2D, Script, or AssetLib) and back to 3D once after enabling this plugin, and also upon engine startup, to activate the plugin correctly.\n\nUsage: You can set the 3D cursor's position by using Shift + Right Click.\n\nVersion 1.2: The Pie Menu / Undo-Redo Update\n\nIn this update, I’ve added a Pie Menu, similar to Blender’s, which can be invoked with Shift + S. This menu displays commands found in the Command Palette (Ctrl + Shift + P) and offers faster access to desired functionality.\n\nAnother major feature in this version is the Undo-Redo functionality. This should be straightforward, except for the ‘Remove 3D Cursor from Scene’ command, which is intentionally not undoable, as it frees the cursor object itself."
|
||||||
|
author="Marco"
|
||||||
|
version="1.3.2"
|
||||||
|
script="plugin.gd"
|
||||||
488
source/addons/godot_3d_cursor/plugin.gd
Normal file
@ -0,0 +1,488 @@
|
|||||||
|
@tool
|
||||||
|
extends EditorPlugin
|
||||||
|
|
||||||
|
|
||||||
|
## This variable indicates whether the active tab is 3D
|
||||||
|
var is_in_3d_tab: bool = false
|
||||||
|
## The position of the mouse used to raycast into the 3D world
|
||||||
|
var mouse_position: Vector2
|
||||||
|
## The camera used for raycasting to calculate the position
|
||||||
|
## for the 3D cursor
|
||||||
|
var temp_camera: Camera3D
|
||||||
|
## The Editor Viewport used to get the mouse position
|
||||||
|
var editor_viewport: SubViewport
|
||||||
|
## The camera that displays what the user sees in the 3D editor tab
|
||||||
|
var editor_camera: Camera3D
|
||||||
|
## The root node of the active scene
|
||||||
|
var edited_scene_root: Node
|
||||||
|
## The scene used to instantiate the 3D Cursor
|
||||||
|
var cursor_scene: PackedScene
|
||||||
|
## The instance of the 3D Cursor
|
||||||
|
var cursor: Cursor3D
|
||||||
|
## The scene used to instantiate the pie menu for the 3D Cursor
|
||||||
|
var pie_menu_scene: PackedScene
|
||||||
|
## The instance of the pie menu for the 3D Cursor
|
||||||
|
var pie_menu: PieMenu
|
||||||
|
## A reference to the [EditorCommandPalette] singleton used to add
|
||||||
|
## some useful actions to the command palette such as '3D Cursor to Origin'
|
||||||
|
## or '3D Cursor to selected object' like in Blender
|
||||||
|
var command_palette: EditorCommandPalette
|
||||||
|
## The InputEvent holding the MouseButton event to trigger the
|
||||||
|
## set position function of the 3D Cursor
|
||||||
|
var input_event_set_3d_cursor: InputEventMouseButton
|
||||||
|
var input_event_show_pie_menu: InputEventKey
|
||||||
|
## The boolean that ensures the _recover_cursor function is executed once
|
||||||
|
var cursor_set: bool = false
|
||||||
|
## The instance of the Undo Redo class
|
||||||
|
var undo_redo: EditorUndoRedoManager
|
||||||
|
|
||||||
|
|
||||||
|
func _enter_tree() -> void:
|
||||||
|
# Register the switching of tabs in the editor. We only want the
|
||||||
|
# 3D Cursor functionality within the 3D tab
|
||||||
|
connect("main_screen_changed", _on_main_scene_changed)
|
||||||
|
# We want to place newly added Nodes that inherit [Node3D] at
|
||||||
|
# the location of the 3D Cursor. Therefore we listen to the
|
||||||
|
# node_added event
|
||||||
|
get_tree().connect("node_added", _on_node_added)
|
||||||
|
|
||||||
|
# Loading the 3D Cursor scene for later instancing
|
||||||
|
cursor_scene = preload("res://addons/godot_3d_cursor/3d_cursor.tscn")
|
||||||
|
pie_menu_scene = preload("res://addons/godot_3d_cursor/pie_menu.tscn")
|
||||||
|
|
||||||
|
command_palette = EditorInterface.get_command_palette()
|
||||||
|
# Adding the previously mentioned actions
|
||||||
|
command_palette.add_command("3D Cursor to Origin", "3D Cursor/3D Cursor to Origin", _3d_cursor_to_origin)
|
||||||
|
command_palette.add_command("3D Cursor to Selected Object", "3D Cursor/3D Cursor to Selected Object", _3d_cursor_to_selected_objects)
|
||||||
|
command_palette.add_command("Selected Object to 3D Cursor", "3D Cursor/Selected Object to 3D Cursor", _selected_object_to_3d_cursor)
|
||||||
|
# Adding the remove 3D Cursor in Scene action
|
||||||
|
command_palette.add_command("Remove 3D Cursor from Scene", "3D Cursor/Remove 3D Cursor from Scene", _remove_3d_cursor_from_scene)
|
||||||
|
command_palette.add_command("Toggle 3D Cursor", "3D Cursor/Toggle 3D Cursor", _toggle_3d_cursor)
|
||||||
|
|
||||||
|
editor_viewport = EditorInterface.get_editor_viewport_3d()
|
||||||
|
editor_camera = editor_viewport.get_camera_3d()
|
||||||
|
|
||||||
|
# Get the reference to the UndoRedo instance of the editor
|
||||||
|
undo_redo = get_undo_redo()
|
||||||
|
|
||||||
|
# Instantiating the pie menu for the 3D Cursor commands
|
||||||
|
pie_menu = pie_menu_scene.instantiate()
|
||||||
|
pie_menu.hide()
|
||||||
|
# Connecting the button events from the pie menu to the corresponding function
|
||||||
|
pie_menu.connect("cursor_to_origin_pressed", _3d_cursor_to_origin)
|
||||||
|
pie_menu.connect("cursor_to_selected_objects_pressed", _3d_cursor_to_selected_objects)
|
||||||
|
pie_menu.connect("selected_object_to_cursor_pressed", _selected_object_to_3d_cursor)
|
||||||
|
pie_menu.connect("remove_cursor_from_scene_pressed", _remove_3d_cursor_from_scene)
|
||||||
|
pie_menu.connect("toggle_cursor_pressed", _toggle_3d_cursor)
|
||||||
|
add_child(pie_menu)
|
||||||
|
|
||||||
|
|
||||||
|
# Setting up the InputMap so that we can set the 3D Cursor
|
||||||
|
# by Shift + Right Click
|
||||||
|
if not InputMap.has_action("3d_cursor_set_location"):
|
||||||
|
InputMap.add_action("3d_cursor_set_location")
|
||||||
|
input_event_set_3d_cursor = InputEventMouseButton.new()
|
||||||
|
input_event_set_3d_cursor.button_index = MOUSE_BUTTON_RIGHT
|
||||||
|
InputMap.action_add_event("3d_cursor_set_location", input_event_set_3d_cursor)
|
||||||
|
|
||||||
|
# Adding the action that shows the pie menu for the 3D Cursor commands.
|
||||||
|
if not InputMap.has_action("3d_cursor_show_pie_menu"):
|
||||||
|
InputMap.add_action("3d_cursor_show_pie_menu")
|
||||||
|
input_event_show_pie_menu = InputEventKey.new()
|
||||||
|
input_event_show_pie_menu.keycode = KEY_S
|
||||||
|
InputMap.action_add_event("3d_cursor_show_pie_menu", input_event_show_pie_menu)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
# Removing listeners
|
||||||
|
disconnect("main_screen_changed", _on_main_scene_changed)
|
||||||
|
get_tree().disconnect("node_added", _on_node_added)
|
||||||
|
|
||||||
|
pie_menu.disconnect("cursor_to_origin_pressed", _3d_cursor_to_origin)
|
||||||
|
pie_menu.disconnect("cursor_to_selected_objects_pressed", _3d_cursor_to_selected_objects)
|
||||||
|
pie_menu.disconnect("selected_object_to_cursor_pressed", _selected_object_to_3d_cursor)
|
||||||
|
pie_menu.disconnect("remove_cursor_from_scene_pressed", _remove_3d_cursor_from_scene)
|
||||||
|
pie_menu.disconnect("toggle_cursor_pressed", _toggle_3d_cursor)
|
||||||
|
|
||||||
|
# Removing the actions from the [EditorCommandPalette]
|
||||||
|
command_palette.remove_command("3D Cursor/3D Cursor to Origin")
|
||||||
|
command_palette.remove_command("3D Cursor/3D Cursor to Selected Object")
|
||||||
|
command_palette.remove_command("3D Cursor/Selected Object to 3D Cursor")
|
||||||
|
command_palette.remove_command("3D Cursor/Remove 3D Cursor from Scene")
|
||||||
|
command_palette.remove_command("3D Cursor/Toggle 3D Cursor")
|
||||||
|
command_palette = null
|
||||||
|
|
||||||
|
# Removing the '3D Cursor set Location' action from the InputMap
|
||||||
|
if InputMap.has_action("3d_cursor_set_location"):
|
||||||
|
InputMap.action_erase_event("3d_cursor_set_location", input_event_set_3d_cursor)
|
||||||
|
InputMap.erase_action("3d_cursor_set_location")
|
||||||
|
|
||||||
|
# Removing the 'Show Pie Menu' action from the InputMap
|
||||||
|
if InputMap.has_action("3d_cursor_show_pie_menu"):
|
||||||
|
InputMap.action_erase_event("3d_cursor_show_pie_menu", input_event_show_pie_menu)
|
||||||
|
InputMap.erase_action("3d_cursor_show_pie_menu")
|
||||||
|
|
||||||
|
# Removing and freeing the helper objects
|
||||||
|
if temp_camera != null and editor_viewport != null:
|
||||||
|
editor_viewport.remove_child(temp_camera)
|
||||||
|
temp_camera.queue_free()
|
||||||
|
|
||||||
|
# Deleting the 3D Cursor
|
||||||
|
if cursor != null:
|
||||||
|
cursor.queue_free()
|
||||||
|
cursor_scene = null
|
||||||
|
|
||||||
|
# Deleting the pie menu
|
||||||
|
if pie_menu != null:
|
||||||
|
pie_menu.queue_free()
|
||||||
|
pie_menu_scene = null
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
# Only allow setting the 3D Cursors location in 3D tab
|
||||||
|
if not is_in_3d_tab:
|
||||||
|
return
|
||||||
|
|
||||||
|
# If the action is not yet set up: return
|
||||||
|
if not InputMap.has_action("3d_cursor_set_location"):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Set the location of the 3D Cursor
|
||||||
|
if Input.is_key_pressed(KEY_SHIFT) and Input.is_action_just_pressed("3d_cursor_set_location"):
|
||||||
|
mouse_position = editor_viewport.get_mouse_position()
|
||||||
|
_get_selection()
|
||||||
|
|
||||||
|
if cursor == null or not cursor.is_inside_tree():
|
||||||
|
return
|
||||||
|
|
||||||
|
if Input.is_key_pressed(KEY_SHIFT) and Input.is_action_just_pressed("3d_cursor_show_pie_menu"):
|
||||||
|
pie_menu.visible = not pie_menu.visible
|
||||||
|
_set_visibility_toggle_label()
|
||||||
|
|
||||||
|
|
||||||
|
func _input(event: InputEvent) -> void:
|
||||||
|
if event.is_released():
|
||||||
|
return
|
||||||
|
|
||||||
|
if not pie_menu.visible:
|
||||||
|
return
|
||||||
|
|
||||||
|
if pie_menu.hit_any_button():
|
||||||
|
return
|
||||||
|
|
||||||
|
if event is InputEventKey and event.keycode == KEY_S and event.is_echo():
|
||||||
|
return
|
||||||
|
|
||||||
|
if event is InputEventKey or event is InputEventMouseButton:
|
||||||
|
pie_menu.hide()
|
||||||
|
# CAUTION: Do not mess with this statement! It can render your editor
|
||||||
|
# responseless. If it happens remove the plugin and restart the engine.
|
||||||
|
editor_viewport.set_input_as_handled()
|
||||||
|
|
||||||
|
|
||||||
|
## Checks whether the current active tab is named '3D'
|
||||||
|
## returns true if so, otherwise false
|
||||||
|
func _on_main_scene_changed(screen_name: String) -> void:
|
||||||
|
is_in_3d_tab = screen_name == "3D"
|
||||||
|
|
||||||
|
|
||||||
|
## Connected to the node_added event of the get_tree()
|
||||||
|
func _on_node_added(node: Node) -> void:
|
||||||
|
if not _cursor_available():
|
||||||
|
return
|
||||||
|
if EditorInterface.get_edited_scene_root() != cursor.owner:
|
||||||
|
return
|
||||||
|
if node.name == cursor.name:
|
||||||
|
return
|
||||||
|
if cursor.is_ancestor_of(node):
|
||||||
|
return
|
||||||
|
if not node is Node3D:
|
||||||
|
return
|
||||||
|
# Apply the position of the new node to the 3D Cursors position if the
|
||||||
|
# 3D cursor is available, the node is not the 3D cursor itself, the node
|
||||||
|
# is no descendant of the 3D Cursor and the node inherits [Node3D]
|
||||||
|
node.global_position = cursor.global_position
|
||||||
|
|
||||||
|
|
||||||
|
## Set the postion of the 3D Cursor to the origin (or [Vector3.ZERO])
|
||||||
|
func _3d_cursor_to_origin() -> void:
|
||||||
|
if not _cursor_available():
|
||||||
|
return
|
||||||
|
|
||||||
|
_create_undo_redo_action(
|
||||||
|
cursor,
|
||||||
|
"global_position",
|
||||||
|
Vector3.ZERO,
|
||||||
|
"Move 3D Cursor to Origin",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
## Set the position of the 3D Cursor to the selected object and if multiple
|
||||||
|
## Nodes are selected to the average of the positions of all selected nodes
|
||||||
|
## that inherit [Node3D]
|
||||||
|
func _3d_cursor_to_selected_objects() -> void:
|
||||||
|
if not _cursor_available():
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get the selection and through this the selected nodes as an Array of Nodes
|
||||||
|
var selection: EditorSelection = EditorInterface.get_selection()
|
||||||
|
var selected_nodes: Array[Node] = selection.get_selected_nodes()
|
||||||
|
|
||||||
|
if selected_nodes.is_empty():
|
||||||
|
return
|
||||||
|
if selected_nodes.size() == 1 and not selected_nodes.front() is Node3D:
|
||||||
|
return
|
||||||
|
|
||||||
|
# If only one Node is selected and it inherits Node3D set the position
|
||||||
|
# of the 3D Cursor to its position
|
||||||
|
if selected_nodes.size() == 1:
|
||||||
|
_create_undo_redo_action(
|
||||||
|
cursor,
|
||||||
|
"global_position",
|
||||||
|
selected_nodes.front().global_position,
|
||||||
|
"Move 3D Cursor to selected Object",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Introduce a count variable to keep track of the amount of valid positions
|
||||||
|
# to calculate the average position later
|
||||||
|
var count = 0
|
||||||
|
var position_sum: Vector3 = Vector3.ZERO
|
||||||
|
|
||||||
|
for node in selected_nodes:
|
||||||
|
if not (node is Node3D or node is Cursor3D):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# If the node is a valid object increment count and add the position
|
||||||
|
# to position_sum
|
||||||
|
count += 1
|
||||||
|
position_sum += node.global_position
|
||||||
|
|
||||||
|
if count == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Calculate the average position for multiple selected Nodes and set
|
||||||
|
# the 3D Cursor to this position
|
||||||
|
var average_position = position_sum / count
|
||||||
|
_create_undo_redo_action(
|
||||||
|
cursor,
|
||||||
|
"global_position",
|
||||||
|
average_position,
|
||||||
|
"Move 3D Cursor to selected Objects",
|
||||||
|
)
|
||||||
|
cursor.global_position = average_position
|
||||||
|
|
||||||
|
|
||||||
|
## Set the position of the selected object that inherits [Node3D]
|
||||||
|
## to the position of the 3D Cursor. If multiple nodes are selected the first
|
||||||
|
## valid node (i.e. a node that inherits [Node3D]) will be moved to
|
||||||
|
## position of the 3D Cursor. This funcitonality is disabled if the cursor
|
||||||
|
## is not set or hidden in the scene.
|
||||||
|
func _selected_object_to_3d_cursor() -> void:
|
||||||
|
if not _cursor_available():
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get the selection and through this the selected nodes as an Array of Nodes
|
||||||
|
var selection: EditorSelection = EditorInterface.get_selection()
|
||||||
|
var selected_nodes: Array[Node] = selection.get_selected_nodes()
|
||||||
|
|
||||||
|
if selected_nodes.is_empty():
|
||||||
|
return
|
||||||
|
if selected_nodes.size() == 1 and not selected_nodes.front() is Node3D:
|
||||||
|
return
|
||||||
|
selected_nodes = selected_nodes.filter(func(node): return node is Node3D and not node is Cursor3D)
|
||||||
|
if selected_nodes.is_empty():
|
||||||
|
return
|
||||||
|
|
||||||
|
_create_undo_redo_action(
|
||||||
|
selected_nodes.front(),
|
||||||
|
"global_position",
|
||||||
|
cursor.global_position,
|
||||||
|
"Move Object to 3D Cursor"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
## Disable the 3D Cursor to prevent the node placement at the position of
|
||||||
|
## the 3D Cursor.
|
||||||
|
func _toggle_3d_cursor() -> void:
|
||||||
|
if not _cursor_available(true):
|
||||||
|
return
|
||||||
|
|
||||||
|
cursor.visible = not cursor.visible
|
||||||
|
_set_visibility_toggle_label()
|
||||||
|
|
||||||
|
|
||||||
|
## Sets the correct label on the toggle visibility button in the pie menu
|
||||||
|
func _set_visibility_toggle_label() -> void:
|
||||||
|
pie_menu.change_toggle_label(cursor.visible)
|
||||||
|
|
||||||
|
|
||||||
|
## Remove every 3D Cursor from the scene including the active one.
|
||||||
|
func _remove_3d_cursor_from_scene() -> void:
|
||||||
|
if cursor == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Remove the active 3D Cursor
|
||||||
|
cursor.queue_free()
|
||||||
|
cursor = null
|
||||||
|
|
||||||
|
# Get the root nodes children to filter for old instances of [Cursor3D]
|
||||||
|
var root_children = edited_scene_root.get_children()
|
||||||
|
if root_children.any(func(node): return node is Cursor3D):
|
||||||
|
# Iterate over all old instances and free them
|
||||||
|
for old_cursor: Cursor3D in root_children.filter(func(node): return node is Cursor3D):
|
||||||
|
old_cursor.queue_free()
|
||||||
|
|
||||||
|
|
||||||
|
## Check whether the 3D Cursor is set up and ready for use. A hidden 3D Cursor
|
||||||
|
## should also disable its functionality. Therefore this function yields false
|
||||||
|
## if the cursor is hidden in the scene
|
||||||
|
func _cursor_available(ignore_hidden = false) -> bool:
|
||||||
|
# CAUTION: Do not mess with this statement! It can render your editor
|
||||||
|
# responseless. If it happens remove the plugin and restart the engine.
|
||||||
|
editor_viewport.set_input_as_handled()
|
||||||
|
if cursor == null:
|
||||||
|
return false
|
||||||
|
if not cursor.is_inside_tree():
|
||||||
|
return false
|
||||||
|
if ignore_hidden and not cursor.is_visible_in_tree():
|
||||||
|
return true
|
||||||
|
if not cursor.is_visible_in_tree():
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
## This function uses raycasting to determine the position of the mouse click
|
||||||
|
## to set the position of the 3D Cursor. This means that it is necessary for
|
||||||
|
## the clicked on objects to have a collider the raycast can hit
|
||||||
|
func _get_selection() -> void:
|
||||||
|
# If the scene is switched stop
|
||||||
|
if edited_scene_root != null and edited_scene_root != EditorInterface.get_edited_scene_root() and cursor != null:
|
||||||
|
# Reset scene root, viewport and camera for new scene
|
||||||
|
edited_scene_root = null
|
||||||
|
editor_viewport = EditorInterface.get_editor_viewport_3d()
|
||||||
|
editor_camera = editor_viewport.get_camera_3d()
|
||||||
|
|
||||||
|
# Clear the 3D Cursor on the old screen.
|
||||||
|
cursor.queue_free()
|
||||||
|
cursor = null
|
||||||
|
|
||||||
|
if not cursor_set:
|
||||||
|
_recover_cursor()
|
||||||
|
|
||||||
|
if temp_camera == null:
|
||||||
|
# Set up the temp_camera to resemble the one of the 3D Viewport
|
||||||
|
_create_temp_camera()
|
||||||
|
|
||||||
|
# Get the transform of the camera from the 3D Viewport
|
||||||
|
var editor_camera_transform = _get_editor_camera_transform()
|
||||||
|
|
||||||
|
# Position the temp_camera so that it is exactly where the 3D Viewport
|
||||||
|
# camera is located
|
||||||
|
temp_camera.global_transform = editor_camera_transform
|
||||||
|
|
||||||
|
# if the editor_camera_transform is Transform3D.IDENTITY that means
|
||||||
|
# that for some reason the editor_camera is null.
|
||||||
|
if editor_camera_transform == Transform3D.IDENTITY:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Set up the raycast parameters
|
||||||
|
var ray_origin = temp_camera.project_ray_origin(mouse_position)
|
||||||
|
var ray_end = temp_camera.project_position(mouse_position, 1000)
|
||||||
|
var ray_length = 1000
|
||||||
|
|
||||||
|
if edited_scene_root == null:
|
||||||
|
edited_scene_root = EditorInterface.get_edited_scene_root()
|
||||||
|
|
||||||
|
# The space state where the raycast should be performed in
|
||||||
|
var space_state = edited_scene_root.get_world_3d().direct_space_state
|
||||||
|
|
||||||
|
# Perform a raycast with the parameters above and store the result
|
||||||
|
var result = space_state.intersect_ray(PhysicsRayQueryParameters3D.create(ray_origin, ray_end))
|
||||||
|
|
||||||
|
var just_created: bool = false
|
||||||
|
|
||||||
|
# When the cursor is not yet created instantiate it, add it to the scene
|
||||||
|
# and position it at the collision detected by the raycast
|
||||||
|
if cursor == null:
|
||||||
|
cursor = cursor_scene.instantiate()
|
||||||
|
edited_scene_root.add_child(cursor)
|
||||||
|
cursor.owner = edited_scene_root
|
||||||
|
just_created = true
|
||||||
|
|
||||||
|
# If the cursor is not in the node tree at this point it means that the
|
||||||
|
# user probably deleted it. Then add it again
|
||||||
|
if not cursor.is_inside_tree():
|
||||||
|
edited_scene_root.add_child(cursor)
|
||||||
|
cursor.owner = edited_scene_root
|
||||||
|
just_created = true
|
||||||
|
|
||||||
|
# No collision means do nothing
|
||||||
|
if result.is_empty():
|
||||||
|
return
|
||||||
|
|
||||||
|
if just_created:
|
||||||
|
# Position the 3D Cursor to the position of the collision
|
||||||
|
cursor.global_transform.origin = result.position
|
||||||
|
return
|
||||||
|
|
||||||
|
_create_undo_redo_action(
|
||||||
|
cursor,
|
||||||
|
"global_position",
|
||||||
|
result.position,
|
||||||
|
"Set Position for 3D Cursor"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
## This function creates the temp_camera and sets it up so that it resembles
|
||||||
|
## the camera from 3D Tab itself
|
||||||
|
func _create_temp_camera() -> void:
|
||||||
|
temp_camera = Camera3D.new()
|
||||||
|
temp_camera.hide()
|
||||||
|
|
||||||
|
# Add the temp_camera to the editor_viewport so that we can perform raycasts
|
||||||
|
# later on
|
||||||
|
editor_viewport.add_child(temp_camera)
|
||||||
|
|
||||||
|
# These are the most important settings the temp_camera needs to copy
|
||||||
|
# from the editor_camera so that their image is congruent
|
||||||
|
temp_camera.fov = editor_camera.fov
|
||||||
|
temp_camera.near = editor_camera.near
|
||||||
|
temp_camera.far = editor_camera.far
|
||||||
|
|
||||||
|
|
||||||
|
## This function returns the transform of the camera from the 3D Editor itself
|
||||||
|
func _get_editor_camera_transform() -> Transform3D:
|
||||||
|
if editor_camera != null:
|
||||||
|
return editor_camera.get_camera_transform()
|
||||||
|
return Transform3D.IDENTITY
|
||||||
|
|
||||||
|
|
||||||
|
## This function recovers any 3D Cursor present in the scene if you reload
|
||||||
|
## the project
|
||||||
|
func _recover_cursor() -> void:
|
||||||
|
# This boolean ensures this function is run exactly once
|
||||||
|
cursor_set = true
|
||||||
|
# Gets the children of the active scenes root node
|
||||||
|
var root_children = EditorInterface.get_edited_scene_root().get_children()
|
||||||
|
# Checks whether there are any nodes of type [Cursor3D] in the list of
|
||||||
|
# children
|
||||||
|
if root_children.any(func(node): return node is Cursor3D):
|
||||||
|
# Get the first and probably only instance of [Cursor3D] and assign
|
||||||
|
# it to the cursor variable. Now the 3D Cursor is considered recovered
|
||||||
|
cursor = root_children.filter(func(node): return node is Cursor3D).front()
|
||||||
|
|
||||||
|
|
||||||
|
func _create_undo_redo_action(node: Node3D, property: String, value: Variant, action_name: String = "") -> void:
|
||||||
|
if node == null or property.is_empty() or value == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
if action_name.is_empty():
|
||||||
|
action_name = "Set " + property + " for " + node.name
|
||||||
|
|
||||||
|
undo_redo.create_action(action_name)
|
||||||
|
var old_value: Variant = node.get(property)
|
||||||
|
undo_redo.add_do_property(node, property, value)
|
||||||
|
undo_redo.add_undo_property(node, property, old_value)
|
||||||
|
undo_redo.commit_action()
|
||||||
1
source/addons/godot_3d_cursor/plugin.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://bjeulwhnkq10f
|
||||||
BIN
source/addons/godot_3d_cursor/selection_indicator.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
40
source/addons/godot_3d_cursor/selection_indicator.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://r1rpga7n1quy"
|
||||||
|
path="res://.godot/imported/selection_indicator.png-2775b0425d2acc692b5fb62566ad8521.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/godot_3d_cursor/selection_indicator.png"
|
||||||
|
dest_files=["res://.godot/imported/selection_indicator.png-2775b0425d2acc692b5fb62566ad8521.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
source/addons/godot_3d_cursor/selection_ring.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
40
source/addons/godot_3d_cursor/selection_ring.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dd7qbrp08e8qe"
|
||||||
|
path="res://.godot/imported/selection_ring.png-dfbd0ecaedb53139c0c4b6c57699fb8f.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/godot_3d_cursor/selection_ring.png"
|
||||||
|
dest_files=["res://.godot/imported/selection_ring.png-dfbd0ecaedb53139c0c4b6c57699fb8f.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
@ -64,8 +64,8 @@ func toggle_3d_collision_shape_visibility() -> void:
|
|||||||
or node is GPUParticlesCollisionBox3D \
|
or node is GPUParticlesCollisionBox3D \
|
||||||
or node is GPUParticlesCollisionHeightField3D \
|
or node is GPUParticlesCollisionHeightField3D \
|
||||||
or node is GPUParticlesCollisionSDF3D \
|
or node is GPUParticlesCollisionSDF3D \
|
||||||
or node is GPUParticlesCollisionSphere3D \
|
or node is GPUParticlesCollisionSphere3D:# \
|
||||||
or node is CSGPrimitive3D:
|
#or node is CSGPrimitive3D:
|
||||||
# remove and re-add the node to the tree to force a redraw
|
# remove and re-add the node to the tree to force a redraw
|
||||||
# https://github.com/godotengine/godot/blob/26b1fd0d842fa3c2f090ead47e8ea7cd2d6515e1/scene/3d/collision_object_3d.cpp#L39
|
# https://github.com/godotengine/godot/blob/26b1fd0d842fa3c2f090ead47e8ea7cd2d6515e1/scene/3d/collision_object_3d.cpp#L39
|
||||||
var parent: Node = node.get_parent()
|
var parent: Node = node.get_parent()
|
||||||
|
|||||||
27
source/addons/proto_shape/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# ProtoShape tooling
|
||||||
|
|
||||||
|
## Shapes
|
||||||
|
|
||||||
|
- [ProtoRamp](proto_ramp/README.md)
|
||||||
|
|
||||||
|
## Gizmos
|
||||||
|
|
||||||
|
The gizmo for `ProtoRamp` supports setting 3 properties:
|
||||||
|
|
||||||
|
- Width
|
||||||
|
- Height
|
||||||
|
- Depth
|
||||||
|
|
||||||
|
It utilizes `ProtoGizmoUtils` for advanced 3D math calculations and plane projections to get the desired handle drag offset and set the properties accordingly.
|
||||||
|
|
||||||
|
### Undo/Redo support
|
||||||
|
|
||||||
|
[ProtoRampGizmos](proto_ramp/proto_ramp_gizmos.gd) supports scene-wide undo/redo functionality. It uses the `EditorUndoRedoManager` to set up ramp properties, so the editor takes gizmo-based modifications into account! Editor now warns you to save on exit if you have unsaved changes made with the gizmos.
|
||||||
|
|
||||||
|
### [ProtoGizmoWrapper](proto_gizmo_wrapper/README.md)
|
||||||
|
|
||||||
|
`ProtoGizmoWrapper` is an advanced wrapper for creating gizmo functionality for custom 3D nodes. It exposes 2 signals to implement custom gizmos for your nodes to *redraw* and *update* the properties of your node.
|
||||||
|
|
||||||
|
The gizmo is an `EditorNode3DGizmoPlugin` and is visible when the `ProtoRamp` node or a children of `ProtoGizmoWrapper` is selected. Selection hightlights the mesh with a transparent blue color and shows handles, which you can drag to adjust the shape.
|
||||||
|
|
||||||
|
https://github.com/HLCaptain/proto-shape/assets/22623259/1db3f18d-4d90-400f-9d33-7b03d44f62c7
|
||||||
BIN
source/addons/proto_shape/icon/proto-gizmo-handler.png
Normal file
|
After Width: | Height: | Size: 1007 B |
@ -0,0 +1,41 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bkrb0hpbnnlve"
|
||||||
|
path.s3tc="res://.godot/imported/proto-gizmo-handler.png-4cc70ab2e8b20344f35efde1c0e3d8c1.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/proto_shape/icon/proto-gizmo-handler.png"
|
||||||
|
dest_files=["res://.godot/imported/proto-gizmo-handler.png-4cc70ab2e8b20344f35efde1c0e3d8c1.s3tc.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=2
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=0
|
||||||
51
source/addons/proto_shape/icon/proto-gizmo-handler.svg
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
version="1.1"
|
||||||
|
id="svg2"
|
||||||
|
sodipodi:docname="proto-gizmo-handler.svg"
|
||||||
|
inkscape:version="1.4-beta (62f545ba5e, 2024-04-22)"
|
||||||
|
inkscape:export-filename="proto-gizmo-handlers.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview2"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:zoom="20.771262"
|
||||||
|
inkscape:cx="17.837145"
|
||||||
|
inkscape:cy="13.359805"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1369"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg2" />
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
fill-opacity="0.294"
|
||||||
|
id="circle1"
|
||||||
|
style="stroke-width:2.4"
|
||||||
|
r="12" />
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
fill="#ff5f5f"
|
||||||
|
stroke="#ffffff"
|
||||||
|
id="circle2"
|
||||||
|
style="fill:#8da5ff;fill-opacity:1;stroke-width:2.4"
|
||||||
|
r="8.3999996" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,43 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dpo2412p634n8"
|
||||||
|
path="res://.godot/imported/proto-gizmo-handler.svg-450f3c4251bc782c6a7cb75ed4928a42.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/proto_shape/icon/proto-gizmo-handler.svg"
|
||||||
|
dest_files=["res://.godot/imported/proto-gizmo-handler.svg-450f3c4251bc782c6a7cb75ed4928a42.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
||||||
BIN
source/addons/proto_shape/icon/proto-gizmo-wrapper-icon-mini.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://5cxcoew7dwry"
|
||||||
|
path="res://.godot/imported/proto-gizmo-wrapper-icon-mini.png-1a69b62ae400df904dfb4e09a5f63122.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/proto_shape/icon/proto-gizmo-wrapper-icon-mini.png"
|
||||||
|
dest_files=["res://.godot/imported/proto-gizmo-wrapper-icon-mini.png-1a69b62ae400df904dfb4e09a5f63122.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
source/addons/proto_shape/icon/proto-gizmo-wrapper-icon.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://yd88id1ixiwv"
|
||||||
|
path="res://.godot/imported/proto-gizmo-wrapper-icon.png-74f8ebc9cdc56ecf6bd0c731cb0bf5b3.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/proto_shape/icon/proto-gizmo-wrapper-icon.png"
|
||||||
|
dest_files=["res://.godot/imported/proto-gizmo-wrapper-icon.png-74f8ebc9cdc56ecf6bd0c731cb0bf5b3.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
81
source/addons/proto_shape/icon/proto-gizmo-wrapper-icon.svg
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333333 4.2333333"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
sodipodi:docname="proto-gizmo-wrapper-icon.svg"
|
||||||
|
inkscape:version="1.4-beta (62f545ba5e, 2024-04-22)"
|
||||||
|
inkscape:export-filename="proto-gizmo-wrapper-icon-mini.png"
|
||||||
|
inkscape:export-xdpi="144"
|
||||||
|
inkscape:export-ydpi="144"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="true"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:zoom="32"
|
||||||
|
inkscape:cx="7"
|
||||||
|
inkscape:cy="5.796875"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1369"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false" />
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="matrix(0.01570519,0,0,0.01570519,-0.01085763,-0.01086595)">
|
||||||
|
<path
|
||||||
|
id="path2"
|
||||||
|
style="display:none;fill:none;fill-opacity:0.137324;stroke:#000000;stroke-width:11.1125;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.3;paint-order:fill markers stroke"
|
||||||
|
inkscape:transform-center-x="-2.1913894e-06"
|
||||||
|
d="m 125.59893,11.847581 -5.87813,30.705801 c -0.31705,1.656156 -4.01587,2.484026 -4.9426,1.075243 L 97.475068,17.325206 c -3.659186,-5.562533 -19.740202,1.18625 -18.394101,7.706781 l 6.310354,30.567427 c 0.344133,1.666987 -2.754458,3.911949 -4.162986,2.956089 L 55.099247,40.823705 C 49.607182,37.096662 37.314199,49.388504 41.041586,54.880057 l 17.733448,26.126658 c 0.955949,1.408397 -1.289222,4.5067 -2.956364,4.1626 L 25.248399,78.859547 c -6.521137,-1.345976 -13.270548,14.733546 -7.707496,18.39239 l 26.305865,17.301513 c 1.408914,0.92665 0.580966,4.62513 -1.075345,4.94214 l -30.708656,5.87759 c -7.8363854,1.49989 -7.6699653,18.5043 0,19.97232 l 30.708656,5.87758 c 1.656311,0.31703 2.484259,4.0155 1.075345,4.94215 l -26.305865,17.30151 c -5.563052,3.65884 1.186357,19.73838 7.707496,18.39239 l 30.570271,-6.30978 c 1.667142,-0.34409 3.912313,2.7542 2.956364,4.16261 l -17.733448,26.12667 c -3.727386,5.49155 8.565594,17.78339 14.057661,14.05636 l 26.129088,-17.73182 c 1.408528,-0.95585 4.507119,1.28911 4.162986,2.9561 l -6.310354,30.56742 c -1.346101,6.52053 14.734915,13.26931 18.394101,7.70678 L 114.7782,227.09006 c 0.92673,-1.40878 4.62555,-0.58092 4.9426,1.07524 l 5.87813,30.7058 c 1.50001,7.83565 18.50603,7.66924 19.97418,0 l 5.87812,-30.7058 c 0.31705,-1.65616 4.01588,-2.48402 4.94261,-1.07524 l 17.30312,26.30341 c 3.65919,5.56253 19.74021,-1.18625 18.39411,-7.70678 l -6.31037,-30.56742 c -0.34413,-1.66699 2.75446,-3.91195 4.16299,-2.9561 l 26.12909,17.73182 c 5.49208,3.72703 17.78506,-8.56481 14.05767,-14.05636 L 212.397,189.71196 c -0.95594,-1.40841 1.28922,-4.5067 2.95636,-4.16261 l 30.57027,6.30978 c 6.52114,1.34599 13.27056,-14.73355 7.70749,-18.39239 l -26.30586,-17.30151 c -1.4089,-0.92665 -0.58097,-4.62512 1.07534,-4.94215 l 30.70867,-5.87758 c 8.68099,-1.66153 5.98046,-18.82752 0.2815,-19.9183 l -30.99017,-5.93161 c -1.65629,-0.31701 -2.48424,-4.01549 -1.07534,-4.94214 L 253.7681,97.161909 c 5.54137,-3.64458 -1.10705,-19.692922 -7.60276,-18.35212 l -30.81198,6.36 c -1.66727,0.344146 -3.91238,-2.754572 -2.95636,-4.163074 l 17.75572,-26.159356 c 3.72463,-5.48746 -8.55926,-17.770207 -14.04724,-14.045928 l -26.16179,17.754072 c -1.40863,0.955933 -4.50763,-1.288982 -4.16345,-2.956089 l 6.36057,-30.809108 c 1.34094,-6.495104 -14.70888,-13.142911 -18.35379,-7.602051 l -17.39318,26.44037 c -0.92673,1.408783 -4.62556,0.580911 -4.94261,-1.075243 l -5.93215,-30.987289 c -1.37881,-7.2024177 -18.51277,-7.0703436 -19.92015,0.281488 z"
|
||||||
|
sodipodi:nodetypes="sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" />
|
||||||
|
<path
|
||||||
|
id="path2-5"
|
||||||
|
style="display:none;fill:#ffffff;fill-opacity:1;stroke:#b4b4b4;stroke-width:24.3401;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
inkscape:transform-center-x="-2.363361e-06"
|
||||||
|
d="m 113.09293,23.444456 c -8.04551,1.603632 -16.995544,-4.331742 -24.581627,-1.208716 -7.611041,3.1333 -9.804775,13.670088 -16.66062,18.224526 -6.846479,4.548216 -17.412977,2.471313 -23.22596,8.282489 -5.816562,5.814755 -3.742882,16.387597 -8.294811,23.237685 -4.552052,6.850272 -15.077148,9.044823 -18.210588,16.649358 -3.126689,7.588152 2.781683,16.540592 1.192533,24.592352 -1.589747,8.05478 -10.449551,14.09338 -10.450495,22.30354 -9.44e-4,8.21356 8.860022,14.25693 10.449696,22.31519 1.58763,8.04789 -4.314249,16.99512 -1.190745,24.58017 3.132678,7.60732 13.654906,9.81017 18.20769,16.6627 4.549095,6.84698 2.485402,17.41054 8.298101,23.22328 5.812659,5.8127 16.376118,3.74916 23.223055,8.29823 6.852584,4.55282 9.055571,15.07502 16.662965,18.20769 7.585061,3.12347 16.532276,-2.77838 24.580176,-1.19077 8.05829,1.58965 14.10171,10.45057 22.3153,10.44961 8.21012,-9.6e-4 14.24869,-8.8607 22.30342,-10.45043 8.05179,-1.58914 17.00425,4.31929 24.59243,1.19261 7.60459,-3.13344 9.7992,-13.65855 16.6495,-18.21064 6.85002,-4.55191 17.42277,-2.47837 23.23744,-8.29492 5.8112,-5.81308 3.73417,-16.37971 8.28245,-23.22624 4.55438,-6.85573 15.09109,-9.04929 18.22442,-16.66019 3.12311,-7.58608 -2.81217,-16.53618 -1.20851,-24.58172 1.60996,-8.07711 10.5799,-14.09102 10.58251,-22.32702 0.003,-8.21804 -8.95934,-14.22147 -10.54533,-22.28502 -1.58898,-8.07874 4.46221,-17.053786 1.32245,-24.665144 -3.14287,-7.61889 -13.76673,-9.723175 -18.34604,-16.575549 -4.57477,-6.845575 -2.46622,-17.446457 -8.28816,-23.268438 -5.8219,-5.821946 -16.4227,-3.713547 -23.26824,-8.28828 -6.85251,-4.579395 -8.95698,-15.203401 -16.57606,-18.346244 -7.61133,-3.139645 -16.58622,2.911713 -24.6649,1.322784 -8.06357,-1.585959 -14.06696,-10.548033 -22.28502,-10.545443 -8.23601,0.0026 -14.2499,8.972617 -22.32703,10.58255 z"
|
||||||
|
sodipodi:nodetypes="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" />
|
||||||
|
<path
|
||||||
|
sodipodi:type="star"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#b4b4b4;stroke-width:1.61;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;paint-order:fill markers stroke"
|
||||||
|
id="path1"
|
||||||
|
inkscape:flatsided="false"
|
||||||
|
sodipodi:sides="12"
|
||||||
|
sodipodi:cx="8"
|
||||||
|
sodipodi:cy="8"
|
||||||
|
sodipodi:r1="7.25"
|
||||||
|
sodipodi:r2="5.8363571"
|
||||||
|
sodipodi:arg1="-1.5707963"
|
||||||
|
sodipodi:arg2="-1.3089969"
|
||||||
|
inkscape:rounded="0.19871627"
|
||||||
|
inkscape:randomized="0"
|
||||||
|
d="m 8.0000002,0.75 c 0.439068,1e-8 1.0864532,1.4988728 1.5105603,1.612512 C 9.9346676,2.4761511 11.244756,1.5017819 11.625,1.7213159 c 0.380244,0.219534 0.19146,1.8412886 0.501928,2.1517565 0.310468,0.310468 1.932222,0.1216837 2.151756,0.5019278 0.219534,0.380244 -0.754835,1.6903325 -0.641196,2.1144396 C 13.751127,6.9135469 15.25,7.5609322 15.25,8.0000002 c 0,0.439068 -1.498873,1.0864532 -1.612512,1.5105603 -0.113639,0.4241071 0.86073,1.7341955 0.641196,2.1144395 -0.219534,0.380244 -1.841288,0.19146 -2.151756,0.501928 C 11.81646,12.437396 12.005244,14.05915 11.625,14.278684 11.244756,14.498218 9.9346673,13.523849 9.5105602,13.637488 9.0864531,13.751127 8.4390678,15.25 7.9999998,15.25 7.5609318,15.25 6.9135466,13.751127 6.4894395,13.637488 6.0653324,13.523849 4.7552438,14.498218 4.3749998,14.278684 3.9947558,14.05915 4.1835401,12.437396 3.8730722,12.126928 3.5626043,11.81646 1.9408497,12.005244 1.7213157,11.625 1.5017818,11.244756 2.476151,9.9346673 2.3625119,9.5105602 2.2488727,9.0864531 0.74999999,8.4390678 0.75,7.9999998 0.75000001,7.5609318 2.2488728,6.9135466 2.362512,6.4894395 2.4761511,6.0653324 1.5017819,4.7552438 1.7213159,4.3749998 1.9408499,3.9947558 3.5626045,4.1835401 3.8730724,3.8730722 4.1835404,3.5626043 3.9947561,1.9408497 4.3750002,1.7213157 4.7552442,1.5017818 6.0653327,2.476151 6.4894398,2.3625119 6.9135469,2.2488727 7.5609322,0.74999999 8.0000002,0.75 Z"
|
||||||
|
transform="matrix(16.732069,0,0,16.731613,1.6118621,1.6118507)" />
|
||||||
|
<circle
|
||||||
|
style="display:inline;fill:#ff5f5f;fill-opacity:1;stroke:none;stroke-width:8.81507;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
|
||||||
|
id="path3"
|
||||||
|
cx="135.46632"
|
||||||
|
cy="135.46684"
|
||||||
|
r="67.387489" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 8.6 KiB |
@ -0,0 +1,43 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bhgl0xyyytune"
|
||||||
|
path="res://.godot/imported/proto-gizmo-wrapper-icon.svg-3927e78352256edd1286e1ee01c9bee9.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/proto_shape/icon/proto-gizmo-wrapper-icon.svg"
|
||||||
|
dest_files=["res://.godot/imported/proto-gizmo-wrapper-icon.svg-3927e78352256edd1286e1ee01c9bee9.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
||||||
BIN
source/addons/proto_shape/icon/proto-ramp-icon.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
40
source/addons/proto_shape/icon/proto-ramp-icon.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cltx6vocg7rfm"
|
||||||
|
path="res://.godot/imported/proto-ramp-icon.png-3135a56706d7082ddb1524561da4bad1.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/proto_shape/icon/proto-ramp-icon.png"
|
||||||
|
dest_files=["res://.godot/imported/proto-ramp-icon.png-3135a56706d7082ddb1524561da4bad1.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
source/addons/proto_shape/icon/proto-ramp.psd
Normal file
BIN
source/addons/proto_shape/icon/proto-shape-icon.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
40
source/addons/proto_shape/icon/proto-shape-icon.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bhqug4bqtc5ay"
|
||||||
|
path="res://.godot/imported/proto-shape-icon.png-9ff7624efc04c6128c436057018bb46d.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/proto_shape/icon/proto-shape-icon.png"
|
||||||
|
dest_files=["res://.godot/imported/proto-shape-icon.png-9ff7624efc04c6128c436057018bb46d.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
6143
source/addons/proto_shape/icon/proto-shape-icon.svg
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
43
source/addons/proto_shape/icon/proto-shape-icon.svg.import
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cvundrxfgnyhn"
|
||||||
|
path="res://.godot/imported/proto-shape-icon.svg-8b4b44dede01bdec8a626e48489697a9.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/proto_shape/icon/proto-shape-icon.svg"
|
||||||
|
dest_files=["res://.godot/imported/proto-shape-icon.svg-8b4b44dede01bdec8a626e48489697a9.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
||||||
7
source/addons/proto_shape/plugin.cfg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[plugin]
|
||||||
|
|
||||||
|
name="ProtoShape"
|
||||||
|
description="ProtoShape is a Godot plugin that adds a library of dynamic shapes like ramps and stairs to quickly block out your maps and iterate on your ideas. Create your custom dynamic shapes more easily with the included Gizmo system."
|
||||||
|
author="Illyan"
|
||||||
|
version="1.1.5"
|
||||||
|
script="proto_shape.gd"
|
||||||
39
source/addons/proto_shape/proto_gizmo/README.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# ProtoGizmo
|
||||||
|
|
||||||
|
ProtoGizmo is an `EditorNode3DGizmoPlugin` that provides a base for creating custom gizmos in the Godot editor. It is used to create custom gizmos for the `ProtoShape` addon. With the use of `ProtoGizmoWrapper`, you can create custom gizmos for your 3D nodes.
|
||||||
|
|
||||||
|
## Default materials
|
||||||
|
|
||||||
|
- `proto_handler` - Same as internal "handlers" material for gizmo handles, but blue instead of redish color.
|
||||||
|
- `selected` - Material for selected nodes (bluish transparent color).
|
||||||
|
- `main` - Base redish color material for general or debuging use. (Used for drawing camera projected debug planes).
|
||||||
|
|
||||||
|
## ProtoGizmoUtils
|
||||||
|
|
||||||
|
ProtoGizmoUtils are advanced 3D math utilities used for calculating handle offsets and projecting planes for gizmos based on the camera position and screen coordinates. The projected plane, the user can drag the handles on can be drawn via `ProtoGizmoUtils::debug_draw_handle_grid` on gizmo *redraw*.
|
||||||
|
|
||||||
|
### Calculate handle offset in 3D space
|
||||||
|
|
||||||
|
`ProtoGizmoUtils::get_handle_offset` calculates the offset of the dragged handle in the 3D space on a camera projected plane.
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
|
||||||
|
- `camera: Camera3D` - Camera used for calculating the plane the `screen_pos` is projected on.
|
||||||
|
- `screen_pos: Vector2` - Screen position of the mouse cursor.
|
||||||
|
- `local_gizmo_position: Vector3` - Gizmo position in the node's local space.
|
||||||
|
- `local_offset_axis: Vector3` - Axis the handle can be dragged on in node's local space. Used for calculating the plane the `screen_pos` is projected on.
|
||||||
|
- `node: Node3D` - Node the gizmo is attached to. Used to get global transform and position.
|
||||||
|
|
||||||
|
Returns: `Vector3` - Offset of the dragged handle in the 3D space on a camera projected plane in global space.
|
||||||
|
|
||||||
|
Unfortunately, to get the proper offsets, projections, offsets and drawing of the gizmos, some transitions must be made between the local and global space to get the result. The `camera.position` is in global space, so the `local_gizmo_position` and `local_offset_axis` must be transformed to global space to get the proper offset from projecting `screen_pos` onto a global space plane.
|
||||||
|
|
||||||
|
#### Get camera oriented plane
|
||||||
|
|
||||||
|
The global plane is created by using 3 points:
|
||||||
|
|
||||||
|
- `global_gizmo_position` - The gizmo position in global space, transformed from `local_gizmo_position` with the Node3D's `global_position` and `global_transform.basis`.
|
||||||
|
- `global_offset_axis` - The axis the handle can be dragged on in global space, transformed from `local_offset_axis` with the Node3D's `global_transform.basis`.
|
||||||
|
- A point on the line defined by `camera.position` closest to another line defined by `global_gizmo_position` and `global_offset_axis`. The line with point `camera.position` is perpendicular to the other line and its axis is the plane's normal vector, so the plane is always oriented to the camera. The calculation is found in `ProtoGizmoUtils::get_camera_oriented_plane`.
|
||||||
|
|
||||||
|
The plane can be visualized by drawing a grid with `ProtoGizmoUtils::debug_draw_handle_grid`.
|
||||||
81
source/addons/proto_shape/proto_gizmo/proto_gizmo.gd
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
extends EditorNode3DGizmoPlugin
|
||||||
|
|
||||||
|
const ProtoGizmoWrapper = preload("res://addons/proto_shape/proto_gizmo_wrapper/proto_gizmo_wrapper.gd")
|
||||||
|
const ProtoRamp = preload("res://addons/proto_shape/proto_ramp/proto_ramp.gd")
|
||||||
|
|
||||||
|
# Must be initialized externally by ProtoShape plugin
|
||||||
|
var undo_redo: EditorUndoRedoManager
|
||||||
|
|
||||||
|
signal snapping_changed(snapping: bool)
|
||||||
|
signal fine_snapping_changed(fine_snapping: bool)
|
||||||
|
|
||||||
|
# Must be initialized externally by ProtoShape plugin
|
||||||
|
var _snapping: bool = false
|
||||||
|
var snapping: bool: set = set_snapping, get = get_snapping
|
||||||
|
var _fine_snapping: bool = false
|
||||||
|
var fine_snapping: bool: set = set_fine_snapping, get = get_fine_snapping
|
||||||
|
|
||||||
|
func set_snapping(snapping: bool) -> void:
|
||||||
|
_snapping = snapping
|
||||||
|
snapping_changed.emit(snapping)
|
||||||
|
|
||||||
|
func set_fine_snapping(fine_snapping: bool) -> void:
|
||||||
|
_fine_snapping = fine_snapping
|
||||||
|
fine_snapping_changed.emit(fine_snapping)
|
||||||
|
|
||||||
|
func get_snapping() -> bool:
|
||||||
|
return _snapping
|
||||||
|
|
||||||
|
func get_fine_snapping() -> bool:
|
||||||
|
return _fine_snapping
|
||||||
|
|
||||||
|
func _init() -> void:
|
||||||
|
create_material("main", Color(1, 0.3725, 0.3725, 0.5))
|
||||||
|
create_material("selected", Color(0, 0, 1, 0.1))
|
||||||
|
create_handle_material("proto_handler", false, load("res://addons/proto_shape/icon/proto-gizmo-handler.png"))
|
||||||
|
|
||||||
|
func _has_gizmo(node: Node3D) -> bool:
|
||||||
|
if node.get_parent() is ProtoGizmoWrapper or node is ProtoRamp:
|
||||||
|
return true
|
||||||
|
else:
|
||||||
|
return false
|
||||||
|
|
||||||
|
func _get_gizmo_name() -> String:
|
||||||
|
return "ProtoGizmo"
|
||||||
|
|
||||||
|
func _redraw(gizmo: EditorNode3DGizmo) -> void:
|
||||||
|
var node := gizmo.get_node_3d()
|
||||||
|
if node is ProtoRamp:
|
||||||
|
node.gizmos.redraw_gizmos(gizmo, self)
|
||||||
|
return
|
||||||
|
if node.get_parent() is ProtoGizmoWrapper:
|
||||||
|
node.get_parent().redraw_gizmos_for_child(gizmo, self)
|
||||||
|
return
|
||||||
|
|
||||||
|
func _set_handle(
|
||||||
|
gizmo: EditorNode3DGizmo,
|
||||||
|
handle_id: int,
|
||||||
|
secondary: bool,
|
||||||
|
camera: Camera3D,
|
||||||
|
screen_pos: Vector2) -> void:
|
||||||
|
var node := gizmo.get_node_3d()
|
||||||
|
if node is ProtoRamp:
|
||||||
|
node.gizmos.set_handle(gizmo, self, handle_id, secondary, camera, screen_pos)
|
||||||
|
return
|
||||||
|
if node.get_parent() is ProtoGizmoWrapper:
|
||||||
|
node.get_parent().set_handle_for_child(gizmo, self, handle_id, secondary, camera, screen_pos)
|
||||||
|
return
|
||||||
|
|
||||||
|
func _commit_handle(
|
||||||
|
gizmo: EditorNode3DGizmo,
|
||||||
|
handle_id: int,
|
||||||
|
secondary: bool,
|
||||||
|
restore: Variant,
|
||||||
|
cancel: bool) -> void:
|
||||||
|
var node := gizmo.get_node_3d()
|
||||||
|
if node is ProtoRamp:
|
||||||
|
node.gizmos.commit_handle(gizmo, handle_id, secondary, restore, cancel)
|
||||||
|
return
|
||||||
|
if node.get_parent() is ProtoGizmoWrapper:
|
||||||
|
node.get_parent().commit_handle_for_child(gizmo, handle_id, secondary, restore, cancel)
|
||||||
|
return
|
||||||
1
source/addons/proto_shape/proto_gizmo/proto_gizmo.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://dld6sttc0b5f3
|
||||||