move standalone projects into own directory
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
import sys.io.Process;
|
||||
import haxe.xml.Access;
|
||||
import sys.FileSystem;
|
||||
import sys.io.File;
|
||||
|
||||
using StringTools;
|
||||
|
||||
class Setup {
|
||||
public static function main() {
|
||||
// Checking haxelib for godot externs.
|
||||
final haxelibCheck = new Process("haxelib", ["path", "godot"]);
|
||||
if (haxelibCheck.exitCode() != 0) {
|
||||
Sys.print("haxelib");
|
||||
return;
|
||||
}
|
||||
|
||||
// Find unique csproj file.
|
||||
var csproj = null;
|
||||
|
||||
for (entry in FileSystem.readDirectory(".")) {
|
||||
if (FileSystem.isDirectory(entry)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.endsWith(".csproj")) {
|
||||
if (csproj != null) {
|
||||
Sys.print("multiple_csproj");
|
||||
return;
|
||||
}
|
||||
|
||||
csproj = entry;
|
||||
}
|
||||
}
|
||||
|
||||
if (csproj == null) {
|
||||
Sys.print("csproj");
|
||||
return;
|
||||
}
|
||||
|
||||
// Dirty check.
|
||||
final dirty = ["build.hxml", "build/", "scripts/"].filter(entry -> FileSystem.exists(entry));
|
||||
|
||||
if (dirty.length != 0) {
|
||||
Sys.print("dirty:" + dirty.join(" "));
|
||||
return;
|
||||
}
|
||||
|
||||
// Update csproj file.
|
||||
final csprojData = new Access(Xml.parse(File.getContent(csproj)));
|
||||
final propertyGroup = csprojData.node.Project.node.PropertyGroup;
|
||||
|
||||
for (property in propertyGroup.elements) {
|
||||
switch (property.name) {
|
||||
case "AllowUnsafeBlocks", "TargetFramework":
|
||||
propertyGroup.x.removeChild(property.x);
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
propertyGroup.x.addChild(Xml.parse("<AllowUnsafeBlocks>true</AllowUnsafeBlocks>"));
|
||||
propertyGroup.x.addChild(Xml.parse("<TargetFramework>netstandard2.1</TargetFramework>"));
|
||||
|
||||
File.saveContent(csproj, XmlPrinter.print(csprojData.x));
|
||||
|
||||
// Create project.
|
||||
FileSystem.createDirectory("scripts");
|
||||
File.saveContent("scripts/import.hx", "import godot.*;\nimport godot.GD.*;\n\nusing godot.Utils;\n");
|
||||
File.saveContent("build.hxml", "--cs build\n--define net-ver=50\n--define no-compilation\n--define analyzer-optimize\n--class-path scripts\n--library godot\n--macro godot.Godot.buildProject()\n--dce full\n");
|
||||
|
||||
final ret = Sys.command("haxe", ["build.hxml"]);
|
||||
if (ret == 0) {
|
||||
Sys.print("ok");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modified version of haxe.xml.Printer
|
||||
class XmlPrinter {
|
||||
static public function print(xml:Xml) {
|
||||
final printer = new XmlPrinter();
|
||||
printer.writeNode(xml, "");
|
||||
return printer.output.toString();
|
||||
}
|
||||
|
||||
var output:StringBuf;
|
||||
|
||||
function new() {
|
||||
output = new StringBuf();
|
||||
}
|
||||
|
||||
function writeNode(value:Xml, indent:String) {
|
||||
switch (value.nodeType) {
|
||||
case CData:
|
||||
write(indent + "<![CDATA[");
|
||||
write(value.nodeValue);
|
||||
write("]]>");
|
||||
newline();
|
||||
case Comment:
|
||||
var commentContent = value.nodeValue;
|
||||
commentContent = ~/[\n\r\t]+/g.replace(commentContent, "");
|
||||
commentContent = "<!--" + commentContent + "-->";
|
||||
write(indent);
|
||||
write(StringTools.trim(commentContent));
|
||||
newline();
|
||||
case Document:
|
||||
for (child in value) {
|
||||
writeNode(child, indent);
|
||||
}
|
||||
case Element:
|
||||
write(indent + "<");
|
||||
write(value.nodeName);
|
||||
for (attribute in value.attributes()) {
|
||||
write(" " + attribute + "=\"");
|
||||
write(StringTools.htmlEscape(value.get(attribute), true));
|
||||
write("\"");
|
||||
}
|
||||
if (hasChildren(value)) {
|
||||
final textOnly = hasTextOnly(value);
|
||||
write(">");
|
||||
if (!textOnly) {
|
||||
newline();
|
||||
}
|
||||
for (child in value) {
|
||||
writeNode(child, textOnly ? "" : (indent + " "));
|
||||
}
|
||||
write((textOnly ? "" : indent) + "</");
|
||||
write(value.nodeName);
|
||||
write(">");
|
||||
newline();
|
||||
} else {
|
||||
write("/>");
|
||||
newline();
|
||||
}
|
||||
case PCData:
|
||||
final nodeValue = value.nodeValue.trim();
|
||||
if (nodeValue.length != 0) {
|
||||
write(indent + StringTools.htmlEscape(nodeValue));
|
||||
}
|
||||
case ProcessingInstruction:
|
||||
write("<?" + value.nodeValue + "?>");
|
||||
newline();
|
||||
case DocType:
|
||||
write("<!DOCTYPE " + value.nodeValue + ">");
|
||||
newline();
|
||||
}
|
||||
}
|
||||
|
||||
inline function write(input:String) {
|
||||
output.add(input);
|
||||
}
|
||||
|
||||
inline function newline() {
|
||||
output.add("\n");
|
||||
}
|
||||
|
||||
function hasTextOnly(value:Xml):Bool {
|
||||
for (child in value) {
|
||||
switch (child.nodeType) {
|
||||
case PCData:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function hasChildren(value:Xml):Bool {
|
||||
for (child in value) {
|
||||
switch (child.nodeType) {
|
||||
case Element, PCData:
|
||||
return true;
|
||||
case CData, Comment:
|
||||
if (StringTools.ltrim(child.nodeValue).length != 0) {
|
||||
return true;
|
||||
}
|
||||
case _:
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
tool
|
||||
class_name Building
|
||||
|
||||
extends Control
|
||||
|
||||
func build_haxe_project():
|
||||
print("Building haxe project...");
|
||||
|
||||
var res = OS.execute("haxe", ["build.hxml"], true);
|
||||
|
||||
$ProgressBar.value = 1
|
||||
yield(VisualServer, 'frame_post_draw')
|
||||
|
||||
print("Project builded with code: ", res)
|
||||
|
||||
queue_free()
|
@@ -0,0 +1,6 @@
|
||||
tool
|
||||
class_name HaxePluginConstants
|
||||
|
||||
const SETTING_HIDE_NATIVE_SCRIPT_FIELD := "haxe/hide_native_script_field"
|
||||
const SETTING_EXTERNAL_EDITOR := "haxe/external_editor"
|
||||
const BUILD_ON_PLAY := "haxe/build_on_play"
|
@@ -0,0 +1,164 @@
|
||||
tool
|
||||
class_name HaxePluginEditorProperty
|
||||
extends EditorProperty
|
||||
|
||||
var haxe_icon := preload("res://addons/haxe/icons/haxe.svg")
|
||||
var new_script_dialog := preload("res://addons/haxe/scenes/new_script.tscn")
|
||||
|
||||
var base:Control
|
||||
var object:Node
|
||||
var script_name := ""
|
||||
var script_path := ""
|
||||
var b:MenuButton
|
||||
var b2:MenuButton
|
||||
|
||||
func setup(base:Control, object:Node) -> void:
|
||||
self.base = base
|
||||
self.object = object
|
||||
label = "Haxe Script"
|
||||
|
||||
var h := HBoxContainer.new()
|
||||
|
||||
# TODO revert icon
|
||||
b = MenuButton.new()
|
||||
b.flat = true
|
||||
h.add_child(b)
|
||||
|
||||
b2 = MenuButton.new()
|
||||
b2.flat = true
|
||||
b2.icon = base.get_icon("GuiDropdown", "EditorIcons")
|
||||
h.add_child(b2)
|
||||
|
||||
add_child(h)
|
||||
|
||||
update_property()
|
||||
|
||||
func setup_menu(base:Control, button:MenuButton, has_script:bool) -> void:
|
||||
if not button.is_connected("gui_input", self, "on_menu_gui"):
|
||||
button.connect("gui_input", self, "on_menu_gui")
|
||||
|
||||
var menu := button.get_popup()
|
||||
|
||||
for i in range(menu.get_item_count()):
|
||||
menu.remove_item(0)
|
||||
|
||||
if not has_script:
|
||||
menu.add_icon_item(base.get_icon("ScriptCreate", "EditorIcons"), "New Haxe Script")
|
||||
else:
|
||||
menu.add_icon_item(base.get_icon("ScriptRemove", "EditorIcons"), "Remove Haxe Script")
|
||||
|
||||
menu.add_icon_item(base.get_icon("Load", "EditorIcons"), "Load Haxe Script")
|
||||
|
||||
if has_script:
|
||||
menu.add_icon_item(base.get_icon("Edit", "EditorIcons"), "Edit")
|
||||
|
||||
if not menu.is_connected("index_pressed", self, "on_popup_select"):
|
||||
menu.connect("index_pressed", self, "on_popup_select", [has_script])
|
||||
|
||||
func on_menu_gui(event:InputEvent) -> void:
|
||||
# If is right click then pretend it's a left click
|
||||
if event is InputEventMouseButton and event.pressed and event.button_index == 2:
|
||||
event.button_index = 1
|
||||
|
||||
func on_popup_select(id:int, has_script:bool) -> void:
|
||||
if id == 0: # New/Remove
|
||||
if not has_script: # New
|
||||
var dialog := new_script_dialog.instance()
|
||||
dialog.setup(base, object.get_class(), object.get_path().get_name(object.get_path().get_name_count() - 1))
|
||||
dialog.theme = base.theme
|
||||
dialog.connect("create", self, "on_create")
|
||||
base.add_child(dialog)
|
||||
dialog.popup_centered()
|
||||
else: # Remove
|
||||
object.remove_meta("haxe_script")
|
||||
object.set_script(null)
|
||||
elif id == 1: # Load
|
||||
var dialog := EditorFileDialog.new()
|
||||
base.add_child(dialog)
|
||||
dialog.access = EditorFileDialog.ACCESS_RESOURCES
|
||||
dialog.current_dir = "res://scripts/"
|
||||
dialog.mode = EditorFileDialog.MODE_OPEN_FILE
|
||||
dialog.theme = base.theme
|
||||
dialog.add_filter("*.hx ; Haxe script")
|
||||
dialog.connect("file_selected", self, "on_load_file")
|
||||
dialog.popup_centered_ratio()
|
||||
elif id == 2: # Edit
|
||||
open_file(script_path)
|
||||
else:
|
||||
print("Unknown entry: ", id)
|
||||
|
||||
func on_create(is_load:bool, class_value:String, path_value:String) -> void:
|
||||
if not is_load:
|
||||
var f := path_value.find_last("/")
|
||||
var name := path_value.substr(f + 1, path_value.find_last(".hx") - f - 1)
|
||||
|
||||
var d := path_value.substr(14).split("/")
|
||||
d.remove(d.size() - 1)
|
||||
|
||||
var pack := d.join(".")
|
||||
if not pack.empty():
|
||||
pack = " " + pack;
|
||||
|
||||
if class_value == name:
|
||||
class_value = "godot." + class_value
|
||||
|
||||
var file := File.new()
|
||||
file.open(path_value, File.WRITE)
|
||||
file.store_string("package" + pack + ";\n\nclass " + name + " extends " + class_value + " {\n}\n")
|
||||
file.close()
|
||||
|
||||
open_file(path_value)
|
||||
|
||||
on_load_file(path_value)
|
||||
|
||||
func open_file(path:String) -> void:
|
||||
var editor:String = ProjectSettings.get(HaxePluginConstants.SETTING_EXTERNAL_EDITOR)
|
||||
if editor == "None":
|
||||
pass
|
||||
elif editor == "VSCode":
|
||||
OS.execute("code", [ProjectSettings.globalize_path(path)], false)
|
||||
else:
|
||||
print("Unknown external editor: " + editor)
|
||||
|
||||
func on_load_file(path:String) -> void:
|
||||
object.set_meta("haxe_script", path)
|
||||
var cs_path := path.replace("res://scripts", "")
|
||||
var p := cs_path.find_last("/")
|
||||
var name := cs_path.substr(p, cs_path.length() - 2 - p) + "cs"
|
||||
cs_path = "build/src" + cs_path.substr(0, p)
|
||||
|
||||
var d := Directory.new()
|
||||
d.make_dir_recursive(cs_path)
|
||||
|
||||
var file_path := "res://" + cs_path + name
|
||||
var cs_file := File.new()
|
||||
if not cs_file.file_exists(file_path):
|
||||
cs_file.open(file_path, File.WRITE)
|
||||
cs_file.store_string("\n")
|
||||
cs_file.close()
|
||||
object.set_script(load(file_path))
|
||||
|
||||
func update_property() -> void:
|
||||
var script_name := "[empty]"
|
||||
|
||||
if object.has_meta("haxe_script"):
|
||||
if not object.get_script():
|
||||
object.remove_meta("haxe_script")
|
||||
else:
|
||||
script_path = object.get_meta("haxe_script")
|
||||
var p := script_path.find_last("/")
|
||||
script_name = script_path.substr(p + 1)
|
||||
|
||||
var has_script := script_path != ""
|
||||
|
||||
b.size_flags_horizontal = MenuButton.SIZE_EXPAND_FILL
|
||||
if has_script:
|
||||
b.icon = haxe_icon
|
||||
b.text = script_name
|
||||
b.hint_tooltip = script_path
|
||||
setup_menu(base, b, has_script)
|
||||
|
||||
setup_menu(base, b2, has_script)
|
||||
|
||||
func get_tooltip_text() -> String:
|
||||
return "Haxe Script"
|
@@ -0,0 +1,103 @@
|
||||
tool
|
||||
class_name HaxePlugin
|
||||
extends EditorPlugin
|
||||
|
||||
var about_dialog := preload("res://addons/haxe/scenes/about.tscn")
|
||||
var tab := preload("res://addons/haxe/scenes/tab.tscn").instance()
|
||||
var build_dialog := preload("res://addons/haxe/scenes/building.tscn")
|
||||
|
||||
var inspector_plugin:HaxePluginInspectorPlugin
|
||||
|
||||
func _enter_tree() -> void:
|
||||
var base := get_editor_interface().get_base_control()
|
||||
|
||||
# Init
|
||||
setup_settings()
|
||||
|
||||
# Inspector plugin
|
||||
inspector_plugin = HaxePluginInspectorPlugin.new()
|
||||
inspector_plugin.setup(base)
|
||||
add_inspector_plugin(inspector_plugin)
|
||||
|
||||
# Tool menu entry
|
||||
var menu := PopupMenu.new()
|
||||
menu.add_item("About")
|
||||
menu.add_item("Setup")
|
||||
menu.connect("index_pressed", self, "on_menu")
|
||||
add_tool_submenu_item("Haxe", menu)
|
||||
|
||||
# Bottom dock tab
|
||||
tab.setup(base)
|
||||
add_control_to_bottom_panel(tab, "Haxe")
|
||||
|
||||
func _exit_tree() -> void:
|
||||
# TODO tab.gd still leaks?
|
||||
remove_control_from_bottom_panel(tab)
|
||||
tab.queue_free()
|
||||
remove_tool_menu_item("Haxe")
|
||||
remove_inspector_plugin(inspector_plugin)
|
||||
|
||||
func setup_settings() -> void:
|
||||
if not ProjectSettings.has_setting(HaxePluginConstants.SETTING_HIDE_NATIVE_SCRIPT_FIELD):
|
||||
ProjectSettings.set_setting(HaxePluginConstants.SETTING_HIDE_NATIVE_SCRIPT_FIELD, true)
|
||||
|
||||
if not ProjectSettings.has_setting(HaxePluginConstants.SETTING_EXTERNAL_EDITOR):
|
||||
ProjectSettings.set_setting(HaxePluginConstants.SETTING_EXTERNAL_EDITOR, "VSCode")
|
||||
ProjectSettings.add_property_info({
|
||||
"name": HaxePluginConstants.SETTING_EXTERNAL_EDITOR,
|
||||
"type": TYPE_STRING,
|
||||
"hint": PROPERTY_HINT_ENUM,
|
||||
"hint_string": "None,VSCode"
|
||||
});
|
||||
|
||||
if not ProjectSettings.has_setting(HaxePluginConstants.BUILD_ON_PLAY):
|
||||
ProjectSettings.set_setting(HaxePluginConstants.BUILD_ON_PLAY, false)
|
||||
|
||||
func on_menu(id:int) -> void:
|
||||
var theme := get_editor_interface().get_base_control().theme
|
||||
|
||||
if id == 0: # About
|
||||
var dialog := about_dialog.instance()
|
||||
add_child(dialog)
|
||||
dialog.theme = theme
|
||||
dialog.popup_centered()
|
||||
elif id == 1: # Setup
|
||||
var output := []
|
||||
OS.execute("haxe", ["--class-path", "addons/haxe/scripts", "--run", "Setup"], true, output, true)
|
||||
|
||||
var dialog := AcceptDialog.new()
|
||||
add_child(dialog)
|
||||
|
||||
if output.size() != 1:
|
||||
dialog.dialog_text = "Unknown error:\n" + PoolStringArray(output).join("\n")
|
||||
elif "command not found" in output[0].to_lower():
|
||||
dialog.dialog_text = "Haxe command not found."
|
||||
elif output[0] == "haxelib":
|
||||
dialog.dialog_text = "Godot externs not found.\nRun 'haxelib install godot' first."
|
||||
elif output[0] == "multiple_csproj":
|
||||
dialog.dialog_text = "Multiple C# solutions found.\nCannot setup."
|
||||
elif output[0] == "csproj":
|
||||
dialog.dialog_text = "C# solution not found (.csproj file).\nYou need to setup Godot Mono first:\nProject -> Tools -> Mono -> Create C# solution."
|
||||
elif output[0].begins_with("dirty:"):
|
||||
dialog.dialog_text = "Project already contains: " + output[0].substr(6) + "\nTo avoid data loss the setup wasn't run."
|
||||
elif output[0] == "ok":
|
||||
dialog.dialog_text = "Setup successful."
|
||||
else:
|
||||
dialog.dialog_text = "Unknown error: " + output[0]
|
||||
|
||||
dialog.theme = theme
|
||||
dialog.window_title = "Haxe Setup"
|
||||
dialog.popup_centered()
|
||||
else:
|
||||
print("Unknown menu: ", id)
|
||||
|
||||
func _input(event):
|
||||
if event is InputEventKey and ProjectSettings.get_setting(HaxePluginConstants.BUILD_ON_PLAY):
|
||||
if event.scancode == KEY_F5 or event.scancode == KEY_F6 and event.echo:
|
||||
var dialog = build_dialog.instance()
|
||||
|
||||
add_child(dialog)
|
||||
|
||||
yield(VisualServer, 'frame_post_draw')
|
||||
|
||||
dialog.call("build_haxe_project")
|
@@ -0,0 +1,22 @@
|
||||
tool
|
||||
class_name HaxePluginInspectorPlugin
|
||||
extends EditorInspectorPlugin
|
||||
|
||||
var base:Control
|
||||
|
||||
func setup(base:Control) -> void:
|
||||
self.base = base
|
||||
|
||||
#warning-ignore:unused_argument
|
||||
func can_handle(object:Object) -> bool:
|
||||
return true
|
||||
|
||||
#warning-ignore:unused_argument
|
||||
func parse_property(object:Object, type:int, path:String, hint:int, hint_text:String, usage:int) -> bool:
|
||||
if object is Node and type == TYPE_OBJECT and path == "script":
|
||||
var e := HaxePluginEditorProperty.new()
|
||||
e.setup(base, object)
|
||||
add_custom_control(e)
|
||||
return ProjectSettings.get_setting(HaxePluginConstants.SETTING_HIDE_NATIVE_SCRIPT_FIELD)
|
||||
|
||||
return false
|
@@ -0,0 +1,157 @@
|
||||
tool
|
||||
extends WindowDialog
|
||||
|
||||
signal create(is_load, class_value, path_value)
|
||||
|
||||
var base:Control
|
||||
|
||||
var cancel_button:Button
|
||||
var create_button:Button
|
||||
|
||||
var class_valid := true
|
||||
var path_valid := true
|
||||
var name_valid := true
|
||||
var name_warning := false
|
||||
var extension_valid := true
|
||||
|
||||
var is_load := false
|
||||
var class_value := ""
|
||||
var path_value := ""
|
||||
|
||||
func setup(base:Control, class_value:String, name:String) -> void:
|
||||
self.base = base
|
||||
|
||||
var left := $MarginContainer/VBoxContainer/Buttons/Left
|
||||
var right := $MarginContainer/VBoxContainer/Buttons/Right
|
||||
|
||||
if OS.get_name() == "Windows" or OS.get_name() == "UWP":
|
||||
setup_buttons(right, left)
|
||||
else:
|
||||
setup_buttons(left, right)
|
||||
|
||||
$MarginContainer/VBoxContainer/GridContainer/ClassValue.connect("text_changed", self, "on_class")
|
||||
$MarginContainer/VBoxContainer/GridContainer/Path/PathValue.connect("text_changed", self, "on_path")
|
||||
|
||||
var path_button := $MarginContainer/VBoxContainer/GridContainer/Path/Load
|
||||
path_button.icon = base.get_icon("Folder", "EditorIcons")
|
||||
path_button.connect("button_down", self, "on_folder")
|
||||
|
||||
on_class(class_value)
|
||||
on_path("res://scripts/" + name.substr(0, 1).to_upper() + name.substr(1) + ".hx")
|
||||
|
||||
func setup_buttons(cancel:Button, create:Button) -> void:
|
||||
cancel.text = "Cancel"
|
||||
cancel.connect("button_down", self, "on_cancel")
|
||||
cancel_button = cancel
|
||||
|
||||
create.text = "Create"
|
||||
create.connect("button_down", self, "on_create")
|
||||
create_button = create
|
||||
|
||||
func on_cancel() -> void:
|
||||
hide()
|
||||
|
||||
func on_create() -> void:
|
||||
hide()
|
||||
emit_signal("create", is_load, class_value, path_value)
|
||||
|
||||
func on_class(value:String) -> void:
|
||||
class_value = value
|
||||
class_valid = ClassDB.class_exists(value) and ClassDB.can_instance(value)
|
||||
revalidate()
|
||||
|
||||
func on_folder() -> void:
|
||||
var file := path_value
|
||||
file = file.substr(file.find_last("/") + 1)
|
||||
|
||||
var dialog := EditorFileDialog.new()
|
||||
base.add_child(dialog)
|
||||
dialog.access = EditorFileDialog.ACCESS_RESOURCES
|
||||
dialog.current_dir = "res://scripts/"
|
||||
dialog.current_file = file
|
||||
dialog.disable_overwrite_warning = true
|
||||
dialog.theme = base.theme
|
||||
dialog.window_title = "Open Haxe Script / Choose Location"
|
||||
dialog.add_filter("*.hx ; Haxe script")
|
||||
dialog.connect("file_selected", self, "on_path")
|
||||
dialog.get_ok().text = "Open"
|
||||
dialog.popup_centered_ratio()
|
||||
|
||||
func on_path(fullpath:String) -> void:
|
||||
path_value = fullpath
|
||||
|
||||
var dir_p := fullpath.find_last("/")
|
||||
var ext_p := fullpath.find_last(".")
|
||||
|
||||
var path := ""
|
||||
var file := ""
|
||||
|
||||
if dir_p < ext_p:
|
||||
path = fullpath.substr(0, dir_p)
|
||||
file = fullpath.substr(dir_p + 1)
|
||||
else:
|
||||
path = fullpath
|
||||
|
||||
var d := Directory.new()
|
||||
var f := File.new()
|
||||
|
||||
is_load = f.file_exists(path_value)
|
||||
extension_valid = file.ends_with(".hx")
|
||||
name_valid = ext_p < fullpath.length() - 1 and ext_p > dir_p + 1
|
||||
name_warning = name_valid && extension_valid && isBuiltin(file.substr(0, file.length() - 3))
|
||||
path_valid = path.begins_with("res://") and d.dir_exists(path)
|
||||
revalidate()
|
||||
|
||||
func isBuiltin(name:String) -> bool:
|
||||
var haxeGodotBuiltins = ["Action", "CustomSignal", "CustomSignalUsings", "Godot", "Nullable1", "Signal", "SignalUsings", "Utils"]
|
||||
return ClassDB.class_exists(name) or haxeGodotBuiltins.has(name)
|
||||
|
||||
func revalidate() -> void:
|
||||
var text_edit := $MarginContainer/VBoxContainer/TextEdit
|
||||
text_edit.bbcode_text = ""
|
||||
|
||||
var valid_color := Color(0.062775, 0.730469, 0.062775)
|
||||
var error_color := Color(0.820312, 0.028839, 0.028839)
|
||||
var warning_color := Color(0.9375, 0.537443, 0.06958)
|
||||
|
||||
if not class_valid:
|
||||
text_edit.push_color(error_color)
|
||||
text_edit.append_bbcode("- Invalid inherited parent name.\n\n")
|
||||
text_edit.pop()
|
||||
elif not extension_valid:
|
||||
text_edit.push_color(error_color)
|
||||
text_edit.append_bbcode("- Invalid extension.\n\n")
|
||||
text_edit.pop()
|
||||
elif not path_valid:
|
||||
text_edit.push_color(error_color)
|
||||
text_edit.append_bbcode("- Invalid path.\n\n")
|
||||
text_edit.pop()
|
||||
elif not name_valid:
|
||||
text_edit.push_color(error_color)
|
||||
text_edit.append_bbcode("- Invalid filename.\n\n")
|
||||
text_edit.pop()
|
||||
else:
|
||||
text_edit.push_color(valid_color)
|
||||
text_edit.append_bbcode("- Haxe script path is valid.\n\n")
|
||||
|
||||
if is_load:
|
||||
text_edit.append_bbcode("- Will load an existing Haxe script.\n\n")
|
||||
else:
|
||||
text_edit.append_bbcode("- Will create a new Haxe script.\n\n")
|
||||
|
||||
text_edit.pop()
|
||||
|
||||
if name_warning:
|
||||
text_edit.push_color(warning_color)
|
||||
text_edit.append_bbcode("Warning: Having the script name be the same as a built-in type is usually not desired.\n\n")
|
||||
text_edit.pop()
|
||||
|
||||
var class_edit:LineEdit = $MarginContainer/VBoxContainer/GridContainer/ClassValue
|
||||
var class_edit_column := class_edit.caret_position
|
||||
class_edit.text = class_value
|
||||
class_edit.caret_position = class_edit_column if class_edit_column <= class_value.length() else class_value.length()
|
||||
|
||||
var path_edit:LineEdit = $MarginContainer/VBoxContainer/GridContainer/Path/PathValue
|
||||
var path_edit_column := path_edit.caret_position
|
||||
path_edit.text = path_value
|
||||
path_edit.caret_position = path_edit_column if path_edit_column <= path_value.length() else path_value.length()
|
@@ -0,0 +1,67 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
onready var button := $VBoxContainer/Button
|
||||
onready var text_log := $VBoxContainer/TextLog
|
||||
|
||||
var base:Control
|
||||
var icon := 0
|
||||
var icons := []
|
||||
var mutex := Mutex.new()
|
||||
var output := []
|
||||
var time := 0.0
|
||||
var thread:Thread = null
|
||||
|
||||
func setup(base:Control) -> void:
|
||||
self.base = base
|
||||
|
||||
for i in range(8):
|
||||
icons.append(base.get_icon("Progress%s"%(i + 1), "EditorIcons"))
|
||||
|
||||
func _ready() -> void:
|
||||
button.connect("button_down", self, "build_haxe_project")
|
||||
|
||||
func build_haxe_project() -> void:
|
||||
if thread != null:
|
||||
return
|
||||
|
||||
thread = Thread.new()
|
||||
|
||||
button.icon = icons[0]
|
||||
button.text = "Building Haxe Project ..."
|
||||
icon = 0
|
||||
text_log.text = ""
|
||||
time = 0.0
|
||||
output = []
|
||||
|
||||
thread.start(self, "run_thread")
|
||||
|
||||
func _process(delta:float) -> void:
|
||||
if thread != null:
|
||||
update_log()
|
||||
time += delta
|
||||
if time > 0.1:
|
||||
time = 0
|
||||
icon = (icon + 1) % 8
|
||||
button.icon = icons[icon]
|
||||
|
||||
func run_thread(userdata) -> void:
|
||||
var ret := OS.execute("haxe", ["build.hxml"], true, output, true)
|
||||
update_log()
|
||||
button.icon = base.get_icon("StatusSuccess" if ret == 0 else "StatusError", "EditorIcons")
|
||||
button.text = "Build Haxe Project"
|
||||
call_deferred("end_thread")
|
||||
|
||||
func end_thread() -> void:
|
||||
thread.wait_to_finish()
|
||||
thread = null
|
||||
|
||||
func update_log() -> void:
|
||||
mutex.lock()
|
||||
text_log.text = PoolStringArray(output).join("\n")
|
||||
mutex.unlock()
|
||||
|
||||
func _exit_tree():
|
||||
if thread != null:
|
||||
thread.wait_to_finish()
|
||||
thread = null
|
Reference in New Issue
Block a user