1
+ using Avalonia . Controls . PanAndZoom ;
1
2
using Avalonia . Controls . Selection ;
2
- using Avalonia . Media . Imaging ;
3
3
using Avalonia . Threading ;
4
4
using Definitions . ObjectModels ;
5
5
using DynamicData ;
@@ -30,20 +30,6 @@ public class ImageTableViewModel : ReactiveObject, IExtraContentViewModel
30
30
[ Reactive ]
31
31
public ColourRemapSwatch SelectedSecondarySwatch { get ; set ; } = ColourRemapSwatch . SecondaryRemap ;
32
32
33
- readonly DispatcherTimer animationTimer ;
34
- int currentFrameIndex ;
35
-
36
- public IList < Bitmap > SelectedBitmaps { get ; set ; }
37
-
38
- [ Reactive ] public Bitmap SelectedBitmapPreview { get ; set ; }
39
- public Avalonia . Size SelectedBitmapPreviewBorder
40
- => SelectedBitmapPreview == null
41
- ? new Avalonia . Size ( )
42
- : new Avalonia . Size ( SelectedBitmapPreview . Size . Width + 2 , SelectedBitmapPreview . Size . Height + 2 ) ;
43
-
44
- [ Reactive ]
45
- public int AnimationSpeed { get ; set ; } = 40 ;
46
-
47
33
[ Reactive ]
48
34
public ICommand ReplaceImageCommand { get ; set ; }
49
35
@@ -56,29 +42,33 @@ public Avalonia.Size SelectedBitmapPreviewBorder
56
42
[ Reactive ]
57
43
public ICommand CropAllImagesCommand { get ; set ; }
58
44
45
+ [ Reactive ]
46
+ public ICommand ZeroOffsetAllImagesCommand { get ; set ; }
47
+
48
+ [ Reactive ]
49
+ public ICommand CenterOffsetAllImagesCommand { get ; set ; }
50
+
59
51
// what is displaying on the ui
60
52
[ Reactive ]
61
- public ObservableCollection < Bitmap ? > Bitmaps { get ; set ; }
53
+ public ObservableCollection < ImageViewModel > ImageViewModels { get ; set ; } = [ ] ;
62
54
63
55
[ Reactive ]
64
56
public int SelectedImageIndex { get ; set ; } = - 1 ;
65
57
66
58
[ Reactive ]
67
- public SelectionModel < Bitmap > SelectionModel { get ; set ; }
68
-
69
- public UIG1Element32 ? SelectedG1Element
70
- => SelectedImageIndex == - 1 || Model . G1Provider . GraphicsElements . Count == 0 || SelectedImageIndex >= Model . G1Provider . GraphicsElements . Count
71
- ? null
72
- : new UIG1Element32 ( SelectedImageIndex , Model . GetImageName ( SelectedImageIndex ) , Model . G1Provider . GraphicsElements [ SelectedImageIndex ] ) ;
73
-
74
- public Avalonia . Point SelectedG1ElementOffset
75
- => SelectedG1Element == null
76
- ? new Avalonia . Point ( )
77
- : new Avalonia . Point ( - SelectedG1Element ? . XOffset ?? 0 , - SelectedG1Element ? . YOffset ?? 0 ) ;
78
- public Avalonia . Size SelectedG1ElementSize
79
- => SelectedG1Element == null
80
- ? new Avalonia . Size ( )
81
- : new Avalonia . Size ( SelectedG1Element ? . Width ?? 0 , SelectedG1Element ? . Height ?? 0 ) ;
59
+ public SelectionModel < ImageViewModel > SelectionModel { get ; set ; }
60
+
61
+ [ Reactive ]
62
+ public ImageViewModel ? SelectedImage { get ; set ; }
63
+
64
+ readonly DispatcherTimer animationTimer ;
65
+ int currentFrameIndex ;
66
+
67
+ [ Reactive ]
68
+ public IList < ImageViewModel > SelectedBitmaps { get ; set ; }
69
+
70
+ [ Reactive ]
71
+ public int AnimationSpeed { get ; set ; } = 40 ;
82
72
83
73
ImageTableModel Model { get ; init ; }
84
74
@@ -95,17 +85,12 @@ public ImageTableViewModel(ImageTableModel model)
95
85
. Subscribe ( _ => UpdateBitmaps ( ) ) ;
96
86
97
87
_ = this . WhenAnyValue ( o => o . SelectedImageIndex )
98
- . Subscribe ( _ => this . RaisePropertyChanged ( nameof ( SelectedG1Element ) ) ) ; // disabling this line stops mem leak
99
- _ = this . WhenAnyValue ( o => o . SelectedG1Element )
100
- . Subscribe ( _ => this . RaisePropertyChanged ( nameof ( SelectedG1ElementOffset ) ) ) ;
101
- _ = this . WhenAnyValue ( o => o . SelectedG1Element )
102
- . Subscribe ( _ => this . RaisePropertyChanged ( nameof ( SelectedG1ElementSize ) ) ) ;
103
- _ = this . WhenAnyValue ( o => o . SelectedG1Element )
104
- . Subscribe ( _ => this . RaisePropertyChanged ( nameof ( SelectedBitmapPreview ) ) ) ;
105
- _ = this . WhenAnyValue ( o => o . SelectedBitmapPreview )
106
- . Subscribe ( _ => this . RaisePropertyChanged ( nameof ( SelectedBitmapPreviewBorder ) ) ) ;
88
+ . Where ( index => index >= 0 && index < ImageViewModels ? . Count )
89
+ . Subscribe ( _ => SelectedImage = ImageViewModels [ SelectedImageIndex ] ) ;
90
+
107
91
_ = this . WhenAnyValue ( o => o . AnimationSpeed )
108
- . Subscribe ( _ => UpdateAnimationSpeed ( ) ) ;
92
+ . Where ( _ => animationTimer != null )
93
+ . Subscribe ( _ => animationTimer ! . Interval = TimeSpan . FromMilliseconds ( 1000 / AnimationSpeed ) ) ;
109
94
110
95
ImportImagesCommand = ReactiveCommand . CreateFromTask ( ImportImages ) ;
111
96
ExportImagesCommand = ReactiveCommand . CreateFromTask ( ExportImages ) ;
@@ -116,6 +101,24 @@ public ImageTableViewModel(ImageTableModel model)
116
101
UpdateBitmaps ( ) ;
117
102
} ) ;
118
103
104
+ ZeroOffsetAllImagesCommand = ReactiveCommand . Create ( ( ) =>
105
+ {
106
+ foreach ( var ivm in ImageViewModels )
107
+ {
108
+ ivm . XOffset = 0 ;
109
+ ivm . YOffset = 0 ;
110
+ }
111
+ } ) ;
112
+
113
+ CenterOffsetAllImagesCommand = ReactiveCommand . Create ( ( ) =>
114
+ {
115
+ foreach ( var ivm in ImageViewModels )
116
+ {
117
+ ivm . XOffset = ( short ) ( - ivm . Width / 2 ) ;
118
+ ivm . YOffset = ( short ) ( - ivm . Height / 2 ) ;
119
+ }
120
+ } ) ;
121
+
119
122
UpdateBitmaps ( ) ;
120
123
121
124
// Set up the animation timer
@@ -129,7 +132,7 @@ public ImageTableViewModel(ImageTableModel model)
129
132
130
133
void SelectionChanged ( object sender , SelectionModelSelectionChangedEventArgs e )
131
134
{
132
- var sm = ( SelectionModel < Bitmap > ) sender ;
135
+ var sm = ( SelectionModel < ImageViewModel > ) sender ;
133
136
134
137
if ( sm . SelectedIndexes . Count > 0 )
135
138
{
@@ -142,17 +145,7 @@ void SelectionChanged(object sender, SelectionModelSelectionChangedEventArgs e)
142
145
}
143
146
144
147
// ... handle selection changed
145
- SelectedBitmaps = [ .. sm . SelectedItems . Cast < Bitmap > ( ) ] ;
146
- }
147
-
148
- void UpdateAnimationSpeed ( )
149
- {
150
- if ( animationTimer == null )
151
- {
152
- return ;
153
- }
154
-
155
- animationTimer . Interval = TimeSpan . FromMilliseconds ( 1000 / AnimationSpeed ) ;
148
+ SelectedBitmaps = [ .. sm . SelectedItems . Cast < ImageViewModel > ( ) ] ;
156
149
}
157
150
158
151
void AnimationTimer_Tick ( object ? sender , EventArgs e )
@@ -167,8 +160,7 @@ void AnimationTimer_Tick(object? sender, EventArgs e)
167
160
currentFrameIndex = 0 ;
168
161
}
169
162
170
- // Update the displayed image
171
- SelectedBitmapPreview = SelectedBitmaps [ currentFrameIndex ] ;
163
+ // Update the displayed image viewmodel
172
164
SelectedImageIndex = SelectionModel . SelectedIndexes [ currentFrameIndex ] ; // disabling this also makes the memory leaks stop
173
165
174
166
// Move to the next frame, looping back to the beginning if necessary
@@ -177,7 +169,7 @@ void AnimationTimer_Tick(object? sender, EventArgs e)
177
169
178
170
void CreateSelectionModel ( )
179
171
{
180
- SelectionModel = new SelectionModel < Bitmap >
172
+ SelectionModel = new SelectionModel < ImageViewModel >
181
173
{
182
174
SingleSelect = false
183
175
} ;
@@ -213,7 +205,15 @@ public async Task ImportImages()
213
205
public void UpdateBitmaps ( )
214
206
{
215
207
Model . RecalcImages ( SelectedPrimarySwatch , SelectedSecondarySwatch ) ;
216
- Bitmaps = [ .. G1ImageConversion . CreateAvaloniaImages ( Model . Images ) ] ;
208
+ var newImages = G1ImageConversion . CreateAvaloniaImages ( Model . Images ) ;
209
+
210
+ ImageViewModels . Clear ( ) ;
211
+ var i = 0 ;
212
+ foreach ( var image in newImages )
213
+ {
214
+ ImageViewModels . Add ( new ImageViewModel ( i , Model . GetImageName ( i ) , Model . G1Provider . GraphicsElements [ i ] , image ) ) ;
215
+ i ++ ;
216
+ }
217
217
}
218
218
219
219
public async Task ExportImages ( )
0 commit comments