Partial source code rewrite
- [src/*] Update comments - [src/*] Improve code quality - [export_presets.cfg] All exports use a console wrapper now - [src/console.gd] Add highlighting for "arbitrary" command - [src/console.gd] Add special message if nothing has been typed in - [src/misc.gd, src/console.gd] Move BooleanState, get_last() (now called get_shortened_array), get_boolean(), get_int() and get_int_direct() into misc - [src/console_info.gd] Remove useless _init() function - [src/console_info.gd] Make get_error_string() function more compact - [Loader.tscn, src/loader.gd] Remove window size support and slow initialization functionality - [src/loader.gd] Remove warning on startup (will be reimplemented at some point, most likely graphically) - [src/loader.gd] Replaced append_log() function with a lambda - [src/loader.gd] Implement argument parser with configuration support - [src/loader.gd] Add Presencode version information as constants and format_version() function - [src/misc.gd] Reorganize functions - [src/pmana.gd] Add checks to avoid slide change collisions - [src/pmana.gd] Replace logger.warn() calls to "await logger.error()" calls - [src/pmana.gd, src/misc.gd, src/console.gd] Remove pmana.shutdown() function in favour of misc.shutdown() which now does the same - [src/preader.gd] Fix resource loading issues for presentation directories - [src/preader.gd] Move resource loading workaround into seperate function _read_resource_workaround() - [src/processor.gd, src/console.gd, src/loader.gd, src/pmana.gd, src/ui_engine.gd] Move all _process() functions into seperate file - [src/processor.gd, src/console.gd, src/loader.gd, src/pmana.gd, src/ui_engine.gd, src/ui/welcome.gd] Move everything dragging related (except variables) into processor.gd - [ui/Welcome.tscn, src/ui/welcome.gd] Add support for presentation directories - [src/ui/welcome.gd] Update splash text
This commit is contained in:
parent
19d3e8a0d0
commit
b5acd36479
21 changed files with 767 additions and 522 deletions
|
@ -93,5 +93,5 @@ theme_override_fonts/font = ExtResource("4_jqfsc")
|
||||||
theme_override_font_sizes/font_size = 18
|
theme_override_font_sizes/font_size = 18
|
||||||
placeholder_text = "Enter a command here"
|
placeholder_text = "Enter a command here"
|
||||||
|
|
||||||
[connection signal="pressed" from="Bar/CloseButton" to="." method="close_console"]
|
[connection signal="pressed" from="Bar/CloseButton" to="." method="toggle_console"]
|
||||||
[connection signal="text_changed" from="Shell/Input" to="." method="input_changed"]
|
[connection signal="text_changed" from="Shell/Input" to="." method="input_changed"]
|
||||||
|
|
40
Loader.tscn
40
Loader.tscn
|
@ -8,43 +8,3 @@ offset_bottom = 1440.0
|
||||||
size_flags_horizontal = 4
|
size_flags_horizontal = 4
|
||||||
color = Color(0, 0, 0, 1)
|
color = Color(0, 0, 0, 1)
|
||||||
script = ExtResource("1_dpffy")
|
script = ExtResource("1_dpffy")
|
||||||
|
|
||||||
[node name="WindowSizeSupport" type="Control" parent="."]
|
|
||||||
anchors_preset = 0
|
|
||||||
offset_right = 40.0
|
|
||||||
offset_bottom = 40.0
|
|
||||||
|
|
||||||
[node name="EndPixel" type="ColorRect" parent="WindowSizeSupport"]
|
|
||||||
layout_mode = 0
|
|
||||||
offset_left = 1920.0
|
|
||||||
offset_top = 1080.0
|
|
||||||
offset_right = 1921.0
|
|
||||||
offset_bottom = 1081.0
|
|
||||||
|
|
||||||
[node name="1920+" type="ColorRect" parent="WindowSizeSupport"]
|
|
||||||
layout_mode = 0
|
|
||||||
offset_right = 9999.0
|
|
||||||
offset_bottom = 30.0
|
|
||||||
|
|
||||||
[node name="1920" type="ColorRect" parent="WindowSizeSupport"]
|
|
||||||
layout_mode = 0
|
|
||||||
offset_right = 1920.0
|
|
||||||
offset_bottom = 30.0
|
|
||||||
color = Color(0, 0, 1, 1)
|
|
||||||
|
|
||||||
[node name="1441" type="ColorRect" parent="WindowSizeSupport"]
|
|
||||||
layout_mode = 0
|
|
||||||
offset_right = 30.0
|
|
||||||
offset_bottom = 9999.0
|
|
||||||
|
|
||||||
[node name="1440" type="ColorRect" parent="WindowSizeSupport"]
|
|
||||||
layout_mode = 0
|
|
||||||
offset_right = 30.0
|
|
||||||
offset_bottom = 1440.0
|
|
||||||
color = Color(1, 1, 0, 1)
|
|
||||||
|
|
||||||
[node name="1080" type="ColorRect" parent="WindowSizeSupport"]
|
|
||||||
layout_mode = 0
|
|
||||||
offset_right = 30.0
|
|
||||||
offset_bottom = 1080.0
|
|
||||||
color = Color(1, 0, 1, 1)
|
|
||||||
|
|
32
docs/docs/reference/api/loader.md
Normal file
32
docs/docs/reference/api/loader.md
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
# Loader
|
||||||
|
Initializes Presencode and holds the viewport while presenting.
|
||||||
|
|
||||||
|
## Enums
|
||||||
|
### `VersionType`
|
||||||
|
- values
|
||||||
|
- `RELEASE`
|
||||||
|
- `RELEASECANDIDATE`
|
||||||
|
- `BETA`
|
||||||
|
- `ALPHA`
|
||||||
|
## Constants
|
||||||
|
### `version_release`
|
||||||
|
- type `int`
|
||||||
|
- description `Contains the current release number (e.g. 1)`
|
||||||
|
### `version_type`
|
||||||
|
- type `VersionType`
|
||||||
|
- description `Contains the current release type (e.g. VersionType.BETA)`
|
||||||
|
### `version_typerelease`
|
||||||
|
- type `int`
|
||||||
|
- description `Contains the current release type version (e.g. 3)`
|
||||||
|
### `format_version`
|
||||||
|
- return type `String`
|
||||||
|
- description `Replaces the variables %release%, %type_raw%, %type%, %type_short%, %type_technical% and %typerelease%.`
|
||||||
|
- arguments
|
||||||
|
- `format`
|
||||||
|
- type `string`
|
||||||
|
- mandatory `yes`
|
||||||
|
- description `The string that you want to format`
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 1
|
sidebar_position: 2
|
||||||
---
|
---
|
||||||
|
|
||||||
# Logger
|
# Logger
|
||||||
|
|
|
@ -1,27 +1,45 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 2
|
sidebar_position: 3
|
||||||
---
|
---
|
||||||
|
|
||||||
# Miscellaneous (misc)
|
# Miscellaneous (misc)
|
||||||
Miscellaneous functions that do not fit into other scripts.
|
Miscellaneous functions that do not fit into other scripts.
|
||||||
|
|
||||||
|
## Enums
|
||||||
|
### `BooleanState`
|
||||||
|
- values
|
||||||
|
- `TRUE`
|
||||||
|
- `FALSE`
|
||||||
|
- `INVALID`
|
||||||
## Variables
|
## Variables
|
||||||
### `config_shutdown_invisible`
|
### `config_shutdown_invisible`
|
||||||
- type `bool`
|
- type `bool`
|
||||||
- description `Hides the main window on shutdown if true, displays a white texture on shutdown if false`
|
- description `Hides the main window on shutdown if true, displays a white texture on shutdown if false`
|
||||||
## Functions
|
## Functions
|
||||||
### `shutdown`
|
### `get_bool`
|
||||||
- return type `void`
|
- return type `BooleanState`
|
||||||
- description `Registers a new presentation controller`
|
- description `Retrieves a bool from a String`
|
||||||
- arguments
|
- arguments
|
||||||
- `exitcode`
|
- `string`
|
||||||
- type `int`
|
- type `String`
|
||||||
- mandatory `no`
|
- mandatory `yes`
|
||||||
- description `DUDE DO YOU DON'T KNOW WHAT A EXITCODE IS?!`
|
- description `The string that you want to convert into a bool`
|
||||||
### `get_temporary_dir`
|
### `get_int`
|
||||||
- return type `String`
|
- return type `Vector2i`
|
||||||
- description `Return a temporary directory`
|
- description `Retrieves the next valid integer from an Array. Returns Vector2i(0, NUMBER) if successful, Vector2i(1, 0) if not`
|
||||||
- arguments `none`
|
- arguments
|
||||||
|
- `array`
|
||||||
|
- type `Array`
|
||||||
|
- mandatory `yes`
|
||||||
|
- description `The array that you want to get an integer out of`
|
||||||
|
### `get_int_direct`
|
||||||
|
- return type `Vector2i`
|
||||||
|
- description `Converts a String into an int. Returns Vector2i(0, NUMBER) if successful, Vector2i(1, 0) if not`
|
||||||
|
- arguments
|
||||||
|
- `string`
|
||||||
|
- type `String`
|
||||||
|
- mandatory `yes`
|
||||||
|
- description `The string that you want to convert to an integer`
|
||||||
### `get_center`
|
### `get_center`
|
||||||
- return type `Vector2i`
|
- return type `Vector2i`
|
||||||
- description `Calculates the center of a child inside its parent (Vector2i edition)`
|
- description `Calculates the center of a child inside its parent (Vector2i edition)`
|
||||||
|
@ -46,18 +64,28 @@ Miscellaneous functions that do not fit into other scripts.
|
||||||
- type `Vector2`
|
- type `Vector2`
|
||||||
- mandatory `yes`
|
- mandatory `yes`
|
||||||
- description `The size of the child object`
|
- description `The size of the child object`
|
||||||
### `clear_viewport`
|
### `get_shortened_array`
|
||||||
- return type `void`
|
- return type `Array`
|
||||||
- description `Clears the presentation viewport`
|
- description `Removes n items from an array (starting from the beginning)`
|
||||||
- arguments `none`
|
- arguments
|
||||||
### `hide_log`
|
- `array`
|
||||||
- return type `void`
|
- type `Array`
|
||||||
- description `Hides log output`
|
- mandatory `yes`
|
||||||
- arguments `none`
|
- description `The array that you want to shorten`
|
||||||
### `show_log`
|
- `skip`
|
||||||
- return type `void`
|
- type `int`
|
||||||
- description `Unhides log output`
|
- mandatory `yes`
|
||||||
|
- description `The amount of items that you want to remove from the beginning.`
|
||||||
|
- warning `This function automatically adds 1 to the skip variable. To only skip one element, use 0 (for example)`
|
||||||
|
### `get_temporary_dir`
|
||||||
|
- return type `String`
|
||||||
|
- description `Return a temporary directory`
|
||||||
- arguments `none`
|
- arguments `none`
|
||||||
### `shutdown`
|
### `shutdown`
|
||||||
- return type `void`
|
- return type `void`
|
||||||
- description `Ends the presentation and shuts Presencode down`
|
- description `Registers a new presentation controller`
|
||||||
|
- arguments
|
||||||
|
- `exitcode`
|
||||||
|
- type `int`
|
||||||
|
- mandatory `no`
|
||||||
|
- description `DUDE DO YOU DON'T KNOW WHAT A EXITCODE IS?!`
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 3
|
sidebar_position: 4
|
||||||
---
|
---
|
||||||
|
|
||||||
# Presentation Manager (pmana)
|
# Presentation Manager (pmana)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 4
|
sidebar_position: 5
|
||||||
---
|
---
|
||||||
|
|
||||||
# Presentation Reader (preader)
|
# Presentation Reader (preader)
|
||||||
|
|
|
@ -18,7 +18,7 @@ encrypt_directory=false
|
||||||
|
|
||||||
custom_template/debug=""
|
custom_template/debug=""
|
||||||
custom_template/release=""
|
custom_template/release=""
|
||||||
debug/export_console_wrapper=1
|
debug/export_console_wrapper=2
|
||||||
binary_format/embed_pck=true
|
binary_format/embed_pck=true
|
||||||
texture_format/bptc=true
|
texture_format/bptc=true
|
||||||
texture_format/s3tc=true
|
texture_format/s3tc=true
|
||||||
|
@ -81,7 +81,7 @@ encrypt_directory=false
|
||||||
|
|
||||||
custom_template/debug=""
|
custom_template/debug=""
|
||||||
custom_template/release=""
|
custom_template/release=""
|
||||||
debug/export_console_wrapper=1
|
debug/export_console_wrapper=2
|
||||||
binary_format/embed_pck=true
|
binary_format/embed_pck=true
|
||||||
texture_format/bptc=true
|
texture_format/bptc=true
|
||||||
texture_format/s3tc=true
|
texture_format/s3tc=true
|
||||||
|
|
|
@ -26,6 +26,7 @@ misc="*res://src/misc.gd"
|
||||||
preader="*res://src/preader.gd"
|
preader="*res://src/preader.gd"
|
||||||
pmana="*res://src/pmana.gd"
|
pmana="*res://src/pmana.gd"
|
||||||
ui_engine="*res://src/ui_engine.gd"
|
ui_engine="*res://src/ui_engine.gd"
|
||||||
|
processor="*res://src/processor.gd"
|
||||||
|
|
||||||
[display]
|
[display]
|
||||||
|
|
||||||
|
@ -73,8 +74,8 @@ content_scale_switch={
|
||||||
}
|
}
|
||||||
console={
|
console={
|
||||||
"deadzone": 0.5,
|
"deadzone": 0.5,
|
||||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":0,"key_label":96,"unicode":0,"echo":false,"script":null)
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":0,"key_label":4194334,"unicode":0,"echo":false,"script":null)
|
||||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":96,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
|
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194334,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
editor_switchres={
|
editor_switchres={
|
||||||
|
|
|
@ -23,9 +23,10 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
extends Button
|
extends Button
|
||||||
|
|
||||||
# Setup clickoverlay
|
# Initialize clickoverlay
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
# Set properties
|
logger.diag("Initializing ClickOverlay")
|
||||||
|
# Set button properties
|
||||||
mouse_filter = Control.MOUSE_FILTER_STOP
|
mouse_filter = Control.MOUSE_FILTER_STOP
|
||||||
position = Vector2i(0, 0)
|
position = Vector2i(0, 0)
|
||||||
# Hide button
|
# Hide button
|
||||||
|
@ -34,17 +35,13 @@ func _ready() -> void:
|
||||||
add_theme_stylebox_override("pressed", StyleBoxEmpty.new())
|
add_theme_stylebox_override("pressed", StyleBoxEmpty.new())
|
||||||
add_theme_stylebox_override("disabled", StyleBoxEmpty.new())
|
add_theme_stylebox_override("disabled", StyleBoxEmpty.new())
|
||||||
add_theme_stylebox_override("focus", StyleBoxEmpty.new())
|
add_theme_stylebox_override("focus", StyleBoxEmpty.new())
|
||||||
# Connect "pressed" signal to function "clicked"
|
# Connect pressed signal
|
||||||
connect("pressed", Callable(self, "clicked"))
|
connect("pressed", Callable(self, "clicked"))
|
||||||
# Simple fix for a bug
|
# Simple fix for a bug
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
clicked()
|
clicked()
|
||||||
|
|
||||||
|
# Clicked event
|
||||||
func clicked() -> void:
|
func clicked() -> void:
|
||||||
# Increase current_slide by one
|
|
||||||
logger.info("Navigating one slide forwards (click)")
|
logger.info("Navigating one slide forwards (click)")
|
||||||
pmana.change_slide(pmana.current_slide+1, true)
|
pmana.change_slide(pmana.current_slide+1, true)
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
|
||||||
# Scale clickoverlay to window size
|
|
||||||
size = DisplayServer.window_get_size()
|
|
||||||
|
|
207
src/console.gd
207
src/console.gd
|
@ -23,13 +23,6 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
extends ColorRect
|
extends ColorRect
|
||||||
|
|
||||||
# Enums
|
|
||||||
enum BooleanState {
|
|
||||||
TRUE,
|
|
||||||
FALSE,
|
|
||||||
INVALID
|
|
||||||
}
|
|
||||||
|
|
||||||
# Nodes
|
# Nodes
|
||||||
@onready var input: TextEdit = get_node("Shell/Input")
|
@onready var input: TextEdit = get_node("Shell/Input")
|
||||||
@onready var output: RichTextLabel = get_node("Shell/Output")
|
@onready var output: RichTextLabel = get_node("Shell/Output")
|
||||||
|
@ -43,20 +36,24 @@ var dragging: bool = false
|
||||||
var drag_area: Vector2 = Vector2(0, 0)
|
var drag_area: Vector2 = Vector2(0, 0)
|
||||||
var cursor_origin: Vector2 = Vector2(0, 0)
|
var cursor_origin: Vector2 = Vector2(0, 0)
|
||||||
|
|
||||||
|
# Initialize debug console
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
logger.info("Initializing debug console")
|
logger.info("Initializing debug console")
|
||||||
|
# Set properties
|
||||||
visible = false
|
visible = false
|
||||||
position = Vector2(30, 30)
|
position = Vector2(30, 30)
|
||||||
calculate_drag_area()
|
# Calculate console drag area
|
||||||
|
processor.update_dragging_area(processor.DragNode.CONSOLE)
|
||||||
# Setup window dragging
|
# Setup window dragging
|
||||||
$Bar/DragButton.connect("button_down", func():
|
$Bar/DragButton.connect("button_down", func() -> void:
|
||||||
dragging = true
|
dragging = true
|
||||||
cursor_origin = get_tree().root.get_viewport().get_mouse_position()
|
cursor_origin = get_tree().root.get_viewport().get_mouse_position()
|
||||||
)
|
)
|
||||||
$Bar/DragButton.connect("button_up", func():
|
$Bar/DragButton.connect("button_up", func() -> void:
|
||||||
dragging = false
|
dragging = false
|
||||||
cursor_origin = Vector2(0,0)
|
cursor_origin = Vector2(0,0)
|
||||||
)
|
)
|
||||||
|
# Setup ExpressionScript (in which arbitrary expressions are run)
|
||||||
expressionscript.name = "ExpressionScript"
|
expressionscript.name = "ExpressionScript"
|
||||||
expressionscript.set_script(ResourceLoader.load("res://src/console_expressionscript.gd"))
|
expressionscript.set_script(ResourceLoader.load("res://src/console_expressionscript.gd"))
|
||||||
expressionscript.logger = get_node("/root/logger")
|
expressionscript.logger = get_node("/root/logger")
|
||||||
|
@ -67,60 +64,18 @@ func _ready() -> void:
|
||||||
expressionscript.console = self
|
expressionscript.console = self
|
||||||
expressionscript.loader = get_node("/root/Presencode")
|
expressionscript.loader = get_node("/root/Presencode")
|
||||||
add_child(expressionscript)
|
add_child(expressionscript)
|
||||||
|
# Reset console session
|
||||||
await process_command(PackedStringArray(["exit"]))
|
await process_command(PackedStringArray(["exit"]))
|
||||||
logger.info("Debug console initialized")
|
logger.info("Debug console initialized")
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
# Toggle console visibility
|
||||||
# Move to top
|
func toggle_console() -> void:
|
||||||
get_tree().root.move_child(self, get_tree().root.get_child_count(true))
|
|
||||||
# Visibility toggle key
|
|
||||||
if Input.is_action_just_pressed("console"):
|
|
||||||
logger.info("Toggling console visibility")
|
logger.info("Toggling console visibility")
|
||||||
visible = !visible
|
visible = !visible
|
||||||
if dragging:
|
|
||||||
# Get new cursor position
|
|
||||||
var cursor_position = get_tree().root.get_viewport().get_mouse_position()
|
|
||||||
# If nothing changed, don't do anything
|
|
||||||
if cursor_origin != cursor_position:
|
|
||||||
# Calculate cursor offset
|
|
||||||
var cursor_offset: Vector2 = Vector2(0, 0)
|
|
||||||
cursor_offset.x = cursor_origin.x-cursor_position.x
|
|
||||||
cursor_offset.y = cursor_origin.y-cursor_position.y
|
|
||||||
# Change console position
|
|
||||||
position.x = position.x-cursor_offset.x
|
|
||||||
position.y = position.y-cursor_offset.y
|
|
||||||
# Set new cursor_origin
|
|
||||||
cursor_origin = cursor_position
|
|
||||||
# Prevent console from going out of scope
|
|
||||||
var position_new: Vector2 = check_violation()
|
|
||||||
if position != position_new:
|
|
||||||
position = position_new
|
|
||||||
|
|
||||||
# Helper function, prevents console from going out of scope
|
|
||||||
func check_violation() -> Vector2:
|
|
||||||
var new_position: Vector2 = position
|
|
||||||
if position.x <= 0:
|
|
||||||
new_position.x = 0
|
|
||||||
elif position.x >= drag_area.x:
|
|
||||||
new_position.x = drag_area.x
|
|
||||||
if position.y <= 0:
|
|
||||||
new_position.y = 0
|
|
||||||
elif position.y >= drag_area.y:
|
|
||||||
new_position.y = drag_area.y
|
|
||||||
return new_position
|
|
||||||
|
|
||||||
# Calculates a new drag_area
|
|
||||||
func calculate_drag_area(area: Vector2i = DisplayServer.window_get_size()) -> void:
|
|
||||||
drag_area.x = area.x-size.x
|
|
||||||
drag_area.y = area.y-size.y
|
|
||||||
|
|
||||||
# Close console on close button press
|
|
||||||
func close_console() -> void:
|
|
||||||
logger.info("Closing console")
|
|
||||||
visible = false
|
|
||||||
|
|
||||||
# Input changed
|
# Input changed
|
||||||
func input_changed() -> void:
|
func input_changed() -> void:
|
||||||
|
# Check for newline/enter
|
||||||
if input.text.contains("\n"):
|
if input.text.contains("\n"):
|
||||||
input.text = input.text.replace("\n", "")
|
input.text = input.text.replace("\n", "")
|
||||||
var input2: String = input.text
|
var input2: String = input.text
|
||||||
|
@ -128,13 +83,30 @@ func input_changed() -> void:
|
||||||
input.editable = false
|
input.editable = false
|
||||||
await process_command(input2.split(" ", false))
|
await process_command(input2.split(" ", false))
|
||||||
input.editable = true
|
input.editable = true
|
||||||
|
return
|
||||||
|
# Highlight wrong/correct arbitrary gdscript expressions
|
||||||
|
if input.text.begins_with("arbitrary ") and input.text != "arbitrary ":
|
||||||
|
var expression_raw: String = " ".join(PackedStringArray(misc.get_shortened_array(input.text.split(" "), 0)))
|
||||||
|
var expression: Expression = Expression.new()
|
||||||
|
if expression.parse(expression_raw) == Error.OK: input.add_theme_color_override("font_color", Color.LIGHT_GREEN)
|
||||||
|
else: input.add_theme_color_override("font_color", Color.LIGHT_CORAL)
|
||||||
|
else: input.add_theme_color_override("font_color", Color8(255, 255, 255, 255))
|
||||||
|
|
||||||
|
# Write to console output
|
||||||
|
func append_output(text: String, newline: bool = true) -> void:
|
||||||
|
if newline: output.text = output.text + text + "\n"
|
||||||
|
else: output.text = output.text + text
|
||||||
|
|
||||||
# Process commands
|
# Process commands
|
||||||
|
## This function is completely undocumented, looking a bit through the function and
|
||||||
|
## reading the append_output() calls should give you a rough understanding though.
|
||||||
func process_command(command: PackedStringArray) -> void:
|
func process_command(command: PackedStringArray) -> void:
|
||||||
logger.diag("Processing command [" + " ".join(command) + "]")
|
logger.diag("Processing command [" + " ".join(command) + "]")
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
append_output("[color=gray]$ " + " ".join(command) + "[color=white]")
|
if command.size() == 0:
|
||||||
if command.size() == 0: return
|
append_output("[color=gray]$ *nothing*[color=white]\nI don't think that entering nothing does anything. Try running [b]help[/b].")
|
||||||
|
return
|
||||||
|
else: append_output("[color=gray]$ " + " ".join(command) + "[color=white]")
|
||||||
match(command[0]):
|
match(command[0]):
|
||||||
"clear":
|
"clear":
|
||||||
match(command.size()):
|
match(command.size()):
|
||||||
|
@ -154,7 +126,7 @@ To get started, enter \"help\". To close the console, press the X button.[color=
|
||||||
1: exitcode = 0
|
1: exitcode = 0
|
||||||
2: exitcode = int(command[1])
|
2: exitcode = int(command[1])
|
||||||
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.TOO_MANY_ARGUMENTS))
|
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.TOO_MANY_ARGUMENTS))
|
||||||
pmana.shutdown(exitcode)
|
misc.shutdown(exitcode)
|
||||||
"help":
|
"help":
|
||||||
match(command.size()):
|
match(command.size()):
|
||||||
1: append_output(info.get_help_topic(ConsoleInfo.HelpTopic.INDEX))
|
1: append_output(info.get_help_topic(ConsoleInfo.HelpTopic.INDEX))
|
||||||
|
@ -215,59 +187,59 @@ MISC_SHUTDOWN_INVISIBLE | bool | Toggles if the window should be made invisibl
|
||||||
_:
|
_:
|
||||||
match(command[2]):
|
match(command[2]):
|
||||||
"LOGGER_ENABLED":
|
"LOGGER_ENABLED":
|
||||||
match(get_boolean(" ".join(get_last(command, 2)))):
|
match(misc.get_bool(" ".join(misc.get_shortened_array(command, 2)))):
|
||||||
BooleanState.TRUE:
|
misc.BooleanState.TRUE:
|
||||||
logger.config_enabled = true
|
logger.config_enabled = true
|
||||||
append_output("Set \"" + str(command[2]) + "\" to [b]true[/b].")
|
append_output("Set \"" + str(command[2]) + "\" to [b]true[/b].")
|
||||||
BooleanState.FALSE:
|
misc.BooleanState.FALSE:
|
||||||
logger.config_enabled = false
|
logger.config_enabled = false
|
||||||
append_output("Set \"" + str(command[2]) + "\" to [b]false[/b]")
|
append_output("Set \"" + str(command[2]) + "\" to [b]false[/b]")
|
||||||
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
||||||
"LOGGER_DIAGNOSTIC":
|
"LOGGER_DIAGNOSTIC":
|
||||||
match(get_boolean(" ".join(get_last(command, 2)))):
|
match(misc.get_bool(" ".join(misc.get_shortened_array(command, 2)))):
|
||||||
BooleanState.TRUE:
|
misc.BooleanState.TRUE:
|
||||||
logger.config_diagnostic = true
|
logger.config_diagnostic = true
|
||||||
append_output("Set \"" + str(command[2]) + "\" to [b]true[/b]")
|
append_output("Set \"" + str(command[2]) + "\" to [b]true[/b]")
|
||||||
BooleanState.FALSE:
|
misc.BooleanState.FALSE:
|
||||||
logger.config_diagnostic = false
|
logger.config_diagnostic = false
|
||||||
append_output("Set \"" + str(command[2]) + "\" to [b]false[/b]")
|
append_output("Set \"" + str(command[2]) + "\" to [b]false[/b]")
|
||||||
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
||||||
"LOGGER_COLORED":
|
"LOGGER_COLORED":
|
||||||
match(get_boolean(" ".join(get_last(command, 2)))):
|
match(misc.get_bool(" ".join(misc.get_shortened_array(command, 2)))):
|
||||||
BooleanState.TRUE:
|
misc.BooleanState.TRUE:
|
||||||
logger.config_colored = true
|
logger.config_colored = true
|
||||||
append_output("Set \"" + str(command[2]) + "\" to [b]true[/b]")
|
append_output("Set \"" + str(command[2]) + "\" to [b]true[/b]")
|
||||||
BooleanState.FALSE:
|
misc.BooleanState.FALSE:
|
||||||
logger.config_colored = false
|
logger.config_colored = false
|
||||||
append_output("Set \"" + str(command[2]) + "\" to [b]false[/b]")
|
append_output("Set \"" + str(command[2]) + "\" to [b]false[/b]")
|
||||||
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
||||||
"LOGGER_HARDFAIL":
|
"LOGGER_HARDFAIL":
|
||||||
match(get_boolean(" ".join(get_last(command, 2)))):
|
match(misc.get_bool(" ".join(misc.get_shortened_array(command, 2)))):
|
||||||
BooleanState.TRUE:
|
misc.BooleanState.TRUE:
|
||||||
logger.config_hardfail = true
|
logger.config_hardfail = true
|
||||||
append_output("Set \"" + str(command[2]) + "\" to [b]true[/b]")
|
append_output("Set \"" + str(command[2]) + "\" to [b]true[/b]")
|
||||||
BooleanState.FALSE:
|
misc.BooleanState.FALSE:
|
||||||
logger.config_hardfail = false
|
logger.config_hardfail = false
|
||||||
append_output("Set \"" + str(command[2]) + "\" to [b]false[/b]")
|
append_output("Set \"" + str(command[2]) + "\" to [b]false[/b]")
|
||||||
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
||||||
"LOGGER_LOGSTRING":
|
"LOGGER_LOGSTRING":
|
||||||
logger.config_logstring = " ".join(PackedStringArray(get_last(command, 2)))
|
logger.config_logstring = " ".join(PackedStringArray(misc.get_shortened_array(command, 2)))
|
||||||
append_output("Set \"" + str(command[2]) + "\" to [b]\"" + logger.config_logstring + "\"[/b]")
|
append_output("Set \"" + str(command[2]) + "\" to [b]\"" + logger.config_logstring + "\"[/b]")
|
||||||
"PMANA_ALLOW_FULLSCREEN":
|
"PMANA_ALLOW_FULLSCREEN":
|
||||||
match(get_boolean(" ".join(get_last(command, 2)))):
|
match(misc.get_bool(" ".join(misc.get_shortened_array(command, 2)))):
|
||||||
BooleanState.TRUE:
|
misc.BooleanState.TRUE:
|
||||||
pmana.config_allow_fullscreen = true
|
pmana.config_allow_fullscreen = true
|
||||||
append_output("Set \"" + str(command[2]) + "\" to [b]true[/b]")
|
append_output("Set \"" + str(command[2]) + "\" to [b]true[/b]")
|
||||||
BooleanState.FALSE:
|
misc.BooleanState.FALSE:
|
||||||
pmana.config_allow_fullscreen = false
|
pmana.config_allow_fullscreen = false
|
||||||
append_output("Set \"" + str(command[2]) + "\" to [b]false[/b]")
|
append_output("Set \"" + str(command[2]) + "\" to [b]false[/b]")
|
||||||
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
||||||
"MISC_SHUTDOWN_INVISIBLE":
|
"MISC_SHUTDOWN_INVISIBLE":
|
||||||
match(get_boolean(" ".join(get_last(command, 2)))):
|
match(misc.get_bool(" ".join(misc.get_shortened_array(command, 2)))):
|
||||||
BooleanState.TRUE:
|
misc.BooleanState.TRUE:
|
||||||
misc.config_shutdown_invisible = true
|
misc.config_shutdown_invisible = true
|
||||||
append_output("Set \"" + str(command[2]) + "\" to [b]true[/b]")
|
append_output("Set \"" + str(command[2]) + "\" to [b]true[/b]")
|
||||||
BooleanState.FALSE:
|
misc.BooleanState.FALSE:
|
||||||
misc.config_shutdown_invisible = false
|
misc.config_shutdown_invisible = false
|
||||||
append_output("Set \"" + str(command[2]) + "\" to [b]false[/b]")
|
append_output("Set \"" + str(command[2]) + "\" to [b]false[/b]")
|
||||||
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
||||||
|
@ -301,11 +273,11 @@ MISC_SHUTDOWN_INVISIBLE | bool | Toggles if the window should be made invisibl
|
||||||
5: append_output(info.get_error_string(ConsoleInfo.ConsoleError.TOO_FEW_ARGUMENTS))
|
5: append_output(info.get_error_string(ConsoleInfo.ConsoleError.TOO_FEW_ARGUMENTS))
|
||||||
6: append_output(info.get_error_string(ConsoleInfo.ConsoleError.TOO_FEW_ARGUMENTS))
|
6: append_output(info.get_error_string(ConsoleInfo.ConsoleError.TOO_FEW_ARGUMENTS))
|
||||||
7:
|
7:
|
||||||
var version: Vector2 = get_int_direct(command[2])
|
var version: Vector2 = misc.get_int_direct(command[2])
|
||||||
var slides: Vector2 = get_int_direct(command[3])
|
var slides: Vector2 = misc.get_int_direct(command[3])
|
||||||
var animations: BooleanState = get_boolean(command[4])
|
var animations: misc.BooleanState = misc.get_bool(command[4])
|
||||||
var animations_bool: bool = false
|
var animations_bool: bool = false
|
||||||
var quit_last_slide: BooleanState = get_boolean(command[5])
|
var quit_last_slide: misc.BooleanState = misc.get_bool(command[5])
|
||||||
var quit_last_slide_bool: bool = false
|
var quit_last_slide_bool: bool = false
|
||||||
var controller: NodePath = NodePath(command[6])
|
var controller: NodePath = NodePath(command[6])
|
||||||
if version.x != 0:
|
if version.x != 0:
|
||||||
|
@ -315,14 +287,14 @@ MISC_SHUTDOWN_INVISIBLE | bool | Toggles if the window should be made invisibl
|
||||||
append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "int"}))
|
append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "int"}))
|
||||||
return
|
return
|
||||||
match(animations):
|
match(animations):
|
||||||
BooleanState.TRUE: animations_bool = true
|
misc.BooleanState.TRUE: animations_bool = true
|
||||||
BooleanState.FALSE: animations_bool = false
|
misc.BooleanState.FALSE: animations_bool = false
|
||||||
_:
|
_:
|
||||||
append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
||||||
return
|
return
|
||||||
match(quit_last_slide):
|
match(quit_last_slide):
|
||||||
BooleanState.TRUE: quit_last_slide_bool = true
|
misc.BooleanState.TRUE: quit_last_slide_bool = true
|
||||||
BooleanState.FALSE: quit_last_slide_bool = false
|
misc.BooleanState.FALSE: quit_last_slide_bool = false
|
||||||
_:
|
_:
|
||||||
append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
||||||
return
|
return
|
||||||
|
@ -346,31 +318,31 @@ MISC_SHUTDOWN_INVISIBLE | bool | Toggles if the window should be made invisibl
|
||||||
3:
|
3:
|
||||||
if !pmana.registered: append_output(info.get_error_string(ConsoleInfo.ConsoleError.NO_CONTROLLER_REGISTERED))
|
if !pmana.registered: append_output(info.get_error_string(ConsoleInfo.ConsoleError.NO_CONTROLLER_REGISTERED))
|
||||||
else:
|
else:
|
||||||
var slide: Vector2i = get_int_direct(command[2])
|
var slide: Vector2i = misc.get_int_direct(command[2])
|
||||||
match(slide.x):
|
match(slide.x):
|
||||||
0:
|
0:
|
||||||
pmana.change_slide(slide.y)
|
pmana.change_slide(slide.y)
|
||||||
append_output("Switched to slide [b]" + str(slide.y) + "[/b]")
|
append_output("Switched to slide [b]" + str(slide.y) + "[/b]")
|
||||||
1: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "int"}))
|
1: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "int"}))
|
||||||
_: append_output(info.generate_internal_error("Invalid get_int() status number"))
|
_: append_output(info.generate_internal_error("Invalid misc.get_int() status number"))
|
||||||
4:
|
4:
|
||||||
if !pmana.registered: append_output(info.get_error_string(ConsoleInfo.ConsoleError.NO_CONTROLLER_REGISTERED))
|
if !pmana.registered: append_output(info.get_error_string(ConsoleInfo.ConsoleError.NO_CONTROLLER_REGISTERED))
|
||||||
else:
|
else:
|
||||||
var slide: Vector2i = get_int_direct(command[2])
|
var slide: Vector2i = misc.get_int_direct(command[2])
|
||||||
match(slide.x):
|
match(slide.x):
|
||||||
0:
|
0:
|
||||||
var no_animations: BooleanState = get_boolean(command[3])
|
var no_animations: misc.BooleanState = misc.get_bool(command[3])
|
||||||
match(no_animations):
|
match(no_animations):
|
||||||
BooleanState.TRUE:
|
misc.BooleanState.TRUE:
|
||||||
pmana.change_slide(slide.y, true)
|
pmana.change_slide(slide.y, true)
|
||||||
append_output("Switched to slide [b]" + str(slide.y) + "[/b] without animations")
|
append_output("Switched to slide [b]" + str(slide.y) + "[/b] without animations")
|
||||||
BooleanState.FALSE:
|
misc.BooleanState.FALSE:
|
||||||
pmana.change_slide(slide.y, false)
|
pmana.change_slide(slide.y, false)
|
||||||
append_output("Switched to slide [b]" + str(slide.y) + "[/b]")
|
append_output("Switched to slide [b]" + str(slide.y) + "[/b]")
|
||||||
BooleanState.INVALID:
|
misc.BooleanState.INVALID:
|
||||||
append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "bool"}))
|
||||||
1: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "int"}))
|
1: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_TYPE, {"expected_type": "int"}))
|
||||||
_: append_output(info.generate_internal_error("Invalid get_int() status number"))
|
_: append_output(info.generate_internal_error("Invalid misc.get_int() status number"))
|
||||||
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.TOO_MANY_ARGUMENTS))
|
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.TOO_MANY_ARGUMENTS))
|
||||||
"get_slide":
|
"get_slide":
|
||||||
if !pmana.registered: append_output(info.get_error_string(ConsoleInfo.ConsoleError.NO_CONTROLLER_REGISTERED))
|
if !pmana.registered: append_output(info.get_error_string(ConsoleInfo.ConsoleError.NO_CONTROLLER_REGISTERED))
|
||||||
|
@ -423,7 +395,7 @@ MISC_SHUTDOWN_INVISIBLE | bool | Toggles if the window should be made invisibl
|
||||||
match(command.size()):
|
match(command.size()):
|
||||||
1: append_output(info.get_error_string(ConsoleInfo.ConsoleError.TOO_FEW_ARGUMENTS))
|
1: append_output(info.get_error_string(ConsoleInfo.ConsoleError.TOO_FEW_ARGUMENTS))
|
||||||
_:
|
_:
|
||||||
var expression_raw: String = " ".join(PackedStringArray(get_last(command, 0)))
|
var expression_raw: String = " ".join(PackedStringArray(misc.get_shortened_array(command, 0)))
|
||||||
var expression: Expression = Expression.new()
|
var expression: Expression = Expression.new()
|
||||||
if expression.parse(expression_raw) != Error.OK:
|
if expression.parse(expression_raw) != Error.OK:
|
||||||
append_output(info.get_error_string(ConsoleInfo.ConsoleError.EXPRESSION_PARSING_FAILED, {"error": expression.get_error_text()}))
|
append_output(info.get_error_string(ConsoleInfo.ConsoleError.EXPRESSION_PARSING_FAILED, {"error": expression.get_error_text()}))
|
||||||
|
@ -435,48 +407,3 @@ MISC_SHUTDOWN_INVISIBLE | bool | Toggles if the window should be made invisibl
|
||||||
append_output("""Executed arbitrary expression successfully.
|
append_output("""Executed arbitrary expression successfully.
|
||||||
Returned: """ + str(returned))
|
Returned: """ + str(returned))
|
||||||
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_COMMAND))
|
_: append_output(info.get_error_string(ConsoleInfo.ConsoleError.INVALID_COMMAND))
|
||||||
|
|
||||||
# Helper function. I'm bad at explaining and naming things, just look at the code... please.
|
|
||||||
func get_last(array: Array, n: int) -> Array:
|
|
||||||
# Makes it easier
|
|
||||||
n = n+1
|
|
||||||
# Create new array
|
|
||||||
var new_array: Array = []
|
|
||||||
if n >= array.size():
|
|
||||||
logger.error("n is bigger than array.size()")
|
|
||||||
return []
|
|
||||||
for value in array:
|
|
||||||
if n == 0: # Append to new_array
|
|
||||||
new_array.append(value)
|
|
||||||
else: # Count down
|
|
||||||
n = n-1
|
|
||||||
return new_array
|
|
||||||
|
|
||||||
# Helper function. Tries to get a bool from an Array.
|
|
||||||
func get_boolean(string: String) -> BooleanState:
|
|
||||||
match(string):
|
|
||||||
"true": return BooleanState.TRUE
|
|
||||||
"false": return BooleanState.FALSE
|
|
||||||
_: return BooleanState.INVALID
|
|
||||||
|
|
||||||
# Helper function. Tries to get a int from an Array.
|
|
||||||
## Returns Vector2i(0, NUMBER) if successful
|
|
||||||
## Returns Vector2i(1, 0) if not successful
|
|
||||||
func get_int(array: Array) -> Vector2i:
|
|
||||||
for value in array:
|
|
||||||
if str(value).is_valid_int(): return Vector2i(0, int(value))
|
|
||||||
return Vector2i(1, 0)
|
|
||||||
|
|
||||||
# Helper function. Tries to get a int from a String.
|
|
||||||
## Returns Vector2i(0, NUMBER) if successful
|
|
||||||
## Returns Vector2i(1, 0) if not successful
|
|
||||||
func get_int_direct(string: String) -> Vector2i:
|
|
||||||
if string.is_valid_int(): return Vector2i(0, int(string))
|
|
||||||
else: return Vector2i(1, 0)
|
|
||||||
|
|
||||||
# Helper function. Appends text to output.text
|
|
||||||
func append_output(text: String, newline: bool = true) -> void:
|
|
||||||
if newline:
|
|
||||||
output.text = output.text + text + "\n"
|
|
||||||
else:
|
|
||||||
output.text = output.text + text
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
extends Node
|
extends Node
|
||||||
class_name ConsoleInfo
|
class_name ConsoleInfo
|
||||||
|
|
||||||
|
# Enums
|
||||||
enum ConsoleError {
|
enum ConsoleError {
|
||||||
OK,
|
OK,
|
||||||
UNIMPLEMENTED,
|
UNIMPLEMENTED,
|
||||||
|
@ -55,57 +56,38 @@ enum HelpTopic {
|
||||||
ARBITRARY
|
ARBITRARY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Variables
|
||||||
var error_color: String = "[color=red]"
|
var error_color: String = "[color=red]"
|
||||||
var internal_error_color: String = "[b][color=red]"
|
var internal_error_color: String = "[b][color=red]"
|
||||||
|
|
||||||
func _init() -> void:
|
# Generates an internal error
|
||||||
logger.diag("ConsoleInfo initialized")
|
|
||||||
|
|
||||||
func generate_internal_error(error: String) -> String:
|
func generate_internal_error(error: String) -> String:
|
||||||
var origin = misc.get_origin()
|
var origin = misc.get_origin()
|
||||||
logger.warn("Debug console (" + origin["file"] + ":" + origin["function"] + ":" + str(origin["line"]) + ") experienced an internal error: " + error)
|
logger.warn("Debug console (" + origin["file"] + ":" + origin["function"] + ":" + str(origin["line"]) + ") experienced an internal error: " + error)
|
||||||
return internal_error_color + "INTERNAL ERROR (" + error + ") [" + origin["file"] + ":" + origin["function"] + ":" + str(origin["line"]) + "]"
|
return internal_error_color + "INTERNAL ERROR (" + error + ") [" + origin["file"] + ":" + origin["function"] + ":" + str(origin["line"]) + "]"
|
||||||
|
|
||||||
|
# Converts ConsoleError into a String
|
||||||
func get_error_string(error: ConsoleError, context: Dictionary = {}) -> String:
|
func get_error_string(error: ConsoleError, context: Dictionary = {}) -> String:
|
||||||
match(error):
|
match(error):
|
||||||
ConsoleError.OK:
|
ConsoleError.OK: return generate_internal_error("ConsoleError.OK is not a valid error")
|
||||||
return generate_internal_error("ConsoleError.OK is not a valid error")
|
ConsoleError.UNIMPLEMENTED: return error_color + "Function unimplemented, aborting."
|
||||||
ConsoleError.UNIMPLEMENTED:
|
ConsoleError.INVALID_COMMAND: return error_color + "Invalid command. Execute \"help\" for a list of all available commands."
|
||||||
return error_color + "Function unimplemented, aborting."
|
ConsoleError.TOO_MANY_ARGUMENTS: return error_color + "Too many arguments."
|
||||||
ConsoleError.INVALID_COMMAND:
|
ConsoleError.TOO_FEW_ARGUMENTS: return error_color + "Too few arguments."
|
||||||
return error_color + "Invalid command. Execute \"help\" for a list of all available commands."
|
ConsoleError.INVALID_ARGUMENT: return error_color + "Invalid argument."
|
||||||
ConsoleError.TOO_MANY_ARGUMENTS:
|
ConsoleError.INVALID_TYPE: return error_color + "Invalid type. Command expected type " + str(context["expected_type"]) + "."
|
||||||
return error_color + "Too many arguments."
|
ConsoleError.NOT_AN_OBJECT: return error_color + "Invalid type. Command expected a valid NodePath."
|
||||||
ConsoleError.TOO_FEW_ARGUMENTS:
|
ConsoleError.NO_SCRIPT_ATTACHED: return error_color + "Invalid object. Command expected a script-attached object."
|
||||||
return error_color + "Too few arguments."
|
ConsoleError.INVALID_HELP_TOPIC: return error_color + "Invalid help topic."
|
||||||
ConsoleError.INVALID_ARGUMENT:
|
ConsoleError.INVALID_CONFIG_KEY: return error_color + "Invalid config key \"" + str(context["key"]) + "\". Execute \"config list\" for a list of all config keys."
|
||||||
return error_color + "Invalid argument."
|
ConsoleError.NO_PRESENTATION_OPEN: return error_color + "No presentation is currently open."
|
||||||
ConsoleError.INVALID_TYPE:
|
ConsoleError.CONTROLLER_ALREADY_REGISTERED: return error_color + "A presentation controller has been registered already."
|
||||||
return error_color + "Invalid type. Command expected type " + str(context["expected_type"]) + "."
|
ConsoleError.NO_CONTROLLER_REGISTERED: return error_color + "No presentation controller has been registered yet."
|
||||||
ConsoleError.NOT_AN_OBJECT:
|
ConsoleError.EXPRESSION_PARSING_FAILED: return error_color + "Could not parse arbitrary expression successfully.\nError: " + str(context["error"])
|
||||||
return error_color + "Invalid type. Command expected a valid NodePath."
|
ConsoleError.EXPRESSION_EXECUTION_FAILED: return error_color + "Could not execute arbitrary expression successfully.\nError: " + str(context["error"]) + "\nReturned: " + str(context["returned"])
|
||||||
ConsoleError.NO_SCRIPT_ATTACHED:
|
_: return generate_internal_error("Invalid ConsoleError \"" + str(error) + "\", context: " + str(context))
|
||||||
return error_color + "Invalid object. Command expected a script-attached object."
|
|
||||||
ConsoleError.INVALID_HELP_TOPIC:
|
|
||||||
return error_color + "Invalid help topic."
|
|
||||||
ConsoleError.INVALID_CONFIG_KEY:
|
|
||||||
return error_color + "Invalid config key \"" + str(context["key"]) + "\". Execute \"config list\" for a list of all config keys."
|
|
||||||
ConsoleError.NO_PRESENTATION_OPEN:
|
|
||||||
return error_color + "No presentation is currently open."
|
|
||||||
ConsoleError.CONTROLLER_ALREADY_REGISTERED:
|
|
||||||
return error_color + "A presentation controller has been registered already."
|
|
||||||
ConsoleError.NO_CONTROLLER_REGISTERED:
|
|
||||||
return error_color + "No presentation controller has been registered yet."
|
|
||||||
ConsoleError.EXPRESSION_PARSING_FAILED:
|
|
||||||
return error_color + """Could not parse arbitrary expression successfully.
|
|
||||||
Error: """ + str(context["error"])
|
|
||||||
ConsoleError.EXPRESSION_EXECUTION_FAILED:
|
|
||||||
return error_color + """Could not execute arbitrary expression successfully.
|
|
||||||
Error: """ + str(context["error"]) + """
|
|
||||||
Returned: """ + str(context["returned"])
|
|
||||||
_:
|
|
||||||
return generate_internal_error("Invalid ConsoleError \"" + str(error) + "\", context: " + str(context))
|
|
||||||
|
|
||||||
|
# Converts HelpTopic into a String
|
||||||
func get_help_topic(topic: HelpTopic) -> String:
|
func get_help_topic(topic: HelpTopic) -> String:
|
||||||
match(topic):
|
match(topic):
|
||||||
HelpTopic.INDEX:
|
HelpTopic.INDEX:
|
||||||
|
@ -158,5 +140,4 @@ Calls functions belonging to the Presentation Reader"""
|
||||||
|
|
||||||
Executes arbitrary GDScript expressions.
|
Executes arbitrary GDScript expressions.
|
||||||
-> EXPERIMENTAL"""
|
-> EXPERIMENTAL"""
|
||||||
_:
|
_: return generate_internal_error("Invalid HelpTopic \"" + str(topic) + "\"")
|
||||||
return generate_internal_error("Invalid HelpTopic \"" + str(topic) + "\"")
|
|
||||||
|
|
193
src/loader.gd
193
src/loader.gd
|
@ -23,21 +23,26 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
# Loader configuration
|
# Enums
|
||||||
## Window size support
|
enum VersionType {
|
||||||
### This is/was used for configuring scaling
|
RELEASE,
|
||||||
var config_window_size_support: bool = false
|
RELEASECANDIDATE,
|
||||||
## Skip malicious scripts warning if running as debug build
|
BETA,
|
||||||
var config_skipwarning: bool = true
|
ALPHA
|
||||||
## Slow init
|
}
|
||||||
### I don't know why I put this here lol
|
|
||||||
var config_slow_init: bool = false
|
# Constants
|
||||||
|
const version_release: int = 1
|
||||||
|
const version_type: VersionType = VersionType.ALPHA
|
||||||
|
const version_typerelease: int = 2
|
||||||
|
|
||||||
# Nodes
|
# Nodes
|
||||||
var logrtl: RichTextLabel = null
|
var logrtl: RichTextLabel = null
|
||||||
var console: Control = null
|
var console: Control = null
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
#while true: await get_tree().create_timer(0.05).timeout
|
||||||
|
misc.set_main_window_visibility(false)
|
||||||
logger.info("Updating loader scene")
|
logger.info("Updating loader scene")
|
||||||
# Rename loader scene
|
# Rename loader scene
|
||||||
name = "Presencode"
|
name = "Presencode"
|
||||||
|
@ -62,7 +67,7 @@ func _ready() -> void:
|
||||||
logrtl.add_theme_font_size_override("normal_font_size", 14)
|
logrtl.add_theme_font_size_override("normal_font_size", 14)
|
||||||
logrtl.add_theme_font_size_override("bold_font_size", 14)
|
logrtl.add_theme_font_size_override("bold_font_size", 14)
|
||||||
## Connect to logger
|
## Connect to logger
|
||||||
logger.connect("log_event", Callable(self, "append_log"))
|
logger.connect("log_event", func(_type: logger.Types, _message: String, logstring: String) -> void: logrtl.text = get_node("/root/Presencode/Log").text + logstring + "\n")
|
||||||
## Add to SceneTree
|
## Add to SceneTree
|
||||||
add_child(logrtl)
|
add_child(logrtl)
|
||||||
## Remove VScrollBar
|
## Remove VScrollBar
|
||||||
|
@ -74,14 +79,6 @@ func _ready() -> void:
|
||||||
vsbar.add_theme_stylebox_override("grabber", StyleBoxEmpty.new())
|
vsbar.add_theme_stylebox_override("grabber", StyleBoxEmpty.new())
|
||||||
vsbar.add_theme_stylebox_override("grabber_highlight", StyleBoxEmpty.new())
|
vsbar.add_theme_stylebox_override("grabber_highlight", StyleBoxEmpty.new())
|
||||||
vsbar.add_theme_stylebox_override("grabber_pressed", StyleBoxEmpty.new())
|
vsbar.add_theme_stylebox_override("grabber_pressed", StyleBoxEmpty.new())
|
||||||
## Window size support
|
|
||||||
if config_window_size_support:
|
|
||||||
$WindowSizeSupport.modulate = Color8(255, 255, 255, 255)
|
|
||||||
else:
|
|
||||||
$WindowSizeSupport.modulate = Color8(255, 255, 255, 0)
|
|
||||||
## Update process_mode
|
|
||||||
logger.process_mode = Node.PROCESS_MODE_ALWAYS
|
|
||||||
misc.process_mode = Node.PROCESS_MODE_ALWAYS
|
|
||||||
## Initialize Presencode
|
## Initialize Presencode
|
||||||
initialize()
|
initialize()
|
||||||
|
|
||||||
|
@ -98,24 +95,77 @@ func initialize() -> void:
|
||||||
Copyright (c) 2024 JeremyStarTM & Contributers
|
Copyright (c) 2024 JeremyStarTM & Contributers
|
||||||
Licensed under the GNU General Public License version 3
|
Licensed under the GNU General Public License version 3
|
||||||
""")
|
""")
|
||||||
if config_slow_init: await get_tree().create_timer(randf_range(0.2, 0.6)).timeout
|
|
||||||
# Check for platform
|
# Check for platform
|
||||||
misc.check_platform()
|
misc.check_platform()
|
||||||
# Create temporary directory
|
# Create temporary directory
|
||||||
DirAccess.make_dir_recursive_absolute(misc.get_temporary_dir())
|
DirAccess.make_dir_recursive_absolute(misc.get_temporary_dir())
|
||||||
|
# Load debug console
|
||||||
logger.info("Injecting console")
|
logger.info("Injecting console")
|
||||||
console = ResourceLoader.load("res://Console.tscn").instantiate()
|
console = ResourceLoader.load("res://Console.tscn").instantiate()
|
||||||
get_tree().root.add_child.call_deferred(console)
|
get_tree().root.add_child.call_deferred(console)
|
||||||
if config_slow_init: await get_tree().create_timer(randf_range(0.1, 0.15)).timeout
|
# Initialize processor
|
||||||
# Check for presentation path in commandline arguments
|
processor.initialize.call_deferred()
|
||||||
# Open presentation archive/directory
|
# Process arguments
|
||||||
var path: String = " ".join(OS.get_cmdline_user_args())
|
var path: String = parse_arguments()
|
||||||
if OS.get_cmdline_user_args().size() == 0:
|
# Update window properties
|
||||||
|
misc.set_main_window_visibility(true)
|
||||||
|
# Check path variable
|
||||||
|
if path == "":
|
||||||
ui_engine.initialize(self)
|
ui_engine.initialize(self)
|
||||||
else:
|
else:
|
||||||
await print_warning()
|
|
||||||
await load_presentation(path)
|
await load_presentation(path)
|
||||||
|
|
||||||
|
# Process commandline arguments
|
||||||
|
func parse_arguments() -> String:
|
||||||
|
var path: String = ""
|
||||||
|
var next_argument_value: String = ""
|
||||||
|
for arg in OS.get_cmdline_user_args():
|
||||||
|
match(next_argument_value):
|
||||||
|
"logger_enabled":
|
||||||
|
match(misc.get_bool(arg)):
|
||||||
|
misc.BooleanState.TRUE: logger.config_enabled = true
|
||||||
|
misc.BooleanState.FALSE: logger.config_enabled = false
|
||||||
|
_: logger.error("Value \"" + arg + "\" does not match \"true\" or \"false\"")
|
||||||
|
"logger_diagnostic":
|
||||||
|
match(misc.get_bool(arg)):
|
||||||
|
misc.BooleanState.TRUE: logger.config_diagnostic = true
|
||||||
|
misc.BooleanState.FALSE: logger.config_diagnostic = false
|
||||||
|
_: logger.error("Value \"" + arg + "\" does not match \"true\" or \"false\"")
|
||||||
|
"logger_colored":
|
||||||
|
match(misc.get_bool(arg)):
|
||||||
|
misc.BooleanState.TRUE: logger.config_colored = true
|
||||||
|
misc.BooleanState.FALSE: logger.config_colored = false
|
||||||
|
_: logger.error("Value \"" + arg + "\" does not match \"true\" or \"false\"")
|
||||||
|
"logger_hardfail":
|
||||||
|
match(misc.get_bool(arg)):
|
||||||
|
misc.BooleanState.TRUE: logger.config_hardfail = true
|
||||||
|
misc.BooleanState.FALSE: logger.config_hardfail = false
|
||||||
|
_: logger.error("Value \"" + arg + "\" does not match \"true\" or \"false\"")
|
||||||
|
"logger_logstring": logger.config_logstring = arg
|
||||||
|
"misc_shutdown_invisible":
|
||||||
|
match(misc.get_bool(arg)):
|
||||||
|
misc.BooleanState.TRUE: misc.config_shutdown_invisible = true
|
||||||
|
misc.BooleanState.FALSE: misc.config_shutdown_invisible = false
|
||||||
|
_: logger.error("Value \"" + arg + "\" does not match \"true\" or \"false\"")
|
||||||
|
if next_argument_value != "":
|
||||||
|
next_argument_value = ""
|
||||||
|
continue
|
||||||
|
match(arg):
|
||||||
|
"--help": continue
|
||||||
|
"--logger-enabled": next_argument_value = "logger_enabled"
|
||||||
|
"--logger-diagnostic": next_argument_value = "logger_diagnostic"
|
||||||
|
"--logger-colored": next_argument_value = "logger_colored"
|
||||||
|
"--logger-hardfail": next_argument_value = "logger_hardfail"
|
||||||
|
"--logger-logstring": next_argument_value = "logger_logstring"
|
||||||
|
"--shutdown-invisible": next_argument_value = "misc_shutdown_invisible"
|
||||||
|
_:
|
||||||
|
# doesn't match any of the above, append to path instead
|
||||||
|
## this causes an interesting side effect, which is best explained by an example:
|
||||||
|
## C:/Users/Example User/Documents/Important --shutdown-invisible false Documents/Example --logger-colored false Presentation.pcpa
|
||||||
|
if path == "": path = arg
|
||||||
|
else: path = path + " " + arg
|
||||||
|
return path
|
||||||
|
|
||||||
# Load a presentation from commandline arguments
|
# Load a presentation from commandline arguments
|
||||||
func load_presentation(path: String) -> void:
|
func load_presentation(path: String) -> void:
|
||||||
if FileAccess.file_exists(path) and path.ends_with(".zip") or path.ends_with(".pcpa"): # .pcpa = presencode presentation archive
|
if FileAccess.file_exists(path) and path.ends_with(".zip") or path.ends_with(".pcpa"): # .pcpa = presencode presentation archive
|
||||||
|
@ -126,81 +176,52 @@ func load_presentation(path: String) -> void:
|
||||||
preader.open_presentation(path, false)
|
preader.open_presentation(path, false)
|
||||||
else:
|
else:
|
||||||
await logger.error("Presentation file/directory \"" + path + "\" not found")
|
await logger.error("Presentation file/directory \"" + path + "\" not found")
|
||||||
if config_slow_init: await get_tree().create_timer(randf_range(0.6, 1)).timeout
|
return
|
||||||
# Read manifest & entrypoint files
|
# Read manifest & entrypoint files
|
||||||
preader.read_manifest()
|
preader.read_manifest()
|
||||||
preader.read_entrypoint()
|
preader.read_entrypoint()
|
||||||
# Update window properties
|
# Update window properties
|
||||||
console.calculate_drag_area(preader.get_ratio_resolution())
|
processor.update_dragging_area(processor.DragNode.CONSOLE, preader.get_ratio_resolution())
|
||||||
DisplayServer.window_set_title("Presencode » Presenting \"" + preader.get_topic() + "\" by \"" + preader.get_authors() + "\"")
|
DisplayServer.window_set_title("Presencode » Presenting \"" + preader.get_topic() + "\" by \"" + preader.get_authors() + "\"")
|
||||||
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
|
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
|
||||||
DisplayServer.window_set_size(preader.get_ratio_resolution())
|
DisplayServer.window_set_size(preader.get_ratio_resolution())
|
||||||
DisplayServer.window_set_min_size(preader.get_ratio_resolution())
|
DisplayServer.window_set_min_size(preader.get_ratio_resolution())
|
||||||
if config_slow_init: await get_tree().create_timer(randf_range(0.1, 0.3)).timeout
|
|
||||||
if config_window_size_support: $WindowSizeSupport/EndPixel.position = Vector2(preader.get_ratio_resolution().x-1, preader.get_ratio_resolution().y-1)
|
|
||||||
get_tree().root.content_scale_size = preader.get_ratio_resolution()
|
get_tree().root.content_scale_size = preader.get_ratio_resolution()
|
||||||
get_tree().root.content_scale_mode = Window.CONTENT_SCALE_MODE_VIEWPORT
|
get_tree().root.content_scale_mode = Window.CONTENT_SCALE_MODE_VIEWPORT
|
||||||
get_tree().root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_KEEP
|
get_tree().root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_KEEP
|
||||||
get_tree().root.content_scale_factor = 1.0
|
get_tree().root.content_scale_factor = 1.0
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
DisplayServer.window_set_position(misc.get_center(DisplayServer.screen_get_size(), DisplayServer.window_get_size()))
|
DisplayServer.window_set_position(misc.get_center(DisplayServer.screen_get_size(), DisplayServer.window_get_size()))
|
||||||
if config_slow_init: await get_tree().create_timer(randf_range(1, 1.5)).timeout
|
|
||||||
# Add entrypoint to SceneTree
|
# Add entrypoint to SceneTree
|
||||||
get_tree().root.add_child(preader.get_entrypoint())
|
get_tree().root.add_child(preader.get_entrypoint())
|
||||||
|
|
||||||
# seeeeeeeeeeeeelf explanitory
|
func format_version(format: String) -> String:
|
||||||
func _process(_delta: float) -> void:
|
var version: String = format
|
||||||
# Move to top
|
var version_type_normal: String = ""
|
||||||
get_tree().root.move_child(self, get_tree().root.get_child_count(true)-1)
|
var version_type_short: String = ""
|
||||||
# Change sizes
|
var version_type_technical: String = ""
|
||||||
size = DisplayServer.window_get_size()
|
match(version_type):
|
||||||
if typeof(logrtl) == TYPE_OBJECT:
|
VersionType.RELEASE:
|
||||||
logrtl.size = DisplayServer.window_get_size()
|
version_type_normal = "Release"
|
||||||
if config_window_size_support: move_child($WindowSizeSupport, get_child_count(true))
|
version_type_short = "Release"
|
||||||
# Fullscreen key combo
|
version_type_technical = "r"
|
||||||
if pmana.config_allow_fullscreen and Input.is_action_just_pressed("fullscreen"):
|
VersionType.RELEASECANDIDATE:
|
||||||
if DisplayServer.window_get_mode() == DisplayServer.WINDOW_MODE_WINDOWED:
|
version_type_normal = "Releasecandidate"
|
||||||
# window is windowed, set to fullscreen mode
|
version_type_short = "RC"
|
||||||
logger.info("Switched to fullscreen mode")
|
version_type_technical = "rc"
|
||||||
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
|
VersionType.BETA:
|
||||||
else:
|
version_type_normal = "Beta"
|
||||||
# window is in fullscreen (or something else) mode, set to windowed mode
|
version_type_short = "Beta"
|
||||||
logger.info("Switched to windowed mode")
|
version_type_technical = "b"
|
||||||
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
|
VersionType.ALPHA:
|
||||||
# Content scale switch combo
|
version_type_normal = "Alpha"
|
||||||
if Input.is_action_just_pressed("content_scale_switch"):
|
version_type_short = "Alpha"
|
||||||
match(get_tree().root.content_scale_stretch):
|
version_type_technical = "a"
|
||||||
Window.CONTENT_SCALE_STRETCH_FRACTIONAL:
|
_: logger.info("Invalid version type \"" + str(version_type) + "\"")
|
||||||
logger.info("Switching to fractional scaling")
|
version = version.replace("%release%", str(version_release))
|
||||||
get_tree().root.content_scale_stretch = Window.CONTENT_SCALE_STRETCH_INTEGER
|
version = version.replace("%type_raw%", str(version_type))
|
||||||
Window.CONTENT_SCALE_STRETCH_INTEGER:
|
version = version.replace("%type%", version_type_normal)
|
||||||
logger.info("Switching to integer scaling")
|
version = version.replace("%type_short%", version_type_short)
|
||||||
get_tree().root.content_scale_stretch = Window.CONTENT_SCALE_STRETCH_FRACTIONAL
|
version = version.replace("%type_technical%", version_type_technical)
|
||||||
_:
|
version = version.replace("%typerelease%", str(version_typerelease))
|
||||||
logger.error("Invalid content_scale_stretch value")
|
return version
|
||||||
|
|
||||||
# Append log output to logrtl.text
|
|
||||||
func append_log(_type: logger.Types, _message: String, log_str: String) -> void:
|
|
||||||
logrtl.text = $Log.text + log_str + "\n"
|
|
||||||
|
|
||||||
func print_warning() -> void:
|
|
||||||
if !config_skipwarning and OS.is_debug_build():
|
|
||||||
logger.warn("""Displaying warning
|
|
||||||
###################################################
|
|
||||||
##### !!! WARNING !!! WARNING !!! WARNING !!! #####
|
|
||||||
###################################################
|
|
||||||
Presentations made with Presencode perform
|
|
||||||
malicious actions such as collect your passwords,
|
|
||||||
encrypt your files, display you unwanted ads,
|
|
||||||
install other malware, etc..
|
|
||||||
|
|
||||||
ONLY VIEW PRESENCODE PRESENTATIONS IF YOU TRUST THE
|
|
||||||
AUTHOR AND HAVE VERIFIED THE PRESENTATION SCRIPT!
|
|
||||||
YOU HAVE 5 SECONDS TO EXIT PRESENCODE
|
|
||||||
|
|
||||||
YOU HAVE BEEN WARNED.
|
|
||||||
###################################################
|
|
||||||
##### !!! WARNING !!! WARNING !!! WARNING !!! #####
|
|
||||||
###################################################
|
|
||||||
""")
|
|
||||||
await get_tree().create_timer(5).timeout
|
|
||||||
|
|
|
@ -35,7 +35,9 @@ var config_enabled: bool = true
|
||||||
var config_diagnostic: bool = true
|
var config_diagnostic: bool = true
|
||||||
## Toggle colored output
|
## Toggle colored output
|
||||||
var config_colored: bool = true
|
var config_colored: bool = true
|
||||||
## Exit Presencode on error? (don't set this to false)
|
## Makes errors fail hard
|
||||||
|
### Shuts Presencode down if error() is called
|
||||||
|
### HIGHLY RECOMMENDED TO LEAVE ENABLED
|
||||||
var config_hardfail: bool = true
|
var config_hardfail: bool = true
|
||||||
## Logging template
|
## Logging template
|
||||||
### Variables (begin and end with '%'): runtime, time, file, function, line, color, type, message
|
### Variables (begin and end with '%'): runtime, time, file, function, line, color, type, message
|
||||||
|
|
171
src/misc.gd
171
src/misc.gd
|
@ -35,8 +35,13 @@ enum Error {
|
||||||
MANIFEST_INVALID_PROGRAM,
|
MANIFEST_INVALID_PROGRAM,
|
||||||
MANIFEST_INVALID_RATIO
|
MANIFEST_INVALID_RATIO
|
||||||
}
|
}
|
||||||
|
enum BooleanState {
|
||||||
|
TRUE,
|
||||||
|
FALSE,
|
||||||
|
INVALID
|
||||||
|
}
|
||||||
|
|
||||||
# Manifest specification
|
# Constants
|
||||||
const manifest_version: int = 1
|
const manifest_version: int = 1
|
||||||
const manifest_program: String = "Presencode"
|
const manifest_program: String = "Presencode"
|
||||||
|
|
||||||
|
@ -44,45 +49,46 @@ const manifest_program: String = "Presencode"
|
||||||
## Make window invisible on shutdown
|
## Make window invisible on shutdown
|
||||||
### Hides the main window on shutdown if true
|
### Hides the main window on shutdown if true
|
||||||
### Displays RenderingServer.get_white_texture() if false instead
|
### Displays RenderingServer.get_white_texture() if false instead
|
||||||
var config_shutdown_invisible: bool = true
|
var config_shutdown_invisible: bool = false
|
||||||
|
|
||||||
# Get call origin from stacktrace
|
# Helper function to retrieve a bool from a String
|
||||||
func get_origin(n: int = 0) -> Dictionary:
|
func get_bool(string: String) -> BooleanState:
|
||||||
var stack: Dictionary = get_stack()[2+n]
|
match(string):
|
||||||
return {"file": stack["source"].replace("user://", "").replace("res://", ""), "line": stack["line"], "function": stack["function"]}
|
"true": return BooleanState.TRUE
|
||||||
|
"false": return BooleanState.FALSE
|
||||||
|
_: return BooleanState.INVALID
|
||||||
|
|
||||||
# Shutdown Presencode safely
|
# Helper function to retrieve the next valid int from an Array
|
||||||
func shutdown(exitcode: int = 0) -> void:
|
## Returns Vector2i(0, NUMBER) if successful
|
||||||
logger.info("Shutting down (code " + str(exitcode) + ")")
|
## Returns Vector2i(1, 0) if not successful
|
||||||
get_tree().paused = true
|
func get_int(array: Array) -> Vector2i:
|
||||||
# Display white texture
|
for value in array:
|
||||||
var npr: NinePatchRect = NinePatchRect.new()
|
if str(value).is_valid_int(): return Vector2i(0, int(value))
|
||||||
npr.name = "OverlayTexture"
|
return Vector2i(1, 0)
|
||||||
npr.texture = ImageTexture.create_from_image(RenderingServer.texture_2d_get(RenderingServer.get_white_texture()))
|
|
||||||
npr.size = Vector2(100000, 100000)
|
# Helper function to retrieve a int from a String
|
||||||
npr.position = Vector2(-50000, -50000)
|
## Returns Vector2i(0, NUMBER) if successful
|
||||||
get_tree().root.add_child(npr)
|
## Returns Vector2i(1, 0) if not successful
|
||||||
get_tree().root.move_child(npr, get_tree().root.get_child_count(true))
|
func get_int_direct(string: String) -> Vector2i:
|
||||||
# Window stuff
|
if string.is_valid_int(): return Vector2i(0, int(string))
|
||||||
if config_shutdown_invisible:
|
else: return Vector2i(1, 0)
|
||||||
# Make window invisible
|
|
||||||
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
|
# Returns a shortened array, by skipping "skip" Items
|
||||||
DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_BORDERLESS, true)
|
func get_shortened_array(array: Array, skip: int) -> Array:
|
||||||
DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_RESIZE_DISABLED, true)
|
# We want to remove at least one item
|
||||||
DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_NO_FOCUS, true)
|
skip = skip+1
|
||||||
DisplayServer.window_set_min_size(Vector2i(1, 1))
|
# Create new array
|
||||||
DisplayServer.window_set_size(Vector2i(1, 1))
|
var new_array: Array = []
|
||||||
DisplayServer.window_set_position(Vector2i(0, 0))
|
if skip >= array.size():
|
||||||
logger.diag("Removing temporary directory")
|
logger.error("n is bigger than array.size()")
|
||||||
# Remove tempdir
|
return []
|
||||||
DirAccess.remove_absolute(get_temporary_dir())
|
# Loop through array
|
||||||
# Wait for all log messages to be printed to console/log
|
for value in array:
|
||||||
logger.diag("Waiting for log messages")
|
if skip == 0: # Append to new_array
|
||||||
await get_tree().create_timer(0.25, true).timeout
|
new_array.append(value)
|
||||||
print("Exiting!")
|
else: # Count down
|
||||||
get_tree().quit(exitcode)
|
skip = skip-1
|
||||||
# Insanely long timer to prevent Godot from executing code during exit
|
return new_array
|
||||||
await get_tree().create_timer(999, true).timeout
|
|
||||||
|
|
||||||
# Calculate the center of a child inside its parent (Vector2i)
|
# Calculate the center of a child inside its parent (Vector2i)
|
||||||
func get_center(parent_size: Vector2i, child_size: Vector2i) -> Vector2i:
|
func get_center(parent_size: Vector2i, child_size: Vector2i) -> Vector2i:
|
||||||
|
@ -105,26 +111,10 @@ func get_sign_float(number: float) -> float:
|
||||||
elif number < 0: return -1
|
elif number < 0: return -1
|
||||||
else: return 0
|
else: return 0
|
||||||
|
|
||||||
# Return path to temporary directory
|
# Get call origin from stacktrace
|
||||||
## This function tries to utilize the operating system's temporary directory.
|
func get_origin(n: int = 0) -> Dictionary:
|
||||||
## If all of them can't be used, it falls back to "user://temp" instead.
|
var stack: Dictionary = get_stack()[2+n]
|
||||||
func get_temporary_dir() -> String:
|
return {"file": stack["source"].replace("user://", "").replace("res://", ""), "line": stack["line"], "function": stack["function"]}
|
||||||
match(OS.get_name()):
|
|
||||||
"Linux": # Use "/tmp" or fallback
|
|
||||||
if DirAccess.dir_exists_absolute("/tmp"):
|
|
||||||
return "/tmp/presencode"
|
|
||||||
else:
|
|
||||||
return "user://temp"
|
|
||||||
"Windows": # Use "%USERPROFILE%/AppData/Local/Temp/Presencode" or "C:/Users/%USERNAME%/AppData/Local/Temp/Presencode" or fallback
|
|
||||||
if OS.get_environment("USERPROFILE") != "" and DirAccess.dir_exists_absolute(OS.get_environment("USERPROFILE").replace("\\", "/")):
|
|
||||||
return OS.get_environment("USERPROFILE").replace("\\", "/") + "/AppData/Local/Temp/Presencode"
|
|
||||||
elif OS.get_environment("USERNAME") != "" and DirAccess.dir_exists_absolute("C:/Users/" + OS.get_environment("USERNAME")):
|
|
||||||
return "C:/Users/" + OS.get_environment("USERNAME") + "/AppData/Local/Temp/Presencode"
|
|
||||||
else:
|
|
||||||
return "user://temp"
|
|
||||||
_: # Platform not supported
|
|
||||||
logger.warn("The " + OS.get_name() + " platform is not supported by Presencode. You can add support for that platform to Presencode yourself, if you want.")
|
|
||||||
return ""
|
|
||||||
|
|
||||||
# Check platform support
|
# Check platform support
|
||||||
func check_platform() -> void:
|
func check_platform() -> void:
|
||||||
|
@ -149,7 +139,70 @@ func get_best_resolution() -> Vector2i:
|
||||||
if closest_resolution == Vector2(NAN, NAN): return Vector2i(960, 540)
|
if closest_resolution == Vector2(NAN, NAN): return Vector2i(960, 540)
|
||||||
else: return closest_resolution
|
else: return closest_resolution
|
||||||
|
|
||||||
# Check for manifest consistency
|
# Return path to temporary directory
|
||||||
|
## This function tries to utilize the operating system's temporary directory.
|
||||||
|
## If all of them can't be used, it falls back to "user://temp" instead.
|
||||||
|
func get_temporary_dir() -> String:
|
||||||
|
match(OS.get_name()):
|
||||||
|
"Linux": # Use "/tmp" or fallback
|
||||||
|
if DirAccess.dir_exists_absolute("/tmp"):
|
||||||
|
return "/tmp/presencode"
|
||||||
|
else:
|
||||||
|
return "user://temp"
|
||||||
|
"Windows": # Use "%USERPROFILE%/AppData/Local/Temp/Presencode" or "C:/Users/%USERNAME%/AppData/Local/Temp/Presencode" or fallback
|
||||||
|
if OS.get_environment("USERPROFILE") != "" and DirAccess.dir_exists_absolute(OS.get_environment("USERPROFILE").replace("\\", "/")):
|
||||||
|
return OS.get_environment("USERPROFILE").replace("\\", "/") + "/AppData/Local/Temp/Presencode"
|
||||||
|
elif OS.get_environment("USERNAME") != "" and DirAccess.dir_exists_absolute("C:/Users/" + OS.get_environment("USERNAME")):
|
||||||
|
return "C:/Users/" + OS.get_environment("USERNAME") + "/AppData/Local/Temp/Presencode"
|
||||||
|
else:
|
||||||
|
return "user://temp"
|
||||||
|
_: # Platform not supported
|
||||||
|
logger.warn("The " + OS.get_name() + " platform is not supported by Presencode. You can add support for that platform to Presencode yourself, if you want.")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# Shutdown Presencode safely
|
||||||
|
func shutdown(exitcode: int = 0) -> void:
|
||||||
|
logger.info("Shutting down (code " + str(exitcode) + ")")
|
||||||
|
get_tree().paused = true
|
||||||
|
# Call controller's presentation_end() function if a controller is registered
|
||||||
|
if pmana.registered: await pmana.controller.presentation_end()
|
||||||
|
# Display white texture
|
||||||
|
var npr: NinePatchRect = NinePatchRect.new()
|
||||||
|
npr.name = "OverlayTexture"
|
||||||
|
npr.texture = ImageTexture.create_from_image(RenderingServer.texture_2d_get(RenderingServer.get_white_texture()))
|
||||||
|
npr.size = Vector2(100000, 100000)
|
||||||
|
npr.position = Vector2(-50000, -50000)
|
||||||
|
get_tree().root.add_child(npr)
|
||||||
|
get_tree().root.move_child(npr, get_tree().root.get_child_count(true))
|
||||||
|
# Set window properties
|
||||||
|
if config_shutdown_invisible: set_main_window_visibility(false)
|
||||||
|
# Remove temporary directory
|
||||||
|
logger.diag("Removing temporary directory")
|
||||||
|
DirAccess.remove_absolute(get_temporary_dir())
|
||||||
|
# Wait for all log messages to be printed to console/log
|
||||||
|
logger.diag("Waiting for log messages")
|
||||||
|
await get_tree().create_timer(0.25, true).timeout
|
||||||
|
print("Exiting!")
|
||||||
|
get_tree().quit(exitcode)
|
||||||
|
# Insanely long timer to prevent Godot from executing code during exit
|
||||||
|
await get_tree().create_timer(999, true).timeout
|
||||||
|
|
||||||
|
# Makes the window invisible/visible
|
||||||
|
func set_main_window_visibility(visible: bool) -> void:
|
||||||
|
if DisplayServer.window_get_mode() != DisplayServer.WINDOW_MODE_WINDOWED: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED, true)
|
||||||
|
DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_BORDERLESS, !visible)
|
||||||
|
DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_RESIZE_DISABLED, !visible)
|
||||||
|
DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_NO_FOCUS, !visible)
|
||||||
|
if visible:
|
||||||
|
DisplayServer.window_set_min_size(Vector2i(960, 540))
|
||||||
|
DisplayServer.window_set_size(Vector2i(960, 540))
|
||||||
|
DisplayServer.window_set_position(get_center(DisplayServer.screen_get_size(), DisplayServer.window_get_size()))
|
||||||
|
else:
|
||||||
|
DisplayServer.window_set_min_size(Vector2i(1, 1))
|
||||||
|
DisplayServer.window_set_size(Vector2i(1, 1))
|
||||||
|
DisplayServer.window_set_position(Vector2i(0, 0))
|
||||||
|
|
||||||
|
# Checks for manifest consistency
|
||||||
func check_manifest_consistency(manifest: Dictionary) -> misc.Error:
|
func check_manifest_consistency(manifest: Dictionary) -> misc.Error:
|
||||||
logger.diag("Checking manifest for consistency")
|
logger.diag("Checking manifest for consistency")
|
||||||
|
|
||||||
|
|
71
src/pmana.gd
71
src/pmana.gd
|
@ -26,6 +26,10 @@ extends Node
|
||||||
# Constants
|
# Constants
|
||||||
const entrypoint_version: int = 1
|
const entrypoint_version: int = 1
|
||||||
|
|
||||||
|
# Nodes
|
||||||
|
var clickoverlay: Button = null
|
||||||
|
var viewport: Control = null
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
var config_allow_fullscreen: bool = true
|
var config_allow_fullscreen: bool = true
|
||||||
|
|
||||||
|
@ -39,8 +43,7 @@ var quit_last_slide: bool = true
|
||||||
var registered: bool = false
|
var registered: bool = false
|
||||||
var current_slide: int = -1
|
var current_slide: int = -1
|
||||||
var animation_active: bool = false
|
var animation_active: bool = false
|
||||||
var clickoverlay: Button = null
|
var action_running: bool = false
|
||||||
var viewport: Control = null
|
|
||||||
|
|
||||||
# Register a controller
|
# Register a controller
|
||||||
func register(version: int, slides_: int, animations_: bool, quit_last_slide_: bool, controller_: NodePath) -> void:
|
func register(version: int, slides_: int, animations_: bool, quit_last_slide_: bool, controller_: NodePath) -> void:
|
||||||
|
@ -55,11 +58,13 @@ func register(version: int, slides_: int, animations_: bool, quit_last_slide_: b
|
||||||
if get_node(controller_) == null:
|
if get_node(controller_) == null:
|
||||||
await logger.error("The presentation controller could not be located.")
|
await logger.error("The presentation controller could not be located.")
|
||||||
# Set controller information
|
# Set controller information
|
||||||
|
logger.diag("Setting controller information")
|
||||||
slides = slides_
|
slides = slides_
|
||||||
animations = animations_
|
animations = animations_
|
||||||
quit_last_slide = quit_last_slide_
|
quit_last_slide = quit_last_slide_
|
||||||
controller = get_node(controller_)
|
controller = get_node(controller_)
|
||||||
# Check for essential functions
|
# Check for required functions
|
||||||
|
logger.diag("Check for required functions")
|
||||||
var lacking_functions: Array = []
|
var lacking_functions: Array = []
|
||||||
var check_functions: Array = ["change_slide", "presentation_start", "presentation_end"] ## Base functions
|
var check_functions: Array = ["change_slide", "presentation_start", "presentation_end"] ## Base functions
|
||||||
## "display_end_slide" function
|
## "display_end_slide" function
|
||||||
|
@ -80,19 +85,21 @@ func register(version: int, slides_: int, animations_: bool, quit_last_slide_: b
|
||||||
logger.warn("Consult the documentation or take a look at the example presentation if you need help.")
|
logger.warn("Consult the documentation or take a look at the example presentation if you need help.")
|
||||||
await misc.shutdown(1)
|
await misc.shutdown(1)
|
||||||
# Create presentation viewport
|
# Create presentation viewport
|
||||||
|
logger.diag("Creating presentation viewport")
|
||||||
viewport = Control.new()
|
viewport = Control.new()
|
||||||
viewport.name = "Viewport"
|
viewport.name = "Viewport"
|
||||||
viewport.size = preader.get_ratio_resolution()
|
viewport.size = preader.get_ratio_resolution()
|
||||||
viewport.position = Vector2(0, 0)
|
viewport.position = Vector2(0, 0)
|
||||||
get_node("/root/Presencode").add_child(viewport)
|
get_node("/root/Presencode").add_child(viewport)
|
||||||
# Create clickoverlay
|
# Create clickoverlay
|
||||||
|
logger.diag("Creating clickoverlay")
|
||||||
clickoverlay = Button.new()
|
clickoverlay = Button.new()
|
||||||
clickoverlay.name = "ClickOverlay"
|
clickoverlay.name = "ClickOverlay"
|
||||||
clickoverlay.set_script(ResourceLoader.load("res://src/clickoverlay.gd"))
|
clickoverlay.set_script(ResourceLoader.load("res://src/clickoverlay.gd"))
|
||||||
get_node("/root/Presencode").add_child(clickoverlay)
|
get_node("/root/Presencode").add_child(clickoverlay)
|
||||||
# Did you know that every big galaxy contains a massive black hole in it's center?
|
# Did you know that every big galaxy contains a massive black hole in it's center?
|
||||||
registered = true
|
registered = true
|
||||||
# Invoke presentation_start()
|
# Invoke controller's presentation_start()
|
||||||
controller.presentation_start(viewport)
|
controller.presentation_start(viewport)
|
||||||
|
|
||||||
# Unregister a controller
|
# Unregister a controller
|
||||||
|
@ -101,17 +108,23 @@ func unregister() -> void:
|
||||||
logger.warn("No presentation controller has been registered yet. Please call register() first.")
|
logger.warn("No presentation controller has been registered yet. Please call register() first.")
|
||||||
return
|
return
|
||||||
logger.info("Unregistering presentation controller")
|
logger.info("Unregistering presentation controller")
|
||||||
# Reset to default values
|
while action_running:
|
||||||
|
logger.warn("Waiting for action to finish")
|
||||||
|
await get_tree().create_timer(1).timeout
|
||||||
|
# Reset variables to default values
|
||||||
|
logger.diag("Resetting variables")
|
||||||
registered = false
|
registered = false
|
||||||
current_slide = -1
|
current_slide = -1
|
||||||
animation_active = false
|
animation_active = false
|
||||||
config_allow_fullscreen = true
|
config_allow_fullscreen = true
|
||||||
# Remove clickoverlay
|
# Remove nodes
|
||||||
|
logger.diag("Removing node")
|
||||||
|
## Remove clickoverlay
|
||||||
get_node("/root/Presencode/").remove_child(clickoverlay)
|
get_node("/root/Presencode/").remove_child(clickoverlay)
|
||||||
clickoverlay = null
|
clickoverlay = null
|
||||||
|
## Remove viewport
|
||||||
get_node("/root/Presencode/").remove_child(viewport)
|
get_node("/root/Presencode/").remove_child(viewport)
|
||||||
viewport = null
|
viewport = null
|
||||||
await get_tree().process_frame
|
|
||||||
|
|
||||||
# Change slide
|
# Change slide
|
||||||
func change_slide(slide: int, no_animations: bool = false) -> void:
|
func change_slide(slide: int, no_animations: bool = false) -> void:
|
||||||
|
@ -131,7 +144,7 @@ func change_slide(slide: int, no_animations: bool = false) -> void:
|
||||||
# Quit after last slide?
|
# Quit after last slide?
|
||||||
if quit_last_slide:
|
if quit_last_slide:
|
||||||
logger.info("Ending presentation")
|
logger.info("Ending presentation")
|
||||||
await shutdown()
|
await misc.shutdown(0)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
logger.warn("Over max slides by " + str(slide-slides))
|
logger.warn("Over max slides by " + str(slide-slides))
|
||||||
|
@ -142,33 +155,30 @@ func change_slide(slide: int, no_animations: bool = false) -> void:
|
||||||
return
|
return
|
||||||
else: # End presentation (slide is over max slides by two or more)
|
else: # End presentation (slide is over max slides by two or more)
|
||||||
logger.info("Ending presentation")
|
logger.info("Ending presentation")
|
||||||
await shutdown()
|
await misc.shutdown(0)
|
||||||
return
|
return
|
||||||
# Slide is not over max slides, continue slide change
|
# Slide is not over max slides, continue slide change
|
||||||
|
action_running = true
|
||||||
# Play switch away animation
|
# Play switch away animation
|
||||||
if animations and !no_animations:
|
if animations and !no_animations:
|
||||||
await controller.animation_switch_away(current_slide, slide)
|
await controller.animation_switch_away(current_slide, slide)
|
||||||
# Check if controller has unregistered during animation
|
# Check if controller has unregistered during animation
|
||||||
if !registered:
|
if !registered: logger.error("The current presentation controller has been unregistered during execution")
|
||||||
logger.warn("The current presentation controller has been unregistered during execution, aborting")
|
|
||||||
return
|
|
||||||
# Change slide
|
# Change slide
|
||||||
await controller.change_slide(slide)
|
await controller.change_slide(slide)
|
||||||
# Check if controller has unregistered during animation
|
# Check if controller has unregistered during slide change
|
||||||
if !registered:
|
if !registered: logger.error("The current presentation controller has been unregistered during execution")
|
||||||
logger.warn("The current presentation controller has been unregistered during execution, aborting")
|
|
||||||
return
|
|
||||||
# Set current_slide to new slide
|
# Set current_slide to new slide
|
||||||
current_slide = slide
|
current_slide = slide
|
||||||
# Play switch to animation
|
# Play switch to animation
|
||||||
if animations and !no_animations:
|
if animations and !no_animations: await controller.animation_switch_to(current_slide, slide)
|
||||||
await controller.animation_switch_to(current_slide, slide)
|
|
||||||
|
|
||||||
# Clear the viewport
|
# Clear the viewport
|
||||||
func clear_viewport() -> void:
|
func clear_viewport() -> void:
|
||||||
if !registered:
|
if !registered:
|
||||||
logger.warn("No presentation controller has been registered yet. Please call register() first.")
|
logger.warn("No presentation controller has been registered yet. Please call register() first.")
|
||||||
return
|
return
|
||||||
|
logger.diag("Clearing viewport")
|
||||||
if viewport.get_child_count(true) == 0:
|
if viewport.get_child_count(true) == 0:
|
||||||
logger.warn("No children found in viewport")
|
logger.warn("No children found in viewport")
|
||||||
return
|
return
|
||||||
|
@ -180,6 +190,7 @@ func hide_log() -> void:
|
||||||
if !registered:
|
if !registered:
|
||||||
logger.warn("No presentation controller has been registered yet. Please call register() first.")
|
logger.warn("No presentation controller has been registered yet. Please call register() first.")
|
||||||
return
|
return
|
||||||
|
logger.diag("Hiding log")
|
||||||
get_node("/root/Presencode/Log").modulate = Color8(255, 255, 255, 0)
|
get_node("/root/Presencode/Log").modulate = Color8(255, 255, 255, 0)
|
||||||
|
|
||||||
# Show log output
|
# Show log output
|
||||||
|
@ -187,27 +198,5 @@ func show_log() -> void:
|
||||||
if !registered:
|
if !registered:
|
||||||
logger.warn("No presentation controller has been registered yet. Please call register() first.")
|
logger.warn("No presentation controller has been registered yet. Please call register() first.")
|
||||||
return
|
return
|
||||||
|
logger.diag("Showing log")
|
||||||
get_node("/root/Presencode/Log").modulate = Color8(255, 255, 255, 255)
|
get_node("/root/Presencode/Log").modulate = Color8(255, 255, 255, 255)
|
||||||
|
|
||||||
# Helper function. Shutdown Presencode
|
|
||||||
func shutdown(exitcode: int = 0) -> void:
|
|
||||||
logger.diag("Shutting down Presencode from Presentation Manager")
|
|
||||||
if registered: await controller.presentation_end()
|
|
||||||
await misc.shutdown(exitcode)
|
|
||||||
|
|
||||||
# Runs every frame (duh)
|
|
||||||
func _process(_delta: float) -> void:
|
|
||||||
if !registered: return
|
|
||||||
# Navigation key combos
|
|
||||||
if Input.is_action_pressed("slide_forwards") and Input.is_action_pressed("slide_backwards"): return
|
|
||||||
else:
|
|
||||||
if get_node_or_null("/root/Console") == null or !get_node("/root/Console").visible:
|
|
||||||
if Input.is_action_just_pressed("slide_forwards"):
|
|
||||||
# Increase current_slide by one
|
|
||||||
logger.info("Navigating one slide forwards (key)")
|
|
||||||
change_slide(current_slide+1)
|
|
||||||
elif Input.is_action_just_pressed("slide_backwards"):
|
|
||||||
# Decrease current_slide by one
|
|
||||||
logger.info("Navigating one slide backwards (key)")
|
|
||||||
|
|
||||||
change_slide(current_slide-1)
|
|
||||||
|
|
|
@ -25,7 +25,10 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
# Reading
|
# States
|
||||||
|
var is_open: bool = false
|
||||||
|
|
||||||
|
# Reading support
|
||||||
var directorypath: String = ""
|
var directorypath: String = ""
|
||||||
var ziphandler: ZIPReader = ZIPReader.new()
|
var ziphandler: ZIPReader = ZIPReader.new()
|
||||||
|
|
||||||
|
@ -33,10 +36,7 @@ var ziphandler: ZIPReader = ZIPReader.new()
|
||||||
var manifest: Dictionary = {}
|
var manifest: Dictionary = {}
|
||||||
var entrypoint: Node = null
|
var entrypoint: Node = null
|
||||||
|
|
||||||
# States
|
# Open a presentation archive/directory
|
||||||
var is_open: bool = false
|
|
||||||
|
|
||||||
# Opening a presentation
|
|
||||||
func open_presentation(path: String, zip: bool) -> Error:
|
func open_presentation(path: String, zip: bool) -> Error:
|
||||||
if is_open:
|
if is_open:
|
||||||
logger.warn("Another presentation is still in memory")
|
logger.warn("Another presentation is still in memory")
|
||||||
|
@ -53,7 +53,7 @@ func open_presentation(path: String, zip: bool) -> Error:
|
||||||
is_open = true
|
is_open = true
|
||||||
return Error.OK
|
return Error.OK
|
||||||
|
|
||||||
# Close the currently open presentation
|
# Close opened presentation
|
||||||
func close_presentation() -> Error:
|
func close_presentation() -> Error:
|
||||||
if !is_open:
|
if !is_open:
|
||||||
logger.warn("No presentation is currently opened")
|
logger.warn("No presentation is currently opened")
|
||||||
|
@ -120,14 +120,11 @@ func read_resource(path: String) -> Resource:
|
||||||
file.store_buffer(resource_bytes)
|
file.store_buffer(resource_bytes)
|
||||||
file.close()
|
file.close()
|
||||||
var resource: Resource = null
|
var resource: Resource = null
|
||||||
if path.ends_with(".ttf") or path.ends_with(".otf") or path.ends_with(".woff") or path.ends_with(".woff2"):
|
# Attempt workaround to mitigate loading issues
|
||||||
resource = FontFile.new()
|
resource = _read_resource_workaround(misc.get_temporary_dir() + "/" + str(split_path[split_path.size()-1]))
|
||||||
resource.load_dynamic_font(misc.get_temporary_dir() + "/" + str(split_path[split_path.size()-1]))
|
if resource == null: # Workaround did not work, load resource normally
|
||||||
elif path.ends_with(".png") or path.ends_with(".jpg") or path.ends_with(".svg") or path.ends_with(".ktx") or path.ends_with(".tga") or path.ends_with(".webp"):
|
|
||||||
resource = Image.load_from_file(misc.get_temporary_dir() + "/" + str(split_path[split_path.size()-1]))
|
|
||||||
else:
|
|
||||||
resource = ResourceLoader.load(misc.get_temporary_dir() + "/" + str(split_path[split_path.size()-1]))
|
resource = ResourceLoader.load(misc.get_temporary_dir() + "/" + str(split_path[split_path.size()-1]))
|
||||||
if resource == null:
|
if resource == null: # Resource could not be read
|
||||||
logger.warn("Resource could not be read, resource is null")
|
logger.warn("Resource could not be read, resource is null")
|
||||||
return null
|
return null
|
||||||
return resource
|
return resource
|
||||||
|
@ -135,13 +132,29 @@ func read_resource(path: String) -> Resource:
|
||||||
if !FileAccess.file_exists(directorypath + "/" + path):
|
if !FileAccess.file_exists(directorypath + "/" + path):
|
||||||
logger.error("Requested resource is missing in presentation directory")
|
logger.error("Requested resource is missing in presentation directory")
|
||||||
return null
|
return null
|
||||||
var resource: Resource = ResourceLoader.load(directorypath + "/" + path)
|
var resource: Resource = null
|
||||||
if resource == null:
|
# Attempt workaround to mitigate loading issues
|
||||||
|
resource = _read_resource_workaround(directorypath + "/" + path)
|
||||||
|
if resource == null: # Workaround did not work, load resource normally
|
||||||
|
resource = ResourceLoader.load(directorypath + "/" + path)
|
||||||
|
if resource == null: # Resource could not be read
|
||||||
logger.warn("Resource could not be read, resource is null")
|
logger.warn("Resource could not be read, resource is null")
|
||||||
return null
|
return null
|
||||||
return resource
|
return resource
|
||||||
|
|
||||||
# Read a resource from the presentation archive/directory (unsafe)
|
# Workaround to make loading certain resources possible, even if outside res:// and user://
|
||||||
|
func _read_resource_workaround(path: String) -> Resource:
|
||||||
|
var resource: Resource = null
|
||||||
|
if path.ends_with(".ttf") or path.ends_with(".otf") or path.ends_with(".woff") or path.ends_with(".woff2"):
|
||||||
|
# Font workaround
|
||||||
|
resource = FontFile.new()
|
||||||
|
resource.load_dynamic_font(path)
|
||||||
|
elif path.ends_with(".png") or path.ends_with(".jpg") or path.ends_with(".svg") or path.ends_with(".ktx") or path.ends_with(".tga") or path.ends_with(".webp"):
|
||||||
|
# Image workaround
|
||||||
|
resource = Image.load_from_file(path)
|
||||||
|
return resource
|
||||||
|
|
||||||
|
# Read a resource from the presentation archive/directory (unsafe, without workaround)
|
||||||
func read_resource_unsafe(path: String) -> Resource:
|
func read_resource_unsafe(path: String) -> Resource:
|
||||||
if !is_open:
|
if !is_open:
|
||||||
logger.warn("No presentation is currently opened")
|
logger.warn("No presentation is currently opened")
|
||||||
|
@ -173,7 +186,7 @@ func read_resource_unsafe(path: String) -> Resource:
|
||||||
return null
|
return null
|
||||||
return resource
|
return resource
|
||||||
|
|
||||||
# Check if a file exists in presentation archive/direcoty
|
# Check if file exists in presentation archive/directory
|
||||||
func file_exists(path: String) -> bool:
|
func file_exists(path: String) -> bool:
|
||||||
if !is_open:
|
if !is_open:
|
||||||
logger.warn("No presentation is currently opened")
|
logger.warn("No presentation is currently opened")
|
||||||
|
@ -232,7 +245,7 @@ func get_entrypoint() -> Node:
|
||||||
return null
|
return null
|
||||||
return entrypoint
|
return entrypoint
|
||||||
|
|
||||||
# Return presentation topic
|
# Return the presentation topic
|
||||||
func get_topic() -> String:
|
func get_topic() -> String:
|
||||||
if !is_open:
|
if !is_open:
|
||||||
logger.warn("No presentation is currently opened")
|
logger.warn("No presentation is currently opened")
|
||||||
|
@ -243,7 +256,7 @@ func get_topic() -> String:
|
||||||
return ""
|
return ""
|
||||||
return manifest["topic"]
|
return manifest["topic"]
|
||||||
|
|
||||||
# Return presentation authors
|
# Return the presentation authors
|
||||||
func get_authors() -> String:
|
func get_authors() -> String:
|
||||||
if !is_open:
|
if !is_open:
|
||||||
logger.warn("No presentation is currently opened")
|
logger.warn("No presentation is currently opened")
|
||||||
|
@ -258,7 +271,7 @@ func get_authors() -> String:
|
||||||
else: authors = authors + ", " + author
|
else: authors = authors + ", " + author
|
||||||
return authors
|
return authors
|
||||||
|
|
||||||
# Return display ratio
|
# Return the presentation display ratio
|
||||||
func get_ratio() -> String:
|
func get_ratio() -> String:
|
||||||
if !is_open:
|
if !is_open:
|
||||||
logger.warn("No presentation is currently opened")
|
logger.warn("No presentation is currently opened")
|
||||||
|
@ -269,7 +282,7 @@ func get_ratio() -> String:
|
||||||
return ""
|
return ""
|
||||||
return manifest["ratio"]
|
return manifest["ratio"]
|
||||||
|
|
||||||
# Return display resolution from display ratio
|
# Return the display resolution (derived from display ratio)
|
||||||
func get_ratio_resolution() -> Vector2i:
|
func get_ratio_resolution() -> Vector2i:
|
||||||
if !is_open:
|
if !is_open:
|
||||||
logger.warn("No presentation is currently opened")
|
logger.warn("No presentation is currently opened")
|
||||||
|
|
172
src/processor.gd
Normal file
172
src/processor.gd
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
##############################################################################
|
||||||
|
### PRESENCODE SOURCE FILE ###
|
||||||
|
### Copyright (c) 2024 JeremyStarTM & Contributors ###
|
||||||
|
### Licensed under the GNU General Public License v3 ###
|
||||||
|
### ###
|
||||||
|
### This program is free software: you can redistribute it and/or modify ###
|
||||||
|
### it under the terms of the GNU General Public License as published by ###
|
||||||
|
### the Free Software Foundation, either version 3 of the License, or ###
|
||||||
|
### (at your option) any later version. ###
|
||||||
|
### ###
|
||||||
|
### This program is distributed in the hope that it will be useful, ###
|
||||||
|
### but WITHOUT ANY WARRANTY; without even the implied warranty of ###
|
||||||
|
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ###
|
||||||
|
### GNU General Public License for more details. ###
|
||||||
|
### ###
|
||||||
|
### You should have received a copy of the GNU General Public License ###
|
||||||
|
### along with this program. If not, see <https://www.gnu.org/licenses/>. ###
|
||||||
|
##############################################################################
|
||||||
|
### src/processor.gd (Processor) ###
|
||||||
|
### ###
|
||||||
|
### This source file is solely used for doing things every frame. This ###
|
||||||
|
### includes (for example) input handling, updating sizes, etc.. ###
|
||||||
|
##############################################################################
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
# Enums
|
||||||
|
enum DragNode {
|
||||||
|
CONSOLE
|
||||||
|
}
|
||||||
|
|
||||||
|
# Nodes
|
||||||
|
var nodes: Array[Node] = [null, null]
|
||||||
|
var loader: Node = null
|
||||||
|
var console: Node = null
|
||||||
|
|
||||||
|
# States
|
||||||
|
var initialized: bool = false
|
||||||
|
|
||||||
|
# Initialize processor
|
||||||
|
func initialize() -> void:
|
||||||
|
logger.diag("Initializing processor")
|
||||||
|
loader = get_node("/root/Presencode")
|
||||||
|
console = get_node("/root/Console")
|
||||||
|
nodes = [
|
||||||
|
loader,
|
||||||
|
console
|
||||||
|
]
|
||||||
|
initialized = true
|
||||||
|
|
||||||
|
# What did you expect?
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
if !initialized: return
|
||||||
|
move_to_top()
|
||||||
|
handle_keys()
|
||||||
|
change_sizes()
|
||||||
|
update_dragging()
|
||||||
|
|
||||||
|
# Move elements to top
|
||||||
|
func move_to_top() -> void:
|
||||||
|
if !initialized: return
|
||||||
|
var index: int = get_tree().root.get_child_count(true)
|
||||||
|
for node in nodes:
|
||||||
|
get_tree().root.move_child(node, index)
|
||||||
|
index = index-1
|
||||||
|
|
||||||
|
# Handles key inputs
|
||||||
|
func handle_keys() -> void:
|
||||||
|
if !initialized: return
|
||||||
|
# Global
|
||||||
|
## Scaling method
|
||||||
|
if Input.is_action_just_pressed("content_scale_switch"):
|
||||||
|
match(get_tree().root.content_scale_stretch):
|
||||||
|
Window.CONTENT_SCALE_STRETCH_FRACTIONAL: # Current scaling mode is integer scaling
|
||||||
|
logger.info("Switched to integer scaling")
|
||||||
|
get_tree().root.content_scale_stretch = Window.CONTENT_SCALE_STRETCH_INTEGER
|
||||||
|
Window.CONTENT_SCALE_STRETCH_INTEGER: # Current scaling mode is fractional scaling
|
||||||
|
logger.info("Switched to fractional scaling")
|
||||||
|
get_tree().root.content_scale_stretch = Window.CONTENT_SCALE_STRETCH_FRACTIONAL
|
||||||
|
_: # Invalid value
|
||||||
|
logger.error("Invalid content_scale_stretch value")
|
||||||
|
# Presentation Manager
|
||||||
|
## Fullscreen
|
||||||
|
if pmana.config_allow_fullscreen and Input.is_action_just_pressed("fullscreen"):
|
||||||
|
if DisplayServer.window_get_mode() == DisplayServer.WINDOW_MODE_WINDOWED: # Window is windowed, set to fullscreen mode
|
||||||
|
logger.info("Switched to fullscreen mode")
|
||||||
|
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
|
||||||
|
else: # Window is in fullscreen (or something else) mode, set to windowed mode
|
||||||
|
logger.info("Switched to windowed mode")
|
||||||
|
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
|
||||||
|
## Navigation
|
||||||
|
if pmana.registered and Input.is_action_pressed("slide_forwards") and Input.is_action_pressed("slide_backwards"): return
|
||||||
|
else:
|
||||||
|
if get_node_or_null("/root/Console") == null or !get_node("/root/Console").visible:
|
||||||
|
if Input.is_action_just_pressed("slide_forwards"): # Increase current_slide by one
|
||||||
|
logger.info("Navigated one slide forwards")
|
||||||
|
pmana.change_slide(pmana.current_slide+1)
|
||||||
|
elif Input.is_action_just_pressed("slide_backwards"): # Decrease current_slide by one
|
||||||
|
logger.info("Navigated one slide backwards")
|
||||||
|
pmana.change_slide(pmana.current_slide-1)
|
||||||
|
# Console
|
||||||
|
## Visibility toggle
|
||||||
|
if Input.is_action_just_pressed("console"): console.toggle_console()
|
||||||
|
# UI Engine
|
||||||
|
## Switch resolution
|
||||||
|
if ui_engine.initialized and Input.is_action_just_pressed("editor_switchres"):
|
||||||
|
match(ui_engine.resolution):
|
||||||
|
"960x540": ui_engine.update_resolution(Vector2i(1920, 1080))
|
||||||
|
"1920x1080": ui_engine.update_resolution(Vector2i(2560, 1440))
|
||||||
|
"2560x1440": ui_engine.update_resolution(Vector2i(3840, 2160))
|
||||||
|
"3840x2160": ui_engine.update_resolution(Vector2i(960, 540))
|
||||||
|
|
||||||
|
# Change sizes
|
||||||
|
func change_sizes() -> void:
|
||||||
|
if !initialized: return
|
||||||
|
# Loader
|
||||||
|
loader.size = DisplayServer.window_get_size()
|
||||||
|
if typeof(loader.logrtl) == TYPE_OBJECT:
|
||||||
|
loader.logrtl.size = DisplayServer.window_get_size()
|
||||||
|
# ClickOverlay
|
||||||
|
if get_node_or_null("/root/Presencode/ClickOverlay") != null: get_node("/root/Presencode/ClickOverlay").size = DisplayServer.window_get_size()
|
||||||
|
|
||||||
|
# Makes dragging windows possible
|
||||||
|
func update_dragging() -> void:
|
||||||
|
if !initialized: return
|
||||||
|
# Console
|
||||||
|
if console.dragging:
|
||||||
|
# Get new cursor position
|
||||||
|
var cursor_position = get_tree().root.get_viewport().get_mouse_position()
|
||||||
|
if console.cursor_origin != cursor_position: # If mouse didn't move, don't execute further
|
||||||
|
# Calculate cursor offset
|
||||||
|
var cursor_offset: Vector2 = Vector2(0, 0)
|
||||||
|
cursor_offset.x = console.cursor_origin.x-cursor_position.x
|
||||||
|
cursor_offset.y = console.cursor_origin.y-cursor_position.y
|
||||||
|
# Change console position
|
||||||
|
console.position.x = console.position.x-cursor_offset.x
|
||||||
|
console.position.y = console.position.y-cursor_offset.y
|
||||||
|
# Set new console.cursor_origin
|
||||||
|
console.cursor_origin = cursor_position
|
||||||
|
# Prevent console from going out of scope
|
||||||
|
var position_new: Vector2 = await check_dragging_area_violation(DragNode.CONSOLE)
|
||||||
|
if console.position != position_new:
|
||||||
|
console.position = position_new
|
||||||
|
|
||||||
|
# Calculate drag area
|
||||||
|
func update_dragging_area(dragnode: DragNode, area: Vector2i = DisplayServer.window_get_size()) -> void:
|
||||||
|
while !initialized:
|
||||||
|
logger.diag("Waiting for Processor to initialize")
|
||||||
|
await get_tree().create_timer(0.25).timeout
|
||||||
|
match(dragnode):
|
||||||
|
DragNode.CONSOLE:
|
||||||
|
logger.diag("Updating drag area for CONSOLE")
|
||||||
|
console.drag_area.x = area.x-console.size.x
|
||||||
|
console.drag_area.y = area.y-console.size.y
|
||||||
|
_: await logger.error("Invalid DragNode \"" + str(dragnode) + "\"")
|
||||||
|
|
||||||
|
# Check against drag area violations
|
||||||
|
func check_dragging_area_violation(dragnode: DragNode) -> Vector2:
|
||||||
|
if !initialized: await logger.error("Processor is not initialized yet.")
|
||||||
|
var new_position: Vector2 = Vector2(0, 0)
|
||||||
|
match(dragnode):
|
||||||
|
DragNode.CONSOLE:
|
||||||
|
new_position = console.position
|
||||||
|
if console.position.x <= 0:
|
||||||
|
new_position.x = 0
|
||||||
|
elif console.position.x >= console.drag_area.x:
|
||||||
|
new_position.x = console.drag_area.x
|
||||||
|
if console.position.y <= 0:
|
||||||
|
new_position.y = 0
|
||||||
|
elif console.position.y >= console.drag_area.y:
|
||||||
|
new_position.y = console.drag_area.y
|
||||||
|
_: await logger.error("Invalid DragNode \"" + str(dragnode) + "\"")
|
||||||
|
return new_position
|
|
@ -1,3 +1,25 @@
|
||||||
|
##############################################################################
|
||||||
|
### PRESENCODE SOURCE FILE ###
|
||||||
|
### Copyright (c) 2024 JeremyStarTM & Contributors ###
|
||||||
|
### Licensed under the GNU General Public License v3 ###
|
||||||
|
### ###
|
||||||
|
### This program is free software: you can redistribute it and/or modify ###
|
||||||
|
### it under the terms of the GNU General Public License as published by ###
|
||||||
|
### the Free Software Foundation, either version 3 of the License, or ###
|
||||||
|
### (at your option) any later version. ###
|
||||||
|
### ###
|
||||||
|
### This program is distributed in the hope that it will be useful, ###
|
||||||
|
### but WITHOUT ANY WARRANTY; without even the implied warranty of ###
|
||||||
|
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ###
|
||||||
|
### GNU General Public License for more details. ###
|
||||||
|
### ###
|
||||||
|
### You should have received a copy of the GNU General Public License ###
|
||||||
|
### along with this program. If not, see <https://www.gnu.org/licenses/>. ###
|
||||||
|
##############################################################################
|
||||||
|
### src/ui/welcome.gd (Welcome UI) ###
|
||||||
|
### ###
|
||||||
|
### This source file controls the welcome user interface scene. ###
|
||||||
|
##############################################################################
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
func switch_mode() -> void:
|
func switch_mode() -> void:
|
||||||
|
@ -43,10 +65,12 @@ func update_resolution(new_resolution: Vector2i) -> void:
|
||||||
base.get_node("Icon").position = Vector2(base.size.x/2-base.get_node("Icon").size.x/2, base.size.y*0.05)
|
base.get_node("Icon").position = Vector2(base.size.x/2-base.get_node("Icon").size.x/2, base.size.y*0.05)
|
||||||
base.get_node("Splash").size = Vector2(new_resolution.x/1.5, new_resolution.y/15.88235294117647)
|
base.get_node("Splash").size = Vector2(new_resolution.x/1.5, new_resolution.y/15.88235294117647)
|
||||||
base.get_node("Splash").position = Vector2(base.size.x/2-base.get_node("Splash").size.x/2, base.get_node("Icon").position.y+11*(new_resolution.y/49.09090909090909))
|
base.get_node("Splash").position = Vector2(base.size.x/2-base.get_node("Splash").size.x/2, base.get_node("Icon").position.y+11*(new_resolution.y/49.09090909090909))
|
||||||
base.get_node("OpenButton").size = Vector2(new_resolution.x/4.403669724770642, new_resolution.y/14.21052631578947)
|
base.get_node("OpenArchiveButton").size = Vector2(new_resolution.x/4.403669724770642, new_resolution.y/14.21052631578947)
|
||||||
base.get_node("OpenButton").position = Vector2(base.size.x/16, base.size.y/2.410714285714286)
|
base.get_node("OpenArchiveButton").position = Vector2(base.size.x/16, base.size.y/2.410714285714286)
|
||||||
|
base.get_node("OpenDirButton").size = Vector2(new_resolution.x/4.403669724770642, new_resolution.y/14.21052631578947)
|
||||||
|
base.get_node("OpenDirButton").position = Vector2(base.size.x/16, base.get_node("OpenArchiveButton").position.y+base.get_node("OpenArchiveButton").size.y+base.size.y/108)
|
||||||
base.get_node("EditorButton").size = Vector2(new_resolution.x/4.403669724770642, new_resolution.y/14.21052631578947)
|
base.get_node("EditorButton").size = Vector2(new_resolution.x/4.403669724770642, new_resolution.y/14.21052631578947)
|
||||||
base.get_node("EditorButton").position = Vector2(base.size.x-base.get_node("OpenButton").position.x-base.get_node("EditorButton").size.x, base.size.y/2.410714285714286)
|
base.get_node("EditorButton").position = Vector2(base.size.x-base.get_node("OpenArchiveButton").position.x-base.get_node("EditorButton").size.x, base.size.y/2.410714285714286)
|
||||||
base.get_node("AboutText").size = Vector2(new_resolution.x/1.5, new_resolution.y/7.5)
|
base.get_node("AboutText").size = Vector2(new_resolution.x/1.5, new_resolution.y/7.5)
|
||||||
base.get_node("AboutText").position = Vector2(base.size.x/2-base.get_node("AboutText").size.x/2, base.size.y-base.size.y/54-base.size.y/7.5)
|
base.get_node("AboutText").position = Vector2(base.size.x/2-base.get_node("AboutText").size.x/2, base.size.y-base.size.y/54-base.size.y/7.5)
|
||||||
|
|
||||||
|
@ -60,7 +84,7 @@ func get_stylebox_blur(resolution_: Vector2i) -> StyleBoxFlat:
|
||||||
stylebox.corner_radius_bottom_right = resolution_.x/30
|
stylebox.corner_radius_bottom_right = resolution_.x/30
|
||||||
return stylebox
|
return stylebox
|
||||||
|
|
||||||
func open_presentation_picker() -> void:
|
func open_presentation_archive_picker() -> void:
|
||||||
logger.info("Opening presentation")
|
logger.info("Opening presentation")
|
||||||
var fd: FileDialog = FileDialog.new()
|
var fd: FileDialog = FileDialog.new()
|
||||||
fd.access = FileDialog.ACCESS_FILESYSTEM
|
fd.access = FileDialog.ACCESS_FILESYSTEM
|
||||||
|
@ -70,12 +94,28 @@ func open_presentation_picker() -> void:
|
||||||
fd.add_filter("*.zip", "")
|
fd.add_filter("*.zip", "")
|
||||||
fd.mode_overrides_title = false
|
fd.mode_overrides_title = false
|
||||||
fd.show_hidden_files = true
|
fd.show_hidden_files = true
|
||||||
fd.title = "Open a Presencode presentation file"
|
fd.title = "Open a Presencode presentation archive"
|
||||||
fd.use_native_dialog = true
|
fd.use_native_dialog = true
|
||||||
fd.cancel_button_text = "Cancel"
|
fd.cancel_button_text = "Cancel"
|
||||||
fd.ok_button_text = "Present"
|
fd.ok_button_text = "Present"
|
||||||
fd.visible = true
|
fd.visible = true
|
||||||
fd.connect("file_selected", func(path: String): open_presentation(path))
|
fd.connect("file_selected", func(path: String) -> void: open_presentation(path))
|
||||||
|
add_child(fd)
|
||||||
|
|
||||||
|
func open_presentation_dir_picker() -> void:
|
||||||
|
logger.info("Opening presentation")
|
||||||
|
var fd: FileDialog = FileDialog.new()
|
||||||
|
fd.access = FileDialog.ACCESS_FILESYSTEM
|
||||||
|
fd.current_path = "user://"
|
||||||
|
fd.file_mode = FileDialog.FILE_MODE_OPEN_DIR
|
||||||
|
fd.mode_overrides_title = false
|
||||||
|
fd.show_hidden_files = true
|
||||||
|
fd.title = "Open a Presencode presentation directory"
|
||||||
|
fd.use_native_dialog = true
|
||||||
|
fd.cancel_button_text = "Cancel"
|
||||||
|
fd.ok_button_text = "Present"
|
||||||
|
fd.visible = true
|
||||||
|
fd.connect("dir_selected", func(path: String) -> void: open_presentation(path))
|
||||||
add_child(fd)
|
add_child(fd)
|
||||||
|
|
||||||
func open_presentation(path: String) -> void:
|
func open_presentation(path: String) -> void:
|
||||||
|
@ -91,12 +131,11 @@ func open_presentation(path: String) -> void:
|
||||||
preader.read_manifest()
|
preader.read_manifest()
|
||||||
preader.read_entrypoint()
|
preader.read_entrypoint()
|
||||||
# Update window properties
|
# Update window properties
|
||||||
get_node("/root/Console").calculate_drag_area(preader.get_ratio_resolution())
|
processor.update_dragging_area(processor.DragNode.CONSOLE, preader.get_ratio_resolution())
|
||||||
DisplayServer.window_set_title("Presencode » Presenting \"" + preader.get_topic() + "\" by \"" + preader.get_authors() + "\"")
|
DisplayServer.window_set_title("Presencode » Presenting \"" + preader.get_topic() + "\" by \"" + preader.get_authors() + "\"")
|
||||||
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
|
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
|
||||||
DisplayServer.window_set_size(preader.get_ratio_resolution())
|
DisplayServer.window_set_size(preader.get_ratio_resolution())
|
||||||
DisplayServer.window_set_min_size(preader.get_ratio_resolution())
|
DisplayServer.window_set_min_size(preader.get_ratio_resolution())
|
||||||
if get_node("/root/Presencode").config_window_size_support: get_node("/root/Presencode/WindowSizeSupport/EndPixel").position = Vector2(preader.get_ratio_resolution().x-1, preader.get_ratio_resolution().y-1)
|
|
||||||
get_tree().root.content_scale_size = preader.get_ratio_resolution()
|
get_tree().root.content_scale_size = preader.get_ratio_resolution()
|
||||||
get_tree().root.content_scale_mode = Window.CONTENT_SCALE_MODE_VIEWPORT
|
get_tree().root.content_scale_mode = Window.CONTENT_SCALE_MODE_VIEWPORT
|
||||||
get_tree().root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_KEEP
|
get_tree().root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_KEEP
|
||||||
|
@ -109,12 +148,17 @@ func open_presentation(path: String) -> void:
|
||||||
ui_engine.uninitialize()
|
ui_engine.uninitialize()
|
||||||
|
|
||||||
func update_splash() -> void:
|
func update_splash() -> void:
|
||||||
logger.diag("Updating splash text")
|
var splash: String = ""
|
||||||
get_node("Wallpaper/Welcome/Splash").text = "[center]" + [
|
var splash_ok: bool = false
|
||||||
|
while !splash_ok:
|
||||||
|
splash = [
|
||||||
"The first native code-based presentation viewer.", # Tagline
|
"The first native code-based presentation viewer.", # Tagline
|
||||||
"Presenting your presentations since 2023!", # Inspired by LulzSec's "Laughing at your security since 2011!"
|
"Presenting your presentations since 2023!", # Inspired by LulzSec's "Laughing at your security since 2011!"
|
||||||
"Made using Godot", # FACT
|
"Made using Godot", # FACT
|
||||||
"nice", # nice :)
|
"100% open source", # FACT
|
||||||
|
"'s icons were made with figlet", # FACT
|
||||||
|
"This text was inspired by Minecraft", # It is!
|
||||||
|
"nice", # nice
|
||||||
"[b]your mom[/b]", # idk why i put this in
|
"[b]your mom[/b]", # idk why i put this in
|
||||||
"Also try LibreOffice!", # Inspired by Minecraft's "Also play Terraria" and Terraria's "Also play Minecraft"
|
"Also try LibreOffice!", # Inspired by Minecraft's "Also play Terraria" and Terraria's "Also play Minecraft"
|
||||||
"... exists.", # We finished the sentence.
|
"... exists.", # We finished the sentence.
|
||||||
|
@ -129,11 +173,13 @@ func update_splash() -> void:
|
||||||
"Extra spicy!", # Where did I leave my chilli?
|
"Extra spicy!", # Where did I leave my chilli?
|
||||||
"--- Debugging process stopped ---", # Godot message after stopping a debug build
|
"--- Debugging process stopped ---", # Godot message after stopping a debug build
|
||||||
"/effect @s 16 99999 255 true", # Infinite (or rather, veeeery long) night vision command for Minecraft 1.12.2
|
"/effect @s 16 99999 255 true", # Infinite (or rather, veeeery long) night vision command for Minecraft 1.12.2
|
||||||
"This text was inspired by Minecraft", # It is!
|
|
||||||
"In this update we made the app much better for you.", # Parody of mobile game/application developers simply putting "We made the app better for you" into their changelog without mentioning any of the changes they've made.
|
"In this update we made the app much better for you.", # Parody of mobile game/application developers simply putting "We made the app better for you" into their changelog without mentioning any of the changes they've made.
|
||||||
"NVIDIA fuck you", # Reference to Linus Torvalds
|
"NVIDIA fuck you", # Reference to Linus Torvalds
|
||||||
"100% open source", # FACT
|
|
||||||
"is made by idiots.", # if you're working on Presencode or using it you're probably not the smartest person on earth
|
"is made by idiots.", # if you're working on Presencode or using it you're probably not the smartest person on earth
|
||||||
"'s icons were made with figlet", # FACT
|
"https://billgates.sex is real", # Reference to MattKC
|
||||||
"https://billgates.sex is real" # Reference to MattKC
|
"happy :)", # happy :)
|
||||||
].pick_random() + "[/center]"
|
"E" # E
|
||||||
|
].pick_random()
|
||||||
|
if splash == get_node("Wallpaper/Welcome/Splash").text.replace("[center]", "").replace("[/center]", ""): logger.warn("Got same splash text, picking another one")
|
||||||
|
else: splash_ok = true
|
||||||
|
get_node("Wallpaper/Welcome/Splash").text = "[center]" + splash + "[/center]"
|
||||||
|
|
|
@ -15,16 +15,22 @@ var initialized: bool = false
|
||||||
var ui_mode: UIMode = UIMode.UNKNOWN
|
var ui_mode: UIMode = UIMode.UNKNOWN
|
||||||
var resolution: String = "960x540"
|
var resolution: String = "960x540"
|
||||||
|
|
||||||
|
# Initialize engine
|
||||||
func initialize(loader_: Control) -> void:
|
func initialize(loader_: Control) -> void:
|
||||||
if initialized:
|
if initialized:
|
||||||
logger.error("The UI Engine been initialized already")
|
logger.error("The UI Engine been initialized already")
|
||||||
return
|
return
|
||||||
logger.info("Initializing UI Engine")
|
logger.info("Initializing UI Engine")
|
||||||
|
# Set variables
|
||||||
loader = loader_
|
loader = loader_
|
||||||
initialized = true
|
initialized = true
|
||||||
|
# Switch mode
|
||||||
logger.diag("Switching to welcome mode")
|
logger.diag("Switching to welcome mode")
|
||||||
switch_mode(UIMode.WELCOME)
|
switch_mode(UIMode.WELCOME)
|
||||||
|
# Update resolution to next best
|
||||||
|
logger.diag("Updating resolution to next best resolution")
|
||||||
update_resolution(misc.get_best_resolution())
|
update_resolution(misc.get_best_resolution())
|
||||||
|
# Update window properties
|
||||||
logger.diag("Updating window properties")
|
logger.diag("Updating window properties")
|
||||||
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
|
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
|
||||||
DisplayServer.window_set_min_size(Vector2i(960, 540))
|
DisplayServer.window_set_min_size(Vector2i(960, 540))
|
||||||
|
@ -32,50 +38,54 @@ func initialize(loader_: Control) -> void:
|
||||||
get_tree().root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_KEEP
|
get_tree().root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_KEEP
|
||||||
get_tree().root.content_scale_factor = 1.0
|
get_tree().root.content_scale_factor = 1.0
|
||||||
|
|
||||||
|
# Uninitialize engine
|
||||||
func uninitialize() -> void:
|
func uninitialize() -> void:
|
||||||
if !initialized:
|
if !initialized:
|
||||||
logger.error("The UI Engine is not initialized.")
|
logger.error("The UI Engine is not initialized.")
|
||||||
return
|
return
|
||||||
logger.info("Uninitializing UI Engine")
|
logger.info("Uninitializing UI Engine")
|
||||||
|
# Reset variables
|
||||||
loader = null
|
loader = null
|
||||||
initialized = false
|
initialized = false
|
||||||
resolution = "960x540"
|
resolution = "960x540"
|
||||||
ui_mode = UIMode.UNKNOWN
|
ui_mode = UIMode.UNKNOWN
|
||||||
logger.info("Unloading UI mode")
|
logger.info("Unloading UI mode")
|
||||||
|
# Unload current UI mode
|
||||||
ui_mode_node.queue_free()
|
ui_mode_node.queue_free()
|
||||||
ui_mode_node = null
|
ui_mode_node = null
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
# Switch UI mode
|
||||||
if !initialized: return
|
|
||||||
if Input.is_action_just_pressed("editor_switchres"):
|
|
||||||
match(resolution):
|
|
||||||
"960x540": update_resolution(Vector2i(1920, 1080))
|
|
||||||
"1920x1080": update_resolution(Vector2i(2560, 1440))
|
|
||||||
"2560x1440": update_resolution(Vector2i(3840, 2160))
|
|
||||||
"3840x2160": update_resolution(Vector2i(960, 540))
|
|
||||||
|
|
||||||
func switch_mode(mode: UIMode) -> void:
|
func switch_mode(mode: UIMode) -> void:
|
||||||
if !initialized:
|
if !initialized:
|
||||||
logger.error("The UI Engine hasn't been initialized yet")
|
logger.error("The UI Engine hasn't been initialized yet")
|
||||||
return
|
return
|
||||||
if mode == UIMode.UNKNOWN: return
|
if mode == UIMode.UNKNOWN: await logger.error("Invalid UI mode \"" + str(mode) + "\"")
|
||||||
logger.info("Switching to mode " + str(mode))
|
logger.info("Switching to mode " + str(mode))
|
||||||
|
# Remove current UI mode node
|
||||||
if ui_mode_node != null: loader.remove_child(ui_mode_node)
|
if ui_mode_node != null: loader.remove_child(ui_mode_node)
|
||||||
|
# Load UI node into ui_mode_node and set ui_mode
|
||||||
match(mode):
|
match(mode):
|
||||||
UIMode.WELCOME:
|
UIMode.WELCOME:
|
||||||
ui_mode_node = ResourceLoader.load("res://ui/Welcome.tscn").instantiate()
|
ui_mode_node = ResourceLoader.load("res://ui/Welcome.tscn").instantiate()
|
||||||
ui_mode = UIMode.WELCOME
|
ui_mode = UIMode.WELCOME
|
||||||
|
# Add UI mode node to Loader
|
||||||
loader.add_child(ui_mode_node)
|
loader.add_child(ui_mode_node)
|
||||||
|
# UI mode node's switch_mode() takes over
|
||||||
ui_mode_node.switch_mode()
|
ui_mode_node.switch_mode()
|
||||||
|
|
||||||
|
# Updates the resolution
|
||||||
func update_resolution(new_resolution: Vector2i) -> void:
|
func update_resolution(new_resolution: Vector2i) -> void:
|
||||||
if !initialized:
|
if !initialized:
|
||||||
logger.error("The UI Engine hasn't been initialized yet")
|
logger.error("The UI Engine hasn't been initialized yet")
|
||||||
return
|
return
|
||||||
|
# Update window properties
|
||||||
DisplayServer.window_set_size(new_resolution)
|
DisplayServer.window_set_size(new_resolution)
|
||||||
get_tree().root.content_scale_size = new_resolution
|
get_tree().root.content_scale_size = new_resolution
|
||||||
if get_node_or_null("/root/Console") != null: get_node("/root/Console").calculate_drag_area(new_resolution)
|
# Calculate new console drag area
|
||||||
|
processor.update_dragging_area(processor.DragNode.CONSOLE)
|
||||||
|
# Update resolution variable
|
||||||
resolution = str(new_resolution.x) + "x" + str(new_resolution.y)
|
resolution = str(new_resolution.x) + "x" + str(new_resolution.y)
|
||||||
|
# Call current UI mode's update_resolution() function
|
||||||
match(ui_mode):
|
match(ui_mode):
|
||||||
UIMode.UNKNOWN: return
|
UIMode.UNKNOWN: return
|
||||||
UIMode.WELCOME: ui_mode_node.update_resolution(new_resolution)
|
UIMode.WELCOME: ui_mode_node.update_resolution(new_resolution)
|
||||||
|
|
|
@ -94,7 +94,7 @@ Licensed under the [b]GNU General Public License version 3[/b].
|
||||||
Thank you for using Presencode <3[/center]"
|
Thank you for using Presencode <3[/center]"
|
||||||
scroll_active = false
|
scroll_active = false
|
||||||
|
|
||||||
[node name="OpenButton" type="Button" parent="Wallpaper/Welcome" groups=["font_one", "font_one_normal"]]
|
[node name="OpenArchiveButton" type="Button" parent="Wallpaper/Welcome" groups=["font_one", "font_one_normal"]]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 4
|
anchors_preset = 4
|
||||||
anchor_top = 0.5
|
anchor_top = 0.5
|
||||||
|
@ -104,7 +104,19 @@ offset_top = -19.0
|
||||||
offset_right = 278.0
|
offset_right = 278.0
|
||||||
offset_bottom = 19.0
|
offset_bottom = 19.0
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
text = "Open presentation"
|
text = "Open archive"
|
||||||
|
|
||||||
|
[node name="OpenDirButton" type="Button" parent="Wallpaper/Welcome" groups=["font_one", "font_one_normal"]]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 4
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = 60.0
|
||||||
|
offset_top = 24.0
|
||||||
|
offset_right = 278.0
|
||||||
|
offset_bottom = 62.0
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "Open directory"
|
||||||
|
|
||||||
[node name="EditorButton" type="Button" parent="Wallpaper/Welcome" groups=["font_one", "font_one_normal"]]
|
[node name="EditorButton" type="Button" parent="Wallpaper/Welcome" groups=["font_one", "font_one_normal"]]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
|
@ -122,4 +134,5 @@ grow_vertical = 2
|
||||||
text = "Edit presentation"
|
text = "Edit presentation"
|
||||||
|
|
||||||
[connection signal="pressed" from="Wallpaper/Welcome" to="." method="update_splash"]
|
[connection signal="pressed" from="Wallpaper/Welcome" to="." method="update_splash"]
|
||||||
[connection signal="pressed" from="Wallpaper/Welcome/OpenButton" to="." method="open_presentation_picker"]
|
[connection signal="pressed" from="Wallpaper/Welcome/OpenArchiveButton" to="." method="open_presentation_archive_picker"]
|
||||||
|
[connection signal="pressed" from="Wallpaper/Welcome/OpenDirButton" to="." method="open_presentation_dir_picker"]
|
||||||
|
|
Loading…
Reference in a new issue