diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f28239b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +root = true + +[*] +charset = utf-8 diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 9c1f110..d498b69 100755 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,4 +1,4 @@ # These are supported funding model platforms patreon: YwmaaStudio -custom: ['https://youtube.com/YwmaaGamesStudio', 'https://twitter.com/ywmaaDev','https://discord.gg/Fp7ncA2xHw'] +custom: ['https://youtube.com/YwmaaGamesStudio', 'https://x.com/ywmaapersonal','https://discord.gg/Fp7ncA2xHw'] diff --git a/.github/workflows/Publish-Godot-Project.yml b/.github/workflows/Publish-Godot-Project.yml index 579ead4..03401d1 100755 --- a/.github/workflows/Publish-Godot-Project.yml +++ b/.github/workflows/Publish-Godot-Project.yml @@ -29,7 +29,7 @@ env: PROJECT_NAME: "My-Touch" # Needs to be added, PLEASE DON'T USE SPACES ITCH_PROJECT_NAME: "my-touch" # Needs to be added ITCH_USER_NAME: "ywmaa" # Needs to be added - GODOT_VERSION: 4.1.1 # Needs to be added + GODOT_VERSION: 4.3 # Needs to be added GODOT_ANDROID_KEYSTORE_DEBUG_PATH: "/home/runner/work/My-Touch/My-Touch/android/debug.keystore" # Needs to be added GODOT_ANDROID_KEYSTORE_DEBUG_USER: "androiddebugkey" # Needs to be added GODOT_ANDROID_KEYSTORE_DEBUG_PASSWORD: "android" # Needs to be added @@ -37,20 +37,10 @@ env: GODOT_ANDROID_KEYSTORE_RELEASE_USER: "" # Needs to be added GODOT_ANDROID_KEYSTORE_RELEASE_PASSWORD: "" # Needs to be added jobs: - CleanArtifacts: - # This job clears out the previous artifacts made so you don't run out of space in your github account - runs-on: ubuntu-latest - steps: - - uses: kolpav/purge-artifacts-action@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - expire-in: 1hr - Export: - needs: CleanArtifacts # wait for artifacts to clean before making a new one runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up JDK 11 uses: actions/setup-java@v3 @@ -112,10 +102,11 @@ jobs: - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: exports path: exports + overwrite: true Release: needs: Export @@ -211,7 +202,7 @@ jobs: content: v${{ github.event.inputs.export_version }} mode: 0655 - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: VERSION path: ./VERSION.txt @@ -222,7 +213,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download Exports - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: exports path: exports @@ -258,12 +249,3 @@ jobs: ./butler push linux-release-v${{ github.event.inputs.export_version }}.zip ${{env.ITCH_USER_NAME}}/${{env.ITCH_PROJECT_NAME}}:linux-release ./butler push mac-release-v${{ github.event.inputs.export_version }}.zip ${{env.ITCH_USER_NAME}}/${{env.ITCH_PROJECT_NAME}}:mac-release ./butler push android-release-v${{ github.event.inputs.export_version }}.zip ${{env.ITCH_USER_NAME}}/${{env.ITCH_PROJECT_NAME}}:android-release - - -# Cleanup: -# needs: [Export, Release, Publish] -# runs-on: ubuntu-latest -# steps: -# - uses: geekyeggo/delete-artifact@v1 -# with: -# name: VERSION diff --git a/.gitignore b/.gitignore index dde08f2..e994f17 100755 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ export.cfg *.mt.tres *.mt.res +exports/* diff --git a/UI/graphics/tools/layers_icon.png b/UI/graphics/tools/layers_icon.png new file mode 100644 index 0000000..6e9c101 Binary files /dev/null and b/UI/graphics/tools/layers_icon.png differ diff --git a/UI/graphics/tools/layers_icon.png.import b/UI/graphics/tools/layers_icon.png.import new file mode 100644 index 0000000..58fbdce --- /dev/null +++ b/UI/graphics/tools/layers_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://2laa5p61x6uj" +path="res://.godot/imported/layers_icon.png-d6ebca362e67f9e8bf6ef2e1f18d2e02.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://UI/graphics/tools/layers_icon.png" +dest_files=["res://.godot/imported/layers_icon.png-d6ebca362e67f9e8bf6ef2e1f18d2e02.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/UI/graphics/tools/properties_settings_icon.png b/UI/graphics/tools/properties_settings_icon.png new file mode 100644 index 0000000..978cbbc Binary files /dev/null and b/UI/graphics/tools/properties_settings_icon.png differ diff --git a/UI/graphics/tools/properties_settings_icon.png.import b/UI/graphics/tools/properties_settings_icon.png.import new file mode 100644 index 0000000..85034b7 --- /dev/null +++ b/UI/graphics/tools/properties_settings_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bm5uju3gv805p" +path="res://.godot/imported/properties_settings_icon.png-e78332d20a5eb020a6e0e2a77e60dc1f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://UI/graphics/tools/properties_settings_icon.png" +dest_files=["res://.godot/imported/properties_settings_icon.png-e78332d20a5eb020a6e0e2a77e60dc1f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/UI/graphics/tools/redo.png b/UI/graphics/tools/redo.png new file mode 100644 index 0000000..29174aa Binary files /dev/null and b/UI/graphics/tools/redo.png differ diff --git a/UI/graphics/tools/redo.png.import b/UI/graphics/tools/redo.png.import new file mode 100644 index 0000000..916c30d --- /dev/null +++ b/UI/graphics/tools/redo.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bdvp2p8534rib" +path="res://.godot/imported/redo.png-d6dac43fdea077a00b54de53edb1e4fb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://UI/graphics/tools/redo.png" +dest_files=["res://.godot/imported/redo.png-d6dac43fdea077a00b54de53edb1e4fb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/UI/graphics/tools/undo.png b/UI/graphics/tools/undo.png new file mode 100644 index 0000000..ccdc7cf Binary files /dev/null and b/UI/graphics/tools/undo.png differ diff --git a/UI/graphics/tools/undo.png.import b/UI/graphics/tools/undo.png.import new file mode 100644 index 0000000..71ac87d --- /dev/null +++ b/UI/graphics/tools/undo.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bl02c1qtbrhqv" +path="res://.godot/imported/undo.png-4a33aafcb80d7ca705f63bd040d8e518.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://UI/graphics/tools/undo.png" +dest_files=["res://.godot/imported/undo.png-4a33aafcb80d7ca705f63bd040d8e518.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/UI/panels/graph/Camera2D.gd b/UI/panels/graph/Camera2D.gd index 416f9a8..a084e7e 100644 --- a/UI/panels/graph/Camera2D.gd +++ b/UI/panels/graph/Camera2D.gd @@ -91,18 +91,19 @@ func _input(event: InputEvent) -> void: elif event.is_action_released("pan"): drag = false elif event.is_action_pressed("zoom_in", false, true): # Wheel Up Event - zoom_camera(-1) + if !drag: + zoom_camera(-1) elif event.is_action_pressed("zoom_out", false, true): # Wheel Down Event - zoom_camera(1) - + if !drag: + zoom_camera(1) + elif event is InputEventPanGesture: + # Pan Gesture on a Laptop touchpad + offset = offset + event.delta.rotated(rotation) * 1/zoom * 2 # for moving the canvas elif event is InputEventMagnifyGesture: # Zoom Gesture on a Laptop touchpad if event.factor < 1: - zoom_camera(1) + zoom_camera(-0.3) else: - zoom_camera(-1) - elif event is InputEventPanGesture and OS.get_name() != "Android": - # Pan Gesture on a Latop touchpad - offset = offset + event.delta.rotated(rotation) * 1/zoom * 7 # for moving the canvas + zoom_camera(0.3) elif event is InputEventMouseMotion && drag: offset = offset - event.relative.rotated(rotation) * 1/zoom update_transparent_checker_offset() @@ -134,10 +135,10 @@ func _set_camera_rotation_degrees(degrees: float) -> void: # Zoom Camera -func zoom_camera(dir: int) -> void: +func zoom_camera(dir: float) -> void: var viewport_size = get_viewport().size if mt_globals.smooth_zoom: - var zoom_margin = zoom * dir / 5 + var zoom_margin = (zoom * dir) / (pow(mt_globals.zoom_speed, -1)) var new_zoom = zoom + zoom_margin if new_zoom > zoom_min && new_zoom < zoom_max: var new_offset = ( @@ -148,18 +149,18 @@ func zoom_camera(dir: int) -> void: tween.set_trans(Tween.TRANS_LINEAR).set_ease(Tween.EASE_IN) tween.connect("step_finished", _on_tween_step) tween.tween_property(self, "zoom", new_zoom, 0.05) - tween.tween_property(self, "offset", new_offset, 0.05) + #tween.tween_property(self, "offset", new_offset, 0.05) else: var prev_zoom := zoom - var zoom_margin = zoom * dir / 10 + var zoom_margin = zoom * dir / 5.0 if zoom + zoom_margin > zoom_min: zoom += zoom_margin if zoom > zoom_max: zoom = zoom_max - offset = offset + ((viewport_size * 0.5) - mouse_pos).rotated(rotation) * -(zoom - prev_zoom) + #offset = offset + ((viewport_size * 0.5) - mouse_pos).rotated(rotation) * -(zoom - prev_zoom) zoom_changed() diff --git a/UI/panels/graph/Canvas.gd b/UI/panels/graph/Canvas.gd index 5660c4c..1d4715f 100644 --- a/UI/panels/graph/Canvas.gd +++ b/UI/panels/graph/Canvas.gd @@ -65,4 +65,3 @@ func render(p:Node, layers_array:Array[base_layer], _parent_layer:base_layer=nul instance.owner = self if layer is project_layer: render(instance, layer.project.layers_container.layers) - diff --git a/UI/panels/graph/Preview.gd b/UI/panels/graph/Preview.gd index 43e2e07..970307e 100644 --- a/UI/panels/graph/Preview.gd +++ b/UI/panels/graph/Preview.gd @@ -3,7 +3,7 @@ extends TextureRect func _process(delta): if !texture.viewport_path: - texture.viewport_path = mt_globals.main_window.find_child("AppRender").get_path() + texture.viewport_path = mt_globals.main_window.app_render.get_path() queue_redraw() if !get_parent().get_parent().get_parent().visible or get_parent().get_parent().get_parent().has_focus == false: return @@ -12,7 +12,7 @@ func _process(delta): ToolsManager.previous_mouse_position = get_local_mouse_position() func _draw(): - ToolsManager.call("draw_preview", self, get_local_mouse_position()) + ToolsManager.call_thread_safe("draw_preview", self, get_local_mouse_position()) func pass_event_to_tool(event) -> bool: if Input.is_action_just_pressed("mouse_left"): diff --git a/UI/panels/graph/TransparentChecker.gdshader b/UI/panels/graph/TransparentChecker.gdshader old mode 100755 new mode 100644 diff --git a/UI/panels/graph/graph.tscn b/UI/panels/graph/graph.tscn index 3917442..5e1e472 100644 --- a/UI/panels/graph/graph.tscn +++ b/UI/panels/graph/graph.tscn @@ -60,7 +60,7 @@ snap_2d_vertices_to_pixel = true physics_object_picking = true sdf_oversize = 0 sdf_scale = 0 -size = Vector2i(1240, 720) +size = Vector2i(1201, 720) render_target_update_mode = 4 [node name="TransparentChecker" type="ColorRect" parent="SubViewportContainer/Viewport" node_paths=PackedStringArray("graph")] diff --git a/UI/panels/graph/resize_rect.gd b/UI/panels/graph/resize_rect.gd old mode 100755 new mode 100644 index e259e7a..8935f1e --- a/UI/panels/graph/resize_rect.gd +++ b/UI/panels/graph/resize_rect.gd @@ -19,7 +19,13 @@ func _ready(): $"Y+".gui_input.connect(_on_child_gui_input.bind(Vector2.DOWN)) func _process(_delta): - visible = ToolsManager.TOOLS[3].tool_active + if ToolsManager.current_tool and ToolsManager.current_tool.tool_name == "Crop Tool" and ToolsManager.current_tool.tool_active: + visible = true + return + if ToolsManager.shortcut_tool and ToolsManager.shortcut_tool.tool_name == "Crop Tool" and ToolsManager.shortcut_tool.tool_active: + visible = true + return + visible = false func _draw(): var anchor = (resize_direction + Vector2.ONE) * 0.5 diff --git a/UI/panels/inspector_base.gd b/UI/panels/inspector_base.gd new file mode 100644 index 0000000..f2ed574 --- /dev/null +++ b/UI/panels/inspector_base.gd @@ -0,0 +1,110 @@ +extends Control +class_name InspectorBase + +var current_object : Resource + +signal current_object_changed +@export var properties_box : PropertiesBox +# Called when the node enters the scene tree for the first time. +func _ready(): + properties_box.connect("value_changed", value_changed) + current_object_changed.connect(create_ui) + + +func create_ui(): + #print("(" + get_script().resource_path.get_file() + ") UI Refresh") + properties_box.clear() + + if !current_object: + return + if !current_object.get_inspector_properties(): + return + var PropertiesView : Array = current_object.get_inspector_properties() + var PropertiesGroups : Array[String] = PropertiesView[0] + var PropertiesToShow : Dictionary = PropertiesView[1] + + for group in PropertiesGroups: + properties_box.add_group(group) + for property in PropertiesToShow: + if PropertiesToShow[property] == group: + + if property.contains(","): # An Enum + var property_info : PackedStringArray = property.split(",") + var property_key = property_info[0] + property_info.remove_at(0) + properties_box.add_options(property_key, property_info) + continue + + + var property_value = current_object.get(property.split(":")[0] if property.contains(":") else property) + if property_value is Callable: + properties_box.add_button(property, property_value) + if property_value is int: + if property.contains(":"): # hardness_property:min:1.0:max:100.0 + var property_info : PackedStringArray = property.split(":") + var property_key = property_info[0] + property_info.remove_at(0) + var minvalue : float = -99999900000.0 + var maxvalue : float = 99999900000.0 + for i in property_info.size()-1: + if property_info[i] == "minvalue": + minvalue = float(property_info[i+1]) + if property_info[i] == "maxvalue": + maxvalue = float(property_info[i+1]) + + properties_box.add_int(property_key, property_value, minvalue, maxvalue) + else: + properties_box.add_int(property, property_value) + continue + if property_value is float: + if property.contains(":"): # hardness_property:min:1.0:max:100.0 + var property_info : PackedStringArray = property.split(":") + var property_key = property_info[0] + property_info.remove_at(0) + var minvalue : float = 0.0 + var maxvalue : float = 100.0 + var step : float = 0.1 + for i in property_info.size()-1: + if property_info[i] == "minvalue": + minvalue = float(property_info[i+1]) + if property_info[i] == "maxvalue": + maxvalue = float(property_info[i+1]) + if property_info[i] == "step": + step = float(property_info[i+1]) + + properties_box.add_float(property_key, property_value, minvalue, maxvalue, step) + else: + properties_box.add_float(property, property_value) + continue + if property_value is String: + properties_box.add_string(property, property_value) + continue + if property_value is bool: + properties_box.add_bool(property, property_value) + continue + if property_value is Vector2: + if property.contains(":"): # vector_property:lock_aspect(bool) + var property_info : PackedStringArray = property.split(":") + var property_key = property_info[0] + property_info.remove_at(0) + var lock_aspect_key : String = property_info[0] + var lock_aspect : bool = current_object.get(lock_aspect_key) + properties_box.add_vector2(property_key, property_value, lock_aspect_key, lock_aspect) + else: + properties_box.add_vector2(property, property_value) + continue + if property_value is Color: + properties_box.add_color(property, property_value) + continue + properties_box.end_group() + +func update(): + for k in properties_box._keys: + + properties_box._keys[k] = current_object.get(k) + properties_box.update() + +func value_changed(property:String, value): + current_object.disconnect("changed",update) + current_object.set(property, value) + current_object.connect("changed",update) diff --git a/UI/panels/layer_inspector/LayerInspector.gd b/UI/panels/layer_inspector/LayerInspector.gd index 6a980f7..0a81a52 100644 --- a/UI/panels/layer_inspector/LayerInspector.gd +++ b/UI/panels/layer_inspector/LayerInspector.gd @@ -1,95 +1,28 @@ -extends ScrollContainer +extends InspectorBase var current_project : Project -var current_layer : base_layer - -signal current_layer_changed -@export var properties_box : PropertiesBox -# Called when the node enters the scene tree for the first time. -func _ready(): - properties_box.connect("value_changed", value_changed) - current_layer_changed.connect(create_ui) - func _process(_delta): if !ProjectsManager.current_project: visible = false - current_layer = null - current_layer_changed.emit() + current_object = null + current_object_changed.emit() return if !current_project or current_project != ProjectsManager.current_project: visible = false current_project = ProjectsManager.current_project return if current_project.layers_container.selected_layers.is_empty(): - current_layer = null - current_layer_changed.emit() + current_object = null + current_object_changed.emit() visible = false return - if current_layer != current_project.layers_container.selected_layers.front(): - current_layer = current_project.layers_container.selected_layers.front() - current_layer_changed.emit() - if current_layer.main_object == null: + if current_object != current_project.layers_container.selected_layers.front(): + current_object = current_project.layers_container.selected_layers.front() + current_object_changed.emit() + if current_object.main_object == null: return visible = true - if !current_layer.changed.is_connected(create_ui): - current_layer.connect("changed",create_ui) - -func create_ui(): - properties_box.clear() - - if !current_layer: - return - var PropertiesView : Array = current_layer.get_layer_inspector_properties() - var PropertiesGroups : Array[String] = PropertiesView[0] - var PropertiesToShow : Dictionary = PropertiesView[1] - - for group in PropertiesGroups: - properties_box.add_group(group) - for property in PropertiesToShow: - if PropertiesToShow[property] == group: - - if property.contains(","): # An Enum - var property_info : PackedStringArray = property.split(",") - var property_key = property_info[0] - property_info.remove_at(0) - properties_box.add_options(property_key, property_info) - continue - - - var property_value = current_layer.get(property) - if property_value is int: - properties_box.add_int(property, property_value) - continue - if property_value is float: - properties_box.add_float(property, property_value) - continue - if property_value is String: - properties_box.add_string(property, property_value) - continue - if property_value is bool: - properties_box.add_bool(property, property_value) - continue - if property_value is Vector2: - properties_box.add_vector2(property, property_value) - continue - if property_value is Color: - properties_box.add_color(property, property_value) - continue - properties_box.end_group() - - - -func value_changed(property:String, value): - current_layer.disconnect("changed",create_ui) - - if property.contains("X") or property.contains("Y"): - var new_vector : Vector2 = current_layer.get(property.trim_suffix(" X").trim_suffix(" Y")) - new_vector[0 if property.contains("X") else 1] = value - current_layer.set(property.trim_suffix(" X").trim_suffix(" Y"), new_vector) - current_layer.connect("changed",create_ui) - return - - current_layer.set(property, value) - current_layer.connect("changed",create_ui) + if !current_object.changed.is_connected(update): + current_object.connect("changed",update) diff --git a/UI/panels/layer_inspector/LayerInspector.tscn b/UI/panels/layer_inspector/LayerInspector.tscn old mode 100755 new mode 100644 diff --git a/UI/panels/reference/reference_panel.gd b/UI/panels/reference/reference_panel.gd old mode 100755 new mode 100644 index 1bdae43..380554a --- a/UI/panels/reference/reference_panel.gd +++ b/UI/panels/reference/reference_panel.gd @@ -145,7 +145,6 @@ func _on_ContextMenu_index_pressed(index): match index: 0: var dialog = preload("res://UI/windows/file_dialog/file_dialog.tscn").instantiate() - add_child(dialog) dialog.min_size = Vector2(500, 500) dialog.access = FileDialog.ACCESS_FILESYSTEM dialog.mode = FileDialog.FILE_MODE_OPEN_FILE @@ -157,6 +156,7 @@ func _on_ContextMenu_index_pressed(index): dialog.add_filter("*.svg;SVG Image") dialog.add_filter("*.tga;TGA Image") dialog.add_filter("*.webp;WebP Image") + add_child(dialog) var files = await dialog.select_files() if files.size() == 1: on_drop_image_file(files[0]) diff --git a/UI/panels/timeline/timeline.tscn b/UI/panels/timeline/timeline.tscn index 9a6c8c4..a2ad519 100644 --- a/UI/panels/timeline/timeline.tscn +++ b/UI/panels/timeline/timeline.tscn @@ -5,7 +5,7 @@ resource_name = "new_animation" [sub_resource type="AnimationLibrary" id="AnimationLibrary_r5u28"] _data = { -"new_animation": SubResource("Animation_ufppa") +&"new_animation": SubResource("Animation_ufppa") } [node name="Timeline" type="Panel"] @@ -21,5 +21,5 @@ grow_vertical = 2 [node name="AnimationPlayer" type="AnimationPlayer" parent="."] libraries = { -"": SubResource("AnimationLibrary_r5u28") +&"": SubResource("AnimationLibrary_r5u28") } diff --git a/UI/panels/tools bar/ToolButton.tscn b/UI/panels/tools bar/ToolButton.tscn old mode 100755 new mode 100644 index a98d5e7..2f61595 --- a/UI/panels/tools bar/ToolButton.tscn +++ b/UI/panels/tools bar/ToolButton.tscn @@ -1,13 +1,33 @@ -[gd_scene load_steps=3 format=3 uid="uid://ch0j87kh07p73"] +[gd_scene load_steps=4 format=3 uid="uid://ch0j87kh07p73"] [ext_resource type="Texture2D" uid="uid://btagbsdvxesyh" path="res://UI/graphics/tools/tool_background.png" id="1_e3peg"] [ext_resource type="Texture2D" uid="uid://snk0kn8v44dk" path="res://UI/graphics/tools/select.png" id="2_1ou6d"] +[sub_resource type="GDScript" id="GDScript_74ptu"] +script/source = "extends Button + +func _enter_tree() -> void: + custom_minimum_size = Vector2(get_parent().owner.custom_minimum_size.x, get_parent().owner.custom_minimum_size.x) * 0.75 + size = Vector2(get_parent().owner.custom_minimum_size.x, get_parent().owner.custom_minimum_size.x) * 0.75 +" + [node name="ToolButton" type="Button"] -custom_minimum_size = Vector2(24, 24) -offset_right = 8.0 -offset_bottom = 8.0 +custom_minimum_size = Vector2(50, 50) +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -12.0 +offset_top = -12.0 +offset_right = 12.0 +offset_bottom = 12.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 mouse_default_cursor_shape = 2 +script = SubResource("GDScript_74ptu") [node name="Background" type="NinePatchRect" parent="."] visible = false @@ -31,3 +51,4 @@ grow_horizontal = 2 grow_vertical = 2 texture = ExtResource("2_1ou6d") expand_mode = 1 +stretch_mode = 5 diff --git a/UI/panels/tools bar/tool_settings.gd b/UI/panels/tools bar/tool_settings.gd index 265e33c..fda815f 100644 --- a/UI/panels/tools bar/tool_settings.gd +++ b/UI/panels/tools bar/tool_settings.gd @@ -1,22 +1,14 @@ -extends ScrollContainer +extends InspectorBase var current_project : Project -var current_tool : ToolBase - -signal current_tool_changed -@export var properties_box : PropertiesBox -# Called when the node enters the scene tree for the first time. -func _ready(): - properties_box.connect("value_changed", value_changed) - current_tool_changed.connect(create_ui) func _process(_delta): # return if !ProjectsManager.current_project: visible = false - current_tool = null - current_tool_changed.emit() + current_object = null + current_object_changed.emit() return if !current_project or current_project != ProjectsManager.current_project: visible = false @@ -24,107 +16,15 @@ func _process(_delta): return ## Assign Current Tool - if current_tool != ToolsManager.current_tool: - current_tool = ToolsManager.current_tool - current_tool_changed.emit() - if current_tool == null: return + if current_object != ToolsManager.current_tool: + current_object = ToolsManager.current_tool + current_object_changed.emit() + if current_object == null: return visible = true - if !current_tool.changed.is_connected(create_ui): - current_tool.connect("changed",create_ui) + if !current_object.changed.is_connected(update): + current_object.changed.connect(update) -func create_ui(): - properties_box.clear() - - if !current_tool: - return - if !current_tool.get_tool_inspector_properties(): - return - var PropertiesView : Array = current_tool.get_tool_inspector_properties() - var PropertiesGroups : Array[String] = PropertiesView[0] - var PropertiesToShow : Dictionary = PropertiesView[1] - - for group in PropertiesGroups: - properties_box.add_group(group) - for property in PropertiesToShow: - if PropertiesToShow[property] == group: - - if property.contains(","): # An Enum - var property_info : PackedStringArray = property.split(",") - var property_key = property_info[0] - property_info.remove_at(0) - properties_box.add_options(property_key, property_info) - continue - - - var property_value = current_tool.get(property.split(":")[0] if property.contains(":") else property) - if property_value is Callable: - properties_box.add_button(property, property_value) - if property_value is int: - if property.contains(":"): # hardness_property:min:1.0:max:100.0 - var property_info : PackedStringArray = property.split(":") - var property_key = property_info[0] - property_info.remove_at(0) - var minvalue : float = -99999900000.0 - var maxvalue : float = 99999900000.0 - for i in property_info.size()-1: - if property_info[i] == "minvalue": - minvalue = float(property_info[i+1]) - if property_info[i] == "maxvalue": - maxvalue = float(property_info[i+1]) - - properties_box.add_int(property_key, property_value, minvalue, maxvalue) - else: - properties_box.add_int(property, property_value) - continue - if property_value is float: - if property.contains(":"): # hardness_property:min:1.0:max:100.0 - var property_info : PackedStringArray = property.split(":") - var property_key = property_info[0] - property_info.remove_at(0) - var minvalue : float = -99999900000.0 - var maxvalue : float = 99999900000.0 - var step : float = 1.0 - for i in property_info.size()-1: - if property_info[i] == "minvalue": - minvalue = float(property_info[i+1]) - if property_info[i] == "maxvalue": - maxvalue = float(property_info[i+1]) - if property_info[i] == "step": - step = float(property_info[i+1]) - - properties_box.add_float(property_key, property_value, minvalue, maxvalue, step) - else: - properties_box.add_float(property, property_value) - continue - if property_value is String: - properties_box.add_string(property, property_value) - continue - if property_value is bool: - properties_box.add_bool(property, property_value) - continue - if property_value is Vector2: - properties_box.add_vector2(property, property_value) - continue - if property_value is Color: - properties_box.add_color(property, property_value) - continue - properties_box.end_group() - - - -func value_changed(property:String, value): - current_tool.disconnect("changed",create_ui) - - if property.contains("X") or property.contains("Y"): - var new_vector : Vector2 = current_tool.get(property.trim_suffix(" X").trim_suffix(" Y")) - new_vector[0 if property.contains("X") else 1] = value - current_tool.set(property.trim_suffix(" X").trim_suffix(" Y"), new_vector) - current_tool.connect("changed",create_ui) - return - - current_tool.set(property, value) - current_tool.connect("changed",create_ui) ## Called every frame. 'delta' is the elapsed time since the previous frame. diff --git a/UI/panels/tools bar/tool_settings.tscn b/UI/panels/tools bar/tool_settings.tscn old mode 100755 new mode 100644 diff --git a/UI/panels/tools bar/tools_panel.gd b/UI/panels/tools bar/tools_panel.gd old mode 100755 new mode 100644 index 6522862..b0e8c38 --- a/UI/panels/tools bar/tools_panel.gd +++ b/UI/panels/tools bar/tools_panel.gd @@ -5,6 +5,10 @@ extends ScrollContainer var has_focus var _tool_button_scene: PackedScene = preload("res://UI/panels/tools bar/ToolButton.tscn") func _ready(): + if OS.get_name() == "Android" or OS.get_name() == "iOS": + custom_minimum_size.x = 75 + else: + custom_minimum_size.x = 35 create_menu(ToolsManager.TOOLS, ToolsManager, tree) ToolsManager.connect("tool_changed", selected_tool_changed) self.connect("mouse_entered",_on_mouse_entered) @@ -37,7 +41,20 @@ func create_menu(menu_def : Array, object, menu:HFlowContainer): tool_button.tooltip_text = menu_item_tip menu.add_child(tool_button) tool_button.connect("pressed", on_menu_item_pressed.bind(menu_def, object, i)) - + tool_button.connect("gui_input", create_temp_tool_settings_panel) +var popup : PopupPanel = PopupPanel.new() +func create_temp_tool_settings_panel(event: InputEvent, pos:Vector2 = get_global_mouse_position()): + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT: + add_child(popup) + for child in popup.get_children(): + popup.remove_child(child) + child.queue_free() + var tool_settings = preload("res://UI/panels/tools bar/tool_settings.tscn").instantiate() + tool_settings.custom_minimum_size = Vector2(300,300) + popup.add_child(tool_settings) + popup.position = pos + popup.visible = true + @@ -53,6 +70,10 @@ func update_tool_buttons() -> void: var background: NinePatchRect = child.get_node("Background") background.visible = ToolsManager.current_tool.tool_name == child.name +func _process(delta: float) -> void: + for child in tree.get_children(): + if child is BaseButton: + child.disabled = ToolsManager.TOOLS[tree.get_children().find(child)].is_tool_disabled() func _on_mouse_entered(): has_focus = true diff --git a/UI/panels/tools bar/tools_panel.tscn b/UI/panels/tools bar/tools_panel.tscn old mode 100755 new mode 100644 index b5e919d..983e99c --- a/UI/panels/tools bar/tools_panel.tscn +++ b/UI/panels/tools bar/tools_panel.tscn @@ -3,13 +3,9 @@ [ext_resource type="Script" path="res://UI/panels/tools bar/tools_panel.gd" id="1_xme5t"] [node name="Tools" type="ScrollContainer"] -custom_minimum_size = Vector2(36, 36) -anchors_preset = 15 -anchor_right = 1.0 +custom_minimum_size = Vector2(75, 36) +anchors_preset = 9 anchor_bottom = 1.0 -offset_right = -1250.0 -offset_bottom = -230.0 -grow_horizontal = 2 grow_vertical = 2 follow_focus = true script = ExtResource("1_xme5t") diff --git a/UI/theme/dark.tres b/UI/theme/dark.tres index 45fec7c..2378ced 100644 --- a/UI/theme/dark.tres +++ b/UI/theme/dark.tres @@ -65,19 +65,21 @@ content_margin_left = 6.0 content_margin_top = 4.0 content_margin_right = 6.0 content_margin_bottom = 4.0 -bg_color = Color(0.134118, 0.134118, 0.134118, 1) +bg_color = Color(0.133333, 0.133333, 0.133333, 0.580392) border_width_left = 1 border_width_top = 1 border_width_right = 1 border_width_bottom = 1 -border_color = Color(0.104314, 0.104314, 0.104314, 1) +border_color = Color(0.105882, 0.105882, 0.105882, 0) +shadow_color = Color(0, 0, 0, 0.843137) +shadow_size = 1 [sub_resource type="StyleBoxFlat" id="59"] content_margin_left = 6.0 content_margin_top = 4.0 content_margin_right = 6.0 content_margin_bottom = 4.0 -bg_color = Color(0.111765, 0.111765, 0.111765, 1) +bg_color = Color(0.113725, 0.113725, 0.113725, 1) border_width_left = 1 border_width_top = 1 border_width_right = 1 @@ -101,7 +103,7 @@ content_margin_left = 6.0 content_margin_top = 4.0 content_margin_right = 6.0 content_margin_bottom = 4.0 -bg_color = Color(0.111765, 0.111765, 0.111765, 1) +bg_color = Color(0.137255, 0.137255, 0.137255, 1) border_width_left = 1 border_width_top = 1 border_width_right = 1 diff --git a/UI/widgets/float_edit/float_edit.gd b/UI/widgets/float_edit/float_edit.gd old mode 100755 new mode 100644 index fcfd7e1..fac74b1 --- a/UI/widgets/float_edit/float_edit.gd +++ b/UI/widgets/float_edit/float_edit.gd @@ -1,27 +1,6 @@ -extends LineEdit +extends SpinBox class_name FloatEdit -@export var value : float = 0.5 : - set(v): - if v is float: - value = clampf(v, min_value, max_value) - text = str(v) - do_update() - $Slider.visible = true - emit_signal("value_changed", value) - emit_signal("value_changed_undo", value, false) -@export var min_value : float = 0.0: - set(v): - min_value = v - do_update() -@export var max_value : float = 1.0 : - set(v): - max_value = v - do_update() -@export var step : float = 0.0 : - set(v): - step = v - do_update() -@export var float_only : bool = false + var sliding : bool = false var start_position : float @@ -31,27 +10,14 @@ var modifiers : int var from_lower_bound : bool = false var from_upper_bound : bool = false -@onready var slider = $Slider -@onready var cursor = $Slider/Cursor -signal value_changed(value) -signal value_changed_undo(value, merge_undo) +signal value_changed_undo(value, merge_undo) +var has_focus : bool func _ready() -> void: - connect("text_submitted",_on_LineEdit_text_entered) - connect("focus_exited",_on_LineEdit_text_entered) - connect("mouse_exited",_on_LineEdit_text_entered) - do_update() - - -func do_update(update_text : bool = true) -> void: - if update_text and $Slider.visible: - text = str(value) - if cursor != null: - if max_value != min_value: - cursor.get_rect().size.x = (clamp(value, min_value, max_value)-min_value)*(slider.get_rect().size.x-cursor.get_rect().size.x)/(max_value-min_value) - else: - cursor.get_rect().size.x = 0 + get_line_edit().deselect_on_focus_loss_enabled = true + self.connect("mouse_entered",_on_mouse_entered) + self.connect("mouse_exited",_on_mouse_exited) func get_modifiers(event): var new_modifiers = 0 @@ -63,29 +29,35 @@ func get_modifiers(event): new_modifiers |= 4 return new_modifiers -func _gui_input(event : InputEvent) -> void: - if !slider.visible or !sliding and !editable: +func _input(event : InputEvent) -> void: + #if !has_focus: + #get_line_edit().deselect() + #get_line_edit().release_focus() + if !sliding and !editable: return + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: - if event.is_pressed(): - if event.double_click: - await get_tree().process_frame - select_all() - else: - last_position = event.position.x - start_position = last_position - start_value = value - sliding = true - from_lower_bound = value <= min_value - from_upper_bound = value >= max_value - modifiers = get_modifiers(event) - emit_signal("value_changed_undo", value) - editable = false - selecting_enabled = false + + if event.is_pressed() and has_focus: + get_line_edit().grab_focus() + get_line_edit().select_all() + last_position = event.position.x + start_position = last_position + start_value = value + sliding = true + from_lower_bound = value <= min_value + from_upper_bound = value >= max_value + modifiers = get_modifiers(event) + emit_signal("value_changed_undo", value) + editable = true + get_line_edit().selecting_enabled = false + #Input.mouse_mode = Input.MOUSE_MODE_CONFINED_HIDDEN else: sliding = false editable = true - selecting_enabled = true + #Input.mouse_mode = Input.MOUSE_MODE_VISIBLE + get_line_edit().selecting_enabled = true + elif sliding and event is InputEventMouseMotion and event.button_mask == MOUSE_BUTTON_MASK_LEFT: var new_modifiers = get_modifiers(event) if new_modifiers != modifiers: @@ -122,18 +94,9 @@ func _gui_input(event : InputEvent) -> void: modifiers = get_modifiers(event) - -func _on_LineEdit_text_entered(new_text : String = text, release = true) -> void: - new_text = str(new_text.to_float()) - var expr : Expression = Expression.new() - expr.parse(new_text) - var new_value : float = expr.execute() - value = new_value - do_update() - emit_signal("value_changed", value) - emit_signal("value_changed_undo", value, false) - $Slider.visible = true - if release: - release_focus() +func _on_mouse_entered(): + has_focus = true +func _on_mouse_exited(): + has_focus = false diff --git a/UI/widgets/float_edit/float_edit.tscn b/UI/widgets/float_edit/float_edit.tscn old mode 100755 new mode 100644 index 0d77b6c..332708a --- a/UI/widgets/float_edit/float_edit.tscn +++ b/UI/widgets/float_edit/float_edit.tscn @@ -2,7 +2,7 @@ [ext_resource type="Script" path="res://UI/widgets/float_edit/float_edit.gd" id="1"] -[node name="FloatEdit" type="LineEdit"] +[node name="FloatEdit" type="SpinBox"] anchors_preset = 11 anchor_left = 1.0 anchor_right = 1.0 @@ -11,25 +11,9 @@ offset_left = -67.0625 grow_horizontal = 0 grow_vertical = 2 focus_mode = 1 -text = "0.5" +step = 0.1 +allow_greater = true +allow_lesser = true +custom_arrow_step = 0.1 select_all_on_focus = true -caret_blink = true script = ExtResource("1") - -[node name="Slider" type="ColorRect" parent="."] -layout_mode = 1 -anchors_preset = 12 -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 0 -mouse_filter = 2 -color = Color(0.501961, 0.501961, 0.501961, 1) - -[node name="Cursor" type="ColorRect" parent="Slider"] -layout_mode = 0 -mouse_filter = 2 - -[connection signal="resized" from="." to="." method="do_update"] -[connection signal="resized" from="Slider" to="." method="do_update"] diff --git a/UI/widgets/vector2_edit/vector2_edit.gd b/UI/widgets/vector2_edit/vector2_edit.gd new file mode 100644 index 0000000..018b30f --- /dev/null +++ b/UI/widgets/vector2_edit/vector2_edit.gd @@ -0,0 +1,56 @@ +extends HBoxContainer +class_name Vector2Edit + +var value: Vector2: + set(v): + value = v + if float_edit_x and float_edit_y: + float_edit_x.value_changed.disconnect(x_value_changed) + float_edit_y.value_changed.disconnect(y_value_changed) + float_edit_x.value = value.x + float_edit_y.value = value.y + float_edit_x.value_changed.connect(x_value_changed) + float_edit_y.value_changed.connect(y_value_changed) +var lock_aspect: bool = false +signal value_changed(value:Vector2) +signal lock_aspect_changed(value:bool) + +@onready var float_edit_x = $VBoxContainer/PanelContainer/HBoxContainer/FloatEditX +@onready var float_edit_y = $VBoxContainer/Panel/HBoxContainer/FloatEditY +@onready var lock_button = $LockButton + + + +func _ready(): + float_edit_x.value = value.x + float_edit_y.value = value.y + lock_button.button_pressed = lock_aspect + float_edit_x.value_changed.connect(x_value_changed) + float_edit_y.value_changed.connect(y_value_changed) + lock_button.toggled.connect(_on_lock_button_toggled) + +#func _enter_tree(): + + +func x_value_changed(v: float): + if lock_aspect: + float_edit_y.value_changed.disconnect(y_value_changed) + float_edit_y.value += v - value.x + value.y = float_edit_y.value + float_edit_y.value_changed.connect(y_value_changed) + value.x = v + value_changed.emit(value) + +func y_value_changed(v: float): + if lock_aspect: + float_edit_x.value_changed.disconnect(x_value_changed) + float_edit_x.value += v - value.y + value.x = float_edit_x.value + float_edit_x.value_changed.connect(x_value_changed) + value.y = v + value_changed.emit(value) + + +func _on_lock_button_toggled(toggled_on): + lock_aspect = toggled_on + lock_aspect_changed.emit(lock_aspect) diff --git a/UI/widgets/vector2_edit/vector2_edit.tscn b/UI/widgets/vector2_edit/vector2_edit.tscn new file mode 100644 index 0000000..2a31316 --- /dev/null +++ b/UI/widgets/vector2_edit/vector2_edit.tscn @@ -0,0 +1,86 @@ +[gd_scene load_steps=8 format=3 uid="uid://5lx6m28c4kfq"] + +[ext_resource type="PackedScene" uid="uid://cuc4qcivfps74" path="res://UI/widgets/float_edit/float_edit.tscn" id="1_3ut4q"] +[ext_resource type="Script" path="res://UI/widgets/vector2_edit/vector2_edit.gd" id="1_mctat"] +[ext_resource type="Texture2D" uid="uid://do418dfoolgwc" path="res://UI/graphics/misc/lock_aspect_2.png" id="3_0lmq8"] +[ext_resource type="Texture2D" uid="uid://dkm5wfyx3uabc" path="res://UI/graphics/misc/lock_aspect.png" id="4_1ew8g"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_4a6mv"] +bg_color = Color(0.698039, 0.0941176, 0.12549, 1) + +[sub_resource type="LabelSettings" id="LabelSettings_imoch"] +font_color = Color(0, 0, 0, 1) +shadow_color = Color(0, 0, 0, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_naxla"] +bg_color = Color(0.619608, 0.827451, 0, 1) + +[node name="Vector2Edit" type="HBoxContainer"] +process_thread_group = 2 +process_thread_group_order = 0 +process_thread_messages = 0 +anchors_preset = 11 +anchor_left = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = -67.0625 +grow_horizontal = 0 +grow_vertical = 2 +focus_mode = 1 +script = ExtResource("1_mctat") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="PanelContainer" type="PanelContainer" parent="VBoxContainer"] +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_4a6mv") + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/PanelContainer"] +layout_mode = 2 +theme_override_constants/separation = 0 + +[node name="Label" type="Label" parent="VBoxContainer/PanelContainer/HBoxContainer"] +custom_minimum_size = Vector2(20, 0) +layout_mode = 2 +size_flags_vertical = 1 +text = "X" +label_settings = SubResource("LabelSettings_imoch") +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="FloatEditX" parent="VBoxContainer/PanelContainer/HBoxContainer" instance=ExtResource("1_3ut4q")] +layout_mode = 2 +size_flags_horizontal = 3 +custom_arrow_step = 1.0 + +[node name="Panel" type="PanelContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 4 +theme_override_styles/panel = SubResource("StyleBoxFlat_naxla") + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/Panel"] +layout_mode = 2 +theme_override_constants/separation = 0 + +[node name="Label" type="Label" parent="VBoxContainer/Panel/HBoxContainer"] +custom_minimum_size = Vector2(20, 0) +layout_mode = 2 +size_flags_vertical = 1 +text = "Y" +label_settings = SubResource("LabelSettings_imoch") +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="FloatEditY" parent="VBoxContainer/Panel/HBoxContainer" instance=ExtResource("1_3ut4q")] +layout_mode = 2 +size_flags_horizontal = 3 +custom_arrow_step = 1.0 + +[node name="LockButton" type="TextureButton" parent="."] +layout_mode = 2 +size_flags_vertical = 4 +toggle_mode = true +texture_normal = ExtResource("3_0lmq8") +texture_pressed = ExtResource("4_1ew8g") diff --git a/UI/windows/about/about.gd b/UI/windows/about/about.gd old mode 100755 new mode 100644 diff --git a/UI/windows/about/about.tscn b/UI/windows/about/about.tscn old mode 100755 new mode 100644 index aac40ee..a7f7df6 --- a/UI/windows/about/about.tscn +++ b/UI/windows/about/about.tscn @@ -13,9 +13,8 @@ [node name="About" type="PopupPanel"] disable_3d = true title = "About..." -size = Vector2i(664, 377) +size = Vector2i(704, 412) visible = true -wrap_controls = false transient = false unresizable = false always_on_top = true @@ -77,10 +76,12 @@ layout_mode = 2 size_flags_horizontal = 3 size_flags_vertical = 3 tab_alignment = 1 +current_tab = 0 [node name="Authors" type="ScrollContainer" parent="HBoxContainer/VBoxContainer/VBoxContainer"] custom_minimum_size = Vector2(620, 245) layout_mode = 2 +metadata/_tab_index = 0 [node name="List" type="GridContainer" parent="HBoxContainer/VBoxContainer/VBoxContainer/Authors"] layout_mode = 2 @@ -89,6 +90,7 @@ size_flags_vertical = 3 columns = 2 [node name="Godot" type="HBoxContainer" parent="HBoxContainer/VBoxContainer/VBoxContainer/Authors/List"] +visible = false layout_mode = 2 [node name="Godot" type="TextureButton" parent="HBoxContainer/VBoxContainer/VBoxContainer/Authors/List/Godot"] @@ -102,6 +104,7 @@ layout_mode = 2 text = " Godot Engine" [node name="Label" type="Label" parent="HBoxContainer/VBoxContainer/VBoxContainer/Authors/List"] +visible = false layout_mode = 2 size_flags_horizontal = 3 text = "90% of My Touch's code is the awesome Godot Engine" @@ -110,6 +113,7 @@ text = "90% of My Touch's code is the awesome Godot Engine" visible = false custom_minimum_size = Vector2(620, 245) layout_mode = 2 +metadata/_tab_index = 1 [node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer/VBoxContainer/VBoxContainer/Donors"] layout_mode = 2 @@ -157,6 +161,7 @@ The above copyright notice and this permission notice shall be included in all c 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." editable = false +metadata/_tab_index = 2 [node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/VBoxContainer"] layout_mode = 2 @@ -220,5 +225,5 @@ stretch_mode = 4 [connection signal="pressed" from="HBoxContainer/SocialNetworks/ItchIo" to="." method="open_url" binds= ["https://ywmaa.itch.io/my-touch"]] [connection signal="pressed" from="HBoxContainer/SocialNetworks/Github" to="." method="open_url" binds= ["https://github.com/ywmaa/my-touch"]] [connection signal="pressed" from="HBoxContainer/SocialNetworks/Discord" to="." method="open_url" binds= ["https://discord.com/invite/Fp7ncA2xHw"]] -[connection signal="pressed" from="HBoxContainer/SocialNetworks/Twitter" to="." method="open_url" binds= ["https://twitter.com/ywmaadev"]] +[connection signal="pressed" from="HBoxContainer/SocialNetworks/Twitter" to="." method="open_url" binds= ["https://x.com/ywmaapersonal"]] [connection signal="pressed" from="HBoxContainer/SocialNetworks/Youtube" to="." method="open_url" binds= ["https://www.youtube.com/YwmaaGamesStudio"]] diff --git a/UI/windows/file_dialog/file_dialog.gd b/UI/windows/file_dialog/file_dialog.gd old mode 100755 new mode 100644 index 613d800..1607b83 --- a/UI/windows/file_dialog/file_dialog.gd +++ b/UI/windows/file_dialog/file_dialog.gd @@ -7,7 +7,14 @@ var volume_option = null signal return_paths(path_list) +func _enter_tree() -> void: + if OS.get_name() == "Android": + root_subfolder = "/storage/emulated/0" + func _ready() -> void: + if OS.get_name() == "Android" or OS.get_name() == "iOS": + return + var vbox = get_vbox() var hbox = HSplitContainer.new() add_child(hbox) @@ -34,10 +41,16 @@ func get_full_current_dir() -> String: return prefix+get_current_dir() func _on_FileDialog_file_selected(path) -> void: + if !left_panel: + emit_signal("return_paths", [ path ]) + return left_panel.add_recent(get_full_current_dir()) emit_signal("return_paths", [ path ]) func _on_FileDialog_files_selected(paths) -> void: + if !left_panel: + emit_signal("return_paths", paths) + return left_panel.add_recent(get_full_current_dir()) emit_signal("return_paths", paths) @@ -54,4 +67,6 @@ func select_files() -> Array: return result func add_favorite(): + if !left_panel: + return left_panel.add_favorite(get_full_current_dir()) diff --git a/UI/windows/file_dialog/file_dialog.tscn b/UI/windows/file_dialog/file_dialog.tscn old mode 100755 new mode 100644 index c44f7ab..6689d66 --- a/UI/windows/file_dialog/file_dialog.tscn +++ b/UI/windows/file_dialog/file_dialog.tscn @@ -3,8 +3,11 @@ [ext_resource type="Script" path="res://UI/windows/file_dialog/file_dialog.gd" id="1"] [node name="FileDialog" type="FileDialog"] -size = Vector2i(392, 162) +position = Vector2i(0, 36) visible = true +min_size = Vector2i(100, 70) +content_scale_factor = 0.8 +dialog_autowrap = true script = ExtResource("1") [connection signal="dir_selected" from="." to="." method="_on_FileDialog_dir_selected"] diff --git a/UI/windows/file_dialog/left_panel.tscn b/UI/windows/file_dialog/left_panel.tscn old mode 100755 new mode 100644 index 5829cde..ab402b2 --- a/UI/windows/file_dialog/left_panel.tscn +++ b/UI/windows/file_dialog/left_panel.tscn @@ -3,9 +3,10 @@ [ext_resource type="Script" path="res://UI/windows/file_dialog/left_panel.gd" id="1"] [node name="LeftPanel" type="VBoxContainer"] -custom_minimum_size = Vector2(100, 40) -offset_right = 100.0 -offset_bottom = 64.0 +clip_contents = true +custom_minimum_size = Vector2(100, 20) +offset_right = 64.0 +offset_bottom = 58.0 size_flags_vertical = 3 script = ExtResource("1") diff --git a/UI/windows/undocked_window/undocked_window.tscn b/UI/windows/undocked_window/undocked_window.tscn old mode 100755 new mode 100644 index 2491133..f56f4d7 --- a/UI/windows/undocked_window/undocked_window.tscn +++ b/UI/windows/undocked_window/undocked_window.tscn @@ -8,7 +8,6 @@ script/source = "extends Window func _ready(): self.connect(\"close_requested\",func(): queue_free()) - " [node name="Window" type="Window"] diff --git a/UI/windows/windows_manager/WindowsManager.gd b/UI/windows/windows_manager/WindowsManager.gd old mode 100755 new mode 100644 diff --git a/UI/windows/windows_manager/WindowsManager.tscn b/UI/windows/windows_manager/WindowsManager.tscn old mode 100755 new mode 100644 diff --git a/addons/dockable_container/split_handle.gd b/addons/dockable_container/split_handle.gd old mode 100755 new mode 100644 index baf4b1f..4444f8b --- a/addons/dockable_container/split_handle.gd +++ b/addons/dockable_container/split_handle.gd @@ -31,11 +31,11 @@ func _draw() -> void: func _gui_input(event: InputEvent) -> void: - if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: + if (event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and OS.get_name() != "Android" and OS.get_name() != "iOS") or event is InputEventScreenTouch: _dragging = event.is_pressed() if event.double_click: layout_split.percent = 0.5 - elif _dragging and event is InputEventMouseMotion: + elif _dragging and (event is InputEventMouseMotion or event is InputEventScreenTouch): var mouse_in_parent := get_parent_control().get_local_mouse_position() if layout_split.is_horizontal(): layout_split.percent = ( diff --git a/addons/tnowe_extra_controls/elements/properties_box.gd b/addons/tnowe_extra_controls/elements/properties_box.gd index 8affa3b..239ea13 100644 --- a/addons/tnowe_extra_controls/elements/properties_box.gd +++ b/addons/tnowe_extra_controls/elements/properties_box.gd @@ -4,6 +4,7 @@ extends VBoxContainer ## A form to input multiple values of different types. Supports numbers, strings, and options (as in [UnfoldedOptionButton]) signal value_changed(key : StringName, new_value : Variant) +signal vector2_changed(key : StringName, new_value : Vector2) signal number_changed(key : StringName, new_value : float) signal string_changed(key : StringName, new_value : String) signal color_changed(key : StringName, new_value : Color) @@ -30,13 +31,16 @@ func update(): var index = 0 for key in _keys: var editor = _editors[index] - if editor is Button: editor.pressed = _keys[key] - if editor is SpinBox: editor.value = _keys[key] - if editor is LineEdit: editor.text = _keys[key] - if editor is TextEdit: editor.text = _keys[key] - if editor is RichTextLabel: editor.text = str(_keys[key]) - if editor is UnfoldedOptionButton: editor.value = _keys[key] - index += 1 + if _keys[key] is Callable: continue + if editor is ColorPickerButton: editor.color = _keys[key]; index += 1; continue + if editor is Button: editor.button_pressed = _keys[key]; index += 1; continue + if editor is SpinBox: editor.value = _keys[key]; index += 1; continue + if editor is FloatEdit: editor.value = _keys[key]; index += 1; continue + if editor is Vector2Edit: editor.value = _keys[key]; index += 1; continue + if editor is LineEdit: editor.text = _keys[key]; index += 1; continue + if editor is TextEdit: editor.text = _keys[key]; index += 1; continue + if editor is RichTextLabel: editor.text = str(_keys[key]); index += 1; continue + if editor is UnfoldedOptionButton: editor.value = _keys[key]; index += 1; continue ## Adds a [Button]. Retrieve the value with [method get_button]. func add_button(key : StringName, value : Callable): var editor = Button.new() @@ -54,9 +58,13 @@ func add_color(key : StringName, value : Color = Color.RED): editor.color = value _add_property_editor(key, editor, editor.color_changed, _on_color_changed) -func add_vector2(key : StringName, value : Vector2 = Vector2.ZERO): - add_float(key+" X", value.x) - add_float(key+" Y", value.y) +func add_vector2(key : StringName, value : Vector2 = Vector2.ZERO, lock_aspect_key : StringName = "", lock_aspect_value : bool = false): + var editor : Vector2Edit = preload("res://UI/widgets/vector2_edit/vector2_edit.tscn").instantiate() + editor.value = value + if lock_aspect_key != "": + editor.lock_aspect = lock_aspect_value + editor.lock_aspect_changed.connect(_on_bool_changed.bind(lock_aspect_key)) + _add_property_editor(key, editor, editor.value_changed, _on_vector2_changed) ## Adds a [SpinBox]. Retrieve the value with [method get_float] or [method get_int]. ## If both [code]minvalue[/code] and [code]maxvalue[/code] are specified, also creates an [HSlider]. @@ -65,12 +73,14 @@ func add_int(key : StringName, value : int = 0, minvalue : int = -2147483648, ma ## Adds a [SpinBox]. Retrieve the value with [method get_float] or [method get_int]. ## If both [code]minvalue[/code] and [code]maxvalue[/code] are specified, also creates an [HSlider]. -func add_float(key : StringName, value : float = 0.0, minvalue : float = -2147483648.0, maxvalue : float = 2147483648.0, step : float = 1.0): +func add_float(key : StringName, value : float = 0.0, minvalue : float = -2147483648.0, maxvalue : float = 2147483648.0, step : float = 0.1): var editor : FloatEdit = preload("res://UI/widgets/float_edit/float_edit.tscn").instantiate() var is_slider = minvalue > -2147483648 && maxvalue < 2147483648 editor.step = step - editor.min_value = -10000 if not is_slider else minvalue#minvalue - editor.max_value = 10000 if not is_slider else maxvalue#maxvalue + editor.allow_greater = true if not is_slider else false + editor.allow_lesser = true if not is_slider else false + editor.min_value = 0 if not is_slider else minvalue#minvalue + editor.max_value = 100 if not is_slider else maxvalue#maxvalue editor.value = value _add_property_editor(key, editor, editor.value_changed, _on_number_changed) # if is_slider: @@ -209,6 +219,11 @@ func get_bool(key : StringName) -> bool: var editor = _editors[_keys[key]] return editor.pressed +## Retrieve a number. +func get_vector2(key : StringName) -> Vector2: + var editor = _editors[_keys[key]] + return editor.value + ## Retrieve a number or option. func get_int(key : StringName) -> int: var editor = _editors[_keys[key]] @@ -255,7 +270,7 @@ func _add_property_editor(key : StringName, editor : Control, editor_signal : Si var box = HBoxContainer.new() var label = Label.new() - label.text = key + label.text = key.replace("_", " ").capitalize() label.clip_text = true label.size_flags_vertical = 0 label.size_flags_horizontal = SIZE_EXPAND_FILL @@ -267,6 +282,9 @@ func _add_property_editor(key : StringName, editor : Control, editor_signal : Si if editable: editor_signal.connect(signal_handler.bind(key)) +func _on_vector2_changed(value : Vector2, key : StringName): + vector2_changed.emit(key, value) + value_changed.emit(key, value) func _on_number_changed(value : float, key : StringName): number_changed.emit(key, value) diff --git a/editor.gd b/editor.gd index 095e8e4..541dc72 100644 --- a/editor.gd +++ b/editor.gd @@ -10,7 +10,7 @@ var updating : bool = false var need_update : bool = false #@onready var projects = $VBoxContainer/ProjectTabs - +@onready var app_render : SubViewport = $AppRender @onready var layout : DockableContainer = $VBoxContainer/Layout const SAVED_LAYOUT_PATH := "user://layout.tres" var library @@ -66,7 +66,8 @@ const MENU = [ { menu="View/Center view", command="view_center", shortcut="C" }, { menu="View/Reset zoom", command="view_reset_zoom", shortcut="Control+0" }, { menu="View/-" }, - { menu="View/Touch Friendly Layout", command="touch_mode_switch", shortcut="Control+Space" }, + { menu="View/Mobile Friendly Layout", command="graph_only_mode", shortcut="" }, + { menu="View/Tablet Friendly Layout", command="touch_mode_switch", shortcut="Control+Space" }, { menu="View/Default Layout", command="default_mode_switch", shortcut="" }, { menu="View/User Layout", command="user_mode_switch", shortcut="" }, { menu="View/-" }, @@ -91,17 +92,25 @@ func _input(event: InputEvent) -> void: func _enter_tree(): mt_globals.main_window = self - -#func _process(_delta): +var current_screen_sensor : DisplayServer.ScreenOrientation +func _process(_delta): + #if current_screen_sensor != DisplayServer.screen_get_orientation(): + #current_screen_sensor = DisplayServer.screen_get_orientation() + if layout._layout.resource_name.contains("touch"): + touch_mode_switch() # layout._update_layout_with_children() # print(layout.get_tab_count()) func _ready() -> void: set_physics_process(false) get_tree().set_auto_accept_quit(false) + if OS.get_name() == "Android": + OS.request_permissions() + + if mt_globals.get_config("locale") == "": mt_globals.set_config("locale", TranslationServer.get_locale()) - + on_config_changed() get_screen_position() @@ -150,7 +159,10 @@ func _ready() -> void: layout.set_layout(saved_layout.clone()) else: print("Warning: Can't User Load Layout") - default_mode_switch() + if OS.get_name() == "Android" or OS.get_name() == "iOS": + graph_only_mode() + else: + default_mode_switch() var context_menu : PopupMenu = PopupMenu.new() @@ -185,7 +197,7 @@ func add_context_menu_item_pressed(id: int): return #var new_paint_layer = paint_layer.new() #new_paint_layer.init(ProjectsManager.current_project.layers_container.get_unused_layer_name(),"", ProjectsManager.current_project,base_layer.layer_type.brush) - paint_layer.new().init(ProjectsManager.current_project.layers_container.get_unused_layer_name(),"", ProjectsManager.current_project) + paint_layer.new().init(ProjectsManager.current_project.layers_container.get_unused_layer_name(), ProjectsManager.current_project) 5: #text layer if !ProjectsManager.current_project: return @@ -199,7 +211,30 @@ func add_context_menu_item_pressed(id: int): #var new_selection_layer = selection_layer.new() #new_selection_layer.init(ProjectsManager.current_project.layers_container.get_unused_layer_name(),ProjectsManager.default_icon, ProjectsManager.current_project, base_layer.layer_type.mask) - + +var popup : PopupPanel = PopupPanel.new() +func create_temp_properties_panel(pos:Vector2 = get_global_mouse_position()): + add_child(popup) + for child in popup.get_children(): + popup.remove_child(child) + child.queue_free() + var properties = preload("res://UI/panels/layer_inspector/LayerInspector.tscn").instantiate() + properties.custom_minimum_size = Vector2(300,300) + popup.add_child(properties) + popup.position = pos + popup.visible = true +func create_temp_layers_panel(pos:Vector2 = get_global_mouse_position()): + add_child(popup) + for child in popup.get_children(): + popup.remove_child(child) + child.queue_free() + var layers = preload("res://UI/panels/layers/layers.tscn").instantiate() + layers.custom_minimum_size = Vector2(300,300) + popup.add_child(layers) + popup.position = pos + popup.visible = true + + func on_config_changed() -> void: DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if mt_globals.get_config("vsync") else DisplayServer.VSYNC_DISABLED) # Convert FPS to microseconds per frame. @@ -255,12 +290,11 @@ func new_project() -> void: func load_project() -> void: var dialog = preload("res://UI/windows/file_dialog/file_dialog.tscn").instantiate() - add_child(dialog) dialog.min_size = Vector2(500, 500) dialog.access = FileDialog.ACCESS_FILESYSTEM dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILES dialog.add_filter("*.mt.tres;My Touch text files") - + add_child(dialog) if mt_globals.config.has_section_key("path", "project"): dialog.current_dir = mt_globals.config.get_value("path", "project") var files = await dialog.select_files() @@ -378,11 +412,11 @@ func export_png_image(): return # Prompt for a target PNG file var dialog = preload("res://UI/windows/file_dialog/file_dialog.tscn").instantiate() - add_child(dialog) dialog.min_size = Vector2(500, 500) dialog.access = FileDialog.ACCESS_FILESYSTEM dialog.file_mode = FileDialog.FILE_MODE_SAVE_FILE dialog.add_filter("*.png;PNG image file") + add_child(dialog) var files = await dialog.select_files() if files.size() != 1: return @@ -399,11 +433,11 @@ func export_jpeg_image(): return # Prompt for a target PNG file var dialog = preload("res://UI/windows/file_dialog/file_dialog.tscn").instantiate() - add_child(dialog) dialog.min_size = Vector2(500, 500) dialog.access = FileDialog.ACCESS_FILESYSTEM dialog.file_mode = FileDialog.FILE_MODE_SAVE_FILE dialog.add_filter("*.jpeg;JPEG image file") + add_child(dialog) var files = await dialog.select_files() if files.size() != 1: return @@ -487,6 +521,8 @@ func edit_copy() -> void: ProjectsManager.copy() func edit_paste() -> void: + if DisplayServer.clipboard_has_image(): + ProjectsManager.on_import_image_clipboard() ProjectsManager.paste() func edit_duplicate() -> void: @@ -512,12 +548,12 @@ func parent_layer() -> void: ProjectsManager.current_project.layers_container.add_layer(selected_layers[i], selected_layers[0]) func edit_load_selection() -> void: var dialog = preload("res://UI/windows/file_dialog/file_dialog.tscn").instantiate() - add_child(dialog) dialog.min_size = Vector2(500, 500) dialog.access = FileDialog.ACCESS_FILESYSTEM dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILES dialog.add_filter("*.mt.tres;My Touch text files") - + add_child(dialog) + if mt_globals.config.has_section_key("path", "project"): dialog.current_dir = mt_globals.config.get_value("path", "project") var files = await dialog.select_files() @@ -529,12 +565,11 @@ func edit_save_selection(): func edit_load_project_as_image() -> void: var dialog = preload("res://UI/windows/file_dialog/file_dialog.tscn").instantiate() - add_child(dialog) dialog.min_size = Vector2(500, 500) dialog.access = FileDialog.ACCESS_FILESYSTEM dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILES dialog.add_filter("*.mt.tres;My Touch text files") - + add_child(dialog) if mt_globals.config.has_section_key("path", "project"): dialog.current_dir = mt_globals.config.get_value("path", "project") var files = await dialog.select_files() @@ -575,15 +610,32 @@ func view_center() -> void: func view_reset_zoom() -> void: signal_view_reset_zoom.emit() - -func touch_mode_switch() -> void: - var saved_layout : DockableLayout = load("res://touch_editor_layout.tres") +func graph_only_mode() -> void: + var saved_layout : DockableLayout = load("res://graph_only_layout.tres") if saved_layout: var clone = saved_layout.clone() - clone.resource_name = "touch_layout" + clone.resource_name = "graph_only_layout" layout.set_layout(clone) else: print("Error: Can't Load Layout") + view_center() + +func touch_mode_switch() -> void: + var saved_layout : DockableLayout = load("res://touch_editor_layout.tres") + var saved_layout_vertical : DockableLayout = load("res://vertical_touch_editor_layout.tres") + if saved_layout and saved_layout_vertical: + if size.x > size.y and layout._layout.resource_name != "touch_layout": + var clone = saved_layout.clone() + clone.resource_name = "touch_layout" + layout.set_layout(clone) + view_center() + if size.x < size.y and layout._layout.resource_name != "vertical_touch_layout": + var clone = saved_layout_vertical.clone() + clone.resource_name = "vertical_touch_layout" + layout.set_layout(clone) + view_center() + else: + print("Error: Can't Load Layout") func default_mode_switch() -> void: var saved_layout : DockableLayout = load("res://normal_editor_layout.tres") if saved_layout: @@ -592,6 +644,7 @@ func default_mode_switch() -> void: layout.set_layout(clone) else: print("Error: Can't Load Layout") + view_center() func user_mode_switch() -> void: var saved_layout : DockableLayout = ResourceLoader.load(SAVED_LAYOUT_PATH) if saved_layout: @@ -655,7 +708,6 @@ func about() -> void: #image import func import_image() -> void: var dialog = preload("res://UI/windows/file_dialog/file_dialog.tscn").instantiate() - add_child(dialog) dialog.min_size = Vector2(500, 500) dialog.access = FileDialog.ACCESS_FILESYSTEM dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILES @@ -664,6 +716,7 @@ func import_image() -> void: dialog.add_filter("*.svg;SVG Image") dialog.add_filter("*.tga;TGA Image") dialog.add_filter("*.webp;WebP Image") + add_child(dialog) var files = await dialog.select_files() if files.size() > 0: on_files_dropped(files) @@ -680,6 +733,3 @@ func on_files_dropped(files : PackedStringArray) -> void: do_load_project(f) "jpg", "jpeg", "png", "svg", "webp": ProjectsManager.on_import_image_file(f) - - - diff --git a/editor.tscn b/editor.tscn index 5354e79..59d5190 100644 --- a/editor.tscn +++ b/editor.tscn @@ -5,7 +5,7 @@ [ext_resource type="PackedScene" uid="uid://cliund3ivs7rq" path="res://UI/widgets/render_counter/render_counter.tscn" id="3_dljtu"] [ext_resource type="Script" path="res://tabs.gd" id="4_ejxk4"] [ext_resource type="Script" path="res://addons/dockable_container/dockable_container.gd" id="6_jlrni"] -[ext_resource type="Resource" uid="uid://busuw7nyk34mk" path="res://touch_editor_layout.tres" id="6_yg31v"] +[ext_resource type="Resource" uid="uid://0wfawbv87br4" path="res://graph_only_layout.tres" id="6_upj0v"] [ext_resource type="PackedScene" uid="uid://di4qw4bosuns4" path="res://UI/windows/windows_manager/WindowsManager.tscn" id="7_8bflp"] [ext_resource type="Script" path="res://UI/panels/graph/Canvas.gd" id="7_kirsr"] @@ -13,7 +13,7 @@ script/source = "extends Label func show_step(step : int): - text = \"Undo/Redo action added (%d)\" % step + text = \"Undo/Redo \" + ToolsManager.current_project.undo_redo.get_current_action_name() + \" added (%d)\" % step $AnimationPlayer.stop() $AnimationPlayer.play(\"show\") @@ -53,7 +53,7 @@ tracks/1/keys = { [sub_resource type="AnimationLibrary" id="AnimationLibrary_21bw6"] _data = { -"show": SubResource("7") +&"show": SubResource("7") } [node name="Editor" type="Panel"] @@ -94,7 +94,7 @@ layout_mode = 2 layout_mode = 2 [node name="ProjectTabs" type="Panel" parent="VBoxContainer"] -custom_minimum_size = Vector2(950, 25) +custom_minimum_size = Vector2(0, 25) layout_mode = 2 script = ExtResource("4_ejxk4") metadata/_edit_layout_mode = 1 @@ -115,9 +115,10 @@ drag_to_rearrange_enabled = true layout_mode = 2 size_flags_vertical = 3 script = ExtResource("6_jlrni") -layout = ExtResource("6_yg31v") +layout = ExtResource("6_upj0v") [node name="Tool Settings" parent="VBoxContainer/Layout" instance=ExtResource("7_8bflp")] +visible = false layout_mode = 2 init_window = 3 @@ -131,9 +132,11 @@ layout_mode = 2 init_window = 2 [node name="Layers Panel" parent="VBoxContainer/Layout" instance=ExtResource("7_8bflp")] +visible = false layout_mode = 2 [node name="Layer Inspector" parent="VBoxContainer/Layout" instance=ExtResource("7_8bflp")] +visible = false layout_mode = 2 init_window = 1 @@ -153,7 +156,7 @@ script = SubResource("6") [node name="AnimationPlayer" type="AnimationPlayer" parent="MessageLabel"] libraries = { -"": SubResource("AnimationLibrary_21bw6") +&"": SubResource("AnimationLibrary_21bw6") } [node name="LeftCursor" type="Sprite2D" parent="."] diff --git a/export_presets.cfg b/export_presets.cfg old mode 100755 new mode 100644 index 7f8c5b6..04af19f --- a/export_presets.cfg +++ b/export_presets.cfg @@ -3,16 +3,19 @@ name="windows" platform="Windows Desktop" runnable=true +advanced_options=false dedicated_server=false custom_features="" export_filter="all_resources" include_filter="" exclude_filter="AI/*" -export_path="./exports/My Touch.x86_64.exe" +export_path="exports/My Touch.x86_64.exe" +patches=PackedStringArray() encryption_include_filters="" encryption_exclude_filters="" encrypt_pck=false encrypt_directory=false +script_export_mode=2 [preset.0.options] @@ -20,10 +23,8 @@ custom_template/debug="" custom_template/release="" debug/export_console_wrapper=1 binary_format/embed_pck=true -texture_format/bptc=false -texture_format/s3tc=true -texture_format/etc=false -texture_format/etc2=false +texture_format/s3tc_bptc=true +texture_format/etc2_astc=false binary_format/architecture="x86_64" codesign/enable=false codesign/timestamp=true @@ -42,6 +43,9 @@ application/product_name="My Touch" application/file_description="" application/copyright="" application/trademarks="" +application/export_angle=0 +application/export_d3d12=0 +application/d3d12_agility_sdk_multiarch=true ssh_remote_deploy/enabled=false ssh_remote_deploy/host="user@host_ip" ssh_remote_deploy/port="22" @@ -59,6 +63,10 @@ Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorActi ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue Remove-Item -Recurse -Force '{temp_dir}'" +texture_format/bptc=false +texture_format/s3tc=true +texture_format/etc=false +texture_format/etc2=false debug/export_console_script=1 [preset.1] @@ -66,16 +74,19 @@ debug/export_console_script=1 name="mac" platform="macOS" runnable=true +advanced_options=false dedicated_server=false custom_features="" export_filter="all_resources" include_filter="" exclude_filter="AI/*" export_path="./exports/My Touch.app.zip" +patches=PackedStringArray() encryption_include_filters="" encryption_exclude_filters="" encrypt_pck=false encrypt_directory=false +script_export_mode=2 [preset.1.options] @@ -93,8 +104,11 @@ application/short_version="0.1" application/version="0.1.5" application/copyright="" application/copyright_localized={} -application/min_macos_version="10.12" +application/min_macos_version_x86_64="10.12" +application/min_macos_version_arm64="11.00" +application/export_angle=0 display/high_res=false +application/additional_plist_content="" xcode/platform_build="14C18" xcode/sdk_version="13.1" xcode/sdk_build="22C55" @@ -127,6 +141,7 @@ codesign/entitlements/app_sandbox/files_downloads=0 codesign/entitlements/app_sandbox/files_pictures=0 codesign/entitlements/app_sandbox/files_music=0 codesign/entitlements/app_sandbox/files_movies=0 +codesign/entitlements/app_sandbox/files_user_selected=0 codesign/entitlements/app_sandbox/helper_executables=[] codesign/custom_options=PackedStringArray() notarization/notarization=0 @@ -152,6 +167,148 @@ privacy/network_volumes_usage_description="" privacy/network_volumes_usage_description_localized={} privacy/removable_volumes_usage_description="" privacy/removable_volumes_usage_description_localized={} +privacy/tracking_enabled=false +privacy/tracking_domains=PackedStringArray() +privacy/collected_data/name/collected=false +privacy/collected_data/name/linked_to_user=false +privacy/collected_data/name/used_for_tracking=false +privacy/collected_data/name/collection_purposes=0 +privacy/collected_data/email_address/collected=false +privacy/collected_data/email_address/linked_to_user=false +privacy/collected_data/email_address/used_for_tracking=false +privacy/collected_data/email_address/collection_purposes=0 +privacy/collected_data/phone_number/collected=false +privacy/collected_data/phone_number/linked_to_user=false +privacy/collected_data/phone_number/used_for_tracking=false +privacy/collected_data/phone_number/collection_purposes=0 +privacy/collected_data/physical_address/collected=false +privacy/collected_data/physical_address/linked_to_user=false +privacy/collected_data/physical_address/used_for_tracking=false +privacy/collected_data/physical_address/collection_purposes=0 +privacy/collected_data/other_contact_info/collected=false +privacy/collected_data/other_contact_info/linked_to_user=false +privacy/collected_data/other_contact_info/used_for_tracking=false +privacy/collected_data/other_contact_info/collection_purposes=0 +privacy/collected_data/health/collected=false +privacy/collected_data/health/linked_to_user=false +privacy/collected_data/health/used_for_tracking=false +privacy/collected_data/health/collection_purposes=0 +privacy/collected_data/fitness/collected=false +privacy/collected_data/fitness/linked_to_user=false +privacy/collected_data/fitness/used_for_tracking=false +privacy/collected_data/fitness/collection_purposes=0 +privacy/collected_data/payment_info/collected=false +privacy/collected_data/payment_info/linked_to_user=false +privacy/collected_data/payment_info/used_for_tracking=false +privacy/collected_data/payment_info/collection_purposes=0 +privacy/collected_data/credit_info/collected=false +privacy/collected_data/credit_info/linked_to_user=false +privacy/collected_data/credit_info/used_for_tracking=false +privacy/collected_data/credit_info/collection_purposes=0 +privacy/collected_data/other_financial_info/collected=false +privacy/collected_data/other_financial_info/linked_to_user=false +privacy/collected_data/other_financial_info/used_for_tracking=false +privacy/collected_data/other_financial_info/collection_purposes=0 +privacy/collected_data/precise_location/collected=false +privacy/collected_data/precise_location/linked_to_user=false +privacy/collected_data/precise_location/used_for_tracking=false +privacy/collected_data/precise_location/collection_purposes=0 +privacy/collected_data/coarse_location/collected=false +privacy/collected_data/coarse_location/linked_to_user=false +privacy/collected_data/coarse_location/used_for_tracking=false +privacy/collected_data/coarse_location/collection_purposes=0 +privacy/collected_data/sensitive_info/collected=false +privacy/collected_data/sensitive_info/linked_to_user=false +privacy/collected_data/sensitive_info/used_for_tracking=false +privacy/collected_data/sensitive_info/collection_purposes=0 +privacy/collected_data/contacts/collected=false +privacy/collected_data/contacts/linked_to_user=false +privacy/collected_data/contacts/used_for_tracking=false +privacy/collected_data/contacts/collection_purposes=0 +privacy/collected_data/emails_or_text_messages/collected=false +privacy/collected_data/emails_or_text_messages/linked_to_user=false +privacy/collected_data/emails_or_text_messages/used_for_tracking=false +privacy/collected_data/emails_or_text_messages/collection_purposes=0 +privacy/collected_data/photos_or_videos/collected=false +privacy/collected_data/photos_or_videos/linked_to_user=false +privacy/collected_data/photos_or_videos/used_for_tracking=false +privacy/collected_data/photos_or_videos/collection_purposes=0 +privacy/collected_data/audio_data/collected=false +privacy/collected_data/audio_data/linked_to_user=false +privacy/collected_data/audio_data/used_for_tracking=false +privacy/collected_data/audio_data/collection_purposes=0 +privacy/collected_data/gameplay_content/collected=false +privacy/collected_data/gameplay_content/linked_to_user=false +privacy/collected_data/gameplay_content/used_for_tracking=false +privacy/collected_data/gameplay_content/collection_purposes=0 +privacy/collected_data/customer_support/collected=false +privacy/collected_data/customer_support/linked_to_user=false +privacy/collected_data/customer_support/used_for_tracking=false +privacy/collected_data/customer_support/collection_purposes=0 +privacy/collected_data/other_user_content/collected=false +privacy/collected_data/other_user_content/linked_to_user=false +privacy/collected_data/other_user_content/used_for_tracking=false +privacy/collected_data/other_user_content/collection_purposes=0 +privacy/collected_data/browsing_history/collected=false +privacy/collected_data/browsing_history/linked_to_user=false +privacy/collected_data/browsing_history/used_for_tracking=false +privacy/collected_data/browsing_history/collection_purposes=0 +privacy/collected_data/search_hhistory/collected=false +privacy/collected_data/search_hhistory/linked_to_user=false +privacy/collected_data/search_hhistory/used_for_tracking=false +privacy/collected_data/search_hhistory/collection_purposes=0 +privacy/collected_data/user_id/collected=false +privacy/collected_data/user_id/linked_to_user=false +privacy/collected_data/user_id/used_for_tracking=false +privacy/collected_data/user_id/collection_purposes=0 +privacy/collected_data/device_id/collected=false +privacy/collected_data/device_id/linked_to_user=false +privacy/collected_data/device_id/used_for_tracking=false +privacy/collected_data/device_id/collection_purposes=0 +privacy/collected_data/purchase_history/collected=false +privacy/collected_data/purchase_history/linked_to_user=false +privacy/collected_data/purchase_history/used_for_tracking=false +privacy/collected_data/purchase_history/collection_purposes=0 +privacy/collected_data/product_interaction/collected=false +privacy/collected_data/product_interaction/linked_to_user=false +privacy/collected_data/product_interaction/used_for_tracking=false +privacy/collected_data/product_interaction/collection_purposes=0 +privacy/collected_data/advertising_data/collected=false +privacy/collected_data/advertising_data/linked_to_user=false +privacy/collected_data/advertising_data/used_for_tracking=false +privacy/collected_data/advertising_data/collection_purposes=0 +privacy/collected_data/other_usage_data/collected=false +privacy/collected_data/other_usage_data/linked_to_user=false +privacy/collected_data/other_usage_data/used_for_tracking=false +privacy/collected_data/other_usage_data/collection_purposes=0 +privacy/collected_data/crash_data/collected=false +privacy/collected_data/crash_data/linked_to_user=false +privacy/collected_data/crash_data/used_for_tracking=false +privacy/collected_data/crash_data/collection_purposes=0 +privacy/collected_data/performance_data/collected=false +privacy/collected_data/performance_data/linked_to_user=false +privacy/collected_data/performance_data/used_for_tracking=false +privacy/collected_data/performance_data/collection_purposes=0 +privacy/collected_data/other_diagnostic_data/collected=false +privacy/collected_data/other_diagnostic_data/linked_to_user=false +privacy/collected_data/other_diagnostic_data/used_for_tracking=false +privacy/collected_data/other_diagnostic_data/collection_purposes=0 +privacy/collected_data/environment_scanning/collected=false +privacy/collected_data/environment_scanning/linked_to_user=false +privacy/collected_data/environment_scanning/used_for_tracking=false +privacy/collected_data/environment_scanning/collection_purposes=0 +privacy/collected_data/hands/collected=false +privacy/collected_data/hands/linked_to_user=false +privacy/collected_data/hands/used_for_tracking=false +privacy/collected_data/hands/collection_purposes=0 +privacy/collected_data/head/collected=false +privacy/collected_data/head/linked_to_user=false +privacy/collected_data/head/used_for_tracking=false +privacy/collected_data/head/collection_purposes=0 +privacy/collected_data/other_data_types/collected=false +privacy/collected_data/other_data_types/linked_to_user=false +privacy/collected_data/other_data_types/used_for_tracking=false +privacy/collected_data/other_data_types/collection_purposes=0 ssh_remote_deploy/enabled=false ssh_remote_deploy/host="user@host_ip" ssh_remote_deploy/port="22" @@ -163,24 +320,28 @@ open \"{temp_dir}/{exe_name}.app\" --args {cmd_args}" ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash kill $(pgrep -x -f \"{temp_dir}/{exe_name}.app/Contents/MacOS/{exe_name} {cmd_args}\") rm -rf \"{temp_dir}\"" +application/min_macos_version="10.12" debug/export_console_script=1 notarization/apple_team_id="" [preset.2] name="Linux/X11" -platform="Linux/X11" +platform="Linux" runnable=true +advanced_options=false dedicated_server=false custom_features="" export_filter="all_resources" include_filter="" exclude_filter="AI/*" export_path="./exports/My Touch.x86_64" +patches=PackedStringArray() encryption_include_filters="" encryption_exclude_filters="" encrypt_pck=false encrypt_directory=false +script_export_mode=2 [preset.2.options] @@ -188,10 +349,8 @@ custom_template/debug="" custom_template/release="" debug/export_console_wrapper=1 binary_format/embed_pck=true -texture_format/bptc=false -texture_format/s3tc=true -texture_format/etc=false -texture_format/etc2=false +texture_format/s3tc_bptc=true +texture_format/etc2_astc=false binary_format/architecture="x86_64" ssh_remote_deploy/enabled=false ssh_remote_deploy/host="user@host_ip" @@ -205,6 +364,10 @@ unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\" ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\") rm -rf \"{temp_dir}\"" +texture_format/bptc=false +texture_format/s3tc=true +texture_format/etc=false +texture_format/etc2=false debug/export_console_script=1 [preset.3] @@ -212,22 +375,28 @@ debug/export_console_script=1 name="Android" platform="Android" runnable=true +advanced_options=false dedicated_server=false custom_features="" export_filter="all_resources" include_filter="" exclude_filter="" -export_path="./exports/My Touch.apk" +export_path="exports/My Touch.apk" +patches=PackedStringArray() encryption_include_filters="" encryption_exclude_filters="" encrypt_pck=false encrypt_directory=false +script_export_mode=2 [preset.3.options] custom_template/debug="" custom_template/release="" gradle_build/use_gradle_build=false +gradle_build/gradle_build_directory="" +gradle_build/android_source_template="" +gradle_build/compress_native_libraries=false gradle_build/export_format=0 gradle_build/min_sdk="" gradle_build/target_sdk="" @@ -243,14 +412,15 @@ package/signed=true package/app_category=6 package/retain_data_on_uninstall=false package/exclude_from_recents=false +package/show_in_android_tv=false +package/show_in_app_library=true +package/show_as_launcher_app=false launcher_icons/main_192x192="" launcher_icons/adaptive_foreground_432x432="" launcher_icons/adaptive_background_432x432="" +launcher_icons/adaptive_monochrome_432x432="" graphics/opengl_debug=false xr_features/xr_mode=0 -xr_features/hand_tracking=0 -xr_features/hand_tracking_frequency=0 -xr_features/passthrough=0 screen/immersive_mode=true screen/support_small=true screen/support_normal=true @@ -334,7 +504,7 @@ permissions/location_hardware=false permissions/manage_accounts=false permissions/manage_app_tokens=false permissions/manage_documents=false -permissions/manage_external_storage=false +permissions/manage_external_storage=true permissions/master_clear=false permissions/media_content_control=false permissions/modify_audio_settings=false @@ -343,11 +513,12 @@ permissions/mount_format_filesystems=false permissions/mount_unmount_filesystems=false permissions/nfc=false permissions/persistent_activity=false +permissions/post_notifications=false permissions/process_outgoing_calls=false permissions/read_calendar=false permissions/read_call_log=false permissions/read_contacts=false -permissions/read_external_storage=true +permissions/read_external_storage=false permissions/read_frame_buffer=false permissions/read_history_bookmarks=false permissions/read_input_state=false @@ -398,7 +569,7 @@ permissions/write_apn_settings=false permissions/write_calendar=false permissions/write_call_log=false permissions/write_contacts=false -permissions/write_external_storage=true +permissions/write_external_storage=false permissions/write_gservices=false permissions/write_history_bookmarks=false permissions/write_profile=false @@ -408,3 +579,6 @@ permissions/write_sms=false permissions/write_social_stream=false permissions/write_sync_settings=false permissions/write_user_dictionary=true +xr_features/hand_tracking=0 +xr_features/hand_tracking_frequency=0 +xr_features/passthrough=0 diff --git a/exports/.gitkeep b/exports/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/globals.gd b/globals.gd index 6e0b888..63147d0 100644 --- a/globals.gd +++ b/globals.gd @@ -42,7 +42,7 @@ var show_y_symmetry_axis := false # Preferences var pressure_sensitivity_mode = PressureSensitivity.NONE var smooth_zoom := true - +var zoom_speed : float = 0.06 const DEFAULT_CONFIG = { locale = "", @@ -79,4 +79,3 @@ func get_config(key : String): func set_config(key : String, value): config.set_value("config", key, value) - diff --git a/graph_only_layout.tres b/graph_only_layout.tres new file mode 100644 index 0000000..7f492c6 --- /dev/null +++ b/graph_only_layout.tres @@ -0,0 +1,16 @@ +[gd_resource type="Resource" script_class="DockableLayout" load_steps=4 format=3 uid="uid://0wfawbv87br4"] + +[ext_resource type="Script" path="res://addons/dockable_container/layout_panel.gd" id="1_wa32f"] +[ext_resource type="Script" path="res://addons/dockable_container/layout.gd" id="2_q7cvn"] + +[sub_resource type="Resource" id="Resource_wpevk"] +resource_name = "Tabs" +script = ExtResource("1_wa32f") +names = PackedStringArray("Graph", "Tool Settings", "Project Settings", "Layers Panel", "Layer Inspector") +current_tab = 0 + +[resource] +resource_name = "Layout" +script = ExtResource("2_q7cvn") +root = SubResource("Resource_wpevk") +hidden_tabs = {} diff --git a/normal_editor_layout.tres b/normal_editor_layout.tres old mode 100755 new mode 100644 index 4145f02..1c6c81d --- a/normal_editor_layout.tres +++ b/normal_editor_layout.tres @@ -4,25 +4,25 @@ [ext_resource type="Script" path="res://addons/dockable_container/layout_split.gd" id="2_8i02r"] [ext_resource type="Script" path="res://addons/dockable_container/layout.gd" id="3_8rp8x"] -[sub_resource type="Resource" id="Resource_hkcbp"] +[sub_resource type="Resource" id="Resource_s7ili"] resource_name = "Tabs" script = ExtResource("1_dbddf") names = PackedStringArray("Tool Settings") current_tab = 0 -[sub_resource type="Resource" id="Resource_7gslx"] +[sub_resource type="Resource" id="Resource_bns8w"] resource_name = "Tabs" script = ExtResource("1_dbddf") names = PackedStringArray("Project Settings") current_tab = 0 -[sub_resource type="Resource" id="Resource_m10rm"] +[sub_resource type="Resource" id="Resource_ll4ba"] resource_name = "Split" script = ExtResource("2_8i02r") direction = 1 percent = 0.5 -first = SubResource("Resource_hkcbp") -second = SubResource("Resource_7gslx") +first = SubResource("Resource_s7ili") +second = SubResource("Resource_bns8w") [sub_resource type="Resource" id="Resource_gt0nj"] resource_name = "Tabs" @@ -30,25 +30,25 @@ script = ExtResource("1_dbddf") names = PackedStringArray("Graph") current_tab = 0 -[sub_resource type="Resource" id="Resource_1v1i3"] +[sub_resource type="Resource" id="Resource_dvmfv"] resource_name = "Tabs" script = ExtResource("1_dbddf") names = PackedStringArray("Layers Panel") current_tab = 0 -[sub_resource type="Resource" id="Resource_7jwmo"] +[sub_resource type="Resource" id="Resource_hy0k8"] resource_name = "Tabs" script = ExtResource("1_dbddf") names = PackedStringArray("Layer Inspector") current_tab = 0 -[sub_resource type="Resource" id="Resource_xlcfl"] +[sub_resource type="Resource" id="Resource_alysv"] resource_name = "Split" script = ExtResource("2_8i02r") direction = 1 percent = 0.5 -first = SubResource("Resource_1v1i3") -second = SubResource("Resource_7jwmo") +first = SubResource("Resource_dvmfv") +second = SubResource("Resource_hy0k8") [sub_resource type="Resource" id="Resource_26d7r"] resource_name = "Split" @@ -56,18 +56,18 @@ script = ExtResource("2_8i02r") direction = 0 percent = 0.75 first = SubResource("Resource_gt0nj") -second = SubResource("Resource_xlcfl") +second = SubResource("Resource_alysv") [sub_resource type="Resource" id="Resource_siokk"] resource_name = "Split" script = ExtResource("2_8i02r") direction = 0 percent = 0.2 -first = SubResource("Resource_m10rm") +first = SubResource("Resource_ll4ba") second = SubResource("Resource_26d7r") [resource] -resource_name = "default_layout" +resource_name = "Layout" script = ExtResource("3_8rp8x") root = SubResource("Resource_siokk") hidden_tabs = {} diff --git a/project.godot b/project.godot index d2036ec..1651972 100644 --- a/project.godot +++ b/project.godot @@ -12,8 +12,9 @@ config_version=5 config/name="My Touch" run/main_scene="res://editor.tscn" -config/features=PackedStringArray("4.2") +config/features=PackedStringArray("4.4") run/low_processor_mode=true +boot_splash/image="res://iconbanner.png" config/icon="res://icon.png" config/macos_native_icon="res://icon.png" config/windows_native_icon="res://icon.png" @@ -28,22 +29,6 @@ TaskManager="*res://task_manager.gd" [debug] -gdscript/warnings/unassigned_variable=2 -gdscript/warnings/unassigned_variable_op_assign=2 -gdscript/warnings/unused_variable=2 -gdscript/warnings/unused_local_constant=2 -gdscript/warnings/unused_private_class_variable=2 -gdscript/warnings/unused_parameter=2 -gdscript/warnings/unused_signal=2 -gdscript/warnings/unreachable_code=2 -gdscript/warnings/unreachable_pattern=2 -gdscript/warnings/standalone_expression=2 -gdscript/warnings/standalone_ternary=2 -gdscript/warnings/incompatible_ternary=2 -gdscript/warnings/property_used_as_function=2 -gdscript/warnings/constant_used_as_function=2 -gdscript/warnings/function_used_as_property=2 -gdscript/warnings/unsafe_void_return=2 gdscript/warnings/static_called_on_instance=2 gdscript/warnings/redundant_static_unload=2 gdscript/warnings/redundant_await=2 @@ -54,12 +39,15 @@ gdscript/warnings/int_as_enum_without_cast=2 gdscript/warnings/int_as_enum_without_match=2 gdscript/warnings/empty_file=2 gdscript/warnings/deprecated_keyword=2 -gdscript/warnings/confusable_identifier=2 +gdscript/warnings/property_used_as_function=2 +gdscript/warnings/constant_used_as_function=2 +gdscript/warnings/function_used_as_property=2 [display] window/size/viewport_width=1280 window/size/viewport_height=720 +window/handheld/orientation=6 window/actual_release="0.4" [editor_plugins] @@ -76,31 +64,35 @@ import/fbx/enabled=false config/itch_username="ywmaa" config/itch_project_name="my-touch" +[gui] + +theme/default_theme_scale.mobile=1.75 + [input] move={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":71,"key_label":0,"unicode":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":71,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } rotate={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":82,"key_label":0,"unicode":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":82,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } scale={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } lock_x={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":88,"key_label":0,"unicode":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":88,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } lock_y={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":89,"key_label":0,"unicode":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":89,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } mouse_left={ @@ -110,7 +102,7 @@ mouse_left={ } delete={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194312,"key_label":0,"unicode":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194312,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } zoom_in={ @@ -126,46 +118,47 @@ zoom_out={ pan={ "deadzone": 0.5, "events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":4,"position":Vector2(143, 22),"global_position":Vector2(147, 67),"factor":1.0,"button_index":3,"canceled":false,"pressed":true,"double_click":false,"script":null) +, Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"button_mask":1,"position":Vector2(240.965, 13.7148),"global_position":Vector2(249.965, 59.7148),"factor":1.0,"button_index":1,"canceled":false,"pressed":true,"double_click":false,"script":null) ] } move_mouse_up={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194446,"key_label":0,"unicode":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194446,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } move_mouse_down={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194440,"key_label":0,"unicode":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194440,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } move_mouse_left={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194442,"key_label":0,"unicode":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194442,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } move_mouse_right={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194444,"key_label":0,"unicode":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194444,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } select_all={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } add_context_menu={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":65,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":65,"location":0,"echo":false,"script":null) ] } cancel={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } brush={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":66,"key_label":0,"unicode":98,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":66,"key_label":0,"unicode":98,"location":0,"echo":false,"script":null) ] } pencil={ @@ -174,26 +167,31 @@ pencil={ } show_tool_bar={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":84,"key_label":0,"unicode":116,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":84,"key_label":0,"unicode":116,"location":0,"echo":false,"script":null) ] } bucket={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":70,"key_label":0,"unicode":102,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":70,"key_label":0,"unicode":102,"location":0,"echo":false,"script":null) ] } crop={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":67,"key_label":0,"unicode":99,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":86,"key_label":0,"unicode":118,"location":0,"echo":false,"script":null) ] } focus={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":46,"key_label":0,"unicode":46,"echo":false,"script":null) -, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194436,"key_label":0,"unicode":46,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":46,"key_label":0,"unicode":46,"location":0,"echo":false,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194436,"key_label":0,"unicode":46,"location":0,"echo":false,"script":null) ] } +[input_devices] + +pointing/android/enable_long_press_as_right_click=true +pointing/android/enable_pan_and_scale_gestures=true + [rendering] renderer/rendering_method="mobile" diff --git a/src/layers/base_layer.gd b/src/layers/base_layer.gd index cee6c49..a12b29f 100644 --- a/src/layers/base_layer.gd +++ b/src/layers/base_layer.gd @@ -106,7 +106,7 @@ func get_scale(): -func get_layer_inspector_properties() -> Array: +func get_inspector_properties() -> Array: var PropertiesView : Array = [] var PropertiesGroups : Array[String] = [] PropertiesGroups.append("Transform") @@ -115,10 +115,9 @@ func get_layer_inspector_properties() -> Array: PropertiesToShow["position"] = "Transform" PropertiesToShow["rotation"] = "Transform" PropertiesToShow["size"] = "Transform" - PropertiesToShow["scale"] = "Transform" - PropertiesToShow["lock_aspect"] = "Transform" + PropertiesToShow["scale:lock_aspect"] = "Transform" - PropertiesToShow["opacity"] = "Visibility" + PropertiesToShow["opacity:minvalue:0.0:maxvalue:1.0:step:0.01"] = "Visibility" PropertiesToShow["affect_children_opacity"] = "Visibility" diff --git a/src/layers/image_layer.gd b/src/layers/image_layer.gd index 4edf69b..a17c82d 100644 --- a/src/layers/image_layer.gd +++ b/src/layers/image_layer.gd @@ -31,6 +31,6 @@ func refresh(): func get_copy(_name: String = "copy"): var layer = image_layer.new() layer.init(_name, image_path, parent_project, parent) - for k in get_layer_inspector_properties()[1].keys(): # Copy Properties + for k in get_inspector_properties()[1].keys(): # Copy Properties layer.set(k, get(k)) return layer diff --git a/src/layers/paint_layer.gd b/src/layers/paint_layer.gd index 6980bb9..19c646d 100644 --- a/src/layers/paint_layer.gd +++ b/src/layers/paint_layer.gd @@ -1,72 +1,67 @@ -extends image_layer +extends base_layer class_name paint_layer -var paint_image_path : String - +var canvas : Node2D = Node2D.new() +@export var strokes: Array[Stroke] func set_position(_v): - if !image: - return - if !image.texture: - return - image.position = image.texture.get_size()/2 - emit_changed() + pass func set_rotation(_v): pass func set_size(_v): pass - +func get_size(): + return Vector2.ZERO func set_scale(_v): pass -func update_path(path:String = "./"): - paint_image_path = path.path_join(name.c_unescape() + ".png") +func init(_name: String, project:Project, parent_layer:base_layer=null): + name = _name + parent_project = project + refresh() + parent_project.layers_container.add_layer(self, parent_layer) + func _init(): type = LAYER_TYPE.BRUSH affect_children_opacity = true + main_object.draw.connect(draw) + main_object.queue_redraw() + main_object.process_thread_group = Node.PROCESS_THREAD_GROUP_SUB_THREAD + main_object.process_thread_messages = Node.FLAG_PROCESS_THREAD_MESSAGES_ALL -func save_paint_image(): - if paint_image_path: - image.texture.get_image().save_png(paint_image_path) +func draw(): + for stroke in strokes: + if !stroke.need_redraw: + continue + if !stroke.stroke_node: + stroke.stroke_node = Node2D.new() + main_object.add_child(stroke.stroke_node) + stroke.stroke_node.draw.connect(func(): stroke.draw(stroke.stroke_node)) + stroke.stroke_node.queue_redraw() + stroke.need_redraw = false + #print("stroke id ", strokes.find(stroke), " redraw") -func canvas_changed(_prev:Vector2, new:Vector2): - var prev_image = texture.get_image() - prev_image.crop(new.x,new.y) - prev_image.save_png(paint_image_path) - texture.set_image(prev_image) - position = Vector2.ZERO #Just Invoking the setter, no need to assign a value func get_canvas_node() -> Node: - if image == null: + if canvas == null: return null - return image + return canvas func refresh(): - update_path(parent_project.project_folder_abs_path + "/") - if !parent_project.is_connected("canvas_size_changed",canvas_changed): - parent_project.connect("canvas_size_changed",canvas_changed) - var load_test : Error = Image.new().load(paint_image_path) - if load_test == OK: - var load_image = Image.load_from_file(paint_image_path) - texture.set_image(load_image) - if image: - image.texture = texture - image.name = name - position = Vector2.ZERO #Just Invoking the setter, no need to assign a value - else: - Image.create(ProjectsManager.current_project.canvas_size.x,ProjectsManager.current_project.canvas_size.y,false,Image.FORMAT_RGBA8).save_png(paint_image_path) - var load_image = Image.load_from_file(paint_image_path) - texture.set_image(load_image) - if image: - image.texture = texture - image.name = name - position = Vector2.ZERO #Just Invoking the setter, no need to assign a value - + main_object.queue_redraw() -#func get_rect() -> Rect2: +func get_copy(_name: String = "copy"): + var layer = paint_layer.new() + layer.init(_name, parent_project, parent) + for k in get_inspector_properties()[1].keys(): # Copy Properties + layer.set(k, get(k)) + layer.strokes = strokes.duplicate(true) + return layer +func get_rect() -> Rect2: + return Rect2() ## var graph : MTGraph = mt_globals.main_window.get_current_graph_edit() # var camera = graph.camera # var canvas_position : Vector2 = graph.size/2-camera.offset*(camera.zoom) diff --git a/src/layers/project_layer.gd b/src/layers/project_layer.gd index 2d8b14b..754b014 100644 --- a/src/layers/project_layer.gd +++ b/src/layers/project_layer.gd @@ -30,6 +30,6 @@ func refresh(): func get_copy(_name: String = "copy"): var layer = project_layer.new() layer.init(name, project_path, project) - for k in get_layer_inspector_properties()[1].keys(): # Copy Properties + for k in get_inspector_properties()[1].keys(): # Copy Properties layer.set(k, get(k)) return layer diff --git a/src/layers/selection_layer.gd b/src/layers/selection_layer.gd index cd43581..fe74747 100644 --- a/src/layers/selection_layer.gd +++ b/src/layers/selection_layer.gd @@ -21,8 +21,8 @@ var shader : shape_generator.shader_type: get: return image.shader -func get_layer_inspector_properties() -> Array: - var PropertiesView : Array = super.get_layer_inspector_properties() +func get_inspector_properties() -> Array: + var PropertiesView : Array = super.get_inspector_properties() PropertiesView[0].append("Shape Properties") var PropertiesToShow : Dictionary = {} PropertiesToShow["color"] = "Shape Properties" diff --git a/src/layers/sprite_2d_with_collision.tscn b/src/layers/sprite_2d_with_collision.tscn deleted file mode 100644 index 0b6d4f9..0000000 --- a/src/layers/sprite_2d_with_collision.tscn +++ /dev/null @@ -1,26 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://cov61abrpbyjc"] - -[sub_resource type="RectangleShape2D" id="RectangleShape2D_jl2uf"] -size = Vector2(512, 512) - -[sub_resource type="GDScript" id="GDScript_s17dl"] -script/source = "extends CollisionShape2D - -@onready var sprite_2d = $\"../..\" - -#func _ready(): - #get_parent().mouse_entered.connect(mouse_enter) -#func _process(_delta): - #if sprite_2d.texture: - #shape.size = sprite_2d.get_rect().size# * sprite_2d.scale -#func mouse_enter(): - #print(\"mouse\") -" - -[node name="Sprite2D" type="Sprite2D"] - -[node name="Area2D" type="Area2D" parent="."] - -[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"] -shape = SubResource("RectangleShape2D_jl2uf") -script = SubResource("GDScript_s17dl") diff --git a/src/layers/stroke.gd b/src/layers/stroke.gd new file mode 100644 index 0000000..9d53603 --- /dev/null +++ b/src/layers/stroke.gd @@ -0,0 +1,68 @@ +extends Resource +class_name Stroke + +enum TYPE {CIRCLE, LINE, RECTANGLE, TEXTURE, PIXEL} +@export var type : TYPE = TYPE.CIRCLE +@export var points : PackedVector2Array = [] +@export var size : PackedFloat32Array #= 1.0 +@export var color : PackedColorArray# = Color.BLACK +#@export var texture : Texture2D +@export var aliasing : bool +var stroke_node: Node2D = Node2D.new() +var need_redraw: bool = true + +func add_point(p_point:Vector2, p_color:Color, p_size:float): + if points.has(p_point): + return + match type: + TYPE.CIRCLE: + points.append(p_point) + size.append(p_size) + color.append(p_color) + TYPE.LINE: + points.append(p_point) + size.append(p_size) + color.append(p_color) + TYPE.PIXEL: + points.append(p_point) + color.append(p_color) + +func remove_point(index:int): + match type: + TYPE.CIRCLE: + points.remove_at(index) + size.remove_at(index) + color.remove_at(index) + TYPE.LINE: + points.remove_at(index) + size.remove_at(index) + color.remove_at(index) + if index-1 == -1: + return + size[index-1] = 0 + TYPE.PIXEL: + points.remove_at(index) + color.remove_at(index) + +func draw(draw_node: CanvasItem, starting_index:int=0): + match type: + TYPE.CIRCLE: + for i in points.size(): + if i < starting_index: + continue + draw_node.draw_circle(points[i], size[i], color[i]) + TYPE.LINE: + for i in points.size(): + if i < starting_index: + continue + var next_point = i+1 if i < points.size()-1 else i + draw_node.draw_line(points[i], points[next_point], color[i], size[i], aliasing) + TYPE.TEXTURE: + for i in points.size(): + pass + #draw_node.draw_texture_rect_region(texture, points[i], color[i]) + TYPE.PIXEL: + for i in points.size(): + if i < starting_index: + continue + draw_node.draw_rect(Rect2(points[i], Vector2.ONE), color[i]) diff --git a/src/layers/text_layer.gd b/src/layers/text_layer.gd index b2d3166..b02198b 100644 --- a/src/layers/text_layer.gd +++ b/src/layers/text_layer.gd @@ -11,8 +11,8 @@ var text_label : RichTextLabel = RichTextLabel.new() return text_label.text -func get_layer_inspector_properties() -> Array: - var PropertiesView : Array = super.get_layer_inspector_properties() +func get_inspector_properties() -> Array: + var PropertiesView : Array = super.get_inspector_properties() PropertiesView[0].append("Text Properties") var PropertiesToShow : Dictionary = {} PropertiesToShow["text"] = "Text Properties" @@ -45,7 +45,7 @@ func refresh(): func get_copy(_name: String = "copy"): var layer = text_layer.new() layer.init(_name, parent_project, parent) - for k in get_layer_inspector_properties()[1].keys(): # Copy Properties + for k in get_inspector_properties()[1].keys(): # Copy Properties layer.set(k, get(k)) return layer diff --git a/src/projects/projects_manager.gd b/src/projects/projects_manager.gd index 29a37aa..caead0a 100644 --- a/src/projects/projects_manager.gd +++ b/src/projects/projects_manager.gd @@ -52,6 +52,12 @@ func close_project(index:int): current_project = null projects.clear() +func on_import_image_clipboard(): + if !current_project: + return + var new_image_path : String = current_project.project_folder_abs_path + "/" + current_project.layers_container.get_unused_layer_name() + ".png" + DisplayServer.clipboard_get_image().save_png(new_image_path) + image_layer.new().init(current_project.layers_container.get_unused_layer_name(), new_image_path.get_file(), current_project) @@ -142,11 +148,11 @@ func save_selection() -> void: if !current_project: return var dialog = preload("res://UI/windows/file_dialog/file_dialog.tscn").instantiate() - add_child(dialog) dialog.min_size = Vector2(500, 500) dialog.access = FileDialog.ACCESS_FILESYSTEM dialog.file_mode = FileDialog.FILE_MODE_SAVE_FILE dialog.add_filter("*.mt.tres;My Touch text files") + add_child(dialog) if mt_globals.config.has_section_key("path", "current_project"): dialog.current_dir = mt_globals.config.get_value("path", "current_project") var files = await dialog.select_files() @@ -223,12 +229,12 @@ func save_as() -> bool: return false #replace with preload var dialog = preload("res://UI/windows/file_dialog/file_dialog.tscn").instantiate() - add_child(dialog) + #add_child(dialog) dialog.min_size = Vector2(500, 500) dialog.access = FileDialog.ACCESS_FILESYSTEM dialog.file_mode = FileDialog.FILE_MODE_SAVE_FILE dialog.add_filter("*.mt.tres;My Touch text files") - + add_child(dialog) if mt_globals.config.has_section_key("path", "current_project"): dialog.current_dir = mt_globals.config.get_value("path", "current_project") var files = await dialog.select_files() @@ -260,6 +266,14 @@ func send_changed_signal() -> void: current_project.need_save = true +func can_undo() -> bool: + if !current_project: + return false + return current_project.undo_redo.has_undo() +func can_redo() -> bool: + if !current_project: + return false + return current_project.undo_redo.has_redo() func undo(): if !current_project: @@ -273,4 +287,3 @@ func redo(): current_project.undo_redo.redo() get_node("/root/Editor/MessageLabel").show_message("Current Step : " + str(current_project.undo_redo.get_current_action() + 1)) - diff --git a/src/tools/brush_tool.gd b/src/tools/brush_tool.gd index d735f63..ec7ea3e 100644 --- a/src/tools/brush_tool.gd +++ b/src/tools/brush_tool.gd @@ -3,22 +3,26 @@ extends ToolBase enum { BRUSH_DRAW, BRUSH_ERASE, + BRUSH_PENCIL, BRUSH_CLONE, BRUSH_SHADING, BRUSH_NORMALMAP, } -@export_enum("Draw", "Erase", "Clone", "Normal Map") var brush_type := 0 -@export var chunk_count : int = 1 +var brush_type := 0: + set(v): + brush_type = v + update_tool_ui.call_deferred() + @export var crosshair_color := Color(1.0, 1.0, 1.0, 1.0) +@export var crosshair_size := 3 +@export var crosshair_size_ruler := 32 -var chunk_size := Vector2i(960, 540) var brushsize := 20.0: set(x): brushsize = x brush_offset = Vector2(0.5, 0.5) * float(int(x) % 2) - var brush_offset := Vector2(0.5, 0.5) var hardness := 1.0 var opacity : float = 1.0 @@ -29,40 +33,48 @@ var pen_pressure_usage : pen_flag = pen_flag.size var drawing_color1 := Color() var drawing_color2 := Color() var switch_color_function : Callable = switch_color -var last_edits_chunks := {} -var last_edits_textures := {} + +var ruler_mode := false +var jaggies_removal := true var edited_object -var EditedImage : Image func _init(): tool_name = "Brush Tool" tool_button_shortcut = "Shift+B" tool_desc = "" tool_icon = get_icon_from_project_folder("brush") -func get_tool_inspector_properties(): +func get_inspector_properties(): var PropertiesView : Array = [] var PropertiesGroups : Array[String] = [] PropertiesGroups.append("Settings") - if brush_type == 0 or brush_type == 1: + if brush_type == BRUSH_DRAW or brush_type == BRUSH_ERASE or brush_type == BRUSH_PENCIL: PropertiesGroups.append("Color") + if brush_type == BRUSH_PENCIL: + PropertiesGroups.append("Pencil") var PropertiesToShow : Dictionary = {} - if brush_type == 0 or brush_type == 1: - PropertiesToShow["brush_type,Draw,Erase"] = "Settings" - if brush_type == 2: + if brush_type == BRUSH_DRAW or brush_type == BRUSH_ERASE or brush_type == BRUSH_PENCIL: + PropertiesToShow["brush_type,Draw,Erase,Pencil"] = "Settings" + if brush_type == BRUSH_CLONE: PropertiesToShow["copy_from_whole_canvas"] = "Settings" - PropertiesToShow["brushsize:minvalue:1.0:maxvalue:1024.0:step:1.0"] = "Settings" + if brush_type != BRUSH_PENCIL: + PropertiesToShow["brushsize:minvalue:1.0:maxvalue:1024.0:step:1.0"] = "Settings" PropertiesToShow["hardness:minvalue:0.0:maxvalue:1.0:step:0.01"] = "Settings" PropertiesToShow["opacity:minvalue:0.0:maxvalue:1.0:step:0.01"] = "Settings" PropertiesToShow["pen_pressure_usage,size,opacity,tint"] = "Settings" - if brush_type == 0 or brush_type == 1: + if brush_type == BRUSH_DRAW or brush_type == BRUSH_ERASE or brush_type == BRUSH_PENCIL: PropertiesToShow["drawing_color1"] = "Color" PropertiesToShow["drawing_color2"] = "Color" PropertiesToShow["switch_color_function"] = "Color" + if brush_type == BRUSH_PENCIL: + PropertiesToShow["ruler_mode"] = "Pencil" + PropertiesToShow["jaggies_removal"] = "Pencil" + PropertiesView.append(PropertiesGroups) PropertiesView.append(PropertiesToShow) return PropertiesView - +func update_tool_ui(): + changed.emit() func switch_color(): var color1 : Color = drawing_color1 drawing_color1 = drawing_color2 @@ -100,90 +112,58 @@ func mouse_pressed( func enable_tool(): # Save History and Enable Tool - edited_object = ToolsManager.get_paint_layer() - EditedImage = edited_object.image.texture.get_image() - start_drawing(EditedImage, ToolsManager.current_mouse_position) - -# ToolsManager.current_project.undo_redo.create_action("Move Layers") -# for selected in ToolsManager.current_project.layers_container.selected_layers: -# ToolsManager.current_project.undo_redo.add_undo_property(selected,"position",selected.position) + edited_object = ToolsManager.get_paint_layer() as paint_layer + start_drawing(ToolsManager.current_mouse_position) super.enable_tool() func cancel_tool(): # Redo Actions -# if ToolsManager.current_project.layers_container.selected_layers: -# for selected in ToolsManager.current_project.layers_container.selected_layers: -# ToolsManager.current_project.undo_redo.add_do_property(selected, "position", selected.position) -# ToolsManager.current_project.undo_redo.commit_action() -# for selected in ToolsManager.current_project.layers_container.selected_layers: -# ToolsManager.current_project.undo_redo.undo() super.cancel_tool() func confirm_tool(): # Confirm Actions - - - if brush_type == BRUSH_ERASE: - var worker = TaskManager.create_task(apply_eraser.bind(EditedImage)) - paint_threads.append(worker) - TaskManager.create_task(apply_texture) -# if EditedImage: -# EditedImage.save_png(ToolsManager.current_project.layers_container.selected_layers[0].image_path) -# ToolsManager.current_project.layers_container.selected_layers[0].texture = ImageTexture.create_from_image(EditedImage) -# ToolsManager.current_project.layers_container.selected_layers[0].image.texture = ToolsManager.current_project.layers_container.selected_layers[0].texture -# if ToolsManager.current_project.layers_container.selected_layers: -# for selected in ToolsManager.current_project.layers_container.selected_layers: -# ToolsManager.current_project.undo_redo.add_do_property(selected, "position", selected.position) -# ToolsManager.current_project.undo_redo.commit_action() - super.confirm_tool() -func apply_texture(): - for thread in paint_threads: - thread.wait() - paint_threads.clear() if brush_type != BRUSH_ERASE: - apply_brush(EditedImage) - if edited_object: - edited_object.image.texture.update(EditedImage) #= ImageTexture.create_from_image(EditedImage) - edited_object.save_paint_image() -func start_drawing(image, _start_pos): - # Break the image up into tiles - small images are faster to edit. - last_stroke_pos = _start_pos - chunk_size = image.get_size()/chunk_count - for i in ceil(float(image.get_width()) / chunk_size.x): - for j in ceil(float(image.get_height()) / chunk_size.y): - last_edits_chunks[Vector2i(i, j) * chunk_size] = Image.create( - chunk_size.x, chunk_size.y, - false, image.get_format() - ) - for k in last_edits_chunks: - last_edits_textures[k] = ImageTexture.create_from_image(last_edits_chunks[k]) - # Copy the image to the tiles. Worse opacity handling, - # but with more work can make eraser editing more performant and previewable. - # last_edits_chunks[k].blit_rect(image, Rect2i(k, chunk_size), Vector2i.ZERO) - - -func apply_brush(image): - for k in last_edits_chunks: - image.blend_rect( - last_edits_chunks[k], - Rect2i(Vector2i.ZERO, chunk_size), - k - ) + current_stroke.need_redraw = true + edited_object.main_object.queue_redraw() + else: + pass + #var undo_redo : UndoRedo = ToolsManager.current_project.undo_redo + #undo_redo.add_do_property(edited_object, "strokes", edited_object.strokes.duplicate(true)) + #undo_redo.add_do_method(edited_object.main_object.queue_redraw) + #undo_redo.add_undo_method(func(): for stroke in edited_object.strokes: stroke.need_redraw=true) + #undo_redo.add_undo_method(edited_object.main_object.queue_redraw) + #undo_redo.commit_action(false) + super.confirm_tool() -func apply_eraser(image): - # Cutting off a smaller image does not increase performance. - # Must find another way - erasing is very slow. - paint_mutex.lock() - var pos - for k in last_edits_chunks: - var chunk = last_edits_chunks[k] - var height = mini(image.get_height() - k.y, chunk.get_height()) - for i in mini(image.get_width() - k.x, chunk.get_width()): - for j in height: - pos = Vector2i(i + k.x, j + k.y) - chunk.set_pixel( - i, j, - image.get_pixelv(pos) - chunk.get_pixel(i, j) - ) - image.blit_rect(last_edits_chunks[k], Rect2i(Vector2i.ZERO, chunk_size), k) - paint_mutex.unlock() +func start_drawing(_start_pos): + last_stroke_pos = _start_pos + + + if brush_type != BRUSH_ERASE: + current_stroke = Stroke.new() + last_drawn_index = 0 + var undo_redo : UndoRedo = ToolsManager.current_project.undo_redo + undo_redo.create_action("Brush Stroke") + + undo_redo.add_undo_property(edited_object, "strokes", edited_object.strokes.duplicate()) + edited_object.strokes.append(current_stroke) + undo_redo.add_do_property(edited_object, "strokes", edited_object.strokes.duplicate()) + + undo_redo.add_do_method(edited_object.main_object.add_child.bind(current_stroke.stroke_node)) + undo_redo.add_do_reference(current_stroke.stroke_node) + undo_redo.add_do_method(edited_object.main_object.queue_redraw) + + undo_redo.add_undo_method(edited_object.main_object.remove_child.bind(current_stroke.stroke_node)) + undo_redo.add_undo_method(edited_object.main_object.queue_redraw) + + undo_redo.commit_action(false) + else: + pass + #var undo_redo : UndoRedo = ToolsManager.current_project.undo_redo + #undo_redo.create_action("Erase Stroke") + #undo_redo.add_undo_property(edited_object, "strokes", edited_object.strokes.duplicate(true)) + + if brush_type == BRUSH_PENCIL: + current_stroke.type = Stroke.TYPE.LINE + else: + current_stroke.type = Stroke.TYPE.CIRCLE #var cached_to_draw_mouse_moves : PackedVector2Array func mouse_moved(event : InputEventMouseMotion): @@ -191,74 +171,37 @@ func mouse_moved(event : InputEventMouseMotion): return if !edited_object: return - if ToolsManager.mouse_position_delta.length() > 0.0: - var object_correction = edited_object.image.position-edited_object.size/2 - var stroke_end :Vector2 = ToolsManager.current_mouse_position-object_correction - if last_stroke_pos == null: - last_stroke_pos = stroke_end -# cached_to_draw_mouse_moves.append(stroke_end) - if stroke_end.distance_to(last_stroke_pos) < (brushsize * 0.5) and (ToolsManager.effect_scaling_factor == 0.25 or brushsize > 200.0): + #if ToolsManager.mouse_position_delta.length() > 0.0: + var pt_count = max(abs(event.relative.x), abs(event.relative.y)) + var lerp_step = 0.01 / pt_count + for i in pt_count: + var point : Vector2 = ToolsManager.current_mouse_position - event.relative * lerp_step * i + var draw_pos = last_stroke_pos.lerp(point,0.05) if ToolsManager.effect_scaling_factor == 0.25 else point + if draw_pos.distance_to(last_stroke_pos) < (brushsize * 0.25): # So we don't draw on the same place return -# for v in cached_to_draw_mouse_moves: - var draw_pos = last_stroke_pos.lerp(stroke_end,0.1) if ToolsManager.effect_scaling_factor == 0.25 and brushsize < 200.0 else stroke_end if event.button_mask & MOUSE_BUTTON_MASK_LEFT != 0.0: - stroke(last_stroke_pos, draw_pos, event.pressure) + stroke(draw_pos, event.pressure) else: - stroke(last_stroke_pos, draw_pos, 1.0) + stroke(draw_pos, 1.0) last_stroke_pos = draw_pos -# cached_to_draw_mouse_moves.clear() -var cached_pixels : PackedVector2Array = [] -var solid_color_rect : Rect2i -var paint_mutex : Mutex = Mutex.new() +var current_stroke : Stroke var last_stroke_pos : Vector2 -var paint_threads : Array = [] -func stroke(stroke_start:Vector2, stroke_end:Vector2, pressure): - +var cached_pixels : PackedVector2Array = [] +var solid_color_rect : Rect2i +var points_to_remove: PackedInt32Array = [] +func stroke(point:Vector2, pressure): var unsolid_radius : float = (brushsize * 0.5) * (1.0 - hardness) var radius : float = (brushsize * 0.5) * (pressure if pen_pressure_usage == pen_flag.size else 1.0) var solid_radius : float = radius - unsolid_radius - - #Chunks - var rect = Rect2i(stroke_start, Vector2.ZERO)\ - .expand(stroke_end)\ - .grow(brushsize * 0.5 + 1) - - rect = Rect2i(rect.position / chunk_size, rect.end / chunk_size) - var key - var keyf - for i in rect.size.x + 1: - for j in rect.size.y + 1: - key = (rect.position + Vector2i(i, j)) * chunk_size - keyf = Vector2(key) - if !last_edits_chunks.has(key): continue - TaskManager.create_task( - paint.bind( - last_edits_chunks[key], - stroke_end - keyf, - pressure, - radius, - solid_radius - ) - ,true - ,"Paint Process" - ) - - - -func paint(on_image, stroke_end:Vector2, pressure:float , radius:float, solid_radius:float): - paint_mutex.lock() - - get_all_brush_pixels(radius, solid_radius) - - + if current_stroke.type == Stroke.TYPE.PIXEL: + get_all_brush_pixels(radius, solid_radius) var color : Color if brush_type == BRUSH_ERASE: - color = Color.BLACK + color = Color(1,0,0,0.05) elif pen_pressure_usage == pen_flag.tint: color = lerp(drawing_color2, drawing_color1, pressure) - else: color = drawing_color1 @@ -266,46 +209,47 @@ func paint(on_image, stroke_end:Vector2, pressure:float , radius:float, solid_ra if pen_pressure_usage == pen_flag.opacity: color.a *= pressure - stroke_end = stroke_end.floor() #+ Vector2(0.5, 0.5) - -# var begin = Time.get_ticks_msec() - var edited_image_size : Vector2i = EditedImage.get_size() - if brush_type == BRUSH_DRAW or brush_type == BRUSH_ERASE: - on_image.fill_rect(Rect2i(solid_color_rect.position-Vector2i(2,2)+Vector2i(stroke_end),solid_color_rect.size+Vector2i(4,4)), color) - - var worker = TaskManager.create_group_task(set_pixels.bind(on_image, color, stroke_end, radius, solid_radius, edited_image_size),cached_pixels.size(),-1 ,true) - worker.wait() -# for pixel in cached_pixels: -# var cur_pos = stroke_end+pixel -# if cur_pos.x < 0 or cur_pos.y < 0: -# return -# if cur_pos.x >= chunk_size.x or cur_pos.y >= chunk_size.y or cur_pos.x >= edited_image_size.x or cur_pos.y >= edited_image_size.y: -# return -# -# on_image.set_pixelv(cur_pos, get_new_pixel( -# on_image, color, -# stroke_end, cur_pos, -# radius, solid_radius -# )) - - - for k in last_edits_chunks: - last_edits_textures[k].update(last_edits_chunks[k]) - - paint_mutex.unlock() + #point = point.floor() #+ Vector2(0.5, 0.5) + if brush_type != BRUSH_ERASE: + match current_stroke.type: + Stroke.TYPE.CIRCLE: + current_stroke.add_point(point, color, radius) + Stroke.TYPE.LINE: + current_stroke.add_point(point, color, radius) + current_stroke.aliasing = jaggies_removal + Stroke.TYPE.PIXEL: + for p in cached_pixels: + current_stroke.add_point(point+p, color, radius) + current_stroke.aliasing = jaggies_removal + else: + #var undo_redo : UndoRedo = ToolsManager.current_project.undo_redo + + for stroke in edited_object.strokes: + points_to_remove.clear() + for i in stroke.points.size(): + if stroke.points[i].distance_squared_to(point) < radius*radius: + stroke.need_redraw = true + var point_color : Color = stroke.color[i] + point_color.a = clampf(point_color.a - opacity, 0.0, 1.0) + if point_color.a == 0: + points_to_remove.append(i) + else: + stroke.color[i] = point_color + #if stroke.need_redraw: + #var stroke_index : int = edited_object.strokes.find(stroke) + #undo_redo.add_do_method(set_stroke_to_redraw.bind(stroke_index)) + #undo_redo.add_undo_method(func(): print(stroke_index);set_stroke_to_redraw(stroke_index)) + var iter : int = 0 + for i in points_to_remove: + i -= iter + stroke.remove_point(i) + edited_object.main_object.queue_redraw() + iter += 1 + #for j in points_to_remove: + +func set_stroke_to_redraw(index:int): + edited_object.strokes[index].need_redraw=true -# print("OP Took ", Time.get_ticks_msec()-begin, "ms") -func set_pixels(index:int, on_image, color: Color, stroke_end:Vector2, radius:float, solid_radius:float, edited_image_size:Vector2i): - var cur_pos = stroke_end+cached_pixels[index] - if cur_pos.x < 0 or cur_pos.y < 0: - return - if cur_pos.x >= chunk_size.x or cur_pos.y >= chunk_size.y or cur_pos.x >= edited_image_size.x or cur_pos.y >= edited_image_size.y: - return - on_image.set_pixelv(cur_pos, get_new_pixel( - on_image, color, - stroke_end, cur_pos, - radius, solid_radius - )) func get_all_brush_pixels(radius, solid_radius): cached_pixels.clear() @@ -390,41 +334,40 @@ func GetCircleSymmetry(x:int, y:int, x_center:int = 0, y_center:int = 0): pixels.append(Vector2i(x_center+y, y_center-x)) pixels.append(Vector2i(x_center-y, y_center-x)) return pixels - - - - -func get_new_pixel(on_image, color:Color, stroke_end:Vector2, cur_pos, radius:float, solid_radius:float): - var distance = stroke_end.distance_to(cur_pos) - - if distance <= solid_radius: -# var blended = old_color.blend(color) -# blended.a = max(old_color.a, color.a) - return color - var old_color = on_image.get_pixelv(cur_pos) - if distance <= radius: - var blended = old_color.blend(color) - distance = (distance - solid_radius) / (radius - solid_radius) -# Possible better handling of variable pressure, -# but creates artifacts when zig-zagging - blended.a = max(old_color.a, color.a * (1.0 - distance * distance)) -# This one also creates artifacts, but this is during normal brush usage. -# blended.a = lerp(old_color.a, color.a, (1.0 - distance * distance)) - return blended - else: - return old_color +var redraw_time : float = 5.0 +var time_since_last_redraw : float = redraw_time +var last_drawn_index : int = 0 func draw_preview(image_view : CanvasItem, mouse_position : Vector2i): + if !current_stroke: + return + time_since_last_redraw -= ToolsManager.get_process_delta_time() + if time_since_last_redraw <= 0.0: + last_drawn_index = current_stroke.points.size()-1 + current_stroke.need_redraw = true + edited_object.main_object.queue_redraw() + time_since_last_redraw = redraw_time + if edited_object and tool_active: - for k in last_edits_chunks: - image_view.draw_texture(last_edits_textures[k], (edited_object.position-edited_object.size/2)+Vector2(k)) + current_stroke.draw(image_view, last_drawn_index) - var circle_center = Vector2(mouse_position + Vector2i.ONE) - brush_offset - image_view.draw_arc(circle_center, brushsize * 0.5 + 0.5, PI * 0.1, PI * 0.9, 32, crosshair_color, 1.0) - image_view.draw_arc(circle_center, brushsize * 0.5 + 0.5, PI * 1.1, PI * 1.9, 32, crosshair_color, 1.0) - - if ToolsManager.effect_scaling_factor == 0.25: - image_view.draw_line(last_stroke_pos, mouse_position, Color.RED) + if brush_type == BRUSH_PENCIL: + if !ruler_mode: + draw_crosshair(image_view, mouse_position, crosshair_size, crosshair_color) + else: + draw_crosshair(image_view, mouse_position, crosshair_size_ruler, crosshair_color) + var diag_distance := 8 + var posf := Vector2(mouse_position) + Vector2(0.5, 0.5) + image_view.draw_line(posf + Vector2(-1, +1) * diag_distance, posf + Vector2(-1, +1) * (diag_distance + crosshair_size_ruler), crosshair_color, 1) + image_view.draw_line(posf + Vector2(+1, -1) * diag_distance, posf + Vector2(+1, -1) * (diag_distance + crosshair_size_ruler), crosshair_color, 1) + image_view.draw_line(posf + Vector2(+1, +1) * diag_distance, posf + Vector2(+1, +1) * (diag_distance + crosshair_size_ruler), crosshair_color, 1) + image_view.draw_line(posf + Vector2(-1, -1) * diag_distance, posf + Vector2(-1, -1) * (diag_distance + crosshair_size_ruler), crosshair_color, 1) + else: + var circle_center = Vector2(mouse_position + Vector2i.ONE) - brush_offset + image_view.draw_arc(circle_center, brushsize * 0.5 + 0.5, PI * 0.1, PI * 0.9, 32, crosshair_color, 1.0) + image_view.draw_arc(circle_center, brushsize * 0.5 + 0.5, PI * 1.1, PI * 1.9, 32, crosshair_color, 1.0) + if ToolsManager.effect_scaling_factor == 0.25: + image_view.draw_line(last_stroke_pos, mouse_position, Color.RED) # With region set to (0, 0, 0, 0), hides the image. # image_view.region_enabled = drawing diff --git a/src/tools/bucket_tool.gd b/src/tools/bucket_tool.gd index 22af0de..083b278 100644 --- a/src/tools/bucket_tool.gd +++ b/src/tools/bucket_tool.gd @@ -19,7 +19,7 @@ func _init(): tool_button_shortcut = "Shift+F" tool_desc = "" tool_icon = get_icon_from_project_folder("bucket") -func get_tool_inspector_properties(): +func get_inspector_properties(): var PropertiesView : Array = [] var PropertiesGroups : Array[String] = [] PropertiesGroups.append("Settings") diff --git a/src/tools/context_menu_tool.gd b/src/tools/context_menu_tool.gd old mode 100755 new mode 100644 index d5b33ea..a6840d7 --- a/src/tools/context_menu_tool.gd +++ b/src/tools/context_menu_tool.gd @@ -7,8 +7,8 @@ func _init(): tool_icon = get_icon_from_project_folder("add") -func get_tool_inspector_properties(): - printerr("Not implemented: get_tool_inspector_properties! (" + get_script().resource_path.get_file() + ")") +func get_inspector_properties(): + printerr("Not implemented: get_inspector_properties! (" + get_script().resource_path.get_file() + ")") @@ -41,5 +41,3 @@ func cancel_tool(): # Redo Actions pass func confirm_tool(): # Confirm Actions pass - - diff --git a/src/tools/crop_tool.gd b/src/tools/crop_tool.gd old mode 100755 new mode 100644 index e07ea2c..6595caf --- a/src/tools/crop_tool.gd +++ b/src/tools/crop_tool.gd @@ -3,12 +3,12 @@ extends ToolBase func _init(): tool_name = "Crop Tool" - tool_button_shortcut = "Shift+C" + tool_button_shortcut = "Shift+V" tool_desc = "" tool_icon = get_icon_from_project_folder("crop") -func get_tool_inspector_properties(): +func get_inspector_properties(): pass diff --git a/src/tools/layers_menu_tool.gd b/src/tools/layers_menu_tool.gd new file mode 100644 index 0000000..f332a35 --- /dev/null +++ b/src/tools/layers_menu_tool.gd @@ -0,0 +1,44 @@ +extends ToolBase + +func _init(): + tool_name = "layers_panel" + tool_button_shortcut = "" + tool_desc = "Show Layers Panel" + tool_icon = get_icon_from_project_folder("layers_icon") + + + +func get_inspector_properties(): + printerr("Not implemented: get_inspector_properties! (" + get_script().resource_path.get_file() + ")") + + + +func shortcut_pressed(): + pass + +func mouse_pressed( + _event : InputEventMouseButton, + _image : base_layer, + _color1 : Color = Color.BLACK, + _color2 : Color = Color.WHITE, +): + pass + + +func get_affected_rect() -> Rect2i: + pass + return Rect2i() + + +func mouse_moved(_event : InputEventMouseMotion): + pass +func draw_preview(_image_view : CanvasItem, _mouse_position : Vector2i): + pass + + +func enable_tool(): # Save History and Enable Tool + mt_globals.main_window.create_temp_layers_panel() +func cancel_tool(): # Redo Actions + pass +func confirm_tool(): # Confirm Actions + pass diff --git a/src/tools/move_tool.gd b/src/tools/move_tool.gd index 760a2b6..225ca31 100644 --- a/src/tools/move_tool.gd +++ b/src/tools/move_tool.gd @@ -11,7 +11,7 @@ func _init(): tool_icon = get_icon_from_project_folder("move") -func get_tool_inspector_properties(): +func get_inspector_properties(): pass diff --git a/src/tools/pencil_tool.gd b/src/tools/pencil_tool.gd deleted file mode 100755 index 159ceb2..0000000 --- a/src/tools/pencil_tool.gd +++ /dev/null @@ -1,133 +0,0 @@ -extends ToolBase - -@export var crosshair_color := Color(0.5, 0.5, 0.5, 0.75) -@export var crosshair_size := 3 -@export var crosshair_size_ruler := 32 - -var ruler_mode := false -var jaggies_removal := true - -var drawing_color := Color() -var drawing_positions : Array[Vector2] -var image_size := Vector2() -var last_affected_rect := Rect2i() - -var edited_object -var EditedImage : Image - -func _init(): - tool_name = "Pencil Tool" - tool_button_shortcut = "Shift+P" - tool_desc = "" - tool_icon = get_icon_from_project_folder("pencil") - drawing_positions = [] -func get_tool_inspector_properties(): - var PropertiesView : Array = [] - var PropertiesGroups : Array[String] = [] - PropertiesGroups.append("Settings") - var PropertiesToShow : Dictionary = {} - PropertiesToShow["ruler_mode"] = "Settings" - PropertiesToShow["jaggies_removal"] = "Settings" - PropertiesToShow["drawing_color"] = "Settings" - PropertiesView.append(PropertiesGroups) - PropertiesView.append(PropertiesToShow) - return PropertiesView - -func shortcut_pressed(): - if Input.is_action_just_pressed("pencil") and not Input.is_key_pressed(KEY_SHIFT) and not Input.is_key_pressed(KEY_CTRL) and not Input.is_key_pressed(KEY_ALT): - ToolsManager.shortcut_tool = self - if !tool_active: - enable_tool() - return - if tool_active: - confirm_tool() - return - if Input.is_action_just_pressed("mouse_left"): - if !tool_active and ToolsManager.current_tool == self: - enable_tool() - return - if tool_active: - confirm_tool() - return - if Input.is_action_just_pressed("cancel"): - cancel_tool() - -func mouse_pressed( - event : InputEventMouseButton, - _image : base_layer, -): - - - if event.button_index == MOUSE_BUTTON_RIGHT and tool_active: - cancel_tool() - if event.button_index == MOUSE_BUTTON_LEFT and tool_active and !event.pressed: - confirm_tool() - - if tool_active: - var object_correction = edited_object.main_object.position-edited_object.size/2 - last_affected_rect = Rect2i(ToolsManager.current_mouse_position-object_correction, Vector2i.ZERO) - _add_point(ToolsManager.current_mouse_position-object_correction) -func enable_tool(): # Save History and Enable Tool - edited_object = ToolsManager.get_paint_layer() - EditedImage = edited_object.main_object.texture.get_image() - image_size = EditedImage.get_size() - super.enable_tool() -func cancel_tool(): # Redo Actions - super.cancel_tool() -func confirm_tool(): # Confirm Actions - for x in drawing_positions: - set_image_pixelv(EditedImage, x, drawing_color) - if edited_object: - edited_object.main_object.texture.update(EditedImage) #= ImageTexture.create_from_image(EditedImage) - edited_object.save_paint_image() - drawing_positions.clear() - super.confirm_tool() - -func get_affected_rect(): - return last_affected_rect.grow_individual(0, 0, 1, 1) - - -func mouse_moved(event : InputEventMouseMotion): - if !tool_active: - return - var pt_count = max(abs(event.relative.x), abs(event.relative.y)) - var lerp_step = 1 / pt_count - var object_correction = edited_object.main_object.position-edited_object.size/2 - for i in pt_count: - _add_point(ToolsManager.current_mouse_position-object_correction + Vector2.ONE - event.relative * i * lerp_step - Vector2.ONE) - - -func _add_point(pt : Vector2): - pt = pt.floor() - if drawing_positions.size() >= 1 && drawing_positions[-1] == pt: - return - - if pt.x < 0 || pt.y < 0 || pt.x >= image_size.x || pt.y >= image_size.y: - return - - if jaggies_removal && drawing_positions.size() > 2: - var diff1 = (drawing_positions[-1] - drawing_positions[-2]).abs() - var diff2 = (pt - drawing_positions[-1]).abs() - if diff1 != diff2 && diff1.x + diff1.y + diff2.x + diff2.y == 2: - drawing_positions.pop_back() - - drawing_positions.append(pt) - last_affected_rect = last_affected_rect.expand(pt) - - -func draw_preview(image_view : CanvasItem, mouse_position : Vector2i): - if tool_active: - for x in drawing_positions: - image_view.draw_rect(Rect2(x, Vector2.ONE), drawing_color) - - if !ruler_mode: - draw_crosshair(image_view, mouse_position, crosshair_size, crosshair_color) - - else: - draw_crosshair(image_view, mouse_position, crosshair_size_ruler, crosshair_color) - var diag_distance := 8 - var posf := Vector2(mouse_position) + Vector2(0.5, 0.5) - image_view.draw_line(posf + Vector2(-1, +1) * diag_distance, posf + Vector2(-1, +1) * (diag_distance + crosshair_size_ruler), crosshair_color, 1) - image_view.draw_line(posf + Vector2(+1, -1) * diag_distance, posf + Vector2(+1, -1) * (diag_distance + crosshair_size_ruler), crosshair_color, 1) - image_view.draw_line(posf + Vector2(+1, +1) * diag_distance, posf + Vector2(+1, +1) * (diag_distance + crosshair_size_ruler), crosshair_color, 1) - image_view.draw_line(posf + Vector2(-1, -1) * diag_distance, posf + Vector2(-1, -1) * (diag_distance + crosshair_size_ruler), crosshair_color, 1) diff --git a/src/tools/properties_menu_tool.gd b/src/tools/properties_menu_tool.gd new file mode 100644 index 0000000..a147833 --- /dev/null +++ b/src/tools/properties_menu_tool.gd @@ -0,0 +1,44 @@ +extends ToolBase + +func _init(): + tool_name = "layer_properties" + tool_button_shortcut = "" + tool_desc = "Show Layer Properties" + tool_icon = get_icon_from_project_folder("properties_settings_icon") + + + +func get_inspector_properties(): + printerr("Not implemented: get_inspector_properties! (" + get_script().resource_path.get_file() + ")") + + + +func shortcut_pressed(): + pass + +func mouse_pressed( + _event : InputEventMouseButton, + _image : base_layer, + _color1 : Color = Color.BLACK, + _color2 : Color = Color.WHITE, +): + pass + + +func get_affected_rect() -> Rect2i: + pass + return Rect2i() + + +func mouse_moved(_event : InputEventMouseMotion): + pass +func draw_preview(_image_view : CanvasItem, _mouse_position : Vector2i): + pass + + +func enable_tool(): # Save History and Enable Tool + mt_globals.main_window.create_temp_properties_panel() +func cancel_tool(): # Redo Actions + pass +func confirm_tool(): # Confirm Actions + pass diff --git a/src/tools/redo_tool_button.gd b/src/tools/redo_tool_button.gd new file mode 100644 index 0000000..15e0f2f --- /dev/null +++ b/src/tools/redo_tool_button.gd @@ -0,0 +1,44 @@ +extends ToolBase + +func _init(): + tool_name = "redo" + tool_button_shortcut = "" + tool_desc = "Redo" + tool_icon = get_icon_from_project_folder("redo") + + +func get_inspector_properties(): + printerr("Not implemented: get_inspector_properties! (" + get_script().resource_path.get_file() + ")") + + + +func shortcut_pressed(): + pass + +func mouse_pressed( + _event : InputEventMouseButton, + _image : base_layer, + _color1 : Color = Color.BLACK, + _color2 : Color = Color.WHITE, +): + pass + + +func get_affected_rect() -> Rect2i: + pass + return Rect2i() + + +func mouse_moved(_event : InputEventMouseMotion): + pass +func draw_preview(_image_view : CanvasItem, _mouse_position : Vector2i): + pass + +func is_tool_disabled() -> bool: + return mt_globals.main_window.edit_redo_is_disabled() +func enable_tool(): # Save History and Enable Tool + mt_globals.main_window.edit_redo() +func cancel_tool(): # Redo Actions + pass +func confirm_tool(): # Confirm Actions + pass diff --git a/src/tools/rotate_tool.gd b/src/tools/rotate_tool.gd index edf7cd6..57611a3 100644 --- a/src/tools/rotate_tool.gd +++ b/src/tools/rotate_tool.gd @@ -7,7 +7,7 @@ func _init(): tool_icon = get_icon_from_project_folder("rotate") -func get_tool_inspector_properties(): +func get_inspector_properties(): pass @@ -83,6 +83,3 @@ func confirm_tool(): # Confirm Actions func rotate(object, rotation_amount:float): object.rotation += rotation_amount *ToolsManager.effect_scaling_factor - - - diff --git a/src/tools/scale_tool.gd b/src/tools/scale_tool.gd index 3a45a29..29bd5fb 100644 --- a/src/tools/scale_tool.gd +++ b/src/tools/scale_tool.gd @@ -11,7 +11,7 @@ func _init(): tool_icon = get_icon_from_project_folder("scale") -func get_tool_inspector_properties(): +func get_inspector_properties(): pass @@ -123,4 +123,3 @@ func lock_y(): direction = coordinates.xy else: direction = coordinates.y - diff --git a/src/tools/select_tool.gd b/src/tools/select_tool.gd index 212c2b4..2bc2c15 100644 --- a/src/tools/select_tool.gd +++ b/src/tools/select_tool.gd @@ -34,7 +34,7 @@ func erase(): func invert(): print("test") -func get_tool_inspector_properties(): +func get_inspector_properties(): var PropertiesView : Array = [] var PropertiesGroups : Array[String] = [] PropertiesGroups.append("Settings") @@ -120,6 +120,3 @@ func confirm_tool(): # Confirm Actions ToolsManager.current_project.undo_redo.add_do_property(selected, "position", selected.position) ToolsManager.current_project.undo_redo.commit_action() super.confirm_tool() - - - diff --git a/src/tools/tool_base.gd b/src/tools/tool_base.gd old mode 100755 new mode 100644 index 4cac827..2fd1ae5 --- a/src/tools/tool_base.gd +++ b/src/tools/tool_base.gd @@ -9,6 +9,11 @@ var tool_active : bool = false var selection : BitMap @export var preview_shader : ShaderMaterial @export_enum("None", "When Drawing", "When Active") var image_hide_mode := 0 +## Tool can't be used and won't be able to press +var tool_disabled : bool = false + +func is_tool_disabled() -> bool: + return tool_disabled func get_icon_from_project_folder(icon_name:String) -> ImageTexture: return load("res://UI/graphics/tools/%s.png" % icon_name.to_lower()) @@ -34,8 +39,8 @@ func set_image_pixelv(image : Image, pos : Vector2i, color : Color): # if selection.get_bitv(pos): image.set_pixelv(pos, color) -func get_tool_inspector_properties(): - printerr("Not implemented: get_tool_inspector_properties! (" + get_script().resource_path.get_file() + ")") +func get_inspector_properties(): + printerr("Not implemented: get_inspector_properties! (" + get_script().resource_path.get_file() + ")") func shortcut_pressed(): printerr("Not implemented: shortcut_pressed! (" + get_script().resource_path.get_file() + ")") diff --git a/src/tools/tools_manager.gd b/src/tools/tools_manager.gd index 62d285b..dc343a1 100644 --- a/src/tools/tools_manager.gd +++ b/src/tools/tools_manager.gd @@ -19,11 +19,14 @@ var TOOLS : Array[ToolBase] = [ preload("res://src/tools/rotate_tool.gd").new(), preload("res://src/tools/scale_tool.gd").new(), preload("res://src/tools/crop_tool.gd").new(), - preload("res://src/tools/pencil_tool.gd").new(), preload("res://src/tools/brush_tool.gd").new(), - preload("res://src/tools/brush_clone_tool.gd").new(), - preload("res://src/tools/bucket_tool.gd").new(), + #preload("res://src/tools/brush_clone_tool.gd").new(), + #preload("res://src/tools/bucket_tool.gd").new(), + preload("res://src/tools/undo_tool_button.gd").new(), + preload("res://src/tools/redo_tool_button.gd").new(), preload("res://src/tools/context_menu_tool.gd").new(), + preload("res://src/tools/layers_menu_tool.gd").new(), + preload("res://src/tools/properties_menu_tool.gd").new(), ] var current_tool : ToolBase var shortcut_tool : ToolBase @@ -100,7 +103,11 @@ func _input(_event): func assign_tool(_p_name: String, button: int) -> void: - if TOOLS[button].tool_name == "add_layer": + if TOOLS[button].tool_name == "add_layer" or\ + TOOLS[button].tool_name == "layer_properties" or\ + TOOLS[button].tool_name == "layers_panel" or\ + TOOLS[button].tool_name == "undo" or\ + TOOLS[button].tool_name == "redo": TOOLS[button].enable_tool() return current_tool = TOOLS[button] @@ -135,5 +142,5 @@ func select_or_create_paint_layer(): if !ProjectsManager.current_project: return var new_paint_layer = paint_layer.new() - new_paint_layer.init(ProjectsManager.current_project.layers_container.get_unused_layer_name(),"", ProjectsManager.current_project) + new_paint_layer.init(ProjectsManager.current_project.layers_container.get_unused_layer_name(), ProjectsManager.current_project) ToolsManager.current_project.layers_container.selected_layers.insert(0,new_paint_layer) diff --git a/src/tools/undo_tool_button.gd b/src/tools/undo_tool_button.gd new file mode 100644 index 0000000..2788f5e --- /dev/null +++ b/src/tools/undo_tool_button.gd @@ -0,0 +1,44 @@ +extends ToolBase + +func _init(): + tool_name = "undo" + tool_button_shortcut = "" + tool_desc = "Undo" + tool_icon = get_icon_from_project_folder("undo") + + +func get_inspector_properties(): + printerr("Not implemented: get_inspector_properties! (" + get_script().resource_path.get_file() + ")") + + + +func shortcut_pressed(): + pass + +func mouse_pressed( + _event : InputEventMouseButton, + _image : base_layer, + _color1 : Color = Color.BLACK, + _color2 : Color = Color.WHITE, +): + pass + + +func get_affected_rect() -> Rect2i: + pass + return Rect2i() + + +func mouse_moved(_event : InputEventMouseMotion): + pass +func draw_preview(_image_view : CanvasItem, _mouse_position : Vector2i): + pass + +func is_tool_disabled() -> bool: + return mt_globals.main_window.edit_undo_is_disabled() +func enable_tool(): # Save History and Enable Tool + mt_globals.main_window.edit_undo() +func cancel_tool(): # Redo Actions + pass +func confirm_tool(): # Confirm Actions + pass diff --git a/touch_editor_layout.tres b/touch_editor_layout.tres index 0559746..960eaaa 100644 --- a/touch_editor_layout.tres +++ b/touch_editor_layout.tres @@ -1,61 +1,45 @@ -[gd_resource type="Resource" script_class="DockableLayout" load_steps=11 format=3 uid="uid://busuw7nyk34mk"] +[gd_resource type="Resource" script_class="DockableLayout" load_steps=9 format=3 uid="uid://busuw7nyk34mk"] [ext_resource type="Script" path="res://addons/dockable_container/layout_panel.gd" id="1_8tcst"] [ext_resource type="Script" path="res://addons/dockable_container/layout_split.gd" id="2_ns8yw"] [ext_resource type="Script" path="res://addons/dockable_container/layout.gd" id="3_42blb"] -[sub_resource type="Resource" id="Resource_48pqg"] +[sub_resource type="Resource" id="Resource_52066"] resource_name = "Tabs" script = ExtResource("1_8tcst") -names = PackedStringArray("Project Settings", "Layer Inspector") +names = PackedStringArray("Tool Settings", "Project Settings") current_tab = 0 -[sub_resource type="Resource" id="Resource_wpxgq"] +[sub_resource type="Resource" id="Resource_57cpm"] resource_name = "Tabs" script = ExtResource("1_8tcst") -names = PackedStringArray("Tool Settings") +names = PackedStringArray("Layers Panel", "Layer Inspector") current_tab = 0 -[sub_resource type="Resource" id="Resource_2ms2b"] -resource_name = "Split" -script = ExtResource("2_ns8yw") -direction = 0 -percent = 0.5 -first = SubResource("Resource_48pqg") -second = SubResource("Resource_wpxgq") - -[sub_resource type="Resource" id="Resource_daj1h"] -resource_name = "Tabs" -script = ExtResource("1_8tcst") -names = PackedStringArray("Layers Panel") -current_tab = 0 - -[sub_resource type="Resource" id="Resource_8bq14"] +[sub_resource type="Resource" id="Resource_yreys"] resource_name = "Split" script = ExtResource("2_ns8yw") direction = 1 percent = 0.5 -first = SubResource("Resource_2ms2b") -second = SubResource("Resource_daj1h") +first = SubResource("Resource_52066") +second = SubResource("Resource_57cpm") -[sub_resource type="Resource" id="Resource_x26ns"] +[sub_resource type="Resource" id="Resource_famne"] resource_name = "Tabs" script = ExtResource("1_8tcst") names = PackedStringArray("Graph") current_tab = 0 -[sub_resource type="Resource" id="Resource_h1uxb"] +[sub_resource type="Resource" id="Resource_mphc2"] resource_name = "Split" script = ExtResource("2_ns8yw") direction = 0 percent = 0.2 -first = SubResource("Resource_8bq14") -second = SubResource("Resource_x26ns") +first = SubResource("Resource_yreys") +second = SubResource("Resource_famne") [resource] resource_name = "Layout" script = ExtResource("3_42blb") -root = SubResource("Resource_h1uxb") -hidden_tabs = { -"Project Settings": true -} +root = SubResource("Resource_mphc2") +hidden_tabs = {} diff --git a/vertical_touch_editor_layout.tres b/vertical_touch_editor_layout.tres new file mode 100644 index 0000000..1b63425 --- /dev/null +++ b/vertical_touch_editor_layout.tres @@ -0,0 +1,45 @@ +[gd_resource type="Resource" script_class="DockableLayout" load_steps=9 format=3 uid="uid://jw0l42hvpbhh"] + +[ext_resource type="Script" path="res://addons/dockable_container/layout_panel.gd" id="1_2xin4"] +[ext_resource type="Script" path="res://addons/dockable_container/layout_split.gd" id="2_se2j1"] +[ext_resource type="Script" path="res://addons/dockable_container/layout.gd" id="3_qdfe8"] + +[sub_resource type="Resource" id="Resource_exepu"] +resource_name = "Tabs" +script = ExtResource("1_2xin4") +names = PackedStringArray("Tool Settings", "Project Settings") +current_tab = 0 + +[sub_resource type="Resource" id="Resource_yw2ob"] +resource_name = "Tabs" +script = ExtResource("1_2xin4") +names = PackedStringArray("Layers Panel", "Layer Inspector") +current_tab = 0 + +[sub_resource type="Resource" id="Resource_hpmdj"] +resource_name = "Split" +script = ExtResource("2_se2j1") +direction = 0 +percent = 0.5 +first = SubResource("Resource_exepu") +second = SubResource("Resource_yw2ob") + +[sub_resource type="Resource" id="Resource_wqv5r"] +resource_name = "Tabs" +script = ExtResource("1_2xin4") +names = PackedStringArray("Graph") +current_tab = 0 + +[sub_resource type="Resource" id="Resource_25d38"] +resource_name = "Split" +script = ExtResource("2_se2j1") +direction = 1 +percent = 0.25 +first = SubResource("Resource_hpmdj") +second = SubResource("Resource_wqv5r") + +[resource] +resource_name = "Layout" +script = ExtResource("3_qdfe8") +root = SubResource("Resource_25d38") +hidden_tabs = {}