mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-31 07:29:49 +00:00
Added the Perspective editor (#806)
* Added Perspective Editor * removed unintended changes * Removed unintended changes * removed un-intended changes * Delete Axes.tscn * Delete Axis.gd * Removed MouseGuides from editor I will add them separately * Added MouseGuides * Some changes * Fixed some things * added mouse guide * make MouseGuides remember last setting * don't move if dialog is open * Dont move tracker guides if dialog is open * UI improvement to editor * Update VanishingPoint.gd * UI Improvement * Minor Color Improvements * fixed a bug This was causing a crash * Some UI Changes * Improve UI some more * fix typo * Added Undo/Redo and improved UI * Formatting * formatting * formatting * formatting * Fix Definition out of order * Fix Definition out of order * formatting * formatting * fix Duplicate error * Fix some things * Some UI Changes * Some code refinement * Removed un-needed lines * Some code refinement * Some more UI Changes * Changes, Changes and Changes * Delete LineButton.gd * Delete LineButton.tscn * Delete PerspectiveEditor.gd * Delete PerspectiveEditor.tscn * Delete PointCollapseContainer.gd * Delete PerspectiveLine.tscn * Delete PerspectiveLine.gd * Changed boundary separators to ColorRects * make the guide update more frequently * make default color have full alpha * Dim the boundaries based on luminance * typo * Formatting * Formatting * formatting i forgot to do * Delete VanishingPoint.gd * Delete VanishingPoint.tscn * Fixed rouge collapsible container --------- Co-authored-by: Emmanouil Papadeas <35376950+OverloadedOrama@users.noreply.github.com>
This commit is contained in:
parent
c6d6c6184c
commit
7307743f83
|
@ -159,6 +159,11 @@ _global_script_classes=[ {
|
||||||
"language": "GDScript",
|
"language": "GDScript",
|
||||||
"path": "res://src/UI/Buttons/PatternsPopup.gd"
|
"path": "res://src/UI/Buttons/PatternsPopup.gd"
|
||||||
}, {
|
}, {
|
||||||
|
"base": "Line2D",
|
||||||
|
"class": "PerspectiveLine",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://src/UI/PerspectiveEditor/PerspectiveLine.gd"
|
||||||
|
}, {
|
||||||
"base": "BaseCel",
|
"base": "BaseCel",
|
||||||
"class": "PixelCel",
|
"class": "PixelCel",
|
||||||
"language": "GDScript",
|
"language": "GDScript",
|
||||||
|
@ -250,6 +255,7 @@ _global_script_class_icons={
|
||||||
"PalettePanel": "",
|
"PalettePanel": "",
|
||||||
"PaletteSwatch": "",
|
"PaletteSwatch": "",
|
||||||
"Patterns": "",
|
"Patterns": "",
|
||||||
|
"PerspectiveLine": "",
|
||||||
"PixelCel": "",
|
"PixelCel": "",
|
||||||
"PixelLayer": "",
|
"PixelLayer": "",
|
||||||
"Project": "",
|
"Project": "",
|
||||||
|
|
|
@ -20,6 +20,7 @@ enum ViewMenu {
|
||||||
SHOW_PIXEL_GRID,
|
SHOW_PIXEL_GRID,
|
||||||
SHOW_RULERS,
|
SHOW_RULERS,
|
||||||
SHOW_GUIDES,
|
SHOW_GUIDES,
|
||||||
|
SHOW_MOUSE_GUIDES,
|
||||||
SNAP_TO,
|
SNAP_TO,
|
||||||
}
|
}
|
||||||
enum WindowMenu { WINDOW_OPACITY, PANELS, LAYOUTS, MOVABLE_PANELS, ZEN_MODE, FULLSCREEN_MODE }
|
enum WindowMenu { WINDOW_OPACITY, PANELS, LAYOUTS, MOVABLE_PANELS, ZEN_MODE, FULLSCREEN_MODE }
|
||||||
|
@ -138,6 +139,7 @@ var draw_grid := false
|
||||||
var draw_pixel_grid := false
|
var draw_pixel_grid := false
|
||||||
var show_rulers := true
|
var show_rulers := true
|
||||||
var show_guides := true
|
var show_guides := true
|
||||||
|
var show_mouse_guides := false
|
||||||
var snapping_distance := 10.0
|
var snapping_distance := 10.0
|
||||||
var snap_to_rectangular_grid := false
|
var snap_to_rectangular_grid := false
|
||||||
var snap_to_guides := false
|
var snap_to_guides := false
|
||||||
|
@ -181,6 +183,7 @@ onready var patterns_popup: Popup = control.find_node("PatternsPopup")
|
||||||
onready var palette_panel: PalettePanel = control.find_node("Palettes")
|
onready var palette_panel: PalettePanel = control.find_node("Palettes")
|
||||||
|
|
||||||
onready var references_panel: ReferencesPanel = control.find_node("Reference Images")
|
onready var references_panel: ReferencesPanel = control.find_node("Reference Images")
|
||||||
|
onready var perspective_editor := control.find_node("Perspective Editor")
|
||||||
|
|
||||||
onready var top_menu_container: Panel = control.find_node("TopMenuContainer")
|
onready var top_menu_container: Panel = control.find_node("TopMenuContainer")
|
||||||
onready var rotation_level_button: Button = control.find_node("RotationLevel")
|
onready var rotation_level_button: Button = control.find_node("RotationLevel")
|
||||||
|
|
|
@ -24,6 +24,7 @@ var animation_tags := [] setget _animation_tags_changed # Array of AnimationTag
|
||||||
var guides := [] # Array of Guides
|
var guides := [] # Array of Guides
|
||||||
var brushes := [] # Array of Images
|
var brushes := [] # Array of Images
|
||||||
var reference_images := [] # Array of ReferenceImages
|
var reference_images := [] # Array of ReferenceImages
|
||||||
|
var vanishing_points := [] # Array of Vanishing Points
|
||||||
var fps := 6.0
|
var fps := 6.0
|
||||||
|
|
||||||
var x_symmetry_point
|
var x_symmetry_point
|
||||||
|
@ -91,6 +92,12 @@ func remove() -> void:
|
||||||
undo_redo.free()
|
undo_redo.free()
|
||||||
for ri in reference_images:
|
for ri in reference_images:
|
||||||
ri.queue_free()
|
ri.queue_free()
|
||||||
|
if self == Global.current_project:
|
||||||
|
# If the project is not current_project then the points need not be removed
|
||||||
|
for point_idx in vanishing_points.size():
|
||||||
|
var editor = Global.perspective_editor
|
||||||
|
for c in editor.vanishing_point_container.get_children():
|
||||||
|
c.queue_free()
|
||||||
for guide in guides:
|
for guide in guides:
|
||||||
guide.queue_free()
|
guide.queue_free()
|
||||||
# Prevents memory leak (due to the layers' project reference stopping ref counting from freeing)
|
# Prevents memory leak (due to the layers' project reference stopping ref counting from freeing)
|
||||||
|
@ -186,6 +193,7 @@ func change_project() -> void:
|
||||||
Global.horizontal_ruler.update()
|
Global.horizontal_ruler.update()
|
||||||
Global.vertical_ruler.update()
|
Global.vertical_ruler.update()
|
||||||
Global.references_panel.project_changed()
|
Global.references_panel.project_changed()
|
||||||
|
Global.perspective_editor.update()
|
||||||
Global.cursor_position_label.text = "[%s×%s]" % [size.x, size.y]
|
Global.cursor_position_label.text = "[%s×%s]" % [size.x, size.y]
|
||||||
|
|
||||||
Global.window_title = "%s - Pixelorama %s" % [name, Global.current_version]
|
Global.window_title = "%s - Pixelorama %s" % [name, Global.current_version]
|
||||||
|
@ -325,6 +333,7 @@ func serialize() -> Dictionary:
|
||||||
"frames": frame_data,
|
"frames": frame_data,
|
||||||
"brushes": brush_data,
|
"brushes": brush_data,
|
||||||
"reference_images": reference_image_data,
|
"reference_images": reference_image_data,
|
||||||
|
"vanishing_points": vanishing_points,
|
||||||
"export_directory_path": directory_path,
|
"export_directory_path": directory_path,
|
||||||
"export_file_name": file_name,
|
"export_file_name": file_name,
|
||||||
"export_file_format": file_format,
|
"export_file_format": file_format,
|
||||||
|
@ -412,6 +421,9 @@ func deserialize(dict: Dictionary) -> void:
|
||||||
ri.project = self
|
ri.project = self
|
||||||
ri.deserialize(g)
|
ri.deserialize(g)
|
||||||
Global.canvas.add_child(ri)
|
Global.canvas.add_child(ri)
|
||||||
|
if dict.has("vanishing_points"):
|
||||||
|
vanishing_points = dict.vanishing_points
|
||||||
|
Global.perspective_editor.update()
|
||||||
if dict.has("symmetry_points"):
|
if dict.has("symmetry_points"):
|
||||||
x_symmetry_point = dict.symmetry_points[0]
|
x_symmetry_point = dict.symmetry_points[0]
|
||||||
y_symmetry_point = dict.symmetry_points[1]
|
y_symmetry_point = dict.symmetry_points[1]
|
||||||
|
|
|
@ -416,6 +416,7 @@ func _exit_tree() -> void:
|
||||||
Global.config_cache.set_value("view_menu", "draw_pixel_grid", Global.draw_pixel_grid)
|
Global.config_cache.set_value("view_menu", "draw_pixel_grid", Global.draw_pixel_grid)
|
||||||
Global.config_cache.set_value("view_menu", "show_rulers", Global.show_rulers)
|
Global.config_cache.set_value("view_menu", "show_rulers", Global.show_rulers)
|
||||||
Global.config_cache.set_value("view_menu", "show_guides", Global.show_guides)
|
Global.config_cache.set_value("view_menu", "show_guides", Global.show_guides)
|
||||||
|
Global.config_cache.set_value("view_menu", "show_mouse_guides", Global.show_mouse_guides)
|
||||||
Global.config_cache.save("user://cache.ini")
|
Global.config_cache.save("user://cache.ini")
|
||||||
|
|
||||||
var i := 0
|
var i := 0
|
||||||
|
|
|
@ -16,6 +16,7 @@ onready var grid = $Grid
|
||||||
onready var selection = $Selection
|
onready var selection = $Selection
|
||||||
onready var indicators = $Indicators
|
onready var indicators = $Indicators
|
||||||
onready var previews = $Previews
|
onready var previews = $Previews
|
||||||
|
onready var mouse_guide_container = $MouseGuideContainer
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=15 format=2]
|
[gd_scene load_steps=16 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://src/UI/Canvas/Canvas.gd" type="Script" id=1]
|
[ext_resource path="res://src/UI/Canvas/Canvas.gd" type="Script" id=1]
|
||||||
[ext_resource path="res://src/UI/Canvas/Grid.gd" type="Script" id=2]
|
[ext_resource path="res://src/UI/Canvas/Grid.gd" type="Script" id=2]
|
||||||
|
@ -10,6 +10,7 @@
|
||||||
[ext_resource path="res://src/UI/Canvas/Selection.gd" type="Script" id=8]
|
[ext_resource path="res://src/UI/Canvas/Selection.gd" type="Script" id=8]
|
||||||
[ext_resource path="res://src/Shaders/MarchingAntsOutline.shader" type="Shader" id=9]
|
[ext_resource path="res://src/Shaders/MarchingAntsOutline.shader" type="Shader" id=9]
|
||||||
[ext_resource path="res://src/Shaders/AutoInvertColors.shader" type="Shader" id=10]
|
[ext_resource path="res://src/Shaders/AutoInvertColors.shader" type="Shader" id=10]
|
||||||
|
[ext_resource path="res://src/UI/Canvas/MouseGuideContainer.tscn" type="PackedScene" id=11]
|
||||||
[ext_resource path="res://src/UI/Canvas/OnionSkinning.gd" type="Script" id=12]
|
[ext_resource path="res://src/UI/Canvas/OnionSkinning.gd" type="Script" id=12]
|
||||||
|
|
||||||
[sub_resource type="CanvasItemMaterial" id=1]
|
[sub_resource type="CanvasItemMaterial" id=1]
|
||||||
|
@ -72,3 +73,5 @@ script = ExtResource( 12 )
|
||||||
|
|
||||||
[node name="OnionFuture" type="Node2D" parent="."]
|
[node name="OnionFuture" type="Node2D" parent="."]
|
||||||
script = ExtResource( 12 )
|
script = ExtResource( 12 )
|
||||||
|
|
||||||
|
[node name="MouseGuideContainer" parent="." instance=ExtResource( 11 )]
|
||||||
|
|
77
src/UI/Canvas/MouseGuide.gd
Normal file
77
src/UI/Canvas/MouseGuide.gd
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
extends Line2D
|
||||||
|
|
||||||
|
enum Types { VERTICAL, HORIZONTAL }
|
||||||
|
const INPUT_WIDTH := 4
|
||||||
|
export var type := 0
|
||||||
|
var track_mouse := true
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
# Add a subtle difference to the normal guide color by mixing in some green
|
||||||
|
default_color = Global.guide_color.linear_interpolate(Color(0.2, 0.92, 0.2), .6)
|
||||||
|
width = Global.camera.zoom.x * 2
|
||||||
|
draw_guide_line()
|
||||||
|
|
||||||
|
|
||||||
|
func draw_guide_line():
|
||||||
|
if type == Types.HORIZONTAL:
|
||||||
|
points[0] = Vector2(-19999, 0)
|
||||||
|
points[1] = Vector2(19999, 0)
|
||||||
|
else:
|
||||||
|
points[0] = Vector2(0, 19999)
|
||||||
|
points[1] = Vector2(0, -19999)
|
||||||
|
|
||||||
|
|
||||||
|
func _input(event: InputEvent) -> void:
|
||||||
|
if !Global.show_mouse_guides or !Global.can_draw or !Global.has_focus:
|
||||||
|
visible = false
|
||||||
|
return
|
||||||
|
visible = true
|
||||||
|
if event is InputEventMouseMotion:
|
||||||
|
var tmp_transform = get_canvas_transform().affine_inverse()
|
||||||
|
var tmp_position = Global.main_viewport.get_local_mouse_position()
|
||||||
|
var mouse_point = (tmp_transform.basis_xform(tmp_position) + tmp_transform.origin).snapped(
|
||||||
|
Vector2(0.5, 0.5)
|
||||||
|
)
|
||||||
|
|
||||||
|
var project_size = Global.current_project.size
|
||||||
|
if Rect2(Vector2.ZERO, project_size).has_point(mouse_point):
|
||||||
|
visible = true
|
||||||
|
else:
|
||||||
|
visible = false
|
||||||
|
return
|
||||||
|
if type == Types.HORIZONTAL:
|
||||||
|
points[0].y = mouse_point.y
|
||||||
|
points[1].y = mouse_point.y
|
||||||
|
else:
|
||||||
|
points[0].x = mouse_point.x
|
||||||
|
points[1].x = mouse_point.x
|
||||||
|
update()
|
||||||
|
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
width = Global.camera.zoom.x * 2
|
||||||
|
var viewport_size: Vector2 = Global.main_viewport.rect_size
|
||||||
|
var zoom: Vector2 = Global.camera.zoom
|
||||||
|
|
||||||
|
# viewport_poly is an array of the points that make up the corners of the viewport
|
||||||
|
var viewport_poly := [
|
||||||
|
Vector2.ZERO, Vector2(viewport_size.x, 0), viewport_size, Vector2(0, viewport_size.y)
|
||||||
|
]
|
||||||
|
# Adjusting viewport_poly to take into account the camera offset, zoom, and rotation
|
||||||
|
for p in range(viewport_poly.size()):
|
||||||
|
viewport_poly[p] = (
|
||||||
|
viewport_poly[p].rotated(Global.camera.rotation) * zoom
|
||||||
|
+ Vector2(
|
||||||
|
(
|
||||||
|
Global.camera.offset.x
|
||||||
|
- (viewport_size.rotated(Global.camera.rotation).x / 2) * zoom.x
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Global.camera.offset.y
|
||||||
|
- (viewport_size.rotated(Global.camera.rotation).y / 2) * zoom.y
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
draw_set_transform(viewport_poly[0], Global.camera.rotation, zoom * 2)
|
31
src/UI/Canvas/MouseGuideContainer.tscn
Normal file
31
src/UI/Canvas/MouseGuideContainer.tscn
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
[gd_scene load_steps=4 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://assets/graphics/dotted_line.png" type="Texture" id=1]
|
||||||
|
[ext_resource path="res://src/UI/Canvas/MouseGuide.gd" type="Script" id=2]
|
||||||
|
|
||||||
|
[sub_resource type="AtlasTexture" id=1]
|
||||||
|
flags = 2
|
||||||
|
atlas = ExtResource( 1 )
|
||||||
|
region = Rect2( 0, 0, 8, 1 )
|
||||||
|
|
||||||
|
[node name="MouseGuideContainer" type="Node2D"]
|
||||||
|
|
||||||
|
[node name="Vertical" type="Line2D" parent="."]
|
||||||
|
visible = false
|
||||||
|
points = PoolVector2Array( 0, 19999, 0, -19999 )
|
||||||
|
default_color = Color( 1, 1, 1, 1 )
|
||||||
|
texture = SubResource( 1 )
|
||||||
|
texture_mode = 1
|
||||||
|
script = ExtResource( 2 )
|
||||||
|
|
||||||
|
[node name="Horizontal" type="Line2D" parent="."]
|
||||||
|
visible = false
|
||||||
|
points = PoolVector2Array( -19999, 0, 19999, 0 )
|
||||||
|
default_color = Color( 1, 1, 1, 1 )
|
||||||
|
texture = SubResource( 1 )
|
||||||
|
texture_mode = 1
|
||||||
|
script = ExtResource( 2 )
|
||||||
|
__meta__ = {
|
||||||
|
"_editor_description_": ""
|
||||||
|
}
|
||||||
|
type = 1
|
9
src/UI/PerspectiveEditor/LineButton.gd
Normal file
9
src/UI/PerspectiveEditor/LineButton.gd
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
extends Button
|
||||||
|
|
||||||
|
onready var length_slider = $"%LengthSlider"
|
||||||
|
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
var p_size = Global.current_project.size
|
||||||
|
var suitable_length = sqrt(pow(p_size.x, 2) + pow(p_size.y, 2))
|
||||||
|
length_slider.max_value = suitable_length
|
61
src/UI/PerspectiveEditor/LineButton.tscn
Normal file
61
src/UI/PerspectiveEditor/LineButton.tscn
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
[gd_scene load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://src/UI/Nodes/ValueSlider.tscn" type="PackedScene" id=1]
|
||||||
|
[ext_resource path="res://src/UI/Nodes/CollapsibleContainer.gd" type="Script" id=3]
|
||||||
|
|
||||||
|
[node name="LineButton" type="VBoxContainer"]
|
||||||
|
margin_right = 159.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
theme_type_variation = "CollapsibleContainer"
|
||||||
|
script = ExtResource( 3 )
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="."]
|
||||||
|
visible = false
|
||||||
|
margin_top = 24.0
|
||||||
|
margin_right = 159.0
|
||||||
|
margin_bottom = 76.0
|
||||||
|
|
||||||
|
[node name="Spacer" type="Control" parent="HBoxContainer"]
|
||||||
|
margin_right = 20.0
|
||||||
|
margin_bottom = 52.0
|
||||||
|
rect_min_size = Vector2( 20, 0 )
|
||||||
|
|
||||||
|
[node name="VSeparator" type="VSeparator" parent="HBoxContainer"]
|
||||||
|
margin_left = 24.0
|
||||||
|
margin_right = 28.0
|
||||||
|
margin_bottom = 52.0
|
||||||
|
|
||||||
|
[node name="Properties" type="VBoxContainer" parent="HBoxContainer"]
|
||||||
|
margin_left = 32.0
|
||||||
|
margin_right = 83.0
|
||||||
|
margin_bottom = 52.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="AngleSlider" parent="HBoxContainer/Properties" instance=ExtResource( 1 )]
|
||||||
|
margin_right = 51.0
|
||||||
|
max_value = 359.999
|
||||||
|
step = 0.001
|
||||||
|
prefix = "Angle:"
|
||||||
|
suffix = "°"
|
||||||
|
|
||||||
|
[node name="LengthSlider" parent="HBoxContainer/Properties" instance=ExtResource( 1 )]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
margin_top = 28.0
|
||||||
|
margin_right = 51.0
|
||||||
|
margin_bottom = 52.0
|
||||||
|
max_value = 19999.0
|
||||||
|
value = 19999.0
|
||||||
|
allow_greater = true
|
||||||
|
prefix = "Length:"
|
||||||
|
suffix = "px"
|
||||||
|
|
||||||
|
[node name="Delete" type="Button" parent="HBoxContainer"]
|
||||||
|
margin_left = 87.0
|
||||||
|
margin_right = 151.0
|
||||||
|
margin_bottom = 52.0
|
||||||
|
text = "Remove"
|
||||||
|
|
||||||
|
[node name="VSeparator2" type="VSeparator" parent="HBoxContainer"]
|
||||||
|
margin_left = 155.0
|
||||||
|
margin_right = 159.0
|
||||||
|
margin_bottom = 52.0
|
67
src/UI/PerspectiveEditor/PerspectiveEditor.gd
Normal file
67
src/UI/PerspectiveEditor/PerspectiveEditor.gd
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
var axes: Node2D
|
||||||
|
var do_pool = [] # A pool that stores data of points removed by undo
|
||||||
|
var delete_pool = [] # A pool that containg deleted data and their index
|
||||||
|
var vanishing_point_res := preload("res://src/UI/PerspectiveEditor/VanishingPoint.tscn")
|
||||||
|
|
||||||
|
onready var vanishing_point_container = $"%VanishingPointContainer"
|
||||||
|
|
||||||
|
|
||||||
|
func _on_AddPoint_pressed() -> void:
|
||||||
|
do_pool.clear() # Reset
|
||||||
|
var project = Global.current_project
|
||||||
|
project.undos += 1
|
||||||
|
project.undo_redo.create_action("Add Vanishing Point")
|
||||||
|
project.undo_redo.add_do_method(self, "add_vanishing_point", true)
|
||||||
|
project.undo_redo.add_undo_method(self, "undo_add_vanishing_point")
|
||||||
|
project.undo_redo.commit_action()
|
||||||
|
|
||||||
|
|
||||||
|
func update():
|
||||||
|
for c in vanishing_point_container.get_children():
|
||||||
|
c.queue_free()
|
||||||
|
for idx in Global.current_project.vanishing_points.size():
|
||||||
|
var point_data = Global.current_project.vanishing_points[idx]
|
||||||
|
var vanishing_point := vanishing_point_res.instance()
|
||||||
|
vanishing_point_container.add_child(vanishing_point)
|
||||||
|
vanishing_point.initiate(point_data, idx)
|
||||||
|
|
||||||
|
|
||||||
|
func add_vanishing_point(is_redo := false):
|
||||||
|
var vanishing_point := vanishing_point_res.instance()
|
||||||
|
vanishing_point_container.add_child(vanishing_point)
|
||||||
|
if is_redo and !do_pool.empty():
|
||||||
|
vanishing_point.initiate(do_pool.pop_back())
|
||||||
|
vanishing_point.update_data_to_project()
|
||||||
|
else:
|
||||||
|
vanishing_point.initiate()
|
||||||
|
|
||||||
|
|
||||||
|
func undo_add_vanishing_point():
|
||||||
|
var point = vanishing_point_container.get_child(vanishing_point_container.get_child_count() - 1)
|
||||||
|
point.queue_free()
|
||||||
|
do_pool.append(point.data.duplicate())
|
||||||
|
point.update_data_to_project(true)
|
||||||
|
|
||||||
|
|
||||||
|
func delete_point(idx):
|
||||||
|
var project = Global.current_project
|
||||||
|
project.undos += 1
|
||||||
|
project.undo_redo.create_action("Delete Vanishing Point")
|
||||||
|
project.undo_redo.add_do_method(self, "do_delete_point", idx)
|
||||||
|
project.undo_redo.add_undo_method(self, "undo_delete_point", idx)
|
||||||
|
project.undo_redo.commit_action()
|
||||||
|
|
||||||
|
|
||||||
|
func do_delete_point(idx):
|
||||||
|
var point = vanishing_point_container.get_child(idx)
|
||||||
|
delete_pool.append(point.data)
|
||||||
|
point.queue_free()
|
||||||
|
point.update_data_to_project(true)
|
||||||
|
|
||||||
|
|
||||||
|
func undo_delete_point(idx):
|
||||||
|
var point = delete_pool.pop_back()
|
||||||
|
Global.current_project.vanishing_points.insert(idx, point)
|
||||||
|
update()
|
72
src/UI/PerspectiveEditor/PerspectiveEditor.tscn
Normal file
72
src/UI/PerspectiveEditor/PerspectiveEditor.tscn
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://src/UI/PerspectiveEditor/PerspectiveEditor.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="PerspectiveEditor" type="Control"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_right = -1013.0
|
||||||
|
margin_bottom = -510.0
|
||||||
|
rect_min_size = Vector2( 270, 10 )
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||||
|
self_modulate = Color( 0.698039, 0.698039, 0.698039, 0.698039 )
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_left = 4.0
|
||||||
|
margin_right = -4.0
|
||||||
|
rect_clip_content = true
|
||||||
|
size_flags_vertical = 3
|
||||||
|
__meta__ = {
|
||||||
|
"_editor_description_": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="Header" type="HBoxContainer" parent="VBoxContainer"]
|
||||||
|
margin_right = 262.0
|
||||||
|
margin_bottom = 30.0
|
||||||
|
custom_constants/separation = 0
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/Header"]
|
||||||
|
margin_top = 8.0
|
||||||
|
margin_right = 232.0
|
||||||
|
margin_bottom = 22.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
theme_type_variation = "Header"
|
||||||
|
text = "Perspective Editor"
|
||||||
|
align = 1
|
||||||
|
valign = 1
|
||||||
|
|
||||||
|
[node name="AddPoint" type="Button" parent="VBoxContainer/Header"]
|
||||||
|
margin_left = 232.0
|
||||||
|
margin_right = 262.0
|
||||||
|
margin_bottom = 30.0
|
||||||
|
rect_min_size = Vector2( 30, 30 )
|
||||||
|
text = "+"
|
||||||
|
clip_text = true
|
||||||
|
|
||||||
|
[node name="HSeparator" type="HSeparator" parent="VBoxContainer"]
|
||||||
|
margin_top = 34.0
|
||||||
|
margin_right = 262.0
|
||||||
|
margin_bottom = 38.0
|
||||||
|
|
||||||
|
[node name="HSeparator2" type="HSeparator" parent="VBoxContainer"]
|
||||||
|
margin_top = 42.0
|
||||||
|
margin_right = 262.0
|
||||||
|
margin_bottom = 46.0
|
||||||
|
|
||||||
|
[node name="Content" type="ScrollContainer" parent="VBoxContainer"]
|
||||||
|
margin_top = 50.0
|
||||||
|
margin_right = 262.0
|
||||||
|
margin_bottom = 210.0
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="VanishingPointContainer" type="VBoxContainer" parent="VBoxContainer/Content"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
margin_right = 262.0
|
||||||
|
margin_bottom = 160.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
custom_constants/separation = 5
|
||||||
|
|
||||||
|
[connection signal="pressed" from="VBoxContainer/Header/AddPoint" to="." method="_on_AddPoint_pressed"]
|
101
src/UI/PerspectiveEditor/PerspectiveLine.gd
Normal file
101
src/UI/PerspectiveEditor/PerspectiveLine.gd
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
class_name PerspectiveLine
|
||||||
|
extends Line2D
|
||||||
|
|
||||||
|
const INPUT_WIDTH := 4
|
||||||
|
var hidden = false
|
||||||
|
var track_mouse := false
|
||||||
|
var _data = {"start": Vector2.ZERO, "angle": 0, "length": 19999, "color": Color.black}
|
||||||
|
|
||||||
|
|
||||||
|
func initiate(data: Dictionary):
|
||||||
|
width = Global.camera.zoom.x * 2
|
||||||
|
Global.canvas.add_child(self)
|
||||||
|
refresh(data)
|
||||||
|
|
||||||
|
|
||||||
|
func refresh(data: Dictionary):
|
||||||
|
_data = data
|
||||||
|
default_color = data.color
|
||||||
|
draw_perspective_line()
|
||||||
|
|
||||||
|
|
||||||
|
func draw_perspective_line():
|
||||||
|
var angle = -_data.angle
|
||||||
|
points[0] = _data.start
|
||||||
|
if hidden:
|
||||||
|
points[1] = _data.start
|
||||||
|
else:
|
||||||
|
points[1] = (
|
||||||
|
_data.start
|
||||||
|
+ Vector2(_data.length * cos(deg2rad(angle)), _data.length * sin(deg2rad(angle)))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func hide_perspective_line():
|
||||||
|
points[1] = _data.start
|
||||||
|
hidden = true
|
||||||
|
|
||||||
|
|
||||||
|
func _input(event: InputEvent) -> void:
|
||||||
|
if event is InputEventMouse:
|
||||||
|
if track_mouse:
|
||||||
|
if !Global.can_draw or !Global.has_focus:
|
||||||
|
hide_perspective_line()
|
||||||
|
return
|
||||||
|
default_color.a = 0.5
|
||||||
|
var tmp_transform = get_canvas_transform().affine_inverse()
|
||||||
|
var tmp_position = Global.main_viewport.get_local_mouse_position()
|
||||||
|
var mouse_point = tmp_transform.basis_xform(tmp_position) + tmp_transform.origin
|
||||||
|
var project_size = Global.current_project.size
|
||||||
|
if Rect2(Vector2.ZERO, project_size).has_point(mouse_point):
|
||||||
|
hidden = false
|
||||||
|
draw_perspective_line()
|
||||||
|
var rel_vector = mouse_point - _data.start
|
||||||
|
var test_vector = Vector2(_data.start.x, 0)
|
||||||
|
if sign(test_vector.x) == 0:
|
||||||
|
test_vector.x += 0.5
|
||||||
|
|
||||||
|
_data.angle = rad2deg(test_vector.angle_to(rel_vector))
|
||||||
|
if sign(test_vector.x) == -1:
|
||||||
|
_data.angle += 180
|
||||||
|
|
||||||
|
points[1] = (
|
||||||
|
_data.start
|
||||||
|
+ Vector2(
|
||||||
|
_data.length * cos(deg2rad(_data.angle)),
|
||||||
|
_data.length * sin(deg2rad(_data.angle))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
hide_perspective_line()
|
||||||
|
update()
|
||||||
|
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
draw_circle(_data.start, Global.camera.zoom.x * 5, default_color)
|
||||||
|
width = Global.camera.zoom.x * 2
|
||||||
|
if hidden: # Hidden line
|
||||||
|
return
|
||||||
|
var viewport_size: Vector2 = Global.main_viewport.rect_size
|
||||||
|
var zoom: Vector2 = Global.camera.zoom
|
||||||
|
# viewport_poly is an array of the points that make up the corners of the viewport
|
||||||
|
var viewport_poly := [
|
||||||
|
Vector2.ZERO, Vector2(viewport_size.x, 0), viewport_size, Vector2(0, viewport_size.y)
|
||||||
|
]
|
||||||
|
# Adjusting viewport_poly to take into account the camera offset, zoom, and rotation
|
||||||
|
for p in range(viewport_poly.size()):
|
||||||
|
viewport_poly[p] = (
|
||||||
|
viewport_poly[p].rotated(Global.camera.rotation) * zoom
|
||||||
|
+ Vector2(
|
||||||
|
(
|
||||||
|
Global.camera.offset.x
|
||||||
|
- (viewport_size.rotated(Global.camera.rotation).x / 2) * zoom.x
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Global.camera.offset.y
|
||||||
|
- (viewport_size.rotated(Global.camera.rotation).y / 2) * zoom.y
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# If there's no intersection with a viewport edge, show string in top left corner
|
||||||
|
draw_set_transform(viewport_poly[0], Global.camera.rotation, zoom * 2)
|
7
src/UI/PerspectiveEditor/PerspectiveLine.tscn
Normal file
7
src/UI/PerspectiveEditor/PerspectiveLine.tscn
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://src/UI/PerspectiveEditor/PerspectiveLine.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="PerspectiveLine" type="Line2D"]
|
||||||
|
points = PoolVector2Array( 0, 0, 64, 0 )
|
||||||
|
script = ExtResource( 1 )
|
41
src/UI/PerspectiveEditor/PointCollapseContainer.gd
Normal file
41
src/UI/PerspectiveEditor/PointCollapseContainer.gd
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
extends Button
|
||||||
|
|
||||||
|
# This is NOT related to the CollapsibleContainer class (though it behaves similarly)
|
||||||
|
# i did it like this because the "Content" is part of a different node
|
||||||
|
export var point_text := "" setget _set_text
|
||||||
|
export var visible_content := false setget _set_visible_content
|
||||||
|
onready var content = $"%Content"
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_set_visible(pressed)
|
||||||
|
content.connect("visibility_changed", self, "_child_visibility_changed")
|
||||||
|
|
||||||
|
|
||||||
|
func _set_text(value: String) -> void:
|
||||||
|
$Label.text = value
|
||||||
|
rect_min_size = $Label.rect_size
|
||||||
|
|
||||||
|
|
||||||
|
func _set_visible_content(value: bool) -> void:
|
||||||
|
visible_content = value
|
||||||
|
pressed = value
|
||||||
|
|
||||||
|
|
||||||
|
func _on_Button_toggled(button_pressed: bool) -> void:
|
||||||
|
_set_visible(button_pressed)
|
||||||
|
|
||||||
|
|
||||||
|
func _set_visible(pressed: bool) -> void:
|
||||||
|
if pressed:
|
||||||
|
$TextureRect.rect_rotation = 0
|
||||||
|
else:
|
||||||
|
$TextureRect.rect_rotation = -90
|
||||||
|
content.visible = pressed
|
||||||
|
|
||||||
|
|
||||||
|
# Checks if a child becomes visible from another source and ensures
|
||||||
|
# it remains invisible if the button is not pressed
|
||||||
|
func _child_visibility_changed() -> void:
|
||||||
|
if not pressed:
|
||||||
|
content.visible = false
|
228
src/UI/PerspectiveEditor/VanishingPoint.gd
Normal file
228
src/UI/PerspectiveEditor/VanishingPoint.gd
Normal file
|
@ -0,0 +1,228 @@
|
||||||
|
extends VBoxContainer
|
||||||
|
|
||||||
|
var perspective_lines = []
|
||||||
|
var tracker_line: PerspectiveLine
|
||||||
|
var data = {
|
||||||
|
"position_x": 0,
|
||||||
|
"position_y": 0,
|
||||||
|
"angles": [],
|
||||||
|
"lengths": [],
|
||||||
|
"color": Color(randf(), randf(), randf(), 1).to_html(),
|
||||||
|
}
|
||||||
|
|
||||||
|
onready var color_picker_button = $"%ColorPickerButton"
|
||||||
|
onready var title = $"%PointCollapseContainer"
|
||||||
|
onready var pos_x = $"%X"
|
||||||
|
onready var pos_y = $"%Y"
|
||||||
|
onready var line_buttons_container = $"%LinesContainer"
|
||||||
|
onready var boundary_l = $Content/BoundaryL
|
||||||
|
onready var boundary_r = $Content/BoundaryR
|
||||||
|
onready var boundary_b = $Content/VBoxContainer/BoundaryB
|
||||||
|
|
||||||
|
|
||||||
|
func initiate(start_data = null, idx = -1) -> void:
|
||||||
|
if start_data:
|
||||||
|
data = start_data.duplicate()
|
||||||
|
add_line(null, true)
|
||||||
|
for i in data.angles.size():
|
||||||
|
var loaded_line_data = {
|
||||||
|
"start": Vector2(data.position_x, data.position_y),
|
||||||
|
"angle": data.angles[i],
|
||||||
|
"length": data.lengths[i],
|
||||||
|
"color": Color(data.color)
|
||||||
|
}
|
||||||
|
add_line(loaded_line_data)
|
||||||
|
if idx != -1:
|
||||||
|
title.point_text = str("Point: ", idx + 1)
|
||||||
|
else:
|
||||||
|
title.point_text = str("Point: ", get_parent().get_child_count())
|
||||||
|
pos_x.value = data.position_x
|
||||||
|
pos_y.value = data.position_y
|
||||||
|
color_picker_button.color = Color(data.color)
|
||||||
|
update_boundary_color(color_picker_button.color)
|
||||||
|
color_picker_button.connect("color_changed", self, "_on_color_changed")
|
||||||
|
pos_x.connect("value_changed", self, "_on_X_value_changed")
|
||||||
|
pos_y.connect("value_changed", self, "_on_Y_value_changed")
|
||||||
|
if !start_data:
|
||||||
|
update_data_to_project()
|
||||||
|
|
||||||
|
|
||||||
|
func update_boundary_color(color: Color):
|
||||||
|
var luminance = (0.2126 * color.r) + (0.7152 * color.g) + (0.0722 * color.b)
|
||||||
|
color.a = 0.9 - luminance * 0.4 # Interpolates between 0.5 to 0.9
|
||||||
|
boundary_l.color = color
|
||||||
|
boundary_r.color = color
|
||||||
|
boundary_b.color = color
|
||||||
|
|
||||||
|
|
||||||
|
# Signals
|
||||||
|
func _on_AddLine_pressed() -> void:
|
||||||
|
add_line()
|
||||||
|
update_data_to_project()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_Delete_pressed() -> void:
|
||||||
|
Global.perspective_editor.delete_point(get_index())
|
||||||
|
|
||||||
|
|
||||||
|
func _on_color_changed(_color: Color):
|
||||||
|
update_boundary_color(_color)
|
||||||
|
data.color = _color.to_html()
|
||||||
|
refresh(-1)
|
||||||
|
update_data_to_project()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_X_value_changed(value: float) -> void:
|
||||||
|
data.position_x = value
|
||||||
|
refresh(-1)
|
||||||
|
update_data_to_project()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_Y_value_changed(value):
|
||||||
|
data.position_y = value
|
||||||
|
refresh(-1)
|
||||||
|
update_data_to_project()
|
||||||
|
|
||||||
|
|
||||||
|
func _angle_changed(value: float, line_button):
|
||||||
|
var line_index = line_button.get_index()
|
||||||
|
data.angles[line_index] = value
|
||||||
|
refresh(line_index)
|
||||||
|
update_data_to_project()
|
||||||
|
|
||||||
|
|
||||||
|
func _length_changed(value: float, line_button):
|
||||||
|
var line_index = line_button.get_index()
|
||||||
|
data.lengths[line_index] = value
|
||||||
|
refresh(line_index)
|
||||||
|
update_data_to_project()
|
||||||
|
|
||||||
|
|
||||||
|
func _remove_line_pressed(line_button):
|
||||||
|
var index = line_button.get_index()
|
||||||
|
remove_line(index)
|
||||||
|
line_button.queue_free()
|
||||||
|
update_data_to_project()
|
||||||
|
|
||||||
|
|
||||||
|
# Methods
|
||||||
|
func add_line(loaded_line_data = null, is_tracker := false):
|
||||||
|
var p_size = Global.current_project.size
|
||||||
|
var default_line_data = {
|
||||||
|
"start": Vector2(data.position_x, data.position_y),
|
||||||
|
"angle": 0,
|
||||||
|
"length": 19999,
|
||||||
|
"color": Color(data.color)
|
||||||
|
}
|
||||||
|
if default_line_data.start.x > p_size.x / 2:
|
||||||
|
# If new line is created ahed of half project distance then
|
||||||
|
# reverse it's angle (for beautification)
|
||||||
|
default_line_data.angle = 180
|
||||||
|
|
||||||
|
# Check if we have loading data instead of creating line
|
||||||
|
# Then THAT should be our data
|
||||||
|
if loaded_line_data:
|
||||||
|
default_line_data = loaded_line_data
|
||||||
|
|
||||||
|
if is_tracker: # if we are creating tracker line then length adjustment is not required
|
||||||
|
if tracker_line != null: # Also if the tracker line already exists then cancel creation
|
||||||
|
return
|
||||||
|
else: # If we are not creating a perspective line then adjust it's length
|
||||||
|
var suitable_length = sqrt(pow(p_size.x, 2) + pow(p_size.y, 2))
|
||||||
|
default_line_data.length = suitable_length
|
||||||
|
|
||||||
|
# Create the visual line
|
||||||
|
var line = preload("res://src/UI/PerspectiveEditor/PerspectiveLine.tscn").instance()
|
||||||
|
line.initiate(default_line_data)
|
||||||
|
|
||||||
|
# Set it's mode accordingly
|
||||||
|
if is_tracker: # Settings for Tracker mode
|
||||||
|
line.track_mouse = true
|
||||||
|
tracker_line = line
|
||||||
|
tracker_line.hide_perspective_line()
|
||||||
|
else: # Settings for Normal mode
|
||||||
|
var line_button = preload("res://src/UI/PerspectiveEditor/LineButton.tscn").instance()
|
||||||
|
line_buttons_container.add_child(line_button)
|
||||||
|
var index = line_button.get_parent().get_child_count() - 2
|
||||||
|
line_button.get_parent().move_child(line_button, index)
|
||||||
|
|
||||||
|
var line_name = str(
|
||||||
|
"Line", line_button.get_index() + 1, " (", int(default_line_data.angle), "°)"
|
||||||
|
)
|
||||||
|
line_button.text = line_name
|
||||||
|
|
||||||
|
var remove_button = line_button.find_node("Delete")
|
||||||
|
var angle_slider = line_button.find_node("AngleSlider")
|
||||||
|
var length_slider = line_button.find_node("LengthSlider")
|
||||||
|
|
||||||
|
angle_slider.value = default_line_data.angle
|
||||||
|
length_slider.value = default_line_data.length
|
||||||
|
if !loaded_line_data:
|
||||||
|
data.angles.append(angle_slider.value)
|
||||||
|
data.lengths.append(length_slider.value)
|
||||||
|
|
||||||
|
angle_slider.connect("value_changed", self, "_angle_changed", [line_button])
|
||||||
|
length_slider.connect("value_changed", self, "_length_changed", [line_button])
|
||||||
|
remove_button.connect("pressed", self, "_remove_line_pressed", [line_button])
|
||||||
|
perspective_lines.append(line)
|
||||||
|
|
||||||
|
|
||||||
|
func remove_line(line_index):
|
||||||
|
var line_to_remove = perspective_lines[line_index]
|
||||||
|
perspective_lines.remove(line_index)
|
||||||
|
data.angles.remove(line_index)
|
||||||
|
data.lengths.remove(line_index)
|
||||||
|
line_to_remove.queue_free()
|
||||||
|
|
||||||
|
|
||||||
|
func update_data_to_project(removal := false):
|
||||||
|
var project = Global.current_project
|
||||||
|
var idx = get_index()
|
||||||
|
if removal:
|
||||||
|
project.vanishing_points.remove(idx)
|
||||||
|
return
|
||||||
|
if idx < project.vanishing_points.size():
|
||||||
|
project.vanishing_points[idx] = data
|
||||||
|
else:
|
||||||
|
project.vanishing_points.append(data)
|
||||||
|
Global.current_project.has_changed = true
|
||||||
|
|
||||||
|
|
||||||
|
func refresh(index: int):
|
||||||
|
if index == -1: # means all lines should be refreshed
|
||||||
|
refresh_tracker()
|
||||||
|
for i in data.angles.size():
|
||||||
|
refresh_line(i)
|
||||||
|
else:
|
||||||
|
refresh_line(index)
|
||||||
|
|
||||||
|
|
||||||
|
func refresh_line(index: int):
|
||||||
|
var line_data = {
|
||||||
|
"start": Vector2(data.position_x, data.position_y),
|
||||||
|
"angle": data.angles[index],
|
||||||
|
"length": data.lengths[index],
|
||||||
|
"color": Color(data.color)
|
||||||
|
}
|
||||||
|
var line_button = line_buttons_container.get_child(index)
|
||||||
|
var line_name = str("Line", line_button.get_index() + 1, " (", int(line_data.angle), "°)")
|
||||||
|
line_button.text = line_name
|
||||||
|
perspective_lines[index].refresh(line_data)
|
||||||
|
|
||||||
|
|
||||||
|
func refresh_tracker():
|
||||||
|
var line_data = {
|
||||||
|
"start": Vector2(data.position_x, data.position_y),
|
||||||
|
"angle": tracker_line._data.angle,
|
||||||
|
"length": tracker_line._data.length,
|
||||||
|
"color": Color(data.color)
|
||||||
|
}
|
||||||
|
tracker_line.refresh(line_data)
|
||||||
|
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
if tracker_line:
|
||||||
|
tracker_line.queue_free()
|
||||||
|
tracker_line = null
|
||||||
|
for idx in perspective_lines.size():
|
||||||
|
perspective_lines[idx].queue_free()
|
171
src/UI/PerspectiveEditor/VanishingPoint.tscn
Normal file
171
src/UI/PerspectiveEditor/VanishingPoint.tscn
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
[gd_scene load_steps=6 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://src/UI/Nodes/ValueSlider.tscn" type="PackedScene" id=1]
|
||||||
|
[ext_resource path="res://src/UI/PerspectiveEditor/VanishingPoint.gd" type="Script" id=2]
|
||||||
|
[ext_resource path="res://src/UI/Nodes/CollapsibleContainer.tscn" type="PackedScene" id=3]
|
||||||
|
[ext_resource path="res://assets/graphics/misc/value_arrow.svg" type="Texture" id=4]
|
||||||
|
[ext_resource path="res://src/UI/PerspectiveEditor/PointCollapseContainer.gd" type="Script" id=5]
|
||||||
|
|
||||||
|
[node name="VanishingPoint" type="VBoxContainer" groups=["Entry"]]
|
||||||
|
margin_right = 261.0
|
||||||
|
margin_bottom = 145.0
|
||||||
|
script = ExtResource( 2 )
|
||||||
|
|
||||||
|
[node name="TitleContainer" type="HBoxContainer" parent="."]
|
||||||
|
margin_right = 261.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
|
||||||
|
[node name="PointCollapseContainer" type="Button" parent="TitleContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
margin_right = 207.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
mouse_default_cursor_shape = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
theme_type_variation = "CollapsibleCheckBox"
|
||||||
|
toggle_mode = true
|
||||||
|
script = ExtResource( 5 )
|
||||||
|
|
||||||
|
[node name="TextureRect" type="TextureRect" parent="TitleContainer/PointCollapseContainer" groups=["UIButtons"]]
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
margin_left = 2.0
|
||||||
|
margin_top = -6.0
|
||||||
|
margin_right = 14.0
|
||||||
|
margin_bottom = 6.0
|
||||||
|
rect_rotation = -90.0
|
||||||
|
rect_pivot_offset = Vector2( 6, 6 )
|
||||||
|
texture = ExtResource( 4 )
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="TitleContainer/PointCollapseContainer"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_left = 14.0
|
||||||
|
theme_type_variation = "Header"
|
||||||
|
valign = 1
|
||||||
|
|
||||||
|
[node name="ColorPickerButton" type="ColorPickerButton" parent="TitleContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
margin_left = 211.0
|
||||||
|
margin_right = 261.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
rect_min_size = Vector2( 50, 0 )
|
||||||
|
|
||||||
|
[node name="Content" type="HBoxContainer" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
margin_top = 24.0
|
||||||
|
margin_right = 261.0
|
||||||
|
margin_bottom = 130.0
|
||||||
|
|
||||||
|
[node name="Spacer" type="Control" parent="Content"]
|
||||||
|
margin_right = 5.0
|
||||||
|
margin_bottom = 106.0
|
||||||
|
rect_min_size = Vector2( 5, 0 )
|
||||||
|
|
||||||
|
[node name="BoundaryL" type="ColorRect" parent="Content"]
|
||||||
|
margin_left = 9.0
|
||||||
|
margin_right = 11.0
|
||||||
|
margin_bottom = 106.0
|
||||||
|
rect_min_size = Vector2( 2, 0 )
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="Content"]
|
||||||
|
margin_left = 15.0
|
||||||
|
margin_right = 255.0
|
||||||
|
margin_bottom = 106.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="PointInfo" type="HBoxContainer" parent="Content/VBoxContainer"]
|
||||||
|
margin_right = 240.0
|
||||||
|
margin_bottom = 52.0
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="Content/VBoxContainer/PointInfo"]
|
||||||
|
margin_right = 56.0
|
||||||
|
margin_bottom = 52.0
|
||||||
|
size_flags_vertical = 5
|
||||||
|
text = "Position:"
|
||||||
|
|
||||||
|
[node name="Position" type="VBoxContainer" parent="Content/VBoxContainer/PointInfo"]
|
||||||
|
margin_left = 60.0
|
||||||
|
margin_right = 240.0
|
||||||
|
margin_bottom = 52.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="X" parent="Content/VBoxContainer/PointInfo/Position" instance=ExtResource( 1 )]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
margin_right = 180.0
|
||||||
|
step = 0.5
|
||||||
|
allow_greater = true
|
||||||
|
allow_lesser = true
|
||||||
|
prefix = "X :"
|
||||||
|
|
||||||
|
[node name="Y" parent="Content/VBoxContainer/PointInfo/Position" instance=ExtResource( 1 )]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
margin_top = 28.0
|
||||||
|
margin_right = 180.0
|
||||||
|
margin_bottom = 52.0
|
||||||
|
step = 0.5
|
||||||
|
allow_greater = true
|
||||||
|
allow_lesser = true
|
||||||
|
prefix = "Y :"
|
||||||
|
|
||||||
|
[node name="CollapsibleContainer" parent="Content/VBoxContainer" instance=ExtResource( 3 )]
|
||||||
|
margin_top = 56.0
|
||||||
|
margin_right = 240.0
|
||||||
|
margin_bottom = 76.0
|
||||||
|
text = "Lines"
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="Content/VBoxContainer/CollapsibleContainer"]
|
||||||
|
visible = false
|
||||||
|
margin_top = 24.0
|
||||||
|
margin_right = 261.0
|
||||||
|
margin_bottom = 44.0
|
||||||
|
|
||||||
|
[node name="Spacer" type="Control" parent="Content/VBoxContainer/CollapsibleContainer/HBoxContainer"]
|
||||||
|
margin_right = 20.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
rect_min_size = Vector2( 20, 0 )
|
||||||
|
|
||||||
|
[node name="VSeparator" type="VSeparator" parent="Content/VBoxContainer/CollapsibleContainer/HBoxContainer"]
|
||||||
|
margin_right = 4.0
|
||||||
|
margin_bottom = 40.0
|
||||||
|
|
||||||
|
[node name="LinesContainer" type="VBoxContainer" parent="Content/VBoxContainer/CollapsibleContainer/HBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
margin_left = 24.0
|
||||||
|
margin_right = 261.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="AddLine" type="Button" parent="Content/VBoxContainer/CollapsibleContainer/HBoxContainer/LinesContainer"]
|
||||||
|
margin_right = 237.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
text = "Add Line"
|
||||||
|
|
||||||
|
[node name="Delete" type="Button" parent="Content/VBoxContainer"]
|
||||||
|
margin_top = 80.0
|
||||||
|
margin_right = 240.0
|
||||||
|
margin_bottom = 100.0
|
||||||
|
rect_min_size = Vector2( 40, 0 )
|
||||||
|
text = "Delete Point"
|
||||||
|
|
||||||
|
[node name="BoundaryB" type="ColorRect" parent="Content/VBoxContainer"]
|
||||||
|
margin_top = 104.0
|
||||||
|
margin_right = 240.0
|
||||||
|
margin_bottom = 106.0
|
||||||
|
rect_min_size = Vector2( 0, 2 )
|
||||||
|
|
||||||
|
[node name="BoundaryR" type="ColorRect" parent="Content"]
|
||||||
|
margin_left = 259.0
|
||||||
|
margin_right = 261.0
|
||||||
|
margin_bottom = 106.0
|
||||||
|
rect_min_size = Vector2( 2, 0 )
|
||||||
|
|
||||||
|
[node name="HSeparator" type="HSeparator" parent="."]
|
||||||
|
margin_top = 134.0
|
||||||
|
margin_right = 261.0
|
||||||
|
margin_bottom = 144.0
|
||||||
|
custom_constants/separation = 10
|
||||||
|
|
||||||
|
[connection signal="toggled" from="TitleContainer/PointCollapseContainer" to="TitleContainer/PointCollapseContainer" method="_on_Button_toggled"]
|
||||||
|
[connection signal="pressed" from="Content/VBoxContainer/CollapsibleContainer/HBoxContainer/LinesContainer/AddLine" to="." method="_on_AddLine_pressed"]
|
||||||
|
[connection signal="pressed" from="Content/VBoxContainer/Delete" to="." method="_on_Delete_pressed"]
|
|
@ -123,6 +123,7 @@ func _setup_view_menu() -> void:
|
||||||
"Show Pixel Grid",
|
"Show Pixel Grid",
|
||||||
"Show Rulers",
|
"Show Rulers",
|
||||||
"Show Guides",
|
"Show Guides",
|
||||||
|
"Show Mouse Guides",
|
||||||
"Snap To",
|
"Snap To",
|
||||||
]
|
]
|
||||||
view_menu = view_menu_button.get_popup()
|
view_menu = view_menu_button.get_popup()
|
||||||
|
@ -160,8 +161,13 @@ func _setup_view_menu() -> void:
|
||||||
var show_guides: bool = Global.config_cache.get_value(
|
var show_guides: bool = Global.config_cache.get_value(
|
||||||
"view_menu", "show_guides", Global.show_guides
|
"view_menu", "show_guides", Global.show_guides
|
||||||
)
|
)
|
||||||
|
var show_mouse_guides: bool = Global.config_cache.get_value(
|
||||||
|
"view_menu", "show_mouse_guides", Global.show_mouse_guides
|
||||||
|
)
|
||||||
if show_guides != Global.show_guides:
|
if show_guides != Global.show_guides:
|
||||||
_toggle_show_guides()
|
_toggle_show_guides()
|
||||||
|
if show_mouse_guides != Global.show_mouse_guides:
|
||||||
|
_toggle_show_mouse_guides()
|
||||||
|
|
||||||
|
|
||||||
func _setup_tile_mode_submenu(item: String) -> void:
|
func _setup_tile_mode_submenu(item: String) -> void:
|
||||||
|
@ -460,6 +466,8 @@ func view_menu_id_pressed(id: int) -> void:
|
||||||
_toggle_show_rulers()
|
_toggle_show_rulers()
|
||||||
Global.ViewMenu.SHOW_GUIDES:
|
Global.ViewMenu.SHOW_GUIDES:
|
||||||
_toggle_show_guides()
|
_toggle_show_guides()
|
||||||
|
Global.ViewMenu.SHOW_MOUSE_GUIDES:
|
||||||
|
_toggle_show_mouse_guides()
|
||||||
_:
|
_:
|
||||||
_handle_metadata(id, view_menu_button)
|
_handle_metadata(id, view_menu_button)
|
||||||
|
|
||||||
|
@ -574,8 +582,6 @@ func _toggle_show_grid() -> void:
|
||||||
func _toggle_show_pixel_grid() -> void:
|
func _toggle_show_pixel_grid() -> void:
|
||||||
Global.draw_pixel_grid = !Global.draw_pixel_grid
|
Global.draw_pixel_grid = !Global.draw_pixel_grid
|
||||||
view_menu.set_item_checked(Global.ViewMenu.SHOW_PIXEL_GRID, Global.draw_pixel_grid)
|
view_menu.set_item_checked(Global.ViewMenu.SHOW_PIXEL_GRID, Global.draw_pixel_grid)
|
||||||
if Global.canvas.pixel_grid:
|
|
||||||
Global.canvas.pixel_grid.update()
|
|
||||||
|
|
||||||
|
|
||||||
func _toggle_show_rulers() -> void:
|
func _toggle_show_rulers() -> void:
|
||||||
|
@ -598,6 +604,15 @@ func _toggle_show_guides() -> void:
|
||||||
guide.visible = Global.show_y_symmetry_axis and Global.show_guides
|
guide.visible = Global.show_y_symmetry_axis and Global.show_guides
|
||||||
|
|
||||||
|
|
||||||
|
func _toggle_show_mouse_guides() -> void:
|
||||||
|
Global.show_mouse_guides = !Global.show_mouse_guides
|
||||||
|
view_menu.set_item_checked(Global.ViewMenu.SHOW_MOUSE_GUIDES, Global.show_mouse_guides)
|
||||||
|
if Global.show_mouse_guides:
|
||||||
|
if Global.canvas.mouse_guide_container:
|
||||||
|
Global.canvas.mouse_guide_container.get_child(0).update()
|
||||||
|
Global.canvas.mouse_guide_container.get_child(1).update()
|
||||||
|
|
||||||
|
|
||||||
func _toggle_zen_mode() -> void:
|
func _toggle_zen_mode() -> void:
|
||||||
for i in ui_elements.size():
|
for i in ui_elements.size():
|
||||||
if ui_elements[i].name == "Main Canvas":
|
if ui_elements[i].name == "Main Canvas":
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=48 format=2]
|
[gd_scene load_steps=49 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://src/UI/Tools/Tools.tscn" type="PackedScene" id=1]
|
[ext_resource path="res://src/UI/Tools/Tools.tscn" type="PackedScene" id=1]
|
||||||
[ext_resource path="res://src/UI/Canvas/CanvasPreview.tscn" type="PackedScene" id=2]
|
[ext_resource path="res://src/UI/Canvas/CanvasPreview.tscn" type="PackedScene" id=2]
|
||||||
|
@ -11,6 +11,7 @@
|
||||||
[ext_resource path="res://src/Shaders/TransparentChecker.shader" type="Shader" id=9]
|
[ext_resource path="res://src/Shaders/TransparentChecker.shader" type="Shader" id=9]
|
||||||
[ext_resource path="res://src/UI/GlobalToolOptions/GlobalToolOptions.tscn" type="PackedScene" id=10]
|
[ext_resource path="res://src/UI/GlobalToolOptions/GlobalToolOptions.tscn" type="PackedScene" id=10]
|
||||||
[ext_resource path="res://src/UI/ReferenceImages/ReferencesPanel.tscn" type="PackedScene" id=11]
|
[ext_resource path="res://src/UI/ReferenceImages/ReferencesPanel.tscn" type="PackedScene" id=11]
|
||||||
|
[ext_resource path="res://src/UI/PerspectiveEditor/PerspectiveEditor.tscn" type="PackedScene" id=12]
|
||||||
[ext_resource path="res://addons/dockable_container/layout.gd" type="Script" id=14]
|
[ext_resource path="res://addons/dockable_container/layout.gd" type="Script" id=14]
|
||||||
[ext_resource path="res://src/UI/CanvasPreviewContainer/CanvasPreviewContainer.tscn" type="PackedScene" id=16]
|
[ext_resource path="res://src/UI/CanvasPreviewContainer/CanvasPreviewContainer.tscn" type="PackedScene" id=16]
|
||||||
[ext_resource path="res://src/UI/ColorPickers/ColorPickers.tscn" type="PackedScene" id=17]
|
[ext_resource path="res://src/UI/ColorPickers/ColorPickers.tscn" type="PackedScene" id=17]
|
||||||
|
@ -34,7 +35,7 @@ shader_param/size = Vector2( 100, 100 )
|
||||||
[sub_resource type="Resource" id=1]
|
[sub_resource type="Resource" id=1]
|
||||||
resource_name = "Tabs"
|
resource_name = "Tabs"
|
||||||
script = ExtResource( 36 )
|
script = ExtResource( 36 )
|
||||||
names = PoolStringArray( "Tools" )
|
names = PoolStringArray( "Tools", "Perspective Editor" )
|
||||||
current_tab = 0
|
current_tab = 0
|
||||||
|
|
||||||
[sub_resource type="Resource" id=8]
|
[sub_resource type="Resource" id=8]
|
||||||
|
@ -404,6 +405,11 @@ margin_left = 1079.0
|
||||||
margin_right = 1080.0
|
margin_right = 1080.0
|
||||||
margin_bottom = 1004.0
|
margin_bottom = 1004.0
|
||||||
|
|
||||||
|
[node name="Perspective Editor" parent="DockableContainer" instance=ExtResource( 12 )]
|
||||||
|
visible = false
|
||||||
|
margin_right = -1010.0
|
||||||
|
margin_bottom = -710.0
|
||||||
|
|
||||||
[connection signal="item_rect_changed" from="DockableContainer/Main Canvas" to="." method="_on_main_canvas_item_rect_changed"]
|
[connection signal="item_rect_changed" from="DockableContainer/Main Canvas" to="." method="_on_main_canvas_item_rect_changed"]
|
||||||
[connection signal="visibility_changed" from="DockableContainer/Main Canvas" to="." method="_on_main_canvas_visibility_changed"]
|
[connection signal="visibility_changed" from="DockableContainer/Main Canvas" to="." method="_on_main_canvas_visibility_changed"]
|
||||||
[connection signal="reposition_active_tab_request" from="DockableContainer/Main Canvas/TabsContainer/Tabs" to="DockableContainer/Main Canvas/TabsContainer/Tabs" method="_on_Tabs_reposition_active_tab_request"]
|
[connection signal="reposition_active_tab_request" from="DockableContainer/Main Canvas/TabsContainer/Tabs" to="DockableContainer/Main Canvas/TabsContainer/Tabs" method="_on_Tabs_reposition_active_tab_request"]
|
||||||
|
|
Loading…
Reference in a new issue