16
16
using LibSidWiz ;
17
17
using LibSidWiz . Outputs ;
18
18
using LibSidWiz . Triggers ;
19
+ using Microsoft . WindowsAPICodePack . Dialogs ;
19
20
using Newtonsoft . Json ;
20
21
using SkiaSharp ;
21
22
@@ -642,7 +643,7 @@ private Channel GetClickedChannel(int clickX, int clickY)
642
643
var previewAspectRatio = ( double ) Preview . Width / Preview . Height ;
643
644
if ( previewAspectRatio > imageAspectRatio )
644
645
{
645
- // Preview is wider, we have pillarboxing
646
+ // Preview is wider, we have pillar-boxing
646
647
// So the y one is correct, x needs to be modified:
647
648
// +--+-----+--+
648
649
// | | | |
@@ -1033,6 +1034,14 @@ private void Initialize(object sender, EventArgs e)
1033
1034
toolStrip1 . Items . Insert ( indexToInsertAt , newItem ) ;
1034
1035
}
1035
1036
}
1037
+
1038
+ // Load settings if passed on the commandline
1039
+ foreach ( var arg in Environment . GetCommandLineArgs ( )
1040
+ . Skip ( 1 )
1041
+ . Where ( x => x . ToLowerInvariant ( ) . EndsWith ( ".sidwizplus.json" ) ) )
1042
+ {
1043
+ LoadSettingsFromFile ( arg ) ;
1044
+ }
1036
1045
}
1037
1046
1038
1047
private void RemoveSilentChannels ( object sender , EventArgs e )
@@ -1097,11 +1106,162 @@ private void LoadProject(object sender, EventArgs e)
1097
1106
return ;
1098
1107
}
1099
1108
1109
+ LoadSettingsFromFile ( ofd . FileName ) ;
1110
+ }
1111
+
1112
+ private void LoadSettingsFromFile ( string path )
1113
+ {
1100
1114
lock ( _settings )
1101
1115
{
1102
- JsonConvert . PopulateObject ( File . ReadAllText ( ofd . FileName ) , _settings ) ;
1116
+ var newSettings = JsonConvert . DeserializeObject < Settings > ( File . ReadAllText ( path ) ) ;
1103
1117
1104
- foreach ( var channel in _settings . Channels )
1118
+ // We inspect to decide what to do...
1119
+ var clearExistingChannels = false ;
1120
+ var discardNewChannels = false ;
1121
+ var removeMissingFiles = false ;
1122
+ var removeDuplicates = false ;
1123
+ if ( newSettings . Channels . Any ( ) )
1124
+ {
1125
+ // No new channels means nothing to check...
1126
+
1127
+ // If we already have channels, ask if the user wants to add or replace.
1128
+ if ( _settings . Channels . Any ( ) )
1129
+ {
1130
+ using var dialog = new TaskDialog ( ) ;
1131
+ dialog . InstructionText = "Loading new channels" ;
1132
+ dialog . Text =
1133
+ $ "The settings being loaded contain { newSettings . Channels . Count } channels. What do you want to do?";
1134
+ dialog . Cancelable = true ;
1135
+ dialog . Icon = TaskDialogStandardIcon . Warning ;
1136
+ dialog . StandardButtons = TaskDialogStandardButtons . Cancel ;
1137
+ dialog . DetailsExpandedText = $ """
1138
+ Existing channels:
1139
+ { string . Join ( "\n " , PrintFilenames ( _settings . Channels , null ) ) }
1140
+ New channels:
1141
+ { string . Join ( "\n " , PrintFilenames ( newSettings . Channels , _settings . Channels ) ) }
1142
+ """ ;
1143
+ AddDialogButton ( dialog , "Add" , "Add to the existing channels" , ( ) => { } ) ;
1144
+ AddDialogButton ( dialog , "Replace" , "Replace the existing channels" ,
1145
+ ( ) => { clearExistingChannels = true ; } ) ;
1146
+ AddDialogButton ( dialog , "Discard" , "Discard the new channels" ,
1147
+ ( ) => { discardNewChannels = true ; } ) ;
1148
+
1149
+ if ( dialog . Show ( ) == TaskDialogResult . Cancel )
1150
+ {
1151
+ return ;
1152
+ }
1153
+ }
1154
+ }
1155
+
1156
+ if ( ! discardNewChannels && ! clearExistingChannels )
1157
+ {
1158
+ // If the new channels refer to files that don't exist, the user may not want them.
1159
+ var missingFiles = newSettings . Channels
1160
+ . Select ( x => x . Filename ) . Where ( x => ! File . Exists ( x ) )
1161
+ . Distinct ( )
1162
+ . ToList ( ) ;
1163
+
1164
+ if ( missingFiles . Any ( ) )
1165
+ {
1166
+ using var dialog = new TaskDialog ( ) ;
1167
+ dialog . InstructionText = "Missing audio files" ;
1168
+ dialog . Text =
1169
+ $ "The settings being loaded contain { newSettings . Channels . Count } channels, but { missingFiles . Count } refer to files that don't exist. Do you want to add them anyway?";
1170
+ dialog . Cancelable = true ;
1171
+ dialog . Icon = TaskDialogStandardIcon . Warning ;
1172
+ dialog . StandardButtons = TaskDialogStandardButtons . Yes | TaskDialogStandardButtons . No |
1173
+ TaskDialogStandardButtons . Cancel ;
1174
+ dialog . DetailsExpandedText = string . Join ( "\n " , PrintFilenames ( newSettings . Channels , null ) ) ;
1175
+
1176
+ switch ( dialog . Show ( ) )
1177
+ {
1178
+ case TaskDialogResult . Cancel :
1179
+ return ;
1180
+ case TaskDialogResult . Yes :
1181
+ removeMissingFiles = true ;
1182
+ // Also clear the channels from the settings for the next check
1183
+ newSettings . Channels . RemoveAll ( x => missingFiles . Contains ( x . Filename ) ) ;
1184
+ break ;
1185
+ }
1186
+ }
1187
+
1188
+ // Now also check for duplicates
1189
+ if ( _settings . Channels . Any ( ) )
1190
+ {
1191
+ var duplicates = newSettings . Channels
1192
+ . Where ( x => _settings . Channels . Any ( y =>
1193
+ Path . GetFullPath ( y . Filename ) == Path . GetFullPath ( x . Filename ) ) )
1194
+ . ToList ( ) ;
1195
+ if ( duplicates . Any ( ) )
1196
+ {
1197
+ using var dialog = new TaskDialog ( ) ;
1198
+ dialog . InstructionText = "Duplicate audio files" ;
1199
+ dialog . Text =
1200
+ $ "The settings being loaded contain { duplicates . Count } channels where the file is already loaded. Do you want to add them anyway?";
1201
+ dialog . Cancelable = true ;
1202
+ dialog . Icon = TaskDialogStandardIcon . Warning ;
1203
+ dialog . StandardButtons = TaskDialogStandardButtons . Yes | TaskDialogStandardButtons . No |
1204
+ TaskDialogStandardButtons . Cancel ;
1205
+ dialog . DetailsExpandedText = "New channels:\n " + string . Join ( "\n " ,
1206
+ PrintFilenames ( newSettings . Channels , _settings . Channels ) ) ;
1207
+
1208
+ switch ( dialog . Show ( ) )
1209
+ {
1210
+ case TaskDialogResult . Cancel :
1211
+ return ;
1212
+ case TaskDialogResult . No :
1213
+ removeDuplicates = true ;
1214
+ break ;
1215
+ }
1216
+ }
1217
+ }
1218
+ }
1219
+
1220
+ // Deserialize again on top, so partial JSON loads will work
1221
+ if ( clearExistingChannels )
1222
+ {
1223
+ _settings . Channels . Clear ( ) ;
1224
+ }
1225
+ var countOfOldChannels = _settings . Channels . Count ;
1226
+ JsonConvert . PopulateObject ( File . ReadAllText ( path ) , _settings ) ;
1227
+ if ( discardNewChannels )
1228
+ {
1229
+ var oldChannels = _settings . Channels . Take ( countOfOldChannels ) . ToList ( ) ;
1230
+ _settings . Channels . Clear ( ) ;
1231
+ _settings . Channels . AddRange ( oldChannels ) ;
1232
+ }
1233
+
1234
+ // Then remove channels as specified
1235
+ if ( removeMissingFiles )
1236
+ {
1237
+ var channelsToRemove = _settings . Channels
1238
+ . Skip ( countOfOldChannels )
1239
+ . Where ( x => ! File . Exists ( x . Filename ) )
1240
+ . ToList ( ) ;
1241
+ foreach ( var channel in channelsToRemove )
1242
+ {
1243
+ _settings . Channels . Remove ( channel ) ;
1244
+ }
1245
+ }
1246
+
1247
+ if ( removeDuplicates )
1248
+ {
1249
+ var oldChannels = _settings . Channels
1250
+ . Take ( countOfOldChannels )
1251
+ . Select ( x => Path . GetFullPath ( x . Filename ) )
1252
+ . ToList ( ) ;
1253
+ var channelsToRemove = _settings . Channels
1254
+ . Skip ( countOfOldChannels )
1255
+ . Where ( x => oldChannels . Contains ( Path . GetFullPath ( x . Filename ) ) )
1256
+ . ToList ( ) ;
1257
+ foreach ( var channel in channelsToRemove )
1258
+ {
1259
+ _settings . Channels . Remove ( channel ) ;
1260
+ }
1261
+ }
1262
+
1263
+ // Finally, trigger a load on the new channels (and attach our event handler)
1264
+ foreach ( var channel in _settings . Channels . Skip ( countOfOldChannels ) )
1105
1265
{
1106
1266
channel . Changed += ChannelOnChanged ;
1107
1267
channel . LoadDataAsync ( ) ;
@@ -1111,6 +1271,49 @@ private void LoadProject(object sender, EventArgs e)
1111
1271
}
1112
1272
}
1113
1273
1274
+ private static IEnumerable < string > PrintFilenames ( List < Channel > channels , List < Channel > existingChannels )
1275
+ {
1276
+ foreach ( var channel in channels )
1277
+ {
1278
+ string icon ;
1279
+ if ( ! File . Exists ( channel . Filename ) )
1280
+ {
1281
+ icon = "❌" ;
1282
+ }
1283
+ else if (
1284
+ existingChannels != null &&
1285
+ ! existingChannels . Contains ( channel ) &&
1286
+ existingChannels . Any ( x => x . Filename == channel . Filename ) )
1287
+ {
1288
+ icon = "💥" ;
1289
+ }
1290
+ else
1291
+ {
1292
+ icon = "🔉" ;
1293
+ }
1294
+
1295
+ yield return $@ "{ icon } { channel . Filename } ";
1296
+ }
1297
+ yield return "❌ = file not found" ;
1298
+ yield return "💥 = file is already present" ;
1299
+ }
1300
+
1301
+ private static void AddDialogButton ( TaskDialog dialog , string text , string instruction , Action action )
1302
+ {
1303
+ var button = new TaskDialogCommandLink
1304
+ {
1305
+ Text = text ,
1306
+ Instruction = instruction ,
1307
+ } ;
1308
+ button . Click += ( _ , _ ) =>
1309
+ {
1310
+ action ( ) ;
1311
+ // ReSharper disable once AccessToDisposedClosure
1312
+ dialog . Close ( TaskDialogResult . Ok ) ;
1313
+ } ;
1314
+ dialog . Controls . Add ( button ) ;
1315
+ }
1316
+
1114
1317
private void CopyChannelSettings ( object sender , EventArgs e )
1115
1318
{
1116
1319
if ( PropertyGrid . SelectedObject is not Channel source )
@@ -1240,7 +1443,7 @@ private void VideoCodec_DropDown(object sender, EventArgs e)
1240
1443
try
1241
1444
{
1242
1445
// We run FFMPEG to find what codecs it supports
1243
- using var process = new ProcessWrapper ( _programSettings . FfmpegPath , "-encoders" , false , true ) ;
1446
+ using var process = new ProcessWrapper ( _programSettings . FfmpegPath , "-encoders" ) ;
1244
1447
process . WaitForExit ( ) ;
1245
1448
foreach ( var grouping in process
1246
1449
. Lines ( )
0 commit comments