1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-02-27 16:03:14 +00:00

Organize image and layer effects into subcategories

The amount of image/layer effects keeps getting bigger and bigger, especially now that users can load their own effects.

At some point, it might also be a good idea to refactor the code so that image and layer effect code combines. Image effects could use ShaderLoader.gd to generate their UI, like layer effects do.
This commit is contained in:
Emmanouil Papadeas 2025-01-31 00:14:54 +02:00
parent 3e01247d95
commit 96d0efe3ba
5 changed files with 178 additions and 115 deletions
Translations
src
Autoload
Classes
UI
Timeline/LayerEffects
TopMenuContainer

View file

@ -277,6 +277,18 @@ msgstr ""
msgid "Preferences"
msgstr ""
#. A submenu of the Effects menu. Contains effects that generate new pixels, such as outline, drop shadow and gradient.
msgid "Procedural"
msgstr ""
#. Refers to effects that blur the image.
msgid "Blur"
msgstr ""
#. A submenu of the Effects menu. Contains effects that have been loaded by the user.
msgid "Loader"
msgstr ""
#. An option in the View menu. When selected, the canvas is being placed on the center of the screen.
msgid "Center Canvas"
msgstr ""

View file

@ -65,26 +65,6 @@ enum ImageMenu {
CROP_TO_SELECTION,
CROP_TO_CONTENT,
}
## Enumeration of items present in the Effects menu.
enum EffectsMenu {
OFFSET_IMAGE,
FLIP,
ROTATE,
OUTLINE,
DROP_SHADOW,
INVERT_COLORS,
DESATURATION,
HSV,
BRIGHTNESS_SATURATION,
COLOR_CURVES,
PALETTIZE,
PIXELIZE,
POSTERIZE,
GAUSSIAN_BLUR,
GRADIENT,
GRADIENT_MAP,
LOADED_EFFECTS
}
## Enumeration of items present in the Select Menu.
enum SelectMenu { SELECT_ALL, CLEAR_SELECTION, INVERT, WRAP_STROKES, MODIFY }
## Enumeration of items present in the Help Menu.

View file

@ -3,18 +3,20 @@ extends RefCounted
var name := ""
var shader: Shader
var category := ""
var params := {}
var enabled := true
func _init(_name := "", _shader: Shader = null, _params := {}) -> void:
func _init(_name := "", _shader: Shader = null, _category := "", _params := {}) -> void:
name = _name
shader = _shader
category = _category
params = _params
func duplicate() -> LayerEffect:
return LayerEffect.new(name, shader, params.duplicate())
return LayerEffect.new(name, shader, category, params.duplicate())
func serialize() -> Dictionary:

View file

@ -5,28 +5,47 @@ const DELETE_TEXTURE := preload("res://assets/graphics/misc/close.svg")
var effects: Array[LayerEffect] = [
LayerEffect.new(
"Convolution Matrix", preload("res://src/Shaders/Effects/ConvolutionMatrix.gdshader")
"Convolution Matrix",
preload("res://src/Shaders/Effects/ConvolutionMatrix.gdshader"),
"Color"
),
LayerEffect.new("Gaussian Blur", preload("res://src/Shaders/Effects/GaussianBlur.gdshader")),
LayerEffect.new("Offset", preload("res://src/Shaders/Effects/OffsetPixels.gdshader")),
LayerEffect.new("Outline", preload("res://src/Shaders/Effects/OutlineInline.gdshader")),
LayerEffect.new("Drop Shadow", preload("res://src/Shaders/Effects/DropShadow.gdshader")),
LayerEffect.new("Invert Colors", preload("res://src/Shaders/Effects/Invert.gdshader")),
LayerEffect.new("Desaturation", preload("res://src/Shaders/Effects/Desaturate.gdshader")),
LayerEffect.new(
"Adjust Hue/Saturation/Value", preload("res://src/Shaders/Effects/HSV.gdshader")
"Gaussian Blur", preload("res://src/Shaders/Effects/GaussianBlur.gdshader"), "Blur"
),
LayerEffect.new(
"Offset", preload("res://src/Shaders/Effects/OffsetPixels.gdshader"), "Transform"
),
LayerEffect.new(
"Outline", preload("res://src/Shaders/Effects/OutlineInline.gdshader"), "Procedural"
),
LayerEffect.new(
"Drop Shadow", preload("res://src/Shaders/Effects/DropShadow.gdshader"), "Procedural"
),
LayerEffect.new("Invert Colors", preload("res://src/Shaders/Effects/Invert.gdshader"), "Color"),
LayerEffect.new(
"Desaturation", preload("res://src/Shaders/Effects/Desaturate.gdshader"), "Color"
),
LayerEffect.new(
"Adjust Hue/Saturation/Value", preload("res://src/Shaders/Effects/HSV.gdshader"), "Color"
),
LayerEffect.new(
"Adjust Brightness/Contrast",
preload("res://src/Shaders/Effects/BrightnessContrast.gdshader")
preload("res://src/Shaders/Effects/BrightnessContrast.gdshader"),
"Color"
),
LayerEffect.new("Color Curves", preload("res://src/Shaders/Effects/ColorCurves.gdshader")),
LayerEffect.new("Palettize", preload("res://src/Shaders/Effects/Palettize.gdshader")),
LayerEffect.new("Pixelize", preload("res://src/Shaders/Effects/Pixelize.gdshader")),
LayerEffect.new("Posterize", preload("res://src/Shaders/Effects/Posterize.gdshader")),
LayerEffect.new("Gradient Map", preload("res://src/Shaders/Effects/GradientMap.gdshader")),
LayerEffect.new("Index Map", preload("res://src/Shaders/Effects/IndexMap.gdshader")),
LayerEffect.new(
"Color Curves", preload("res://src/Shaders/Effects/ColorCurves.gdshader"), "Color"
),
LayerEffect.new("Palettize", preload("res://src/Shaders/Effects/Palettize.gdshader"), "Color"),
LayerEffect.new("Pixelize", preload("res://src/Shaders/Effects/Pixelize.gdshader"), "Blur"),
LayerEffect.new("Posterize", preload("res://src/Shaders/Effects/Posterize.gdshader"), "Color"),
LayerEffect.new(
"Gradient Map", preload("res://src/Shaders/Effects/GradientMap.gdshader"), "Color"
),
LayerEffect.new("Index Map", preload("res://src/Shaders/Effects/IndexMap.gdshader"), "Color"),
]
## Dictionary of [String] and [PopupMenu], mapping each category to a PopupMenu.
var category_submenus := {}
@onready var enabled_button: CheckButton = $VBoxContainer/HBoxContainer/EnabledButton
@onready var effect_list: MenuButton = $VBoxContainer/HBoxContainer/EffectList
@ -35,14 +54,15 @@ var effects: Array[LayerEffect] = [
func _ready() -> void:
for effect in effects:
effect_list.get_popup().add_item(effect.name)
var effect_list_popup := effect_list.get_popup()
for i in effects.size():
_add_effect_to_list(i)
if not DirAccess.dir_exists_absolute(OpenSave.SHADERS_DIRECTORY):
DirAccess.make_dir_recursive_absolute(OpenSave.SHADERS_DIRECTORY)
for file_name in DirAccess.get_files_at(OpenSave.SHADERS_DIRECTORY):
_load_shader_file(OpenSave.SHADERS_DIRECTORY.path_join(file_name))
OpenSave.shader_copied.connect(_load_shader_file)
effect_list.get_popup().id_pressed.connect(_on_effect_list_id_pressed)
effect_list_popup.index_pressed.connect(_on_effect_list_pressed.bind(effect_list_popup))
func _notification(what: int) -> void:
@ -65,15 +85,38 @@ func _on_visibility_changed() -> void:
child.queue_free()
func _add_effect_to_list(i: int) -> void:
var effect_list_popup := effect_list.get_popup()
var effect := effects[i]
if effect.category.is_empty():
effect_list_popup.add_item(effect.name)
effect_list_popup.set_item_metadata(effect_list_popup.item_count - 1, i)
else:
if category_submenus.has(effect.category):
var submenu := category_submenus[effect.category] as PopupMenu
submenu.add_item(effect.name)
submenu.set_item_metadata(submenu.item_count - 1, i)
else:
var submenu := PopupMenu.new()
effect_list_popup.add_submenu_node_item(effect.category, submenu)
submenu.add_item(effect.name)
submenu.set_item_metadata(submenu.item_count - 1, i)
submenu.index_pressed.connect(_on_effect_list_pressed.bind(submenu))
category_submenus[effect.category] = submenu
func _load_shader_file(file_path: String) -> void:
var file := load(file_path)
if file is Shader:
var effect_name := file_path.get_file().get_basename()
effects.append(LayerEffect.new(effect_name, file))
effect_list.get_popup().add_item(effect_name)
var new_effect := LayerEffect.new(effect_name, file, "Loaded")
effects.append(new_effect)
_add_effect_to_list(effects.size() - 1)
#effect_list.get_popup().add_item(effect_name)
func _on_effect_list_id_pressed(index: int) -> void:
func _on_effect_list_pressed(menu_item_index: int, menu: PopupMenu) -> void:
var index: int = menu.get_item_metadata(menu_item_index)
var layer := Global.current_project.layers[Global.current_project.current_layer]
var effect := effects[index].duplicate()
Global.current_project.undos += 1

View file

@ -14,7 +14,18 @@ const HEART_ICON := preload("res://assets/graphics/misc/heart.svg")
var recent_projects := []
var selected_layout := 0
var zen_mode := false
var loaded_effects_submenu: PopupMenu
var tile_mode_submenu := PopupMenu.new()
var selection_modify_submenu := PopupMenu.new()
var color_mode_submenu := PopupMenu.new()
var snap_to_submenu := PopupMenu.new()
var panels_submenu := PopupMenu.new()
var layouts_submenu := PopupMenu.new()
var recent_projects_submenu := PopupMenu.new()
var effects_transform_submenu := PopupMenu.new()
var effects_color_submenu := PopupMenu.new()
var effects_procedural_submenu := PopupMenu.new()
var effects_blur_submenu := PopupMenu.new()
var effects_loaded_submenu: PopupMenu
# Dialogs
var new_image_dialog := Dialog.new("res://src/UI/Dialogs/CreateNewImage.tscn")
@ -58,13 +69,6 @@ var about_dialog := Dialog.new("res://src/UI/Dialogs/AboutDialog.tscn")
@onready var help_menu := $MarginContainer/HBoxContainer/MenuBar/Help as PopupMenu
@onready var greyscale_vision: ColorRect = main_ui.find_child("GreyscaleVision")
@onready var tile_mode_submenu := PopupMenu.new()
@onready var selection_modify_submenu := PopupMenu.new()
@onready var color_mode_submenu := PopupMenu.new()
@onready var snap_to_submenu := PopupMenu.new()
@onready var panels_submenu := PopupMenu.new()
@onready var layouts_submenu := PopupMenu.new()
@onready var recent_projects_submenu := PopupMenu.new()
@onready var current_frame_mark := %CurrentFrameMark as Label
@ -446,37 +450,45 @@ func _setup_color_mode_submenu(item: String) -> void:
func _setup_effects_menu() -> void:
# Order as in Global.EffectMenu enum
var menu_items := {
"Offset Image": "offset_image",
"Mirror Image": "mirror_image",
"Rotate Image": "rotate_image",
"Outline": "outline",
"Drop Shadow": "drop_shadow",
"Invert Colors": "invert_colors",
"Desaturation": "desaturation",
"Adjust Hue/Saturation/Value": "adjust_hsv",
"Adjust Brightness/Contrast": "adjust_brightness_contrast",
"Color Curves": "color_curves",
"Palettize": "palettize",
"Pixelize": "pixelize",
"Posterize": "posterize",
"Gaussian Blur": "gaussian_blur",
"Gradient": "gradient",
"Gradient Map": "gradient_map",
"Loaded": ""
}
var i := 0
for item in menu_items:
if item == "Loaded":
_setup_loaded_effects_submenu()
else:
_set_menu_shortcut(menu_items[item], effects_menu, i, item)
i += 1
_set_menu_shortcut(&"offset_image", effects_transform_submenu, 0, "Offset Image")
_set_menu_shortcut(&"mirror_image", effects_transform_submenu, 1, "Mirror Image")
_set_menu_shortcut(&"rotate_image", effects_transform_submenu, 2, "Rotate Image")
effects_transform_submenu.id_pressed.connect(_on_effects_transform_submenu_id_pressed)
effects_menu.add_child(effects_transform_submenu)
effects_menu.add_submenu_node_item("Transform", effects_transform_submenu)
_set_menu_shortcut(&"invert_colors", effects_color_submenu, 0, "Invert Colors")
_set_menu_shortcut(&"desaturation", effects_color_submenu, 1, "Desaturation")
_set_menu_shortcut(&"adjust_hsv", effects_color_submenu, 2, "Adjust Hue/Saturation/Value")
_set_menu_shortcut(
&"adjust_brightness_contrast", effects_color_submenu, 3, "Adjust Brightness/Contrast"
)
_set_menu_shortcut(&"color_curves", effects_color_submenu, 4, "Color Curves")
_set_menu_shortcut(&"palettize", effects_color_submenu, 5, "Palettize")
_set_menu_shortcut(&"posterize", effects_color_submenu, 6, "Posterize")
_set_menu_shortcut(&"gradient_map", effects_color_submenu, 7, "Gradient Map")
effects_color_submenu.id_pressed.connect(_on_effects_color_submenu_id_pressed)
effects_menu.add_child(effects_color_submenu)
effects_menu.add_submenu_node_item("Color", effects_color_submenu)
_set_menu_shortcut(&"outline", effects_procedural_submenu, 0, "Outline")
_set_menu_shortcut(&"drop_shadow", effects_procedural_submenu, 1, "Drop Shadow")
_set_menu_shortcut(&"gradient", effects_procedural_submenu, 2, "Gradient")
effects_procedural_submenu.id_pressed.connect(_on_effects_procedural_submenu_id_pressed)
effects_menu.add_child(effects_procedural_submenu)
effects_menu.add_submenu_node_item("Procedural", effects_procedural_submenu)
_set_menu_shortcut(&"pixelize", effects_blur_submenu, 0, "Pixelize")
_set_menu_shortcut(&"gaussian_blur", effects_blur_submenu, 1, "Gaussian Blur")
effects_blur_submenu.id_pressed.connect(_on_effects_blur_submenu_id_pressed)
effects_menu.add_child(effects_blur_submenu)
effects_menu.add_submenu_node_item("Blur", effects_blur_submenu)
_setup_effects_loaded_submenu()
effects_menu.id_pressed.connect(effects_menu_id_pressed)
func _setup_loaded_effects_submenu() -> void:
func _setup_effects_loaded_submenu() -> void:
if not DirAccess.dir_exists_absolute(OpenSave.SHADERS_DIRECTORY):
DirAccess.make_dir_recursive_absolute(OpenSave.SHADERS_DIRECTORY)
var shader_files := DirAccess.get_files_at(OpenSave.SHADERS_DIRECTORY)
@ -491,15 +503,15 @@ func _load_shader_file(file_path: String) -> void:
if file is not Shader:
return
var effect_name := file_path.get_file().get_basename()
if not is_instance_valid(loaded_effects_submenu):
loaded_effects_submenu = PopupMenu.new()
loaded_effects_submenu.set_name("loaded_effects_submenu")
loaded_effects_submenu.id_pressed.connect(_loaded_effects_submenu_id_pressed)
effects_menu.add_child(loaded_effects_submenu)
effects_menu.add_submenu_item("Loaded", loaded_effects_submenu.get_name())
loaded_effects_submenu.add_item(effect_name)
var effect_index := loaded_effects_submenu.item_count - 1
loaded_effects_submenu.set_item_metadata(effect_index, file)
if not is_instance_valid(effects_loaded_submenu):
effects_loaded_submenu = PopupMenu.new()
effects_loaded_submenu.set_name("effects_loaded_submenu")
effects_loaded_submenu.id_pressed.connect(_effects_loaded_submenu_id_pressed)
effects_menu.add_child(effects_loaded_submenu)
effects_menu.add_submenu_node_item("Loaded", effects_loaded_submenu)
effects_loaded_submenu.add_item(effect_name)
var effect_index := effects_loaded_submenu.item_count - 1
effects_loaded_submenu.set_item_metadata(effect_index, file)
loaded_effect_dialogs.append(Dialog.new("res://src/UI/Dialogs/ImageEffects/ShaderEffect.tscn"))
@ -814,14 +826,14 @@ func _snap_to_submenu_id_pressed(id: int) -> void:
snap_to_submenu.set_item_checked(id, Global.snap_to_perspective_guides)
func _loaded_effects_submenu_id_pressed(id: int) -> void:
func _effects_loaded_submenu_id_pressed(id: int) -> void:
var dialog := loaded_effect_dialogs[id]
if is_instance_valid(dialog.node):
dialog.popup()
else:
dialog.instantiate_scene()
var shader := loaded_effects_submenu.get_item_metadata(id) as Shader
dialog.node.change_shader(shader, loaded_effects_submenu.get_item_text(id))
var shader := effects_loaded_submenu.get_item_metadata(id) as Shader
dialog.node.change_shader(shader, effects_loaded_submenu.get_item_text(id))
dialog.popup()
@ -972,41 +984,55 @@ func image_menu_id_pressed(id: int) -> void:
func effects_menu_id_pressed(id: int) -> void:
_handle_metadata(id, effects_menu)
func _on_effects_transform_submenu_id_pressed(id: int) -> void:
match id:
Global.EffectsMenu.OFFSET_IMAGE:
0:
offset_image_dialog.popup()
Global.EffectsMenu.FLIP:
1:
mirror_image_dialog.popup()
Global.EffectsMenu.ROTATE:
2:
rotate_image_dialog.popup()
Global.EffectsMenu.INVERT_COLORS:
func _on_effects_color_submenu_id_pressed(id: int) -> void:
match id:
0:
invert_colors_dialog.popup()
Global.EffectsMenu.DESATURATION:
1:
desaturate_dialog.popup()
Global.EffectsMenu.OUTLINE:
outline_dialog.popup()
Global.EffectsMenu.DROP_SHADOW:
drop_shadow_dialog.popup()
Global.EffectsMenu.HSV:
2:
hsv_dialog.popup()
Global.EffectsMenu.BRIGHTNESS_SATURATION:
3:
adjust_brightness_saturation_dialog.popup()
Global.EffectsMenu.COLOR_CURVES:
4:
color_curves_dialog.popup()
Global.EffectsMenu.GAUSSIAN_BLUR:
gaussian_blur_dialog.popup()
Global.EffectsMenu.GRADIENT:
gradient_dialog.popup()
Global.EffectsMenu.GRADIENT_MAP:
gradient_map_dialog.popup()
Global.EffectsMenu.PALETTIZE:
5:
palettize_dialog.popup()
Global.EffectsMenu.PIXELIZE:
pixelize_dialog.popup()
Global.EffectsMenu.POSTERIZE:
6:
posterize_dialog.popup()
_:
_handle_metadata(id, effects_menu)
7:
gradient_map_dialog.popup()
func _on_effects_procedural_submenu_id_pressed(id: int) -> void:
match id:
0:
outline_dialog.popup()
1:
drop_shadow_dialog.popup()
2:
gradient_dialog.popup()
func _on_effects_blur_submenu_id_pressed(id: int) -> void:
match id:
0:
pixelize_dialog.popup()
1:
gaussian_blur_dialog.popup()
func select_menu_id_pressed(id: int) -> void: