diff --git a/src/WebCamControl.Core/IPresets.cs b/src/WebCamControl.Core/IPresets.cs
index e64b0ba..d85a838 100644
--- a/src/WebCamControl.Core/IPresets.cs
+++ b/src/WebCamControl.Core/IPresets.cs
@@ -30,5 +30,10 @@ public interface IPresets
///
/// Preset index to overwrite. If null, a new preset will be saved.
public void SaveCurrent(ICamera camera, string name, int? index);
+
+ ///
+ /// Deletes the preset at the specified index.
+ ///
+ public void Delete(PresetConfig preset);
}
diff --git a/src/WebCamControl.Core/Presets.cs b/src/WebCamControl.Core/Presets.cs
index c2a11e0..8259862 100644
--- a/src/WebCamControl.Core/Presets.cs
+++ b/src/WebCamControl.Core/Presets.cs
@@ -67,4 +67,14 @@ public void SaveCurrent(ICamera camera, string name, int? index)
_configManager.Save();
OnChange?.Invoke(this, EventArgs.Empty);
}
+
+ ///
+ /// Deletes the preset at the specified index.
+ ///
+ public void Delete(PresetConfig preset)
+ {
+ PresetConfigs.Remove(preset);
+ _configManager.Save();
+ OnChange?.Invoke(this, EventArgs.Empty);
+ }
}
diff --git a/src/WebCamControl.Gtk/FullWindow.blp b/src/WebCamControl.Gtk/FullWindow.blp
index 4b5dea3..0382dd0 100644
--- a/src/WebCamControl.Gtk/FullWindow.blp
+++ b/src/WebCamControl.Gtk/FullWindow.blp
@@ -43,6 +43,16 @@ Adw.ApplicationWindow full_window {
}
};
}
+ Adw.ViewStackPage {
+ name: "presets";
+ title: _("Presets");
+ child: ListBox _presetsList {
+ styles [
+ "boxed-list",
+ "settings-page",
+ ]
+ };
+ }
}
};
}
diff --git a/src/WebCamControl.Gtk/FullWindow.cs b/src/WebCamControl.Gtk/FullWindow.cs
index cfe7e52..3c2b30f 100644
--- a/src/WebCamControl.Gtk/FullWindow.cs
+++ b/src/WebCamControl.Gtk/FullWindow.cs
@@ -1,8 +1,6 @@
using Adw;
using Gtk;
using WebCamControl.Core;
-using WebCamControl.Core.Linux;
-using WebCamControl.Gtk.Extensions;
using WebCamControl.Gtk.Widgets;
namespace WebCamControl.Gtk;
@@ -13,26 +11,31 @@ namespace WebCamControl.Gtk;
public class FullWindow : Adw.Window
{
private readonly ICamera _camera;
+ private readonly IPresets _presets;
#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value
[Connect] private readonly ListBox _controls = default!;
[Connect] private readonly ActionRow _exampleRow = default!;
+ [Connect] private readonly ListBox _presetsList = default!;
#pragma warning restore CS0649 // Field is never assigned to, and will always have its default value
public FullWindow(
Adw.Application app,
- ICamera camera
- ) : this(new Builder("FullWindow.ui"), camera)
+ ICamera camera,
+ IPresets presets
+ ) : this(new Builder("FullWindow.ui"), camera, presets)
{
Application = app;
}
private FullWindow(
Builder builder,
- ICamera camera
+ ICamera camera,
+ IPresets presets
) : base(builder.GetPointer("full_window"), false)
{
_camera = camera;
+ _presets = presets;
builder.Connect(this);
// TODO: Configure proper icon
@@ -57,5 +60,19 @@ private void InitializeWidgets()
{
_controls.Append(control!);
}
+
+ InitializePresets();
+ _presets.OnChange += (_, _) => InitializePresets();
+ }
+
+ private void InitializePresets()
+ {
+ _presetsList.RemoveAll();
+ foreach (var preset in _presets.PresetConfigs)
+ {
+ var row = new PresetRow(preset);
+ row.OnDelete += (_, _) => _presets.Delete(preset);
+ _presetsList.Append(row);
+ }
}
}
diff --git a/src/WebCamControl.Gtk/Widgets/PresetRow.cs b/src/WebCamControl.Gtk/Widgets/PresetRow.cs
new file mode 100644
index 0000000..e00ad1d
--- /dev/null
+++ b/src/WebCamControl.Gtk/Widgets/PresetRow.cs
@@ -0,0 +1,70 @@
+using Adw;
+using Gtk;
+using WebCamControl.Core.Configuration;
+using MessageDialog = Adw.MessageDialog;
+
+namespace WebCamControl.Gtk.Widgets;
+
+///
+/// A row representing a saved preset.
+///
+public class PresetRow : ExpanderRow
+{
+ private readonly PresetConfig _preset;
+ public event EventHandler? OnDelete;
+
+ public PresetRow(PresetConfig preset)
+ : this(Adw.Internal.ExpanderRow.New(), false, preset)
+ {
+
+ }
+ private PresetRow(IntPtr ptr, bool ownedRef, PresetConfig preset)
+ : base(ptr, ownedRef)
+ {
+ _preset = preset;
+ Title = preset.Name;
+
+ if (preset.Tilt != null)
+ {
+ var tilt = ActionRow.New();
+ tilt.Title = $"Tilt: {Math.Round((decimal)preset.Tilt.Value, decimals: 2)}";
+ AddRow(tilt);
+ }
+ if (preset.Pan != null)
+ {
+ var pan = ActionRow.New();
+ pan.Title = $"Pan: {Math.Round((decimal)preset.Pan.Value, decimals: 2)}";
+ AddRow(pan);
+ }
+
+ var deleteButton = Button.New();
+ deleteButton.TooltipText = $"Delete {preset.Name}";
+ deleteButton.IconName = "user-trash-symbolic";
+ deleteButton.CssClasses = ["flat", "image-button"];
+ deleteButton.OnClicked += (_, _) => ConfirmDelete();
+ AddSuffix(deleteButton);
+ }
+
+ private void ConfirmDelete()
+ {
+ const string deleteButtonId = "delete";
+ const string cancelButtonId = "cancel";
+
+ var dialog = new MessageDialog();
+ dialog.SetParent(this);
+ dialog.Body = $"Are you sure you want to delete preset '{_preset.Name}'?";
+ dialog.AddResponse(cancelButtonId, "Cancel");
+ dialog.AddResponse(deleteButtonId, "Delete");
+ dialog.SetResponseAppearance(deleteButtonId, ResponseAppearance.Destructive);
+ dialog.SetDefaultResponse(cancelButtonId);
+ dialog.SetCloseResponse(cancelButtonId);
+ dialog.OnResponse += (_, args) =>
+ {
+ if (args.Response == deleteButtonId)
+ {
+ OnDelete?.Invoke(this, EventArgs.Empty);
+ }
+ };
+ dialog.Present();
+ }
+}