* feat(P2-006): migrate HotkeyTextBox, FilterableComboBox, and Hotkey to Avalonia (#19) Hotkey.cs (Framework): - Replace System.Windows.Input (Key, ModifierKeys, Keyboard.Modifiers) with Avalonia.Input (Key, KeyModifiers) - ModifierKeys.Windows → KeyModifiers.Meta - IsTriggered(Key) → IsTriggered(Key, KeyModifiers): receives explicit modifiers from the caller's KeyEventArgs instead of the WPF global Keyboard.Modifiers static (which does not exist in Avalonia) UserSettings.cs (Settings): - Replace using System.Windows / System.Windows.Input with Avalonia.Controls / Avalonia.Input - ModifierKeys.Control → KeyModifiers.Control on the three default hotkey values (AssetAddTab, AssetRemoveTab, AddAudio) HotkeyTextBox.cs: - WPF TextBox / DependencyProperty / FrameworkPropertyMetadata replaced by Avalonia TextBox / StyledProperty<Hotkey> with BindingMode.TwoWay - Changed property-changed hook to AddClassHandler static ctor pattern - OnPreviewKeyDown → OnKeyDown; Keyboard.Modifiers → e.KeyModifiers - Key.System / e.SystemKey handling removed (not applicable on Linux X11/Wayland; Alt key arrives directly via e.Key in Avalonia) - Key.OemClear removed (not in Avalonia.Input.Key enum) - Key.DeadCharProcessed removed (not in Avalonia.Input.Key enum) - IsReadOnlyCaretVisible / IsUndoEnabled removed (no Avalonia equivalent) - ContextMenu set to null instead of collapsed (no default ContextMenu) FilterableComboBox.cs: - WPF ComboBox / DependencyProperty / CollectionViewSource replaced by Avalonia ComboBox / StyledProperty / manual filter-list pattern - CollectionViewSource.GetDefaultView().Filter → store original IEnumerable, rebuild filtered List<object> in ApplyFilter() on each text change; _isUpdatingItems flag prevents recursion - OnPreviewKeyDown → OnKeyDown - OnPreviewLostKeyboardFocus(KeyboardFocusChangedEventArgs) → OnLostFocus + TopLevel.FocusManager check to avoid false commits when focus moves between ComboBox and its own TextBox - GetTemplateChild in Loaded handler → OnApplyTemplate NameScope.Find - TextBoxBaseUserChangeTracker: PreviewTextInput→TextInput, PreviewKeyDown→KeyDown, PreviewKeyUp→KeyUp; SelectionLength replaced with SelectionEnd - SelectionStart (Avalonia TextBox API) - StaysOpenOnEdit / IsTextSearchEnabled removed (not in Avalonia ComboBox) MainWindow.xaml.cs: - Update 7 IsTriggered(e.Key) call sites to IsTriggered(e.Key, e.KeyModifiers) Closes #19 * fix(P2-006): address #19 review findings and PR comments Hotkey.cs: - [M1] IsTriggered: modifiers.HasFlag(Modifiers) → modifiers == Modifiers (HasFlag(None) is always true, so any key combo with no modifiers requirement would incorrectly fire for every key press with modifiers) - [S1] Add [JsonConverter(typeof(StringEnumConverter))] on Key and Modifiers properties so they serialise as strings rather than integers; Avalonia.Input.Key integer values differ from System.Windows.Input.Key values (e.g. Key.A: WPF=44, Avalonia=65), so integer serialisation would load wrong keys from existing AppSettings.json on first launch HotkeyTextBox.cs: - [C1]/PR-1 Move e.Handled = true into capturing cases only (Delete/Back/ Escape clears hotkey; default captures new hotkey). Modifier-only keys, Tab/Enter/Space without modifiers now propagate unhandled so Tab focus navigation works correctly. (OnPreviewKeyDown does not exist as a virtual override in Avalonia TextBox; OnKeyDown is correct.) - [m1] Remove dead HasKeyChar method (never called) FilterableComboBox.cs: - [M2] OnLostFocus: replace reference equality to _editableTextBox with IsVisualAncestorOf(focused) (covers all template parts including the dropdown popup, not just the TextBox part) - [M3] AttachSourceFilter: reset _currentFilter = string.Empty before ApplyFilter() so a stale filter is not applied to a new source - [m2]/PR-6 Remove dead FilterItem method - [m3] FreezeTextBoxState: wrap action() in try/finally so _textBoxFrozen is always reset even if action() throws - PR-3 Subscribe to INotifyCollectionChanged on the new _originalSource in AttachSourceFilter; unsubscribe from the old one in OnPropertyChanged before replacing _originalSource. This keeps the filtered ItemsSource live when items are added/removed in the bound collection (e.g. GameSelectorViewModel.DetectedDirectories). - PR-4 Normalize tb.Text to string.Empty in OnUserTextChanged before Length/Substring to avoid NullReferenceException on empty TextBox - PR-5 Use string.Contains(filter, StringComparison.OrdinalIgnoreCase) in ApplyFilter instead of ToLower().Contains(); removes per-item allocations and makes matching locale-independent - Store _currentFilter without lower-casing (OrdinalIgnoreCase does not need pre-normalised input) AudioPlayer.xaml.cs: - PR-2 Update 4× IsTriggered(e.Key) → IsTriggered(e.Key, e.KeyModifiers) (missed call sites from original migration; old 1-arg overload removed) * fix(P2-006): address second-pass #19 review findings FilterableComboBox.cs: - [M1] Add OnDetachedFromVisualTree: unsubscribe from INotifyCollectionChanged.CollectionChanged when the control is removed from the visual tree. Without this, a long-lived source collection (e.g. GameSelectorViewModel.DetectedDirectories) would hold a strong reference to the FilterableComboBox instance via the event delegate, preventing GC of the control after removal. - [m2] Remove dead/inverted _lastText == currentText clause from TextBoxUserChangeTracker.TextChanged handler. TextChanged never fires with equal text in Avalonia, so the clause never executed; removing it eliminates confusing dead code (the equality check was logically inverted relative to its intended meaning). Hotkey.cs: - [S1] Add comment documenting StringEnumConverter round-trip behaviour for [Flags] KeyModifiers values (Newtonsoft serialises them as comma-separated strings, e.g. "Control, Shift", and round-trips correctly through the same format). * fix(P2-006): address third-pass #19 review findings FilterableComboBox.cs: - [m1] Remove dead _lastText field and its two assignment sites (constructor init + TextChanged update). The field became unreachable after the [m2] fix removed the only read site (_lastText == text predicate). No behavioral change. Hotkey.cs: - Fix typo in comment: "combinationsthrough" → "combinations through" * fix(P2-006): use SetCurrentValue in ApplyFilter to preserve XAML binding FilterableComboBox.cs: - ApplyFilter previously called ItemsSource = ... which invokes SetValue at LocalValue priority, clearing any XAML binding on ItemsSource. If the bound ViewModel property is later updated (e.g. the VM replaces DetectedDirectories), the severed binding means OnPropertyChanged never fires and the new source is never captured. - Switch to SetCurrentValue(ItemsSourceProperty, filtered) which writes the filtered list at LocalValue priority without removing the binding, so ViewModel-driven ItemsSource replacements continue to flow through normally after filtering has been applied. |
||
|---|---|---|
| .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.