Checkpoint Player Menu visual revisions
This commit is contained in:
parent
bcffe2013d
commit
5af84eaf47
29 changed files with 3236 additions and 628 deletions
|
|
@ -26,8 +26,8 @@ const DEFORMATION_Y_AMPLITUDE: float = 0.007
|
|||
|
||||
@export_range(0, PlayerHotbarType.SLOT_COUNT - 1, 1) var slot_index: int = 0
|
||||
@export_group("Authored Layout")
|
||||
@export var desktop_size: Vector2 = Vector2(80.0, 78.0)
|
||||
@export var compact_size: Vector2 = Vector2(56.0, 54.0)
|
||||
@export var desktop_size: Vector2 = Vector2(78.0, 78.0)
|
||||
@export var compact_size: Vector2 = Vector2(54.0, 54.0)
|
||||
@export var desktop_anchor: Vector2 = Vector2.ZERO
|
||||
@export var compact_anchor: Vector2 = Vector2.ZERO
|
||||
@export_group("Motion")
|
||||
|
|
@ -204,29 +204,31 @@ func _apply_style() -> void:
|
|||
return
|
||||
var normal_fill: Color = profile.normal_fill
|
||||
normal_fill.a = 1.0
|
||||
var normal_border: Color = profile.normal_border
|
||||
var normal_border_width: int = profile.normal_border_width
|
||||
var selected_fill: Color = normal_fill
|
||||
if _selected:
|
||||
normal_border = profile.pressed_border
|
||||
normal_border_width = profile.emphasized_border_width
|
||||
selected_fill = normal_fill.lightened(0.12)
|
||||
add_theme_stylebox_override(
|
||||
"normal",
|
||||
_make_style(normal_fill, normal_border, normal_border_width)
|
||||
_make_style(
|
||||
selected_fill,
|
||||
5 if _selected else 2,
|
||||
0.38 if _selected else 0.20,
|
||||
)
|
||||
)
|
||||
add_theme_stylebox_override(
|
||||
"hover",
|
||||
_make_style(
|
||||
normal_fill,
|
||||
profile.hover_border,
|
||||
profile.emphasized_border_width
|
||||
selected_fill.lightened(0.055),
|
||||
5 if _selected else 3,
|
||||
0.40 if _selected else 0.29,
|
||||
)
|
||||
)
|
||||
add_theme_stylebox_override(
|
||||
"pressed",
|
||||
_make_style(
|
||||
normal_fill,
|
||||
profile.pressed_border,
|
||||
profile.emphasized_border_width
|
||||
selected_fill.lightened(0.085),
|
||||
6,
|
||||
0.44,
|
||||
)
|
||||
)
|
||||
add_theme_stylebox_override(
|
||||
|
|
@ -237,8 +239,8 @@ func _apply_style() -> void:
|
|||
"disabled",
|
||||
_make_style(
|
||||
normal_fill,
|
||||
profile.disabled_border,
|
||||
profile.normal_border_width
|
||||
1,
|
||||
0.12,
|
||||
)
|
||||
)
|
||||
add_theme_color_override("font_color", profile.text_color)
|
||||
|
|
@ -249,21 +251,20 @@ func _apply_style() -> void:
|
|||
|
||||
func _make_style(
|
||||
fill_color: Color,
|
||||
border_color: Color,
|
||||
border_width: int,
|
||||
shadow_size: int,
|
||||
shadow_alpha: float,
|
||||
) -> StyleBoxFlat:
|
||||
var style := StyleBoxFlat.new()
|
||||
style.bg_color = fill_color
|
||||
style.border_color = border_color
|
||||
style.border_width_left = border_width
|
||||
style.border_width_top = border_width
|
||||
style.border_width_right = border_width
|
||||
style.border_width_bottom = border_width
|
||||
style.set_border_width_all(0)
|
||||
var radius: int = ceili(maxf(_presented_size.x, _presented_size.y) * 0.5)
|
||||
style.corner_radius_top_left = radius
|
||||
style.corner_radius_top_right = radius
|
||||
style.corner_radius_bottom_right = radius
|
||||
style.corner_radius_bottom_left = radius
|
||||
style.shadow_color = Color(0.015, 0.06, 0.09, shadow_alpha)
|
||||
style.shadow_size = shadow_size
|
||||
style.shadow_offset = Vector2(0.0, 2.0)
|
||||
return style
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
[ext_resource type="Theme" path="res://ui/game_theme.tres" id="3_theme"]
|
||||
|
||||
[node name="BubbleHotbarSlot" type="Button"]
|
||||
custom_minimum_size = Vector2(80, 78)
|
||||
custom_minimum_size = Vector2(78, 78)
|
||||
focus_mode = 0
|
||||
mouse_default_cursor_shape = 2
|
||||
theme = ExtResource("3_theme")
|
||||
|
|
|
|||
131
ui/components/bubble_menu/bag_item_sprite.gd
Normal file
131
ui/components/bubble_menu/bag_item_sprite.gd
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
class_name BagItemSprite
|
||||
extends ItemDragSource
|
||||
|
||||
signal drag_started
|
||||
signal drag_finished
|
||||
|
||||
@onready var _visual_root: Control = %VisualRoot
|
||||
@onready var _item_texture: TextureRect = %ItemTexture
|
||||
@onready var _quantity_badge: PanelContainer = %QuantityBadge
|
||||
@onready var _quantity_label: Label = %QuantityLabel
|
||||
@onready var _compatibility_marker: Label = %CompatibilityMarker
|
||||
|
||||
var _motion_phase: float = 0.0
|
||||
var _depth_scale: float = 1.0
|
||||
var _selected: bool = false
|
||||
var _hovered: bool = false
|
||||
var _dragging: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
mouse_entered.connect(_set_hovered.bind(true))
|
||||
mouse_exited.connect(_set_hovered.bind(false))
|
||||
focus_entered.connect(_refresh_style)
|
||||
focus_exited.connect(_refresh_style)
|
||||
resized.connect(_update_visual_pivot)
|
||||
_update_visual_pivot()
|
||||
_apply_quantity_style()
|
||||
_refresh_style()
|
||||
|
||||
|
||||
func configure_item(
|
||||
new_item_id: StringName,
|
||||
new_item_name: String,
|
||||
new_icon: Texture2D,
|
||||
quantity: int,
|
||||
hotbar_compatible: bool,
|
||||
phase: float,
|
||||
depth_scale: float,
|
||||
) -> void:
|
||||
setup(new_item_id, new_item_name, new_icon)
|
||||
_item_texture.texture = new_icon
|
||||
_quantity_label.text = "×%d" % quantity
|
||||
_quantity_badge.visible = quantity > 1
|
||||
_compatibility_marker.visible = not hotbar_compatible
|
||||
_motion_phase = phase
|
||||
_depth_scale = depth_scale
|
||||
|
||||
|
||||
func set_selected(selected: bool) -> void:
|
||||
_selected = selected
|
||||
_refresh_style()
|
||||
|
||||
|
||||
func advance_presentation(elapsed: float, motion_enabled: bool) -> void:
|
||||
if not motion_enabled or _dragging:
|
||||
return
|
||||
var bob: float = sin(elapsed * TAU / 7.4 + _motion_phase) * 0.9
|
||||
var tilt: float = sin(
|
||||
elapsed * TAU / 10.2 + _motion_phase * 1.29
|
||||
) * 0.014
|
||||
_visual_root.position = Vector2(0.0, bob)
|
||||
_visual_root.rotation = tilt
|
||||
var emphasis: float = 1.04 if _hovered or has_focus() else 1.0
|
||||
_visual_root.scale = Vector2.ONE * _depth_scale * emphasis
|
||||
|
||||
|
||||
func _get_drag_data(at_position: Vector2) -> Variant:
|
||||
var payload: Variant = super(at_position)
|
||||
if payload != null:
|
||||
_dragging = true
|
||||
drag_started.emit()
|
||||
return payload
|
||||
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_DRAG_END and _dragging:
|
||||
_dragging = false
|
||||
drag_finished.emit()
|
||||
|
||||
|
||||
func _has_point(point: Vector2) -> bool:
|
||||
var radius: Vector2 = size * Vector2(0.46, 0.42)
|
||||
if radius.x <= 0.0 or radius.y <= 0.0:
|
||||
return false
|
||||
var normalized: Vector2 = (point - size * 0.5) / radius
|
||||
return normalized.length_squared() <= 1.0
|
||||
|
||||
|
||||
func _set_hovered(hovered: bool) -> void:
|
||||
_hovered = hovered
|
||||
_refresh_style()
|
||||
|
||||
|
||||
func _update_visual_pivot() -> void:
|
||||
_visual_root.pivot_offset = size * 0.5
|
||||
|
||||
|
||||
func _refresh_style() -> void:
|
||||
var style := StyleBoxFlat.new()
|
||||
style.bg_color = Color(0.95, 0.9, 0.75, 0.12) if _selected else Color.TRANSPARENT
|
||||
style.border_color = Color.TRANSPARENT
|
||||
var width: int = 0
|
||||
if _selected:
|
||||
style.border_color = Color(0.28, 0.19, 0.1, 1.0)
|
||||
width = 4
|
||||
if has_focus():
|
||||
style.border_color = Color(0.035, 0.145, 0.22, 1.0)
|
||||
width = 4
|
||||
elif _hovered:
|
||||
style.border_color = Color(0.48, 0.35, 0.2, 0.9)
|
||||
width = 2
|
||||
style.set_border_width_all(width)
|
||||
style.set_corner_radius_all(64)
|
||||
for state: StringName in [
|
||||
&"normal",
|
||||
&"hover",
|
||||
&"focus",
|
||||
&"pressed",
|
||||
]:
|
||||
add_theme_stylebox_override(state, style)
|
||||
|
||||
|
||||
func _apply_quantity_style() -> void:
|
||||
var style := StyleBoxFlat.new()
|
||||
style.bg_color = Color(0.94, 0.86, 0.64, 1.0)
|
||||
style.border_color = Color(0.31, 0.22, 0.12, 1.0)
|
||||
style.set_border_width_all(2)
|
||||
style.set_corner_radius_all(18)
|
||||
style.content_margin_left = 5.0
|
||||
style.content_margin_right = 5.0
|
||||
_quantity_badge.add_theme_stylebox_override("panel", style)
|
||||
1
ui/components/bubble_menu/bag_item_sprite.gd.uid
Normal file
1
ui/components/bubble_menu/bag_item_sprite.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dgbagitemsprite2026
|
||||
83
ui/components/bubble_menu/bag_item_sprite.tscn
Normal file
83
ui/components/bubble_menu/bag_item_sprite.tscn
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/components/bubble_menu/bag_item_sprite.gd" id="1_script"]
|
||||
|
||||
[node name="BagItemSprite" type="Button"]
|
||||
custom_minimum_size = Vector2(118, 86)
|
||||
focus_mode = 1
|
||||
mouse_default_cursor_shape = 2
|
||||
script = ExtResource("1_script")
|
||||
|
||||
[node name="VisualRoot" type="Control" parent="."]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="ItemTexture" type="TextureRect" parent="VisualRoot"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 10.0
|
||||
offset_top = 8.0
|
||||
offset_right = -10.0
|
||||
offset_bottom = -8.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
texture_filter = 1
|
||||
expand_mode = 1
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="QuantityBadge" type="PanelContainer" parent="VisualRoot"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 3
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -42.0
|
||||
offset_top = -28.0
|
||||
offset_right = -2.0
|
||||
offset_bottom = -2.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="QuantityLabel" type="Label" parent="VisualRoot/QuantityBadge"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
theme_override_colors/font_color = Color(0.17, 0.105, 0.05, 1)
|
||||
theme_override_font_sizes/font_size = 15
|
||||
text = "×2"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="CompatibilityMarker" type="Label" parent="VisualRoot"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 1
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -28.0
|
||||
offset_top = 0.0
|
||||
offset_right = -2.0
|
||||
offset_bottom = 24.0
|
||||
grow_horizontal = 0
|
||||
mouse_filter = 2
|
||||
theme_override_colors/font_color = Color(0.31, 0.22, 0.12, 1)
|
||||
theme_override_colors/font_outline_color = Color(0.96, 0.93, 0.82, 1)
|
||||
theme_override_constants/outline_size = 2
|
||||
theme_override_font_sizes/font_size = 17
|
||||
text = "×"
|
||||
horizontal_alignment = 1
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
class_name BubbleInventoryCell
|
||||
extends Button
|
||||
|
||||
@export var profile: BubbleMenuProfile
|
||||
|
||||
@onready var _icon: TextureRect = %Icon
|
||||
@onready var _primary_label: Label = %PrimaryLabel
|
||||
@onready var _secondary_label: Label = %SecondaryLabel
|
||||
@onready var _favorite_marker: Label = %FavoriteMarker
|
||||
@onready var _selected_marker: Label = %SelectedMarker
|
||||
|
||||
var _selected: bool = false
|
||||
var _focused_item: bool = false
|
||||
var _compact: bool = false
|
||||
var _icon_texture: Texture2D
|
||||
var _primary_text: String = ""
|
||||
var _secondary_text: String = ""
|
||||
var _favorite: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
focus_entered.connect(_refresh_style)
|
||||
focus_exited.connect(_refresh_style)
|
||||
_apply_compact_layout()
|
||||
_apply_content()
|
||||
_refresh_style()
|
||||
|
||||
|
||||
func configure(
|
||||
icon_texture: Texture2D,
|
||||
primary_text: String,
|
||||
secondary_text: String,
|
||||
) -> void:
|
||||
_icon_texture = icon_texture
|
||||
_primary_text = primary_text
|
||||
_secondary_text = secondary_text
|
||||
if is_node_ready():
|
||||
_apply_content()
|
||||
|
||||
|
||||
func set_item_state(
|
||||
selected: bool,
|
||||
focused_item: bool,
|
||||
favorite: bool,
|
||||
) -> void:
|
||||
_selected = selected
|
||||
_focused_item = focused_item
|
||||
_favorite = favorite
|
||||
if is_node_ready():
|
||||
_apply_content()
|
||||
_refresh_style()
|
||||
|
||||
|
||||
func set_compact(compact: bool) -> void:
|
||||
_compact = compact
|
||||
if not is_node_ready():
|
||||
custom_minimum_size = (
|
||||
Vector2(104.0, 98.0)
|
||||
if compact
|
||||
else Vector2(144.0, 136.0)
|
||||
)
|
||||
return
|
||||
_apply_compact_layout()
|
||||
|
||||
|
||||
func _apply_compact_layout() -> void:
|
||||
custom_minimum_size = (
|
||||
Vector2(104.0, 98.0)
|
||||
if _compact
|
||||
else Vector2(144.0, 136.0)
|
||||
)
|
||||
_icon.custom_minimum_size = (
|
||||
Vector2(72.0, 44.0)
|
||||
if _compact
|
||||
else Vector2(104.0, 68.0)
|
||||
)
|
||||
_primary_label.add_theme_font_size_override(
|
||||
"font_size",
|
||||
15 if _compact else 18,
|
||||
)
|
||||
_secondary_label.add_theme_font_size_override(
|
||||
"font_size",
|
||||
13 if _compact else 15,
|
||||
)
|
||||
|
||||
|
||||
func _apply_content() -> void:
|
||||
_icon.texture = _icon_texture
|
||||
_primary_label.text = _primary_text
|
||||
_secondary_label.text = _secondary_text
|
||||
_selected_marker.visible = _selected
|
||||
_favorite_marker.visible = _favorite
|
||||
|
||||
|
||||
func _has_point(point: Vector2) -> bool:
|
||||
var radius: Vector2 = size * 0.5
|
||||
if radius.x <= 0.0 or radius.y <= 0.0:
|
||||
return false
|
||||
var normalized: Vector2 = (point - radius) / radius
|
||||
return normalized.length_squared() <= 1.0
|
||||
|
||||
|
||||
func _refresh_style() -> void:
|
||||
if profile == null:
|
||||
return
|
||||
var normal_style: StyleBoxFlat = profile.make_normal_style()
|
||||
var border_width: int = (
|
||||
profile.emphasized_border_width
|
||||
if _selected or _focused_item or has_focus()
|
||||
else profile.normal_border_width
|
||||
)
|
||||
normal_style.border_width_left = border_width
|
||||
normal_style.border_width_top = border_width
|
||||
normal_style.border_width_right = border_width
|
||||
normal_style.border_width_bottom = border_width
|
||||
if _selected:
|
||||
normal_style.bg_color = profile.pressed_fill
|
||||
if _focused_item:
|
||||
normal_style.border_color = profile.text_color
|
||||
add_theme_stylebox_override("normal", normal_style)
|
||||
add_theme_stylebox_override("hover", profile.make_hover_style())
|
||||
add_theme_stylebox_override("focus", normal_style)
|
||||
add_theme_stylebox_override("pressed", profile.make_pressed_style())
|
||||
add_theme_stylebox_override("disabled", profile.make_disabled_style())
|
||||
add_theme_color_override("font_color", profile.text_color)
|
||||
|
|
@ -1 +0,0 @@
|
|||
uid://bubbleinventorycell
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
[gd_scene load_steps=3 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/components/bubble_menu/bubble_inventory_cell.gd" id="1_cell"]
|
||||
[ext_resource type="Resource" path="res://ui/components/bubble_menu/bubble_menu_profile.tres" id="2_profile"]
|
||||
|
||||
[node name="BubbleInventoryCell" type="Button"]
|
||||
custom_minimum_size = Vector2(144, 136)
|
||||
toggle_mode = true
|
||||
script = ExtResource("1_cell")
|
||||
profile = ExtResource("2_profile")
|
||||
|
||||
[node name="Content" type="VBoxContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 17.0
|
||||
offset_top = 14.0
|
||||
offset_right = -17.0
|
||||
offset_bottom = -14.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
theme_override_constants/separation = 2
|
||||
|
||||
[node name="Icon" type="TextureRect" parent="Content"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(104, 68)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
mouse_filter = 2
|
||||
texture_filter = 1
|
||||
expand_mode = 1
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="PrimaryLabel" type="Label" parent="Content"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
theme_override_font_sizes/font_size = 18
|
||||
horizontal_alignment = 1
|
||||
text_overrun_behavior = 3
|
||||
|
||||
[node name="SecondaryLabel" type="Label" parent="Content"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
theme_override_colors/font_color = Color(0.16, 0.25, 0.29, 0.78)
|
||||
theme_override_font_sizes/font_size = 15
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="FavoriteMarker" type="Label" parent="."]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 0
|
||||
offset_left = 102.0
|
||||
offset_top = 12.0
|
||||
offset_right = 132.0
|
||||
offset_bottom = 42.0
|
||||
mouse_filter = 2
|
||||
theme_override_colors/font_color = Color(1, 0.82, 0.4, 1)
|
||||
theme_override_font_sizes/font_size = 23
|
||||
text = "★"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="SelectedMarker" type="Label" parent="."]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 0
|
||||
offset_left = 14.0
|
||||
offset_top = 10.0
|
||||
offset_right = 42.0
|
||||
offset_bottom = 38.0
|
||||
mouse_filter = 2
|
||||
theme_override_colors/font_color = Color(0.035, 0.145, 0.22, 1)
|
||||
theme_override_font_sizes/font_size = 22
|
||||
text = "✓"
|
||||
horizontal_alignment = 1
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
[ext_resource type="Resource" path="res://ui/components/bubble_menu/bubble_menu_profile.tres" id="2_profile"]
|
||||
|
||||
[node name="BubbleStatusBubble" type="PanelContainer"]
|
||||
custom_minimum_size = Vector2(128, 88)
|
||||
custom_minimum_size = Vector2(112, 62)
|
||||
mouse_filter = 2
|
||||
script = ExtResource("1_status")
|
||||
profile = ExtResource("2_profile")
|
||||
|
|
@ -19,7 +19,7 @@ alignment = 1
|
|||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
theme_override_font_sizes/font_size = 15
|
||||
theme_override_font_sizes/font_size = 13
|
||||
text = "status"
|
||||
horizontal_alignment = 1
|
||||
|
||||
|
|
@ -27,6 +27,6 @@ horizontal_alignment = 1
|
|||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
theme_override_font_sizes/font_size = 21
|
||||
theme_override_font_sizes/font_size = 18
|
||||
text = "0"
|
||||
horizontal_alignment = 1
|
||||
|
|
|
|||
140
ui/components/bubble_menu/cooler_fish_sprite.gd
Normal file
140
ui/components/bubble_menu/cooler_fish_sprite.gd
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
class_name CoolerFishSprite
|
||||
extends Button
|
||||
|
||||
@onready var _visual_root: Control = %VisualRoot
|
||||
@onready var _fish_shadow: TextureRect = %FishShadow
|
||||
@onready var _fish_texture: TextureRect = %FishTexture
|
||||
@onready var _favorite_marker: Label = %FavoriteMarker
|
||||
|
||||
var catch_id: StringName
|
||||
var _neutral_position := Vector2.ZERO
|
||||
var _target_position := Vector2.ZERO
|
||||
var _motion_phase: float = 0.0
|
||||
var _depth_scale: float = 1.0
|
||||
var _batch_selected: bool = false
|
||||
var _focused_catch: bool = false
|
||||
var _hovered: bool = false
|
||||
var _rarity_color := Color.WHITE
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
resized.connect(_update_visual_pivot)
|
||||
focus_entered.connect(_refresh_style)
|
||||
focus_exited.connect(_refresh_style)
|
||||
mouse_entered.connect(func() -> void:
|
||||
_hovered = true
|
||||
_refresh_style()
|
||||
)
|
||||
mouse_exited.connect(func() -> void:
|
||||
_hovered = false
|
||||
_refresh_style()
|
||||
)
|
||||
_update_visual_pivot()
|
||||
_refresh_style()
|
||||
|
||||
|
||||
func configure(
|
||||
identity: StringName,
|
||||
texture: Texture2D,
|
||||
phase: float,
|
||||
depth_scale: float,
|
||||
rarity_color: Color,
|
||||
) -> void:
|
||||
catch_id = identity
|
||||
_fish_texture.texture = texture
|
||||
_fish_shadow.texture = texture
|
||||
_motion_phase = phase
|
||||
_depth_scale = depth_scale
|
||||
_rarity_color = rarity_color
|
||||
_refresh_style()
|
||||
|
||||
|
||||
func set_target_position(target: Vector2, immediate: bool = false) -> void:
|
||||
_target_position = target
|
||||
if immediate:
|
||||
_neutral_position = target
|
||||
position = _neutral_position
|
||||
|
||||
|
||||
func set_item_state(
|
||||
batch_selected: bool,
|
||||
focused_catch: bool,
|
||||
favorite: bool,
|
||||
) -> void:
|
||||
_batch_selected = batch_selected
|
||||
_focused_catch = focused_catch
|
||||
_favorite_marker.visible = favorite
|
||||
_refresh_style()
|
||||
|
||||
|
||||
func advance_presentation(delta: float, elapsed: float) -> void:
|
||||
var response: float = 1.0 - exp(-9.0 * delta)
|
||||
_neutral_position = _neutral_position.lerp(_target_position, response)
|
||||
position = _neutral_position
|
||||
var bob: float = sin(elapsed * TAU / 7.2 + _motion_phase) * 1.1
|
||||
var tilt: float = sin(elapsed * TAU / 9.0 + _motion_phase * 1.31) * 0.018
|
||||
var interaction_lift: float = 0.0
|
||||
if _batch_selected:
|
||||
interaction_lift += 3.0
|
||||
if _focused_catch or has_focus():
|
||||
interaction_lift += 1.5
|
||||
elif _hovered:
|
||||
interaction_lift += 0.8
|
||||
_visual_root.position = Vector2(0.0, bob - interaction_lift)
|
||||
_visual_root.rotation = tilt
|
||||
var emphasis: float = 1.0
|
||||
if _batch_selected:
|
||||
emphasis += 0.085
|
||||
if _focused_catch or has_focus():
|
||||
emphasis += 0.035
|
||||
elif _hovered:
|
||||
emphasis += 0.045
|
||||
_visual_root.scale = Vector2.ONE * _depth_scale * emphasis
|
||||
|
||||
|
||||
func _has_point(point: Vector2) -> bool:
|
||||
var radius: float = minf(size.x, size.y) * 0.48
|
||||
if radius <= 0.0:
|
||||
return false
|
||||
return (point - size * 0.5).length_squared() <= radius * radius
|
||||
|
||||
|
||||
func _update_visual_pivot() -> void:
|
||||
_visual_root.pivot_offset = size * 0.5
|
||||
|
||||
|
||||
func _refresh_style() -> void:
|
||||
var normal := _make_rarity_style(_rarity_color, 2, 0.25)
|
||||
var hover := _make_rarity_style(_rarity_color.lightened(0.08), 4, 0.34)
|
||||
var selected_fill: Color = (
|
||||
_rarity_color.lightened(0.12)
|
||||
if _batch_selected
|
||||
else _rarity_color
|
||||
)
|
||||
var selected := _make_rarity_style(
|
||||
selected_fill,
|
||||
6 if _batch_selected else 4,
|
||||
0.46 if _batch_selected else 0.34,
|
||||
)
|
||||
add_theme_stylebox_override(
|
||||
"normal",
|
||||
selected if _batch_selected or _focused_catch else normal,
|
||||
)
|
||||
add_theme_stylebox_override("hover", selected if _batch_selected else hover)
|
||||
add_theme_stylebox_override("focus", selected)
|
||||
add_theme_stylebox_override("pressed", selected)
|
||||
|
||||
|
||||
func _make_rarity_style(
|
||||
fill: Color,
|
||||
shadow_size: int,
|
||||
shadow_alpha: float,
|
||||
) -> StyleBoxFlat:
|
||||
var style := StyleBoxFlat.new()
|
||||
style.bg_color = fill
|
||||
style.set_border_width_all(0)
|
||||
style.set_corner_radius_all(128)
|
||||
style.shadow_color = Color(0.01, 0.045, 0.06, shadow_alpha)
|
||||
style.shadow_size = shadow_size
|
||||
style.shadow_offset = Vector2(0.0, 2.0)
|
||||
return style
|
||||
1
ui/components/bubble_menu/cooler_fish_sprite.gd.uid
Normal file
1
ui/components/bubble_menu/cooler_fish_sprite.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dscoolerfishsprite
|
||||
75
ui/components/bubble_menu/cooler_fish_sprite.tscn
Normal file
75
ui/components/bubble_menu/cooler_fish_sprite.tscn
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/components/bubble_menu/cooler_fish_sprite.gd" id="1_script"]
|
||||
|
||||
[node name="CoolerFishSprite" type="Button"]
|
||||
custom_minimum_size = Vector2(72, 72)
|
||||
focus_mode = 1
|
||||
mouse_default_cursor_shape = 2
|
||||
script = ExtResource("1_script")
|
||||
|
||||
[node name="VisualRoot" type="Control" parent="."]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
pivot_offset = Vector2(36, 36)
|
||||
|
||||
[node name="FishShadow" type="TextureRect" parent="VisualRoot"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 10.0
|
||||
offset_top = 11.0
|
||||
offset_right = -4.0
|
||||
offset_bottom = -3.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
modulate = Color(0.015, 0.055, 0.07, 0.32)
|
||||
texture_filter = 1
|
||||
expand_mode = 1
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="FishTexture" type="TextureRect" parent="VisualRoot"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 7.0
|
||||
offset_top = 7.0
|
||||
offset_right = -7.0
|
||||
offset_bottom = -7.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
texture_filter = 1
|
||||
expand_mode = 1
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="FavoriteMarker" type="Label" parent="VisualRoot"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 1
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -22.0
|
||||
offset_top = 0.0
|
||||
offset_right = 0.0
|
||||
offset_bottom = 22.0
|
||||
grow_horizontal = 0
|
||||
mouse_filter = 2
|
||||
theme_override_colors/font_color = Color(0.92, 0.68, 0.16, 1)
|
||||
theme_override_colors/font_outline_color = Color(0.035, 0.145, 0.22, 1)
|
||||
theme_override_constants/outline_size = 2
|
||||
theme_override_font_sizes/font_size = 16
|
||||
text = "★"
|
||||
horizontal_alignment = 1
|
||||
40
ui/components/bubble_menu/cooler_water.gdshader
Normal file
40
ui/components/bubble_menu/cooler_water.gdshader
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
shader_type canvas_item;
|
||||
render_mode unshaded;
|
||||
|
||||
uniform vec4 water_top : source_color = vec4(0.055, 0.38, 0.50, 1.0);
|
||||
uniform vec4 water_bottom : source_color = vec4(0.018, 0.16, 0.25, 1.0);
|
||||
uniform vec4 caustic_color : source_color = vec4(0.66, 0.91, 0.95, 1.0);
|
||||
uniform float caustic_opacity : hint_range(0.0, 0.2) = 0.055;
|
||||
uniform float caustic_speed : hint_range(0.0, 0.2) = 0.045;
|
||||
uniform float bubble_opacity : hint_range(0.0, 0.25) = 0.11;
|
||||
|
||||
float hash(float value) {
|
||||
return fract(sin(value * 91.713) * 43758.5453);
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
vec2 uv = UV;
|
||||
vec3 base = mix(water_top.rgb, water_bottom.rgb, smoothstep(0.0, 1.0, uv.y));
|
||||
float slow_time = TIME * caustic_speed;
|
||||
float broad_wave = sin((uv.x * 8.0 + uv.y * 5.0 + slow_time) * 6.28318);
|
||||
float crossing_wave = sin((uv.x * 5.5 - uv.y * 7.0 - slow_time * 0.73) * 6.28318);
|
||||
float caustic = smoothstep(1.46, 1.88, broad_wave + crossing_wave);
|
||||
base += caustic_color.rgb * caustic * caustic_opacity;
|
||||
float sheen = (1.0 - smoothstep(0.0, 0.12, uv.y)) * 0.11;
|
||||
base += caustic_color.rgb * sheen;
|
||||
|
||||
float bubbles = 0.0;
|
||||
for (int index = 0; index < 8; index++) {
|
||||
float key = float(index) + 1.0;
|
||||
float x = 0.08 + hash(key * 2.13) * 0.84;
|
||||
float phase = hash(key * 4.71);
|
||||
float y = 1.08 - mod(slow_time * (0.42 + hash(key) * 0.34) + phase, 1.18);
|
||||
float radius = 0.005 + hash(key * 8.23) * 0.008;
|
||||
vec2 delta = uv - vec2(x, y);
|
||||
delta.x *= 0.62;
|
||||
float distance_to_edge = abs(length(delta) - radius);
|
||||
bubbles += 1.0 - smoothstep(0.0015, 0.004, distance_to_edge);
|
||||
}
|
||||
base += caustic_color.rgb * min(bubbles, 1.0) * bubble_opacity;
|
||||
COLOR = vec4(base, 1.0);
|
||||
}
|
||||
1
ui/components/bubble_menu/cooler_water.gdshader.uid
Normal file
1
ui/components/bubble_menu/cooler_water.gdshader.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dejhqrp2nij1
|
||||
103
ui/components/bubble_menu/logbook_entry.gd
Normal file
103
ui/components/bubble_menu/logbook_entry.gd
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
class_name LogbookEntry
|
||||
extends PanelContainer
|
||||
|
||||
var _discovered: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_apply_paper_style(_discovered)
|
||||
|
||||
|
||||
func configure(
|
||||
artwork: Texture2D,
|
||||
species_name: String,
|
||||
rarity_name: String,
|
||||
owned_count: int,
|
||||
discovered: bool,
|
||||
) -> void:
|
||||
_discovered = discovered
|
||||
var artwork_control := get_node(
|
||||
^"Margin/Content/Artwork"
|
||||
) as TextureRect
|
||||
var name_control := get_node(
|
||||
^"Margin/Content/Text/NameLabel"
|
||||
) as Label
|
||||
var rarity_control := get_node(
|
||||
^"Margin/Content/Text/RarityLabel"
|
||||
) as Label
|
||||
var owned_control := get_node(
|
||||
^"Margin/Content/Text/OwnedLabel"
|
||||
) as Label
|
||||
artwork_control.texture = artwork
|
||||
artwork_control.modulate = (
|
||||
Color.WHITE
|
||||
if discovered
|
||||
else Color(0.20, 0.17, 0.13, 0.48)
|
||||
)
|
||||
name_control.text = species_name if discovered else "???"
|
||||
rarity_control.text = rarity_name if discovered else "undiscovered"
|
||||
owned_control.text = (
|
||||
"owned: %d" % owned_count if discovered else "not recorded"
|
||||
)
|
||||
owned_control.visible = true
|
||||
_apply_paper_style(discovered)
|
||||
|
||||
|
||||
func apply_compact_layout(compact: bool) -> void:
|
||||
var artwork_control := get_node(
|
||||
^"Margin/Content/Artwork"
|
||||
) as TextureRect
|
||||
var name_control := get_node(
|
||||
^"Margin/Content/Text/NameLabel"
|
||||
) as Label
|
||||
var rarity_control := get_node(
|
||||
^"Margin/Content/Text/RarityLabel"
|
||||
) as Label
|
||||
var owned_control := get_node(
|
||||
^"Margin/Content/Text/OwnedLabel"
|
||||
) as Label
|
||||
custom_minimum_size = (
|
||||
Vector2(236.0, 108.0) if compact else Vector2(214.0, 150.0)
|
||||
)
|
||||
artwork_control.custom_minimum_size = (
|
||||
Vector2(92.0, 54.0) if compact else Vector2(128.0, 76.0)
|
||||
)
|
||||
name_control.add_theme_font_size_override(
|
||||
"font_size",
|
||||
16 if compact else 18,
|
||||
)
|
||||
rarity_control.add_theme_font_size_override(
|
||||
"font_size",
|
||||
11 if compact else 13,
|
||||
)
|
||||
owned_control.add_theme_font_size_override(
|
||||
"font_size",
|
||||
11 if compact else 13,
|
||||
)
|
||||
|
||||
|
||||
func _apply_paper_style(discovered: bool) -> void:
|
||||
if not is_node_ready():
|
||||
return
|
||||
var style := StyleBoxFlat.new()
|
||||
style.bg_color = (
|
||||
Color(0.965, 0.925, 0.80, 0.78)
|
||||
if discovered
|
||||
else Color(0.89, 0.84, 0.72, 0.58)
|
||||
)
|
||||
style.border_color = (
|
||||
Color(0.50, 0.39, 0.25, 0.62)
|
||||
if discovered
|
||||
else Color(0.39, 0.34, 0.27, 0.42)
|
||||
)
|
||||
style.border_width_bottom = 2
|
||||
style.corner_radius_top_left = 18
|
||||
style.corner_radius_top_right = 12
|
||||
style.corner_radius_bottom_right = 16
|
||||
style.corner_radius_bottom_left = 10
|
||||
style.content_margin_left = 8.0
|
||||
style.content_margin_top = 6.0
|
||||
style.content_margin_right = 8.0
|
||||
style.content_margin_bottom = 6.0
|
||||
add_theme_stylebox_override("panel", style)
|
||||
1
ui/components/bubble_menu/logbook_entry.gd.uid
Normal file
1
ui/components/bubble_menu/logbook_entry.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dclogbookentry2026
|
||||
66
ui/components/bubble_menu/logbook_entry.tscn
Normal file
66
ui/components/bubble_menu/logbook_entry.tscn
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/components/bubble_menu/logbook_entry.gd" id="1_script"]
|
||||
|
||||
[node name="LogbookEntry" type="PanelContainer"]
|
||||
custom_minimum_size = Vector2(214, 150)
|
||||
mouse_filter = 2
|
||||
script = ExtResource("1_script")
|
||||
|
||||
[node name="Margin" type="MarginContainer" parent="."]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
theme_override_constants/margin_left = 5
|
||||
theme_override_constants/margin_top = 4
|
||||
theme_override_constants/margin_right = 5
|
||||
theme_override_constants/margin_bottom = 4
|
||||
|
||||
[node name="Content" type="HBoxContainer" parent="Margin"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
theme_override_constants/separation = 7
|
||||
|
||||
[node name="Artwork" type="TextureRect" parent="Margin/Content"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(128, 76)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
mouse_filter = 2
|
||||
texture_filter = 1
|
||||
expand_mode = 1
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="Text" type="VBoxContainer" parent="Margin/Content"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 4
|
||||
mouse_filter = 2
|
||||
theme_override_constants/separation = 2
|
||||
|
||||
[node name="NameLabel" type="Label" parent="Margin/Content/Text"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
theme_override_colors/font_color = Color(0.20, 0.145, 0.085, 1)
|
||||
theme_override_font_sizes/font_size = 18
|
||||
text = "species"
|
||||
horizontal_alignment = 1
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="RarityLabel" type="Label" parent="Margin/Content/Text"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
theme_override_colors/font_color = Color(0.34, 0.25, 0.15, 1)
|
||||
theme_override_font_sizes/font_size = 13
|
||||
text = "common"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="OwnedLabel" type="Label" parent="Margin/Content/Text"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
theme_override_colors/font_color = Color(0.34, 0.25, 0.15, 1)
|
||||
theme_override_font_sizes/font_size = 13
|
||||
text = "owned: 0"
|
||||
horizontal_alignment = 1
|
||||
82
ui/components/bubble_menu/notepad_ink_action.gd
Normal file
82
ui/components/bubble_menu/notepad_ink_action.gd
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
class_name NotepadInkAction
|
||||
extends Button
|
||||
|
||||
@export var ink_color := Color(0.19, 0.16, 0.12, 1.0)
|
||||
@export var disabled_ink_color := Color(0.31, 0.28, 0.23, 0.46)
|
||||
@export var persistent_mark: bool = false:
|
||||
set(value):
|
||||
persistent_mark = value
|
||||
_refresh_ink()
|
||||
|
||||
@onready var _ink_outline: NotepadInkOutline = %InkOutline
|
||||
|
||||
var _hovered: bool = false
|
||||
var _focused: bool = false
|
||||
var _pressed: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
mouse_entered.connect(_set_hovered.bind(true))
|
||||
mouse_exited.connect(_set_hovered.bind(false))
|
||||
focus_entered.connect(_set_focused.bind(true))
|
||||
focus_exited.connect(_set_focused.bind(false))
|
||||
button_down.connect(_set_pressed.bind(true))
|
||||
button_up.connect(_set_pressed.bind(false))
|
||||
_apply_paper_style()
|
||||
_refresh_ink()
|
||||
|
||||
|
||||
func refresh_ink_state() -> void:
|
||||
_apply_text_color()
|
||||
_refresh_ink()
|
||||
|
||||
|
||||
func _set_hovered(value: bool) -> void:
|
||||
_hovered = value
|
||||
_refresh_ink()
|
||||
|
||||
|
||||
func _set_focused(value: bool) -> void:
|
||||
_focused = value
|
||||
_refresh_ink()
|
||||
|
||||
|
||||
func _set_pressed(value: bool) -> void:
|
||||
_pressed = value
|
||||
_refresh_ink()
|
||||
|
||||
|
||||
func _refresh_ink() -> void:
|
||||
if not is_node_ready():
|
||||
return
|
||||
var strength: float = 0.0
|
||||
if not disabled:
|
||||
if persistent_mark:
|
||||
strength = 0.78
|
||||
if _hovered or _focused:
|
||||
strength = maxf(strength, 0.92)
|
||||
if _pressed:
|
||||
strength = 1.0
|
||||
_ink_outline.set_mark_strength(strength)
|
||||
|
||||
|
||||
func _apply_paper_style() -> void:
|
||||
var empty := StyleBoxEmpty.new()
|
||||
for state: StringName in [
|
||||
&"normal",
|
||||
&"hover",
|
||||
&"pressed",
|
||||
&"focus",
|
||||
&"disabled",
|
||||
]:
|
||||
add_theme_stylebox_override(state, empty)
|
||||
_apply_text_color()
|
||||
|
||||
|
||||
func _apply_text_color() -> void:
|
||||
var color: Color = disabled_ink_color if disabled else ink_color
|
||||
add_theme_color_override("font_color", color)
|
||||
add_theme_color_override("font_hover_color", color.darkened(0.08))
|
||||
add_theme_color_override("font_focus_color", color.darkened(0.08))
|
||||
add_theme_color_override("font_pressed_color", color.darkened(0.16))
|
||||
add_theme_color_override("font_disabled_color", disabled_ink_color)
|
||||
1
ui/components/bubble_menu/notepad_ink_action.gd.uid
Normal file
1
ui/components/bubble_menu/notepad_ink_action.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b42bnpyhxn35k
|
||||
23
ui/components/bubble_menu/notepad_ink_action.tscn
Normal file
23
ui/components/bubble_menu/notepad_ink_action.tscn
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
[gd_scene load_steps=3 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/components/bubble_menu/notepad_ink_action.gd" id="1_action"]
|
||||
[ext_resource type="Script" path="res://ui/components/bubble_menu/notepad_ink_outline.gd" id="2_outline"]
|
||||
|
||||
[node name="NotepadInkAction" type="Button"]
|
||||
custom_minimum_size = Vector2(104, 46)
|
||||
focus_mode = 1
|
||||
mouse_default_cursor_shape = 2
|
||||
flat = true
|
||||
script = ExtResource("1_action")
|
||||
|
||||
[node name="InkOutline" type="Control" parent="."]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
script = ExtResource("2_outline")
|
||||
114
ui/components/bubble_menu/notepad_ink_choice.gd
Normal file
114
ui/components/bubble_menu/notepad_ink_choice.gd
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
class_name NotepadInkChoice
|
||||
extends OptionButton
|
||||
|
||||
@export var ink_color := Color(0.19, 0.16, 0.12, 1.0)
|
||||
|
||||
@onready var _ink_outline: NotepadInkOutline = %InkOutline
|
||||
|
||||
var _hovered: bool = false
|
||||
var _focused: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
mouse_entered.connect(_set_hovered.bind(true))
|
||||
mouse_exited.connect(_set_hovered.bind(false))
|
||||
focus_entered.connect(_set_focused.bind(true))
|
||||
focus_exited.connect(_set_focused.bind(false))
|
||||
_apply_paper_style()
|
||||
_style_popup()
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func refresh_ink_state() -> void:
|
||||
_refresh_ink()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
var chevron_x: float = size.x - 13.0
|
||||
var chevron_y: float = size.y * 0.5 - 1.0
|
||||
var chevron := PackedVector2Array([
|
||||
Vector2(chevron_x - 4.0, chevron_y - 2.0),
|
||||
Vector2(chevron_x, chevron_y + 2.0),
|
||||
Vector2(chevron_x + 4.0, chevron_y - 2.5),
|
||||
])
|
||||
draw_polyline(chevron, ink_color, 1.8, true)
|
||||
var underline_y: float = size.y - 5.0
|
||||
var underline := PackedVector2Array([
|
||||
Vector2(7.0, underline_y),
|
||||
Vector2(size.x * 0.34, underline_y + 0.7),
|
||||
Vector2(size.x * 0.68, underline_y - 0.5),
|
||||
Vector2(size.x - 8.0, underline_y + 0.2),
|
||||
])
|
||||
var underline_color: Color = ink_color
|
||||
underline_color.a = 0.48
|
||||
draw_polyline(underline, underline_color, 1.1, true)
|
||||
|
||||
|
||||
func _set_hovered(value: bool) -> void:
|
||||
_hovered = value
|
||||
_refresh_ink()
|
||||
|
||||
|
||||
func _set_focused(value: bool) -> void:
|
||||
_focused = value
|
||||
_refresh_ink()
|
||||
|
||||
|
||||
func _refresh_ink() -> void:
|
||||
if is_node_ready():
|
||||
_ink_outline.set_mark_strength(
|
||||
0.88 if (_hovered or _focused) and not disabled else 0.0
|
||||
)
|
||||
|
||||
|
||||
func _apply_paper_style() -> void:
|
||||
var empty := StyleBoxEmpty.new()
|
||||
for state: StringName in [
|
||||
&"normal",
|
||||
&"hover",
|
||||
&"pressed",
|
||||
&"focus",
|
||||
&"disabled",
|
||||
]:
|
||||
add_theme_stylebox_override(state, empty)
|
||||
var empty_arrow := ImageTexture.new()
|
||||
add_theme_icon_override("arrow", empty_arrow)
|
||||
add_theme_color_override("font_color", ink_color)
|
||||
add_theme_color_override("font_hover_color", ink_color.darkened(0.08))
|
||||
add_theme_color_override("font_focus_color", ink_color.darkened(0.08))
|
||||
add_theme_color_override("font_pressed_color", ink_color.darkened(0.14))
|
||||
add_theme_color_override("font_disabled_color", Color(ink_color, 0.42))
|
||||
|
||||
|
||||
func _style_popup() -> void:
|
||||
var popup: PopupMenu = get_popup()
|
||||
var paper := StyleBoxFlat.new()
|
||||
paper.bg_color = Color(0.93, 0.885, 0.73, 1.0)
|
||||
paper.border_color = Color(0.22, 0.19, 0.15, 1.0)
|
||||
paper.set_border_width_all(2)
|
||||
paper.set_corner_radius_all(5)
|
||||
var hover_paper := paper.duplicate() as StyleBoxFlat
|
||||
hover_paper.bg_color = Color(0.82, 0.775, 0.63, 1.0)
|
||||
hover_paper.border_color = Color(0.30, 0.26, 0.20, 0.62)
|
||||
hover_paper.set_border_width_all(1)
|
||||
popup.add_theme_stylebox_override("panel", paper)
|
||||
popup.add_theme_stylebox_override("hover", hover_paper)
|
||||
popup.add_theme_stylebox_override("separator", StyleBoxEmpty.new())
|
||||
popup.add_theme_color_override("font_color", ink_color)
|
||||
popup.add_theme_color_override("font_hover_color", ink_color.darkened(0.08))
|
||||
popup.add_theme_color_override(
|
||||
"font_separator_color",
|
||||
Color(ink_color, 0.56),
|
||||
)
|
||||
var empty_mark := ImageTexture.new()
|
||||
for icon_name: StringName in [
|
||||
&"checked",
|
||||
&"unchecked",
|
||||
&"radio_checked",
|
||||
&"radio_unchecked",
|
||||
&"checked_disabled",
|
||||
&"unchecked_disabled",
|
||||
&"radio_checked_disabled",
|
||||
&"radio_unchecked_disabled",
|
||||
]:
|
||||
popup.add_theme_icon_override(icon_name, empty_mark)
|
||||
1
ui/components/bubble_menu/notepad_ink_choice.gd.uid
Normal file
1
ui/components/bubble_menu/notepad_ink_choice.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://h754d8qatlse
|
||||
24
ui/components/bubble_menu/notepad_ink_choice.tscn
Normal file
24
ui/components/bubble_menu/notepad_ink_choice.tscn
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
[gd_scene load_steps=3 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/components/bubble_menu/notepad_ink_choice.gd" id="1_choice"]
|
||||
[ext_resource type="Script" path="res://ui/components/bubble_menu/notepad_ink_outline.gd" id="2_outline"]
|
||||
|
||||
[node name="NotepadInkChoice" type="OptionButton"]
|
||||
custom_minimum_size = Vector2(124, 38)
|
||||
focus_mode = 1
|
||||
mouse_default_cursor_shape = 2
|
||||
clip_text = true
|
||||
fit_to_longest_item = false
|
||||
script = ExtResource("1_choice")
|
||||
|
||||
[node name="InkOutline" type="Control" parent="."]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
script = ExtResource("2_outline")
|
||||
64
ui/components/bubble_menu/notepad_ink_outline.gd
Normal file
64
ui/components/bubble_menu/notepad_ink_outline.gd
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
class_name NotepadInkOutline
|
||||
extends Control
|
||||
|
||||
@export var ink_color := Color(0.20, 0.17, 0.13, 0.9)
|
||||
@export_range(0.5, 6.0, 0.1) var stroke_width: float = 2.0
|
||||
@export_range(0.0, 16.0, 0.5) var padding: float = 3.0
|
||||
@export_range(0, 1000000, 1) var shape_seed: int = 17
|
||||
|
||||
var _mark_strength: float = 0.0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
|
||||
|
||||
func set_mark_strength(strength: float) -> void:
|
||||
_mark_strength = clampf(strength, 0.0, 1.0)
|
||||
visible = _mark_strength > 0.001
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
if _mark_strength <= 0.001:
|
||||
return
|
||||
var center: Vector2 = size * 0.5
|
||||
var radius := Vector2(
|
||||
maxf(size.x * 0.5 - padding, 1.0),
|
||||
maxf(size.y * 0.5 - padding, 1.0),
|
||||
)
|
||||
var primary := _build_rough_loop(center, radius, 0)
|
||||
var secondary := _build_rough_loop(
|
||||
center + Vector2(0.7, -0.45),
|
||||
radius - Vector2(1.2, 0.8),
|
||||
41,
|
||||
)
|
||||
var primary_color: Color = ink_color
|
||||
primary_color.a *= _mark_strength
|
||||
var secondary_color: Color = ink_color
|
||||
secondary_color.a *= _mark_strength * 0.36
|
||||
draw_polyline(primary, primary_color, stroke_width, true)
|
||||
draw_polyline(secondary, secondary_color, maxf(stroke_width * 0.62, 0.8), true)
|
||||
|
||||
|
||||
func _build_rough_loop(
|
||||
center: Vector2,
|
||||
radius: Vector2,
|
||||
seed_offset: int,
|
||||
) -> PackedVector2Array:
|
||||
const POINT_COUNT: int = 26
|
||||
var points := PackedVector2Array()
|
||||
for index: int in POINT_COUNT:
|
||||
var angle: float = TAU * float(index) / float(POINT_COUNT)
|
||||
var wobble: float = (
|
||||
sin(float(shape_seed + seed_offset) * 0.73 + float(index) * 2.17)
|
||||
+ sin(float(shape_seed + seed_offset) * 0.31 + float(index) * 4.03)
|
||||
* 0.45
|
||||
)
|
||||
var radial_scale: float = 1.0 + wobble * 0.018
|
||||
points.append(
|
||||
center
|
||||
+ Vector2(cos(angle), sin(angle)) * radius * radial_scale
|
||||
)
|
||||
points.append(points[0])
|
||||
return points
|
||||
1
ui/components/bubble_menu/notepad_ink_outline.gd.uid
Normal file
1
ui/components/bubble_menu/notepad_ink_outline.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dwh3kpogaelxo
|
||||
|
|
@ -162,9 +162,9 @@ func _apply_layout() -> void:
|
|||
available_size.y - reference_size.y * presentation_scale
|
||||
)
|
||||
var field_size := (
|
||||
Vector2(600.0, 82.0)
|
||||
Vector2(580.0, 82.0)
|
||||
if _compact_layout
|
||||
else Vector2(820.0, 104.0)
|
||||
else Vector2(790.0, 104.0)
|
||||
)
|
||||
_bubble_field.size = field_size
|
||||
_bubble_field.position = Vector2(
|
||||
|
|
|
|||
|
|
@ -37,73 +37,73 @@ mouse_filter = 2
|
|||
[node name="BubbleField" type="Control" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 0
|
||||
offset_left = 230.0
|
||||
offset_left = 245.0
|
||||
offset_top = 608.0
|
||||
offset_right = 1050.0
|
||||
offset_right = 1035.0
|
||||
offset_bottom = 712.0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="Slot1" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
|
||||
layout_mode = 0
|
||||
slot_index = 0
|
||||
desktop_anchor = Vector2(58, 49)
|
||||
compact_anchor = Vector2(52, 42)
|
||||
desktop_anchor = Vector2(55, 49)
|
||||
compact_anchor = Vector2(50, 42)
|
||||
motion_phase = 0.15
|
||||
|
||||
[node name="Slot2" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
|
||||
layout_mode = 0
|
||||
slot_index = 1
|
||||
desktop_anchor = Vector2(146, 53)
|
||||
compact_anchor = Vector2(114, 46)
|
||||
desktop_anchor = Vector2(140, 53)
|
||||
compact_anchor = Vector2(110, 46)
|
||||
motion_phase = 0.82
|
||||
|
||||
[node name="Slot3" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
|
||||
layout_mode = 0
|
||||
slot_index = 2
|
||||
desktop_anchor = Vector2(234, 57)
|
||||
compact_anchor = Vector2(176, 50)
|
||||
desktop_anchor = Vector2(225, 57)
|
||||
compact_anchor = Vector2(170, 50)
|
||||
motion_phase = 1.49
|
||||
|
||||
[node name="Slot4" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
|
||||
layout_mode = 0
|
||||
slot_index = 3
|
||||
desktop_anchor = Vector2(322, 60)
|
||||
compact_anchor = Vector2(238, 53)
|
||||
desktop_anchor = Vector2(310, 60)
|
||||
compact_anchor = Vector2(230, 53)
|
||||
motion_phase = 2.16
|
||||
|
||||
[node name="Slot5" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
|
||||
layout_mode = 0
|
||||
slot_index = 4
|
||||
desktop_anchor = Vector2(410, 62)
|
||||
compact_anchor = Vector2(300, 55)
|
||||
desktop_anchor = Vector2(395, 62)
|
||||
compact_anchor = Vector2(290, 55)
|
||||
motion_phase = 2.83
|
||||
|
||||
[node name="Slot6" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
|
||||
layout_mode = 0
|
||||
slot_index = 5
|
||||
desktop_anchor = Vector2(498, 60)
|
||||
compact_anchor = Vector2(362, 53)
|
||||
desktop_anchor = Vector2(480, 60)
|
||||
compact_anchor = Vector2(350, 53)
|
||||
motion_phase = 3.5
|
||||
|
||||
[node name="Slot7" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
|
||||
layout_mode = 0
|
||||
slot_index = 6
|
||||
desktop_anchor = Vector2(586, 57)
|
||||
compact_anchor = Vector2(424, 50)
|
||||
desktop_anchor = Vector2(565, 57)
|
||||
compact_anchor = Vector2(410, 50)
|
||||
motion_phase = 4.17
|
||||
|
||||
[node name="Slot8" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
|
||||
layout_mode = 0
|
||||
slot_index = 7
|
||||
desktop_anchor = Vector2(674, 53)
|
||||
compact_anchor = Vector2(486, 46)
|
||||
desktop_anchor = Vector2(650, 53)
|
||||
compact_anchor = Vector2(470, 46)
|
||||
motion_phase = 4.84
|
||||
|
||||
[node name="Slot9" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
|
||||
layout_mode = 0
|
||||
slot_index = 8
|
||||
desktop_anchor = Vector2(762, 49)
|
||||
compact_anchor = Vector2(548, 42)
|
||||
desktop_anchor = Vector2(735, 49)
|
||||
compact_anchor = Vector2(530, 42)
|
||||
motion_phase = 5.51
|
||||
|
||||
[node name="SelectedItemLabel" type="Label" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot"]
|
||||
|
|
|
|||
1797
ui/player_menu.gd
1797
ui/player_menu.gd
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue