From 36ce4ba4bf5316ff28f849e2d4f431153c3dbcdd Mon Sep 17 00:00:00 2001 From: teamcons Date: Mon, 9 Mar 2026 19:59:40 +0100 Subject: [PATCH 1/2] Make both panes static, and introduce more widgets for granularity --- po/POTFILES | 1 + src/Views/TranslationView.vala | 47 ++++++------- src/Widgets/HeaderBar.vala | 10 +-- src/Widgets/LanguageDropDown.vala | 60 +++++++++++++++++ src/Widgets/LanguageSelectionBox.vala | 97 +++++++++++++++++++++++++++ src/Widgets/Panes/Pane.vala | 51 -------------- src/Widgets/Panes/SourcePane.vala | 22 +----- src/Widgets/Panes/TargetPane.vala | 23 +------ src/meson.build | 2 + 9 files changed, 191 insertions(+), 122 deletions(-) create mode 100644 src/Widgets/LanguageDropDown.vala create mode 100644 src/Widgets/LanguageSelectionBox.vala diff --git a/po/POTFILES b/po/POTFILES index 17e6b60..79ebd29 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -10,6 +10,7 @@ src/Widgets/PopoverWidgets/ApiLevel.vala src/Widgets/Buttons/OrientationBox.vala src/Widgets/Popovers/SettingsPopover.vala src/Widgets/Popovers/OptionsPopover.vala +src/Widgets/LanguageSelectionBox.vala src/Widgets/Panes/Pane.vala src/Widgets/Panes/SourcePane.vala src/Widgets/Panes/TargetPane.vala diff --git a/src/Views/TranslationView.vala b/src/Views/TranslationView.vala index 76194a2..5d65c0d 100644 --- a/src/Views/TranslationView.vala +++ b/src/Views/TranslationView.vala @@ -8,9 +8,10 @@ */ public class Inscriptions.TranslationView : Gtk.Box { - Gtk.Paned paned {get; set;} + Gtk.CenterBox paned {get; set;} public Inscriptions.SourcePane source_pane; public Inscriptions.TargetPane target_pane; + private Inscriptions.LanguageSelectionBox language_selection; // Add a debounce so we aren't requesting the API constantly public uint debounce_timer_id = 0; @@ -37,7 +38,7 @@ public class Inscriptions.TranslationView : Gtk.Box { }; construct { - orientation = HORIZONTAL; + orientation = VERTICAL; spacing = 0; actions = new SimpleActionGroup (); @@ -58,26 +59,26 @@ public class Inscriptions.TranslationView : Gtk.Box { /* ---------------- UI ---------------- */ source_pane = new Inscriptions.SourcePane (); - var selected_source_language = Application.settings.get_string ("source-language"); - - source_pane.language = selected_source_language; - target_pane = new Inscriptions.TargetPane (); - var selected_target_language = Application.settings.get_string ("target-language"); - target_pane.language = selected_target_language; - paned = new Gtk.Paned (HORIZONTAL) { - start_child = source_pane, - end_child = target_pane, - shrink_start_child = shrink_end_child = false + paned = new Gtk.CenterBox () { + vexpand = true }; + paned.start_widget = source_pane; + paned.center_widget = new Gtk.Separator (VERTICAL); + paned.end_widget = target_pane; - append (paned); + // paned.start_ (source_pane); + // paned.append (source_pane); + // paned.append (target_pane); + language_selection = new Inscriptions.LanguageSelectionBox (); + append (language_selection); + append (paned); - /* ---------------- CONNECTS ---------------- */ + /* ---------------- CONNECTS AND BINDS ---------------- */ // Logic for toggling the panes/layout on_orientation_toggled (); Application.settings.changed["vertical-layout"].connect (on_orientation_toggled); @@ -100,16 +101,16 @@ public class Inscriptions.TranslationView : Gtk.Box { if (if_connect) { // translate when text is entered or user changes any language or option source_pane.textview.buffer.changed.connect (on_text_to_translate); - source_pane.language_changed.connect (on_text_to_translate); - target_pane.language_changed.connect (on_text_to_translate); + language_selection.source_changed.connect (on_text_to_translate); + language_selection.target_changed.connect (on_text_to_translate); Application.settings.changed["context"].connect (on_text_to_translate); Application.settings.changed["formality"].connect (on_text_to_translate); } else { // no source_pane.textview.buffer.changed.disconnect (on_text_to_translate); - source_pane.language_changed.disconnect (on_text_to_translate); - target_pane.language_changed.disconnect (on_text_to_translate); + language_selection.source_changed.disconnect (on_text_to_translate); + language_selection.target_changed.disconnect (on_text_to_translate); Application.settings.changed["context"].disconnect (on_text_to_translate); Application.settings.changed["formality"].disconnect (on_text_to_translate); } @@ -124,17 +125,17 @@ public class Inscriptions.TranslationView : Gtk.Box { connect_all (false); // Temp variables - var newtarget = source_pane.language; + var newtarget = language_selection.selected_source; var newtarget_text = source_pane.text; - var newsource = target_pane.language; + var newsource = language_selection.selected_target; var newsource_text = target_pane.text; // Letsgo - source_pane.language = newsource; + language_selection.selected_source = newsource; source_pane.text = newsource_text; - target_pane.language = newtarget; + language_selection.selected_target = newtarget; target_pane.text = newtarget_text; source_pane.textview.refresh (); @@ -166,7 +167,7 @@ public class Inscriptions.TranslationView : Gtk.Box { * Filter not-requests, set or reset debounce_timer */ public void on_text_to_translate () { - if (source_pane.language == target_pane.language) { + if (language_selection.selected_source == language_selection.selected_target) { source_pane.message (_("Target language is the same as source")); return; } diff --git a/src/Widgets/HeaderBar.vala b/src/Widgets/HeaderBar.vala index d995917..c539185 100644 --- a/src/Widgets/HeaderBar.vala +++ b/src/Widgets/HeaderBar.vala @@ -105,10 +105,10 @@ public class Inscriptions.HeaderBar : Granite.Bin { //TRANSLATORS: This is for a button that switches source and target language - switchlang_button = new Gtk.Button.from_icon_name ("media-playlist-repeat") { - tooltip_markup = Granite.markup_accel_tooltip ({"I"}, _("Switch languages")) - }; - switchlang_button.action_name = TranslationView.ACTION_PREFIX + TranslationView.ACTION_SWITCH_LANG; + // switchlang_button = new Gtk.Button.from_icon_name ("media-playlist-repeat") { + // tooltip_markup = Granite.markup_accel_tooltip ({"I"}, _("Switch languages")) + // }; + // switchlang_button.action_name = TranslationView.ACTION_PREFIX + TranslationView.ACTION_SWITCH_LANG; var toggle_highlight = new Gtk.ToggleButton () { icon_name = "format-text-highlight", @@ -118,7 +118,7 @@ public class Inscriptions.HeaderBar : Granite.Bin { }; var toolbar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 5); - toolbar.append (switchlang_button); + //toolbar.append (switchlang_button); //toolbar.append (toggle_highlight); toolbar_revealer = new Gtk.Revealer () { diff --git a/src/Widgets/LanguageDropDown.vala b/src/Widgets/LanguageDropDown.vala new file mode 100644 index 0000000..dc57f3a --- /dev/null +++ b/src/Widgets/LanguageDropDown.vala @@ -0,0 +1,60 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 2025 Stella & Charlie (teamcons.carrd.co) + */ + +/** + * A convenience wrapper allowing to build the DropDown we want with a list of languages, and access selection and changes easily + */ +public class Inscriptions.LanguageDropDown : Granite.Bin { + + Inscriptions.DDModel model; + Gtk.DropDown dropdown; + + public string selected { + owned get { return get_selected_language ();} + set { set_selected_language (value);} + } + + public signal void language_changed (string code = ""); + + public LanguageDropDown (Lang[] languages) { + + hexpand = true; + model = new Inscriptions.DDModel (); + + foreach (var language in languages) { + model.model_append (language); + } + + var expression = new Gtk.PropertyExpression (typeof (Inscriptions.Lang), null, "both"); + dropdown = new Gtk.DropDown (model.model, expression) { + factory = model.factory_header, + list_factory = model.factory_list, + enable_search = true, + search_match_mode= Gtk.StringFilterMatchMode.SUBSTRING, + show_arrow = false, + hexpand = true + }; + + child = dropdown; + + /* ---------------- CONNECTS AND BINDS ---------------- */ + dropdown.notify["selected-item"].connect (on_selected_language); + } + + public void on_selected_language () { + var selected_lang = dropdown.get_selected_item () as Lang; + language_changed (selected_lang.code); + } + + private void set_selected_language (string code) { + var position = model.model_where_code (code); + dropdown.set_selected (position); + } + + private string get_selected_language () { + var selected_lang = dropdown.get_selected_item () as Lang; + return selected_lang.code; + } +} diff --git a/src/Widgets/LanguageSelectionBox.vala b/src/Widgets/LanguageSelectionBox.vala new file mode 100644 index 0000000..cb30af4 --- /dev/null +++ b/src/Widgets/LanguageSelectionBox.vala @@ -0,0 +1,97 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 2025 Stella & Charlie (teamcons.carrd.co) + */ + +/** + * Small horizontal box containing Source and Target dropdowns and a switch languages button + */ +public class Inscriptions.LanguageSelectionBox : Gtk.Box { + + public LanguageDropDown dropdown_source {get; set;} + public LanguageDropDown dropdown_target {get; set;} + + public string selected_source { + owned get { return get_selected_language (true);} + set { set_selected_language (value, true);} + } + + public string selected_target { + owned get { return get_selected_language (false);} + set { set_selected_language (value, false);} + } + + public signal void source_changed (string code = ""); + public signal void target_changed (string code = ""); + + construct { + orientation = Gtk.Orientation.HORIZONTAL; + spacing = 0; + hexpand = true; + + /* ---------------- SOURCE ---------------- */ + dropdown_source = new LanguageDropDown (Inscriptions.SourceLang ()) { + tooltip_text = _("Set the language to translate from") + }; + + //TRANSLATORS: This is for a button that switches source and target language + var switchlang_button = new Gtk.Button.from_icon_name ("media-playlist-repeat") { + tooltip_markup = Granite.markup_accel_tooltip ({"I"}, _("Switch languages")) + }; + switchlang_button.action_name = TranslationView.ACTION_PREFIX + TranslationView.ACTION_SWITCH_LANG; + + dropdown_target = new LanguageDropDown (Inscriptions.SourceLang ()) { + tooltip_text = _("Set the language to translate to") + }; + + + + var cb = new Gtk.CenterBox () { + hexpand = true + }; + + cb.start_widget = dropdown_source; + cb.center_widget = switchlang_button; + cb.end_widget = dropdown_target; + + append (cb); + + /* ---------------- CONNECTS AND BINDS ---------------- */ + + Application.settings.bind (KEY_SOURCE_LANGUAGE, + this, "selected_source", + GLib.SettingsBindFlags.DEFAULT + ); + + Application.settings.bind (KEY_TARGET_LANGUAGE, + this, "selected_target", + GLib.SettingsBindFlags.DEFAULT + ); + + dropdown_source.language_changed.connect ( (language_code) => {source_changed (language_code);}); + dropdown_target.language_changed.connect ( (language_code) => {target_changed (language_code);}); + } + + + private void set_selected_language (string code, bool is_source) { + if (is_source) { + dropdown_source.selected = code; + + } else { + dropdown_target.selected = code; + } + + print ("Set " + code + " Source?" + is_source.to_string () + "\n"); + } + + private string get_selected_language (bool is_source) { + if (is_source) { + //print ("is selected " + selected.code + selected.name + "\n"); + return dropdown_source.selected; + + } else { + //print ("is selected " + selected.code + selected.name + "\n"); + return dropdown_target.selected; + } + } +} diff --git a/src/Widgets/Panes/Pane.vala b/src/Widgets/Panes/Pane.vala index b46348f..12c3f09 100644 --- a/src/Widgets/Panes/Pane.vala +++ b/src/Widgets/Panes/Pane.vala @@ -11,9 +11,6 @@ public class Inscriptions.Pane : Gtk.Box { public Inscriptions.DDModel model {get; construct;} - public Gtk.Revealer dropdown_revealer; - public Gtk.DropDown dropdown; - public Inscriptions.Lang selected; public Inscriptions.TextView textview; public Gtk.ScrolledWindow scrolledwindow; public Gtk.ActionBar actionbar; @@ -28,33 +25,10 @@ public class Inscriptions.Pane : Gtk.Box { set { textview.buffer.text = value;} } - public string language { - owned get { return get_selected_language ();} - set { set_selected_language (value);} - } - - public signal void language_changed (string code = ""); - - public Pane (DDModel model) { - Object (model: model); - } - construct { orientation = Gtk.Orientation.VERTICAL; spacing = 0; - var expression = new Gtk.PropertyExpression (typeof(Inscriptions.Lang), null, "both"); - - /* ---------------- DROPDOWN ---------------- */ - dropdown = new Gtk.DropDown (model.model, expression) { - factory = model.factory_header, - list_factory = model.factory_list, - enable_search = true, - search_match_mode= Gtk.StringFilterMatchMode.SUBSTRING, - show_arrow = false - }; - dropdown.notify["selected-item"].connect(on_selected_language); - /* ---------------- VIEW ---------------- */ textview = new Inscriptions.TextView (); textview.set_wrap_mode (Gtk.WrapMode.WORD_CHAR); @@ -97,37 +71,12 @@ public class Inscriptions.Pane : Gtk.Box { }; stack.add_child (main_view); - append (dropdown); append (stack); toast.default_action.connect (() => { textview.buffer.undo (); }); } - - public void on_selected_language () { - selected = dropdown.get_selected_item () as Lang; - language_changed (selected.code); - //print ("\nS selected %s:%s", selected.code, selected.name); - } - - private void set_selected_language (string code) { - //print ("got " + code + "\n"); - var position = model.model_where_code (code); - dropdown.set_selected (position); - } - - private string get_selected_language () { - selected = dropdown.get_selected_item () as Lang; - //print ("is selected " + selected.code + selected.name + "\n"); - return selected.code; - } - - public string language_localized_name () { - selected = dropdown.get_selected_item () as Lang; - return selected.name; - } - // Respectful of Undo public void replace_text (string new_text) { diff --git a/src/Widgets/Panes/SourcePane.vala b/src/Widgets/Panes/SourcePane.vala index 7930be6..3c5ae18 100644 --- a/src/Widgets/Panes/SourcePane.vala +++ b/src/Widgets/Panes/SourcePane.vala @@ -8,17 +8,9 @@ */ public class Inscriptions.SourcePane : Inscriptions.Pane { - public SourcePane () { - var model = new Inscriptions.DDModel (); - foreach (var language in Inscriptions.SourceLang ()) { - model.model_append (language); - } - base (model); - } - construct { stack.visible_child = main_view; - dropdown.tooltip_text = _("Set the language to translate from"); + // var options_button_label = new Gtk.Label (_("Options")); var options_button_box = new Gtk.Box (HORIZONTAL, 0); @@ -68,24 +60,12 @@ public class Inscriptions.SourcePane : Inscriptions.Pane { /***************** CONNECTS AND BINDS *****************/ - language = Application.settings.get_string ("source-language"); - Application.settings.bind ("source-language", - this, "language", - GLib.SettingsBindFlags.DEFAULT - ); - paste_button.clicked.connect (paste_from_clipboard); - language_changed.connect (on_language_changed); - textview.buffer.changed.connect (() => { clear_button.sensitive = (text != ""); }); } - private void on_language_changed (string code) { - Application.settings.set_string ("source-language", code); - } - private void paste_from_clipboard () { var clipboard = Gdk.Display.get_default ().get_clipboard (); diff --git a/src/Widgets/Panes/TargetPane.vala b/src/Widgets/Panes/TargetPane.vala index c1830ec..40d8c4a 100644 --- a/src/Widgets/Panes/TargetPane.vala +++ b/src/Widgets/Panes/TargetPane.vala @@ -12,16 +12,7 @@ public class Inscriptions.TargetPane : Inscriptions.Pane { Gtk.Spinner loading; Gtk.WindowHandle spin_view; - public TargetPane () { - var model = new Inscriptions.DDModel (); - foreach (var language in Inscriptions.TargetLang ()) { - model.model_append (language); - } - base (model); - } - construct { - dropdown.tooltip_text = _("Set the language to translate to"); //textview.editable = false; /* -------- PLACEHOLDER -------- */ @@ -33,7 +24,7 @@ public class Inscriptions.TargetPane : Inscriptions.Pane { margin_end = MARGIN_MENU_HALF }; - var placeholder = new Gtk.Label (_("Ready to translate")) { + var placeholder = new Gtk.Label (_("Ready!")) { wrap = true }; placeholder.add_css_class (Granite.STYLE_CLASS_H2_LABEL); @@ -100,15 +91,8 @@ public class Inscriptions.TargetPane : Inscriptions.Pane { placeholder_switcher, "active", GLib.SettingsBindFlags.DEFAULT); - language = Application.settings.get_string ("target-language"); - Application.settings.bind ("target-language", - this, "language", - GLib.SettingsBindFlags.DEFAULT - ); - Application.settings.changed["auto-translate"].connect (on_auto_translate_changed); copy.clicked.connect (copy_to_clipboard); - language_changed.connect (on_language_changed); textview.buffer.changed.connect (on_buffer_changed); } @@ -123,11 +107,6 @@ public class Inscriptions.TargetPane : Inscriptions.Pane { } } - private void on_language_changed (string code) { - Application.settings.set_string ("target-language", code); - clear (); - } - private void copy_to_clipboard () { var clipboard = Gdk.Display.get_default ().get_clipboard (); clipboard.set_text (textview.buffer.text); diff --git a/src/meson.build b/src/meson.build index 39cee62..e86e2a2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -24,6 +24,8 @@ sources = files ( 'Widgets' / 'ErrorBonusBox.vala', 'Widgets' / 'TextView.vala', 'Widgets' / 'HeaderBar.vala', + 'Widgets' / 'LanguageSelectionBox.vala', + 'Widgets' / 'LanguageDropDown.vala', 'Widgets' / 'Buttons' / 'OrientationBox.vala', 'Widgets' / 'Buttons' / 'RetryButton.vala', From 6e396d21aeec9d865f9f93881ea29ee7606e974d Mon Sep 17 00:00:00 2001 From: teamcons Date: Mon, 9 Mar 2026 20:03:33 +0100 Subject: [PATCH 2/2] touchup, symbolic button --- src/Widgets/LanguageDropDown.vala | 2 +- src/Widgets/LanguageSelectionBox.vala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Widgets/LanguageDropDown.vala b/src/Widgets/LanguageDropDown.vala index dc57f3a..32c3114 100644 --- a/src/Widgets/LanguageDropDown.vala +++ b/src/Widgets/LanguageDropDown.vala @@ -43,7 +43,7 @@ public class Inscriptions.LanguageDropDown : Granite.Bin { dropdown.notify["selected-item"].connect (on_selected_language); } - public void on_selected_language () { + private void on_selected_language () { var selected_lang = dropdown.get_selected_item () as Lang; language_changed (selected_lang.code); } diff --git a/src/Widgets/LanguageSelectionBox.vala b/src/Widgets/LanguageSelectionBox.vala index cb30af4..e37c6dc 100644 --- a/src/Widgets/LanguageSelectionBox.vala +++ b/src/Widgets/LanguageSelectionBox.vala @@ -35,7 +35,7 @@ public class Inscriptions.LanguageSelectionBox : Gtk.Box { }; //TRANSLATORS: This is for a button that switches source and target language - var switchlang_button = new Gtk.Button.from_icon_name ("media-playlist-repeat") { + var switchlang_button = new Gtk.Button.from_icon_name ("media-playlist-repeat-symbolic") { tooltip_markup = Granite.markup_accel_tooltip ({"I"}, _("Switch languages")) }; switchlang_button.action_name = TranslationView.ACTION_PREFIX + TranslationView.ACTION_SWITCH_LANG;