Skip to content

Commit 3e8058a

Browse files
committed
Preserve scroll position in AssetBrowser refresh
1 parent 79eebb5 commit 3e8058a

File tree

3 files changed

+116
-8
lines changed

3 files changed

+116
-8
lines changed

game/addons/menu/Code/MenuUI/ContentBlock/ContentBlockHero.razor

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
@if (Current == null) return;
77

8-
<root class="hero bgcolor@BgColor">
8+
<root class="hero bgcolor@BgColor" onclick="@Clicked">
99

1010
@if (BackgroundUrl != null)
1111
{
@@ -14,7 +14,7 @@
1414

1515
<div class="content">
1616

17-
<div class="left" onclick="@Clicked">
17+
<div class="left">
1818
<div class="icon"><img src="@Current.Thumb" /></div>
1919
<div class="title">@Current.Title</div>
2020
<div class="description">@Current.Summary</div>
@@ -40,7 +40,6 @@
4040

4141
protected override async Task OnParametersSetAsync()
4242
{
43-
4443
Current = Group.Packages.OrderBy( x => Guid.NewGuid() ).FirstOrDefault();
4544
Current = await Package.FetchAsync( Current.FullIdent, false );
4645
UpdateBackgroundMedia();
@@ -66,7 +65,6 @@
6665

6766
BackgroundUrl = bg;
6867
BgColor = Random.Shared.Int(0, 4);
69-
7068
}
7169

7270
void Clicked()

game/addons/menu/Code/MenuUI/ContentBlock/ContentBlockHero.razor.scss

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
2-
.hero
1+
.hero
32
{
43
min-height: 40vh;
54
position: relative;
@@ -12,6 +11,14 @@
1211
margin: 4px;
1312
margin-top: 2rem;
1413
border: 1px solid #fff2;
14+
cursor: pointer;
15+
transition: all 0.3s ease;
16+
17+
&:hover
18+
{
19+
border: 1px solid #08f4;
20+
transition: all 0.1s ease;
21+
}
1522
}
1623

1724
.background-media
@@ -37,7 +44,6 @@
3744
max-width: 250px;
3845
flex-direction: column;
3946
gap: 1rem;
40-
cursor: pointer;
4147
text-shadow: 1px 1px 2px #000d;
4248
}
4349

game/addons/tools/Code/Editor/AssetBrowser/AssetBrowser.cs

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,104 @@ public AssetListViewMode ViewModeType
130130

131131
private FileSystemWatcher watcher;
132132

133+
int lastKnownScrollPosition = 0;
134+
135+
private struct ScrollAnchor
136+
{
137+
public string Key;
138+
public int Index;
139+
public int Scroll;
140+
141+
public ScrollAnchor( string key, int index, int scroll )
142+
{
143+
Key = key;
144+
Index = index;
145+
Scroll = scroll;
146+
}
147+
}
148+
149+
private bool TryGetItemKey( object item, out string key )
150+
{
151+
key = item switch
152+
{
153+
AssetEntry ae => ae.FileInfo.FullName ?? ae.Asset?.AbsolutePath,
154+
DirectoryEntry de => de.DirectoryInfo.FullName,
155+
_ => null
156+
};
157+
158+
return !string.IsNullOrEmpty( key );
159+
}
160+
161+
private ScrollAnchor CaptureScrollAnchor()
162+
{
163+
if ( AssetList?.VerticalScrollbar?.IsValid() == true )
164+
{
165+
lastKnownScrollPosition = AssetList.VerticalScrollbar.Value;
166+
}
167+
168+
if ( AssetList?.Items.Any() != true )
169+
return new ScrollAnchor( null, 0, lastKnownScrollPosition );
170+
171+
var itemHeight = MathF.Max( AssetList.ItemSize.y + AssetList.ItemSpacing.y, 1f );
172+
int index = (int)MathF.Floor( lastKnownScrollPosition / itemHeight );
173+
index = Math.Clamp( index, 0, AssetList.Items.Count() - 1 );
174+
175+
string key = null;
176+
var item = AssetList.Items.ElementAt( index );
177+
TryGetItemKey( item, out key );
178+
179+
return new ScrollAnchor( key, index, lastKnownScrollPosition );
180+
}
181+
182+
private void RestoreScrollPosition( int target )
183+
{
184+
if ( AssetList?.VerticalScrollbar?.IsValid() != true )
185+
return;
186+
187+
void Apply()
188+
{
189+
if ( AssetList?.VerticalScrollbar?.IsValid() != true )
190+
return;
191+
192+
var scrollbar = AssetList.VerticalScrollbar;
193+
var clamped = Math.Clamp( target, scrollbar.Minimum, scrollbar.Maximum );
194+
scrollbar.Value = clamped;
195+
AssetList.SmoothScrollTarget = 0;
196+
lastKnownScrollPosition = clamped;
197+
}
198+
199+
Apply();
200+
MainThread.Queue( Apply );
201+
}
202+
203+
private void RestoreScrollAnchor( ScrollAnchor anchor )
204+
{
205+
if ( AssetList?.VerticalScrollbar?.IsValid() != true )
206+
return;
207+
208+
var desired = anchor.Scroll;
209+
210+
if ( !string.IsNullOrEmpty( anchor.Key ) && AssetList.Items.Any() )
211+
{
212+
var match = AssetList.Items.Select( ( x, i ) => (x, i) )
213+
.FirstOrDefault( tuple => TryGetItemKey( tuple.x, out var key ) && StringComparer.OrdinalIgnoreCase.Equals( key, anchor.Key ) );
214+
215+
if ( match != default && match.i >= 0 )
216+
{
217+
var itemHeight = MathF.Max( AssetList.ItemSize.y + AssetList.ItemSpacing.y, 1f );
218+
desired = (int)(match.i * itemHeight);
219+
}
220+
}
221+
else if ( AssetList.Items.Any() )
222+
{
223+
var idx = Math.Clamp( anchor.Index, 0, AssetList.Items.Count() - 1 );
224+
var itemHeight = MathF.Max( AssetList.ItemSize.y + AssetList.ItemSpacing.y, 1f );
225+
desired = (int)(idx * itemHeight);
226+
}
227+
228+
RestoreScrollPosition( desired );
229+
}
230+
133231
public AssetBrowser( Widget parent ) : this( parent, null )
134232
{
135233

@@ -410,7 +508,7 @@ private async Task<bool> UpdateAssetListAsync( bool recursive, CancellationToken
410508
List<object> items = new List<object>();
411509
var tagCounts = new Dictionary<string, int>();
412510

413-
AssetList.Clear();
511+
var anchor = CaptureScrollAnchor();
414512

415513
await Task.Run( () =>
416514
{
@@ -501,6 +599,9 @@ await Task.Run( () =>
501599
return false;
502600

503601
AssetList.SetItems( items );
602+
603+
RestoreScrollAnchor( anchor );
604+
504605
if ( !string.IsNullOrEmpty( lastSortColumn ) )
505606
{
506607
SortAssetList( lastSortColumn, lastSortAscending );
@@ -522,6 +623,7 @@ await Task.Run( () =>
522623

523624
private void SortAssetList( string sortBy, bool ascending )
524625
{
626+
var anchor = CaptureScrollAnchor();
525627
List<object> items;
526628

527629
switch ( sortBy )
@@ -594,6 +696,8 @@ private void SortAssetList( string sortBy, bool ascending )
594696
items.Reverse();
595697
}
596698
AssetList.SetItems( items );
699+
RestoreScrollAnchor( anchor );
700+
MainThread.Queue( () => RestoreScrollAnchor( anchor ) );
597701

598702
lastSortColumn = sortBy;
599703
lastSortAscending = ascending;

0 commit comments

Comments
 (0)