Skip to content

Commit 5611551

Browse files
Merge pull request #1 from DistTopic/feature/dat-parser-independent-feature-flags
feat: category-specific import menus & DAT parser independent feature flags
2 parents d2d708b + f123405 commit 5611551

4 files changed

Lines changed: 185 additions & 107 deletions

File tree

src/App/MainWindow.axaml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,20 @@
303303
<MenuItem Header="Transplant Item..." Command="{Binding TransplantItemCommand}">
304304
<MenuItem.Icon><i:Icon Value="fa-solid fa-arrow-right-arrow-left" FontSize="14" Foreground="#cba6f7"/></MenuItem.Icon>
305305
</MenuItem>
306-
<MenuItem Header="Merge Session Into Current…" x:Name="MergeSessionMenuItem">
307-
<MenuItem.Icon><i:Icon Value="fa-solid fa-code-merge" FontSize="14" Foreground="#89b4fa"/></MenuItem.Icon>
306+
<MenuItem Header="Import Items from other session" x:Name="ImportItemsMenuItem">
307+
<MenuItem.Icon><i:Icon Value="fa-solid fa-cube" FontSize="14" Foreground="#89b4fa"/></MenuItem.Icon>
308+
<MenuItem Header="Loading…" IsEnabled="False"/>
309+
</MenuItem>
310+
<MenuItem Header="Import Outfits from other session" x:Name="ImportOutfitsMenuItem">
311+
<MenuItem.Icon><i:Icon Value="fa-solid fa-shirt" FontSize="14" Foreground="#a6e3a1"/></MenuItem.Icon>
312+
<MenuItem Header="Loading…" IsEnabled="False"/>
313+
</MenuItem>
314+
<MenuItem Header="Import Effects from other session" x:Name="ImportEffectsMenuItem">
315+
<MenuItem.Icon><i:Icon Value="fa-solid fa-wand-magic-sparkles" FontSize="14" Foreground="#f9e2af"/></MenuItem.Icon>
316+
<MenuItem Header="Loading…" IsEnabled="False"/>
317+
</MenuItem>
318+
<MenuItem Header="Import Missiles from other session" x:Name="ImportMissilesMenuItem">
319+
<MenuItem.Icon><i:Icon Value="fa-solid fa-location-arrow" FontSize="14" Foreground="#f38ba8"/></MenuItem.Icon>
308320
<MenuItem Header="Loading…" IsEnabled="False"/>
309321
</MenuItem>
310322
</MenuItem>

src/App/MainWindow.axaml.cs

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -60,43 +60,11 @@ public MainWindow()
6060

6161
await vm.TryLoadLastSessionAsync();
6262

63-
// Wire Merge Session menu (dynamic submenu listing other sessions)
64-
var mergeMenuItem = this.FindControl<Avalonia.Controls.MenuItem>("MergeSessionMenuItem");
65-
if (mergeMenuItem != null)
66-
{
67-
mergeMenuItem.SubmenuOpened += (_, _) =>
68-
{
69-
mergeMenuItem.Items.Clear();
70-
var sources = vm.Sessions
71-
.Where(s => s != vm.ActiveSession && s.DatData != null && s.SprFile != null)
72-
.ToList();
73-
74-
if (sources.Count == 0 || vm.ActiveSession?.DatData == null)
75-
{
76-
var empty = new Avalonia.Controls.MenuItem
77-
{
78-
Header = vm.ActiveSession?.DatData == null
79-
? "Current session has no DAT loaded"
80-
: "No other sessions with DAT/SPR loaded",
81-
IsEnabled = false,
82-
};
83-
mergeMenuItem.Items.Add(empty);
84-
}
85-
else
86-
{
87-
foreach (var source in sources)
88-
{
89-
var mi = new Avalonia.Controls.MenuItem
90-
{
91-
Header = $"{source.Name} ({source.DatData!.Items.Count + source.DatData.Outfits.Count + source.DatData.Effects.Count + source.DatData.Missiles.Count} things)",
92-
Tag = source,
93-
};
94-
mi.Click += async (_, _) => await vm.MergeSessionAsync(source);
95-
mergeMenuItem.Items.Add(mi);
96-
}
97-
}
98-
};
99-
}
63+
// Wire per-category Import menus (dynamic submenus listing other sessions)
64+
WireImportMenu("ImportItemsMenuItem", ThingCategory.Item, vm);
65+
WireImportMenu("ImportOutfitsMenuItem", ThingCategory.Outfit, vm);
66+
WireImportMenu("ImportEffectsMenuItem", ThingCategory.Effect, vm);
67+
WireImportMenu("ImportMissilesMenuItem", ThingCategory.Missile, vm);
10068

10169
// Wire confirmation dialog for palette delete operations
10270
if (vm.Palette != null)
@@ -133,6 +101,46 @@ public MainWindow()
133101
};
134102
}
135103

104+
private void WireImportMenu(string controlName, ThingCategory category, MainWindowViewModel vm)
105+
{
106+
var menuItem = this.FindControl<Avalonia.Controls.MenuItem>(controlName);
107+
if (menuItem == null) return;
108+
109+
menuItem.SubmenuOpened += (_, _) =>
110+
{
111+
menuItem.Items.Clear();
112+
var sources = vm.Sessions
113+
.Where(s => s != vm.ActiveSession && s.DatData != null && s.SprFile != null)
114+
.ToList();
115+
116+
if (sources.Count == 0 || vm.ActiveSession?.DatData == null)
117+
{
118+
var empty = new Avalonia.Controls.MenuItem
119+
{
120+
Header = vm.ActiveSession?.DatData == null
121+
? "Current session has no DAT loaded"
122+
: "No other sessions with DAT/SPR loaded",
123+
IsEnabled = false,
124+
};
125+
menuItem.Items.Add(empty);
126+
}
127+
else
128+
{
129+
foreach (var source in sources)
130+
{
131+
var dict = MainWindowViewModel.GetCategoryDict(source.DatData!, category);
132+
var mi = new Avalonia.Controls.MenuItem
133+
{
134+
Header = $"{source.Name} ({dict.Count} {category.ToString().ToLowerInvariant()}s)",
135+
Tag = source,
136+
};
137+
mi.Click += async (_, _) => await vm.MergeSessionAsync(source, category);
138+
menuItem.Items.Add(mi);
139+
}
140+
}
141+
};
142+
}
143+
136144
private bool _closeConfirmed;
137145

138146
private async void OnWindowClosing(object? sender, WindowClosingEventArgs e)

src/App/ViewModels/MainWindowViewModel.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -570,10 +570,11 @@ private static void StripUnsupportedFlags(DatThingType thing, int targetProtocol
570570
// ── Full session merge (DAT/SPR) ──
571571

572572
/// <summary>
573-
/// Merge all items from a source session into the current (active) session.
573+
/// Import things from a source session into the current (active) session.
574+
/// When <paramref name="categoryFilter"/> is specified, only that category is imported.
574575
/// Detects duplicates by comparing sprite images and shows a batch preview dialog.
575576
/// </summary>
576-
public async Task MergeSessionAsync(SessionViewModel sourceSession)
577+
public async Task MergeSessionAsync(SessionViewModel sourceSession, ThingCategory? categoryFilter = null)
577578
{
578579
if (_datData == null || _sprFile == null)
579580
{
@@ -591,16 +592,21 @@ public async Task MergeSessionAsync(SessionViewModel sourceSession)
591592
var sourceProtocol = sourceDat.ProtocolVersion;
592593
var targetProtocol = _datData.ProtocolVersion;
593594

594-
var categories = new[]
595+
var allCategories = new[]
595596
{
596597
(ThingCategory.Item, sourceDat.Items, _datData.Items),
597598
(ThingCategory.Outfit, sourceDat.Outfits, _datData.Outfits),
598599
(ThingCategory.Effect, sourceDat.Effects, _datData.Effects),
599600
(ThingCategory.Missile, sourceDat.Missiles, _datData.Missiles),
600601
};
601602

603+
var categories = categoryFilter.HasValue
604+
? allCategories.Where(c => c.Item1 == categoryFilter.Value).ToArray()
605+
: allCategories;
606+
602607
int totalSource = categories.Sum(c => c.Item2.Count);
603-
StatusText = $"Analyzing {totalSource} source things for duplicates…";
608+
var label = categoryFilter?.ToString().ToLowerInvariant() ?? "thing";
609+
StatusText = $"Analyzing {totalSource} source {label}s for duplicates…";
604610

605611
// Analyze each category
606612
var entries = new List<TransplantEntry>();
@@ -5192,7 +5198,7 @@ private Dictionary<ushort, DatThingType> GetDatDictForCategory(ThingCategory cat
51925198
return GetCategoryDict(_datData!, category);
51935199
}
51945200

5195-
private static Dictionary<ushort, DatThingType> GetCategoryDict(DatData data, ThingCategory category)
5201+
public static Dictionary<ushort, DatThingType> GetCategoryDict(DatData data, ThingCategory category)
51965202
{
51975203
return category switch
51985204
{

0 commit comments

Comments
 (0)