claude godot 4 port
This commit is contained in:
@@ -6,91 +6,94 @@
|
||||
## is treated as a separate tab. You might also want to hide
|
||||
## the horizontal scroll bar at the bottom, as it does nothing
|
||||
|
||||
@tool
|
||||
extends ScrollContainer
|
||||
|
||||
signal tab_switched(tab)
|
||||
|
||||
onready var tabs_holder := MarginContainer.new()
|
||||
onready var children := get_children()
|
||||
onready var sizex := rect_size.x
|
||||
@onready var tabs_holder := MarginContainer.new()
|
||||
@onready var _initial_children := get_children()
|
||||
@onready var sizex: float = size.x
|
||||
|
||||
export(int) var current_tab = 0
|
||||
export(float) var swipe_threshold = 128.0
|
||||
export(bool) var smooth_switch = true
|
||||
export(float) var switch_power = 5.0
|
||||
@export var current_tab: int = 0
|
||||
@export var swipe_threshold: float = 128.0
|
||||
@export var smooth_switch: bool = true
|
||||
@export var switch_power: float = 5.0
|
||||
|
||||
var children: Array = []
|
||||
var scroll_velocity := Vector2.ZERO
|
||||
var scrolling := false
|
||||
var target_scroll := 0.0
|
||||
var current_scroll := 0.0
|
||||
var prev_on_tab := false
|
||||
var drag_init_pos := Vector2.ZERO
|
||||
var scrolling := false
|
||||
var target_scroll: float = 0.0
|
||||
var current_scroll: float = 0.0
|
||||
var prev_on_tab := false
|
||||
var drag_init_pos := Vector2.ZERO
|
||||
var swipe_threshold_reached := false
|
||||
var scrolled_with_wheel := false
|
||||
|
||||
func _ready() -> void:
|
||||
# add a tab holder to the container and move all the children to it
|
||||
add_child(tabs_holder)
|
||||
for child in children:
|
||||
for child in _initial_children:
|
||||
if(child is ScrollBar): continue
|
||||
remove_child(child)
|
||||
tabs_holder.add_child(child)
|
||||
child.mouse_filter = Control.MOUSE_FILTER_PASS
|
||||
children = tabs_holder.get_children()
|
||||
|
||||
|
||||
# adjust all the properties of the containers
|
||||
scroll_vertical_enabled = false
|
||||
scroll_horizontal_enabled = true
|
||||
tabs_holder.size_flags_vertical = 3
|
||||
vertical_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
||||
horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_AUTO
|
||||
tabs_holder.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
tabs_holder.mouse_filter = Control.MOUSE_FILTER_PASS
|
||||
|
||||
|
||||
# connect required signals
|
||||
get_tree().get_root().connect("size_changed", self, "resize")
|
||||
tabs_holder.connect("sort_children", self, "resize")
|
||||
connect("gui_input", self, "_manage_input")
|
||||
get_tree().get_root().size_changed.connect(resize)
|
||||
tabs_holder.sort_children.connect(resize)
|
||||
gui_input.connect(_manage_input)
|
||||
resize()
|
||||
switch_tab()
|
||||
update_target_scroll(true)
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if scrolling:
|
||||
current_scroll = scroll_horizontal
|
||||
else:
|
||||
# smoothly scroll to the current tab
|
||||
if prev_on_tab or scrolled_with_wheel: current_scroll = target_scroll
|
||||
else: current_scroll += (target_scroll - scroll_horizontal) * 8.0 * delta
|
||||
if prev_on_tab or scrolled_with_wheel:
|
||||
current_scroll = target_scroll
|
||||
else:
|
||||
current_scroll += (target_scroll - scroll_horizontal) * 8.0 * delta
|
||||
scroll_horizontal = current_scroll
|
||||
|
||||
|
||||
# prevent actual mouse wheel scrolling
|
||||
prev_on_tab = abs(current_scroll - target_scroll) < 1
|
||||
|
||||
|
||||
func resize() -> void:
|
||||
# handle window resizing
|
||||
sizex = rect_size.x
|
||||
tabs_holder.rect_min_size.x = sizex * children.size()
|
||||
|
||||
sizex = size.x
|
||||
tabs_holder.custom_minimum_size.x = sizex * children.size()
|
||||
|
||||
var childi := 0
|
||||
for child in children:
|
||||
child.rect_size.x = sizex
|
||||
child.rect_position.x = sizex * childi
|
||||
child.size.x = sizex
|
||||
child.position.x = sizex * childi
|
||||
childi += 1
|
||||
|
||||
|
||||
update_target_scroll(true)
|
||||
|
||||
|
||||
func _manage_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
# when the drag is stopped, end scrolling
|
||||
if event.button_index in [BUTTON_WHEEL_UP, BUTTON_WHEEL_DOWN, BUTTON_WHEEL_LEFT, BUTTON_WHEEL_RIGHT]:
|
||||
if event.button_index in [MOUSE_BUTTON_WHEEL_UP, MOUSE_BUTTON_WHEEL_DOWN, MOUSE_BUTTON_WHEEL_LEFT, MOUSE_BUTTON_WHEEL_RIGHT]:
|
||||
scrolled_with_wheel = true
|
||||
|
||||
|
||||
elif event is InputEventScreenDrag:
|
||||
scroll_velocity = event.relative
|
||||
|
||||
|
||||
# check for swipe threshold
|
||||
if not swipe_threshold_reached:
|
||||
#scroll_horizontal = target_scroll
|
||||
var diff = abs(drag_init_pos.x - event.position.x)
|
||||
if diff > swipe_threshold:
|
||||
if diff > swipe_threshold:
|
||||
swipe_threshold_reached = true
|
||||
else:
|
||||
scroll_horizontal = target_scroll
|
||||
@@ -98,7 +101,7 @@ func _manage_input(event: InputEvent) -> void:
|
||||
# fake scroll, because for some reason, real scrolling stops
|
||||
current_scroll -= event.relative.x
|
||||
scroll_horizontal = current_scroll
|
||||
|
||||
|
||||
elif event is InputEventScreenTouch:
|
||||
if event.is_pressed():
|
||||
scrolling = true
|
||||
@@ -107,28 +110,28 @@ func _manage_input(event: InputEvent) -> void:
|
||||
scrolled_with_wheel = false
|
||||
else:
|
||||
end_scroll()
|
||||
|
||||
|
||||
func end_scroll() -> void:
|
||||
# calculate current tab, based on the horizontal scroll and the drag velocity
|
||||
# calculate current tab, based on the horizontal scroll and the drag velocity
|
||||
# and then switch to it
|
||||
current_tab = int(clamp(round((scroll_horizontal - min(scroll_velocity.x * switch_power, sizex)) / sizex), 0, children.size()-1))
|
||||
current_tab = int(clamp(round((scroll_horizontal - min(scroll_velocity.x * switch_power, sizex)) / sizex), 0, children.size() - 1))
|
||||
switch_tab()
|
||||
scroll_velocity = Vector2.ZERO
|
||||
scrolling = false
|
||||
|
||||
func update_target_scroll(instant:bool=false) -> void:
|
||||
|
||||
func update_target_scroll(instant: bool = false) -> void:
|
||||
# calculate horizontal scrolling required to fully switch to a single tab, with no overlaps
|
||||
# if instant is true, also update the current scroll
|
||||
target_scroll = current_tab * sizex
|
||||
if instant:
|
||||
if instant:
|
||||
current_scroll = target_scroll
|
||||
scroll_horizontal = current_scroll
|
||||
scroll_horizontal = int(current_scroll)
|
||||
else:
|
||||
prev_on_tab = false
|
||||
|
||||
func switch_tab(tab:int=-1) -> void:
|
||||
if tab >= 0:
|
||||
|
||||
func switch_tab(tab: int = -1) -> void:
|
||||
if tab >= 0:
|
||||
current_tab = tab
|
||||
scrolled_with_wheel = false
|
||||
update_target_scroll(!smooth_switch)
|
||||
emit_signal("tab_switched", current_tab)
|
||||
tab_switched.emit(current_tab)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://ci1vctgruq15r
|
||||
@@ -1,8 +1,9 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/class-icon.svg-c87135634ec50ad20a48fb432e8b6f1f.stex"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bovq2qx32oqyb"
|
||||
path="res://.godot/imported/class-icon.svg-c87135634ec50ad20a48fb432e8b6f1f.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
@@ -10,26 +11,33 @@ metadata={
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/BetterTabContainer/class-icon.svg"
|
||||
dest_files=[ "res://.import/class-icon.svg-c87135634ec50ad20a48fb432e8b6f1f.stex" ]
|
||||
dest_files=["res://.godot/imported/class-icon.svg-c87135634ec50ad20a48fb432e8b6f1f.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
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/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
tool
|
||||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://iimqt42rdljf
|
||||
+30
-34
@@ -1,80 +1,76 @@
|
||||
@tool
|
||||
extends Node
|
||||
class_name WeatherAPINode
|
||||
tool
|
||||
|
||||
signal received_current(json)
|
||||
signal received_forecast(json)
|
||||
|
||||
export var api_key:String
|
||||
export var location:String = "Amsterdam"
|
||||
@export var api_key: String
|
||||
@export var location: String = "Amsterdam"
|
||||
|
||||
export var base_url := "http://api.weatherapi.com/v1/" setget set_base_url
|
||||
@export var base_url: String = "http://api.weatherapi.com/v1/":
|
||||
set = set_base_url
|
||||
var http = HTTPRequest.new()
|
||||
|
||||
var current_history := []
|
||||
var forecast_history := []
|
||||
|
||||
func set_base_url(newurl:String):
|
||||
func set_base_url(newurl: String):
|
||||
if not newurl.begins_with('http://') and not newurl.begins_with('https://'):
|
||||
newurl = 'http://'+newurl
|
||||
newurl = 'http://' + newurl
|
||||
if !newurl.ends_with('/'):
|
||||
newurl += '/'
|
||||
base_url = newurl
|
||||
|
||||
func _ready():
|
||||
add_child(http)
|
||||
http.connect("request_completed", self, "_on_http_response")
|
||||
|
||||
func get_current(include_air_quality:=false):
|
||||
func get_current(include_air_quality: bool = false):
|
||||
var url = _form_url('current.json', {'aqi': 'yes' if include_air_quality else 'no'})
|
||||
print(url)
|
||||
var out = yield(_wait_on_request(url), "completed")
|
||||
var out = await _wait_on_request(url)
|
||||
if out[0]:
|
||||
current_history.append(out)
|
||||
out = JSON.parse(out[-1]).result
|
||||
emit_signal("received_current",out)
|
||||
return out
|
||||
var parsed = JSON.parse_string(out[-1])
|
||||
received_current.emit(parsed)
|
||||
return parsed
|
||||
else:
|
||||
print("no answer")
|
||||
return out[1]
|
||||
|
||||
func _bool2YN(b:bool):
|
||||
func _bool2YN(b: bool):
|
||||
return 'yes' if b else 'no'
|
||||
|
||||
func get_forecast(days:=1, include_air_quality:=false, alerts:=false):
|
||||
var url = _form_url('current.json', {'aqi': _bool2YN(include_air_quality), 'days':days, 'alerts':_bool2YN(alerts)})
|
||||
var out = yield(_wait_on_request(url), "completed")
|
||||
func get_forecast(days: int = 1, include_air_quality: bool = false, alerts: bool = false):
|
||||
var url = _form_url('current.json', {'aqi': _bool2YN(include_air_quality), 'days': days, 'alerts': _bool2YN(alerts)})
|
||||
var out = await _wait_on_request(url)
|
||||
if out[0]:
|
||||
out = JSON.parse(out[-1]).result
|
||||
current_history.append(out)
|
||||
forecast_history.append(out)
|
||||
emit_signal("received_forecast",out)
|
||||
emit_signal("received_current",out)
|
||||
return out
|
||||
var parsed = JSON.parse_string(out[-1])
|
||||
current_history.append(parsed)
|
||||
forecast_history.append(parsed)
|
||||
received_forecast.emit(parsed)
|
||||
received_current.emit(parsed)
|
||||
return parsed
|
||||
else:
|
||||
return out[1]
|
||||
|
||||
func _wait_on_request(url)->Array:
|
||||
func _wait_on_request(url) -> Array:
|
||||
# Returns:
|
||||
# when answered: [http was answered<bool>, result, response_code, headers, raw_body, utf8_body]
|
||||
# when not answered: [false, error]
|
||||
var err = http.request(url)
|
||||
if err == OK:
|
||||
var out = yield(http, "request_completed")
|
||||
out.append(out[-1].get_string_from_utf8())
|
||||
return [true] + out
|
||||
yield()
|
||||
var result = await http.request_completed
|
||||
result.append(result[-1].get_string_from_utf8())
|
||||
return [true] + result
|
||||
return [false, err]
|
||||
|
||||
func _form_url(endpoint:='current.json', args:={}):
|
||||
func _form_url(endpoint: String = 'current.json', args: Dictionary = {}):
|
||||
if endpoint.ends_with('/'):
|
||||
endpoint = endpoint.substr(0,len(endpoint))
|
||||
endpoint = endpoint.substr(0, len(endpoint))
|
||||
var out = base_url + endpoint
|
||||
out += '?key='+api_key
|
||||
out += '&q='+location
|
||||
out += '?key=' + api_key
|
||||
out += '&q=' + location
|
||||
for key in args:
|
||||
out += '&{0}={1}'.format([key, args[key]])
|
||||
return out
|
||||
|
||||
func _on_http_response(result: int, response_code: int, headers: PoolStringArray, body: PoolByteArray):
|
||||
pass
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://cdts80k64rgos
|
||||
@@ -0,0 +1 @@
|
||||
uid://dbo4hxroi7ggj
|
||||
@@ -1,4 +1,4 @@
|
||||
tool
|
||||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://bs1adwqasxy73
|
||||
Reference in New Issue
Block a user