UI functionality

This commit is contained in:
Bucket Of Chicken
2025-08-31 20:31:49 +02:00
parent cf74d35371
commit e0c7c050f2
13 changed files with 231 additions and 74 deletions
+16
View File
@@ -0,0 +1,16 @@
using Godot;
using System;
using System.Reflection.Metadata;
using System.Data.Common;
using System.Reflection.PortableExecutable;
using System.IO;
public partial class Metadatatest : Control
{
public override void _Ready()
{
base._Ready();
}
}
+1
View File
@@ -0,0 +1 @@
uid://csihi5ila47ga
+20 -2
View File
@@ -1,9 +1,10 @@
[gd_scene load_steps=15 format=3 uid="uid://mfcbf2sfino6"]
[gd_scene load_steps=18 format=3 uid="uid://mfcbf2sfino6"]
[ext_resource type="Texture2D" uid="uid://0jo87vtoeheu" path="res://Images/pole2.jpg" id="1_6bp64"]
[ext_resource type="Texture2D" uid="uid://df2e70jxwrmjs" path="res://Icons/BackOne.png" id="1_8gbba"]
[ext_resource type="Texture2D" uid="uid://0r1tx6l1lc6x" path="res://Icons/settingscog.png" id="2_344ge"]
[ext_resource type="Texture2D" uid="uid://daq8wnhtscpjl" path="res://Icons/Skip.png" id="2_bo1nx"]
[ext_resource type="Script" uid="uid://csihi5ila47ga" path="res://Scenes/Metadatatest.cs" id="2_fdnlq"]
[ext_resource type="Texture2D" uid="uid://ctb4s2nks73rx" path="res://Icons/Play.png" id="2_jjvhh"]
[ext_resource type="Texture2D" uid="uid://myq6n4bshduj" path="res://Icons/search.png" id="2_ynf5e"]
[ext_resource type="Script" uid="uid://bq55jftgugexl" path="res://Scripts/Context.cs" id="3_8gbba"]
@@ -11,6 +12,8 @@
[ext_resource type="Script" uid="uid://dq3yj21reqk80" path="res://Scripts/SearchDisplay.cs" id="4_hptm8"]
[ext_resource type="Texture2D" uid="uid://cekkhyppj88xi" path="res://Icons/Headphones.png" id="4_kry3j"]
[ext_resource type="PackedScene" uid="uid://c21wc1bq2pnm" path="res://Scenes/song_display.tscn" id="5_d1ilt"]
[ext_resource type="Script" uid="uid://ci5h1wwbedkbt" path="res://Scripts/UIManager.cs" id="12_6iyac"]
[ext_resource type="Texture2D" uid="uid://ch8wymyxftkb3" path="res://Icons/Pause.png" id="14_jkdf5"]
[sub_resource type="GDScript" id="GDScript_bo1nx"]
resource_name = "OpenDirGlue"
@@ -81,6 +84,7 @@ offset_right = -29.0
offset_bottom = -31.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("2_fdnlq")
[node name="VBoxContainer" type="VBoxContainer" parent="Padding"]
layout_mode = 1
@@ -208,6 +212,7 @@ expand_icon = true
[node name="PlayButton" type="Button" parent="Padding/VBoxContainer/Bottom/HBoxContainer"]
custom_minimum_size = Vector2(42, 0)
layout_mode = 2
toggle_mode = true
icon = ExtResource("2_jjvhh")
expand_icon = true
@@ -221,6 +226,8 @@ expand_icon = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 4
max_value = 1.0
step = 0.0010000000038417056
tick_count = 5
ticks_position = 3
@@ -256,7 +263,7 @@ offset_bottom = -42.0
grow_horizontal = 2
grow_vertical = 0
max_value = 1.0
step = 0.010000000009313226
step = 0.01000000000931322
value = 1.0
script = SubResource("GDScript_d1ilt")
@@ -291,3 +298,14 @@ UpperMargin = NodePath("../Padding/VBoxContainer/Center/SearchResults/ScrollCont
SongContainer = NodePath("../Padding/VBoxContainer/Center/SearchResults/ScrollContainer/VBoxContainer/SongContainer")
LowerMargin = NodePath("../Padding/VBoxContainer/Center/SearchResults/ScrollContainer/VBoxContainer/LowerMargin")
Scroll = NodePath("../Padding/VBoxContainer/Center/SearchResults/ScrollContainer")
[node name="UiManager" type="Node" parent="." node_paths=PackedStringArray("PlayPauseButton", "ProgressIndicator", "SkipButton", "GoBackButton", "LoopButton", "RandomizeButton")]
script = ExtResource("12_6iyac")
PlayPauseButton = NodePath("../Padding/VBoxContainer/Bottom/HBoxContainer/PlayButton")
PauseImage = ExtResource("14_jkdf5")
PlayImage = ExtResource("2_jjvhh")
ProgressIndicator = NodePath("../Padding/VBoxContainer/Bottom/HBoxContainer/HSlider")
SkipButton = NodePath("../Padding/VBoxContainer/Bottom/HBoxContainer/SkipButton")
GoBackButton = NodePath("../Padding/VBoxContainer/Bottom/HBoxContainer/BackButton")
LoopButton = NodePath("../Padding/VBoxContainer/Bottom/HBoxContainer/Loop")
RandomizeButton = NodePath("../Padding/VBoxContainer/Bottom/HBoxContainer/Shuffle")
+13 -1
View File
@@ -12,7 +12,7 @@ font_color = Color(0.7919991, 0.79199916, 0.7919991, 1)
shadow_size = 2
shadow_color = Color(0, 0, 0, 0.5647059)
[node name="SongDisplay" type="Control" node_paths=PackedStringArray("background", "NameLabel", "ArtistLabel", "PlayButton")]
[node name="SongDisplay" type="Control" node_paths=PackedStringArray("background", "NameLabel", "ArtistLabel", "PlayButton", "OpenURLButton")]
custom_minimum_size = Vector2(0, 75)
layout_mode = 3
anchors_preset = 10
@@ -23,6 +23,7 @@ background = NodePath("TextureRect")
NameLabel = NodePath("VBoxContainer/Name")
ArtistLabel = NodePath("VBoxContainer/Artist")
PlayButton = NodePath("Playbutton")
OpenURLButton = NodePath("OpenURl")
[node name="Panel" type="Panel" parent="."]
layout_mode = 1
@@ -81,3 +82,14 @@ anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
flat = true
[node name="OpenURl" type="Button" parent="."]
layout_mode = 1
anchors_preset = -1
anchor_left = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -73.0
grow_horizontal = 0
grow_vertical = 2
text = "open url"
+8 -43
View File
@@ -10,61 +10,26 @@ public partial class Context : Node
public Thread processingThread;
public static Context instance;
public IEnumerable<Song> Songs;
AudioStreamPlayer[] StreamPlayers;
DirectoryLoader manager = new();
public event EventHandler SongsUpdated;
public delegate void SongsUpdatedEventHandler(object sender, SongsUpdatedEventArgs e);
static public SongPlayer ISongPlayer;
public event Action<IEnumerable<Song>> SongsUpdated;
public override void _Ready()
{
base._Ready();
instance = this;
ISongPlayer = new SongPlayer();
AddChild(ISongPlayer);
}
public void LoadDirectory(String path){
GD.Print(path);
GD.Print("Loading ",path);
Songs = manager.LoadDirectory(path);
GD.Print("Songs loaded");
SongsUpdatedEventArgs args = new();
args.songs = Songs;
OnSongsUpdated(args);
}
protected virtual void OnSongsUpdated(SongsUpdatedEventArgs e){
SongsUpdated.Invoke(this,e);
}
AudioStreamPlayer Player;
public void PlaySong(){
GD.Print("PlaySongFromDisk");
Player?.Play();
}
public void LoadSong(String Path){
Player?.QueueFree();
if (Path.ToLower().EndsWith(".mp3")){
AudioStreamMP3 stream = AudioStreamMP3.LoadFromFile(Path);
Player = new AudioStreamPlayer();
Player.Stream = stream;
AddChild(Player);
}
else if(Path.ToLower().EndsWith(".wav")){
AudioStreamWav stream = AudioStreamWav.LoadFromFile(Path);
Player = new AudioStreamPlayer();
Player.Stream = stream;
AddChild(Player);
}
else if(Path.ToLower().EndsWith(".ogg")){
AudioStreamOggVorbis stream = AudioStreamOggVorbis.LoadFromFile(Path);
Player = new AudioStreamPlayer();
Player.Stream = stream;
AddChild(Player);
}
Player.Bus = "Music";
// Just event stuff
SongsUpdated(Songs);
}
}
public class SongsUpdatedEventArgs : EventArgs
{
public IEnumerable<Song> songs;
}
+19 -14
View File
@@ -6,26 +6,32 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Godot;
using TagLib;
using TagLib.Riff;
using ATL.AudioData;
using ATL;
public class Song{
public String Name;
public bool LoadedMetadata;
public String[] Artists;
public String Artist;
public String Album;
public float Length;
public String Comment;
public String URL;
public String Directory;
public void LoadMetadata(){
var TLfile = TagLib.File.Create(Directory);
Album ??= TLfile.Tag.Album;
Artists ??= TLfile.Tag.Performers;
Name ??= TLfile.Tag.Title;
Length = TLfile.Length;
Comment ??= TLfile.Tag.Comment;
TLfile.Dispose();
Track theTrack = new Track(Directory);
if (theTrack.AdditionalFields.ContainsKey("comment")){
URL = theTrack.AdditionalFields["comment"];
}
Album ??= theTrack.Album;
Artist ??= theTrack.Artist;
Name = String.IsNullOrEmpty(TLfile.Tag.Title) ? Name : theTrack.Title;
Length = theTrack.Duration;
Comment = theTrack.Comment;
}
public Image LoadImage(){
var TLfile = TagLib.File.Create(Directory);
@@ -73,13 +79,12 @@ public class DirectoryLoader{
{
Directory = file,
};
//TLfile.Tag.CopyTo(Tag)
//GD.Print("File Valid, file path ",song.Directory);
String[] parts = file.Split("/");
String LastPart = parts[^1 ];
song.Name = LastPart;
Songs = Songs.Append(song);
//if (file.EndsWith(".mp3"))
}
return Songs;
+7 -9
View File
@@ -18,10 +18,9 @@ public partial class SearchDisplay : Node
}
IEnumerable<Song> DisplayedSongs = [];
void UpdateDisplay(object sender,EventArgs eventArgs){
SongsUpdatedEventArgs args = (SongsUpdatedEventArgs)eventArgs;
DisplayedSongs = args.songs;
GD.Print("Updated, songs ",args.songs.Count());
void UpdateDisplay(IEnumerable<Song> songs){
DisplayedSongs = songs;
GD.Print("Updated, songs ",songs.Count());
}
@@ -67,7 +66,6 @@ public partial class SearchDisplay : Node
scene.Setup(Songinfo);
scene.DisplayId = i;
SongContainer.MoveChild(scene,i - CurrentIndex);
GD.Print("IDKENX ", i - CurrentIndex );
GD.Print("CurrentIndex ", CurrentIndex);
displays = displays.Append(scene);
}
@@ -79,10 +77,10 @@ public partial class SearchDisplay : Node
}
update_margins(CurrentIndex);
}
void update_margins(int CurrentIndex){
int ChildSize = SongContainer.GetChildren().Count * 75;
int TotalSize = 75 * DisplayedSongs.Count();
int TopMarginSize = CurrentIndex*75;
void update_margins(int CurrentIndex,int songsize = 75){
int ChildSize = SongContainer.GetChildren().Count * songsize;
int TotalSize = songsize * DisplayedSongs.Count();
int TopMarginSize = CurrentIndex*songsize;
int LowMarginSize = TotalSize-ChildSize-TopMarginSize;
UpperMargin.CustomMinimumSize = new Vector2(0,TopMarginSize);
LowerMargin.CustomMinimumSize = new Vector2(0, LowMarginSize);
+8 -5
View File
@@ -10,6 +10,7 @@ public partial class SongDisplay : Control
[Export] Label NameLabel;
[Export] Label ArtistLabel;
[Export] Button PlayButton;
[Export] Button OpenURLButton;
public void Setup(Song info){
SavedInfo = info;
Image image = info.LoadImage();
@@ -18,14 +19,16 @@ public partial class SongDisplay : Control
background.Texture = tex;
}
NameLabel.Text = SavedInfo.Name;
if (SavedInfo.Artists.Any()){
ArtistLabel.Text = SavedInfo.Artists[0];
ArtistLabel.Text = SavedInfo.Artist;
}
PlayButton.Pressed += ButtonPressed;
OpenURLButton.Pressed += URLOpen;
}
void ButtonPressed(){
Context.instance.LoadSong(SavedInfo.Directory);
Context.instance.PlaySong();
Context.ISongPlayer.LoadSong(SavedInfo);
Context.ISongPlayer.PlaySong();
}
void URLOpen(){
OS.ShellOpen(SavedInfo.URL);
}
}
+68
View File
@@ -0,0 +1,68 @@
using Godot;
using System;
public partial class SongPlayer : Node{
AudioStreamPlayer Player;
public Action<Song> SongChanged;
public Action<bool> SongStateUpdated;
public void PlaySong(){
GD.Print("PlaySong");
Player?.Play();
SongStateUpdated?.Invoke(false);
}
public void PauseSong(){
GD.Print("PauseSong");
if (Player == null){
return;
}
Player.StreamPaused = true;
SongStateUpdated?.Invoke(true);
}
public void UnpauseSong(){
GD.Print("UnpauseSong");
if (Player == null){
return;
}
Player.StreamPaused = false;
SongStateUpdated?.Invoke(false);
}
public void LoadSong(Song song){
Player?.QueueFree();
if (song.Directory.ToLower().EndsWith(".mp3")){
AudioStreamMP3 stream = AudioStreamMP3.LoadFromFile(song.Directory);
Player = new AudioStreamPlayer();
Player.Stream = stream;
AddChild(Player);
}
else if(song.Directory.ToLower().EndsWith(".wav")){
AudioStreamWav stream = AudioStreamWav.LoadFromFile(song.Directory);
Player = new AudioStreamPlayer();
Player.Stream = stream;
AddChild(Player);
}
else if(song.Directory.ToLower().EndsWith(".ogg")){
AudioStreamOggVorbis stream = AudioStreamOggVorbis.LoadFromFile(song.Directory);
Player = new AudioStreamPlayer();
Player.Stream = stream;
AddChild(Player);
}
GD.Print("Playing ", song.Directory);
SongChanged?.Invoke(song);
Player.Bus = "Music";
}
// 0 - 1 range
public void SetPosition(float Position){
if (Player == null || Player.Stream == null){
return;
}
float length = (float)Player.Stream.GetLength();
Player.Play(length*Position);
}
public float GetPosition(){
if (Player == null || Player.Stream == null){
return 0f;
}
float length = (float)Player.Stream.GetLength();
return (float)Player.GetPlaybackPosition()/length;
}
}
+1
View File
@@ -0,0 +1 @@
uid://d3v27hhdedguv
+68
View File
@@ -0,0 +1,68 @@
using Godot;
using Instances;
using System;
using System.Collections.Generic;
using System.Linq;
public partial class UIManager : Node{
[Export] Button PlayPauseButton;
[Export] Texture2D PauseImage;
[Export] Texture2D PlayImage;
[Export] HSlider ProgressIndicator;
[Export] Button SkipButton;
[Export] Button GoBackButton;
[Export] Button LoopButton;
[Export] Button RandomizeButton;
bool SliderDragging;
static UIManager instance;
public override void _Ready()
{
base._Ready();
instance = this;
ProgressIndicator.DragStarted += sliderDrag;
ProgressIndicator.DragEnded += sliderDragEnded;
PlayPauseButton.Toggled += PausePlay;
Context.ISongPlayer.SongStateUpdated += UpdatePausePlay;
}
void PausePlay(bool Newstate){
if (Newstate){
Context.ISongPlayer.PauseSong();
PlayPauseButton.Icon = PlayImage;
}
else{
Context.ISongPlayer.UnpauseSong();
PlayPauseButton.Icon = PauseImage;
}
}
void UpdatePausePlay(bool paused){
if (paused){
PlayPauseButton.Icon = PlayImage;
PlayPauseButton.ButtonPressed = true;
}
else{
PlayPauseButton.Icon = PauseImage;
PlayPauseButton.ButtonPressed = false;
}
}
public override void _Process(double delta)
{
base._Process(delta);
if (!SliderDragging){
ProgressIndicator.Value = Context.ISongPlayer.GetPosition();
}
}
void sliderDrag(){
SliderDragging = true;
}
void sliderDragEnded(bool changed){
SliderDragging = false;
Context.ISongPlayer.SetPosition((float)ProgressIndicator.Value);
}
}
+1
View File
@@ -0,0 +1 @@
uid://ci5h1wwbedkbt
+1
View File
@@ -8,5 +8,6 @@
<PackageReference Include="TagLibSharp" Version="2.3.0" />
<PackageReference Include="YoutubeDLSharp" Version="1.1.2" />
<PackageReference Include="FFMpegCore" Version="5.2.0" />
<PackageReference Include="z440.atl.core" Version="7.3.0" />
</ItemGroup>
</Project>