From 30864bdb0482445be535ba48a299c554bfc28569 Mon Sep 17 00:00:00 2001 From: teamcons Date: Sat, 15 Nov 2025 17:48:34 +0100 Subject: [PATCH 1/9] Add a list feature --- data/jorts.gschema.xml | 5 +++++ src/Widgets/ActionBar.vala | 14 ++++++++++++++ src/Widgets/TextView.vala | 22 ++++++++++++++++++++++ src/Windows/StickyNoteWindow.vala | 3 +++ 4 files changed, 44 insertions(+) diff --git a/data/jorts.gschema.xml b/data/jorts.gschema.xml index 3e07f6b3..635aab15 100644 --- a/data/jorts.gschema.xml +++ b/data/jorts.gschema.xml @@ -11,5 +11,10 @@ Hide actionbar Whether to hide the actionbar and its buttons + + " - " + Hide actionbar + Whether to hide the actionbar and its buttons + diff --git a/src/Widgets/ActionBar.vala b/src/Widgets/ActionBar.vala index 0c06e273..6513c4bf 100644 --- a/src/Widgets/ActionBar.vala +++ b/src/Widgets/ActionBar.vala @@ -45,6 +45,19 @@ delete_item.action_name = StickyNoteWindow.ACTION_PREFIX + StickyNoteWindow.ACTION_DELETE; /* **** RIGHT **** */ + var list_button = new Gtk.Button () { + icon_name = "view-list-symbolic", + width_request = 32, + height_request = 32, + tooltip_markup = Granite.markup_accel_tooltip ( + {"w"}, + _("Toggle list") + ) + }; + list_button.add_css_class ("themedbutton"); + list_button.action_name = StickyNoteWindow.ACTION_PREFIX + StickyNoteWindow.ACTION_LIST; + + emojichooser_popover = new Gtk.EmojiChooser (); emoji_button = new Gtk.MenuButton () { @@ -80,6 +93,7 @@ actionbar.pack_start (delete_item); actionbar.pack_end (menu_button); actionbar.pack_end (emoji_button); + actionbar.pack_end (list_button); handle = new Gtk.WindowHandle () { child = actionbar diff --git a/src/Widgets/TextView.vala b/src/Widgets/TextView.vala index 8566234f..00f8df1e 100644 --- a/src/Widgets/TextView.vala +++ b/src/Widgets/TextView.vala @@ -43,4 +43,26 @@ public class Jorts.TextView : Granite.HyperTextView { } }); } + + public void list () { + Gtk.TextIter start, end; + buffer.get_selection_bounds (out start, out end); + + var first_line = (uint8)start.get_line (); + var last_line = (uint8)end.get_line (); + debug ("got " + first_line.to_string () + " to " + last_line.to_string ()); + + Gtk.TextIter startline; + var list_item_start = Application.gsettings.get_string ("list-item-start"); + + buffer.begin_user_action (); + for (uint8 i = first_line; i <= last_line; i++) { + + debug ("doing line " + i.to_string ()); + buffer.get_iter_at_line_index (out startline, i, 0); + buffer.insert (ref startline, list_item_start, -1); + } + buffer.end_user_action (); + + } } diff --git a/src/Windows/StickyNoteWindow.vala b/src/Windows/StickyNoteWindow.vala index 4db4f3dc..b7cd0b76 100644 --- a/src/Windows/StickyNoteWindow.vala +++ b/src/Windows/StickyNoteWindow.vala @@ -41,6 +41,7 @@ public class Jorts.StickyNoteWindow : Gtk.Window { public const string ACTION_ZOOM_IN = "action_zoom_in"; public const string ACTION_TOGGLE_MONO = "action_toggle_mono"; public const string ACTION_DELETE = "action_delete"; + public const string ACTION_LIST = "action_list"; public const string ACTION_THEME_1 = "action_theme_1"; public const string ACTION_THEME_2 = "action_theme_2"; @@ -63,6 +64,7 @@ public class Jorts.StickyNoteWindow : Gtk.Window { { ACTION_ZOOM_OUT, action_zoom_out}, { ACTION_ZOOM_DEFAULT, action_zoom_default}, { ACTION_TOGGLE_MONO, action_toggle_mono}, + { ACTION_LIST, action_list}, { ACTION_ZOOM_IN, action_zoom_in}, { ACTION_THEME_1, action_theme_1}, { ACTION_THEME_2, action_theme_2}, @@ -242,6 +244,7 @@ public class Jorts.StickyNoteWindow : Gtk.Window { private void action_show_menu () {view.menu_button.activate ();} private void action_delete () {((Jorts.Application)this.application).manager.delete_note (this);} private void action_toggle_mono () {popover.monospace = !popover.monospace;} + private void action_list () {view.textview.list ();} private void action_zoom_out () {zoomcontroller.zoom_out ();} private void action_zoom_default () {zoomcontroller.zoom_default ();} From f82a431baa1ae8a4df0cd1bfdf989a674c8b9662 Mon Sep 17 00:00:00 2001 From: teamcons Date: Sat, 15 Nov 2025 17:48:44 +0100 Subject: [PATCH 2/9] expose list customization in settings --- src/Services/Constants.vala | 2 +- src/Views/PreferencesView.vala | 75 +++++++++++++++---- .../PreferencesWidgets/SettingsSwitch.vala | 2 +- src/Windows/PreferenceWindow.vala | 9 --- 4 files changed, 61 insertions(+), 27 deletions(-) diff --git a/src/Services/Constants.vala b/src/Services/Constants.vala index c506b13f..98b13808 100644 --- a/src/Services/Constants.vala +++ b/src/Services/Constants.vala @@ -36,7 +36,7 @@ namespace Jorts.Constants { // New preference window const int DEFAULT_PREF_WIDTH = 550; - const int DEFAULT_PREF_HEIGHT = 290; + const int DEFAULT_PREF_HEIGHT = 310; /*************************************************/ // Shortcuts diff --git a/src/Views/PreferencesView.vala b/src/Views/PreferencesView.vala index d6284108..57a5e10a 100644 --- a/src/Views/PreferencesView.vala +++ b/src/Views/PreferencesView.vala @@ -12,10 +12,10 @@ construct { orientation = VERTICAL; - margin_top = 12; - margin_bottom = 12; - margin_start = 12; - margin_end = 12; + margin_top = 10; + margin_bottom = 10; + margin_start = 10; + margin_end = 10; var overlay = new Gtk.Overlay (); append (overlay); @@ -24,10 +24,10 @@ overlay.add_overlay (toast); // the box with all the settings - var settingsbox = new Gtk.Box (VERTICAL, 24) { - margin_top = 6, - margin_start = 6, - margin_end = 6, + var settingsbox = new Gtk.Box (VERTICAL, 20) { + margin_top = 5, + margin_start = 5, + margin_end = 5, hexpand = true, vexpand = true, valign = Gtk.Align.START @@ -59,6 +59,36 @@ settingsbox.append (hidebar_box); + /***************************************/ + /* lists */ + /***************************************/ + + var lists_box = new Gtk.Box (HORIZONTAL, 5); + + var list_entry = new Gtk.Entry () { + halign = Gtk.Align.END, + hexpand = true, + valign = Gtk.Align.CENTER, + }; + + var list_label = new Granite.HeaderLabel (_("List item symbol")) { + mnemonic_widget = list_entry, + secondary_text = _("Symbol by which to begin each list item") + }; + + lists_box.append (list_label); + lists_box.append (list_entry); + + Application.gsettings.bind ( + "list-item-start", + list_entry, "text", + SettingsBindFlags.DEFAULT); + + + settingsbox.append (lists_box); + + + /****************************************************/ /* Autostart Request */ /****************************************************/ @@ -109,8 +139,8 @@ /*************************************************/ // Bar at the bottom var actionbar = new Gtk.CenterBox () { - margin_start = 6, - margin_end = 6, + margin_start = 5, + margin_end = 5, valign = Gtk.Align.END }; actionbar.set_hexpand (true); @@ -123,12 +153,6 @@ ); actionbar.start_widget = support_button; - // Reset - //reset_button = new Gtk.Button (); - //reset_button.set_label ( _("Reset to Default")); - //reset_button.tooltip_markup = (_("Reset all settings to defaults")); - //actionbar.pack_end (reset_button); - close_button = new Gtk.Button () { width_request = 96, label = _("Close"), @@ -139,7 +163,26 @@ }; actionbar.end_widget = close_button; + var reset = new Gtk.Button.from_icon_name ("system-reboot") { + tooltip_markup = _("Reset all settings to defaults") + }; + reset.clicked.connect (on_reset); + + append (settingsbox); append (actionbar); } + + private void on_reset () { + debug ("Resetting settings…"); + + string[] keys = {"scribbly-mode-active", "hide-bar"}; + foreach (var key in keys) { + Application.gsettings.reset (key); + } + +#if !WINDOWS + Jorts.Utils.autostart_remove (); +#endif + } } diff --git a/src/Widgets/PreferencesWidgets/SettingsSwitch.vala b/src/Widgets/PreferencesWidgets/SettingsSwitch.vala index 84a36920..25d1d970 100644 --- a/src/Widgets/PreferencesWidgets/SettingsSwitch.vala +++ b/src/Widgets/PreferencesWidgets/SettingsSwitch.vala @@ -12,7 +12,7 @@ public class Jorts.SettingsSwitch : Gtk.Box { public SettingsSwitch (string name, string explanation, string key) { orientation = Gtk.Orientation.HORIZONTAL; - spacing = 6; + spacing = 5; var toggle = new Gtk.Switch () { halign = Gtk.Align.END, diff --git a/src/Windows/PreferenceWindow.vala b/src/Windows/PreferenceWindow.vala index 16fee334..b2a53f26 100644 --- a/src/Windows/PreferenceWindow.vala +++ b/src/Windows/PreferenceWindow.vala @@ -69,13 +69,4 @@ public class Jorts.PreferenceWindow : Gtk.Window { //prefview.reset_button.clicked.connect (on_reset); prefview.close_button.clicked.connect (() => {close ();}); } - -/* private void on_reset () { - debug ("Resetting settings…"); - - string[] keys = {"scribbly-mode-active", "hide-bar"}; - foreach (var key in keys) { - Application.gsettings.reset (key); - } - } */ } From cadecb590cb6f8ba403c5fb79d6bfb1cb9b97196 Mon Sep 17 00:00:00 2001 From: teamcons Date: Sat, 15 Nov 2025 22:42:18 +0100 Subject: [PATCH 3/9] change spacing --- data/jorts.metainfo.xml.in | 4 +++- src/Views/PreferencesView.vala | 9 +++++---- src/Windows/StickyNoteWindow.vala | 1 + 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/data/jorts.metainfo.xml.in b/data/jorts.metainfo.xml.in index bbe348ef..fe90fafd 100644 --- a/data/jorts.metainfo.xml.in +++ b/data/jorts.metainfo.xml.in @@ -99,6 +99,7 @@

🚀 4.0.0 Jorts of Hyperspace!

  • Version 4 to align with Gtk version
  • +
  • Added button to toggle lists, and ability to customize them
  • Ctrl+Scroll to zoom-in, zoom-out
  • More zoom options
  • Keyboard shortcuts work from popover now
  • @@ -114,7 +115,8 @@ Fixed zoom impacting emojichooser and context menu Fixed coloring bleeding into icons in emojichooser and context menu - Fixed absence of Ctrl+scroll + Added Ctrl+scroll + Added list feature diff --git a/src/Views/PreferencesView.vala b/src/Views/PreferencesView.vala index 57a5e10a..8c80f7c1 100644 --- a/src/Views/PreferencesView.vala +++ b/src/Views/PreferencesView.vala @@ -67,8 +67,9 @@ var list_entry = new Gtk.Entry () { halign = Gtk.Align.END, - hexpand = true, + hexpand = false, valign = Gtk.Align.CENTER, + width_request = 15 }; var list_label = new Granite.HeaderLabel (_("List item symbol")) { @@ -93,13 +94,13 @@ /* Autostart Request */ /****************************************************/ #if !WINDOWS - var both_buttons = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6) { + var both_buttons = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 5) { halign = Gtk.Align.FILL }; ///TRANSLATORS: Button to autostart the application var set_autostart = new Gtk.Button () { - label = _("Set autostart"), + label = _("Autostart"), valign = Gtk.Align.CENTER }; @@ -124,7 +125,7 @@ both_buttons.append (set_autostart); both_buttons.append (remove_autostart); - var autostart_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6); + var autostart_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 5); var autostart_label = new Granite.HeaderLabel (_("Allow to start at login")) { mnemonic_widget = both_buttons, diff --git a/src/Windows/StickyNoteWindow.vala b/src/Windows/StickyNoteWindow.vala index b7cd0b76..88d3bcc1 100644 --- a/src/Windows/StickyNoteWindow.vala +++ b/src/Windows/StickyNoteWindow.vala @@ -250,6 +250,7 @@ public class Jorts.StickyNoteWindow : Gtk.Window { private void action_zoom_default () {zoomcontroller.zoom_default ();} private void action_zoom_in () {zoomcontroller.zoom_in ();} + // Careful! The keyboard counts from 1 to 10 (0), but the themes are from 0 to 9 private void action_theme_1 () {popover.color = (Jorts.Themes.all ())[0];} private void action_theme_2 () {popover.color = (Jorts.Themes.all ())[1];} private void action_theme_3 () {popover.color = (Jorts.Themes.all ())[2];} From c3e4b65c765338e9440c36ffa56d8e750fa5ad29 Mon Sep 17 00:00:00 2001 From: teamcons Date: Sat, 15 Nov 2025 23:55:13 +0100 Subject: [PATCH 4/9] Expand list function --- src/Application.vala | 1 + src/Views/PreferencesView.vala | 74 ++++++++++++++++-------------- src/Widgets/ActionBar.vala | 4 +- src/Widgets/TextView.vala | 76 ++++++++++++++++++++++++++++--- src/Windows/StickyNoteWindow.vala | 6 +-- 5 files changed, 116 insertions(+), 45 deletions(-) diff --git a/src/Application.vala b/src/Application.vala index 187aa56f..0117ec71 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -100,6 +100,7 @@ public class Jorts.Application : Gtk.Application { set_accels_for_action ("win.action_toggle_mono", {"m"}); set_accels_for_action ("win.action_focus_title", {"L"}); set_accels_for_action ("win.action_show_emoji", {"period"}); + set_accels_for_action ("win.action_toggle_list", {"F12"}); set_accels_for_action ("win.action_show_menu", {"G", "O"}); set_accels_for_action ("win.action_theme_1", {"1"}); diff --git a/src/Views/PreferencesView.vala b/src/Views/PreferencesView.vala index 8c80f7c1..9566e9d1 100644 --- a/src/Views/PreferencesView.vala +++ b/src/Views/PreferencesView.vala @@ -33,31 +33,6 @@ valign = Gtk.Align.START }; - /*************************************************/ - /* scribbly Toggle */ - /*************************************************/ - - debug ("Built UI. Lets do connects and binds"); - - var scribbly_box = new Jorts.SettingsSwitch ( - _("Make unfocused notes unreadable"), - _("If enabled, unfocused sticky notes become unreadable to protect their content from peeking eyes (Ctrl+H)"), - "scribbly-mode-active"); - - settingsbox.append (scribbly_box); - - - /*************************************************/ - /* hidebar Toggle */ - /*************************************************/ - - var hidebar_box = new Jorts.SettingsSwitch ( - _("Hide buttons"), - _("If enabled, hides the bottom bar in sticky notes. Keyboard shortcuts will still function (Ctrl+T)"), - "hide-bar"); - - settingsbox.append (hidebar_box); - /***************************************/ /* lists */ @@ -69,12 +44,13 @@ halign = Gtk.Align.END, hexpand = false, valign = Gtk.Align.CENTER, - width_request = 15 + max_width_chars = 5 }; var list_label = new Granite.HeaderLabel (_("List item symbol")) { mnemonic_widget = list_entry, - secondary_text = _("Symbol by which to begin each list item") + secondary_text = _("Prefix by which to begin each item in a list"), + hexpand = true }; lists_box.append (list_label); @@ -89,6 +65,31 @@ settingsbox.append (lists_box); + /*************************************************/ + /* scribbly Toggle */ + /*************************************************/ + + debug ("Built UI. Lets do connects and binds"); + + var scribbly_box = new Jorts.SettingsSwitch ( + _("Make unfocused notes unreadable"), + _("If enabled, unfocused sticky notes become unreadable to protect their content from peeking eyes (Ctrl+H)"), + "scribbly-mode-active"); + + settingsbox.append (scribbly_box); + + + /*************************************************/ + /* hidebar Toggle */ + /*************************************************/ + + var hidebar_box = new Jorts.SettingsSwitch ( + _("Hide buttons"), + _("If enabled, hides the bottom bar in sticky notes. Keyboard shortcuts will still function (Ctrl+T)"), + "hide-bar"); + + settingsbox.append (hidebar_box); + /****************************************************/ /* Autostart Request */ @@ -142,10 +143,10 @@ var actionbar = new Gtk.CenterBox () { margin_start = 5, margin_end = 5, - valign = Gtk.Align.END + valign = Gtk.Align.END, + hexpand = true, + vexpand = false }; - actionbar.set_hexpand (true); - actionbar.set_vexpand (false); // Monies? var support_button = new Gtk.LinkButton.with_label ( @@ -162,13 +163,17 @@ _("Close preferences") ) }; - actionbar.end_widget = close_button; - var reset = new Gtk.Button.from_icon_name ("system-reboot") { - tooltip_markup = _("Reset all settings to defaults") + var reset = new Gtk.Button.from_icon_name ("system-reboot-symbolic") { + tooltip_markup = _("Reset all settings to defaults"), + valign = Gtk.Align.CENTER }; reset.clicked.connect (on_reset); + var end_box = new Gtk.Box (HORIZONTAL, 5); + end_box.append (reset); + end_box.append (close_button); + actionbar.end_widget = end_box; append (settingsbox); append (actionbar); @@ -177,13 +182,14 @@ private void on_reset () { debug ("Resetting settings…"); - string[] keys = {"scribbly-mode-active", "hide-bar"}; + string[] keys = {"scribbly-mode-active", "hide-bar", "list-item-start"}; foreach (var key in keys) { Application.gsettings.reset (key); } #if !WINDOWS Jorts.Utils.autostart_remove (); + toast.send_notification (); #endif } } diff --git a/src/Widgets/ActionBar.vala b/src/Widgets/ActionBar.vala index 6513c4bf..a0c766d3 100644 --- a/src/Widgets/ActionBar.vala +++ b/src/Widgets/ActionBar.vala @@ -50,12 +50,12 @@ width_request = 32, height_request = 32, tooltip_markup = Granite.markup_accel_tooltip ( - {"w"}, + {"F12"}, _("Toggle list") ) }; list_button.add_css_class ("themedbutton"); - list_button.action_name = StickyNoteWindow.ACTION_PREFIX + StickyNoteWindow.ACTION_LIST; + list_button.action_name = StickyNoteWindow.ACTION_PREFIX + StickyNoteWindow.ACTION_TOGGLE_LIST; emojichooser_popover = new Gtk.EmojiChooser (); diff --git a/src/Widgets/TextView.vala b/src/Widgets/TextView.vala index 00f8df1e..42004a0e 100644 --- a/src/Widgets/TextView.vala +++ b/src/Widgets/TextView.vala @@ -44,7 +44,7 @@ public class Jorts.TextView : Granite.HyperTextView { }); } - public void list () { + public void toggle_list () { Gtk.TextIter start, end; buffer.get_selection_bounds (out start, out end); @@ -52,17 +52,81 @@ public class Jorts.TextView : Granite.HyperTextView { var last_line = (uint8)end.get_line (); debug ("got " + first_line.to_string () + " to " + last_line.to_string ()); - Gtk.TextIter startline; var list_item_start = Application.gsettings.get_string ("list-item-start"); + var selected_is_list = this.is_list (first_line, last_line, list_item_start); buffer.begin_user_action (); - for (uint8 i = first_line; i <= last_line; i++) { + if (selected_is_list) + { + this.remove_list (first_line, last_line, list_item_start); - debug ("doing line " + i.to_string ()); - buffer.get_iter_at_line_index (out startline, i, 0); - buffer.insert (ref startline, list_item_start, -1); + } else { + this.set_list (first_line, last_line, list_item_start); } buffer.end_user_action (); + } + + /** + * Add the list prefix only to lines who hasnt it already + */ + private bool has_prefix (uint8 line_number, string list_item_start) { + Gtk.TextIter start, end; + buffer.get_iter_at_line_offset (out start, line_number, 0); + + end = start.copy (); + end.forward_to_line_end (); + + var text_in_line = buffer.get_slice (start, end, false); + + return text_in_line.has_prefix (list_item_start); + } + + /** + * Checks whether Line x to Line y are all bulleted. + */ + private bool is_list (uint8 first_line, uint8 last_line, string list_item_start) { + + for (uint8 line_number = first_line; line_number <= last_line; line_number++) { + debug ("doing line " + line_number.to_string ()); + + if (!this.has_prefix (line_number, list_item_start)) { + return false; + } + } + return true; } + + /** + * Add the list prefix only to lines who hasnt it already + */ + private void set_list (uint8 first_line, uint8 last_line, string list_item_start) { + Gtk.TextIter line_start; + for (uint8 line_number = first_line; line_number <= last_line; line_number++) { + + debug ("doing line " + line_number.to_string ()); + if (!this.has_prefix (line_number, list_item_start)) { + buffer.get_iter_at_line_offset (out line_start, line_number, 0); + buffer.insert (ref line_start, list_item_start, -1); + } + } + } + + /** + * Remove list prefix from line x to line y. Presuppose it is there + */ + private void remove_list (uint8 first_line, uint8 last_line, string list_item_start) { + Gtk.TextIter line_start, prefix_end; + var remove_range = list_item_start.length; + + for (uint8 line_number = first_line; line_number <= last_line; line_number++) { + + debug ("doing line " + line_number.to_string ()); + buffer.get_iter_at_line_offset (out line_start, line_number, 0); + buffer.get_iter_at_line_offset (out prefix_end, line_number, remove_range); + buffer.delete (ref line_start, ref prefix_end); + } + } + + } diff --git a/src/Windows/StickyNoteWindow.vala b/src/Windows/StickyNoteWindow.vala index 88d3bcc1..a7951363 100644 --- a/src/Windows/StickyNoteWindow.vala +++ b/src/Windows/StickyNoteWindow.vala @@ -41,7 +41,7 @@ public class Jorts.StickyNoteWindow : Gtk.Window { public const string ACTION_ZOOM_IN = "action_zoom_in"; public const string ACTION_TOGGLE_MONO = "action_toggle_mono"; public const string ACTION_DELETE = "action_delete"; - public const string ACTION_LIST = "action_list"; + public const string ACTION_TOGGLE_LIST = "action_toggle_list"; public const string ACTION_THEME_1 = "action_theme_1"; public const string ACTION_THEME_2 = "action_theme_2"; @@ -64,7 +64,7 @@ public class Jorts.StickyNoteWindow : Gtk.Window { { ACTION_ZOOM_OUT, action_zoom_out}, { ACTION_ZOOM_DEFAULT, action_zoom_default}, { ACTION_TOGGLE_MONO, action_toggle_mono}, - { ACTION_LIST, action_list}, + { ACTION_TOGGLE_LIST, action_toggle_list}, { ACTION_ZOOM_IN, action_zoom_in}, { ACTION_THEME_1, action_theme_1}, { ACTION_THEME_2, action_theme_2}, @@ -244,7 +244,7 @@ public class Jorts.StickyNoteWindow : Gtk.Window { private void action_show_menu () {view.menu_button.activate ();} private void action_delete () {((Jorts.Application)this.application).manager.delete_note (this);} private void action_toggle_mono () {popover.monospace = !popover.monospace;} - private void action_list () {view.textview.list ();} + private void action_toggle_list () {view.textview.toggle_list ();} private void action_zoom_out () {zoomcontroller.zoom_out ();} private void action_zoom_default () {zoomcontroller.zoom_default ();} From f92f85870e8198a42c1ae76faccff13e27e4be70 Mon Sep 17 00:00:00 2001 From: teamcons Date: Sun, 16 Nov 2025 13:14:29 +0100 Subject: [PATCH 5/9] reactive buffer to user inputs in regards to lists --- src/Widgets/TextView.vala | 96 +++++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 14 deletions(-) diff --git a/src/Widgets/TextView.vala b/src/Widgets/TextView.vala index 42004a0e..0e5ca334 100644 --- a/src/Widgets/TextView.vala +++ b/src/Widgets/TextView.vala @@ -11,6 +11,9 @@ */ public class Jorts.TextView : Granite.HyperTextView { + private Gtk.EventControllerKey keyboard; + private string list_item_start; + public string text { owned get {return buffer.text;} set {buffer.text = value;} @@ -27,7 +30,14 @@ public class Jorts.TextView : Granite.HyperTextView { set_vexpand (true); set_wrap_mode (Gtk.WrapMode.WORD_CHAR); - //Application.gsettings.bind ("scribbly-mode-active", this, "scribbly", SettingsBindFlags.DEFAULT); + list_item_start = Application.gsettings.get_string ("list-item-start"); + //Application.gsettings.bind ("list-item-start", this, "list-item-start", GLib.SettingsBindFlags.GET); + + keyboard = new Gtk.EventControllerKey (); + add_controller (keyboard); + + keyboard.key_pressed.connect (on_key_pressed); + keyboard.key_released.connect (on_key_released); } public void paste () { @@ -52,16 +62,15 @@ public class Jorts.TextView : Granite.HyperTextView { var last_line = (uint8)end.get_line (); debug ("got " + first_line.to_string () + " to " + last_line.to_string ()); - var list_item_start = Application.gsettings.get_string ("list-item-start"); var selected_is_list = this.is_list (first_line, last_line, list_item_start); buffer.begin_user_action (); if (selected_is_list) { - this.remove_list (first_line, last_line, list_item_start); + this.remove_list (first_line, last_line); } else { - this.set_list (first_line, last_line, list_item_start); + this.set_list (first_line, last_line); } buffer.end_user_action (); } @@ -69,7 +78,7 @@ public class Jorts.TextView : Granite.HyperTextView { /** * Add the list prefix only to lines who hasnt it already */ - private bool has_prefix (uint8 line_number, string list_item_start) { + private bool has_prefix (uint8 line_number) { Gtk.TextIter start, end; buffer.get_iter_at_line_offset (out start, line_number, 0); @@ -89,7 +98,7 @@ public class Jorts.TextView : Granite.HyperTextView { for (uint8 line_number = first_line; line_number <= last_line; line_number++) { debug ("doing line " + line_number.to_string ()); - if (!this.has_prefix (line_number, list_item_start)) { + if (!this.has_prefix (line_number)) { return false; } } @@ -100,12 +109,12 @@ public class Jorts.TextView : Granite.HyperTextView { /** * Add the list prefix only to lines who hasnt it already */ - private void set_list (uint8 first_line, uint8 last_line, string list_item_start) { + private void set_list (uint8 first_line, uint8 last_line) { Gtk.TextIter line_start; for (uint8 line_number = first_line; line_number <= last_line; line_number++) { debug ("doing line " + line_number.to_string ()); - if (!this.has_prefix (line_number, list_item_start)) { + if (!this.has_prefix (line_number)) { buffer.get_iter_at_line_offset (out line_start, line_number, 0); buffer.insert (ref line_start, list_item_start, -1); } @@ -115,18 +124,77 @@ public class Jorts.TextView : Granite.HyperTextView { /** * Remove list prefix from line x to line y. Presuppose it is there */ - private void remove_list (uint8 first_line, uint8 last_line, string list_item_start) { + private void remove_list (uint8 first_line, uint8 last_line) { + for (uint8 line_number = first_line; line_number <= last_line; line_number++) { + remove_prefix (line_number); + } + } + + /** + * Remove list prefix from line x to line y. Presuppose it is there + */ + private void remove_prefix (uint8 line_number) { Gtk.TextIter line_start, prefix_end; var remove_range = list_item_start.length; - for (uint8 line_number = first_line; line_number <= last_line; line_number++) { + debug ("doing line " + line_number.to_string ()); + buffer.get_iter_at_line_offset (out line_start, line_number, 0); + buffer.get_iter_at_line_offset (out prefix_end, line_number, remove_range); + buffer.delete (ref line_start, ref prefix_end); + } - debug ("doing line " + line_number.to_string ()); - buffer.get_iter_at_line_offset (out line_start, line_number, 0); - buffer.get_iter_at_line_offset (out prefix_end, line_number, remove_range); - buffer.delete (ref line_start, ref prefix_end); + + /** + * Handler whenever a key is pressed, to see if user needs something and get ahead + * Some local stuff is deduplicated in the Ifs, because i do not like the idea of getting computation done not needed 98% of the time + */ + private bool on_key_pressed (uint keyval, uint keycode, Gdk.ModifierType state) { + print ("char typed"); + // User didnt like list being expanded. Undo that one. + if (keyval == Gdk.Key.BackSpace) { + print ("backspace"); + + Gtk.TextIter start, end; + buffer.get_selection_bounds (out start, out end); + + var line_number = (uint8)start.get_line (); + + if (has_prefix (line_number)) { + + buffer.get_iter_at_line_offset (out start, line_number, 0); + var text_in_line = buffer.get_slice (start, end, false); + + if (text_in_line == list_item_start) { + + buffer.begin_user_action (); + buffer.delete (ref start, ref end); + buffer.insert_at_cursor ("\n", -1); + buffer.end_user_action (); + } + } } + + return false; } + private void on_key_released (uint keyval, uint keycode, Gdk.ModifierType state) { + + // User did Enter + if (keyval == Gdk.Key.Return) { + Gtk.TextIter start, end; + buffer.get_selection_bounds (out start, out end); + start.backward_line (); + var line_number = (uint8)start.get_line (); + + if (this.has_prefix (line_number)) { + + buffer.begin_user_action (); + buffer.insert_at_cursor (list_item_start, -1); + buffer.end_user_action (); + } + } + + + } } From e19a805d0d60afce038d1f2d6cf5e7963f2e3a6c Mon Sep 17 00:00:00 2001 From: teamcons Date: Sun, 16 Nov 2025 21:16:51 +0100 Subject: [PATCH 6/9] hide button if no prefix --- src/Views/PreferencesView.vala | 3 ++- src/Widgets/ActionBar.vala | 3 +++ src/Widgets/TextView.vala | 16 ++++++++++++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Views/PreferencesView.vala b/src/Views/PreferencesView.vala index 9566e9d1..eb4e440a 100644 --- a/src/Views/PreferencesView.vala +++ b/src/Views/PreferencesView.vala @@ -44,12 +44,13 @@ halign = Gtk.Align.END, hexpand = false, valign = Gtk.Align.CENTER, + max_length = 5, max_width_chars = 5 }; var list_label = new Granite.HeaderLabel (_("List item symbol")) { mnemonic_widget = list_entry, - secondary_text = _("Prefix by which to begin each item in a list"), + secondary_text = _("Prefix by which to begin each item in a list. If there is no prefix, the toggle list button will be hidden"), hexpand = true }; diff --git a/src/Widgets/ActionBar.vala b/src/Widgets/ActionBar.vala index a0c766d3..dd73b575 100644 --- a/src/Widgets/ActionBar.vala +++ b/src/Widgets/ActionBar.vala @@ -57,6 +57,9 @@ list_button.add_css_class ("themedbutton"); list_button.action_name = StickyNoteWindow.ACTION_PREFIX + StickyNoteWindow.ACTION_TOGGLE_LIST; + // Hide the list button if user has specified no list item symbol + Application.gsettings.changed["list-item-start"].connect ( + () => {list_button.visible = (Application.gsettings.get_string ("list-item-start") != "");}); emojichooser_popover = new Gtk.EmojiChooser (); diff --git a/src/Widgets/TextView.vala b/src/Widgets/TextView.vala index 0e5ca334..2d1f949f 100644 --- a/src/Widgets/TextView.vala +++ b/src/Widgets/TextView.vala @@ -33,11 +33,15 @@ public class Jorts.TextView : Granite.HyperTextView { list_item_start = Application.gsettings.get_string ("list-item-start"); //Application.gsettings.bind ("list-item-start", this, "list-item-start", GLib.SettingsBindFlags.GET); + Application.gsettings.changed["list-item-start"].connect ( + () => {list_item_start = Application.gsettings.get_string ("list-item-start");}); + keyboard = new Gtk.EventControllerKey (); add_controller (keyboard); - keyboard.key_pressed.connect (on_key_pressed); keyboard.key_released.connect (on_key_released); + + buffer.notify["cursor_position"].connect (on_cursor_changed); } public void paste () { @@ -181,7 +185,6 @@ public class Jorts.TextView : Granite.HyperTextView { // User did Enter if (keyval == Gdk.Key.Return) { - Gtk.TextIter start, end; buffer.get_selection_bounds (out start, out end); start.backward_line (); @@ -194,7 +197,16 @@ public class Jorts.TextView : Granite.HyperTextView { buffer.end_user_action (); } } + } + private void on_cursor_changed () { + Gtk.TextIter start, end; + buffer.get_selection_bounds (out start, out end); + start.backward_line (); + var line_number = (uint8)start.get_line (); + if (this.has_prefix (line_number)) { + print ("YES THIS IS LIST"); + } } } From 553507b6842ad8b4583ba750bc20efda7a833418 Mon Sep 17 00:00:00 2001 From: teamcons Date: Sun, 16 Nov 2025 21:32:29 +0100 Subject: [PATCH 7/9] refine hide button thingy --- src/Widgets/ActionBar.vala | 16 +++++++++++----- src/Widgets/TextView.vala | 14 ++++++++------ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/Widgets/ActionBar.vala b/src/Widgets/ActionBar.vala index dd73b575..402bfe36 100644 --- a/src/Widgets/ActionBar.vala +++ b/src/Widgets/ActionBar.vala @@ -12,6 +12,7 @@ public class Jorts.ActionBar : Granite.Bin { public Gtk.ActionBar actionbar; + private Gtk.Button list_button; public Gtk.MenuButton emoji_button; public Gtk.EmojiChooser emojichooser_popover; public Gtk.MenuButton menu_button; @@ -45,7 +46,7 @@ delete_item.action_name = StickyNoteWindow.ACTION_PREFIX + StickyNoteWindow.ACTION_DELETE; /* **** RIGHT **** */ - var list_button = new Gtk.Button () { + list_button = new Gtk.Button () { icon_name = "view-list-symbolic", width_request = 32, height_request = 32, @@ -57,10 +58,6 @@ list_button.add_css_class ("themedbutton"); list_button.action_name = StickyNoteWindow.ACTION_PREFIX + StickyNoteWindow.ACTION_TOGGLE_LIST; - // Hide the list button if user has specified no list item symbol - Application.gsettings.changed["list-item-start"].connect ( - () => {list_button.visible = (Application.gsettings.get_string ("list-item-start") != "");}); - emojichooser_popover = new Gtk.EmojiChooser (); emoji_button = new Gtk.MenuButton () { @@ -106,6 +103,11 @@ // Randomize-skip emoji icon emojichooser_popover.show.connect (on_emoji_popover); + + // Hide the list button if user has specified no list item symbol + on_prefix_changed (); + Application.gsettings.changed["list-item-start"].connect (on_prefix_changed); + } /** @@ -126,4 +128,8 @@ ) ); } + + private void on_prefix_changed () { + list_button.visible = (Application.gsettings.get_string ("list-item-start") != ""); + } } diff --git a/src/Widgets/TextView.vala b/src/Widgets/TextView.vala index 2d1f949f..b427108e 100644 --- a/src/Widgets/TextView.vala +++ b/src/Widgets/TextView.vala @@ -33,15 +33,13 @@ public class Jorts.TextView : Granite.HyperTextView { list_item_start = Application.gsettings.get_string ("list-item-start"); //Application.gsettings.bind ("list-item-start", this, "list-item-start", GLib.SettingsBindFlags.GET); - Application.gsettings.changed["list-item-start"].connect ( - () => {list_item_start = Application.gsettings.get_string ("list-item-start");}); - keyboard = new Gtk.EventControllerKey (); add_controller (keyboard); keyboard.key_pressed.connect (on_key_pressed); keyboard.key_released.connect (on_key_released); buffer.notify["cursor_position"].connect (on_cursor_changed); + Application.gsettings.changed["list-item-start"].connect (on_prefix_changed); } public void paste () { @@ -199,14 +197,18 @@ public class Jorts.TextView : Granite.HyperTextView { } } + private void on_prefix_changed () { + list_item_start = Application.gsettings.get_string ("list-item-start"); + } + private void on_cursor_changed () { Gtk.TextIter start, end; buffer.get_selection_bounds (out start, out end); start.backward_line (); var line_number = (uint8)start.get_line (); - if (this.has_prefix (line_number)) { - print ("YES THIS IS LIST"); - } + if (this.has_prefix (line_number)) { + print ("YES THIS IS LIST"); + } } } From 50e1014a8db382b2b75a144d9d5ccd945ac6b827 Mon Sep 17 00:00:00 2001 From: teamcons Date: Sun, 16 Nov 2025 21:45:19 +0100 Subject: [PATCH 8/9] More elegant and snappy list expand --- src/Widgets/TextView.vala | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/Widgets/TextView.vala b/src/Widgets/TextView.vala index b427108e..4d296e56 100644 --- a/src/Widgets/TextView.vala +++ b/src/Widgets/TextView.vala @@ -36,9 +36,8 @@ public class Jorts.TextView : Granite.HyperTextView { keyboard = new Gtk.EventControllerKey (); add_controller (keyboard); keyboard.key_pressed.connect (on_key_pressed); - keyboard.key_released.connect (on_key_released); - buffer.notify["cursor_position"].connect (on_cursor_changed); + move_cursor.connect (on_cursor_changed); Application.gsettings.changed["list-item-start"].connect (on_prefix_changed); } @@ -145,14 +144,14 @@ public class Jorts.TextView : Granite.HyperTextView { buffer.delete (ref line_start, ref prefix_end); } - /** * Handler whenever a key is pressed, to see if user needs something and get ahead * Some local stuff is deduplicated in the Ifs, because i do not like the idea of getting computation done not needed 98% of the time */ private bool on_key_pressed (uint keyval, uint keycode, Gdk.ModifierType state) { print ("char typed"); - // User didnt like list being expanded. Undo that one. + + // If backspace on a prefix: Delete the prefix. if (keyval == Gdk.Key.BackSpace) { print ("backspace"); @@ -174,27 +173,27 @@ public class Jorts.TextView : Granite.HyperTextView { buffer.end_user_action (); } } - } - - return false; - } - private void on_key_released (uint keyval, uint keycode, Gdk.ModifierType state) { + return false; - // User did Enter - if (keyval == Gdk.Key.Return) { + // If Enter on a list item, add a list prefix on the new line + } else if (keyval == Gdk.Key.Return) { Gtk.TextIter start, end; buffer.get_selection_bounds (out start, out end); - start.backward_line (); var line_number = (uint8)start.get_line (); if (this.has_prefix (line_number)) { buffer.begin_user_action (); - buffer.insert_at_cursor (list_item_start, -1); + buffer.insert_at_cursor ("\n" + list_item_start, -1); buffer.end_user_action (); + + return true; } } + + // Nothing, carry on + return false; } private void on_prefix_changed () { From c1cc4fa8d4b3fd5ce4edb6da340c95e8292aaa1b Mon Sep 17 00:00:00 2001 From: teamcons Date: Sun, 16 Nov 2025 22:16:14 +0100 Subject: [PATCH 9/9] attempt at a dynamic togglebutton --- src/Views/NoteView.vala | 2 ++ src/Widgets/ActionBar.vala | 2 +- src/Widgets/TextView.vala | 16 +++++++++------- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Views/NoteView.vala b/src/Views/NoteView.vala index 3db3b7a8..c5e20c91 100644 --- a/src/Views/NoteView.vala +++ b/src/Views/NoteView.vala @@ -68,6 +68,8 @@ emojichooser_popover.show.connect (randomize_emote_button); emojichooser_popover.emoji_picked.connect (on_emoji_picked); //Application.gsettings.bind ("hide-bar", actionbar, "revealed", SettingsBindFlags.INVERT_BOOLEAN); + + //textview.bind_property ("on_list_item", actionbar.list_button, "active", GLib.BindingFlags.DEFAULT); } // Randomize the button emoji when clicked diff --git a/src/Widgets/ActionBar.vala b/src/Widgets/ActionBar.vala index 402bfe36..5a7dba41 100644 --- a/src/Widgets/ActionBar.vala +++ b/src/Widgets/ActionBar.vala @@ -12,7 +12,7 @@ public class Jorts.ActionBar : Granite.Bin { public Gtk.ActionBar actionbar; - private Gtk.Button list_button; + public Gtk.Button list_button; public Gtk.MenuButton emoji_button; public Gtk.EmojiChooser emojichooser_popover; public Gtk.MenuButton menu_button; diff --git a/src/Widgets/TextView.vala b/src/Widgets/TextView.vala index 4d296e56..f4cef519 100644 --- a/src/Widgets/TextView.vala +++ b/src/Widgets/TextView.vala @@ -13,6 +13,7 @@ public class Jorts.TextView : Granite.HyperTextView { private Gtk.EventControllerKey keyboard; private string list_item_start; + public bool on_list_item {public get; private set;} public string text { owned get {return buffer.text;} @@ -31,14 +32,16 @@ public class Jorts.TextView : Granite.HyperTextView { set_wrap_mode (Gtk.WrapMode.WORD_CHAR); list_item_start = Application.gsettings.get_string ("list-item-start"); - //Application.gsettings.bind ("list-item-start", this, "list-item-start", GLib.SettingsBindFlags.GET); + Application.gsettings.changed["list-item-start"].connect (on_prefix_changed); keyboard = new Gtk.EventControllerKey (); add_controller (keyboard); keyboard.key_pressed.connect (on_key_pressed); - move_cursor.connect (on_cursor_changed); - Application.gsettings.changed["list-item-start"].connect (on_prefix_changed); + //TODO: Buggy. Clicking anywhere brings it out of whack + // on_cursor_changed (); + // move_cursor.connect_after (on_cursor_changed); + } public void paste () { @@ -203,11 +206,10 @@ public class Jorts.TextView : Granite.HyperTextView { private void on_cursor_changed () { Gtk.TextIter start, end; buffer.get_selection_bounds (out start, out end); - start.backward_line (); var line_number = (uint8)start.get_line (); - if (this.has_prefix (line_number)) { - print ("YES THIS IS LIST"); - } + on_list_item = this.has_prefix (line_number); + + print ("THIS IS LIST. HAS " + on_list_item.to_string () + "ON LINE " + line_number.to_string ()); } }