diff --git a/src/Model/CaseListItemModel.vala b/src/Model/CaseListItemModel.vala new file mode 100644 index 0000000..ad9f00a --- /dev/null +++ b/src/Model/CaseListItemModel.vala @@ -0,0 +1,18 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 2020-2024 Ryo Nakano + */ + +public class CaseListItemModel : Object { + public Define.CaseType case_type { get; construct; } + public string name { get; construct; } + public string description { get; construct; } + + public CaseListItemModel (Define.CaseType case_type, string name, string description) { + Object ( + case_type: case_type, + name: name, + description: description + ); + } +} diff --git a/src/Model/TextPaneModel.vala b/src/Model/TextPaneModel.vala index a5f7d81..84ba4ea 100644 --- a/src/Model/TextPaneModel.vala +++ b/src/Model/TextPaneModel.vala @@ -6,7 +6,8 @@ public class TextPaneModel : Object { public Define.TextType text_type { get; construct; } public Define.CaseType case_type { get; set; } - public string case_description { get; set; } + public ListStore case_listmodel { get; construct; } + public Gtk.CClosureExpression l10n_case_expression { get; construct; } public GtkSource.Buffer buffer { get; private set; } public string text { get; set; } @@ -24,18 +25,6 @@ public class TextPaneModel : Object { { "result-case-type", "result-text" }, // Define.TextType.RESULT }; - private struct CaseTypeData { - string description; - } - private const CaseTypeData[] CASE_TYPE_DATA_TBL = { - { N_("Each word is separated by a space") }, // Define.CaseType.SPACE_SEPARATED - { N_("The first character of compound words is in lowercase") }, // Define.CaseType.CAMEL - { N_("The first character of compound words is in uppercase") }, // Define.CaseType.PASCAL - { N_("Each word is separated by an underscore") }, // Define.CaseType.SNAKE - { N_("Each word is separated by a hyphen") }, // Define.CaseType.KEBAB - { N_("The first character of the first word in the sentence is in uppercase") }, // Define.CaseType.SENTENCE - }; - public TextPaneModel (Define.TextType text_type) { Object ( text_type: text_type @@ -45,6 +34,47 @@ public class TextPaneModel : Object { construct { case_type = (Define.CaseType) Application.settings.get_enum (TEXT_TYPE_DATA_TABLE[text_type].key_case_type); + case_listmodel = new ListStore (typeof (CaseListItemModel)); + case_listmodel.append (new CaseListItemModel ( + Define.CaseType.SPACE_SEPARATED, + N_("Space separated"), + N_("Each word is separated by a space") + )); + case_listmodel.append (new CaseListItemModel ( + Define.CaseType.CAMEL, + "camelCase", + N_("The first character of compound words is in lowercase") + )); + case_listmodel.append (new CaseListItemModel ( + Define.CaseType.PASCAL, + "PascalCase", + N_("The first character of compound words is in uppercase") + )); + case_listmodel.append (new CaseListItemModel ( + Define.CaseType.SNAKE, + "snake_case", + N_("Each word is separated by an underscore") + )); + case_listmodel.append (new CaseListItemModel ( + Define.CaseType.KEBAB, + "kebab-case", + N_("Each word is separated by a hyphen") + )); + case_listmodel.append (new CaseListItemModel ( + Define.CaseType.SENTENCE, + "Sentence case", + N_("The first character of the first word in the sentence is in uppercase") + )); + + var case_expression = new Gtk.PropertyExpression ( + typeof (CaseListItemModel), null, "name" + ); + l10n_case_expression = new Gtk.CClosureExpression ( + typeof (string), null, { case_expression }, + (Callback) localize_str, + null, null + ); + buffer = new GtkSource.Buffer (null); style_scheme_manager = new GtkSource.StyleSchemeManager (); @@ -71,18 +101,12 @@ public class TextPaneModel : Object { Application.settings.bind (TEXT_TYPE_DATA_TABLE[text_type].key_text, this, "text", SettingsBindFlags.DEFAULT); - bind_property ( - "case-type", this, "case-description", - BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE, - (binding, from_value, ref to_value) => { - var case_type = (Define.CaseType) from_value; - to_value.set_string (_(CASE_TYPE_DATA_TBL[case_type].description)); - return true; - } - ); - notify["case-type"].connect (() => { Application.settings.set_enum (TEXT_TYPE_DATA_TABLE[text_type].key_case_type, case_type); }); } + + private string localize_str (string str) { + return _(str); + } } diff --git a/src/View/TextPane.vala b/src/View/TextPane.vala index 12796dd..667c193 100644 --- a/src/View/TextPane.vala +++ b/src/View/TextPane.vala @@ -25,14 +25,13 @@ public class TextPane : Gtk.Box { orientation = Gtk.Orientation.VERTICAL; spacing = 0; - var case_dropdown = new Gtk.DropDown.from_strings ({ - _("Space separated"), - "camelCase", - "PascalCase", - "snake_case", - "kebab-case", - "Sentence case", - }); + var case_list_factory = new Gtk.SignalListItemFactory (); + case_list_factory.bind.connect (case_list_factory_bind); + case_list_factory.setup.connect (case_list_factory_setup); + + var case_dropdown = new Gtk.DropDown (model.case_listmodel, model.l10n_case_expression) { + list_factory = case_list_factory + }; case_dropdown.selected = model.case_type; var case_label = new Gtk.Label (header_label) { @@ -40,10 +39,6 @@ public class TextPane : Gtk.Box { mnemonic_widget = case_dropdown }; - var case_info_button_icon = new Gtk.Image.from_icon_name ("dialog-information-symbolic") { - tooltip_text = model.case_description - }; - var copy_clipboard_button = new Gtk.Button.from_icon_name ("edit-copy") { tooltip_text = _("Copy to Clipboard") }; @@ -57,7 +52,6 @@ public class TextPane : Gtk.Box { }; toolbar.append (case_label); toolbar.append (case_dropdown); - toolbar.append (case_info_button_icon); toolbar.append (copy_clipboard_button); source_view = new GtkSource.View.with_buffer (model.buffer) { @@ -99,4 +93,20 @@ public class TextPane : Gtk.Box { public void focus_source_view () { source_view.grab_focus (); } + + private void case_list_factory_setup (Object object) { + var item = object as Gtk.ListItem; + + var row = new DropDownRow (); + item.child = row; + } + + private void case_list_factory_bind (Object object) { + var item = object as Gtk.ListItem; + var model = item.item as CaseListItemModel; + var row = item.child as DropDownRow; + + row.title.label = _(model.name); + row.description.label = _(model.description); + } } diff --git a/src/Widget/DropDownRow.vala b/src/Widget/DropDownRow.vala new file mode 100644 index 0000000..943e9f0 --- /dev/null +++ b/src/Widget/DropDownRow.vala @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 2020-2024 Ryo Nakano + */ + +public class DropDownRow : Gtk.Box { + public Gtk.Label title { get; set; } + public Gtk.Label description { get; set; } + + public DropDownRow () { + } + + construct { + orientation = Gtk.Orientation.VERTICAL; + spacing = 2; + + title = new Gtk.Label (null) { + halign = Gtk.Align.START + }; + title.add_css_class ("heading"); + + description = new Gtk.Label (null) { + halign = Gtk.Align.START + }; + description.add_css_class ("dim-label"); + + append (title); + append (description); + } +} diff --git a/src/meson.build b/src/meson.build index b6dbfe6..153a017 100644 --- a/src/meson.build +++ b/src/meson.build @@ -32,10 +32,12 @@ else endif sources = files( + 'Model/CaseListItemModel.vala', 'Model/MainWindowModel.vala', 'Model/TextPaneModel.vala', 'View/MainWindow.vala', 'View/TextPane.vala', + 'Widget/DropDownRow.vala', 'Application.vala', 'Define.vala', 'Util.vala',