using Gtk; using Adw; using System.Text; using GLib; namespace Photomator.Views; public partial class MainWindow : Adw.ApplicationWindow { private readonly Adw.Application _application; public MainWindow(Adw.Application application) : base() { _application = application; SetTitle(AppInfo.ApplicationName); SetIconName(AppInfo.IconName); PreferencesPage pageSingle = InitPageSingle(); PreferencesPage pageFolder = InitPageFolder(); ViewStack viewStack = ViewStack.New(); viewStack.AddTitledWithIcon(pageSingle, "page-single", "Einzelne Datei", "image-x-generic-symbolic"); viewStack.AddTitledWithIcon(pageFolder, "page-folder", "Ordner", "folder-symbolic"); ViewSwitcher viewSwitcher = ViewSwitcher.New(); viewSwitcher.SetStack(viewStack); viewSwitcher.SetPolicy(ViewSwitcherPolicy.Wide); SetDefaultSize(600, 800); Adw.AboutDialog aboutDialog = InitAboutDialog(); Adw.HeaderBar headerBar = Adw.HeaderBar.New(); Button btnAbout = Button.NewFromIconName("help-about-symbolic"); btnAbout.OnClicked += (_, _) => aboutDialog.Present(this); headerBar.SetTitleWidget(viewSwitcher); headerBar.PackEnd(btnAbout); ToolbarView view = ToolbarView.New(); view.AddTopBar(headerBar); view.SetContent(viewStack); SetContent(view); } public void Start() { _application.AddWindow(this); Present(); } public PreferencesPage InitPageSingle() { PreferencesPage page = PreferencesPage.New(); PreferencesGroup pgSource = PreferencesGroup.New(); pgSource.SetTitle("Bild"); pgSource.SetDescription("Als Eingabeformate werden BMP, GIF, JPEG, PBM, PNG, TIFF, TGA und WebP unterstützt."); EntryRow erSource = EntryRow.New(); erSource.SetTitle("Zu konvertierendes Bild"); erSource.SetEditable(false); PreferencesGroup pgOptions = PreferencesGroup.New(); pgOptions.SetTitle("Optionen"); pgOptions.SetDescription("Diese Parameter beeinflussen die Qualität und Größe der Bilder."); ComboRow crRes = ComboRow.New(); crRes.SetTitle("Auflösung"); crRes.SetSubtitle("Länge der kurzen Seite in Pixel"); StringList resOptions = StringList.New(["720", "1080", "1440", "2160"]); crRes.SetModel(resOptions); crRes.SetSelected(2); pgOptions.Add(crRes); ComboRow crFormat = ComboRow.New(); crFormat.SetTitle("Konvertierungsart"); crFormat.SetModel(StringList.New(["Verlustbehaftet", "Verlustfrei"])); crFormat.SetSelected(0); pgOptions.Add(crFormat); PreferencesGroup pgBtn = PreferencesGroup.New(); pgBtn.SetValign(Align.Center); pgBtn.SetHalign(Align.Center); Button btnConvert = Button.NewWithLabel("Konvertieren"); btnConvert.OnClicked += async (_, _) => { FileDialog fileDialog = FileDialog.New(); Gio.ListStore listStore = Gio.ListStore.New(FileFilter.GetGType()); FileFilter filter = FileFilter.New(); filter.SetName("WebP (*.webp)"); filter.AddPattern("*.webp"); filter.AddPattern("*.WEBP"); listStore.Append(filter); fileDialog.SetFilters(listStore); Gio.File? file; try { file = await fileDialog.SaveAsync(this); } catch { file = null; } if (file != null && file.GetPath() != null) { ConvertOptions options = new(resOptions.GetString(crRes.GetSelected()), crFormat.GetSelected()); await Lib.Convert(erSource.GetText(), file.GetPath()!, options); } else InitInfoAlert("Kein Ziel ausgewählt", "Es wurde keine Zieldatei ausgewählt. Konvertierung wird abgebrochen."); }; btnConvert.SetCssClasses(["pill", "suggested-action", "long"]); btnConvert.SetSensitive(false); pgBtn.Add(btnConvert); Button btnSelect = Button.New(); btnSelect.SetValign(Align.Center); btnSelect.AddCssClass("flat"); btnSelect.SetIconName("document-open-symbolic"); btnSelect.OnClicked += async (_, _) => { FileDialog fileDialog = FileDialog.New(); fileDialog.SetFilters(GetSourceFileFilter()); Gio.File? file; try { file = await fileDialog.OpenAsync(this); } catch { file = null; } if (file != null && file.GetPath() != null) { erSource.SetText(file.GetPath()!); btnConvert.SetSensitive(true); } else if (erSource.GetText() == "") btnConvert.SetSensitive(false); }; erSource.AddSuffix(btnSelect); pgSource.Add(erSource); page.Add(pgSource); page.Add(pgOptions); page.Add(pgBtn); return page; } public PreferencesPage InitPageFolder() { EntryRow erSource = EntryRow.New(); erSource.SetTitle("Quellordner"); erSource.SetEditable(false); EntryRow erDest = EntryRow.New(); erDest.SetTitle("Zielordner"); erDest.SetEditable(false); PreferencesGroup pgOptions = PreferencesGroup.New(); pgOptions.SetTitle("Optionen"); pgOptions.SetDescription("Diese Parameter beeinflussen die Qualität und Größe der Bilder."); ComboRow crRes = ComboRow.New(); crRes.SetTitle("Auflösung"); crRes.SetSubtitle("Länge der kurzen Seite in Pixel"); StringList resOptions = StringList.New(["720", "1080", "1440", "2160"]); crRes.SetModel(resOptions); crRes.SetSelected(2); pgOptions.Add(crRes); ComboRow crFormat = ComboRow.New(); crFormat.SetTitle("Konvertierungsart"); crFormat.SetModel(StringList.New(["Verlustbehaftet", "Verlustfrei"])); crFormat.SetSelected(0); pgOptions.Add(crFormat); PreferencesGroup pgBtn = PreferencesGroup.New(); pgBtn.SetValign(Align.Center); pgBtn.SetHalign(Align.Center); Button btnConvert = Button.NewWithLabel("Konvertieren"); btnConvert.OnClicked += async (_, _) => { string[] filesSource; if (Directory.Exists(erSource.GetText())) filesSource = Directory.GetFiles(erSource.GetText()); else { InitInfoAlert("Quellordner existiert nicht", "Der ausgewählte Quellordner ist nicht im Dateisystem vorhanden. Die Konvertierung wurde abgebrochen."); return; } if (filesSource.Length == 0) { InitInfoAlert("Quellordner ist leer", "Im ausgewählten Quellordner befinden sich keine Dateien. Die Konvertierung wurde abgebrochen."); return; } string dest = erDest.GetText(); Directory.CreateDirectory(dest); StatusDialog statusDialog = new(_application, this); statusDialog.Start(); try { ConvertOptions options = new(resOptions.GetString(crRes.GetSelected()), crFormat.GetSelected()); ConvertError[] convertErrors = await Lib.ConvertList(filesSource, dest, options, statusDialog.SetProgress); if (convertErrors.Length > 0) statusDialog.Partial(filesSource.Length, dest, convertErrors); else statusDialog.Success(filesSource.Length, dest); } catch (Exception e) { statusDialog.Error(e.Message); } }; btnConvert.SetCssClasses(["pill", "suggested-action", "long"]); btnConvert.SetSensitive(false); pgBtn.Add(btnConvert); void checkButtonState() { if (erSource.GetText() != "" && erDest.GetText() != "") btnConvert.SetSensitive(true); else btnConvert.SetSensitive(false); } erSource.AddSuffix(InitButtonSelectFolder(erSource, checkButtonState)); erDest.AddSuffix(InitButtonSelectFolder(erDest, checkButtonState)); PreferencesPage page = PreferencesPage.New(); PreferencesGroup pgFolders = PreferencesGroup.New(); pgFolders.SetTitle("Ordner"); pgFolders.SetDescription("Wähle einen Quell- und einen Zielordner. Es werden alle Dateien im Ordner konvertiert, jedoch keine Unterordner."); pgFolders.Add(erSource); pgFolders.Add(erDest); page.Add(pgFolders); page.Add(pgOptions); page.Add(pgBtn); return page; } public void InitInfoAlert(string title, string body) { Adw.AlertDialog alert = Adw.AlertDialog.New(title, body); alert.AddResponse("ok", "OK"); alert.SetResponseAppearance("ok", ResponseAppearance.Suggested); alert.SetDefaultResponse("ok"); alert.SetCloseResponse("ok"); alert.Present(this); } public static Adw.AboutDialog InitAboutDialog() { Adw.AboutDialog aboutDialog = Adw.AboutDialog.New(); aboutDialog.SetApplicationName(AppInfo.ApplicationName); aboutDialog.SetDeveloperName(AppInfo.DeveloperName); aboutDialog.SetApplicationIcon(AppInfo.IconName); aboutDialog.SetCopyright(AppInfo.Copyright); aboutDialog.SetIssueUrl(AppInfo.IssueUrl); aboutDialog.SetWebsite(AppInfo.Website); aboutDialog.SetReleaseNotes(AppInfo.ReleaseNotes); aboutDialog.SetVersion(AppInfo.Version); aboutDialog.SetLicenseType(License.MitX11); return aboutDialog; } public Button InitButtonSelectFolder(EntryRow entryRow, VoidFunc checkButtonState) { Button btnSelect = Button.New(); btnSelect.SetValign(Align.Center); btnSelect.AddCssClass("flat"); btnSelect.SetIconName("document-open-symbolic"); btnSelect.OnClicked += async (_, _) => { FileDialog fileDialog = FileDialog.New(); Gio.File? file; try { file = await fileDialog.SelectFolderAsync(this); } catch { file = null; } if (file != null && file.GetPath() != null) entryRow.SetText(file.GetPath()!); checkButtonState(); }; return btnSelect; } public static Gio.ListStore GetSourceFileFilter() { Gio.ListStore listStore = Gio.ListStore.New(FileFilter.GetGType()); FileFilter filterAll = FileFilter.New(); filterAll.SetName("Alle unterstützten Bildformate"); string[][] formats = [["bmp", "dib"], ["gif"], ["jpeg", "jpg", "jpe", "jfif"], ["pbm"], ["png"], ["tiff", "tif"], ["tga", "bpx", "icb", "pix"], ["webp"]]; foreach (string[] format in formats) { FileFilter filter = FileFilter.New(); StringBuilder name = new($"{format[0].ToUpper()} ("); for (int i = 0; i < format.Length; i++) { name.Append($"*.{format[i]}"); if (i != format.Length - 1) name.Append(", "); filter.AddPattern($"*.{format[i]}"); filterAll.AddPattern($"*.{format[i]}"); filter.AddPattern($"*.{format[i].ToUpper()}"); filterAll.AddPattern($"*.{format[i].ToUpper()}"); } name.Append(')'); filter.SetName(name.ToString()); listStore.Append(filter); } listStore.Insert(0, filterAll); return listStore; } }