mirror of
https://github.com/Relintai/GraphicsEditor.git
synced 2025-04-19 10:43:13 +02:00
changed editor to tab editor, ......
This commit is contained in:
parent
5d231a2153
commit
6ca768ee8e
21
.gitignore
vendored
21
.gitignore
vendored
@ -1,14 +1,11 @@
|
||||
\exports/
|
||||
\.import/
|
||||
|
||||
.import/
|
||||
export.cfg
|
||||
export_presets.cfg
|
||||
|
||||
addons/*
|
||||
# Imported translations (automatically generated from CSV files)
|
||||
*.translation
|
||||
|
||||
!addons/graphics_editor
|
||||
|
||||
scene-notes\.ini
|
||||
|
||||
todo\.cache\.ini
|
||||
|
||||
todo\.config\.ini
|
||||
|
||||
export_presets\.cfg
|
||||
# Mono-specific ignores
|
||||
.mono/
|
||||
data_*/
|
@ -0,0 +1,3 @@
|
||||
source_md5="7ba250dc0369bd9ea174a98fa96fd159"
|
||||
dest_md5="592d848ccf689082959787d416db762f"
|
||||
|
BIN
.import/arrow_down.png-6353fddfb758b7080149cf1c92b356e5.stex
Normal file
BIN
.import/arrow_down.png-6353fddfb758b7080149cf1c92b356e5.stex
Normal file
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
source_md5="2117353e2e3a97b4461460d303806021"
|
||||
dest_md5="35ac6bd3dfff4656d63f0245d37ed74e"
|
||||
|
BIN
.import/arrow_up.png-5a32daf21cc72903f29e9dc2d45d90bf.stex
Normal file
BIN
.import/arrow_up.png-5a32daf21cc72903f29e9dc2d45d90bf.stex
Normal file
Binary file not shown.
3
.import/icon.png-487276ed1e3a0c39cad0279d744ee560.md5
Normal file
3
.import/icon.png-487276ed1e3a0c39cad0279d744ee560.md5
Normal file
@ -0,0 +1,3 @@
|
||||
source_md5="47313fa4c47a9963fddd764e1ec6e4a8"
|
||||
dest_md5="2ded9e7f9060e2b530aab678b135fc5b"
|
||||
|
BIN
.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex
Normal file
BIN
.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex
Normal file
Binary file not shown.
3
.import/icon.png-622f0db5e19ff24d06caa70a7b56e7cc.md5
Normal file
3
.import/icon.png-622f0db5e19ff24d06caa70a7b56e7cc.md5
Normal file
@ -0,0 +1,3 @@
|
||||
source_md5="adad2e5a70e96772dddf92b495d1e0ed"
|
||||
dest_md5="9b6188fa4147bfc4b5e5977abb8469af"
|
||||
|
BIN
.import/icon.png-622f0db5e19ff24d06caa70a7b56e7cc.stex
Normal file
BIN
.import/icon.png-622f0db5e19ff24d06caa70a7b56e7cc.stex
Normal file
Binary file not shown.
3
.import/mehl.png-2d646cfa1d4d604007c31b10f2e878e9.md5
Normal file
3
.import/mehl.png-2d646cfa1d4d604007c31b10f2e878e9.md5
Normal file
@ -0,0 +1,3 @@
|
||||
source_md5="4e6da06002747457d0e002efd2f49ef8"
|
||||
dest_md5="46ed73e9c81c4cac671c27036b30b777"
|
||||
|
BIN
.import/mehl.png-2d646cfa1d4d604007c31b10f2e878e9.stex
Normal file
BIN
.import/mehl.png-2d646cfa1d4d604007c31b10f2e878e9.stex
Normal file
Binary file not shown.
3
.import/mehl1.png-6c01596ebada11f38e2e4f8e993ff1e0.md5
Normal file
3
.import/mehl1.png-6c01596ebada11f38e2e4f8e993ff1e0.md5
Normal file
@ -0,0 +1,3 @@
|
||||
source_md5="c4ed68c81275539e6cbf8391d88276c2"
|
||||
dest_md5="f55ead5c7be937b3aacf4e61f3f1603b"
|
||||
|
BIN
.import/mehl1.png-6c01596ebada11f38e2e4f8e993ff1e0.stex
Normal file
BIN
.import/mehl1.png-6c01596ebada11f38e2e4f8e993ff1e0.stex
Normal file
Binary file not shown.
3
.import/mehl2.png-dc740ae9694cbdda3fcb1860a3762c2f.md5
Normal file
3
.import/mehl2.png-dc740ae9694cbdda3fcb1860a3762c2f.md5
Normal file
@ -0,0 +1,3 @@
|
||||
source_md5="7c09c98e65f6ff015128c19855d2f7fb"
|
||||
dest_md5="40c2029dc0099f4030c789a32e7b84ad"
|
||||
|
BIN
.import/mehl2.png-dc740ae9694cbdda3fcb1860a3762c2f.stex
Normal file
BIN
.import/mehl2.png-dc740ae9694cbdda3fcb1860a3762c2f.stex
Normal file
Binary file not shown.
3
.import/mehl3.png-f2893ca98133a7cf31308e1d1e5a493c.md5
Normal file
3
.import/mehl3.png-f2893ca98133a7cf31308e1d1e5a493c.md5
Normal file
@ -0,0 +1,3 @@
|
||||
source_md5="99c754b29181eaddbf4461e2954e265f"
|
||||
dest_md5="5771e849f36b5516b53bbbef9ceef73a"
|
||||
|
BIN
.import/mehl3.png-f2893ca98133a7cf31308e1d1e5a493c.stex
Normal file
BIN
.import/mehl3.png-f2893ca98133a7cf31308e1d1e5a493c.stex
Normal file
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
source_md5="e0848eef5591cbefcdd580e2266df32a"
|
||||
dest_md5="b383e9e9635223c43c25b6c9c30e158d"
|
||||
|
BIN
.import/minidotta.png-0170a8b64a557748e03bc1c7c0cbfd33.stex
Normal file
BIN
.import/minidotta.png-0170a8b64a557748e03bc1c7c0cbfd33.stex
Normal file
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
source_md5="ed7ea9ed6750cf2fbe5141c6745f1a80"
|
||||
dest_md5="b53ed83de9acfb64b40bb7e19266a861"
|
||||
|
Binary file not shown.
1
.import/sample.csv-a43505412796765c81f547218e383389.md5
Normal file
1
.import/sample.csv-a43505412796765c81f547218e383389.md5
Normal file
@ -0,0 +1 @@
|
||||
source_md5="be8428ecca46883304ee0a8437c6b2cc"
|
3
.import/test.png-2b0b935732229e5bd5e655f2644b2498.md5
Normal file
3
.import/test.png-2b0b935732229e5bd5e655f2644b2498.md5
Normal file
@ -0,0 +1,3 @@
|
||||
source_md5="9898b4b50cf2b080d5c106e39863f916"
|
||||
dest_md5="64289bfd5608e896cab1ef7ed48d84e6"
|
||||
|
BIN
.import/test.png-2b0b935732229e5bd5e655f2644b2498.stex
Normal file
BIN
.import/test.png-2b0b935732229e5bd5e655f2644b2498.stex
Normal file
Binary file not shown.
3
.import/test2.png-dc930d6a9dd4d7b13b21ba611cfdebca.md5
Normal file
3
.import/test2.png-dc930d6a9dd4d7b13b21ba611cfdebca.md5
Normal file
@ -0,0 +1,3 @@
|
||||
source_md5="4adc812d45f40a06b9b2ca01cf81ae95"
|
||||
dest_md5="d6d99a1c7f42a184a39920f8abb2e0b4"
|
||||
|
BIN
.import/test2.png-dc930d6a9dd4d7b13b21ba611cfdebca.stex
Normal file
BIN
.import/test2.png-dc930d6a9dd4d7b13b21ba611cfdebca.stex
Normal file
Binary file not shown.
3
.import/test3.png-8f9b5bfe1c2a8f5f1fc480e2ea82bb92.md5
Normal file
3
.import/test3.png-8f9b5bfe1c2a8f5f1fc480e2ea82bb92.md5
Normal file
@ -0,0 +1,3 @@
|
||||
source_md5="bec155c5904394450131d27b462c96e4"
|
||||
dest_md5="71febc6938a68e205920ca412ebaf71d"
|
||||
|
BIN
.import/test3.png-8f9b5bfe1c2a8f5f1fc480e2ea82bb92.stex
Normal file
BIN
.import/test3.png-8f9b5bfe1c2a8f5f1fc480e2ea82bb92.stex
Normal file
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
source_md5="f6bdc4cf50b93bf6accef209602404a3"
|
||||
dest_md5="8102e795bd6d15849efc2870c51252b9"
|
||||
|
BIN
.import/test_blend.png-a13f0a261f39166a0d5d0b76154a64e2.stex
Normal file
BIN
.import/test_blend.png-a13f0a261f39166a0d5d0b76154a64e2.stex
Normal file
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
source_md5="3503838b09b288e7ba25eda91156f748"
|
||||
dest_md5="707338f082324b175177059fbd3c6032"
|
||||
|
BIN
.import/test_blend1.png-167afecc24d1a4f652165e618d695c31.stex
Normal file
BIN
.import/test_blend1.png-167afecc24d1a4f652165e618d695c31.stex
Normal file
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
source_md5="16749baf6a306a99dc4e80eee2abefbf"
|
||||
dest_md5="55aba65ce681911f66cffde93b5491ea"
|
||||
|
BIN
.import/test_blend2.png-f0dad7baf25c6e54b41a6f2a116ecf42.stex
Normal file
BIN
.import/test_blend2.png-f0dad7baf25c6e54b41a6f2a116ecf42.stex
Normal file
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
source_md5="d7a9507fc7dbc1dcf4fcba5f438d20d3"
|
||||
dest_md5="9b21ddc79734d495f2bcc94862d43b43"
|
||||
|
BIN
.import/test_blend3.png-feec22cacb1aa18f93c44c7160f20f42.stex
Normal file
BIN
.import/test_blend3.png-feec22cacb1aa18f93c44c7160f20f42.stex
Normal file
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
source_md5="976b0714fcbc434f323dad76d3b5bf36"
|
||||
dest_md5="0f5e8acf1d61ab0711f44f75905e5a8a"
|
||||
|
BIN
.import/test_blend4.png-8619abbd051622dc3a1a96b29ef7aaae.stex
Normal file
BIN
.import/test_blend4.png-8619abbd051622dc3a1a96b29ef7aaae.stex
Normal file
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
source_md5="06f1cb8e512e5adfad002ef0338a818e"
|
||||
dest_md5="87b2e06d78c49f4dc5456f18656eb3d3"
|
||||
|
BIN
.import/test_blend5.png-952e9ca6dabcfbaa26ca722fb438460d.stex
Normal file
BIN
.import/test_blend5.png-952e9ca6dabcfbaa26ca722fb438460d.stex
Normal file
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
source_md5="2d4a406047a743eb20e0ce47be843558"
|
||||
dest_md5="86808acdf32b0015647e3b12e728ce0a"
|
||||
|
BIN
.import/test_blend6.png-c312879c7424d3f742a8629bdf12c861.stex
Normal file
BIN
.import/test_blend6.png-c312879c7424d3f742a8629bdf12c861.stex
Normal file
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
source_md5="c576029f055c5661a5ab02e79f718143"
|
||||
dest_md5="03d4d90c298c894e9d624b48ca00b128"
|
||||
|
BIN
.import/test_blend7.png-3fa1be78ca4193859b8a428052ed246f.stex
Normal file
BIN
.import/test_blend7.png-3fa1be78ca4193859b8a428052ed246f.stex
Normal file
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
source_md5="4440cfb0f469fe68adca066948bc8183"
|
||||
dest_md5="da9faa3bbd2610755b629238ae47dc44"
|
||||
|
BIN
.import/test_blend8.png-8430826c445aa334cda4e6aa4e2be776.stex
Normal file
BIN
.import/test_blend8.png-8430826c445aa334cda4e6aa4e2be776.stex
Normal file
Binary file not shown.
22
LICENSE.md
22
LICENSE.md
@ -1,22 +0,0 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 Flairieve
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
11
README.md
11
README.md
@ -1,11 +0,0 @@
|
||||
# GraphicsEditor
|
||||
|
||||
Made by Flairieve!
|
||||
|
||||
## About
|
||||
This plugin was built in Godot v3.1.2 and is currently in alpha so it doesn't work fully and it's not finished!
|
||||
Please give credit if you fork and use any code from this project!
|
||||
|
||||
### Stuff that's still WIP and are not finished:
|
||||
* Images can only save in the PNG format.
|
||||
* Camera is broken when running as a plugin. Godot bug?
|
7
addons/godot-plugin-refresher/plugin.cfg
Normal file
7
addons/godot-plugin-refresher/plugin.cfg
Normal file
@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="Godot Plugin Refresher"
|
||||
description="A toolbar addition to facilitate toggling off/on a selected plugin."
|
||||
author="willnationsdev"
|
||||
version="1.0"
|
||||
script="plugin_refresher_plugin.gd"
|
53
addons/godot-plugin-refresher/plugin_refresher.gd
Normal file
53
addons/godot-plugin-refresher/plugin_refresher.gd
Normal file
@ -0,0 +1,53 @@
|
||||
tool
|
||||
extends HBoxContainer
|
||||
|
||||
signal request_refresh_plugin(p_name)
|
||||
signal confirm_refresh_plugin(p_name)
|
||||
|
||||
onready var options = $OptionButton
|
||||
|
||||
func _ready():
|
||||
$RefreshButton.icon = get_icon('Reload', 'EditorIcons')
|
||||
|
||||
func update_items(p_plugins):
|
||||
if not options:
|
||||
return
|
||||
options.clear()
|
||||
var plugin_dirs = p_plugins.keys()
|
||||
for idx in plugin_dirs.size():
|
||||
var plugin_dirname = plugin_dirs[idx]
|
||||
var plugin_name = p_plugins[plugin_dirname]
|
||||
options.add_item(plugin_name, idx)
|
||||
options.set_item_metadata(idx, plugin_dirname)
|
||||
|
||||
func select_plugin(p_name):
|
||||
if not options:
|
||||
return
|
||||
if p_name == null or p_name.empty():
|
||||
return
|
||||
|
||||
for idx in options.get_item_count():
|
||||
var plugin = options.get_item_metadata(idx)
|
||||
if plugin == p_name:
|
||||
options.selected = options.get_item_id(idx)
|
||||
break
|
||||
|
||||
func _on_RefreshButton_pressed():
|
||||
if options.selected == -1:
|
||||
return # nothing selected
|
||||
|
||||
var plugin = options.get_item_metadata(options.selected)
|
||||
if not plugin or plugin.empty():
|
||||
return
|
||||
emit_signal("request_refresh_plugin", plugin)
|
||||
|
||||
func show_warning(p_name):
|
||||
$ConfirmationDialog.dialog_text = """
|
||||
Plugin `%s` is currently disabled.\n
|
||||
Do you want to enable it now?
|
||||
""" % [p_name]
|
||||
$ConfirmationDialog.popup_centered()
|
||||
|
||||
func _on_ConfirmationDialog_confirmed():
|
||||
var plugin = options.get_item_metadata(options.selected)
|
||||
emit_signal('confirm_refresh_plugin', plugin)
|
32
addons/godot-plugin-refresher/plugin_refresher.tscn
Normal file
32
addons/godot-plugin-refresher/plugin_refresher.tscn
Normal file
@ -0,0 +1,32 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot-plugin-refresher/plugin_refresher.gd" type="Script" id=1]
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer"]
|
||||
margin_right = 40.0
|
||||
margin_bottom = 40.0
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="VSeparator" type="VSeparator" parent="."]
|
||||
margin_right = 4.0
|
||||
margin_bottom = 40.0
|
||||
|
||||
[node name="OptionButton" type="OptionButton" parent="."]
|
||||
margin_left = 8.0
|
||||
margin_right = 158.0
|
||||
margin_bottom = 40.0
|
||||
rect_min_size = Vector2( 150, 0 )
|
||||
|
||||
[node name="RefreshButton" type="ToolButton" parent="."]
|
||||
margin_left = 162.0
|
||||
margin_right = 174.0
|
||||
margin_bottom = 40.0
|
||||
|
||||
[node name="ConfirmationDialog" type="ConfirmationDialog" parent="."]
|
||||
margin_right = 278.0
|
||||
margin_bottom = 110.0
|
||||
rect_min_size = Vector2( 300, 70 )
|
||||
window_title = "Plugin Refresher"
|
||||
dialog_autowrap = true
|
||||
[connection signal="pressed" from="RefreshButton" to="." method="_on_RefreshButton_pressed"]
|
||||
[connection signal="confirmed" from="ConfirmationDialog" to="." method="_on_ConfirmationDialog_confirmed"]
|
125
addons/godot-plugin-refresher/plugin_refresher_plugin.gd
Normal file
125
addons/godot-plugin-refresher/plugin_refresher_plugin.gd
Normal file
@ -0,0 +1,125 @@
|
||||
tool
|
||||
extends EditorPlugin
|
||||
|
||||
const ADDONS_PATH = "res://addons/"
|
||||
const PLUGIN_CONFIG_DIR = 'plugins/plugin_refresher'
|
||||
const PLUGIN_CONFIG = 'settings.cfg'
|
||||
const SETTINGS = 'settings'
|
||||
const SETTING_RECENT = 'recently_used'
|
||||
|
||||
var plugin_config = ConfigFile.new()
|
||||
var refresher
|
||||
|
||||
func _enter_tree():
|
||||
refresher = preload("plugin_refresher.tscn").instance()
|
||||
add_control_to_container(CONTAINER_TOOLBAR, refresher)
|
||||
|
||||
# Watch whether any plugin is changed, added or removed on the filesystem
|
||||
var efs = get_editor_interface().get_resource_filesystem()
|
||||
efs.connect("filesystem_changed", self, "_on_filesystem_changed")
|
||||
|
||||
refresher.connect("request_refresh_plugin", self, "_on_request_refresh_plugin")
|
||||
refresher.connect("confirm_refresh_plugin", self, "_on_confirm_refresh_plugin")
|
||||
|
||||
_reload_plugins_list()
|
||||
_load_settings()
|
||||
|
||||
func _exit_tree():
|
||||
remove_control_from_container(CONTAINER_TOOLBAR, refresher)
|
||||
refresher.free()
|
||||
|
||||
func _reload_plugins_list():
|
||||
var refresher_dir = get_plugin_path().get_file()
|
||||
var plugins = {}
|
||||
var origins = {}
|
||||
|
||||
var dir = Directory.new()
|
||||
dir.open(ADDONS_PATH)
|
||||
dir.list_dir_begin(true, true)
|
||||
var file = dir.get_next()
|
||||
while file:
|
||||
var addon_dir = ADDONS_PATH.plus_file(file)
|
||||
if dir.dir_exists(addon_dir) and file != refresher_dir:
|
||||
var display_name = file
|
||||
var plugin_config_path = addon_dir.plus_file("plugin.cfg")
|
||||
if not dir.file_exists(plugin_config_path):
|
||||
continue # not a plugin
|
||||
var plugin_cfg = ConfigFile.new()
|
||||
plugin_cfg.load(plugin_config_path)
|
||||
display_name = plugin_cfg.get_value("plugin", "name", file)
|
||||
if not display_name in origins:
|
||||
origins[display_name] = [file]
|
||||
else:
|
||||
origins[display_name].append(file)
|
||||
plugins[file] = display_name
|
||||
file = dir.get_next()
|
||||
|
||||
# Specify the exact plugin name in parenthesis in case of naming collisions.
|
||||
for display_name in origins:
|
||||
var plugin_names = origins[display_name]
|
||||
if plugin_names.size() > 1:
|
||||
for n in plugin_names:
|
||||
plugins[n] = "%s (%s)" % [display_name, n]
|
||||
|
||||
refresher.update_items(plugins)
|
||||
|
||||
func _load_settings():
|
||||
var path = get_config_path()
|
||||
|
||||
var fs = Directory.new()
|
||||
if not fs.file_exists(path):
|
||||
# Create new if running for the first time
|
||||
var config = ConfigFile.new()
|
||||
fs.make_dir_recursive(path.get_base_dir())
|
||||
config.save(path)
|
||||
else:
|
||||
plugin_config.load(path)
|
||||
|
||||
func _save_settings():
|
||||
plugin_config.save(get_config_path())
|
||||
|
||||
func get_config_path():
|
||||
var dir = get_editor_interface().get_editor_settings().get_project_settings_dir()
|
||||
var home = dir.plus_file(PLUGIN_CONFIG_DIR)
|
||||
var path = home.plus_file(PLUGIN_CONFIG)
|
||||
|
||||
return path
|
||||
|
||||
func _on_filesystem_changed():
|
||||
if refresher:
|
||||
_reload_plugins_list()
|
||||
refresher.select_plugin(get_recent_plugin())
|
||||
|
||||
func get_recent_plugin():
|
||||
if not plugin_config.has_section_key(SETTINGS, SETTING_RECENT):
|
||||
return null # not saved yet
|
||||
|
||||
var recent = plugin_config.get_value(SETTINGS, SETTING_RECENT)
|
||||
return recent
|
||||
|
||||
func _on_request_refresh_plugin(p_name):
|
||||
assert(not p_name.empty())
|
||||
|
||||
var disabled = not get_editor_interface().is_plugin_enabled(p_name)
|
||||
if disabled:
|
||||
refresher.show_warning(p_name)
|
||||
else:
|
||||
refresh_plugin(p_name)
|
||||
|
||||
func _on_confirm_refresh_plugin(p_name):
|
||||
refresh_plugin(p_name)
|
||||
|
||||
func get_plugin_path():
|
||||
return get_script().resource_path.get_base_dir()
|
||||
|
||||
func refresh_plugin(p_name):
|
||||
print("Refreshing plugin: ", p_name)
|
||||
|
||||
var enabled = get_editor_interface().is_plugin_enabled(p_name)
|
||||
if enabled: # can only disable an active plugin
|
||||
get_editor_interface().set_plugin_enabled(p_name, false)
|
||||
|
||||
get_editor_interface().set_plugin_enabled(p_name, true)
|
||||
|
||||
plugin_config.set_value(SETTINGS, SETTING_RECENT, p_name)
|
||||
_save_settings()
|
@ -1,8 +1,21 @@
|
||||
extends Node
|
||||
class_name BrushPrefabs
|
||||
|
||||
func _ready():
|
||||
print("test")
|
||||
pass
|
||||
|
||||
func draw_pixel():
|
||||
print("Drawed pixel!")
|
||||
const list = [
|
||||
[ Vector2(0, -1),
|
||||
Vector2(-1, 0), Vector2(0, 0), Vector2(1, 0),
|
||||
Vector2(0, 1)
|
||||
],
|
||||
[Vector2(-1, -1), Vector2(0, -1), Vector2(1, -1),
|
||||
Vector2(-1, 0), Vector2(0, 0), Vector2(1, 0),
|
||||
Vector2(-1, 1), Vector2(0, 1), Vector2(1, 1),
|
||||
],
|
||||
[
|
||||
Vector2(-1, 0), Vector2(0, 0), Vector2(1, 0),
|
||||
],
|
||||
[ Vector2(0, -1),
|
||||
Vector2(0, 0),
|
||||
Vector2(0, 1)
|
||||
]
|
||||
]
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
#This script isn't a tool script because you can accidently move the camera while trying to edit the scene
|
||||
extends Camera2D
|
||||
|
||||
#TODO: Make the camera movement snap to the nearest highlighted cell
|
||||
|
||||
var speed = 10
|
||||
func _process(delta):
|
||||
if Input.is_key_pressed(KEY_LEFT):
|
||||
position += Vector2(-1, 0) * speed
|
||||
elif Input.is_key_pressed(KEY_RIGHT):
|
||||
position += Vector2(1, 0) * speed
|
||||
|
||||
if Input.is_key_pressed(KEY_UP):
|
||||
position += Vector2(0, -1) * speed
|
||||
elif Input.is_key_pressed(KEY_DOWN):
|
||||
position += Vector2(0, 1) * speed
|
@ -2,23 +2,26 @@ tool
|
||||
extends Control
|
||||
|
||||
export var color = Color()
|
||||
export var width = 3
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func _draw():
|
||||
draw_outline_box(rect_size, color, width)
|
||||
var size = get_parent().get_node("Grids").rect_size
|
||||
var pos = get_parent().get_node("Grids").rect_position
|
||||
draw_outline_box(pos, size, color, 1)
|
||||
|
||||
func draw_outline_box(size, color, width):
|
||||
func draw_outline_box(pos, size, color, width):
|
||||
#Top line
|
||||
draw_line(Vector2(0 + 1, 0), Vector2(size.x, 0), color, width)
|
||||
pos -= Vector2(0, 0)
|
||||
size += Vector2(0, 0)
|
||||
draw_line(pos, pos + Vector2(size.x, 0), color, width)
|
||||
#Left line
|
||||
draw_line(Vector2(0 + 1, 0), Vector2(0, size.y), color, width)
|
||||
draw_line(pos, pos + Vector2(0, size.y), color, width)
|
||||
#Bottom line
|
||||
draw_line(Vector2(0 + 1, size.y), Vector2(size.x, size.y), color, width)
|
||||
draw_line(pos + Vector2(0, size.y), pos + Vector2(size.x, size.y), color, width)
|
||||
#Right line
|
||||
draw_line(Vector2(size.x, 0), Vector2(size.x, size.y), color, width)
|
||||
draw_line(pos + Vector2(size.x, 0), pos + Vector2(size.x, size.y), color, width)
|
||||
|
||||
func _process(delta):
|
||||
update()
|
||||
|
@ -1,34 +0,0 @@
|
||||
tool
|
||||
extends ColorPickerButton
|
||||
|
||||
var color_picking = false
|
||||
var mouse_on_top = false
|
||||
|
||||
func _ready():
|
||||
var color_picker = get_picker()
|
||||
var color_picker_popup = get_popup()
|
||||
var color_picker_button = color_picker.get_children()[0].get_children()[1]
|
||||
color_picker_popup.connect("popup_hide", self, "color_picker_popup_hide")
|
||||
color_picker_button.disconnect("pressed", color_picker, "_screen_pick_pressed")
|
||||
color_picker_button.connect("pressed", self, "color_picker_button_pressed")
|
||||
|
||||
func _process(delta):
|
||||
if color_picking and not mouse_on_top:
|
||||
var editor = get_node("/root/Editor")
|
||||
var paint_canvas = get_node("/root/Editor/PaintCanvasContainer/ViewportContainer/Viewport/PaintCanvas")
|
||||
var highlighted_color = paint_canvas.get_pixel(editor.cell_mouse_position)
|
||||
if not highlighted_color == null:
|
||||
color = highlighted_color
|
||||
|
||||
func color_picker_button_pressed():
|
||||
if not color_picking:
|
||||
color_picking = true
|
||||
|
||||
func color_picker_popup_hide():
|
||||
color_picking = false
|
||||
|
||||
func _on_ColorPicker_mouse_entered():
|
||||
mouse_on_top = true
|
||||
|
||||
func _on_ColorPicker_mouse_exited():
|
||||
mouse_on_top = false
|
23
addons/graphics_editor/Colors.gd
Normal file
23
addons/graphics_editor/Colors.gd
Normal file
@ -0,0 +1,23 @@
|
||||
tool
|
||||
extends GridContainer
|
||||
|
||||
signal color_change_request
|
||||
|
||||
func _enter_tree():
|
||||
for child in get_children():
|
||||
child.set("custom_styles/normal", StyleBoxFlat.new())
|
||||
child.get("custom_styles/normal").set("bg_color", Color(randf(), randf(), randf()))
|
||||
for child in get_children():
|
||||
if child.is_connected("pressed", self, "change_color_to"):
|
||||
return
|
||||
child.connect("pressed", self, "change_color_to", [child.get("custom_styles/normal").bg_color])
|
||||
|
||||
|
||||
func change_color_to(color):
|
||||
emit_signal("color_change_request", color)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
9
addons/graphics_editor/DebugTextDisplay.gd
Normal file
9
addons/graphics_editor/DebugTextDisplay.gd
Normal file
@ -0,0 +1,9 @@
|
||||
extends RichTextLabel
|
||||
tool
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
|
||||
func display_text(text):
|
||||
self.text = text
|
@ -1,21 +0,0 @@
|
||||
extends Control
|
||||
|
||||
var util = preload("res://addons/graphics_editor/Util.gd")
|
||||
|
||||
func _ready():
|
||||
var dialog_folder = get_script().resource_path.get_base_dir()
|
||||
var files = util.get_files_from_path(dialog_folder.plus_file("Dialogs"))
|
||||
for i in files:
|
||||
var file_name = util.get_file_name(i)
|
||||
if i.get_extension() == "tscn":
|
||||
var new_scene = load(i).instance()
|
||||
add_child(new_scene)
|
||||
|
||||
func show_dialog(dialog_name):
|
||||
var dialog_node = get_node_or_null(dialog_name)
|
||||
if dialog_node:
|
||||
dialog_node.set_anchors_preset(PRESET_CENTER)
|
||||
dialog_node.rect_position = Vector2((rect_size.x / 2) - (dialog_node.rect_size.x / 2), (rect_size.y / 2) - (dialog_node.rect_size.y / 2))
|
||||
dialog_node.show()
|
||||
else:
|
||||
push_error("Can't load dialog! Either missing node or file?")
|
@ -1,13 +0,0 @@
|
||||
extends WindowDialog
|
||||
|
||||
onready var paint_canvas = get_node("/root/Editor/PaintCanvasContainer/ViewportContainer/Viewport/PaintCanvas")
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func _on_Ok_pressed():
|
||||
var new_canvas_size = Vector2()
|
||||
new_canvas_size.x = get_node("CanvasSize/SpinBox").value
|
||||
new_canvas_size.y = get_node("CanvasSize/SpinBox2").value
|
||||
paint_canvas.expand_canvas(new_canvas_size)
|
||||
hide()
|
@ -1,53 +0,0 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/graphics_editor/Dialogs/ExpandCanvas.gd" type="Script" id=1]
|
||||
|
||||
[node name="ExpandCanvas" type="WindowDialog"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_right = -734.0
|
||||
margin_bottom = -520.0
|
||||
window_title = "Expand Canvas"
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="CanvasSize" type="Control" parent="."]
|
||||
margin_left = 10.0
|
||||
margin_top = 10.0
|
||||
margin_right = 240.0
|
||||
margin_bottom = 34.0
|
||||
|
||||
[node name="Label" type="Label" parent="CanvasSize"]
|
||||
margin_right = 80.0
|
||||
margin_bottom = 24.0
|
||||
text = "Canvas Size:"
|
||||
valign = 1
|
||||
|
||||
[node name="Label2" type="Label" parent="CanvasSize"]
|
||||
margin_left = 170.0
|
||||
margin_right = 190.0
|
||||
margin_bottom = 24.0
|
||||
text = "X"
|
||||
align = 1
|
||||
valign = 1
|
||||
|
||||
[node name="SpinBox" type="SpinBox" parent="CanvasSize"]
|
||||
margin_left = 90.0
|
||||
margin_right = 170.0
|
||||
margin_bottom = 24.0
|
||||
max_value = 10000.0
|
||||
value = 100.0
|
||||
|
||||
[node name="SpinBox2" type="SpinBox" parent="CanvasSize"]
|
||||
margin_left = 190.0
|
||||
margin_right = 270.0
|
||||
margin_bottom = 24.0
|
||||
max_value = 10000.0
|
||||
value = 100.0
|
||||
|
||||
[node name="Ok" type="Button" parent="."]
|
||||
margin_left = 200.0
|
||||
margin_top = 50.0
|
||||
margin_right = 280.0
|
||||
margin_bottom = 70.0
|
||||
text = "Ok"
|
||||
[connection signal="pressed" from="Ok" to="." method="_on_Ok_pressed"]
|
@ -1,30 +0,0 @@
|
||||
tool
|
||||
extends FileDialog
|
||||
|
||||
onready var canvas = get_parent().get_parent().get_node("PaintCanvasContainer/ViewportContainer/Viewport/PaintCanvas")
|
||||
|
||||
var file_path = ""
|
||||
|
||||
func _ready():
|
||||
get_line_edit().connect("text_entered", self, "_on_LineEdit_text_entered")
|
||||
invalidate()
|
||||
clear_filters()
|
||||
add_filter("*.png ; PNG Images")
|
||||
|
||||
func load_file():
|
||||
canvas.load_image_from_file(file_path)
|
||||
|
||||
func _on_LineEdit_text_entered(text):
|
||||
load_file()
|
||||
|
||||
func _on_LoadFileDialog_confirmed():
|
||||
load_file()
|
||||
|
||||
func _on_LoadFileDialog_file_selected(path):
|
||||
file_path = path
|
||||
|
||||
func _on_LoadFileDialog_about_to_show():
|
||||
invalidate()
|
||||
|
||||
func _on_LoadFileDialog_visibility_changed():
|
||||
invalidate()
|
@ -1,13 +0,0 @@
|
||||
extends WindowDialog
|
||||
|
||||
onready var paint_canvas = get_node("/root/Editor/PaintCanvasContainer/ViewportContainer/Viewport/PaintCanvas")
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func _on_Ok_pressed():
|
||||
var new_canvas_size = Vector2()
|
||||
new_canvas_size.x = get_node("ImageSize/SpinBox").value
|
||||
new_canvas_size.y = get_node("ImageSize/SpinBox2").value
|
||||
paint_canvas.canvas_size = new_canvas_size
|
||||
hide()
|
@ -1,54 +0,0 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/graphics_editor/Dialogs/NewImage.gd" type="Script" id=1]
|
||||
|
||||
|
||||
[node name="NewImage" type="WindowDialog"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_right = -734.0
|
||||
margin_bottom = -520.0
|
||||
window_title = "New Image"
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="ImageSize" type="Control" parent="."]
|
||||
margin_left = 10.0
|
||||
margin_top = 10.0
|
||||
margin_right = 240.0
|
||||
margin_bottom = 34.0
|
||||
|
||||
[node name="Label" type="Label" parent="ImageSize"]
|
||||
margin_right = 80.0
|
||||
margin_bottom = 24.0
|
||||
text = "Image Size:"
|
||||
valign = 1
|
||||
|
||||
[node name="Label2" type="Label" parent="ImageSize"]
|
||||
margin_left = 170.0
|
||||
margin_right = 190.0
|
||||
margin_bottom = 24.0
|
||||
text = "X"
|
||||
align = 1
|
||||
valign = 1
|
||||
|
||||
[node name="SpinBox" type="SpinBox" parent="ImageSize"]
|
||||
margin_left = 90.0
|
||||
margin_right = 170.0
|
||||
margin_bottom = 24.0
|
||||
max_value = 10000.0
|
||||
value = 100.0
|
||||
|
||||
[node name="SpinBox2" type="SpinBox" parent="ImageSize"]
|
||||
margin_left = 190.0
|
||||
margin_right = 270.0
|
||||
margin_bottom = 24.0
|
||||
max_value = 10000.0
|
||||
value = 100.0
|
||||
|
||||
[node name="Ok" type="Button" parent="."]
|
||||
margin_left = 200.0
|
||||
margin_top = 50.0
|
||||
margin_right = 280.0
|
||||
margin_bottom = 70.0
|
||||
text = "Ok"
|
||||
[connection signal="pressed" from="Ok" to="." method="_on_Ok_pressed"]
|
@ -1,32 +0,0 @@
|
||||
tool
|
||||
extends FileDialog
|
||||
|
||||
onready var canvas = get_parent().get_parent().get_node("PaintCanvasContainer/ViewportContainer/Viewport/PaintCanvas")
|
||||
|
||||
var file_path = ""
|
||||
|
||||
func _ready():
|
||||
get_line_edit().connect("text_entered", self, "_on_LineEdit_text_entered")
|
||||
invalidate()
|
||||
clear_filters()
|
||||
add_filter("*.png ; PNG Images")
|
||||
|
||||
func save_file():
|
||||
canvas.image.unlock()
|
||||
canvas.image.save_png(file_path)
|
||||
canvas.image.lock()
|
||||
|
||||
func _on_LineEdit_text_entered(text):
|
||||
save_file()
|
||||
|
||||
func _on_SaveFileDialog_confirmed():
|
||||
save_file()
|
||||
|
||||
func _on_SaveFileDialog_file_selected(path):
|
||||
file_path = path
|
||||
|
||||
func _on_SaveFileDialog_about_to_show():
|
||||
invalidate()
|
||||
|
||||
func _on_SaveFileDialog_visibility_changed():
|
||||
invalidate()
|
@ -1,196 +0,0 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
#TODO: Make the settings auto generate!
|
||||
|
||||
onready var editor = get_parent().get_parent()
|
||||
onready var canvas_outline = editor.get_node("PaintCanvasContainer/ViewportContainer/Viewport/PaintCanvas/CanvasOutline")
|
||||
onready var visual_grid_1 = editor.get_node("PaintCanvasContainer/ViewportContainer/Viewport/PaintCanvas/Grids/VisualGrid")
|
||||
onready var visual_grid_2 = editor.get_node("PaintCanvasContainer/ViewportContainer/Viewport/PaintCanvas/Grids/VisualGrid2")
|
||||
onready var scroll_container = get_node("ScrollContainer")
|
||||
|
||||
#{
|
||||
# "CATEGORY": {
|
||||
# "SETTINGNAME": {
|
||||
# "node": "PATHTONODE",
|
||||
# "valueMod": "VALUETOMODIFY",
|
||||
# "setterType": "SETTERTYPE"
|
||||
# }
|
||||
# }
|
||||
#}
|
||||
|
||||
#ValueSetterType List:
|
||||
#ColorPicker
|
||||
#CheckButton
|
||||
#SpinBox
|
||||
|
||||
var setting_storage = {
|
||||
"Canvas Outline": {
|
||||
"Enabled": {
|
||||
"node": canvas_outline,
|
||||
"valueMod": "visible",
|
||||
"setterType": "CheckBox"
|
||||
},
|
||||
"Color": {
|
||||
"node": canvas_outline,
|
||||
"valueMod": "color",
|
||||
"setterType": "ColorPicker"
|
||||
},
|
||||
"Width": {
|
||||
"node": canvas_outline,
|
||||
"valueMod": "width",
|
||||
"setterType": "SpinBox"
|
||||
}
|
||||
},
|
||||
"Grids": {
|
||||
"Grid1_Color": {
|
||||
"node": visual_grid_1,
|
||||
"valueMod": "color",
|
||||
"setterType": "ColorPicker"
|
||||
},
|
||||
"Grid1_Size": {
|
||||
"node": visual_grid_1,
|
||||
"valueMod": "grid_size",
|
||||
"setterType": "SpinBox"
|
||||
},
|
||||
"Grid2_Color": {
|
||||
"node": visual_grid_2,
|
||||
"valueMod": "color",
|
||||
"setterType": "ColorPicker"
|
||||
},
|
||||
"Grid2_Size": {
|
||||
"node": visual_grid_2,
|
||||
"valueMod": "grid_size",
|
||||
"setterType": "SpinBox"
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#TODO: Instead of this current system, we can make a function type of system instead like this
|
||||
#generate_category(name)
|
||||
#generate_property(category_name, node, valueMod) # setterType is automatically detected from the property it gets from the node
|
||||
|
||||
func _ready():
|
||||
generate_category_container("Canvas Outline")
|
||||
generate_property_container("Canvas Outline", canvas_outline, "Enabled", "visible")
|
||||
generate_property_container("Canvas Outline", canvas_outline, "Color", "color")
|
||||
generate_property_container("Canvas Outline", canvas_outline, "Width", "width")
|
||||
generate_category_container("Grids")
|
||||
generate_property_container("Grids", visual_grid_1, "Grid1 Enabled", "visible")
|
||||
generate_property_container("Grids", visual_grid_1, "Grid1 Color", "color")
|
||||
generate_property_container("Grids", visual_grid_1, "Grid1 Size", "size")
|
||||
generate_property_container("Grids", visual_grid_2, "Grid2 Enabled", "visible")
|
||||
generate_property_container("Grids", visual_grid_2, "Grid2 Color", "color")
|
||||
generate_property_container("Grids", visual_grid_2, "Grid2 Size", "size")
|
||||
|
||||
func generate_settings():
|
||||
for i in setting_storage:
|
||||
generate_category_container(i)
|
||||
for j in setting_storage[i]:
|
||||
var valuemod = setting_storage[i][j]["valueMod"]
|
||||
var settertype = setting_storage[i][j]["setterType"]
|
||||
generate_property_container(i, j, valuemod, settertype)
|
||||
|
||||
func generate_category_container(category):
|
||||
var vboxContainer = VBoxContainer.new()
|
||||
vboxContainer.name = category
|
||||
var label = Label.new()
|
||||
label.text = category + ":"
|
||||
label.valign = Label.ALIGN_CENTER
|
||||
vboxContainer.add_child(label)
|
||||
var vboxPropertiesContainer = VBoxContainer.new()
|
||||
vboxPropertiesContainer.name = "VBoxContainer"
|
||||
vboxContainer.add_child(vboxPropertiesContainer)
|
||||
get_node("ScrollContainer/VBoxContainer").add_child(vboxContainer)
|
||||
|
||||
func generate_property_container(category, node, propertyname, valuemod):
|
||||
var hbox = HBoxContainer.new()
|
||||
hbox.rect_min_size = Vector2(scroll_container.rect_size.x, 20)
|
||||
hbox.name = propertyname
|
||||
hbox.add_constant_override("separation", 0)
|
||||
var label = Label.new()
|
||||
label.rect_min_size = Vector2(scroll_container.rect_size.x / 2, 20)
|
||||
label.text = propertyname.capitalize()
|
||||
label.align = Label.ALIGN_CENTER
|
||||
label.valign = Label.ALIGN_CENTER
|
||||
var settertypenode
|
||||
var get_value = node.get(valuemod)
|
||||
match typeof(get_value):
|
||||
TYPE_INT:
|
||||
settertypenode = SpinBox.new()
|
||||
settertypenode.max_value = 9999
|
||||
settertypenode.value = get_value
|
||||
settertypenode.connect("value_changed", self, "on_setting_changed", [node, valuemod, settertypenode, "value"])
|
||||
pass
|
||||
TYPE_REAL:
|
||||
settertypenode = SpinBox.new()
|
||||
settertypenode.max_value = 9999
|
||||
settertypenode.value = get_value
|
||||
settertypenode.connect("value_changed", self, "on_setting_changed", [node, valuemod, settertypenode, "value"])
|
||||
pass
|
||||
TYPE_COLOR:
|
||||
settertypenode = ColorPickerButton.new()
|
||||
settertypenode.color = get_value
|
||||
settertypenode.connect("color_changed", self, "on_setting_changed", [node, valuemod, settertypenode, "color"])
|
||||
pass
|
||||
TYPE_VECTOR2:
|
||||
pass
|
||||
TYPE_BOOL:
|
||||
settertypenode = CheckBox.new()
|
||||
settertypenode.text = "On"
|
||||
settertypenode.pressed = get_value
|
||||
var styleboxflat = StyleBoxFlat.new()
|
||||
styleboxflat.bg_color = Color(0.254902, 0.254902, 0.254902)
|
||||
settertypenode.add_stylebox_override("normal", styleboxflat)
|
||||
settertypenode.add_stylebox_override("hover", styleboxflat)
|
||||
settertypenode.add_stylebox_override("pressed", styleboxflat)
|
||||
settertypenode.connect("pressed", self, "on_setting_changed", [null, node, valuemod, settertypenode, "pressed"])
|
||||
pass
|
||||
# match settertype:
|
||||
# "ColorPicker":
|
||||
# settertypenode = ColorPickerButton.new()
|
||||
# "CheckBox":
|
||||
# settertypenode = CheckBox.new()
|
||||
# settertypenode.text = "On"
|
||||
# var styleboxflat = StyleBoxFlat.new()
|
||||
# styleboxflat.bg_color = Color(0.254902, 0.254902, 0.254902)
|
||||
# settertypenode.add_stylebox_override("normal", styleboxflat)
|
||||
# settertypenode.add_stylebox_override("hover", styleboxflat)
|
||||
# settertypenode.add_stylebox_override("pressed", styleboxflat)
|
||||
# "SpinBox":
|
||||
# settertypenode = SpinBox.new()
|
||||
if settertypenode == null:
|
||||
push_error("Setter type not found! Returning! DEBUG_INFO: %s | %s | %s" % [node, node.name, typeof(get_value)])
|
||||
return
|
||||
settertypenode.rect_min_size = Vector2(scroll_container.rect_size.x / 2, 20)
|
||||
hbox.add_child(label)
|
||||
hbox.add_child(settertypenode)
|
||||
get_node("ScrollContainer/VBoxContainer/%s/VBoxContainer" % [category]).add_child(hbox)
|
||||
|
||||
func _on_Ok_pressed():
|
||||
hide()
|
||||
|
||||
func on_setting_changed(default_signal, node, value_to_get, setter, value_setter_get):
|
||||
var setter_new_value = setter.get(value_setter_get)
|
||||
node.set(value_to_get, setter_new_value)
|
||||
|
||||
func _on_CanvasOutline_Enabled_value_changed(button_pressed):
|
||||
canvas_outline.visible = button_pressed
|
||||
|
||||
func _on_CanvasOutline_Color_value_changed(color):
|
||||
canvas_outline.color = color
|
||||
|
||||
func _on_CanvasOutline_SpinBox_value_changed(value):
|
||||
canvas_outline.width = value
|
||||
|
||||
func _on_Grids_Grid1Color_value_changed(color):
|
||||
visual_grid_1.color = color
|
||||
|
||||
func _on_Grids_Grid1Size_value_changed(value):
|
||||
visual_grid_1.size = value
|
||||
|
||||
func _on_Grids_Grid2Color_value_changed(color):
|
||||
visual_grid_2.color = color
|
||||
|
||||
func _on_Grids_Grid2Size_value_changed(value):
|
||||
visual_grid_2.size = value
|
@ -1,35 +0,0 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/graphics_editor/Dialogs/Settings.gd" type="Script" id=1]
|
||||
|
||||
[node name="Settings" type="WindowDialog"]
|
||||
margin_top = 20.0
|
||||
margin_right = 250.0
|
||||
margin_bottom = 270.0
|
||||
popup_exclusive = true
|
||||
window_title = "Settings"
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Ok" type="Button" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -90.0
|
||||
margin_top = -30.0
|
||||
margin_right = -10.0
|
||||
margin_bottom = -10.0
|
||||
text = "Ok"
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_right = -12.0
|
||||
margin_bottom = -40.0
|
||||
scroll_horizontal_enabled = false
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="ScrollContainer"]
|
||||
margin_right = 100.0
|
||||
margin_bottom = 36.0
|
||||
custom_constants/separation = 0
|
||||
[connection signal="pressed" from="Ok" to="." method="_on_Ok_pressed"]
|
@ -1,52 +1,139 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
onready var paint_canvas_container_node = get_node("PaintCanvasContainer")
|
||||
onready var paint_canvas_node = paint_canvas_container_node.get_node("ViewportContainer/Viewport/PaintCanvas")
|
||||
onready var paint_canvas_image_node = paint_canvas_node.get_node("CanvasImage")
|
||||
onready var camera = paint_canvas_container_node.get_node("ViewportContainer/Viewport/Camera2D")
|
||||
onready var grids_node = paint_canvas_node.get_node("Grids")
|
||||
onready var tool_manager = get_node("ToolManager")
|
||||
onready var textinfo = get_node("BottomPanel/TextInfo")
|
||||
onready var layers = get_node("ToolMenu/Layers")
|
||||
onready var grid_size = paint_canvas_node.grid_size
|
||||
onready var chunk_size = paint_canvas_node.chunk_size
|
||||
enum Tools {
|
||||
PAINT,
|
||||
BRUSH,
|
||||
BUCKET,
|
||||
RAINBOW,
|
||||
LINE,
|
||||
RECT,
|
||||
DARKEN,
|
||||
BRIGHTEN
|
||||
COLORPICKER,
|
||||
CUT,
|
||||
}
|
||||
|
||||
var paint_canvas_container_node
|
||||
var paint_canvas_node
|
||||
var grids_node
|
||||
var colors_grid
|
||||
var selected_color = Color(1, 1, 1, 1)
|
||||
var util = preload("res://addons/graphics_editor/Util.gd")
|
||||
var textinfo
|
||||
onready var grid_size = paint_canvas_node.grid_size
|
||||
onready var region_size = paint_canvas_node.region_size
|
||||
var allow_drawing = true
|
||||
|
||||
#TODO:
|
||||
#Work on the brush system!
|
||||
#Make a GUI Notification script!
|
||||
|
||||
func _ready():
|
||||
#-----------------
|
||||
#Setup active tool
|
||||
#-----------------
|
||||
tool_manager.set_active_tool("Pencil")
|
||||
var _left_mouse_pressed_start_pos = Vector2()
|
||||
var _previous_tool
|
||||
|
||||
var _layer_button_ref = {}
|
||||
|
||||
var _total_added_layers = 1
|
||||
|
||||
var selected_brush_prefab = 0
|
||||
var _last_drawn_pixel = Vector2.ZERO
|
||||
var _last_preview_draw_cell_pos = Vector2.ZERO
|
||||
var _selection = []
|
||||
var _just_cut = false
|
||||
var _show_cut = false
|
||||
var _cut_pos = Vector2.ZERO
|
||||
var _cut_size = Vector2.ZERO
|
||||
|
||||
var _actions_history = [] # for undo
|
||||
var _redo_history = []
|
||||
|
||||
var Actions = {
|
||||
Tools.PAINT: load("res://addons/graphics_editor/actions/Pencil.gd").new(),
|
||||
}
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
#--------------------
|
||||
#Setup nodes
|
||||
#--------------------
|
||||
paint_canvas_container_node = find_node("PaintCanvasContainer")
|
||||
paint_canvas_node = paint_canvas_container_node.find_node("PaintCanvas")
|
||||
grids_node = paint_canvas_node.find_node("Grids")
|
||||
textinfo = find_node("DebugTextDisplay")
|
||||
selected_color = find_node("ColorPicker").color
|
||||
colors_grid = find_node("Colors")
|
||||
|
||||
#---------------------------
|
||||
#Setup the info bottom panel
|
||||
#---------------------------
|
||||
add_text_info_variables()
|
||||
set_process(true)
|
||||
#--------------------
|
||||
# Setup Actions
|
||||
#--------------------
|
||||
for key in Actions:
|
||||
Actions[key].painter = paint_canvas_node
|
||||
|
||||
#--------------------
|
||||
#connect nodes
|
||||
#--------------------
|
||||
if not colors_grid.is_connected("color_change_request", self, "change_color"):
|
||||
colors_grid.connect("color_change_request", self, "change_color")
|
||||
|
||||
if not is_connected("visibility_changed", self, "_on_Editor_visibility_changed"):
|
||||
connect("visibility_changed", self, "_on_Editor_visibility_changed")
|
||||
|
||||
#--------------------
|
||||
#Setup the layer
|
||||
#--------------------
|
||||
var layer_container = find_node("Layers")
|
||||
|
||||
for child in layer_container.get_children():
|
||||
if child.name == "Layer1" or child.name == "Button":
|
||||
continue
|
||||
print("too many children: ", child.name)
|
||||
# child.queue_free()
|
||||
|
||||
#------------------
|
||||
#Setup visual grids
|
||||
#------------------
|
||||
paint_canvas_node.connect("grid_resized", self, "grid_resized")
|
||||
grid_resized(paint_canvas_node.grid_size)
|
||||
# for i in grids_node.get_children():
|
||||
# i.rect_size = Vector2(paint_canvas_node.canvas_size.x * grid_size, paint_canvas_node.canvas_size.y * grid_size)
|
||||
# grids_node.get_node("VisualGrid").size = grid_size
|
||||
# grids_node.get_node("VisualGrid2").size = grid_size * region_size
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
#Set the selected color to what the color picker has selected as default
|
||||
#-----------------------------------------------------------------------
|
||||
selected_color = get_node("ToolMenu/Buttons/ColorPicker").color
|
||||
#-----------------------------------
|
||||
#Setup canvas node size and position
|
||||
#-----------------------------------
|
||||
# paint_canvas_node.rect_size = Vector2(paint_canvas_node.canvas_size.x * grid_size,
|
||||
# paint_canvas_node.canvas_size.y * grid_size)
|
||||
# paint_canvas_node.rect_min_size = Vector2(paint_canvas_node.canvas_size.x * grid_size,
|
||||
# paint_canvas_node.canvas_size.y * grid_size)
|
||||
|
||||
#----------------------------------------------------------------
|
||||
#Setup is done so we can now allow the user to draw on the canvas
|
||||
#----------------------------------------------------------------
|
||||
paint_canvas_node.can_draw = true
|
||||
|
||||
#TODO: Make the paint canvas chunk size not a vector2?
|
||||
func grid_resized(size):
|
||||
grids_node.get_node("VisualGrid").rect_size = paint_canvas_node.canvas_size * size
|
||||
grids_node.get_node("VisualGrid").size = size
|
||||
grids_node.get_node("VisualGrid2").rect_size = paint_canvas_node.canvas_size * size
|
||||
grids_node.get_node("VisualGrid2").size = size * paint_canvas_node.chunk_size.x
|
||||
|
||||
func _ready():
|
||||
_add_init_layers()
|
||||
|
||||
|
||||
func _add_init_layers():
|
||||
var i = 0
|
||||
for layer in paint_canvas_node.layers:
|
||||
if layer == paint_canvas_node.preview_layer:
|
||||
continue
|
||||
_layer_button_ref[layer] = find_node("Layers").get_child(i)
|
||||
print("layer: ", layer, " is ", find_node("Layers").get_child(i).name)
|
||||
i += 1
|
||||
_connect_layer_buttons()
|
||||
|
||||
|
||||
func _input(event):
|
||||
if Input.is_key_pressed(KEY_Z):
|
||||
print("Z")
|
||||
elif Input.is_key_pressed(KEY_Y):
|
||||
print("Y")
|
||||
|
||||
|
||||
|
||||
var brush_mode = Tools.PAINT
|
||||
|
||||
var mouse_position = Vector2()
|
||||
var canvas_position = Vector2()
|
||||
@ -55,133 +142,527 @@ var cell_mouse_position = Vector2()
|
||||
var cell_region_position = Vector2()
|
||||
var cell_position_in_region = Vector2()
|
||||
var cell_color = Color()
|
||||
func process_common_used_variables():
|
||||
grid_size = paint_canvas_node.grid_size
|
||||
chunk_size = paint_canvas_node.chunk_size
|
||||
mouse_position = get_local_mouse_position()
|
||||
canvas_mouse_position = paint_canvas_node.get_local_mouse_position()
|
||||
cell_mouse_position = Vector2(floor(canvas_mouse_position.x / grid_size), floor(canvas_mouse_position.y / grid_size))
|
||||
cell_region_position = Vector2(floor(cell_mouse_position.x / chunk_size.x), floor(cell_mouse_position.y / chunk_size.y))
|
||||
cell_position_in_region = paint_canvas_node.pixel_in_canvas_region(cell_mouse_position)
|
||||
cell_color = paint_canvas_node.get_pixel(cell_mouse_position)
|
||||
|
||||
var last_mouse_position = Vector2()
|
||||
var last_canvas_position = Vector2()
|
||||
var last_canvas_mouse_position = Vector2()
|
||||
var last_cell_mouse_position = Vector2()
|
||||
var last_cell_color = Color()
|
||||
func process_last_common_used_variables():
|
||||
last_mouse_position = mouse_position
|
||||
last_canvas_position = canvas_position
|
||||
last_canvas_mouse_position = canvas_mouse_position
|
||||
last_cell_mouse_position = cell_mouse_position
|
||||
last_cell_color = cell_color
|
||||
|
||||
var active_tool
|
||||
func process_active_tool():
|
||||
active_tool = get_node("ToolManager").get_active_tool()
|
||||
active_tool.cell_mouse_position = cell_mouse_position
|
||||
active_tool.last_cell_mouse_position = last_cell_mouse_position
|
||||
active_tool.selected_color = selected_color
|
||||
active_tool.cell_color = cell_color
|
||||
|
||||
# warning-ignore:unused_argument
|
||||
func _process(delta):
|
||||
update_text_info()
|
||||
#It's a lot more easier to just keep updating the variables in here than just have a bunch of local variables
|
||||
#in every update function and make it very messy
|
||||
|
||||
#Update commonly used variables
|
||||
process_common_used_variables()
|
||||
if paint_canvas_node == null:
|
||||
#_check_variables()
|
||||
set_process(false)
|
||||
return
|
||||
|
||||
#Process the active tool
|
||||
process_active_tool()
|
||||
#Update commonly used variables
|
||||
grid_size = paint_canvas_node.grid_size
|
||||
region_size = paint_canvas_node.region_size
|
||||
mouse_position = paint_canvas_node.get_local_mouse_position()
|
||||
canvas_position = paint_canvas_container_node.rect_position
|
||||
canvas_mouse_position = Vector2(mouse_position.x - canvas_position.x, mouse_position.y - canvas_position.y)
|
||||
cell_mouse_position = Vector2(floor(canvas_mouse_position.x / grid_size), floor(canvas_mouse_position.y / grid_size))
|
||||
cell_region_position = Vector2(floor(cell_mouse_position.x / region_size), floor(cell_mouse_position.y / region_size))
|
||||
cell_position_in_region = paint_canvas_node.get_region_from_cell(cell_mouse_position.x, cell_mouse_position.y)
|
||||
cell_color = paint_canvas_node.get_pixel_cell_color(cell_mouse_position.x, cell_mouse_position.y)
|
||||
|
||||
#Process the brush drawing stuff
|
||||
if paint_canvas_container_node.mouse_in_region and paint_canvas_container_node.mouse_on_top:
|
||||
if (paint_canvas_node.mouse_in_region and paint_canvas_node.mouse_on_top) \
|
||||
or paint_canvas_node.preview_enabled:
|
||||
brush_process()
|
||||
|
||||
#Render the highlighting stuff
|
||||
update()
|
||||
|
||||
#Canvas Shift Moving
|
||||
if mouse_position != last_mouse_position:
|
||||
if paint_canvas_container_node.has_focus():
|
||||
if Input.is_key_pressed(KEY_SHIFT) or Input.is_mouse_button_pressed(BUTTON_MIDDLE):
|
||||
if Input.is_mouse_button_pressed(BUTTON_LEFT) or Input.is_mouse_button_pressed(BUTTON_MIDDLE):
|
||||
if not mouse_position == last_mouse_position:
|
||||
if paint_canvas_node.has_focus():
|
||||
if Input.is_key_pressed(KEY_SHIFT):
|
||||
if Input.is_mouse_button_pressed(BUTTON_LEFT):
|
||||
var relative = mouse_position - last_mouse_position
|
||||
camera.position -= relative * camera.zoom
|
||||
paint_canvas_node.rect_position += relative
|
||||
allow_drawing = false
|
||||
else:
|
||||
allow_drawing = true
|
||||
|
||||
#Update text info
|
||||
update_text_info()
|
||||
|
||||
#Update last variables with the current variables
|
||||
process_last_common_used_variables()
|
||||
last_mouse_position = mouse_position
|
||||
last_canvas_position = canvas_position
|
||||
last_canvas_mouse_position = canvas_mouse_position
|
||||
last_cell_mouse_position = cell_mouse_position
|
||||
last_cell_color = cell_color
|
||||
|
||||
var currently_selecting = false
|
||||
func _draw():
|
||||
if paint_canvas_node == null:
|
||||
return
|
||||
if paint_canvas_node.mouse_in_region and paint_canvas_node.mouse_in_region:
|
||||
#draw cell_mouse_position
|
||||
if paint_canvas_node.cell_in_canvas_region(cell_mouse_position.x, cell_mouse_position.y):
|
||||
draw_rect(Rect2(Vector2(
|
||||
(cell_mouse_position.x * grid_size) + canvas_position.x,
|
||||
(cell_mouse_position.y * grid_size) + canvas_position.y),
|
||||
Vector2(grid_size, grid_size)), Color(0.8, 0.8, 0.8, 0.8), true)
|
||||
|
||||
func draw_outline_box(pos, size, color, width):
|
||||
#Top line
|
||||
draw_line(Vector2(0 + 1 + pos.x, 0 + pos.y), Vector2(pos.x + size.x, 0 + pos.y), color, width)
|
||||
#Left line
|
||||
draw_line(Vector2(0 + 1 + pos.x, 0 + pos.y), Vector2(0 + pos.x, pos.y + size.y), color, width)
|
||||
#Bottom line
|
||||
draw_line(Vector2(0 + 1 + pos.x, pos.y + size.y), Vector2(pos.x + size.x, pos.y + size.y), color, width)
|
||||
#Right line
|
||||
draw_line(Vector2(pos.x + size.x, 0 + pos.y), Vector2(pos.x + size.x, pos.y + size.y), color, width)
|
||||
|
||||
func pool_vector2_array_append_new_value(vec2array, vec2):
|
||||
for i in vec2array:
|
||||
if i == vec2:
|
||||
return
|
||||
vec2array.append(vec2)
|
||||
|
||||
func custom_rect_size_brush(x, y, color, size):
|
||||
for cx in range(x, x + size):
|
||||
for cy in range(y, y + size):
|
||||
paint_canvas_node.set_pixel_cell(cx, cy, color)
|
||||
pass
|
||||
|
||||
|
||||
func _handle_cut():
|
||||
if Input.is_mouse_button_pressed(BUTTON_RIGHT):
|
||||
_just_cut = false
|
||||
_show_cut = false
|
||||
paint_canvas_node.preview_enabled = true
|
||||
paint_canvas_node.clear_layer("preview")
|
||||
brush_mode = _previous_tool
|
||||
paint_canvas_node.preview_enabled = false
|
||||
_selection = []
|
||||
return
|
||||
|
||||
if Input.is_mouse_button_pressed(BUTTON_LEFT):
|
||||
for pixel_pos in paint_canvas_node.get_pixels_from_line(cell_mouse_position, last_cell_mouse_position):
|
||||
for pixel in _selection:
|
||||
var pos = pixel[0]
|
||||
pos -= _cut_pos
|
||||
pos += pixel_pos
|
||||
paint_canvas_node.set_pixel_cell_v(pos, pixel[1])
|
||||
else:
|
||||
if _last_preview_draw_cell_pos == cell_mouse_position:
|
||||
return
|
||||
paint_canvas_node.preview_enabled = true
|
||||
paint_canvas_node.clear_layer("preview")
|
||||
for pixel in _selection:
|
||||
var pos = pixel[0]
|
||||
pos -= _cut_pos
|
||||
pos += cell_mouse_position
|
||||
paint_canvas_node.set_pixel_cell_v(pos, pixel[1])
|
||||
paint_canvas_node.preview_enabled = false
|
||||
_last_preview_draw_cell_pos = cell_mouse_position
|
||||
|
||||
|
||||
func brush_process():
|
||||
if not allow_drawing:
|
||||
return
|
||||
|
||||
if _just_cut:
|
||||
_handle_cut()
|
||||
return
|
||||
if Input.is_mouse_button_pressed(BUTTON_LEFT):
|
||||
if allow_drawing:
|
||||
active_tool.on_left_mouse_click()
|
||||
do_action(Actions[brush_mode], [cell_mouse_position, last_cell_mouse_position, selected_color])
|
||||
return
|
||||
match brush_mode:
|
||||
Tools.PAINT:
|
||||
paint_canvas_node.set_pixels_from_line(cell_mouse_position, last_cell_mouse_position, selected_color)
|
||||
Tools.BRUSH:
|
||||
for pixel_pos in paint_canvas_node.get_pixels_from_line(cell_mouse_position, last_cell_mouse_position):
|
||||
for off in BrushPrefabs.list[selected_brush_prefab]:
|
||||
paint_canvas_node.set_pixel_cell_v(pixel_pos + off, selected_color)
|
||||
Tools.LINE:
|
||||
paint_canvas_node.preview_enabled = true
|
||||
if _left_mouse_pressed_start_pos == Vector2.ZERO:
|
||||
_left_mouse_pressed_start_pos = cell_mouse_position
|
||||
paint_canvas_node.clear_layer("preview")
|
||||
paint_canvas_node.set_pixels_from_line(
|
||||
cell_mouse_position, _left_mouse_pressed_start_pos, selected_color)
|
||||
|
||||
Tools.RECT:
|
||||
paint_canvas_node.preview_enabled = true
|
||||
if _left_mouse_pressed_start_pos == Vector2.ZERO:
|
||||
_left_mouse_pressed_start_pos = cell_mouse_position
|
||||
paint_canvas_node.clear_layer("preview")
|
||||
|
||||
var p = _left_mouse_pressed_start_pos
|
||||
var s = cell_mouse_position - _left_mouse_pressed_start_pos
|
||||
|
||||
paint_canvas_node.set_pixels_from_line(
|
||||
p, p + Vector2(s.x, 0), selected_color)
|
||||
paint_canvas_node.set_pixels_from_line(
|
||||
p, p + Vector2(0, s.y), selected_color)
|
||||
paint_canvas_node.set_pixels_from_line(
|
||||
p + s, p + s + Vector2(0, -s.y), selected_color)
|
||||
paint_canvas_node.set_pixels_from_line(
|
||||
p + s, p + s + Vector2(-s.x, 0), selected_color)
|
||||
|
||||
Tools.DARKEN:
|
||||
var pixels = paint_canvas_node.get_pixels_from_line(cell_mouse_position, last_cell_mouse_position)
|
||||
var val = 0.9
|
||||
for pixel in pixels:
|
||||
if _last_drawn_pixel == pixel:
|
||||
continue
|
||||
_last_drawn_pixel = pixel
|
||||
|
||||
var new_color = paint_canvas_node.get_pixel_cell_color(pixel.x, pixel.y)
|
||||
new_color.r *= val
|
||||
new_color.g *= val
|
||||
new_color.b *= val
|
||||
paint_canvas_node.set_pixel_cell_v(pixel, new_color)
|
||||
|
||||
Tools.BRIGHTEN:
|
||||
var pixels = paint_canvas_node.get_pixels_from_line(cell_mouse_position, last_cell_mouse_position)
|
||||
var val = 1.1
|
||||
for pixel in pixels:
|
||||
if _last_drawn_pixel == pixel:
|
||||
continue
|
||||
_last_drawn_pixel = pixel
|
||||
|
||||
var new_color = paint_canvas_node.get_pixel_cell_color(pixel.x, pixel.y)
|
||||
new_color.r *= val
|
||||
new_color.g *= val
|
||||
new_color.b *= val
|
||||
paint_canvas_node.set_pixel_cell_v(pixel, new_color)
|
||||
|
||||
Tools.COLORPICKER:
|
||||
change_color(paint_canvas_node.get_pixel_cell_color(cell_mouse_position.x, cell_mouse_position.y))
|
||||
|
||||
Tools.CUT:
|
||||
paint_canvas_node.preview_enabled = true
|
||||
if _left_mouse_pressed_start_pos == Vector2.ZERO:
|
||||
_left_mouse_pressed_start_pos = cell_mouse_position
|
||||
paint_canvas_node.clear_layer("preview")
|
||||
|
||||
var p = _left_mouse_pressed_start_pos
|
||||
var s = cell_mouse_position - _left_mouse_pressed_start_pos
|
||||
|
||||
var selection_color = Color(0.8, 0.8, 0.8, 0.5)
|
||||
|
||||
paint_canvas_node.set_pixels_from_line(
|
||||
p, p + Vector2(s.x, 0), selection_color)
|
||||
paint_canvas_node.set_pixels_from_line(
|
||||
p, p + Vector2(0, s.y), selection_color)
|
||||
paint_canvas_node.set_pixels_from_line(
|
||||
p + s, p + s + Vector2(0, -s.y), selection_color)
|
||||
paint_canvas_node.set_pixels_from_line(
|
||||
p + s, p + s + Vector2(-s.x, 0), selection_color)
|
||||
|
||||
Tools.BUCKET:
|
||||
paint_canvas_node.flood_fill(cell_mouse_position.x, cell_mouse_position.y, cell_color, selected_color)
|
||||
Tools.RAINBOW:
|
||||
paint_canvas_node.set_random_pixels_from_line(cell_mouse_position, last_cell_mouse_position)
|
||||
_:
|
||||
print("no brush selected")
|
||||
# paint_canvas_node.set_pixels_from_line(cell_mouse_position, last_cell_mouse_position, selected_color)
|
||||
elif Input.is_mouse_button_pressed(BUTTON_RIGHT):
|
||||
if allow_drawing:
|
||||
active_tool.on_right_mouse_click()
|
||||
match brush_mode:
|
||||
Tools.PAINT:
|
||||
paint_canvas_node.set_pixels_from_line(cell_mouse_position, last_cell_mouse_position, Color(0, 0, 0, 0))
|
||||
# Tools.BUCKET:
|
||||
# paint_canvas_node.flood_fill(cell_mouse_position.x, cell_mouse_position.y, cell_color, Color(0, 0, 0, 0))
|
||||
Tools.BRUSH:
|
||||
for pixel_pos in paint_canvas_node.get_pixels_from_line(cell_mouse_position, last_cell_mouse_position):
|
||||
for off in BrushPrefabs.list[selected_brush_prefab]:
|
||||
paint_canvas_node.set_pixel_cell_v(pixel_pos + off, Color(0, 0, 0, 0))
|
||||
Tools.RAINBOW:
|
||||
paint_canvas_node.set_pixels_from_line(cell_mouse_position, last_cell_mouse_position, Color(0, 0, 0, 0))
|
||||
_:
|
||||
paint_canvas_node.set_pixels_from_line(cell_mouse_position, last_cell_mouse_position, Color(0, 0, 0, 0))
|
||||
|
||||
if paint_canvas_node.preview_enabled:
|
||||
if not Input.is_mouse_button_pressed(BUTTON_LEFT):
|
||||
match brush_mode:
|
||||
Tools.LINE:
|
||||
paint_canvas_node.clear_layer("preview")
|
||||
paint_canvas_node.preview_enabled = false
|
||||
paint_canvas_node.set_pixels_from_line(
|
||||
cell_mouse_position, _left_mouse_pressed_start_pos, selected_color)
|
||||
_left_mouse_pressed_start_pos = Vector2.ZERO
|
||||
|
||||
Tools.RECT:
|
||||
paint_canvas_node.clear_layer("preview")
|
||||
paint_canvas_node.preview_enabled = false
|
||||
|
||||
var p = _left_mouse_pressed_start_pos
|
||||
var s = cell_mouse_position - _left_mouse_pressed_start_pos
|
||||
|
||||
paint_canvas_node.set_pixels_from_line(
|
||||
p, p + Vector2(s.x, 0), selected_color)
|
||||
paint_canvas_node.set_pixels_from_line(
|
||||
p, p + Vector2(0, s.y), selected_color)
|
||||
paint_canvas_node.set_pixels_from_line(
|
||||
p + s, p + s + Vector2(0, -s.y), selected_color)
|
||||
paint_canvas_node.set_pixels_from_line(
|
||||
p + s, p + s + Vector2(-s.x, 0), selected_color)
|
||||
_left_mouse_pressed_start_pos = Vector2.ZERO
|
||||
|
||||
Tools.CUT:
|
||||
paint_canvas_node.clear_layer("preview")
|
||||
paint_canvas_node.preview_enabled = false
|
||||
|
||||
var p = _left_mouse_pressed_start_pos
|
||||
var s = cell_mouse_position - _left_mouse_pressed_start_pos
|
||||
_cut_pos = p + s / 2
|
||||
_cut_size = s
|
||||
|
||||
for x in range(abs(s.x)+1):
|
||||
for y in range(abs(s.y)+1):
|
||||
var px = x
|
||||
var py = y
|
||||
if s.x < 0:
|
||||
px *= -1
|
||||
if s.y < 0:
|
||||
py *= -1
|
||||
|
||||
var pos = p + Vector2(px, py)
|
||||
var color = paint_canvas_node.get_pixel_cell_color(pos.x, pos.y)
|
||||
if color.a == 0:
|
||||
continue
|
||||
_selection.append([pos, color])
|
||||
paint_canvas_node.set_pixel_cell_v(pos, Color.transparent)
|
||||
_left_mouse_pressed_start_pos = Vector2.ZERO
|
||||
_just_cut = true
|
||||
paint_canvas_node.preview_enabled = true
|
||||
|
||||
var zoom_amount = 0.5
|
||||
func _input(event):
|
||||
if event is InputEventMouseButton:
|
||||
if event.is_pressed():
|
||||
if paint_canvas_container_node.mouse_in_region and paint_canvas_container_node.mouse_on_top:
|
||||
if event.button_index == BUTTON_WHEEL_UP:
|
||||
if camera.zoom - Vector2(zoom_amount, zoom_amount) > Vector2(0, 0):
|
||||
camera.zoom -= Vector2(zoom_amount, zoom_amount)
|
||||
elif event.button_index == BUTTON_WHEEL_DOWN:
|
||||
camera.zoom += Vector2(zoom_amount, zoom_amount)
|
||||
|
||||
func add_text_info_variables():
|
||||
textinfo.add_text_info("FPS")
|
||||
textinfo.add_text_info("Mouse Position")
|
||||
textinfo.add_text_info("Canvas Mouse Position")
|
||||
textinfo.add_text_info("Canvas Position")
|
||||
textinfo.add_text_info("Cell Position")
|
||||
var cell_color_texture_rect = ColorRect.new()
|
||||
cell_color_texture_rect.name = "Cell Color"
|
||||
cell_color_texture_rect.rect_size = Vector2(14, 14)
|
||||
cell_color_texture_rect.rect_position.x = 120
|
||||
textinfo.add_text_info("Cell Color", cell_color_texture_rect)
|
||||
textinfo.add_text_info("Cell Region")
|
||||
textinfo.add_text_info("Cell Position in Region")
|
||||
|
||||
func update_text_info():
|
||||
textinfo.update_text_info("FPS", Engine.get_frames_per_second())
|
||||
textinfo.update_text_info("Mouse Position", mouse_position)
|
||||
textinfo.update_text_info("Canvas Mouse Position", canvas_mouse_position)
|
||||
textinfo.update_text_info("Canvas Position", canvas_position)
|
||||
textinfo.update_text_info("Cell Position", cell_mouse_position)
|
||||
var text = ""
|
||||
|
||||
var cell_color_text = cell_color
|
||||
if paint_canvas_container_node.mouse_in_region and paint_canvas_container_node.mouse_on_top:
|
||||
if Input.is_mouse_button_pressed(BUTTON_LEFT) or Input.is_mouse_button_pressed(BUTTON_RIGHT):
|
||||
if paint_canvas_node.last_pixel_drawn.size() > 0:
|
||||
cell_color_text = paint_canvas_node.last_pixel_drawn[1]
|
||||
if cell_color_text == null:
|
||||
cell_color_text = Color(0, 0, 0, 0)
|
||||
textinfo.update_text_info("Cell Color", cell_color_text, "Cell Color", "color", cell_color_text)
|
||||
textinfo.update_text_info("Cell Region", cell_region_position)
|
||||
textinfo.update_text_info("Cell Position in Region", cell_position_in_region)
|
||||
# if paint_canvas_node.mouse_in_region and paint_canvas_container_node.mouse_on_top:
|
||||
# if Input.is_mouse_button_pressed(BUTTON_LEFT) or Input.is_mouse_button_pressed(BUTTON_RIGHT):
|
||||
# if paint_canvas_node.last_pixel.size() > 0:
|
||||
# cell_color_text = paint_canvas_node.last_pixel[2]
|
||||
cell_color_text = Color(0, 0, 0, 0)
|
||||
|
||||
text += \
|
||||
str("FPS %s\t" + \
|
||||
"Mouse Position %s\t" + \
|
||||
"Canvas Mouse Position %s \t" + \
|
||||
"Canvas Position %s\t\n" + \
|
||||
"Cell Position %s \t" + \
|
||||
"Cell Color %s\t" + \
|
||||
"Cell Region %s \t" + \
|
||||
"Cell Position %s\t") % [
|
||||
str(Engine.get_frames_per_second()),
|
||||
str(mouse_position),
|
||||
str(canvas_mouse_position),
|
||||
str(canvas_position),
|
||||
str(cell_mouse_position),
|
||||
str(cell_color_text),
|
||||
str(cell_region_position),
|
||||
str(cell_position_in_region),
|
||||
]
|
||||
|
||||
find_node("DebugTextDisplay").display_text(text)
|
||||
|
||||
func _on_PaintTool_pressed():
|
||||
tool_manager.set_active_tool("Pencil")
|
||||
|
||||
func _on_BucketTool_pressed():
|
||||
tool_manager.set_active_tool("Bucket")
|
||||
func select_layer(layer_name: String):
|
||||
print("select layer: ", layer_name)
|
||||
paint_canvas_node.active_layer = layer_name
|
||||
|
||||
func _on_ColorPicker_color_changed(color):
|
||||
selected_color = color
|
||||
|
||||
func _on_Save_pressed():
|
||||
get_node("SaveFileDialog").show()
|
||||
|
||||
|
||||
|
||||
#---------------------------------------
|
||||
# Actions
|
||||
#---------------------------------------
|
||||
|
||||
|
||||
func do_action(action, data: Array):
|
||||
_actions_history.push_back(action)
|
||||
action.do_action(data)
|
||||
_redo_history.clear()
|
||||
|
||||
|
||||
func redo_action():
|
||||
pass
|
||||
|
||||
|
||||
func undo_action():
|
||||
var action = _actions_history.pop_back()
|
||||
_redo_history.append(action)
|
||||
action.undo_action()
|
||||
|
||||
|
||||
#---------------------------------------
|
||||
# Brushes
|
||||
#---------------------------------------
|
||||
|
||||
|
||||
func set_brush(new_mode):
|
||||
if brush_mode == new_mode:
|
||||
return
|
||||
_previous_tool = brush_mode
|
||||
brush_mode = new_mode
|
||||
|
||||
|
||||
func change_color(new_color):
|
||||
if new_color.a == 0:
|
||||
return
|
||||
selected_color = new_color
|
||||
find_node("ColorPicker").color = selected_color
|
||||
|
||||
|
||||
func _on_ColorPicker_color_changed(color):
|
||||
selected_color = color
|
||||
|
||||
|
||||
func _on_PaintTool_pressed():
|
||||
brush_mode = Tools.PAINT
|
||||
|
||||
|
||||
func _on_BucketTool_pressed():
|
||||
brush_mode = Tools.BUCKET
|
||||
|
||||
|
||||
func _on_RainbowTool_pressed():
|
||||
tool_manager.set_active_tool("Rainbow")
|
||||
set_brush(Tools.RAINBOW)
|
||||
|
||||
|
||||
func _on_BrushTool_pressed():
|
||||
var prev_mode = brush_mode
|
||||
set_brush(Tools.BRUSH)
|
||||
if prev_mode != brush_mode:
|
||||
return
|
||||
selected_brush_prefab += 1
|
||||
selected_brush_prefab = selected_brush_prefab % BrushPrefabs.list.size()
|
||||
var value = float(selected_brush_prefab) / BrushPrefabs.list.size()
|
||||
|
||||
find_node("BrushTool").get("custom_styles/normal").set("bg_color", Color(value, value, value, 1.0))
|
||||
|
||||
|
||||
func _on_LineTool_pressed():
|
||||
set_brush(Tools.LINE)
|
||||
|
||||
|
||||
func _on_RectTool_pressed():
|
||||
set_brush(Tools.RECT)
|
||||
|
||||
|
||||
func _on_DarkenTool_pressed():
|
||||
set_brush(Tools.DARKEN)
|
||||
|
||||
|
||||
func _on_BrightenTool_pressed():
|
||||
set_brush(Tools.BRIGHTEN)
|
||||
|
||||
|
||||
func _on_ColorPickerTool_pressed():
|
||||
set_brush(Tools.COLORPICKER)
|
||||
|
||||
|
||||
func _on_CutTool_pressed():
|
||||
set_brush(Tools.CUT)
|
||||
|
||||
|
||||
func _on_Editor_visibility_changed():
|
||||
pause_mode = not visible
|
||||
|
||||
|
||||
func _connect_layer_buttons():
|
||||
for layer_btn in get_tree().get_nodes_in_group("layer"):
|
||||
if layer_btn.is_connected("pressed", self, "select_layer"):
|
||||
continue
|
||||
layer_btn.connect("pressed", self, "select_layer", [get_layer_by_button_name(layer_btn.name)])
|
||||
layer_btn.find_node("Visible").connect("pressed", self, "toggle_layer_visibility",
|
||||
[layer_btn.find_node("Visible"), get_layer_by_button_name(layer_btn.name)])
|
||||
layer_btn.find_node("Up").connect("pressed", self, "move_up", [layer_btn])
|
||||
layer_btn.find_node("Down").connect("pressed", self, "move_down", [layer_btn])
|
||||
|
||||
|
||||
func toggle_layer_visibility(button, layer_name: String):
|
||||
print("toggling: ", layer_name)
|
||||
print(paint_canvas_node.layers.keys())
|
||||
paint_canvas_node.toggle_layer_visibility(layer_name)
|
||||
|
||||
|
||||
func add_new_layer():
|
||||
var layers = get_tree().get_nodes_in_group("layer")
|
||||
var new_layer = layers.back().duplicate()
|
||||
find_node("Layers").add_child_below_node(layers.back(), new_layer, true)
|
||||
_total_added_layers += 1
|
||||
new_layer.text = "Layer " + str(_total_added_layers)
|
||||
|
||||
var new_layer_name = paint_canvas_node.add_new_layer(new_layer.name)
|
||||
|
||||
_layer_button_ref[new_layer_name] = new_layer
|
||||
|
||||
_connect_layer_buttons()
|
||||
|
||||
print("added layer: ", new_layer_name, "(total:", layers.size(), ")")
|
||||
|
||||
|
||||
func remove_active_layer():
|
||||
if _layer_button_ref.size() < 2:
|
||||
return
|
||||
|
||||
_layer_button_ref[paint_canvas_node.active_layer].get_parent().remove_child(_layer_button_ref[paint_canvas_node.active_layer])
|
||||
_layer_button_ref[paint_canvas_node.active_layer].queue_free()
|
||||
_layer_button_ref.erase(paint_canvas_node.active_layer)
|
||||
paint_canvas_node.remove_layer(paint_canvas_node.active_layer)
|
||||
|
||||
|
||||
func duplicate_active_layer():
|
||||
# copy the last layer button (or the initial one)
|
||||
var layer_buttons = get_tree().get_nodes_in_group("layer")
|
||||
var new_layer_button = layer_buttons.back().duplicate()
|
||||
find_node("Layers").add_child_below_node(layer_buttons.back(), new_layer_button, true)
|
||||
|
||||
_total_added_layers += 1 # for keeping track...
|
||||
new_layer_button.text = "Layer " + str(_total_added_layers)
|
||||
|
||||
var new_layer_name = paint_canvas_node.duplicate_layer(paint_canvas_node.active_layer, new_layer_button.name)
|
||||
|
||||
_layer_button_ref[new_layer_name] = new_layer_button
|
||||
|
||||
_connect_layer_buttons()
|
||||
|
||||
print("added layer: ", new_layer_name, " (total:", layer_buttons.size(), ")")
|
||||
|
||||
|
||||
func get_layer_by_button_name(button_name: String):
|
||||
for layer_name in _layer_button_ref:
|
||||
var button = _layer_button_ref[layer_name]
|
||||
if button.name == button_name:
|
||||
return layer_name
|
||||
return null
|
||||
|
||||
|
||||
func move_down(layer_btn, button_name: String):
|
||||
print("move_up: ", button_name)
|
||||
var layer_name = get_layer_by_button_name(button_name)
|
||||
var chunk_node = paint_canvas_node.layers[layer_name].chunks
|
||||
chunk_node.get_parent().move_child(chunk_node, max(chunk_node.get_index() + 1, 0))
|
||||
layer_btn.get_parent().move_child(layer_btn, max(layer_btn.get_index() + 1, 0))
|
||||
|
||||
|
||||
func move_up(layer_btn, button_name: String):
|
||||
print("move_up: ", button_name)
|
||||
var layer_name = get_layer_by_button_name(button_name)
|
||||
var chunk_node = paint_canvas_node.layers[layer_name].chunks
|
||||
chunk_node.get_parent().move_child(chunk_node,
|
||||
min(chunk_node.get_index() - 1, chunk_node.get_parent().get_child_count() - 1))
|
||||
layer_btn.get_parent().move_child(layer_btn,
|
||||
min(layer_btn.get_index() - 1, layer_btn.get_parent().get_child_count() - 1))
|
||||
|
||||
|
||||
func _on_Button_pressed():
|
||||
add_new_layer()
|
||||
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,34 +0,0 @@
|
||||
tool
|
||||
extends Control
|
||||
onready var layers = get_node("../../../../")
|
||||
onready var canvas = layers.canvas
|
||||
var image_storage = Image.new() setget set_image_storage
|
||||
var layer_visible = true setget set_layer_visible
|
||||
|
||||
func _ready():
|
||||
var canvas_size = canvas.image.get_size()
|
||||
image_storage.create(canvas_size.x, canvas_size.y, true, Image.FORMAT_RGBA8)
|
||||
|
||||
func set_image_storage(image_data):
|
||||
image_storage = image_data
|
||||
var texture = ImageTexture.new()
|
||||
texture.create_from_image(image_data)
|
||||
texture.set_flags(0)
|
||||
texture.setup_local_to_scene()
|
||||
get_node("LayerPreview/TextureRect").texture = texture
|
||||
|
||||
func set_layer_visible(value):
|
||||
layer_visible = value
|
||||
if layer_visible:
|
||||
get_node("Visible").modulate = Color(1, 1, 1)
|
||||
else:
|
||||
get_node("Visible").modulate = Color(0.572549, 0.572549, 0.572549)
|
||||
|
||||
func _on_LayerButton_pressed():
|
||||
layers.active_layer = name
|
||||
|
||||
func _on_Visible_pressed():
|
||||
set_layer_visible(!layer_visible)
|
||||
|
||||
func _on_Delete_pressed():
|
||||
layers.remove_layer(name)
|
@ -1,68 +0,0 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/graphics_editor/Layer.gd" type="Script" id=1]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=1]
|
||||
bg_color = Color( 1, 1, 1, 1 )
|
||||
|
||||
[node name="Layer" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_right = -924.0
|
||||
margin_bottom = -510.0
|
||||
rect_min_size = Vector2( 100, 90 )
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Panel" type="Panel" parent="."]
|
||||
modulate = Color( 0.117647, 0.117647, 0.117647, 1 )
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
custom_styles/panel = SubResource( 1 )
|
||||
|
||||
[node name="LayerButton" type="Button" parent="."]
|
||||
modulate = Color( 1, 1, 1, 0 )
|
||||
margin_right = 100.0
|
||||
margin_bottom = 90.0
|
||||
|
||||
[node name="Name" type="Label" parent="."]
|
||||
margin_left = 10.0
|
||||
margin_top = 4.0
|
||||
margin_right = 56.0
|
||||
margin_bottom = 18.0
|
||||
text = "Layer 1"
|
||||
|
||||
[node name="Visible" type="Button" parent="."]
|
||||
margin_left = 80.0
|
||||
margin_top = 20.0
|
||||
margin_right = 100.0
|
||||
margin_bottom = 40.0
|
||||
focus_mode = 0
|
||||
enabled_focus_mode = 0
|
||||
text = "V"
|
||||
|
||||
[node name="Delete" type="Button" parent="."]
|
||||
margin_left = 80.0
|
||||
margin_top = 40.0
|
||||
margin_right = 100.0
|
||||
margin_bottom = 60.0
|
||||
focus_mode = 0
|
||||
enabled_focus_mode = 0
|
||||
text = "X"
|
||||
|
||||
[node name="LayerPreview" type="ColorRect" parent="."]
|
||||
margin_left = 10.0
|
||||
margin_top = 20.0
|
||||
margin_right = 74.0
|
||||
margin_bottom = 84.0
|
||||
mouse_filter = 2
|
||||
color = Color( 0.329412, 0.329412, 0.329412, 1 )
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="LayerPreview"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
expand = true
|
||||
stretch_mode = 1
|
||||
[connection signal="pressed" from="LayerButton" to="." method="_on_LayerButton_pressed"]
|
||||
[connection signal="pressed" from="Visible" to="." method="_on_Visible_pressed"]
|
||||
[connection signal="pressed" from="Delete" to="." method="_on_Delete_pressed"]
|
70
addons/graphics_editor/LayerButton.tscn
Normal file
70
addons/graphics_editor/LayerButton.tscn
Normal file
@ -0,0 +1,70 @@
|
||||
[gd_scene load_steps=6 format=2]
|
||||
|
||||
[ext_resource path="res://addons/graphics_editor/assets/minidotta_invis.png" type="Texture" id=1]
|
||||
[ext_resource path="res://addons/graphics_editor/assets/minidotta.png" type="Texture" id=2]
|
||||
[ext_resource path="res://addons/graphics_editor/assets/arrow_down.png" type="Texture" id=3]
|
||||
[ext_resource path="res://addons/graphics_editor/assets/arrow_up.png" type="Texture" id=4]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=1]
|
||||
bg_color = Color( 0.25098, 0.25098, 0.25098, 1 )
|
||||
|
||||
[node name="Layer1" type="Button" groups=[
|
||||
"layer",
|
||||
]]
|
||||
margin_right = 114.0
|
||||
margin_bottom = 20.0
|
||||
rect_min_size = Vector2( 0, 32 )
|
||||
custom_styles/hover = SubResource( 1 )
|
||||
custom_styles/pressed = SubResource( 1 )
|
||||
custom_styles/focus = SubResource( 1 )
|
||||
custom_styles/disabled = SubResource( 1 )
|
||||
custom_styles/normal = SubResource( 1 )
|
||||
text = "Layer 1"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Visible" type="CheckButton" parent="."]
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_top = -12.0
|
||||
margin_right = 28.0
|
||||
margin_bottom = 12.0
|
||||
custom_icons/off = ExtResource( 1 )
|
||||
custom_icons/on = ExtResource( 2 )
|
||||
pressed = true
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -20.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Up" type="TextureButton" parent="VBoxContainer"]
|
||||
margin_right = 20.0
|
||||
margin_bottom = 14.0
|
||||
rect_min_size = Vector2( 20, 0 )
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
texture_normal = ExtResource( 4 )
|
||||
texture_pressed = ExtResource( 2 )
|
||||
expand = true
|
||||
stretch_mode = 3
|
||||
|
||||
[node name="Down" type="TextureButton" parent="VBoxContainer"]
|
||||
margin_top = 18.0
|
||||
margin_right = 20.0
|
||||
margin_bottom = 32.0
|
||||
rect_min_size = Vector2( 20, 0 )
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
texture_normal = ExtResource( 3 )
|
||||
texture_pressed = ExtResource( 2 )
|
||||
expand = true
|
||||
stretch_mode = 3
|
@ -1,70 +0,0 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
onready var canvas = get_node("../../PaintCanvasContainer/ViewportContainer/Viewport/PaintCanvas")
|
||||
onready var layer_list = get_node("Panel/ScrollContainer/VBoxContainer")
|
||||
var layer_scene = preload("res://addons/graphics_editor/Layer.tscn")
|
||||
var active_layer setget set_active_layer
|
||||
|
||||
func _ready():
|
||||
if layer_list.get_children().size() <= 0:
|
||||
add_new_layer(true)
|
||||
|
||||
func _process(delta):
|
||||
var active_node = get_node_or_null("Panel/ScrollContainer/VBoxContainer/%s" % [active_layer])
|
||||
if active_node:
|
||||
active_node.image_storage = canvas.image.duplicate()
|
||||
canvas.image_pixel_array = get_all_layer_images()
|
||||
|
||||
func set_active_layer(new_layer):
|
||||
if active_layer:
|
||||
var cur_node = get_node_or_null("Panel/ScrollContainer/VBoxContainer/%s" % [active_layer])
|
||||
if cur_node:
|
||||
cur_node.get_node("Panel").modulate = Color(0.117647, 0.117647, 0.117647)
|
||||
active_layer = new_layer
|
||||
var new_node = get_node_or_null("Panel/ScrollContainer/VBoxContainer/%s" % [new_layer])
|
||||
if new_node and new_node.image_storage:
|
||||
new_node.get_node("Panel").modulate = Color(0.156863, 0.156863, 0.156863)
|
||||
canvas.load_image(new_node.image_storage)
|
||||
|
||||
func get_all_layer_images():
|
||||
var array = []
|
||||
for i in layer_list.get_children():
|
||||
if i.layer_visible:
|
||||
array.append(i.image_storage)
|
||||
return array
|
||||
|
||||
var num_increase = 1
|
||||
func increase_number_string(array, name_string):
|
||||
var name_to_return = "%s %s" % [name_string, num_increase]
|
||||
num_increase += 1
|
||||
return name_to_return
|
||||
|
||||
func _on_AddLayer_pressed():
|
||||
add_new_layer()
|
||||
|
||||
func add_new_layer(is_active = false):
|
||||
var get_children_name = PoolStringArray()
|
||||
for i in layer_list.get_children():
|
||||
get_children_name.append(i.name)
|
||||
var new_node_name = increase_number_string(get_children_name, "New Layer")
|
||||
var new_layer_node = layer_scene.instance()
|
||||
new_layer_node.get_node("Name").text = new_node_name
|
||||
new_layer_node.name = new_node_name
|
||||
layer_list.add_child(new_layer_node)
|
||||
if is_active:
|
||||
set_active_layer(new_node_name)
|
||||
|
||||
func remove_layer(layer_name):
|
||||
var layer_children = layer_list.get_children()
|
||||
if layer_children.size() <= 1:
|
||||
print("There needs to be an active layer always!")
|
||||
return
|
||||
for i in layer_children.size():
|
||||
if layer_children[i].name == layer_name:
|
||||
if layer_children[i].name == active_layer:
|
||||
if layer_children.size() != i+1:
|
||||
set_active_layer(layer_children[i+1].name)
|
||||
else:
|
||||
set_active_layer(layer_children[i-1].name)
|
||||
layer_children[i].queue_free()
|
@ -9,3 +9,5 @@ func _ready():
|
||||
|
||||
func id_pressed(id):
|
||||
emit_signal("item_pressed", name, popup.get_item_text(id))
|
||||
|
||||
|
||||
|
@ -1,66 +1,84 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
var navbar_storage = {
|
||||
"File": {
|
||||
"items": ["New", "Load", "Save", "Quit"],
|
||||
"export_only": ["Quit"]
|
||||
},
|
||||
"Editor": {
|
||||
"items": ["Settings", "Toggle Grid", "Reset Camera Position"],
|
||||
},
|
||||
"Image": {
|
||||
"items": ["Resize"]
|
||||
}
|
||||
}
|
||||
|
||||
onready var dialogs = get_parent().get_node("Dialogs")
|
||||
var editor
|
||||
var paint_canvas
|
||||
|
||||
func _ready():
|
||||
var x_to_add = 0
|
||||
var menu_button_script = load("res://addons/graphics_editor/MenuButtonExtended.gd")
|
||||
for i in navbar_storage:
|
||||
var menu_button = MenuButton.new()
|
||||
menu_button.name = i
|
||||
menu_button.rect_size = Vector2(90, 20)
|
||||
menu_button.rect_position = Vector2(x_to_add, 0)
|
||||
x_to_add += menu_button.rect_size.x
|
||||
menu_button.switch_on_hover = true
|
||||
menu_button.flat = false
|
||||
menu_button.text = i
|
||||
menu_button.set_script(menu_button_script)
|
||||
var items_to_remove = []
|
||||
if Engine.editor_hint:
|
||||
if navbar_storage[i].get("export_only"):
|
||||
for j in navbar_storage[i]["export_only"]:
|
||||
items_to_remove.append(j)
|
||||
if navbar_storage[i].get("items"):
|
||||
for j in navbar_storage[i]["items"]:
|
||||
var item_index = items_to_remove.find(j)
|
||||
if item_index == -1:
|
||||
menu_button.get_popup().add_item(j)
|
||||
get_node("Buttons").add_child(menu_button)
|
||||
editor = owner
|
||||
paint_canvas = editor.find_node("PaintCanvas")
|
||||
|
||||
for i in get_node("Buttons").get_children():
|
||||
i.connect("item_pressed", self, "button_pressed")
|
||||
|
||||
func button_pressed(button_name, button_item):
|
||||
if button_name == "File":
|
||||
if button_item == "New":
|
||||
dialogs.show_dialog("NewImage")
|
||||
if button_item == "Load":
|
||||
dialogs.show_dialog("LoadFileDialog")
|
||||
if button_item == "Save":
|
||||
dialogs.show_dialog("SaveFileDialog")
|
||||
if button_item == "Quit":
|
||||
get_tree().quit()
|
||||
elif button_name == "Editor":
|
||||
if button_item == "Settings":
|
||||
dialogs.show_dialog("Settings")
|
||||
elif button_item == "Toggle Grid":
|
||||
var grids_node = get_parent().get_node("PaintCanvasContainer/ViewportContainer/Viewport/PaintCanvas/Grids")
|
||||
print("pressed: ", button_name)
|
||||
print("pressed item is: '%s'" % button_item)
|
||||
|
||||
match button_name:
|
||||
"File":
|
||||
handle_file_menu(button_item)
|
||||
"Edit":
|
||||
handle_edit_menu(button_item)
|
||||
"Canvas":
|
||||
handle_canvas_menu(button_item)
|
||||
"Layer":
|
||||
handle_layer_menu(button_item)
|
||||
"Grid":
|
||||
handle_grid_menu(button_item)
|
||||
"Magic":
|
||||
handle_magic_menu(button_item)
|
||||
"Editor":
|
||||
handle_editor_menu(button_item)
|
||||
|
||||
|
||||
func handle_file_menu(pressed_item: String):
|
||||
match pressed_item:
|
||||
"Save":
|
||||
owner.get_node("SaveFileDialog").show()
|
||||
|
||||
|
||||
func handle_edit_menu(pressed_item: String):
|
||||
match pressed_item:
|
||||
"Add Layer":
|
||||
editor.add_new_layer()
|
||||
|
||||
|
||||
func handle_canvas_menu(pressed_item: String):
|
||||
match pressed_item:
|
||||
"Add Layer":
|
||||
editor.add_new_layer()
|
||||
|
||||
|
||||
func handle_layer_menu(pressed_item: String):
|
||||
match pressed_item:
|
||||
"Add Layer":
|
||||
editor.add_new_layer()
|
||||
"Delete Layer":
|
||||
editor.remove_active_layer()
|
||||
"Duplicate Layer":
|
||||
editor.duplicate_active_layer()
|
||||
|
||||
|
||||
func handle_grid_menu(pressed_item: String):
|
||||
match pressed_item:
|
||||
"Add Layer":
|
||||
editor.add_new_layer()
|
||||
|
||||
|
||||
func handle_magic_menu(pressed_item: String):
|
||||
match pressed_item:
|
||||
"Add Layer":
|
||||
editor.add_new_layer()
|
||||
|
||||
|
||||
func handle_editor_menu(pressed_item: String):
|
||||
match pressed_item:
|
||||
"Settings":
|
||||
owner.get_node("Settings").show()
|
||||
"Toggle Grid":
|
||||
var grids_node = owner.find_node("Grids")
|
||||
grids_node.visible = !grids_node.visible
|
||||
elif button_item == "Reset Camera Position":
|
||||
get_parent().camera.position = Vector2(0, 0)
|
||||
elif button_name == "Image":
|
||||
if button_item == "Resize":
|
||||
dialogs.show_dialog("ExpandCanvas")
|
||||
"Reset Canvas Position":
|
||||
owner.paint_canvas_node.rect_position = Vector2(0, 0)
|
||||
|
||||
|
@ -1,14 +0,0 @@
|
||||
extends Control
|
||||
|
||||
var message
|
||||
var time
|
||||
|
||||
func _ready():
|
||||
get_node("Label").text = message
|
||||
get_node("Timer").start(time)
|
||||
|
||||
func _on_Timer_timeout():
|
||||
queue_free()
|
||||
|
||||
func _on_Button_pressed():
|
||||
queue_free()
|
@ -1,38 +0,0 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/graphics_editor/Notification.gd" type="Script" id=1]
|
||||
|
||||
[node name="Notification" type="Control"]
|
||||
margin_right = 200.0
|
||||
margin_bottom = 100.0
|
||||
rect_min_size = Vector2( 0, 100 )
|
||||
mouse_filter = 2
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Panel" type="ColorRect" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
color = Color( 0.501961, 0.501961, 0.501961, 0.27451 )
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 10.0
|
||||
margin_top = 10.0
|
||||
margin_right = -40.0
|
||||
margin_bottom = -10.0
|
||||
text = "Notifcation Test!"
|
||||
|
||||
[node name="Button" type="Button" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
margin_left = -30.0
|
||||
margin_top = 10.0
|
||||
margin_right = -10.0
|
||||
margin_bottom = 30.0
|
||||
text = "X"
|
||||
|
||||
[node name="Timer" type="Timer" parent="."]
|
||||
one_shot = true
|
||||
[connection signal="pressed" from="Button" to="." method="_on_Button_pressed"]
|
@ -1,22 +0,0 @@
|
||||
extends Control
|
||||
|
||||
var limit = 3
|
||||
|
||||
var notification_storage = []
|
||||
|
||||
func create(message, time):
|
||||
var msg_scene = load("res://addons/graphics_editor/Notification.tscn").instance()
|
||||
msg_scene.message = message
|
||||
msg_scene.time = time
|
||||
if get_node("VBoxContainer").get_children().size() >= limit:
|
||||
notification_storage.push_back([message, time])
|
||||
return
|
||||
msg_scene.connect("tree_exited", self, "notification_deleted")
|
||||
get_node("VBoxContainer").add_child(msg_scene)
|
||||
get_node("VBoxContainer").move_child(msg_scene, 0)
|
||||
|
||||
func notification_deleted():
|
||||
if get_node("VBoxContainer").get_children().size() <= limit:
|
||||
if notification_storage.size() > 0:
|
||||
create(notification_storage[0][0], notification_storage[0][1])
|
||||
notification_storage.remove(0)
|
@ -1,182 +1,490 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
export var grid_size = 16 setget resize_grid
|
||||
export var canvas_size = Vector2(100, 100) setget resize_canvas
|
||||
export var chunk_size = Vector2(10, 10)
|
||||
var image = Image.new()
|
||||
var last_pixel = []
|
||||
onready var canvas_image_node = get_node("CanvasImage")
|
||||
export var grid_size = 16
|
||||
export var canvas_size = Vector2(48, 28)
|
||||
export var region_size = 10
|
||||
export var can_draw = true
|
||||
onready var canvas_node = get_node("CanvasImage")
|
||||
onready var util = get_node("Util")
|
||||
|
||||
var mouse_in_region
|
||||
var last_pixel_drawn = []
|
||||
var image = Image.new()
|
||||
var image_render = Image.new()
|
||||
var image_texture = ImageTexture.new()
|
||||
signal grid_resized
|
||||
signal canvas_resized
|
||||
var mouse_on_top
|
||||
|
||||
#terms
|
||||
#global cell - a cell that has a global grid position on the canvas
|
||||
#local cell - a cell that has a local grid position in a chunk region on the canvas
|
||||
#chunk region - a set of cells contained in an even number
|
||||
|
||||
#TODO: Maybe each chunk region can hold an image resource so that way the engine wouldn't lag at all when updating the canvas
|
||||
|
||||
var layers = {}
|
||||
var active_layer
|
||||
|
||||
var preview_layer = "preview"
|
||||
var preview_enabled = false
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
|
||||
#----------------------
|
||||
# init Layer
|
||||
#----------------------
|
||||
layers[preview_layer] = {
|
||||
"layer": null,
|
||||
"data": [],
|
||||
"chunks": null,
|
||||
}
|
||||
|
||||
canvas_size = Vector2(int(rect_size.x / grid_size), int(rect_size.y / grid_size))
|
||||
print("canvas_size: ", canvas_size)
|
||||
|
||||
|
||||
func _ready():
|
||||
image.create(canvas_size.x, canvas_size.y, true, Image.FORMAT_RGBA8)
|
||||
image_render.create(canvas_size.x, canvas_size.y, true, Image.FORMAT_RGBA8)
|
||||
rect_min_size = Vector2(canvas_size.x * grid_size, canvas_size.y * grid_size)
|
||||
rect_size = Vector2(canvas_size.x * grid_size, canvas_size.y * grid_size)
|
||||
canvas_node.rect_min_size = Vector2(canvas_size.x * grid_size, canvas_size.y * grid_size)
|
||||
canvas_node.rect_size = Vector2(canvas_size.x * grid_size, canvas_size.y * grid_size)
|
||||
image.lock()
|
||||
image_render.lock()
|
||||
active_layer = add_existing_layer(get_tree().get_nodes_in_group("layer")[0])
|
||||
print("active Layer: ", active_layer)
|
||||
|
||||
|
||||
func get_layer_data(layer_name):
|
||||
return layers[layer_name]
|
||||
|
||||
|
||||
func get_active_layer():
|
||||
return layers[active_layer]
|
||||
|
||||
|
||||
func get_preview_layer():
|
||||
return layers[preview_layer]
|
||||
|
||||
|
||||
func clear_active_layer():
|
||||
for pixel in layers[active_layer].data:
|
||||
set_global_cell_in_chunk(pixel[0], pixel[1], Color(0,0,0,0))
|
||||
|
||||
|
||||
func clear_layer(layer_name: String):
|
||||
for pixel in layers[layer_name].data:
|
||||
set_global_cell_in_chunk(pixel[0], pixel[1], Color(0,0,0,0))
|
||||
|
||||
|
||||
func clear_preview_layer():
|
||||
for pixel in layers["preview"].data:
|
||||
set_global_cell_in_chunk(pixel[0], pixel[1], Color(0,0,0,0))
|
||||
|
||||
|
||||
func remove_layer(layer_name):
|
||||
get_node("ChunkNodes").remove_child(layers[layer_name].chunks)
|
||||
layers[layer_name].chunks.queue_free()
|
||||
|
||||
layers.erase(layer_name)
|
||||
|
||||
if active_layer == layer_name:
|
||||
for layer in layers:
|
||||
if layer == preview_layer:
|
||||
continue
|
||||
active_layer = layer
|
||||
break
|
||||
|
||||
return active_layer
|
||||
|
||||
|
||||
|
||||
# only needed for init
|
||||
func add_existing_layer(layer):
|
||||
layers[layer.name] = {
|
||||
"layer": layer,
|
||||
"data": [],
|
||||
"chunks": null,
|
||||
}
|
||||
generate_chunks()
|
||||
return layer.name
|
||||
|
||||
|
||||
func add_new_layer(layer_name):
|
||||
layers[layer_name] = {
|
||||
"layer": null,
|
||||
"data": [],
|
||||
"chunks": null,
|
||||
}
|
||||
|
||||
generate_chunks()
|
||||
|
||||
return layer_name
|
||||
|
||||
|
||||
func duplicate_layer(layer: String, neu_layer_name: String):
|
||||
var _preview = preview_enabled
|
||||
preview_enabled = false
|
||||
var _temp = active_layer
|
||||
active_layer = neu_layer_name
|
||||
|
||||
layers[neu_layer_name] = {
|
||||
"layer": null,
|
||||
"data": layers[layer].data.duplicate(true),
|
||||
"chunks": null,
|
||||
}
|
||||
|
||||
generate_chunks()
|
||||
# get_node("ChunkNodes").remove_child(layers[neu_layer_name].chunks)
|
||||
# get_node("ChunkNodes").add_child_below_node(layers[layer].chunks, layers[neu_layer_name].chunks, true)
|
||||
|
||||
for pixel in layers[neu_layer_name].data:
|
||||
set_pixel_cell(pixel[0], pixel[1], pixel[2])
|
||||
active_layer = _temp
|
||||
|
||||
preview_enabled = _preview
|
||||
return neu_layer_name
|
||||
|
||||
|
||||
func toggle_layer_visibility(layer_name):
|
||||
layers[layer_name].chunks.visible = not layers[layer_name].chunks.visible
|
||||
print("Layer: ", layer_name, " is now: ", layers[layer_name].chunks.visible)
|
||||
|
||||
|
||||
var util = preload("res://addons/graphics_editor/Util.gd")
|
||||
|
||||
|
||||
func _on_mouse_entered():
|
||||
mouse_on_top = true
|
||||
|
||||
|
||||
func _on_mouse_exited():
|
||||
mouse_on_top = false
|
||||
|
||||
|
||||
func _process(delta):
|
||||
update_canvas()
|
||||
var mouse_position = get_local_mouse_position()
|
||||
var rect = Rect2(Vector2(0, 0), rect_size)
|
||||
mouse_in_region = rect.has_point(mouse_position)
|
||||
update()
|
||||
#if not Engine.editor_hint:
|
||||
# print(mouse_on_canvas, " | ", has_focus())
|
||||
#draw_canvas_out just updates the image constantly
|
||||
#if can_draw:
|
||||
# draw_canvas_out()
|
||||
|
||||
#----------------------
|
||||
#---SETGET FUNCTIONS---
|
||||
#----------------------
|
||||
|
||||
func resize_grid(new_size):
|
||||
grid_size = new_size
|
||||
if canvas_node:
|
||||
#generate_chunks()
|
||||
rect_min_size = Vector2(canvas_size.x * new_size, canvas_size.y * new_size)
|
||||
rect_size = Vector2(canvas_size.x * new_size, canvas_size.y * new_size)
|
||||
canvas_node.rect_min_size = Vector2(canvas_size.x * new_size, canvas_size.y * new_size)
|
||||
canvas_node.rect_size = Vector2(canvas_size.x * new_size, canvas_size.y * new_size)
|
||||
emit_signal("grid_resized", new_size)
|
||||
|
||||
func resize_canvas(new_size):
|
||||
canvas_size = new_size
|
||||
if canvas_node:
|
||||
image.unlock()
|
||||
image = Image.new()
|
||||
image.create(canvas_size.x, canvas_size.y, true, Image.FORMAT_RGBA8)
|
||||
image.lock()
|
||||
image_render.unlock()
|
||||
image_render.create(canvas_size.x, canvas_size.y, true, Image.FORMAT_RGBA8)
|
||||
image_render.lock()
|
||||
rect_min_size = Vector2(new_size.x * grid_size, new_size.y * grid_size)
|
||||
rect_size = Vector2(new_size.x * grid_size, new_size.y * grid_size)
|
||||
canvas_node.rect_min_size = Vector2(new_size.x * grid_size, new_size.y * grid_size)
|
||||
canvas_node.rect_size = Vector2(new_size.x * grid_size, new_size.y * grid_size)
|
||||
emit_signal("canvas_resized", new_size)
|
||||
|
||||
#---------------------
|
||||
#---CHUNK FUNCTIONS---
|
||||
#---------------------
|
||||
|
||||
func spawn_chunk(pos):
|
||||
pass
|
||||
|
||||
func update_chunk(pos):
|
||||
pass
|
||||
|
||||
func get_chunk_from_pixel(pos):
|
||||
pass
|
||||
|
||||
func set_chunk(pos):
|
||||
pass
|
||||
|
||||
func remove_chunk(pos):
|
||||
pass
|
||||
|
||||
func generate_chunks():
|
||||
pass
|
||||
var maxium_chunk_size = get_maxium_filled_chunks()
|
||||
#TODO: We probably don't need to check for x and y anymore
|
||||
for key in layers:
|
||||
if layers[key].chunks != null:
|
||||
continue
|
||||
|
||||
var chunk_node = Control.new()
|
||||
get_node("ChunkNodes").add_child(chunk_node)
|
||||
chunk_node.owner = self
|
||||
|
||||
layers[key].chunks = chunk_node
|
||||
|
||||
for x in maxium_chunk_size.x:
|
||||
for y in maxium_chunk_size.y:
|
||||
var paint_canvas_chunk = load("res://addons/graphics_editor/PaintCanvasChunk.tscn").instance()
|
||||
paint_canvas_chunk.setup(region_size)
|
||||
paint_canvas_chunk.name = "C-%s-%s" % [x, y]
|
||||
paint_canvas_chunk.rect_position = Vector2(x * (grid_size * region_size), y * (grid_size * region_size))
|
||||
layers[key].chunks.add_child(paint_canvas_chunk)
|
||||
|
||||
#---------------------
|
||||
#---PIXEL FUNCTIONS---
|
||||
#---------------------
|
||||
|
||||
func get_pixel(pos):
|
||||
if not pixel_in_canvas_region(pos):
|
||||
func get_maxium_filled_chunks():
|
||||
return Vector2(canvas_size.x / region_size, canvas_size.y / region_size).ceil()
|
||||
|
||||
#TODO: Remake these functions with godot's setget features
|
||||
#so that we don't have to call these functions
|
||||
func resize_grid(grid):
|
||||
#print(grid)
|
||||
if grid <= 0:
|
||||
return
|
||||
grid_size = grid
|
||||
canvas_image_node.rect_scale = Vector2(grid, grid)
|
||||
|
||||
func resize_canvas(x, y):
|
||||
image.unlock()
|
||||
image.create(x, y, true, Image.FORMAT_RGBA8)
|
||||
canvas_size = Vector2(x, y)
|
||||
#setup_all_chunks()
|
||||
image.lock()
|
||||
|
||||
#func draw_canvas_out(a = ""):
|
||||
# if canvas_image_node == null:
|
||||
# return
|
||||
# var image_texture = ImageTexture.new()
|
||||
# image_texture.create_from_image(image)
|
||||
# image_texture.set_flags(0)
|
||||
# canvas_image_node.texture = image_texture
|
||||
|
||||
func get_wrapped_region_cell(x, y):
|
||||
return Vector2(wrapi(x, 0, region_size), wrapi(y, 0, region_size))
|
||||
|
||||
func get_region_from_cell(x, y):
|
||||
return Vector2(floor(x / region_size), floor(y / region_size))
|
||||
|
||||
|
||||
func set_local_cell_in_chunk(chunk_x, chunk_y, local_cell_x, local_cell_y, color):
|
||||
var chunk_node
|
||||
|
||||
if preview_enabled:
|
||||
chunk_node = layers.preview.chunks.get_node_or_null("C-%s-%s" % [chunk_x, chunk_y])
|
||||
else:
|
||||
chunk_node = layers[active_layer].chunks.get_node_or_null("C-%s-%s" % [chunk_x, chunk_y])
|
||||
|
||||
if chunk_node == null:
|
||||
print("Can't find chunk node!")
|
||||
return
|
||||
chunk_node.set_cell(local_cell_x, local_cell_y, color)
|
||||
|
||||
|
||||
func set_global_cell_in_chunk(cell_x, cell_y, color):
|
||||
var chunk = get_region_from_cell(cell_x, cell_y)
|
||||
var wrapped_cell = get_wrapped_region_cell(cell_x, cell_y)
|
||||
set_local_cell_in_chunk(chunk.x, chunk.y, wrapped_cell.x, wrapped_cell.y, color)
|
||||
|
||||
#func update_chunk_region_from_cell(x, y):
|
||||
# var region_to_update = get_region_from_cell(x, y)
|
||||
# update_chunk_region(region_to_update.x, region_to_update.y)
|
||||
|
||||
func get_pixel_cell_color(x, y):
|
||||
if not cell_in_canvas_region(x, y):
|
||||
return null
|
||||
var pixel_cell = get_pixel_cell(x, y)
|
||||
if pixel_cell == null:
|
||||
#We already checked that the cell can't be out of the canvas region so we can assume the pixel cell is completely transparent if it's null
|
||||
return Color(0, 0, 0, 0)
|
||||
else:
|
||||
return util.color_from_array(pixel_cell[2])
|
||||
|
||||
func get_pixel_cell_color_v(vec2):
|
||||
return get_pixel_cell_color(vec2.x, vec2.y)
|
||||
|
||||
func get_pixel_cell(x, y):
|
||||
if active_layer == null:
|
||||
return
|
||||
if not cell_in_canvas_region(x, y):
|
||||
return null
|
||||
|
||||
return image.get_pixelv(pos)
|
||||
|
||||
func set_pixel(pos, color):
|
||||
if not pixel_in_canvas_region(pos):
|
||||
return null
|
||||
for pixel in get_active_layer().data:
|
||||
if pixel[0] == x and pixel[1] == y:
|
||||
return pixel
|
||||
|
||||
last_pixel_drawn = [pos, color]
|
||||
return image.set_pixelv(pos, color)
|
||||
return null
|
||||
|
||||
func pixel_in_canvas_region(pos):
|
||||
if pos.x < canvas_size.x and pos.x > -1 and pos.y < canvas_size.y and pos.y > -1:
|
||||
func get_pixel_cell_v(vec2):
|
||||
return get_pixel_cell(vec2.x, vec2.y)
|
||||
|
||||
#func remove_pixel_cell(x, y):
|
||||
# if can_draw == false:
|
||||
# return false
|
||||
# if not cell_in_canvas_region(x, y):
|
||||
# return false
|
||||
# var layer_data = get_layer_data("Layer 1")
|
||||
# for pixel in range(0, layer_data.size()):
|
||||
# if layer_data[pixel][0] == x and layer_data[pixel][1] == y:
|
||||
# layer_data.remove(pixel)
|
||||
# #update_chunk_region_from_cell(x, y)
|
||||
# #TOOD: If pixel exists in temp_pool_pixels then remove it
|
||||
# image.set_pixel(x, y, Color(0, 0, 0, 0))
|
||||
# return true
|
||||
# return false
|
||||
|
||||
#func remove_pixel_cell_v(vec2):
|
||||
# return remove_pixel_cell(vec2.x, vec2.y)
|
||||
|
||||
func set_pixel_cell(x, y, color):
|
||||
if can_draw == false:
|
||||
return false
|
||||
|
||||
if not cell_in_canvas_region(x, y):
|
||||
return false
|
||||
|
||||
var layer
|
||||
if preview_enabled:
|
||||
layer = get_preview_layer()
|
||||
else:
|
||||
layer = get_active_layer()
|
||||
|
||||
var index = 0
|
||||
for pixel in layer.data:
|
||||
#TODO: Make a better way of accessing the array because the more pixels we have, the longer it takes to
|
||||
#set the pixel
|
||||
if pixel[0] == x and pixel[1] == y:
|
||||
#No reason to set the pixel again if the colors are the same
|
||||
|
||||
#If the color we are setting is 0, 0, 0, 0 then there is no reason to keep the information about the pixel
|
||||
#so we remove it from the layer data
|
||||
if color == Color(0, 0, 0, 0):
|
||||
layer.data.remove(index)
|
||||
else:
|
||||
pixel[2] = color
|
||||
#TODO: The new system is going to allow chunks to each have their own TextureRect and Image
|
||||
#nodes so what we are doing in here is that we are setting the local cell in the region of that image
|
||||
set_global_cell_in_chunk(x, y, color)
|
||||
last_pixel = [x, y, color]
|
||||
return true
|
||||
index += 1
|
||||
#don't append any data if the color is 0, 0, 0, 0
|
||||
if color != Color(0, 0, 0, 0):
|
||||
#if the pixel data doesn't exist then we add it in
|
||||
layer.data.append([x, y, color])
|
||||
set_global_cell_in_chunk(x, y, color)
|
||||
last_pixel = [x, y, color]
|
||||
return true
|
||||
|
||||
func set_pixel_cell_v(vec2, color):
|
||||
return set_pixel_cell(vec2.x, vec2.y, color)
|
||||
|
||||
func set_pixels_from_line(vec2_1, vec2_2, color):
|
||||
var points = get_pixels_from_line(vec2_1, vec2_2)
|
||||
for i in points:
|
||||
set_pixel_cell_v(i, color)
|
||||
|
||||
func set_random_pixels_from_line(vec2_1, vec2_2):
|
||||
var points = get_pixels_from_line(vec2_1, vec2_2)
|
||||
for i in points:
|
||||
set_pixel_cell_v(i, util.random_color_alt())
|
||||
|
||||
func get_pixels_from_line(vec2_1, vec2_2):
|
||||
var points = PoolVector2Array()
|
||||
|
||||
var dx = abs(vec2_2.x - vec2_1.x)
|
||||
var dy = abs(vec2_2.y - vec2_1.y)
|
||||
|
||||
var x = vec2_1.x
|
||||
var y = vec2_1.y
|
||||
|
||||
var sx = 0
|
||||
if vec2_1.x > vec2_2.x:
|
||||
sx = -1
|
||||
else:
|
||||
sx = 1
|
||||
|
||||
var sy = 0
|
||||
if vec2_1.y > vec2_2.y:
|
||||
sy = -1
|
||||
else:
|
||||
sy = 1
|
||||
|
||||
if dx > dy:
|
||||
var err = dx / 2
|
||||
while(true):
|
||||
if x == vec2_2.x:
|
||||
break
|
||||
points.push_back(Vector2(x, y))
|
||||
|
||||
err -= dy
|
||||
if err < 0:
|
||||
y += sy
|
||||
err += dx
|
||||
x += sx
|
||||
else:
|
||||
var err = dy / 2
|
||||
while (true):
|
||||
if y == vec2_2.y:
|
||||
break
|
||||
points.push_back(Vector2(x, y))
|
||||
|
||||
err -= dx
|
||||
if err < 0:
|
||||
x += sx
|
||||
err += dy
|
||||
y += sy
|
||||
points.push_back(Vector2(x, y))
|
||||
return points
|
||||
|
||||
|
||||
#even though the function checks for it, we can't afford adding more functions to the call stack
|
||||
#because godot has a limit until it crashes
|
||||
var flood_fill_queue = 0
|
||||
func flood_fill(x, y, target_color, replacement_color):
|
||||
#yield(get_tree().create_timer(1), "timeout")
|
||||
flood_fill_queue += 1
|
||||
if not cell_in_canvas_region(x, y):
|
||||
flood_fill_queue -= 1
|
||||
return
|
||||
if target_color == replacement_color:
|
||||
flood_fill_queue -= 1
|
||||
return
|
||||
elif not get_pixel_cell_color(x, y) == target_color:
|
||||
flood_fill_queue -= 1
|
||||
return
|
||||
else:
|
||||
set_pixel_cell(x, y, replacement_color)
|
||||
if flood_fill_queue >= 500:
|
||||
print(flood_fill_queue)
|
||||
yield(get_tree().create_timer(0.01), "timeout")
|
||||
#up
|
||||
if get_pixel_cell_color(x, y - 1) == target_color:
|
||||
flood_fill(x, y - 1, target_color, replacement_color)
|
||||
#down
|
||||
if get_pixel_cell_color(x, y + 1) == target_color:
|
||||
flood_fill(x, y + 1, target_color, replacement_color)
|
||||
#left
|
||||
if get_pixel_cell_color(x - 1, y) == target_color:
|
||||
flood_fill(x - 1, y, target_color, replacement_color)
|
||||
#right
|
||||
if get_pixel_cell_color(x + 1, y) == target_color:
|
||||
flood_fill(x + 1, y, target_color, replacement_color)
|
||||
flood_fill_queue -= 1
|
||||
return
|
||||
|
||||
#func flood_fill_erase(x, y, target_color):
|
||||
# yield(get_tree().create_timer(0.001), "timeout")
|
||||
# if not cell_in_canvas_region(x, y):
|
||||
# print("cell not in canvas")
|
||||
# return
|
||||
# #if target_color == replacement_color:
|
||||
# # return
|
||||
# elif not get_pixel_cell_color(x, y) == target_color:
|
||||
# print("cell doesn't match pixel color")
|
||||
# return
|
||||
# elif not get_pixel_cell(x, y):
|
||||
# print("cell already erased")
|
||||
# return
|
||||
# else:
|
||||
# print("removed pixel")
|
||||
# remove_pixel_cell(x, y)
|
||||
# print("x: ", x, " y: ", y, " color: ", target_color)
|
||||
# #up
|
||||
# flood_fill_erase(x, y - 1, target_color)
|
||||
# #down
|
||||
# flood_fill_erase(x, y + 1, target_color)
|
||||
# #left
|
||||
# flood_fill_erase(x - 1, y, target_color)
|
||||
# #right
|
||||
# flood_fill_erase(x + 1, y, target_color)
|
||||
# return
|
||||
|
||||
func cell_in_canvas_region(x, y):
|
||||
if x > canvas_size.x - 1 or x < 0 or y > canvas_size.y - 1 or y < 0:
|
||||
#out of bounds, return false
|
||||
return false
|
||||
else:
|
||||
return true
|
||||
return false
|
||||
|
||||
#--------------------
|
||||
#--Canvas Rendering--
|
||||
#--------------------
|
||||
#Both of these functions right now just return the starting position of the canvas and the last position of the canvas
|
||||
func get_all_used_regions_in_canvas():
|
||||
var first_used_region = get_first_used_region_in_canvas()
|
||||
var last_used_region = get_last_used_region_in_canvas()
|
||||
var chunk_pool = PoolVector2Array()
|
||||
for chunk_x in range(first_used_region.x, last_used_region.x):
|
||||
for chunk_y in range(first_used_region.y, last_used_region.y):
|
||||
chunk_pool.append(Vector2(chunk_x, chunk_y))
|
||||
return chunk_pool
|
||||
|
||||
var image_pixel_array = []
|
||||
func update_canvas():
|
||||
image_render.fill(Color(0, 0, 0, 0))
|
||||
for i in image_pixel_array:
|
||||
image_render.blend_rect(i, Rect2(Vector2.ZERO, canvas_size), Vector2.ZERO)
|
||||
image_texture.create_from_image(image_render)
|
||||
image_texture.set_flags(0)
|
||||
if canvas_node:
|
||||
canvas_node.texture = image_texture
|
||||
func get_first_used_region_in_canvas():
|
||||
return get_region_from_cell(0, 0)
|
||||
|
||||
#---------------------
|
||||
#---IMAGE FUNCTIONS---
|
||||
#---------------------
|
||||
func get_last_used_region_in_canvas():
|
||||
return get_region_from_cell(canvas_size.x - 1, canvas_size.y - 1)
|
||||
|
||||
func load_image(image_data):
|
||||
var array_data = image_data_to_array(image_data)
|
||||
image.unlock()
|
||||
image.create(canvas_size.x, canvas_size.y, true, Image.FORMAT_RGBA8)
|
||||
image.lock()
|
||||
image_render.unlock()
|
||||
image_render.create(canvas_size.x, canvas_size.y, true, Image.FORMAT_RGBA8)
|
||||
image_render.lock()
|
||||
set_pixels_from_array(array_data)
|
||||
rect_min_size = Vector2(canvas_size.x * grid_size, canvas_size.y * grid_size)
|
||||
rect_size = Vector2(canvas_size.x * grid_size, canvas_size.y * grid_size)
|
||||
canvas_node.rect_min_size = Vector2(canvas_size.x * grid_size, canvas_size.y * grid_size)
|
||||
canvas_node.rect_size = Vector2(canvas_size.x * grid_size, canvas_size.y * grid_size)
|
||||
emit_signal("canvas_resized", canvas_size)
|
||||
|
||||
func load_image_from_file(file_path):
|
||||
image.unlock()
|
||||
image.load(file_path)
|
||||
image.lock()
|
||||
canvas_size = image.get_size()
|
||||
image_render.unlock()
|
||||
image_render.create(canvas_size.x, canvas_size.y, true, Image.FORMAT_RGBA8)
|
||||
image_render.lock()
|
||||
rect_min_size = Vector2(canvas_size.x * grid_size, canvas_size.y * grid_size)
|
||||
rect_size = Vector2(canvas_size.x * grid_size, canvas_size.y * grid_size)
|
||||
canvas_node.rect_min_size = Vector2(canvas_size.x * grid_size, canvas_size.y * grid_size)
|
||||
canvas_node.rect_size = Vector2(canvas_size.x * grid_size, canvas_size.y * grid_size)
|
||||
emit_signal("canvas_resized", canvas_size)
|
||||
|
||||
func expand_canvas(new_size):
|
||||
canvas_size = new_size
|
||||
if canvas_node:
|
||||
var array_data = image_data_to_array(image)
|
||||
image.unlock()
|
||||
image.create(new_size.x, new_size.y, true, Image.FORMAT_RGBA8)
|
||||
image.lock()
|
||||
image_render.unlock()
|
||||
image_render.create(new_size.x, new_size.y, true, Image.FORMAT_RGBA8)
|
||||
image_render.lock()
|
||||
set_pixels_from_array(array_data)
|
||||
rect_min_size = Vector2(new_size.x * grid_size, new_size.y * grid_size)
|
||||
rect_size = Vector2(new_size.x * grid_size, new_size.y * grid_size)
|
||||
canvas_node.rect_min_size = Vector2(new_size.x * grid_size, new_size.y * grid_size)
|
||||
canvas_node.rect_size = Vector2(new_size.x * grid_size, new_size.y * grid_size)
|
||||
emit_signal("canvas_resized", new_size)
|
||||
|
||||
func set_pixels_from_array(array):
|
||||
for i in array:
|
||||
set_pixel(i[0], i[1])
|
||||
|
||||
func image_data_to_array(image_data):
|
||||
var array = []
|
||||
if image_data:
|
||||
image_data.lock()
|
||||
var image_data_size = image_data.get_size()
|
||||
for x in image_data_size.x:
|
||||
for y in image_data_size.y:
|
||||
array.append([Vector2(x, y), image_data.get_pixel(x, y)])
|
||||
return array
|
||||
func get_cells_in_region(x, y):
|
||||
var start_cell = Vector2(x * region_size, y * region_size)
|
||||
var end_cell = Vector2((x * region_size) + region_size, (y * region_size) + region_size)
|
||||
var cell_array = []
|
||||
for cx in range(start_cell.x, end_cell.x):
|
||||
for cy in range(start_cell.y, end_cell.y):
|
||||
var pixel_cell = get_pixel_cell(cx, cy)
|
||||
if pixel_cell == null:
|
||||
pixel_cell = [cx, cy, Color(0, 0, 0, 0)]
|
||||
cell_array.append(pixel_cell)
|
||||
return cell_array
|
||||
|
File diff suppressed because one or more lines are too long
@ -20,11 +20,8 @@ func set_cell(x, y, color):
|
||||
image.set_pixel(x, y, color)
|
||||
update_chunk()
|
||||
|
||||
func get_cell(x, y):
|
||||
return image.get_pixel(x, y)
|
||||
|
||||
func _on_VisibilityNotifier2D_screen_entered():
|
||||
visible = true
|
||||
|
||||
func _on_VisibilityNotifier2D_screen_exited():
|
||||
visible = false
|
||||
visible = false
|
||||
|
@ -1,19 +1,2 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
var mouse_in_region
|
||||
var mouse_on_top
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func _process(delta):
|
||||
var mouse_position = get_local_mouse_position()
|
||||
var rect = Rect2(Vector2(0, 0), rect_size)
|
||||
mouse_in_region = rect.has_point(mouse_position)
|
||||
|
||||
func _on_PaintCanvasContainer_mouse_entered():
|
||||
mouse_on_top = true
|
||||
|
||||
func _on_PaintCanvasContainer_mouse_exited():
|
||||
mouse_on_top = false
|
||||
|
@ -1,88 +0,0 @@
|
||||
tool
|
||||
extends Node
|
||||
|
||||
onready var paint_canvas = get_parent()
|
||||
onready var util = preload("res://addons/graphics_editor/Util.gd")
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func set_pixels_from_line(vec2_1, vec2_2, color):
|
||||
var points = get_points_from_line(vec2_1, vec2_2)
|
||||
for i in points:
|
||||
paint_canvas.set_pixel(i, color)
|
||||
|
||||
func get_points_from_line(vec2_1, vec2_2):
|
||||
var points = PoolVector2Array()
|
||||
|
||||
var dx = abs(vec2_2.x - vec2_1.x)
|
||||
var dy = abs(vec2_2.y - vec2_1.y)
|
||||
|
||||
var x = vec2_1.x
|
||||
var y = vec2_1.y
|
||||
|
||||
var sx = 0
|
||||
if vec2_1.x > vec2_2.x:
|
||||
sx = -1
|
||||
else:
|
||||
sx = 1
|
||||
|
||||
var sy = 0
|
||||
if vec2_1.y > vec2_2.y:
|
||||
sy = -1
|
||||
else:
|
||||
sy = 1
|
||||
|
||||
if dx > dy:
|
||||
var err = dx / 2
|
||||
while(true):
|
||||
if x == vec2_2.x:
|
||||
break
|
||||
points.push_back(Vector2(x, y))
|
||||
|
||||
err -= dy
|
||||
if err < 0:
|
||||
y += sy
|
||||
err += dx
|
||||
x += sx
|
||||
else:
|
||||
var err = dy / 2
|
||||
while (true):
|
||||
if y == vec2_2.y:
|
||||
break
|
||||
points.push_back(Vector2(x, y))
|
||||
|
||||
err -= dx
|
||||
if err < 0:
|
||||
x += sx
|
||||
err += dy
|
||||
y += sy
|
||||
points.push_back(Vector2(x, y))
|
||||
return points
|
||||
|
||||
#Flood fill algrorithm copied and modified from Pixeloroma!
|
||||
#https://github.com/OverloadedOrama/Pixelorama/blob/master/Scripts/Canvas.gd
|
||||
func flood_fill(pos, target_color, replacement_color):
|
||||
if target_color == replacement_color:
|
||||
return
|
||||
elif paint_canvas.get_pixel(pos) != target_color:
|
||||
return
|
||||
elif !paint_canvas.pixel_in_canvas_region(pos):
|
||||
return
|
||||
var q = [pos]
|
||||
for n in q:
|
||||
var west = n
|
||||
var east = n
|
||||
while paint_canvas.get_pixel(west) == target_color:
|
||||
west += Vector2.LEFT
|
||||
while paint_canvas.get_pixel(east) == target_color:
|
||||
east += Vector2.RIGHT
|
||||
for px in range(west.x + 1, east.x):
|
||||
var p = Vector2(px, n.y)
|
||||
paint_canvas.set_pixel(p, replacement_color)
|
||||
var north = p + Vector2.UP
|
||||
var south = p + Vector2.DOWN
|
||||
if paint_canvas.get_pixel(north) == target_color:
|
||||
q.append(north)
|
||||
if paint_canvas.get_pixel(south) == target_color:
|
||||
q.append(south)
|
@ -1,14 +0,0 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
var cell_mouse_position = Vector2()
|
||||
var grid_size = 0
|
||||
|
||||
func _process(delta):
|
||||
var canvas_mouse_position = get_parent().get_local_mouse_position()
|
||||
grid_size = get_parent().grid_size
|
||||
cell_mouse_position = Vector2(floor(canvas_mouse_position.x / grid_size), floor(canvas_mouse_position.y / grid_size))
|
||||
update()
|
||||
|
||||
func _draw():
|
||||
draw_rect(Rect2(Vector2((cell_mouse_position.x * grid_size), (cell_mouse_position.y * grid_size)), Vector2(grid_size, grid_size)), Color(0.8, 0.8, 0.8, 0.8), true)
|
83
addons/graphics_editor/SaveFileDialog.gd
Normal file
83
addons/graphics_editor/SaveFileDialog.gd
Normal file
@ -0,0 +1,83 @@
|
||||
tool
|
||||
extends FileDialog
|
||||
|
||||
var canvas
|
||||
|
||||
var file_path = ""
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
canvas = get_parent().find_node("PaintCanvas")
|
||||
|
||||
|
||||
func _ready():
|
||||
# warning-ignore:return_value_discarded
|
||||
get_line_edit().connect("text_entered", self, "_on_LineEdit_text_entered")
|
||||
invalidate()
|
||||
clear_filters()
|
||||
add_filter("*.png ; PNG Images")
|
||||
|
||||
|
||||
func _on_SaveFileDialog_file_selected(path):
|
||||
file_path = path
|
||||
|
||||
# warning-ignore:unused_argument
|
||||
func _on_LineEdit_text_entered(text):
|
||||
save_file()
|
||||
|
||||
func _on_SaveFileDialog_confirmed():
|
||||
save_file()
|
||||
|
||||
|
||||
func save_file():
|
||||
var image = Image.new()
|
||||
image.create(canvas.canvas_size.x, canvas.canvas_size.y, true, Image.FORMAT_RGBA8)
|
||||
image.lock()
|
||||
|
||||
var preview_layer_chunk_node = canvas.get_preview_layer().chunks
|
||||
|
||||
for chunks_node in canvas.get_node("ChunkNodes").get_children():
|
||||
|
||||
if chunks_node.name == preview_layer_chunk_node.name:
|
||||
continue
|
||||
|
||||
if not chunks_node.visible:
|
||||
continue
|
||||
|
||||
for chunk in chunks_node.get_children():
|
||||
var chunk_name = chunk.name
|
||||
var chunk_name_split = chunk_name.split("-")
|
||||
var chunk_x = int(chunk_name_split[1])
|
||||
var chunk_y = int(chunk_name_split[2])
|
||||
var chunk_image = chunk.image.duplicate()
|
||||
chunk_image.lock()
|
||||
var chunk_image_size = chunk_image.get_size()
|
||||
for x in chunk_image_size.x:
|
||||
for y in chunk_image_size.y:
|
||||
var pixel_color = chunk_image.get_pixel(x, y)
|
||||
var global_cell_x = (chunk_x * canvas.region_size) + x
|
||||
var global_cell_y = (chunk_y * canvas.region_size) + y
|
||||
|
||||
if image.get_height() <= global_cell_y:
|
||||
continue
|
||||
if image.get_width() <= global_cell_x:
|
||||
continue
|
||||
if global_cell_x > canvas.canvas_size.x:
|
||||
continue
|
||||
if global_cell_y > canvas.canvas_size.y:
|
||||
continue
|
||||
|
||||
image.lock()
|
||||
var current_color = image.get_pixel(global_cell_x, global_cell_y)
|
||||
if current_color.a != 0:
|
||||
image.set_pixel(global_cell_x, global_cell_y, current_color.blend(pixel_color))
|
||||
else:
|
||||
image.set_pixel(global_cell_x, global_cell_y, pixel_color)
|
||||
image.unlock()
|
||||
image.save_png(file_path)
|
||||
|
||||
func _on_SaveFileDialog_about_to_show():
|
||||
invalidate()
|
||||
|
||||
func _on_SaveFileDialog_visibility_changed():
|
||||
invalidate()
|
@ -21,4 +21,4 @@ func draw_outline_box(size, color, width):
|
||||
#Bottom line
|
||||
draw_line(Vector2(0 + 1, size.y), Vector2(size.x, size.y), color, width)
|
||||
#Right line
|
||||
draw_line(Vector2(size.x, 0), Vector2(size.x, size.y), color, width)
|
||||
draw_line(Vector2(size.x, 0), Vector2(size.x, size.y), color, width)
|
||||
|
36
addons/graphics_editor/Settings.gd
Normal file
36
addons/graphics_editor/Settings.gd
Normal file
@ -0,0 +1,36 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
var editor
|
||||
var canvas_outline
|
||||
var start_time
|
||||
var end_time
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
canvas_outline = get_parent().find_node("CanvasOutline")
|
||||
editor = get_parent()
|
||||
|
||||
|
||||
func _ready():
|
||||
#start_time = OS.get_ticks_msec()
|
||||
return
|
||||
get_node("CanvasOutlineToggle/CheckButton").pressed = canvas_outline.visible
|
||||
get_node("CanvasOutlineColor/ColorPickerButton").color = canvas_outline.color
|
||||
|
||||
func _process(delta):
|
||||
# if get_parent().paint_canvas_node != null:
|
||||
# canvas_outline = get_parent().paint_canvas_node.get_node("CanvasOutline")
|
||||
# end_time = OS.get_ticks_msec()
|
||||
# print("[Settings] Found Editor node in %s seconds!" % [(end_time - start_time) / float(1000)])
|
||||
# set_process(false)
|
||||
pass
|
||||
|
||||
func _on_ColorPickerButton_color_changed(color):
|
||||
canvas_outline.color = color
|
||||
|
||||
func _on_CheckButton_toggled(button_pressed):
|
||||
canvas_outline.visible = button_pressed
|
||||
|
||||
func _on_Ok_pressed():
|
||||
hide()
|
62
addons/graphics_editor/Settings.tscn
Normal file
62
addons/graphics_editor/Settings.tscn
Normal file
@ -0,0 +1,62 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/graphics_editor/Settings.gd" type="Script" id=1]
|
||||
|
||||
[node name="Settings" type="WindowDialog"]
|
||||
margin_top = 20.0
|
||||
margin_right = 300.0
|
||||
margin_bottom = 120.0
|
||||
window_title = "Settings"
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Ok" type="Button" parent="."]
|
||||
margin_left = 210.0
|
||||
margin_top = 70.0
|
||||
margin_right = 290.0
|
||||
margin_bottom = 90.0
|
||||
text = "Ok"
|
||||
|
||||
[node name="CanvasOutlineToggle" type="Control" parent="."]
|
||||
margin_left = 10.0
|
||||
margin_top = 10.0
|
||||
margin_right = 290.0
|
||||
margin_bottom = 30.0
|
||||
__meta__ = {
|
||||
"_edit_group_": true
|
||||
}
|
||||
|
||||
[node name="Label" type="Label" parent="CanvasOutlineToggle"]
|
||||
margin_right = 130.0
|
||||
margin_bottom = 20.0
|
||||
text = "Canvas Outline:"
|
||||
valign = 1
|
||||
|
||||
[node name="CheckButton" type="CheckButton" parent="CanvasOutlineToggle"]
|
||||
margin_left = 210.0
|
||||
margin_top = -10.0
|
||||
margin_right = 286.0
|
||||
margin_bottom = 30.0
|
||||
pressed = true
|
||||
|
||||
[node name="CanvasOutlineColor" type="Control" parent="."]
|
||||
margin_left = 10.0
|
||||
margin_top = 40.0
|
||||
margin_right = 290.0
|
||||
margin_bottom = 60.0
|
||||
__meta__ = {
|
||||
"_edit_group_": true
|
||||
}
|
||||
|
||||
[node name="Label" type="Label" parent="CanvasOutlineColor"]
|
||||
margin_right = 130.0
|
||||
margin_bottom = 20.0
|
||||
text = "Canvas Outline Color:"
|
||||
valign = 1
|
||||
|
||||
[node name="ColorPickerButton" type="ColorPickerButton" parent="CanvasOutlineColor"]
|
||||
margin_left = 170.0
|
||||
margin_right = 280.0
|
||||
margin_bottom = 20.0
|
||||
[connection signal="pressed" from="Ok" to="." method="_on_Ok_pressed"]
|
||||
[connection signal="toggled" from="CanvasOutlineToggle/CheckButton" to="." method="_on_CheckButton_toggled"]
|
||||
[connection signal="color_changed" from="CanvasOutlineColor/ColorPickerButton" to="." method="_on_ColorPickerButton_color_changed"]
|
@ -1,21 +0,0 @@
|
||||
#Main file for the graphic editor tools!
|
||||
tool
|
||||
extends Node
|
||||
|
||||
export var keep_running = false
|
||||
export var tool_name = ""
|
||||
|
||||
#Common variables
|
||||
onready var canvas = get_node("../../../Editor/PaintCanvasContainer/ViewportContainer/Viewport/PaintCanvas")
|
||||
var util = preload("res://addons/graphics_editor/Util.gd")
|
||||
var cell_mouse_position = Vector2()
|
||||
var last_cell_mouse_position = Vector2()
|
||||
var selected_color = Color()
|
||||
var cell_color = Color()
|
||||
|
||||
#Dummy functions
|
||||
func on_left_mouse_click():
|
||||
pass
|
||||
|
||||
func on_right_mouse_click():
|
||||
pass
|
@ -1,38 +0,0 @@
|
||||
tool
|
||||
extends Node
|
||||
|
||||
var util = preload("res://addons/graphics_editor/Util.gd")
|
||||
var active_tool
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func set_active_tool(tool_to_use):
|
||||
var tool_manager_folder = get_script().resource_path.get_base_dir()
|
||||
var tool_scripts = util.get_files_from_path(tool_manager_folder.plus_file("Tools"))
|
||||
for i in tool_scripts:
|
||||
var file_name = util.get_file_name(i)
|
||||
if file_name == tool_to_use:
|
||||
var node = Node.new()
|
||||
node.name = file_name
|
||||
var script_file = load(i)
|
||||
node.set_script(script_file)
|
||||
add_child(node)
|
||||
active_tool = node
|
||||
return node
|
||||
push_error("Can't find tool from script files! Either file missing or wrong name?")
|
||||
|
||||
func get_active_tool():
|
||||
return active_tool
|
||||
|
||||
func get_files_from_path(path):
|
||||
var script_array = PoolStringArray()
|
||||
var dir = Directory.new()
|
||||
if dir.open(path) == OK:
|
||||
dir.list_dir_begin()
|
||||
var file_name = dir.get_next()
|
||||
while (file_name != ""):
|
||||
if !dir.current_is_dir():
|
||||
script_array.append(path.plus_file(file_name))
|
||||
file_name = dir.get_next()
|
||||
return script_array
|
@ -1,8 +0,0 @@
|
||||
tool
|
||||
extends "../Tool.gd"
|
||||
|
||||
func on_left_mouse_click():
|
||||
canvas.util.flood_fill(cell_mouse_position, cell_color, selected_color)
|
||||
|
||||
func on_right_mouse_click():
|
||||
canvas.util.flood_fill(cell_mouse_position, cell_color, Color(0, 0, 0, 0))
|
@ -1,8 +0,0 @@
|
||||
tool
|
||||
extends "../Tool.gd"
|
||||
|
||||
func on_left_mouse_click():
|
||||
canvas.util.set_pixels_from_line(last_cell_mouse_position, cell_mouse_position, selected_color)
|
||||
|
||||
func on_right_mouse_click():
|
||||
canvas.util.set_pixels_from_line(last_cell_mouse_position, cell_mouse_position, Color(0, 0, 0, 0))
|
@ -1,11 +0,0 @@
|
||||
tool
|
||||
extends "../Tool.gd"
|
||||
|
||||
func on_left_mouse_click():
|
||||
if cell_mouse_position != last_cell_mouse_position:
|
||||
var points = canvas.util.get_points_from_line(last_cell_mouse_position, cell_mouse_position)
|
||||
for i in points:
|
||||
canvas.set_pixel(i, util.random_color_alt())
|
||||
|
||||
func on_right_mouse_click():
|
||||
canvas.util.set_pixels_from_line(last_cell_mouse_position, cell_mouse_position, Color(0, 0, 0, 0))
|
@ -1,21 +1,6 @@
|
||||
tool
|
||||
extends Node
|
||||
|
||||
class time_debug:
|
||||
var start_time = 0.0
|
||||
var end_time = 0.0
|
||||
|
||||
func start():
|
||||
start_time = OS.get_ticks_msec()
|
||||
return start_time
|
||||
|
||||
func end():
|
||||
end_time = OS.get_ticks_msec()
|
||||
return end_time
|
||||
|
||||
func get_time_passed():
|
||||
return end_time - start_time
|
||||
|
||||
static func color_from_array(color_array):
|
||||
var r = color_array[0]
|
||||
var g = color_array[1]
|
||||
@ -30,40 +15,28 @@ static func random_color_alt():
|
||||
var rand = randi() % 6
|
||||
|
||||
match rand:
|
||||
#red
|
||||
0:
|
||||
return Color.red
|
||||
#blue
|
||||
1:
|
||||
return Color.blue
|
||||
#green
|
||||
2:
|
||||
return Color.green
|
||||
#orange
|
||||
3:
|
||||
return Color.orange
|
||||
#yellow
|
||||
4:
|
||||
return Color.yellow
|
||||
#purple
|
||||
5:
|
||||
return Color.purple
|
||||
|
||||
static func get_line_string(file, number):
|
||||
return file.get_as_text().split("\n")[number - 1].strip_edges()
|
||||
|
||||
static func get_file_name(path):
|
||||
var file_name_raw = path.get_file()
|
||||
var file_extension = path.get_extension()
|
||||
var file_name = file_name_raw.substr(0, file_name_raw.length()-(file_extension.length()+1))
|
||||
return file_name
|
||||
|
||||
static func get_files_from_path(path):
|
||||
var file_array = PoolStringArray()
|
||||
var dir = Directory.new()
|
||||
if dir.open(path) == OK:
|
||||
dir.list_dir_begin()
|
||||
var file_name = dir.get_next()
|
||||
while (file_name != ""):
|
||||
if !dir.current_is_dir():
|
||||
file_array.append(path.plus_file(file_name))
|
||||
file_name = dir.get_next()
|
||||
return file_array
|
||||
|
||||
static func printv(variable):
|
||||
var stack = get_stack()[get_stack().size() - 1]
|
||||
var line = stack.line
|
||||
|
@ -1,9 +1,8 @@
|
||||
extends ViewportContainer
|
||||
|
||||
func _ready():
|
||||
print(name)
|
||||
pass
|
||||
|
||||
func _notification(what):
|
||||
if what == Control.NOTIFICATION_RESIZED:
|
||||
get_node("Viewport").size = rect_size
|
||||
get_node("Viewport/Node2D/Camera2D").position = Vector2(rect_size.x / 2, rect_size.y / 2)
|
||||
pass
|
||||
|
@ -6,6 +6,11 @@ export var size = 16
|
||||
export var zoom = 0
|
||||
export var offset = Vector2(0, 0)
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
set_process(true)
|
||||
|
||||
|
||||
func _draw():
|
||||
if size == 0:
|
||||
size = 1
|
||||
@ -13,19 +18,22 @@ func _draw():
|
||||
var temp_size = size + zoom
|
||||
|
||||
var wrap_offset = Vector2(wrapf(offset.x, 0, temp_size), wrapf(offset.y, 0, temp_size))
|
||||
|
||||
var ceil_x = floor(rect_size.x / temp_size) + 0.01
|
||||
var ceil_y = floor(rect_size.y / temp_size) + 0.01
|
||||
|
||||
var ceil_x = ceil(rect_size.x / temp_size)
|
||||
var ceil_y = ceil(rect_size.y / temp_size)
|
||||
|
||||
for i in ceil_y:
|
||||
var start_x = Vector2(0, (i * temp_size) + wrap_offset.y)
|
||||
var end_x = Vector2(rect_size.x, (i * temp_size) + wrap_offset.y)
|
||||
# var end_x = Vector2(int(rect_size.x) + size - int(rect_size.x) % size, (i * temp_size) + wrap_offset.y)
|
||||
draw_line(start_x, end_x, color, 1)
|
||||
|
||||
for i in ceil_x:
|
||||
var start_y = Vector2((i * temp_size) + wrap_offset.x, 0)
|
||||
var end_y = Vector2((i * temp_size) + (wrap_offset.x + 0.01), rect_size.y)
|
||||
var end_y = Vector2((i * temp_size) + (wrap_offset.x), rect_size.y)
|
||||
# var end_y = Vector2((i * temp_size) + (wrap_offset.x), int(rect_size.y) + size - int(rect_size.y) % size)
|
||||
draw_line(start_y, end_y, color, 1)
|
||||
|
||||
|
||||
func _process(delta):
|
||||
update()
|
||||
|
17
addons/graphics_editor/actions/Action.gd
Normal file
17
addons/graphics_editor/actions/Action.gd
Normal file
@ -0,0 +1,17 @@
|
||||
extends Reference
|
||||
|
||||
|
||||
var action_data = {}
|
||||
var painter
|
||||
|
||||
|
||||
func _init():
|
||||
pass
|
||||
|
||||
|
||||
func do_action(data: Array):
|
||||
pass
|
||||
|
||||
|
||||
func undo_action(data: Array):
|
||||
pass
|
25
addons/graphics_editor/actions/Pencil.gd
Normal file
25
addons/graphics_editor/actions/Pencil.gd
Normal file
@ -0,0 +1,25 @@
|
||||
extends "res://addons/graphics_editor/actions/Action.gd"
|
||||
|
||||
|
||||
|
||||
func do_action(data: Array):
|
||||
action_data["do"] = {
|
||||
"cell_position": data[0],
|
||||
"last_cell_position": data[1],
|
||||
"color": data[2],
|
||||
}
|
||||
|
||||
action_data["undo"] = {
|
||||
"cell_position": data[0],
|
||||
"last_cell_position": data[1],
|
||||
"color": get("painter").get_pixel_cell_color_v(action_data.do.cell_position),
|
||||
}
|
||||
|
||||
get("painter").set_pixels_from_line(action_data.do.cell_position, action_data.do.last_cell_position, action_data.do.color)
|
||||
|
||||
|
||||
func undo_action(data: Array):
|
||||
get("painter").set_pixels_from_line(action_data.undo.cell_position, action_data.undo.last_cell_position, action_data.undo.color)
|
||||
|
||||
|
||||
|
BIN
addons/graphics_editor/assets/arrow_down.png
Normal file
BIN
addons/graphics_editor/assets/arrow_down.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 562 B |
34
addons/graphics_editor/assets/arrow_down.png.import
Normal file
34
addons/graphics_editor/assets/arrow_down.png.import
Normal file
@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/arrow_down.png-6353fddfb758b7080149cf1c92b356e5.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/graphics_editor/assets/arrow_down.png"
|
||||
dest_files=[ "res://.import/arrow_down.png-6353fddfb758b7080149cf1c92b356e5.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user