* feat(images): Migrate BitmapImage/ImageSource to Avalonia.Media.Imaging.Bitmap [P2-011] Replace WPF image types in the three affected ViewModels with their Avalonia.Media.Imaging.Bitmap equivalents. Closes #24. TabControlViewModel.cs (TabImage): - Remove 'using System.Windows' and 'using System.Windows.Media.Imaging' - Add 'using Avalonia.Media.Imaging' - BitmapImage _image / public BitmapImage Image -> Bitmap - Both SetImage overloads (SKBitmap and CTexture): replace BeginInit/CacheOption/StreamSource/EndInit/Freeze pattern with 'Image = new Bitmap(stream)'. Bitmap reads the stream into an internal buffer at construction; disposing the MemoryStream after is safe. GameFileViewModel.cs: - Remove 'using System.Windows', '.Windows.Media', '.Windows.Media.Imaging' - Add 'using Avalonia.Media.Imaging', 'using Avalonia.Threading' - ImageSource _previewImage / public ImageSource PreviewImage -> Bitmap - SetPreviewImage: replace WPF BitmapImage construction + Application.Current.Dispatcher.InvokeAsync with new Bitmap(stream) + Dispatcher.UIThread.Post. Bitmap is immutable and not UI-thread-affine; constructing on the background Thread and posting the property assignment is safe. CustomDirectoriesViewModel.cs: - Remove 'using System.Windows', '.Windows.Controls', '.Windows.Media.Imaging' - Add 'using Avalonia.Controls', 'using Avalonia.Layout', 'using Avalonia.Media.Imaging', 'using Avalonia.Platform' - MenuItem/Image/Separator/Control -> Avalonia equivalents (same class names, different namespaces) - BitmapImage(new Uri('/FModel;component/Resources/xxx.png')) -> new Bitmap(AssetLoader.Open(new Uri('avares://FModel/...'))) for the four directory-icon menu items * fix(images): Address PR #79 review findings [P2-011] FModel.csproj [C1]: - Change <Resource> to <AvaloniaResource> for the four directory icon PNGs (add_directory, delete, edit, go_to_directory). WPF <Resource> items are not processed into Avalonia's avares resource manifest, so AssetLoader.Open would have thrown at runtime on every app startup. GameFileViewModel.cs [m1 + PR comment]: - Remove redundant 'ms.Position = 0' in SetPreviewImage: MemoryStream initializes to position 0, making the reset a no-op. - Fix 'Resolved |= ~EResolveCompute.Preview' to 'Resolved &= ~...'. The bitwise-NOT operator on an enum value produces a large negative int, ORing in undefined bits; ORing never clears bits, so the intent (undo the premature Preview flag set at the top of ResolveByExtensionAsync) required &= ~, not |= ~. CustomDirectoriesViewModel.cs [PR comment]: - Extract private static LoadIcon(string filename) helper to wrap each AssetLoader.Open call in a using, ensuring the stream returned by AssetLoader.Open is disposed after Bitmap copies its data. [m2] (Bitmap disposal in Image/PreviewImage setters) is intentionally deferred: disposing the old Bitmap in the setter while the Avalonia render thread may still hold it for the current frame risks a crash. * fix(magnifier): Address review findings [M1, m1, m2, S1] MagnifierManager.cs [M1]: - Replace AdornerLayer.SetAdornment(element, adorner) / SetAdornment(element, null) with AdornerLayer.SetAdornedElement + layer.Children.Add in VerifyAdornerLayer and Parent-cast + Children.Remove in Detach(). SetAdornment is a single-slot API that silently evicts any other adornment on the same element; the collection API matches WPF's AdornerLayer.Add/Remove semantics and allows co-existing adorners. MagnifierManager.cs [S1]: - Set e.Handled = true after a zoom change when the adorner is visible so that a parent ScrollViewer does not also scroll while the user is zooming the magnifier. - Adjust the zoom-out floor from 0 to ZoomFactorOnMouseWheel now that the ZoomFactor validator rejects values <= 0. - Only call UpdateViewBox when the adorner is visible (no-op otherwise). Magnifier.cs [m1]: - Change ZoomFactor validate: v >= 0 -> v > 0. ZoomFactor = 0 produced a zero-sized SourceRect on the VisualBrush which rendered undefined content. The minimum meaningful zoom is any positive value. MagnifierAdorner.cs [m2]: - Return early from HandlePointerEvent when Bounds.Width and Bounds.Height are both 0: the first PointerPressed arrives before the adorner canvas has been through a layout pass, so GetPosition(this) returns meaningless coordinates. The subsequent PointerMoved fires after layout and picks up correct values. * Fix reviewer to stop it getting confused |
||
|---|---|---|
| .github | ||
| .vscode | ||
| CUE4Parse@06fbf1aced | ||
| FModel | ||
| .editorconfig | ||
| .gitignore | ||
| .gitmodules | ||
| LICENSE | ||
| NOTICE | ||
| README.md | ||
FModel Linux — Unreal Engine Archives Explorer for Linux
This is an unofficial Linux port of FModel, originally created by Asval (4sval) and contributors. It is not affiliated with or endorsed by the upstream project or its maintainers. Please do not report Linux-port-specific issues upstream.
Description
FModel Linux is a Linux port of FModel — an archive explorer for Unreal Engine games. It uses CUE4Parse as its core parsing library, providing robust support for the latest UE4 and UE5 archive formats, along with a comprehensive set of tools for previewing and converting game packages.
This fork replaces the Windows-only WPF UI stack with Avalonia UI and removes other Windows-specific dependencies to enable native Linux support. It is maintained by r6e.
Installation
Installation instructions for the Linux port are available in the project wiki (work in progress).
For the upstream Windows release, refer to the official FModel installation guide.
Supporting the Upstream Project
This fork does not accept donations. If you find FModel valuable, please consider supporting the original FModel project and its contributors.
License
FModel Linux is a derivative work licensed under GPL-3. The original FModel project is copyright © Asval and FModel contributors. Licenses of third-party libraries used are listed in NOTICE.