1
0
forked from joey/godottest

gpu go brrrrrrrr

This commit is contained in:
Joey Eamigh 2025-10-11 01:09:46 -04:00
parent 4510f97126
commit 9732bf52ff
No known key found for this signature in database
GPG Key ID: CE8C05DFFC53C9CB
302 changed files with 11128 additions and 276 deletions

View File

@ -11,5 +11,6 @@
"color": "default"
}
],
"VsCodeTaskButtons.showCounter": false
"VsCodeTaskButtons.showCounter": false,
"rust-analyzer.checkOnSave": true
}

5
Justfile Normal file
View File

@ -0,0 +1,5 @@
test:
RUST_BACKTRACE=1 godot --path godot res://tests/test_runner.tscn -- --quiet-run
bench:
RUST_BACKTRACE=1 godot --path godot res://tests/test_runner.tscn -- --bench

View File

@ -1,3 +1,9 @@
# godottest
messing around with godot and rust
## run tests
```sh
RUST_BACKTRACE=1 godot --path godot res://tests/test_runner.tscn -- --quiet-run
```

View File

@ -1,6 +1,7 @@
[configuration]
entry_symbol = "gdext_rust_init"
compatibility_minimum = 4.1
reloadable = true
[libraries]
"android.debug" = "res://../rust/target/debug/godottest_rs.so"
@ -65,6 +66,6 @@ compatibility_minimum = 4.1
"windows.editor.x86_64" = "res://../rust/target/x86_64-pc-windows-msvc/debug/godottest_rs.dll"
[icons]
AsyncRuntime = "res://addons/rust/NodeRustFerris.svg"
Player = "res://addons/rust/NodeRustFerris.svg"
Mappy = "res://addons/rust/NodeRustFerris.svg"
Player = "res://addons/rust/NodeRustFerris.svg"
AsyncRuntime = "res://addons/rust/NodeRustFerris.svg"

View File

@ -1 +1 @@
uid://dx7md3kauujl
uid://yljs7ohq1dqw

View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2023 Feo (k2kra) Wu
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1 @@
This repository is a mirror that tracks the latest version of [PankuConsole](https://github.com/Ark2000/PankuConsole), so you can add it as a submodule in you addons folder.

View File

@ -0,0 +1,35 @@
extends VBoxContainer
# it is like, an infinite scroll game.
# specifically, the first buffer will be cleared and sent to the last
# when the last buffer is full.
# with buffers, we can constanly output lots of fancy stuff while keeping a smooth experience.
const BUFFER_MAX_PARAGRAPHS = 64
const BUFFERS = 4
var cur_label_idx:int = 0
func add_text(text:String):
var cur_label:RichTextLabel = get_child(cur_label_idx)
cur_label.text += text
if cur_label.get_paragraph_count() > BUFFER_MAX_PARAGRAPHS:
cur_label_idx += 1
if cur_label_idx == BUFFERS:
cur_label_idx = BUFFERS - 1
var first_label:RichTextLabel = get_child(0)
first_label.text = ""
move_child(first_label, BUFFERS - 1)
func _ready():
set("theme_override_constants/separation", 0)
for child in get_children():
child.queue_free()
for i in range(BUFFERS):
var new_buffer:RichTextLabel = RichTextLabel.new()
new_buffer.fit_content = true
new_buffer.bbcode_enabled = true
new_buffer.selection_enabled = true
add_child(new_buffer)

View File

@ -0,0 +1 @@
uid://hxsdaekjx5k0

View File

@ -0,0 +1,126 @@
class_name PankuConfig
const CONFIG_SECTION = "panku"
const OPTIONS = {
# See https://github.com/Ark2000/PankuConsole/issues/170
DISABLE_ON_RELEASE = 'disable_on_release',
# See https://github.com/Ark2000/PankuConsole/issues/173
CUSTOM_DEFAULT_CONFIG = 'custom_default_config',
}
const INITIAL_DEFAULT_CONFIG_FILE_PATH = "res://addons/panku_console/default_panku_config.cfg"
const USER_CONFIG_FILE_PATH = "user://panku_config.cfg"
# Full option name in project settings.
static func panku_option(option: String) -> String:
return CONFIG_SECTION + "/" + option
# A helper function to add custom project settings
# See https://dfaction.net/handling-custom-project-settings-using-gdscript/
static func add_custom_project_setting(
name: String,
default_value,
type: int,
hint: int = PROPERTY_HINT_NONE, hint_string: String = ""
) -> void:
if ProjectSettings.has_setting(name): return
var setting_info: Dictionary = {
"name": name,
"type": type,
"hint": hint,
"hint_string": hint_string
}
ProjectSettings.set_setting(name, default_value)
ProjectSettings.add_property_info(setting_info)
ProjectSettings.set_initial_value(name, default_value)
ProjectSettings.set_as_basic(name, true)
static func init_all_project_settings() -> void:
# Seems we can't add descriptions to custom settings now.
# Disable Panku Console in release builds
add_custom_project_setting(
panku_option(OPTIONS.DISABLE_ON_RELEASE),
false,
TYPE_BOOL
)
# Path to the custom
# `res://` path default config file, useful if you are going to keep panku console in release builds.
add_custom_project_setting(
panku_option(OPTIONS.CUSTOM_DEFAULT_CONFIG),
INITIAL_DEFAULT_CONFIG_FILE_PATH,
TYPE_STRING,
PROPERTY_HINT_FILE,
"*.cfg"
)
# save_project_settings()
static func clear_all_project_settings() -> void:
for option in OPTIONS.values():
var opt: String = panku_option(option)
if ProjectSettings.has_setting(opt):
ProjectSettings.clear(opt)
save_project_settings()
static func save_project_settings() -> void:
var error: int = ProjectSettings.save()
if error != OK:
push_error("Encountered error %d when saving project settings." % error)
# Get custom config file path from project settings
static func get_custom_default_config_path() -> String:
return ProjectSettings.get_setting(panku_option(OPTIONS.CUSTOM_DEFAULT_CONFIG), INITIAL_DEFAULT_CONFIG_FILE_PATH)
# Check if custom config file from project settings exist
static func is_custom_default_config_exists() -> bool:
return FileAccess.file_exists(get_custom_default_config_path())
# load config from file, always return a dictionary
static func _get_config(file_path:String) -> Dictionary:
if FileAccess.file_exists(file_path):
var file = FileAccess.open(file_path, FileAccess.READ)
var content := file.get_as_text()
var config:Dictionary = str_to_var(content)
if config: return config
return {}
# save user config to file
static func set_config(config:Dictionary):
var file = FileAccess.open(USER_CONFIG_FILE_PATH, FileAccess.WRITE)
var content = var_to_str(config)
file.store_string(content)
# get config, if user config exists, return user config, otherwise return default config configured by plugin user
static func get_config() -> Dictionary:
var user_config:Dictionary = _get_config(USER_CONFIG_FILE_PATH)
if not user_config.is_empty():
return user_config
# if no user config, return default config, which is read-only
if is_custom_default_config_exists():
return _get_config(get_custom_default_config_path())
return _get_config(INITIAL_DEFAULT_CONFIG_FILE_PATH)
static func get_value(key:String, default:Variant) -> Variant:
return get_config().get(key, default)
static func set_value(key:String, val:Variant) -> void:
var config = _get_config(USER_CONFIG_FILE_PATH)
config[key] = val
set_config(config)

View File

@ -0,0 +1 @@
uid://bd0ob776pkvry

View File

@ -0,0 +1,276 @@
class_name PankuGDExprEnv
const type_names = {
TYPE_NIL: "null",
TYPE_BOOL: "bool",
TYPE_INT: "int",
TYPE_FLOAT: "float",
TYPE_STRING: "String",
TYPE_VECTOR2: "Vector2",
TYPE_VECTOR2I: "Vector2i",
TYPE_RECT2: "Rect2",
TYPE_RECT2I: "Rect2i",
TYPE_VECTOR3: "Vector3",
TYPE_VECTOR3I: "Vector3i",
TYPE_TRANSFORM2D: "Transform2D",
TYPE_VECTOR4: "Vector4",
TYPE_VECTOR4I: "Vector4i",
TYPE_PLANE: "Plane",
TYPE_QUATERNION: "Quaternion",
TYPE_AABB: "AABB",
TYPE_BASIS: "Basis",
TYPE_TRANSFORM3D: "Transform3D",
TYPE_PROJECTION: "Projection",
TYPE_COLOR: "Color",
TYPE_STRING_NAME: "StringName",
TYPE_NODE_PATH: "NodePath",
TYPE_RID: "RID",
TYPE_OBJECT: "Object",
TYPE_CALLABLE: "Callable",
TYPE_SIGNAL: "Signal",
TYPE_DICTIONARY: "Dictionary",
TYPE_ARRAY: "Array",
TYPE_PACKED_BYTE_ARRAY: "PackedByteArray",
TYPE_PACKED_INT32_ARRAY: "PackedInt32Array",
TYPE_PACKED_INT64_ARRAY: "PackedInt64Array",
TYPE_PACKED_FLOAT32_ARRAY: "PackedFloat32Array",
TYPE_PACKED_FLOAT64_ARRAY: "PackedFloat64Array",
TYPE_PACKED_STRING_ARRAY: "PackedStringArray",
TYPE_PACKED_VECTOR2_ARRAY: "PackedVector2Array",
TYPE_PACKED_VECTOR3_ARRAY: "PackedVector3Array",
TYPE_PACKED_COLOR_ARRAY: "PackedColorArray",
}
var _envs = {}
var _envs_info = {}
var _expression = Expression.new()
var _base_instance:Object
func set_base_instance(base_instance:Object):
_base_instance = base_instance
#add info of base instance
var env_info = extract_info_from_script(_base_instance.get_script())
for k in env_info: _envs_info[k] = env_info[k]
func get_base_instance():
return _base_instance
## Register an environment that run expressions.
## [br][code]env_name[/code]: the name of the environment
## [br][code]env[/code]: The base instance that runs the expressions. For exmaple your player node.
func register_env(env_name:String, env:Object):
_envs[env_name] = env
# output("[color=green][Info][/color] [b]%s[/b] env loaded!"%env_name)
if env is Node:
env.tree_exiting.connect(
func(): remove_env(env_name)
)
if env.get_script():
var env_info = extract_info_from_script(env.get_script())
for k in env_info:
var keyword = "%s.%s" % [env_name, k]
_envs_info[keyword] = env_info[k]
## Return the environment object or [code]null[/code] by its name.
func get_env(env_name:String) -> Node:
return _envs.get(env_name)
## Remove the environment named [code]env_name[/code]
func remove_env(env_name:String):
if _envs.has(env_name):
_envs.erase(env_name)
for k in _envs_info.keys():
if k.begins_with(env_name + "."):
_envs_info.erase(k)
#Execute an expression in a preset environment.
func execute(exp:String) -> Dictionary:
return execute_exp(exp, _expression, _base_instance, _envs)
# TODO: not used
func get_available_export_objs() -> Array:
var result = []
for obj_name in _envs:
var obj = _envs[obj_name]
if !obj.get_script():
continue
var export_properties = get_export_properties_from_script(obj.get_script())
if export_properties.is_empty():
continue
result.push_back(obj_name)
return result
func get_help_info(k:String) -> String:
return _envs_info[k]["help"]
#TODO: refactor all those mess
func parse_exp(exp:String, allow_empty:=false):
var result:Array
var empty_flag = allow_empty and exp.is_empty()
if empty_flag:
result = _envs_info.keys()
else:
result = search_and_sort_and_highlight(exp, _envs_info.keys())
var hints_bbcode = []
var hints_value = []
for r in result:
var keyword:String
var bbcode_main:String
if empty_flag:
keyword = r
bbcode_main = r
else:
keyword = r["keyword"]
bbcode_main = r["bbcode"]
var bbcode_postfix = _envs_info[keyword]["bbcode_postfix"]
var keyword_type = _envs_info[keyword]["type"]
hints_value.push_back(keyword)
hints_bbcode.push_back(bbcode_main + bbcode_postfix)
return {
"hints_bbcode": hints_bbcode,
"hints_value": hints_value
}
static func search_and_sort_and_highlight(s:String, li:Array):
s = s.lstrip(" ").rstrip(" ")
var matched = []
if s == "": return matched
for k in li:
var start = k.find(s)
if start >= 0:
var similarity = 1.0 * s.length() / k.length()
matched.append({
"keyword": k,
"similarity": similarity,
"start": start,
"bbcode": ""
})
matched.sort_custom(
func(k1, k2):
if k1["start"] != k2["start"]:
return k1["start"] > k2["start"]
else:
return k1["similarity"] < k2["similarity"]
)
var line_format = "%s[color=green][b]%s[/b][/color]%s"
for m in matched:
var p = ["", "", ""]
if m["start"] < 0:
p[0] = m["keyword"]
else:
p[0] = m["keyword"].substr(0, m["start"])
p[1] = s
p[2] = m["keyword"].substr(m["start"] + s.length(), -1)
m["bbcode"] = line_format % p
return matched
static func extract_info_from_script(script:Script):
var result = {}
var methods = []
var properties = []
var constants = []
var constants_bbcode_postfix = {}
for m in script.get_script_method_list():
if m["name"] != "" and m["name"].is_valid_identifier() and !m["name"].begins_with("_"):
var args = []
for a in m["args"]:
args.push_back("[color=cyan]%s[/color][color=gray]:[/color][color=orange]%s[/color]"%[a["name"], type_names[a["type"]]])
result[m["name"]] = {
"type": "method",
"bbcode_postfix": "(%s)"%("[color=gray], [/color]".join(PackedStringArray(args)))
}
for p in script.get_script_property_list():
if p["name"] != "" and !p["name"].begins_with("_") and p["name"].is_valid_identifier():
result[p["name"]] = {
"type": "property",
"bbcode_postfix":"[color=gray]:[/color][color=orange]%s[/color]"%type_names[p["type"]]
}
var constant_map = script.get_script_constant_map()
var help_info = {}
for c in constant_map:
if !c.begins_with("_"):
result[c] = {
"type": "constant",
"bbcode_postfix":"[color=gray]:[/color][color=orange]%s[/color]"%type_names[typeof(constant_map[c])]
}
elif c.begins_with("_HELP_") and c.length() > 6 and typeof(constant_map[c]) == TYPE_STRING:
var key = c.lstrip("_HELP_")
help_info[key] = constant_map[c]
for k in result:
if help_info.has(k):
result[k]["help"] = help_info[k]
else:
result[k]["help"] = "No help information provided."
#keyword -> {type, bbcode_postfix, help}
return result
static func execute_exp(exp_str:String, expression:Expression, base_instance:Object, env:Dictionary):
var failed := false
var result = null
var error = expression.parse(exp_str, env.keys())
if error != OK:
failed = true
result = expression.get_error_text()
else:
result = expression.execute(env.values(), base_instance, true)
if expression.has_execute_failed():
failed = true
result = expression.get_error_text()
return {
"failed": failed,
"result": result
}
static func get_export_properties_from_script(script:Script):
var result = []
var data = script.get_script_property_list()
for d in data:
if !(d.usage == PROPERTY_USAGE_SCRIPT_VARIABLE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE):
continue
result.append(d)
return result
static func generate_help_text_from_script(script:Script):
var result = ["[color=cyan][b]User script defined identifiers[/b][/color]: "]
var env_info = extract_info_from_script(script)
var keys = env_info.keys()
keys.sort()
for k in keys:
result.push_back("%s - [i]%s[/i]"%[k + env_info[k]["bbcode_postfix"], env_info[k]["help"]])
return "\n".join(PackedStringArray(result))
#returns a string containing all public script properties of an object
#please BE AWARE when using this function on an object with custom getters.
static func get_object_outline(obj:Object) -> String:
var result := PackedStringArray()
if obj == null: return "null"
var script = obj.get_script()
if script == null:
return "this object has no script attached."
var properties = script.get_script_property_list()
for p in properties:
if p.usage & PROPERTY_USAGE_SCRIPT_VARIABLE == 0:
continue
if p.name.begins_with("_"):
continue
result.append("%s: %s" % [p.name, str(obj.get(p.name))])
if result.is_empty():
return "this object has no public script variables."
return "\n".join(result)

View File

@ -0,0 +1 @@
uid://xnce2n76k5p6

View File

@ -0,0 +1,9 @@
extends Panel
func hey_i_am_here():
modulate.a = 0.0
var t = create_tween()
t.set_speed_scale(1.0 / Engine.time_scale)
for i in range(2):
t.tween_property(self, "modulate:a", 0.3, 0.1)
t.tween_property(self, "modulate:a", 0.0, 0.1)

View File

@ -0,0 +1 @@
uid://b2oil1la5ccpf

View File

@ -0,0 +1,298 @@
class_name PankuLynxWindow extends ColorRect
#Do not connect the button node directly, use these signals to detect click event.
signal title_btn_clicked
signal window_closed
const lynx_window_shader_material:ShaderMaterial = preload("./lynx_window_shader_material.tres")
const OS_WINDOW_MARKER = "PankuOSWindow"
@export var _window_title_container:HBoxContainer
@export var _title_btn:PankuButton
@export var _close_btn:PankuButton
@export var _options_btn:PankuButton
@export var _resize_btn:Button
@export var _shadow_focus:Panel
@export var _shadow:NinePatchRect
@export var _container:Panel
@export var _pop_btn:PankuButton
@export var no_resize := false
@export var no_resize_x := false
@export var no_resize_y := false
@export var no_move := false
@export var no_snap := false
@export var no_title := false:
set(v):
no_title = v
_window_title_container.visible = !v
@export var queue_free_on_close := true
@export var flicker := true
var transform_interp_speed := 40.0
var bounds_interp_speed := 50.0
var anim_interp_speed := 10.0
var _is_dragging := false
var _drag_start_position:Vector2
var _drag_start_position_global:Vector2
var _is_resizing := false
var _resize_start_position:Vector2
var _os_window:Window
var _content:Control
var _size_before_folded:Vector2
var _folded:bool = false
var _size_animation:bool = false
var _target_size:Vector2
func add_options_button(callback:Callable):
_options_btn.show()
_options_btn.pressed.connect(callback)
func get_layout_position(layout:Control.LayoutPreset) -> Vector2:
var window_rect = get_rect()
var screen_rect = get_viewport_rect()
var new_position = Vector2.ZERO
var end_position = screen_rect.size - window_rect.size
var center_position = end_position / 2
if layout == PRESET_TOP_LEFT:
pass
elif layout == PRESET_CENTER_TOP:
new_position.x = center_position.x
elif layout == PRESET_TOP_RIGHT:
new_position.x = end_position.x
elif layout == PRESET_CENTER_LEFT:
new_position.y = center_position.y
elif layout == PRESET_CENTER:
new_position = center_position
elif layout == PRESET_CENTER_RIGHT:
new_position.x = end_position.x
new_position.y = center_position.y
elif layout == PRESET_BOTTOM_LEFT:
new_position.y = end_position.y
elif layout == PRESET_CENTER_BOTTOM:
new_position.x = center_position.x
new_position.y = end_position.y
elif layout == PRESET_BOTTOM_RIGHT:
new_position = end_position
return new_position
func get_content():
return _content
func set_content(node:Control):
_content = node
if _os_window and _os_window.visible:
if _os_window.get_child_count() > 0:
push_error("Error: error in set_content")
return
_os_window.add_child(node)
return
if _container.get_child_count() > 0:
push_error("Error: error in set_content.")
return
_container.add_child(node)
func highlight(v:bool):
_shadow_focus.visible = v
func _init_os_window():
_os_window = Window.new()
_os_window.set_meta(OS_WINDOW_MARKER, true)
var color_rect = ColorRect.new()
color_rect.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
_os_window.add_child(color_rect)
get_tree().root.add_child(_os_window)
#destructor
tree_exiting.connect(
func():
_os_window.queue_free()
)
#switch back to embed window when os window close requested
_os_window.close_requested.connect(
func():
_os_window.remove_child(_content)
_os_window.hide()
set_content(_content)
show()
)
if get_parent().has_method("get_os_window_bg_color"):
color_rect.color = get_parent().get_os_window_bg_color()
func switch_to_os_window():
if _content == null:
push_error("Error: No content. ")
return
if _os_window == null:
_init_os_window()
_container.remove_child(_content)
_os_window.add_child(_content)
_os_window.size = size
_os_window.title = _title_btn.text
_os_window.position = Vector2(DisplayServer.window_get_position(0)) + position
_content.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
_os_window.show()
hide()
func show_window():
if _os_window and _os_window.visible:
return
show()
move_to_front()
modulate.a = 0.0
create_tween().tween_property(self, "modulate:a", 1.0, 0.2)
func hide_window():
if _os_window and _os_window.visible:
_os_window.close_requested.emit()
hide()
func toggle_window_visibility():
if _os_window.visible or visible:
hide_window()
else:
show_window()
func set_window_visibility(b:bool):
if b: show_window()
else: hide_window()
func get_window_visibility() -> bool:
return visible or _os_window.visible
func set_window_title_text(text:String):
if _os_window and _os_window.visible:
_os_window.title = text
else:
_title_btn.text = " " + text
func get_normal_window_size():
if _folded: return _size_before_folded
return size
func get_title_bar_height():
return _window_title_container.size.y
func _ready():
custom_minimum_size = _window_title_container.get_minimum_size()
_options_btn.visible = false
_title_btn.button_down.connect(
func():
_is_dragging = true
_drag_start_position = get_local_mouse_position()
_drag_start_position_global = get_global_mouse_position()
)
_title_btn.button_up.connect(
func():
_is_dragging = false
)
_resize_btn.button_down.connect(
func():
_is_resizing = true
_resize_start_position = _resize_btn.get_local_mouse_position()
)
_resize_btn.button_up.connect(
func():
_is_resizing = false
)
_close_btn.pressed.connect(
func():
window_closed.emit()
if queue_free_on_close:
queue_free()
else:
hide()
)
_title_btn.button.gui_input.connect(
func(e):
if e is InputEventMouseButton and !e.pressed:
if e.button_index != MOUSE_BUTTON_NONE:
if (get_global_mouse_position() - _drag_start_position_global).length_squared() < 4:
title_btn_clicked.emit()
)
visibility_changed.connect(
func():
if is_visible_in_tree() and flicker:
$Border.hey_i_am_here()
)
if flicker:
$Border.hey_i_am_here()
_pop_btn.pressed.connect(switch_to_os_window)
if _container.get_child_count() > 0:
_content = _container.get_child(0)
if get_parent().has_method("get_enable_os_popup_btns"):
_pop_btn.visible = get_parent().get_enable_os_popup_btns()
# feature: foldable window
title_btn_clicked.connect(
func():
if _folded:
_target_size = _size_before_folded
else:
if !_size_animation:
_size_before_folded = size
_target_size = _window_title_container.size
_size_animation = true
_folded = !_folded
_resize_btn.visible = !_folded
)
func _input(e):
#release focus when you click outside of the window
if is_visible:
if e is InputEventMouseButton and e.pressed:
if !get_global_rect().has_point(get_global_mouse_position()):
var f = get_viewport().gui_get_focus_owner()
if f and is_ancestor_of(f):
f.release_focus()
if e is InputEventKey and e.keycode == KEY_ESCAPE and e.pressed and get_global_rect().has_point(get_global_mouse_position()):
window_closed.emit()
if queue_free_on_close:
queue_free()
else:
hide()
func _process(delta: float) -> void:
if !no_move and _is_dragging:
var tp := position + get_local_mouse_position() - _drag_start_position
position = PankuUtils.interp(position, tp, transform_interp_speed, delta)
elif !no_resize and _is_resizing:
var ts := size + _resize_btn.get_local_mouse_position() - _resize_start_position
ts.x = min(ts.x, get_viewport_rect().size.x)
ts.y = min(ts.y, get_viewport_rect().size.y)
if !no_resize_x:
size.x = PankuUtils.interp(size.x, ts.x, transform_interp_speed, delta)
if !no_resize_y:
size.y = PankuUtils.interp(size.y, ts.y, transform_interp_speed, delta)
elif !no_snap:
var window_rect := get_rect()
var screen_rect := get_viewport_rect()
var target_position := window_rect.position
var target_size := window_rect.size.clamp(Vector2.ZERO, screen_rect.size)
if window_rect.position.y < 0:
target_position.y = 0
if window_rect.end.y > screen_rect.end.y:
target_position.y = screen_rect.end.y - window_rect.size.y
if window_rect.end.y > screen_rect.end.y + window_rect.size.y / 2:
target_position.y = screen_rect.end.y - get_title_bar_height()
if window_rect.position.x < 0:
target_position.x = 0
if window_rect.end.x > screen_rect.end.x:
target_position.x = screen_rect.end.x - window_rect.size.x
var current_position = window_rect.position
current_position = PankuUtils.interp(current_position, target_position, bounds_interp_speed, delta)
size = PankuUtils.interp(size, target_size, bounds_interp_speed, delta)
position = current_position
if _size_animation:
if _target_size.is_equal_approx(size):
_size_animation = false
size = PankuUtils.interp(size, _target_size, anim_interp_speed, delta)

View File

@ -0,0 +1 @@
uid://buw6hpyf4b2an

View File

@ -0,0 +1,204 @@
[gd_scene load_steps=19 format=3 uid="uid://s88loppa6gja"]
[ext_resource type="Material" uid="uid://dyipeqsa8lcpc" path="res://addons/panku_console/common/lynx_window2/lynx_window_shader_material.tres" id="1_tvp6i"]
[ext_resource type="Script" path="res://addons/panku_console/common/lynx_window2/lynx_window_2.gd" id="2_1ul5o"]
[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="2_3fhqk"]
[ext_resource type="Texture2D" uid="uid://dosm26riekruh" path="res://addons/panku_console/res/icons2/menu.svg" id="4_4dlyn"]
[ext_resource type="PackedScene" uid="uid://drn5t13m088fb" path="res://addons/panku_console/common/panku_button.tscn" id="4_dnesi"]
[ext_resource type="Texture2D" uid="uid://gav3m4qtvgje" path="res://addons/panku_console/res/icons2/pop-out-svgrepo-com.svg" id="4_im81u"]
[ext_resource type="Texture2D" uid="uid://8g5afcuanbl6" path="res://addons/panku_console/res/icons2/close.svg" id="5_l4qpm"]
[ext_resource type="Texture2D" uid="uid://dvr12fl5prm78" path="res://addons/panku_console/res/effect/square_shadow.png" id="6_mfp1h"]
[ext_resource type="Texture2D" uid="uid://ciu5jiw4xmkq0" path="res://addons/panku_console/res/icons2/resize-svgrepo-com.svg" id="7_duwqn"]
[ext_resource type="Script" path="res://addons/panku_console/common/lynx_window2/border.gd" id="8_gj3ji"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_hv45g"]
draw_center = false
border_width_left = 1
border_width_top = 1
border_width_right = 1
border_width_bottom = 1
border_color = Color(1, 1, 1, 0.25098)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_6i67d"]
content_margin_left = 8.0
content_margin_top = 8.0
content_margin_right = 8.0
content_margin_bottom = 8.0
draw_center = false
border_width_left = 1
border_width_right = 1
border_width_bottom = 1
border_color = Color(1, 1, 1, 0.25098)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_lct0k"]
draw_center = false
shadow_color = Color(0, 0, 0, 0.0627451)
shadow_size = 16
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_p3y6j"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_r0x7y"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_p7tml"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_5muk4"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_uldta"]
draw_center = false
border_width_left = 4
border_width_top = 4
border_width_right = 4
border_width_bottom = 4
border_color = Color(1, 1, 1, 1)
[node name="LynxWindow2" type="ColorRect" node_paths=PackedStringArray("_window_title_container", "_title_btn", "_close_btn", "_options_btn", "_resize_btn", "_shadow_focus", "_shadow", "_container", "_pop_btn")]
material = ExtResource("1_tvp6i")
offset_right = 413.0
offset_bottom = 305.0
theme = ExtResource("2_3fhqk")
script = ExtResource("2_1ul5o")
_window_title_container = NodePath("MainBody/VBoxContainer/Up")
_title_btn = NodePath("MainBody/VBoxContainer/Up/TitleButton")
_close_btn = NodePath("MainBody/VBoxContainer/Up/CloseButton")
_options_btn = NodePath("MainBody/VBoxContainer/Up/MenuButton")
_resize_btn = NodePath("Button")
_shadow_focus = NodePath("Shadow2")
_shadow = NodePath("Shadow")
_container = NodePath("MainBody/VBoxContainer/Down")
_pop_btn = NodePath("MainBody/VBoxContainer/Up/PopupButton")
[node name="MainBody" type="Control" parent="."]
clip_contents = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="VBoxContainer" type="VBoxContainer" parent="MainBody"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/separation = 0
[node name="Up" type="HBoxContainer" parent="MainBody/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 0
[node name="TitleButton" parent="MainBody/VBoxContainer/Up" instance=ExtResource("4_dnesi")]
layout_mode = 2
size_flags_horizontal = 3
theme_override_styles/panel = SubResource("StyleBoxFlat_hv45g")
[node name="TextureRect" parent="MainBody/VBoxContainer/Up/TitleButton/HBoxContainer" index="0"]
texture = null
[node name="Label" parent="MainBody/VBoxContainer/Up/TitleButton/HBoxContainer" index="1"]
text = "Window Title"
[node name="PopupButton" parent="MainBody/VBoxContainer/Up" instance=ExtResource("4_dnesi")]
layout_mode = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_hv45g")
[node name="TextureRect" parent="MainBody/VBoxContainer/Up/PopupButton/HBoxContainer" index="0"]
texture = ExtResource("4_im81u")
[node name="Label" parent="MainBody/VBoxContainer/Up/PopupButton/HBoxContainer" index="1"]
visible = false
[node name="MenuButton" parent="MainBody/VBoxContainer/Up" instance=ExtResource("4_dnesi")]
layout_mode = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_hv45g")
[node name="TextureRect" parent="MainBody/VBoxContainer/Up/MenuButton/HBoxContainer" index="0"]
texture = ExtResource("4_4dlyn")
[node name="Label" parent="MainBody/VBoxContainer/Up/MenuButton/HBoxContainer" index="1"]
visible = false
[node name="CloseButton" parent="MainBody/VBoxContainer/Up" instance=ExtResource("4_dnesi")]
layout_mode = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_hv45g")
[node name="TextureRect" parent="MainBody/VBoxContainer/Up/CloseButton/HBoxContainer" index="0"]
texture = ExtResource("5_l4qpm")
[node name="Label" parent="MainBody/VBoxContainer/Up/CloseButton/HBoxContainer" index="1"]
visible = false
[node name="Down" type="Panel" parent="MainBody/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
theme_override_styles/panel = SubResource("StyleBoxFlat_6i67d")
[node name="Shadow" type="NinePatchRect" parent="."]
modulate = Color(1, 1, 1, 0.501961)
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -64.0
offset_top = -79.0
offset_right = 63.0
offset_bottom = 47.0
grow_horizontal = 2
grow_vertical = 2
texture = ExtResource("6_mfp1h")
draw_center = false
region_rect = Rect2(0, 0, 512, 512)
patch_margin_left = 64
patch_margin_top = 80
patch_margin_right = 64
patch_margin_bottom = 48
[node name="Shadow2" type="Panel" parent="."]
visible = false
layout_mode = 2
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_lct0k")
[node name="Button" type="Button" parent="."]
self_modulate = Color(1, 1, 1, 0.501961)
layout_mode = 1
anchors_preset = 3
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -12.0
offset_top = -12.0
grow_horizontal = 0
grow_vertical = 0
mouse_default_cursor_shape = 12
theme_override_styles/focus = SubResource("StyleBoxEmpty_p3y6j")
theme_override_styles/hover = SubResource("StyleBoxEmpty_r0x7y")
theme_override_styles/pressed = SubResource("StyleBoxEmpty_p7tml")
theme_override_styles/normal = SubResource("StyleBoxEmpty_5muk4")
icon = ExtResource("7_duwqn")
flat = true
expand_icon = true
[node name="Border" type="Panel" parent="."]
modulate = Color(1, 1, 1, 0)
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_uldta")
script = ExtResource("8_gj3ji")
[editable path="MainBody/VBoxContainer/Up/TitleButton"]
[editable path="MainBody/VBoxContainer/Up/PopupButton"]
[editable path="MainBody/VBoxContainer/Up/MenuButton"]
[editable path="MainBody/VBoxContainer/Up/CloseButton"]

View File

@ -0,0 +1,8 @@
[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://dyipeqsa8lcpc"]
[ext_resource type="Shader" path="res://addons/panku_console/res/shader/simple_fast_blur.gdshader" id="1_3h55m"]
[resource]
shader = ExtResource("1_3h55m")
shader_parameter/lod = 4.0
shader_parameter/modulate = Color(0, 0, 0, 0.12549)

View File

@ -0,0 +1,80 @@
#A simple control node managing its child windows
class_name PankuLynxWindowsManager extends Control
const CFG_ENABLE_OS_WINDOW = "enable_os_window"
const CFG_OS_WINDOW_BGCOLOR = "os_window_bg_color"
@onready var console:PankuConsole = get_node(PankuConsole.SingletonPath)
var os_popup_btn_enabled:bool
var os_window_bg_color:Color
func _ready():
load_data()
func _input(e):
if e is InputEventMouseButton and e.pressed:
var flag = true
#traverse child windows in reverse order, use double shadow to highlight current active window.
for i in range(get_child_count() - 1, -1, -1):
var w:Control = get_child(i)
if w.visible and w.get_global_rect().has_point(get_global_mouse_position()):
var forefront = get_child(get_child_count() - 1)
if forefront.has_method("highlight"): forefront.highlight(false)
w.move_to_front()
forefront = get_child(get_child_count() - 1)
if forefront.has_method("highlight"): forefront.highlight(true)
flag = false
break
if flag and get_child_count() > 0:
var forefront = get_child(get_child_count() - 1)
if forefront.has_method("highlight"): forefront.highlight(false)
func create_window(content:Control) -> PankuLynxWindow:
var new_window:PankuLynxWindow = preload("lynx_window_2.tscn").instantiate()
content.anchors_preset = Control.PRESET_FULL_RECT
new_window.set_content(content)
add_child(new_window)
new_window.show_window()
return new_window
func enable_os_popup_btns(b:bool):
#note that this may affect your project
get_viewport().gui_embed_subwindows = !b
os_popup_btn_enabled = b
for w in get_children():
#maybe there's a better way to get node type
if !w.has_method("switch_to_os_window"):
continue
w._pop_btn.visible = b
func get_enable_os_popup_btns() -> bool:
return os_popup_btn_enabled
func set_os_window_bg_color(c:Color):
os_window_bg_color = c
for w in get_children():
#maybe there's a better way to get node type
if !w.has_method("switch_to_os_window"):
continue
if w._os_window != null:
w._os_window.get_child(0).color = c
func get_os_window_bg_color() -> Color:
return os_window_bg_color
func save_data():
var cfg = PankuConfig.get_config()
cfg[CFG_ENABLE_OS_WINDOW] = os_popup_btn_enabled
cfg[CFG_OS_WINDOW_BGCOLOR] = os_window_bg_color
PankuConfig.set_config(cfg)
func load_data():
var cfg = PankuConfig.get_config()
enable_os_popup_btns(cfg.get(CFG_ENABLE_OS_WINDOW, false))
set_os_window_bg_color(cfg.get(CFG_OS_WINDOW_BGCOLOR, Color("#2b2e32")))
func _notification(what):
#quit event
if what == NOTIFICATION_WM_CLOSE_REQUEST:
save_data()

View File

@ -0,0 +1 @@
uid://xjhlmbdx8fjf

View File

@ -0,0 +1,54 @@
class_name PankuModuleManager
var _modules:Array[PankuModule]
var _modules_table:Dictionary
var _core:PankuConsole
func init_manager(_core:PankuConsole, _modules:Array[PankuModule]):
self._modules = _modules
self._core = _core
load_modules()
func load_modules():
# The extra tree structure is purely used for avoiding using RefCounted which may cause uncessary leaked instance warnings.
var manager_node:Node = Node.new()
manager_node.name = "_Modules_"
_core.add_child(manager_node)
for _m in _modules:
var module:PankuModule = _m
_modules_table[module.get_module_name()] = module
module.name = module.get_module_name()
manager_node.add_child(module)
for _m in _modules:
var module:PankuModule = _m
module.core = _core
module._init_module()
#print("[info] %s module loaded!" % module.get_module_name())
func update_modules(delta:float):
for _m in _modules:
var module:PankuModule = _m
module.update_module(delta)
func get_module(module_name:String):
return _modules_table[module_name]
func has_module(module_name:String):
return _modules_table.has(module_name)
func get_module_option_objects():
var objects = []
for _m in _modules:
var module:PankuModule = _m
if module._opt != null:
objects.append(module._opt)
return objects
func quit_modules():
for _m in _modules:
var module:PankuModule = _m
module.quit_module()

View File

@ -0,0 +1 @@
uid://rkefpsd8kk4q

View File

@ -0,0 +1,11 @@
class_name ModuleOptions extends Resource
var _module:PankuModule
var _loaded := false
#FIXME: Tricky part of saving data, needs to be reworked
func update_setting(key: String, value: Variant):
self.set(key, value)
if _loaded and _module:
_module.save_module_data(key, value)

View File

@ -0,0 +1 @@
uid://dhh5181ty0ng6

View File

@ -0,0 +1,39 @@
class_name PankuButton extends Control
signal pressed
signal button_down
signal button_up
@export
var button:Button
@export
var trect:TextureRect
@export
var label:Label
var icon:
set(v):
trect.texture = v
get:
return trect.texture
var text:
set(v):
label.text = v
get:
return label.text
func _ready():
button.pressed.connect(
func():
pressed.emit()
)
button.button_down.connect(
func(): button_down.emit()
)
button.button_up.connect(
func(): button_up.emit()
)

View File

@ -0,0 +1 @@
uid://bdhu7gchsjvpf

View File

@ -0,0 +1,42 @@
[gd_scene load_steps=5 format=3 uid="uid://drn5t13m088fb"]
[ext_resource type="Script" path="res://addons/panku_console/common/panku_button.gd" id="1_7kf5f"]
[ext_resource type="Texture2D" uid="uid://dchvk7qgfe37m" path="res://addons/panku_console/res/icons2/fold-svgrepo-com.svg" id="2_su653"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_v3kpx"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_cwnaw"]
content_margin_top = 4.0
content_margin_bottom = 4.0
[node name="PankuButton" type="PanelContainer" node_paths=PackedStringArray("button", "trect", "label")]
editor_description = "Godot's Button can't handle scaling icons properly as descripted in https://github.com/godotengine/godot-proposals/issues/660, so I have to make a new one."
self_modulate = Color(1, 1, 1, 0)
offset_right = 112.0
offset_bottom = 31.0
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxEmpty_v3kpx")
script = ExtResource("1_7kf5f")
button = NodePath("Button")
trect = NodePath("HBoxContainer/TextureRect")
label = NodePath("HBoxContainer/Label")
[node name="Button" type="Button" parent="."]
layout_mode = 2
[node name="HBoxContainer" type="HBoxContainer" parent="."]
layout_mode = 2
mouse_filter = 2
theme_override_constants/separation = 0
[node name="TextureRect" type="TextureRect" parent="HBoxContainer"]
layout_mode = 2
mouse_filter = 2
texture = ExtResource("2_su653")
expand_mode = 2
[node name="Label" type="Label" parent="HBoxContainer"]
layout_mode = 2
size_flags_vertical = 1
theme_override_styles/normal = SubResource("StyleBoxEmpty_cwnaw")
vertical_alignment = 1

View File

@ -0,0 +1,101 @@
class_name PankuModule extends Node
# extends Node: A hacky way to avoid cyclic RefCounted verbose warnings which is uncessary to worry about.
var core:PankuConsole
var _env:RefCounted = null
var _opt:ModuleOptions = null
# dir name of the module
func get_module_name() -> String:
return get_script().resource_path.get_base_dir().get_file()
# called when the module is loaded
func init_module():
pass
# called when the module is unloaded (quit program)
func quit_module():
if _opt:
_opt._loaded = false
# called at the start of each physics frame
func update_module(delta:float):
pass
func save_module_data(key:String, value:Variant):
var cfg:Dictionary = PankuConfig.get_config()
var module_name:String = get_module_name()
if !cfg.has(module_name):
cfg[module_name] = {}
cfg[module_name][key] = value
PankuConfig.set_config(cfg)
func load_module_data(key:String, default_value:Variant = null) -> Variant:
var cfg:Dictionary = PankuConfig.get_config()
var module_name:String = get_module_name()
var module_data = cfg.get(module_name, {})
return module_data.get(key, default_value)
func has_module_data(key:String) -> bool:
var cfg:Dictionary = PankuConfig.get_config()
var module_name:String = get_module_name()
var module_data = cfg.get(module_name, {})
return module_data.has(key)
func load_window_data(window:PankuLynxWindow):
window.position = load_module_data("window_position", window.get_layout_position([
Control.PRESET_TOP_LEFT,
Control.PRESET_CENTER_TOP,
Control.PRESET_TOP_RIGHT,
Control.PRESET_CENTER_LEFT,
Control.PRESET_CENTER,
Control.PRESET_CENTER_RIGHT,
Control.PRESET_BOTTOM_LEFT,
Control.PRESET_CENTER_BOTTOM,
Control.PRESET_BOTTOM_RIGHT,
][randi()%9]))
window.size = load_module_data("window_size", window.get_normal_window_size())
window.set_window_visibility(load_module_data("window_visibility", false))
func save_window_data(window:PankuLynxWindow):
_save_window_geometry(window)
save_module_data("window_visibility", window.visible)
func _save_window_geometry(window:PankuLynxWindow):
save_module_data("window_position", window.position)
save_module_data("window_size", window.get_normal_window_size())
# Add hook to window to auto save its geometry on close.
func add_auto_save_hook(window: PankuLynxWindow) -> void:
# Here some global settings check can be implemented,
# if we decide to make "save on close" feature optional
window.window_closed.connect(_save_window_geometry.bind(window))
func get_module_env() -> RefCounted:
return _env
func get_module_opt() -> ModuleOptions:
return _opt
func _init_module():
var module_script_dir:String = get_script().resource_path.get_base_dir()
var env_script_path = module_script_dir + "/env.gd"
var opt_script_path = module_script_dir + "/opt.gd"
if ResourceLoader.exists(env_script_path, "GDScript"):
_env = load(env_script_path).new()
_env._module = self
core.gd_exprenv.register_env(get_module_name(), _env)
if ResourceLoader.exists(opt_script_path, "GDScript"):
#print(opt_script_path)
_opt = load(opt_script_path).new() as ModuleOptions
_opt._module = self
init_module()
if _opt:
_opt._loaded = true

View File

@ -0,0 +1 @@
uid://ce7g5hrgs5lql

View File

@ -0,0 +1,23 @@
var _core:PankuConsole
const _HELP_help := "List all environment variables."
var help:String:
get:
var result = ["Registered objects:\n"]
var colors = ["#7c3f58", "#eb6b6f", "#f9a875", "#fff6d3"]
var i = 0
for k in _core.gd_exprenv._envs:
var c = colors[i%4]
i = i + 1
result.push_back("[b][color=%s]%s[/color][/b] "%[c, k])
result.push_back("\n")
result.push_back("You can type [b]helpe(object)[/b] to get more information.")
return "".join(PackedStringArray(result))
const _HELP_helpe := "Provide detailed information about one specific environment variable."
func helpe(obj:Object) -> String:
if !obj:
return "Invalid!"
if !obj.get_script():
return "It has no attached script!"
return PankuGDExprEnv.generate_help_text_from_script(obj.get_script())

View File

@ -0,0 +1 @@
uid://b8fo6s8tlpkh4

View File

@ -0,0 +1,57 @@
extends PanelContainer
@export var clip_container:Control
@export var scrollbar:VScrollBar
@export var follow_content:bool = true
@onready var content:Control = clip_container.get_child(0)
var scroll_progress:float = 0.0
var prev_content_size_y:float = 0.0
func init_progressbar() -> void:
scrollbar.min_value = 0.0
scrollbar.allow_greater = true
scrollbar.allow_lesser = true
scrollbar.value = 0.0
func _gui_input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.is_pressed():
var step:float = clip_container.size.y / 8.0
if event.button_index == MOUSE_BUTTON_WHEEL_UP:
scrollbar.value -= step
if event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
scrollbar.value += step
func _process(delta: float) -> void:
# add a tiny optimization here
if not is_visible_in_tree(): return
# See https://github.com/Ark2000/PankuConsole/issues/183, looks quirky
# content.size = Vector2(clip_container.size.x, 0)
# content.position = Vector2.ZERO
content.size.x = clip_container.size.x
content.size.y = 0
content.position.y = 0
content.position.x = 0
scrollbar.max_value = content.size.y
var scrollbar_value_max = max(0, scrollbar.max_value - clip_container.size.y)
scrollbar.value = PankuUtils.interp(scrollbar.value, clampf(scrollbar.value, 0.0, scrollbar_value_max), 10, delta)
scrollbar.page = clip_container.size.y
scrollbar.visible = content.size.y > clip_container.size.y
scroll_progress = PankuUtils.interp(scroll_progress, scrollbar.value, 10, delta)
content.position.y = - scroll_progress
if !follow_content: return
if prev_content_size_y != content.size.y:
var should_follow:bool = (scrollbar.value + scrollbar.page) / prev_content_size_y > 0.99
prev_content_size_y = content.size.y
if should_follow:
scrollbar.value = scrollbar.max_value - scrollbar.page
func _ready() -> void:
init_progressbar()

View File

@ -0,0 +1 @@
uid://dtang12b2rua7

View File

@ -0,0 +1,30 @@
[gd_scene load_steps=3 format=3 uid="uid://dyq4rjkkjs55d"]
[ext_resource type="Script" path="res://addons/panku_console/common/smooth_scroll/smooth_scroll.gd" id="1_ma8ku"]
[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_pa7xs"]
[node name="SmoothScrollContainer" type="PanelContainer" node_paths=PackedStringArray("clip_container", "scrollbar")]
self_modulate = Color(1, 1, 1, 0)
clip_contents = true
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("1_pa7xs")
script = ExtResource("1_ma8ku")
clip_container = NodePath("HBoxContainer/Control")
scrollbar = NodePath("HBoxContainer/VScrollBar")
[node name="HBoxContainer" type="HBoxContainer" parent="."]
layout_mode = 2
[node name="Control" type="Control" parent="HBoxContainer"]
clip_contents = true
layout_mode = 2
size_flags_horizontal = 3
[node name="VScrollBar" type="VScrollBar" parent="HBoxContainer"]
layout_mode = 2
page = 20.0
value = 80.0

View File

@ -0,0 +1,43 @@
#@tool
#extends EditorScript
class_name PankuUtils
# It will be included if you download the plugin from mirror repo(https://github.com/Ark2000/panku_console)
const COMMIT_SHA_FILE_PATH = "res://addons/panku_console/COMMIT_SHA"
static func get_plugin_version() -> String:
var error_result = "Unknown version"
#load version string from plugin.cfg
var cfg = ConfigFile.new()
if cfg.load("res://addons/panku_console/plugin.cfg") != OK:
return error_result
return cfg.get_value("plugin", "version", error_result)
static func get_commit_sha() -> String:
if FileAccess.file_exists(COMMIT_SHA_FILE_PATH):
return FileAccess.get_file_as_string(COMMIT_SHA_FILE_PATH)
return ""
static func get_commit_sha_short() -> String:
return get_commit_sha().substr(0, 7)
static func get_commit_url() -> String:
var sha := get_commit_sha()
if sha != "":
return "https://github.com/Ark2000/PankuConsole/commit/" + sha
return ""
# Framerate-independent interpolation.
static func interp(from, to, lambda: float, delta: float):
if from is Vector2:
if abs(from.x - to.x) < 1.0: from.x = to.x
if abs(from.y - to.y) < 1.0: from.y = to.y
if from is float:
if abs(from - to) < 0.01: from = to
return lerp(from, to, 1.0 - exp(-lambda * delta))
#func _run():
# print("plugin_version: ", get_plugin_version())
# print("commit_sha: ", get_commit_sha())
# print("commit_sha_short: ", get_commit_sha_short())
# print("commit_url: ", get_commit_url())

View File

@ -0,0 +1 @@
uid://yw3dk5jaii26

View File

@ -0,0 +1,86 @@
class_name PankuConsole extends CanvasLayer
# `console.gd` is a global singleton that provides all modules with a common interface
# you can also use some of its members to interact with the console
signal interactive_shell_visibility_changed(visible:bool)
signal new_expression_entered(expression:String, result)
signal new_notification_created(bbcode:String, id:int)
signal toggle_console_action_just_pressed()
const SingletonName = "Panku"
const SingletonPath = "/root/" + SingletonName
const ToggleConsoleAction = "toggle_console"
# create_data_controller(objs:Array[Object]) -> PankuLynxWindow
var create_data_controller_window:Callable = func(objs:Array): return null
var windows_manager:PankuLynxWindowsManager
var module_manager:PankuModuleManager = PankuModuleManager.new()
var gd_exprenv:PankuGDExprEnv = PankuGDExprEnv.new()
var _shell_visibility := false
# notification whose id>=0 will be fixed to the bottom of the notification list
# useful for loop print
# you can use `get_instance_id()` as notification's unique id
func notify(any, id=-1) -> void:
var text = str(any)
new_notification_created.emit(text, id)
func get_shell_visibility() -> bool:
return _shell_visibility
func _input(event: InputEvent):
if event.is_action_pressed(ToggleConsoleAction):
toggle_console_action_just_pressed.emit()
func _ready():
assert(get_tree().current_scene != self, "Do not run console.tscn as a scene!")
# Yep, seems like double check project settings in the main singleton
# is the only "correct" way to work with custom project setting
# https://github.com/godotengine/godot/issues/56598#issuecomment-1904100640
PankuConfig.init_all_project_settings()
if not PankuConfig.is_custom_default_config_exists():
push_warning("[Panku Console] Default config file not found. Using code-level default config.")
windows_manager = $LynxWindowsManager
var base_instance = preload("./common/repl_base_instance.gd").new()
base_instance._core = self
gd_exprenv.set_base_instance(base_instance)
# add default input action if not defined by user
if not InputMap.has_action(ToggleConsoleAction):
InputMap.add_action(ToggleConsoleAction)
var default_toggle_console_event = InputEventKey.new()
default_toggle_console_event.physical_keycode = KEY_QUOTELEFT
InputMap.action_add_event(ToggleConsoleAction, default_toggle_console_event)
# since panku console servers numerous purposes
# we use a module system to manage all different features
# modules are invisible to each other by design to avoid coupling
# you can add or remove any modules here as you wish
var modules:Array[PankuModule] = [
PankuModuleNativeLogger.new(),
PankuModuleScreenNotifier.new(),
PankuModuleSystemReport.new(),
PankuModuleHistoryManager.new(),
PankuModuleEngineTools.new(),
PankuModuleKeyboardShortcuts.new(),
PankuModuleCheckLatestRelease.new(),
PankuModuleInteractiveShell.new(),
PankuModuleGeneralSettings.new(),
PankuModuleDataController.new(),
PankuModuleScreenCrtEffect.new(),
PankuModuleExpressionMonitor.new(),
PankuModuleTextureViewer.new(),
PankuModuleVariableTracker.new(),
PankuModuleAbout.new(),
PankuModuleSnakeGame.new(),
]
module_manager.init_manager(self, modules)
func _notification(what):
# quit event
if what == NOTIFICATION_WM_CLOSE_REQUEST:
module_manager.quit_modules()

View File

@ -0,0 +1 @@
uid://otltxiojr8qu

View File

@ -0,0 +1,22 @@
[gd_scene load_steps=4 format=3 uid="uid://cyftuo4syatlv"]
[ext_resource type="Script" path="res://addons/panku_console/console.gd" id="1_dohs1"]
[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="2_wxhx6"]
[ext_resource type="Script" path="res://addons/panku_console/common/lynx_window2/lynx_windows_manager_2.gd" id="10_f7qaq"]
[node name="Console" type="CanvasLayer"]
process_mode = 3
layer = 128
script = ExtResource("1_dohs1")
[node name="LynxWindowsManager" type="Control" parent="."]
z_index = 1
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
theme = ExtResource("2_wxhx6")
script = ExtResource("10_f7qaq")

View File

@ -0,0 +1,80 @@
{
"enable_os_window": false,
"engine_tools": {
"time_scale": 1.0
},
"exp_history": [],
"expression_monitor": {
"monitor_data": [{
"expressions": ["engine_tools.get_performance_info()"],
"group_name": "default group"
}],
"window_position": Vector2(0, 49),
"window_size": Vector2(85, 74),
"window_visibility": false
},
"general_settings": {
"enable_os_window": false,
"lynx_window_base_color": Color(0, 0.0470588, 0.0941176, 0.501961),
"lynx_window_blur_effect": true,
"lynx_window_enable_os_window": false,
"lynx_window_os_window_bg_color": Color(0, 0, 0, 0.658824),
"os_window_bg_color": Color(0, 0, 0, 0.992157),
"window_blur_effect": true,
"window_position": Vector2(429.546, 94.1911),
"window_size": Vector2(512.568, 478.128),
"window_visibility": true
},
"history_manager": {
"window_position": Vector2(317.728, 138.82),
"window_size": Vector2(411.987, 339.537),
"window_visibility": false
},
"interactive_shell": {
"gui_mode": 0,
"histories": [],
"init_expr": "",
"output_font_size": 14.0,
"pause_if_input": false,
"pause_if_popup": false,
"show_side_menu": true,
"unified_visibility": false,
"unified_window_visibility": false,
"window_position": Vector2(427.419, 75.3913),
"window_size": Vector2(510.736, 410.437),
"window_visibility": true
},
"keyboard_shortcuts": {
"key_mapper": [],
"window_position": Vector2(0, 49),
"window_size": Vector2(85, 74),
"window_visibility": false
},
"native_logger": {
"font_size": 17.0,
"logger_tags": ["[error]", "[warning]", "[info]"],
"screen_overlay": 0,
"screen_overlay_alpha": 0.44,
"screen_overlay_font_shadow": true,
"screen_overlay_font_size": 20.0,
"show_timestamp": true,
"window_position": Vector2(284.123, 124.547),
"window_size": Vector2(483.998, 379.028),
"window_visibility": false
},
"os_window_bg_color": Color(0, 0, 0, 0.992157),
"os_window_bgcolor": Color(0, 0, 0, 0.658824),
"snake": {
"leader_board": [{
"score": 40,
"timestamp": "2024-01-29T16:00:00"
}, {
"score": 20,
"timestamp": "2024-01-29T16:01:14"
}]
},
"variable_tracker": {
"tracking_delay": 0.5,
"use_last_as_current": true
}
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Created with Vectornator (http://vectornator.io/) -->
<svg height="100%" stroke-miterlimit="10" style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;" version="1.1" viewBox="0 0 512 512" width="100%" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:vectornator="http://vectornator.io" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path d="M78.6372 264.735L139.342 44.5235L459.206 45.5892L389.109 263.19L78.6372 264.735Z" id="Fill"/>
</defs>
<g id="图层-2" vectornator:layerName="图层 2">
<path d="M0 0L512 0L512 512L0 512L0 0Z" fill="#478cbf" fill-rule="nonzero" opacity="1" stroke="none" vectornator:layerName="长方形 4"/>
</g>
<g id="图层-1" vectornator:layerName="图层 1">
<g opacity="1">
<use fill="#478cbf" fill-rule="nonzero" stroke="none" xlink:href="#Fill"/>
<mask height="220.212" id="StrokeMask" maskUnits="userSpaceOnUse" width="380.569" x="78.6372" y="44.5235">
<rect fill="#000000" height="220.212" stroke="none" width="380.569" x="78.6372" y="44.5235"/>
<use fill="#ffffff" fill-rule="evenodd" stroke="none" xlink:href="#Fill"/>
</mask>
<use fill="none" mask="url(#StrokeMask)" stroke="#ffffff" stroke-linecap="butt" stroke-linejoin="miter" stroke-width="60" xlink:href="#Fill"/>
</g>
<path d="M229.891 266.654C231.828 264.177 218.37 242.519 220.63 240.48C222.442 238.844 247.135 257.79 249.114 256.443C252.197 254.345 249.038 231.287 252.413 229.909C255.736 228.551 268.109 253.653 271.582 253.015C276.859 252.047 283.021 228.024 288.263 228.781C292.516 229.396 287.421 254.697 291.378 256.495C294.114 257.738 316.072 234.87 318.567 236.696C321.621 238.932 308.408 265.782 310.691 268.58C323.902 284.773 319.362 303.216 304.973 321.62C288.099 343.204 257.612 348.397 236.879 333.219C216.145 318.04 213.017 288.238 229.891 266.654Z" fill="#ffffff" fill-rule="nonzero" opacity="1" stroke="#478cbf" stroke-linecap="butt" stroke-linejoin="miter" stroke-width="8"/>
<path d="M73.5951 243.897C40.3754 235.104 50.2275 296.435 80.0691 306.613C92.3236 310.793 154.435 321.768 181.637 337.332C195.509 345.269 187.644 368.316 185.141 375.17C182.469 382.484 173.867 401.273 150.162 406.311C124.07 411.856 84.5598 401.403 73.382 396.752C63.9879 392.842 67.7167 451.378 72.7168 456.046C82.0707 464.776 137.282 465.493 181.93 463.32C225.448 461.202 227.232 403.857 264.785 403.333C285.04 403.051 309.943 401.305 316.067 408.513C331.898 427.144 299.954 467.823 315.414 467.474C337.118 466.984 374.108 467.477 374.108 467.477C374.108 467.477 385.778 455.386 389.874 430.9C393.969 406.415 393.91 386.546 390.488 369.534C386.006 347.25 298.321 345.372 278.96 345.427C268.776 345.456 233.057 349.793 219.907 317.792C214.983 305.809 213.961 301.983 216.883 287.594C220.32 270.672 230.493 259.169 227.398 259.66C184.391 266.486 117.357 255.48 73.5951 243.897Z" fill="#ffffff" fill-rule="nonzero" opacity="1" stroke="#478cbf" stroke-linecap="butt" stroke-linejoin="miter" stroke-width="8"/>
<path d="M313.794 266.658C311.539 271.238 320.142 279.678 320.035 289.379C319.921 299.638 313.692 312.301 309.736 317.886C305.122 324.399 309.5 330.672 315.154 330.78C338.818 331.232 376.929 316.129 396.221 307.535C434.181 290.624 458.655 238.94 423.225 234.033C418.517 233.381 397.473 251.601 370.075 259.473C346.488 266.25 315.889 262.405 313.794 266.658Z" fill="#ffffff" fill-rule="nonzero" opacity="1" stroke="#478cbf" stroke-linecap="butt" stroke-linejoin="miter" stroke-width="8"/>
<path d="M237.026 95.9347L336.678 154.629L215.794 203.182" fill="none" opacity="1" stroke="#ffffff" stroke-linecap="butt" stroke-linejoin="miter" stroke-width="30"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://rkxm4c3bbf34"
path="res://.godot/imported/logo.svg-5c6f042742ccac523c072414b9eb3caf.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/panku_console/logo.svg"
dest_files=["res://.godot/imported/logo.svg-5c6f042742ccac523c072414b9eb3caf.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View File

@ -0,0 +1,26 @@
extends Control
var _module:PankuModule
@export var intro:Label
@export var project_page_button:Button
@export var check_update_button:Button
# Called when the node enters the scene tree for the first time.
func _ready():
var version:String = PankuUtils.get_plugin_version()
var sha:String = PankuUtils.get_commit_sha_short()
if sha == "": sha = "Unknown"
intro.text = intro.text.replace("<version>", version)
intro.text = intro.text.replace("<commit>", sha)
project_page_button.pressed.connect(
func():
OS.shell_open("https://github.com/Ark2000/PankuConsole")
)
check_update_button.pressed.connect(
func():
_module.core.gd_exprenv.execute("check_latest_release.check()")
)

View File

@ -0,0 +1 @@
uid://pkgdt4duvguc

View File

@ -0,0 +1,215 @@
[gd_scene load_steps=10 format=3 uid="uid://cgwg3foes57mq"]
[ext_resource type="Script" path="res://addons/panku_console/modules/about/about.gd" id="1_kpix3"]
[ext_resource type="PackedScene" uid="uid://dyq4rjkkjs55d" path="res://addons/panku_console/common/smooth_scroll/smooth_scroll.tscn" id="2_sev6e"]
[ext_resource type="Texture2D" uid="uid://rkxm4c3bbf34" path="res://addons/panku_console/logo.svg" id="3_eycho"]
[ext_resource type="PackedScene" uid="uid://cxmplwhfv5l88" path="res://addons/panku_console/modules/about/url_button.tscn" id="4_cqu2c"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_knn3o"]
content_margin_left = 8.0
content_margin_top = 8.0
content_margin_right = 8.0
content_margin_bottom = 8.0
bg_color = Color(0, 0, 0, 0.270588)
[sub_resource type="FontVariation" id="FontVariation_v70xy"]
variation_embolden = 0.5
[sub_resource type="FontVariation" id="FontVariation_wgi7f"]
variation_embolden = 0.5
[sub_resource type="SystemFont" id="SystemFont_6on77"]
font_names = PackedStringArray("Monospace")
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_cqcex"]
content_margin_left = 4.0
content_margin_top = 4.0
content_margin_right = 4.0
content_margin_bottom = 4.0
bg_color = Color(0, 0, 0, 0.25098)
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[node name="about" type="Control" node_paths=PackedStringArray("intro", "project_page_button", "check_update_button")]
clip_contents = true
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_kpix3")
intro = NodePath("VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/PanelContainer/HBoxContainer/Label")
project_page_button = NodePath("VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/ProjectPageButton")
check_update_button = NodePath("VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/CheckUpdateButton")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = -1
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 8.0
offset_top = 8.0
offset_right = -8.0
offset_bottom = -8.0
grow_horizontal = 2
grow_vertical = 2
[node name="SmoothScrollContainer" parent="VBoxContainer" instance=ExtResource("2_sev6e")]
layout_mode = 2
size_flags_vertical = 3
follow_content = false
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control" index="0"]
layout_mode = 1
anchors_preset = 10
anchor_right = 1.0
offset_bottom = 995.0
grow_horizontal = 2
[node name="PanelContainer" type="PanelContainer" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer"]
layout_mode = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_knn3o")
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/PanelContainer"]
layout_mode = 2
alignment = 1
[node name="TextureRect" type="TextureRect" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/PanelContainer/HBoxContainer"]
layout_mode = 2
texture = ExtResource("3_eycho")
expand_mode = 2
[node name="Label" type="Label" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/PanelContainer/HBoxContainer"]
layout_mode = 2
text = "Panku Console <version> [<commit>]
© 2022-present Panku Console contributors.
© 2022 Ark2000.
"
[node name="Label" type="Label" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer"]
layout_mode = 2
text = "Panku Console is a feature-packed real-time debugging toolkit for Godot Engine."
clip_text = true
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer"]
layout_mode = 2
[node name="ProjectPageButton" type="Button" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_fonts/font = SubResource("FontVariation_v70xy")
text = "Project Page"
[node name="CheckUpdateButton" type="Button" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_fonts/font = SubResource("FontVariation_v70xy")
text = "Check Update"
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer"]
layout_mode = 2
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer"]
layout_mode = 2
[node name="Label" type="Label" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer"]
layout_mode = 2
theme_override_fonts/font = SubResource("FontVariation_wgi7f")
text = "Project Manager"
[node name="Button" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")]
layout_mode = 2
text = "Feo Wu (Ark2000)"
url = "https://github.com/Ark2000"
[node name="Label2" type="Label" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer"]
layout_mode = 2
theme_override_fonts/font = SubResource("FontVariation_wgi7f")
text = "Contributors"
[node name="Button2" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")]
layout_mode = 2
text = "Feo Wu (Ark2000)"
url = "https://github.com/Ark2000"
[node name="Button3" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")]
layout_mode = 2
text = "Rafael Correa (scriptsengineer)"
url = "https://github.com/scriptsengineer"
[node name="Button4" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")]
layout_mode = 2
text = "worron"
url = "https://github.com/worron"
[node name="Button5" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")]
layout_mode = 2
text = "mieldepoche"
url = "https://github.com/mieldepoche"
[node name="Button6" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")]
layout_mode = 2
text = "Eggbertx"
url = "https://github.com/Eggbertx"
[node name="Button7" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")]
layout_mode = 2
text = "univeous"
url = "https://github.com/univeous"
[node name="Button8" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")]
layout_mode = 2
text = "CheapMeow"
url = "https://github.com/CheapMeow"
[node name="Button9" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")]
layout_mode = 2
text = "winston-yallow (Winston)"
url = "https://github.com/winston-yallow"
[node name="Label3" type="Label" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer"]
layout_mode = 2
theme_override_fonts/font = SubResource("FontVariation_wgi7f")
text = "Icons"
[node name="Button10" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer" instance=ExtResource("4_cqu2c")]
layout_mode = 2
text = "SVG Repo"
url = "https://www.svgrepo.com/page/licensing/"
[node name="Label4" type="Label" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer"]
layout_mode = 2
theme_override_fonts/font = SubResource("FontVariation_wgi7f")
text = "License"
[node name="Label5" type="Label" parent="VBoxContainer/SmoothScrollContainer/HBoxContainer/Control/VBoxContainer/VBoxContainer"]
layout_mode = 2
theme_override_fonts/font = SubResource("SystemFont_6on77")
theme_override_styles/normal = SubResource("StyleBoxFlat_cqcex")
text = "The MIT License (MIT)
Copyright (c) 2022-present Panku Console contributors.
Copyright (c) 2022 Ark2000
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the \"Software\"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
clip_text = true
[editable path="VBoxContainer/SmoothScrollContainer"]

View File

@ -0,0 +1,5 @@
var _module:PankuModule
const _HELP_open = "Open about window"
func open() -> void:
_module.open_window()

View File

@ -0,0 +1 @@
uid://cbd0wepa77b0c

View File

@ -0,0 +1,15 @@
class_name PankuModuleAbout extends PankuModule
var window:PankuLynxWindow
const ui = preload("./about.tscn")
func open_window():
if window: return
var ui_instance = ui.instantiate()
ui_instance._module = self
window = core.windows_manager.create_window(ui_instance)
window.set_window_title_text("About")
window.show_window()
window.window_closed.connect(
func(): window = null
)

View File

@ -0,0 +1 @@
uid://bhcijrphn6uto

View File

@ -0,0 +1,9 @@
extends Button
@export var url:String
func _ready():
pressed.connect(
func():
OS.shell_open(url)
)

View File

@ -0,0 +1 @@
uid://btw5pitk8auv6

View File

@ -0,0 +1,17 @@
[gd_scene load_steps=3 format=3 uid="uid://cxmplwhfv5l88"]
[ext_resource type="Script" path="res://addons/panku_console/modules/about/url_button.gd" id="1_01blg"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ivnlg"]
content_margin_left = 8.0
bg_color = Color(0, 0, 0, 0.243137)
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[node name="Button" type="Button"]
theme_override_styles/normal = SubResource("StyleBoxFlat_ivnlg")
text = "Button Text"
alignment = 0
script = ExtResource("1_01blg")

View File

@ -0,0 +1,5 @@
var _module:PankuModule
const _HELP_check = "Fetch latest release information from Github"
func check():
_module.check()

View File

@ -0,0 +1 @@
uid://dad7nd3c3hjqv

View File

@ -0,0 +1,32 @@
class_name PankuModuleCheckLatestRelease extends PankuModule
signal check_lasted_release_requested()
signal check_lasted_release_responded(msg:Dictionary)
func send_request() -> Node:
var node = preload("./network.gd").new()
core.add_child(node)
node.check_latest_release()
node.response_received.connect(
func(_v): node.queue_free()
)
return node
func check_update():
send_request().response_received.connect(
func(msg:Dictionary):
check_lasted_release_responded.emit(msg)
)
func check():
send_request().response_received.connect(
func(msg:Dictionary):
if !msg["success"]:
core.notify("[color=red][Error][/color] Failed! " + msg["msg"])
else:
core.notify("[color=green][info][/color] Latest: [%s] [url=%s]%s[/url]" % [msg["published_at"], msg["html_url"], msg["name"]])
)
func init_module():
# implement core functions
check_lasted_release_requested.connect(check_update)

View File

@ -0,0 +1 @@
uid://ba42o6b87vvna

View File

@ -0,0 +1,59 @@
extends HTTPRequest
signal response_received(msg:Dictionary)
const LATEST_RELEASE_URL = "https://api.github.com/repos/Ark2000/PankuConsole/releases/latest"
const REQUEST_RESULT = {
RESULT_SUCCESS: "SUCCESS",
RESULT_CHUNKED_BODY_SIZE_MISMATCH: "CHUNKED_BODY_SIZE_MISMATCH",
RESULT_CANT_CONNECT: "CANT_CONNECT",
RESULT_CANT_RESOLVE: "CANT_RESOLVE",
RESULT_CONNECTION_ERROR: "CONNECTION_ERROR",
RESULT_TLS_HANDSHAKE_ERROR: "TLS_HANDSHAKE_ERROR",
RESULT_NO_RESPONSE: "NO_RESPONSE",
RESULT_BODY_SIZE_LIMIT_EXCEEDED: "BODY_SIZE_LIMIT_EXCEEDED",
RESULT_BODY_DECOMPRESS_FAILED: "BODY_DECOMPRESS_FAILED",
RESULT_REQUEST_FAILED: "REQUEST_FAILED",
RESULT_DOWNLOAD_FILE_CANT_OPEN: "DOWNLOAD_FILE_CANT_OPEN",
RESULT_DOWNLOAD_FILE_WRITE_ERROR: "DOWNLOAD_FILE_WRITE_ERROR",
RESULT_REDIRECT_LIMIT_REACHED: "REDIRECT_LIMIT_REACHED",
RESULT_TIMEOUT: "TIMEOUT"
}
static func dget(dict:Dictionary, key, default_value=""):
return default_value if !dict.has(key) else dict[key]
var is_busy := false
func _ready():
request_completed.connect(_on_request_completed)
func check_latest_release():
if is_busy: return
is_busy = true
var error = request(LATEST_RELEASE_URL)
if error != OK:
is_busy = false
response_received.emit({
"success": false,
"msg": "An error occurred in the HTTP request."
})
func _on_request_completed(result:int, response_code:int, headers:PackedStringArray, body:PackedByteArray):
is_busy = false
if result != RESULT_SUCCESS:
response_received.emit({
"success": false,
"msg": REQUEST_RESULT[result]
})
return
var json = JSON.new()
json.parse(body.get_string_from_utf8())
var response:Dictionary = json.get_data()
response_received.emit({
"success": true,
"published_at": dget(response, "published_at", "???"),
"name": dget(response, "name", "???"),
"html_url": dget(response, "html_url", "???")
})

View File

@ -0,0 +1 @@
uid://dojjr6xbfugxm

View File

@ -0,0 +1,8 @@
extends ModuleOptions
@export_group("check_latest_release")
@export var export_button_check_update := "Check Update"
func check_update():
_module.check()

View File

@ -0,0 +1 @@
uid://dwah7jcf3nn6i

View File

@ -0,0 +1,30 @@
var _module:PankuModule
const _HELP_toggle_fullscreen = "Toggle [fullscreen / windowed] mode"
func toggle_fullscreen() -> void:
_module.toggle_fullscreen()
const _HELP_set_time_scale = "Equals to [color=green]Engine.time_scale[/color]"
func set_time_scale(val:float) -> void:
_module.set_time_scale(val)
const _HELP_get_performance_info = "Show performance info"
func get_performance_info(count_nodes := false) -> String:
return _module.get_performance_info(count_nodes)
const _HELP_take_screenshot = "Take a screenshot of current window"
func take_screenshot() -> void:
_module.take_screenshot()
const _HELP_quit = "Quit application"
func quit() -> void:
_module.quit()
const _HELP_toggle_2d_collision_shape_visibility = "Toggle visibility of 2D collision shapes, useful for debugging"
func toggle_2d_collision_shape_visibility() -> void:
_module.toggle_2d_collision_shape_visibility()
const _HELP_reload_current_scene = "Reload current scene"
func reload_current_scene() -> void:
_module.reload_current_scene()

View File

@ -0,0 +1 @@
uid://b02ldrmvchylr

View File

@ -0,0 +1,72 @@
class_name PankuModuleEngineTools extends PankuModule
func init_module():
get_module_opt().count_nodes = load_module_data("count_nodes", false)
super.init_module()
func toggle_fullscreen() -> void:
if DisplayServer.window_get_mode() != DisplayServer.WINDOW_MODE_WINDOWED:
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
else:
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
core.notify("Fullscreen: " + str(DisplayServer.window_get_mode() == DisplayServer.WINDOW_MODE_FULLSCREEN))
func set_time_scale(val:float) -> void:
Engine.time_scale = val
class ClsCountNodesInTree:
func calc_children_count(core: PankuConsole, node_path: String) -> int:
var nd: Node = core.get_tree().current_scene.get_node(node_path)
return count_all_children(nd)
func count_all_children(nd: Node) -> int:
var count: int = nd.get_children().size()
for child: Node in nd.get_children():
count += count_all_children(child)
return count
func get_performance_info(count_nodes:bool) -> String:
var result = "FPS: %d | Mem: %.2fMB | Objs: %d" % [
Engine.get_frames_per_second(),
OS.get_static_memory_usage()/1048576.0,
Performance.get_monitor(Performance.OBJECT_COUNT)
]
if count_nodes:
var cls_count: ClsCountNodesInTree = ClsCountNodesInTree.new()
var root_count: int = cls_count.calc_children_count(core, "/root")
var panku_count: int = cls_count.calc_children_count(core, "/root/Panku")
result += " | Nodes: %d" % [root_count - panku_count]
return result
func take_screenshot() -> void:
var image = core.get_viewport().get_texture().get_image()
var time = str(int(Time.get_unix_time_from_system() * 1000.0))
var file_name = "screenshot_%s.png" % time
var path = "user://".path_join(file_name)
var real_path = OS.get_user_data_dir().path_join(file_name)
image.save_png(path)
core.notify("[b]Screenshot[/b] saved at [color=green][url=%s]%s[/url][/color]" % [real_path, real_path])
func quit() -> void:
core.get_tree().root.propagate_notification(core.NOTIFICATION_WM_CLOSE_REQUEST)
core.get_tree().quit()
# Currently godot can't toggle visibility of 2D collision shapes at runtime, this is a workaround.
# See https://github.com/godotengine/godot-proposals/issues/2072
func toggle_2d_collision_shape_visibility() -> void:
var tree := core.get_tree()
tree.debug_collisions_hint = not tree.debug_collisions_hint
# Traverse tree to call queue_redraw on instances of
# CollisionShape2D and CollisionPolygon2D.
var node_stack: Array[Node] = [tree.get_root()]
while not node_stack.is_empty():
var node: Node = node_stack.pop_back()
if is_instance_valid(node):
if node is CollisionShape2D or node is CollisionPolygon2D:
node.queue_redraw()
node_stack.append_array(node.get_children())
core.notify("2D Debug Draw: " + str(tree.debug_collisions_hint))
func reload_current_scene() -> void:
core.get_tree().reload_current_scene()
core.notify("Scene reloaded")

View File

@ -0,0 +1 @@
uid://dan217hmehfix

View File

@ -0,0 +1,40 @@
extends ModuleOptions
@export_group("engine_tools")
@export var export_button_toggle_fullscreen := "Toggle Fullscreen"
func toggle_fullscreen():
_module.toggle_fullscreen()
@export var export_button_take_screenshot := "Take Screenshot"
func take_screenshot():
_module.take_screenshot()
@export var export_button_quit := "Quit"
func quit():
_module.quit()
@export var export_button_toggle_2d_debug_draw := "Toggle 2D Debug Draw"
func toggle_2d_debug_draw():
_module.toggle_2d_collision_shape_visibility()
@export var export_button_reload_current_scene := "Reload Current Scene"
func reload_current_scene():
_module.reload_current_scene()
@export_range(0.1, 10.0, 0.01) var time_scale := 1.0:
set(v):
time_scale = v
_module.set_time_scale(time_scale)
@export var export_comment_count_nodes = "Show node count in performance info (can issue extra performance hit)."
@export var count_nodes := false
@export var readonly_performance_info:String:
get:
return _module.get_performance_info(count_nodes)

View File

@ -0,0 +1 @@
uid://v2u6b17gkyxf

View File

@ -0,0 +1,4 @@
var _module:PankuModule
func open_window():
_module.open_window()

View File

@ -0,0 +1 @@
uid://cwk00j0krbxbk

View File

@ -0,0 +1,33 @@
extends Control
signal expr_changed(new_expr:String)
signal removing
@export var x_btn:Button
@export var ledit:LineEdit
@export var label:Label
func set_result(text:String):
label.text = text
label.get_parent().visible = (text != "")
func set_expr(text:String):
ledit.text = text
func get_expr() -> String:
return ledit.text
func _ready():
x_btn.pressed.connect(
func():
removing.emit()
queue_free()
)
ledit.focus_exited.connect(
func():
expr_changed.emit(ledit.text)
)
ledit.text_submitted.connect(
func(new_text:String):
expr_changed.emit(new_text)
)

View File

@ -0,0 +1 @@
uid://cncy7a8mdovjf

View File

@ -0,0 +1,46 @@
[gd_scene load_steps=4 format=3 uid="uid://om8bp40jo1e"]
[ext_resource type="Script" path="res://addons/panku_console/modules/expression_monitor/expression_item.gd" id="1_dnu23"]
[ext_resource type="Texture2D" uid="uid://8g5afcuanbl6" path="res://addons/panku_console/res/icons2/close.svg" id="2_bc3ds"]
[ext_resource type="PackedScene" uid="uid://drn5t13m088fb" path="res://addons/panku_console/common/panku_button.tscn" id="3_n03xa"]
[node name="VBoxContainer" type="VBoxContainer" node_paths=PackedStringArray("x_btn", "ledit", "label")]
anchors_preset = 10
anchor_right = 1.0
offset_bottom = 31.0
grow_horizontal = 2
size_flags_horizontal = 3
script = ExtResource("1_dnu23")
x_btn = NodePath("expression_item/PankuButton/Button")
ledit = NodePath("expression_item/LineEdit")
label = NodePath("HBoxContainer/Label")
[node name="expression_item" type="HBoxContainer" parent="."]
layout_mode = 2
[node name="PankuButton" parent="expression_item" instance=ExtResource("3_n03xa")]
layout_mode = 2
[node name="TextureRect" parent="expression_item/PankuButton/HBoxContainer" index="0"]
texture = ExtResource("2_bc3ds")
[node name="LineEdit" type="LineEdit" parent="expression_item"]
layout_mode = 2
size_flags_horizontal = 3
placeholder_text = "Input expression here..."
[node name="HBoxContainer" type="HBoxContainer" parent="."]
visible = false
layout_mode = 2
[node name="ColorRect" type="ColorRect" parent="HBoxContainer"]
custom_minimum_size = Vector2(8, 0)
layout_mode = 2
color = Color(0.239216, 0.533333, 0.886275, 0.752941)
[node name="Label" type="Label" parent="HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
autowrap_mode = 1
[editable path="expression_item/PankuButton"]

View File

@ -0,0 +1,24 @@
extends Control
@onready var monitor_groups_ui := $SmoothScrollContainer/HBoxContainer/Control/MonitorGroupsUI
var _module:PankuModule
func _physics_process(delta: float) -> void:
if Engine.get_physics_frames() % 10 != 1:
return
if !is_visible_in_tree():
return
var exprss = monitor_groups_ui.get_expressions_by_group()
var resultss = []
for exprs in exprss:
var results = []
for expr in exprs:
if expr == "":
continue
var eval_result_dict = _module.core.gd_exprenv.execute(expr)
var eval_result:String = str(eval_result_dict["result"])
results.append(eval_result)
resultss.append(results)
monitor_groups_ui.set_results_by_group(resultss)

View File

@ -0,0 +1 @@
uid://jkmkx3lj1vj3

View File

@ -0,0 +1,30 @@
[gd_scene load_steps=4 format=3 uid="uid://biuybfe60pr4u"]
[ext_resource type="Script" path="res://addons/panku_console/modules/expression_monitor/expression_monitor2.gd" id="1_ha27e"]
[ext_resource type="PackedScene" uid="uid://dyq4rjkkjs55d" path="res://addons/panku_console/common/smooth_scroll/smooth_scroll.tscn" id="2_6rd5x"]
[ext_resource type="PackedScene" uid="uid://ctgf7kewoa1cn" path="res://addons/panku_console/modules/expression_monitor/monitor_groups_ui.tscn" id="2_sa5u0"]
[node name="expression_monitor2" type="Control"]
clip_contents = true
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_ha27e")
[node name="SmoothScrollContainer" parent="." instance=ExtResource("2_6rd5x")]
layout_mode = 1
[node name="MonitorGroupsUI" parent="SmoothScrollContainer/HBoxContainer/Control" index="0" instance=ExtResource("2_sa5u0")]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_right = 0.0
offset_bottom = 0.0
grow_horizontal = 2
grow_vertical = 2
[editable path="SmoothScrollContainer"]

View File

@ -0,0 +1,29 @@
class_name PankuModuleExpressionMonitor extends PankuModule
var monitor
var monitor_window:PankuLynxWindow
func init_module():
init_monitor_window()
load_window_data(monitor_window)
monitor.monitor_groups_ui.load_persistent_data(load_module_data("monitor_data", [{
"group_name": "default group",
"expressions": []
}]))
func quit_module():
super.quit_module()
save_window_data(monitor_window)
save_module_data("monitor_data", monitor.monitor_groups_ui.get_persistent_data())
func init_monitor_window():
monitor = preload("./expression_monitor2.tscn").instantiate()
monitor._module = self
# monitor.set_data(load_module_data("exprs", []))
monitor_window = core.windows_manager.create_window(monitor)
add_auto_save_hook(monitor_window)
monitor_window.queue_free_on_close = false
monitor_window.set_window_title_text("Expression Monitor")
func open_window():
monitor_window.show_window()

View File

@ -0,0 +1 @@
uid://bk4d660m07xto

View File

@ -0,0 +1,133 @@
extends VBoxContainer
signal group_move_up
signal group_move_down
const exp_item_ui_prefab:PackedScene = preload("./expression_item.tscn")
const play_icon:Texture2D = preload("res://addons/panku_console/res/icons2/play-1001-svgrepo-com.svg")
const pause_icon:Texture2D = preload("res://addons/panku_console/res/icons2/pause-1010-svgrepo-com.svg")
const expand_icon:Texture2D = preload("res://addons/panku_console/res/icons2/chevron_right.svg")
const collapse_icon:Texture2D = preload("res://addons/panku_console/res/icons2/expand_more.svg")
@onready var group_toggle_button:Button = $GroupManager/ToggleButton
@onready var rename_line_edit:LineEdit = $GroupManager/RenameLineEdit
@onready var state_control_button:PankuButton = $GroupManager/StateControlButton
@onready var rename_button:PankuButton = $GroupManager/RenameButton
@onready var confirm_rename_button:PankuButton = $GroupManager/ConfirmRenameButton
@onready var cancel_rename_button:PankuButton = $GroupManager/CancelRenameButton
@onready var move_up_button:PankuButton = $GroupManager/MoveUpButton
@onready var move_down_button:PankuButton = $GroupManager/MoveDownButton
@onready var exp_body_container:Control = $PanelContainer
@onready var exp_container:Control = $PanelContainer/VBoxContainer/ExpressionContainer
@onready var add_exp_button:Button = $PanelContainer/VBoxContainer/AddNewExpressionButton
@onready var remove_this_group_button:PankuButton = $GroupManager/RemoveButton
@onready var normal_ui_group:Array = [
group_toggle_button,
state_control_button,
rename_button
]
@onready var edit_ui_group:Array = [
rename_line_edit,
confirm_rename_button,
cancel_rename_button,
move_up_button,
move_down_button,
remove_this_group_button
]
func _ready():
edit_ui_group.map(func(item): item.hide())
normal_ui_group.map(func(item): item.show())
exp_body_container.hide()
group_toggle_button.toggle_mode = true
group_toggle_button.button_pressed = false
group_toggle_button.toggled.connect(
func(button_pressed:bool):
exp_body_container.visible = button_pressed
group_toggle_button.icon = collapse_icon if button_pressed else expand_icon
)
add_exp_button.pressed.connect(
func():
var exp_item = exp_item_ui_prefab.instantiate()
exp_container.add_child(exp_item)
)
state_control_button.button.toggle_mode = true
state_control_button.button.button_pressed = false
state_control_button.button.toggled.connect(
func(button_pressed:bool):
state_control_button.icon = pause_icon if button_pressed else play_icon
)
rename_button.pressed.connect(
func():
edit_ui_group.map(func(item): item.show())
normal_ui_group.map(func(item): item.hide())
rename_line_edit.text = group_toggle_button.text
)
cancel_rename_button.pressed.connect(
func():
edit_ui_group.map(func(item): item.hide())
normal_ui_group.map(func(item): item.show())
)
confirm_rename_button.pressed.connect(
func():
edit_ui_group.map(func(item): item.hide())
normal_ui_group.map(func(item): item.show())
group_toggle_button.text = rename_line_edit.text
)
move_up_button.pressed.connect(
func():
group_move_up.emit()
)
move_down_button.pressed.connect(
func():
group_move_down.emit()
)
remove_this_group_button.pressed.connect(queue_free)
load_persistent_data({
"group_name": "Unnamed Group",
"expressions": []
})
func get_expressions(show_hidden := false) -> Array:
# optimization?
var exps = []
if state_control_button.button.button_pressed or show_hidden:
for child in exp_container.get_children():
exps.append(child.get_expr())
return exps
func set_results(results:Array):
if results.size() > exp_container.get_child_count():
push_error("unexpected parameters.")
return
for i in range(results.size()):
var result:String = results[i]
exp_container.get_child(i).set_result(result)
func get_persistent_data() -> Dictionary:
return {
"group_name": group_toggle_button.text,
"expressions": get_expressions(true)
}
func load_persistent_data(data:Dictionary):
group_toggle_button.text = data["group_name"]
for child in exp_container.get_children():
child.queue_free()
for exp in data["expressions"]:
var exp_item = exp_item_ui_prefab.instantiate()
exp_container.add_child(exp_item)
exp_item.set_expr(exp)

View File

@ -0,0 +1 @@
uid://pnr5pml8b4y6

View File

@ -0,0 +1,145 @@
[gd_scene load_steps=17 format=3 uid="uid://dlnkho5p7p2aq"]
[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_5nvur"]
[ext_resource type="Script" path="res://addons/panku_console/modules/expression_monitor/monitor_group_ui.gd" id="1_b5egi"]
[ext_resource type="Texture2D" uid="uid://ws58gucuygx1" path="res://addons/panku_console/res/icons2/chevron_right.svg" id="1_k5xby"]
[ext_resource type="Texture2D" uid="uid://ecmevhk0tuas" path="res://addons/panku_console/res/icons2/play-1001-svgrepo-com.svg" id="2_wnb5s"]
[ext_resource type="Texture2D" uid="uid://2cjvp0dp8ede" path="res://addons/panku_console/res/icons2/check-svgrepo-com.svg" id="3_h1h1v"]
[ext_resource type="Texture2D" uid="uid://8g5afcuanbl6" path="res://addons/panku_console/res/icons2/close.svg" id="4_2d3kd"]
[ext_resource type="Texture2D" uid="uid://brf6iwx4r6bdd" path="res://addons/panku_console/res/icons2/rename-svgrepo-com.svg" id="4_3tm8i"]
[ext_resource type="Gradient" uid="uid://nr65cgweqh8n" path="res://addons/panku_console/res/green_gradient_1d.tres" id="4_gsqii"]
[ext_resource type="PackedScene" uid="uid://drn5t13m088fb" path="res://addons/panku_console/common/panku_button.tscn" id="5_6smru"]
[ext_resource type="Texture2D" uid="uid://d0k813mm5y0d5" path="res://addons/panku_console/res/icons2/arrow-up-md-svgrepo-com.svg" id="5_xed2e"]
[ext_resource type="Texture2D" uid="uid://cdxbns8lyctqp" path="res://addons/panku_console/res/icons2/arrow-down-svgrepo-com.svg" id="6_168yw"]
[ext_resource type="PackedScene" uid="uid://om8bp40jo1e" path="res://addons/panku_console/modules/expression_monitor/expression_item.tscn" id="9_2py4a"]
[ext_resource type="Texture2D" uid="uid://cngs5d4uosvmt" path="res://addons/panku_console/res/icons2/bin-cancel-delete-remove-trash-garbage-svgrepo-com.svg" id="10_jdwtu"]
[ext_resource type="Texture2D" uid="uid://dprpfr0l5xvmu" path="res://addons/panku_console/res/icons2/add.svg" id="10_l2ajq"]
[sub_resource type="GradientTexture1D" id="GradientTexture1D_c12ue"]
gradient = ExtResource("4_gsqii")
width = 128
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fdb5g"]
content_margin_left = 4.0
content_margin_top = 4.0
content_margin_right = 4.0
content_margin_bottom = 4.0
bg_color = Color(0, 0, 0, 0.12549)
border_width_left = 1
border_width_top = 1
border_width_right = 1
border_width_bottom = 1
border_color = Color(0.8, 0.8, 0.8, 0.501961)
[node name="MonitorGroupUI" type="VBoxContainer"]
offset_right = 431.0
offset_bottom = 124.0
theme = ExtResource("1_5nvur")
script = ExtResource("1_b5egi")
[node name="GroupManager" type="HBoxContainer" parent="."]
layout_mode = 2
[node name="ToggleButton" type="Button" parent="GroupManager"]
layout_mode = 2
size_flags_horizontal = 3
text = "Default Group"
icon = ExtResource("1_k5xby")
flat = true
alignment = 0
expand_icon = true
[node name="TextureRect" type="TextureRect" parent="GroupManager/ToggleButton"]
show_behind_parent = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
texture = SubResource("GradientTexture1D_c12ue")
expand_mode = 1
[node name="RenameLineEdit" type="LineEdit" parent="GroupManager"]
visible = false
layout_mode = 2
size_flags_horizontal = 3
text = "Default Group"
[node name="StateControlButton" parent="GroupManager" instance=ExtResource("5_6smru")]
layout_mode = 2
[node name="TextureRect" parent="GroupManager/StateControlButton/HBoxContainer" index="0"]
texture = ExtResource("2_wnb5s")
[node name="RenameButton" parent="GroupManager" instance=ExtResource("5_6smru")]
layout_mode = 2
[node name="TextureRect" parent="GroupManager/RenameButton/HBoxContainer" index="0"]
texture = ExtResource("4_3tm8i")
[node name="ConfirmRenameButton" parent="GroupManager" instance=ExtResource("5_6smru")]
visible = false
layout_mode = 2
[node name="TextureRect" parent="GroupManager/ConfirmRenameButton/HBoxContainer" index="0"]
texture = ExtResource("3_h1h1v")
[node name="CancelRenameButton" parent="GroupManager" instance=ExtResource("5_6smru")]
visible = false
layout_mode = 2
[node name="TextureRect" parent="GroupManager/CancelRenameButton/HBoxContainer" index="0"]
texture = ExtResource("4_2d3kd")
[node name="MoveUpButton" parent="GroupManager" instance=ExtResource("5_6smru")]
visible = false
layout_mode = 2
[node name="TextureRect" parent="GroupManager/MoveUpButton/HBoxContainer" index="0"]
texture = ExtResource("5_xed2e")
[node name="MoveDownButton" parent="GroupManager" instance=ExtResource("5_6smru")]
visible = false
layout_mode = 2
[node name="TextureRect" parent="GroupManager/MoveDownButton/HBoxContainer" index="0"]
texture = ExtResource("6_168yw")
[node name="RemoveButton" parent="GroupManager" instance=ExtResource("5_6smru")]
layout_mode = 2
[node name="TextureRect" parent="GroupManager/RemoveButton/HBoxContainer" index="0"]
texture = ExtResource("10_jdwtu")
[node name="PanelContainer" type="PanelContainer" parent="."]
layout_mode = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_fdb5g")
[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer"]
layout_mode = 2
[node name="ExpressionContainer" type="VBoxContainer" parent="PanelContainer/VBoxContainer"]
layout_mode = 2
[node name="VBoxContainer" parent="PanelContainer/VBoxContainer/ExpressionContainer" instance=ExtResource("9_2py4a")]
layout_mode = 2
[node name="VBoxContainer2" parent="PanelContainer/VBoxContainer/ExpressionContainer" instance=ExtResource("9_2py4a")]
layout_mode = 2
[node name="AddNewExpressionButton" type="Button" parent="PanelContainer/VBoxContainer"]
layout_mode = 2
text = "Add New Expression"
icon = ExtResource("10_l2ajq")
alignment = 0
expand_icon = true
[editable path="GroupManager/StateControlButton"]
[editable path="GroupManager/RenameButton"]
[editable path="GroupManager/ConfirmRenameButton"]
[editable path="GroupManager/CancelRenameButton"]
[editable path="GroupManager/MoveUpButton"]
[editable path="GroupManager/MoveDownButton"]
[editable path="GroupManager/RemoveButton"]

View File

@ -0,0 +1,50 @@
extends VBoxContainer
const MonitorGroup:GDScript = preload("./monitor_group_ui.gd")
const group_prefab:PackedScene = preload("./monitor_group_ui.tscn")
@onready var groups_container:Control = $Groups
@onready var add_group_button:Button = $AddGroupButton
func _ready():
add_group_button.pressed.connect(add_group)
func get_expressions_by_group() -> Array:
var result := []
for child in groups_container.get_children():
var group:MonitorGroup = child
result.append(group.get_expressions())
return result
func set_results_by_group(results:Array):
if results.size() > groups_container.get_child_count():
push_error("unexpected parameters.")
return
for i in range(results.size()):
groups_container.get_child(i).set_results(results[i])
func add_group() -> MonitorGroup:
var group_ui:Node = group_prefab.instantiate()
groups_container.add_child(group_ui)
group_ui.group_move_up.connect(
func():
groups_container.move_child(group_ui, group_ui.get_index() - 1)
)
group_ui.group_move_down.connect(
func():
groups_container.move_child(group_ui, group_ui.get_index() + 1)
)
return group_ui
func get_persistent_data() -> Array:
var data := []
for child in groups_container.get_children():
data.append(child.get_persistent_data())
return data
func load_persistent_data(data:Array):
for child in groups_container.get_children():
child.queue_free()
for group_data in data:
var group_ui = add_group()
group_ui.load_persistent_data(group_data)

View File

@ -0,0 +1 @@
uid://c7nca3l6nwgyw

View File

@ -0,0 +1,31 @@
[gd_scene load_steps=5 format=3 uid="uid://ctgf7kewoa1cn"]
[ext_resource type="Script" path="res://addons/panku_console/modules/expression_monitor/monitor_groups_ui.gd" id="1_8ojgn"]
[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_gc4dk"]
[ext_resource type="PackedScene" uid="uid://dlnkho5p7p2aq" path="res://addons/panku_console/modules/expression_monitor/monitor_group_ui.tscn" id="1_l15o5"]
[ext_resource type="Texture2D" uid="uid://dprpfr0l5xvmu" path="res://addons/panku_console/res/icons2/add.svg" id="4_utrvo"]
[node name="MonitorGroupsUI" type="VBoxContainer"]
offset_right = 411.0
offset_bottom = 309.0
theme = ExtResource("1_gc4dk")
script = ExtResource("1_8ojgn")
[node name="Groups" type="VBoxContainer" parent="."]
layout_mode = 2
[node name="MonitorGroupUI" parent="Groups" instance=ExtResource("1_l15o5")]
layout_mode = 2
[node name="MonitorGroupUI2" parent="Groups" instance=ExtResource("1_l15o5")]
layout_mode = 2
[node name="MonitorGroupUI3" parent="Groups" instance=ExtResource("1_l15o5")]
layout_mode = 2
[node name="AddGroupButton" type="Button" parent="."]
layout_mode = 2
text = "Add New Group"
icon = ExtResource("4_utrvo")
alignment = 0
expand_icon = true

View File

@ -0,0 +1,4 @@
var _module:PankuModule
func open():
_module.open_settings_window()

View File

@ -0,0 +1 @@
uid://b0m1kd1d2kjyc

View File

@ -0,0 +1,68 @@
class_name PankuModuleGeneralSettings extends PankuModule
var window:PankuLynxWindow
func open_settings_window():
if window: return
# create a new exporter window
window = core.create_data_controller_window.call(
core.module_manager.get_module_option_objects()
)
window.set_window_title_text("General Settings")
load_window_data(window)
window.show_window()
window.window_closed.connect(
func():
save_window_data(window)
window = null
)
# Taken from https://github.com/godotengine/godot/blob/master/editor/editor_settings.cpp#L1539
static func get_auto_display_scale() -> float:
var flag := false
match OS.get_name():
"macOS":
flag = true
"Linux", "FreeBSD", "NetBSD", "OpenBSD", "BSD":
if DisplayServer.get_name() == "Wayland":
flag = true
"Android":
flag = true
"iOS":
flag = true
if flag:
return DisplayServer.screen_get_max_scale()
var screen := DisplayServer.window_get_current_screen()
if (DisplayServer.screen_get_size(screen) == Vector2i()):
# Invalid screen size, skip.
return 1.0
# Use the smallest dimension to use a correct display scale on portrait displays.
var smallest_dimension = min(DisplayServer.screen_get_size().x, DisplayServer.screen_get_size().y)
if DisplayServer.screen_get_dpi(screen) >= 192 and smallest_dimension >= 1400:
# hiDPI display.
return 2.0
elif smallest_dimension >= 1700:
# Likely a hiDPI display, but we aren't certain due to the returned DPI.
# Use an intermediate scale to handle this situation.
return 1.5
elif smallest_dimension <= 800:
# Small loDPI display. Use a smaller display scale so that editor elements fit more easily.
# Icons won't look great, but this is better than having editor elements overflow from its window.
return 0.75
return 1.0
func init_module():
# load settings
get_module_opt().window_blur_effect = load_module_data("window_blur_effect", true)
get_module_opt().window_base_color = load_module_data("window_base_color", Color("#000c1880"))
get_module_opt().enable_os_window = load_module_data("enable_os_window", false)
get_module_opt().os_window_bg_color = load_module_data("os_window_bg_color", Color(0, 0, 0, 0))
get_module_opt().global_font_size = load_module_data("global_font_size", int(16 * get_auto_display_scale()))
func quit_module():
super.quit_module()
if window:
save_window_data(window)

View File

@ -0,0 +1 @@
uid://bqx8byqbawedh

View File

@ -0,0 +1,49 @@
extends ModuleOptions
@export_group("general_settings")
@export var window_blur_effect:bool = true:
set(v):
PankuLynxWindow.lynx_window_shader_material.set("shader_parameter/lod", 4.0 if v else 0.0)
get:
return PankuLynxWindow.lynx_window_shader_material.get("shader_parameter/lod") > 0.0
@export var window_base_color:Color = Color(0.0, 0.0, 0.0, 0.1):
set(v):
PankuLynxWindow.lynx_window_shader_material.set("shader_parameter/modulate", v)
get:
return PankuLynxWindow.lynx_window_shader_material.get("shader_parameter/modulate")
@export var enable_os_window := false:
set(v):
_module.core.windows_manager.enable_os_popup_btns(v)
get:
return _module.core.windows_manager.os_popup_btn_enabled
@export var os_window_bg_color:Color:
set(v):
_module.core.windows_manager.set_os_window_bg_color(v)
get:
return _module.core.windows_manager.os_window_bg_color
@export var global_font_size:int:
set(v):
_module.core.windows_manager.theme.default_font_size = v
get:
return _module.core.windows_manager.theme.default_font_size
@export var export_comment_auto_global_font_size = (
"Adjust global font size automatically according to your device DPI"
)
@export var export_button_auto_global_font_size := "Auto Global Font Size"
func auto_global_font_size():
global_font_size = int(16 * _module.get_auto_display_scale())
@export var export_button_report_bugs := "Report Bugs"
func report_bugs():
OS.shell_open("https://github.com/Ark2000/PankuConsole/issues")
@export var export_button_suggest_features := "Suggest Features"
func suggest_features():
OS.shell_open("https://github.com/Ark2000/PankuConsole/issues")

View File

@ -0,0 +1 @@
uid://bkxa6b0jf83y3

View File

@ -0,0 +1,4 @@
var _module:PankuModule
func open() -> void:
_module.open_window()

View File

@ -0,0 +1 @@
uid://cr2kkri0xrsqv

View File

@ -0,0 +1,206 @@
extends Control
@onready var console:PankuConsole
const exp_item_prefab = preload("./exp_history_item.tscn")
const CFG_EXP_HISTORY = "exp_history"
@export var item_container:VBoxContainer
@export var copy_button:Button
@export var monitor_button:Button
@export var favorite_button:Button
@export var delete_button:Button
@export var reverse_select_button:Button
@export var prev_page_button:Button
@export var next_page_button:Button
@export var first_page_button:Button
@export var last_page_button:Button
@export var page_ledit:LineEdit
@export var page_label:Label
var current_page := 1
var all_pages := 1
var items_per_page := 5
#[checked:bool, fav:bool, exp:String]
var item_data := []
func _ready():
load_data()
copy_button.pressed.connect(copy_selected)
monitor_button.pressed.connect(monitor_selected)
favorite_button.pressed.connect(star_selected)
delete_button.pressed.connect(remove_selected)
reverse_select_button.pressed.connect(invert_selected)
prev_page_button.pressed.connect(
func():
current_page -= 1
reload()
)
next_page_button.pressed.connect(
func():
current_page += 1
reload()
)
first_page_button.pressed.connect(
func():
current_page = 1;
reload()
)
last_page_button.pressed.connect(
func():
current_page = 99999999;
reload()
)
page_ledit.text_submitted.connect(
func(_new_text:String):
current_page = page_ledit.text.to_int()
reload()
)
page_ledit.focus_exited.connect(
func():
current_page = page_ledit.text.to_int()
reload()
)
create_tween().set_loops().set_process_mode(Tween.TWEEN_PROCESS_PHYSICS).tween_callback(
func():
if !is_visible_in_tree(): return
if item_container.get_child_count() < 1: return
var item_height = item_container.get_child(0).size.y
var item_gap = item_container.get("theme_override_constants/separation")
var container_height = item_container.get_parent().size.y
var _items_per_page = floor((container_height + item_gap) / (item_height + item_gap))
_items_per_page = max(5, _items_per_page)
if _items_per_page != items_per_page:
items_per_page = _items_per_page
reload()
).set_delay(0.1)
visibility_changed.connect(
func():
if is_visible_in_tree(): reload()
)
func reload():
#calculate pages
all_pages = max(1, ceil(1.0 * item_data.size() / items_per_page))
current_page = clamp(current_page, 1, all_pages)
page_label.text = " / %d" % all_pages
page_ledit.text = str(current_page)
#remove existing list items
var start_idx := (current_page - 1) * items_per_page
var end_idx := mini(start_idx + items_per_page, item_data.size())
for c in item_container.get_children():
c.queue_free()
#add new list items
for i in range(start_idx, end_idx):
var list_item = exp_item_prefab.instantiate()
list_item.checkbox.button_pressed = item_data[i][0]
list_item.fav_icon.visible = item_data[i][1]
list_item.line_edit.text = item_data[i][2]
list_item.checkbox.toggled.connect(
func(val:bool): item_data[i][0] = val
)
list_item.line_edit.text_changed.connect(
func(val:String): item_data[i][2] = val
)
item_container.add_child(list_item)
func copy_selected():
var result = combine_selected()
if result != "":
DisplayServer.clipboard_set(result)
console.notify("Combined expression has beed added to clipboard!")
clear_selected()
func monitor_selected():
var result = combine_selected()
if result != "":
pass
# console.add_monitor_window(result, 0.1).centered()
clear_selected()
func combine_selected() -> String:
var selected_exp = []
var combined_exp = ""
for d in item_data:
if !d[0]: continue
selected_exp.append(d[2])
if selected_exp.size() > 8:
console.notify("Maximum 8 items!")
return ""
if selected_exp.size() == 0:
console.notify("Nothing to copy!")
return ""
elif selected_exp.size() == 1:
combined_exp = selected_exp[0]
else:
for i in range(selected_exp.size()):
selected_exp[i] = "'%s: ' + str(%s)" % [selected_exp[i], selected_exp[i]]
combined_exp = " + '\\n' + ".join(PackedStringArray(selected_exp))
return combined_exp
func clear_selected():
for d in item_data:
d[0] = false
reload()
func invert_selected():
for d in item_data:
d[0] = !d[0]
reload()
func star_selected():
var flag := true
for d in item_data:
if !d[0]: continue
d[1] = !d[1]
d[0] = false
flag = false
if flag:
console.notify("No selected items!")
return
#sort favorite
var fav_id := 0
var fav_items := []
var items := []
for d in item_data:
if d[1]: fav_items.append(d)
else: items.append(d)
item_data = fav_items + items
reload()
func remove_selected():
var result = []
for d in item_data:
if d[0]: continue
result.append(d)
if item_data.size() == result.size():
console.notify("No selected items!")
return
console.notify("Removed %d items." % (item_data.size() - result.size()))
item_data = result
reload()
func load_data():
#get saved data from cfg
var cfg = PankuConfig.get_config()
item_data = cfg.get(CFG_EXP_HISTORY, [])
func save_data():
var cfg = PankuConfig.get_config()
cfg[CFG_EXP_HISTORY] = item_data
PankuConfig.set_config(cfg)
func _notification(what):
if what == NOTIFICATION_WM_CLOSE_REQUEST:
save_data()
func add_history(exp:String):
#ignore consecutive same
if item_data.size() > 0 and exp == item_data.back()[2]:
return
item_data.append([false, false, exp])
if is_visible_in_tree(): reload()

View File

@ -0,0 +1 @@
uid://nsybsat5vf4e

View File

@ -0,0 +1,149 @@
[gd_scene load_steps=4 format=3 uid="uid://fladd1y6sa1j"]
[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_q7hjy"]
[ext_resource type="Script" path="res://addons/panku_console/modules/history_manager/exp_history.gd" id="2_kgk33"]
[ext_resource type="PackedScene" uid="uid://dhsvbbxqlb1xy" path="res://addons/panku_console/modules/history_manager/exp_history_item.tscn" id="3_wac0s"]
[node name="ExpHistory" type="Control" node_paths=PackedStringArray("item_container", "copy_button", "monitor_button", "favorite_button", "delete_button", "reverse_select_button", "prev_page_button", "next_page_button", "first_page_button", "last_page_button", "page_ledit", "page_label")]
clip_contents = true
layout_mode = 3
anchors_preset = 0
offset_left = 227.0
offset_top = 149.0
offset_right = 634.0
offset_bottom = 437.0
theme = ExtResource("1_q7hjy")
script = ExtResource("2_kgk33")
item_container = NodePath("VBoxContainer2/Control/ItemContainer")
copy_button = NodePath("VBoxContainer2/HBoxContainer/CopyButton")
monitor_button = NodePath("VBoxContainer2/HBoxContainer/MonitorButton")
favorite_button = NodePath("VBoxContainer2/HBoxContainer/FavoriteButton")
delete_button = NodePath("VBoxContainer2/HBoxContainer/DeleteButton")
reverse_select_button = NodePath("VBoxContainer2/HBoxContainer/InvertSelect")
prev_page_button = NodePath("VBoxContainer2/HBoxContainer2/PrevPageButton")
next_page_button = NodePath("VBoxContainer2/HBoxContainer2/NextPageButton")
first_page_button = NodePath("VBoxContainer2/HBoxContainer2/FirstpageButton")
last_page_button = NodePath("VBoxContainer2/HBoxContainer2/LastPageButton")
page_ledit = NodePath("VBoxContainer2/HBoxContainer2/PageNumberEdit")
page_label = NodePath("VBoxContainer2/HBoxContainer2/TotalPageLabel")
metadata/_edit_vertical_guides_ = [161.838]
[node name="Panel" type="Panel" parent="."]
visible = false
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="VBoxContainer2" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 4.0
offset_top = 4.0
offset_right = -4.0
offset_bottom = -4.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer2"]
layout_mode = 2
[node name="CopyButton" type="Button" parent="VBoxContainer2/HBoxContainer"]
visible = false
layout_mode = 2
size_flags_horizontal = 3
text = "Copy"
[node name="MonitorButton" type="Button" parent="VBoxContainer2/HBoxContainer"]
visible = false
layout_mode = 2
size_flags_horizontal = 3
text = "Monitor"
[node name="FavoriteButton" type="Button" parent="VBoxContainer2/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Favorite"
[node name="DeleteButton" type="Button" parent="VBoxContainer2/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Delete"
[node name="InvertSelect" type="Button" parent="VBoxContainer2/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Invert Select"
[node name="HSeparator2" type="HSeparator" parent="VBoxContainer2"]
layout_mode = 2
[node name="Control" type="Control" parent="VBoxContainer2"]
clip_contents = true
layout_mode = 2
size_flags_vertical = 3
[node name="ItemContainer" type="VBoxContainer" parent="VBoxContainer2/Control"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_vertical = 3
theme_override_constants/separation = 2
[node name="ExpItem" parent="VBoxContainer2/Control/ItemContainer" instance=ExtResource("3_wac0s")]
layout_mode = 2
[node name="ExpItem2" parent="VBoxContainer2/Control/ItemContainer" instance=ExtResource("3_wac0s")]
layout_mode = 2
[node name="ExpItem3" parent="VBoxContainer2/Control/ItemContainer" instance=ExtResource("3_wac0s")]
layout_mode = 2
[node name="HSeparator" type="HSeparator" parent="VBoxContainer2"]
layout_mode = 2
[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer2"]
layout_mode = 2
[node name="FirstpageButton" type="Button" parent="VBoxContainer2/HBoxContainer2"]
layout_mode = 2
size_flags_horizontal = 3
text = "<<<"
[node name="PrevPageButton" type="Button" parent="VBoxContainer2/HBoxContainer2"]
layout_mode = 2
size_flags_horizontal = 3
text = "<"
[node name="PageNumberEdit" type="LineEdit" parent="VBoxContainer2/HBoxContainer2"]
layout_mode = 2
text = "1"
[node name="TotalPageLabel" type="Label" parent="VBoxContainer2/HBoxContainer2"]
layout_mode = 2
text = "/ 10"
vertical_alignment = 1
[node name="NextPageButton" type="Button" parent="VBoxContainer2/HBoxContainer2"]
layout_mode = 2
size_flags_horizontal = 3
text = ">"
[node name="LastPageButton" type="Button" parent="VBoxContainer2/HBoxContainer2"]
layout_mode = 2
size_flags_horizontal = 3
text = ">>>"
[node name="HFlowContainer" type="HFlowContainer" parent="."]
layout_mode = 2
offset_right = 399.0
size_flags_vertical = 0

View File

@ -0,0 +1,5 @@
extends HBoxContainer
@export var checkbox:CheckBox
@export var fav_icon:TextureRect
@export var line_edit:LineEdit

View File

@ -0,0 +1 @@
uid://dy7ywh6we3xug

View File

@ -0,0 +1,27 @@
[gd_scene load_steps=4 format=3 uid="uid://dhsvbbxqlb1xy"]
[ext_resource type="Theme" uid="uid://bk18yfu0d77wk" path="res://addons/panku_console/res/panku_console_theme.tres" id="1_rsfup"]
[ext_resource type="Script" path="res://addons/panku_console/modules/history_manager/exp_history_item.gd" id="2_a3mfr"]
[ext_resource type="Texture2D" uid="uid://hf6h8otb8qkv" path="res://addons/panku_console/res/icons2/favorite.svg" id="3_1odvn"]
[node name="ExpItem" type="HBoxContainer" node_paths=PackedStringArray("checkbox", "fav_icon", "line_edit")]
offset_right = 155.0
offset_bottom = 20.0
theme = ExtResource("1_rsfup")
script = ExtResource("2_a3mfr")
checkbox = NodePath("CheckBox")
fav_icon = NodePath("TextureRect")
line_edit = NodePath("LineEdit")
[node name="CheckBox" type="CheckBox" parent="."]
layout_mode = 2
flat = true
[node name="TextureRect" type="TextureRect" parent="."]
layout_mode = 2
texture = ExtResource("3_1odvn")
stretch_mode = 3
[node name="LineEdit" type="LineEdit" parent="."]
layout_mode = 2
size_flags_horizontal = 3

View File

@ -0,0 +1,26 @@
class_name PankuModuleHistoryManager extends PankuModule
var window:PankuLynxWindow
func init_module():
# setup ui
var ui = preload("./exp_history.tscn").instantiate()
ui.console = core
core.new_expression_entered.connect(
func(expression, result):
ui.add_history(expression)
)
# bind window
window = core.windows_manager.create_window(ui)
add_auto_save_hook(window)
window.queue_free_on_close = false
window.set_window_title_text("History Manager")
load_window_data(window)
func quit_module():
super.quit_module()
save_window_data(window)
func open_window():
window.show_window()

View File

@ -0,0 +1 @@
uid://du280gsd10ts4

View File

@ -0,0 +1,7 @@
extends ModuleOptions
@export_group("history_manager")
@export var export_button_open_window := "Open Window"
func open_window():
_module.open_window()

Some files were not shown because too many files have changed in this diff Show More