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
This update has been brought to you by the contributions of:
Igor Santarek (jegor377)
Igor Santarek (jegor377), rob-a-bolton
### 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>
## [v0.7] - 2020-05-16

View file

@ -732,9 +732,6 @@ msgstr ""
msgid "Current frame:"
msgstr ""
msgid "Current frame: 1/1"
msgstr ""
msgid "Jump to the first frame\n"
"(%s)"
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_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]
bg_color = Color( 0.109804, 0.0862745, 0.0862745, 0 )
border_width_left = 1
@ -245,18 +257,6 @@ corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
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]
bg_color = Color( 0.445313, 0.432846, 0.370514, 1 )
border_width_left = 5
@ -367,6 +367,20 @@ HSplitContainer/constants/autohide = 1
HSplitContainer/constants/separation = 6
HSplitContainer/icons/grabber = ExtResource( 4 )
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/font_color = Color( 0, 0, 0, 1 )
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/drop_position_color = Color( 1, 0.3, 0.2, 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/relationship_line_color = Color( 0.27451, 0.27451, 0.27451, 1 )
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]
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]
bg_color = Color( 0.109804, 0.0862745, 0.0862745, 0 )
border_width_left = 1
@ -286,18 +298,6 @@ corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
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]
border_width_left = 2
border_width_right = 2
@ -419,6 +419,20 @@ HSplitContainer/constants/autohide = 1
HSplitContainer/constants/separation = 6
HSplitContainer/icons/grabber = ExtResource( 4 )
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/font_color = Color( 1, 1, 1, 1 )
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_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]
bg_color = Color( 0.109804, 0.0862745, 0.0862745, 0 )
border_width_left = 1
@ -258,18 +270,6 @@ corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
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]
bg_color = Color( 0.321569, 0.321569, 0.321569, 1 )
border_width_left = 2
@ -370,6 +370,20 @@ HSplitContainer/constants/autohide = 1
HSplitContainer/constants/separation = 6
HSplitContainer/icons/grabber = ExtResource( 6 )
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/font_color = Color( 1, 1, 1, 1 )
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
[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 )
border_width_left = 1
border_width_top = 1
@ -188,10 +200,10 @@ corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
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 )
[sub_resource type="StyleBoxFlat" id=21]
[sub_resource type="StyleBoxFlat" id=22]
content_margin_left = 4.5
content_margin_right = 4.5
content_margin_top = 3.0
@ -202,7 +214,7 @@ corner_radius_top_right = 5
corner_radius_bottom_right = 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 )
border_width_left = 6
border_width_top = 10
@ -215,10 +227,10 @@ corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
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 )
[sub_resource type="StyleBoxFlat" id=24]
[sub_resource type="StyleBoxFlat" id=25]
bg_color = Color( 0.627451, 0.627451, 0.627451, 1 )
border_width_left = 5
border_width_top = 10
@ -231,7 +243,7 @@ corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
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 )
border_width_left = 10
border_width_top = 6
@ -239,7 +251,7 @@ border_width_right = 10
border_width_bottom = 8
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 )
border_width_left = 10
border_width_top = 6
@ -247,7 +259,7 @@ border_width_right = 10
border_width_bottom = 8
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 )
border_width_left = 10
border_width_top = 6
@ -255,19 +267,6 @@ border_width_right = 10
border_width_bottom = 8
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]
bg_color = Color( 0.627451, 0.627451, 0.627451, 1 )
border_width_left = 4
@ -279,6 +278,7 @@ 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=30]
bg_color = Color( 0.529412, 0.529412, 0.529412, 1 )
@ -390,6 +390,20 @@ HSplitContainer/constants/autohide = 1
HSplitContainer/constants/separation = 6
HSplitContainer/icons/grabber = ExtResource( 1 )
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/font_color = Color( 0, 0, 0, 1 )
Label/colors/font_color_shadow = Color( 0, 0, 0, 0 )
@ -410,7 +424,7 @@ LineEdit/constants/minimum_spaces = 12
LineEdit/fonts/font = null
LineEdit/icons/clear = null
LineEdit/styles/focus = null
LineEdit/styles/normal = SubResource( 19 )
LineEdit/styles/normal = SubResource( 20 )
LineEdit/styles/read_only = null
MenuButton/colors/font_color = Color( 0, 0, 0, 1 )
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/normal = null
OptionButton/styles/pressed = null
Panel/styles/panel = SubResource( 20 )
Panel/styles/panel = SubResource( 21 )
Panel/styles/panelf = 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_accel = Color( 0.164706, 0.164706, 0.164706, 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/labeled_separator_left = null
PopupMenu/styles/labeled_separator_right = null
PopupMenu/styles/panel = SubResource( 22 )
PopupMenu/styles/panel = SubResource( 23 )
PopupMenu/styles/panel_disabled = null
PopupMenu/styles/separator = null
PopupPanel/styles/panel = SubResource( 23 )
PopupPanel/styles/panel = SubResource( 24 )
SpinBox/icons/updown = ExtResource( 6 )
TabContainer/colors/font_color_bg = Color( 0, 0, 0, 1 )
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/menu = null
TabContainer/icons/menu_highlight = null
TabContainer/styles/panel = SubResource( 24 )
TabContainer/styles/tab_bg = SubResource( 25 )
TabContainer/styles/tab_disabled = SubResource( 26 )
TabContainer/styles/tab_fg = SubResource( 27 )
TabContainer/styles/panel = SubResource( 25 )
TabContainer/styles/tab_bg = SubResource( 26 )
TabContainer/styles/tab_disabled = 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_disabled = Color( 0.9, 0.9, 0.9, 0.2 )
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/styles/button = null
Tabs/styles/button_pressed = null
Tabs/styles/panel = SubResource( 24 )
Tabs/styles/tab_bg = SubResource( 25 )
Tabs/styles/tab_disabled = SubResource( 26 )
Tabs/styles/tab_fg = SubResource( 27 )
Tabs/styles/panel = SubResource( 25 )
Tabs/styles/tab_bg = SubResource( 26 )
Tabs/styles/tab_disabled = SubResource( 27 )
Tabs/styles/tab_fg = SubResource( 28 )
TextEdit/colors/background_color = Color( 0, 0, 0, 0 )
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 )
@ -529,7 +543,7 @@ TextEdit/fonts/font = null
TextEdit/icons/tab = null
TextEdit/styles/completion = null
TextEdit/styles/focus = null
TextEdit/styles/normal = SubResource( 28 )
TextEdit/styles/normal = SubResource( 29 )
TextEdit/styles/read_only = null
ToolButton/colors/font_color = Color( 0, 0, 0, 1 )
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/unchecked = null
Tree/icons/updown = null
Tree/styles/bg = SubResource( 29 )
Tree/styles/bg = SubResource( 19 )
Tree/styles/bg_focus = null
Tree/styles/button_pressed = null
Tree/styles/cursor = null

View file

@ -9,16 +9,31 @@
config_version=4
_global_script_classes=[ {
"base": "Reference",
"class": "AnimationTag",
"language": "GDScript",
"path": "res://src/Classes/AnimationTag.gd"
}, {
"base": "Node2D",
"class": "Canvas",
"language": "GDScript",
"path": "res://src/Canvas.gd"
}, {
"base": "Reference",
"class": "Cel",
"language": "GDScript",
"path": "res://src/Classes/Cel.gd"
}, {
"base": "Line2D",
"class": "Guide",
"language": "GDScript",
"path": "res://src/UI/Rulers/Guides.gd"
}, {
"base": "Reference",
"class": "Layer",
"language": "GDScript",
"path": "res://src/Classes/Layer.gd"
}, {
"base": "Button",
"class": "LayerButton",
"language": "GDScript",
@ -35,8 +50,11 @@ _global_script_classes=[ {
"path": "res://src/Palette/PaletteColor.gd"
} ]
_global_script_class_icons={
"AnimationTag": "",
"Canvas": "",
"Cel": "",
"Guide": "",
"Layer": "",
"LayerButton": "",
"Palette": "",
"PaletteColor": ""
@ -60,6 +78,7 @@ config/Version="v0.7"
Global="*res://src/Autoload/Global.gd"
Import="*res://src/Autoload/Import.gd"
OpenSave="*res://src/Autoload/OpenSave.gd"
DrawingAlgos="*res://src/Autoload/DrawingAlgos.gd"
[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
enum Grid_Types {CARTESIAN, ISOMETRIC, ALL}
enum Pressure_Sensitivity {NONE, ALPHA, SIZE, ALPHA_AND_SIZE}
enum Brush_Types {PIXEL, CIRCLE, FILLED_CIRCLE, FILE, RANDOM_FILE, CUSTOM}
var root_directory := "."
var window_title := "" setget title_changed # Why doesn't Godot have get_window_title()?
var config_cache := ConfigFile.new()
var XDGDataPaths = preload("res://src/XDGDataPaths.gd")
var directory_module : Reference
enum Direction {UP, DOWN, LEFT, RIGHT}
enum Mouse_Button {LEFT, RIGHT}
enum Tools {PENCIL, ERASER, BUCKET, LIGHTENDARKEN, RECTSELECT, COLORPICKER, ZOOM}
enum Theme_Types {DARK, BLUE, CARAMEL, LIGHT}
enum Fill_Area {SAME_COLOR_AREA, SAME_COLOR_PIXELS}
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 ^.^
const low_speed_move_rate := 150.0
const medium_speed_move_rate := 750.0
const high_speed_move_rate := 3750.0
enum Direction {
UP = 0,
DOWN = 1,
LEFT = 2,
RIGHT = 3
}
var root_directory := "."
var window_title := "" setget title_changed # Why doesn't Godot have get_window_title()?
var config_cache := ConfigFile.new()
var XDGDataPaths = preload("res://src/XDGDataPaths.gd")
var directory_module : Reference
# Indices are as in the Direction enum
# This is the total time the key for
@ -51,10 +53,10 @@ var right_cursor_tool_texture : ImageTexture
var selected_pixels := []
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 theme_type := "Dark"
var theme_type : int = Theme_Types.DARK
var is_default_image := true
var default_image_width := 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_2 := Color(0.34, 0.35, 0.34, 1)
var autosave_interval := 5.0
var enable_autosave := true
# Tools & options
var current_left_tool := "Pencil"
var current_right_tool := "Eraser"
var current_tools := [Tools.PENCIL, Tools.ERASER]
var show_left_tool_icon := true
var show_right_tool_icon := true
var left_square_indicator_visible := true
var right_square_indicator_visible := false
# 0 for area of same color, 1 for all pixels of the same color
var left_fill_area := 0
var right_fill_area := 0
var fill_areas := [Fill_Area.SAME_COLOR_AREA, Fill_Area.SAME_COLOR_AREA]
var fill_with := [Fill_With.COLOR, Fill_With.COLOR]
var fill_pattern_offsets := [Vector2.ZERO, Vector2.ZERO]
var left_fill_with := 0
var right_fill_with := 0
var ld_modes := [Lighten_Darken_Mode.LIGHTEN, Lighten_Darken_Mode.LIGHTEN]
var ld_amounts := [0.1, 0.1]
var left_fill_pattern_offset := Vector2.ZERO
var right_fill_pattern_offset := Vector2.ZERO
var color_picker_for := [Mouse_Button.LEFT, Mouse_Button.RIGHT]
# 0 for lighten, 1 for darken
var left_ld := 0
var right_ld := 0
var left_ld_amount := 0.1
var right_ld_amount := 0.1
var zoom_modes := [Zoom_Mode.ZOOM_IN, Zoom_Mode.ZOOM_OUT]
# 0 for the left, 1 for the right
var left_color_picker_for := 0
var right_color_picker_for := 1
# 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
var horizontal_mirror := [false, false]
var vertical_mirror := [false, false]
var pixel_perfect := [false, false]
# View menu options
var tile_mode := false
@ -122,29 +109,23 @@ var onion_skinning_future_rate := 1.0
var onion_skinning_blue_red := false
# Brushes
var left_brush_size := 1
var right_brush_size := 1
var current_left_brush_type = Brush_Types.PIXEL
var current_right_brush_type = Brush_Types.PIXEL
var brush_sizes := [1, 1]
var current_brush_types := [Brush_Types.PIXEL, Brush_Types.PIXEL]
var brush_type_window_position := "left"
var brush_type_window_position : int = Mouse_Button.LEFT
var left_circle_points := []
var right_circle_points := []
var brushes_from_files := 0
var custom_brushes := []
var custom_left_brush_index := -1
var custom_right_brush_index := -1
var custom_left_brush_image : Image
var custom_right_brush_image : Image
var custom_left_brush_texture := ImageTexture.new()
var custom_right_brush_texture := ImageTexture.new()
var custom_brush_indexes := [-1, -1]
var custom_brush_images := [Image.new(), Image.new()]
var custom_brush_textures := [ImageTexture.new(), ImageTexture.new()]
# Patterns
var patterns := []
var pattern_window_position := "left"
var pattern_left_image : Image
var pattern_right_image : Image
var pattern_window_position : int = Mouse_Button.LEFT
var pattern_images := [Image.new(), Image.new()]
# Palettes
var palettes := {}
@ -176,65 +157,48 @@ var zoom_level_label : Label
var import_sprites_dialog : FileDialog
var export_dialog : AcceptDialog
var preferences_dialog : AcceptDialog
var left_color_picker : ColorPickerButton
var right_color_picker : ColorPickerButton
var color_pickers := []
var color_switch_button : BaseButton
var left_tool_options_container : Container
var right_tool_options_container : Container
var tool_options_containers := []
var left_brush_type_container : Container
var right_brush_type_container : Container
var left_brush_type_button : BaseButton
var right_brush_type_button : BaseButton
var brush_type_containers := []
var brush_type_buttons := []
var brushes_popup : Popup
var file_brush_container : GridContainer
var project_brush_container : GridContainer
var patterns_popup : Popup
var left_brush_size_edit : SpinBox
var left_brush_size_slider : HSlider
var right_brush_size_edit : SpinBox
var right_brush_size_slider : HSlider
var brush_size_edits := []
var brush_size_sliders := []
var left_pixel_perfect_container : VBoxContainer
var right_pixel_perfect_container : VBoxContainer
var pixel_perfect_containers := []
var left_color_interpolation_container : Container
var right_color_interpolation_container : Container
var left_interpolate_spinbox : SpinBox
var left_interpolate_slider : HSlider
var right_interpolate_spinbox : SpinBox
var right_interpolate_slider : HSlider
var color_interpolation_containers := []
var interpolate_spinboxes := []
var interpolate_sliders := []
var left_fill_area_container : Container
var left_fill_pattern_container : Container
var right_fill_area_container : Container
var right_fill_pattern_container : Container
var fill_area_containers := []
var fill_pattern_containers := []
var left_ld_container : Container
var left_ld_amount_slider : HSlider
var left_ld_amount_spinbox : SpinBox
var right_ld_container : Container
var right_ld_amount_slider : HSlider
var right_ld_amount_spinbox : SpinBox
var ld_containers := []
var ld_amount_sliders := []
var ld_amount_spinboxes := []
var left_colorpicker_container : Container
var right_colorpicker_container : Container
var colorpicker_containers := []
var left_zoom_container : Container
var right_zoom_container : Container
var zoom_containers := []
var left_mirror_container : Container
var right_mirror_container : Container
var mirror_containers := []
var animation_timeline : Panel
var animation_timer : Timer
var frame_ids : HBoxContainer
var current_frame_label : Label
var current_frame_mark_label : Label
var onion_skinning_button : BaseButton
var loop_animation_button : BaseButton
var play_forward : BaseButton
@ -313,58 +277,59 @@ func _ready() -> void:
import_sprites_dialog = find_node_by_name(root, "ImportSprites")
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")
right_tool_options_container = find_node_by_name(root, "RightToolOptions")
tool_options_containers.append(find_node_by_name(root, "LeftToolOptions"))
tool_options_containers.append(find_node_by_name(root, "RightToolOptions"))
left_color_picker = find_node_by_name(root, "LeftColorPickerButton")
right_color_picker = find_node_by_name(root, "RightColorPickerButton")
color_pickers.append(find_node_by_name(root, "LeftColorPickerButton"))
color_pickers.append(find_node_by_name(root, "RightColorPickerButton"))
color_switch_button = find_node_by_name(root, "ColorSwitch")
left_brush_type_container = find_node_by_name(left_tool_options_container, "LeftBrushType")
right_brush_type_container = find_node_by_name(right_tool_options_container, "RightBrushType")
left_brush_type_button = find_node_by_name(left_brush_type_container, "LeftBrushTypeButton")
right_brush_type_button = find_node_by_name(right_brush_type_container, "RightBrushTypeButton")
brush_type_containers.append(find_node_by_name(tool_options_containers[0], "LeftBrushType"))
brush_type_containers.append(find_node_by_name(tool_options_containers[1], "RightBrushType"))
brush_type_buttons.append(find_node_by_name(brush_type_containers[0], "LeftBrushTypeButton"))
brush_type_buttons.append(find_node_by_name(brush_type_containers[1], "RightBrushTypeButton"))
brushes_popup = find_node_by_name(root, "BrushesPopup")
file_brush_container = find_node_by_name(brushes_popup, "FileBrushContainer")
project_brush_container = find_node_by_name(brushes_popup, "ProjectBrushContainer")
patterns_popup = find_node_by_name(root, "PatternsPopup")
left_brush_size_edit = find_node_by_name(root, "LeftBrushSizeEdit")
left_brush_size_slider = find_node_by_name(root, "LeftBrushSizeSlider")
right_brush_size_edit = find_node_by_name(root, "RightBrushSizeEdit")
right_brush_size_slider = find_node_by_name(root, "RightBrushSizeSlider")
brush_size_edits.append(find_node_by_name(root, "LeftBrushSizeEdit"))
brush_size_sliders.append(find_node_by_name(root, "LeftBrushSizeSlider"))
brush_size_edits.append(find_node_by_name(root, "RightBrushSizeEdit"))
brush_size_sliders.append(find_node_by_name(root, "RightBrushSizeSlider"))
left_pixel_perfect_container = 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, "LeftBrushPixelPerfectMode"))
pixel_perfect_containers.append(find_node_by_name(root, "RightBrushPixelPerfectMode"))
left_color_interpolation_container = find_node_by_name(root, "LeftColorInterpolation")
right_color_interpolation_container = find_node_by_name(root, "RightColorInterpolation")
left_interpolate_spinbox = find_node_by_name(root, "LeftInterpolateFactor")
left_interpolate_slider = find_node_by_name(root, "LeftInterpolateSlider")
right_interpolate_spinbox = find_node_by_name(root, "RightInterpolateFactor")
right_interpolate_slider = find_node_by_name(root, "RightInterpolateSlider")
color_interpolation_containers.append(find_node_by_name(root, "LeftColorInterpolation"))
color_interpolation_containers.append(find_node_by_name(root, "RightColorInterpolation"))
interpolate_spinboxes.append(find_node_by_name(root, "LeftInterpolateFactor"))
interpolate_sliders.append(find_node_by_name(root, "LeftInterpolateSlider"))
interpolate_spinboxes.append(find_node_by_name(root, "RightInterpolateFactor"))
interpolate_sliders.append(find_node_by_name(root, "RightInterpolateSlider"))
left_fill_area_container = find_node_by_name(root, "LeftFillArea")
left_fill_pattern_container = find_node_by_name(root, "LeftFillPattern")
right_fill_area_container = find_node_by_name(root, "RightFillArea")
right_fill_pattern_container = find_node_by_name(root, "RightFillPattern")
fill_area_containers.append(find_node_by_name(root, "LeftFillArea"))
fill_pattern_containers.append(find_node_by_name(root, "LeftFillPattern"))
fill_area_containers.append(find_node_by_name(root, "RightFillArea"))
fill_pattern_containers.append(find_node_by_name(root, "RightFillPattern"))
left_ld_container = find_node_by_name(root, "LeftLDOptions")
left_ld_amount_slider = find_node_by_name(root, "LeftLDAmountSlider")
left_ld_amount_spinbox = find_node_by_name(root, "LeftLDAmountSpinbox")
right_ld_container = find_node_by_name(root, "RightLDOptions")
right_ld_amount_slider = find_node_by_name(root, "RightLDAmountSlider")
right_ld_amount_spinbox = find_node_by_name(root, "RightLDAmountSpinbox")
ld_containers.append(find_node_by_name(root, "LeftLDOptions"))
ld_amount_sliders.append(find_node_by_name(root, "LeftLDAmountSlider"))
ld_amount_spinboxes.append(find_node_by_name(root, "LeftLDAmountSpinbox"))
ld_containers.append(find_node_by_name(root, "RightLDOptions"))
ld_amount_sliders.append(find_node_by_name(root, "RightLDAmountSlider"))
ld_amount_spinboxes.append(find_node_by_name(root, "RightLDAmountSpinbox"))
left_colorpicker_container = find_node_by_name(root, "LeftColorPickerOptions")
right_colorpicker_container = find_node_by_name(root, "RightColorPickerOptions")
colorpicker_containers.append(find_node_by_name(root, "LeftColorPickerOptions"))
colorpicker_containers.append(find_node_by_name(root, "RightColorPickerOptions"))
left_zoom_container = find_node_by_name(root, "LeftZoomOptions")
right_zoom_container = find_node_by_name(root, "RightZoomOptions")
zoom_containers.append(find_node_by_name(root, "LeftZoomOptions"))
zoom_containers.append(find_node_by_name(root, "RightZoomOptions"))
left_mirror_container = find_node_by_name(root, "LeftMirrorButtons")
right_mirror_container = find_node_by_name(root, "RightMirrorButtons")
mirror_containers.append(find_node_by_name(root, "LeftMirrorButtons"))
mirror_containers.append(find_node_by_name(root, "RightMirrorButtons"))
animation_timeline = find_node_by_name(root, "AnimationTimeline")
@ -372,7 +337,7 @@ func _ready() -> void:
frames_container = find_node_by_name(animation_timeline, "FramesContainer")
animation_timer = find_node_by_name(animation_timeline, "AnimationTimer")
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")
loop_animation_button = find_node_by_name(animation_timeline, "LoopAnim")
play_forward = find_node_by_name(animation_timeline, "PlayForward")
@ -401,13 +366,11 @@ func _ready() -> void:
error_dialog = find_node_by_name(root, "ErrorDialog")
# Store [Layer name (0), Layer visibility boolean (1), Layer lock boolean (2), Frame container (3),
# will new cels be linked boolean (4), Array of linked cels (5)]
layers.append([tr("Layer") + " 0", true, false, HBoxContainer.new(), false, []])
layers.append(Layer.new())
# 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:
return root
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)
elif action_name == "Change Frame Order":
canvas_parent.move_child(_canvases[0], _canvases[0].frame)
canvas_parent.move_child(canvas_parent.get_node("TransparentChecker"), 0)
canvas.update()
if !project_has_changed:
@ -498,6 +462,7 @@ func redo(_canvases : Array, layer_index : int = -1) -> void:
animation_timer.stop()
elif action_name == "Change Frame Order":
canvas_parent.move_child(_canvases[0], _canvases[0].frame)
canvas_parent.move_child(canvas_parent.get_node("TransparentChecker"), 0)
canvas.update()
if !project_has_changed:
@ -523,7 +488,7 @@ func canvases_changed(value : Array) -> void:
frame_id.queue_free()
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()):
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()
cel_button.frame = j
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
# 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
if play_only_tags:
for tag in animation_tags:
if current_frame + 1 >= tag[2] && current_frame + 1 <= tag[3]:
animation_timeline.first_frame = tag[2] - 1
animation_timeline.last_frame = min(canvases.size() - 1, tag[3] - 1)
if current_frame + 1 >= tag.from && current_frame + 1 <= tag.to:
animation_timeline.first_frame = tag.from - 1
animation_timeline.last_frame = min(canvases.size() - 1, tag.to - 1)
func clear_canvases() -> void:
@ -591,27 +556,27 @@ func layers_changed(value : Array) -> void:
for i in range(layers.size() - 1, -1, -1):
var layer_container = load("res://src/UI/Timeline/LayerButton.tscn").instance()
layer_container.i = i
if !layers[i][0]:
layers[i][0] = tr("Layer") + " %s" % i
if layers[i].name == tr("Layer") + " 0":
layers[i].name = tr("Layer") + " %s" % i
layers_container.add_child(layer_container)
layer_container.label.text = layers[i][0]
layer_container.line_edit.text = layers[i][0]
layer_container.label.text = layers[i].name
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()):
var cel_button = load("res://src/UI/Timeline/CelButton.tscn").instance()
cel_button.frame = j
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)
layer_button.pressed = true
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)
if layers.size() == 1:
@ -619,13 +584,13 @@ func layers_changed(value : Array) -> void:
disable_button(move_up_layer_button, true)
disable_button(move_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)
func frame_changed(value : int) -> void:
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
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.line_2d.set_point_position(1, c.line_2d.points[0])
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
frame_ids.get_child(i).add_color_override("font_color", text_color)
for layer in layers:
if i < layer[3].get_child_count():
layer[3].get_child(i).pressed = false
if i < layer.frame_container.get_child_count():
layer.frame_container.get_child(i).pressed = false
i += 1
# Select the new canvas/frame
canvas = canvases[current_frame]
canvas.visible = true
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():
layers[current_layer][3].get_child(current_frame).pressed = true
if current_frame < layers[current_layer].frame_container.get_child_count():
layers[current_layer].frame_container.get_child(current_frame).pressed = true
if canvases.size() == 1:
disable_button(remove_frame_button, true)
elif !layers[current_layer][2]:
elif !layers[current_layer].locked:
disable_button(remove_frame_button, false)
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:
current_layer = value
layer_opacity_slider.value = canvas.layers[current_layer][2] * 100
layer_opacity_spinbox.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].opacity * 100
for container in layers_container.get_children():
container.pressed = false
@ -681,7 +646,7 @@ func layer_changed(value : int) -> void:
disable_button(merge_down_layer_button, true)
if current_layer < layers.size():
if layers[current_layer][2]:
if layers[current_layer].locked:
disable_button(remove_layer_button, true)
else:
if layers.size() > 1:
@ -711,8 +676,8 @@ func disable_button(button : BaseButton, disable : bool) -> void:
if button is Button:
var theme := theme_type
if theme == "Caramel":
theme = "Dark"
if theme == Theme_Types.CARAMEL:
theme = Theme_Types.DARK
for c in button.get_children():
if c is TextureRect:
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)
var tag_position := tag_container.get_child_count() - 1
tag_container.move_child(tag_c, tag_position)
tag_c.get_node("Label").text = tag[0]
tag_c.get_node("Label").modulate = tag[1]
tag_c.get_node("Line2D").default_color = tag[1]
tag_c.get_node("Label").text = tag.name
tag_c.get_node("Label").modulate = tag.color
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.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)
@ -757,9 +722,9 @@ func animation_tags_changed(value : Array) -> void:
animation_timeline.last_frame = canvases.size() - 1
if play_only_tags:
for tag in animation_tags:
if current_frame + 1 >= tag[2] && current_frame + 1 <= tag[3]:
animation_timeline.first_frame = tag[2] - 1
animation_timeline.last_frame = min(canvases.size() - 1, tag[3] - 1)
if current_frame + 1 >= tag.from && current_frame + 1 <= tag.to:
animation_timeline.first_frame = tag.from - 1
animation_timeline.last_frame = min(canvases.size() - 1, tag.to - 1)
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:
current_left_brush_type = Brush_Types.PIXEL
current_right_brush_type = Brush_Types.PIXEL
current_brush_types[0] = Brush_Types.PIXEL
current_brush_types[1] = Brush_Types.PIXEL
for child in project_brush_container.get_children():
child.queue_free()
@ -884,56 +849,32 @@ func redo_custom_brush(_brush_button : BaseButton = null) -> void:
project_brush_container.remove_child(_brush_button)
func update_left_custom_brush() -> void:
if current_left_brush_type == Brush_Types.PIXEL:
func update_custom_brush(mouse_button : int) -> void:
if current_brush_types[mouse_button] == Brush_Types.PIXEL:
var pixel := Image.new()
pixel = preload("res://assets/graphics/pixel_image.png")
left_brush_type_button.get_child(0).texture.create_from_image(pixel, 0)
elif current_left_brush_type == Brush_Types.CIRCLE:
brush_type_buttons[mouse_button].get_child(0).texture.create_from_image(pixel, 0)
elif current_brush_types[mouse_button] == Brush_Types.CIRCLE:
var pixel := Image.new()
pixel = preload("res://assets/graphics/circle_9x9.png")
left_brush_type_button.get_child(0).texture.create_from_image(pixel, 0)
left_circle_points = plot_circle(left_brush_size)
elif current_left_brush_type == Brush_Types.FILLED_CIRCLE:
brush_type_buttons[mouse_button].get_child(0).texture.create_from_image(pixel, 0)
left_circle_points = plot_circle(brush_sizes[0])
right_circle_points = plot_circle(brush_sizes[1])
elif current_brush_types[mouse_button] == Brush_Types.FILLED_CIRCLE:
var pixel := Image.new()
pixel = preload("res://assets/graphics/circle_filled_9x9.png")
left_brush_type_button.get_child(0).texture.create_from_image(pixel, 0)
left_circle_points = plot_circle(left_brush_size)
brush_type_buttons[mouse_button].get_child(0).texture.create_from_image(pixel, 0)
left_circle_points = plot_circle(brush_sizes[0])
right_circle_points = plot_circle(brush_sizes[1])
else:
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()
custom_brush.resize(custom_brush_size.x * left_brush_size, custom_brush_size.y * left_brush_size, Image.INTERPOLATE_NEAREST)
custom_left_brush_image = blend_image_with_color(custom_brush, left_color_picker.color, left_interpolate_spinbox.value / 100)
custom_left_brush_texture.create_from_image(custom_left_brush_image, 0)
custom_brush.resize(custom_brush_size.x * brush_sizes[mouse_button], custom_brush_size.y * brush_sizes[mouse_button], Image.INTERPOLATE_NEAREST)
custom_brush_images[mouse_button] = blend_image_with_color(custom_brush, color_pickers[mouse_button].color, interpolate_spinboxes[mouse_button].value / 100)
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
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
brush_type_buttons[mouse_button].get_child(0).texture = custom_brush_textures[mouse_button]
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
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:
config_cache.set_value("window", "screen", OS.current_screen)
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:
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()
pattern_left_tex.create_from_image(Global.pattern_left_image, 0)
Global.left_fill_pattern_container.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.left_fill_pattern_container.get_child(3).get_child(1).max_value = image_size.y - 1
pattern_left_tex.create_from_image(Global.pattern_images[0], 0)
Global.fill_pattern_containers[0].get_child(0).get_child(0).texture = pattern_left_tex
Global.fill_pattern_containers[0].get_child(2).get_child(1).max_value = image_size.x - 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()
pattern_right_tex.create_from_image(Global.pattern_right_image, 0)
Global.right_fill_pattern_container.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.right_fill_pattern_container.get_child(3).get_child(1).max_value = image_size.y - 1
pattern_right_tex.create_from_image(Global.pattern_images[1], 0)
Global.fill_pattern_containers[1].get_child(0).get_child(0).texture = pattern_right_tex
Global.fill_pattern_containers[1].get_child(2).get_child(1).max_value = image_size.x - 1
Global.fill_pattern_containers[1].get_child(3).get_child(1).max_value = image_size.y - 1
func import_gpl(path : String) -> Palette:

View file

@ -3,7 +3,6 @@ extends Node
var current_save_path := ""
# Stores a filename of a backup file in user:// until user saves manually
var backup_save_path = ""
var default_autosave_interval := 5 # Minutes
onready var autosave_timer : Timer
@ -14,8 +13,7 @@ func _ready() -> void:
autosave_timer.process_mode = Timer.TIMER_PROCESS_IDLE
autosave_timer.connect("timeout", self, "_on_Autosave_timeout")
add_child(autosave_timer)
set_autosave_interval(default_autosave_interval)
toggle_autosave(true) # Gets started from preferences dialog
update_autosave()
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()
linked_cels.append(file.get_var())
# Store [Layer name (0), Layer visibility boolean (1), Layer lock boolean (2), Frame container (3),
# will new cels be linked boolean (4), Array of linked cels (5)]
Global.layers.append([layer_name, layer_visibility, layer_lock, HBoxContainer.new(), layer_new_cels_linked, []])
var l := Layer.new(layer_name, layer_visibility, layer_lock, HBoxContainer.new(), layer_new_cels_linked, [])
Global.layers.append(l)
global_layer_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:
var layer_name_old_version = file.get_line()
if frame == 0:
# 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)]
Global.layers.append([layer_name_old_version, true, false, HBoxContainer.new(), false, []])
var l := Layer.new(layer_name_old_version)
Global.layers.append(l)
var layer_transparency := 1.0
if file_major_version >= 0 and file_minor_version > 5:
layer_transparency = file.get_float()
var image := Image.new()
image.create_from_data(width, height, false, Image.FORMAT_RGBA8, buffer)
image.lock()
var tex := ImageTexture.new()
tex.create_from_image(image, 0)
canvas.layers.append([image, tex, layer_transparency])
canvas.layers.append(Cel.new(image, layer_transparency))
if file_major_version >= 0 and file_minor_version >= 7:
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_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.layers = Global.layers # Just to call Global.layers_changed
# Load tool options
Global.left_color_picker.color = file.get_var()
Global.right_color_picker.color = file.get_var()
Global.left_brush_size = file.get_8()
Global.left_brush_size_edit.value = Global.left_brush_size
Global.right_brush_size = file.get_8()
Global.right_brush_size_edit.value = Global.right_brush_size
Global.color_pickers[0].color = file.get_var()
Global.color_pickers[1].color = file.get_var()
Global.brush_sizes[0] = file.get_8()
Global.brush_size_edits[0].value = Global.brush_sizes[0]
Global.brush_sizes[1] = file.get_8()
Global.brush_size_edits[1].value = Global.brush_sizes[1]
if file_major_version == 0 and file_minor_version < 7:
var left_palette = file.get_var()
var right_palette = file.get_var()
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:
Global.right_color_picker.get_picker().add_preset(color)
Global.color_pickers[1].get_picker().add_preset(color)
# Load custom brushes
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_from := 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()
tag_line = file.get_line()
@ -187,12 +181,12 @@ func save_pxo_file(path : String, autosave : bool) -> void:
# Store Global layers
for layer in Global.layers:
file.store_line(".")
file.store_line(layer[0]) # Layer name
file.store_8(layer[1]) # Layer visibility
file.store_8(layer[2]) # Layer lock
file.store_8(layer[4]) # Future cels linked
file.store_line(layer.name)
file.store_8(layer.visible)
file.store_8(layer.locked)
file.store_8(layer.new_cels_linked)
var linked_cels := []
for canvas in layer[5]:
for canvas in layer.linked_cels:
linked_cels.append(canvas.frame)
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)
for layer in canvas.layers: # Store canvas layers
file.store_line("-")
file.store_buffer(layer[0].get_data())
file.store_float(layer[2]) # Layer transparency
file.store_buffer(layer.image.get_data())
file.store_float(layer.opacity)
file.store_line("END_LAYERS")
# Store guides
@ -224,10 +218,10 @@ func save_pxo_file(path : String, autosave : bool) -> void:
file.store_line("END_FRAMES")
# Save tool options
var left_color : Color = Global.left_color_picker.color
var right_color : Color = Global.right_color_picker.color
var left_brush_size : int = Global.left_brush_size
var right_brush_size : int = Global.right_brush_size
var left_color : Color = Global.color_pickers[0].color
var right_color : Color = Global.color_pickers[1].color
var left_brush_size : int = Global.brush_sizes[0]
var right_brush_size : int = Global.brush_sizes[1]
file.store_var(left_color)
file.store_var(right_color)
file.store_8(left_brush_size)
@ -245,10 +239,10 @@ func save_pxo_file(path : String, autosave : bool) -> void:
# Store animation tags
for tag in Global.animation_tags:
file.store_line(".T/")
file.store_line(tag[0]) # Tag name
file.store_var(tag[1]) # Tag color
file.store_8(tag[2]) # Tag "from", the first frame
file.store_8(tag[3]) # Tag "to", the last frame
file.store_line(tag.name)
file.store_var(tag.color)
file.store_8(tag.from)
file.store_8(tag.to)
file.store_line("END_FRAME_TAGS")
file.close()
@ -271,16 +265,11 @@ func save_pxo_file(path : String, autosave : bool) -> void:
Global.notification_label("File failed to save")
func toggle_autosave(enable : bool) -> void:
if enable:
func update_autosave() -> void:
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()
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:

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.
func _ready() -> void:
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.
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
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"):
OS.window_size = Global.config_cache.get_value("window", "size")
func setup_file_menu() -> void:
var file_menu_items := {
"New..." : InputMap.get_action_list("new_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(),
"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 := {
"Undo" : InputMap.get_action_list("undo")[0].get_scancode_with_modifiers(),
"Redo" : InputMap.get_action_list("redo")[0].get_scancode_with_modifiers(),
"Clear Selection" : 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 := {
"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(),
@ -54,6 +130,21 @@ func _ready() -> void:
"Show Guides" : InputMap.get_action_list("show_guides")[0].get_scancode_with_modifiers(),
"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 := {
"Scale Image" : 0,
"Crop Image" : 0,
@ -65,6 +156,19 @@ func _ready() -> void:
"Outline" : 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 := {
"View Splash Screen" : 0,
"Online Docs" : 0,
@ -72,86 +176,17 @@ func _ready() -> void:
"Changelog" : 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 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
var i := 0
for item in help_menu_items.keys():
help_menu.add_item(item, i, help_menu_items[item])
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")
# 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
yield(get_tree().create_timer(0.01), "timeout")
if Global.config_cache.get_value("preferences", "startup"):
@ -160,6 +195,8 @@ func _ready() -> void:
else:
Global.can_draw = true
func handle_backup() -> void:
# If backup file exists then Pixelorama was not closed properly (probably crashed) - reopen backup
$BackupConfirmation.get_cancel().text = tr("Delete")
if Global.config_cache.has_section("backups"):
@ -183,34 +220,16 @@ func _ready() -> void:
if Global.open_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 _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 handle_loading_files(files : PoolStringArray) -> void:
for file in files:
if file.get_extension().to_lower() == "pxo":
_on_OpenSprite_file_selected(file)
else:
if file == files[0]:
$ImportSprites.new_frame = false
$ImportSprites._on_ImportSprites_files_selected([file])
$ImportSprites.new_frame = true
func _notification(what : int) -> void:
@ -218,53 +237,85 @@ func _notification(what : int) -> void:
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:
match id:
0: # New
if Global.project_has_changed:
unsaved_canvas_state = id
$UnsavedCanvasDialog.popup_centered()
else:
$CreateNewImage.popup_centered()
Global.dialog_open(true)
on_new_project_file_menu_option_pressed(id)
1: # Open
$OpenSprite.popup_centered()
Global.dialog_open(true)
opensprite_file_selected = false
open_project_file()
2: # Open last project
# 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)
on_open_last_project_file_menu_option_pressed(id)
3: # Save
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)
save_project_file()
4: # Save as
is_quitting_on_save = false
$SaveSprite.popup_centered()
Global.dialog_open(true)
save_project_file_as()
5: # Import
$ImportSprites.popup_centered()
Global.dialog_open(true)
opensprite_file_selected = false
import_file()
6: # Export
if $ExportDialog.was_exported == false:
$ExportDialog.popup_centered()
Global.dialog_open(true)
else:
$ExportDialog.external_export()
export_file()
7: # Export as
$ExportDialog.popup_centered()
Global.dialog_open(true)
@ -293,134 +344,190 @@ func edit_menu_id_pressed(id : int) -> void:
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:
match id:
0: # Tile mode
Global.tile_mode = !Global.tile_mode
view_menu.set_item_checked(0, Global.tile_mode)
toggle_tile_mode()
1: # Show grid
Global.draw_grid = !Global.draw_grid
view_menu.set_item_checked(1, Global.draw_grid)
toggle_show_grid()
2: # Show rulers
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
toggle_show_rulers()
3: # Show guides
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
toggle_show_guides()
4: # Show animation timeline
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
toggle_show_anim_timeline()
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:
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
match id:
0: # Scale Image
$ScaleImage.popup_centered()
Global.dialog_open(true)
show_scale_image_popup()
1: # Crop Image
# Use first cel as a starting rectangle
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()
crop_image()
2: # Flip Horizontal
var canvas : Canvas = Global.canvas
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")
flip_image_horizontal()
3: # Flip Vertical
var canvas : Canvas = Global.canvas
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")
flip_image_vertical()
4: # Rotate
var image : Image = Global.canvas.layers[Global.current_layer][0]
$RotateImage.set_sprite(image)
$RotateImage.popup_centered()
Global.dialog_open(true)
show_rotate_image_popup()
5: # Invert Colors
var image : Image = Global.canvas.layers[Global.current_layer][0]
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")
invert_image_colors()
6: # Desaturation
var image : Image = Global.canvas.layers[Global.current_layer][0]
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")
desaturate_image()
7: # Outline
$OutlineDialog.popup_centered()
Global.dialog_open(true)
show_add_outline_popup()
8: # HSV
$HSVDialog.popup_centered()
Global.dialog_open(true)
show_hsv_configuration_popup()
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/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/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/AboutDialog.tscn" type="PackedScene" id=34]
[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()
Global.dialog_open(true)
left_color_button.modulate = Global.left_color_picker.color
right_color_button.modulate = Global.right_color_picker.color
left_color_button.modulate = Global.color_pickers[0].color
right_color_button.modulate = Global.color_pickers[1].color
func _display_palette() -> void:
@ -177,12 +177,12 @@ func _refresh_hint_tooltip(_index : int) -> 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)
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)

View file

@ -165,11 +165,11 @@ func on_color_select(index : int) -> void:
var color : Color = Global.palettes[current_palette].get_color(index)
if Input.is_action_just_pressed("left_mouse"):
Global.left_color_picker.color = color
Global.update_left_custom_brush()
Global.color_pickers[0].color = color
Global.update_custom_brush(0)
elif Input.is_action_just_pressed("right_mouse"):
Global.right_color_picker.color = color
Global.update_right_custom_brush()
Global.color_pickers[1].color = color
Global.update_custom_brush(1)
func _load_palettes() -> void:
@ -195,7 +195,7 @@ func _load_palettes() -> void:
# You need these two lines because when you remove a palette
# Then this just won't work and _on_PaletteOptionButton_item_selected
# method won't fire.
Global.palette_option_button.selected
Global.palette_option_button.selected = index
on_palette_select("Default")
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/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"]
margin_left = -3.0
@ -33,12 +40,10 @@ __meta__ = {
"_edit_use_anchors_": false
}
[node name="Tree" type="Tree" parent="HSplitContainer"]
[node name="List" type="ItemList" parent="HSplitContainer"]
margin_right = 86.0
margin_bottom = 1110.0
rect_min_size = Vector2( 85, 0 )
custom_constants/item_margin = -2
hide_root = true
[node name="ScrollContainer" type="ScrollContainer" parent="HSplitContainer"]
margin_left = 98.0
@ -49,15 +54,15 @@ size_flags_horizontal = 3
[node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer/ScrollContainer"]
margin_right = 506.0
margin_bottom = 1286.0
margin_bottom = 180.0
size_flags_horizontal = 3
[node name="General" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_right = 494.0
margin_right = 506.0
margin_bottom = 180.0
[node name="SmoothZoom" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_right = 494.0
margin_right = 506.0
margin_bottom = 24.0
hint_tooltip = "Adds a smoother transition when zooming in or out"
mouse_default_cursor_shape = 2
@ -66,19 +71,19 @@ text = "Smooth Zoom"
[node name="HSeparator2" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 28.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 32.0
[node name="GridContainer" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 36.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 88.0
custom_constants/vseparation = 4
custom_constants/hseparation = 4
columns = 2
[node name="LeftIndicatorCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"]
margin_right = 245.0
margin_right = 251.0
margin_bottom = 24.0
hint_tooltip = "Show left mouse pixel indicator or brush on the canvas when drawing"
mouse_default_cursor_shape = 2
@ -87,8 +92,8 @@ pressed = true
text = "Left pixel indicator"
[node name="RightIndicatorCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"]
margin_left = 249.0
margin_right = 494.0
margin_left = 255.0
margin_right = 506.0
margin_bottom = 24.0
hint_tooltip = "Show right mouse pixel indicator or brush on the canvas when drawing"
mouse_default_cursor_shape = 2
@ -97,7 +102,7 @@ text = "Right pixel indicator"
[node name="LeftToolIconCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"]
margin_top = 28.0
margin_right = 245.0
margin_right = 251.0
margin_bottom = 52.0
hint_tooltip = "Displays an icon of the selected left tool next to the cursor on the canvas"
mouse_default_cursor_shape = 2
@ -106,9 +111,9 @@ pressed = true
text = "Show left tool icon"
[node name="RightToolIconCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"]
margin_left = 249.0
margin_left = 255.0
margin_top = 28.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 52.0
hint_tooltip = "Displays an icon of the selected right tool next to the cursor on the canvas"
mouse_default_cursor_shape = 2
@ -118,14 +123,14 @@ text = "Show right tool icon"
[node name="HSeparator3" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 92.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 96.0
[node name="PressureSentivity" type="HBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
visible = false
margin_top = 116.0
margin_right = 334.0
margin_bottom = 136.0
margin_top = 100.0
margin_right = 506.0
margin_bottom = 120.0
[node name="PressureSensitivityLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/PressureSentivity"]
margin_top = 3.0
@ -143,7 +148,7 @@ selected = 1
[node name="OpenLastProject" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 100.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 124.0
hint_tooltip = "Opens last opened project on startup"
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"]
margin_top = 128.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 152.0
mouse_default_cursor_shape = 2
pressed = true
@ -162,7 +167,7 @@ __meta__ = {
[node name="AutosaveInterval" type="HBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 156.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 180.0
__meta__ = {
"_edit_use_anchors_": false
@ -176,7 +181,7 @@ text = "Autosave interval:"
[node name="AutosaveInterval" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/AutosaveInterval"]
margin_left = 119.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
@ -191,171 +196,196 @@ __meta__ = {
}
[node name="Languages" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
visible = false
margin_top = 184.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 632.0
script = ExtResource( 4 )
[node name="System Language" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_right = 494.0
margin_right = 506.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
pressed = true
group = SubResource( 1 )
text = "System Language"
[node name="Czech" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 28.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 52.0
mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Czech [cs]"
[node name="German" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 56.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 80.0
mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Deutsch [de]"
[node name="Greek" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 84.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 108.0
mouse_default_cursor_shape = 2
custom_fonts/font = ExtResource( 2 )
group = SubResource( 1 )
text = "Ελληνικά [el]"
[node name="English" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 112.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 136.0
mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "English [en]"
[node name="Esperanto" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 140.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 164.0
mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Esperanto [eo]"
[node name="Spanish" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 168.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 192.0
mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Español [es]"
[node name="French" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 196.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 220.0
mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Français [fr]"
[node name="Indonesian" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 224.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 248.0
mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Indonesian [id]"
[node name="Italian" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 252.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 276.0
mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Italiano [it]"
[node name="Latvian" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 280.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 304.0
mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Latvian [lv]"
[node name="Polish" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 308.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 332.0
mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Polski [pl]"
[node name="Brazilian Portuguese" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 336.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 360.0
mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Português Brasileiro [pt_BR]"
[node name="Russian" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 364.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 388.0
mouse_default_cursor_shape = 2
group = SubResource( 1 )
text = "Русский [ru]"
[node name="Chinese Simplified" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 392.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 418.0
mouse_default_cursor_shape = 2
custom_fonts/font = ExtResource( 3 )
group = SubResource( 1 )
text = "简体中文 [zh_CN]"
[node name="Chinese Traditional" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 422.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 448.0
mouse_default_cursor_shape = 2
custom_fonts/font = ExtResource( 3 )
group = SubResource( 1 )
text = "繁體中文 [zh_TW]"
[node name="Themes" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_top = 636.0
margin_right = 494.0
margin_bottom = 772.0
visible = false
margin_right = 506.0
margin_bottom = 136.0
script = ExtResource( 5 )
[node name="Dark Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"]
margin_right = 494.0
margin_right = 506.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
group = SubResource( 2 )
text = "Dark"
[node name="Gray Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"]
margin_top = 28.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 52.0
mouse_default_cursor_shape = 2
group = SubResource( 2 )
text = "Gray"
[node name="Blue Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"]
margin_top = 56.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 80.0
mouse_default_cursor_shape = 2
group = SubResource( 2 )
text = "Blue"
[node name="Caramel Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"]
margin_top = 84.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 108.0
mouse_default_cursor_shape = 2
group = SubResource( 2 )
text = "Caramel"
[node name="Light Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"]
margin_top = 112.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 136.0
mouse_default_cursor_shape = 2
group = SubResource( 2 )
text = "Light"
[node name="Canvas" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_top = 776.0
margin_right = 494.0
margin_bottom = 968.0
visible = false
margin_top = 184.0
margin_right = 506.0
margin_bottom = 376.0
[node name="GuideOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"]
margin_right = 494.0
margin_right = 506.0
margin_bottom = 20.0
custom_constants/vseparation = 4
custom_constants/hseparation = 4
@ -372,7 +402,7 @@ text = "Guides color:"
[node name="GuideColor" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GuideOptions"]
margin_left = 114.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 20.0
rect_min_size = Vector2( 64, 20 )
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"]
margin_top = 24.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 28.0
[node name="GridOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"]
margin_top = 32.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 108.0
custom_constants/vseparation = 4
custom_constants/hseparation = 4
@ -404,13 +434,14 @@ text = "Grid width:"
[node name="GridWidthValue" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions"]
margin_left = 114.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 24.0
hint_tooltip = "Sets how far apart are vertical lines of the grid"
mouse_default_cursor_shape = 2
min_value = 1.0
max_value = 16384.0
value = 1.0
rounded = true
align = 2
suffix = "px"
@ -425,7 +456,7 @@ text = "Grid height:"
[node name="GridHeightValue" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions"]
margin_left = 114.0
margin_top = 28.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 52.0
hint_tooltip = "Sets how far apart are horizontal lines of the grid"
mouse_default_cursor_shape = 2
@ -433,6 +464,7 @@ size_flags_horizontal = 3
min_value = 1.0
max_value = 16384.0
value = 1.0
rounded = true
align = 2
suffix = "px"
@ -447,7 +479,7 @@ text = "Grid color:"
[node name="GridColor" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions"]
margin_left = 114.0
margin_top = 56.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 76.0
rect_min_size = Vector2( 64, 20 )
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"]
margin_top = 112.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 116.0
[node name="CheckerOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"]
margin_top = 120.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 192.0
custom_constants/vseparation = 4
custom_constants/hseparation = 4
@ -477,13 +509,15 @@ text = "Checker size:"
[node name="CheckerSizeValue" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions"]
margin_left = 114.0
margin_right = 188.0
margin_right = 506.0
margin_bottom = 24.0
hint_tooltip = "Size of the transparent checker background"
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
min_value = 1.0
max_value = 16384.0
value = 10.0
rounded = true
align = 2
suffix = "px"
@ -498,7 +532,7 @@ text = "Checker color 1:"
[node name="CheckerColor1" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions"]
margin_left = 114.0
margin_top = 28.0
margin_right = 188.0
margin_right = 506.0
margin_bottom = 48.0
rect_min_size = Vector2( 64, 20 )
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"]
margin_left = 114.0
margin_top = 52.0
margin_right = 188.0
margin_right = 506.0
margin_bottom = 72.0
rect_min_size = Vector2( 64, 20 )
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 )
[node name="Image" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_top = 972.0
margin_right = 494.0
margin_bottom = 1048.0
visible = false
margin_top = 184.0
margin_right = 506.0
margin_bottom = 260.0
[node name="ImageOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image"]
margin_right = 494.0
margin_right = 506.0
margin_bottom = 76.0
custom_constants/vseparation = 4
custom_constants/hseparation = 4
@ -546,7 +581,7 @@ text = "Default width:"
[node name="ImageDefaultWidth" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions"]
margin_left = 114.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 24.0
hint_tooltip = "A default width of a new image"
mouse_default_cursor_shape = 2
@ -554,6 +589,7 @@ size_flags_horizontal = 3
min_value = 1.0
max_value = 16384.0
value = 64.0
rounded = true
align = 2
suffix = "px"
@ -568,13 +604,14 @@ text = "Default height:"
[node name="ImageDefaultHeight" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions"]
margin_left = 114.0
margin_top = 28.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 52.0
hint_tooltip = "A default height of a new image"
mouse_default_cursor_shape = 2
min_value = 1.0
max_value = 16384.0
value = 64.0
rounded = true
align = 2
suffix = "px"
@ -589,7 +626,7 @@ text = "Default fill color:"
[node name="DefaultFillColor" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions"]
margin_left = 114.0
margin_top = 56.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 76.0
rect_min_size = Vector2( 64, 20 )
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 )
[node name="Shortcuts" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_top = 1052.0
margin_right = 494.0
margin_bottom = 1286.0
visible = false
margin_top = 184.0
margin_right = 506.0
margin_bottom = 418.0
script = ExtResource( 6 )
[node name="HBoxContainer" type="HBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts"]
margin_right = 494.0
margin_right = 506.0
margin_bottom = 20.0
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"]
margin_left = 49.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 20.0
hint_tooltip = "Only custom preset can be modified"
mouse_default_cursor_shape = 2
@ -625,12 +664,12 @@ selected = 0
[node name="HSeparator" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts"]
margin_top = 24.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 28.0
[node name="Shortcuts" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts"]
margin_top = 32.0
margin_right = 494.0
margin_right = 506.0
margin_bottom = 234.0
custom_constants/vseparation = 2
custom_constants/hseparation = 5
@ -642,7 +681,7 @@ margin_bottom = 14.0
[node name="LeftToolLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0
margin_right = 315.0
margin_right = 321.0
margin_bottom = 14.0
hint_tooltip = "A tool assigned to the left mouse button"
mouse_filter = 0
@ -650,8 +689,8 @@ text = "Left Tool:"
align = 1
[node name="RightToolLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 320.0
margin_right = 493.0
margin_left = 326.0
margin_right = 505.0
margin_bottom = 14.0
hint_tooltip = "A tool assigned to the right mouse button"
mouse_filter = 0
@ -665,20 +704,21 @@ margin_bottom = 20.0
[node name="HSeparator" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
visible = false
margin_top = 18.0
margin_right = 137.0
margin_bottom = 22.0
margin_left = 184.0
margin_top = 16.0
margin_right = 321.0
margin_bottom = 20.0
[node name="HSeparator2" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0
margin_top = 16.0
margin_right = 315.0
margin_right = 321.0
margin_bottom = 20.0
[node name="HSeparator3" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 320.0
margin_left = 326.0
margin_top = 16.0
margin_right = 493.0
margin_right = 505.0
margin_bottom = 20.0
[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"]
margin_left = 142.0
margin_top = 22.0
margin_right = 315.0
margin_right = 321.0
margin_bottom = 42.0
size_flags_horizontal = 3
[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_right = 493.0
margin_right = 505.0
margin_bottom = 42.0
size_flags_horizontal = 3
@ -710,14 +750,14 @@ text = "Zoom"
[node name="left_zoom_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0
margin_top = 44.0
margin_right = 315.0
margin_right = 321.0
margin_bottom = 64.0
size_flags_horizontal = 3
[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_right = 493.0
margin_right = 505.0
margin_bottom = 64.0
size_flags_horizontal = 3
@ -730,13 +770,13 @@ text = "Color Picker"
[node name="left_colorpicker_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0
margin_top = 66.0
margin_right = 315.0
margin_right = 321.0
margin_bottom = 86.0
[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_right = 493.0
margin_right = 505.0
margin_bottom = 86.0
[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"]
margin_left = 142.0
margin_top = 88.0
margin_right = 315.0
margin_right = 321.0
margin_bottom = 108.0
[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_right = 493.0
margin_right = 505.0
margin_bottom = 108.0
[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"]
margin_left = 142.0
margin_top = 110.0
margin_right = 315.0
margin_right = 321.0
margin_bottom = 130.0
[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_right = 493.0
margin_right = 505.0
margin_bottom = 130.0
[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"]
margin_left = 142.0
margin_top = 132.0
margin_right = 315.0
margin_right = 321.0
margin_bottom = 152.0
[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_right = 493.0
margin_right = 505.0
margin_bottom = 152.0
[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"]
margin_left = 142.0
margin_top = 154.0
margin_right = 315.0
margin_right = 321.0
margin_bottom = 174.0
[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_right = 493.0
margin_right = 505.0
margin_bottom = 174.0
[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"]
margin_left = 142.0
margin_top = 176.0
margin_right = 315.0
margin_right = 321.0
margin_bottom = 180.0
[node name="HSeparator6" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 320.0
margin_left = 326.0
margin_top = 176.0
margin_right = 493.0
margin_right = 505.0
margin_bottom = 180.0
[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"]
margin_left = 142.0
margin_top = 182.0
margin_right = 315.0
margin_right = 321.0
margin_bottom = 202.0
[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="popup_hide" from="." to="." method="_on_PreferencesDialog_popup_hide"]
[connection signal="item_selected" from="HSplitContainer/Tree" to="." method="_on_Tree_item_selected"]
[connection signal="pressed" from="HSplitContainer/ScrollContainer/VBoxContainer/General/SmoothZoom" to="." method="_on_SmoothZoom_pressed"]
[connection signal="toggled" from="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer/LeftIndicatorCheckbox" to="." method="_on_LeftIndicatorCheckbox_toggled"]
[connection signal="toggled" from="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer/RightIndicatorCheckbox" to="." method="_on_RightIndicatorCheckbox_toggled"]
[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"]
[connection signal="item_selected" from="HSplitContainer/List" to="." method="_on_List_item_selected"]
[connection signal="item_selected" from="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/HBoxContainer/PresetOptionButton" to="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts" method="_on_PresetOptionButton_item_selected"]
[connection signal="confirmed" from="Popups/ShortcutSelector" to="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts" method="_on_ShortcutSelector_confirmed"]
[connection signal="popup_hide" from="Popups/ShortcutSelector" to="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts" method="_on_ShortcutSelector_popup_hide"]

View file

@ -20,24 +20,24 @@ func _ready() -> void:
func _process(_delta : float) -> void:
if Global.layers[Global.current_layer][2]:
if Global.layers[Global.current_layer].locked:
return
var mouse_pos: Vector2 = get_local_mouse_position() - Global.canvas.location
var mouse_pos_floored := mouse_pos.floor()
var start_pos := polygon[0]
var end_pos := polygon[2]
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:
visible = false
else:
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
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
is_dragging = true
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
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
start_pos.x = orig_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[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
is_dragging = false
if move_pixels:

View file

@ -12,76 +12,52 @@ func _on_BrushButton_pressed() -> void:
_on_DeleteButton_pressed()
return
# Change left brush
if Global.brush_type_window_position == "left":
Global.current_left_brush_type = brush_type
Global.custom_left_brush_index = custom_brush_index
if custom_brush_index > -1: # Custom brush
if Global.current_left_tool == "Pencil":
Global.left_color_interpolation_container.visible = true
# Change brush
Global.current_brush_types[Global.brush_type_window_position] = brush_type
Global.custom_brush_indexes[Global.brush_type_window_position] = custom_brush_index
if custom_brush_index > -1: # Custom brush
if Global.current_tools[Global.brush_type_window_position] == Global.Tools.PENCIL:
Global.color_interpolation_containers[Global.brush_type_window_position].visible = true
# if hint_tooltip == "":
# Global.left_brush_type_label.text = tr("Custom brush")
# else:
# Global.left_brush_type_label.text = tr("Brush:") + " %s" % hint_tooltip
elif custom_brush_index == -3: # Pixel brush
Global.left_color_interpolation_container.visible = false
elif custom_brush_index == -3: # Pixel brush
Global.color_interpolation_containers[Global.brush_type_window_position].visible = false
# Global.left_brush_type_label.text = tr("Brush: Pixel")
elif custom_brush_index == -2: # Circle brush
Global.left_color_interpolation_container.visible = false
elif custom_brush_index == -2: # Circle brush
Global.color_interpolation_containers[Global.brush_type_window_position].visible = false
# Global.left_brush_type_label.text = tr("Brush: Circle")
elif custom_brush_index == -1: # Filled Circle brush
Global.left_color_interpolation_container.visible = false
elif custom_brush_index == -1: # Filled Circle brush
Global.color_interpolation_containers[Global.brush_type_window_position].visible = false
# Global.left_brush_type_label.text = tr("Brush: Filled Circle")
Global.update_left_custom_brush()
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()
Global.update_custom_brush(Global.brush_type_window_position)
Global.brushes_popup.hide()
func _on_DeleteButton_pressed() -> void:
if brush_type == Global.Brush_Types.CUSTOM:
if Global.custom_left_brush_index == custom_brush_index:
Global.custom_left_brush_index = -3
Global.current_left_brush_type = Global.Brush_Types.PIXEL
if Global.custom_brush_indexes[0] == custom_brush_index:
Global.custom_brush_indexes[0] = -3
Global.current_brush_types[0] = Global.Brush_Types.PIXEL
# Global.left_brush_type_label.text = "Brush: Pixel"
Global.update_left_custom_brush()
if Global.custom_right_brush_index == custom_brush_index:
Global.custom_right_brush_index = -3
Global.current_right_brush_type = Global.Brush_Types.PIXEL
Global.update_custom_brush(0)
if Global.custom_brush_indexes[1] == custom_brush_index:
Global.custom_brush_indexes[1] = -3
Global.current_brush_types[1] = Global.Brush_Types.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
Global.undos += 1
Global.undo_redo.create_action("Delete Custom Brush")
for i in range(project_brush_index, Global.project_brush_container.get_child_count()):
var bb = Global.project_brush_container.get_child(i)
if Global.custom_left_brush_index == bb.custom_brush_index:
Global.custom_left_brush_index -= 1
if Global.custom_right_brush_index == bb.custom_brush_index:
Global.custom_right_brush_index -= 1
if Global.custom_brush_indexes[0] == bb.custom_brush_index:
Global.custom_brush_indexes[0] -= 1
if Global.custom_brush_indexes[1] == bb.custom_brush_index:
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_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]
[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"]
margin_right = 226.0
margin_bottom = 144.0
@ -34,21 +64,27 @@ hint_tooltip = "Pixel brush"
mouse_default_cursor_shape = 2
[node name="CircleBrushButton" parent="TabContainer/File/FileBrushContainer" instance=ExtResource( 2 )]
margin_left = 35.0
margin_right = 67.0
margin_left = 36.0
margin_right = 68.0
hint_tooltip = "Filled circle brush"
mouse_default_cursor_shape = 2
brush_type = 1
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 )]
margin_left = 70.0
margin_right = 102.0
margin_left = 72.0
margin_right = 104.0
hint_tooltip = "Circle brush"
mouse_default_cursor_shape = 2
brush_type = 2
custom_brush_index = -1
[node name="BrushTexture" parent="TabContainer/File/FileBrushContainer/FilledCircleBrushButton" index="0"]
texture = SubResource( 4 )
[node name="Project" type="ScrollContainer" parent="TabContainer"]
visible = false
anchor_right = 1.0
@ -63,3 +99,7 @@ scroll_horizontal_enabled = false
[node name="ProjectBrushContainer" type="GridContainer" parent="TabContainer/Project"]
columns = 5
[editable path="TabContainer/File/FileBrushContainer/CircleBrushButton"]
[editable path="TabContainer/File/FileBrushContainer/FilledCircleBrushButton"]

View file

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

View file

@ -75,9 +75,7 @@ func _on_CreateNewImage_confirmed() -> void:
var fill_color : Color = fill_color_node.color
Global.clear_canvases()
Global.layers.clear()
# 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)]
Global.layers.append([tr("Layer") + " 0", true, false, HBoxContainer.new(), false, []])
Global.layers.append(Layer.new())
Global.canvas = load("res://src/Canvas.tscn").instance()
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.project_has_changed = false
if fill_color.a > 0:
Global.canvas.layers[0][0].fill(fill_color)
Global.canvas.layers[0][0].lock()
Global.canvas.layers[0].image.fill(fill_color)
Global.canvas.layers[0].image.lock()
Global.canvas.update_texture(0)

View file

@ -147,8 +147,8 @@ func process_spritesheet() -> void:
# Range of frames determined by tags
var frames := []
if frame_current_tag > 0:
var frame_start = Global.animation_tags[frame_current_tag - 1][2]
var frame_end = Global.animation_tags[frame_current_tag - 1][3]
var frame_start = Global.animation_tags[frame_current_tag - 1].from
var frame_end = Global.animation_tags[frame_current_tag - 1].to
frames = Global.canvases.slice(frame_start-1, frame_end-1, 1, true)
else:
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:
# Check if processed image is in frame tag and assign frame tag and start id if yes
# Then stop
if (processed_image_id + 1) >= animation_tag[2] and (processed_image_id + 1) <= animation_tag[3]:
result_animation_tag_and_start_id = [animation_tag[0], animation_tag[2]]
if (processed_image_id + 1) >= animation_tag.from and (processed_image_id + 1) <= animation_tag.to:
result_animation_tag_and_start_id = [animation_tag.name, animation_tag.from]
break
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()
var layer_i := 0
for layer in canvas.layers:
if Global.layers[layer_i][1]:
if Global.layers[layer_i].visible:
var layer_image := Image.new()
layer_image.copy_from(layer[0])
layer_image.copy_from(layer.image)
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 yy in layer_image.get_size().y:
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))
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
image.unlock()
@ -454,7 +454,7 @@ func create_frame_tag_list() -> void:
# Repopulate list with current tag list
for item in Global.animation_tags:
frame_container.add_item(item[0])
frame_container.add_item(item.name)
func store_export_settings() -> void:

View file

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

View file

@ -41,7 +41,7 @@ func _on_ImportSprites_files_selected(paths : PoolStringArray) -> void:
Global.layers.clear()
# 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)]
Global.layers.append([tr("Layer") + " 0", true, false, HBoxContainer.new(), false, []])
Global.layers.append(Layer.new())
Global.current_layer = 0
var first_path : String = paths[0]
@ -64,22 +64,14 @@ func _on_ImportSprites_files_selected(paths : PoolStringArray) -> void:
canvas.size = image.get_size()
image.convert(Image.FORMAT_RGBA8)
image.lock()
var tex := ImageTexture.new()
tex.create_from_image(image, 0)
# Store [Image, ImageTexture, Opacity]
canvas.layers.append([image, tex, 1])
canvas.layers.append(Cel.new(image, 1))
for _i in range(1, Global.layers.size()):
var empty_sprite := Image.new()
empty_sprite.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8)
empty_sprite.fill(Color(0, 0, 0, 0))
empty_sprite.lock()
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.layers.append(Cel.new(empty_sprite, 1))
canvas.frame = i
Global.canvases.append(canvas)
@ -119,21 +111,14 @@ func _on_ImportSprites_files_selected(paths : PoolStringArray) -> void:
canvas.size = cropped_image.get_size()
cropped_image.convert(Image.FORMAT_RGBA8)
cropped_image.lock()
var tex := ImageTexture.new()
tex.create_from_image(cropped_image, 0)
# Store [Image, ImageTexture, Opacity]
canvas.layers.append([cropped_image, tex, 1])
canvas.layers.append(Cel.new(cropped_image, 1))
for _i in range(1, Global.layers.size()):
var empty_sprite := Image.new()
empty_sprite.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8)
empty_sprite.fill(Color(0, 0, 0, 0))
empty_sprite.lock()
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.layers.append(Cel.new(empty_sprite, 1))
canvas.frame = i
Global.canvases.append(canvas)

View file

@ -10,7 +10,7 @@ func _on_OutlineDialog_confirmed() -> void:
var diagonal : bool = $OptionsContainer/DiagonalCheckBox.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():
return
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")
match $VBoxContainer/HBoxContainer2/OptionButton.text:
"Rotxel":
Global.rotxel(layer,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
DrawingAlgos.rotxel(layer,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
"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":
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")
$VBoxContainer/HBoxContainer/HSlider.value = 0
@ -45,11 +45,11 @@ func rotate() -> void:
sprite.copy_from(aux_img)
match $VBoxContainer/HBoxContainer2/OptionButton.text:
"Rotxel":
Global.rotxel(sprite,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
DrawingAlgos.rotxel(sprite,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
"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":
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)

View file

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

View file

@ -14,16 +14,9 @@ func _ready() -> void:
func _on_PatternButton_pressed() -> void:
if Global.pattern_window_position == "left":
Global.pattern_left_image = image
Global.left_fill_pattern_container.get_child(0).get_child(0).texture = texture
Global.left_fill_pattern_container.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
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.pattern_images[Global.pattern_window_position] = image
Global.fill_pattern_containers[Global.pattern_window_position].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.fill_pattern_containers[Global.pattern_window_position].get_child(3).get_child(1).max_value = image_size.y - 1
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_forward := true
var first_frame := 0
var last_frame := Global.canvases.size() - 1
var last_frame : int = Global.canvases.size() - 1
var timeline_scroll : ScrollContainer
var tag_scroll_container : ScrollContainer
@ -28,7 +28,7 @@ func add_frame() -> void:
new_canvas.size = Global.canvas.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)
Global.undos += 1
@ -45,8 +45,8 @@ func add_frame() -> void:
Global.undo_redo.add_undo_property(c, "visible", c.visible)
for l_i in range(Global.layers.size()):
if Global.layers[l_i][4]: # If the link button is pressed
Global.layers[l_i][5].append(new_canvas)
if Global.layers[l_i].new_cels_linked: # If the link button is pressed
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, "canvas", Global.canvas)
@ -61,32 +61,43 @@ func _on_DeleteFrame_pressed(frame := -1) -> void:
frame = Global.current_frame
var canvas : Canvas = Global.canvases[frame]
var new_canvases := Global.canvases.duplicate()
var new_canvases : Array = Global.canvases.duplicate()
new_canvases.erase(canvas)
var current_frame := Global.current_frame
if current_frame > 0 && current_frame == new_canvases.size(): # If it's the last frame
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
for tag in new_animation_tags:
if frame + 1 >= tag[2] && frame + 1 <= tag[3]:
if tag[3] == tag[2]: # If we're deleting the only frame in the tag
if frame + 1 >= tag.from && frame + 1 <= tag.to:
if tag.from == tag.to: # If we're deleting the only frame in the tag
new_animation_tags.erase(tag)
else:
tag[3] -= 1
elif frame + 1 < tag[2]:
tag[2] -= 1
tag[3] -= 1
tag.to -= 1
elif frame + 1 < tag.from:
tag.from -= 1
tag.to -= 1
# Check if one of the cels of the frame is linked
# if they are, unlink them too
# 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 linked in layer[5]:
for linked in layer.linked_cels:
if linked == Global.canvases[frame]:
layer[5].erase(linked)
layer.linked_cels.erase(linked)
Global.undos += 1
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
var sprite := Image.new()
sprite.copy_from(layer[0])
sprite.copy_from(layer.image)
sprite.lock()
var tex := ImageTexture.new()
tex.create_from_image(sprite, 0)
new_canvas.layers.append([sprite, tex, layer[2]])
new_canvas.layers.append(Cel.new(sprite, layer.opacity))
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
for tag in new_animation_tags:
if frame + 1 >= tag[2] && frame + 1 <= tag[3]:
tag[3] += 1
if frame + 1 >= tag.from && frame + 1 <= tag.to:
tag.to += 1
Global.undos += 1
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, "animation_tags", new_animation_tags)
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_undo_property(child, "pressed", child.pressed)
for c in Global.canvases:
@ -265,9 +279,9 @@ func play_animation(play : bool, forward_dir : bool) -> void:
last_frame = Global.canvases.size() - 1
if Global.play_only_tags:
for tag in Global.animation_tags:
if Global.current_frame + 1 >= tag[2] && Global.current_frame + 1 <= tag[3]:
first_frame = tag[2] - 1
last_frame = min(Global.canvases.size() - 1, tag[3] - 1)
if Global.current_frame + 1 >= tag.from && Global.current_frame + 1 <= tag.to:
first_frame = tag.from - 1
last_frame = min(Global.canvases.size() - 1, tag.to - 1)
if first_frame == last_frame:
if forward_dir:
@ -336,15 +350,11 @@ func _on_BlueRedMode_toggled(button_pressed : bool) -> void:
# Layer buttons
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()
# 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)]
new_layers.append([layer_name, true, false, HBoxContainer.new(), false, []])
var l := Layer.new()
if !is_new: # Clone layer
l.name = Global.layers[Global.current_layer].name + " (" + tr("copy") + ")"
new_layers.append(l)
Global.undos += 1
Global.undo_redo.create_action("Add Layer")
@ -354,15 +364,12 @@ func add_layer(is_new := true) -> void:
if is_new:
new_layer.create(c.size.x, c.size.y, false, Image.FORMAT_RGBA8)
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()
var new_layer_tex := ImageTexture.new()
new_layer_tex.create_from_image(new_layer, 0)
var new_canvas_layers : Array = c.layers.duplicate()
# Store [Image, ImageTexture, Opacity]
new_canvas_layers.append([new_layer, new_layer_tex, 1])
new_canvas_layers.append(Cel.new(new_layer, 1))
Global.undo_redo.add_do_property(c, "layers", new_canvas_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
Global.undo_redo.create_action("Change Layer Order")
for c in Global.canvases:
var new_layers_canvas : Array = c.layers.duplicate()
var temp_canvas = new_layers_canvas[Global.current_layer]
new_layers_canvas[Global.current_layer] = new_layers_canvas[change]
new_layers_canvas[change] = temp_canvas
Global.undo_redo.add_do_property(c, "layers", new_layers_canvas)
var new_canvas_layers : Array = c.layers.duplicate()
var temp_canvas = new_canvas_layers[Global.current_layer]
new_canvas_layers[Global.current_layer] = new_canvas_layers[change]
new_canvas_layers[change] = temp_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_do_property(Global, "current_layer", change)
@ -427,39 +434,43 @@ func change_layer_order(rate : int) -> 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.undo_redo.create_action("Merge Layer")
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()
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()
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 yy in selected_layer.get_size().y:
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))
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()
c.blend_rect(new_layer, selected_layer, Rect2(c.position, c.size), Vector2.ZERO)
new_layers_canvas.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]):
new_layers[Global.current_layer - 1][5].erase(c)
var tex := ImageTexture.new()
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
DrawingAlgos.blend_rect(new_layer, selected_layer, Rect2(c.position, c.size), Vector2.ZERO)
new_canvas_layers.remove(Global.current_layer)
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].linked_cels.erase(c)
new_canvas_layers[Global.current_layer - 1].image = new_layer
else:
Global.undo_redo.add_do_property(c.layers[Global.current_layer - 1][0], "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_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].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)
new_layers.remove(Global.current_layer)
@ -474,7 +485,7 @@ func _on_MergeDownLayer_pressed() -> 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_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/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://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]
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:
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
popup_menu.set_item_text(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
change_frame_order(1)
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 new_layers := Global.layers.duplicate(true)
var new_canvas_layers : Array = c.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)
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":
new_layers[layer][5].remove(cel_index)
new_layers[layer].linked_cels.remove(cel_index)
var sprite := Image.new()
sprite.copy_from(Global.canvases[frame].layers[layer][0])
sprite.copy_from(Global.canvases[frame].layers[layer].image)
sprite.lock()
var tex := ImageTexture.new()
tex.create_from_image(sprite, 0)
new_canvas_layers[layer][0] = sprite
new_canvas_layers[layer][1] = tex
new_canvas_layers[layer].image = sprite
Global.undo_redo.create_action("Unlink Cel")
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.commit_action()
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.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
# to the first linked cel's image
new_canvas_layers[layer][0] = new_layers[layer][5][0].layers[layer][0]
new_canvas_layers[layer][1] = new_layers[layer][5][0].layers[layer][1]
new_canvas_layers[layer].image = new_layers[layer].linked_cels[0].layers[layer].image
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_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:
var change = frame + rate
var new_canvases := Global.canvases.duplicate()
var new_canvases : Array = Global.canvases.duplicate()
var temp = new_canvases[frame]
new_canvases[frame] = new_canvases[change]
new_canvases[change] = temp

View file

@ -25,10 +25,10 @@ func _on_FrameTagDialog_about_to_show() -> void:
var vbox_cont := VBoxContainer.new()
var hbox_cont := HBoxContainer.new()
var tag_label := Label.new()
if tag[2] == tag[3]:
tag_label.text = "Tag %s (Frame %s)" % [i + 1, tag[2]]
if tag.from == tag.to:
tag_label.text = "Tag %s (Frame %s)" % [i + 1, tag.from]
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)
var edit_button := Button.new()
@ -39,8 +39,8 @@ func _on_FrameTagDialog_about_to_show() -> void:
vbox_cont.add_child(hbox_cont)
var name_label := Label.new()
name_label.text = tag[0]
name_label.modulate = tag[1]
name_label.text = tag.name
name_label.modulate = tag.color
vbox_cont.add_child(name_label)
var hsep := HSeparator.new()
@ -70,10 +70,10 @@ func _on_AddTag_pressed() -> void:
func _on_EditButton_pressed(_tag_id : int) -> void:
options_dialog.popup_centered()
current_tag_id = _tag_id
options_dialog.get_node("GridContainer/NameLineEdit").text = Global.animation_tags[_tag_id][0]
options_dialog.get_node("GridContainer/ColorPickerButton").color = Global.animation_tags[_tag_id][1]
options_dialog.get_node("GridContainer/FromSpinBox").value = Global.animation_tags[_tag_id][2]
options_dialog.get_node("GridContainer/ToSpinBox").value = Global.animation_tags[_tag_id][3]
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].color
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].to
if !delete_tag_button:
delete_tag_button = options_dialog.add_button("Delete Tag", true, "delete_tag")
else:
@ -92,14 +92,19 @@ func _on_TagOptions_confirmed() -> void:
if 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():
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:
new_animation_tags[current_tag_id][0] = tag_name
new_animation_tags[current_tag_id][1] = tag_color
new_animation_tags[current_tag_id][2] = tag_from
new_animation_tags[current_tag_id][3] = tag_to
new_animation_tags[current_tag_id].name = tag_name
new_animation_tags[current_tag_id].color = tag_color
new_animation_tags[current_tag_id].from = tag_from
new_animation_tags[current_tag_id].to = tag_to
# Handle Undo/Redo
Global.undos += 1
@ -114,7 +119,7 @@ func _on_TagOptions_confirmed() -> void:
func _on_TagOptions_custom_action(action : String) -> void:
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)
# Handle Undo/Redo
Global.undos += 1

View file

@ -1,6 +1,6 @@
[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]
[node name="FrameTagDialog" type="AcceptDialog"]

View file

@ -16,7 +16,7 @@ func _ready() -> void:
label = Global.find_node_by_name(self, "Label")
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")
visibility_button.get_child(0).rect_size = Vector2(24, 14)
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_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")
else:
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")
else:
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
label.text = new_name
Global.layers_changed_skip = true
Global.layers[i][0] = new_name
Global.layers[i].name = new_name
func _on_VisibilityButton_pressed() -> void:
Global.layers[i][1] = !Global.layers[i][1]
Global.layers[i].visible = !Global.layers[i].visible
Global.canvas.update()
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:
Global.layers[i][4] = !Global.layers[i][4]
if Global.layers[i][4] && !Global.layers[i][5]:
Global.layers[i][5].append(Global.canvas)
Global.layers[i][3].get_child(Global.current_frame)._ready()
Global.layers[i].new_cels_linked = !Global.layers[i].new_cels_linked
if Global.layers[i].new_cels_linked && !Global.layers[i].linked_cels:
Global.layers[i].linked_cels.append(Global.canvas)
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:
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):
Global.current_left_tool = current_action
# 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
left_tool_name = current_action.to_lower()
current_mouse_button = Global.Mouse_Button.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
# Start from 1, so the label won't get invisible
for i in range(1, Global.right_tool_options_container.get_child_count()):
Global.right_tool_options_container.get_child(i).visible = false
right_tool_name = current_action.to_lower()
current_mouse_button = Global.Mouse_Button.RIGHT
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
if current_action == "Pencil":
Global.right_brush_type_container.visible = true
Global.right_brush_size_slider.visible = true
Global.right_pixel_perfect_container.visible = true
Global.right_mirror_container.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:
Global.right_color_interpolation_container.visible = true
elif current_action == "Eraser":
Global.right_brush_type_container.visible = true
Global.right_brush_size_slider.visible = true
Global.right_pixel_perfect_container.visible = true
Global.right_mirror_container.visible = true
elif current_action == "Bucket":
Global.right_fill_area_container.visible = true
Global.right_mirror_container.visible = true
elif current_action == "LightenDarken":
Global.right_brush_type_container.visible = true
Global.right_brush_size_slider.visible = true
Global.right_pixel_perfect_container.visible = true
Global.right_ld_container.visible = true
Global.right_mirror_container.visible = true
elif current_action == "ColorPicker":
Global.right_colorpicker_container.visible = true
elif current_action == "Zoom":
Global.right_zoom_container.visible = true
if current_tool == Global.Tools.PENCIL:
Global.brush_type_containers[current_mouse_button].visible = true
Global.brush_size_sliders[current_mouse_button].visible = true
Global.pixel_perfect_containers[current_mouse_button].visible = true
Global.mirror_containers[current_mouse_button].visible = true
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.color_interpolation_containers[current_mouse_button].visible = true
elif current_tool == Global.Tools.ERASER:
Global.brush_type_containers[current_mouse_button].visible = true
Global.brush_size_sliders[current_mouse_button].visible = true
Global.pixel_perfect_containers[current_mouse_button].visible = true
Global.mirror_containers[current_mouse_button].visible = true
elif current_tool == Global.Tools.BUCKET:
Global.fill_area_containers[current_mouse_button].visible = true
Global.mirror_containers[current_mouse_button].visible = true
elif current_tool == Global.Tools.LIGHTENDARKEN:
Global.brush_type_containers[current_mouse_button].visible = true
Global.brush_size_sliders[current_mouse_button].visible = true
Global.pixel_perfect_containers[current_mouse_button].visible = true
Global.ld_containers[current_mouse_button].visible = true
Global.mirror_containers[current_mouse_button].visible = true
elif current_tool == Global.Tools.COLORPICKER:
Global.colorpicker_containers[current_mouse_button].visible = true
elif current_tool == Global.Tools.ZOOM:
Global.zoom_containers[current_mouse_button].visible = true
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)
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())
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())
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())
else:
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.right_cursor_tool_texture.create_from_image(load("res://assets/graphics/cursor_icons/%s_cursor.png" % Global.current_right_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" % right_tool_name), 0)

View file

@ -7,6 +7,9 @@ margin_right = 1280.0
margin_bottom = 28.0
rect_min_size = Vector2( 0, 28 )
custom_styles/panel = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="MenuItems" type="HBoxContainer" parent="."]
margin_left = 2.0
@ -17,40 +20,40 @@ __meta__ = {
}
[node name="FileMenu" type="MenuButton" parent="MenuItems"]
margin_right = 29.0
margin_bottom = 21.0
margin_right = 35.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
text = "File"
switch_on_hover = true
[node name="EditMenu" type="MenuButton" parent="MenuItems"]
margin_left = 33.0
margin_right = 64.0
margin_bottom = 21.0
margin_left = 39.0
margin_right = 75.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
text = "Edit"
switch_on_hover = true
[node name="ViewMenu" type="MenuButton" parent="MenuItems"]
margin_left = 68.0
margin_right = 104.0
margin_bottom = 21.0
margin_left = 79.0
margin_right = 121.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
text = "View"
switch_on_hover = true
[node name="ImageMenu" type="MenuButton" parent="MenuItems"]
margin_left = 108.0
margin_right = 152.0
margin_bottom = 21.0
margin_left = 125.0
margin_right = 177.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
text = "Image"
switch_on_hover = true
[node name="HelpMenu" type="MenuButton" parent="MenuItems"]
margin_left = 156.0
margin_right = 191.0
margin_bottom = 21.0
margin_left = 181.0
margin_right = 223.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
text = "Help"
switch_on_hover = true
@ -67,7 +70,7 @@ __meta__ = {
}
[node name="ZoomLevel" type="Label" parent="TopLabels"]
margin_top = 6.0
margin_top = 7.0
margin_right = 60.0
margin_bottom = 21.0
rect_min_size = Vector2( 60, 0 )
@ -76,8 +79,8 @@ align = 2
[node name="CursorPosition" type="Label" parent="TopLabels"]
margin_left = 80.0
margin_top = 6.0
margin_right = 120.0
margin_top = 7.0
margin_right = 128.0
margin_bottom = 21.0
text = "[64×64]"
align = 2
@ -98,12 +101,20 @@ __meta__ = {
}
[node name="CurrentFrame" type="Label" parent="HBoxContainer"]
margin_left = 113.0
margin_top = 6.0
margin_right = 216.0
margin_bottom = 21.0
text = "Current Frame: 1/1"
margin_left = 106.0
margin_right = 198.0
margin_bottom = 28.0
size_flags_vertical = 1
text = "Current frame:"
valign = 1
__meta__ = {
"_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
}
[node name="Tools" type="VBoxContainer" parent="ToolPanel/PanelContainer"]
[node name="ToolButtons" type="VBoxContainer" parent="ToolPanel/PanelContainer"]
margin_left = 7.0
margin_top = 7.0
margin_right = 39.0
@ -69,7 +69,7 @@ __meta__ = {
"_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",
]]
margin_right = 32.0
@ -78,7 +78,7 @@ rect_min_size = Vector2( 32, 32 )
mouse_default_cursor_shape = 2
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_bottom = 32.0
texture = ExtResource( 12 )
@ -86,7 +86,7 @@ __meta__ = {
"_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",
]]
margin_top = 36.0
@ -96,7 +96,7 @@ rect_min_size = Vector2( 32, 32 )
mouse_default_cursor_shape = 2
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_bottom = 32.0
texture = ExtResource( 21 )
@ -104,7 +104,7 @@ __meta__ = {
"_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",
]]
margin_top = 72.0
@ -114,7 +114,7 @@ rect_min_size = Vector2( 32, 32 )
mouse_default_cursor_shape = 2
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_bottom = 32.0
texture = ExtResource( 11 )
@ -122,7 +122,7 @@ __meta__ = {
"_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",
]]
margin_top = 108.0
@ -132,7 +132,7 @@ rect_min_size = Vector2( 32, 32 )
mouse_default_cursor_shape = 2
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_bottom = 32.0
texture = ExtResource( 14 )
@ -140,7 +140,7 @@ __meta__ = {
"_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",
]]
margin_top = 144.0
@ -150,7 +150,7 @@ rect_min_size = Vector2( 32, 32 )
mouse_default_cursor_shape = 2
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_bottom = 32.0
texture = ExtResource( 13 )
@ -158,7 +158,7 @@ __meta__ = {
"_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",
]]
margin_top = 180.0
@ -168,7 +168,7 @@ rect_min_size = Vector2( 32, 32 )
mouse_default_cursor_shape = 2
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_bottom = 32.0
texture = ExtResource( 10 )
@ -176,7 +176,7 @@ __meta__ = {
"_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",
]]
margin_top = 216.0
@ -186,7 +186,7 @@ rect_min_size = Vector2( 32, 32 )
mouse_default_cursor_shape = 2
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_bottom = 32.0
texture = ExtResource( 15 )