1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-01-18 17:19:50 +00:00

Bring refactoring changes to master (#253)

* Refactoring image_menu_id_pressed method in Main.gd (#243)

* Refactoring image_menu_id_pressed method in Main.gd

I've moved the code from each "match" case into a seperate method to make it more readable.

Co-authored-by: OverloadedOrama <35376950+OverloadedOrama@users.noreply.github.com>

* Refactoring Main.gd. Mostly cutting big methods into smaller ones. (#244)

* Refactoring Main.gd. Mostly cutting big methods into smaller one.

- Reduced size of _ready method in Main.gd
- Moved code from certain parts of old _ready method into seperate methods
- Fixed the translation bug related to CurrentFrame node in TopMenuContainer scene. The CurrentFrame node wasn't updating the language when I was changing language. I've also changed the translation file for this.
- Fixed Global.palette_option_button.selected related warning. Because of some unknown reasons, git didn't push completed line there.
- Moved code from file_menu_id_pressed and view_menu_id_pressed method in Main.gd to separate methods to make it more readable.

* Removed window_title changes from Main.tscn

Co-authored-by: OverloadedOrama <35376950+OverloadedOrama@users.noreply.github.com>

* Fixed TextureRect images of the circle brushes in BrushesPopup

They all had the pixel brush image in their TextureRect

* Split code from PreferencesDialog.gd to HandleLanguages.gd

Also moved PreferencesDialog script & scene to src/Preferences. More Preferences code splitting will follow.

* Split theme related code from PreferencesDialog into HandleThemes.gd

* Moved shortcuts code from PreferencesDialog

* Created DrawingAlgos.gd and moved a lot of drawing code there

Moved code from Global.gd and Canvas.gd to DrawingAlgos.gd. Will also move the fill_gaps and draw_brush methods of Canvas.gd next. Maybe even refactor the inside of them a bit to make them easier to read.

* Connected "files_dropped" signal to a method

This lets the user drag and drop files into Pixelorama, while it runs, to open them. This doesn't work properly and will crash when it can't open the files. It will get merged into master soon.

* Renamed handle_running_pixelorama_with_arguments() to handle_loading_files()

handle_loading_files() is also used for _on_files_dropped()

* Moved draw_brush() and fill_gaps() from Canvas.gd to DrawingAlgos.gd

draw_brush() is currently very ugly and probably needs inside refactoring

* Removed coord clamping from fill_gaps()

This should make line making behave as expected when the mouse is outside of canvas boundaries

* Drawing is no longer limited by the canvas boundaries

his means that, if you have a brush largen than 1px, you can draw on the edges of the canvas. All pixels that are being drawn outside of the canvas will still have no effect.

* Use enums instead of strings for tools

This could be a slight increase in performance

* Fixed line making with Shift and don't let color picker pick colors outside of canvas

* Changed Global node variables to arrays for left/right

Instead of having 2 variables for left & right nodes, use an array instead. This will help with better looking code, automation and less repetitive code, as seen in ToolButtons.gd. Move related refactoring will follow.

* More Global left/right variables became Arrays

Global.update_left_custom_brush() and its right counterpart have also now become Global.update_custom_brush(mouse_button : int)

* Use Global.Mouse_Button instead of strings for comparison

This should be a slight increase in performance

* Refactoring perferences dialog (#251)

* Added ItemList to themes

* Language and theme checkboxes are now radio buttons

* Even more Global left/right variables became arrays

ColorAndToolOptions has now the same code for left and right tool options, with more similar refactoring coming soon to places like Canvas and DrawingAlgos

* Refactored Canvas.gd

* Refactored DrawingAlgos.draw_brush(), made draw_pixel() method

This also fixes alpha blending and lighting/darkening issues when drawing pixels with mirroring.

* Remove draw_pixel(), use draw_pixel_blended() instead

* Ignore warnings

I don't know what else to do about them, they seem trivial anyway

* Use enum instead of strings for Global.theme_type

Another potential small performance boost when changing themes.

* Use a new Layer class to handle layer information

This replaces the old Global.layers nested array mess, and makes the code easier to read and to understand.

* Fixed linked cel crash and layer naming

* Created a new Cel class, to handle cel information

Like the Layer class, it is used in place of Canvas.layers nested array mess. It hasn't been tested thoroughly yet, so there may be crashes.

* Fixed issue where if you moved a frame to the start (move left), it was invisible

* Added AnimationTag class

Replaces nested Global.animation_tags arrays. Also replaced array.duplicate(true) with looping through the array and creating a new class for each array element, because duplicate(true) does not create new classes, unfortunately, which was causing issues with undo/redo.

Co-authored-by: Igor Santarek <jegor377@gmail.com>
Co-authored-by: Kinwailo <lokinwai@gmail.com>
This commit is contained in:
Manolis Papadeas 2020-06-02 20:00:18 +03:00 committed by GitHub
parent 7a8ae9428b
commit 881e53dadc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 4037 additions and 4151 deletions

View file

@ -7,10 +7,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [v0.7.1] - Unreleased ## [v0.7.1] - Unreleased
This update has been brought to you by the contributions of: This update has been brought to you by the contributions of:
Igor Santarek (jegor377) Igor Santarek (jegor377), rob-a-bolton
### Added ### Added
- Ability to remove the current palette - Ability to remove the current palette.
- You can now drag & drop files into the program while it's running to open them.
### Changed
- Drawing is no longer limited by the canvas boundaries. This means that, if you have a brush largen than 1px, you can draw on the edges of the canvas. All pixels that are being drawn outside of the canvas will still have no effect.
- Language and theme checkboxes are now radio buttons.
- The Blue theme has more similar margins and seperations with the rest of the themes.
### Fixed
- Fixed failed imports of gpl palettes by adding support for the newer variant of gpl files. ([#250](https://github.com/Orama-Interactive/Pixelorama/pull/250))
- Fixed alpha blending and lighting/darkening issues when drawing pixels with mirroring.
- Fixed issue where if you moved a frame to the start (move left), it was invisible.
<br><br> <br><br>
## [v0.7] - 2020-05-16 ## [v0.7] - 2020-05-16

View file

@ -732,9 +732,6 @@ msgstr ""
msgid "Current frame:" msgid "Current frame:"
msgstr "" msgstr ""
msgid "Current frame: 1/1"
msgstr ""
msgid "Jump to the first frame\n" msgid "Jump to the first frame\n"
"(%s)" "(%s)"
msgstr "" msgstr ""

File diff suppressed because one or more lines are too long

View file

@ -152,6 +152,18 @@ border_color = Color( 0.321569, 0.321569, 0.321569, 1 )
expand_margin_top = 2.0 expand_margin_top = 2.0
expand_margin_bottom = 2.0 expand_margin_bottom = 2.0
[sub_resource type="StyleBoxFlat" id=27]
bg_color = Color( 0.588235, 0.568627, 0.470588, 1 )
border_width_left = 4
border_width_top = 4
border_width_right = 4
border_width_bottom = 4
border_color = Color( 0.588235, 0.568627, 0.470588, 1 )
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="StyleBoxFlat" id=17] [sub_resource type="StyleBoxFlat" id=17]
bg_color = Color( 0.109804, 0.0862745, 0.0862745, 0 ) bg_color = Color( 0.109804, 0.0862745, 0.0862745, 0 )
border_width_left = 1 border_width_left = 1
@ -245,18 +257,6 @@ corner_radius_bottom_right = 4
corner_radius_bottom_left = 4 corner_radius_bottom_left = 4
anti_aliasing = false anti_aliasing = false
[sub_resource type="StyleBoxFlat" id=27]
bg_color = Color( 0.588235, 0.568627, 0.470588, 1 )
border_width_left = 4
border_width_top = 4
border_width_right = 4
border_width_bottom = 4
border_color = Color( 0.588235, 0.568627, 0.470588, 1 )
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="StyleBoxFlat" id=28] [sub_resource type="StyleBoxFlat" id=28]
bg_color = Color( 0.445313, 0.432846, 0.370514, 1 ) bg_color = Color( 0.445313, 0.432846, 0.370514, 1 )
border_width_left = 5 border_width_left = 5
@ -367,6 +367,20 @@ HSplitContainer/constants/autohide = 1
HSplitContainer/constants/separation = 6 HSplitContainer/constants/separation = 6
HSplitContainer/icons/grabber = ExtResource( 4 ) HSplitContainer/icons/grabber = ExtResource( 4 )
HSplitContainer/styles/bg = null HSplitContainer/styles/bg = null
ItemList/colors/font_color = Color( 0, 0, 0, 1 )
ItemList/colors/font_color_selected = Color( 0.278431, 0.278431, 0.278431, 1 )
ItemList/colors/guide_color = Color( 0, 0, 0, 0.1 )
ItemList/constants/hseparation = 4
ItemList/constants/icon_margin = 4
ItemList/constants/line_separation = 2
ItemList/constants/vseparation = 4
ItemList/fonts/font = null
ItemList/styles/bg = SubResource( 27 )
ItemList/styles/bg_focus = null
ItemList/styles/cursor = null
ItemList/styles/cursor_unfocused = null
ItemList/styles/selected = null
ItemList/styles/selected_focus = null
"Label/colors/Selected Color" = Color( 0.235294, 0.364706, 0.458824, 1 ) "Label/colors/Selected Color" = Color( 0.235294, 0.364706, 0.458824, 1 )
Label/colors/font_color = Color( 0, 0, 0, 1 ) Label/colors/font_color = Color( 0, 0, 0, 1 )
Label/colors/font_color_shadow = Color( 0, 0, 0, 0 ) Label/colors/font_color_shadow = Color( 0, 0, 0, 0 )
@ -512,7 +526,7 @@ Tree/colors/cursor_color = Color( 0, 0, 0, 1 )
Tree/colors/custom_button_font_highlight = Color( 0.941176, 0.941176, 0.941176, 1 ) Tree/colors/custom_button_font_highlight = Color( 0.941176, 0.941176, 0.941176, 1 )
Tree/colors/drop_position_color = Color( 1, 0.3, 0.2, 1 ) Tree/colors/drop_position_color = Color( 1, 0.3, 0.2, 1 )
Tree/colors/font_color = Color( 0, 0, 0, 1 ) Tree/colors/font_color = Color( 0, 0, 0, 1 )
Tree/colors/font_color_selected = Color( 0, 0, 0, 1 ) Tree/colors/font_color_selected = Color( 0.443137, 0.443137, 0.443137, 1 )
Tree/colors/guide_color = Color( 0, 0, 0, 0.1 ) Tree/colors/guide_color = Color( 0, 0, 0, 0.1 )
Tree/colors/relationship_line_color = Color( 0.27451, 0.27451, 0.27451, 1 ) Tree/colors/relationship_line_color = Color( 0.27451, 0.27451, 0.27451, 1 )
Tree/colors/selection_color = Color( 0.1, 0.1, 1, 0.8 ) Tree/colors/selection_color = Color( 0.1, 0.1, 1, 0.8 )

View file

@ -172,6 +172,18 @@ border_color = Color( 0.321569, 0.321569, 0.321569, 1 )
[sub_resource type="StyleBoxFlat" id=19] [sub_resource type="StyleBoxFlat" id=19]
bg_color = Color( 0.133333, 0.133333, 0.133333, 1 ) bg_color = Color( 0.133333, 0.133333, 0.133333, 1 )
[sub_resource type="StyleBoxFlat" id=32]
bg_color = Color( 0.321569, 0.321569, 0.321569, 1 )
border_width_left = 4
border_width_top = 4
border_width_right = 4
border_width_bottom = 4
border_color = Color( 0.321569, 0.321569, 0.321569, 1 )
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="StyleBoxFlat" id=20] [sub_resource type="StyleBoxFlat" id=20]
bg_color = Color( 0.109804, 0.0862745, 0.0862745, 0 ) bg_color = Color( 0.109804, 0.0862745, 0.0862745, 0 )
border_width_left = 1 border_width_left = 1
@ -286,18 +298,6 @@ corner_radius_bottom_right = 4
corner_radius_bottom_left = 4 corner_radius_bottom_left = 4
anti_aliasing = false anti_aliasing = false
[sub_resource type="StyleBoxFlat" id=32]
bg_color = Color( 0.321569, 0.321569, 0.321569, 1 )
border_width_left = 4
border_width_top = 4
border_width_right = 4
border_width_bottom = 4
border_color = Color( 0.321569, 0.321569, 0.321569, 1 )
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="StyleBoxFlat" id=33] [sub_resource type="StyleBoxFlat" id=33]
border_width_left = 2 border_width_left = 2
border_width_right = 2 border_width_right = 2
@ -419,6 +419,20 @@ HSplitContainer/constants/autohide = 1
HSplitContainer/constants/separation = 6 HSplitContainer/constants/separation = 6
HSplitContainer/icons/grabber = ExtResource( 4 ) HSplitContainer/icons/grabber = ExtResource( 4 )
HSplitContainer/styles/bg = SubResource( 19 ) HSplitContainer/styles/bg = SubResource( 19 )
ItemList/colors/font_color = Color( 0.690196, 0.690196, 0.690196, 1 )
ItemList/colors/font_color_selected = Color( 1, 1, 1, 1 )
ItemList/colors/guide_color = Color( 0, 0, 0, 0.1 )
ItemList/constants/hseparation = 4
ItemList/constants/icon_margin = 4
ItemList/constants/line_separation = 2
ItemList/constants/vseparation = 4
ItemList/fonts/font = null
ItemList/styles/bg = SubResource( 32 )
ItemList/styles/bg_focus = null
ItemList/styles/cursor = null
ItemList/styles/cursor_unfocused = null
ItemList/styles/selected = null
ItemList/styles/selected_focus = null
"Label/colors/Selected Color" = Color( 0.235294, 0.364706, 0.458824, 1 ) "Label/colors/Selected Color" = Color( 0.235294, 0.364706, 0.458824, 1 )
Label/colors/font_color = Color( 1, 1, 1, 1 ) Label/colors/font_color = Color( 1, 1, 1, 1 )
Label/colors/font_color_shadow = Color( 0, 0, 0, 0 ) Label/colors/font_color_shadow = Color( 0, 0, 0, 0 )

View file

@ -165,6 +165,18 @@ border_color = Color( 0.321569, 0.321569, 0.321569, 1 )
expand_margin_top = 2.0 expand_margin_top = 2.0
expand_margin_bottom = 2.0 expand_margin_bottom = 2.0
[sub_resource type="StyleBoxFlat" id=28]
bg_color = Color( 0.321569, 0.321569, 0.321569, 1 )
border_width_left = 4
border_width_top = 4
border_width_right = 4
border_width_bottom = 4
border_color = Color( 0.321569, 0.321569, 0.321569, 1 )
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="StyleBoxFlat" id=18] [sub_resource type="StyleBoxFlat" id=18]
bg_color = Color( 0.109804, 0.0862745, 0.0862745, 0 ) bg_color = Color( 0.109804, 0.0862745, 0.0862745, 0 )
border_width_left = 1 border_width_left = 1
@ -258,18 +270,6 @@ corner_radius_bottom_right = 4
corner_radius_bottom_left = 4 corner_radius_bottom_left = 4
anti_aliasing = false anti_aliasing = false
[sub_resource type="StyleBoxFlat" id=28]
bg_color = Color( 0.321569, 0.321569, 0.321569, 1 )
border_width_left = 4
border_width_top = 4
border_width_right = 4
border_width_bottom = 4
border_color = Color( 0.321569, 0.321569, 0.321569, 1 )
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="StyleBoxFlat" id=29] [sub_resource type="StyleBoxFlat" id=29]
bg_color = Color( 0.321569, 0.321569, 0.321569, 1 ) bg_color = Color( 0.321569, 0.321569, 0.321569, 1 )
border_width_left = 2 border_width_left = 2
@ -370,6 +370,20 @@ HSplitContainer/constants/autohide = 1
HSplitContainer/constants/separation = 6 HSplitContainer/constants/separation = 6
HSplitContainer/icons/grabber = ExtResource( 6 ) HSplitContainer/icons/grabber = ExtResource( 6 )
HSplitContainer/styles/bg = null HSplitContainer/styles/bg = null
ItemList/colors/font_color = Color( 0.690196, 0.690196, 0.690196, 1 )
ItemList/colors/font_color_selected = Color( 1, 1, 1, 1 )
ItemList/colors/guide_color = Color( 0, 0, 0, 0.1 )
ItemList/constants/hseparation = 4
ItemList/constants/icon_margin = 4
ItemList/constants/line_separation = 2
ItemList/constants/vseparation = 4
ItemList/fonts/font = null
ItemList/styles/bg = SubResource( 28 )
ItemList/styles/bg_focus = null
ItemList/styles/cursor = null
ItemList/styles/cursor_unfocused = null
ItemList/styles/selected = null
ItemList/styles/selected_focus = null
"Label/colors/Selected Color" = Color( 0.235294, 0.364706, 0.458824, 1 ) "Label/colors/Selected Color" = Color( 0.235294, 0.364706, 0.458824, 1 )
Label/colors/font_color = Color( 1, 1, 1, 1 ) Label/colors/font_color = Color( 1, 1, 1, 1 )
Label/colors/font_color_shadow = Color( 0, 0, 0, 0 ) Label/colors/font_color_shadow = Color( 0, 0, 0, 0 )

View file

@ -176,6 +176,18 @@ expand_margin_top = 2.0
expand_margin_bottom = 2.0 expand_margin_bottom = 2.0
[sub_resource type="StyleBoxFlat" id=19] [sub_resource type="StyleBoxFlat" id=19]
bg_color = Color( 0.627451, 0.627451, 0.627451, 1 )
border_width_left = 4
border_width_top = 4
border_width_right = 4
border_width_bottom = 4
border_color = Color( 0.627451, 0.627451, 0.627451, 1 )
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="StyleBoxFlat" id=20]
bg_color = Color( 0.109804, 0.0862745, 0.0862745, 0 ) bg_color = Color( 0.109804, 0.0862745, 0.0862745, 0 )
border_width_left = 1 border_width_left = 1
border_width_top = 1 border_width_top = 1
@ -188,10 +200,10 @@ corner_radius_bottom_right = 4
corner_radius_bottom_left = 4 corner_radius_bottom_left = 4
anti_aliasing = false anti_aliasing = false
[sub_resource type="StyleBoxFlat" id=20] [sub_resource type="StyleBoxFlat" id=21]
bg_color = Color( 0.772549, 0.772549, 0.772549, 1 ) bg_color = Color( 0.772549, 0.772549, 0.772549, 1 )
[sub_resource type="StyleBoxFlat" id=21] [sub_resource type="StyleBoxFlat" id=22]
content_margin_left = 4.5 content_margin_left = 4.5
content_margin_right = 4.5 content_margin_right = 4.5
content_margin_top = 3.0 content_margin_top = 3.0
@ -202,7 +214,7 @@ corner_radius_top_right = 5
corner_radius_bottom_right = 5 corner_radius_bottom_right = 5
corner_radius_bottom_left = 5 corner_radius_bottom_left = 5
[sub_resource type="StyleBoxFlat" id=22] [sub_resource type="StyleBoxFlat" id=23]
bg_color = Color( 0.627451, 0.627451, 0.627451, 1 ) bg_color = Color( 0.627451, 0.627451, 0.627451, 1 )
border_width_left = 6 border_width_left = 6
border_width_top = 10 border_width_top = 10
@ -215,10 +227,10 @@ corner_radius_bottom_right = 4
corner_radius_bottom_left = 4 corner_radius_bottom_left = 4
anti_aliasing = false anti_aliasing = false
[sub_resource type="StyleBoxFlat" id=23] [sub_resource type="StyleBoxFlat" id=24]
bg_color = Color( 0.764706, 0.764706, 0.764706, 1 ) bg_color = Color( 0.764706, 0.764706, 0.764706, 1 )
[sub_resource type="StyleBoxFlat" id=24] [sub_resource type="StyleBoxFlat" id=25]
bg_color = Color( 0.627451, 0.627451, 0.627451, 1 ) bg_color = Color( 0.627451, 0.627451, 0.627451, 1 )
border_width_left = 5 border_width_left = 5
border_width_top = 10 border_width_top = 10
@ -231,7 +243,7 @@ corner_radius_bottom_right = 4
corner_radius_bottom_left = 4 corner_radius_bottom_left = 4
anti_aliasing = false anti_aliasing = false
[sub_resource type="StyleBoxFlat" id=25] [sub_resource type="StyleBoxFlat" id=26]
bg_color = Color( 0.352941, 0.352941, 0.352941, 1 ) bg_color = Color( 0.352941, 0.352941, 0.352941, 1 )
border_width_left = 10 border_width_left = 10
border_width_top = 6 border_width_top = 6
@ -239,7 +251,7 @@ border_width_right = 10
border_width_bottom = 8 border_width_bottom = 8
border_color = Color( 0.352941, 0.352941, 0.352941, 1 ) border_color = Color( 0.352941, 0.352941, 0.352941, 1 )
[sub_resource type="StyleBoxFlat" id=26] [sub_resource type="StyleBoxFlat" id=27]
bg_color = Color( 0.239216, 0.239216, 0.239216, 1 ) bg_color = Color( 0.239216, 0.239216, 0.239216, 1 )
border_width_left = 10 border_width_left = 10
border_width_top = 6 border_width_top = 6
@ -247,7 +259,7 @@ border_width_right = 10
border_width_bottom = 8 border_width_bottom = 8
border_color = Color( 0.239216, 0.239216, 0.239216, 1 ) border_color = Color( 0.239216, 0.239216, 0.239216, 1 )
[sub_resource type="StyleBoxFlat" id=27] [sub_resource type="StyleBoxFlat" id=28]
bg_color = Color( 0.627451, 0.627451, 0.627451, 1 ) bg_color = Color( 0.627451, 0.627451, 0.627451, 1 )
border_width_left = 10 border_width_left = 10
border_width_top = 6 border_width_top = 6
@ -255,19 +267,6 @@ border_width_right = 10
border_width_bottom = 8 border_width_bottom = 8
border_color = Color( 0.627451, 0.627451, 0.627451, 1 ) border_color = Color( 0.627451, 0.627451, 0.627451, 1 )
[sub_resource type="StyleBoxFlat" id=28]
bg_color = Color( 0.627451, 0.627451, 0.627451, 1 )
border_width_left = 4
border_width_top = 4
border_width_right = 4
border_width_bottom = 4
border_color = Color( 0.627451, 0.627451, 0.627451, 1 )
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
anti_aliasing = false
[sub_resource type="StyleBoxFlat" id=29] [sub_resource type="StyleBoxFlat" id=29]
bg_color = Color( 0.627451, 0.627451, 0.627451, 1 ) bg_color = Color( 0.627451, 0.627451, 0.627451, 1 )
border_width_left = 4 border_width_left = 4
@ -279,6 +278,7 @@ corner_radius_top_left = 4
corner_radius_top_right = 4 corner_radius_top_right = 4
corner_radius_bottom_right = 4 corner_radius_bottom_right = 4
corner_radius_bottom_left = 4 corner_radius_bottom_left = 4
anti_aliasing = false
[sub_resource type="StyleBoxFlat" id=30] [sub_resource type="StyleBoxFlat" id=30]
bg_color = Color( 0.529412, 0.529412, 0.529412, 1 ) bg_color = Color( 0.529412, 0.529412, 0.529412, 1 )
@ -390,6 +390,20 @@ HSplitContainer/constants/autohide = 1
HSplitContainer/constants/separation = 6 HSplitContainer/constants/separation = 6
HSplitContainer/icons/grabber = ExtResource( 1 ) HSplitContainer/icons/grabber = ExtResource( 1 )
HSplitContainer/styles/bg = null HSplitContainer/styles/bg = null
ItemList/colors/font_color = Color( 0, 0, 0, 1 )
ItemList/colors/font_color_selected = Color( 0.278431, 0.278431, 0.278431, 1 )
ItemList/colors/guide_color = Color( 0, 0, 0, 0.1 )
ItemList/constants/hseparation = 4
ItemList/constants/icon_margin = 4
ItemList/constants/line_separation = 2
ItemList/constants/vseparation = 4
ItemList/fonts/font = null
ItemList/styles/bg = SubResource( 19 )
ItemList/styles/bg_focus = null
ItemList/styles/cursor = null
ItemList/styles/cursor_unfocused = null
ItemList/styles/selected = null
ItemList/styles/selected_focus = null
"Label/colors/Selected Color" = Color( 0.545098, 0.619608, 0.788235, 1 ) "Label/colors/Selected Color" = Color( 0.545098, 0.619608, 0.788235, 1 )
Label/colors/font_color = Color( 0, 0, 0, 1 ) Label/colors/font_color = Color( 0, 0, 0, 1 )
Label/colors/font_color_shadow = Color( 0, 0, 0, 0 ) Label/colors/font_color_shadow = Color( 0, 0, 0, 0 )
@ -410,7 +424,7 @@ LineEdit/constants/minimum_spaces = 12
LineEdit/fonts/font = null LineEdit/fonts/font = null
LineEdit/icons/clear = null LineEdit/icons/clear = null
LineEdit/styles/focus = null LineEdit/styles/focus = null
LineEdit/styles/normal = SubResource( 19 ) LineEdit/styles/normal = SubResource( 20 )
LineEdit/styles/read_only = null LineEdit/styles/read_only = null
MenuButton/colors/font_color = Color( 0, 0, 0, 1 ) MenuButton/colors/font_color = Color( 0, 0, 0, 1 )
MenuButton/colors/font_color_disabled = Color( 1, 1, 1, 0.3 ) MenuButton/colors/font_color_disabled = Color( 1, 1, 1, 0.3 )
@ -436,10 +450,10 @@ OptionButton/styles/focus = null
OptionButton/styles/hover = null OptionButton/styles/hover = null
OptionButton/styles/normal = null OptionButton/styles/normal = null
OptionButton/styles/pressed = null OptionButton/styles/pressed = null
Panel/styles/panel = SubResource( 20 ) Panel/styles/panel = SubResource( 21 )
Panel/styles/panelf = null Panel/styles/panelf = null
Panel/styles/panelnc = null Panel/styles/panelnc = null
PanelContainer/styles/panel = SubResource( 21 ) PanelContainer/styles/panel = SubResource( 22 )
PopupMenu/colors/font_color = Color( 0, 0, 0, 1 ) PopupMenu/colors/font_color = Color( 0, 0, 0, 1 )
PopupMenu/colors/font_color_accel = Color( 0.164706, 0.164706, 0.164706, 0.8 ) PopupMenu/colors/font_color_accel = Color( 0.164706, 0.164706, 0.164706, 0.8 )
PopupMenu/colors/font_color_disabled = Color( 0.4, 0.4, 0.4, 0.8 ) PopupMenu/colors/font_color_disabled = Color( 0.4, 0.4, 0.4, 0.8 )
@ -455,10 +469,10 @@ PopupMenu/icons/unchecked = null
PopupMenu/styles/hover = null PopupMenu/styles/hover = null
PopupMenu/styles/labeled_separator_left = null PopupMenu/styles/labeled_separator_left = null
PopupMenu/styles/labeled_separator_right = null PopupMenu/styles/labeled_separator_right = null
PopupMenu/styles/panel = SubResource( 22 ) PopupMenu/styles/panel = SubResource( 23 )
PopupMenu/styles/panel_disabled = null PopupMenu/styles/panel_disabled = null
PopupMenu/styles/separator = null PopupMenu/styles/separator = null
PopupPanel/styles/panel = SubResource( 23 ) PopupPanel/styles/panel = SubResource( 24 )
SpinBox/icons/updown = ExtResource( 6 ) SpinBox/icons/updown = ExtResource( 6 )
TabContainer/colors/font_color_bg = Color( 0, 0, 0, 1 ) TabContainer/colors/font_color_bg = Color( 0, 0, 0, 1 )
TabContainer/colors/font_color_disabled = Color( 0.9, 0.9, 0.9, 0.2 ) TabContainer/colors/font_color_disabled = Color( 0.9, 0.9, 0.9, 0.2 )
@ -475,10 +489,10 @@ TabContainer/icons/increment = null
TabContainer/icons/increment_highlight = null TabContainer/icons/increment_highlight = null
TabContainer/icons/menu = null TabContainer/icons/menu = null
TabContainer/icons/menu_highlight = null TabContainer/icons/menu_highlight = null
TabContainer/styles/panel = SubResource( 24 ) TabContainer/styles/panel = SubResource( 25 )
TabContainer/styles/tab_bg = SubResource( 25 ) TabContainer/styles/tab_bg = SubResource( 26 )
TabContainer/styles/tab_disabled = SubResource( 26 ) TabContainer/styles/tab_disabled = SubResource( 27 )
TabContainer/styles/tab_fg = SubResource( 27 ) TabContainer/styles/tab_fg = SubResource( 28 )
Tabs/colors/font_color_bg = Color( 0.69, 0.69, 0.69, 1 ) Tabs/colors/font_color_bg = Color( 0.69, 0.69, 0.69, 1 )
Tabs/colors/font_color_disabled = Color( 0.9, 0.9, 0.9, 0.2 ) Tabs/colors/font_color_disabled = Color( 0.9, 0.9, 0.9, 0.2 )
Tabs/colors/font_color_fg = Color( 0.94, 0.94, 0.94, 1 ) Tabs/colors/font_color_fg = Color( 0.94, 0.94, 0.94, 1 )
@ -494,10 +508,10 @@ Tabs/icons/increment = null
Tabs/icons/increment_highlight = null Tabs/icons/increment_highlight = null
Tabs/styles/button = null Tabs/styles/button = null
Tabs/styles/button_pressed = null Tabs/styles/button_pressed = null
Tabs/styles/panel = SubResource( 24 ) Tabs/styles/panel = SubResource( 25 )
Tabs/styles/tab_bg = SubResource( 25 ) Tabs/styles/tab_bg = SubResource( 26 )
Tabs/styles/tab_disabled = SubResource( 26 ) Tabs/styles/tab_disabled = SubResource( 27 )
Tabs/styles/tab_fg = SubResource( 27 ) Tabs/styles/tab_fg = SubResource( 28 )
TextEdit/colors/background_color = Color( 0, 0, 0, 0 ) TextEdit/colors/background_color = Color( 0, 0, 0, 0 )
TextEdit/colors/brace_mismatch_color = Color( 1, 0.2, 0.2, 1 ) TextEdit/colors/brace_mismatch_color = Color( 1, 0.2, 0.2, 1 )
TextEdit/colors/breakpoint_color = Color( 0.8, 0.8, 0.4, 0.2 ) TextEdit/colors/breakpoint_color = Color( 0.8, 0.8, 0.4, 0.2 )
@ -529,7 +543,7 @@ TextEdit/fonts/font = null
TextEdit/icons/tab = null TextEdit/icons/tab = null
TextEdit/styles/completion = null TextEdit/styles/completion = null
TextEdit/styles/focus = null TextEdit/styles/focus = null
TextEdit/styles/normal = SubResource( 28 ) TextEdit/styles/normal = SubResource( 29 )
TextEdit/styles/read_only = null TextEdit/styles/read_only = null
ToolButton/colors/font_color = Color( 0, 0, 0, 1 ) ToolButton/colors/font_color = Color( 0, 0, 0, 1 )
ToolButton/colors/font_color_disabled = Color( 0.9, 0.95, 1, 0.3 ) ToolButton/colors/font_color_disabled = Color( 0.9, 0.95, 1, 0.3 )
@ -568,7 +582,7 @@ Tree/icons/checked = null
Tree/icons/select_arrow = null Tree/icons/select_arrow = null
Tree/icons/unchecked = null Tree/icons/unchecked = null
Tree/icons/updown = null Tree/icons/updown = null
Tree/styles/bg = SubResource( 29 ) Tree/styles/bg = SubResource( 19 )
Tree/styles/bg_focus = null Tree/styles/bg_focus = null
Tree/styles/button_pressed = null Tree/styles/button_pressed = null
Tree/styles/cursor = null Tree/styles/cursor = null

View file

@ -9,16 +9,31 @@
config_version=4 config_version=4
_global_script_classes=[ { _global_script_classes=[ {
"base": "Reference",
"class": "AnimationTag",
"language": "GDScript",
"path": "res://src/Classes/AnimationTag.gd"
}, {
"base": "Node2D", "base": "Node2D",
"class": "Canvas", "class": "Canvas",
"language": "GDScript", "language": "GDScript",
"path": "res://src/Canvas.gd" "path": "res://src/Canvas.gd"
}, { }, {
"base": "Reference",
"class": "Cel",
"language": "GDScript",
"path": "res://src/Classes/Cel.gd"
}, {
"base": "Line2D", "base": "Line2D",
"class": "Guide", "class": "Guide",
"language": "GDScript", "language": "GDScript",
"path": "res://src/UI/Rulers/Guides.gd" "path": "res://src/UI/Rulers/Guides.gd"
}, { }, {
"base": "Reference",
"class": "Layer",
"language": "GDScript",
"path": "res://src/Classes/Layer.gd"
}, {
"base": "Button", "base": "Button",
"class": "LayerButton", "class": "LayerButton",
"language": "GDScript", "language": "GDScript",
@ -35,8 +50,11 @@ _global_script_classes=[ {
"path": "res://src/Palette/PaletteColor.gd" "path": "res://src/Palette/PaletteColor.gd"
} ] } ]
_global_script_class_icons={ _global_script_class_icons={
"AnimationTag": "",
"Canvas": "", "Canvas": "",
"Cel": "",
"Guide": "", "Guide": "",
"Layer": "",
"LayerButton": "", "LayerButton": "",
"Palette": "", "Palette": "",
"PaletteColor": "" "PaletteColor": ""
@ -60,6 +78,7 @@ config/Version="v0.7"
Global="*res://src/Autoload/Global.gd" Global="*res://src/Autoload/Global.gd"
Import="*res://src/Autoload/Import.gd" Import="*res://src/Autoload/Import.gd"
OpenSave="*res://src/Autoload/OpenSave.gd" OpenSave="*res://src/Autoload/OpenSave.gd"
DrawingAlgos="*res://src/Autoload/DrawingAlgos.gd"
[debug] [debug]

View file

@ -0,0 +1,646 @@
extends Node
const Drawer = preload("res://src/Classes/Drawers.gd").Drawer
const SimpleDrawer = preload("res://src/Classes/Drawers.gd").SimpleDrawer
const PixelPerfectDrawer = preload("res://src/Classes/Drawers.gd").PixelPerfectDrawer
var pixel_perfect_drawer := PixelPerfectDrawer.new()
var pixel_perfect_drawer_h_mirror := PixelPerfectDrawer.new()
var pixel_perfect_drawer_v_mirror := PixelPerfectDrawer.new()
var pixel_perfect_drawer_hv_mirror := PixelPerfectDrawer.new()
var simple_drawer := SimpleDrawer.new()
var mouse_press_pixels := [] # Cleared after mouse release
var mouse_press_pressure_values := [] # Cleared after mouse release
func draw_pixel_blended(sprite : Image, pos : Vector2, color : Color, pen_pressure : float, current_mouse_button := -1, current_action := -1, drawer : Drawer = simple_drawer) -> void:
var west_limit = Global.canvas.west_limit
var east_limit = Global.canvas.east_limit
var north_limit = Global.canvas.north_limit
var south_limit = Global.canvas.south_limit
if !point_in_rectangle(pos, Vector2(west_limit - 1, north_limit - 1), Vector2(east_limit, south_limit)):
return
var pos_floored := pos.floor()
var current_pixel_color = sprite.get_pixelv(pos)
var saved_pixel_index := mouse_press_pixels.find(pos_floored)
if current_action == Global.Tools.PENCIL && color.a < 1:
color = blend_colors(color, current_pixel_color)
if current_pixel_color != color && (saved_pixel_index == -1 || pen_pressure > mouse_press_pressure_values[saved_pixel_index]):
if current_action == Global.Tools.LIGHTENDARKEN:
var ld : int = Global.ld_modes[current_mouse_button]
var ld_amount : float = Global.ld_amounts[current_mouse_button]
if ld == Global.Lighten_Darken_Mode.LIGHTEN:
color = current_pixel_color.lightened(ld_amount)
else:
color = current_pixel_color.darkened(ld_amount)
if saved_pixel_index == -1:
mouse_press_pixels.append(pos_floored)
mouse_press_pressure_values.append(pen_pressure)
else:
mouse_press_pressure_values[saved_pixel_index] = pen_pressure
drawer.set_pixel(sprite, pos, color)
func draw_brush(sprite : Image, pos : Vector2, color : Color, current_mouse_button : int, pen_pressure : float, current_action := -1) -> void:
if Global.can_draw && Global.has_focus:
var west_limit = Global.canvas.west_limit
var east_limit = Global.canvas.east_limit
var north_limit = Global.canvas.north_limit
var south_limit = Global.canvas.south_limit
if Global.pressure_sensitivity_mode == Global.Pressure_Sensitivity.ALPHA:
if current_action == Global.Tools.PENCIL:
color.a *= pen_pressure
elif current_action == Global.Tools.ERASER: # This is not working
color.a *= (1.0 - pen_pressure)
var brush_size : int = Global.brush_sizes[current_mouse_button]
var brush_type : int = Global.current_brush_types[current_mouse_button]
var horizontal_mirror : bool = Global.horizontal_mirror[current_mouse_button]
var vertical_mirror : bool = Global.vertical_mirror[current_mouse_button]
if brush_type == Global.Brush_Types.PIXEL || current_action == Global.Tools.LIGHTENDARKEN:
var start_pos_x = pos.x - (brush_size >> 1)
var start_pos_y = pos.y - (brush_size >> 1)
var end_pos_x = start_pos_x + brush_size
var end_pos_y = start_pos_y + brush_size
for cur_pos_x in range(start_pos_x, end_pos_x):
for cur_pos_y in range(start_pos_y, end_pos_y):
var pixel_perfect : bool = Global.pixel_perfect[current_mouse_button]
# warning-ignore:incompatible_ternary
var drawer : Drawer = pixel_perfect_drawer if pixel_perfect else simple_drawer
draw_pixel_blended(sprite, Vector2(cur_pos_x, cur_pos_y), color, pen_pressure, current_mouse_button, current_action, drawer)
# Handle mirroring
var mirror_x = east_limit + west_limit - cur_pos_x - 1
var mirror_y = south_limit + north_limit - cur_pos_y - 1
if horizontal_mirror:
# warning-ignore:incompatible_ternary
var drawer_h_mirror : Drawer = pixel_perfect_drawer_h_mirror if pixel_perfect else simple_drawer
draw_pixel_blended(sprite, Vector2(mirror_x, cur_pos_y), color, pen_pressure, current_mouse_button, current_action, drawer_h_mirror)
if vertical_mirror:
# warning-ignore:incompatible_ternary
var drawer_v_mirror : Drawer = pixel_perfect_drawer_v_mirror if pixel_perfect else simple_drawer
draw_pixel_blended(sprite, Vector2(cur_pos_x, mirror_y), color, pen_pressure, current_mouse_button, current_action, drawer_v_mirror)
if horizontal_mirror && vertical_mirror:
# warning-ignore:incompatible_ternary
var drawer_hv_mirror : Drawer = pixel_perfect_drawer_hv_mirror if pixel_perfect else simple_drawer
draw_pixel_blended(sprite, Vector2(mirror_x, mirror_y), color, pen_pressure, current_mouse_button, current_action, drawer_hv_mirror)
Global.canvas.sprite_changed_this_frame = true
elif brush_type == Global.Brush_Types.CIRCLE || brush_type == Global.Brush_Types.FILLED_CIRCLE:
plot_circle(sprite, pos.x, pos.y, brush_size, color, brush_type == Global.Brush_Types.FILLED_CIRCLE)
# Handle mirroring
var mirror_x = east_limit + west_limit - pos.x
var mirror_y = south_limit + north_limit - pos.y
if horizontal_mirror:
plot_circle(sprite, mirror_x, pos.y, brush_size, color, brush_type == Global.Brush_Types.FILLED_CIRCLE)
if vertical_mirror:
plot_circle(sprite, pos.x, mirror_y, brush_size, color, brush_type == Global.Brush_Types.FILLED_CIRCLE)
if horizontal_mirror && vertical_mirror:
plot_circle(sprite, mirror_x, mirror_y, brush_size, color, brush_type == Global.Brush_Types.FILLED_CIRCLE)
Global.canvas.sprite_changed_this_frame = true
else:
var brush_index : int = Global.custom_brush_indexes[current_mouse_button]
var custom_brush_image : Image
if brush_type != Global.Brush_Types.RANDOM_FILE:
custom_brush_image = Global.custom_brush_images[current_mouse_button]
else: # Handle random brush
var brush_button = Global.file_brush_container.get_child(brush_index + 3)
var random_index = randi() % brush_button.random_brushes.size()
custom_brush_image = Image.new()
custom_brush_image.copy_from(brush_button.random_brushes[random_index])
var custom_brush_size = custom_brush_image.get_size()
custom_brush_image.resize(custom_brush_size.x * brush_size, custom_brush_size.y * brush_size, Image.INTERPOLATE_NEAREST)
custom_brush_image = Global.blend_image_with_color(custom_brush_image, color, Global.interpolate_spinboxes[current_mouse_button].value / 100)
custom_brush_image.lock()
var custom_brush_size := custom_brush_image.get_size() - Vector2.ONE
pos = pos.floor()
var dst := rectangle_center(pos, custom_brush_size)
var src_rect := Rect2(Vector2.ZERO, custom_brush_size + Vector2.ONE)
# Rectangle with the same size as the brush, but at cursor's position
var pos_rect := Rect2(dst, custom_brush_size + Vector2.ONE)
# The selection rectangle
# If there's no rectangle, the whole canvas is considered a selection
var selection_rect := Rect2()
selection_rect.position = Vector2(west_limit, north_limit)
selection_rect.end = Vector2(east_limit, south_limit)
# Intersection of the position rectangle and selection
var pos_rect_clipped := pos_rect.clip(selection_rect)
# If the size is 0, that means that the brush wasn't positioned inside the selection
if pos_rect_clipped.size == Vector2.ZERO:
return
# Re-position src_rect and dst based on the clipped position
var pos_difference := (pos_rect.position - pos_rect_clipped.position).abs()
# Obviously, if pos_rect and pos_rect_clipped are the same, pos_difference is Vector2.ZERO
src_rect.position = pos_difference
dst += pos_difference
src_rect.end -= pos_rect.end - pos_rect_clipped.end
# If the selection rectangle is smaller than the brush, ...
# ... make sure pixels aren't being drawn outside the selection by adjusting src_rect's size
src_rect.size.x = min(src_rect.size.x, selection_rect.size.x)
src_rect.size.y = min(src_rect.size.y, selection_rect.size.y)
# Handle mirroring
var mirror_x = east_limit + west_limit - pos.x - (pos.x - dst.x)
var mirror_y = south_limit + north_limit - pos.y - (pos.y - dst.y)
if int(pos_rect_clipped.size.x) % 2 != 0:
mirror_x -= 1
if int(pos_rect_clipped.size.y) % 2 != 0:
mirror_y -= 1
# Use custom blend function cause of godot's issue #31124
if color.a > 0: # If it's the pencil
blend_rect(sprite, custom_brush_image, src_rect, dst)
if horizontal_mirror:
blend_rect(sprite, custom_brush_image, src_rect, Vector2(mirror_x, dst.y))
if vertical_mirror:
blend_rect(sprite, custom_brush_image, src_rect, Vector2(dst.x, mirror_y))
if horizontal_mirror && vertical_mirror:
blend_rect(sprite, custom_brush_image, src_rect, Vector2(mirror_x, mirror_y))
else: # if it's transparent - if it's the eraser
var custom_brush := Image.new()
custom_brush.copy_from(Global.custom_brushes[brush_index])
custom_brush_size = custom_brush.get_size()
custom_brush.resize(custom_brush_size.x * brush_size, custom_brush_size.y * brush_size, Image.INTERPOLATE_NEAREST)
var custom_brush_blended = Global.blend_image_with_color(custom_brush, color, 1)
sprite.blit_rect_mask(custom_brush_blended, custom_brush, src_rect, dst)
if horizontal_mirror:
sprite.blit_rect_mask(custom_brush_blended, custom_brush, src_rect, Vector2(mirror_x, dst.y))
if vertical_mirror:
sprite.blit_rect_mask(custom_brush_blended, custom_brush, src_rect, Vector2(dst.x, mirror_y))
if horizontal_mirror && vertical_mirror:
sprite.blit_rect_mask(custom_brush_blended, custom_brush, src_rect, Vector2(mirror_x, mirror_y))
sprite.lock()
Global.canvas.sprite_changed_this_frame = true
Global.canvas.previous_mouse_pos_for_lines = pos.floor() + Vector2(0.5, 0.5)
Global.canvas.previous_mouse_pos_for_lines.x = clamp(Global.canvas.previous_mouse_pos_for_lines.x, Global.canvas.location.x, Global.canvas.location.x + Global.canvas.size.x)
Global.canvas.previous_mouse_pos_for_lines.y = clamp(Global.canvas.previous_mouse_pos_for_lines.y, Global.canvas.location.y, Global.canvas.location.y + Global.canvas.size.y)
if Global.canvas.is_making_line:
Global.canvas.line_2d.set_point_position(0, Global.canvas.previous_mouse_pos_for_lines)
# Bresenham's Algorithm
# Thanks to https://godotengine.org/qa/35276/tile-based-line-drawing-algorithm-efficiency
func fill_gaps(sprite : Image, end_pos : Vector2, start_pos : Vector2, color : Color, current_mouse_button : int, pen_pressure : float, current_action := -1) -> void:
var previous_mouse_pos_floored = start_pos.floor()
var mouse_pos_floored = end_pos.floor()
var dx := int(abs(mouse_pos_floored.x - previous_mouse_pos_floored.x))
var dy := int(-abs(mouse_pos_floored.y - previous_mouse_pos_floored.y))
var err := dx + dy
var e2 := err << 1 # err * 2
var sx = 1 if previous_mouse_pos_floored.x < mouse_pos_floored.x else -1
var sy = 1 if previous_mouse_pos_floored.y < mouse_pos_floored.y else -1
var x = previous_mouse_pos_floored.x
var y = previous_mouse_pos_floored.y
while !(x == mouse_pos_floored.x && y == mouse_pos_floored.y):
draw_brush(sprite, Vector2(x, y), color, current_mouse_button, pen_pressure, current_action)
e2 = err << 1
if e2 >= dy:
err += dy
x += sx
if e2 <= dx:
err += dx
y += sy
# Algorithm based on http://members.chello.at/easyfilter/bresenham.html
func plot_circle(sprite : Image, xm : int, ym : int, r : int, color : Color, fill := false) -> void:
var radius := r # Used later for filling
var x := -r
var y := 0
var err := 2 - r * 2 # II. Quadrant
while x < 0:
var quadrant_1 := Vector2(xm - x, ym + y)
var quadrant_2 := Vector2(xm - y, ym - x)
var quadrant_3 := Vector2(xm + x, ym - y)
var quadrant_4 := Vector2(xm + y, ym + x)
draw_pixel_blended(sprite, quadrant_1, color, Global.canvas.pen_pressure)
draw_pixel_blended(sprite, quadrant_2, color, Global.canvas.pen_pressure)
draw_pixel_blended(sprite, quadrant_3, color, Global.canvas.pen_pressure)
draw_pixel_blended(sprite, quadrant_4, color, Global.canvas.pen_pressure)
r = err
if r <= y:
y += 1
err += y * 2 + 1
if r > x || err > y:
x += 1
err += x * 2 + 1
if fill:
for j in range (-radius, radius + 1):
for i in range (-radius, radius + 1):
if i * i + j * j <= radius * radius:
var draw_pos := Vector2(i + xm, j + ym)
draw_pixel_blended(sprite, draw_pos, color, Global.canvas.pen_pressure)
# Thanks to https://en.wikipedia.org/wiki/Flood_fill
func flood_fill(sprite : Image, pos : Vector2, target_color : Color, replace_color : Color) -> void:
var west_limit = Global.canvas.west_limit
var east_limit = Global.canvas.east_limit
var north_limit = Global.canvas.north_limit
var south_limit = Global.canvas.south_limit
pos = pos.floor()
var pixel = sprite.get_pixelv(pos)
if target_color == replace_color:
return
elif pixel != target_color:
return
else:
if !point_in_rectangle(pos, Vector2(west_limit - 1, north_limit - 1), Vector2(east_limit, south_limit)):
return
var q = [pos]
for n in q:
# If the difference in colors is very small, break the loop (thanks @azagaya on GitHub!)
if target_color == replace_color:
break
var west : Vector2 = n
var east : Vector2 = n
while west.x >= west_limit && sprite.get_pixelv(west) == target_color:
west += Vector2.LEFT
while east.x < east_limit && sprite.get_pixelv(east) == target_color:
east += Vector2.RIGHT
for px in range(west.x + 1, east.x):
var p := Vector2(px, n.y)
# Draw
sprite.set_pixelv(p, replace_color)
replace_color = sprite.get_pixelv(p)
var north := p + Vector2.UP
var south := p + Vector2.DOWN
if north.y >= north_limit && sprite.get_pixelv(north) == target_color:
q.append(north)
if south.y < south_limit && sprite.get_pixelv(south) == target_color:
q.append(south)
Global.canvas.sprite_changed_this_frame = true
func pattern_fill(sprite : Image, pos : Vector2, pattern : Image, target_color : Color, var offset : Vector2) -> void:
var west_limit = Global.canvas.west_limit
var east_limit = Global.canvas.east_limit
var north_limit = Global.canvas.north_limit
var south_limit = Global.canvas.south_limit
pos = pos.floor()
if !point_in_rectangle(pos, Vector2(west_limit - 1, north_limit - 1), Vector2(east_limit, south_limit)):
return
pattern.lock()
var pattern_size := pattern.get_size()
var q = [pos]
for n in q:
var west : Vector2 = n
var east : Vector2 = n
while west.x >= west_limit && sprite.get_pixelv(west) == target_color:
west += Vector2.LEFT
while east.x < east_limit && sprite.get_pixelv(east) == target_color:
east += Vector2.RIGHT
for px in range(west.x + 1, east.x):
var p := Vector2(px, n.y)
var xx : int = int(px + offset.x) % int(pattern_size.x)
var yy : int = int(n.y + offset.y) % int(pattern_size.y)
var pattern_color : Color = pattern.get_pixel(xx, yy)
if pattern_color == target_color:
continue
sprite.set_pixelv(p, pattern_color)
var north := p + Vector2.UP
var south := p + Vector2.DOWN
if north.y >= north_limit && sprite.get_pixelv(north) == target_color:
q.append(north)
if south.y < south_limit && sprite.get_pixelv(south) == target_color:
q.append(south)
pattern.unlock()
Global.canvas.sprite_changed_this_frame = true
func blend_colors(color_1 : Color, color_2 : Color) -> Color:
var color := Color()
color.a = color_1.a + color_2.a * (1 - color_1.a) # Blend alpha
if color.a != 0:
# Blend colors
color.r = (color_1.r * color_1.a + color_2.r * color_2.a * (1-color_1.a)) / color.a
color.g = (color_1.g * color_1.a + color_2.g * color_2.a * (1-color_1.a)) / color.a
color.b = (color_1.b * color_1.a + color_2.b * color_2.a * (1-color_1.a)) / color.a
return color
# Custom blend rect function, needed because Godot's issue #31124
func blend_rect(bg : Image, brush : Image, src_rect : Rect2, dst : Vector2) -> void:
var brush_size := brush.get_size()
var clipped_src_rect := Rect2(Vector2.ZERO, brush_size).clip(src_rect)
if clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0:
return
var src_underscan := Vector2(min(0, src_rect.position.x), min(0, src_rect.position.y))
var dest_rect := Rect2(0, 0, bg.get_width(), bg.get_height()).clip(Rect2(dst - src_underscan, clipped_src_rect.size))
for x in range(0, dest_rect.size.x):
for y in range(0, dest_rect.size.y):
var src_x := clipped_src_rect.position.x + x;
var src_y := clipped_src_rect.position.y + y;
var dst_x := dest_rect.position.x + x;
var dst_y := dest_rect.position.y + y;
brush.lock()
var brush_color := brush.get_pixel(src_x, src_y)
var bg_color := bg.get_pixel(dst_x, dst_y)
var out_color := blend_colors(brush_color, bg_color)
if out_color.a != 0:
bg.set_pixel(dst_x, dst_y, out_color)
brush.unlock()
func scale3X(sprite : Image, tol : float = 50) -> Image:
var scaled = Image.new()
scaled.create(sprite.get_width()*3, sprite.get_height()*3, false, Image.FORMAT_RGBA8)
scaled.lock()
sprite.lock()
var a : Color
var b : Color
var c : Color
var d : Color
var e : Color
var f : Color
var g : Color
var h : Color
var i : Color
for x in range(1,sprite.get_width()-1):
for y in range(1,sprite.get_height()-1):
var xs : float = 3*x
var ys : float = 3*y
a = sprite.get_pixel(x-1,y-1)
b = sprite.get_pixel(x,y-1)
c = sprite.get_pixel(x+1,y-1)
d = sprite.get_pixel(x-1,y)
e = sprite.get_pixel(x,y)
f = sprite.get_pixel(x+1,y)
g = sprite.get_pixel(x-1,y+1)
h = sprite.get_pixel(x,y+1)
i = sprite.get_pixel(x+1,y+1)
var db : bool = similarColors(d, b, tol)
var dh : bool = similarColors(d, h, tol)
var bf : bool = similarColors(f, b, tol)
var ec : bool = similarColors(e, c, tol)
var ea : bool = similarColors(e, a, tol)
var fh : bool = similarColors(f, h, tol)
var eg : bool = similarColors(e, g, tol)
var ei : bool = similarColors(e, i, tol)
scaled.set_pixel(xs-1, ys-1, d if (db and !dh and !bf) else e )
scaled.set_pixel(xs, ys-1, b if (db and !dh and !bf and !ec) or
(bf and !db and !fh and !ea) else e)
scaled.set_pixel(xs+1, ys-1, f if (bf and !db and !fh) else e)
scaled.set_pixel(xs-1, ys, d if (dh and !fh and !db and !ea) or
(db and !dh and !bf and !eg) else e)
scaled.set_pixel(xs, ys, e);
scaled.set_pixel(xs+1, ys, f if (bf and !db and !fh and !ei) or
(fh and !bf and !dh and !ec) else e)
scaled.set_pixel(xs-1, ys+1, d if (dh and !fh and !db) else e)
scaled.set_pixel(xs, ys+1, h if (fh and !bf and !dh and !eg) or
(dh and !fh and !db and !ei) else e)
scaled.set_pixel(xs+1, ys+1, f if (fh and !bf and !dh) else e)
scaled.unlock()
sprite.unlock()
return scaled
func rotxel(sprite : Image, angle : float) -> void:
# If angle is simple, then nn rotation is the best
if angle == 0 || angle == PI/2 || angle == PI || angle == 2*PI:
nn_rotate(sprite, angle)
return
var aux : Image = Image.new()
aux.copy_from(sprite)
# warning-ignore:integer_division
# warning-ignore:integer_division
var center : Vector2 = Vector2(sprite.get_width() / 2, sprite.get_height() / 2)
var ox : int
var oy : int
var p : Color
aux.lock()
sprite.lock()
for x in range(sprite.get_width()):
for y in range(sprite.get_height()):
var dx = 3*(x - center.x)
var dy = 3*(y - center.y)
var found_pixel : bool = false
for k in range(9):
var i = -1 + k % 3
# warning-ignore:integer_division
var j = -1 + int(k / 3)
var dir = atan2(dy + j, dx + i)
var mag = sqrt(pow(dx + i, 2) + pow(dy + j, 2))
dir -= angle
ox = round(center.x*3 + 1 + mag*cos(dir))
oy = round(center.y*3 + 1 + mag*sin(dir))
if (sprite.get_width() % 2 != 0):
ox += 1
oy += 1
if (ox >= 0 && ox < sprite.get_width()*3
&& oy >= 0 && oy < sprite.get_height()*3):
found_pixel = true
break
if !found_pixel:
sprite.set_pixel(x, y, Color(0,0,0,0))
continue
var fil : int = oy % 3
var col : int = ox % 3
var index : int = col + 3*fil
ox = round((ox - 1)/3.0);
oy = round((oy - 1)/3.0);
var a : Color
var b : Color
var c : Color
var d : Color
var e : Color
var f : Color
var g : Color
var h : Color
var i : Color
if (ox == 0 || ox == sprite.get_width() - 1 ||
oy == 0 || oy == sprite.get_height() - 1):
p = aux.get_pixel(ox, oy)
else:
a = aux.get_pixel(ox-1,oy-1);
b = aux.get_pixel(ox,oy-1);
c = aux.get_pixel(ox+1,oy-1);
d = aux.get_pixel(ox-1,oy);
e = aux.get_pixel(ox,oy);
f = aux.get_pixel(ox+1,oy);
g = aux.get_pixel(ox-1,oy+1);
h = aux.get_pixel(ox,oy+1);
i = aux.get_pixel(ox+1,oy+1);
match(index):
0:
p = d if (similarColors(d,b) && !similarColors(d,h)
&& !similarColors(b,f)) else e;
1:
p = b if ((similarColors(d,b) && !similarColors(d,h) &&
!similarColors(b,f) && !similarColors(e,c)) ||
(similarColors(b,f) && !similarColors(d,b) &&
!similarColors(f,h) && !similarColors(e,a))) else e;
2:
p = f if (similarColors(b,f) && !similarColors(d,b) &&
!similarColors(f,h)) else e;
3:
p = d if ((similarColors(d,h) && !similarColors(f,h) &&
!similarColors(d,b) && !similarColors(e,a)) ||
(similarColors(d,b) && !similarColors(d,h) &&
!similarColors(b,f) && !similarColors(e,g))) else e;
4:
p = e
5:
p = f if((similarColors(b,f) && !similarColors(d,b) &&
!similarColors(f,h) && !similarColors(e,i))
|| (similarColors(f,h) && !similarColors(b,f) &&
!similarColors(d,h) && !similarColors(e,c))) else e;
6:
p = d if (similarColors(d,h) && !similarColors(f,h) &&
!similarColors(d,b)) else e;
7:
p = h if ((similarColors(f,h) && !similarColors(f,b) &&
!similarColors(d,h) && !similarColors(e,g))
|| (similarColors(d,h) && !similarColors(f,h) &&
!similarColors(d,b) && !similarColors(e,i))) else e;
8:
p = f if (similarColors(f,h) && !similarColors(f,b) &&
!similarColors(d,h)) else e;
sprite.set_pixel(x, y, p)
sprite.unlock()
aux.unlock()
func fake_rotsprite(sprite : Image, angle : float) -> void:
sprite.copy_from(scale3X(sprite))
nn_rotate(sprite,angle)
# warning-ignore:integer_division
# warning-ignore:integer_division
sprite.resize(sprite.get_width() / 3, sprite.get_height() / 3, 0)
func nn_rotate(sprite : Image, angle : float) -> void:
var aux : Image = Image.new()
aux.copy_from(sprite)
sprite.lock()
aux.lock()
var ox: int
var oy: int
# warning-ignore:integer_division
# warning-ignore:integer_division
var center : Vector2 = Vector2(sprite.get_width() / 2, sprite.get_height() / 2)
for x in range(sprite.get_width()):
for y in range(sprite.get_height()):
ox = (x - center.x)*cos(angle) + (y - center.y)*sin(angle) + center.x
oy = -(x - center.x)*sin(angle) + (y - center.y)*cos(angle) + center.y
if ox >= 0 && ox < sprite.get_width() && oy >= 0 && oy < sprite.get_height():
sprite.set_pixel(x, y, aux.get_pixel(ox, oy))
else:
sprite.set_pixel(x, y, Color(0,0,0,0))
sprite.unlock()
aux.unlock()
func similarColors(c1 : Color, c2 : Color, tol : float = 100) -> bool:
var dist = colorDistance(c1, c2)
return dist <= tol
func colorDistance(c1 : Color, c2 : Color) -> float:
return sqrt(pow((c1.r - c2.r)*255, 2) + pow((c1.g - c2.g)*255, 2)
+ pow((c1.b - c2.b)*255, 2) + pow((c1.a - c2.a)*255, 2))
func adjust_hsv(img: Image, id : int, delta : float) -> void:
var west_limit = Global.canvas.west_limit
var east_limit = Global.canvas.east_limit
var north_limit = Global.canvas.north_limit
var south_limit = Global.canvas.south_limit
img.lock()
match id:
0: # Hue
for i in range(west_limit, east_limit):
for j in range(north_limit, south_limit):
var c : Color = img.get_pixel(i,j)
var hue = range_lerp(c.h,0,1,-180,180)
hue = hue + delta
while(hue >= 180):
hue -= 360
while(hue < -180):
hue += 360
c.h = range_lerp(hue,-180,180,0,1)
img.set_pixel(i,j,c)
1: # Saturation
for i in range(west_limit, east_limit):
for j in range(north_limit, south_limit):
var c : Color = img.get_pixel(i,j)
var sat = c.s
if delta > 0:
sat = range_lerp(delta,0,100,c.s,1)
elif delta < 0:
sat = range_lerp(delta,-100,0,0,c.s)
c.s = sat
img.set_pixel(i,j,c)
2: # Value
for i in range(west_limit, east_limit):
for j in range(north_limit, south_limit):
var c : Color = img.get_pixel(i,j)
var val = c.v
if delta > 0:
val = range_lerp(delta,0,100,c.v,1)
elif delta < 0:
val = range_lerp(delta,-100,0,0,c.v)
c.v = val
img.set_pixel(i,j,c)
img.unlock()
# Checks if a point is inside a rectangle
func point_in_rectangle(p : Vector2, coord1 : Vector2, coord2 : Vector2) -> bool:
return p.x > coord1.x && p.y > coord1.y && p.x < coord2.x && p.y < coord2.y
# Returns the position in the middle of a rectangle
func rectangle_center(rect_position : Vector2, rect_size : Vector2) -> Vector2:
return (rect_position - rect_size / 2).floor()

View file

@ -1,26 +1,28 @@
extends Node extends Node
enum Grid_Types {CARTESIAN, ISOMETRIC, ALL} enum Grid_Types {CARTESIAN, ISOMETRIC, ALL}
enum Pressure_Sensitivity {NONE, ALPHA, SIZE, ALPHA_AND_SIZE} enum Pressure_Sensitivity {NONE, ALPHA, SIZE, ALPHA_AND_SIZE}
enum Brush_Types {PIXEL, CIRCLE, FILLED_CIRCLE, FILE, RANDOM_FILE, CUSTOM} enum Brush_Types {PIXEL, CIRCLE, FILLED_CIRCLE, FILE, RANDOM_FILE, CUSTOM}
enum Direction {UP, DOWN, LEFT, RIGHT}
var root_directory := "." enum Mouse_Button {LEFT, RIGHT}
var window_title := "" setget title_changed # Why doesn't Godot have get_window_title()? enum Tools {PENCIL, ERASER, BUCKET, LIGHTENDARKEN, RECTSELECT, COLORPICKER, ZOOM}
var config_cache := ConfigFile.new() enum Theme_Types {DARK, BLUE, CARAMEL, LIGHT}
var XDGDataPaths = preload("res://src/XDGDataPaths.gd") enum Fill_Area {SAME_COLOR_AREA, SAME_COLOR_PIXELS}
var directory_module : Reference enum Fill_With {COLOR, PATTERN}
enum Lighten_Darken_Mode {LIGHTEN, DARKEN}
enum Zoom_Mode {ZOOM_IN, ZOOM_OUT}
# Stuff for arrowkey-based canvas movements nyaa ^.^ # Stuff for arrowkey-based canvas movements nyaa ^.^
const low_speed_move_rate := 150.0 const low_speed_move_rate := 150.0
const medium_speed_move_rate := 750.0 const medium_speed_move_rate := 750.0
const high_speed_move_rate := 3750.0 const high_speed_move_rate := 3750.0
enum Direction { var root_directory := "."
UP = 0, var window_title := "" setget title_changed # Why doesn't Godot have get_window_title()?
DOWN = 1, var config_cache := ConfigFile.new()
LEFT = 2, var XDGDataPaths = preload("res://src/XDGDataPaths.gd")
RIGHT = 3 var directory_module : Reference
}
# Indices are as in the Direction enum # Indices are as in the Direction enum
# This is the total time the key for # This is the total time the key for
@ -51,10 +53,10 @@ var right_cursor_tool_texture : ImageTexture
var selected_pixels := [] var selected_pixels := []
var image_clipboard : Image var image_clipboard : Image
var animation_tags := [] setget animation_tags_changed # [Name, Color, From, To] var animation_tags := [] setget animation_tags_changed
var play_only_tags := true var play_only_tags := true
var theme_type := "Dark" var theme_type : int = Theme_Types.DARK
var is_default_image := true var is_default_image := true
var default_image_width := 64 var default_image_width := 64
var default_image_height := 64 var default_image_height := 64
@ -68,45 +70,30 @@ var checker_size := 10
var checker_color_1 := Color(0.47, 0.47, 0.47, 1) var checker_color_1 := Color(0.47, 0.47, 0.47, 1)
var checker_color_2 := Color(0.34, 0.35, 0.34, 1) var checker_color_2 := Color(0.34, 0.35, 0.34, 1)
var autosave_interval := 5.0
var enable_autosave := true
# Tools & options # Tools & options
var current_left_tool := "Pencil" var current_tools := [Tools.PENCIL, Tools.ERASER]
var current_right_tool := "Eraser"
var show_left_tool_icon := true var show_left_tool_icon := true
var show_right_tool_icon := true var show_right_tool_icon := true
var left_square_indicator_visible := true var left_square_indicator_visible := true
var right_square_indicator_visible := false var right_square_indicator_visible := false
# 0 for area of same color, 1 for all pixels of the same color var fill_areas := [Fill_Area.SAME_COLOR_AREA, Fill_Area.SAME_COLOR_AREA]
var left_fill_area := 0 var fill_with := [Fill_With.COLOR, Fill_With.COLOR]
var right_fill_area := 0 var fill_pattern_offsets := [Vector2.ZERO, Vector2.ZERO]
var left_fill_with := 0 var ld_modes := [Lighten_Darken_Mode.LIGHTEN, Lighten_Darken_Mode.LIGHTEN]
var right_fill_with := 0 var ld_amounts := [0.1, 0.1]
var left_fill_pattern_offset := Vector2.ZERO var color_picker_for := [Mouse_Button.LEFT, Mouse_Button.RIGHT]
var right_fill_pattern_offset := Vector2.ZERO
# 0 for lighten, 1 for darken var zoom_modes := [Zoom_Mode.ZOOM_IN, Zoom_Mode.ZOOM_OUT]
var left_ld := 0
var right_ld := 0
var left_ld_amount := 0.1
var right_ld_amount := 0.1
# 0 for the left, 1 for the right var horizontal_mirror := [false, false]
var left_color_picker_for := 0 var vertical_mirror := [false, false]
var right_color_picker_for := 1 var pixel_perfect := [false, false]
# 0 for zoom in, 1 for zoom out
var left_zoom_mode := 0
var right_zoom_mode := 1
var left_horizontal_mirror := false
var left_vertical_mirror := false
var right_horizontal_mirror := false
var right_vertical_mirror := false
var left_pixel_perfect := false
var right_pixel_perfect := false
# View menu options # View menu options
var tile_mode := false var tile_mode := false
@ -122,29 +109,23 @@ var onion_skinning_future_rate := 1.0
var onion_skinning_blue_red := false var onion_skinning_blue_red := false
# Brushes # Brushes
var left_brush_size := 1 var brush_sizes := [1, 1]
var right_brush_size := 1 var current_brush_types := [Brush_Types.PIXEL, Brush_Types.PIXEL]
var current_left_brush_type = Brush_Types.PIXEL
var current_right_brush_type = Brush_Types.PIXEL
var brush_type_window_position := "left" var brush_type_window_position : int = Mouse_Button.LEFT
var left_circle_points := [] var left_circle_points := []
var right_circle_points := [] var right_circle_points := []
var brushes_from_files := 0 var brushes_from_files := 0
var custom_brushes := [] var custom_brushes := []
var custom_left_brush_index := -1 var custom_brush_indexes := [-1, -1]
var custom_right_brush_index := -1 var custom_brush_images := [Image.new(), Image.new()]
var custom_left_brush_image : Image var custom_brush_textures := [ImageTexture.new(), ImageTexture.new()]
var custom_right_brush_image : Image
var custom_left_brush_texture := ImageTexture.new()
var custom_right_brush_texture := ImageTexture.new()
# Patterns # Patterns
var patterns := [] var patterns := []
var pattern_window_position := "left" var pattern_window_position : int = Mouse_Button.LEFT
var pattern_left_image : Image var pattern_images := [Image.new(), Image.new()]
var pattern_right_image : Image
# Palettes # Palettes
var palettes := {} var palettes := {}
@ -176,65 +157,48 @@ var zoom_level_label : Label
var import_sprites_dialog : FileDialog var import_sprites_dialog : FileDialog
var export_dialog : AcceptDialog var export_dialog : AcceptDialog
var preferences_dialog : AcceptDialog
var left_color_picker : ColorPickerButton var color_pickers := []
var right_color_picker : ColorPickerButton
var color_switch_button : BaseButton var color_switch_button : BaseButton
var left_tool_options_container : Container var tool_options_containers := []
var right_tool_options_container : Container
var left_brush_type_container : Container var brush_type_containers := []
var right_brush_type_container : Container var brush_type_buttons := []
var left_brush_type_button : BaseButton
var right_brush_type_button : BaseButton
var brushes_popup : Popup var brushes_popup : Popup
var file_brush_container : GridContainer var file_brush_container : GridContainer
var project_brush_container : GridContainer var project_brush_container : GridContainer
var patterns_popup : Popup var patterns_popup : Popup
var left_brush_size_edit : SpinBox var brush_size_edits := []
var left_brush_size_slider : HSlider var brush_size_sliders := []
var right_brush_size_edit : SpinBox
var right_brush_size_slider : HSlider
var left_pixel_perfect_container : VBoxContainer var pixel_perfect_containers := []
var right_pixel_perfect_container : VBoxContainer
var left_color_interpolation_container : Container var color_interpolation_containers := []
var right_color_interpolation_container : Container var interpolate_spinboxes := []
var left_interpolate_spinbox : SpinBox var interpolate_sliders := []
var left_interpolate_slider : HSlider
var right_interpolate_spinbox : SpinBox
var right_interpolate_slider : HSlider
var left_fill_area_container : Container var fill_area_containers := []
var left_fill_pattern_container : Container var fill_pattern_containers := []
var right_fill_area_container : Container
var right_fill_pattern_container : Container
var left_ld_container : Container var ld_containers := []
var left_ld_amount_slider : HSlider var ld_amount_sliders := []
var left_ld_amount_spinbox : SpinBox var ld_amount_spinboxes := []
var right_ld_container : Container
var right_ld_amount_slider : HSlider
var right_ld_amount_spinbox : SpinBox
var left_colorpicker_container : Container var colorpicker_containers := []
var right_colorpicker_container : Container
var left_zoom_container : Container var zoom_containers := []
var right_zoom_container : Container
var left_mirror_container : Container var mirror_containers := []
var right_mirror_container : Container
var animation_timeline : Panel var animation_timeline : Panel
var animation_timer : Timer var animation_timer : Timer
var frame_ids : HBoxContainer var frame_ids : HBoxContainer
var current_frame_label : Label var current_frame_mark_label : Label
var onion_skinning_button : BaseButton var onion_skinning_button : BaseButton
var loop_animation_button : BaseButton var loop_animation_button : BaseButton
var play_forward : BaseButton var play_forward : BaseButton
@ -313,58 +277,59 @@ func _ready() -> void:
import_sprites_dialog = find_node_by_name(root, "ImportSprites") import_sprites_dialog = find_node_by_name(root, "ImportSprites")
export_dialog = find_node_by_name(root, "ExportDialog") export_dialog = find_node_by_name(root, "ExportDialog")
preferences_dialog = find_node_by_name(root, "PreferencesDialog")
left_tool_options_container = find_node_by_name(root, "LeftToolOptions") tool_options_containers.append(find_node_by_name(root, "LeftToolOptions"))
right_tool_options_container = find_node_by_name(root, "RightToolOptions") tool_options_containers.append(find_node_by_name(root, "RightToolOptions"))
left_color_picker = find_node_by_name(root, "LeftColorPickerButton") color_pickers.append(find_node_by_name(root, "LeftColorPickerButton"))
right_color_picker = find_node_by_name(root, "RightColorPickerButton") color_pickers.append(find_node_by_name(root, "RightColorPickerButton"))
color_switch_button = find_node_by_name(root, "ColorSwitch") color_switch_button = find_node_by_name(root, "ColorSwitch")
left_brush_type_container = find_node_by_name(left_tool_options_container, "LeftBrushType") brush_type_containers.append(find_node_by_name(tool_options_containers[0], "LeftBrushType"))
right_brush_type_container = find_node_by_name(right_tool_options_container, "RightBrushType") brush_type_containers.append(find_node_by_name(tool_options_containers[1], "RightBrushType"))
left_brush_type_button = find_node_by_name(left_brush_type_container, "LeftBrushTypeButton") brush_type_buttons.append(find_node_by_name(brush_type_containers[0], "LeftBrushTypeButton"))
right_brush_type_button = find_node_by_name(right_brush_type_container, "RightBrushTypeButton") brush_type_buttons.append(find_node_by_name(brush_type_containers[1], "RightBrushTypeButton"))
brushes_popup = find_node_by_name(root, "BrushesPopup") brushes_popup = find_node_by_name(root, "BrushesPopup")
file_brush_container = find_node_by_name(brushes_popup, "FileBrushContainer") file_brush_container = find_node_by_name(brushes_popup, "FileBrushContainer")
project_brush_container = find_node_by_name(brushes_popup, "ProjectBrushContainer") project_brush_container = find_node_by_name(brushes_popup, "ProjectBrushContainer")
patterns_popup = find_node_by_name(root, "PatternsPopup") patterns_popup = find_node_by_name(root, "PatternsPopup")
left_brush_size_edit = find_node_by_name(root, "LeftBrushSizeEdit") brush_size_edits.append(find_node_by_name(root, "LeftBrushSizeEdit"))
left_brush_size_slider = find_node_by_name(root, "LeftBrushSizeSlider") brush_size_sliders.append(find_node_by_name(root, "LeftBrushSizeSlider"))
right_brush_size_edit = find_node_by_name(root, "RightBrushSizeEdit") brush_size_edits.append(find_node_by_name(root, "RightBrushSizeEdit"))
right_brush_size_slider = find_node_by_name(root, "RightBrushSizeSlider") brush_size_sliders.append(find_node_by_name(root, "RightBrushSizeSlider"))
left_pixel_perfect_container = find_node_by_name(root, "LeftBrushPixelPerfectMode") pixel_perfect_containers.append(find_node_by_name(root, "LeftBrushPixelPerfectMode"))
right_pixel_perfect_container = find_node_by_name(root, "RightBrushPixelPerfectMode") pixel_perfect_containers.append(find_node_by_name(root, "RightBrushPixelPerfectMode"))
left_color_interpolation_container = find_node_by_name(root, "LeftColorInterpolation") color_interpolation_containers.append(find_node_by_name(root, "LeftColorInterpolation"))
right_color_interpolation_container = find_node_by_name(root, "RightColorInterpolation") color_interpolation_containers.append(find_node_by_name(root, "RightColorInterpolation"))
left_interpolate_spinbox = find_node_by_name(root, "LeftInterpolateFactor") interpolate_spinboxes.append(find_node_by_name(root, "LeftInterpolateFactor"))
left_interpolate_slider = find_node_by_name(root, "LeftInterpolateSlider") interpolate_sliders.append(find_node_by_name(root, "LeftInterpolateSlider"))
right_interpolate_spinbox = find_node_by_name(root, "RightInterpolateFactor") interpolate_spinboxes.append(find_node_by_name(root, "RightInterpolateFactor"))
right_interpolate_slider = find_node_by_name(root, "RightInterpolateSlider") interpolate_sliders.append(find_node_by_name(root, "RightInterpolateSlider"))
left_fill_area_container = find_node_by_name(root, "LeftFillArea") fill_area_containers.append(find_node_by_name(root, "LeftFillArea"))
left_fill_pattern_container = find_node_by_name(root, "LeftFillPattern") fill_pattern_containers.append(find_node_by_name(root, "LeftFillPattern"))
right_fill_area_container = find_node_by_name(root, "RightFillArea") fill_area_containers.append(find_node_by_name(root, "RightFillArea"))
right_fill_pattern_container = find_node_by_name(root, "RightFillPattern") fill_pattern_containers.append(find_node_by_name(root, "RightFillPattern"))
left_ld_container = find_node_by_name(root, "LeftLDOptions") ld_containers.append(find_node_by_name(root, "LeftLDOptions"))
left_ld_amount_slider = find_node_by_name(root, "LeftLDAmountSlider") ld_amount_sliders.append(find_node_by_name(root, "LeftLDAmountSlider"))
left_ld_amount_spinbox = find_node_by_name(root, "LeftLDAmountSpinbox") ld_amount_spinboxes.append(find_node_by_name(root, "LeftLDAmountSpinbox"))
right_ld_container = find_node_by_name(root, "RightLDOptions") ld_containers.append(find_node_by_name(root, "RightLDOptions"))
right_ld_amount_slider = find_node_by_name(root, "RightLDAmountSlider") ld_amount_sliders.append(find_node_by_name(root, "RightLDAmountSlider"))
right_ld_amount_spinbox = find_node_by_name(root, "RightLDAmountSpinbox") ld_amount_spinboxes.append(find_node_by_name(root, "RightLDAmountSpinbox"))
left_colorpicker_container = find_node_by_name(root, "LeftColorPickerOptions") colorpicker_containers.append(find_node_by_name(root, "LeftColorPickerOptions"))
right_colorpicker_container = find_node_by_name(root, "RightColorPickerOptions") colorpicker_containers.append(find_node_by_name(root, "RightColorPickerOptions"))
left_zoom_container = find_node_by_name(root, "LeftZoomOptions") zoom_containers.append(find_node_by_name(root, "LeftZoomOptions"))
right_zoom_container = find_node_by_name(root, "RightZoomOptions") zoom_containers.append(find_node_by_name(root, "RightZoomOptions"))
left_mirror_container = find_node_by_name(root, "LeftMirrorButtons") mirror_containers.append(find_node_by_name(root, "LeftMirrorButtons"))
right_mirror_container = find_node_by_name(root, "RightMirrorButtons") mirror_containers.append(find_node_by_name(root, "RightMirrorButtons"))
animation_timeline = find_node_by_name(root, "AnimationTimeline") animation_timeline = find_node_by_name(root, "AnimationTimeline")
@ -372,7 +337,7 @@ func _ready() -> void:
frames_container = find_node_by_name(animation_timeline, "FramesContainer") frames_container = find_node_by_name(animation_timeline, "FramesContainer")
animation_timer = find_node_by_name(animation_timeline, "AnimationTimer") animation_timer = find_node_by_name(animation_timeline, "AnimationTimer")
frame_ids = find_node_by_name(animation_timeline, "FrameIDs") frame_ids = find_node_by_name(animation_timeline, "FrameIDs")
current_frame_label = find_node_by_name(control, "CurrentFrame") current_frame_mark_label = find_node_by_name(control, "CurrentFrameMark")
onion_skinning_button = find_node_by_name(animation_timeline, "OnionSkinning") onion_skinning_button = find_node_by_name(animation_timeline, "OnionSkinning")
loop_animation_button = find_node_by_name(animation_timeline, "LoopAnim") loop_animation_button = find_node_by_name(animation_timeline, "LoopAnim")
play_forward = find_node_by_name(animation_timeline, "PlayForward") play_forward = find_node_by_name(animation_timeline, "PlayForward")
@ -401,13 +366,11 @@ func _ready() -> void:
error_dialog = find_node_by_name(root, "ErrorDialog") error_dialog = find_node_by_name(root, "ErrorDialog")
# Store [Layer name (0), Layer visibility boolean (1), Layer lock boolean (2), Frame container (3), layers.append(Layer.new())
# will new cels be linked boolean (4), Array of linked cels (5)]
layers.append([tr("Layer") + " 0", true, false, HBoxContainer.new(), false, []])
# Thanks to https://godotengine.org/qa/17524/how-to-find-an-instanced-scene-by-its-name # Thanks to https://godotengine.org/qa/17524/how-to-find-an-instanced-scene-by-its-name
func find_node_by_name(root, node_name) -> Node: func find_node_by_name(root : Node, node_name : String) -> Node:
if root.get_name() == node_name: if root.get_name() == node_name:
return root return root
for child in root.get_children(): for child in root.get_children():
@ -467,6 +430,7 @@ func undo(_canvases : Array, layer_index : int = -1) -> void:
canvas_parent.move_child(_canvases[0], _canvases[0].frame) canvas_parent.move_child(_canvases[0], _canvases[0].frame)
elif action_name == "Change Frame Order": elif action_name == "Change Frame Order":
canvas_parent.move_child(_canvases[0], _canvases[0].frame) canvas_parent.move_child(_canvases[0], _canvases[0].frame)
canvas_parent.move_child(canvas_parent.get_node("TransparentChecker"), 0)
canvas.update() canvas.update()
if !project_has_changed: if !project_has_changed:
@ -498,6 +462,7 @@ func redo(_canvases : Array, layer_index : int = -1) -> void:
animation_timer.stop() animation_timer.stop()
elif action_name == "Change Frame Order": elif action_name == "Change Frame Order":
canvas_parent.move_child(_canvases[0], _canvases[0].frame) canvas_parent.move_child(_canvases[0], _canvases[0].frame)
canvas_parent.move_child(canvas_parent.get_node("TransparentChecker"), 0)
canvas.update() canvas.update()
if !project_has_changed: if !project_has_changed:
@ -523,7 +488,7 @@ func canvases_changed(value : Array) -> void:
frame_id.queue_free() frame_id.queue_free()
for i in range(layers.size() - 1, -1, -1): for i in range(layers.size() - 1, -1, -1):
frames_container.add_child(layers[i][3]) frames_container.add_child(layers[i].frame_container)
for j in range(canvases.size()): for j in range(canvases.size()):
var label := Label.new() var label := Label.new()
@ -536,9 +501,9 @@ func canvases_changed(value : Array) -> void:
var cel_button = load("res://src/UI/Timeline/CelButton.tscn").instance() var cel_button = load("res://src/UI/Timeline/CelButton.tscn").instance()
cel_button.frame = j cel_button.frame = j
cel_button.layer = i cel_button.layer = i
cel_button.get_child(0).texture = Global.canvases[j].layers[i][1] cel_button.get_child(0).texture = Global.canvases[j].layers[i].image_texture
layers[i][3].add_child(cel_button) layers[i].frame_container.add_child(cel_button)
# This is useful in case tagged frames get deleted DURING the animation is playing # This is useful in case tagged frames get deleted DURING the animation is playing
# otherwise, this code is useless in this context, since these values are being set # otherwise, this code is useless in this context, since these values are being set
@ -547,9 +512,9 @@ func canvases_changed(value : Array) -> void:
animation_timeline.last_frame = canvases.size() - 1 animation_timeline.last_frame = canvases.size() - 1
if play_only_tags: if play_only_tags:
for tag in animation_tags: for tag in animation_tags:
if current_frame + 1 >= tag[2] && current_frame + 1 <= tag[3]: if current_frame + 1 >= tag.from && current_frame + 1 <= tag.to:
animation_timeline.first_frame = tag[2] - 1 animation_timeline.first_frame = tag.from - 1
animation_timeline.last_frame = min(canvases.size() - 1, tag[3] - 1) animation_timeline.last_frame = min(canvases.size() - 1, tag.to - 1)
func clear_canvases() -> void: func clear_canvases() -> void:
@ -591,27 +556,27 @@ func layers_changed(value : Array) -> void:
for i in range(layers.size() - 1, -1, -1): for i in range(layers.size() - 1, -1, -1):
var layer_container = load("res://src/UI/Timeline/LayerButton.tscn").instance() var layer_container = load("res://src/UI/Timeline/LayerButton.tscn").instance()
layer_container.i = i layer_container.i = i
if !layers[i][0]: if layers[i].name == tr("Layer") + " 0":
layers[i][0] = tr("Layer") + " %s" % i layers[i].name = tr("Layer") + " %s" % i
layers_container.add_child(layer_container) layers_container.add_child(layer_container)
layer_container.label.text = layers[i][0] layer_container.label.text = layers[i].name
layer_container.line_edit.text = layers[i][0] layer_container.line_edit.text = layers[i].name
frames_container.add_child(layers[i][3]) frames_container.add_child(layers[i].frame_container)
for j in range(canvases.size()): for j in range(canvases.size()):
var cel_button = load("res://src/UI/Timeline/CelButton.tscn").instance() var cel_button = load("res://src/UI/Timeline/CelButton.tscn").instance()
cel_button.frame = j cel_button.frame = j
cel_button.layer = i cel_button.layer = i
cel_button.get_child(0).texture = Global.canvases[j].layers[i][1] cel_button.get_child(0).texture = Global.canvases[j].layers[i].image_texture
layers[i][3].add_child(cel_button) layers[i].frame_container.add_child(cel_button)
var layer_button = layers_container.get_child(layers_container.get_child_count() - 1 - current_layer) var layer_button = layers_container.get_child(layers_container.get_child_count() - 1 - current_layer)
layer_button.pressed = true layer_button.pressed = true
self.current_frame = current_frame # Call frame_changed to update UI self.current_frame = current_frame # Call frame_changed to update UI
if layers[current_layer][2]: if layers[current_layer].locked:
disable_button(remove_layer_button, true) disable_button(remove_layer_button, true)
if layers.size() == 1: if layers.size() == 1:
@ -619,13 +584,13 @@ func layers_changed(value : Array) -> void:
disable_button(move_up_layer_button, true) disable_button(move_up_layer_button, true)
disable_button(move_down_layer_button, true) disable_button(move_down_layer_button, true)
disable_button(merge_down_layer_button, true) disable_button(merge_down_layer_button, true)
elif !layers[current_layer][2]: elif !layers[current_layer].locked:
disable_button(remove_layer_button, false) disable_button(remove_layer_button, false)
func frame_changed(value : int) -> void: func frame_changed(value : int) -> void:
current_frame = value current_frame = value
current_frame_label.text = tr("Current frame:") + " %s/%s" % [str(current_frame + 1), canvases.size()] current_frame_mark_label.text = "%s/%s" % [str(current_frame + 1), canvases.size()]
var i := 0 var i := 0
for c in canvases: # De-select all the other canvases/frames for c in canvases: # De-select all the other canvases/frames
@ -633,24 +598,24 @@ func frame_changed(value : int) -> void:
c.is_making_line = false c.is_making_line = false
c.line_2d.set_point_position(1, c.line_2d.points[0]) c.line_2d.set_point_position(1, c.line_2d.points[0])
var text_color := Color.white var text_color := Color.white
if theme_type == "Caramel" || theme_type == "Light": if theme_type == Theme_Types.CARAMEL || theme_type == Theme_Types.LIGHT:
text_color = Color.black text_color = Color.black
frame_ids.get_child(i).add_color_override("font_color", text_color) frame_ids.get_child(i).add_color_override("font_color", text_color)
for layer in layers: for layer in layers:
if i < layer[3].get_child_count(): if i < layer.frame_container.get_child_count():
layer[3].get_child(i).pressed = false layer.frame_container.get_child(i).pressed = false
i += 1 i += 1
# Select the new canvas/frame # Select the new canvas/frame
canvas = canvases[current_frame] canvas = canvases[current_frame]
canvas.visible = true canvas.visible = true
frame_ids.get_child(current_frame).add_color_override("font_color", control.theme.get_color("Selected Color", "Label")) frame_ids.get_child(current_frame).add_color_override("font_color", control.theme.get_color("Selected Color", "Label"))
if current_frame < layers[current_layer][3].get_child_count(): if current_frame < layers[current_layer].frame_container.get_child_count():
layers[current_layer][3].get_child(current_frame).pressed = true layers[current_layer].frame_container.get_child(current_frame).pressed = true
if canvases.size() == 1: if canvases.size() == 1:
disable_button(remove_frame_button, true) disable_button(remove_frame_button, true)
elif !layers[current_layer][2]: elif !layers[current_layer].locked:
disable_button(remove_frame_button, false) disable_button(remove_frame_button, false)
Global.transparent_checker._ready() # To update the rect size Global.transparent_checker._ready() # To update the rect size
@ -658,8 +623,8 @@ func frame_changed(value : int) -> void:
func layer_changed(value : int) -> void: func layer_changed(value : int) -> void:
current_layer = value current_layer = value
layer_opacity_slider.value = canvas.layers[current_layer][2] * 100 layer_opacity_slider.value = canvas.layers[current_layer].opacity * 100
layer_opacity_spinbox.value = canvas.layers[current_layer][2] * 100 layer_opacity_spinbox.value = canvas.layers[current_layer].opacity * 100
for container in layers_container.get_children(): for container in layers_container.get_children():
container.pressed = false container.pressed = false
@ -681,7 +646,7 @@ func layer_changed(value : int) -> void:
disable_button(merge_down_layer_button, true) disable_button(merge_down_layer_button, true)
if current_layer < layers.size(): if current_layer < layers.size():
if layers[current_layer][2]: if layers[current_layer].locked:
disable_button(remove_layer_button, true) disable_button(remove_layer_button, true)
else: else:
if layers.size() > 1: if layers.size() > 1:
@ -711,8 +676,8 @@ func disable_button(button : BaseButton, disable : bool) -> void:
if button is Button: if button is Button:
var theme := theme_type var theme := theme_type
if theme == "Caramel": if theme == Theme_Types.CARAMEL:
theme = "Dark" theme = Theme_Types.DARK
for c in button.get_children(): for c in button.get_children():
if c is TextureRect: if c is TextureRect:
var normal_file_name = c.texture.resource_path.get_file().trim_suffix(".png").replace("_disabled", "") var normal_file_name = c.texture.resource_path.get_file().trim_suffix(".png").replace("_disabled", "")
@ -739,13 +704,13 @@ func animation_tags_changed(value : Array) -> void:
tag_container.add_child(tag_c) tag_container.add_child(tag_c)
var tag_position := tag_container.get_child_count() - 1 var tag_position := tag_container.get_child_count() - 1
tag_container.move_child(tag_c, tag_position) tag_container.move_child(tag_c, tag_position)
tag_c.get_node("Label").text = tag[0] tag_c.get_node("Label").text = tag.name
tag_c.get_node("Label").modulate = tag[1] tag_c.get_node("Label").modulate = tag.color
tag_c.get_node("Line2D").default_color = tag[1] tag_c.get_node("Line2D").default_color = tag.color
tag_c.rect_position.x = (tag[2] - 1) * 39 + tag[2] tag_c.rect_position.x = (tag.from - 1) * 39 + tag.from
var size : int = tag[3] - tag[2] var size : int = tag.to - tag.from
tag_c.rect_min_size.x = (size + 1) * 39 tag_c.rect_min_size.x = (size + 1) * 39
tag_c.get_node("Line2D").points[2] = Vector2(tag_c.rect_min_size.x, 0) tag_c.get_node("Line2D").points[2] = Vector2(tag_c.rect_min_size.x, 0)
tag_c.get_node("Line2D").points[3] = Vector2(tag_c.rect_min_size.x, 32) tag_c.get_node("Line2D").points[3] = Vector2(tag_c.rect_min_size.x, 32)
@ -757,9 +722,9 @@ func animation_tags_changed(value : Array) -> void:
animation_timeline.last_frame = canvases.size() - 1 animation_timeline.last_frame = canvases.size() - 1
if play_only_tags: if play_only_tags:
for tag in animation_tags: for tag in animation_tags:
if current_frame + 1 >= tag[2] && current_frame + 1 <= tag[3]: if current_frame + 1 >= tag.from && current_frame + 1 <= tag.to:
animation_timeline.first_frame = tag[2] - 1 animation_timeline.first_frame = tag.from - 1
animation_timeline.last_frame = min(canvases.size() - 1, tag[3] - 1) animation_timeline.last_frame = min(canvases.size() - 1, tag.to - 1)
func update_hint_tooltips() -> void: func update_hint_tooltips() -> void:
@ -862,8 +827,8 @@ func create_brush_button(brush_img : Image, brush_type := Brush_Types.CUSTOM, hi
func remove_brush_buttons() -> void: func remove_brush_buttons() -> void:
current_left_brush_type = Brush_Types.PIXEL current_brush_types[0] = Brush_Types.PIXEL
current_right_brush_type = Brush_Types.PIXEL current_brush_types[1] = Brush_Types.PIXEL
for child in project_brush_container.get_children(): for child in project_brush_container.get_children():
child.queue_free() child.queue_free()
@ -884,56 +849,32 @@ func redo_custom_brush(_brush_button : BaseButton = null) -> void:
project_brush_container.remove_child(_brush_button) project_brush_container.remove_child(_brush_button)
func update_left_custom_brush() -> void: func update_custom_brush(mouse_button : int) -> void:
if current_left_brush_type == Brush_Types.PIXEL: if current_brush_types[mouse_button] == Brush_Types.PIXEL:
var pixel := Image.new() var pixel := Image.new()
pixel = preload("res://assets/graphics/pixel_image.png") pixel = preload("res://assets/graphics/pixel_image.png")
left_brush_type_button.get_child(0).texture.create_from_image(pixel, 0) brush_type_buttons[mouse_button].get_child(0).texture.create_from_image(pixel, 0)
elif current_left_brush_type == Brush_Types.CIRCLE: elif current_brush_types[mouse_button] == Brush_Types.CIRCLE:
var pixel := Image.new() var pixel := Image.new()
pixel = preload("res://assets/graphics/circle_9x9.png") pixel = preload("res://assets/graphics/circle_9x9.png")
left_brush_type_button.get_child(0).texture.create_from_image(pixel, 0) brush_type_buttons[mouse_button].get_child(0).texture.create_from_image(pixel, 0)
left_circle_points = plot_circle(left_brush_size) left_circle_points = plot_circle(brush_sizes[0])
elif current_left_brush_type == Brush_Types.FILLED_CIRCLE: right_circle_points = plot_circle(brush_sizes[1])
elif current_brush_types[mouse_button] == Brush_Types.FILLED_CIRCLE:
var pixel := Image.new() var pixel := Image.new()
pixel = preload("res://assets/graphics/circle_filled_9x9.png") pixel = preload("res://assets/graphics/circle_filled_9x9.png")
left_brush_type_button.get_child(0).texture.create_from_image(pixel, 0) brush_type_buttons[mouse_button].get_child(0).texture.create_from_image(pixel, 0)
left_circle_points = plot_circle(left_brush_size) left_circle_points = plot_circle(brush_sizes[0])
right_circle_points = plot_circle(brush_sizes[1])
else: else:
var custom_brush := Image.new() var custom_brush := Image.new()
custom_brush.copy_from(custom_brushes[custom_left_brush_index]) custom_brush.copy_from(custom_brushes[custom_brush_indexes[mouse_button]])
var custom_brush_size = custom_brush.get_size() var custom_brush_size = custom_brush.get_size()
custom_brush.resize(custom_brush_size.x * left_brush_size, custom_brush_size.y * left_brush_size, Image.INTERPOLATE_NEAREST) custom_brush.resize(custom_brush_size.x * brush_sizes[mouse_button], custom_brush_size.y * brush_sizes[mouse_button], Image.INTERPOLATE_NEAREST)
custom_left_brush_image = blend_image_with_color(custom_brush, left_color_picker.color, left_interpolate_spinbox.value / 100) custom_brush_images[mouse_button] = blend_image_with_color(custom_brush, color_pickers[mouse_button].color, interpolate_spinboxes[mouse_button].value / 100)
custom_left_brush_texture.create_from_image(custom_left_brush_image, 0) custom_brush_textures[mouse_button].create_from_image(custom_brush_images[mouse_button], 0)
left_brush_type_button.get_child(0).texture = custom_left_brush_texture brush_type_buttons[mouse_button].get_child(0).texture = custom_brush_textures[mouse_button]
func update_right_custom_brush() -> void:
if current_right_brush_type == Brush_Types.PIXEL:
var pixel := Image.new()
pixel = preload("res://assets/graphics/pixel_image.png")
right_brush_type_button.get_child(0).texture.create_from_image(pixel, 0)
elif current_right_brush_type == Brush_Types.CIRCLE:
var pixel := Image.new()
pixel = preload("res://assets/graphics/circle_9x9.png")
right_brush_type_button.get_child(0).texture.create_from_image(pixel, 0)
right_circle_points = plot_circle(right_brush_size)
elif current_right_brush_type == Brush_Types.FILLED_CIRCLE:
var pixel := Image.new()
pixel = preload("res://assets/graphics/circle_filled_9x9.png")
right_brush_type_button.get_child(0).texture.create_from_image(pixel, 0)
right_circle_points = plot_circle(right_brush_size)
else:
var custom_brush := Image.new()
custom_brush.copy_from(custom_brushes[custom_right_brush_index])
var custom_brush_size = custom_brush.get_size()
custom_brush.resize(custom_brush_size.x * right_brush_size, custom_brush_size.y * right_brush_size, Image.INTERPOLATE_NEAREST)
custom_right_brush_image = blend_image_with_color(custom_brush, right_color_picker.color, right_interpolate_spinbox.value / 100)
custom_right_brush_texture.create_from_image(custom_right_brush_image, 0)
right_brush_type_button.get_child(0).texture = custom_right_brush_texture
func blend_image_with_color(image : Image, color : Color, interpolate_factor : float) -> Image: func blend_image_with_color(image : Image, color : Color, interpolate_factor : float) -> Image:
@ -979,212 +920,6 @@ func plot_circle(r : int) -> Array:
return circle_points return circle_points
func scale3X(sprite : Image, tol : float = 50) -> Image:
var scaled = Image.new()
scaled.create(sprite.get_width()*3, sprite.get_height()*3, false, Image.FORMAT_RGBA8)
scaled.lock()
sprite.lock()
var a : Color
var b : Color
var c : Color
var d : Color
var e : Color
var f : Color
var g : Color
var h : Color
var i : Color
for x in range(1,sprite.get_width()-1):
for y in range(1,sprite.get_height()-1):
var xs : float = 3*x
var ys : float = 3*y
a = sprite.get_pixel(x-1,y-1)
b = sprite.get_pixel(x,y-1)
c = sprite.get_pixel(x+1,y-1)
d = sprite.get_pixel(x-1,y)
e = sprite.get_pixel(x,y)
f = sprite.get_pixel(x+1,y)
g = sprite.get_pixel(x-1,y+1)
h = sprite.get_pixel(x,y+1)
i = sprite.get_pixel(x+1,y+1)
var db : bool = similarColors(d, b, tol)
var dh : bool = similarColors(d, h, tol)
var bf : bool = similarColors(f, b, tol)
var ec : bool = similarColors(e, c, tol)
var ea : bool = similarColors(e, a, tol)
var fh : bool = similarColors(f, h, tol)
var eg : bool = similarColors(e, g, tol)
var ei : bool = similarColors(e, i, tol)
scaled.set_pixel(xs-1, ys-1, d if (db and !dh and !bf) else e )
scaled.set_pixel(xs, ys-1, b if (db and !dh and !bf and !ec) or
(bf and !db and !fh and !ea) else e)
scaled.set_pixel(xs+1, ys-1, f if (bf and !db and !fh) else e)
scaled.set_pixel(xs-1, ys, d if (dh and !fh and !db and !ea) or
(db and !dh and !bf and !eg) else e)
scaled.set_pixel(xs, ys, e);
scaled.set_pixel(xs+1, ys, f if (bf and !db and !fh and !ei) or
(fh and !bf and !dh and !ec) else e)
scaled.set_pixel(xs-1, ys+1, d if (dh and !fh and !db) else e)
scaled.set_pixel(xs, ys+1, h if (fh and !bf and !dh and !eg) or
(dh and !fh and !db and !ei) else e)
scaled.set_pixel(xs+1, ys+1, f if (fh and !bf and !dh) else e)
scaled.unlock()
sprite.unlock()
return scaled
func rotxel(sprite : Image, angle : float) -> void:
# If angle is simple, then nn rotation is the best
if angle == 0 || angle == PI/2 || angle == PI || angle == 2*PI:
nn_rotate(sprite, angle)
return
var aux : Image = Image.new()
aux.copy_from(sprite)
var center : Vector2 = Vector2(sprite.get_width()/2, sprite.get_height()/2)
var ox : int
var oy : int
var p : Color
aux.lock()
sprite.lock()
for x in range(sprite.get_width()):
for y in range(sprite.get_height()):
var dx = 3*(x - center.x)
var dy = 3*(y - center.y)
var found_pixel : bool = false
for k in range(9):
var i = -1 + k % 3
var j = -1 + int(k / 3)
var dir = atan2(dy + j, dx + i)
var mag = sqrt(pow(dx + i, 2) + pow(dy + j, 2))
dir -= angle
ox = round(center.x*3 + 1 + mag*cos(dir))
oy = round(center.y*3 + 1 + mag*sin(dir))
if (sprite.get_width() % 2 != 0):
ox += 1
oy += 1
if (ox >= 0 && ox < sprite.get_width()*3
&& oy >= 0 && oy < sprite.get_height()*3):
found_pixel = true
break
if !found_pixel:
sprite.set_pixel(x, y, Color(0,0,0,0))
continue
var fil : int = oy % 3
var col : int = ox % 3
var index : int = col + 3*fil
ox = round((ox - 1)/3.0);
oy = round((oy - 1)/3.0);
var a : Color
var b : Color
var c : Color
var d : Color
var e : Color
var f : Color
var g : Color
var h : Color
var i : Color
if (ox == 0 || ox == sprite.get_width() - 1 ||
oy == 0 || oy == sprite.get_height() - 1):
p = aux.get_pixel(ox, oy)
else:
a = aux.get_pixel(ox-1,oy-1);
b = aux.get_pixel(ox,oy-1);
c = aux.get_pixel(ox+1,oy-1);
d = aux.get_pixel(ox-1,oy);
e = aux.get_pixel(ox,oy);
f = aux.get_pixel(ox+1,oy);
g = aux.get_pixel(ox-1,oy+1);
h = aux.get_pixel(ox,oy+1);
i = aux.get_pixel(ox+1,oy+1);
match(index):
0:
p = d if (similarColors(d,b) && !similarColors(d,h)
&& !similarColors(b,f)) else e;
1:
p = b if ((similarColors(d,b) && !similarColors(d,h) &&
!similarColors(b,f) && !similarColors(e,c)) ||
(similarColors(b,f) && !similarColors(d,b) &&
!similarColors(f,h) && !similarColors(e,a))) else e;
2:
p = f if (similarColors(b,f) && !similarColors(d,b) &&
!similarColors(f,h)) else e;
3:
p = d if ((similarColors(d,h) && !similarColors(f,h) &&
!similarColors(d,b) && !similarColors(e,a)) ||
(similarColors(d,b) && !similarColors(d,h) &&
!similarColors(b,f) && !similarColors(e,g))) else e;
4:
p = e
5:
p = f if((similarColors(b,f) && !similarColors(d,b) &&
!similarColors(f,h) && !similarColors(e,i))
|| (similarColors(f,h) && !similarColors(b,f) &&
!similarColors(d,h) && !similarColors(e,c))) else e;
6:
p = d if (similarColors(d,h) && !similarColors(f,h) &&
!similarColors(d,b)) else e;
7:
p = h if ((similarColors(f,h) && !similarColors(f,b) &&
!similarColors(d,h) && !similarColors(e,g))
|| (similarColors(d,h) && !similarColors(f,h) &&
!similarColors(d,b) && !similarColors(e,i))) else e;
8:
p = f if (similarColors(f,h) && !similarColors(f,b) &&
!similarColors(d,h)) else e;
sprite.set_pixel(x, y, p)
sprite.unlock()
aux.unlock()
func fake_rotsprite(sprite : Image, angle : float) -> void:
sprite.copy_from(scale3X(sprite))
nn_rotate(sprite,angle)
sprite.resize(sprite.get_width()/3,sprite.get_height()/3,0)
func nn_rotate(sprite : Image, angle : float) -> void:
var aux : Image = Image.new()
aux.copy_from(sprite)
sprite.lock()
aux.lock()
var ox: int
var oy: int
var center : Vector2 = Vector2(sprite.get_width()/2, sprite.get_height()/2)
for x in range(sprite.get_width()):
for y in range(sprite.get_height()):
ox = (x - center.x)*cos(angle) + (y - center.y)*sin(angle) + center.x
oy = -(x - center.x)*sin(angle) + (y - center.y)*cos(angle) + center.y
if ox >= 0 && ox < sprite.get_width() && oy >= 0 && oy < sprite.get_height():
sprite.set_pixel(x, y, aux.get_pixel(ox, oy))
else:
sprite.set_pixel(x, y, Color(0,0,0,0))
sprite.unlock()
aux.unlock()
func similarColors(c1 : Color, c2 : Color, tol : float = 100) -> bool:
var dist = colorDistance(c1, c2)
return dist <= tol
func colorDistance(c1 : Color, c2 : Color) -> float:
return sqrt(pow((c1.r - c2.r)*255, 2) + pow((c1.g - c2.g)*255, 2)
+ pow((c1.b - c2.b)*255, 2) + pow((c1.a - c2.a)*255, 2))
func _exit_tree() -> void: func _exit_tree() -> void:
config_cache.set_value("window", "screen", OS.current_screen) config_cache.set_value("window", "screen", OS.current_screen)
config_cache.set_value("window", "maximized", OS.window_maximized || OS.window_fullscreen) config_cache.set_value("window", "maximized", OS.window_maximized || OS.window_fullscreen)

View file

@ -249,19 +249,19 @@ func import_patterns(priority_ordered_search_path: Array) -> void:
if Global.patterns.size() > 0: if Global.patterns.size() > 0:
var image_size = Global.patterns[0].get_size() var image_size = Global.patterns[0].get_size()
Global.pattern_left_image = Global.patterns[0] Global.pattern_images[0] = Global.patterns[0]
var pattern_left_tex := ImageTexture.new() var pattern_left_tex := ImageTexture.new()
pattern_left_tex.create_from_image(Global.pattern_left_image, 0) pattern_left_tex.create_from_image(Global.pattern_images[0], 0)
Global.left_fill_pattern_container.get_child(0).get_child(0).texture = pattern_left_tex Global.fill_pattern_containers[0].get_child(0).get_child(0).texture = pattern_left_tex
Global.left_fill_pattern_container.get_child(2).get_child(1).max_value = image_size.x - 1 Global.fill_pattern_containers[0].get_child(2).get_child(1).max_value = image_size.x - 1
Global.left_fill_pattern_container.get_child(3).get_child(1).max_value = image_size.y - 1 Global.fill_pattern_containers[0].get_child(3).get_child(1).max_value = image_size.y - 1
Global.pattern_right_image = Global.patterns[0] Global.pattern_images[1] = Global.patterns[0]
var pattern_right_tex := ImageTexture.new() var pattern_right_tex := ImageTexture.new()
pattern_right_tex.create_from_image(Global.pattern_right_image, 0) pattern_right_tex.create_from_image(Global.pattern_images[1], 0)
Global.right_fill_pattern_container.get_child(0).get_child(0).texture = pattern_right_tex Global.fill_pattern_containers[1].get_child(0).get_child(0).texture = pattern_right_tex
Global.right_fill_pattern_container.get_child(2).get_child(1).max_value = image_size.x - 1 Global.fill_pattern_containers[1].get_child(2).get_child(1).max_value = image_size.x - 1
Global.right_fill_pattern_container.get_child(3).get_child(1).max_value = image_size.y - 1 Global.fill_pattern_containers[1].get_child(3).get_child(1).max_value = image_size.y - 1
func import_gpl(path : String) -> Palette: func import_gpl(path : String) -> Palette:

View file

@ -3,7 +3,6 @@ extends Node
var current_save_path := "" var current_save_path := ""
# Stores a filename of a backup file in user:// until user saves manually # Stores a filename of a backup file in user:// until user saves manually
var backup_save_path = "" var backup_save_path = ""
var default_autosave_interval := 5 # Minutes
onready var autosave_timer : Timer onready var autosave_timer : Timer
@ -14,8 +13,7 @@ func _ready() -> void:
autosave_timer.process_mode = Timer.TIMER_PROCESS_IDLE autosave_timer.process_mode = Timer.TIMER_PROCESS_IDLE
autosave_timer.connect("timeout", self, "_on_Autosave_timeout") autosave_timer.connect("timeout", self, "_on_Autosave_timeout")
add_child(autosave_timer) add_child(autosave_timer)
set_autosave_interval(default_autosave_interval) update_autosave()
toggle_autosave(true) # Gets started from preferences dialog
func open_pxo_file(path : String, untitled_backup : bool = false) -> void: func open_pxo_file(path : String, untitled_backup : bool = false) -> void:
@ -62,9 +60,8 @@ func open_pxo_file(path : String, untitled_backup : bool = false) -> void:
var layer_new_cels_linked := file.get_8() var layer_new_cels_linked := file.get_8()
linked_cels.append(file.get_var()) linked_cels.append(file.get_var())
# Store [Layer name (0), Layer visibility boolean (1), Layer lock boolean (2), Frame container (3), var l := Layer.new(layer_name, layer_visibility, layer_lock, HBoxContainer.new(), layer_new_cels_linked, [])
# will new cels be linked boolean (4), Array of linked cels (5)] Global.layers.append(l)
Global.layers.append([layer_name, layer_visibility, layer_lock, HBoxContainer.new(), layer_new_cels_linked, []])
global_layer_line = file.get_line() global_layer_line = file.get_line()
var frame_line := file.get_line() var frame_line := file.get_line()
@ -82,21 +79,18 @@ func open_pxo_file(path : String, untitled_backup : bool = false) -> void:
if file_major_version == 0 and file_minor_version < 7: if file_major_version == 0 and file_minor_version < 7:
var layer_name_old_version = file.get_line() var layer_name_old_version = file.get_line()
if frame == 0: if frame == 0:
# Store [Layer name (0), Layer visibility boolean (1), Layer lock boolean (2), Frame container (3), var l := Layer.new(layer_name_old_version)
# will new frames be linked boolean (4), Array of linked frames (5)] Global.layers.append(l)
Global.layers.append([layer_name_old_version, true, false, HBoxContainer.new(), false, []])
var layer_transparency := 1.0 var layer_transparency := 1.0
if file_major_version >= 0 and file_minor_version > 5: if file_major_version >= 0 and file_minor_version > 5:
layer_transparency = file.get_float() layer_transparency = file.get_float()
var image := Image.new() var image := Image.new()
image.create_from_data(width, height, false, Image.FORMAT_RGBA8, buffer) image.create_from_data(width, height, false, Image.FORMAT_RGBA8, buffer)
image.lock() image.lock()
var tex := ImageTexture.new() canvas.layers.append(Cel.new(image, layer_transparency))
tex.create_from_image(image, 0)
canvas.layers.append([image, tex, layer_transparency])
if file_major_version >= 0 and file_minor_version >= 7: if file_major_version >= 0 and file_minor_version >= 7:
if frame in linked_cels[layer_i]: if frame in linked_cels[layer_i]:
Global.layers[layer_i][5].append(canvas) Global.layers[layer_i].linked_cels.append(canvas)
layer_i += 1 layer_i += 1
layer_line = file.get_line() layer_line = file.get_line()
@ -128,19 +122,19 @@ func open_pxo_file(path : String, untitled_backup : bool = false) -> void:
Global.current_frame = frame - 1 Global.current_frame = frame - 1
Global.layers = Global.layers # Just to call Global.layers_changed Global.layers = Global.layers # Just to call Global.layers_changed
# Load tool options # Load tool options
Global.left_color_picker.color = file.get_var() Global.color_pickers[0].color = file.get_var()
Global.right_color_picker.color = file.get_var() Global.color_pickers[1].color = file.get_var()
Global.left_brush_size = file.get_8() Global.brush_sizes[0] = file.get_8()
Global.left_brush_size_edit.value = Global.left_brush_size Global.brush_size_edits[0].value = Global.brush_sizes[0]
Global.right_brush_size = file.get_8() Global.brush_sizes[1] = file.get_8()
Global.right_brush_size_edit.value = Global.right_brush_size Global.brush_size_edits[1].value = Global.brush_sizes[1]
if file_major_version == 0 and file_minor_version < 7: if file_major_version == 0 and file_minor_version < 7:
var left_palette = file.get_var() var left_palette = file.get_var()
var right_palette = file.get_var() var right_palette = file.get_var()
for color in left_palette: for color in left_palette:
Global.left_color_picker.get_picker().add_preset(color) Global.color_pickers[0].get_picker().add_preset(color)
for color in right_palette: for color in right_palette:
Global.right_color_picker.get_picker().add_preset(color) Global.color_pickers[1].get_picker().add_preset(color)
# Load custom brushes # Load custom brushes
Global.custom_brushes.resize(Global.brushes_from_files) Global.custom_brushes.resize(Global.brushes_from_files)
@ -164,7 +158,7 @@ func open_pxo_file(path : String, untitled_backup : bool = false) -> void:
var tag_color : Color = file.get_var() var tag_color : Color = file.get_var()
var tag_from := file.get_8() var tag_from := file.get_8()
var tag_to := file.get_8() var tag_to := file.get_8()
Global.animation_tags.append([tag_name, tag_color, tag_from, tag_to]) Global.animation_tags.append(AnimationTag.new(tag_name, tag_color, tag_from, tag_to))
Global.animation_tags = Global.animation_tags # To execute animation_tags_changed() Global.animation_tags = Global.animation_tags # To execute animation_tags_changed()
tag_line = file.get_line() tag_line = file.get_line()
@ -187,12 +181,12 @@ func save_pxo_file(path : String, autosave : bool) -> void:
# Store Global layers # Store Global layers
for layer in Global.layers: for layer in Global.layers:
file.store_line(".") file.store_line(".")
file.store_line(layer[0]) # Layer name file.store_line(layer.name)
file.store_8(layer[1]) # Layer visibility file.store_8(layer.visible)
file.store_8(layer[2]) # Layer lock file.store_8(layer.locked)
file.store_8(layer[4]) # Future cels linked file.store_8(layer.new_cels_linked)
var linked_cels := [] var linked_cels := []
for canvas in layer[5]: for canvas in layer.linked_cels:
linked_cels.append(canvas.frame) linked_cels.append(canvas.frame)
file.store_var(linked_cels) # Linked cels as cel numbers file.store_var(linked_cels) # Linked cels as cel numbers
@ -205,8 +199,8 @@ func save_pxo_file(path : String, autosave : bool) -> void:
file.store_16(canvas.size.y) file.store_16(canvas.size.y)
for layer in canvas.layers: # Store canvas layers for layer in canvas.layers: # Store canvas layers
file.store_line("-") file.store_line("-")
file.store_buffer(layer[0].get_data()) file.store_buffer(layer.image.get_data())
file.store_float(layer[2]) # Layer transparency file.store_float(layer.opacity)
file.store_line("END_LAYERS") file.store_line("END_LAYERS")
# Store guides # Store guides
@ -224,10 +218,10 @@ func save_pxo_file(path : String, autosave : bool) -> void:
file.store_line("END_FRAMES") file.store_line("END_FRAMES")
# Save tool options # Save tool options
var left_color : Color = Global.left_color_picker.color var left_color : Color = Global.color_pickers[0].color
var right_color : Color = Global.right_color_picker.color var right_color : Color = Global.color_pickers[1].color
var left_brush_size : int = Global.left_brush_size var left_brush_size : int = Global.brush_sizes[0]
var right_brush_size : int = Global.right_brush_size var right_brush_size : int = Global.brush_sizes[1]
file.store_var(left_color) file.store_var(left_color)
file.store_var(right_color) file.store_var(right_color)
file.store_8(left_brush_size) file.store_8(left_brush_size)
@ -245,10 +239,10 @@ func save_pxo_file(path : String, autosave : bool) -> void:
# Store animation tags # Store animation tags
for tag in Global.animation_tags: for tag in Global.animation_tags:
file.store_line(".T/") file.store_line(".T/")
file.store_line(tag[0]) # Tag name file.store_line(tag.name)
file.store_var(tag[1]) # Tag color file.store_var(tag.color)
file.store_8(tag[2]) # Tag "from", the first frame file.store_8(tag.from)
file.store_8(tag[3]) # Tag "to", the last frame file.store_8(tag.to)
file.store_line("END_FRAME_TAGS") file.store_line("END_FRAME_TAGS")
file.close() file.close()
@ -271,16 +265,11 @@ func save_pxo_file(path : String, autosave : bool) -> void:
Global.notification_label("File failed to save") Global.notification_label("File failed to save")
func toggle_autosave(enable : bool) -> void: func update_autosave() -> void:
if enable: autosave_timer.stop()
autosave_timer.wait_time = Global.autosave_interval * 60 # Interval parameter is in minutes, wait_time is seconds
if Global.enable_autosave:
autosave_timer.start() autosave_timer.start()
else:
autosave_timer.stop()
func set_autosave_interval(interval : float) -> void:
autosave_timer.wait_time = interval * 60 # Interval parameter is in minutes, wait_time is seconds
autosave_timer.start()
func _on_Autosave_timeout() -> void: func _on_Autosave_timeout() -> void:

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,15 @@
class_name AnimationTag extends Reference
# A class for frame tag properties
var name : String
var color : Color
var from : int
var to : int
func _init(_name, _color, _from, _to) -> void:
name = _name
color = _color
from = _from
to = _to

18
src/Classes/Cel.gd Normal file
View file

@ -0,0 +1,18 @@
class_name Cel extends Reference
# A class for cel properties
var image : Image setget image_changed
var image_texture : ImageTexture
var opacity : float
func _init(_image := Image.new(), _opacity := 1.0) -> void:
self.image = _image
opacity = _opacity
func image_changed(value : Image) -> void:
image = value
image_texture = ImageTexture.new()
image_texture.create_from_image(image, 0)

19
src/Classes/Layer.gd Normal file
View file

@ -0,0 +1,19 @@
class_name Layer extends Reference
# A class for layer properties
var name := ""
var visible := true
var locked := false
var frame_container : HBoxContainer
var new_cels_linked := false
var linked_cels := [] # Array of Canvases
func _init(_name := tr("Layer") + " 0", _visible := true, _locked := false, _frame_container := HBoxContainer.new(), _new_cels_linked := false, _linked_cels := []) -> void:
name = _name
visible = _visible
locked = _locked
frame_container = _frame_container
new_cels_linked = _new_cels_linked
linked_cels = _linked_cels

View file

@ -11,12 +11,64 @@ var is_quitting_on_save := false
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready() -> void: func _ready() -> void:
get_tree().set_auto_accept_quit(false) get_tree().set_auto_accept_quit(false)
setup_application_window_size()
setup_file_menu()
setup_edit_menu()
setup_view_menu()
setup_image_menu()
setup_help_menu()
Global.window_title = "(" + tr("untitled") + ") - Pixelorama " + Global.current_version
Global.layers[0].name = tr("Layer") + " 0"
Global.layers_container.get_child(0).label.text = Global.layers[0].name
Global.layers_container.get_child(0).line_edit.text = Global.layers[0].name
Import.import_brushes(Global.directory_module.get_brushes_search_path_in_order())
Import.import_patterns(Global.directory_module.get_patterns_search_path_in_order())
Global.color_pickers[0].get_picker().presets_visible = false
Global.color_pickers[1].get_picker().presets_visible = false
$QuitAndSaveDialog.add_button("Save & Exit", false, "Save")
$QuitAndSaveDialog.get_ok().text = "Exit without saving"
if not Global.config_cache.has_section_key("preferences", "startup"):
Global.config_cache.set_value("preferences", "startup", true)
show_splash_screen()
handle_backup()
# If the user wants to run Pixelorama with arguments in terminal mode
# or open files with Pixelorama directly, then handle that
if OS.get_cmdline_args():
handle_loading_files(OS.get_cmdline_args())
get_tree().connect("files_dropped", self, "_on_files_dropped")
func _input(event : InputEvent) -> void:
Global.left_cursor.position = get_global_mouse_position() + Vector2(-32, 32)
Global.left_cursor.texture = Global.left_cursor_tool_texture
Global.right_cursor.position = get_global_mouse_position() + Vector2(32, 32)
Global.right_cursor.texture = Global.right_cursor_tool_texture
if event is InputEventKey and (event.scancode == KEY_ENTER or event.scancode == KEY_KP_ENTER):
if get_focus_owner() is LineEdit:
get_focus_owner().release_focus()
if event.is_action_pressed("toggle_fullscreen"):
OS.window_fullscreen = !OS.window_fullscreen
if event.is_action_pressed("redo_secondary"): # Shift + Ctrl + Z
redone = true
Global.undo_redo.redo()
redone = false
func setup_application_window_size() -> void:
# Set a minimum window size to prevent UI elements from collapsing on each other. # Set a minimum window size to prevent UI elements from collapsing on each other.
OS.min_window_size = Vector2(1024, 576) OS.min_window_size = Vector2(1024, 576)
Global.loaded_locales = TranslationServer.get_loaded_locales()
# Make sure locales are always sorted, in the same order
Global.loaded_locales.sort()
# Restore the window position/size if values are present in the configuration cache # Restore the window position/size if values are present in the configuration cache
if Global.config_cache.has_section_key("window", "screen"): if Global.config_cache.has_section_key("window", "screen"):
@ -30,6 +82,8 @@ func _ready() -> void:
if Global.config_cache.has_section_key("window", "size"): if Global.config_cache.has_section_key("window", "size"):
OS.window_size = Global.config_cache.get_value("window", "size") OS.window_size = Global.config_cache.get_value("window", "size")
func setup_file_menu() -> void:
var file_menu_items := { var file_menu_items := {
"New..." : InputMap.get_action_list("new_file")[0].get_scancode_with_modifiers(), "New..." : InputMap.get_action_list("new_file")[0].get_scancode_with_modifiers(),
"Open..." : InputMap.get_action_list("open_file")[0].get_scancode_with_modifiers(), "Open..." : InputMap.get_action_list("open_file")[0].get_scancode_with_modifiers(),
@ -41,12 +95,34 @@ func _ready() -> void:
"Export as..." : InputMap.get_action_list("export_file_as")[0].get_scancode_with_modifiers(), "Export as..." : InputMap.get_action_list("export_file_as")[0].get_scancode_with_modifiers(),
"Quit" : InputMap.get_action_list("quit")[0].get_scancode_with_modifiers(), "Quit" : InputMap.get_action_list("quit")[0].get_scancode_with_modifiers(),
} }
file_menu = Global.file_menu.get_popup()
var i := 0
for item in file_menu_items.keys():
file_menu.add_item(item, i, file_menu_items[item])
i += 1
file_menu.connect("id_pressed", self, "file_menu_id_pressed")
func setup_edit_menu() -> void:
var edit_menu_items := { var edit_menu_items := {
"Undo" : InputMap.get_action_list("undo")[0].get_scancode_with_modifiers(), "Undo" : InputMap.get_action_list("undo")[0].get_scancode_with_modifiers(),
"Redo" : InputMap.get_action_list("redo")[0].get_scancode_with_modifiers(), "Redo" : InputMap.get_action_list("redo")[0].get_scancode_with_modifiers(),
"Clear Selection" : 0, "Clear Selection" : 0,
"Preferences" : 0 "Preferences" : 0
} }
var edit_menu : PopupMenu = Global.edit_menu.get_popup()
var i := 0
for item in edit_menu_items.keys():
edit_menu.add_item(item, i, edit_menu_items[item])
i += 1
edit_menu.connect("id_pressed", self, "edit_menu_id_pressed")
func setup_view_menu() -> void:
var view_menu_items := { var view_menu_items := {
"Tile Mode" : InputMap.get_action_list("tile_mode")[0].get_scancode_with_modifiers(), "Tile Mode" : InputMap.get_action_list("tile_mode")[0].get_scancode_with_modifiers(),
"Show Grid" : InputMap.get_action_list("show_grid")[0].get_scancode_with_modifiers(), "Show Grid" : InputMap.get_action_list("show_grid")[0].get_scancode_with_modifiers(),
@ -54,6 +130,21 @@ func _ready() -> void:
"Show Guides" : InputMap.get_action_list("show_guides")[0].get_scancode_with_modifiers(), "Show Guides" : InputMap.get_action_list("show_guides")[0].get_scancode_with_modifiers(),
"Show Animation Timeline" : 0 "Show Animation Timeline" : 0
} }
view_menu = Global.view_menu.get_popup()
var i := 0
for item in view_menu_items.keys():
view_menu.add_check_item(item, i, view_menu_items[item])
i += 1
view_menu.set_item_checked(2, true) # Show Rulers
view_menu.set_item_checked(3, true) # Show Guides
view_menu.set_item_checked(4, true) # Show Animation Timeline
view_menu.hide_on_checkable_item_selection = false
view_menu.connect("id_pressed", self, "view_menu_id_pressed")
func setup_image_menu() -> void:
var image_menu_items := { var image_menu_items := {
"Scale Image" : 0, "Scale Image" : 0,
"Crop Image" : 0, "Crop Image" : 0,
@ -65,6 +156,19 @@ func _ready() -> void:
"Outline" : 0, "Outline" : 0,
"Adjust Hue/Saturation/Value" : 0 "Adjust Hue/Saturation/Value" : 0
} }
var image_menu : PopupMenu = Global.image_menu.get_popup()
var i := 0
for item in image_menu_items.keys():
image_menu.add_item(item, i, image_menu_items[item])
if i == 4:
image_menu.add_separator()
i += 1
image_menu.connect("id_pressed", self, "image_menu_id_pressed")
func setup_help_menu() -> void:
var help_menu_items := { var help_menu_items := {
"View Splash Screen" : 0, "View Splash Screen" : 0,
"Online Docs" : 0, "Online Docs" : 0,
@ -72,86 +176,17 @@ func _ready() -> void:
"Changelog" : 0, "Changelog" : 0,
"About Pixelorama" : 0 "About Pixelorama" : 0
} }
# Load language
if Global.config_cache.has_section_key("preferences", "locale"):
var saved_locale : String = Global.config_cache.get_value("preferences", "locale")
TranslationServer.set_locale(saved_locale)
# Set the language option menu's default selected option to the loaded locale
var locale_index: int = Global.loaded_locales.find(saved_locale)
$PreferencesDialog.languages.get_child(0).pressed = false # Unset System Language option in preferences
$PreferencesDialog.languages.get_child(locale_index + 1).pressed = true
else: # If the user doesn't have a language preference, set it to their OS' locale
TranslationServer.set_locale(OS.get_locale())
if "zh" in TranslationServer.get_locale():
theme.default_font = preload("res://assets/fonts/CJK/NotoSansCJKtc-Regular.tres")
else:
theme.default_font = preload("res://assets/fonts/Roboto-Regular.tres")
file_menu = Global.file_menu.get_popup()
var edit_menu : PopupMenu = Global.edit_menu.get_popup()
view_menu = Global.view_menu.get_popup()
var image_menu : PopupMenu = Global.image_menu.get_popup()
var help_menu : PopupMenu = Global.help_menu.get_popup() var help_menu : PopupMenu = Global.help_menu.get_popup()
var i = 0 var i := 0
for item in file_menu_items.keys():
file_menu.add_item(item, i, file_menu_items[item])
i += 1
i = 0
for item in edit_menu_items.keys():
edit_menu.add_item(item, i, edit_menu_items[item])
i += 1
i = 0
for item in view_menu_items.keys():
view_menu.add_check_item(item, i, view_menu_items[item])
i += 1
view_menu.set_item_checked(2, true) # Show Rulers
view_menu.set_item_checked(3, true) # Show Guides
view_menu.set_item_checked(4, true) # Show Animation Timeline
view_menu.hide_on_checkable_item_selection = false
i = 0
for item in image_menu_items.keys():
image_menu.add_item(item, i, image_menu_items[item])
if i == 4:
image_menu.add_separator()
i += 1
i = 0
for item in help_menu_items.keys(): for item in help_menu_items.keys():
help_menu.add_item(item, i, help_menu_items[item]) help_menu.add_item(item, i, help_menu_items[item])
i += 1 i += 1
file_menu.connect("id_pressed", self, "file_menu_id_pressed")
edit_menu.connect("id_pressed", self, "edit_menu_id_pressed")
view_menu.connect("id_pressed", self, "view_menu_id_pressed")
image_menu.connect("id_pressed", self, "image_menu_id_pressed")
help_menu.connect("id_pressed", self, "help_menu_id_pressed") help_menu.connect("id_pressed", self, "help_menu_id_pressed")
# Checks to see if it's 3.1.x
if Engine.get_version_info().major == 3 and Engine.get_version_info().minor < 2:
Global.left_color_picker.get_picker().move_child(Global.left_color_picker.get_picker().get_child(0), 1)
Global.right_color_picker.get_picker().move_child(Global.right_color_picker.get_picker().get_child(0), 1)
Global.window_title = "(" + tr("untitled") + ") - Pixelorama " + Global.current_version
Global.layers[0][0] = tr("Layer") + " 0"
Global.layers_container.get_child(0).label.text = Global.layers[0][0]
Global.layers_container.get_child(0).line_edit.text = Global.layers[0][0]
Import.import_brushes(Global.directory_module.get_brushes_search_path_in_order())
Import.import_patterns(Global.directory_module.get_patterns_search_path_in_order())
Global.left_color_picker.get_picker().presets_visible = false
Global.right_color_picker.get_picker().presets_visible = false
$QuitAndSaveDialog.add_button("Save & Exit", false, "Save")
$QuitAndSaveDialog.get_ok().text = "Exit without saving"
if not Global.config_cache.has_section_key("preferences", "startup"):
Global.config_cache.set_value("preferences", "startup", true)
func show_splash_screen() -> void:
# Wait for the window to adjust itself, so the popup is correctly centered # Wait for the window to adjust itself, so the popup is correctly centered
yield(get_tree().create_timer(0.01), "timeout") yield(get_tree().create_timer(0.01), "timeout")
if Global.config_cache.get_value("preferences", "startup"): if Global.config_cache.get_value("preferences", "startup"):
@ -160,6 +195,8 @@ func _ready() -> void:
else: else:
Global.can_draw = true Global.can_draw = true
func handle_backup() -> void:
# If backup file exists then Pixelorama was not closed properly (probably crashed) - reopen backup # If backup file exists then Pixelorama was not closed properly (probably crashed) - reopen backup
$BackupConfirmation.get_cancel().text = tr("Delete") $BackupConfirmation.get_cancel().text = tr("Delete")
if Global.config_cache.has_section("backups"): if Global.config_cache.has_section("backups"):
@ -183,34 +220,16 @@ func _ready() -> void:
if Global.open_last_project: if Global.open_last_project:
load_last_project() load_last_project()
if OS.get_cmdline_args():
for arg in OS.get_cmdline_args():
if arg.get_extension().to_lower() == "pxo":
_on_OpenSprite_file_selected(arg)
else:
if arg == OS.get_cmdline_args()[0]:
$ImportSprites.new_frame = false
$ImportSprites._on_ImportSprites_files_selected([arg])
$ImportSprites.new_frame = true
func handle_loading_files(files : PoolStringArray) -> void:
func _input(event : InputEvent) -> void: for file in files:
Global.left_cursor.position = get_global_mouse_position() + Vector2(-32, 32) if file.get_extension().to_lower() == "pxo":
Global.left_cursor.texture = Global.left_cursor_tool_texture _on_OpenSprite_file_selected(file)
Global.right_cursor.position = get_global_mouse_position() + Vector2(32, 32) else:
Global.right_cursor.texture = Global.right_cursor_tool_texture if file == files[0]:
$ImportSprites.new_frame = false
if event is InputEventKey and (event.scancode == KEY_ENTER or event.scancode == KEY_KP_ENTER): $ImportSprites._on_ImportSprites_files_selected([file])
if get_focus_owner() is LineEdit: $ImportSprites.new_frame = true
get_focus_owner().release_focus()
if event.is_action_pressed("toggle_fullscreen"):
OS.window_fullscreen = !OS.window_fullscreen
if event.is_action_pressed("redo_secondary"): # Shift + Ctrl + Z
redone = true
Global.undo_redo.redo()
redone = false
func _notification(what : int) -> void: func _notification(what : int) -> void:
@ -218,53 +237,85 @@ func _notification(what : int) -> void:
show_quit_dialog() show_quit_dialog()
func _on_files_dropped(_files : PoolStringArray, _screen : int) -> void:
handle_loading_files(_files)
func on_new_project_file_menu_option_pressed(id : int) -> void:
if Global.project_has_changed:
unsaved_canvas_state = id
$UnsavedCanvasDialog.popup_centered()
else:
$CreateNewImage.popup_centered()
Global.dialog_open(true)
func open_project_file() -> void:
$OpenSprite.popup_centered()
Global.dialog_open(true)
opensprite_file_selected = false
func on_open_last_project_file_menu_option_pressed(id : int) -> void:
# Check if last project path is set and if yes then open
if Global.config_cache.has_section_key("preferences", "last_project_path"):
if Global.project_has_changed:
unsaved_canvas_state = id
$UnsavedCanvasDialog.popup_centered()
Global.dialog_open(true)
else:
load_last_project()
else: # if not then warn user that he didn't edit any project yet
Global.error_dialog.set_text("You haven't saved or opened any project in Pixelorama yet!")
Global.error_dialog.popup_centered()
Global.dialog_open(true)
func save_project_file() -> void:
is_quitting_on_save = false
if OpenSave.current_save_path == "":
$SaveSprite.popup_centered()
Global.dialog_open(true)
else:
_on_SaveSprite_file_selected(OpenSave.current_save_path)
func save_project_file_as() -> void:
is_quitting_on_save = false
$SaveSprite.popup_centered()
Global.dialog_open(true)
func import_file() -> void:
$ImportSprites.popup_centered()
Global.dialog_open(true)
opensprite_file_selected = false
func export_file() -> void:
if $ExportDialog.was_exported == false:
$ExportDialog.popup_centered()
Global.dialog_open(true)
else:
$ExportDialog.external_export()
func file_menu_id_pressed(id : int) -> void: func file_menu_id_pressed(id : int) -> void:
match id: match id:
0: # New 0: # New
if Global.project_has_changed: on_new_project_file_menu_option_pressed(id)
unsaved_canvas_state = id
$UnsavedCanvasDialog.popup_centered()
else:
$CreateNewImage.popup_centered()
Global.dialog_open(true)
1: # Open 1: # Open
$OpenSprite.popup_centered() open_project_file()
Global.dialog_open(true)
opensprite_file_selected = false
2: # Open last project 2: # Open last project
# Check if last project path is set and if yes then open on_open_last_project_file_menu_option_pressed(id)
if Global.config_cache.has_section_key("preferences", "last_project_path"):
if Global.project_has_changed:
unsaved_canvas_state = id
$UnsavedCanvasDialog.popup_centered()
Global.dialog_open(true)
else:
load_last_project()
else: # if not then warn user that he didn't edit any project yet
Global.error_dialog.set_text("You haven't saved or opened any project in Pixelorama yet!")
Global.error_dialog.popup_centered()
Global.dialog_open(true)
3: # Save 3: # Save
is_quitting_on_save = false save_project_file()
if OpenSave.current_save_path == "":
$SaveSprite.popup_centered()
Global.dialog_open(true)
else:
_on_SaveSprite_file_selected(OpenSave.current_save_path)
4: # Save as 4: # Save as
is_quitting_on_save = false save_project_file_as()
$SaveSprite.popup_centered()
Global.dialog_open(true)
5: # Import 5: # Import
$ImportSprites.popup_centered() import_file()
Global.dialog_open(true)
opensprite_file_selected = false
6: # Export 6: # Export
if $ExportDialog.was_exported == false: export_file()
$ExportDialog.popup_centered()
Global.dialog_open(true)
else:
$ExportDialog.external_export()
7: # Export as 7: # Export as
$ExportDialog.popup_centered() $ExportDialog.popup_centered()
Global.dialog_open(true) Global.dialog_open(true)
@ -293,134 +344,190 @@ func edit_menu_id_pressed(id : int) -> void:
Global.dialog_open(true) Global.dialog_open(true)
func toggle_tile_mode() -> void:
Global.tile_mode = !Global.tile_mode
view_menu.set_item_checked(0, Global.tile_mode)
func toggle_show_grid() -> void:
Global.draw_grid = !Global.draw_grid
view_menu.set_item_checked(1, Global.draw_grid)
func toggle_show_rulers() -> void:
Global.show_rulers = !Global.show_rulers
view_menu.set_item_checked(2, Global.show_rulers)
Global.horizontal_ruler.visible = Global.show_rulers
Global.vertical_ruler.visible = Global.show_rulers
func toggle_show_guides() -> void:
Global.show_guides = !Global.show_guides
view_menu.set_item_checked(3, Global.show_guides)
for canvas in Global.canvases:
for guide in canvas.get_children():
if guide is Guide:
guide.visible = Global.show_guides
func toggle_show_anim_timeline() -> void:
Global.show_animation_timeline = !Global.show_animation_timeline
view_menu.set_item_checked(4, Global.show_animation_timeline)
Global.animation_timeline.visible = Global.show_animation_timeline
func view_menu_id_pressed(id : int) -> void: func view_menu_id_pressed(id : int) -> void:
match id: match id:
0: # Tile mode 0: # Tile mode
Global.tile_mode = !Global.tile_mode toggle_tile_mode()
view_menu.set_item_checked(0, Global.tile_mode)
1: # Show grid 1: # Show grid
Global.draw_grid = !Global.draw_grid toggle_show_grid()
view_menu.set_item_checked(1, Global.draw_grid)
2: # Show rulers 2: # Show rulers
Global.show_rulers = !Global.show_rulers toggle_show_rulers()
view_menu.set_item_checked(2, Global.show_rulers)
Global.horizontal_ruler.visible = Global.show_rulers
Global.vertical_ruler.visible = Global.show_rulers
3: # Show guides 3: # Show guides
Global.show_guides = !Global.show_guides toggle_show_guides()
view_menu.set_item_checked(3, Global.show_guides)
for canvas in Global.canvases:
for guide in canvas.get_children():
if guide is Guide:
guide.visible = Global.show_guides
4: # Show animation timeline 4: # Show animation timeline
Global.show_animation_timeline = !Global.show_animation_timeline toggle_show_anim_timeline()
view_menu.set_item_checked(4, Global.show_animation_timeline)
Global.animation_timeline.visible = Global.show_animation_timeline
Global.canvas.update() Global.canvas.update()
func show_scale_image_popup() -> void:
$ScaleImage.popup_centered()
Global.dialog_open(true)
func crop_image() -> void:
# Use first cel as a starting rectangle
var used_rect : Rect2 = Global.canvases[0].layers[0].image.get_used_rect()
for c in Global.canvases:
# However, if first cel is empty, loop through all cels until we find one that isn't
for layer in c.layers:
if used_rect != Rect2(0, 0, 0, 0):
break
else:
if layer[0].get_used_rect() != Rect2(0, 0, 0, 0):
used_rect = layer.image.get_used_rect()
# Merge all layers with content
for layer in c.layers:
if layer.image.get_used_rect() != Rect2(0, 0, 0, 0):
used_rect = used_rect.merge(layer.image.get_used_rect())
# If no layer has any content, just return
if used_rect == Rect2(0, 0, 0, 0):
return
var width := used_rect.size.x
var height := used_rect.size.y
Global.undos += 1
Global.undo_redo.create_action("Scale")
for c in Global.canvases:
Global.undo_redo.add_do_property(c, "size", Vector2(width, height).floor())
# Loop through all the layers to crop them
for j in range(Global.canvas.layers.size() - 1, -1, -1):
var sprite : Image = c.layers[j].image.get_rect(used_rect)
Global.undo_redo.add_do_property(c.layers[j].image, "data", sprite.data)
Global.undo_redo.add_undo_property(c.layers[j].image, "data", c.layers[j].image.data)
Global.undo_redo.add_undo_property(c, "size", c.size)
Global.undo_redo.add_undo_method(Global, "undo", Global.canvases)
Global.undo_redo.add_do_method(Global, "redo", Global.canvases)
Global.undo_redo.commit_action()
func flip_image_horizontal() -> void:
var canvas : Canvas = Global.canvas
canvas.handle_undo("Draw")
canvas.layers[Global.current_layer].image.unlock()
canvas.layers[Global.current_layer].image.flip_x()
canvas.layers[Global.current_layer].image.lock()
canvas.handle_redo("Draw")
func flip_image_vertical() -> void:
var canvas : Canvas = Global.canvas
canvas.handle_undo("Draw")
canvas.layers[Global.current_layer].image.unlock()
canvas.layers[Global.current_layer].image.flip_y()
canvas.layers[Global.current_layer].image.lock()
canvas.handle_redo("Draw")
func show_rotate_image_popup() -> void:
var image : Image = Global.canvas.layers[Global.current_layer].image
$RotateImage.set_sprite(image)
$RotateImage.popup_centered()
Global.dialog_open(true)
func invert_image_colors() -> void:
var image : Image = Global.canvas.layers[Global.current_layer].image
Global.canvas.handle_undo("Draw")
for xx in image.get_size().x:
for yy in image.get_size().y:
var px_color = image.get_pixel(xx, yy).inverted()
if px_color.a == 0:
continue
image.set_pixel(xx, yy, px_color)
Global.canvas.handle_redo("Draw")
func desaturate_image() -> void:
var image : Image = Global.canvas.layers[Global.current_layer].image
Global.canvas.handle_undo("Draw")
for xx in image.get_size().x:
for yy in image.get_size().y:
var px_color = image.get_pixel(xx, yy)
if px_color.a == 0:
continue
var gray = image.get_pixel(xx, yy).v
px_color = Color(gray, gray, gray, px_color.a)
image.set_pixel(xx, yy, px_color)
Global.canvas.handle_redo("Draw")
func show_add_outline_popup() -> void:
$OutlineDialog.popup_centered()
Global.dialog_open(true)
func show_hsv_configuration_popup() -> void:
$HSVDialog.popup_centered()
Global.dialog_open(true)
func image_menu_id_pressed(id : int) -> void: func image_menu_id_pressed(id : int) -> void:
if Global.layers[Global.current_layer][2]: # No changes if the layer is locked if Global.layers[Global.current_layer].locked: # No changes if the layer is locked
return return
match id: match id:
0: # Scale Image 0: # Scale Image
$ScaleImage.popup_centered() show_scale_image_popup()
Global.dialog_open(true)
1: # Crop Image 1: # Crop Image
# Use first cel as a starting rectangle crop_image()
var used_rect : Rect2 = Global.canvases[0].layers[0][0].get_used_rect()
for c in Global.canvases:
# However, if first cel is empty, loop through all cels until we find one that isn't
for layer in c.layers:
if used_rect != Rect2(0, 0, 0, 0):
break
else:
if layer[0].get_used_rect() != Rect2(0, 0, 0, 0):
used_rect = layer[0].get_used_rect()
# Merge all layers with content
for layer in c.layers:
if layer[0].get_used_rect() != Rect2(0, 0, 0, 0):
used_rect = used_rect.merge(layer[0].get_used_rect())
# If no layer has any content, just return
if used_rect == Rect2(0, 0, 0, 0):
return
var width := used_rect.size.x
var height := used_rect.size.y
Global.undos += 1
Global.undo_redo.create_action("Scale")
for c in Global.canvases:
Global.undo_redo.add_do_property(c, "size", Vector2(width, height).floor())
# Loop through all the layers to crop them
for j in range(Global.canvas.layers.size() - 1, -1, -1):
var sprite : Image = c.layers[j][0].get_rect(used_rect)
Global.undo_redo.add_do_property(c.layers[j][0], "data", sprite.data)
Global.undo_redo.add_undo_property(c.layers[j][0], "data", c.layers[j][0].data)
Global.undo_redo.add_undo_property(c, "size", c.size)
Global.undo_redo.add_undo_method(Global, "undo", Global.canvases)
Global.undo_redo.add_do_method(Global, "redo", Global.canvases)
Global.undo_redo.commit_action()
2: # Flip Horizontal 2: # Flip Horizontal
var canvas : Canvas = Global.canvas flip_image_horizontal()
canvas.handle_undo("Draw")
canvas.layers[Global.current_layer][0].unlock()
canvas.layers[Global.current_layer][0].flip_x()
canvas.layers[Global.current_layer][0].lock()
canvas.handle_redo("Draw")
3: # Flip Vertical 3: # Flip Vertical
var canvas : Canvas = Global.canvas flip_image_vertical()
canvas.handle_undo("Draw")
canvas.layers[Global.current_layer][0].unlock()
canvas.layers[Global.current_layer][0].flip_y()
canvas.layers[Global.current_layer][0].lock()
canvas.handle_redo("Draw")
4: # Rotate 4: # Rotate
var image : Image = Global.canvas.layers[Global.current_layer][0] show_rotate_image_popup()
$RotateImage.set_sprite(image)
$RotateImage.popup_centered()
Global.dialog_open(true)
5: # Invert Colors 5: # Invert Colors
var image : Image = Global.canvas.layers[Global.current_layer][0] invert_image_colors()
Global.canvas.handle_undo("Draw")
for xx in image.get_size().x:
for yy in image.get_size().y:
var px_color = image.get_pixel(xx, yy).inverted()
if px_color.a == 0:
continue
image.set_pixel(xx, yy, px_color)
Global.canvas.handle_redo("Draw")
6: # Desaturation 6: # Desaturation
var image : Image = Global.canvas.layers[Global.current_layer][0] desaturate_image()
Global.canvas.handle_undo("Draw")
for xx in image.get_size().x:
for yy in image.get_size().y:
var px_color = image.get_pixel(xx, yy)
if px_color.a == 0:
continue
var gray = image.get_pixel(xx, yy).v
px_color = Color(gray, gray, gray, px_color.a)
image.set_pixel(xx, yy, px_color)
Global.canvas.handle_redo("Draw")
7: # Outline 7: # Outline
$OutlineDialog.popup_centered() show_add_outline_popup()
Global.dialog_open(true)
8: # HSV 8: # HSV
$HSVDialog.popup_centered() show_hsv_configuration_popup()
Global.dialog_open(true)
func help_menu_id_pressed(id : int) -> void: func help_menu_id_pressed(id : int) -> void:

View file

@ -12,7 +12,7 @@
[ext_resource path="res://src/UI/Dialogs/CreateNewImage.tscn" type="PackedScene" id=28] [ext_resource path="res://src/UI/Dialogs/CreateNewImage.tscn" type="PackedScene" id=28]
[ext_resource path="res://src/UI/Dialogs/ImportSprites.tscn" type="PackedScene" id=29] [ext_resource path="res://src/UI/Dialogs/ImportSprites.tscn" type="PackedScene" id=29]
[ext_resource path="res://src/UI/Dialogs/ScaleImage.tscn" type="PackedScene" id=31] [ext_resource path="res://src/UI/Dialogs/ScaleImage.tscn" type="PackedScene" id=31]
[ext_resource path="res://src/UI/Dialogs/PreferencesDialog.tscn" type="PackedScene" id=32] [ext_resource path="res://src/Preferences/PreferencesDialog.tscn" type="PackedScene" id=32]
[ext_resource path="res://src/UI/Dialogs/OutlineDialog.tscn" type="PackedScene" id=33] [ext_resource path="res://src/UI/Dialogs/OutlineDialog.tscn" type="PackedScene" id=33]
[ext_resource path="res://src/UI/Dialogs/AboutDialog.tscn" type="PackedScene" id=34] [ext_resource path="res://src/UI/Dialogs/AboutDialog.tscn" type="PackedScene" id=34]
[ext_resource path="res://src/UI/Dialogs/RotateImage.tscn" type="PackedScene" id=38] [ext_resource path="res://src/UI/Dialogs/RotateImage.tscn" type="PackedScene" id=38]

View file

@ -27,8 +27,8 @@ func open(palette : String) -> void:
self.popup_centered() self.popup_centered()
Global.dialog_open(true) Global.dialog_open(true)
left_color_button.modulate = Global.left_color_picker.color left_color_button.modulate = Global.color_pickers[0].color
right_color_button.modulate = Global.right_color_picker.color right_color_button.modulate = Global.color_pickers[1].color
func _display_palette() -> void: func _display_palette() -> void:
@ -177,12 +177,12 @@ func _refresh_hint_tooltip(_index : int) -> void:
func _on_LeftColor_pressed() -> void: func _on_LeftColor_pressed() -> void:
color_picker.color = Global.left_color_picker.color color_picker.color = Global.color_pickers[0].color
_on_EditPaletteColorPicker_color_changed(color_picker.color) _on_EditPaletteColorPicker_color_changed(color_picker.color)
func _on_RightColor_pressed() -> void: func _on_RightColor_pressed() -> void:
color_picker.color = Global.right_color_picker.color color_picker.color = Global.color_pickers[1].color
_on_EditPaletteColorPicker_color_changed(color_picker.color) _on_EditPaletteColorPicker_color_changed(color_picker.color)

View file

@ -165,11 +165,11 @@ func on_color_select(index : int) -> void:
var color : Color = Global.palettes[current_palette].get_color(index) var color : Color = Global.palettes[current_palette].get_color(index)
if Input.is_action_just_pressed("left_mouse"): if Input.is_action_just_pressed("left_mouse"):
Global.left_color_picker.color = color Global.color_pickers[0].color = color
Global.update_left_custom_brush() Global.update_custom_brush(0)
elif Input.is_action_just_pressed("right_mouse"): elif Input.is_action_just_pressed("right_mouse"):
Global.right_color_picker.color = color Global.color_pickers[1].color = color
Global.update_right_custom_brush() Global.update_custom_brush(1)
func _load_palettes() -> void: func _load_palettes() -> void:
@ -195,7 +195,7 @@ func _load_palettes() -> void:
# You need these two lines because when you remove a palette # You need these two lines because when you remove a palette
# Then this just won't work and _on_PaletteOptionButton_item_selected # Then this just won't work and _on_PaletteOptionButton_item_selected
# method won't fire. # method won't fire.
Global.palette_option_button.selected Global.palette_option_button.selected = index
on_palette_select("Default") on_palette_select("Default")
Global.palette_option_button.select(index) Global.palette_option_button.select(index)

View file

@ -0,0 +1,50 @@
extends Node
func _ready() -> void:
Global.loaded_locales = TranslationServer.get_loaded_locales()
# Make sure locales are always sorted, in the same order
Global.loaded_locales.sort()
# Load language
if Global.config_cache.has_section_key("preferences", "locale"):
var saved_locale : String = Global.config_cache.get_value("preferences", "locale")
TranslationServer.set_locale(saved_locale)
# Set the language option menu's default selected option to the loaded locale
var locale_index: int = Global.loaded_locales.find(saved_locale)
get_child(0).pressed = false # Unset System Language option in preferences
get_child(locale_index + 1).pressed = true
else: # If the user doesn't have a language preference, set it to their OS' locale
TranslationServer.set_locale(OS.get_locale())
if "zh" in TranslationServer.get_locale():
Global.control.theme.default_font = preload("res://assets/fonts/CJK/NotoSansCJKtc-Regular.tres")
else:
Global.control.theme.default_font = preload("res://assets/fonts/Roboto-Regular.tres")
for child in get_children():
if child is Button:
child.connect("pressed", self, "_on_Language_pressed", [child.get_index()])
child.hint_tooltip = child.name
func _on_Language_pressed(index : int) -> void:
get_child(index).pressed = true
if index == 0:
TranslationServer.set_locale(OS.get_locale())
else:
TranslationServer.set_locale(Global.loaded_locales[index - 1])
if "zh" in TranslationServer.get_locale():
Global.control.theme.default_font = preload("res://assets/fonts/CJK/NotoSansCJKtc-Regular.tres")
else:
Global.control.theme.default_font = preload("res://assets/fonts/Roboto-Regular.tres")
Global.config_cache.set_value("preferences", "locale", TranslationServer.get_locale())
Global.config_cache.save("user://cache.ini")
# Update Translations
Global.update_hint_tooltips()
Global.preferences_dialog._on_PreferencesDialog_popup_hide()
Global.preferences_dialog._on_PreferencesDialog_about_to_show(true)

View file

@ -0,0 +1,125 @@
extends Node
var default_shortcuts_preset := {}
var custom_shortcuts_preset := {}
var action_being_edited := ""
var shortcut_already_assigned = false
var old_input_event : InputEventKey
var new_input_event : InputEventKey
onready var shortcut_selector_popup = Global.preferences_dialog.get_node("Popups/ShortcutSelector")
onready var theme_font_color : Color = Global.preferences_dialog.get_node("Popups/ShortcutSelector/EnteredShortcut").get_color("font_color")
func _ready() -> void:
# Disable input until the shortcut selector is displayed
set_process_input(false)
# Get default preset for shortcuts from project input map
# Buttons in shortcuts selector should be called the same as actions
for shortcut_grid_item in get_node("Shortcuts").get_children():
if shortcut_grid_item is Button:
var input_events = InputMap.get_action_list(shortcut_grid_item.name)
if input_events.size() > 1:
printerr("Every shortcut action should have just one input event assigned in input map")
shortcut_grid_item.text = (input_events[0] as InputEventKey).as_text()
shortcut_grid_item.connect("pressed", self, "_on_Shortcut_button_pressed", [shortcut_grid_item])
default_shortcuts_preset[shortcut_grid_item.name] = input_events[0]
# Load custom shortcuts from the config file
custom_shortcuts_preset = default_shortcuts_preset.duplicate()
for action in default_shortcuts_preset:
var saved_input_event = Global.config_cache.get_value("shortcuts", action, 0)
if saved_input_event is InputEventKey:
custom_shortcuts_preset[action] = saved_input_event
var shortcuts_preset = Global.config_cache.get_value("shortcuts", "shortcuts_preset", 0)
get_node("HBoxContainer/PresetOptionButton").select(shortcuts_preset)
_on_PresetOptionButton_item_selected(shortcuts_preset)
func _input(event : InputEvent) -> void:
if event is InputEventKey:
if event.pressed:
if event.scancode == KEY_ESCAPE:
shortcut_selector_popup.hide()
else:
# Check if shortcut was already used
for action in InputMap.get_actions():
for input_event in InputMap.get_action_list(action):
if input_event is InputEventKey:
if OS.get_scancode_string(input_event.get_scancode_with_modifiers()) == OS.get_scancode_string(event.get_scancode_with_modifiers()):
shortcut_selector_popup.get_node("EnteredShortcut").text = tr("Already assigned")
shortcut_selector_popup.get_node("EnteredShortcut").add_color_override("font_color", Color.crimson)
get_tree().set_input_as_handled()
shortcut_already_assigned = true
return
# Store new shortcut
shortcut_already_assigned = false
old_input_event = InputMap.get_action_list(action_being_edited)[0]
new_input_event = event
shortcut_selector_popup.get_node("EnteredShortcut").text = OS.get_scancode_string(event.get_scancode_with_modifiers())
shortcut_selector_popup.get_node("EnteredShortcut").add_color_override("font_color", theme_font_color)
get_tree().set_input_as_handled()
func _on_PresetOptionButton_item_selected(id : int) -> void:
# Only custom preset which is modifiable
toggle_shortcut_buttons(true if id == 1 else false)
match id:
0:
apply_shortcuts_preset(default_shortcuts_preset)
1:
apply_shortcuts_preset(custom_shortcuts_preset)
Global.config_cache.set_value("shortcuts", "shortcuts_preset", id)
Global.config_cache.save("user://cache.ini")
func apply_shortcuts_preset(preset) -> void:
for action in preset:
var old_input_event : InputEventKey = InputMap.get_action_list(action)[0]
set_action_shortcut(action, old_input_event, preset[action])
get_node("Shortcuts/" + action).text = OS.get_scancode_string(preset[action].get_scancode_with_modifiers())
func toggle_shortcut_buttons(enabled : bool) -> void:
for shortcut_grid_item in get_node("Shortcuts").get_children():
if shortcut_grid_item is Button:
shortcut_grid_item.disabled = not enabled
if shortcut_grid_item.disabled:
shortcut_grid_item.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
else:
shortcut_grid_item.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
func set_action_shortcut(action : String, old_input : InputEventKey, new_input : InputEventKey) -> void:
InputMap.action_erase_event(action, old_input)
InputMap.action_add_event(action, new_input)
Global.update_hint_tooltips()
# Set shortcut to switch colors button
if action == "switch_colors":
Global.color_switch_button.shortcut.shortcut = InputMap.get_action_list("switch_colors")[0]
func _on_Shortcut_button_pressed(button : Button) -> void:
set_process_input(true)
action_being_edited = button.name
new_input_event = InputMap.get_action_list(button.name)[0]
shortcut_already_assigned = true
shortcut_selector_popup.popup_centered()
func _on_ShortcutSelector_popup_hide() -> void:
set_process_input(false)
shortcut_selector_popup.get_node("EnteredShortcut").text = ""
func _on_ShortcutSelector_confirmed() -> void:
if not shortcut_already_assigned:
set_action_shortcut(action_being_edited, old_input_event, new_input_event)
custom_shortcuts_preset[action_being_edited] = new_input_event
Global.config_cache.set_value("shortcuts", action_being_edited, new_input_event)
Global.config_cache.save("user://cache.ini")
get_node("Shortcuts/" + action_being_edited).text = OS.get_scancode_string(new_input_event.get_scancode_with_modifiers())
shortcut_selector_popup.hide()

View file

@ -0,0 +1,123 @@
extends Node
func _ready() -> void:
for child in get_children():
if child is Button:
child.connect("pressed", self, "_on_Theme_pressed", [child.get_index()])
if Global.config_cache.has_section_key("preferences", "theme"):
var theme_id = Global.config_cache.get_value("preferences", "theme")
change_theme(theme_id)
get_child(theme_id).pressed = true
else:
change_theme(0)
get_child(0).pressed = true
func _on_Theme_pressed(index : int) -> void:
get_child(index).pressed = true
change_theme(index)
Global.config_cache.set_value("preferences", "theme", index)
Global.config_cache.save("user://cache.ini")
func change_theme(ID : int) -> void:
var font = Global.control.theme.default_font
var main_theme : Theme
var top_menu_style
var ruler_style
if ID == 0: # Dark Theme
Global.theme_type = Global.Theme_Types.DARK
main_theme = preload("res://assets/themes/dark/theme.tres")
top_menu_style = preload("res://assets/themes/dark/top_menu_style.tres")
ruler_style = preload("res://assets/themes/dark/ruler_style.tres")
elif ID == 1: # Gray Theme
Global.theme_type = Global.Theme_Types.DARK
main_theme = preload("res://assets/themes/gray/theme.tres")
top_menu_style = preload("res://assets/themes/gray/top_menu_style.tres")
ruler_style = preload("res://assets/themes/dark/ruler_style.tres")
elif ID == 2: # Godot's Theme
Global.theme_type = Global.Theme_Types.BLUE
main_theme = preload("res://assets/themes/blue/theme.tres")
top_menu_style = preload("res://assets/themes/blue/top_menu_style.tres")
ruler_style = preload("res://assets/themes/blue/ruler_style.tres")
elif ID == 3: # Caramel Theme
Global.theme_type = Global.Theme_Types.CARAMEL
main_theme = preload("res://assets/themes/caramel/theme.tres")
top_menu_style = preload("res://assets/themes/caramel/top_menu_style.tres")
ruler_style = preload("res://assets/themes/caramel/ruler_style.tres")
elif ID == 4: # Light Theme
Global.theme_type = Global.Theme_Types.LIGHT
main_theme = preload("res://assets/themes/light/theme.tres")
top_menu_style = preload("res://assets/themes/light/top_menu_style.tres")
ruler_style = preload("res://assets/themes/light/ruler_style.tres")
Global.control.theme = main_theme
Global.control.theme.default_font = font
var default_clear_color : Color = main_theme.get_stylebox("panel", "PanelContainer").bg_color
VisualServer.set_default_clear_color(Color(default_clear_color))
(Global.animation_timeline.get_stylebox("panel", "Panel") as StyleBoxFlat).bg_color = main_theme.get_stylebox("panel", "Panel").bg_color
var layer_button_panel_container : PanelContainer = Global.find_node_by_name(Global.animation_timeline, "LayerButtonPanelContainer")
(layer_button_panel_container.get_stylebox("panel", "PanelContainer") as StyleBoxFlat).bg_color = default_clear_color
Global.top_menu_container.add_stylebox_override("panel", top_menu_style)
Global.horizontal_ruler.add_stylebox_override("normal", ruler_style)
Global.horizontal_ruler.add_stylebox_override("pressed", ruler_style)
Global.horizontal_ruler.add_stylebox_override("hover", ruler_style)
Global.horizontal_ruler.add_stylebox_override("focus", ruler_style)
Global.vertical_ruler.add_stylebox_override("normal", ruler_style)
Global.vertical_ruler.add_stylebox_override("pressed", ruler_style)
Global.vertical_ruler.add_stylebox_override("hover", ruler_style)
Global.vertical_ruler.add_stylebox_override("focus", ruler_style)
var fake_vsplit_grabber : TextureRect = Global.find_node_by_name(Global.animation_timeline, "FakeVSplitContainerGrabber")
if Global.theme_type == Global.Theme_Types.DARK or Global.theme_type == Global.Theme_Types.BLUE:
fake_vsplit_grabber.texture = preload("res://assets/themes/dark/icons/vsplit.png")
else:
fake_vsplit_grabber.texture = preload("res://assets/themes/light/icons/vsplit.png")
for button in get_tree().get_nodes_in_group("UIButtons"):
if button is TextureButton:
var last_backslash = button.texture_normal.resource_path.get_base_dir().find_last("/")
var button_category = button.texture_normal.resource_path.get_base_dir().right(last_backslash + 1)
var normal_file_name = button.texture_normal.resource_path.get_file()
var theme_type := Global.theme_type
if theme_type == Global.Theme_Types.BLUE:
theme_type = Global.Theme_Types.DARK
var theme_type_string : String = Global.Theme_Types.keys()[theme_type].to_lower()
button.texture_normal = load("res://assets/graphics/%s_themes/%s/%s" % [theme_type_string, button_category, normal_file_name])
if button.texture_pressed:
var pressed_file_name = button.texture_pressed.resource_path.get_file()
button.texture_pressed = load("res://assets/graphics/%s_themes/%s/%s" % [theme_type_string, button_category, pressed_file_name])
if button.texture_hover:
var hover_file_name = button.texture_hover.resource_path.get_file()
button.texture_hover = load("res://assets/graphics/%s_themes/%s/%s" % [theme_type_string, button_category, hover_file_name])
if button.texture_disabled:
var disabled_file_name = button.texture_disabled.resource_path.get_file()
button.texture_disabled = load("res://assets/graphics/%s_themes/%s/%s" % [theme_type_string, button_category, disabled_file_name])
elif button is Button:
var texture : TextureRect
for child in button.get_children():
if child is TextureRect:
texture = child
break
if texture:
var last_backslash = texture.texture.resource_path.get_base_dir().find_last("/")
var button_category = texture.texture.resource_path.get_base_dir().right(last_backslash + 1)
var normal_file_name = texture.texture.resource_path.get_file()
var theme_type := Global.theme_type
if theme_type == Global.Theme_Types.CARAMEL or (theme_type == Global.Theme_Types.BLUE and button_category != "tools"):
theme_type = Global.Theme_Types.DARK
var theme_type_string : String = Global.Theme_Types.keys()[theme_type].to_lower()
texture.texture = load("res://assets/graphics/%s_themes/%s/%s" % [theme_type_string, button_category, normal_file_name])
# Make sure the frame text gets updated
Global.current_frame = Global.current_frame
Global.preferences_dialog.get_node("Popups/ShortcutSelector").theme = main_theme

View file

@ -0,0 +1,125 @@
extends AcceptDialog
# Preferences table: [Prop name in Global, relative node path, value type]
var preferences = [
["open_last_project", "General/OpenLastProject", "pressed"],
["smooth_zoom", "General/SmoothZoom", "pressed"],
["pressure_sensitivity_mode", "General/PressureSentivity/PressureSensitivityOptionButton", "selected"],
["show_left_tool_icon", "General/GridContainer/LeftToolIconCheckbox", "pressed"],
["show_right_tool_icon", "General/GridContainer/RightToolIconCheckbox", "pressed"],
["left_square_indicator_visible", "General/GridContainer/LeftIndicatorCheckbox", "pressed"],
["right_square_indicator_visible", "General/GridContainer/RightIndicatorCheckbox", "pressed"],
["autosave_interval", "General/AutosaveInterval/AutosaveInterval", "value"],
["enable_autosave", "General/EnableAutosave", "pressed"],
["default_image_width", "Image/ImageOptions/ImageDefaultWidth", "value"],
["default_image_height", "Image/ImageOptions/ImageDefaultHeight", "value"],
["default_fill_color", "Image/ImageOptions/DefaultFillColor", "color"],
["grid_width", "Canvas/GridOptions/GridWidthValue", "value"],
["grid_height", "Canvas/GridOptions/GridHeightValue", "value"],
["grid_color", "Canvas/GridOptions/GridColor", "color"],
["guide_color", "Canvas/GuideOptions/GuideColor", "color"],
["checker_size", "Canvas/CheckerOptions/CheckerSizeValue", "value"],
["checker_color_1", "Canvas/CheckerOptions/CheckerColor1", "color"],
["checker_color_2", "Canvas/CheckerOptions/CheckerColor2", "color"],
]
onready var list : ItemList = $HSplitContainer/List
onready var right_side : VBoxContainer = $HSplitContainer/ScrollContainer/VBoxContainer
onready var general = $HSplitContainer/ScrollContainer/VBoxContainer/General
func _ready() -> void:
# Replace OK with Close since preference changes are being applied immediately, not after OK confirmation
get_ok().text = tr("Close")
for pref in preferences:
var node = right_side.get_node(pref[1])
if Global.config_cache.has_section_key("preferences", pref[0]):
var value = Global.config_cache.get_value("preferences", pref[0])
Global.set(pref[0], value)
node.set(pref[2], value)
match pref[2]:
"pressed":
node.connect("toggled", self, "_on_Preference_toggled", [pref[0]])
"value":
node.connect("value_changed", self, "_on_Preference_value_changed", [pref[0]])
"color":
node.get_picker().presets_visible = false
node.connect("color_changed", self, "_on_Preference_color_changed", [pref[0]])
"selected":
node.connect("item_selected", self, "_on_Preference_item_selected", [pref[0]])
Global.transparent_checker._ready()
for canvas in Global.canvases:
for guide in canvas.get_children():
if guide is Guide:
guide.default_color = Global.guide_color
func _on_Preference_toggled(button_pressed : bool, prop : String) -> void:
Global.set(prop, button_pressed)
Global.config_cache.set_value("preferences", prop, button_pressed)
preference_update(prop)
func _on_Preference_value_changed(value : float, prop : String) -> void:
Global.set(prop, value)
Global.config_cache.set_value("preferences", prop, value)
preference_update(prop)
func _on_Preference_color_changed(color : Color, prop : String) -> void:
Global.set(prop, color)
Global.config_cache.set_value("preferences", prop, color)
preference_update(prop)
func _on_Preference_item_selected(id : int, prop : String) -> void:
Global.set(prop, id)
Global.config_cache.set_value("preferences", prop, id)
preference_update(prop)
func preference_update(prop : String) -> void:
if prop in ["autosave_interval", "enable_autosave"]:
OpenSave.update_autosave()
if prop in ["grid_width", "grid_height", "grid_color"]:
Global.canvas.update()
if prop in ["checker_size", "checker_color_1", "checker_color_2"]:
Global.transparent_checker._ready()
if prop in ["guide_color"]:
for canvas in Global.canvases:
for guide in canvas.get_children():
if guide is Guide:
guide.default_color = Global.guide_color
Global.config_cache.save("user://cache.ini")
func _on_PreferencesDialog_about_to_show(changed_language := false) -> void:
list.add_item(" " + tr("General"))
list.add_item(" " + tr("Language"))
list.add_item(" " + tr("Themes"))
list.add_item(" " + tr("Canvas"))
list.add_item(" " + tr("Image"))
list.add_item(" " + tr("Shortcuts"))
list.select(1 if changed_language else 0)
general.get_node("AutosaveInterval/AutosaveInterval").suffix = tr("minute(s)")
func _on_PreferencesDialog_popup_hide() -> void:
list.clear()
func _on_List_item_selected(index):
for child in right_side.get_children():
child.visible = child.name == ["General", "Languages", "Themes", "Canvas", "Image", "Shortcuts"][index]

View file

@ -1,8 +1,15 @@
[gd_scene load_steps=4 format=2] [gd_scene load_steps=9 format=2]
[ext_resource path="res://src/UI/Dialogs/PreferencesDialog.gd" type="Script" id=1] [ext_resource path="res://src/Preferences/PreferencesDialog.gd" type="Script" id=1]
[ext_resource path="res://assets/fonts/Roboto-Regular.tres" type="DynamicFont" id=2] [ext_resource path="res://assets/fonts/Roboto-Regular.tres" type="DynamicFont" id=2]
[ext_resource path="res://assets/fonts/CJK/NotoSansCJKtc-Regular.tres" type="DynamicFont" id=3] [ext_resource path="res://assets/fonts/CJK/NotoSansCJKtc-Regular.tres" type="DynamicFont" id=3]
[ext_resource path="res://src/Preferences/HandleLanguages.gd" type="Script" id=4]
[ext_resource path="res://src/Preferences/HandleThemes.gd" type="Script" id=5]
[ext_resource path="res://src/Preferences/HandleShortcuts.gd" type="Script" id=6]
[sub_resource type="ButtonGroup" id=1]
[sub_resource type="ButtonGroup" id=2]
[node name="PreferencesDialog" type="AcceptDialog"] [node name="PreferencesDialog" type="AcceptDialog"]
margin_left = -3.0 margin_left = -3.0
@ -33,12 +40,10 @@ __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="Tree" type="Tree" parent="HSplitContainer"] [node name="List" type="ItemList" parent="HSplitContainer"]
margin_right = 86.0 margin_right = 86.0
margin_bottom = 1110.0 margin_bottom = 1110.0
rect_min_size = Vector2( 85, 0 ) rect_min_size = Vector2( 85, 0 )
custom_constants/item_margin = -2
hide_root = true
[node name="ScrollContainer" type="ScrollContainer" parent="HSplitContainer"] [node name="ScrollContainer" type="ScrollContainer" parent="HSplitContainer"]
margin_left = 98.0 margin_left = 98.0
@ -49,15 +54,15 @@ size_flags_horizontal = 3
[node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer/ScrollContainer"] [node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer/ScrollContainer"]
margin_right = 506.0 margin_right = 506.0
margin_bottom = 1286.0 margin_bottom = 180.0
size_flags_horizontal = 3 size_flags_horizontal = 3
[node name="General" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"] [node name="General" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_right = 494.0 margin_right = 506.0
margin_bottom = 180.0 margin_bottom = 180.0
[node name="SmoothZoom" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"] [node name="SmoothZoom" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_right = 494.0 margin_right = 506.0
margin_bottom = 24.0 margin_bottom = 24.0
hint_tooltip = "Adds a smoother transition when zooming in or out" hint_tooltip = "Adds a smoother transition when zooming in or out"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
@ -66,19 +71,19 @@ text = "Smooth Zoom"
[node name="HSeparator2" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"] [node name="HSeparator2" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 28.0 margin_top = 28.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 32.0 margin_bottom = 32.0
[node name="GridContainer" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"] [node name="GridContainer" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 36.0 margin_top = 36.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 88.0 margin_bottom = 88.0
custom_constants/vseparation = 4 custom_constants/vseparation = 4
custom_constants/hseparation = 4 custom_constants/hseparation = 4
columns = 2 columns = 2
[node name="LeftIndicatorCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"] [node name="LeftIndicatorCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"]
margin_right = 245.0 margin_right = 251.0
margin_bottom = 24.0 margin_bottom = 24.0
hint_tooltip = "Show left mouse pixel indicator or brush on the canvas when drawing" hint_tooltip = "Show left mouse pixel indicator or brush on the canvas when drawing"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
@ -87,8 +92,8 @@ pressed = true
text = "Left pixel indicator" text = "Left pixel indicator"
[node name="RightIndicatorCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"] [node name="RightIndicatorCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"]
margin_left = 249.0 margin_left = 255.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 24.0 margin_bottom = 24.0
hint_tooltip = "Show right mouse pixel indicator or brush on the canvas when drawing" hint_tooltip = "Show right mouse pixel indicator or brush on the canvas when drawing"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
@ -97,7 +102,7 @@ text = "Right pixel indicator"
[node name="LeftToolIconCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"] [node name="LeftToolIconCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"]
margin_top = 28.0 margin_top = 28.0
margin_right = 245.0 margin_right = 251.0
margin_bottom = 52.0 margin_bottom = 52.0
hint_tooltip = "Displays an icon of the selected left tool next to the cursor on the canvas" hint_tooltip = "Displays an icon of the selected left tool next to the cursor on the canvas"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
@ -106,9 +111,9 @@ pressed = true
text = "Show left tool icon" text = "Show left tool icon"
[node name="RightToolIconCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"] [node name="RightToolIconCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"]
margin_left = 249.0 margin_left = 255.0
margin_top = 28.0 margin_top = 28.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 52.0 margin_bottom = 52.0
hint_tooltip = "Displays an icon of the selected right tool next to the cursor on the canvas" hint_tooltip = "Displays an icon of the selected right tool next to the cursor on the canvas"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
@ -118,14 +123,14 @@ text = "Show right tool icon"
[node name="HSeparator3" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"] [node name="HSeparator3" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 92.0 margin_top = 92.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 96.0 margin_bottom = 96.0
[node name="PressureSentivity" type="HBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"] [node name="PressureSentivity" type="HBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
visible = false visible = false
margin_top = 116.0 margin_top = 100.0
margin_right = 334.0 margin_right = 506.0
margin_bottom = 136.0 margin_bottom = 120.0
[node name="PressureSensitivityLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/PressureSentivity"] [node name="PressureSensitivityLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/PressureSentivity"]
margin_top = 3.0 margin_top = 3.0
@ -143,7 +148,7 @@ selected = 1
[node name="OpenLastProject" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"] [node name="OpenLastProject" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 100.0 margin_top = 100.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 124.0 margin_bottom = 124.0
hint_tooltip = "Opens last opened project on startup" hint_tooltip = "Opens last opened project on startup"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
@ -151,7 +156,7 @@ text = "Open last project on startup"
[node name="EnableAutosave" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"] [node name="EnableAutosave" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 128.0 margin_top = 128.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 152.0 margin_bottom = 152.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
pressed = true pressed = true
@ -162,7 +167,7 @@ __meta__ = {
[node name="AutosaveInterval" type="HBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"] [node name="AutosaveInterval" type="HBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 156.0 margin_top = 156.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 180.0 margin_bottom = 180.0
__meta__ = { __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
@ -176,7 +181,7 @@ text = "Autosave interval:"
[node name="AutosaveInterval" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/AutosaveInterval"] [node name="AutosaveInterval" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/AutosaveInterval"]
margin_left = 119.0 margin_left = 119.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 24.0 margin_bottom = 24.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
@ -191,171 +196,196 @@ __meta__ = {
} }
[node name="Languages" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"] [node name="Languages" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
visible = false
margin_top = 184.0 margin_top = 184.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 632.0 margin_bottom = 632.0
script = ExtResource( 4 )
[node name="System Language" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="System Language" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_right = 494.0 margin_right = 506.0
margin_bottom = 24.0 margin_bottom = 24.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
pressed = true pressed = true
group = SubResource( 1 )
text = "System Language" text = "System Language"
[node name="Czech" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="Czech" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 28.0 margin_top = 28.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 52.0 margin_bottom = 52.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Czech [cs]" text = "Czech [cs]"
[node name="German" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="German" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 56.0 margin_top = 56.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 80.0 margin_bottom = 80.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Deutsch [de]" text = "Deutsch [de]"
[node name="Greek" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="Greek" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 84.0 margin_top = 84.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 108.0 margin_bottom = 108.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
custom_fonts/font = ExtResource( 2 ) custom_fonts/font = ExtResource( 2 )
group = SubResource( 1 )
text = "Ελληνικά [el]" text = "Ελληνικά [el]"
[node name="English" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="English" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 112.0 margin_top = 112.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 136.0 margin_bottom = 136.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "English [en]" text = "English [en]"
[node name="Esperanto" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="Esperanto" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 140.0 margin_top = 140.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 164.0 margin_bottom = 164.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Esperanto [eo]" text = "Esperanto [eo]"
[node name="Spanish" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="Spanish" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 168.0 margin_top = 168.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 192.0 margin_bottom = 192.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Español [es]" text = "Español [es]"
[node name="French" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="French" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 196.0 margin_top = 196.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 220.0 margin_bottom = 220.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Français [fr]" text = "Français [fr]"
[node name="Indonesian" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="Indonesian" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 224.0 margin_top = 224.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 248.0 margin_bottom = 248.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Indonesian [id]" text = "Indonesian [id]"
[node name="Italian" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="Italian" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 252.0 margin_top = 252.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 276.0 margin_bottom = 276.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Italiano [it]" text = "Italiano [it]"
[node name="Latvian" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="Latvian" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 280.0 margin_top = 280.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 304.0 margin_bottom = 304.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Latvian [lv]" text = "Latvian [lv]"
[node name="Polish" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="Polish" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 308.0 margin_top = 308.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 332.0 margin_bottom = 332.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Polski [pl]" text = "Polski [pl]"
[node name="Brazilian Portuguese" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="Brazilian Portuguese" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 336.0 margin_top = 336.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 360.0 margin_bottom = 360.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Português Brasileiro [pt_BR]" text = "Português Brasileiro [pt_BR]"
[node name="Russian" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="Russian" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 364.0 margin_top = 364.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 388.0 margin_bottom = 388.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Русский [ru]" text = "Русский [ru]"
[node name="Chinese Simplified" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="Chinese Simplified" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 392.0 margin_top = 392.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 418.0 margin_bottom = 418.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
custom_fonts/font = ExtResource( 3 ) custom_fonts/font = ExtResource( 3 )
group = SubResource( 1 )
text = "简体中文 [zh_CN]" text = "简体中文 [zh_CN]"
[node name="Chinese Traditional" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"] [node name="Chinese Traditional" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 422.0 margin_top = 422.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 448.0 margin_bottom = 448.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
custom_fonts/font = ExtResource( 3 ) custom_fonts/font = ExtResource( 3 )
group = SubResource( 1 )
text = "繁體中文 [zh_TW]" text = "繁體中文 [zh_TW]"
[node name="Themes" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"] [node name="Themes" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_top = 636.0 visible = false
margin_right = 494.0 margin_right = 506.0
margin_bottom = 772.0 margin_bottom = 136.0
script = ExtResource( 5 )
[node name="Dark Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"] [node name="Dark Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"]
margin_right = 494.0 margin_right = 506.0
margin_bottom = 24.0 margin_bottom = 24.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 2 )
text = "Dark" text = "Dark"
[node name="Gray Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"] [node name="Gray Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"]
margin_top = 28.0 margin_top = 28.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 52.0 margin_bottom = 52.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 2 )
text = "Gray" text = "Gray"
[node name="Blue Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"] [node name="Blue Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"]
margin_top = 56.0 margin_top = 56.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 80.0 margin_bottom = 80.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 2 )
text = "Blue" text = "Blue"
[node name="Caramel Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"] [node name="Caramel Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"]
margin_top = 84.0 margin_top = 84.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 108.0 margin_bottom = 108.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 2 )
text = "Caramel" text = "Caramel"
[node name="Light Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"] [node name="Light Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"]
margin_top = 112.0 margin_top = 112.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 136.0 margin_bottom = 136.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
group = SubResource( 2 )
text = "Light" text = "Light"
[node name="Canvas" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"] [node name="Canvas" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_top = 776.0 visible = false
margin_right = 494.0 margin_top = 184.0
margin_bottom = 968.0 margin_right = 506.0
margin_bottom = 376.0
[node name="GuideOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"] [node name="GuideOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"]
margin_right = 494.0 margin_right = 506.0
margin_bottom = 20.0 margin_bottom = 20.0
custom_constants/vseparation = 4 custom_constants/vseparation = 4
custom_constants/hseparation = 4 custom_constants/hseparation = 4
@ -372,7 +402,7 @@ text = "Guides color:"
[node name="GuideColor" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GuideOptions"] [node name="GuideColor" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GuideOptions"]
margin_left = 114.0 margin_left = 114.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 20.0 margin_bottom = 20.0
rect_min_size = Vector2( 64, 20 ) rect_min_size = Vector2( 64, 20 )
hint_tooltip = "A color of ruler guides displayed on the canvas" hint_tooltip = "A color of ruler guides displayed on the canvas"
@ -382,12 +412,12 @@ color = Color( 0.63, 0.13, 0.94, 1 )
[node name="HSeparator" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"] [node name="HSeparator" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"]
margin_top = 24.0 margin_top = 24.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 28.0 margin_bottom = 28.0
[node name="GridOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"] [node name="GridOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"]
margin_top = 32.0 margin_top = 32.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 108.0 margin_bottom = 108.0
custom_constants/vseparation = 4 custom_constants/vseparation = 4
custom_constants/hseparation = 4 custom_constants/hseparation = 4
@ -404,13 +434,14 @@ text = "Grid width:"
[node name="GridWidthValue" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions"] [node name="GridWidthValue" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions"]
margin_left = 114.0 margin_left = 114.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 24.0 margin_bottom = 24.0
hint_tooltip = "Sets how far apart are vertical lines of the grid" hint_tooltip = "Sets how far apart are vertical lines of the grid"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
min_value = 1.0 min_value = 1.0
max_value = 16384.0 max_value = 16384.0
value = 1.0 value = 1.0
rounded = true
align = 2 align = 2
suffix = "px" suffix = "px"
@ -425,7 +456,7 @@ text = "Grid height:"
[node name="GridHeightValue" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions"] [node name="GridHeightValue" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions"]
margin_left = 114.0 margin_left = 114.0
margin_top = 28.0 margin_top = 28.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 52.0 margin_bottom = 52.0
hint_tooltip = "Sets how far apart are horizontal lines of the grid" hint_tooltip = "Sets how far apart are horizontal lines of the grid"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
@ -433,6 +464,7 @@ size_flags_horizontal = 3
min_value = 1.0 min_value = 1.0
max_value = 16384.0 max_value = 16384.0
value = 1.0 value = 1.0
rounded = true
align = 2 align = 2
suffix = "px" suffix = "px"
@ -447,7 +479,7 @@ text = "Grid color:"
[node name="GridColor" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions"] [node name="GridColor" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions"]
margin_left = 114.0 margin_left = 114.0
margin_top = 56.0 margin_top = 56.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 76.0 margin_bottom = 76.0
rect_min_size = Vector2( 64, 20 ) rect_min_size = Vector2( 64, 20 )
hint_tooltip = "A color of the grid" hint_tooltip = "A color of the grid"
@ -455,12 +487,12 @@ mouse_default_cursor_shape = 2
[node name="HSeparator2" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"] [node name="HSeparator2" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"]
margin_top = 112.0 margin_top = 112.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 116.0 margin_bottom = 116.0
[node name="CheckerOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"] [node name="CheckerOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"]
margin_top = 120.0 margin_top = 120.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 192.0 margin_bottom = 192.0
custom_constants/vseparation = 4 custom_constants/vseparation = 4
custom_constants/hseparation = 4 custom_constants/hseparation = 4
@ -477,13 +509,15 @@ text = "Checker size:"
[node name="CheckerSizeValue" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions"] [node name="CheckerSizeValue" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions"]
margin_left = 114.0 margin_left = 114.0
margin_right = 188.0 margin_right = 506.0
margin_bottom = 24.0 margin_bottom = 24.0
hint_tooltip = "Size of the transparent checker background" hint_tooltip = "Size of the transparent checker background"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
size_flags_horizontal = 3
min_value = 1.0 min_value = 1.0
max_value = 16384.0 max_value = 16384.0
value = 10.0 value = 10.0
rounded = true
align = 2 align = 2
suffix = "px" suffix = "px"
@ -498,7 +532,7 @@ text = "Checker color 1:"
[node name="CheckerColor1" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions"] [node name="CheckerColor1" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions"]
margin_left = 114.0 margin_left = 114.0
margin_top = 28.0 margin_top = 28.0
margin_right = 188.0 margin_right = 506.0
margin_bottom = 48.0 margin_bottom = 48.0
rect_min_size = Vector2( 64, 20 ) rect_min_size = Vector2( 64, 20 )
hint_tooltip = "First color of the transparent checker background" hint_tooltip = "First color of the transparent checker background"
@ -516,7 +550,7 @@ text = "Checker color 2:"
[node name="CheckerColor2" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions"] [node name="CheckerColor2" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions"]
margin_left = 114.0 margin_left = 114.0
margin_top = 52.0 margin_top = 52.0
margin_right = 188.0 margin_right = 506.0
margin_bottom = 72.0 margin_bottom = 72.0
rect_min_size = Vector2( 64, 20 ) rect_min_size = Vector2( 64, 20 )
hint_tooltip = "Second color of the transparent checker background" hint_tooltip = "Second color of the transparent checker background"
@ -524,12 +558,13 @@ mouse_default_cursor_shape = 2
color = Color( 0.341176, 0.34902, 0.341176, 1 ) color = Color( 0.341176, 0.34902, 0.341176, 1 )
[node name="Image" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"] [node name="Image" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_top = 972.0 visible = false
margin_right = 494.0 margin_top = 184.0
margin_bottom = 1048.0 margin_right = 506.0
margin_bottom = 260.0
[node name="ImageOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image"] [node name="ImageOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image"]
margin_right = 494.0 margin_right = 506.0
margin_bottom = 76.0 margin_bottom = 76.0
custom_constants/vseparation = 4 custom_constants/vseparation = 4
custom_constants/hseparation = 4 custom_constants/hseparation = 4
@ -546,7 +581,7 @@ text = "Default width:"
[node name="ImageDefaultWidth" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions"] [node name="ImageDefaultWidth" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions"]
margin_left = 114.0 margin_left = 114.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 24.0 margin_bottom = 24.0
hint_tooltip = "A default width of a new image" hint_tooltip = "A default width of a new image"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
@ -554,6 +589,7 @@ size_flags_horizontal = 3
min_value = 1.0 min_value = 1.0
max_value = 16384.0 max_value = 16384.0
value = 64.0 value = 64.0
rounded = true
align = 2 align = 2
suffix = "px" suffix = "px"
@ -568,13 +604,14 @@ text = "Default height:"
[node name="ImageDefaultHeight" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions"] [node name="ImageDefaultHeight" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions"]
margin_left = 114.0 margin_left = 114.0
margin_top = 28.0 margin_top = 28.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 52.0 margin_bottom = 52.0
hint_tooltip = "A default height of a new image" hint_tooltip = "A default height of a new image"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
min_value = 1.0 min_value = 1.0
max_value = 16384.0 max_value = 16384.0
value = 64.0 value = 64.0
rounded = true
align = 2 align = 2
suffix = "px" suffix = "px"
@ -589,7 +626,7 @@ text = "Default fill color:"
[node name="DefaultFillColor" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions"] [node name="DefaultFillColor" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions"]
margin_left = 114.0 margin_left = 114.0
margin_top = 56.0 margin_top = 56.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 76.0 margin_bottom = 76.0
rect_min_size = Vector2( 64, 20 ) rect_min_size = Vector2( 64, 20 )
hint_tooltip = "A default background color of a new image" hint_tooltip = "A default background color of a new image"
@ -597,12 +634,14 @@ mouse_default_cursor_shape = 2
color = Color( 0, 0, 0, 0 ) color = Color( 0, 0, 0, 0 )
[node name="Shortcuts" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"] [node name="Shortcuts" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_top = 1052.0 visible = false
margin_right = 494.0 margin_top = 184.0
margin_bottom = 1286.0 margin_right = 506.0
margin_bottom = 418.0
script = ExtResource( 6 )
[node name="HBoxContainer" type="HBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts"] [node name="HBoxContainer" type="HBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts"]
margin_right = 494.0 margin_right = 506.0
margin_bottom = 20.0 margin_bottom = 20.0
hint_tooltip = "Only custom preset can be modified" hint_tooltip = "Only custom preset can be modified"
@ -614,7 +653,7 @@ text = "Preset:"
[node name="PresetOptionButton" type="OptionButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/HBoxContainer"] [node name="PresetOptionButton" type="OptionButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/HBoxContainer"]
margin_left = 49.0 margin_left = 49.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 20.0 margin_bottom = 20.0
hint_tooltip = "Only custom preset can be modified" hint_tooltip = "Only custom preset can be modified"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
@ -625,12 +664,12 @@ selected = 0
[node name="HSeparator" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts"] [node name="HSeparator" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts"]
margin_top = 24.0 margin_top = 24.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 28.0 margin_bottom = 28.0
[node name="Shortcuts" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts"] [node name="Shortcuts" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts"]
margin_top = 32.0 margin_top = 32.0
margin_right = 494.0 margin_right = 506.0
margin_bottom = 234.0 margin_bottom = 234.0
custom_constants/vseparation = 2 custom_constants/vseparation = 2
custom_constants/hseparation = 5 custom_constants/hseparation = 5
@ -642,7 +681,7 @@ margin_bottom = 14.0
[node name="LeftToolLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="LeftToolLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0 margin_left = 142.0
margin_right = 315.0 margin_right = 321.0
margin_bottom = 14.0 margin_bottom = 14.0
hint_tooltip = "A tool assigned to the left mouse button" hint_tooltip = "A tool assigned to the left mouse button"
mouse_filter = 0 mouse_filter = 0
@ -650,8 +689,8 @@ text = "Left Tool:"
align = 1 align = 1
[node name="RightToolLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="RightToolLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 320.0 margin_left = 326.0
margin_right = 493.0 margin_right = 505.0
margin_bottom = 14.0 margin_bottom = 14.0
hint_tooltip = "A tool assigned to the right mouse button" hint_tooltip = "A tool assigned to the right mouse button"
mouse_filter = 0 mouse_filter = 0
@ -665,20 +704,21 @@ margin_bottom = 20.0
[node name="HSeparator" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="HSeparator" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
visible = false visible = false
margin_top = 18.0 margin_left = 184.0
margin_right = 137.0 margin_top = 16.0
margin_bottom = 22.0 margin_right = 321.0
margin_bottom = 20.0
[node name="HSeparator2" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="HSeparator2" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0 margin_left = 142.0
margin_top = 16.0 margin_top = 16.0
margin_right = 315.0 margin_right = 321.0
margin_bottom = 20.0 margin_bottom = 20.0
[node name="HSeparator3" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="HSeparator3" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 320.0 margin_left = 326.0
margin_top = 16.0 margin_top = 16.0
margin_right = 493.0 margin_right = 505.0
margin_bottom = 20.0 margin_bottom = 20.0
[node name="RectSelectLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="RectSelectLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
@ -690,14 +730,14 @@ text = "Rectangular Selection"
[node name="left_rectangle_select_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="left_rectangle_select_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0 margin_left = 142.0
margin_top = 22.0 margin_top = 22.0
margin_right = 315.0 margin_right = 321.0
margin_bottom = 42.0 margin_bottom = 42.0
size_flags_horizontal = 3 size_flags_horizontal = 3
[node name="right_rectangle_select_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="right_rectangle_select_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 320.0 margin_left = 326.0
margin_top = 22.0 margin_top = 22.0
margin_right = 493.0 margin_right = 505.0
margin_bottom = 42.0 margin_bottom = 42.0
size_flags_horizontal = 3 size_flags_horizontal = 3
@ -710,14 +750,14 @@ text = "Zoom"
[node name="left_zoom_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="left_zoom_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0 margin_left = 142.0
margin_top = 44.0 margin_top = 44.0
margin_right = 315.0 margin_right = 321.0
margin_bottom = 64.0 margin_bottom = 64.0
size_flags_horizontal = 3 size_flags_horizontal = 3
[node name="right_zoom_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="right_zoom_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 320.0 margin_left = 326.0
margin_top = 44.0 margin_top = 44.0
margin_right = 493.0 margin_right = 505.0
margin_bottom = 64.0 margin_bottom = 64.0
size_flags_horizontal = 3 size_flags_horizontal = 3
@ -730,13 +770,13 @@ text = "Color Picker"
[node name="left_colorpicker_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="left_colorpicker_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0 margin_left = 142.0
margin_top = 66.0 margin_top = 66.0
margin_right = 315.0 margin_right = 321.0
margin_bottom = 86.0 margin_bottom = 86.0
[node name="right_colorpicker_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="right_colorpicker_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 320.0 margin_left = 326.0
margin_top = 66.0 margin_top = 66.0
margin_right = 493.0 margin_right = 505.0
margin_bottom = 86.0 margin_bottom = 86.0
[node name="PencilLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="PencilLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
@ -748,13 +788,13 @@ text = "Pencil"
[node name="left_pencil_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="left_pencil_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0 margin_left = 142.0
margin_top = 88.0 margin_top = 88.0
margin_right = 315.0 margin_right = 321.0
margin_bottom = 108.0 margin_bottom = 108.0
[node name="right_pencil_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="right_pencil_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 320.0 margin_left = 326.0
margin_top = 88.0 margin_top = 88.0
margin_right = 493.0 margin_right = 505.0
margin_bottom = 108.0 margin_bottom = 108.0
[node name="EraserLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="EraserLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
@ -766,13 +806,13 @@ text = "Eraser"
[node name="left_eraser_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="left_eraser_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0 margin_left = 142.0
margin_top = 110.0 margin_top = 110.0
margin_right = 315.0 margin_right = 321.0
margin_bottom = 130.0 margin_bottom = 130.0
[node name="right_eraser_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="right_eraser_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 320.0 margin_left = 326.0
margin_top = 110.0 margin_top = 110.0
margin_right = 493.0 margin_right = 505.0
margin_bottom = 130.0 margin_bottom = 130.0
[node name="BucketLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="BucketLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
@ -784,13 +824,13 @@ text = "Bucket"
[node name="left_fill_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="left_fill_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0 margin_left = 142.0
margin_top = 132.0 margin_top = 132.0
margin_right = 315.0 margin_right = 321.0
margin_bottom = 152.0 margin_bottom = 152.0
[node name="right_fill_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="right_fill_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 320.0 margin_left = 326.0
margin_top = 132.0 margin_top = 132.0
margin_right = 493.0 margin_right = 505.0
margin_bottom = 152.0 margin_bottom = 152.0
[node name="LightenDarkenLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="LightenDarkenLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
@ -802,13 +842,13 @@ text = "Lighten/Darken"
[node name="left_lightdark_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="left_lightdark_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0 margin_left = 142.0
margin_top = 154.0 margin_top = 154.0
margin_right = 315.0 margin_right = 321.0
margin_bottom = 174.0 margin_bottom = 174.0
[node name="right_lightdark_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="right_lightdark_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 320.0 margin_left = 326.0
margin_top = 154.0 margin_top = 154.0
margin_right = 493.0 margin_right = 505.0
margin_bottom = 174.0 margin_bottom = 174.0
[node name="HSeparator4" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="HSeparator4" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
@ -819,13 +859,13 @@ margin_bottom = 180.0
[node name="HSeparator5" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="HSeparator5" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0 margin_left = 142.0
margin_top = 176.0 margin_top = 176.0
margin_right = 315.0 margin_right = 321.0
margin_bottom = 180.0 margin_bottom = 180.0
[node name="HSeparator6" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="HSeparator6" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 320.0 margin_left = 326.0
margin_top = 176.0 margin_top = 176.0
margin_right = 493.0 margin_right = 505.0
margin_bottom = 180.0 margin_bottom = 180.0
[node name="Switch Colors" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="Switch Colors" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
@ -837,7 +877,7 @@ text = "Switch Colors"
[node name="switch_colors" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"] [node name="switch_colors" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0 margin_left = 142.0
margin_top = 182.0 margin_top = 182.0
margin_right = 315.0 margin_right = 321.0
margin_bottom = 202.0 margin_bottom = 202.0
[node name="Popups" type="Node" parent="."] [node name="Popups" type="Node" parent="."]
@ -865,26 +905,7 @@ __meta__ = {
} }
[connection signal="about_to_show" from="." to="." method="_on_PreferencesDialog_about_to_show"] [connection signal="about_to_show" from="." to="." method="_on_PreferencesDialog_about_to_show"]
[connection signal="popup_hide" from="." to="." method="_on_PreferencesDialog_popup_hide"] [connection signal="popup_hide" from="." to="." method="_on_PreferencesDialog_popup_hide"]
[connection signal="item_selected" from="HSplitContainer/Tree" to="." method="_on_Tree_item_selected"] [connection signal="item_selected" from="HSplitContainer/List" to="." method="_on_List_item_selected"]
[connection signal="pressed" from="HSplitContainer/ScrollContainer/VBoxContainer/General/SmoothZoom" to="." method="_on_SmoothZoom_pressed"] [connection signal="item_selected" from="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/HBoxContainer/PresetOptionButton" to="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts" method="_on_PresetOptionButton_item_selected"]
[connection signal="toggled" from="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer/LeftIndicatorCheckbox" to="." method="_on_LeftIndicatorCheckbox_toggled"] [connection signal="confirmed" from="Popups/ShortcutSelector" to="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts" method="_on_ShortcutSelector_confirmed"]
[connection signal="toggled" from="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer/RightIndicatorCheckbox" to="." method="_on_RightIndicatorCheckbox_toggled"] [connection signal="popup_hide" from="Popups/ShortcutSelector" to="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts" method="_on_ShortcutSelector_popup_hide"]
[connection signal="toggled" from="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer/LeftToolIconCheckbox" to="." method="_on_LeftToolIconCheckbox_toggled"]
[connection signal="toggled" from="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer/RightToolIconCheckbox" to="." method="_on_RightToolIconCheckbox_toggled"]
[connection signal="item_selected" from="HSplitContainer/ScrollContainer/VBoxContainer/General/PressureSentivity/PressureSensitivityOptionButton" to="." method="_on_PressureSensitivityOptionButton_item_selected"]
[connection signal="pressed" from="HSplitContainer/ScrollContainer/VBoxContainer/General/OpenLastProject" to="." method="_on_OpenLastProject_pressed"]
[connection signal="toggled" from="HSplitContainer/ScrollContainer/VBoxContainer/General/EnableAutosave" to="." method="_on_EnableAutosave_toggled"]
[connection signal="value_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/General/AutosaveInterval/AutosaveInterval" to="." method="_on_AutosaveInterval_value_changed"]
[connection signal="color_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GuideOptions/GuideColor" to="." method="_on_GuideColor_color_changed"]
[connection signal="value_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions/GridWidthValue" to="." method="_on_GridWidthValue_value_changed"]
[connection signal="value_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions/GridHeightValue" to="." method="_on_GridHeightValue_value_changed"]
[connection signal="color_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions/GridColor" to="." method="_on_GridColor_color_changed"]
[connection signal="value_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions/CheckerSizeValue" to="." method="_on_CheckerSize_value_changed"]
[connection signal="color_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions/CheckerColor1" to="." method="_on_CheckerColor1_color_changed"]
[connection signal="color_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions/CheckerColor2" to="." method="_on_CheckerColor2_color_changed"]
[connection signal="value_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions/ImageDefaultWidth" to="." method="_on_ImageDefaultWidth_value_changed"]
[connection signal="value_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions/ImageDefaultHeight" to="." method="_on_ImageDefaultHeight_value_changed"]
[connection signal="color_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions/DefaultFillColor" to="." method="_on_DefaultBackground_color_changed"]
[connection signal="item_selected" from="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/HBoxContainer/PresetOptionButton" to="." method="_on_PresetOptionButton_item_selected"]
[connection signal="confirmed" from="Popups/ShortcutSelector" to="." method="_on_ShortcutSelector_confirmed"]
[connection signal="popup_hide" from="Popups/ShortcutSelector" to="." method="_on_ShortcutSelector_popup_hide"]

View file

@ -20,24 +20,24 @@ func _ready() -> void:
func _process(_delta : float) -> void: func _process(_delta : float) -> void:
if Global.layers[Global.current_layer][2]: if Global.layers[Global.current_layer].locked:
return return
var mouse_pos: Vector2 = get_local_mouse_position() - Global.canvas.location var mouse_pos: Vector2 = get_local_mouse_position() - Global.canvas.location
var mouse_pos_floored := mouse_pos.floor() var mouse_pos_floored := mouse_pos.floor()
var start_pos := polygon[0] var start_pos := polygon[0]
var end_pos := polygon[2] var end_pos := polygon[2]
var current_layer_index : int = Global.current_layer var current_layer_index : int = Global.current_layer
var layer : Image = Global.canvas.layers[current_layer_index][0] var layer : Image = Global.canvas.layers[current_layer_index].image
if end_pos == start_pos: if end_pos == start_pos:
visible = false visible = false
else: else:
visible = true visible = true
if Global.can_draw and Global.has_focus and point_in_rectangle(mouse_pos, polygon[0], polygon[2]) and Global.selected_pixels.size() > 0 and (Global.current_left_tool == "RectSelect" or Global.current_right_tool == "RectSelect"): if Global.can_draw and Global.has_focus and point_in_rectangle(mouse_pos, polygon[0], polygon[2]) and Global.selected_pixels.size() > 0 and (Global.current_tools[0] == Global.Tools.RECTSELECT or Global.current_tools[1] == Global.Tools.RECTSELECT):
get_parent().get_parent().mouse_default_cursor_shape = Input.CURSOR_MOVE get_parent().get_parent().mouse_default_cursor_shape = Input.CURSOR_MOVE
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
if (Global.current_left_tool == "RectSelect" && Input.is_action_just_pressed("left_mouse")) || (Global.current_right_tool == "RectSelect" && Input.is_action_just_pressed("right_mouse")): if (Global.current_tools[0] == Global.Tools.RECTSELECT && Input.is_action_just_pressed("left_mouse")) || (Global.current_tools[1] == Global.Tools.RECTSELECT && Input.is_action_just_pressed("right_mouse")):
# Begin dragging # Begin dragging
is_dragging = true is_dragging = true
if Input.is_key_pressed(KEY_SHIFT): if Input.is_key_pressed(KEY_SHIFT):
@ -72,7 +72,7 @@ func _process(_delta : float) -> void:
get_parent().get_parent().mouse_default_cursor_shape = Input.CURSOR_ARROW get_parent().get_parent().mouse_default_cursor_shape = Input.CURSOR_ARROW
if is_dragging: if is_dragging:
if (Global.current_left_tool == "RectSelect" && Input.is_action_pressed("left_mouse")) || (Global.current_right_tool == "RectSelect" && Input.is_action_pressed("right_mouse")): if (Global.current_tools[0] == Global.Tools.RECTSELECT && Input.is_action_pressed("left_mouse")) || (Global.current_tools[1] == Global.Tools.RECTSELECT && Input.is_action_pressed("right_mouse")):
# Drag # Drag
start_pos.x = orig_x + mouse_pos_floored.x start_pos.x = orig_x + mouse_pos_floored.x
end_pos.x = diff_x + mouse_pos_floored.x end_pos.x = diff_x + mouse_pos_floored.x
@ -84,7 +84,7 @@ func _process(_delta : float) -> void:
polygon[2] = end_pos polygon[2] = end_pos
polygon[3] = Vector2(start_pos.x, end_pos.y) polygon[3] = Vector2(start_pos.x, end_pos.y)
if (Global.current_left_tool == "RectSelect" && Input.is_action_just_released("left_mouse")) || (Global.current_right_tool == "RectSelect" && Input.is_action_just_released("right_mouse")): if (Global.current_tools[0] == Global.Tools.RECTSELECT && Input.is_action_just_released("left_mouse")) || (Global.current_tools[1] == Global.Tools.RECTSELECT && Input.is_action_just_released("right_mouse")):
# Release Drag # Release Drag
is_dragging = false is_dragging = false
if move_pixels: if move_pixels:

View file

@ -12,76 +12,52 @@ func _on_BrushButton_pressed() -> void:
_on_DeleteButton_pressed() _on_DeleteButton_pressed()
return return
# Change left brush # Change brush
if Global.brush_type_window_position == "left": Global.current_brush_types[Global.brush_type_window_position] = brush_type
Global.current_left_brush_type = brush_type Global.custom_brush_indexes[Global.brush_type_window_position] = custom_brush_index
Global.custom_left_brush_index = custom_brush_index if custom_brush_index > -1: # Custom brush
if custom_brush_index > -1: # Custom brush if Global.current_tools[Global.brush_type_window_position] == Global.Tools.PENCIL:
if Global.current_left_tool == "Pencil": Global.color_interpolation_containers[Global.brush_type_window_position].visible = true
Global.left_color_interpolation_container.visible = true
# if hint_tooltip == "": # if hint_tooltip == "":
# Global.left_brush_type_label.text = tr("Custom brush") # Global.left_brush_type_label.text = tr("Custom brush")
# else: # else:
# Global.left_brush_type_label.text = tr("Brush:") + " %s" % hint_tooltip # Global.left_brush_type_label.text = tr("Brush:") + " %s" % hint_tooltip
elif custom_brush_index == -3: # Pixel brush elif custom_brush_index == -3: # Pixel brush
Global.left_color_interpolation_container.visible = false Global.color_interpolation_containers[Global.brush_type_window_position].visible = false
# Global.left_brush_type_label.text = tr("Brush: Pixel") # Global.left_brush_type_label.text = tr("Brush: Pixel")
elif custom_brush_index == -2: # Circle brush elif custom_brush_index == -2: # Circle brush
Global.left_color_interpolation_container.visible = false Global.color_interpolation_containers[Global.brush_type_window_position].visible = false
# Global.left_brush_type_label.text = tr("Brush: Circle") # Global.left_brush_type_label.text = tr("Brush: Circle")
elif custom_brush_index == -1: # Filled Circle brush elif custom_brush_index == -1: # Filled Circle brush
Global.left_color_interpolation_container.visible = false Global.color_interpolation_containers[Global.brush_type_window_position].visible = false
# Global.left_brush_type_label.text = tr("Brush: Filled Circle") # Global.left_brush_type_label.text = tr("Brush: Filled Circle")
Global.update_left_custom_brush() Global.update_custom_brush(Global.brush_type_window_position)
Global.brushes_popup.hide() Global.brushes_popup.hide()
else: # Change right brush
Global.current_right_brush_type = brush_type
Global.custom_right_brush_index = custom_brush_index
if custom_brush_index > -1:
if Global.current_right_tool == "Pencil":
Global.right_color_interpolation_container.visible = true
# if hint_tooltip == "":
# Global.right_brush_type_label.text = tr("Custom brush")
# else:
# Global.right_brush_type_label.text = tr("Brush:") + " %s" % hint_tooltip
elif custom_brush_index == -3: # Pixel brush
Global.right_color_interpolation_container.visible = false
# Global.right_brush_type_label.text = tr("Brush: Pixel")
elif custom_brush_index == -2: # Circle brush
Global.right_color_interpolation_container.visible = false
# Global.right_brush_type_label.text = tr("Brush: Circle")
elif custom_brush_index == -1: # Filled Circle brush
Global.right_color_interpolation_container.visible = false
# Global.right_brush_type_label.text = tr("Brush: Filled Circle")
Global.update_right_custom_brush()
Global.brushes_popup.hide()
func _on_DeleteButton_pressed() -> void: func _on_DeleteButton_pressed() -> void:
if brush_type == Global.Brush_Types.CUSTOM: if brush_type == Global.Brush_Types.CUSTOM:
if Global.custom_left_brush_index == custom_brush_index: if Global.custom_brush_indexes[0] == custom_brush_index:
Global.custom_left_brush_index = -3 Global.custom_brush_indexes[0] = -3
Global.current_left_brush_type = Global.Brush_Types.PIXEL Global.current_brush_types[0] = Global.Brush_Types.PIXEL
# Global.left_brush_type_label.text = "Brush: Pixel" # Global.left_brush_type_label.text = "Brush: Pixel"
Global.update_left_custom_brush() Global.update_custom_brush(0)
if Global.custom_right_brush_index == custom_brush_index: if Global.custom_brush_indexes[1] == custom_brush_index:
Global.custom_right_brush_index = -3 Global.custom_brush_indexes[1] = -3
Global.current_right_brush_type = Global.Brush_Types.PIXEL Global.current_brush_types[1] = Global.Brush_Types.PIXEL
# Global.right_brush_type_label.text = "Brush: Pixel" # Global.right_brush_type_label.text = "Brush: Pixel"
Global.update_right_custom_brush() Global.update_custom_brush(1)
var project_brush_index = custom_brush_index - Global.brushes_from_files var project_brush_index = custom_brush_index - Global.brushes_from_files
Global.undos += 1 Global.undos += 1
Global.undo_redo.create_action("Delete Custom Brush") Global.undo_redo.create_action("Delete Custom Brush")
for i in range(project_brush_index, Global.project_brush_container.get_child_count()): for i in range(project_brush_index, Global.project_brush_container.get_child_count()):
var bb = Global.project_brush_container.get_child(i) var bb = Global.project_brush_container.get_child(i)
if Global.custom_left_brush_index == bb.custom_brush_index: if Global.custom_brush_indexes[0] == bb.custom_brush_index:
Global.custom_left_brush_index -= 1 Global.custom_brush_indexes[0] -= 1
if Global.custom_right_brush_index == bb.custom_brush_index: if Global.custom_brush_indexes[1] == bb.custom_brush_index:
Global.custom_right_brush_index -= 1 Global.custom_brush_indexes[1] -= 1
Global.undo_redo.add_do_property(bb, "custom_brush_index", bb.custom_brush_index - 1) Global.undo_redo.add_do_property(bb, "custom_brush_index", bb.custom_brush_index - 1)
Global.undo_redo.add_undo_property(bb, "custom_brush_index", bb.custom_brush_index) Global.undo_redo.add_undo_property(bb, "custom_brush_index", bb.custom_brush_index)

View file

@ -1,7 +1,37 @@
[gd_scene load_steps=2 format=2] [gd_scene load_steps=6 format=2]
[ext_resource path="res://src/UI/BrushButton.tscn" type="PackedScene" id=2] [ext_resource path="res://src/UI/BrushButton.tscn" type="PackedScene" id=2]
[sub_resource type="Image" id=5]
data = {
"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 255, 0, 255, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 255, 0, 255, 0, 0, 0, 0, 0, 0 ),
"format": "LumAlpha8",
"height": 9,
"mipmaps": false,
"width": 9
}
[sub_resource type="ImageTexture" id=2]
flags = 3
flags = 3
image = SubResource( 5 )
size = Vector2( 9, 9 )
[sub_resource type="Image" id=6]
data = {
"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 255, 0, 255, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 0, 0, 0, 0, 0, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 0, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 0, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 0, 0, 0, 0, 0, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 255, 0, 255, 0, 0, 0, 0, 0, 0 ),
"format": "LumAlpha8",
"height": 9,
"mipmaps": false,
"width": 9
}
[sub_resource type="ImageTexture" id=4]
flags = 3
flags = 3
image = SubResource( 6 )
size = Vector2( 9, 9 )
[node name="BrushesPopup" type="Popup"] [node name="BrushesPopup" type="Popup"]
margin_right = 226.0 margin_right = 226.0
margin_bottom = 144.0 margin_bottom = 144.0
@ -34,21 +64,27 @@ hint_tooltip = "Pixel brush"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
[node name="CircleBrushButton" parent="TabContainer/File/FileBrushContainer" instance=ExtResource( 2 )] [node name="CircleBrushButton" parent="TabContainer/File/FileBrushContainer" instance=ExtResource( 2 )]
margin_left = 35.0 margin_left = 36.0
margin_right = 67.0 margin_right = 68.0
hint_tooltip = "Filled circle brush" hint_tooltip = "Filled circle brush"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
brush_type = 1 brush_type = 1
custom_brush_index = -2 custom_brush_index = -2
[node name="BrushTexture" parent="TabContainer/File/FileBrushContainer/CircleBrushButton" index="0"]
texture = SubResource( 2 )
[node name="FilledCircleBrushButton" parent="TabContainer/File/FileBrushContainer" instance=ExtResource( 2 )] [node name="FilledCircleBrushButton" parent="TabContainer/File/FileBrushContainer" instance=ExtResource( 2 )]
margin_left = 70.0 margin_left = 72.0
margin_right = 102.0 margin_right = 104.0
hint_tooltip = "Circle brush" hint_tooltip = "Circle brush"
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
brush_type = 2 brush_type = 2
custom_brush_index = -1 custom_brush_index = -1
[node name="BrushTexture" parent="TabContainer/File/FileBrushContainer/FilledCircleBrushButton" index="0"]
texture = SubResource( 4 )
[node name="Project" type="ScrollContainer" parent="TabContainer"] [node name="Project" type="ScrollContainer" parent="TabContainer"]
visible = false visible = false
anchor_right = 1.0 anchor_right = 1.0
@ -63,3 +99,7 @@ scroll_horizontal_enabled = false
[node name="ProjectBrushContainer" type="GridContainer" parent="TabContainer/Project"] [node name="ProjectBrushContainer" type="GridContainer" parent="TabContainer/Project"]
columns = 5 columns = 5
[editable path="TabContainer/File/FileBrushContainer/CircleBrushButton"]
[editable path="TabContainer/File/FileBrushContainer/FilledCircleBrushButton"]

View file

@ -1,32 +1,25 @@
extends VBoxContainer extends VBoxContainer
var previous_left_color := Color.black var previous_colors := [Color.black, Color.white]
var previous_right_color := Color.white
func _on_ColorSwitch_pressed() -> void: func _on_ColorSwitch_pressed() -> void:
var temp: Color = Global.left_color_picker.color var temp : Color = Global.color_pickers[0].color
Global.left_color_picker.color = Global.right_color_picker.color Global.color_pickers[0].color = Global.color_pickers[1].color
Global.right_color_picker.color = temp Global.color_pickers[1].color = temp
Global.update_left_custom_brush() Global.update_custom_brush(0)
Global.update_right_custom_brush() Global.update_custom_brush(1)
func _on_ColorPickerButton_color_changed(color : Color, right : bool): func _on_ColorPickerButton_color_changed(color : Color, right : bool):
var mouse_button := int(right)
# If the color changed while it's on full transparency, make it opaque (GH issue #54) # If the color changed while it's on full transparency, make it opaque (GH issue #54)
if right: if color.a == 0:
if color.a == 0: if previous_colors[mouse_button].r != color.r or previous_colors[mouse_button].g != color.g or previous_colors[mouse_button].b != color.b:
if previous_right_color.r != color.r or previous_right_color.g != color.g or previous_right_color.b != color.b: Global.color_pickers[mouse_button].color.a = 1
Global.right_color_picker.color.a = 1 Global.update_custom_brush(mouse_button)
Global.update_right_custom_brush() previous_colors[mouse_button] = color
previous_right_color = color
else:
if color.a == 0:
if previous_left_color.r != color.r or previous_left_color.g != color.g or previous_left_color.b != color.b:
Global.left_color_picker.color.a = 1
Global.update_left_custom_brush()
previous_left_color = color
func _on_ColorPickerButton_pressed() -> void: func _on_ColorPickerButton_pressed() -> void:
@ -38,10 +31,10 @@ func _on_ColorPickerButton_popup_closed() -> void:
func _on_ColorDefaults_pressed() -> void: func _on_ColorDefaults_pressed() -> void:
Global.left_color_picker.color = Color.black Global.color_pickers[0].color = Color.black
Global.right_color_picker.color = Color.white Global.color_pickers[1].color = Color.white
Global.update_left_custom_brush() Global.update_custom_brush(0)
Global.update_right_custom_brush() Global.update_custom_brush(1)
func _on_FitToFrameButton_pressed() -> void: func _on_FitToFrameButton_pressed() -> void:
@ -57,132 +50,89 @@ func _on_100ZoomButton_pressed() -> void:
func _on_BrushTypeButton_pressed(right : bool) -> void: func _on_BrushTypeButton_pressed(right : bool) -> void:
if right: var mouse_button := int(right)
Global.brushes_popup.popup(Rect2(Global.right_brush_type_button.rect_global_position, Vector2(226, 72))) Global.brushes_popup.popup(Rect2(Global.brush_type_buttons[mouse_button].rect_global_position, Vector2(226, 72)))
Global.brush_type_window_position = "right" Global.brush_type_window_position = mouse_button
else:
Global.brushes_popup.popup(Rect2(Global.left_brush_type_button.rect_global_position, Vector2(226, 72)))
Global.brush_type_window_position = "left"
func _on_BrushSizeEdit_value_changed(value : float, right : bool) -> void: func _on_BrushSizeEdit_value_changed(value : float, right : bool) -> void:
var mouse_button := int(right)
var new_size = int(value) var new_size = int(value)
if right: Global.brush_size_edits[mouse_button].value = value
Global.right_brush_size_edit.value = value Global.brush_size_sliders[mouse_button].value = value
Global.right_brush_size_slider.value = value Global.brush_sizes[mouse_button] = new_size
Global.right_brush_size = new_size Global.update_custom_brush(mouse_button)
Global.update_right_custom_brush()
else:
Global.left_brush_size_edit.value = value
Global.left_brush_size_slider.value = value
Global.left_brush_size = new_size
Global.update_left_custom_brush()
func _on_PixelPerfectMode_toggled(button_pressed : bool, right : bool) -> void: func _on_PixelPerfectMode_toggled(button_pressed : bool, right : bool) -> void:
if right: var mouse_button := int(right)
Global.right_pixel_perfect = button_pressed Global.pixel_perfect[mouse_button] = button_pressed
else:
Global.left_pixel_perfect = button_pressed
func _on_InterpolateFactor_value_changed(value : float, right : bool) -> void: func _on_InterpolateFactor_value_changed(value : float, right : bool) -> void:
if right: var mouse_button := int(right)
Global.right_interpolate_spinbox.value = value Global.interpolate_spinboxes[mouse_button].value = value
Global.right_interpolate_slider.value = value Global.interpolate_sliders[mouse_button].value = value
Global.update_right_custom_brush() Global.update_custom_brush(mouse_button)
else:
Global.left_interpolate_spinbox.value = value
Global.left_interpolate_slider.value = value
Global.update_left_custom_brush()
func _on_FillAreaOptions_item_selected(ID : int, right : bool) -> void: func _on_FillAreaOptions_item_selected(ID : int, right : bool) -> void:
if right: var mouse_button := int(right)
Global.right_fill_area = ID Global.fill_areas[mouse_button] = ID
else:
Global.left_fill_area = ID
func _on_FillWithOptions_item_selected(ID : int, right : bool) -> void: func _on_FillWithOptions_item_selected(ID : int, right : bool) -> void:
if right: var mouse_button := int(right)
Global.right_fill_with = ID Global.fill_with[mouse_button] = ID
if ID == 1: if ID == 1:
Global.right_fill_pattern_container.visible = true Global.fill_pattern_containers[mouse_button].visible = true
else:
Global.right_fill_pattern_container.visible = false
else: else:
Global.left_fill_with = ID Global.fill_pattern_containers[mouse_button].visible = false
if ID == 1:
Global.left_fill_pattern_container.visible = true
else:
Global.left_fill_pattern_container.visible = false
func _on_PatternTypeButton_pressed(right : bool) -> void: func _on_PatternTypeButton_pressed(right : bool) -> void:
if right: var mouse_button := int(right)
Global.pattern_window_position = "right" Global.pattern_window_position = mouse_button
Global.patterns_popup.popup(Rect2(Global.right_brush_type_button.rect_global_position, Vector2(226, 72))) Global.patterns_popup.popup(Rect2(Global.brush_type_buttons[mouse_button].rect_global_position, Vector2(226, 72)))
else:
Global.pattern_window_position = "left"
Global.patterns_popup.popup(Rect2(Global.left_brush_type_button.rect_global_position, Vector2(226, 72)))
func _on_PatternOffsetX_value_changed(value : float, right : bool) -> void: func _on_PatternOffsetX_value_changed(value : float, right : bool) -> void:
if right: var mouse_button := int(right)
Global.right_fill_pattern_offset.x = value Global.fill_pattern_offsets[mouse_button].x = value
else:
Global.left_fill_pattern_offset.x = value
func _on_PatternOffsetY_value_changed(value : float, right : bool) -> void: func _on_PatternOffsetY_value_changed(value : float, right : bool) -> void:
if right: var mouse_button := int(right)
Global.right_fill_pattern_offset.y = value Global.fill_pattern_offsets[mouse_button].y = value
else:
Global.left_fill_pattern_offset.y = value
func _on_LightenDarken_item_selected(ID : int, right : bool) -> void: func _on_LightenDarken_item_selected(ID : int, right : bool) -> void:
if right: var mouse_button := int(right)
Global.right_ld = ID Global.ld_modes[mouse_button] = ID
else:
Global.left_ld = ID
func _on_LDAmount_value_changed(value : float, right : bool) -> void: func _on_LDAmount_value_changed(value : float, right : bool) -> void:
if right: var mouse_button := int(right)
Global.right_ld_amount = value / 100 Global.ld_amounts[mouse_button] = value / 100
Global.right_ld_amount_slider.value = value Global.ld_amount_sliders[mouse_button].value = value
Global.right_ld_amount_spinbox.value = value Global.ld_amount_spinboxes[mouse_button].value = value
else:
Global.left_ld_amount = value / 100
Global.left_ld_amount_slider.value = value
Global.left_ld_amount_spinbox.value = value
func _on_ForColorOptions_item_selected(ID : int, right : bool) -> void: func _on_ForColorOptions_item_selected(ID : int, right : bool) -> void:
if right: var mouse_button := int(right)
Global.right_color_picker_for = ID Global.color_picker_for[mouse_button] = ID
else:
Global.left_color_picker_for = ID
func _on_ZoomModeOptions_item_selected(ID : int, right : bool) -> void: func _on_ZoomModeOptions_item_selected(ID : int, right : bool) -> void:
if right: var mouse_button := int(right)
Global.right_zoom_mode = ID Global.zoom_modes[mouse_button] = ID
else:
Global.left_zoom_mode = ID
func _on_HorizontalMirroring_toggled(button_pressed : bool, right : bool) -> void: func _on_HorizontalMirroring_toggled(button_pressed : bool, right : bool) -> void:
if right: var mouse_button := int(right)
Global.right_horizontal_mirror = button_pressed Global.horizontal_mirror[mouse_button] = button_pressed
else:
Global.left_horizontal_mirror = button_pressed
func _on_VerticalMirroring_toggled(button_pressed : bool, right : bool) -> void: func _on_VerticalMirroring_toggled(button_pressed : bool, right : bool) -> void:
if right: var mouse_button := int(right)
Global.right_vertical_mirror = button_pressed Global.vertical_mirror[mouse_button] = button_pressed
else:
Global.left_vertical_mirror = button_pressed

View file

@ -75,9 +75,7 @@ func _on_CreateNewImage_confirmed() -> void:
var fill_color : Color = fill_color_node.color var fill_color : Color = fill_color_node.color
Global.clear_canvases() Global.clear_canvases()
Global.layers.clear() Global.layers.clear()
# Store [Layer name (0), Layer visibility boolean (1), Layer lock boolean (2), Frame container (3), Global.layers.append(Layer.new())
# will new frames be linked boolean (4), Array of linked frames (5)]
Global.layers.append([tr("Layer") + " 0", true, false, HBoxContainer.new(), false, []])
Global.canvas = load("res://src/Canvas.tscn").instance() Global.canvas = load("res://src/Canvas.tscn").instance()
Global.canvas.size = Vector2(width, height).floor() Global.canvas.size = Vector2(width, height).floor()
@ -89,8 +87,8 @@ func _on_CreateNewImage_confirmed() -> void:
Global.layers = Global.layers # To trigger Global.layers_changed() Global.layers = Global.layers # To trigger Global.layers_changed()
Global.project_has_changed = false Global.project_has_changed = false
if fill_color.a > 0: if fill_color.a > 0:
Global.canvas.layers[0][0].fill(fill_color) Global.canvas.layers[0].image.fill(fill_color)
Global.canvas.layers[0][0].lock() Global.canvas.layers[0].image.lock()
Global.canvas.update_texture(0) Global.canvas.update_texture(0)

View file

@ -147,8 +147,8 @@ func process_spritesheet() -> void:
# Range of frames determined by tags # Range of frames determined by tags
var frames := [] var frames := []
if frame_current_tag > 0: if frame_current_tag > 0:
var frame_start = Global.animation_tags[frame_current_tag - 1][2] var frame_start = Global.animation_tags[frame_current_tag - 1].from
var frame_end = Global.animation_tags[frame_current_tag - 1][3] var frame_end = Global.animation_tags[frame_current_tag - 1].to
frames = Global.canvases.slice(frame_start-1, frame_end-1, 1, true) frames = Global.canvases.slice(frame_start-1, frame_end-1, 1, true)
else: else:
frames = Global.canvases frames = Global.canvases
@ -283,8 +283,8 @@ func get_proccessed_image_animation_tag_and_start_id(processed_image_id : int) -
for animation_tag in Global.animation_tags: for animation_tag in Global.animation_tags:
# Check if processed image is in frame tag and assign frame tag and start id if yes # Check if processed image is in frame tag and assign frame tag and start id if yes
# Then stop # Then stop
if (processed_image_id + 1) >= animation_tag[2] and (processed_image_id + 1) <= animation_tag[3]: if (processed_image_id + 1) >= animation_tag.from and (processed_image_id + 1) <= animation_tag.to:
result_animation_tag_and_start_id = [animation_tag[0], animation_tag[2]] result_animation_tag_and_start_id = [animation_tag.name, animation_tag.from]
break break
return result_animation_tag_and_start_id return result_animation_tag_and_start_id
@ -365,17 +365,17 @@ func blend_layers(image: Image, canvas: Canvas, origin: Vector2 = Vector2(0, 0))
image.lock() image.lock()
var layer_i := 0 var layer_i := 0
for layer in canvas.layers: for layer in canvas.layers:
if Global.layers[layer_i][1]: if Global.layers[layer_i].visible:
var layer_image := Image.new() var layer_image := Image.new()
layer_image.copy_from(layer[0]) layer_image.copy_from(layer.image)
layer_image.lock() layer_image.lock()
if layer[2] < 1: # If we have layer transparency if layer.opacity < 1: # If we have layer transparency
for xx in layer_image.get_size().x: for xx in layer_image.get_size().x:
for yy in layer_image.get_size().y: for yy in layer_image.get_size().y:
var pixel_color := layer_image.get_pixel(xx, yy) var pixel_color := layer_image.get_pixel(xx, yy)
var alpha : float = pixel_color.a * layer[2] var alpha : float = pixel_color.a * layer.opacity
layer_image.set_pixel(xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha)) layer_image.set_pixel(xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha))
canvas.blend_rect(image, layer_image, Rect2(canvas.position, canvas.size), origin) DrawingAlgos.blend_rect(image, layer_image, Rect2(canvas.position, canvas.size), origin)
layer_i += 1 layer_i += 1
image.unlock() image.unlock()
@ -454,7 +454,7 @@ func create_frame_tag_list() -> void:
# Repopulate list with current tag list # Repopulate list with current tag list
for item in Global.animation_tags: for item in Global.animation_tags:
frame_container.add_item(item[0]) frame_container.add_item(item.name)
func store_export_settings() -> void: func store_export_settings() -> void:

View file

@ -23,7 +23,7 @@ func _ready() -> void:
func _on_HSVDialog_about_to_show() -> void: func _on_HSVDialog_about_to_show() -> void:
current_layer = Global.canvas.layers[Global.current_layer][0] current_layer = Global.canvas.layers[Global.current_layer].image
preview_image.copy_from(current_layer) preview_image.copy_from(current_layer)
update_preview() update_preview()
@ -35,9 +35,9 @@ func _on_Cancel_pressed() -> void:
func _on_Apply_pressed() -> void: func _on_Apply_pressed() -> void:
Global.canvas.handle_undo("Draw") Global.canvas.handle_undo("Draw")
Global.canvas.adjust_hsv(current_layer,0,hue_slider.value) DrawingAlgos.adjust_hsv(current_layer,0,hue_slider.value)
Global.canvas.adjust_hsv(current_layer,1,sat_slider.value) DrawingAlgos.adjust_hsv(current_layer,1,sat_slider.value)
Global.canvas.adjust_hsv(current_layer,2,val_slider.value) DrawingAlgos.adjust_hsv(current_layer,2,val_slider.value)
Global.canvas.update_texture(Global.current_layer) Global.canvas.update_texture(Global.current_layer)
Global.canvas.handle_redo("Draw") Global.canvas.handle_redo("Draw")
reset() reset()
@ -57,9 +57,9 @@ func reset() -> void:
func update_preview() -> void: func update_preview() -> void:
preview_image.copy_from(current_layer) preview_image.copy_from(current_layer)
Global.canvas.adjust_hsv(preview_image,0,hue_slider.value) DrawingAlgos.adjust_hsv(preview_image,0,hue_slider.value)
Global.canvas.adjust_hsv(preview_image,1,sat_slider.value) DrawingAlgos.adjust_hsv(preview_image,1,sat_slider.value)
Global.canvas.adjust_hsv(preview_image,2,val_slider.value) DrawingAlgos.adjust_hsv(preview_image,2,val_slider.value)
preview_texture.create_from_image(preview_image, 0) preview_texture.create_from_image(preview_image, 0)
preview.texture = preview_texture preview.texture = preview_texture

View file

@ -41,7 +41,7 @@ func _on_ImportSprites_files_selected(paths : PoolStringArray) -> void:
Global.layers.clear() Global.layers.clear()
# Store [Layer name (0), Layer visibility boolean (1), Layer lock boolean (2), Frame container (3), # Store [Layer name (0), Layer visibility boolean (1), Layer lock boolean (2), Frame container (3),
# will new frames be linked boolean (4), Array of linked frames (5)] # will new frames be linked boolean (4), Array of linked frames (5)]
Global.layers.append([tr("Layer") + " 0", true, false, HBoxContainer.new(), false, []]) Global.layers.append(Layer.new())
Global.current_layer = 0 Global.current_layer = 0
var first_path : String = paths[0] var first_path : String = paths[0]
@ -64,22 +64,14 @@ func _on_ImportSprites_files_selected(paths : PoolStringArray) -> void:
canvas.size = image.get_size() canvas.size = image.get_size()
image.convert(Image.FORMAT_RGBA8) image.convert(Image.FORMAT_RGBA8)
image.lock() image.lock()
var tex := ImageTexture.new() canvas.layers.append(Cel.new(image, 1))
tex.create_from_image(image, 0)
# Store [Image, ImageTexture, Opacity]
canvas.layers.append([image, tex, 1])
for _i in range(1, Global.layers.size()): for _i in range(1, Global.layers.size()):
var empty_sprite := Image.new() var empty_sprite := Image.new()
empty_sprite.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8) empty_sprite.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8)
empty_sprite.fill(Color(0, 0, 0, 0)) empty_sprite.fill(Color(0, 0, 0, 0))
empty_sprite.lock() empty_sprite.lock()
canvas.layers.append(Cel.new(empty_sprite, 1))
var empty_tex := ImageTexture.new()
empty_tex.create_from_image(empty_sprite, 0)
# Store [Image, ImageTexture, Opacity]
canvas.layers.append([empty_sprite, empty_tex, 1])
canvas.frame = i canvas.frame = i
Global.canvases.append(canvas) Global.canvases.append(canvas)
@ -119,21 +111,14 @@ func _on_ImportSprites_files_selected(paths : PoolStringArray) -> void:
canvas.size = cropped_image.get_size() canvas.size = cropped_image.get_size()
cropped_image.convert(Image.FORMAT_RGBA8) cropped_image.convert(Image.FORMAT_RGBA8)
cropped_image.lock() cropped_image.lock()
var tex := ImageTexture.new() canvas.layers.append(Cel.new(cropped_image, 1))
tex.create_from_image(cropped_image, 0)
# Store [Image, ImageTexture, Opacity]
canvas.layers.append([cropped_image, tex, 1])
for _i in range(1, Global.layers.size()): for _i in range(1, Global.layers.size()):
var empty_sprite := Image.new() var empty_sprite := Image.new()
empty_sprite.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8) empty_sprite.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8)
empty_sprite.fill(Color(0, 0, 0, 0)) empty_sprite.fill(Color(0, 0, 0, 0))
empty_sprite.lock() empty_sprite.lock()
canvas.layers.append(Cel.new(empty_sprite, 1))
var empty_tex := ImageTexture.new()
empty_tex.create_from_image(empty_sprite, 0)
# Store [Image, ImageTexture, Opacity]
canvas.layers.append([empty_sprite, empty_tex, 1])
canvas.frame = i canvas.frame = i
Global.canvases.append(canvas) Global.canvases.append(canvas)

View file

@ -10,7 +10,7 @@ func _on_OutlineDialog_confirmed() -> void:
var diagonal : bool = $OptionsContainer/DiagonalCheckBox.pressed var diagonal : bool = $OptionsContainer/DiagonalCheckBox.pressed
var inside_image : bool = $OptionsContainer/InsideImageCheckBox.pressed var inside_image : bool = $OptionsContainer/InsideImageCheckBox.pressed
var image : Image = Global.canvas.layers[Global.current_layer][0] var image : Image = Global.canvas.layers[Global.current_layer].image
if image.is_invisible(): if image.is_invisible():
return return
var new_image := Image.new() var new_image := Image.new()

View file

@ -1,575 +0,0 @@
extends AcceptDialog
onready var tree : Tree = $HSplitContainer/Tree
onready var right_side : VBoxContainer = $HSplitContainer/ScrollContainer/VBoxContainer
onready var general = $HSplitContainer/ScrollContainer/VBoxContainer/General
onready var languages = $HSplitContainer/ScrollContainer/VBoxContainer/Languages
onready var themes = $HSplitContainer/ScrollContainer/VBoxContainer/Themes
onready var canvas = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas
onready var image = $HSplitContainer/ScrollContainer/VBoxContainer/Image
onready var shortcuts = $HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts
onready var open_last_project_button = $HSplitContainer/ScrollContainer/VBoxContainer/General/OpenLastProject
onready var smooth_zoom_button = $HSplitContainer/ScrollContainer/VBoxContainer/General/SmoothZoom
onready var sensitivity_option = $HSplitContainer/ScrollContainer/VBoxContainer/General/PressureSentivity/PressureSensitivityOptionButton
onready var left_tool_icon = $HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer/LeftToolIconCheckbox
onready var right_tool_icon = $HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer/RightToolIconCheckbox
onready var default_width_value = $HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions/ImageDefaultWidth
onready var default_height_value = $HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions/ImageDefaultHeight
onready var default_fill_color = $HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions/DefaultFillColor
onready var grid_width_value = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions/GridWidthValue
onready var grid_height_value = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions/GridHeightValue
onready var grid_color = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions/GridColor
onready var guide_color = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GuideOptions/GuideColor
onready var checker_size_value = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions/CheckerSizeValue
onready var checker_color_1 = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions/CheckerColor1
onready var checker_color_2 = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions/CheckerColor2
# Shortcuts
onready var theme_font_color : Color = $Popups/ShortcutSelector/EnteredShortcut.get_color("font_color")
var default_shortcuts_preset := {}
var custom_shortcuts_preset := {}
var action_being_edited := ""
var shortcut_already_assigned = false
var old_input_event : InputEventKey
var new_input_event : InputEventKey
func _ready() -> void:
# Disable input until the shortcut selector is displayed
set_process_input(false)
# Replace OK with Close since preference changes are being applied immediately, not after OK confirmation
get_ok().text = tr("Close")
for child in languages.get_children():
if child is Button:
child.connect("pressed", self, "_on_Language_pressed", [child])
child.hint_tooltip = child.name
for child in themes.get_children():
if child is Button:
child.connect("pressed", self, "_on_Theme_pressed", [child])
if Global.config_cache.has_section_key("preferences", "theme"):
var theme_id = Global.config_cache.get_value("preferences", "theme")
change_theme(theme_id)
themes.get_child(theme_id).pressed = true
else:
change_theme(0)
themes.get_child(0).pressed = true
# Set default values for General options
if Global.config_cache.has_section_key("preferences", "open_last_project"):
Global.open_last_project = Global.config_cache.get_value("preferences", "open_last_project")
open_last_project_button.pressed = Global.open_last_project
if Global.config_cache.has_section_key("preferences", "smooth_zoom"):
Global.smooth_zoom = Global.config_cache.get_value("preferences", "smooth_zoom")
smooth_zoom_button.pressed = Global.smooth_zoom
if Global.config_cache.has_section_key("preferences", "pressure_sensitivity"):
Global.pressure_sensitivity_mode = Global.config_cache.get_value("preferences", "pressure_sensitivity")
sensitivity_option.selected = Global.pressure_sensitivity_mode
if Global.config_cache.has_section_key("preferences", "show_left_tool_icon"):
Global.show_left_tool_icon = Global.config_cache.get_value("preferences", "show_left_tool_icon")
left_tool_icon.pressed = Global.show_left_tool_icon
if Global.config_cache.has_section_key("preferences", "show_right_tool_icon"):
Global.show_right_tool_icon = Global.config_cache.get_value("preferences", "show_right_tool_icon")
right_tool_icon.pressed = Global.show_right_tool_icon
# Get autosave settings
if Global.config_cache.has_section_key("preferences", "autosave_interval"):
var autosave_interval = Global.config_cache.get_value("preferences", "autosave_interval")
OpenSave.set_autosave_interval(autosave_interval)
general.get_node("AutosaveInterval/AutosaveInterval").value = autosave_interval
if Global.config_cache.has_section_key("preferences", "enable_autosave"):
var enable_autosave = Global.config_cache.get_value("preferences", "enable_autosave")
OpenSave.toggle_autosave(enable_autosave)
general.get_node("EnableAutosave").pressed = enable_autosave
# Set default values for Canvas options
if Global.config_cache.has_section_key("preferences", "grid_size"):
var grid_size = Global.config_cache.get_value("preferences", "grid_size")
Global.grid_width = int(grid_size.x)
Global.grid_height = int(grid_size.y)
grid_width_value.value = grid_size.x
grid_height_value.value = grid_size.y
if Global.config_cache.has_section_key("preferences", "grid_color"):
Global.grid_color = Global.config_cache.get_value("preferences", "grid_color")
grid_color.color = Global.grid_color
if Global.config_cache.has_section_key("preferences", "checker_size"):
var checker_size = Global.config_cache.get_value("preferences", "checker_size")
Global.checker_size = int(checker_size)
checker_size_value.value = checker_size
if Global.config_cache.has_section_key("preferences", "checker_color_1"):
Global.checker_color_1 = Global.config_cache.get_value("preferences", "checker_color_1")
checker_color_1.color = Global.checker_color_1
if Global.config_cache.has_section_key("preferences", "checker_color_2"):
Global.checker_color_2 = Global.config_cache.get_value("preferences", "checker_color_2")
checker_color_2.color = Global.checker_color_2
Global.transparent_checker._ready()
if Global.config_cache.has_section_key("preferences", "guide_color"):
Global.guide_color = Global.config_cache.get_value("preferences", "guide_color")
for canvas in Global.canvases:
for guide in canvas.get_children():
if guide is Guide:
guide.default_color = Global.guide_color
guide_color.color = Global.guide_color
# Set default values for Image
if Global.config_cache.has_section_key("preferences", "default_width"):
var default_width = Global.config_cache.get_value("preferences", "default_width")
Global.default_image_width = int(default_width)
default_width_value.value = Global.default_image_width
if Global.config_cache.has_section_key("preferences", "default_height"):
var default_height = Global.config_cache.get_value("preferences", "default_height")
Global.default_image_height = int(default_height)
default_height_value.value = Global.default_image_height
if Global.config_cache.has_section_key("preferences", "default_fill_color"):
var fill_color = Global.config_cache.get_value("preferences", "default_fill_color")
Global.default_fill_color = fill_color
default_fill_color.color = Global.default_fill_color
guide_color.get_picker().presets_visible = false
grid_color.get_picker().presets_visible = false
checker_color_1.get_picker().presets_visible = false
checker_color_2.get_picker().presets_visible = false
default_fill_color.get_picker().presets_visible = false
# Get default preset for shortcuts from project input map
# Buttons in shortcuts selector should be called the same as actions
for shortcut_grid_item in shortcuts.get_node("Shortcuts").get_children():
if shortcut_grid_item is Button:
var input_events = InputMap.get_action_list(shortcut_grid_item.name)
if input_events.size() > 1:
printerr("Every shortcut action should have just one input event assigned in input map")
shortcut_grid_item.text = (input_events[0] as InputEventKey).as_text()
shortcut_grid_item.connect("pressed", self, "_on_Shortcut_button_pressed", [shortcut_grid_item])
default_shortcuts_preset[shortcut_grid_item.name] = input_events[0]
# Load custom shortcuts from the config file
custom_shortcuts_preset = default_shortcuts_preset.duplicate()
for action in default_shortcuts_preset:
var saved_input_event = Global.config_cache.get_value("shortcuts", action, 0)
if saved_input_event is InputEventKey:
custom_shortcuts_preset[action] = saved_input_event
var shortcuts_preset = Global.config_cache.get_value("shortcuts", "shortcuts_preset", 0)
shortcuts.get_node("HBoxContainer/PresetOptionButton").select(shortcuts_preset)
_on_PresetOptionButton_item_selected(shortcuts_preset)
func _input(event : InputEvent) -> void:
if event is InputEventKey:
if event.pressed:
if event.scancode == KEY_ESCAPE:
$Popups/ShortcutSelector.hide()
else:
# Check if shortcut was already used
for action in InputMap.get_actions():
for input_event in InputMap.get_action_list(action):
if input_event is InputEventKey:
if OS.get_scancode_string(input_event.get_scancode_with_modifiers()) == OS.get_scancode_string(event.get_scancode_with_modifiers()):
$Popups/ShortcutSelector/EnteredShortcut.text = tr("Already assigned")
$Popups/ShortcutSelector/EnteredShortcut.add_color_override("font_color", Color.crimson)
get_tree().set_input_as_handled()
shortcut_already_assigned = true
return
# Store new shortcut
shortcut_already_assigned = false
old_input_event = InputMap.get_action_list(action_being_edited)[0]
new_input_event = event
$Popups/ShortcutSelector/EnteredShortcut.text = OS.get_scancode_string(event.get_scancode_with_modifiers())
$Popups/ShortcutSelector/EnteredShortcut.add_color_override("font_color", theme_font_color)
get_tree().set_input_as_handled()
func _on_PreferencesDialog_about_to_show(changed_language := false) -> void:
var root := tree.create_item()
var general_button := tree.create_item(root)
var language_button := tree.create_item(root)
var theme_button := tree.create_item(root)
var canvas_button := tree.create_item(root)
var image_button := tree.create_item(root)
var shortcuts_button := tree.create_item(root)
general_button.set_text(0, " " + tr("General"))
# We use metadata to avoid being affected by translations
general_button.set_metadata(0, "General")
language_button.set_text(0, " " + tr("Language"))
language_button.set_metadata(0, "Language")
theme_button.set_text(0, " " + tr("Themes"))
theme_button.set_metadata(0, "Themes")
canvas_button.set_text(0, " " + tr("Canvas"))
canvas_button.set_metadata(0, "Canvas")
image_button.set_text(0, " " + tr("Image"))
image_button.set_metadata(0, "Image")
shortcuts_button.set_text(0, " " + tr("Shortcuts"))
shortcuts_button.set_metadata(0, "Shortcuts")
if changed_language:
language_button.select(0)
else:
general_button.select(0)
general.get_node("AutosaveInterval/AutosaveInterval").suffix = tr("minute(s)")
func _on_PreferencesDialog_popup_hide() -> void:
tree.clear()
func _on_Tree_item_selected() -> void:
for child in right_side.get_children():
child.visible = false
var selected : String = tree.get_selected().get_metadata(0)
if "General" in selected:
general.visible = true
elif "Language" in selected:
languages.visible = true
elif "Themes" in selected:
themes.visible = true
elif "Canvas" in selected:
canvas.visible = true
elif "Image" in selected:
image.visible = true
elif "Shortcuts" in selected:
shortcuts.visible = true
func _on_PressureSensitivityOptionButton_item_selected(id : int) -> void:
Global.pressure_sensitivity_mode = id
Global.config_cache.set_value("preferences", "pressure_sensitivity", id)
Global.config_cache.save("user://cache.ini")
func _on_SmoothZoom_pressed() -> void:
Global.smooth_zoom = !Global.smooth_zoom
Global.config_cache.set_value("preferences", "smooth_zoom", Global.smooth_zoom)
Global.config_cache.save("user://cache.ini")
func _on_Language_pressed(button : Button) -> void:
var index := 0
var i := -1
for child in languages.get_children():
if child is Button:
if child == button:
button.pressed = true
index = i
else:
child.pressed = false
i += 1
if index == -1:
TranslationServer.set_locale(OS.get_locale())
else:
TranslationServer.set_locale(Global.loaded_locales[index])
if "zh" in TranslationServer.get_locale():
Global.control.theme.default_font = preload("res://assets/fonts/CJK/NotoSansCJKtc-Regular.tres")
else:
Global.control.theme.default_font = preload("res://assets/fonts/Roboto-Regular.tres")
Global.config_cache.set_value("preferences", "locale", TranslationServer.get_locale())
Global.config_cache.save("user://cache.ini")
# Update Translations
Global.update_hint_tooltips()
_on_PreferencesDialog_popup_hide()
_on_PreferencesDialog_about_to_show(true)
func _on_Theme_pressed(button : Button) -> void:
var index := 0
var i := 0
for child in themes.get_children():
if child is Button:
if child == button:
button.pressed = true
index = i
else:
child.pressed = false
i += 1
change_theme(index)
Global.config_cache.set_value("preferences", "theme", index)
Global.config_cache.save("user://cache.ini")
func change_theme(ID : int) -> void:
var font = Global.control.theme.default_font
var main_theme : Theme
var top_menu_style
var ruler_style
if ID == 0: # Dark Theme
Global.theme_type = "Dark"
main_theme = preload("res://assets/themes/dark/theme.tres")
top_menu_style = preload("res://assets/themes/dark/top_menu_style.tres")
ruler_style = preload("res://assets/themes/dark/ruler_style.tres")
elif ID == 1: # Gray Theme
Global.theme_type = "Dark"
main_theme = preload("res://assets/themes/gray/theme.tres")
top_menu_style = preload("res://assets/themes/gray/top_menu_style.tres")
ruler_style = preload("res://assets/themes/dark/ruler_style.tres")
elif ID == 2: # Godot's Theme
Global.theme_type = "Blue"
main_theme = preload("res://assets/themes/blue/theme.tres")
top_menu_style = preload("res://assets/themes/blue/top_menu_style.tres")
ruler_style = preload("res://assets/themes/blue/ruler_style.tres")
elif ID == 3: # Caramel Theme
Global.theme_type = "Caramel"
main_theme = preload("res://assets/themes/caramel/theme.tres")
top_menu_style = preload("res://assets/themes/caramel/top_menu_style.tres")
ruler_style = preload("res://assets/themes/caramel/ruler_style.tres")
elif ID == 4: # Light Theme
Global.theme_type = "Light"
main_theme = preload("res://assets/themes/light/theme.tres")
top_menu_style = preload("res://assets/themes/light/top_menu_style.tres")
ruler_style = preload("res://assets/themes/light/ruler_style.tres")
Global.control.theme = main_theme
Global.control.theme.default_font = font
var default_clear_color : Color = main_theme.get_stylebox("panel", "PanelContainer").bg_color
VisualServer.set_default_clear_color(Color(default_clear_color))
(Global.animation_timeline.get_stylebox("panel", "Panel") as StyleBoxFlat).bg_color = main_theme.get_stylebox("panel", "Panel").bg_color
var layer_button_panel_container : PanelContainer = Global.find_node_by_name(Global.animation_timeline, "LayerButtonPanelContainer")
(layer_button_panel_container.get_stylebox("panel", "PanelContainer") as StyleBoxFlat).bg_color = default_clear_color
Global.top_menu_container.add_stylebox_override("panel", top_menu_style)
Global.horizontal_ruler.add_stylebox_override("normal", ruler_style)
Global.horizontal_ruler.add_stylebox_override("pressed", ruler_style)
Global.horizontal_ruler.add_stylebox_override("hover", ruler_style)
Global.horizontal_ruler.add_stylebox_override("focus", ruler_style)
Global.vertical_ruler.add_stylebox_override("normal", ruler_style)
Global.vertical_ruler.add_stylebox_override("pressed", ruler_style)
Global.vertical_ruler.add_stylebox_override("hover", ruler_style)
Global.vertical_ruler.add_stylebox_override("focus", ruler_style)
var fake_vsplit_grabber : TextureRect = Global.find_node_by_name(Global.animation_timeline, "FakeVSplitContainerGrabber")
if Global.theme_type == "Dark" or Global.theme_type == "Blue":
fake_vsplit_grabber.texture = preload("res://assets/themes/dark/icons/vsplit.png")
else:
fake_vsplit_grabber.texture = preload("res://assets/themes/light/icons/vsplit.png")
for button in get_tree().get_nodes_in_group("UIButtons"):
if button is TextureButton:
var last_backslash = button.texture_normal.resource_path.get_base_dir().find_last("/")
var button_category = button.texture_normal.resource_path.get_base_dir().right(last_backslash + 1)
var normal_file_name = button.texture_normal.resource_path.get_file()
var theme_type := Global.theme_type
if theme_type == "Blue":
theme_type = "Dark"
button.texture_normal = load("res://assets/graphics/%s_themes/%s/%s" % [theme_type.to_lower(), button_category, normal_file_name])
if button.texture_pressed:
var pressed_file_name = button.texture_pressed.resource_path.get_file()
button.texture_pressed = load("res://assets/graphics/%s_themes/%s/%s" % [theme_type.to_lower(), button_category, pressed_file_name])
if button.texture_hover:
var hover_file_name = button.texture_hover.resource_path.get_file()
button.texture_hover = load("res://assets/graphics/%s_themes/%s/%s" % [theme_type.to_lower(), button_category, hover_file_name])
if button.texture_disabled:
var disabled_file_name = button.texture_disabled.resource_path.get_file()
button.texture_disabled = load("res://assets/graphics/%s_themes/%s/%s" % [theme_type.to_lower(), button_category, disabled_file_name])
elif button is Button:
var texture : TextureRect
for child in button.get_children():
if child is TextureRect:
texture = child
break
if texture:
var last_backslash = texture.texture.resource_path.get_base_dir().find_last("/")
var button_category = texture.texture.resource_path.get_base_dir().right(last_backslash + 1)
var normal_file_name = texture.texture.resource_path.get_file()
var theme_type := Global.theme_type
if theme_type == "Caramel" or (theme_type == "Blue" and button_category != "tools"):
theme_type = "Dark"
texture.texture = load("res://assets/graphics/%s_themes/%s/%s" % [theme_type.to_lower(), button_category, normal_file_name])
# Make sure the frame text gets updated
Global.current_frame = Global.current_frame
$Popups/ShortcutSelector.theme = main_theme
func apply_shortcuts_preset(preset) -> void:
for action in preset:
var old_input_event : InputEventKey = InputMap.get_action_list(action)[0]
set_action_shortcut(action, old_input_event, preset[action])
shortcuts.get_node("Shortcuts/" + action).text = OS.get_scancode_string(preset[action].get_scancode_with_modifiers())
func toggle_shortcut_buttons(enabled : bool) -> void:
for shortcut_grid_item in shortcuts.get_node("Shortcuts").get_children():
if shortcut_grid_item is Button:
shortcut_grid_item.disabled = not enabled
if shortcut_grid_item.disabled:
shortcut_grid_item.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
else:
shortcut_grid_item.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
func set_action_shortcut(action : String, old_input : InputEventKey, new_input : InputEventKey) -> void:
InputMap.action_erase_event(action, old_input)
InputMap.action_add_event(action, new_input)
Global.update_hint_tooltips()
# Set shortcut to switch colors button
if action == "switch_colors":
Global.color_switch_button.shortcut.shortcut = InputMap.get_action_list("switch_colors")[0]
func _on_GridWidthValue_value_changed(value : float) -> void:
Global.grid_width = value
Global.canvas.update()
Global.config_cache.set_value("preferences", "grid_size", Vector2(value, grid_height_value.value))
Global.config_cache.save("user://cache.ini")
func _on_GridHeightValue_value_changed(value : float) -> void:
Global.grid_height = value
Global.canvas.update()
Global.config_cache.set_value("preferences", "grid_size", Vector2(grid_width_value.value, value))
Global.config_cache.save("user://cache.ini")
func _on_GridColor_color_changed(color : Color) -> void:
Global.grid_color = color
Global.canvas.update()
Global.config_cache.set_value("preferences", "grid_color", color)
Global.config_cache.save("user://cache.ini")
func _on_CheckerSize_value_changed(value : float) -> void:
Global.checker_size = value
Global.transparent_checker._ready()
Global.config_cache.set_value("preferences", "checker_size", value)
Global.config_cache.save("user://cache.ini")
func _on_CheckerColor1_color_changed(color : Color) -> void:
Global.checker_color_1 = color
Global.transparent_checker._ready()
Global.config_cache.set_value("preferences", "checker_color_1", color)
Global.config_cache.save("user://cache.ini")
func _on_CheckerColor2_color_changed(color : Color) -> void:
Global.checker_color_2 = color
Global.transparent_checker._ready()
Global.config_cache.set_value("preferences", "checker_color_2", color)
Global.config_cache.save("user://cache.ini")
func _on_GuideColor_color_changed(color : Color) -> void:
Global.guide_color = color
for canvas in Global.canvases:
for guide in canvas.get_children():
if guide is Guide:
guide.default_color = color
Global.config_cache.set_value("preferences", "guide_color", color)
Global.config_cache.save("user://cache.ini")
func _on_ImageDefaultWidth_value_changed(value: float) -> void:
Global.default_image_width = value
Global.config_cache.set_value("preferences", "default_width", value)
Global.config_cache.save("user://cache.ini")
func _on_ImageDefaultHeight_value_changed(value: float) -> void:
Global.default_image_height = value
Global.config_cache.set_value("preferences", "default_height", value)
Global.config_cache.save("user://cache.ini")
func _on_DefaultBackground_color_changed(color: Color) -> void:
Global.default_fill_color = color
Global.config_cache.set_value("preferences", "default_fill_color", color)
Global.config_cache.save("user://cache.ini")
func _on_LeftIndicatorCheckbox_toggled(button_pressed : bool) -> void:
Global.left_square_indicator_visible = button_pressed
func _on_RightIndicatorCheckbox_toggled(button_pressed : bool) -> void:
Global.right_square_indicator_visible = button_pressed
func _on_LeftToolIconCheckbox_toggled(button_pressed : bool) -> void:
Global.show_left_tool_icon = button_pressed
Global.config_cache.set_value("preferences", "show_left_tool_icon", Global.show_left_tool_icon)
Global.config_cache.save("user://cache.ini")
func _on_RightToolIconCheckbox_toggled(button_pressed : bool) -> void:
Global.show_right_tool_icon = button_pressed
Global.config_cache.set_value("preferences", "show_right_tool_icon", Global.show_right_tool_icon)
Global.config_cache.save("user://cache.ini")
func _on_Shortcut_button_pressed(button : Button) -> void:
set_process_input(true)
action_being_edited = button.name
new_input_event = InputMap.get_action_list(button.name)[0]
shortcut_already_assigned = true
$Popups/ShortcutSelector.popup_centered()
func _on_ShortcutSelector_popup_hide() -> void:
set_process_input(false)
$Popups/ShortcutSelector/EnteredShortcut.text = ""
func _on_PresetOptionButton_item_selected(id : int) -> void:
# Only custom preset which is modifiable
toggle_shortcut_buttons(true if id == 1 else false)
match id:
0:
apply_shortcuts_preset(default_shortcuts_preset)
1:
apply_shortcuts_preset(custom_shortcuts_preset)
Global.config_cache.set_value("shortcuts", "shortcuts_preset", id)
Global.config_cache.save("user://cache.ini")
func _on_ShortcutSelector_confirmed() -> void:
if not shortcut_already_assigned:
set_action_shortcut(action_being_edited, old_input_event, new_input_event)
custom_shortcuts_preset[action_being_edited] = new_input_event
Global.config_cache.set_value("shortcuts", action_being_edited, new_input_event)
Global.config_cache.save("user://cache.ini")
shortcuts.get_node("Shortcuts/" + action_being_edited).text = OS.get_scancode_string(new_input_event.get_scancode_with_modifiers())
$Popups/ShortcutSelector.hide()
func _on_OpenLastProject_pressed() -> void:
Global.open_last_project = !Global.open_last_project
Global.config_cache.set_value("preferences", "open_last_project", Global.open_last_project)
Global.config_cache.save("user://cache.ini")
func _on_EnableAutosave_toggled(button_pressed : bool) -> void:
OpenSave.toggle_autosave(button_pressed)
Global.config_cache.set_value("preferences", "enable_autosave", button_pressed)
Global.config_cache.save("user://cache.ini")
func _on_AutosaveInterval_value_changed(value : float) -> void:
OpenSave.set_autosave_interval(value)
Global.config_cache.set_value("preferences", "autosave_interval", value)
Global.config_cache.save("user://cache.ini")

View file

@ -32,11 +32,11 @@ func _on_RotateImage_confirmed() -> void:
Global.canvas.handle_undo("Draw") Global.canvas.handle_undo("Draw")
match $VBoxContainer/HBoxContainer2/OptionButton.text: match $VBoxContainer/HBoxContainer2/OptionButton.text:
"Rotxel": "Rotxel":
Global.rotxel(layer,$VBoxContainer/HBoxContainer/HSlider.value*PI/180) DrawingAlgos.rotxel(layer,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
"Nearest neighbour": "Nearest neighbour":
Global.nn_rotate(layer,$VBoxContainer/HBoxContainer/HSlider.value*PI/180) DrawingAlgos.nn_rotate(layer,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
"Upscale, Rotate and Downscale": "Upscale, Rotate and Downscale":
Global.fake_rotsprite(layer,$VBoxContainer/HBoxContainer/HSlider.value*PI/180) DrawingAlgos.fake_rotsprite(layer,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
Global.canvas.handle_redo("Draw") Global.canvas.handle_redo("Draw")
$VBoxContainer/HBoxContainer/HSlider.value = 0 $VBoxContainer/HBoxContainer/HSlider.value = 0
@ -45,11 +45,11 @@ func rotate() -> void:
sprite.copy_from(aux_img) sprite.copy_from(aux_img)
match $VBoxContainer/HBoxContainer2/OptionButton.text: match $VBoxContainer/HBoxContainer2/OptionButton.text:
"Rotxel": "Rotxel":
Global.rotxel(sprite,$VBoxContainer/HBoxContainer/HSlider.value*PI/180) DrawingAlgos.rotxel(sprite,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
"Nearest neighbour": "Nearest neighbour":
Global.nn_rotate(sprite,$VBoxContainer/HBoxContainer/HSlider.value*PI/180) DrawingAlgos.nn_rotate(sprite,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
"Upscale, Rotate and Downscale": "Upscale, Rotate and Downscale":
Global.fake_rotsprite(sprite,$VBoxContainer/HBoxContainer/HSlider.value*PI/180) DrawingAlgos.fake_rotsprite(sprite,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
texture.create_from_image(sprite, 0) texture.create_from_image(sprite, 0)

View file

@ -12,10 +12,10 @@ func _on_ScaleImage_confirmed() -> void:
Global.undo_redo.add_do_property(c, "size", Vector2(width, height).floor()) Global.undo_redo.add_do_property(c, "size", Vector2(width, height).floor())
for i in range(c.layers.size() - 1, -1, -1): for i in range(c.layers.size() - 1, -1, -1):
var sprite := Image.new() var sprite := Image.new()
sprite.copy_from(c.layers[i][0]) sprite.copy_from(c.layers[i].image)
sprite.resize(width, height, interpolation) sprite.resize(width, height, interpolation)
Global.undo_redo.add_do_property(c.layers[i][0], "data", sprite.data) Global.undo_redo.add_do_property(c.layers[i].image, "data", sprite.data)
Global.undo_redo.add_undo_property(c.layers[i][0], "data", c.layers[i][0].data) Global.undo_redo.add_undo_property(c.layers[i].image, "data", c.layers[i].image.data)
Global.undo_redo.add_undo_property(c, "size", c.size) Global.undo_redo.add_undo_property(c, "size", c.size)
Global.undo_redo.add_undo_method(Global, "undo", Global.canvases) Global.undo_redo.add_undo_method(Global, "undo", Global.canvases)

View file

@ -14,16 +14,9 @@ func _ready() -> void:
func _on_PatternButton_pressed() -> void: func _on_PatternButton_pressed() -> void:
if Global.pattern_window_position == "left": Global.pattern_images[Global.pattern_window_position] = image
Global.pattern_left_image = image Global.fill_pattern_containers[Global.pattern_window_position].get_child(0).get_child(0).texture = texture
Global.left_fill_pattern_container.get_child(0).get_child(0).texture = texture Global.fill_pattern_containers[Global.pattern_window_position].get_child(2).get_child(1).max_value = image_size.x - 1
Global.left_fill_pattern_container.get_child(2).get_child(1).max_value = image_size.x - 1 Global.fill_pattern_containers[Global.pattern_window_position].get_child(3).get_child(1).max_value = image_size.y - 1
Global.left_fill_pattern_container.get_child(3).get_child(1).max_value = image_size.y - 1
elif Global.pattern_window_position == "right":
Global.pattern_right_image = image
Global.right_fill_pattern_container.get_child(0).get_child(0).texture = texture
Global.right_fill_pattern_container.get_child(2).get_child(1).max_value = image_size.x - 1
Global.right_fill_pattern_container.get_child(3).get_child(1).max_value = image_size.y - 1
Global.patterns_popup.hide() Global.patterns_popup.hide()

View file

@ -4,7 +4,7 @@ var fps := 6.0
var animation_loop := 1 # 0 is no loop, 1 is cycle loop, 2 is ping-pong loop var animation_loop := 1 # 0 is no loop, 1 is cycle loop, 2 is ping-pong loop
var animation_forward := true var animation_forward := true
var first_frame := 0 var first_frame := 0
var last_frame := Global.canvases.size() - 1 var last_frame : int = Global.canvases.size() - 1
var timeline_scroll : ScrollContainer var timeline_scroll : ScrollContainer
var tag_scroll_container : ScrollContainer var tag_scroll_container : ScrollContainer
@ -28,7 +28,7 @@ func add_frame() -> void:
new_canvas.size = Global.canvas.size new_canvas.size = Global.canvas.size
new_canvas.frame = Global.canvases.size() new_canvas.frame = Global.canvases.size()
var new_canvases: Array = Global.canvases.duplicate() var new_canvases : Array = Global.canvases.duplicate()
new_canvases.append(new_canvas) new_canvases.append(new_canvas)
Global.undos += 1 Global.undos += 1
@ -45,8 +45,8 @@ func add_frame() -> void:
Global.undo_redo.add_undo_property(c, "visible", c.visible) Global.undo_redo.add_undo_property(c, "visible", c.visible)
for l_i in range(Global.layers.size()): for l_i in range(Global.layers.size()):
if Global.layers[l_i][4]: # If the link button is pressed if Global.layers[l_i].new_cels_linked: # If the link button is pressed
Global.layers[l_i][5].append(new_canvas) Global.layers[l_i].linked_cels.append(new_canvas)
Global.undo_redo.add_undo_property(Global, "canvases", Global.canvases) Global.undo_redo.add_undo_property(Global, "canvases", Global.canvases)
Global.undo_redo.add_undo_property(Global, "canvas", Global.canvas) Global.undo_redo.add_undo_property(Global, "canvas", Global.canvas)
@ -61,32 +61,43 @@ func _on_DeleteFrame_pressed(frame := -1) -> void:
frame = Global.current_frame frame = Global.current_frame
var canvas : Canvas = Global.canvases[frame] var canvas : Canvas = Global.canvases[frame]
var new_canvases := Global.canvases.duplicate() var new_canvases : Array = Global.canvases.duplicate()
new_canvases.erase(canvas) new_canvases.erase(canvas)
var current_frame := Global.current_frame var current_frame := Global.current_frame
if current_frame > 0 && current_frame == new_canvases.size(): # If it's the last frame if current_frame > 0 && current_frame == new_canvases.size(): # If it's the last frame
current_frame -= 1 current_frame -= 1
var new_animation_tags := Global.animation_tags.duplicate(true) var new_animation_tags := Global.animation_tags.duplicate()
# Loop through the tags to create new classes for them, so that they won't be the same
# as Global.animation_tags's classes. Needed for undo/redo to work properly.
for i in new_animation_tags.size():
new_animation_tags[i] = AnimationTag.new(new_animation_tags[i].name, new_animation_tags[i].color, new_animation_tags[i].from, new_animation_tags[i].to)
# Loop through the tags to see if the frame is in one # Loop through the tags to see if the frame is in one
for tag in new_animation_tags: for tag in new_animation_tags:
if frame + 1 >= tag[2] && frame + 1 <= tag[3]: if frame + 1 >= tag.from && frame + 1 <= tag.to:
if tag[3] == tag[2]: # If we're deleting the only frame in the tag if tag.from == tag.to: # If we're deleting the only frame in the tag
new_animation_tags.erase(tag) new_animation_tags.erase(tag)
else: else:
tag[3] -= 1 tag.to -= 1
elif frame + 1 < tag[2]: elif frame + 1 < tag.from:
tag[2] -= 1 tag.from -= 1
tag[3] -= 1 tag.to -= 1
# Check if one of the cels of the frame is linked # Check if one of the cels of the frame is linked
# if they are, unlink them too # if they are, unlink them too
# this prevents removed cels being kept in linked memory # this prevents removed cels being kept in linked memory
var new_layers := Global.layers.duplicate(true) var new_layers : Array = Global.layers.duplicate()
# Loop through the array to create new classes for each element, so that they
# won't be the same as the original array's classes. Needed for undo/redo to work properly.
for i in new_layers.size():
var new_linked_cels = new_layers[i].linked_cels.duplicate()
new_layers[i] = Layer.new(new_layers[i].name, new_layers[i].visible, new_layers[i].locked, new_layers[i].frame_container, new_layers[i].new_cels_linked, new_linked_cels)
for layer in new_layers: for layer in new_layers:
for linked in layer[5]: for linked in layer.linked_cels:
if linked == Global.canvases[frame]: if linked == Global.canvases[frame]:
layer[5].erase(linked) layer.linked_cels.erase(linked)
Global.undos += 1 Global.undos += 1
Global.undo_redo.create_action("Remove Frame") Global.undo_redo.create_action("Remove Frame")
@ -130,17 +141,20 @@ func _on_CopyFrame_pressed(frame := -1) -> void:
for layer in canvas.layers: # Copy every layer for layer in canvas.layers: # Copy every layer
var sprite := Image.new() var sprite := Image.new()
sprite.copy_from(layer[0]) sprite.copy_from(layer.image)
sprite.lock() sprite.lock()
var tex := ImageTexture.new() new_canvas.layers.append(Cel.new(sprite, layer.opacity))
tex.create_from_image(sprite, 0)
new_canvas.layers.append([sprite, tex, layer[2]]) var new_animation_tags := Global.animation_tags.duplicate()
# Loop through the tags to create new classes for them, so that they won't be the same
# as Global.animation_tags's classes. Needed for undo/redo to work properly.
for i in new_animation_tags.size():
new_animation_tags[i] = AnimationTag.new(new_animation_tags[i].name, new_animation_tags[i].color, new_animation_tags[i].from, new_animation_tags[i].to)
var new_animation_tags := Global.animation_tags.duplicate(true)
# Loop through the tags to see if the frame is in one # Loop through the tags to see if the frame is in one
for tag in new_animation_tags: for tag in new_animation_tags:
if frame + 1 >= tag[2] && frame + 1 <= tag[3]: if frame + 1 >= tag.from && frame + 1 <= tag.to:
tag[3] += 1 tag.to += 1
Global.undos += 1 Global.undos += 1
Global.undo_redo.create_action("Add Frame") Global.undo_redo.create_action("Add Frame")
@ -152,7 +166,7 @@ func _on_CopyFrame_pressed(frame := -1) -> void:
Global.undo_redo.add_do_property(Global, "current_frame", frame + 1) Global.undo_redo.add_do_property(Global, "current_frame", frame + 1)
Global.undo_redo.add_do_property(Global, "animation_tags", new_animation_tags) Global.undo_redo.add_do_property(Global, "animation_tags", new_animation_tags)
for i in range(Global.layers.size()): for i in range(Global.layers.size()):
for child in Global.layers[i][3].get_children(): for child in Global.layers[i].frame_container.get_children():
Global.undo_redo.add_do_property(child, "pressed", false) Global.undo_redo.add_do_property(child, "pressed", false)
Global.undo_redo.add_undo_property(child, "pressed", child.pressed) Global.undo_redo.add_undo_property(child, "pressed", child.pressed)
for c in Global.canvases: for c in Global.canvases:
@ -265,9 +279,9 @@ func play_animation(play : bool, forward_dir : bool) -> void:
last_frame = Global.canvases.size() - 1 last_frame = Global.canvases.size() - 1
if Global.play_only_tags: if Global.play_only_tags:
for tag in Global.animation_tags: for tag in Global.animation_tags:
if Global.current_frame + 1 >= tag[2] && Global.current_frame + 1 <= tag[3]: if Global.current_frame + 1 >= tag.from && Global.current_frame + 1 <= tag.to:
first_frame = tag[2] - 1 first_frame = tag.from - 1
last_frame = min(Global.canvases.size() - 1, tag[3] - 1) last_frame = min(Global.canvases.size() - 1, tag.to - 1)
if first_frame == last_frame: if first_frame == last_frame:
if forward_dir: if forward_dir:
@ -336,15 +350,11 @@ func _on_BlueRedMode_toggled(button_pressed : bool) -> void:
# Layer buttons # Layer buttons
func add_layer(is_new := true) -> void: func add_layer(is_new := true) -> void:
var layer_name = null
if !is_new: # Clone layer
layer_name = Global.layers[Global.current_layer][0] + " (" + tr("copy") + ")"
var new_layers : Array = Global.layers.duplicate() var new_layers : Array = Global.layers.duplicate()
var l := Layer.new()
# Store [Layer name (0), Layer visibility boolean (1), Layer lock boolean (2), Frame container (3), if !is_new: # Clone layer
# will new frames be linked boolean (4), Array of linked frames (5)] l.name = Global.layers[Global.current_layer].name + " (" + tr("copy") + ")"
new_layers.append([layer_name, true, false, HBoxContainer.new(), false, []]) new_layers.append(l)
Global.undos += 1 Global.undos += 1
Global.undo_redo.create_action("Add Layer") Global.undo_redo.create_action("Add Layer")
@ -354,15 +364,12 @@ func add_layer(is_new := true) -> void:
if is_new: if is_new:
new_layer.create(c.size.x, c.size.y, false, Image.FORMAT_RGBA8) new_layer.create(c.size.x, c.size.y, false, Image.FORMAT_RGBA8)
else: # Clone layer else: # Clone layer
new_layer.copy_from(c.layers[Global.current_layer][0]) new_layer.copy_from(c.layers[Global.current_layer].image)
new_layer.lock() new_layer.lock()
var new_layer_tex := ImageTexture.new()
new_layer_tex.create_from_image(new_layer, 0)
var new_canvas_layers : Array = c.layers.duplicate() var new_canvas_layers : Array = c.layers.duplicate()
# Store [Image, ImageTexture, Opacity] new_canvas_layers.append(Cel.new(new_layer, 1))
new_canvas_layers.append([new_layer, new_layer_tex, 1])
Global.undo_redo.add_do_property(c, "layers", new_canvas_layers) Global.undo_redo.add_do_property(c, "layers", new_canvas_layers)
Global.undo_redo.add_undo_property(c, "layers", c.layers) Global.undo_redo.add_undo_property(c, "layers", c.layers)
@ -409,11 +416,11 @@ func change_layer_order(rate : int) -> void:
new_layers[change] = temp new_layers[change] = temp
Global.undo_redo.create_action("Change Layer Order") Global.undo_redo.create_action("Change Layer Order")
for c in Global.canvases: for c in Global.canvases:
var new_layers_canvas : Array = c.layers.duplicate() var new_canvas_layers : Array = c.layers.duplicate()
var temp_canvas = new_layers_canvas[Global.current_layer] var temp_canvas = new_canvas_layers[Global.current_layer]
new_layers_canvas[Global.current_layer] = new_layers_canvas[change] new_canvas_layers[Global.current_layer] = new_canvas_layers[change]
new_layers_canvas[change] = temp_canvas new_canvas_layers[change] = temp_canvas
Global.undo_redo.add_do_property(c, "layers", new_layers_canvas) Global.undo_redo.add_do_property(c, "layers", new_canvas_layers)
Global.undo_redo.add_undo_property(c, "layers", c.layers) Global.undo_redo.add_undo_property(c, "layers", c.layers)
Global.undo_redo.add_do_property(Global, "current_layer", change) Global.undo_redo.add_do_property(Global, "current_layer", change)
@ -427,39 +434,43 @@ func change_layer_order(rate : int) -> void:
func _on_MergeDownLayer_pressed() -> void: func _on_MergeDownLayer_pressed() -> void:
var new_layers : Array = Global.layers.duplicate(true) var new_layers : Array = Global.layers.duplicate()
# Loop through the array to create new classes for each element, so that they
# won't be the same as the original array's classes. Needed for undo/redo to work properly.
for i in new_layers.size():
var new_linked_cels = new_layers[i].linked_cels.duplicate()
new_layers[i] = Layer.new(new_layers[i].name, new_layers[i].visible, new_layers[i].locked, new_layers[i].frame_container, new_layers[i].new_cels_linked, new_linked_cels)
Global.undos += 1 Global.undos += 1
Global.undo_redo.create_action("Merge Layer") Global.undo_redo.create_action("Merge Layer")
for c in Global.canvases: for c in Global.canvases:
var new_layers_canvas : Array = c.layers.duplicate(true) var new_canvas_layers : Array = c.layers.duplicate()
for i in new_canvas_layers.size():
new_canvas_layers[i] = Cel.new(new_canvas_layers[i].image, new_canvas_layers[i].opacity)
var selected_layer := Image.new() var selected_layer := Image.new()
selected_layer.copy_from(new_layers_canvas[Global.current_layer][0]) selected_layer.copy_from(new_canvas_layers[Global.current_layer].image)
selected_layer.lock() selected_layer.lock()
if c.layers[Global.current_layer][2] < 1: # If we have layer transparency if c.layers[Global.current_layer].opacity < 1: # If we have layer transparency
for xx in selected_layer.get_size().x: for xx in selected_layer.get_size().x:
for yy in selected_layer.get_size().y: for yy in selected_layer.get_size().y:
var pixel_color : Color = selected_layer.get_pixel(xx, yy) var pixel_color : Color = selected_layer.get_pixel(xx, yy)
var alpha : float = pixel_color.a * c.layers[Global.current_layer][2] var alpha : float = pixel_color.a * c.layers[Global.current_layer].opacity
selected_layer.set_pixel(xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha)) selected_layer.set_pixel(xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha))
var new_layer := Image.new() var new_layer := Image.new()
new_layer.copy_from(c.layers[Global.current_layer - 1][0]) new_layer.copy_from(c.layers[Global.current_layer - 1].image)
new_layer.lock() new_layer.lock()
c.blend_rect(new_layer, selected_layer, Rect2(c.position, c.size), Vector2.ZERO) DrawingAlgos.blend_rect(new_layer, selected_layer, Rect2(c.position, c.size), Vector2.ZERO)
new_layers_canvas.remove(Global.current_layer) new_canvas_layers.remove(Global.current_layer)
if !selected_layer.is_invisible() and Global.layers[Global.current_layer - 1][5].size() > 1 and (c in Global.layers[Global.current_layer - 1][5]): if !selected_layer.is_invisible() and Global.layers[Global.current_layer - 1].linked_cels.size() > 1 and (c in Global.layers[Global.current_layer - 1].linked_cels):
new_layers[Global.current_layer - 1][5].erase(c) new_layers[Global.current_layer - 1].linked_cels.erase(c)
var tex := ImageTexture.new() new_canvas_layers[Global.current_layer - 1].image = new_layer
tex.create_from_image(new_layer, 0)
new_layers_canvas[Global.current_layer - 1][0] = new_layer
new_layers_canvas[Global.current_layer - 1][1] = tex
else: else:
Global.undo_redo.add_do_property(c.layers[Global.current_layer - 1][0], "data", new_layer.data) Global.undo_redo.add_do_property(c.layers[Global.current_layer - 1].image, "data", new_layer.data)
Global.undo_redo.add_undo_property(c.layers[Global.current_layer - 1][0], "data", c.layers[Global.current_layer - 1][0].data) Global.undo_redo.add_undo_property(c.layers[Global.current_layer - 1].image, "data", c.layers[Global.current_layer - 1].image.data)
Global.undo_redo.add_do_property(c, "layers", new_layers_canvas) Global.undo_redo.add_do_property(c, "layers", new_canvas_layers)
Global.undo_redo.add_undo_property(c, "layers", c.layers) Global.undo_redo.add_undo_property(c, "layers", c.layers)
new_layers.remove(Global.current_layer) new_layers.remove(Global.current_layer)
@ -474,7 +485,7 @@ func _on_MergeDownLayer_pressed() -> void:
func _on_OpacitySlider_value_changed(value) -> void: func _on_OpacitySlider_value_changed(value) -> void:
Global.canvas.layers[Global.current_layer][2] = value / 100 Global.canvas.layers[Global.current_layer].opacity = value / 100
Global.layer_opacity_slider.value = value Global.layer_opacity_slider.value = value
Global.layer_opacity_slider.value = value Global.layer_opacity_slider.value = value
Global.layer_opacity_spinbox.value = value Global.layer_opacity_spinbox.value = value

View file

@ -22,7 +22,7 @@
[ext_resource path="res://assets/graphics/dark_themes/timeline/onion_skinning_off.png" type="Texture" id=29] [ext_resource path="res://assets/graphics/dark_themes/timeline/onion_skinning_off.png" type="Texture" id=29]
[ext_resource path="res://assets/graphics/dark_themes/timeline/expandable.png" type="Texture" id=30] [ext_resource path="res://assets/graphics/dark_themes/timeline/expandable.png" type="Texture" id=30]
[ext_resource path="res://assets/graphics/dark_themes/timeline/loop.png" type="Texture" id=31] [ext_resource path="res://assets/graphics/dark_themes/timeline/loop.png" type="Texture" id=31]
[ext_resource path="res://src/UI/Dialogs/FrameTagDialog.tscn" type="PackedScene" id=42] [ext_resource path="res://src/UI/Timeline/FrameTagDialog.tscn" type="PackedScene" id=42]
[sub_resource type="StyleBoxFlat" id=1] [sub_resource type="StyleBoxFlat" id=1]
bg_color = Color( 0.0627451, 0.0627451, 0.0627451, 1 ) bg_color = Color( 0.0627451, 0.0627451, 0.0627451, 1 )

View file

@ -8,7 +8,7 @@ onready var popup_menu : PopupMenu = $PopupMenu
func _ready() -> void: func _ready() -> void:
hint_tooltip = "Frame: %s, Layer: %s" % [frame + 1, layer] hint_tooltip = "Frame: %s, Layer: %s" % [frame + 1, layer]
if Global.canvases[frame] in Global.layers[layer][5]: if Global.canvases[frame] in Global.layers[layer].linked_cels:
get_node("LinkedIndicator").visible = true get_node("LinkedIndicator").visible = true
popup_menu.set_item_text(4, "Unlink Cel") popup_menu.set_item_text(4, "Unlink Cel")
popup_menu.set_item_metadata(4, "Unlink Cel") popup_menu.set_item_metadata(4, "Unlink Cel")
@ -53,20 +53,24 @@ func _on_PopupMenu_id_pressed(ID : int) -> void:
3: # Move Right 3: # Move Right
change_frame_order(1) change_frame_order(1)
4: # Unlink Cel 4: # Unlink Cel
var cel_index : int = Global.layers[layer][5].find(Global.canvases[frame]) var cel_index : int = Global.layers[layer].linked_cels.find(Global.canvases[frame])
var c = Global.canvases[frame] var c = Global.canvases[frame]
var new_layers := Global.layers.duplicate(true) var new_layers : Array = Global.layers.duplicate()
var new_canvas_layers : Array = c.layers.duplicate(true) # Loop through the array to create new classes for each element, so that they
# won't be the same as the original array's classes. Needed for undo/redo to work properly.
for i in new_layers.size():
var new_linked_cels = new_layers[i].linked_cels.duplicate()
new_layers[i] = Layer.new(new_layers[i].name, new_layers[i].visible, new_layers[i].locked, new_layers[i].frame_container, new_layers[i].new_cels_linked, new_linked_cels)
var new_canvas_layers : Array = c.layers.duplicate()
for i in new_canvas_layers.size():
new_canvas_layers[i] = Cel.new(new_canvas_layers[i].image, new_canvas_layers[i].opacity)
if popup_menu.get_item_metadata(4) == "Unlink Cel": if popup_menu.get_item_metadata(4) == "Unlink Cel":
new_layers[layer][5].remove(cel_index) new_layers[layer].linked_cels.remove(cel_index)
var sprite := Image.new() var sprite := Image.new()
sprite.copy_from(Global.canvases[frame].layers[layer][0]) sprite.copy_from(Global.canvases[frame].layers[layer].image)
sprite.lock() sprite.lock()
var tex := ImageTexture.new() new_canvas_layers[layer].image = sprite
tex.create_from_image(sprite, 0)
new_canvas_layers[layer][0] = sprite
new_canvas_layers[layer][1] = tex
Global.undo_redo.create_action("Unlink Cel") Global.undo_redo.create_action("Unlink Cel")
Global.undo_redo.add_do_property(Global, "layers", new_layers) Global.undo_redo.add_do_property(Global, "layers", new_layers)
@ -78,14 +82,14 @@ func _on_PopupMenu_id_pressed(ID : int) -> void:
Global.undo_redo.add_do_method(Global, "redo", [Global.canvases[frame]], layer) Global.undo_redo.add_do_method(Global, "redo", [Global.canvases[frame]], layer)
Global.undo_redo.commit_action() Global.undo_redo.commit_action()
elif popup_menu.get_item_metadata(4) == "Link Cel": elif popup_menu.get_item_metadata(4) == "Link Cel":
new_layers[layer][5].append(Global.canvases[frame]) new_layers[layer].linked_cels.append(Global.canvases[frame])
Global.undo_redo.create_action("Link Cel") Global.undo_redo.create_action("Link Cel")
Global.undo_redo.add_do_property(Global, "layers", new_layers) Global.undo_redo.add_do_property(Global, "layers", new_layers)
if new_layers[layer][5].size() > 1: if new_layers[layer].linked_cels.size() > 1:
# If there are already linked cels, set the current cel's image # If there are already linked cels, set the current cel's image
# to the first linked cel's image # to the first linked cel's image
new_canvas_layers[layer][0] = new_layers[layer][5][0].layers[layer][0] new_canvas_layers[layer].image = new_layers[layer].linked_cels[0].layers[layer].image
new_canvas_layers[layer][1] = new_layers[layer][5][0].layers[layer][1] new_canvas_layers[layer].image_texture = new_layers[layer].linked_cels[0].layers[layer].image_texture
Global.undo_redo.add_do_property(c, "layers", new_canvas_layers) Global.undo_redo.add_do_property(c, "layers", new_canvas_layers)
Global.undo_redo.add_undo_property(c, "layers", c.layers) Global.undo_redo.add_undo_property(c, "layers", c.layers)
@ -97,7 +101,7 @@ func _on_PopupMenu_id_pressed(ID : int) -> void:
func change_frame_order(rate : int) -> void: func change_frame_order(rate : int) -> void:
var change = frame + rate var change = frame + rate
var new_canvases := Global.canvases.duplicate() var new_canvases : Array = Global.canvases.duplicate()
var temp = new_canvases[frame] var temp = new_canvases[frame]
new_canvases[frame] = new_canvases[change] new_canvases[frame] = new_canvases[change]
new_canvases[change] = temp new_canvases[change] = temp

View file

@ -25,10 +25,10 @@ func _on_FrameTagDialog_about_to_show() -> void:
var vbox_cont := VBoxContainer.new() var vbox_cont := VBoxContainer.new()
var hbox_cont := HBoxContainer.new() var hbox_cont := HBoxContainer.new()
var tag_label := Label.new() var tag_label := Label.new()
if tag[2] == tag[3]: if tag.from == tag.to:
tag_label.text = "Tag %s (Frame %s)" % [i + 1, tag[2]] tag_label.text = "Tag %s (Frame %s)" % [i + 1, tag.from]
else: else:
tag_label.text = "Tag %s (Frames %s-%s)" % [i + 1, tag[2], tag[3]] tag_label.text = "Tag %s (Frames %s-%s)" % [i + 1, tag.from, tag.to]
hbox_cont.add_child(tag_label) hbox_cont.add_child(tag_label)
var edit_button := Button.new() var edit_button := Button.new()
@ -39,8 +39,8 @@ func _on_FrameTagDialog_about_to_show() -> void:
vbox_cont.add_child(hbox_cont) vbox_cont.add_child(hbox_cont)
var name_label := Label.new() var name_label := Label.new()
name_label.text = tag[0] name_label.text = tag.name
name_label.modulate = tag[1] name_label.modulate = tag.color
vbox_cont.add_child(name_label) vbox_cont.add_child(name_label)
var hsep := HSeparator.new() var hsep := HSeparator.new()
@ -70,10 +70,10 @@ func _on_AddTag_pressed() -> void:
func _on_EditButton_pressed(_tag_id : int) -> void: func _on_EditButton_pressed(_tag_id : int) -> void:
options_dialog.popup_centered() options_dialog.popup_centered()
current_tag_id = _tag_id current_tag_id = _tag_id
options_dialog.get_node("GridContainer/NameLineEdit").text = Global.animation_tags[_tag_id][0] options_dialog.get_node("GridContainer/NameLineEdit").text = Global.animation_tags[_tag_id].name
options_dialog.get_node("GridContainer/ColorPickerButton").color = Global.animation_tags[_tag_id][1] options_dialog.get_node("GridContainer/ColorPickerButton").color = Global.animation_tags[_tag_id].color
options_dialog.get_node("GridContainer/FromSpinBox").value = Global.animation_tags[_tag_id][2] options_dialog.get_node("GridContainer/FromSpinBox").value = Global.animation_tags[_tag_id].from
options_dialog.get_node("GridContainer/ToSpinBox").value = Global.animation_tags[_tag_id][3] options_dialog.get_node("GridContainer/ToSpinBox").value = Global.animation_tags[_tag_id].to
if !delete_tag_button: if !delete_tag_button:
delete_tag_button = options_dialog.add_button("Delete Tag", true, "delete_tag") delete_tag_button = options_dialog.add_button("Delete Tag", true, "delete_tag")
else: else:
@ -92,14 +92,19 @@ func _on_TagOptions_confirmed() -> void:
if tag_from > tag_to: if tag_from > tag_to:
tag_from = tag_to tag_from = tag_to
var new_animation_tags := Global.animation_tags.duplicate(true) var new_animation_tags := Global.animation_tags.duplicate()
# Loop through the tags to create new classes for them, so that they won't be the same
# as Global.animation_tags's classes. Needed for undo/redo to work properly.
for i in new_animation_tags.size():
new_animation_tags[i] = AnimationTag.new(new_animation_tags[i].name, new_animation_tags[i].color, new_animation_tags[i].from, new_animation_tags[i].to)
if current_tag_id == Global.animation_tags.size(): if current_tag_id == Global.animation_tags.size():
new_animation_tags.append([tag_name, tag_color, tag_from, tag_to]) new_animation_tags.append(AnimationTag.new(tag_name, tag_color, tag_from, tag_to))
else: else:
new_animation_tags[current_tag_id][0] = tag_name new_animation_tags[current_tag_id].name = tag_name
new_animation_tags[current_tag_id][1] = tag_color new_animation_tags[current_tag_id].color = tag_color
new_animation_tags[current_tag_id][2] = tag_from new_animation_tags[current_tag_id].from = tag_from
new_animation_tags[current_tag_id][3] = tag_to new_animation_tags[current_tag_id].to = tag_to
# Handle Undo/Redo # Handle Undo/Redo
Global.undos += 1 Global.undos += 1
@ -114,7 +119,7 @@ func _on_TagOptions_confirmed() -> void:
func _on_TagOptions_custom_action(action : String) -> void: func _on_TagOptions_custom_action(action : String) -> void:
if action == "delete_tag": if action == "delete_tag":
var new_animation_tags := Global.animation_tags.duplicate(true) var new_animation_tags := Global.animation_tags.duplicate()
new_animation_tags.remove(current_tag_id) new_animation_tags.remove(current_tag_id)
# Handle Undo/Redo # Handle Undo/Redo
Global.undos += 1 Global.undos += 1

View file

@ -1,6 +1,6 @@
[gd_scene load_steps=3 format=2] [gd_scene load_steps=3 format=2]
[ext_resource path="res://src/UI/Dialogs/FrameTagDialog.gd" type="Script" id=1] [ext_resource path="res://src/UI/Timeline/FrameTagDialog.gd" type="Script" id=1]
[ext_resource path="res://assets/graphics/dark_themes/timeline/new_frame.png" type="Texture" id=2] [ext_resource path="res://assets/graphics/dark_themes/timeline/new_frame.png" type="Texture" id=2]
[node name="FrameTagDialog" type="AcceptDialog"] [node name="FrameTagDialog" type="AcceptDialog"]

View file

@ -16,7 +16,7 @@ func _ready() -> void:
label = Global.find_node_by_name(self, "Label") label = Global.find_node_by_name(self, "Label")
line_edit = Global.find_node_by_name(self, "LineEdit") line_edit = Global.find_node_by_name(self, "LineEdit")
if Global.layers[i][1]: if Global.layers[i].visible:
Global.change_button_texturerect(visibility_button.get_child(0), "layer_visible.png") Global.change_button_texturerect(visibility_button.get_child(0), "layer_visible.png")
visibility_button.get_child(0).rect_size = Vector2(24, 14) visibility_button.get_child(0).rect_size = Vector2(24, 14)
visibility_button.get_child(0).rect_position = Vector2(4, 9) visibility_button.get_child(0).rect_position = Vector2(4, 9)
@ -25,12 +25,12 @@ func _ready() -> void:
visibility_button.get_child(0).rect_size = Vector2(24, 8) visibility_button.get_child(0).rect_size = Vector2(24, 8)
visibility_button.get_child(0).rect_position = Vector2(4, 12) visibility_button.get_child(0).rect_position = Vector2(4, 12)
if Global.layers[i][2]: if Global.layers[i].locked:
Global.change_button_texturerect(lock_button.get_child(0), "lock.png") Global.change_button_texturerect(lock_button.get_child(0), "lock.png")
else: else:
Global.change_button_texturerect(lock_button.get_child(0), "unlock.png") Global.change_button_texturerect(lock_button.get_child(0), "unlock.png")
if Global.layers[i][4]: # If new layers will be linked if Global.layers[i].new_cels_linked: # If new layers will be linked
Global.change_button_texturerect(linked_button.get_child(0), "linked_layer.png") Global.change_button_texturerect(linked_button.get_child(0), "linked_layer.png")
else: else:
Global.change_button_texturerect(linked_button.get_child(0), "unlinked_layer.png") Global.change_button_texturerect(linked_button.get_child(0), "unlinked_layer.png")
@ -59,20 +59,20 @@ func save_layer_name(new_name : String) -> void:
line_edit.editable = false line_edit.editable = false
label.text = new_name label.text = new_name
Global.layers_changed_skip = true Global.layers_changed_skip = true
Global.layers[i][0] = new_name Global.layers[i].name = new_name
func _on_VisibilityButton_pressed() -> void: func _on_VisibilityButton_pressed() -> void:
Global.layers[i][1] = !Global.layers[i][1] Global.layers[i].visible = !Global.layers[i].visible
Global.canvas.update() Global.canvas.update()
func _on_LockButton_pressed() -> void: func _on_LockButton_pressed() -> void:
Global.layers[i][2] = !Global.layers[i][2] Global.layers[i].locked = !Global.layers[i].locked
func _on_LinkButton_pressed() -> void: func _on_LinkButton_pressed() -> void:
Global.layers[i][4] = !Global.layers[i][4] Global.layers[i].new_cels_linked = !Global.layers[i].new_cels_linked
if Global.layers[i][4] && !Global.layers[i][5]: if Global.layers[i].new_cels_linked && !Global.layers[i].linked_cels:
Global.layers[i][5].append(Global.canvas) Global.layers[i].linked_cels.append(Global.canvas)
Global.layers[i][3].get_child(Global.current_frame)._ready() Global.layers[i].frame_container.get_child(Global.current_frame)._ready()

View file

@ -33,89 +33,66 @@ func _input(event : InputEvent) -> void:
func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_left := true) -> void: func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_left := true) -> void:
var current_action := tool_pressed.name var current_action := tool_pressed.name
var current_tool : int = Global.Tools.keys().find(current_action.to_upper())
var left_tool_name := str(Global.Tools.keys()[Global.current_tools[0]]).to_lower()
var right_tool_name := str(Global.Tools.keys()[Global.current_tools[1]]).to_lower()
var current_mouse_button := -1
if (mouse_press and Input.is_action_just_released("left_mouse")) or (!mouse_press and key_for_left): if (mouse_press and Input.is_action_just_released("left_mouse")) or (!mouse_press and key_for_left):
Global.current_left_tool = current_action left_tool_name = current_action.to_lower()
current_mouse_button = Global.Mouse_Button.LEFT
# Start from 1, so the label won't get invisible
for i in range(1, Global.left_tool_options_container.get_child_count()):
Global.left_tool_options_container.get_child(i).visible = false
Global.left_tool_options_container.get_node("EmptySpacer").visible = true
# Tool options visible depending on the selected tool
if current_action == "Pencil":
Global.left_brush_type_container.visible = true
Global.left_brush_size_slider.visible = true
Global.left_pixel_perfect_container.visible = true
Global.left_mirror_container.visible = true
if Global.current_left_brush_type == Global.Brush_Types.FILE or Global.current_left_brush_type == Global.Brush_Types.CUSTOM or Global.current_left_brush_type == Global.Brush_Types.RANDOM_FILE:
Global.left_color_interpolation_container.visible = true
elif current_action == "Eraser":
Global.left_brush_type_container.visible = true
Global.left_brush_size_slider.visible = true
Global.left_pixel_perfect_container.visible = true
Global.left_mirror_container.visible = true
elif current_action == "Bucket":
Global.left_fill_area_container.visible = true
Global.left_mirror_container.visible = true
elif current_action == "LightenDarken":
Global.left_brush_type_container.visible = true
Global.left_brush_size_slider.visible = true
Global.left_pixel_perfect_container.visible = true
Global.left_ld_container.visible = true
Global.left_mirror_container.visible = true
elif current_action == "ColorPicker":
Global.left_colorpicker_container.visible = true
elif current_action == "Zoom":
Global.left_zoom_container.visible = true
elif (mouse_press and Input.is_action_just_released("right_mouse")) or (!mouse_press and !key_for_left): elif (mouse_press and Input.is_action_just_released("right_mouse")) or (!mouse_press and !key_for_left):
Global.current_right_tool = current_action right_tool_name = current_action.to_lower()
# Start from 1, so the label won't get invisible current_mouse_button = Global.Mouse_Button.RIGHT
for i in range(1, Global.right_tool_options_container.get_child_count()):
Global.right_tool_options_container.get_child(i).visible = false
Global.right_tool_options_container.get_node("EmptySpacer").visible = true if current_mouse_button != -1:
Global.current_tools[current_mouse_button] = current_tool
# Start from 1, so the label won't get invisible
for i in range(1, Global.tool_options_containers[current_mouse_button].get_child_count()):
Global.tool_options_containers[current_mouse_button].get_child(i).visible = false
Global.tool_options_containers[current_mouse_button].get_node("EmptySpacer").visible = true
# Tool options visible depending on the selected tool # Tool options visible depending on the selected tool
if current_action == "Pencil": if current_tool == Global.Tools.PENCIL:
Global.right_brush_type_container.visible = true Global.brush_type_containers[current_mouse_button].visible = true
Global.right_brush_size_slider.visible = true Global.brush_size_sliders[current_mouse_button].visible = true
Global.right_pixel_perfect_container.visible = true Global.pixel_perfect_containers[current_mouse_button].visible = true
Global.right_mirror_container.visible = true Global.mirror_containers[current_mouse_button].visible = true
if Global.current_right_brush_type == Global.Brush_Types.FILE or Global.current_right_brush_type == Global.Brush_Types.CUSTOM or Global.current_right_brush_type == Global.Brush_Types.RANDOM_FILE: if Global.current_brush_types[current_mouse_button] == Global.Brush_Types.FILE or Global.current_brush_types[current_mouse_button] == Global.Brush_Types.CUSTOM or Global.current_brush_types[current_mouse_button] == Global.Brush_Types.RANDOM_FILE:
Global.right_color_interpolation_container.visible = true Global.color_interpolation_containers[current_mouse_button].visible = true
elif current_action == "Eraser": elif current_tool == Global.Tools.ERASER:
Global.right_brush_type_container.visible = true Global.brush_type_containers[current_mouse_button].visible = true
Global.right_brush_size_slider.visible = true Global.brush_size_sliders[current_mouse_button].visible = true
Global.right_pixel_perfect_container.visible = true Global.pixel_perfect_containers[current_mouse_button].visible = true
Global.right_mirror_container.visible = true Global.mirror_containers[current_mouse_button].visible = true
elif current_action == "Bucket": elif current_tool == Global.Tools.BUCKET:
Global.right_fill_area_container.visible = true Global.fill_area_containers[current_mouse_button].visible = true
Global.right_mirror_container.visible = true Global.mirror_containers[current_mouse_button].visible = true
elif current_action == "LightenDarken": elif current_tool == Global.Tools.LIGHTENDARKEN:
Global.right_brush_type_container.visible = true Global.brush_type_containers[current_mouse_button].visible = true
Global.right_brush_size_slider.visible = true Global.brush_size_sliders[current_mouse_button].visible = true
Global.right_pixel_perfect_container.visible = true Global.pixel_perfect_containers[current_mouse_button].visible = true
Global.right_ld_container.visible = true Global.ld_containers[current_mouse_button].visible = true
Global.right_mirror_container.visible = true Global.mirror_containers[current_mouse_button].visible = true
elif current_action == "ColorPicker": elif current_tool == Global.Tools.COLORPICKER:
Global.right_colorpicker_container.visible = true Global.colorpicker_containers[current_mouse_button].visible = true
elif current_action == "Zoom": elif current_tool == Global.Tools.ZOOM:
Global.right_zoom_container.visible = true Global.zoom_containers[current_mouse_button].visible = true
for t in tools: for t in tools:
var tool_name : String = t[0].name var tool_name : String = t[0].name.to_lower()
var texture_button : TextureRect = t[0].get_child(0) var texture_button : TextureRect = t[0].get_child(0)
if tool_name == Global.current_left_tool and tool_name == Global.current_right_tool: if tool_name == left_tool_name and tool_name == right_tool_name:
Global.change_button_texturerect(texture_button, "%s_l_r.png" % tool_name.to_lower()) Global.change_button_texturerect(texture_button, "%s_l_r.png" % tool_name.to_lower())
elif tool_name == Global.current_left_tool: elif tool_name == left_tool_name:
Global.change_button_texturerect(texture_button, "%s_l.png" % tool_name.to_lower()) Global.change_button_texturerect(texture_button, "%s_l.png" % tool_name.to_lower())
elif tool_name == Global.current_right_tool: elif tool_name == right_tool_name:
Global.change_button_texturerect(texture_button, "%s_r.png" % tool_name.to_lower()) Global.change_button_texturerect(texture_button, "%s_r.png" % tool_name.to_lower())
else: else:
Global.change_button_texturerect(texture_button, "%s.png" % tool_name.to_lower()) Global.change_button_texturerect(texture_button, "%s.png" % tool_name.to_lower())
Global.left_cursor_tool_texture.create_from_image(load("res://assets/graphics/cursor_icons/%s_cursor.png" % Global.current_left_tool.to_lower()), 0) Global.left_cursor_tool_texture.create_from_image(load("res://assets/graphics/cursor_icons/%s_cursor.png" % left_tool_name), 0)
Global.right_cursor_tool_texture.create_from_image(load("res://assets/graphics/cursor_icons/%s_cursor.png" % Global.current_right_tool.to_lower()), 0) Global.right_cursor_tool_texture.create_from_image(load("res://assets/graphics/cursor_icons/%s_cursor.png" % right_tool_name), 0)

View file

@ -7,6 +7,9 @@ margin_right = 1280.0
margin_bottom = 28.0 margin_bottom = 28.0
rect_min_size = Vector2( 0, 28 ) rect_min_size = Vector2( 0, 28 )
custom_styles/panel = ExtResource( 1 ) custom_styles/panel = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="MenuItems" type="HBoxContainer" parent="."] [node name="MenuItems" type="HBoxContainer" parent="."]
margin_left = 2.0 margin_left = 2.0
@ -17,40 +20,40 @@ __meta__ = {
} }
[node name="FileMenu" type="MenuButton" parent="MenuItems"] [node name="FileMenu" type="MenuButton" parent="MenuItems"]
margin_right = 29.0 margin_right = 35.0
margin_bottom = 21.0 margin_bottom = 20.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
text = "File" text = "File"
switch_on_hover = true switch_on_hover = true
[node name="EditMenu" type="MenuButton" parent="MenuItems"] [node name="EditMenu" type="MenuButton" parent="MenuItems"]
margin_left = 33.0 margin_left = 39.0
margin_right = 64.0 margin_right = 75.0
margin_bottom = 21.0 margin_bottom = 20.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
text = "Edit" text = "Edit"
switch_on_hover = true switch_on_hover = true
[node name="ViewMenu" type="MenuButton" parent="MenuItems"] [node name="ViewMenu" type="MenuButton" parent="MenuItems"]
margin_left = 68.0 margin_left = 79.0
margin_right = 104.0 margin_right = 121.0
margin_bottom = 21.0 margin_bottom = 20.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
text = "View" text = "View"
switch_on_hover = true switch_on_hover = true
[node name="ImageMenu" type="MenuButton" parent="MenuItems"] [node name="ImageMenu" type="MenuButton" parent="MenuItems"]
margin_left = 108.0 margin_left = 125.0
margin_right = 152.0 margin_right = 177.0
margin_bottom = 21.0 margin_bottom = 20.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
text = "Image" text = "Image"
switch_on_hover = true switch_on_hover = true
[node name="HelpMenu" type="MenuButton" parent="MenuItems"] [node name="HelpMenu" type="MenuButton" parent="MenuItems"]
margin_left = 156.0 margin_left = 181.0
margin_right = 191.0 margin_right = 223.0
margin_bottom = 21.0 margin_bottom = 20.0
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
text = "Help" text = "Help"
switch_on_hover = true switch_on_hover = true
@ -67,7 +70,7 @@ __meta__ = {
} }
[node name="ZoomLevel" type="Label" parent="TopLabels"] [node name="ZoomLevel" type="Label" parent="TopLabels"]
margin_top = 6.0 margin_top = 7.0
margin_right = 60.0 margin_right = 60.0
margin_bottom = 21.0 margin_bottom = 21.0
rect_min_size = Vector2( 60, 0 ) rect_min_size = Vector2( 60, 0 )
@ -76,8 +79,8 @@ align = 2
[node name="CursorPosition" type="Label" parent="TopLabels"] [node name="CursorPosition" type="Label" parent="TopLabels"]
margin_left = 80.0 margin_left = 80.0
margin_top = 6.0 margin_top = 7.0
margin_right = 120.0 margin_right = 128.0
margin_bottom = 21.0 margin_bottom = 21.0
text = "[64×64]" text = "[64×64]"
align = 2 align = 2
@ -98,12 +101,20 @@ __meta__ = {
} }
[node name="CurrentFrame" type="Label" parent="HBoxContainer"] [node name="CurrentFrame" type="Label" parent="HBoxContainer"]
margin_left = 113.0 margin_left = 106.0
margin_top = 6.0 margin_right = 198.0
margin_right = 216.0 margin_bottom = 28.0
margin_bottom = 21.0 size_flags_vertical = 1
text = "Current Frame: 1/1" text = "Current frame:"
valign = 1 valign = 1
__meta__ = { __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="CurrentFrameMark" type="Label" parent="HBoxContainer"]
margin_left = 202.0
margin_right = 223.0
margin_bottom = 28.0
size_flags_vertical = 1
text = "1/2"
valign = 1

View file

@ -59,7 +59,7 @@ __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="Tools" type="VBoxContainer" parent="ToolPanel/PanelContainer"] [node name="ToolButtons" type="VBoxContainer" parent="ToolPanel/PanelContainer"]
margin_left = 7.0 margin_left = 7.0
margin_top = 7.0 margin_top = 7.0
margin_right = 39.0 margin_right = 39.0
@ -69,7 +69,7 @@ __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="RectSelect" type="Button" parent="ToolPanel/PanelContainer/Tools" groups=[ [node name="RectSelect" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[
"UIButtons", "UIButtons",
]] ]]
margin_right = 32.0 margin_right = 32.0
@ -78,7 +78,7 @@ rect_min_size = Vector2( 32, 32 )
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
button_mask = 3 button_mask = 3
[node name="TextureRect" type="TextureRect" parent="ToolPanel/PanelContainer/Tools/RectSelect"] [node name="TextureRect" type="TextureRect" parent="ToolPanel/PanelContainer/ToolButtons/RectSelect"]
margin_right = 32.0 margin_right = 32.0
margin_bottom = 32.0 margin_bottom = 32.0
texture = ExtResource( 12 ) texture = ExtResource( 12 )
@ -86,7 +86,7 @@ __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="Zoom" type="Button" parent="ToolPanel/PanelContainer/Tools" groups=[ [node name="Zoom" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[
"UIButtons", "UIButtons",
]] ]]
margin_top = 36.0 margin_top = 36.0
@ -96,7 +96,7 @@ rect_min_size = Vector2( 32, 32 )
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
button_mask = 3 button_mask = 3
[node name="TextureRect" type="TextureRect" parent="ToolPanel/PanelContainer/Tools/Zoom"] [node name="TextureRect" type="TextureRect" parent="ToolPanel/PanelContainer/ToolButtons/Zoom"]
margin_right = 32.0 margin_right = 32.0
margin_bottom = 32.0 margin_bottom = 32.0
texture = ExtResource( 21 ) texture = ExtResource( 21 )
@ -104,7 +104,7 @@ __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="ColorPicker" type="Button" parent="ToolPanel/PanelContainer/Tools" groups=[ [node name="ColorPicker" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[
"UIButtons", "UIButtons",
]] ]]
margin_top = 72.0 margin_top = 72.0
@ -114,7 +114,7 @@ rect_min_size = Vector2( 32, 32 )
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
button_mask = 3 button_mask = 3
[node name="TextureRect" type="TextureRect" parent="ToolPanel/PanelContainer/Tools/ColorPicker"] [node name="TextureRect" type="TextureRect" parent="ToolPanel/PanelContainer/ToolButtons/ColorPicker"]
margin_right = 32.0 margin_right = 32.0
margin_bottom = 32.0 margin_bottom = 32.0
texture = ExtResource( 11 ) texture = ExtResource( 11 )
@ -122,7 +122,7 @@ __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="Pencil" type="Button" parent="ToolPanel/PanelContainer/Tools" groups=[ [node name="Pencil" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[
"UIButtons", "UIButtons",
]] ]]
margin_top = 108.0 margin_top = 108.0
@ -132,7 +132,7 @@ rect_min_size = Vector2( 32, 32 )
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
button_mask = 3 button_mask = 3
[node name="TextureRect" type="TextureRect" parent="ToolPanel/PanelContainer/Tools/Pencil"] [node name="TextureRect" type="TextureRect" parent="ToolPanel/PanelContainer/ToolButtons/Pencil"]
margin_right = 32.0 margin_right = 32.0
margin_bottom = 32.0 margin_bottom = 32.0
texture = ExtResource( 14 ) texture = ExtResource( 14 )
@ -140,7 +140,7 @@ __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="Eraser" type="Button" parent="ToolPanel/PanelContainer/Tools" groups=[ [node name="Eraser" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[
"UIButtons", "UIButtons",
]] ]]
margin_top = 144.0 margin_top = 144.0
@ -150,7 +150,7 @@ rect_min_size = Vector2( 32, 32 )
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
button_mask = 3 button_mask = 3
[node name="TextureRect" type="TextureRect" parent="ToolPanel/PanelContainer/Tools/Eraser"] [node name="TextureRect" type="TextureRect" parent="ToolPanel/PanelContainer/ToolButtons/Eraser"]
margin_right = 32.0 margin_right = 32.0
margin_bottom = 32.0 margin_bottom = 32.0
texture = ExtResource( 13 ) texture = ExtResource( 13 )
@ -158,7 +158,7 @@ __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="Bucket" type="Button" parent="ToolPanel/PanelContainer/Tools" groups=[ [node name="Bucket" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[
"UIButtons", "UIButtons",
]] ]]
margin_top = 180.0 margin_top = 180.0
@ -168,7 +168,7 @@ rect_min_size = Vector2( 32, 32 )
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
button_mask = 3 button_mask = 3
[node name="TextureRect" type="TextureRect" parent="ToolPanel/PanelContainer/Tools/Bucket"] [node name="TextureRect" type="TextureRect" parent="ToolPanel/PanelContainer/ToolButtons/Bucket"]
margin_right = 32.0 margin_right = 32.0
margin_bottom = 32.0 margin_bottom = 32.0
texture = ExtResource( 10 ) texture = ExtResource( 10 )
@ -176,7 +176,7 @@ __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="LightenDarken" type="Button" parent="ToolPanel/PanelContainer/Tools" groups=[ [node name="LightenDarken" type="Button" parent="ToolPanel/PanelContainer/ToolButtons" groups=[
"UIButtons", "UIButtons",
]] ]]
margin_top = 216.0 margin_top = 216.0
@ -186,7 +186,7 @@ rect_min_size = Vector2( 32, 32 )
mouse_default_cursor_shape = 2 mouse_default_cursor_shape = 2
button_mask = 3 button_mask = 3
[node name="TextureRect" type="TextureRect" parent="ToolPanel/PanelContainer/Tools/LightenDarken"] [node name="TextureRect" type="TextureRect" parent="ToolPanel/PanelContainer/ToolButtons/LightenDarken"]
margin_right = 32.0 margin_right = 32.0
margin_bottom = 32.0 margin_bottom = 32.0
texture = ExtResource( 15 ) texture = ExtResource( 15 )