mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-02-13 09:13:07 +00:00
Compare commits
17 commits
fd0c19b8af
...
c9ad65841a
Author | SHA1 | Date | |
---|---|---|---|
|
c9ad65841a | ||
|
763783f2f1 | ||
|
e10b0d1b08 | ||
|
94735fc08b | ||
|
8077262b32 | ||
|
0d6b140dea | ||
|
dec698024c | ||
|
785d8cfc83 | ||
|
4c7d7da5e7 | ||
|
36329efaf6 | ||
|
7c1435e95f | ||
|
ad77d98f42 | ||
|
2600180736 | ||
|
5739a8b28e | ||
|
ce738f02c2 | ||
|
b0b1361722 | ||
|
5fa97988b5 |
27
CHANGELOG.md
27
CHANGELOG.md
|
@ -4,6 +4,33 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). All the dates are in YYYY-MM-DD format.
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). All the dates are in YYYY-MM-DD format.
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
|
## [v1.0.5] - Unreleased
|
||||||
|
This update has been brought to you by the contributions of:
|
||||||
|
Fayez Akhtar ([@Variable-ind](https://github.com/Variable-ind))
|
||||||
|
|
||||||
|
Built using Godot 4.3
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Add density to the square & circle brushes. 100% density means that the brush gets completely drawn. Anything less leaves gaps inside the brush, acting like a spray tool.
|
||||||
|
- Selection expanding, shrinking and borders have been added as options in the Select menu.
|
||||||
|
- Mouse buttons can now be used as menu shortcuts. [#1070](https://github.com/Orama-Interactive/Pixelorama/issues/1070)
|
||||||
|
- Added confirm and cancel buttons in the selection tool options to confirm/cancel an active transformation.
|
||||||
|
- OKHSL Lightness sorting in palettes has been implemented. [#1126](https://github.com/Orama-Interactive/Pixelorama/pull/1126)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- The brush size no longer changes by <kbd>Control</kbd> + Mouse Wheel when resizing the timeline cels or the palette swatches.
|
||||||
|
- The Recorder panel now automatically records for the current project. This also allows for multiple projects to be recorded at the same time.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Panels no longer get scrolled when using the mouse wheel over a slider.
|
||||||
|
- Fixed layer effect slider values being rounded to the nearest integer.
|
||||||
|
- Fixed memory leak where the project remained referenced by a drawing tool, even when its tab was closed.
|
||||||
|
- Fixed memory leak where the first project remained forever references in memory by the Recorder panel.
|
||||||
|
- Slightly optimize circle brushes by only calling the ellipse algorithms once while drawing
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- The Recorder panel has been removed from the Web version. It wasn't functional anyway in a way that was useful, and it's unsure if we can find a way to make it work.
|
||||||
|
|
||||||
## [v1.0.4] - 2024-10-25
|
## [v1.0.4] - 2024-10-25
|
||||||
This update has been brought to you by the contributions of:
|
This update has been brought to you by the contributions of:
|
||||||
Fayez Akhtar ([@Variable-ind](https://github.com/Variable-ind)), Mariano Semelman ([@msemelman](https://github.com/msemelman))
|
Fayez Akhtar ([@Variable-ind](https://github.com/Variable-ind)), Mariano Semelman ([@msemelman](https://github.com/msemelman))
|
||||||
|
|
|
@ -205,6 +205,43 @@ msgstr ""
|
||||||
msgid "Invert"
|
msgid "Invert"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Modify"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Found under the Select menu, in the Modify submenu. When selected, it shows a window that lets users expand the active selection.
|
||||||
|
msgid "Expand"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Title of a window that lets users expand the active selection.
|
||||||
|
msgid "Expand Selection"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Found under the Select menu, in the Modify submenu. When selected, it shows a window that lets users shrink the active selection.
|
||||||
|
msgid "Shrink"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Title of a window that lets users shrink the active selection.
|
||||||
|
msgid "Shrink Selection"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Found under the Select menu, in the Modify submenu. When selected, it shows a window that lets users create a border of the active selection.
|
||||||
|
msgid "Border"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Title of a window that lets users create a border of the active selection.
|
||||||
|
msgid "Border Selection"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Refers to a diamond-like shape.
|
||||||
|
msgid "Diamond"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Circle"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Square"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Grayscale View"
|
msgid "Grayscale View"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -230,19 +267,16 @@ msgstr ""
|
||||||
msgid "Tile Mode Offsets"
|
msgid "Tile Mode Offsets"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "X-basis x:"
|
#. Found under "Tile Mode Offsets". Basis is a linear algebra term. https://en.wikipedia.org/wiki/Basis_(linear_algebra)
|
||||||
|
msgid "X-basis:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "X-basis y:"
|
#. Found under "Tile Mode Offsets". Basis is a linear algebra term. https://en.wikipedia.org/wiki/Basis_(linear_algebra)
|
||||||
|
msgid "Y-basis:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Y-basis x:"
|
#. Found under "Tile Mode Offsets". It's a button that when pressed, enables masking for tile mode. Masking essentially limits drawing to the visible pixels of the image, thus preventing from drawing on transparent pixels.
|
||||||
msgstr ""
|
msgid "Masking:"
|
||||||
|
|
||||||
msgid "Y-basis y:"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Tile Mask"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
|
@ -1865,6 +1899,10 @@ msgstr ""
|
||||||
msgid "Fills the drawn shape with color, instead of drawing a hollow shape"
|
msgid "Fills the drawn shape with color, instead of drawing a hollow shape"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. Found in the tool options of the Pencil, Eraser and Shading tools. It is a percentage of how dense the brush is. 100% density means that the brush gets completely drawn, anything less leaves gaps inside the brush, acting like a spray tool.
|
||||||
|
msgid "Density:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Brush color from"
|
msgid "Brush color from"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -2808,6 +2846,10 @@ msgstr ""
|
||||||
msgid "Sort by value"
|
msgid "Sort by value"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. An option of the Sort palette button found in the palette panel. When selected, the colors of the palette are being sorted based on their OKHSL Lightness.
|
||||||
|
msgid "Sort by lightness"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. An option of the Sort palette button found in the palette panel. When selected, the colors of the palette are being sorted based on their red channel value.
|
#. An option of the Sort palette button found in the palette panel. When selected, the colors of the palette are being sorted based on their red channel value.
|
||||||
msgid "Sort by red"
|
msgid "Sort by red"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -534,6 +534,10 @@ class SelectionAPI:
|
||||||
Global.canvas.selection.move_borders_start()
|
Global.canvas.selection.move_borders_start()
|
||||||
else:
|
else:
|
||||||
Global.canvas.selection.transform_content_start()
|
Global.canvas.selection.transform_content_start()
|
||||||
|
|
||||||
|
if Global.canvas.selection.original_bitmap.is_empty(): # To avoid copying twice.
|
||||||
|
Global.canvas.selection.original_bitmap.copy_from(Global.current_project.selection_map)
|
||||||
|
|
||||||
Global.canvas.selection.big_bounding_rectangle.size = new_size
|
Global.canvas.selection.big_bounding_rectangle.size = new_size
|
||||||
Global.canvas.selection.resize_selection()
|
Global.canvas.selection.resize_selection()
|
||||||
Global.canvas.selection.move_borders_end()
|
Global.canvas.selection.move_borders_end()
|
||||||
|
|
|
@ -71,7 +71,7 @@ enum EffectsMenu {
|
||||||
SHADER
|
SHADER
|
||||||
}
|
}
|
||||||
## Enumeration of items present in the Select Menu.
|
## Enumeration of items present in the Select Menu.
|
||||||
enum SelectMenu { SELECT_ALL, CLEAR_SELECTION, INVERT, TILE_MODE }
|
enum SelectMenu { SELECT_ALL, CLEAR_SELECTION, INVERT, TILE_MODE, MODIFY }
|
||||||
## Enumeration of items present in the Help Menu.
|
## Enumeration of items present in the Help Menu.
|
||||||
enum HelpMenu {
|
enum HelpMenu {
|
||||||
VIEW_SPLASH_SCREEN,
|
VIEW_SPLASH_SCREEN,
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
class_name SelectionMap
|
class_name SelectionMap
|
||||||
extends Image
|
extends Image
|
||||||
|
|
||||||
var invert_shader := preload("res://src/Shaders/Effects/Invert.gdshader")
|
const INVERT_SHADER := preload("res://src/Shaders/Effects/Invert.gdshader")
|
||||||
|
const OUTLINE_INLINE_SHADER := preload("res://src/Shaders/Effects/OutlineInline.gdshader")
|
||||||
|
|
||||||
|
|
||||||
func is_pixel_selected(pixel: Vector2i, calculate_offset := true) -> bool:
|
func is_pixel_selected(pixel: Vector2i, calculate_offset := true) -> bool:
|
||||||
|
@ -87,8 +88,7 @@ func clear() -> void:
|
||||||
func invert() -> void:
|
func invert() -> void:
|
||||||
var params := {"red": true, "green": true, "blue": true, "alpha": true}
|
var params := {"red": true, "green": true, "blue": true, "alpha": true}
|
||||||
var gen := ShaderImageEffect.new()
|
var gen := ShaderImageEffect.new()
|
||||||
gen.generate_image(self, invert_shader, params, get_size())
|
gen.generate_image(self, INVERT_SHADER, params, get_size())
|
||||||
self.convert(Image.FORMAT_LA8)
|
|
||||||
|
|
||||||
|
|
||||||
## Returns a copy of itself that is cropped to [param size].
|
## Returns a copy of itself that is cropped to [param size].
|
||||||
|
@ -183,3 +183,36 @@ func resize_bitmap_values(
|
||||||
if new_bitmap_size != size:
|
if new_bitmap_size != size:
|
||||||
crop(new_bitmap_size.x, new_bitmap_size.y)
|
crop(new_bitmap_size.x, new_bitmap_size.y)
|
||||||
blit_rect(smaller_image, Rect2i(Vector2i.ZERO, new_bitmap_size), dst)
|
blit_rect(smaller_image, Rect2i(Vector2i.ZERO, new_bitmap_size), dst)
|
||||||
|
|
||||||
|
|
||||||
|
func expand(width: int, brush: int) -> void:
|
||||||
|
var params := {
|
||||||
|
"color": Color(1, 1, 1, 1),
|
||||||
|
"width": width,
|
||||||
|
"brush": brush,
|
||||||
|
}
|
||||||
|
var gen := ShaderImageEffect.new()
|
||||||
|
gen.generate_image(self, OUTLINE_INLINE_SHADER, params, get_size())
|
||||||
|
|
||||||
|
|
||||||
|
func shrink(width: int, brush: int) -> void:
|
||||||
|
var params := {
|
||||||
|
"color": Color(0),
|
||||||
|
"width": width,
|
||||||
|
"brush": brush,
|
||||||
|
"inside": true,
|
||||||
|
}
|
||||||
|
var gen := ShaderImageEffect.new()
|
||||||
|
gen.generate_image(self, OUTLINE_INLINE_SHADER, params, get_size())
|
||||||
|
|
||||||
|
|
||||||
|
func border(width: int, brush: int) -> void:
|
||||||
|
var params := {
|
||||||
|
"color": Color(1, 1, 1, 1),
|
||||||
|
"width": width,
|
||||||
|
"brush": brush,
|
||||||
|
"inside": true,
|
||||||
|
"keep_border_only": true,
|
||||||
|
}
|
||||||
|
var gen := ShaderImageEffect.new()
|
||||||
|
gen.generate_image(self, OUTLINE_INLINE_SHADER, params, get_size())
|
||||||
|
|
|
@ -54,7 +54,7 @@ func generate_image(img: Image, shader: Shader, params: Dictionary, size: Vector
|
||||||
RenderingServer.free_rid(ci_rid)
|
RenderingServer.free_rid(ci_rid)
|
||||||
RenderingServer.free_rid(mat_rid)
|
RenderingServer.free_rid(mat_rid)
|
||||||
RenderingServer.free_rid(texture)
|
RenderingServer.free_rid(texture)
|
||||||
viewport_texture.convert(Image.FORMAT_RGBA8)
|
viewport_texture.convert(img.get_format())
|
||||||
img.copy_from(viewport_texture)
|
img.copy_from(viewport_texture)
|
||||||
if resized_width:
|
if resized_width:
|
||||||
img.crop(img.get_width() - 1, img.get_height())
|
img.crop(img.get_width() - 1, img.get_height())
|
||||||
|
|
|
@ -148,13 +148,13 @@ static func create_ui_for_shader_uniforms(
|
||||||
|
|
||||||
if u_value != "":
|
if u_value != "":
|
||||||
slider.value = int(u_value)
|
slider.value = int(u_value)
|
||||||
|
slider.min_value = min_value
|
||||||
|
slider.max_value = max_value
|
||||||
|
slider.step = step
|
||||||
if params.has(u_name):
|
if params.has(u_name):
|
||||||
slider.value = params[u_name]
|
slider.value = params[u_name]
|
||||||
else:
|
else:
|
||||||
params[u_name] = slider.value
|
params[u_name] = slider.value
|
||||||
slider.min_value = min_value
|
|
||||||
slider.max_value = max_value
|
|
||||||
slider.step = step
|
|
||||||
slider.value_changed.connect(value_changed.bind(u_name))
|
slider.value_changed.connect(value_changed.bind(u_name))
|
||||||
slider.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
slider.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||||
hbox.add_child(slider)
|
hbox.add_child(slider)
|
||||||
|
|
|
@ -90,3 +90,4 @@ func _on_PaletteScroll_gui_input(event: InputEvent) -> void:
|
||||||
return
|
return
|
||||||
resize_grid()
|
resize_grid()
|
||||||
set_sliders(palette_grid.current_palette, palette_grid.grid_window_origin + scroll_vector)
|
set_sliders(palette_grid.current_palette, palette_grid.grid_window_origin + scroll_vector)
|
||||||
|
get_window().set_input_as_handled()
|
||||||
|
|
|
@ -4,9 +4,10 @@ render_mode unshaded;
|
||||||
|
|
||||||
uniform vec4 color : source_color = vec4(1.0);
|
uniform vec4 color : source_color = vec4(1.0);
|
||||||
uniform float width : hint_range(0, 10, 1) = 1.0;
|
uniform float width : hint_range(0, 10, 1) = 1.0;
|
||||||
// uniform_data pattern type:: OptionButton [Diamond||Circle||Square]
|
// uniform_data brush type:: OptionButton [Diamond||Circle||Square]
|
||||||
uniform int pattern : hint_range(0, 2) = 0;
|
uniform int brush : hint_range(0, 2) = 0;
|
||||||
uniform bool inside = false;
|
uniform bool inside = false;
|
||||||
|
uniform bool keep_border_only = false;
|
||||||
uniform sampler2D selection : filter_nearest;
|
uniform sampler2D selection : filter_nearest;
|
||||||
|
|
||||||
bool is_zero_approx(float num) {
|
bool is_zero_approx(float num) {
|
||||||
|
@ -17,11 +18,11 @@ bool has_contrary_neighbour(vec2 uv, vec2 texture_pixel_size, sampler2D tex) {
|
||||||
for (float i = -ceil(width); i <= ceil(width); i++) {
|
for (float i = -ceil(width); i <= ceil(width); i++) {
|
||||||
float offset;
|
float offset;
|
||||||
|
|
||||||
if (pattern == 0) {
|
if (brush == 0) {
|
||||||
offset = width - abs(i);
|
offset = width - abs(i);
|
||||||
} else if (pattern == 1) {
|
} else if (brush == 1) {
|
||||||
offset = floor(sqrt(pow(width + 0.5, 2) - i * i));
|
offset = floor(sqrt(pow(width + 0.5, 2) - i * i));
|
||||||
} else if (pattern == 2) {
|
} else if (brush == 2) {
|
||||||
offset = width;
|
offset = width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +45,15 @@ void fragment() {
|
||||||
|
|
||||||
if ((output.a > 0.0) == inside && has_contrary_neighbour(UV, TEXTURE_PIXEL_SIZE, TEXTURE)) {
|
if ((output.a > 0.0) == inside && has_contrary_neighbour(UV, TEXTURE_PIXEL_SIZE, TEXTURE)) {
|
||||||
output.rgb = inside ? mix(output.rgb, color.rgb, color.a) : color.rgb;
|
output.rgb = inside ? mix(output.rgb, color.rgb, color.a) : color.rgb;
|
||||||
output.a += (1.0 - output.a) * color.a;
|
if (is_zero_approx(color.a)) {
|
||||||
|
output.a = color.a;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
output.a += (1.0 - output.a) * color.a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (keep_border_only) {
|
||||||
|
output.a = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
COLOR = mix(original_color, output, selection_color.a);
|
COLOR = mix(original_color, output, selection_color.a);
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
extends BaseTool
|
extends BaseTool
|
||||||
|
|
||||||
|
const IMAGE_BRUSHES := [Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM]
|
||||||
|
|
||||||
var _brush := Brushes.get_default_brush()
|
var _brush := Brushes.get_default_brush()
|
||||||
var _brush_size := 1
|
var _brush_size := 1
|
||||||
var _brush_size_dynamics := 1
|
var _brush_size_dynamics := 1
|
||||||
|
var _brush_density := 100
|
||||||
var _brush_flip_x := false
|
var _brush_flip_x := false
|
||||||
var _brush_flip_y := false
|
var _brush_flip_y := false
|
||||||
var _brush_rotate_90 := false
|
var _brush_rotate_90 := false
|
||||||
|
@ -89,6 +92,12 @@ func _reset_dynamics() -> void:
|
||||||
save_config()
|
save_config()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_density_value_slider_value_changed(value: int) -> void:
|
||||||
|
_brush_density = value
|
||||||
|
update_config()
|
||||||
|
save_config()
|
||||||
|
|
||||||
|
|
||||||
func _on_InterpolateFactor_value_changed(value: float) -> void:
|
func _on_InterpolateFactor_value_changed(value: float) -> void:
|
||||||
_brush_interpolate = int(value)
|
_brush_interpolate = int(value)
|
||||||
update_config()
|
update_config()
|
||||||
|
@ -111,6 +120,7 @@ func get_config() -> Dictionary:
|
||||||
"brush_type": _brush.type,
|
"brush_type": _brush.type,
|
||||||
"brush_index": _brush.index,
|
"brush_index": _brush.index,
|
||||||
"brush_size": _brush_size,
|
"brush_size": _brush_size,
|
||||||
|
"brush_density": _brush_density,
|
||||||
"brush_interpolate": _brush_interpolate,
|
"brush_interpolate": _brush_interpolate,
|
||||||
"brush_flip_x": _brush_flip_x,
|
"brush_flip_x": _brush_flip_x,
|
||||||
"brush_flip_y": _brush_flip_y,
|
"brush_flip_y": _brush_flip_y,
|
||||||
|
@ -128,6 +138,7 @@ func set_config(config: Dictionary) -> void:
|
||||||
_brush_size_dynamics = _brush_size
|
_brush_size_dynamics = _brush_size
|
||||||
if Tools.dynamics_size != Tools.Dynamics.NONE:
|
if Tools.dynamics_size != Tools.Dynamics.NONE:
|
||||||
_brush_size_dynamics = Tools.brush_size_min
|
_brush_size_dynamics = Tools.brush_size_min
|
||||||
|
_brush_density = config.get("brush_density", _brush_density)
|
||||||
_brush_interpolate = config.get("brush_interpolate", _brush_interpolate)
|
_brush_interpolate = config.get("brush_interpolate", _brush_interpolate)
|
||||||
_brush_flip_x = config.get("brush_flip_x", _brush_flip_x)
|
_brush_flip_x = config.get("brush_flip_x", _brush_flip_x)
|
||||||
_brush_flip_y = config.get("brush_flip_y", _brush_flip_y)
|
_brush_flip_y = config.get("brush_flip_y", _brush_flip_y)
|
||||||
|
@ -177,11 +188,13 @@ func update_brush() -> void:
|
||||||
_brush_texture = ImageTexture.create_from_image(_brush_image)
|
_brush_texture = ImageTexture.create_from_image(_brush_image)
|
||||||
update_mirror_brush()
|
update_mirror_brush()
|
||||||
_stroke_dimensions = _brush_image.get_size()
|
_stroke_dimensions = _brush_image.get_size()
|
||||||
|
_circle_tool_shortcut = []
|
||||||
_indicator = _create_brush_indicator()
|
_indicator = _create_brush_indicator()
|
||||||
_polylines = _create_polylines(_indicator)
|
_polylines = _create_polylines(_indicator)
|
||||||
$Brush/Type/Texture.texture = _brush_texture
|
$Brush/Type/Texture.texture = _brush_texture
|
||||||
$ColorInterpolation.visible = _brush.type in [Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM]
|
$DensityValueSlider.visible = _brush.type not in IMAGE_BRUSHES
|
||||||
$RotationOptions.visible = _brush.type in [Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM]
|
$ColorInterpolation.visible = _brush.type in IMAGE_BRUSHES
|
||||||
|
$RotationOptions.visible = _brush.type in IMAGE_BRUSHES
|
||||||
|
|
||||||
|
|
||||||
func update_random_image() -> void:
|
func update_random_image() -> void:
|
||||||
|
@ -275,6 +288,7 @@ func draw_end(pos: Vector2i) -> void:
|
||||||
super.draw_end(pos)
|
super.draw_end(pos)
|
||||||
_stroke_project = null
|
_stroke_project = null
|
||||||
_stroke_images = []
|
_stroke_images = []
|
||||||
|
_circle_tool_shortcut = []
|
||||||
_brush_size_dynamics = _brush_size
|
_brush_size_dynamics = _brush_size
|
||||||
if Tools.dynamics_size != Tools.Dynamics.NONE:
|
if Tools.dynamics_size != Tools.Dynamics.NONE:
|
||||||
_brush_size_dynamics = Tools.brush_size_min
|
_brush_size_dynamics = Tools.brush_size_min
|
||||||
|
@ -313,10 +327,6 @@ func _prepare_tool() -> void:
|
||||||
# This may prevent a few tests when setting pixels
|
# This may prevent a few tests when setting pixels
|
||||||
_is_mask_size_zero = _mask.size() == 0
|
_is_mask_size_zero = _mask.size() == 0
|
||||||
match _brush.type:
|
match _brush.type:
|
||||||
Brushes.CIRCLE:
|
|
||||||
_prepare_circle_tool(false)
|
|
||||||
Brushes.FILLED_CIRCLE:
|
|
||||||
_prepare_circle_tool(true)
|
|
||||||
Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM:
|
Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM:
|
||||||
# save _brush_image for safe keeping
|
# save _brush_image for safe keeping
|
||||||
_brush_image = _create_blended_brush_image(_orignal_brush_image)
|
_brush_image = _create_blended_brush_image(_orignal_brush_image)
|
||||||
|
@ -326,19 +336,6 @@ func _prepare_tool() -> void:
|
||||||
_stroke_dimensions = _brush_image.get_size()
|
_stroke_dimensions = _brush_image.get_size()
|
||||||
|
|
||||||
|
|
||||||
func _prepare_circle_tool(fill: bool) -> void:
|
|
||||||
var circle_tool_map := _create_circle_indicator(_brush_size_dynamics, fill)
|
|
||||||
# Go through that BitMap and build an Array of the "displacement" from the center of the bits
|
|
||||||
# that are true.
|
|
||||||
var diameter := _brush_size_dynamics * 2 + 1
|
|
||||||
for n in range(0, diameter):
|
|
||||||
for m in range(0, diameter):
|
|
||||||
if circle_tool_map.get_bitv(Vector2i(m, n)):
|
|
||||||
_circle_tool_shortcut.append(
|
|
||||||
Vector2i(m - _brush_size_dynamics, n - _brush_size_dynamics)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
## Make sure to always have invoked _prepare_tool() before this. This computes the coordinates to be
|
## Make sure to always have invoked _prepare_tool() before this. This computes the coordinates to be
|
||||||
## drawn if it can (except for the generic brush, when it's actually drawing them)
|
## drawn if it can (except for the generic brush, when it's actually drawing them)
|
||||||
func _draw_tool(pos: Vector2) -> PackedVector2Array:
|
func _draw_tool(pos: Vector2) -> PackedVector2Array:
|
||||||
|
@ -507,7 +504,7 @@ func draw_indicator(left: bool) -> void:
|
||||||
|
|
||||||
func draw_indicator_at(pos: Vector2i, offset: Vector2i, color: Color) -> void:
|
func draw_indicator_at(pos: Vector2i, offset: Vector2i, color: Color) -> void:
|
||||||
var canvas: Node2D = Global.canvas.indicators
|
var canvas: Node2D = Global.canvas.indicators
|
||||||
if _brush.type in [Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM] and not _draw_line:
|
if _brush.type in IMAGE_BRUSHES and not _draw_line:
|
||||||
pos -= _brush_image.get_size() / 2
|
pos -= _brush_image.get_size() / 2
|
||||||
pos -= offset
|
pos -= offset
|
||||||
canvas.draw_texture(_brush_texture, pos)
|
canvas.draw_texture(_brush_texture, pos)
|
||||||
|
@ -537,6 +534,8 @@ func _set_pixel(pos: Vector2i, ignore_mirroring := false) -> void:
|
||||||
|
|
||||||
|
|
||||||
func _set_pixel_no_cache(pos: Vector2i, ignore_mirroring := false) -> void:
|
func _set_pixel_no_cache(pos: Vector2i, ignore_mirroring := false) -> void:
|
||||||
|
if randi() % 100 >= _brush_density:
|
||||||
|
return
|
||||||
pos = _stroke_project.tiles.get_canon_position(pos)
|
pos = _stroke_project.tiles.get_canon_position(pos)
|
||||||
if Global.current_project.has_selection:
|
if Global.current_project.has_selection:
|
||||||
pos = Global.current_project.selection_map.get_canon_position(pos)
|
pos = Global.current_project.selection_map.get_canon_position(pos)
|
||||||
|
@ -621,10 +620,24 @@ func _create_pixel_indicator(brush_size: int) -> BitMap:
|
||||||
|
|
||||||
|
|
||||||
func _create_circle_indicator(brush_size: int, fill := false) -> BitMap:
|
func _create_circle_indicator(brush_size: int, fill := false) -> BitMap:
|
||||||
_circle_tool_shortcut = []
|
if Tools.dynamics_size != Tools.Dynamics.NONE:
|
||||||
|
_circle_tool_shortcut = []
|
||||||
var brush_size_v2 := Vector2i(brush_size, brush_size)
|
var brush_size_v2 := Vector2i(brush_size, brush_size)
|
||||||
var diameter := brush_size_v2 * 2 + Vector2i.ONE
|
var diameter_v2 := brush_size_v2 * 2 + Vector2i.ONE
|
||||||
return _fill_bitmap_with_points(_compute_draw_tool_circle(brush_size_v2, fill), diameter)
|
var circle_tool_map := _fill_bitmap_with_points(
|
||||||
|
_compute_draw_tool_circle(brush_size_v2, fill), diameter_v2
|
||||||
|
)
|
||||||
|
if _circle_tool_shortcut.is_empty():
|
||||||
|
# Go through that BitMap and build an Array of the "displacement"
|
||||||
|
# from the center of the bits that are true.
|
||||||
|
var diameter := _brush_size_dynamics * 2 + 1
|
||||||
|
for n in range(0, diameter):
|
||||||
|
for m in range(0, diameter):
|
||||||
|
if circle_tool_map.get_bitv(Vector2i(m, n)):
|
||||||
|
_circle_tool_shortcut.append(
|
||||||
|
Vector2i(m - _brush_size_dynamics, n - _brush_size_dynamics)
|
||||||
|
)
|
||||||
|
return circle_tool_map
|
||||||
|
|
||||||
|
|
||||||
func _create_line_indicator(indicator: BitMap, start: Vector2i, end: Vector2i) -> BitMap:
|
func _create_line_indicator(indicator: BitMap, start: Vector2i, end: Vector2i) -> BitMap:
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
[gd_scene load_steps=8 format=3 uid="uid://ubyatap3sylf"]
|
[gd_scene load_steps=9 format=3 uid="uid://ubyatap3sylf"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="1"]
|
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/ValueSlider.tscn" id="1"]
|
||||||
[ext_resource type="PackedScene" uid="uid://ctfgfelg0sho8" path="res://src/Tools/BaseTool.tscn" id="2"]
|
[ext_resource type="PackedScene" uid="uid://ctfgfelg0sho8" path="res://src/Tools/BaseTool.tscn" id="2"]
|
||||||
[ext_resource type="Script" path="res://src/Tools/BaseDraw.gd" id="3"]
|
[ext_resource type="Script" path="res://src/Tools/BaseDraw.gd" id="3"]
|
||||||
[ext_resource type="Script" path="res://src/UI/Nodes/CollapsibleContainer.gd" id="3_76bek"]
|
[ext_resource type="Script" path="res://src/UI/Nodes/CollapsibleContainer.gd" id="3_76bek"]
|
||||||
|
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="5_kdxku"]
|
||||||
|
|
||||||
[sub_resource type="ButtonGroup" id="ButtonGroup_7u3x0"]
|
[sub_resource type="ButtonGroup" id="ButtonGroup_7u3x0"]
|
||||||
resource_name = "rotate"
|
resource_name = "rotate"
|
||||||
|
@ -130,7 +131,25 @@ suffix = "px"
|
||||||
global_increment_action = "brush_size_increment"
|
global_increment_action = "brush_size_increment"
|
||||||
global_decrement_action = "brush_size_decrement"
|
global_decrement_action = "brush_size_decrement"
|
||||||
|
|
||||||
[node name="ColorInterpolation" parent="." index="4" instance=ExtResource("1")]
|
[node name="DensityValueSlider" type="TextureProgressBar" parent="." index="4"]
|
||||||
|
visible = false
|
||||||
|
custom_minimum_size = Vector2(0, 24)
|
||||||
|
layout_mode = 2
|
||||||
|
focus_mode = 2
|
||||||
|
mouse_default_cursor_shape = 2
|
||||||
|
theme_type_variation = &"ValueSlider"
|
||||||
|
min_value = 1.0
|
||||||
|
value = 100.0
|
||||||
|
nine_patch_stretch = true
|
||||||
|
stretch_margin_left = 3
|
||||||
|
stretch_margin_top = 3
|
||||||
|
stretch_margin_right = 3
|
||||||
|
stretch_margin_bottom = 3
|
||||||
|
script = ExtResource("5_kdxku")
|
||||||
|
prefix = "Density:"
|
||||||
|
suffix = "%"
|
||||||
|
|
||||||
|
[node name="ColorInterpolation" parent="." index="5" instance=ExtResource("1")]
|
||||||
visible = false
|
visible = false
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
tooltip_text = "0: Color from the brush itself, 100: the currently selected color"
|
tooltip_text = "0: Color from the brush itself, 100: the currently selected color"
|
||||||
|
@ -143,4 +162,5 @@ prefix = "Brush color from:"
|
||||||
[connection signal="toggled" from="RotationOptions/GridContainer/Rotate/Rotate270" to="." method="_on_rotate_270_toggled"]
|
[connection signal="toggled" from="RotationOptions/GridContainer/Rotate/Rotate270" to="." method="_on_rotate_270_toggled"]
|
||||||
[connection signal="pressed" from="Brush/Type" to="." method="_on_BrushType_pressed"]
|
[connection signal="pressed" from="Brush/Type" to="." method="_on_BrushType_pressed"]
|
||||||
[connection signal="value_changed" from="Brush/BrushSize" to="." method="_on_BrushSize_value_changed"]
|
[connection signal="value_changed" from="Brush/BrushSize" to="." method="_on_BrushSize_value_changed"]
|
||||||
|
[connection signal="value_changed" from="DensityValueSlider" to="." method="_on_density_value_slider_value_changed"]
|
||||||
[connection signal="value_changed" from="ColorInterpolation" to="." method="_on_InterpolateFactor_value_changed"]
|
[connection signal="value_changed" from="ColorInterpolation" to="." method="_on_InterpolateFactor_value_changed"]
|
||||||
|
|
|
@ -106,6 +106,11 @@ func _input(event: InputEvent) -> void:
|
||||||
image_current_pixel = canvas.current_pixel
|
image_current_pixel = canvas.current_pixel
|
||||||
if Global.mirror_view:
|
if Global.mirror_view:
|
||||||
image_current_pixel.x = Global.current_project.size.x - image_current_pixel.x
|
image_current_pixel.x = Global.current_project.size.x - image_current_pixel.x
|
||||||
|
if is_moving_content:
|
||||||
|
if Input.is_action_just_pressed(&"transformation_confirm"):
|
||||||
|
transform_content_confirm()
|
||||||
|
elif Input.is_action_just_pressed(&"transformation_cancel"):
|
||||||
|
transform_content_cancel()
|
||||||
if not project.layers[project.current_layer].can_layer_get_drawn():
|
if not project.layers[project.current_layer].can_layer_get_drawn():
|
||||||
return
|
return
|
||||||
if event is InputEventKey:
|
if event is InputEventKey:
|
||||||
|
|
|
@ -3,7 +3,7 @@ extends Node2D
|
||||||
var tiles: Tiles
|
var tiles: Tiles
|
||||||
var draw_center := false
|
var draw_center := false
|
||||||
|
|
||||||
@onready var canvas := get_parent() as Canvas
|
@onready var canvas := Global.canvas
|
||||||
|
|
||||||
|
|
||||||
func _draw() -> void:
|
func _draw() -> void:
|
||||||
|
|
|
@ -31,7 +31,7 @@ func commit_action(cel: Image, project := Global.current_project) -> void:
|
||||||
var params := {
|
var params := {
|
||||||
"color": color,
|
"color": color,
|
||||||
"width": anim_thickness,
|
"width": anim_thickness,
|
||||||
"pattern": pattern,
|
"brush": pattern,
|
||||||
"inside": inside_image,
|
"inside": inside_image,
|
||||||
"selection": selection_tex
|
"selection": selection_tex
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,16 +51,15 @@ size_flags_horizontal = 3
|
||||||
[node name="PatternLabel" type="Label" parent="VBoxContainer/OutlineOptions" index="4"]
|
[node name="PatternLabel" type="Label" parent="VBoxContainer/OutlineOptions" index="4"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
text = "Pattern:"
|
text = "Brush:"
|
||||||
|
|
||||||
[node name="PatternOptionButton" type="OptionButton" parent="VBoxContainer/OutlineOptions" index="5"]
|
[node name="PatternOptionButton" type="OptionButton" parent="VBoxContainer/OutlineOptions" index="5"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
mouse_default_cursor_shape = 2
|
mouse_default_cursor_shape = 2
|
||||||
item_count = 3
|
|
||||||
selected = 0
|
selected = 0
|
||||||
|
item_count = 3
|
||||||
popup/item_0/text = "Diamond"
|
popup/item_0/text = "Diamond"
|
||||||
popup/item_0/id = 0
|
|
||||||
popup/item_1/text = "Circle"
|
popup/item_1/text = "Circle"
|
||||||
popup/item_1/id = 1
|
popup/item_1/id = 1
|
||||||
popup/item_2/text = "Square"
|
popup/item_2/text = "Square"
|
||||||
|
|
43
src/UI/Dialogs/ModifySelection.gd
Normal file
43
src/UI/Dialogs/ModifySelection.gd
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
extends ConfirmationDialog
|
||||||
|
|
||||||
|
enum Types { EXPAND, SHRINK, BORDER }
|
||||||
|
|
||||||
|
@export var type := Types.EXPAND:
|
||||||
|
set(value):
|
||||||
|
type = value
|
||||||
|
if type == Types.EXPAND:
|
||||||
|
title = "Expand Selection"
|
||||||
|
elif type == Types.SHRINK:
|
||||||
|
title = "Shrink Selection"
|
||||||
|
else:
|
||||||
|
title = "Border Selection"
|
||||||
|
|
||||||
|
@onready var width_slider: ValueSlider = $GridContainer/WidthSlider
|
||||||
|
@onready var brush_option_button: OptionButton = $GridContainer/BrushOptionButton
|
||||||
|
@onready var selection_node := Global.canvas.selection
|
||||||
|
|
||||||
|
|
||||||
|
func _on_visibility_changed() -> void:
|
||||||
|
if not visible:
|
||||||
|
Global.dialog_open(false)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_confirmed() -> void:
|
||||||
|
var project := Global.current_project
|
||||||
|
if !project.has_selection:
|
||||||
|
return
|
||||||
|
selection_node.transform_content_confirm()
|
||||||
|
var undo_data_tmp := selection_node.get_undo_data(false)
|
||||||
|
var width: int = width_slider.value
|
||||||
|
var brush := brush_option_button.selected
|
||||||
|
project.selection_map.crop(project.size.x, project.size.y)
|
||||||
|
if type == Types.EXPAND:
|
||||||
|
project.selection_map.expand(width, brush)
|
||||||
|
elif type == Types.SHRINK:
|
||||||
|
project.selection_map.shrink(width, brush)
|
||||||
|
else:
|
||||||
|
project.selection_map.border(width, brush)
|
||||||
|
selection_node.big_bounding_rectangle = project.selection_map.get_used_rect()
|
||||||
|
project.selection_offset = Vector2.ZERO
|
||||||
|
selection_node.commit_undo("Modify Selection", undo_data_tmp)
|
||||||
|
selection_node.queue_redraw()
|
60
src/UI/Dialogs/ModifySelection.tscn
Normal file
60
src/UI/Dialogs/ModifySelection.tscn
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
[gd_scene load_steps=3 format=3 uid="uid://wcbpnsm7gptu"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="1_3jelw"]
|
||||||
|
[ext_resource type="Script" path="res://src/UI/Dialogs/ModifySelection.gd" id="1_w6rs7"]
|
||||||
|
|
||||||
|
[node name="ModifySelection" type="ConfirmationDialog"]
|
||||||
|
title = "Expand selection"
|
||||||
|
position = Vector2i(0, 36)
|
||||||
|
size = Vector2i(260, 130)
|
||||||
|
script = ExtResource("1_w6rs7")
|
||||||
|
|
||||||
|
[node name="GridContainer" type="GridContainer" parent="."]
|
||||||
|
offset_left = 8.0
|
||||||
|
offset_top = 8.0
|
||||||
|
offset_right = 252.0
|
||||||
|
offset_bottom = 81.0
|
||||||
|
columns = 2
|
||||||
|
|
||||||
|
[node name="WidthLabel" type="Label" parent="GridContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
text = "Width:"
|
||||||
|
|
||||||
|
[node name="WidthSlider" type="TextureProgressBar" parent="GridContainer"]
|
||||||
|
custom_minimum_size = Vector2(0, 24)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
focus_mode = 2
|
||||||
|
mouse_default_cursor_shape = 2
|
||||||
|
theme_type_variation = &"ValueSlider"
|
||||||
|
min_value = 1.0
|
||||||
|
max_value = 25.0
|
||||||
|
value = 1.0
|
||||||
|
allow_greater = true
|
||||||
|
nine_patch_stretch = true
|
||||||
|
stretch_margin_left = 3
|
||||||
|
stretch_margin_top = 3
|
||||||
|
stretch_margin_right = 3
|
||||||
|
stretch_margin_bottom = 3
|
||||||
|
script = ExtResource("1_3jelw")
|
||||||
|
|
||||||
|
[node name="BrushLabel" type="Label" parent="GridContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
text = "Brush:"
|
||||||
|
|
||||||
|
[node name="BrushOptionButton" type="OptionButton" parent="GridContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
mouse_default_cursor_shape = 2
|
||||||
|
selected = 0
|
||||||
|
item_count = 3
|
||||||
|
popup/item_0/text = "Diamond"
|
||||||
|
popup/item_1/text = "Circle"
|
||||||
|
popup/item_1/id = 1
|
||||||
|
popup/item_2/text = "Square"
|
||||||
|
popup/item_2/id = 2
|
||||||
|
|
||||||
|
[connection signal="confirmed" from="." to="." method="_on_confirmed"]
|
||||||
|
[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"]
|
|
@ -1,11 +1,12 @@
|
||||||
extends ConfirmationDialog
|
extends ConfirmationDialog
|
||||||
|
|
||||||
@onready var x_basis_x_spinbox: SpinBox = $VBoxContainer/HBoxContainer/OptionsContainer/XBasisX
|
@onready var x_basis_label: Label = $VBoxContainer/OptionsContainer/XBasisLabel
|
||||||
@onready var x_basis_y_spinbox: SpinBox = $VBoxContainer/HBoxContainer/OptionsContainer/XBasisY
|
@onready var x_basis: ValueSliderV2 = $VBoxContainer/OptionsContainer/XBasis
|
||||||
@onready var y_basis_x_spinbox: SpinBox = $VBoxContainer/HBoxContainer/OptionsContainer/YBasisX
|
@onready var y_basis_label: Label = $VBoxContainer/OptionsContainer/YBasisLabel
|
||||||
@onready var y_basis_y_spinbox: SpinBox = $VBoxContainer/HBoxContainer/OptionsContainer/YBasisY
|
@onready var y_basis: ValueSliderV2 = $VBoxContainer/OptionsContainer/YBasis
|
||||||
@onready var preview_rect: Control = $VBoxContainer/AspectRatioContainer/Preview
|
@onready var preview_rect: Control = $VBoxContainer/AspectRatioContainer/Preview
|
||||||
@onready var tile_mode: Node2D = $VBoxContainer/AspectRatioContainer/Preview/TileMode
|
@onready var tile_mode: Node2D = $VBoxContainer/AspectRatioContainer/Preview/TileMode
|
||||||
|
@onready var masking: CheckButton = $VBoxContainer/OptionsContainer/Masking
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
@ -37,35 +38,25 @@ func _on_TileModeOffsetsDialog_about_to_show() -> void:
|
||||||
tile_mode.tiles.mode = Global.current_project.tiles.mode
|
tile_mode.tiles.mode = Global.current_project.tiles.mode
|
||||||
tile_mode.tiles.x_basis = Global.current_project.tiles.x_basis
|
tile_mode.tiles.x_basis = Global.current_project.tiles.x_basis
|
||||||
tile_mode.tiles.y_basis = Global.current_project.tiles.y_basis
|
tile_mode.tiles.y_basis = Global.current_project.tiles.y_basis
|
||||||
x_basis_x_spinbox.value = tile_mode.tiles.x_basis.x
|
x_basis.value = tile_mode.tiles.x_basis
|
||||||
x_basis_y_spinbox.value = tile_mode.tiles.x_basis.y
|
y_basis.value = tile_mode.tiles.y_basis
|
||||||
y_basis_x_spinbox.value = tile_mode.tiles.y_basis.x
|
|
||||||
y_basis_y_spinbox.value = tile_mode.tiles.y_basis.y
|
|
||||||
|
|
||||||
_show_options()
|
_show_options()
|
||||||
if Global.current_project.tiles.mode == Tiles.MODE.X_AXIS:
|
if Global.current_project.tiles.mode == Tiles.MODE.X_AXIS:
|
||||||
y_basis_x_spinbox.visible = false
|
y_basis.visible = false
|
||||||
y_basis_y_spinbox.visible = false
|
y_basis_label.visible = false
|
||||||
$VBoxContainer/HBoxContainer/OptionsContainer/YBasisXLabel.visible = false
|
|
||||||
$VBoxContainer/HBoxContainer/OptionsContainer/YBasisYLabel.visible = false
|
|
||||||
elif Global.current_project.tiles.mode == Tiles.MODE.Y_AXIS:
|
elif Global.current_project.tiles.mode == Tiles.MODE.Y_AXIS:
|
||||||
x_basis_x_spinbox.visible = false
|
x_basis.visible = false
|
||||||
x_basis_y_spinbox.visible = false
|
x_basis_label.visible = false
|
||||||
$VBoxContainer/HBoxContainer/OptionsContainer/XBasisXLabel.visible = false
|
|
||||||
$VBoxContainer/HBoxContainer/OptionsContainer/XBasisYLabel.visible = false
|
|
||||||
|
|
||||||
update_preview()
|
update_preview()
|
||||||
|
|
||||||
|
|
||||||
func _show_options() -> void:
|
func _show_options() -> void:
|
||||||
x_basis_x_spinbox.visible = true
|
x_basis.visible = true
|
||||||
x_basis_y_spinbox.visible = true
|
y_basis.visible = true
|
||||||
y_basis_x_spinbox.visible = true
|
x_basis_label.visible = true
|
||||||
y_basis_y_spinbox.visible = true
|
y_basis_label.visible = true
|
||||||
$VBoxContainer/HBoxContainer/OptionsContainer/YBasisXLabel.visible = true
|
|
||||||
$VBoxContainer/HBoxContainer/OptionsContainer/YBasisYLabel.visible = true
|
|
||||||
$VBoxContainer/HBoxContainer/OptionsContainer/XBasisXLabel.visible = true
|
|
||||||
$VBoxContainer/HBoxContainer/OptionsContainer/XBasisYLabel.visible = true
|
|
||||||
|
|
||||||
|
|
||||||
func _on_TileModeOffsetsDialog_confirmed() -> void:
|
func _on_TileModeOffsetsDialog_confirmed() -> void:
|
||||||
|
@ -75,23 +66,13 @@ func _on_TileModeOffsetsDialog_confirmed() -> void:
|
||||||
Global.transparent_checker.update_rect()
|
Global.transparent_checker.update_rect()
|
||||||
|
|
||||||
|
|
||||||
func _on_XBasisX_value_changed(value: int) -> void:
|
func _on_x_basis_value_changed(value: Vector2) -> void:
|
||||||
tile_mode.tiles.x_basis.x = value
|
tile_mode.tiles.x_basis = value
|
||||||
update_preview()
|
update_preview()
|
||||||
|
|
||||||
|
|
||||||
func _on_XBasisY_value_changed(value: int) -> void:
|
func _on_y_basis_value_changed(value: Vector2) -> void:
|
||||||
tile_mode.tiles.x_basis.y = value
|
tile_mode.tiles.y_basis = value
|
||||||
update_preview()
|
|
||||||
|
|
||||||
|
|
||||||
func _on_YBasisX_value_changed(value: int) -> void:
|
|
||||||
tile_mode.tiles.y_basis.x = value
|
|
||||||
update_preview()
|
|
||||||
|
|
||||||
|
|
||||||
func _on_YBasisY_value_changed(value: int) -> void:
|
|
||||||
tile_mode.tiles.y_basis.y = value
|
|
||||||
update_preview()
|
update_preview()
|
||||||
|
|
||||||
|
|
||||||
|
@ -122,10 +103,17 @@ func _on_TileModeOffsetsDialog_size_changed() -> void:
|
||||||
func _on_Reset_pressed() -> void:
|
func _on_Reset_pressed() -> void:
|
||||||
tile_mode.tiles.x_basis = Vector2i(Global.current_project.size.x, 0)
|
tile_mode.tiles.x_basis = Vector2i(Global.current_project.size.x, 0)
|
||||||
tile_mode.tiles.y_basis = Vector2i(0, Global.current_project.size.y)
|
tile_mode.tiles.y_basis = Vector2i(0, Global.current_project.size.y)
|
||||||
x_basis_x_spinbox.value = Global.current_project.size.x
|
x_basis.value = tile_mode.tiles.x_basis
|
||||||
x_basis_y_spinbox.value = 0
|
y_basis.value = tile_mode.tiles.y_basis
|
||||||
y_basis_x_spinbox.value = 0
|
update_preview()
|
||||||
y_basis_y_spinbox.value = Global.current_project.size.y
|
|
||||||
|
|
||||||
|
func _on_isometric_pressed() -> void:
|
||||||
|
tile_mode.tiles.x_basis = Global.current_project.size / 2
|
||||||
|
tile_mode.tiles.x_basis.y *= -1
|
||||||
|
tile_mode.tiles.y_basis = Global.current_project.size / 2
|
||||||
|
x_basis.value = tile_mode.tiles.x_basis
|
||||||
|
y_basis.value = tile_mode.tiles.y_basis
|
||||||
update_preview()
|
update_preview()
|
||||||
|
|
||||||
|
|
||||||
|
@ -138,10 +126,7 @@ func change_mask() -> void:
|
||||||
var tiles_size := tiles.tile_size
|
var tiles_size := tiles.tile_size
|
||||||
var image := Image.create(tiles_size.x, tiles_size.y, false, Image.FORMAT_RGBA8)
|
var image := Image.create(tiles_size.x, tiles_size.y, false, Image.FORMAT_RGBA8)
|
||||||
DrawingAlgos.blend_layers(image, current_frame)
|
DrawingAlgos.blend_layers(image, current_frame)
|
||||||
if (
|
if image.get_used_rect().size == Vector2i.ZERO or not masking.button_pressed:
|
||||||
image.get_used_rect().size == Vector2i.ZERO
|
|
||||||
or not $VBoxContainer/HBoxContainer/Masking.button_pressed
|
|
||||||
):
|
|
||||||
tiles.reset_mask()
|
tiles.reset_mask()
|
||||||
else:
|
else:
|
||||||
load_mask(image)
|
load_mask(image)
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
[gd_scene load_steps=5 format=3 uid="uid://c0nuukjakmai2"]
|
[gd_scene load_steps=6 format=3 uid="uid://c0nuukjakmai2"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://3pmb60gpst7b" path="res://src/UI/Nodes/TransparentChecker.tscn" id="1"]
|
[ext_resource type="PackedScene" uid="uid://3pmb60gpst7b" path="res://src/UI/Nodes/TransparentChecker.tscn" id="1"]
|
||||||
[ext_resource type="Script" path="res://src/UI/Canvas/TileMode.gd" id="2"]
|
[ext_resource type="Script" path="res://src/UI/Canvas/TileMode.gd" id="2"]
|
||||||
|
[ext_resource type="PackedScene" path="res://src/UI/Nodes/ValueSliderV2.tscn" id="2_ul2eq"]
|
||||||
[ext_resource type="Script" path="res://src/UI/Dialogs/TileModeOffsetsDialog.gd" id="3"]
|
[ext_resource type="Script" path="res://src/UI/Dialogs/TileModeOffsetsDialog.gd" id="3"]
|
||||||
|
|
||||||
[sub_resource type="CanvasItemMaterial" id="1"]
|
[sub_resource type="CanvasItemMaterial" id="1"]
|
||||||
|
@ -10,83 +11,72 @@ blend_mode = 4
|
||||||
[node name="TileModeOffsetsDialog" type="ConfirmationDialog"]
|
[node name="TileModeOffsetsDialog" type="ConfirmationDialog"]
|
||||||
canvas_item_default_texture_filter = 0
|
canvas_item_default_texture_filter = 0
|
||||||
title = "Tile Mode Offsets"
|
title = "Tile Mode Offsets"
|
||||||
|
position = Vector2i(0, 36)
|
||||||
|
size = Vector2i(298, 536)
|
||||||
script = ExtResource("3")
|
script = ExtResource("3")
|
||||||
|
|
||||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||||
offset_left = 8.0
|
offset_left = 8.0
|
||||||
offset_top = 8.0
|
offset_top = 8.0
|
||||||
offset_right = 293.0
|
offset_right = 290.0
|
||||||
offset_bottom = 386.0
|
offset_bottom = 487.0
|
||||||
|
|
||||||
[node name="TileModeOffsets" type="Label" parent="VBoxContainer"]
|
[node name="TileModeOffsets" type="Label" parent="VBoxContainer"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Tile Mode Offsets"
|
text = "Tile Mode Offsets"
|
||||||
|
|
||||||
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
|
[node name="OptionsContainer" type="GridContainer" parent="VBoxContainer"]
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="OptionsContainer" type="GridContainer" parent="VBoxContainer/HBoxContainer"]
|
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_constants/h_separation = 2
|
theme_override_constants/h_separation = 2
|
||||||
theme_override_constants/v_separation = 4
|
theme_override_constants/v_separation = 4
|
||||||
columns = 2
|
columns = 2
|
||||||
|
|
||||||
[node name="XBasisXLabel" type="Label" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
|
[node name="XBasisLabel" type="Label" parent="VBoxContainer/OptionsContainer"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "X-basis x:"
|
size_flags_horizontal = 3
|
||||||
|
text = "X-basis:"
|
||||||
|
|
||||||
[node name="XBasisX" type="SpinBox" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
|
[node name="XBasis" parent="VBoxContainer/OptionsContainer" instance=ExtResource("2_ul2eq")]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
mouse_default_cursor_shape = 2
|
size_flags_horizontal = 3
|
||||||
min_value = -16384.0
|
allow_greater = true
|
||||||
max_value = 16384.0
|
allow_lesser = true
|
||||||
suffix = "px"
|
suffix_x = "px"
|
||||||
|
suffix_y = "px"
|
||||||
|
|
||||||
[node name="XBasisYLabel" type="Label" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
|
[node name="YBasisLabel" type="Label" parent="VBoxContainer/OptionsContainer"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "X-basis y:"
|
size_flags_horizontal = 3
|
||||||
|
text = "Y-basis:"
|
||||||
|
|
||||||
[node name="XBasisY" type="SpinBox" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
|
[node name="YBasis" parent="VBoxContainer/OptionsContainer" instance=ExtResource("2_ul2eq")]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
mouse_default_cursor_shape = 2
|
size_flags_horizontal = 3
|
||||||
min_value = -16384.0
|
allow_greater = true
|
||||||
max_value = 16384.0
|
allow_lesser = true
|
||||||
suffix = "px"
|
suffix_x = "px"
|
||||||
|
suffix_y = "px"
|
||||||
|
|
||||||
[node name="YBasisXLabel" type="Label" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
|
[node name="MaskingLabel" type="Label" parent="VBoxContainer/OptionsContainer"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Y-basis x:"
|
text = "Masking:"
|
||||||
|
|
||||||
[node name="YBasisX" type="SpinBox" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
|
[node name="Masking" type="CheckButton" parent="VBoxContainer/OptionsContainer"]
|
||||||
layout_mode = 2
|
|
||||||
mouse_default_cursor_shape = 2
|
|
||||||
min_value = -16384.0
|
|
||||||
max_value = 16384.0
|
|
||||||
suffix = "px"
|
|
||||||
|
|
||||||
[node name="YBasisYLabel" type="Label" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Y-basis y:"
|
|
||||||
|
|
||||||
[node name="YBasisY" type="SpinBox" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
mouse_default_cursor_shape = 2
|
|
||||||
min_value = -16384.0
|
|
||||||
max_value = 16384.0
|
|
||||||
suffix = "px"
|
|
||||||
|
|
||||||
[node name="Reset" type="Button" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
mouse_default_cursor_shape = 2
|
|
||||||
text = "Reset"
|
|
||||||
|
|
||||||
[node name="VSeparator" type="VSeparator" parent="VBoxContainer/HBoxContainer"]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="Masking" type="CheckButton" parent="VBoxContainer/HBoxContainer"]
|
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 0
|
size_flags_vertical = 0
|
||||||
text = "Masking"
|
|
||||||
|
[node name="Reset" type="Button" parent="VBoxContainer/OptionsContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
mouse_default_cursor_shape = 2
|
||||||
|
text = "Default"
|
||||||
|
|
||||||
|
[node name="Isometric" type="Button" parent="VBoxContainer/OptionsContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
mouse_default_cursor_shape = 2
|
||||||
|
text = "Isometric"
|
||||||
|
|
||||||
[node name="AspectRatioContainer" type="AspectRatioContainer" parent="VBoxContainer"]
|
[node name="AspectRatioContainer" type="AspectRatioContainer" parent="VBoxContainer"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
@ -111,9 +101,8 @@ anchor_bottom = 1.0
|
||||||
[connection signal="confirmed" from="." to="." method="_on_TileModeOffsetsDialog_confirmed"]
|
[connection signal="confirmed" from="." to="." method="_on_TileModeOffsetsDialog_confirmed"]
|
||||||
[connection signal="size_changed" from="." to="." method="_on_TileModeOffsetsDialog_size_changed"]
|
[connection signal="size_changed" from="." to="." method="_on_TileModeOffsetsDialog_size_changed"]
|
||||||
[connection signal="visibility_changed" from="." to="." method="_on_TileModeOffsetsDialog_visibility_changed"]
|
[connection signal="visibility_changed" from="." to="." method="_on_TileModeOffsetsDialog_visibility_changed"]
|
||||||
[connection signal="value_changed" from="VBoxContainer/HBoxContainer/OptionsContainer/XBasisX" to="." method="_on_XBasisX_value_changed"]
|
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/XBasis" to="." method="_on_x_basis_value_changed"]
|
||||||
[connection signal="value_changed" from="VBoxContainer/HBoxContainer/OptionsContainer/XBasisY" to="." method="_on_XBasisY_value_changed"]
|
[connection signal="value_changed" from="VBoxContainer/OptionsContainer/YBasis" to="." method="_on_y_basis_value_changed"]
|
||||||
[connection signal="value_changed" from="VBoxContainer/HBoxContainer/OptionsContainer/YBasisX" to="." method="_on_YBasisX_value_changed"]
|
[connection signal="toggled" from="VBoxContainer/OptionsContainer/Masking" to="." method="_on_Masking_toggled"]
|
||||||
[connection signal="value_changed" from="VBoxContainer/HBoxContainer/OptionsContainer/YBasisY" to="." method="_on_YBasisY_value_changed"]
|
[connection signal="pressed" from="VBoxContainer/OptionsContainer/Reset" to="." method="_on_Reset_pressed"]
|
||||||
[connection signal="pressed" from="VBoxContainer/HBoxContainer/OptionsContainer/Reset" to="." method="_on_Reset_pressed"]
|
[connection signal="pressed" from="VBoxContainer/OptionsContainer/Isometric" to="." method="_on_isometric_pressed"]
|
||||||
[connection signal="toggled" from="VBoxContainer/HBoxContainer/Masking" to="." method="_on_Masking_toggled"]
|
|
||||||
|
|
|
@ -80,15 +80,21 @@ func _notification(what: int) -> void:
|
||||||
_reset_display(false)
|
_reset_display(false)
|
||||||
|
|
||||||
|
|
||||||
func _input(event: InputEvent) -> void:
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
if not editable or not is_visible_in_tree():
|
if not editable or not is_visible_in_tree():
|
||||||
return
|
return
|
||||||
if event.is_action_pressed(global_increment_action, true):
|
if (
|
||||||
|
not global_increment_action.is_empty()
|
||||||
|
and event.is_action_pressed(global_increment_action, true)
|
||||||
|
):
|
||||||
if snap_by_default:
|
if snap_by_default:
|
||||||
value += step if event.ctrl_pressed else snap_step
|
value += step if event.ctrl_pressed else snap_step
|
||||||
else:
|
else:
|
||||||
value += snap_step if event.ctrl_pressed else step
|
value += snap_step if event.ctrl_pressed else step
|
||||||
elif event.is_action_pressed(global_decrement_action, true):
|
elif (
|
||||||
|
not global_decrement_action.is_empty()
|
||||||
|
and event.is_action_pressed(global_decrement_action, true)
|
||||||
|
):
|
||||||
if snap_by_default:
|
if snap_by_default:
|
||||||
value -= step if event.ctrl_pressed else snap_step
|
value -= step if event.ctrl_pressed else snap_step
|
||||||
else:
|
else:
|
||||||
|
@ -108,11 +114,13 @@ func _gui_input(event: InputEvent) -> void:
|
||||||
value += step if event.ctrl_pressed else snap_step
|
value += step if event.ctrl_pressed else snap_step
|
||||||
else:
|
else:
|
||||||
value += snap_step if event.ctrl_pressed else step
|
value += snap_step if event.ctrl_pressed else step
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
|
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
|
||||||
if snap_by_default:
|
if snap_by_default:
|
||||||
value -= step if event.ctrl_pressed else snap_step
|
value -= step if event.ctrl_pressed else snap_step
|
||||||
else:
|
else:
|
||||||
value -= snap_step if event.ctrl_pressed else step
|
value -= snap_step if event.ctrl_pressed else step
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
elif state == HELD:
|
elif state == HELD:
|
||||||
if event.is_action_released("left_mouse"):
|
if event.is_action_released("left_mouse"):
|
||||||
state = TYPING
|
state = TYPING
|
||||||
|
|
|
@ -85,6 +85,9 @@ class Recorder:
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
if OS.get_name() == "Web":
|
||||||
|
ExtensionsApi.panel.remove_node_from_tab.call_deferred(self)
|
||||||
|
return
|
||||||
Global.project_switched.connect(_on_project_switched)
|
Global.project_switched.connect(_on_project_switched)
|
||||||
# Make a recordings folder if there isn't one
|
# Make a recordings folder if there isn't one
|
||||||
chosen_dir = Global.home_data_directory.path_join("Recordings")
|
chosen_dir = Global.home_data_directory.path_join("Recordings")
|
||||||
|
|
|
@ -141,6 +141,7 @@ func _input(event: InputEvent) -> void:
|
||||||
if timeline_rect.has_point(mouse_pos):
|
if timeline_rect.has_point(mouse_pos):
|
||||||
if Input.is_key_pressed(KEY_CTRL):
|
if Input.is_key_pressed(KEY_CTRL):
|
||||||
cel_size += (2 * int(event.is_action("zoom_in")) - 2 * int(event.is_action("zoom_out")))
|
cel_size += (2 * int(event.is_action("zoom_in")) - 2 * int(event.is_action("zoom_out")))
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
|
||||||
|
|
||||||
func reset_settings() -> void:
|
func reset_settings() -> void:
|
||||||
|
|
|
@ -17,6 +17,7 @@ var zen_mode := false
|
||||||
var new_image_dialog := Dialog.new("res://src/UI/Dialogs/CreateNewImage.tscn")
|
var new_image_dialog := Dialog.new("res://src/UI/Dialogs/CreateNewImage.tscn")
|
||||||
var project_properties_dialog := Dialog.new("res://src/UI/Dialogs/ProjectProperties.tscn")
|
var project_properties_dialog := Dialog.new("res://src/UI/Dialogs/ProjectProperties.tscn")
|
||||||
var preferences_dialog := Dialog.new("res://src/Preferences/PreferencesDialog.tscn")
|
var preferences_dialog := Dialog.new("res://src/Preferences/PreferencesDialog.tscn")
|
||||||
|
var modify_selection := Dialog.new("res://src/UI/Dialogs/ModifySelection.tscn")
|
||||||
var offset_image_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/OffsetImage.tscn")
|
var offset_image_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/OffsetImage.tscn")
|
||||||
var scale_image_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/ScaleImage.tscn")
|
var scale_image_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/ScaleImage.tscn")
|
||||||
var resize_canvas_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/ResizeCanvas.tscn")
|
var resize_canvas_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/ResizeCanvas.tscn")
|
||||||
|
@ -54,6 +55,7 @@ var about_dialog := Dialog.new("res://src/UI/Dialogs/AboutDialog.tscn")
|
||||||
|
|
||||||
@onready var greyscale_vision: ColorRect = main_ui.find_child("GreyscaleVision")
|
@onready var greyscale_vision: ColorRect = main_ui.find_child("GreyscaleVision")
|
||||||
@onready var tile_mode_submenu := PopupMenu.new()
|
@onready var tile_mode_submenu := PopupMenu.new()
|
||||||
|
@onready var selection_modify_submenu := PopupMenu.new()
|
||||||
@onready var snap_to_submenu := PopupMenu.new()
|
@onready var snap_to_submenu := PopupMenu.new()
|
||||||
@onready var panels_submenu := PopupMenu.new()
|
@onready var panels_submenu := PopupMenu.new()
|
||||||
@onready var layouts_submenu := PopupMenu.new()
|
@onready var layouts_submenu := PopupMenu.new()
|
||||||
|
@ -440,17 +442,30 @@ func _setup_select_menu() -> void:
|
||||||
"All": "select_all",
|
"All": "select_all",
|
||||||
"Clear": "clear_selection",
|
"Clear": "clear_selection",
|
||||||
"Invert": "invert_selection",
|
"Invert": "invert_selection",
|
||||||
"Tile Mode": ""
|
"Tile Mode": "",
|
||||||
|
"Modify": ""
|
||||||
}
|
}
|
||||||
for i in select_menu_items.size():
|
for i in select_menu_items.size():
|
||||||
var item: String = select_menu_items.keys()[i]
|
var item: String = select_menu_items.keys()[i]
|
||||||
if item == "Tile Mode":
|
if item == "Tile Mode":
|
||||||
select_menu.add_check_item(item, i)
|
select_menu.add_check_item(item, i)
|
||||||
|
elif item == "Modify":
|
||||||
|
_setup_selection_modify_submenu(item)
|
||||||
else:
|
else:
|
||||||
_set_menu_shortcut(select_menu_items[item], select_menu, i, item)
|
_set_menu_shortcut(select_menu_items[item], select_menu, i, item)
|
||||||
select_menu.id_pressed.connect(select_menu_id_pressed)
|
select_menu.id_pressed.connect(select_menu_id_pressed)
|
||||||
|
|
||||||
|
|
||||||
|
func _setup_selection_modify_submenu(item: String) -> void:
|
||||||
|
selection_modify_submenu.set_name("selection_modify_submenu")
|
||||||
|
selection_modify_submenu.add_item("Expand")
|
||||||
|
selection_modify_submenu.add_item("Shrink")
|
||||||
|
selection_modify_submenu.add_item("Border")
|
||||||
|
selection_modify_submenu.id_pressed.connect(_selection_modify_submenu_id_pressed)
|
||||||
|
select_menu.add_child(selection_modify_submenu)
|
||||||
|
select_menu.add_submenu_item(item, selection_modify_submenu.get_name())
|
||||||
|
|
||||||
|
|
||||||
func _setup_help_menu() -> void:
|
func _setup_help_menu() -> void:
|
||||||
# Order as in Global.HelpMenu enum
|
# Order as in Global.HelpMenu enum
|
||||||
var help_menu_items := {
|
var help_menu_items := {
|
||||||
|
@ -667,6 +682,11 @@ func _tile_mode_submenu_id_pressed(id: Tiles.MODE) -> void:
|
||||||
get_tree().current_scene.tile_mode_offsets_dialog.change_mask()
|
get_tree().current_scene.tile_mode_offsets_dialog.change_mask()
|
||||||
|
|
||||||
|
|
||||||
|
func _selection_modify_submenu_id_pressed(id: int) -> void:
|
||||||
|
modify_selection.popup()
|
||||||
|
modify_selection.node.type = id
|
||||||
|
|
||||||
|
|
||||||
func _snap_to_submenu_id_pressed(id: int) -> void:
|
func _snap_to_submenu_id_pressed(id: int) -> void:
|
||||||
if id == 0:
|
if id == 0:
|
||||||
Global.snap_to_rectangular_grid_boundary = !Global.snap_to_rectangular_grid_boundary
|
Global.snap_to_rectangular_grid_boundary = !Global.snap_to_rectangular_grid_boundary
|
||||||
|
|
Loading…
Reference in a new issue