From 45736cf6240a1ce7b8ffb81f408fb9255bd190c5 Mon Sep 17 00:00:00 2001 From: Variable <77773850+Variable-ind@users.noreply.github.com> Date: Wed, 8 Nov 2023 04:22:55 +0500 Subject: [PATCH] Added Godot generated documentation to the ExtensionsApi and some classes (#925) * ExtensionsAPI.gd to ExtensionsApi.gd * added docs to outer Api * added empty line * added docs to GeneralAPI * added docs to MenuAPI * added docs to DialogAPI * added docs to PanelAPI * added docs to ThemeAPI * added docs to ToolAPI * added docs to SelectionAPI * added docs to the remaining APIs * fix typo * formatting * linting * linting * documented AnimationTag class * documented BaseCel class * more accurate instructions to generate api * improve/clean docs a bit * documented BaseLayer class * linting * added some more docs * Update BaseLayer.gd * typo * added some more info --- project.godot | 2 +- .../{ExtensionsAPI.gd => ExtensionsApi.gd} | 243 ++++++++++++++---- src/Classes/AnimationTag.gd | 50 +++- src/Classes/BaseCel.gd | 44 +++- src/Classes/BaseLayer.gd | 40 ++- src/Classes/Cel3D.gd | 16 +- 6 files changed, 318 insertions(+), 77 deletions(-) rename src/Autoload/{ExtensionsAPI.gd => ExtensionsApi.gd} (61%) diff --git a/project.godot b/project.godot index 102e901ae..7daa669a8 100644 --- a/project.godot +++ b/project.godot @@ -41,7 +41,7 @@ Html5FileExchange="*res://src/Autoload/HTML5FileExchange.gd" Export="*res://src/Autoload/Export.gd" Palettes="*res://src/Autoload/Palettes.gd" Keychain="*res://addons/keychain/Keychain.gd" -ExtensionsApi="*res://src/Autoload/ExtensionsAPI.gd" +ExtensionsApi="*res://src/Autoload/ExtensionsApi.gd" [debug] diff --git a/src/Autoload/ExtensionsAPI.gd b/src/Autoload/ExtensionsApi.gd similarity index 61% rename from src/Autoload/ExtensionsAPI.gd rename to src/Autoload/ExtensionsApi.gd index e63052ac3..bbc6d9b9c 100644 --- a/src/Autoload/ExtensionsAPI.gd +++ b/src/Autoload/ExtensionsApi.gd @@ -1,21 +1,39 @@ extends Node +# NOTE: Goto File-->Save then type "ExtensionsApi" in "Search Help" to read the +# curated documentation of the Api. +# If it still doesn't show try again after doing Project-->Reload current project -# Use these variables in your extension to access the api +## The Official ExtensionsAPI for pixelorama. +## +## This Api gives you the essentials eo develop a working extension for Pixelorama.[br] +## The Api consists of many smaller Apis, each giving access to different areas of the Software. +## [br][br] +## Keep in mind that this API is targeted towards users who are not fully familiar with Pixelorama's +## source code. If you need to do something more complicated and more low-level, you would need to +## interact directly with the source code. +## +## To access this anywhere in the extension use [code]get_node_or_null("/root/ExtensionsApi")[/code] +## +## @tutorial(Add Tutorial here): https://the/tutorial1/url.com + +## Gives access to the general, app related functions of pixelorama +## such as Autoloads, Software Version, Config file etc... var general := GeneralAPI.new() -var menu := MenuAPI.new() -var dialog := DialogAPI.new() -var panel := PanelAPI.new() -var theme := ThemeAPI.new() -var tools := ToolAPI.new() -var selection := SelectionAPI.new() -var project := ProjectAPI.new() -var exports := ExportAPI.new() -var signals := SignalsAPI.new() +var menu := MenuAPI.new() ## Gives ability to add/remove items from menus in the top bar. +var dialog := DialogAPI.new() ## Gives access to Dialog related functions. +var panel := PanelAPI.new() ## Gives access to Tabs and Dockable Container related functions. +var theme := ThemeAPI.new() ## Gives access to theme related functions. +var tools := ToolAPI.new() ## Gives ability to add/remove tools. +var selection := SelectionAPI.new() ## Gives access to pixelorama's selection system. +var project := ProjectAPI.new() ## Gives access to project manipulation. +var exports := ExportAPI.new() ## Gives access to adding custom exporters. +var signals := SignalsAPI.new() ## Gives access to the basic commonly used signals. ## This fail-safe below is designed to work ONLY if Pixelorama is launched in Godot Editor var _action_history: Dictionary = {} +## [code]This function is used internally and not meant to be used by extensions.[/code] func check_sanity(extension_name: String): if extension_name in _action_history.keys(): var extension_history = _action_history[extension_name] @@ -30,11 +48,13 @@ func check_sanity(extension_name: String): print(error_msg) +## [code]This function is used internally and not meant to be used by extensions.[/code] func clear_history(extension_name: String): if extension_name in _action_history.keys(): _action_history.erase(extension_name) +## [code]This function is used internally and not meant to be used by extensions.[/code] func add_action(action: String): var extension_name = _get_caller_extension_name() if extension_name != "Unknown": @@ -45,6 +65,7 @@ func add_action(action: String): _action_history[extension_name] = [action] +## [code]This function is used internally and not meant to be used by extensions.[/code] func remove_action(action: String): var extension_name = _get_caller_extension_name() if extension_name != "Unknown": @@ -52,8 +73,9 @@ func remove_action(action: String): _action_history[extension_name].erase(action) +## [code]This function is used internally and not meant to be used by extensions.[/code] func wait_frame(): # as yield is not available to classes below, so this is the solution - # use by yield(ExtensionsApi.wait_frame(), "completed") + # use by {await ExtensionsApi.wait_frame()} await get_tree().process_frame await get_tree().process_frame @@ -75,36 +97,57 @@ func _exit_tree(): # The Api Methods Start Here +## Returns the version of the ExtensionsApi. func get_api_version() -> int: return ProjectSettings.get_setting("application/config/ExtensionsAPI_Version") +## Gives Access to the general stuff. +## +## This part of Api provides stuff like commonly used Autoloads, App's version info etc +## the most basic (but important) stuff. class GeneralAPI: - # Version And Config + ## Returns the current version of pixelorama. func get_pixelorama_version() -> String: return ProjectSettings.get_setting("application/config/Version") + ## Returns the [ConfigFile] contains all the settings (Brushes, sizes, preferences, etc...). func get_config_file() -> ConfigFile: return Global.config_cache - # Nodes + ## Returns the Global autoload used by Pixelorama.[br] + ## Contains references to almost all UI Elements, Variables that indicate different + ## settings etc..., In short it is the most important autoload of Pixelorama. func get_global() -> Global: return Global + ## Returns the DrawingAlgos autoload, contains different drawing algorithms used by Pixelorama. func get_drawing_algos() -> DrawingAlgos: return DrawingAlgos + ## Gives you a new ShaderImageEffect class. this class can apply shader to an image.[br] + ## It contains method: + ## [code]generate_image(img: Image, shader: Shader, params: Dictionary, size: Vector2)[/code] + ## [br]Whose parameters are identified as: + ## [br][param img] --> image that the shader will be pasted to (Empty Image of size same as + ## project). + ## [br][param shader] --> preload of the shader. + ## [br][param params] --> a dictionary of params used by the shader. + ## [br][param size] --> It is the project's size. func get_new_shader_image_effect() -> ShaderImageEffect: return ShaderImageEffect.new() + ## Returns parent of the nodes listed in extension.json -> "nodes". func get_extensions_node() -> Node: - # node where the nodes listed in "nodes" from extension.json gets placed return Global.control.get_node("Extensions") + ## Returns the main [code]Canvas[/code] node, + ## normally used to add a custom preview to the canvas. func get_canvas() -> Canvas: return Global.canvas +## Gives ability to add/remove items from menus in the top bar. class MenuAPI: enum { FILE, EDIT, SELECT, IMAGE, VIEW, WINDOW, HELP } @@ -127,9 +170,13 @@ class MenuAPI: return Global.top_menu_container.help_menu_button.get_popup() return null + ## Adds a menu item of title [param item_name] to the [param menu_type] defined by + ## [enum @unnamed_enums]. + ## [br][param item_metadata] is usually a window node you want to appear when you click the + ## [param item_name]. That window node should also have a [param menu_item_clicked] + ## function inside its script.[br] + ## Index of the added item is returned (which can be used to remove menu item later on). func add_menu_item(menu_type: int, item_name: String, item_metadata, item_id := -1) -> int: - # item_metadata is usually a popup node you want to appear when you click the item_name - # that popup should also have an (menu_item_clicked) function inside its script var popup_menu: PopupMenu = _get_popup_menu(menu_type) if not popup_menu: return -1 @@ -141,6 +188,8 @@ class MenuAPI: ExtensionsApi.add_action("add_menu") return idx + ## Removes a menu item at index [param item_idx] from the [param menu_type] defined by + ## [enum @unnamed_enums]. func remove_menu_item(menu_type: int, item_idx: int) -> void: var popup_menu: PopupMenu = _get_popup_menu(menu_type) if not popup_menu: @@ -149,29 +198,37 @@ class MenuAPI: ExtensionsApi.remove_action("add_menu") +## Gives access to common dialog related functions. class DialogAPI: + ## Shows an alert dialog with the given [param text]. + ## Useful for displaying messages like "Incompatible API" etc... func show_error(text: String) -> void: - # useful for displaying messages like "Incompatible API" etc... Global.error_dialog.set_text(text) Global.error_dialog.popup_centered() Global.dialog_open(true) + ## Returns the node that is the parent of dialogs used in pixelorama. func get_dialogs_parent_node() -> Node: return Global.control.get_node("Dialogs") + ## Tells pixelorama that some dialog is about to open or close. func dialog_open(open: bool) -> void: Global.dialog_open(open) +## Gives access to Tabs and Dockable Container related functions. class PanelAPI: - func set_tabs_visible(visible: bool) -> void: - var dockable := _get_dockable_container_ui() - dockable.set_tabs_visible(visible) - - func get_tabs_visible() -> bool: - var dockable := _get_dockable_container_ui() - return dockable.get_tabs_visible() + ## Sets the visibility of dokable tabs. + var tabs_visible: bool: + set(value): + var dockable := _get_dockable_container_ui() + dockable.tabs_visible = value + get: + var dockable := _get_dockable_container_ui() + return dockable.tabs_visible + ## Adds the [param node] as a tab. Initially it's placed on the same panel as the tools tab, + ## but can be changed through adding custom layouts. func add_node_as_tab(node: Node) -> void: var dockable := _get_dockable_container_ui() var top_menu_container = Global.top_menu_container @@ -201,6 +258,7 @@ class PanelAPI: dockable.tabs_visible = false ExtensionsApi.add_action("add_tab") + ## Removes the [param node] from the DockableContainer. func remove_node_from_tab(node: Node) -> void: var top_menu_container = Global.top_menu_container var dockable = Global.control.find_child("DockableContainer") @@ -288,20 +346,26 @@ class PanelAPI: return tabs +## Gives access to theme related functions. class ThemeAPI: + ## Adds the [param theme] to [code]Edit -> Preferences -> Interface -> Themes[/code]. func add_theme(theme: Theme) -> void: var themes: BoxContainer = Global.preferences_dialog.find_child("Themes") themes.themes.append(theme) themes.add_theme(theme) ExtensionsApi.add_action("add_theme") + ## Returns index of the [param theme] in preferences. func find_theme_index(theme: Theme) -> int: var themes: BoxContainer = Global.preferences_dialog.find_child("Themes") return themes.themes.find(theme) + ## Returns the current theme resource. func get_theme() -> Theme: return Global.control.theme + ## Sets a theme located at a given [param idx] in preferences. If theme set successfully then + ## return [code]true[/code], else [code]false[/code]. func set_theme(idx: int) -> bool: var themes: BoxContainer = Global.preferences_dialog.find_child("Themes") if idx >= 0 and idx < themes.themes.size(): @@ -310,21 +374,32 @@ class ThemeAPI: else: return false + ## Remove the [param theme] from preferences. func remove_theme(theme: Theme) -> void: Global.preferences_dialog.themes.remove_theme(theme) ExtensionsApi.remove_action("add_theme") +## Gives ability to add/remove tools. class ToolAPI: - # Tool methods + # gdlint: ignore=constant-name + const LayerTypes = Global.LayerTypes + + ## Adds a tool to pixelorama with name [param tool_name] (without spaces), + ## display name [param display_name], tool scene [param scene], layers that the tool works + ## on [param layer_types] defined by [constant LayerTypes], + ## [param extra_hint] (text that appears when mouse havers tool icon), primary shortcut + ## name [param shortcut] and any extra shortcuts [param extra_shortucts]. + ## [br][br]At the moment extensions can't make their own shortcuts so you can ignore + ## [param shortcut] and [param extra_shortucts]. func add_tool( tool_name: String, display_name: String, - shortcut: String, scene: String, + layer_types: PackedInt32Array = [], extra_hint := "", - extra_shortucts := [], - layer_types: PackedInt32Array = [] + shortcut: String = "", + extra_shortucts: PackedStringArray = [] ) -> void: var tool_class := Tools.Tool.new( tool_name, display_name, shortcut, scene, layer_types, extra_hint, extra_shortucts @@ -333,6 +408,8 @@ class ToolAPI: Tools.add_tool_button(tool_class) ExtensionsApi.add_action("add_tool") + ## Removes a tool with name [param tool_name] + ## and assign Pencil as left tool, Eraser as right tool. func remove_tool(tool_name: String) -> void: # Re-assigning the tools in case the tool to be removed is also active Tools.assign_tool("Pencil", MOUSE_BUTTON_LEFT) @@ -343,20 +420,29 @@ class ToolAPI: ExtensionsApi.remove_action("add_tool") +## Gives access to pixelorama's selection system. class SelectionAPI: + ## Clears the selection Gizmo. func clear_selection() -> void: Global.canvas.selection.clear_selection(true) + ## Select the entire region of current cel. func select_all() -> void: Global.canvas.selection.select_all() + ## Selects a portion defined by [param rect] of the current cel. + ## [param operation] influences it's behaviour with previous selection rects + ## (0 for adding, 1 for subtracting, 2 for intersection). func select_rect(rect: Rect2i, operation := 0) -> void: - # 0 for adding, 1 for subtracting, 2 for intersection Global.canvas.selection.transform_content_confirm() var undo_data_tmp = Global.canvas.selection.get_undo_data(false) Global.canvas.selection.select_rect(rect, operation) Global.canvas.selection.commit_undo("Select", undo_data_tmp) + ## Moves a selection to [param destination], + ## with content if [param with_content] is [code]true[/code]. + ## If [param transform_standby] is [code]true[/code] then the transformation will not be + ## applied immediatelyunless [kbd]Enter[/kbd] is pressed. func move_selection(destination: Vector2, with_content := true, transform_standby := false): if not with_content: Global.canvas.selection.transform_content_confirm() @@ -369,6 +455,10 @@ class SelectionAPI: if not transform_standby and with_content: Global.canvas.selection.transform_content_confirm() + ## Resizes the selection to [param new_size], + ## with content if [param with_content] is [code]true[/code]. + ## If [param transform_standby] is [code]true[/code] then the transformation will not be + ## applied immediatelyunless [kbd]Enter[/kbd] is pressed. func resize_selection(new_size: Vector2, with_content := true, transform_standby := false): if not with_content: Global.canvas.selection.transform_content_confirm() @@ -381,23 +471,33 @@ class SelectionAPI: if not transform_standby and with_content: Global.canvas.selection.transform_content_confirm() + ## Inverts the selection gizmo. func invert() -> void: Global.canvas.selection.invert() + ## Makes a project brush out of the current selection's content. func make_brush() -> void: Global.canvas.selection.new_brush() + ## Copies the selection content (works in or between pixelorama instances only). func copy() -> void: Global.canvas.selection.copy() + ## Pastes the selection content. func paste(in_place := false) -> void: Global.canvas.selection.paste(in_place) + ## Deletes the drawing on current cel enclosed within the selection's area. func delete_content() -> void: Global.canvas.selection.delete() +## Gives access to basic project manipulation functions. class ProjectAPI: + ## Creates a new project (with new tab) with name [param name], size [param size], + ## fill color [param fill_color] and frames [param frames]. The created project also + ## gets returned.[br][br] + ## [param frames] is an [Array] of type Frames. Usually it can be left as [code][][/code]. func new_project( frames := [], name := tr("untitled"), @@ -416,31 +516,41 @@ class ProjectAPI: Global.projects.append(new_proj) return new_proj + ## Switches to the tab that contains the [param project]. func switch_to(project: Project): Global.tabs.current_tab = Global.projects.find(project) + ## Returns the project in focus. func get_current_project() -> Project: return Global.current_project + ## Returns a dictionary containing all the project information. func get_project_info(project: Project) -> Dictionary: return project.serialize() + ## Returns the current cel. + ## Cel type can be checked using function [method get_class_name] inside the cel + ## type can be GroupCel, PixelCel, Cel3D, or BaseCel. func get_current_cel() -> BaseCel: return get_current_project().get_current_cel() + ## Frames are counted from left to right, layers are counted from bottom to top. + ## Frames/layers start at "0" and end at [param project.frames.size() - 1] and + ## [param project.layers.size() - 1] respectively. func get_cel_at(project: Project, frame: int, layer: int) -> BaseCel: - # frames from left to right, layers from bottom to top clampi(frame, 0, project.frames.size() - 1) clampi(layer, 0, project.layers.size() - 1) return project.frames[frame].cels[layer] + ## Sets an [param image] at [param frame] and [param layer] on the current project. + ## Frames are counted from left to right, layers are counted from bottom to top. func set_pixelcel_image(image: Image, frame: int, layer: int) -> void: - # frames from left to right, layers from bottom to top if get_cel_at(get_current_project(), frame, layer).get_class_name() == "PixelCel": OpenSave.open_image_at_cel(image, layer, frame) else: print("cel at frame ", frame, ", layer ", layer, " is not a PixelCel") + ## Adds a new frame in the current project after frame [param after_frame]. func add_new_frame(after_frame: int): var project := Global.current_project if after_frame < project.frames.size() and after_frame >= 0: @@ -451,9 +561,12 @@ class ProjectAPI: else: print("invalid (after_frame)") + ## Adds a new Layer of name [param name] in the current project above layer [param above_layer] + ## ([param above_layer] = 0 is the bottom-most layer and so on). + ## [br][param type] = 0 --> PixelLayer, + ## [br][param type] = 1 --> GroupLayer, + ## [br][param type] = 2 --> 3DLayer func add_new_layer(above_layer: int, name := "", type := Global.LayerTypes.PIXEL): - # type = 0 --> PixelLayer, type = 1 --> GroupLayer, type = 2 --> 3DLayer - # above_layer = 0 is the bottom-most layer and so on var project = ExtensionsApi.project.get_current_project() if above_layer < project.layers.size() and above_layer >= 0: var old_current = project.current_layer @@ -471,10 +584,22 @@ class ProjectAPI: print("invalid (above_layer)") +## Gives access to adding custom exporters. class ExportAPI: - # gdlint: ignore=class-variable-name - var ExportTab := Export.ExportTab + # gdlint: ignore=constant-name + const ExportTab := Export.ExportTab + ## [param format_info] has keys: [code]extension[/code] and [code]description[/code] + ## whose values are of type [String] e.g:[codeblock] + ## format_info = {"extension": ".gif", "description": "GIF Image"} + ## [/codeblock] + ## [param exporter_generator] is a node with a script containing the method + ## [method override_export] which takes 1 argument of type Dictionary which is automatically + ## passed to [method override_export] at time of export and contains + ## keys: [code]processed_images[/code], [code]durations[/code], [code]export_dialog[/code], + ## [code]export_paths[/code], [code]project[/code][br] + ## If the value of [param tab] is not in [constant ExportTab] then the format will be added to + ## both tabs. Returns the index of exporter, which can be used to remove exporter later. func add_export_option( format_info: Dictionary, exporter_generator: Object, @@ -504,14 +629,21 @@ class ExportAPI: ExtensionsApi.add_action("add_exporter") return id + ## Removes the exporter with [param id] from Pixelorama. func remove_export_option(id: int): if Export.custom_exporter_generators.has(id): Export.remove_custom_file_format(id) ExtensionsApi.remove_action("add_exporter") +## Gives access to the basic commonly used signals. +## +## Gives access to the basic commonly used signals. +## Some less common signals are not mentioned in Api but could be accessed through source directly. class SignalsAPI: # system to auto-adjust texture_changed to the "current cel" + ## This signal is not meant to be used directly. + ## Use [method connect_current_cel_texture_changed] instead signal texture_changed var _last_cel: BaseCel @@ -530,85 +662,106 @@ class SignalsAPI: texture_changed.emit() # GLOBAL SIGNALS - # pixelorama_opened + ## connects a signal to [param method] present in [param target], that emits + ## when pixelorama is just opened. func connect_pixelorama_opened(callable: Callable): Global.pixelorama_opened.connect(callable) ExtensionsApi.add_action("pixelorama_opened") + ## reverse of [method connect_pixelorama_opened]. func disconnect_pixelorama_opened(callable: Callable): Global.pixelorama_opened.disconnect(callable) ExtensionsApi.remove_action("pixelorama_opened") - # pixelorama_about_to_close + ## connects a signal to [param method] present in [param target], that emits + ## when pixelorama is about to close. func connect_pixelorama_about_to_close(callable: Callable): Global.pixelorama_about_to_close.connect(callable) ExtensionsApi.add_action("pixelorama_about_to_close") + ## reverse of [method connect_pixelorama_about_to_close]. func disconnect_pixelorama_about_to_close(callable: Callable): Global.pixelorama_about_to_close.disconnect(callable) ExtensionsApi.remove_action("pixelorama_about_to_close") - # project_created -> signal has argument of type "Project" + ## connects a signal to [param method] present in [param target], that emits + ## whenever a new project is created.[br] + ## [b]Binds: [/b]It has one bind of type [code]Project[/code] which is the newly created project func connect_project_created(callable: Callable): Global.project_created.connect(callable) ExtensionsApi.add_action("project_created") + ## reverse of [method connect_project_created]. func disconnect_project_created(callable: Callable): Global.project_created.disconnect(callable) ExtensionsApi.remove_action("project_created") - # project_saved + ## connects a signal to [param method] present in [param target], that emits + ## whenever project is about to be saved. func connect_project_about_to_save(callable: Callable): Global.project_saved.connect(callable) ExtensionsApi.add_action("project_saved") + ## reverse of [method connect_project_about_to_save]. func disconnect_project_saved(callable: Callable): Global.project_saved.disconnect(callable) ExtensionsApi.remove_action("project_saved") - # project_changed + ## connects a signal to [param method] present in [param target], that emits + ## whenever you switch to some other project. func connect_project_changed(callable: Callable): Global.project_changed.connect(callable) ExtensionsApi.add_action("project_changed") + ## reverse of [method connect_project_changed]. func disconnect_project_changed(callable: Callable): Global.project_changed.disconnect(callable) ExtensionsApi.remove_action("project_changed") - # cel_changed + ## connects a signal to [param method] present in [param target], that emits + ## whenever you select a different cel. func connect_cel_changed(callable: Callable): Global.cel_changed.connect(callable) ExtensionsApi.add_action("cel_changed") + ## reverse of [method connect_cel_changed]. func disconnect_cel_changed(callable: Callable): Global.cel_changed.disconnect(callable) ExtensionsApi.remove_action("cel_changed") - # TOOL SIGNALs - # cel_changed + # TOOL SIGNALS + ## connects a signal to [param method] present in [param target], that emits + ## whenever a tool changes color. func connect_tool_color_changed(callable: Callable): Tools.color_changed.connect(callable) ExtensionsApi.add_action("color_changed") + ## reverse of [method connect_tool_color_changed]. func disconnect_tool_color_changed(callable: Callable): Tools.color_changed.disconnect(callable) ExtensionsApi.remove_action("color_changed") # UPDATER SIGNALS - # current_cel_texture_changed + ## connects a signal to [param method] present in [param target], that emits + ## whenever texture of the currently focused cel changes. func connect_current_cel_texture_changed(callable: Callable): texture_changed.connect(callable) ExtensionsApi.add_action("texture_changed") + ## reverse of [method connect_current_cel_texture_changed]. func disconnect_current_cel_texture_changed(callable: Callable): texture_changed.disconnect(callable) ExtensionsApi.remove_action("texture_changed") - # Export dialog signals + ## connects a signal to [param method] present in [param target], that emits + ## whenever preview is about to be drawn.[br] + ## [b]Binds: [/b]It has one bind of type [Dictionary] with keys: [code]exporter_id[/code], + ## [code]export_tab[/code], [code]preview_images[/code], [code]durations[/code] func connect_export_about_to_preview(target: Object, method: String): Global.export_dialog.about_to_preview.connect(Callable(target, method)) ExtensionsApi.add_action("export_about_to_preview") + ## reverse of [method connect_export_about_to_preview]. func disconnect_export_about_to_preview(target: Object, method: String): Global.export_dialog.about_to_preview.disconnect(Callable(target, method)) ExtensionsApi.remove_action("export_about_to_preview") diff --git a/src/Classes/AnimationTag.gd b/src/Classes/AnimationTag.gd index 13ac50ea1..ccda0eb38 100644 --- a/src/Classes/AnimationTag.gd +++ b/src/Classes/AnimationTag.gd @@ -1,13 +1,55 @@ class_name AnimationTag extends RefCounted ## A class for frame tag properties +## +## A tag indicates an animation of your sprite. Using several tags you can organize different +## animations of your sprite.[br] +## Here is an example of how a new tag may be created ([b]without[/b] any undo-redo functionality) +##[codeblock] +##func create_tag(tag_name: StringName, color: Color, from: int, to: int): +## var tags_list = Global.current_project.animation_tags.duplicate() +## var new_tag = AnimationTag.new(tag_name, color, from, to) +## tags_list.append(new_tag) +## # now make it the new animation_tags (so that the setter is called to update UI) +## Global.current_project.animation_tags = tags_list +## [/codeblock] +## Here is an example of how a new tag may be created ([b]with[/b] undo-redo functionality) +## [codeblock] +##func create_tag(tag_name: StringName, color: Color, from: int, to: int): +## var new_animation_tags := Global.current_project.animation_tags.duplicate() +## # Loop through the tags to create new classes for them, so that they won't be the same +## # as Global.current_project.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 +## ) +## +## new_animation_tags.append(AnimationTag.new(tag_name, color, from, to)) +## +## # Handle Undo/Redo +## Global.current_project.undos += 1 +## Global.current_project.undo_redo.create_action("Adding a Tag") +## Global.current_project.undo_redo.add_do_method(Global.general_redo) +## Global.current_project.undo_redo.add_undo_method(Global.general_undo) +## Global.current_project.undo_redo.add_do_property( +## Global.current_project, "animation_tags", new_animation_tags +## ) +## Global.current_project.undo_redo.add_undo_property( +## Global.current_project, "animation_tags", Global.current_project.animation_tags +## ) +## Global.current_project.undo_redo.commit_action() +## [/codeblock] -var name: String -var color: Color -var from: int -var to: int +var name: String ## Name of tag +var color: Color ## Color of tag +var from: int ## First frame number in the tag (first frame in timeline is numbered 1) +var to: int ## First frame number in the tag (first frame in timeline is numbered 1) +## Class Constructor (used as [code]AnimationTag.new(name, color, from, to)[/code]) func _init(_name, _color, _from, _to) -> void: name = _name color = _color diff --git a/src/Classes/BaseCel.gd b/src/Classes/BaseCel.gd index 8e777fe39..de4e4be72 100644 --- a/src/Classes/BaseCel.gd +++ b/src/Classes/BaseCel.gd @@ -3,14 +3,17 @@ extends RefCounted ## Base class for cel properties. ## The term "cel" comes from "celluloid" (https://en.wikipedia.org/wiki/Cel). -signal texture_changed +signal texture_changed ## Emitted whenever cel's tecture is changed -var opacity := 1.0 +var opacity := 1.0 ## Opacity/Transparency of the cel. +## The image stored in the cel. var image_texture: Texture2D: get = _get_image_texture -## If the cel is linked a ref to the link set Dictionary this cel is in, or null if not linked: -var link_set = null ## { "cels": Array, "hue": float } or null -var transformed_content: Image ## Used in transformations (moving, scaling etc with selections) +## If the cel is linked then this contains a reference to the link set [Dictionary] this cel is in: +## [param { "cels": Array, "hue": float }]. +## [br] If the cel is not linked then it is [code]null[/code]. +var link_set = null # { "cels": Array, "hue": float } or null +var transformed_content: Image ## Used in transformations (moving, scaling etc with selections). # Methods to Override: @@ -20,33 +23,41 @@ func _get_image_texture() -> Texture2D: ## The content methods deal with the unique content of each cel type. For example, an Image for -## PixelLayers, or a Dictionary of settings for a procedural layer type, and null for Groups. +## PixelCel, or a Dictionary of settings for a procedural layer type, and null for Groups. ## Can be used for linking/unlinking cels, copying, and deleting content -func get_content(): +func get_content() -> Variant: return null +## The content methods deal with the unique content of each cel type. For example, an Image for +## PixelCel, or a Dictionary of settings for a procedural layer type, and null for Groups. +## Can be used for linking/unlinking cels, copying, and deleting content. func set_content(_content, _texture: ImageTexture = null) -> void: return -## Can be used to delete the content of the cel with set_content -## (using the old content from get_content as undo data) -func create_empty_content(): +## The content methods deal with the unique content of each cel type. For example, an Image for +## PixelCel, or a Dictionary of settings for a procedural layer type, and null for Groups. +## Can be used to delete the content of the cel with [method set_content] +## (using the old content from get_content as undo data). +func create_empty_content() -> Variant: return [] -## Can be used for creating copy content for copying cels or unlinking cels -func copy_content(): +## The content methods deal with the unique content of each cel type. For example, an Image for +## PixelCel, or a Dictionary of settings for a procedural layer type, and null for Groups. +## Can be used for creating copy content for copying cels or unlinking cels. +func copy_content() -> Variant: return [] -## Returns the image var for image based cel types, or a render for procedural types. +## Returns the image of image based cel types, or a render for procedural types. ## It's meant for read-only usage of image data, such as copying selections or color picking. func get_image() -> Image: return null +## Used to update the texture of the cel. func update_texture() -> void: texture_changed.emit() if link_set != null: @@ -57,29 +68,36 @@ func update_texture() -> void: cel.texture_changed.emit() +## Returns a curated [Dictionary] containing the cel data. func serialize() -> Dictionary: return {"opacity": opacity} +## Sets the cel data according to a curated [Dictionary] obtained from [method serialize]. func deserialize(dict: Dictionary) -> void: opacity = dict["opacity"] +## Used to save cel image/thumbnail during saving of a pxo file. func save_image_data_to_pxo(_file: FileAccess) -> void: return +## Used to load cel image/thumbnail during loading of a pxo file. func load_image_data_from_pxo(_file: FileAccess, _project_size: Vector2i) -> void: return +## Used to perform cleanup after a cel is removed. func on_remove() -> void: pass +## Returns an instance of the cel button that will be added to the timeline. func instantiate_cel_button() -> Node: return null +## Returns to get the type of the cel class. func get_class_name() -> String: return "BaseCel" diff --git a/src/Classes/BaseLayer.gd b/src/Classes/BaseLayer.gd index 02d4e00a6..889773972 100644 --- a/src/Classes/BaseLayer.gd +++ b/src/Classes/BaseLayer.gd @@ -28,14 +28,14 @@ enum BlendModes { LUMINOSITY ## Uses the blend luminosity while preserving the base hue and saturation. } -var name := "" -var project: Project -var index: int -var parent: BaseLayer -var blend_mode := BlendModes.NORMAL -var visible := true -var locked := false -var new_cels_linked := false +var name := "" ## Name of the layer. +var project: Project ## Project, the layer belongs to. +var index: int ## Index of layer in the timeline. +var parent: BaseLayer ## Parent of the layer. +var visible := true ## Sets visibility of the layer. +var locked := false ## Images of a locked layer won't be overritten. +var new_cels_linked := false ## Determines if new cel of the layer should be linked or not. +var blend_mode := BlendModes.NORMAL ## Blend mode of the current layer. var cel_link_sets: Array[Dictionary] = [] ## Each Dictionary represents a cel's "link set" @@ -48,6 +48,8 @@ func is_ancestor_of(layer: BaseLayer) -> bool: return false +## Returns an [Array] of layers that are children of this layer. +## The process is recursive if [param recursive] is [code]true[/code]. func get_children(recursive: bool) -> Array[BaseLayer]: var children: Array[BaseLayer] = [] if recursive: @@ -61,6 +63,8 @@ func get_children(recursive: bool) -> Array[BaseLayer]: return children +## Returns the number of child nodes. +## The process is recursive if [param recursive] is [code]true[/code]. func get_child_count(recursive: bool) -> int: var count := 0 if recursive: @@ -74,36 +78,46 @@ func get_child_count(recursive: bool) -> int: return count +## Tells if the layer has child layers ([code]true[/code]) or not ([code]false[/code]). func has_children() -> bool: if index == 0: return false return project.layers[index - 1].parent == self +## Tells if the layer is expanded ([code]true[/code]) or collapsed ([code]false[/code]) +## in the hierarchy. func is_expanded_in_hierarchy() -> bool: if is_instance_valid(parent): + # "expanded" variable is located in GroupLayer.gd return parent.expanded and parent.is_expanded_in_hierarchy() return true +## Tells if the layer's content is visible ([code]true[/code]) or hidden ([code]false[/code]) +## in the layer tree. This is influenced by the eye button. func is_visible_in_hierarchy() -> bool: if is_instance_valid(parent) and visible: return parent.is_visible_in_hierarchy() return visible +## Tells if the layer's content is locked ([code]true[/code]) or not ([code]false[/code]) +## in the layer tree. This is influenced by the lock button. func is_locked_in_hierarchy() -> bool: if is_instance_valid(parent) and not locked: return parent.is_locked_in_hierarchy() return locked +## Returns the number of parents above this layer. func get_hierarchy_depth() -> int: if is_instance_valid(parent): return parent.get_hierarchy_depth() + 1 return 0 +## Returns the path of the layer in the timeline as a [String] func get_layer_path() -> String: if is_instance_valid(parent): return str(parent.get_layer_path(), "/", name) @@ -151,6 +165,7 @@ func link_cel(cel: BaseCel, link_set = null) -> void: # Methods to Override: +## Returns a curated [Dictionary] containing the layer data. func serialize() -> Dictionary: assert(index == project.layers.find(self)) var dict := { @@ -172,6 +187,7 @@ func serialize() -> Dictionary: return dict +## Sets the layer data according to a curated [Dictionary] obtained from [method serialize]. func deserialize(dict: Dictionary) -> void: name = dict.name visible = dict.visible @@ -194,25 +210,33 @@ func deserialize(dict: Dictionary) -> void: cel_link_sets.append(link_set) +## Returns a layer type that is one of the [param LayerTypes] +## enum in ["src/Autoload/Global.gd"] Autoload. func get_layer_type() -> int: return -1 +## Returns a new empty [BaseCel] func new_empty_cel() -> BaseCel: return null +## Sets layer name to the default name followed by [param number]. func set_name_to_default(number: int) -> void: name = tr("Layer") + " %s" % number +## Tells if the user is allowed to draw on current layer ([code]true[/code]) +## or not ([code]false[/code]). func can_layer_get_drawn() -> bool: return false +## Tells if the layer allows child layers ([code]true[/code]) or not ([code]true[/code]) func accepts_child(_layer: BaseLayer) -> bool: return false +## Returns an instance of the layer button that will be added to the timeline. func instantiate_layer_button() -> Node: return null diff --git a/src/Classes/Cel3D.gd b/src/Classes/Cel3D.gd index afdba42f3..c915f1941 100644 --- a/src/Classes/Cel3D.gd +++ b/src/Classes/Cel3D.gd @@ -5,13 +5,16 @@ signal selected_object(object) signal scene_property_changed signal objects_changed -var size: Vector2i -var viewport: SubViewport -var parent_node: Node3D -var camera: Camera3D +var size: Vector2i ## Size of the image rendered by the cel. +var viewport: SubViewport ## SubViewport used by the cel. +var parent_node: Node3D ## Parent node of the 3d objects placed in the cel. +var camera: Camera3D ## Camera that is used to render the Image. +## A [Dictionary] of the scene properties such as [param ambient_light_color] etc... var scene_properties := {} -## Key = Cel3DObject's id, Value = Dictionary containing the properties of the Cel3DObject +## Keys are the ids of all [Cel3DObject]'s present in the scene, and their corresponding values +## point to a [Dictionary] containing the properties of that [Cel3DObject]. var object_properties := {} +## The currently selected [Cel3DObject]. var selected: Cel3DObject = null: set(value): if value == selected: @@ -22,9 +25,10 @@ var selected: Cel3DObject = null: if is_instance_valid(selected): # Select new object selected.select() selected_object.emit(value) -var current_object_id := 0 ## Its value never decreases +var current_object_id := 0 ## Its value never decreases. +## Class Constructor (used as [code]Cel3D.new(size, from_pxo, object_prop, scene_prop)[/code]) func _init(_size: Vector2i, from_pxo := false, _object_prop := {}, _scene_prop := {}) -> void: size = _size object_properties = _object_prop