add license, move folders

This commit is contained in:
Nordup 2024-05-04 00:14:24 +04:00
parent 185cc74060
commit 271c4a46a1
132 changed files with 21 additions and 0 deletions

View file

@ -0,0 +1,25 @@
extends AnimationPlayer
@export var ui_events: UiEvents
@export var gate_events: GateEvents
const RESET := "RESET"
const INITIAL := "initial"
const FULLSCREEN := "fullscreen"
var fullscreen := false
func _ready() -> void:
ui_events.ui_mode_changed.connect(on_ui_mode_changed)
gate_events.open_gate.connect(func(_url): on_ui_mode_changed(UiEvents.UiMode.INITIAL))
func on_ui_mode_changed(mode: UiEvents.UiMode) -> void:
if mode == UiEvents.UiMode.INITIAL and fullscreen:
fullscreen = false
play(INITIAL)
if mode == UiEvents.UiMode.FULL_SCREEN and not fullscreen:
fullscreen = true
play(FULLSCREEN)

32
app/scripts/ui/hint.gd Normal file
View file

@ -0,0 +1,32 @@
extends Control
@export var section: String = "hints"
@export var key: String = ""
@export var button: BaseButton
func _ready() -> void:
visible = false
if key.is_empty() or button == null: Debug.logerr("hint has empty vars")
var first = DataSaver.get_value(section, key)
if first == null or not first: show_hint()
func _notification(what: int) -> void:
if not what == NOTIFICATION_VISIBILITY_CHANGED: return
if is_visible_in_tree(): play_anim()
func show_hint() -> void:
visible = true
play_anim()
if button != null: button.pressed.connect(hide_hint)
func play_anim() -> void:
$AnimationPlayer.play("Bounce")
func hide_hint() -> void:
visible = false
DataSaver.set_value(section, key, true)

View file

@ -0,0 +1,16 @@
extends GridContainer
@export var bookmarks: Bookmarks
@export var bookmark_scene: PackedScene
func _ready() -> void:
bookmarks.on_star.connect(show_bookmark)
for gate in bookmarks.gates.values():
show_bookmark(gate)
func show_bookmark(gate: Gate, _featured: bool = false) -> void:
var bookmark: BookmarkUI = bookmark_scene.instantiate()
bookmark.fill(gate)
add_child(bookmark)

View file

@ -0,0 +1,21 @@
extends Node
class_name BookmarkUI
@export var gate_events: GateEvents
@export var image: TextureRect
@export var title: Label
var url: String
func fill(gate: Gate) -> void:
if gate == null: return
url = gate.url
title.text = "Unnamed" if gate.title.is_empty() else gate.title
image.texture = FileTools.load_external_tex(gate.image)
func _on_base_button_pressed() -> void:
if url.is_empty(): return
gate_events.open_gate_emit(url)

View file

@ -0,0 +1,5 @@
extends BaseButton
func _on_pressed() -> void:
get_tree().quit()

View file

@ -0,0 +1,52 @@
extends Resource
class_name History
var history: Array[String]
var index := -1
func get_current() -> String:
if index == -1: return ""
return history[index]
func can_forw() -> bool:
return index + 1 < history.size()
func can_back() -> bool:
return index > -1
func add(url: String) -> void:
if url == get_current(): return
index += 1
history.resize(index)
history.push_back(url)
print_history()
func forw() -> String:
index += 1
print_history()
return history[index]
func back() -> String:
index -= 1
print_history()
if index == -1:
return ""
return history[index]
func clear() -> void:
index = -1
history.clear()
print_history()
func print_history() -> void:
# Debug.logclr("History: " + str(history) + " Current: " + str(index), Color.DIM_GRAY)
pass

View file

@ -0,0 +1,13 @@
extends Control
@export var ui_events: UiEvents
func _ready() -> void:
resized.connect(on_resized)
on_resized()
func on_resized() -> void:
Debug.logclr("Ui resized: %dx%d" % [size.x, size.y], Debug.SILENT_CLR)
ui_events.ui_size_changed_emit(size)

View file

@ -0,0 +1,80 @@
extends Node
@export var gate_events: GateEvents
@export var history: History
@export var go_back: BaseButton
@export var go_forw: BaseButton
@export var reload: BaseButton
@export var home: BaseButton
func _ready() -> void:
gate_events.open_gate.connect(on_new)
gate_events.search.connect(on_new)
go_back.pressed.connect(on_go_back)
go_forw.pressed.connect(on_go_forw)
reload.pressed.connect(on_reload)
home.pressed.connect(on_home)
disable([go_back, go_forw, reload, home])
func on_new(location: String) -> void:
history.add(location)
enable([go_back, reload, home])
if not history.can_forw():
disable([go_forw])
func on_go_back() -> void:
var location = history.back()
enable([go_forw])
if history.can_back():
open(location)
else:
disable([go_back, reload, home])
gate_events.exit_gate_emit()
func on_go_forw() -> void:
var location = history.forw()
enable([go_back])
if not history.can_forw():
disable([go_forw])
open(location)
func on_reload() -> void:
open(history.get_current())
func on_home() -> void:
history.clear()
disable([go_back, go_forw, reload, home])
gate_events.exit_gate_emit()
func open(location: String) -> void:
if Url.is_valid(location):
gate_events.open_gate_emit(location)
else:
gate_events.search_emit(location)
func disable(buttons: Array[BaseButton]) -> void:
for button in buttons:
button.disabled = true
button.modulate.a = 0.5
button.mouse_default_cursor_shape = Control.CURSOR_ARROW
func enable(buttons: Array[BaseButton]) -> void:
for button in buttons:
button.disabled = false
button.modulate.a = 1
button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND

View file

@ -0,0 +1,62 @@
extends Node
@export var gate_events: GateEvents
@export var bookmarks: Bookmarks
@export var star: Control
@export var unstar: Control
var gate: Gate
var url: String
func _ready() -> void:
star.visible = false
unstar.visible = false
gate_events.open_gate.connect(show_buttons)
gate_events.search.connect(func(_query): hide_buttons())
gate_events.exit_gate.connect(hide_buttons)
gate_events.gate_info_loaded.connect(update_info)
func show_buttons(_url: String) -> void:
url = _url
if bookmarks.gates.has(url):
star.visible = false
unstar.visible = true
else:
star.visible = true
unstar.visible = false
func hide_buttons() -> void:
star.visible = false
unstar.visible = false
gate = null
func update_info(_gate: Gate, _is_cached: bool) -> void:
gate = _gate
if bookmarks.gates.has(gate.url):
bookmarks.update(gate)
func _on_star_pressed() -> void:
if gate == null:
gate = Gate.new()
gate.url = url
bookmarks.star(gate)
star.visible = false
unstar.visible = true
func _on_unstar_pressed() -> void:
if gate == null:
gate = Gate.new()
gate.url = url
bookmarks.unstar(gate)
star.visible = true
unstar.visible = false

57
app/scripts/ui/search.gd Normal file
View file

@ -0,0 +1,57 @@
extends LineEdit
class_name Search
signal on_release_focus
signal on_navigation(event: int)
@export var gate_events: GateEvents
@export var prompt_panel: Control
func _ready() -> void:
gate_events.open_gate.connect(set_current_url)
gate_events.search.connect(set_current_url)
gate_events.exit_gate.connect(set_current_url.bind(""))
func set_current_url(_url: String) -> void:
text = _url
on_release_focus.emit()
func _on_text_submitted(_url: String) -> void:
open_gate()
func _on_go_pressed() -> void:
open_gate()
func open_gate() -> void:
if text.is_empty(): return
if Url.is_valid(text):
gate_events.open_gate_emit(text)
else:
gate_events.search_emit(text)
release_focus()
on_release_focus.emit()
func _input(event: InputEvent) -> void:
if not has_focus(): return
if (event is InputEventMouseButton
and not get_global_rect().has_point(event.position)
and not prompt_panel.get_global_rect().has_point(event.position)):
release_focus()
on_release_focus.emit()
if event.is_action_pressed("ui_text_caret_up"):
on_navigation.emit(PromptNavigation.UP)
get_viewport().set_input_as_handled()
elif event.is_action_pressed("ui_text_caret_down"):
on_navigation.emit(PromptNavigation.DOWN)
get_viewport().set_input_as_handled()

View file

@ -0,0 +1,24 @@
extends TextureRect
@export var duration: float
@export var start_scale: float
@export var end_scale: float
@onready var start := Vector2(start_scale, start_scale)
@onready var end := Vector2(end_scale, end_scale)
@onready var default = scale
func _ready() -> void:
animate()
func _notification(what: int) -> void:
if what == NOTIFICATION_ENABLED:
animate()
func animate() -> void:
var tween = create_tween().set_loops()
tween.tween_property(self, "scale", end, duration).from(start)
tween.tween_property(self, "scale", start, duration).from(end)

View file

@ -0,0 +1,6 @@
extends Control
func _ready() -> void:
await get_tree().process_frame
global_position = get_parent().global_position

View file

@ -0,0 +1,9 @@
extends RichTextLabel
func _ready() -> void:
finished.connect(to_line)
func to_line() -> void:
text = text.replace('\n', '\t') # TODO: Handle BBCode

View file

@ -0,0 +1,33 @@
extends Button
class_name PromptResult
@export var gate_events: GateEvents
@export var prompt_text: Label
@export var focus_style: StyleBox
var normal_style: StyleBox
func _ready() -> void:
normal_style = get_theme_stylebox("normal", "")
func fill(prompt: Dictionary) -> void:
if prompt == null: return
var txt: String = prompt["prompt"].to_lower()
txt = StringTools.to_alpha(txt)
prompt_text.text = txt
func _on_button_pressed() -> void:
if prompt_text.text.is_empty(): return
gate_events.search_emit(prompt_text.text)
func focus() -> void:
add_theme_stylebox_override("normal", focus_style)
func unfocus() -> void:
add_theme_stylebox_override("normal", normal_style)

View file

@ -0,0 +1,90 @@
extends Node
class_name PromptNavigation
enum {
UP,
DOWN
}
@export var search: Search
@export var prompt_results: PromptResults
var current_prompt: int = -1
var actual_search_query: String
func _ready() -> void:
search.focus_entered.connect(on_focus_entered)
search.on_release_focus.connect(on_release_focus)
search.on_navigation.connect(on_navigation)
search.text_changed.connect(func(_text): reset())
func on_focus_entered() -> void:
prompt_results._on_search_text_changed(search.text)
func on_release_focus() -> void:
prompt_results.clear()
reset()
func on_navigation(event: int) -> void:
match event:
UP:
prompt_up()
DOWN:
prompt_down()
_:
printerr("Unhandled navigation event")
func prompt_up() -> void:
var from: int = current_prompt
var to: int
if from == -1:
to = prompt_results.get_children().size() - 1
else:
to = from - 1
if from != to:
current_prompt = to
switch_prompt(from, to)
func prompt_down() -> void:
var from: int = current_prompt
var to: int
if from == prompt_results.get_children().size() - 1:
to = -1
else:
to = from + 1
if from != to:
current_prompt = to
switch_prompt(from, to)
func reset() -> void:
current_prompt = -1
actual_search_query = ""
func switch_prompt(from: int, to: int) -> void:
if from == -1:
actual_search_query = search.text
else:
var from_prompt: PromptResult = prompt_results.get_children()[from]
from_prompt.unfocus()
if to == -1:
search.text = actual_search_query
search.caret_column = search.text.length()
else:
var to_prompt: PromptResult = prompt_results.get_children()[to]
to_prompt.focus()
search.text = to_prompt.prompt_text.text
search.caret_column = search.text.length()

View file

@ -0,0 +1,60 @@
extends VBoxContainer
class_name PromptResults
@export var gate_events: GateEvents
@export var api: ApiSettings
@export var result_scene: PackedScene
@export var panel: Control
var prompt_size: float
var result_str: String
func _ready() -> void:
var prompt: Control = result_scene.instantiate()
prompt_size = prompt.size.y
prompt.queue_free()
panel.visible = true
clear()
func _on_search_text_changed(query: String) -> void:
if query.is_empty(): clear(); return
await prompt_request(query)
clear()
var prompts: Array = JSON.parse_string(result_str)
if prompts == null or prompts.is_empty():
return
for prompt in prompts:
var result: PromptResult = result_scene.instantiate()
result.fill(prompt)
add_child(result)
change_size(prompts.size())
func prompt_request(query: String) -> void:
var url = api.prompt + query.uri_encode()
var callback = func(_result, code, _headers, body):
if code == 200:
result_str = body.get_string_from_utf8()
else: Debug.logclr("Request prompt failed. Code " + str(code), Color.RED)
var err = await Backend.request(url, callback)
if err != HTTPRequest.RESULT_SUCCESS: Debug.logclr("Cannot send request prompt", Color.RED)
func clear() -> void:
for child in get_children():
child.queue_free()
remove_child(child)
change_size(0)
func change_size(promt_count: int) -> void:
panel.size = Vector2(panel.size.x, promt_count * prompt_size)

View file

@ -0,0 +1,25 @@
extends Control
class_name SearchResult
@export var gate_events: GateEvents
@export var url: Label
@export var title: Label
@export var description: RichTextLabel
@export var image: TextureRect
func fill(gate: Dictionary) -> void:
if gate == null: return
url.text = gate["url"]
title.text = "Unnamed" if gate["title"].is_empty() else gate["title"]
description.text = gate["description"]
var image_path = await FileDownloader.download(gate["image"])
image.texture = FileTools.load_external_tex(image_path)
func _on_button_pressed() -> void:
if url.text.is_empty(): return
gate_events.open_gate_emit(url.text)

View file

@ -0,0 +1,38 @@
extends VBoxContainer
@export var gate_events: GateEvents
@export var api: ApiSettings
@export var result_scene: PackedScene
var result_str: String = "{}"
func _ready() -> void:
search(gate_events.current_search_query)
func search(query: String) -> void:
Debug.logclr("======== " + query + " ========", Color.LIGHT_SEA_GREEN)
await search_request(query)
var gates = JSON.parse_string(result_str)
if gates == null or gates.is_empty():
Debug.logclr("No gates found", Color.YELLOW)
return
for gate in gates:
var result: SearchResult = result_scene.instantiate()
result.fill(gate)
add_child(result)
Debug.logr(gate["url"])
func search_request(query: String) -> void:
var url = api.search + query.uri_encode()
var callback = func(_result, code, _headers, body):
if code == 200:
result_str = body.get_string_from_utf8()
else: Debug.logclr("Request search failed. Code " + str(code), Color.RED)
var err = await Backend.request(url, callback)
if err != HTTPRequest.RESULT_SUCCESS: Debug.logclr("Cannot send request search", Color.RED)

View file

@ -0,0 +1,32 @@
extends Control
@export var gate_events: GateEvents
@export var search_line_edit: LineEdit
@export var search: Control
@export var downloading: Control
@export var success: Control
@export var error: Control
func _ready() -> void:
search_line_edit.text_changed.connect(func(_text): switch_to(search))
gate_events.search.connect(func(_url): switch_to(search))
gate_events.exit_gate.connect(func(): switch_to(search))
gate_events.open_gate.connect(func(_url): switch_to(downloading))
gate_events.gate_entered.connect(func(): switch_to(success))
gate_events.gate_error.connect(func(_code): switch_to(error))
switch_to(search)
func switch_to(_state: Control) -> void:
disable([search, downloading, success, error])
_state.visible = true
_state.process_mode = Node.PROCESS_MODE_INHERIT
func disable(states: Array[Control]) -> void:
for state in states:
state.visible = false
state.process_mode = Node.PROCESS_MODE_DISABLED

View file

@ -0,0 +1,12 @@
extends BaseButton
@export var gate_events: GateEvents
func _ready() -> void:
visible = false
func _on_search_text_changed(_url: String) -> void:
#visible = true if not _url.is_empty() else false
pass

View file

@ -0,0 +1,25 @@
extends Control
@export var gate_events: GateEvents
@export var image: TextureRect
@export var title: Label
@export var description: RichTextLabel
var gate: Gate
func _ready() -> void:
gate_events.gate_info_loaded.connect(display_info)
gate_events.gate_error.connect(on_gate_error)
func display_info(_gate: Gate, _is_cached: bool) -> void:
gate = _gate
title.text = "Unnamed" if gate.title.is_empty() else gate.title
description.text = "No description" if gate.description.is_empty() else gate.description
image.texture = FileTools.load_external_tex(gate.image)
func on_gate_error(_code: GateEvents.GateError) -> void:
description.set_text("")

View file

@ -0,0 +1,34 @@
extends Label
@export var gate_events: GateEvents
func _ready() -> void:
gate_events.gate_info_loaded.connect(func(_gate, _is_cached): on_gate_info_loaded())
gate_events.gate_entered.connect(on_gate_entered)
gate_events.gate_error.connect(on_gate_error)
set_text("Connecting...")
func on_gate_info_loaded() -> void:
gate_events.download_progress.connect(show_progress)
func show_progress(_url: String, body_size: int, downloaded_bytes: int) -> void:
var percent = int(downloaded_bytes * 100 / body_size)
set_text("Downloading: %d%s" % [percent, "%"])
func on_gate_entered() -> void:
gate_events.download_progress.disconnect(show_progress)
set_text("")
func on_gate_error(code: GateEvents.GateError) -> void:
match code:
GateEvents.GateError.NOT_FOUND:
set_text("Gate not found")
GateEvents.GateError.MISSING_PACK, GateEvents.GateError.MISSING_LIBS:
set_text("Cannot load gate resources")
_:
set_text("Error")

View file

@ -0,0 +1,12 @@
extends Control
@export var gate_events: GateEvents
func _ready() -> void:
gate_events.gate_entered.connect(hide_ui)
visible = true
func hide_ui() -> void:
visible = false

View file

@ -0,0 +1,8 @@
extends Control
func _input(event: InputEvent) -> void:
if (has_focus()
and event is InputEventMouseButton
and not get_global_rect().has_point(event.position)):
release_focus()

View file

@ -0,0 +1,24 @@
extends Control
@export var ui_events: UiEvents
@export var interpolate: float:
set(value):
interpolate = value
animate(value)
var initial: int
var full_screen: int
func _ready() -> void:
var viewport_width = ProjectSettings.get_setting("display/window/size/viewport_width", 1152)
var scale_width = float(custom_minimum_size.x) / viewport_width
full_screen = int(ui_events.current_ui_size.x)
initial = int(full_screen * scale_width)
custom_minimum_size.x = initial
Debug.logclr("WorldCanvas initial: %d full_screen: %d" % [initial, full_screen], Color.DIM_GRAY)
func animate(value: float) -> void:
custom_minimum_size.x = lerp(initial, full_screen, value)

View file

@ -0,0 +1,42 @@
extends Control
@export var ui_events: UiEvents
@export var gate_events: GateEvents
@export var command_events: CommandEvents
var mouse_mode: int = Input.MOUSE_MODE_VISIBLE
var _visible: bool = true
func _ready() -> void:
command_events.set_mouse_mode.connect(set_mouse_mode)
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
func set_mouse_mode(mode: int) -> void:
mouse_mode = mode
if not _visible: Input.set_mouse_mode(mode)
func _input(event: InputEvent) -> void:
if event.is_action_pressed("show_ui") and not event.is_echo():
if _visible:
hide_ui()
else:
show_ui()
func show_ui() -> void:
if _visible: return
_visible = true
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
ui_events.ui_mode_changed_emit(UiEvents.UiMode.INITIAL)
func hide_ui() -> void:
if not _visible: return
_visible = false
Input.set_mouse_mode(mouse_mode)
ui_events.ui_mode_changed_emit(UiEvents.UiMode.FULL_SCREEN)