Compare commits
23 commits
5fdcd225dc
...
2607426926
Author | SHA1 | Date | |
---|---|---|---|
|
2607426926 | ||
|
6224d06428 | ||
|
6459151549 | ||
|
fe6efb0f1d | ||
|
8b1367494d | ||
|
01b55aca07 | ||
|
5f53a3eb7b | ||
|
658477ed4b | ||
|
3fb8484ac5 | ||
|
0484b1012f | ||
|
b87a8e2ab8 | ||
|
e6c4a72158 | ||
|
1dcb696c35 | ||
|
d580523c6e | ||
|
11da07b9ac | ||
|
7cf87ac142 | ||
|
bd7d3b19cc | ||
|
996a234d0d | ||
|
77f6bcf07b | ||
|
fede2d8e6f | ||
|
d0ecf3b03d | ||
|
3d65e48c92 | ||
|
a17ad78c2d |
|
@ -3,16 +3,23 @@ Name=Pixelorama
|
|||
GenericName=2D sprite editor
|
||||
GenericName[el]=Επεξεργαστής δισδιάστατων εικόνων
|
||||
GenericName[fr]=Éditeur de sprites 2D
|
||||
GenericName[ru]=2Д редактор спрайтов
|
||||
GenericName[pt_BR]=Editor de sprites 2D
|
||||
GenericName[uk]=2Д редактор спрайтів
|
||||
GenericName[zh_CN]=2D 精灵编辑器
|
||||
Comment=Create and edit static or animated 2D sprites
|
||||
Comment[el]=Δημιουργήστε και επεξεργαστείτε στατικές ή κινούμενες δισδιάστατες εικόνες
|
||||
Comment[fr]=Créez et modifiez des sprites 2D statiques ou animées
|
||||
Comment[ru]=Создавайте и редактируйте статичные и анимированные 2Д спрайты
|
||||
Comment[pt_BR]=Crie e edite sprites 2D estáticos ou animados
|
||||
Comment[uk]=Створюйте та редагуйте статичні та анімовані 2Д спрайти
|
||||
Comment[zh_CN]=创建并编辑 2D 精灵图片或动画
|
||||
Exec=pixelorama
|
||||
Icon=pixelorama
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Graphics;2DGraphics;RasterGraphics;
|
||||
Keywords=pixel;retro;animation;art;image;2d;sprite;graphics;drawing;editor;
|
||||
Keywords[ru]=pixel;retro;animation;art;image;2d;sprite;graphics;drawing;editor;пиксель;ретро;анимация;арт;изображение;2д;спрайт;графика;рисование;редактор;
|
||||
Keywords[uk]=pixel;retro;animation;art;image;2d;sprite;graphics;drawing;editor;піксель;ретро;анімація;арт;зображення;2д;спрайт;графіка;малювання;редактор;
|
||||
MimeType=image/pxo;image/png;image/bmp;image/vnd.radiance;image/jpeg;image/svg+xml;image/x-tga;image/webp;
|
||||
|
|
BIN
assets/graphics/misc/x_minus_y_mirror_off.png
Normal file
After Width: | Height: | Size: 218 B |
34
assets/graphics/misc/x_minus_y_mirror_off.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://1kj5gcswa3t2"
|
||||
path="res://.godot/imported/x_minus_y_mirror_off.png-da237e3b5b7ad1dfef1c935385f53dc5.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/graphics/misc/x_minus_y_mirror_off.png"
|
||||
dest_files=["res://.godot/imported/x_minus_y_mirror_off.png-da237e3b5b7ad1dfef1c935385f53dc5.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
|
BIN
assets/graphics/misc/x_minus_y_mirror_on.png
Normal file
After Width: | Height: | Size: 187 B |
34
assets/graphics/misc/x_minus_y_mirror_on.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dn14bkxwdqsfk"
|
||||
path="res://.godot/imported/x_minus_y_mirror_on.png-0e9186904d8241facc4a0c1190f32c53.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/graphics/misc/x_minus_y_mirror_on.png"
|
||||
dest_files=["res://.godot/imported/x_minus_y_mirror_on.png-0e9186904d8241facc4a0c1190f32c53.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
|
BIN
assets/graphics/misc/xy_mirror_off.png
Normal file
After Width: | Height: | Size: 183 B |
34
assets/graphics/misc/xy_mirror_off.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dlxhm0ronna25"
|
||||
path="res://.godot/imported/xy_mirror_off.png-8d2fd9ebdf350f0cd384fdf39fed4ec1.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/graphics/misc/xy_mirror_off.png"
|
||||
dest_files=["res://.godot/imported/xy_mirror_off.png-8d2fd9ebdf350f0cd384fdf39fed4ec1.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
|
BIN
assets/graphics/misc/xy_mirror_on.png
Normal file
After Width: | Height: | Size: 185 B |
34
assets/graphics/misc/xy_mirror_on.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cu2uqp5oupt80"
|
||||
path="res://.godot/imported/xy_mirror_on.png-95d443df3b6d17add41283bdd720ea7e.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/graphics/misc/xy_mirror_on.png"
|
||||
dest_files=["res://.godot/imported/xy_mirror_on.png-95d443df3b6d17add41283bdd720ea7e.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
|
Before Width: | Height: | Size: 218 B After Width: | Height: | Size: 374 B |
Before Width: | Height: | Size: 162 B After Width: | Height: | Size: 136 B |
|
@ -184,7 +184,7 @@ var show_x_symmetry_axis := false
|
|||
## If true, the y symmetry guide ( | ) is visible.
|
||||
var show_y_symmetry_axis := false
|
||||
## If true, the x=y symmetry guide ( / ) is visible.
|
||||
var show_x_y_symmetry_axis := false
|
||||
var show_xy_symmetry_axis := false
|
||||
## If true, the x==y symmetry guide ( \ ) is visible.
|
||||
var show_x_minus_y_symmetry_axis := false
|
||||
|
||||
|
@ -337,55 +337,8 @@ var default_height := 64 ## Found in Preferences. The default height of startup
|
|||
var default_fill_color := Color(0, 0, 0, 0)
|
||||
## Found in Preferences. The distance to the guide or grig below which cursor snapping activates.
|
||||
var snapping_distance := 32.0
|
||||
## Found in Preferences. The grid type defined by [enum GridTypes] enum.
|
||||
var grid_type := GridTypes.CARTESIAN:
|
||||
set(value):
|
||||
if value == grid_type:
|
||||
return
|
||||
grid_type = value
|
||||
if is_instance_valid(canvas.grid):
|
||||
canvas.grid.queue_redraw()
|
||||
## Found in Preferences. The size of rectangular grid.
|
||||
var grid_size := Vector2i(2, 2):
|
||||
set(value):
|
||||
if value == grid_size:
|
||||
return
|
||||
grid_size = value
|
||||
if is_instance_valid(canvas.grid):
|
||||
canvas.grid.queue_redraw()
|
||||
## Found in Preferences. The size of isometric grid.
|
||||
var isometric_grid_size := Vector2i(16, 8):
|
||||
set(value):
|
||||
if value == isometric_grid_size:
|
||||
return
|
||||
isometric_grid_size = value
|
||||
if is_instance_valid(canvas.grid):
|
||||
canvas.grid.queue_redraw()
|
||||
## Found in Preferences. The grid offset from top-left corner of the canvas.
|
||||
var grid_offset := Vector2i.ZERO:
|
||||
set(value):
|
||||
if value == grid_offset:
|
||||
return
|
||||
grid_offset = value
|
||||
if is_instance_valid(canvas.grid):
|
||||
canvas.grid.queue_redraw()
|
||||
## Found in Preferences. If [code]true[/code], The grid draws over the area extended by
|
||||
## tile-mode as well.
|
||||
var grid_draw_over_tile_mode := false:
|
||||
set(value):
|
||||
if value == grid_draw_over_tile_mode:
|
||||
return
|
||||
grid_draw_over_tile_mode = value
|
||||
if is_instance_valid(canvas.grid):
|
||||
canvas.grid.queue_redraw()
|
||||
## Found in Preferences. The color of grid.
|
||||
var grid_color := Color.BLACK:
|
||||
set(value):
|
||||
if value == grid_color:
|
||||
return
|
||||
grid_color = value
|
||||
if is_instance_valid(canvas.grid):
|
||||
canvas.grid.queue_redraw()
|
||||
## Contains dictionaries of individual grids.
|
||||
var grids: Array[Grid] = []
|
||||
## Found in Preferences. The minimum zoom after which pixel grid gets drawn if enabled.
|
||||
var pixel_grid_show_at_zoom := 1500.0: # percentage
|
||||
set(value):
|
||||
|
@ -677,6 +630,62 @@ var cel_button_scene: PackedScene = load("res://src/UI/Timeline/CelButton.tscn")
|
|||
@onready var error_dialog: AcceptDialog = control.find_child("ErrorDialog")
|
||||
|
||||
|
||||
class Grid:
|
||||
var grid_type := GridTypes.CARTESIAN:
|
||||
set(value):
|
||||
if value == grid_type:
|
||||
return
|
||||
grid_type = value
|
||||
if is_instance_valid(Global.canvas.grid):
|
||||
Global.canvas.grid.queue_redraw()
|
||||
## Found in Preferences. The size of rectangular grid.
|
||||
var grid_size := Vector2i(2, 2):
|
||||
set(value):
|
||||
if value == grid_size:
|
||||
return
|
||||
grid_size = value
|
||||
if is_instance_valid(Global.canvas.grid):
|
||||
Global.canvas.grid.queue_redraw()
|
||||
## Found in Preferences. The size of isometric grid.
|
||||
var isometric_grid_size := Vector2i(16, 8):
|
||||
set(value):
|
||||
if value == isometric_grid_size:
|
||||
return
|
||||
isometric_grid_size = value
|
||||
if is_instance_valid(Global.canvas.grid):
|
||||
Global.canvas.grid.queue_redraw()
|
||||
## Found in Preferences. The grid offset from top-left corner of the canvas.
|
||||
var grid_offset := Vector2i.ZERO:
|
||||
set(value):
|
||||
if value == grid_offset:
|
||||
return
|
||||
grid_offset = value
|
||||
if is_instance_valid(Global.canvas.grid):
|
||||
Global.canvas.grid.queue_redraw()
|
||||
## Found in Preferences. If [code]true[/code], The grid draws over the area extended by
|
||||
## tile-mode as well.
|
||||
var grid_draw_over_tile_mode := false:
|
||||
set(value):
|
||||
if value == grid_draw_over_tile_mode:
|
||||
return
|
||||
grid_draw_over_tile_mode = value
|
||||
if is_instance_valid(Global.canvas.grid):
|
||||
Global.canvas.grid.queue_redraw()
|
||||
## Found in Preferences. The color of grid.
|
||||
var grid_color := Color.BLACK:
|
||||
set(value):
|
||||
if value == grid_color:
|
||||
return
|
||||
grid_color = value
|
||||
if is_instance_valid(Global.canvas.grid):
|
||||
Global.canvas.grid.queue_redraw()
|
||||
|
||||
func _init(properties := {}) -> void:
|
||||
Global.grids.append(self)
|
||||
for prop in properties.keys():
|
||||
set(prop, properties[prop])
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# Load settings from the config file
|
||||
config_cache.load(CONFIG_PATH)
|
||||
|
@ -713,6 +722,8 @@ func _init() -> void:
|
|||
|
||||
|
||||
func _ready() -> void:
|
||||
# Initialize Grid
|
||||
Grid.new() # gets auto added to grids array
|
||||
_initialize_keychain()
|
||||
default_width = config_cache.get_value("preferences", "default_width", default_width)
|
||||
default_height = config_cache.get_value("preferences", "default_height", default_height)
|
||||
|
@ -729,13 +740,23 @@ func _ready() -> void:
|
|||
if get(pref) == null:
|
||||
continue
|
||||
var value = config_cache.get_value("preferences", pref)
|
||||
set(pref, value)
|
||||
if pref == "grids":
|
||||
if value:
|
||||
update_grids(value)
|
||||
else:
|
||||
set(pref, value)
|
||||
if OS.is_sandboxed():
|
||||
Global.use_native_file_dialogs = true
|
||||
await get_tree().process_frame
|
||||
project_switched.emit()
|
||||
|
||||
|
||||
func update_grids(grids_data: Dictionary):
|
||||
grids.clear()
|
||||
for grid_idx in grids_data.size():
|
||||
Grid.new(grids_data[grid_idx]) # gets auto added to grids array
|
||||
|
||||
|
||||
func _initialize_keychain() -> void:
|
||||
Keychain.config_file = config_cache
|
||||
Keychain.actions = {
|
||||
|
@ -1066,7 +1087,9 @@ func get_available_font_names() -> PackedStringArray:
|
|||
if font_name in font_names:
|
||||
continue
|
||||
font_names.append(font_name)
|
||||
for system_font_name in OS.get_system_fonts():
|
||||
var system_fonts := OS.get_system_fonts()
|
||||
system_fonts.sort()
|
||||
for system_font_name in system_fonts:
|
||||
if system_font_name in font_names:
|
||||
continue
|
||||
font_names.append(system_font_name)
|
||||
|
|
|
@ -90,9 +90,9 @@ func get_brush_files_from_directory(directory: String): # -> Array
|
|||
func add_randomised_brush(fpaths: Array, tooltip_name: String) -> void:
|
||||
# Attempt to load the images from the file paths.
|
||||
var loaded_images: Array = []
|
||||
for filen in fpaths:
|
||||
for file in fpaths:
|
||||
var image := Image.new()
|
||||
var err := image.load(filen)
|
||||
var err := image.load(file)
|
||||
if err == OK:
|
||||
image.convert(Image.FORMAT_RGBA8)
|
||||
loaded_images.append(image)
|
||||
|
|
|
@ -36,9 +36,10 @@ func does_palette_exist(palette_name: String) -> bool:
|
|||
|
||||
|
||||
func select_palette(palette_name: String) -> void:
|
||||
current_palette = palettes.get(palette_name)
|
||||
current_palette = palettes.get(palette_name, null)
|
||||
_clear_selected_colors()
|
||||
Global.config_cache.set_value("data", "last_palette", current_palette.name)
|
||||
if is_instance_valid(current_palette):
|
||||
Global.config_cache.set_value("data", "last_palette", current_palette.name)
|
||||
palette_selected.emit(palette_name)
|
||||
|
||||
|
||||
|
@ -224,6 +225,7 @@ func current_palete_delete(permanent := true) -> void:
|
|||
select_palette(palettes.keys()[0])
|
||||
else:
|
||||
current_palette = null
|
||||
select_palette("")
|
||||
|
||||
|
||||
func current_palette_add_color(mouse_button: int, start_index := 0) -> void:
|
||||
|
|
|
@ -15,8 +15,8 @@ const X_MINUS_Y_LINE := Vector2(0.707107, 0.707107)
|
|||
var picking_color_for := MOUSE_BUTTON_LEFT
|
||||
var horizontal_mirror := false
|
||||
var vertical_mirror := false
|
||||
var diagonal_mirror := false
|
||||
var diagonal_opposite_mirror := false
|
||||
var diagonal_xy_mirror := false
|
||||
var diagonal_x_minus_y_mirror := false
|
||||
var pixel_perfect := false
|
||||
var alpha_locked := false
|
||||
|
||||
|
@ -534,23 +534,23 @@ func get_mirrored_positions(
|
|||
if vertical_mirror:
|
||||
positions.append(calculate_mirror_vertical(mirror_x, project, offset))
|
||||
else:
|
||||
if diagonal_mirror:
|
||||
if diagonal_xy_mirror:
|
||||
positions.append(calculate_mirror_xy(mirror_x, project))
|
||||
if diagonal_opposite_mirror:
|
||||
if diagonal_x_minus_y_mirror:
|
||||
positions.append(calculate_mirror_x_minus_y(mirror_x, project))
|
||||
if vertical_mirror:
|
||||
var mirror_y := calculate_mirror_vertical(pos, project, offset)
|
||||
positions.append(mirror_y)
|
||||
if diagonal_mirror:
|
||||
if diagonal_xy_mirror:
|
||||
positions.append(calculate_mirror_xy(mirror_y, project))
|
||||
if diagonal_opposite_mirror:
|
||||
if diagonal_x_minus_y_mirror:
|
||||
positions.append(calculate_mirror_x_minus_y(mirror_y, project))
|
||||
if diagonal_mirror:
|
||||
if diagonal_xy_mirror:
|
||||
var mirror_diagonal := calculate_mirror_xy(pos, project)
|
||||
positions.append(mirror_diagonal)
|
||||
if not horizontal_mirror and not vertical_mirror:
|
||||
if not horizontal_mirror and not vertical_mirror and diagonal_x_minus_y_mirror:
|
||||
positions.append(calculate_mirror_x_minus_y(mirror_diagonal, project))
|
||||
if diagonal_opposite_mirror:
|
||||
if diagonal_x_minus_y_mirror:
|
||||
positions.append(calculate_mirror_x_minus_y(pos, project))
|
||||
return positions
|
||||
|
||||
|
@ -564,11 +564,14 @@ func calculate_mirror_vertical(pos: Vector2i, project: Project, offset := 0) ->
|
|||
|
||||
|
||||
func calculate_mirror_xy(pos: Vector2i, project: Project) -> Vector2i:
|
||||
return Vector2i(Vector2(pos).reflect(XY_LINE).round()) + project.size - Vector2i.ONE
|
||||
return Vector2i(Vector2(pos).reflect(XY_LINE).round()) + Vector2i(project.xy_symmetry_point)
|
||||
|
||||
|
||||
func calculate_mirror_x_minus_y(pos: Vector2i, _project: Project) -> Vector2i:
|
||||
return Vector2i(Vector2(pos).reflect(X_MINUS_Y_LINE).round())
|
||||
func calculate_mirror_x_minus_y(pos: Vector2i, project: Project) -> Vector2i:
|
||||
return (
|
||||
Vector2i(Vector2(pos).reflect(X_MINUS_Y_LINE).round())
|
||||
+ Vector2i(project.x_minus_y_symmetry_point)
|
||||
)
|
||||
|
||||
|
||||
func set_button_size(button_size: int) -> void:
|
||||
|
|
|
@ -8,7 +8,7 @@ var image: ImageExtended:
|
|||
set = image_changed
|
||||
|
||||
|
||||
func _init(_image: ImageExtended, _opacity := 1.0) -> void:
|
||||
func _init(_image := ImageExtended.new(), _opacity := 1.0) -> void:
|
||||
image_texture = ImageTexture.new()
|
||||
image = _image # Set image and call setter
|
||||
opacity = _opacity
|
||||
|
@ -20,7 +20,7 @@ func image_changed(value: ImageExtended) -> void:
|
|||
image_texture.set_image(image)
|
||||
|
||||
|
||||
func get_content():
|
||||
func get_content() -> ImageExtended:
|
||||
return image
|
||||
|
||||
|
||||
|
@ -34,17 +34,19 @@ func set_content(content, texture: ImageTexture = null) -> void:
|
|||
image_texture.update(image)
|
||||
|
||||
|
||||
func create_empty_content():
|
||||
var empty_image := Image.create(
|
||||
image.get_size().x, image.get_size().y, false, Image.FORMAT_RGBA8
|
||||
)
|
||||
return empty_image
|
||||
func create_empty_content() -> ImageExtended:
|
||||
var empty := Image.create(image.get_width(), image.get_height(), false, image.get_format())
|
||||
var new_image := ImageExtended.new()
|
||||
new_image.copy_from_custom(empty, image.is_indexed)
|
||||
return new_image
|
||||
|
||||
|
||||
func copy_content():
|
||||
var copy_image := Image.create_from_data(
|
||||
image.get_width(), image.get_height(), false, Image.FORMAT_RGBA8, image.get_data()
|
||||
func copy_content() -> ImageExtended:
|
||||
var tmp_image := Image.create_from_data(
|
||||
image.get_width(), image.get_height(), false, image.get_format(), image.get_data()
|
||||
)
|
||||
var copy_image := ImageExtended.new()
|
||||
copy_image.copy_from_custom(tmp_image, image.is_indexed)
|
||||
return copy_image
|
||||
|
||||
|
||||
|
|
|
@ -87,8 +87,8 @@ func set_pixel(image: Image, position: Vector2i, color: Color, ignore_mirroring
|
|||
if (
|
||||
not Tools.horizontal_mirror
|
||||
and not Tools.vertical_mirror
|
||||
and not Tools.diagonal_mirror
|
||||
and not Tools.diagonal_opposite_mirror
|
||||
and not Tools.diagonal_xy_mirror
|
||||
and not Tools.diagonal_x_minus_y_mirror
|
||||
):
|
||||
return
|
||||
# Handle mirroring
|
||||
|
|
|
@ -74,17 +74,20 @@ func select_palette(_name: String, convert_to_rgb := true) -> void:
|
|||
|
||||
## Updates [member palette] to contain the colors of [member current_palette].
|
||||
func update_palette() -> void:
|
||||
if palette.size() != current_palette.colors.size():
|
||||
palette.resize(current_palette.colors.size())
|
||||
if not is_instance_valid(current_palette):
|
||||
return
|
||||
if palette.size() != current_palette.colors_max:
|
||||
palette.resize(current_palette.colors_max)
|
||||
palette.fill(TRANSPARENT)
|
||||
for i in current_palette.colors:
|
||||
palette[i] = current_palette.colors[i].color
|
||||
|
||||
|
||||
## Displays the actual RGBA values of each pixel in the image from indexed mode.
|
||||
func convert_indexed_to_rgb() -> void:
|
||||
if not is_indexed:
|
||||
if not is_indexed or not is_instance_valid(current_palette):
|
||||
return
|
||||
var palette_image := Palettes.current_palette.convert_to_image()
|
||||
var palette_image := current_palette.convert_to_image(false)
|
||||
var palette_texture := ImageTexture.create_from_image(palette_image)
|
||||
var shader_image_effect := ShaderImageEffect.new()
|
||||
var indices_texture := ImageTexture.create_from_image(indices_image)
|
||||
|
@ -96,9 +99,9 @@ func convert_indexed_to_rgb() -> void:
|
|||
## Automatically maps each color of the image's pixel to the closest color of the palette,
|
||||
## by finding the palette color's index and storing it in [member indices_image].
|
||||
func convert_rgb_to_indexed() -> void:
|
||||
if not is_indexed:
|
||||
if not is_indexed or not is_instance_valid(current_palette):
|
||||
return
|
||||
var palette_image := Palettes.current_palette.convert_to_image()
|
||||
var palette_image := current_palette.convert_to_image(false)
|
||||
var palette_texture := ImageTexture.create_from_image(palette_image)
|
||||
var params := {
|
||||
"palette_texture": palette_texture, "rgb_texture": ImageTexture.create_from_image(self)
|
||||
|
|
|
@ -69,6 +69,8 @@ var user_data := "" ## User defined data, set in the project properties.
|
|||
|
||||
var x_symmetry_point: float
|
||||
var y_symmetry_point: float
|
||||
var xy_symmetry_point: Vector2
|
||||
var x_minus_y_symmetry_point: Vector2
|
||||
var x_symmetry_axis := SymmetryGuide.new()
|
||||
var y_symmetry_axis := SymmetryGuide.new()
|
||||
var diagonal_xy_symmetry_axis := SymmetryGuide.new()
|
||||
|
@ -113,6 +115,8 @@ func _init(_frames: Array[Frame] = [], _name := tr("untitled"), _size := Vector2
|
|||
|
||||
x_symmetry_point = size.x - 1
|
||||
y_symmetry_point = size.y - 1
|
||||
xy_symmetry_point = Vector2i(size.y, size.x) - Vector2i.ONE
|
||||
x_minus_y_symmetry_point = Vector2(maxi(size.x - size.y, 0), maxi(size.y - size.x, 0))
|
||||
x_symmetry_axis.type = Guide.Types.HORIZONTAL
|
||||
x_symmetry_axis.project = self
|
||||
x_symmetry_axis.add_point(Vector2(-19999, y_symmetry_point / 2 + 0.5))
|
||||
|
@ -128,13 +132,13 @@ func _init(_frames: Array[Frame] = [], _name := tr("untitled"), _size := Vector2
|
|||
diagonal_xy_symmetry_axis.type = Guide.Types.XY
|
||||
diagonal_xy_symmetry_axis.project = self
|
||||
diagonal_xy_symmetry_axis.add_point(Vector2(19999, -19999))
|
||||
diagonal_xy_symmetry_axis.add_point(Vector2i(-19999, 19999) + size)
|
||||
diagonal_xy_symmetry_axis.add_point(Vector2(-19999, 19999) + xy_symmetry_point + Vector2.ONE)
|
||||
Global.canvas.add_child(diagonal_xy_symmetry_axis)
|
||||
|
||||
diagonal_x_minus_y_symmetry_axis.type = Guide.Types.X_MINUS_Y
|
||||
diagonal_x_minus_y_symmetry_axis.project = self
|
||||
diagonal_x_minus_y_symmetry_axis.add_point(Vector2(-19999, -19999))
|
||||
diagonal_x_minus_y_symmetry_axis.add_point(Vector2(19999, 19999))
|
||||
diagonal_x_minus_y_symmetry_axis.add_point(Vector2(19999, 19999) + x_minus_y_symmetry_point)
|
||||
Global.canvas.add_child(diagonal_x_minus_y_symmetry_axis)
|
||||
|
||||
if OS.get_name() == "Web":
|
||||
|
|
|
@ -25,7 +25,7 @@ var colors_max := 0
|
|||
|
||||
|
||||
class PaletteColor:
|
||||
var color := Color.TRANSPARENT
|
||||
var color := Color(0, 0, 0, 0)
|
||||
var index := -1
|
||||
|
||||
func _init(init_color := Color.BLACK, init_index := -1) -> void:
|
||||
|
@ -358,9 +358,11 @@ static func strip_unvalid_characters(string_to_strip: String) -> String:
|
|||
return regex.sub(string_to_strip, "", true)
|
||||
|
||||
|
||||
func convert_to_image() -> Image:
|
||||
func convert_to_image(crop_image := true) -> Image:
|
||||
var image := Image.create(colors_max, 1, false, Image.FORMAT_RGBA8)
|
||||
for i in colors_max:
|
||||
if colors.has(i):
|
||||
image.set_pixel(i, 0, colors[i].color)
|
||||
image.set_pixel(i, 0, Color(colors[i].color.to_html()))
|
||||
if crop_image:
|
||||
image.copy_from(image.get_region(image.get_used_rect()))
|
||||
return image
|
||||
|
|
|
@ -23,10 +23,6 @@ func _ready() -> void:
|
|||
|
||||
|
||||
func set_palette(new_palette: Palette) -> void:
|
||||
# Only display valid palette objects
|
||||
if not new_palette:
|
||||
return
|
||||
|
||||
current_palette = new_palette
|
||||
grid_window_origin = Vector2.ZERO
|
||||
|
||||
|
@ -87,6 +83,8 @@ func scroll_palette(origin: Vector2i) -> void:
|
|||
## Called when the color changes, either the left or the right, determined by [param mouse_button].
|
||||
## If current palette has [param target_color] as a [Color], then select it.
|
||||
func find_and_select_color(target_color: Color, mouse_button: int) -> void:
|
||||
if not is_instance_valid(current_palette):
|
||||
return
|
||||
var old_index := Palettes.current_palette_get_selected_color_index(mouse_button)
|
||||
for color_ind in swatches.size():
|
||||
if (
|
||||
|
@ -115,6 +113,8 @@ func find_and_select_color(target_color: Color, mouse_button: int) -> void:
|
|||
|
||||
## Displays a left/right highlight over a swatch
|
||||
func select_swatch(mouse_button: int, palette_index: int, old_palette_index: int) -> void:
|
||||
if not is_instance_valid(current_palette):
|
||||
return
|
||||
var index := convert_palette_index_to_grid_index(palette_index)
|
||||
var old_index := convert_palette_index_to_grid_index(old_palette_index)
|
||||
if index >= 0 and index < swatches.size():
|
||||
|
@ -159,16 +159,17 @@ func convert_palette_index_to_grid_index(palette_index: int) -> int:
|
|||
|
||||
|
||||
func resize_grid(new_rect_size: Vector2) -> void:
|
||||
if not is_instance_valid(current_palette):
|
||||
return
|
||||
var grid_x: int = (
|
||||
new_rect_size.x / (swatch_size.x + get("theme_override_constants/h_separation"))
|
||||
)
|
||||
var grid_y: int = (
|
||||
new_rect_size.y / (swatch_size.y + get("theme_override_constants/v_separation"))
|
||||
)
|
||||
grid_size.x = mini(grid_x, current_palette.width)
|
||||
grid_size.y = mini(grid_y, current_palette.height)
|
||||
if is_instance_valid(current_palette):
|
||||
grid_size.x = mini(grid_x, current_palette.width)
|
||||
grid_size.y = mini(grid_y, current_palette.height)
|
||||
else:
|
||||
grid_size = Vector2i.ZERO
|
||||
setup_swatches()
|
||||
draw_palette()
|
||||
|
||||
|
|
|
@ -89,16 +89,16 @@ func select_palette(palette_name: String) -> void:
|
|||
var palette_id = palettes_path_id.get(palette_name)
|
||||
if palette_id != null:
|
||||
palette_select.selected = palette_id
|
||||
palette_grid.set_palette(Palettes.current_palette)
|
||||
palette_scroll.resize_grid()
|
||||
palette_scroll.set_sliders(Palettes.current_palette, palette_grid.grid_window_origin)
|
||||
palette_grid.set_palette(Palettes.current_palette)
|
||||
palette_scroll.resize_grid()
|
||||
palette_scroll.set_sliders(Palettes.current_palette, palette_grid.grid_window_origin)
|
||||
|
||||
var left_selected := Palettes.current_palette_get_selected_color_index(MOUSE_BUTTON_LEFT)
|
||||
var right_selected := Palettes.current_palette_get_selected_color_index(MOUSE_BUTTON_RIGHT)
|
||||
palette_grid.select_swatch(MOUSE_BUTTON_LEFT, left_selected, left_selected)
|
||||
palette_grid.select_swatch(MOUSE_BUTTON_RIGHT, right_selected, right_selected)
|
||||
var left_selected := Palettes.current_palette_get_selected_color_index(MOUSE_BUTTON_LEFT)
|
||||
var right_selected := Palettes.current_palette_get_selected_color_index(MOUSE_BUTTON_RIGHT)
|
||||
palette_grid.select_swatch(MOUSE_BUTTON_LEFT, left_selected, left_selected)
|
||||
palette_grid.select_swatch(MOUSE_BUTTON_RIGHT, right_selected, right_selected)
|
||||
|
||||
toggle_add_delete_buttons()
|
||||
toggle_add_delete_buttons()
|
||||
|
||||
|
||||
## Select and display current palette
|
||||
|
@ -115,6 +115,8 @@ func redraw_current_palette() -> void:
|
|||
|
||||
|
||||
func toggle_add_delete_buttons() -> void:
|
||||
if not is_instance_valid(Palettes.current_palette):
|
||||
return
|
||||
add_color_button.disabled = Palettes.current_palette.is_full()
|
||||
if add_color_button.disabled:
|
||||
add_color_button.mouse_default_cursor_shape = CURSOR_FORBIDDEN
|
||||
|
@ -252,6 +254,7 @@ func _on_ColorPicker_color_changed(color: Color) -> void:
|
|||
== Palettes.current_palette_get_selected_color_index(MOUSE_BUTTON_RIGHT)
|
||||
):
|
||||
Tools.assign_color(color, MOUSE_BUTTON_RIGHT)
|
||||
Palettes.current_palette_set_color(edited_swatch_index, edited_swatch_color)
|
||||
|
||||
|
||||
## Saves edited swatch to palette file when color selection dialog is closed
|
||||
|
|
|
@ -4,9 +4,9 @@ var scroll := Vector2i.ZERO
|
|||
var drag_started := false
|
||||
var drag_start_position := Vector2i.ZERO
|
||||
|
||||
@onready var h_slider := %HScrollBar
|
||||
@onready var v_slider := %VScrollBar
|
||||
@onready var palette_grid := %PaletteGrid
|
||||
@onready var h_slider := %HScrollBar as HScrollBar
|
||||
@onready var v_slider := %VScrollBar as VScrollBar
|
||||
@onready var palette_grid := %PaletteGrid as PaletteGrid
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
|
@ -17,16 +17,21 @@ func _input(event: InputEvent) -> void:
|
|||
|
||||
|
||||
func set_sliders(palette: Palette, origin: Vector2i) -> void:
|
||||
if not is_instance_valid(palette):
|
||||
return
|
||||
h_slider.value = origin.x
|
||||
h_slider.max_value = palette.width
|
||||
h_slider.page = palette_grid.grid_size.x
|
||||
if is_instance_valid(palette):
|
||||
h_slider.value = origin.x
|
||||
h_slider.max_value = palette.width
|
||||
h_slider.page = palette_grid.grid_size.x
|
||||
v_slider.value = origin.y
|
||||
v_slider.max_value = palette.height
|
||||
v_slider.page = palette_grid.grid_size.y
|
||||
else:
|
||||
h_slider.value = 0
|
||||
h_slider.max_value = 0
|
||||
h_slider.page = 0
|
||||
v_slider.value = 0
|
||||
v_slider.max_value = 0
|
||||
v_slider.page = 0
|
||||
h_slider.visible = false if h_slider.max_value <= palette_grid.grid_size.x else true
|
||||
|
||||
v_slider.value = origin.y
|
||||
v_slider.max_value = palette.height
|
||||
v_slider.page = palette_grid.grid_size.y
|
||||
v_slider.visible = false if v_slider.max_value <= palette_grid.grid_size.y else true
|
||||
|
||||
|
||||
|
@ -58,7 +63,7 @@ func _on_PaletteGrid_gui_input(event: InputEvent) -> void:
|
|||
drag_started = true
|
||||
# Keeps position where the dragging started
|
||||
drag_start_position = (
|
||||
event.position + Vector2i(h_slider.value, v_slider.value) * palette_grid.swatch_size
|
||||
event.position + Vector2(h_slider.value, v_slider.value) * palette_grid.swatch_size
|
||||
)
|
||||
|
||||
if event is InputEventMouseMotion and drag_started:
|
||||
|
|
163
src/Preferences/GridPreferences.gd
Normal file
|
@ -0,0 +1,163 @@
|
|||
extends GridContainer
|
||||
|
||||
var grid_preferences: Array[GridPreference] = [
|
||||
GridPreference.new("grid_type", "GridType", "selected", Global.GridTypes.CARTESIAN),
|
||||
GridPreference.new("grid_size", "GridSizeValue", "value", Vector2i(2, 2)),
|
||||
GridPreference.new("isometric_grid_size", "IsometricGridSizeValue", "value", Vector2i(16, 8)),
|
||||
GridPreference.new("grid_offset", "GridOffsetValue", "value", Vector2i.ZERO),
|
||||
GridPreference.new("grid_draw_over_tile_mode", "GridDrawOverTileMode", "button_pressed", false),
|
||||
GridPreference.new("grid_color", "GridColor", "color", Color.BLACK),
|
||||
]
|
||||
|
||||
var grid_selected: int = 0:
|
||||
set(key):
|
||||
grid_selected = key
|
||||
for child: BaseButton in grids_select_container.get_children():
|
||||
if child.get_index() == grid_selected:
|
||||
child.self_modulate = Color.WHITE
|
||||
else:
|
||||
child.self_modulate = Color.DIM_GRAY
|
||||
var grids: Dictionary = Global.config_cache.get_value(
|
||||
"preferences", "grids", {0: create_default_properties()}
|
||||
)
|
||||
if grids.has(key):
|
||||
update_pref_ui(grids[key])
|
||||
|
||||
@onready var grids_select_container: HFlowContainer = $GridsSelectContainer
|
||||
|
||||
|
||||
class GridPreference:
|
||||
var prop_name: String
|
||||
var node_path: String
|
||||
var value_type: String
|
||||
var default_value
|
||||
|
||||
func _init(
|
||||
_prop_name: String,
|
||||
_node_path: String,
|
||||
_value_type: String,
|
||||
_default_value = null,
|
||||
_require_restart := false
|
||||
) -> void:
|
||||
prop_name = _prop_name
|
||||
node_path = _node_path
|
||||
value_type = _value_type
|
||||
if _default_value != null:
|
||||
default_value = _default_value
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var grids = Global.config_cache.get_value(
|
||||
"preferences", "grids", {0: create_default_properties()}
|
||||
)
|
||||
Global.config_cache.set_value("preferences", "grids", grids)
|
||||
$GridsCount.value = grids.size()
|
||||
if grids.size() == 1:
|
||||
add_remove_select_button(0)
|
||||
for pref in grid_preferences:
|
||||
if not has_node(pref.node_path):
|
||||
continue
|
||||
var node := get_node(pref.node_path)
|
||||
var restore_default_button := RestoreDefaultButton.new()
|
||||
restore_default_button.pressed.connect(
|
||||
_on_grid_pref_value_changed.bind(pref.default_value, pref, restore_default_button)
|
||||
)
|
||||
restore_default_button.setting_name = pref.prop_name
|
||||
restore_default_button.value_type = pref.value_type
|
||||
restore_default_button.default_value = pref.default_value
|
||||
restore_default_button.node = node
|
||||
|
||||
var node_position := node.get_index()
|
||||
node.get_parent().add_child(restore_default_button)
|
||||
node.get_parent().move_child(restore_default_button, node_position)
|
||||
|
||||
match pref.value_type:
|
||||
"button_pressed":
|
||||
node.toggled.connect(_on_grid_pref_value_changed.bind(pref, restore_default_button))
|
||||
"value":
|
||||
node.value_changed.connect(
|
||||
_on_grid_pref_value_changed.bind(pref, restore_default_button)
|
||||
)
|
||||
"color":
|
||||
node.get_picker().presets_visible = false
|
||||
node.color_changed.connect(
|
||||
_on_grid_pref_value_changed.bind(pref, restore_default_button)
|
||||
)
|
||||
"selected":
|
||||
node.item_selected.connect(
|
||||
_on_grid_pref_value_changed.bind(pref, restore_default_button)
|
||||
)
|
||||
grid_selected = 0
|
||||
|
||||
|
||||
func _on_grid_pref_value_changed(value, pref: GridPreference, button: RestoreDefaultButton) -> void:
|
||||
var grids: Dictionary = Global.config_cache.get_value(
|
||||
"preferences", "grids", {0: create_default_properties()}
|
||||
)
|
||||
if grids.has(grid_selected): # Failsafe (Always true)
|
||||
var grid_info: Dictionary = grids[grid_selected]
|
||||
var prop := pref.prop_name
|
||||
grid_info[prop] = value
|
||||
grids[grid_selected] = grid_info
|
||||
Global.update_grids(grids)
|
||||
var default_value = pref.default_value
|
||||
var disable: bool = Global.grids[grid_selected].get(prop) == default_value
|
||||
if typeof(value) == TYPE_COLOR:
|
||||
disable = value.is_equal_approx(default_value)
|
||||
disable_restore_default_button(button, disable)
|
||||
Global.config_cache.set_value("preferences", "grids", grids)
|
||||
|
||||
|
||||
func _on_grids_count_value_changed(value: float) -> void:
|
||||
var grid_idx = int(value - 1)
|
||||
var grids: Dictionary = Global.config_cache.get_value(
|
||||
"preferences", "grids", {0: create_default_properties()}
|
||||
)
|
||||
if grid_idx >= grids_select_container.get_child_count():
|
||||
for key in range(grids_select_container.get_child_count(), grid_idx + 1):
|
||||
if not grids.has(key):
|
||||
grids[key] = create_default_properties()
|
||||
add_remove_select_button(key)
|
||||
else:
|
||||
for key: int in range(grid_idx + 1, grids.size()):
|
||||
grids.erase(key)
|
||||
add_remove_select_button(key, true)
|
||||
Global.update_grids(grids)
|
||||
Global.config_cache.set_value("preferences", "grids", grids)
|
||||
|
||||
|
||||
func create_default_properties() -> Dictionary:
|
||||
var grid_info = {}
|
||||
for pref in grid_preferences:
|
||||
grid_info[pref.prop_name] = pref.default_value
|
||||
return grid_info
|
||||
|
||||
|
||||
func disable_restore_default_button(button: RestoreDefaultButton, disable: bool) -> void:
|
||||
button.disabled = disable
|
||||
if disable:
|
||||
button.mouse_default_cursor_shape = Control.CURSOR_ARROW
|
||||
button.tooltip_text = ""
|
||||
else:
|
||||
button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
button.tooltip_text = "Restore default value"
|
||||
|
||||
|
||||
func add_remove_select_button(grid_idx: int, remove := false):
|
||||
if not remove:
|
||||
var select_button = Button.new()
|
||||
select_button.text = str(grid_idx)
|
||||
grids_select_container.add_child(select_button)
|
||||
select_button.pressed.connect(func(): grid_selected = grid_idx)
|
||||
else:
|
||||
if grid_idx < grids_select_container.get_child_count():
|
||||
grids_select_container.get_child(grid_idx).queue_free()
|
||||
grid_selected = min(grid_selected, grid_idx - 1)
|
||||
|
||||
|
||||
func update_pref_ui(grid_data: Dictionary):
|
||||
for pref in grid_preferences:
|
||||
var key = pref.prop_name
|
||||
if grid_data.has(key):
|
||||
var node := get_node(pref.node_path)
|
||||
node.set(pref.value_type, grid_data[key])
|
|
@ -94,21 +94,6 @@ var preferences: Array[Preference] = [
|
|||
Preference.new("smooth_zoom", "Canvas/ZoomOptions/SmoothZoom", "button_pressed", true),
|
||||
Preference.new("integer_zoom", "Canvas/ZoomOptions/IntegerZoom", "button_pressed", false),
|
||||
Preference.new("snapping_distance", "Canvas/SnappingOptions/DistanceValue", "value", 32.0),
|
||||
Preference.new(
|
||||
"grid_type", "Canvas/GridOptions/GridType", "selected", Global.GridTypes.CARTESIAN
|
||||
),
|
||||
Preference.new("grid_size", "Canvas/GridOptions/GridSizeValue", "value", Vector2i(2, 2)),
|
||||
Preference.new(
|
||||
"isometric_grid_size", "Canvas/GridOptions/IsometricGridSizeValue", "value", Vector2i(16, 8)
|
||||
),
|
||||
Preference.new("grid_offset", "Canvas/GridOptions/GridOffsetValue", "value", Vector2i.ZERO),
|
||||
Preference.new(
|
||||
"grid_draw_over_tile_mode",
|
||||
"Canvas/GridOptions/GridDrawOverTileMode",
|
||||
"button_pressed",
|
||||
false
|
||||
),
|
||||
Preference.new("grid_color", "Canvas/GridOptions/GridColor", "color", Color.BLACK),
|
||||
Preference.new(
|
||||
"pixel_grid_show_at_zoom", "Canvas/PixelGridOptions/ShowAtZoom", "value", 1500.0
|
||||
),
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
[gd_scene load_steps=9 format=3 uid="uid://b3hkjj3s6pe4x"]
|
||||
[gd_scene load_steps=11 format=3 uid="uid://b3hkjj3s6pe4x"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/Preferences/PreferencesDialog.gd" id="1"]
|
||||
[ext_resource type="PackedScene" uid="uid://bq7ibhm0txl5p" path="res://addons/keychain/ShortcutEdit.tscn" id="3"]
|
||||
[ext_resource type="Script" path="res://src/Preferences/ThemesPreferences.gd" id="3_nvl8k"]
|
||||
[ext_resource type="Script" path="res://src/Preferences/GridPreferences.gd" id="4_76iff"]
|
||||
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="5_rlmsh"]
|
||||
[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="7"]
|
||||
[ext_resource type="Script" path="res://src/Preferences/ExtensionsPreferences.gd" id="7_8ume5"]
|
||||
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="8"]
|
||||
|
@ -482,6 +484,30 @@ layout_mode = 2
|
|||
theme_override_constants/h_separation = 4
|
||||
theme_override_constants/v_separation = 4
|
||||
columns = 3
|
||||
script = ExtResource("4_76iff")
|
||||
|
||||
[node name="GridsCountLabel" type="Label" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions"]
|
||||
layout_mode = 2
|
||||
text = "Grids Visible:"
|
||||
|
||||
[node name="Spacer" type="Control" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="GridsCount" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions" instance=ExtResource("5_rlmsh")]
|
||||
layout_mode = 2
|
||||
min_value = 1.0
|
||||
max_value = 10.0
|
||||
value = 1.0
|
||||
|
||||
[node name="GridsSelectLabel" type="Label" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions"]
|
||||
layout_mode = 2
|
||||
text = "Editing Grid:"
|
||||
|
||||
[node name="Spacer2" type="Control" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="GridsSelectContainer" type="HFlowContainer" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="GridTypeLabel" type="Label" parent="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions"]
|
||||
layout_mode = 2
|
||||
|
@ -1478,6 +1504,7 @@ dialog_text = "Are you sure you want to reset the selected options? There will b
|
|||
[connection signal="pressed" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Language/System Language" to="." method="_on_language_pressed" binds= [1]]
|
||||
[connection signal="pressed" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Interface/InterfaceOptions/ShrinkContainer/ShrinkApplyButton" to="." method="_on_shrink_apply_button_pressed"]
|
||||
[connection signal="pressed" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Interface/InterfaceOptions/FontSizeContainer/FontSizeApplyButton" to="." method="_on_font_size_apply_button_pressed"]
|
||||
[connection signal="value_changed" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions/GridsCount" to="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Canvas/GridOptions" method="_on_grids_count_value_changed"]
|
||||
[connection signal="pressed" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions/ExtensionsHeader/Explore" to="Store" method="_on_explore_pressed"]
|
||||
[connection signal="empty_clicked" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions/InstalledExtensions" to="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions" method="_on_InstalledExtensions_empty_clicked"]
|
||||
[connection signal="item_selected" from="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions/InstalledExtensions" to="HSplitContainer/VBoxContainer/ScrollContainer/RightSide/Extensions" method="_on_InstalledExtensions_item_selected"]
|
||||
|
|
|
@ -14,7 +14,7 @@ vec4 swap_color(vec4 color) {
|
|||
|
||||
int n_of_colors = textureSize(palette_texture, 0).x;
|
||||
int color_index = find_index(color, n_of_colors, palette_texture);
|
||||
return texture(palette_texture, vec2(float(color_index) / float(n_of_colors), 0.0));
|
||||
return texelFetch(palette_texture, ivec2(color_index, 0), 0);
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
|
|
|
@ -2,8 +2,7 @@ int find_index(vec4 color, int n_of_colors, sampler2D palette_texture) {
|
|||
int color_index = 0;
|
||||
float smaller_distance = distance(color, texture(palette_texture, vec2(0.0)));
|
||||
for (int i = 0; i <= n_of_colors; i++) {
|
||||
vec2 uv = vec2(float(i) / float(n_of_colors), 0.0);
|
||||
vec4 palette_color = texture(palette_texture, uv);
|
||||
vec4 palette_color = texelFetch(palette_texture, ivec2(i, 0), 0);
|
||||
float dist = distance(color, palette_color);
|
||||
if (dist < smaller_distance) {
|
||||
smaller_distance = dist;
|
||||
|
|
|
@ -7,16 +7,16 @@ uniform sampler2D palette_texture : filter_nearest;
|
|||
uniform sampler2D indices_texture : filter_nearest;
|
||||
|
||||
void fragment() {
|
||||
float index = texture(indices_texture, UV).r;
|
||||
float index = texture(indices_texture, UV).r * 255.0;
|
||||
if (index <= EPSILON) { // If index is zero, make it transparent
|
||||
COLOR = vec4(0.0);
|
||||
}
|
||||
else {
|
||||
float n_of_colors = float(textureSize(palette_texture, 0).x);
|
||||
index -= 1.0 / 255.0;
|
||||
float index_normalized = ((index * 255.0)) / n_of_colors;
|
||||
if (index_normalized + EPSILON < 1.0) {
|
||||
COLOR = texture(palette_texture, vec2(index_normalized + EPSILON, 0.0));
|
||||
index -= 1.0;
|
||||
float index_normalized = index / n_of_colors;
|
||||
if (index < n_of_colors) {
|
||||
COLOR = texelFetch(palette_texture, ivec2(int(index), 0), 0);
|
||||
}
|
||||
else {
|
||||
// If index is bigger than the size of the palette, make it transparent.
|
||||
|
|
|
@ -8,7 +8,7 @@ uniform sampler2D palette_texture : filter_nearest;
|
|||
|
||||
void fragment() {
|
||||
vec4 color = texture(rgb_texture, UV);
|
||||
if (color.a <= 0.01) {
|
||||
if (color.a <= 0.0001) {
|
||||
COLOR.r = 0.0;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -159,16 +159,17 @@ func draw_move(pos: Vector2i) -> void:
|
|||
else:
|
||||
pos.x = _start_pos.x
|
||||
if Input.is_action_pressed("transform_snap_grid"):
|
||||
_offset = _offset.snapped(Global.grid_size)
|
||||
_offset = _offset.snapped(Global.grids[0].grid_size)
|
||||
var prev_pos: Vector2i = selection_node.big_bounding_rectangle.position
|
||||
selection_node.big_bounding_rectangle.position = prev_pos.snapped(Global.grid_size)
|
||||
selection_node.big_bounding_rectangle.position = prev_pos.snapped(Global.grids[0].grid_size)
|
||||
selection_node.marching_ants_outline.offset += Vector2(
|
||||
selection_node.big_bounding_rectangle.position - prev_pos
|
||||
)
|
||||
pos = pos.snapped(Global.grid_size)
|
||||
var grid_offset := Global.grid_offset
|
||||
pos = pos.snapped(Global.grids[0].grid_size)
|
||||
var grid_offset := Global.grids[0].grid_offset
|
||||
grid_offset = Vector2i(
|
||||
fmod(grid_offset.x, Global.grid_size.x), fmod(grid_offset.y, Global.grid_size.y)
|
||||
fmod(grid_offset.x, Global.grids[0].grid_size.x),
|
||||
fmod(grid_offset.y, Global.grids[0].grid_size.y)
|
||||
)
|
||||
pos += grid_offset
|
||||
|
||||
|
|
|
@ -129,19 +129,20 @@ func draw_preview() -> void:
|
|||
func snap_position(pos: Vector2) -> Vector2:
|
||||
var snapping_distance := Global.snapping_distance / Global.camera.zoom.x
|
||||
if Global.snap_to_rectangular_grid_boundary:
|
||||
var grid_pos := pos.snapped(Global.grid_size)
|
||||
grid_pos += Vector2(Global.grid_offset)
|
||||
var grid_pos := pos.snapped(Global.grids[0].grid_size)
|
||||
grid_pos += Vector2(Global.grids[0].grid_offset)
|
||||
# keeping grid_pos as is would have been fine but this adds extra accuracy as to
|
||||
# which snap point (from the list below) is closest to mouse and occupy THAT point
|
||||
var t_l := grid_pos + Vector2(-Global.grid_size.x, -Global.grid_size.y)
|
||||
var t_c := grid_pos + Vector2(0, -Global.grid_size.y) # t_c is for "top centre" and so on
|
||||
var t_r := grid_pos + Vector2(Global.grid_size.x, -Global.grid_size.y)
|
||||
var m_l := grid_pos + Vector2(-Global.grid_size.x, 0)
|
||||
# t_l is for "top left" and so on
|
||||
var t_l := grid_pos + Vector2(-Global.grids[0].grid_size.x, -Global.grids[0].grid_size.y)
|
||||
var t_c := grid_pos + Vector2(0, -Global.grids[0].grid_size.y)
|
||||
var t_r := grid_pos + Vector2(Global.grids[0].grid_size.x, -Global.grids[0].grid_size.y)
|
||||
var m_l := grid_pos + Vector2(-Global.grids[0].grid_size.x, 0)
|
||||
var m_c := grid_pos
|
||||
var m_r := grid_pos + Vector2(Global.grid_size.x, 0)
|
||||
var b_l := grid_pos + Vector2(-Global.grid_size.x, Global.grid_size.y)
|
||||
var b_c := grid_pos + Vector2(0, Global.grid_size.y)
|
||||
var b_r := grid_pos + Vector2(Global.grid_size)
|
||||
var m_r := grid_pos + Vector2(Global.grids[0].grid_size.x, 0)
|
||||
var b_l := grid_pos + Vector2(-Global.grids[0].grid_size.x, Global.grids[0].grid_size.y)
|
||||
var b_c := grid_pos + Vector2(0, Global.grids[0].grid_size.y)
|
||||
var b_r := grid_pos + Vector2(Global.grids[0].grid_size)
|
||||
var vec_arr: PackedVector2Array = [t_l, t_c, t_r, m_l, m_c, m_r, b_l, b_c, b_r]
|
||||
for vec in vec_arr:
|
||||
if vec.distance_to(pos) < grid_pos.distance_to(pos):
|
||||
|
@ -152,19 +153,22 @@ func snap_position(pos: Vector2) -> Vector2:
|
|||
pos = grid_point.floor()
|
||||
|
||||
if Global.snap_to_rectangular_grid_center:
|
||||
var grid_center := pos.snapped(Global.grid_size) + Vector2(Global.grid_size / 2)
|
||||
grid_center += Vector2(Global.grid_offset)
|
||||
var grid_center := (
|
||||
pos.snapped(Global.grids[0].grid_size) + Vector2(Global.grids[0].grid_size / 2)
|
||||
)
|
||||
grid_center += Vector2(Global.grids[0].grid_offset)
|
||||
# keeping grid_center as is would have been fine but this adds extra accuracy as to
|
||||
# which snap point (from the list below) is closest to mouse and occupy THAT point
|
||||
var t_l := grid_center + Vector2(-Global.grid_size.x, -Global.grid_size.y)
|
||||
var t_c := grid_center + Vector2(0, -Global.grid_size.y) # t_c is for "top centre" and so on
|
||||
var t_r := grid_center + Vector2(Global.grid_size.x, -Global.grid_size.y)
|
||||
var m_l := grid_center + Vector2(-Global.grid_size.x, 0)
|
||||
# t_l is for "top left" and so on
|
||||
var t_l := grid_center + Vector2(-Global.grids[0].grid_size.x, -Global.grids[0].grid_size.y)
|
||||
var t_c := grid_center + Vector2(0, -Global.grids[0].grid_size.y)
|
||||
var t_r := grid_center + Vector2(Global.grids[0].grid_size.x, -Global.grids[0].grid_size.y)
|
||||
var m_l := grid_center + Vector2(-Global.grids[0].grid_size.x, 0)
|
||||
var m_c := grid_center
|
||||
var m_r := grid_center + Vector2(Global.grid_size.x, 0)
|
||||
var b_l := grid_center + Vector2(-Global.grid_size.x, Global.grid_size.y)
|
||||
var b_c := grid_center + Vector2(0, Global.grid_size.y)
|
||||
var b_r := grid_center + Vector2(Global.grid_size)
|
||||
var m_r := grid_center + Vector2(Global.grids[0].grid_size.x, 0)
|
||||
var b_l := grid_center + Vector2(-Global.grids[0].grid_size.x, Global.grids[0].grid_size.y)
|
||||
var b_c := grid_center + Vector2(0, Global.grids[0].grid_size.y)
|
||||
var b_r := grid_center + Vector2(Global.grids[0].grid_size)
|
||||
var vec_arr := [t_l, t_c, t_r, m_l, m_c, m_r, b_l, b_c, b_r]
|
||||
for vec in vec_arr:
|
||||
if vec.distance_to(pos) < grid_center.distance_to(pos):
|
||||
|
|
|
@ -269,9 +269,11 @@ func fill_in_selection() -> void:
|
|||
var selection_map_copy := project.selection_map.return_cropped_copy(project.size)
|
||||
for image in images:
|
||||
image.blit_rect_mask(filler, selection_map_copy, rect, rect.position)
|
||||
image.convert_rgb_to_indexed()
|
||||
else:
|
||||
for image in images:
|
||||
image.fill(tool_slot.color)
|
||||
image.convert_rgb_to_indexed()
|
||||
else:
|
||||
# End early if we are filling with an empty pattern
|
||||
var pattern_image: Image = _pattern.image
|
||||
|
|
|
@ -16,17 +16,17 @@ func _input(event: InputEvent) -> void:
|
|||
return
|
||||
if event.is_action_pressed("transform_snap_grid"):
|
||||
_snap_to_grid = true
|
||||
_offset = _offset.snapped(Global.grid_size)
|
||||
_offset = _offset.snapped(Global.grids[0].grid_size)
|
||||
if Global.current_project.has_selection and selection_node.is_moving_content:
|
||||
var prev_pos: Vector2i = selection_node.big_bounding_rectangle.position
|
||||
selection_node.big_bounding_rectangle.position = Vector2i(
|
||||
prev_pos.snapped(Global.grid_size)
|
||||
prev_pos.snapped(Global.grids[0].grid_size)
|
||||
)
|
||||
# The first time transform_snap_grid is enabled then _snap_position() is not called
|
||||
# and the selection had wrong offset, so do selection offsetting here
|
||||
var grid_offset := Vector2i(
|
||||
fmod(Global.grid_offset.x, Global.grid_size.x),
|
||||
fmod(Global.grid_offset.y, Global.grid_size.y)
|
||||
fmod(Global.grids[0].grid_offset.x, Global.grids[0].grid_size.x),
|
||||
fmod(Global.grids[0].grid_offset.y, Global.grids[0].grid_size.y)
|
||||
)
|
||||
selection_node.big_bounding_rectangle.position += grid_offset
|
||||
selection_node.marching_ants_outline.offset += Vector2(
|
||||
|
@ -110,16 +110,18 @@ func _snap_position(pos: Vector2) -> Vector2:
|
|||
else:
|
||||
pos.x = _start_pos.x
|
||||
if _snap_to_grid: # Snap to grid
|
||||
pos = pos.snapped(Global.grid_size)
|
||||
pos = pos.snapped(Global.grids[0].grid_size)
|
||||
# The part below only corrects the offset for situations when there is no selection
|
||||
# Offsets when there is selection is controlled in _input() function
|
||||
if !Global.current_project.has_selection:
|
||||
var move_offset := Vector2.ZERO
|
||||
move_offset.x = (
|
||||
_start_pos.x - (_start_pos.x / Global.grid_size.x) * Global.grid_size.x
|
||||
_start_pos.x
|
||||
- (_start_pos.x / Global.grids[0].grid_size.x) * Global.grids[0].grid_size.x
|
||||
)
|
||||
move_offset.y = (
|
||||
_start_pos.y - (_start_pos.y / Global.grid_size.y) * Global.grid_size.y
|
||||
_start_pos.y
|
||||
- (_start_pos.y / Global.grids[0].grid_size.y) * Global.grids[0].grid_size.y
|
||||
)
|
||||
pos += move_offset
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=6 format=3 uid="uid://ct4o5i1jeul3k"]
|
||||
[gd_scene load_steps=6 format=3 uid="uid://bdregpkflev7u"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://ctfgfelg0sho8" path="res://src/Tools/BaseTool.tscn" id="1_1q6ub"]
|
||||
[ext_resource type="Script" path="res://src/Tools/UtilityTools/Text.gd" id="2_ql5g6"]
|
||||
|
@ -63,6 +63,8 @@ stretch_margin_bottom = 3
|
|||
script = ExtResource("3_tidsq")
|
||||
prefix = "Size:"
|
||||
suffix = "px"
|
||||
global_increment_action = "brush_size_increment"
|
||||
global_decrement_action = "brush_size_decrement"
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="." index="4"]
|
||||
layout_mode = 2
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
extends Node2D
|
||||
|
||||
var unique_rect_lines := PackedVector2Array()
|
||||
var unique_iso_lines := PackedVector2Array()
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
Global.project_switched.connect(queue_redraw)
|
||||
|
@ -10,54 +13,60 @@ func _draw() -> void:
|
|||
return
|
||||
|
||||
var target_rect: Rect2i
|
||||
if Global.grid_draw_over_tile_mode:
|
||||
target_rect = Global.current_project.tiles.get_bounding_rect()
|
||||
else:
|
||||
target_rect = Rect2i(Vector2i.ZERO, Global.current_project.size)
|
||||
if not target_rect.has_area():
|
||||
return
|
||||
unique_rect_lines.clear()
|
||||
unique_iso_lines.clear()
|
||||
for grid_idx in range(Global.grids.size() - 1, -1, -1):
|
||||
if Global.grids[grid_idx].grid_draw_over_tile_mode:
|
||||
target_rect = Global.current_project.tiles.get_bounding_rect()
|
||||
else:
|
||||
target_rect = Rect2i(Vector2i.ZERO, Global.current_project.size)
|
||||
if not target_rect.has_area():
|
||||
return
|
||||
|
||||
var grid_type := Global.grid_type
|
||||
if grid_type == Global.GridTypes.CARTESIAN || grid_type == Global.GridTypes.ALL:
|
||||
_draw_cartesian_grid(target_rect)
|
||||
var grid_type := Global.grids[grid_idx].grid_type
|
||||
if grid_type == Global.GridTypes.CARTESIAN || grid_type == Global.GridTypes.ALL:
|
||||
_draw_cartesian_grid(grid_idx, target_rect)
|
||||
|
||||
if grid_type == Global.GridTypes.ISOMETRIC || grid_type == Global.GridTypes.ALL:
|
||||
_draw_isometric_grid(target_rect)
|
||||
if grid_type == Global.GridTypes.ISOMETRIC || grid_type == Global.GridTypes.ALL:
|
||||
_draw_isometric_grid(grid_idx, target_rect)
|
||||
|
||||
|
||||
func _draw_cartesian_grid(target_rect: Rect2i) -> void:
|
||||
func _draw_cartesian_grid(grid_index: int, target_rect: Rect2i) -> void:
|
||||
var grid = Global.grids[grid_index]
|
||||
var grid_multiline_points := PackedVector2Array()
|
||||
|
||||
var x: float = (
|
||||
target_rect.position.x
|
||||
+ fposmod(Global.grid_offset.x - target_rect.position.x, Global.grid_size.x)
|
||||
+ fposmod(grid.grid_offset.x - target_rect.position.x, grid.grid_size.x)
|
||||
)
|
||||
while x <= target_rect.end.x:
|
||||
grid_multiline_points.push_back(Vector2(x, target_rect.position.y))
|
||||
grid_multiline_points.push_back(Vector2(x, target_rect.end.y))
|
||||
x += Global.grid_size.x
|
||||
if not Vector2(x, target_rect.position.y) in unique_rect_lines:
|
||||
grid_multiline_points.push_back(Vector2(x, target_rect.position.y))
|
||||
grid_multiline_points.push_back(Vector2(x, target_rect.end.y))
|
||||
x += grid.grid_size.x
|
||||
|
||||
var y: float = (
|
||||
target_rect.position.y
|
||||
+ fposmod(Global.grid_offset.y - target_rect.position.y, Global.grid_size.y)
|
||||
+ fposmod(grid.grid_offset.y - target_rect.position.y, grid.grid_size.y)
|
||||
)
|
||||
while y <= target_rect.end.y:
|
||||
grid_multiline_points.push_back(Vector2(target_rect.position.x, y))
|
||||
grid_multiline_points.push_back(Vector2(target_rect.end.x, y))
|
||||
y += Global.grid_size.y
|
||||
if not Vector2(target_rect.position.x, y) in unique_rect_lines:
|
||||
grid_multiline_points.push_back(Vector2(target_rect.position.x, y))
|
||||
grid_multiline_points.push_back(Vector2(target_rect.end.x, y))
|
||||
y += grid.grid_size.y
|
||||
|
||||
unique_rect_lines.append_array(grid_multiline_points)
|
||||
if not grid_multiline_points.is_empty():
|
||||
draw_multiline(grid_multiline_points, Global.grid_color)
|
||||
draw_multiline(grid_multiline_points, grid.grid_color)
|
||||
|
||||
|
||||
func _draw_isometric_grid(target_rect: Rect2i) -> void:
|
||||
func _draw_isometric_grid(grid_index: int, target_rect: Rect2i) -> void:
|
||||
var grid = Global.grids[grid_index]
|
||||
var grid_multiline_points := PackedVector2Array()
|
||||
|
||||
var cell_size: Vector2 = Global.isometric_grid_size
|
||||
var cell_size: Vector2 = grid.isometric_grid_size
|
||||
var max_cell_count: Vector2 = Vector2(target_rect.size) / cell_size
|
||||
var origin_offset: Vector2 = Vector2(Global.grid_offset - target_rect.position).posmodv(
|
||||
cell_size
|
||||
)
|
||||
var origin_offset: Vector2 = Vector2(grid.grid_offset - target_rect.position).posmodv(cell_size)
|
||||
|
||||
# lines ↗↗↗ (from bottom-left to top-right)
|
||||
var per_cell_offset: Vector2 = cell_size * Vector2(1, -1)
|
||||
|
@ -70,8 +79,9 @@ func _draw_isometric_grid(target_rect: Rect2i) -> void:
|
|||
var start: Vector2 = Vector2(target_rect.position) + Vector2(0, y)
|
||||
var cells_to_rect_bounds: float = minf(max_cell_count.x, y / cell_size.y)
|
||||
var end := start + cells_to_rect_bounds * per_cell_offset
|
||||
grid_multiline_points.push_back(start)
|
||||
grid_multiline_points.push_back(end)
|
||||
if not start in unique_iso_lines:
|
||||
grid_multiline_points.push_back(start)
|
||||
grid_multiline_points.push_back(end)
|
||||
y += cell_size.y
|
||||
|
||||
# lines ↗↗↗ starting from the rect's bottom side (left to right):
|
||||
|
@ -80,8 +90,9 @@ func _draw_isometric_grid(target_rect: Rect2i) -> void:
|
|||
var start: Vector2 = Vector2(target_rect.position) + Vector2(x, target_rect.size.y)
|
||||
var cells_to_rect_bounds: float = minf(max_cell_count.y, max_cell_count.x - x / cell_size.x)
|
||||
var end: Vector2 = start + cells_to_rect_bounds * per_cell_offset
|
||||
grid_multiline_points.push_back(start)
|
||||
grid_multiline_points.push_back(end)
|
||||
if not start in unique_iso_lines:
|
||||
grid_multiline_points.push_back(start)
|
||||
grid_multiline_points.push_back(end)
|
||||
x += cell_size.x
|
||||
|
||||
# lines ↘↘↘ (from top-left to bottom-right)
|
||||
|
@ -93,8 +104,9 @@ func _draw_isometric_grid(target_rect: Rect2i) -> void:
|
|||
var start: Vector2 = Vector2(target_rect.position) + Vector2(0, y)
|
||||
var cells_to_rect_bounds: float = minf(max_cell_count.x, max_cell_count.y - y / cell_size.y)
|
||||
var end: Vector2 = start + cells_to_rect_bounds * per_cell_offset
|
||||
grid_multiline_points.push_back(start)
|
||||
grid_multiline_points.push_back(end)
|
||||
if not start in unique_iso_lines:
|
||||
grid_multiline_points.push_back(start)
|
||||
grid_multiline_points.push_back(end)
|
||||
y += cell_size.y
|
||||
|
||||
# lines ↘↘↘ starting from the rect's top side (left to right):
|
||||
|
@ -103,9 +115,11 @@ func _draw_isometric_grid(target_rect: Rect2i) -> void:
|
|||
var start: Vector2 = Vector2(target_rect.position) + Vector2(x, 0)
|
||||
var cells_to_rect_bounds: float = minf(max_cell_count.y, max_cell_count.x - x / cell_size.x)
|
||||
var end: Vector2 = start + cells_to_rect_bounds * per_cell_offset
|
||||
grid_multiline_points.push_back(start)
|
||||
grid_multiline_points.push_back(end)
|
||||
if not start in unique_iso_lines:
|
||||
grid_multiline_points.push_back(start)
|
||||
grid_multiline_points.push_back(end)
|
||||
x += cell_size.x
|
||||
grid_multiline_points.append_array(grid_multiline_points)
|
||||
|
||||
if not grid_multiline_points.is_empty():
|
||||
draw_multiline(grid_multiline_points, Global.grid_color)
|
||||
draw_multiline(grid_multiline_points, grid.grid_color)
|
||||
|
|
|
@ -31,12 +31,13 @@ func _input(_event: InputEvent) -> void:
|
|||
if type == Types.HORIZONTAL:
|
||||
point0.y -= width * INPUT_WIDTH
|
||||
point1.y += width * INPUT_WIDTH
|
||||
else:
|
||||
elif type == Types.VERTICAL:
|
||||
point0.x -= width * INPUT_WIDTH
|
||||
point1.x += width * INPUT_WIDTH
|
||||
var rect := Rect2()
|
||||
rect.position = point0
|
||||
rect.end = point1
|
||||
rect = rect.abs()
|
||||
if (
|
||||
Input.is_action_just_pressed(&"left_mouse")
|
||||
and Global.can_draw
|
||||
|
@ -55,7 +56,7 @@ func _input(_event: InputEvent) -> void:
|
|||
var yy := snappedf(mouse_pos.y, 0.5)
|
||||
points[0].y = yy
|
||||
points[1].y = yy
|
||||
else:
|
||||
elif type == Types.VERTICAL:
|
||||
var xx := snappedf(mouse_pos.x, 0.5)
|
||||
points[0].x = xx
|
||||
points[1].x = xx
|
||||
|
@ -234,7 +235,7 @@ func _project_switched() -> void:
|
|||
elif type == Types.VERTICAL:
|
||||
visible = Global.show_y_symmetry_axis and Global.show_guides
|
||||
elif type == Types.XY:
|
||||
visible = Global.show_x_y_symmetry_axis and Global.show_guides
|
||||
visible = Global.show_xy_symmetry_axis and Global.show_guides
|
||||
elif type == Types.X_MINUS_Y:
|
||||
visible = Global.show_x_minus_y_symmetry_axis and Global.show_guides
|
||||
else:
|
||||
|
|
|
@ -214,7 +214,7 @@ func _move_with_arrow_keys(event: InputEvent) -> void:
|
|||
if _is_action_direction(event) and arrow_key_move:
|
||||
var step := Vector2.ONE
|
||||
if Input.is_key_pressed(KEY_CTRL):
|
||||
step = Global.grid_size
|
||||
step = Global.grids[0].grid_size
|
||||
var input := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
|
||||
var move := input.rotated(snappedf(Global.camera.rotation, PI / 2))
|
||||
# These checks are needed to fix a bug where the selection got stuck
|
||||
|
@ -808,9 +808,11 @@ func delete(selected_cels := true) -> void:
|
|||
image.blit_rect_mask(
|
||||
blank, selection_map_copy, big_bounding_rectangle, big_bounding_rectangle.position
|
||||
)
|
||||
image.convert_rgb_to_indexed()
|
||||
else:
|
||||
for image in images:
|
||||
image.fill(0)
|
||||
image.convert_rgb_to_indexed()
|
||||
commit_undo("Draw", undo_data_tmp)
|
||||
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ extends PanelContainer
|
|||
@onready var grid_container: GridContainer = find_child("GridContainer")
|
||||
@onready var horizontal_mirror: BaseButton = grid_container.get_node("Horizontal")
|
||||
@onready var vertical_mirror: BaseButton = grid_container.get_node("Vertical")
|
||||
@onready var diagonal_xy_mirror: BaseButton = grid_container.get_node("DiagonalXY")
|
||||
@onready var diagonal_x_minus_y_mirror: BaseButton = grid_container.get_node("DiagonalXMinusY")
|
||||
@onready var pixel_perfect: BaseButton = grid_container.get_node("PixelPerfect")
|
||||
@onready var alpha_lock: BaseButton = grid_container.get_node("AlphaLock")
|
||||
@onready var dynamics: Button = $"%Dynamics"
|
||||
|
@ -39,25 +41,25 @@ func _on_resized() -> void:
|
|||
grid_container.columns = column_n
|
||||
|
||||
|
||||
func _on_Horizontal_toggled(button_pressed: bool) -> void:
|
||||
Tools.horizontal_mirror = button_pressed
|
||||
Global.config_cache.set_value("tools", "horizontal_mirror", button_pressed)
|
||||
Global.show_y_symmetry_axis = button_pressed
|
||||
func _on_Horizontal_toggled(toggled_on: bool) -> void:
|
||||
Tools.horizontal_mirror = toggled_on
|
||||
Global.config_cache.set_value("tools", "horizontal_mirror", toggled_on)
|
||||
Global.show_y_symmetry_axis = toggled_on
|
||||
Global.current_project.y_symmetry_axis.visible = (
|
||||
Global.show_y_symmetry_axis and Global.show_guides
|
||||
)
|
||||
|
||||
var texture_button: TextureRect = horizontal_mirror.get_node("TextureRect")
|
||||
var file_name := "horizontal_mirror_on.png"
|
||||
if !button_pressed:
|
||||
if not toggled_on:
|
||||
file_name = "horizontal_mirror_off.png"
|
||||
Global.change_button_texturerect(texture_button, file_name)
|
||||
|
||||
|
||||
func _on_Vertical_toggled(button_pressed: bool) -> void:
|
||||
Tools.vertical_mirror = button_pressed
|
||||
Global.config_cache.set_value("tools", "vertical_mirror", button_pressed)
|
||||
Global.show_x_symmetry_axis = button_pressed
|
||||
func _on_Vertical_toggled(toggled_on: bool) -> void:
|
||||
Tools.vertical_mirror = toggled_on
|
||||
Global.config_cache.set_value("tools", "vertical_mirror", toggled_on)
|
||||
Global.show_x_symmetry_axis = toggled_on
|
||||
# If the button is not pressed but another button is, keep the symmetry guide visible
|
||||
Global.current_project.x_symmetry_axis.visible = (
|
||||
Global.show_x_symmetry_axis and Global.show_guides
|
||||
|
@ -65,11 +67,43 @@ func _on_Vertical_toggled(button_pressed: bool) -> void:
|
|||
|
||||
var texture_button: TextureRect = vertical_mirror.get_node("TextureRect")
|
||||
var file_name := "vertical_mirror_on.png"
|
||||
if !button_pressed:
|
||||
if not toggled_on:
|
||||
file_name = "vertical_mirror_off.png"
|
||||
Global.change_button_texturerect(texture_button, file_name)
|
||||
|
||||
|
||||
func _on_diagonal_xy_toggled(toggled_on: bool) -> void:
|
||||
Tools.diagonal_xy_mirror = toggled_on
|
||||
Global.config_cache.set_value("tools", "diagonal_xy_mirror", toggled_on)
|
||||
Global.show_xy_symmetry_axis = toggled_on
|
||||
# If the button is not pressed but another button is, keep the symmetry guide visible
|
||||
Global.current_project.diagonal_xy_symmetry_axis.visible = (
|
||||
Global.show_xy_symmetry_axis and Global.show_guides
|
||||
)
|
||||
|
||||
var texture_button: TextureRect = diagonal_xy_mirror.get_node("TextureRect")
|
||||
var file_name := "xy_mirror_on.png"
|
||||
if not toggled_on:
|
||||
file_name = "xy_mirror_off.png"
|
||||
Global.change_button_texturerect(texture_button, file_name)
|
||||
|
||||
|
||||
func _on_diagonal_x_minus_y_toggled(toggled_on: bool) -> void:
|
||||
Tools.diagonal_x_minus_y_mirror = toggled_on
|
||||
Global.config_cache.set_value("tools", "diagonal_x_minus_y_mirror", toggled_on)
|
||||
Global.show_x_minus_y_symmetry_axis = toggled_on
|
||||
# If the button is not pressed but another button is, keep the symmetry guide visible
|
||||
Global.current_project.diagonal_x_minus_y_symmetry_axis.visible = (
|
||||
Global.show_x_minus_y_symmetry_axis and Global.show_guides
|
||||
)
|
||||
|
||||
var texture_button: TextureRect = diagonal_x_minus_y_mirror.get_node("TextureRect")
|
||||
var file_name := "x_minus_y_mirror_on.png"
|
||||
if not toggled_on:
|
||||
file_name = "x_minus_y_mirror_off.png"
|
||||
Global.change_button_texturerect(texture_button, file_name)
|
||||
|
||||
|
||||
func _on_PixelPerfect_toggled(button_pressed: bool) -> void:
|
||||
Tools.pixel_perfect = button_pressed
|
||||
Global.config_cache.set_value("tools", "pixel_perfect", button_pressed)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=25 format=3 uid="uid://wo0hqxkst808"]
|
||||
[gd_scene load_steps=27 format=3 uid="uid://wo0hqxkst808"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://cjrokejjsp5dm" path="res://assets/graphics/misc/horizontal_mirror_off.png" id="1"]
|
||||
[ext_resource type="Texture2D" uid="uid://hiduvaa73fr6" path="res://assets/graphics/misc/vertical_mirror_off.png" id="2"]
|
||||
|
@ -6,8 +6,10 @@
|
|||
[ext_resource type="Texture2D" uid="uid://ct8wn8m6x4m54" path="res://assets/graphics/misc/value_arrow.svg" id="3_faalk"]
|
||||
[ext_resource type="Texture2D" uid="uid://22h12g8p3jtd" path="res://assets/graphics/misc/pixel_perfect_off.png" id="4"]
|
||||
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="5"]
|
||||
[ext_resource type="Texture2D" uid="uid://dlxhm0ronna25" path="res://assets/graphics/misc/xy_mirror_off.png" id="5_hcmgx"]
|
||||
[ext_resource type="Texture2D" uid="uid://j8eywwy082a4" path="res://assets/graphics/misc/alpha_lock_off.png" id="5_jv20x"]
|
||||
[ext_resource type="Texture2D" uid="uid://dg3dumyfj1682" path="res://assets/graphics/misc/dynamics.png" id="6"]
|
||||
[ext_resource type="Texture2D" uid="uid://1kj5gcswa3t2" path="res://assets/graphics/misc/x_minus_y_mirror_off.png" id="6_sw8fy"]
|
||||
[ext_resource type="Texture2D" uid="uid://di8au2u87jgv5" path="res://assets/graphics/misc/uncheck.png" id="7"]
|
||||
[ext_resource type="Script" path="res://src/UI/GlobalToolOptions/DynamicsPanel.gd" id="7_iqcw1"]
|
||||
[ext_resource type="PackedScene" uid="uid://bmsc0s03pwji4" path="res://src/UI/Nodes/MaxMinEdit.tscn" id="8"]
|
||||
|
@ -179,6 +181,108 @@ grow_vertical = 2
|
|||
texture = ExtResource("3_faalk")
|
||||
stretch_mode = 3
|
||||
|
||||
[node name="DiagonalXY" type="Button" parent="ScrollContainer/CenterContainer/GridContainer" groups=["UIButtons"]]
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(46, 32)
|
||||
layout_mode = 2
|
||||
tooltip_text = "Enable vertical mirrored drawing"
|
||||
mouse_default_cursor_shape = 2
|
||||
toggle_mode = true
|
||||
shortcut = SubResource("Shortcut_ai7qc")
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/CenterContainer/GridContainer/DiagonalXY"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 4
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 5.0
|
||||
offset_top = -10.0
|
||||
offset_right = 25.0
|
||||
offset_bottom = 10.0
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("5_hcmgx")
|
||||
|
||||
[node name="MirrorOptions" type="MenuButton" parent="ScrollContainer/CenterContainer/GridContainer/DiagonalXY"]
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(20, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 6
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -20.0
|
||||
offset_top = -10.0
|
||||
offset_bottom = 10.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
item_count = 2
|
||||
popup/item_0/text = "Move to canvas center"
|
||||
popup/item_1/text = "Move to view center"
|
||||
popup/item_1/id = 1
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/CenterContainer/GridContainer/DiagonalXY/MirrorOptions"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("3_faalk")
|
||||
stretch_mode = 3
|
||||
|
||||
[node name="DiagonalXMinusY" type="Button" parent="ScrollContainer/CenterContainer/GridContainer" groups=["UIButtons"]]
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(46, 32)
|
||||
layout_mode = 2
|
||||
tooltip_text = "Enable vertical mirrored drawing"
|
||||
mouse_default_cursor_shape = 2
|
||||
toggle_mode = true
|
||||
shortcut = SubResource("Shortcut_ai7qc")
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/CenterContainer/GridContainer/DiagonalXMinusY"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 4
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 5.0
|
||||
offset_top = -10.0
|
||||
offset_right = 25.0
|
||||
offset_bottom = 10.0
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("6_sw8fy")
|
||||
|
||||
[node name="MirrorOptions" type="MenuButton" parent="ScrollContainer/CenterContainer/GridContainer/DiagonalXMinusY"]
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(20, 0)
|
||||
layout_mode = 1
|
||||
anchors_preset = 6
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -20.0
|
||||
offset_top = -10.0
|
||||
offset_bottom = 10.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
item_count = 2
|
||||
popup/item_0/text = "Move to canvas center"
|
||||
popup/item_1/text = "Move to view center"
|
||||
popup/item_1/id = 1
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/CenterContainer/GridContainer/DiagonalXMinusY/MirrorOptions"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("3_faalk")
|
||||
stretch_mode = 3
|
||||
|
||||
[node name="PixelPerfect" type="Button" parent="ScrollContainer/CenterContainer/GridContainer" groups=["UIButtons"]]
|
||||
custom_minimum_size = Vector2(32, 32)
|
||||
layout_mode = 2
|
||||
|
@ -546,6 +650,8 @@ offset_bottom = 23.0
|
|||
[connection signal="resized" from="." to="." method="_on_resized"]
|
||||
[connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/Horizontal" to="." method="_on_Horizontal_toggled"]
|
||||
[connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/Vertical" to="." method="_on_Vertical_toggled"]
|
||||
[connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/DiagonalXY" to="." method="_on_diagonal_xy_toggled"]
|
||||
[connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/DiagonalXMinusY" to="." method="_on_diagonal_x_minus_y_toggled"]
|
||||
[connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/PixelPerfect" to="." method="_on_PixelPerfect_toggled"]
|
||||
[connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/AlphaLock" to="." method="_on_alpha_lock_toggled"]
|
||||
[connection signal="pressed" from="ScrollContainer/CenterContainer/GridContainer/Dynamics" to="." method="_on_Dynamics_pressed"]
|
||||
|
|
|
@ -55,6 +55,7 @@ class Recorder:
|
|||
dir.make_dir_recursive(save_directory)
|
||||
project.removed.connect(recorder_panel.finalize_recording.bind(project))
|
||||
project.undo_redo.version_changed.connect(capture_frame)
|
||||
recorder_panel.captured_label.text = ""
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_PREDELETE:
|
||||
|
@ -100,6 +101,9 @@ func _on_project_switched() -> void:
|
|||
initialize_recording()
|
||||
start_button.set_pressed_no_signal(true)
|
||||
Global.change_button_texturerect(start_button.get_child(0), "stop.png")
|
||||
captured_label.text = str(
|
||||
"Saved: ", recorded_projects[Global.current_project].frames_captured
|
||||
)
|
||||
else:
|
||||
finalize_recording()
|
||||
start_button.set_pressed_no_signal(false)
|
||||
|
|
|
@ -40,15 +40,18 @@ mouse_default_cursor_shape = 2
|
|||
toggle_mode = true
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/CenterContainer/GridContainer/Start"]
|
||||
layout_mode = 0
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -10.0
|
||||
offset_top = -10.5
|
||||
offset_right = 10.0
|
||||
offset_bottom = 10.5
|
||||
offset_left = -11.0
|
||||
offset_top = -11.0
|
||||
offset_right = 11.0
|
||||
offset_bottom = 11.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("1")
|
||||
expand_mode = 1
|
||||
stretch_mode = 5
|
||||
|
@ -74,7 +77,7 @@ offset_bottom = 10.5
|
|||
texture = ExtResource("3")
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="OpenFolder" type="Button" parent="ScrollContainer/CenterContainer/GridContainer"]
|
||||
[node name="OpenFolder" type="Button" parent="ScrollContainer/CenterContainer/GridContainer" groups=["UIButtons"]]
|
||||
custom_minimum_size = Vector2(32, 32)
|
||||
layout_mode = 2
|
||||
tooltip_text = "Open Folder"
|
||||
|
|
|
@ -140,8 +140,10 @@ func _input(event: InputEvent) -> void:
|
|||
var timeline_rect := Rect2(global_position, size)
|
||||
if timeline_rect.has_point(mouse_pos):
|
||||
if Input.is_key_pressed(KEY_CTRL):
|
||||
cel_size += (2 * int(event.is_action("zoom_in")) - 2 * int(event.is_action("zoom_out")))
|
||||
get_viewport().set_input_as_handled()
|
||||
var zoom := 2 * int(event.is_action("zoom_in")) - 2 * int(event.is_action("zoom_out"))
|
||||
cel_size += zoom
|
||||
if zoom != 0:
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
|
||||
func reset_settings() -> void:
|
||||
|
|
|
@ -421,7 +421,6 @@ func _setup_color_mode_submenu(item: String) -> void:
|
|||
color_mode_submenu.add_radio_check_item("RGBA", ColorModes.RGBA)
|
||||
color_mode_submenu.set_item_checked(ColorModes.RGBA, true)
|
||||
color_mode_submenu.add_radio_check_item("Indexed", ColorModes.INDEXED)
|
||||
color_mode_submenu.hide_on_checkable_item_selection = false
|
||||
|
||||
color_mode_submenu.id_pressed.connect(_color_mode_submenu_id_pressed)
|
||||
image_menu.add_child(color_mode_submenu)
|
||||
|
@ -838,7 +837,7 @@ func _toggle_show_guides() -> void:
|
|||
elif guide.type == Guide.Types.VERTICAL:
|
||||
guide.visible = Global.show_y_symmetry_axis and Global.show_guides
|
||||
elif guide.type == Guide.Types.XY:
|
||||
guide.visible = Global.show_x_y_symmetry_axis and Global.show_guides
|
||||
guide.visible = Global.show_xy_symmetry_axis and Global.show_guides
|
||||
elif guide.type == Guide.Types.X_MINUS_Y:
|
||||
guide.visible = Global.show_x_minus_y_symmetry_axis and Global.show_guides
|
||||
|
||||
|
|