diff --git a/meson.build b/meson.build index 0e5c4b302..ae6bb0b22 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,7 @@ project( 'io.elementary.code', 'vala', 'c', meson_version: '>= 0.58.0', - version: '8.3.1' + version: '9.0.0' ) add_project_arguments([ @@ -29,16 +29,16 @@ i18n = import('i18n') glib_dep = dependency('glib-2.0', version: '>=2.74.0') gio_unix_dep = dependency('gio-unix-2.0', version: '>=2.20') gee_dep = dependency('gee-0.8', version: '>=0.8.5') -gtk_dep = dependency('gtk+-3.0', version: '>=3.6.0') -granite_dep = dependency('granite', version: '>=6.0.0') -handy_dep = dependency('libhandy-1', version: '>=0.90.0') -gtksourceview_dep = dependency('gtksourceview-4') +gtk_dep = dependency('gtk4', version: '>=4.14.2') +granite_dep = dependency('granite-7', version: '>=7.0.0') +adwaita_dep = dependency('libadwaita-1', version: '>=1.0.0') +gtksourceview_dep = dependency('gtksourceview-5') peas_dep = dependency('libpeas-2') git_dep = dependency('libgit2-glib-1.0', version: '>=1.2.0') fontconfig_dep = dependency('fontconfig') pangofc_dep = dependency('pangoft2') posix_dep = meson.get_compiler('vala').find_library('posix') -vte_dep = dependency('vte-2.91') +vte_dep = dependency('vte-2.91-gtk4', version: '>=0.76') code_resources = gnome.compile_resources( 'code-resources', 'data/' + meson.project_name() + '.gresource.xml', @@ -55,7 +55,7 @@ dependencies = [ gee_dep, gtk_dep, granite_dep, - handy_dep, + adwaita_dep, gtksourceview_dep, peas_dep, git_dep, diff --git a/plugins/brackets-completion/brackets-completion.vala b/plugins/brackets-completion/brackets-completion.vala index 9a86edac0..0711c5cae 100644 --- a/plugins/brackets-completion/brackets-completion.vala +++ b/plugins/brackets-completion/brackets-completion.vala @@ -42,10 +42,12 @@ public class Scratch.Plugins.BracketsCompletion : Peas.ExtensionBase, Scratch.Se plugins = (Scratch.Services.Interface) object; plugins.hook_document.connect (on_hook_document); plugins.hook_window.connect ((w) => { - key_controller = new Gtk.EventControllerKey (w) { + key_controller = new Gtk.EventControllerKey () { propagation_phase = CAPTURE }; + ((Gtk.Widget) w).add_controller (key_controller); key_controller.key_pressed.connect (on_key_down); + key_controller.key_released.connect (on_key_release); }); } @@ -57,15 +59,17 @@ public class Scratch.Plugins.BracketsCompletion : Peas.ExtensionBase, Scratch.Se private void on_hook_document (Scratch.Services.Document doc) { current_buffer = doc.source_view.buffer; - + // var key_controller = new Gtk.EventControllerKey () { + // propagation_phase = BUBBLE + // }; if (current_source_view != null) { - current_source_view.event_after.disconnect (on_event_after); + // current_source_view.event_after.disconnect (on_event_after); current_source_view.backspace.disconnect (on_backspace); } current_source_view = doc.source_view; - current_source_view.event_after.connect (on_event_after); + // current_source_view.event_after.connect (on_event_after); current_source_view.backspace.connect (on_backspace); } @@ -174,11 +178,11 @@ public class Scratch.Plugins.BracketsCompletion : Peas.ExtensionBase, Scratch.Se Gdk.ModifierType state ) requires (current_source_view != null && current_buffer != null) { - if (!current_source_view.is_focus) { + if (!current_source_view.is_focus ()) { return false; } - if (Gdk.ModifierType.MOD1_MASK in state || Gdk.ModifierType.CONTROL_MASK in state) { + if (Gdk.ModifierType.ALT_MASK in state || Gdk.ModifierType.CONTROL_MASK in state) { return false; } @@ -235,22 +239,25 @@ public class Scratch.Plugins.BracketsCompletion : Peas.ExtensionBase, Scratch.Se } } - private void on_event_after (Gdk.Event root_event) { - if (root_event.type != Gdk.EventType.KEY_PRESS) { - return; - } - - var event = root_event.key; + private void on_key_release ( + uint keyval, + uint keycode, + Gdk.ModifierType state + ) { + // private void on_event_after (Gdk.Event root_event) { + // if (root_event.type != Gdk.EventType.KEY_PRESS) { + // return; + // } - if (current_source_view.auto_indent && (event.keyval == Gdk.Key.Return || event.keyval == Gdk.Key.KP_Enter)) { + if (current_source_view.auto_indent && (keyval == Gdk.Key.Return || keyval == Gdk.Key.KP_Enter)) { check_bracket_indent (); } - if (keys.has_key (event.keyval) && - !(Gdk.ModifierType.MOD1_MASK in event.state) && - !(Gdk.ModifierType.CONTROL_MASK in event.state)) { + if (keys.has_key (keyval) && + !(Gdk.ModifierType.ALT_MASK in state) && + !(Gdk.ModifierType.CONTROL_MASK in state)) { - string bracket = keys[event.keyval]; + string bracket = keys[keyval]; string next_char = get_next_char (); string prev_char = get_previous_char (); bool brackets_match = next_char == bracket && prev_char == bracket; diff --git a/plugins/detect-indent/detect-indent.vala b/plugins/detect-indent/detect-indent.vala index f94d91482..db07f9ccf 100644 --- a/plugins/detect-indent/detect-indent.vala +++ b/plugins/detect-indent/detect-indent.vala @@ -25,7 +25,7 @@ public class Scratch.Plugins.DetectIndent: Peas.ExtensionBase, Scratch.Services. return; } - var source_buffer = (Gtk.SourceBuffer) view.buffer; + var source_buffer = (GtkSource.Buffer) view.buffer; Gtk.TextIter it; source_buffer.get_iter_at_line (out it, 0); diff --git a/plugins/fuzzy-search/file-item.vala b/plugins/fuzzy-search/file-item.vala index e5f6563fd..ec04bbfed 100644 --- a/plugins/fuzzy-search/file-item.vala +++ b/plugins/fuzzy-search/file-item.vala @@ -16,8 +16,8 @@ public class FileItem : Gtk.ListBoxRow { } public FileItem (SearchResult res, bool should_distinguish_project = false) { - this.get_style_context ().add_class ("fuzzy-item"); - this.get_style_context ().add_class ("flat"); + this.add_css_class ("fuzzy-item"); + this.add_css_class ("flat"); result = res; Icon icon; @@ -41,18 +41,20 @@ public class FileItem : Gtk.ListBoxRow { icon = ContentType.get_icon ("text/plain"); } - var image = new Gtk.Image.from_gicon (icon, Gtk.IconSize.DND); - image.get_style_context ().add_class ("fuzzy-file-icon"); + var image = new Gtk.Image.from_gicon (icon) { + icon_size = Gtk.IconSize.NORMAL + }; + image.add_css_class ("fuzzy-file-icon"); - path_box.add (filename_label); - path_box.add (path_label); + path_box.append (filename_label); + path_box.append (path_label); var container_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 1) { valign = Gtk.Align.CENTER }; - container_box.add (image); - container_box.add (path_box); + container_box.append (image); + container_box.append (path_box); this.child = container_box; } diff --git a/plugins/fuzzy-search/fuzzy-search-popover.vala b/plugins/fuzzy-search/fuzzy-search-popover.vala index 9cdebf1cb..f27c47710 100644 --- a/plugins/fuzzy-search/fuzzy-search-popover.vala +++ b/plugins/fuzzy-search/fuzzy-search-popover.vala @@ -9,7 +9,7 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { private Gtk.SearchEntry search_term_entry; private Services.FuzzyFinder fuzzy_finder; - private Gtk.ListBox search_result_container; + private Gtk.ListBox search_result_listbox; private int preselected_index; private Gtk.ScrolledWindow scrolled; private Gee.ArrayList items; @@ -17,7 +17,7 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { private int window_height; private int max_items; private Gee.LinkedList cancellables; - private Gtk.EventControllerKey search_term_entry_key_controller; + // private Gtk.EventControllerKey search_term_entry_key_controller; private Gtk.Label title_label; private string current_doc_project; public Scratch.MainWindow current_window { get; construct; } @@ -63,30 +63,28 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { } construct { - modal = true; - relative_to = current_window.document_view; width_request = 500; pointing_to = { 0, 32, 1, 1 }; - this.get_style_context ().add_class ("fuzzy-popover"); + this.add_css_class ("fuzzy-popover"); title_label = new Gtk.Label (_("Find project files")); title_label.halign = Gtk.Align.START; - title_label.get_style_context ().add_class ("h4"); + title_label.add_css_class ("h4"); search_term_entry = new Gtk.SearchEntry (); search_term_entry.halign = Gtk.Align.FILL; search_term_entry.hexpand = true; - search_result_container = new Gtk.ListBox () { + search_result_listbox = new Gtk.ListBox () { selection_mode = Gtk.SelectionMode.NONE, activate_on_single_click = true, can_focus = false }; - search_result_container.get_style_context ().add_class ("fuzzy-list"); + search_result_listbox.add_css_class ("fuzzy-list"); - search_result_container.row_activated.connect ((row) => { + search_result_listbox.row_activated.connect ((row) => { var file_item = row as FileItem; if (file_item == null) { return; @@ -95,7 +93,8 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { handle_item_selection (items.index_of (file_item)); }); - search_term_entry_key_controller = new Gtk.EventControllerKey (search_term_entry); + var search_term_entry_key_controller = new Gtk.EventControllerKey (); + search_term_entry.add_controller (search_term_entry_key_controller); search_term_entry_key_controller.key_pressed.connect ((keyval, keycode, state) => { // Handle key up/down to select other files found by fuzzy search switch (keyval) { @@ -184,10 +183,9 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { bool first = true; - - - foreach (var c in search_result_container.get_children ()) { - search_result_container.remove (c); + var child = search_result_listbox.get_first_child (); + while (child != null) { + search_result_listbox.remove (child); } items.clear (); @@ -198,16 +196,15 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { if (first) { first = false; - file_item.get_style_context ().add_class ("preselect-fuzzy"); + file_item.add_css_class ("preselect-fuzzy"); preselected_index = 0; } - search_result_container.add (file_item); + search_result_listbox.append (file_item); items.add (file_item); } scrolled.hide (); - scrolled.show_all (); // Reset scrolling scrolled.vadjustment.value = 0; @@ -216,8 +213,9 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { return Source.REMOVE; }); } else { - foreach (var c in search_result_container.get_children ()) { - search_result_container.remove (c); + var child = search_result_listbox.get_first_child (); + while (child != null) { + search_result_listbox.remove (child); } items.clear (); @@ -228,24 +226,22 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { var entry_layout = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); entry_layout.valign = Gtk.Align.START; - entry_layout.add (title_label); - entry_layout.add (search_term_entry); + entry_layout.append (title_label); + entry_layout.append (search_term_entry); search_term_entry.valign = Gtk.Align.START; - scrolled = new Gtk.ScrolledWindow (null, null) { + scrolled = new Gtk.ScrolledWindow () { propagate_natural_height = true, - hexpand = true + hexpand = true, + child = search_result_listbox }; - scrolled.add (search_result_container); - var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); - box.pack_start (entry_layout, false, false); - box.pack_end (scrolled, true, true); - box.show_all (); + box.prepend (entry_layout); + box.append (scrolled); scrolled.hide (); - this.add (box); + this.child = box; fuzzy_finder = new Services.FuzzyFinder (search_indexer.project_paths); indexer = search_indexer; @@ -253,8 +249,7 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { cancellables = new Gee.LinkedList (); search_term_entry.realize.connect_after (() => { - int height; - current_window.get_size (null, out height); + int height = current_window.get_size (VERTICAL); // Limit the shown results if the window height is too small if (height > 400) { @@ -266,7 +261,7 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { scrolled.set_max_content_height (45 /* height */ * max_items); current_doc_project = get_current_project (); // This will not change while popover is showing - search_result_container.set_sort_func ((a , b) => { + search_result_listbox.set_sort_func ((a , b) => { var result_a = ((FileItem)a).result; var result_b = ((FileItem)b).result; var project_a_is_current = result_a.project == current_doc_project; @@ -293,8 +288,8 @@ public class Scratch.FuzzySearchPopover : Gtk.Popover { private void preselect_new_item (FileItem old_item, FileItem new_item) { var class_name = "preselect-fuzzy"; - old_item.get_style_context ().remove_class (class_name); - new_item.get_style_context ().add_class (class_name); + old_item.remove_css_class (class_name); + new_item.add_css_class (class_name); } private string get_current_project () { diff --git a/plugins/fuzzy-search/fuzzy-search.vala b/plugins/fuzzy-search/fuzzy-search.vala index e78692afc..169fd5a80 100644 --- a/plugins/fuzzy-search/fuzzy-search.vala +++ b/plugins/fuzzy-search/fuzzy-search.vala @@ -9,7 +9,6 @@ public class Scratch.Plugins.FuzzySearch: Peas.ExtensionBase, Scratch.Services.ActivatablePlugin { public Object object { owned get; set construct; } private const uint ACCEL_KEY = Gdk.Key.F; - private const Gdk.ModifierType ACCEL_MODTYPE = Gdk.ModifierType.MOD1_MASK; private Scratch.Services.FuzzySearchIndexer indexer; private MainWindow window = null; diff --git a/plugins/highlight-word-selection/highlight-word-selection.vala b/plugins/highlight-word-selection/highlight-word-selection.vala index dc44bb726..796225adf 100644 --- a/plugins/highlight-word-selection/highlight-word-selection.vala +++ b/plugins/highlight-word-selection/highlight-word-selection.vala @@ -23,7 +23,7 @@ public class Scratch.Plugins.HighlightSelectedWords : Peas.ExtensionBase, Scratch.Services.ActivatablePlugin { Scratch.Widgets.SourceView current_source; Scratch.MainWindow? main_window = null; - Gtk.SourceSearchContext? current_search_context = null; + GtkSource.SearchContext? current_search_context = null; private const uint SELECTION_HIGHLIGHT_MAX_CHARS = 255; @@ -118,8 +118,8 @@ public class Scratch.Plugins.HighlightSelectedWords : Peas.ExtensionBase, Scratc // We know the selected text is non-zero length, check not too long if (selected_text.char_count () <= SELECTION_HIGHLIGHT_MAX_CHARS) { - current_search_context = new Gtk.SourceSearchContext ( - (Gtk.SourceBuffer)current_source.buffer, + current_search_context = new GtkSource.SearchContext ( + (GtkSource.Buffer)current_source.buffer, null ); current_search_context.settings.search_text = selected_text; diff --git a/plugins/markdown-actions/markdown-actions.vala b/plugins/markdown-actions/markdown-actions.vala index d7efe7c8b..3baf3f03f 100644 --- a/plugins/markdown-actions/markdown-actions.vala +++ b/plugins/markdown-actions/markdown-actions.vala @@ -27,7 +27,7 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Scratch.Services public void update_state () {} - private Gtk.EventControllerKey key_controller; + // private Gtk.EventControllerKey key_controller; private bool is_markdown = false; public void activate () { @@ -43,9 +43,10 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Scratch.Services current_source.notify["language"].connect (configure_shortcuts); }); plugins.hook_window.connect ((w) => { - key_controller = new Gtk.EventControllerKey (w) { + var key_controller = new Gtk.EventControllerKey () { propagation_phase = CAPTURE }; + ((Gtk.Widget) w).add_controller (key_controller); key_controller.key_pressed.connect (shortcut_handler); }); } @@ -56,13 +57,12 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Scratch.Services } private bool shortcut_handler ( - Gtk.EventController controller, uint keyval, uint keycode, Gdk.ModifierType state ) requires (current_source != null) { - if (!current_source.is_focus) { + if (!current_source.is_focus ()) { return false; } diff --git a/plugins/meson.build b/plugins/meson.build index 906dcd078..2d23d61fc 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -7,7 +7,7 @@ subdir('highlight-word-selection') subdir('markdown-actions') subdir('pastebin') subdir('preserve-indent') -subdir('spell') +# subdir('spell') subdir('vim-emulation') subdir('word-completion') subdir('fuzzy-search') diff --git a/plugins/pastebin/pastebin.vala b/plugins/pastebin/pastebin.vala index 7b6f8f0b2..62da34d70 100644 --- a/plugins/pastebin/pastebin.vala +++ b/plugins/pastebin/pastebin.vala @@ -150,8 +150,9 @@ public class Scratch.Plugins.Pastebin : Peas.ExtensionBase, Scratch.Services.Act } else { MainWindow window = plugins.manager.window; pastebin_dialog = new Dialogs.PasteBinDialog (window, doc); - pastebin_dialog.destroy.connect (() => { + pastebin_dialog.close_request.connect (() => { pastebin_dialog = null; + return false; }); } } diff --git a/plugins/pastebin/pastebin_dialog.vala b/plugins/pastebin/pastebin_dialog.vala index 835cc4e9a..eee067087 100644 --- a/plugins/pastebin/pastebin_dialog.vala +++ b/plugins/pastebin/pastebin_dialog.vala @@ -312,7 +312,7 @@ namespace Scratch.Dialogs { grid.attach (private_check, 1, 3, 1, 1); var spinner = new Gtk.Spinner () { - active = true, + spinning = true, height_request = 32, valign = Gtk.Align.CENTER }; @@ -323,19 +323,17 @@ namespace Scratch.Dialogs { margin_start = 12, margin_end = 12 }; - stack.add (grid); - stack.add (spinner); + stack.add_child (grid); + stack.add_child (spinner); - get_content_area ().add (stack); + get_content_area ().append (stack); close_button = (Gtk.Button)add_button (_("Cancel"), Gtk.ResponseType.CANCEL); upload_button = (Gtk.Button)add_button (_("Upload to Pastebin"), Gtk.ResponseType.OK); - upload_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); + upload_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); read_settings (); - show_all (); - format_button.clicked.connect (format_button_clicked); upload_button.clicked.connect (() => { @@ -347,8 +345,9 @@ namespace Scratch.Dialogs { destroy (); }); - this.destroy.connect (() => { + this.close_request.connect (() => { write_settings (); + return false; }); } @@ -372,33 +371,32 @@ namespace Scratch.Dialogs { margin_end = 6 }; - languages_listbox.add (label); + languages_listbox.append (label); } - var languages_scrolled = new Gtk.ScrolledWindow (null, null) { + var languages_scrolled = new Gtk.ScrolledWindow () { hscrollbar_policy = Gtk.PolicyType.NEVER, height_request = 250, hexpand = true, - vexpand = true + vexpand = true, + child = languages_listbox }; - languages_scrolled.add (languages_listbox); var cancel_button = (Gtk.Button)format_dialog.add_button (_("Cancel"), Gtk.ResponseType.CANCEL); var select_button = (Gtk.Button)format_dialog.add_button (_("Select Format"), Gtk.ResponseType.OK); - select_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); + select_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); select_button.clicked.connect (select_button_clicked); var frame = new Gtk.Frame (null) { margin_top = 0, margin_bottom = 12, margin_start = 12, - margin_end = 12 + margin_end = 12, + child = languages_scrolled }; - frame.add (languages_scrolled); - format_dialog.get_content_area ().add (frame); - format_dialog.show_all (); + format_dialog.get_content_area ().append (frame); cancel_button.clicked.connect (() => { format_dialog.destroy (); @@ -447,18 +445,17 @@ namespace Scratch.Dialogs { var submit_result = submit_paste (out link); var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 10); - stack.add (box); + stack.add_child (box); if (submit_result) { //paste successfully var link_button = new Gtk.LinkButton (link); - box.pack_start (link_button, false, true, 25); + box.prepend (link_button); } else { var err_label = new Gtk.Label (link); - box.pack_start (err_label, false, true, 0); + box.prepend (err_label); } - box.show_all (); stack.visible_child = box; } diff --git a/plugins/spell/spell.vala b/plugins/spell/spell.vala index 53f501221..ef7e4df85 100644 --- a/plugins/spell/spell.vala +++ b/plugins/spell/spell.vala @@ -105,7 +105,7 @@ public class Scratch.Plugins.Spell: Peas.ExtensionBase, Scratch.Services.Activat }); // Deactivate Spell checker when we are editing a code file - var source_buffer = (Gtk.SourceBuffer) d.source_view.buffer; + var source_buffer = (GtkSource.Buffer) d.source_view.buffer; var lang = source_buffer.language; if (lang != null && lang.id != "markdown") { spell.detach (); diff --git a/plugins/vim-emulation/vim-emulation.vala b/plugins/vim-emulation/vim-emulation.vala index a32c922a1..4a7e88498 100644 --- a/plugins/vim-emulation/vim-emulation.vala +++ b/plugins/vim-emulation/vim-emulation.vala @@ -36,7 +36,7 @@ public class Scratch.Plugins.VimEmulation : Peas.ExtensionBase, Scratch.Services Scratch.Widgets.SourceView? view = null; Scratch.Services.Interface plugins; - private Gtk.EventControllerKey key_controller; + // private Gtk.EventControllerKey key_controller; public Object object { owned get; set construct; } @@ -55,10 +55,10 @@ public class Scratch.Plugins.VimEmulation : Peas.ExtensionBase, Scratch.Services this.views.add (view); }); plugins.hook_window.connect ((w) => { - key_controller = new Gtk.EventControllerKey (w) { + var key_controller = new Gtk.EventControllerKey () { propagation_phase = CAPTURE }; - + ((Gtk.Widget) w).add_controller (key_controller); key_controller.key_pressed.connect (handle_key_press); }); } @@ -68,13 +68,12 @@ public class Scratch.Plugins.VimEmulation : Peas.ExtensionBase, Scratch.Services } private bool handle_key_press ( - Gtk.EventController controller, uint keyval, uint keycode, Gdk.ModifierType state ) requires (view != null) { - if (!view.is_focus) { + if (!view.is_focus ()) { return false; } @@ -179,7 +178,7 @@ public class Scratch.Plugins.VimEmulation : Peas.ExtensionBase, Scratch.Services view.move_cursor (Gtk.MovementStep.PARAGRAPH_ENDS, 1, false); break; case Gdk.Key.u: - view.undo (); + // view.undo (); //TODO Use native undo break; case Gdk.Key.H: view.move_cursor (Gtk.MovementStep.BUFFER_ENDS, -1, false); diff --git a/plugins/word-completion/completion-provider.vala b/plugins/word-completion/completion-provider.vala index 2624f4d20..79c82a65a 100644 --- a/plugins/word-completion/completion-provider.vala +++ b/plugins/word-completion/completion-provider.vala @@ -19,12 +19,12 @@ * */ -public class Scratch.Plugins.CompletionProvider : Gtk.SourceCompletionProvider, GLib.Object { +public class Scratch.Plugins.CompletionProvider : GtkSource.CompletionProvider, GLib.Object { private const int MAX_COMPLETIONS = 10; public string name { get; construct; } public int priority { get; construct; } public int interactive_delay { get; construct; } - public Gtk.SourceCompletionActivation activation { get; construct; } + public GtkSource.CompletionActivation activation { get; construct; } public const string COMPLETION_END_MARK_NAME = "ScratchWordCompletionEnd"; public const string COMPLETION_START_MARK_NAME = "ScratchWordCompletionStart"; @@ -32,11 +32,11 @@ public class Scratch.Plugins.CompletionProvider : Gtk.SourceCompletionProvider, public Gtk.TextView? view { get; construct; } public Euclide.Completion.Parser parser { get; construct; } - private unowned Gtk.TextBuffer buffer { - get { - return view.buffer; - } - } + // private unowned Gtk.TextBuffer buffer { + // get { + // return view.buffer; + // } + // } private Gtk.TextMark completion_end_mark; private Gtk.TextMark completion_start_mark; @@ -61,93 +61,122 @@ public class Scratch.Plugins.CompletionProvider : Gtk.SourceCompletionProvider, activation = INTERACTIVE | USER_REQUESTED; Gtk.TextIter iter; view.buffer.get_iter_at_offset (out iter, 0); - completion_end_mark = buffer.create_mark (COMPLETION_END_MARK_NAME, iter, false); - completion_start_mark = buffer.create_mark (COMPLETION_START_MARK_NAME, iter, false); + completion_end_mark = view.buffer.create_mark (COMPLETION_END_MARK_NAME, iter, false); + completion_start_mark = view.buffer.create_mark (COMPLETION_START_MARK_NAME, iter, false); } - public bool match (Gtk.SourceCompletionContext context) { + public bool match (GtkSource.CompletionContext context) { Gtk.TextIter start, end; - buffer.get_iter_at_offset (out end, buffer.cursor_position); + var buff = context.get_buffer (); + buff.get_iter_at_offset (out end, buff.cursor_position); start = end.copy (); Euclide.Completion.Parser.back_to_word_start (ref start); - string text = buffer.get_text (start, end, true); + string text = buff.get_text (start, end, true); return parser.match (text); } - public void populate (Gtk.SourceCompletionContext context) { + public async ListModel populate_async (GtkSource.CompletionContext context, Cancellable? cancellable) throws Error { /*Store current insertion point for use in activate_proposal */ - GLib.List? file_props; - bool no_minimum = (context.get_activation () == Gtk.SourceCompletionActivation.USER_REQUESTED); - get_proposals (out file_props, no_minimum); - context.add_proposals (this, file_props, true); + bool no_minimum = (context.get_activation () == GtkSource.CompletionActivation.USER_REQUESTED); + return yield get_proposals (context, no_minimum); + } + + public void display ( + GtkSource.CompletionContext context, + GtkSource.CompletionProposal proposal, + GtkSource.CompletionCell cell + ) { + var columntype = cell.column; + warning ("filling column %s", columntype.to_string ()); + // For now only fill TYPED_TEXT + if (columntype == TYPED_TEXT) { + cell.text = ((CompletionItem) proposal).label; + }; } - public bool activate_proposal (Gtk.SourceCompletionProposal proposal, Gtk.TextIter iter) { + public void activate ( + GtkSource.CompletionContext context, + GtkSource.CompletionProposal proposal + ) { Gtk.TextIter start; Gtk.TextIter end; Gtk.TextMark mark; + var completion_item = (CompletionItem) proposal; + var buff = context.get_buffer (); + mark = buff.get_mark (COMPLETION_END_MARK_NAME); + buff.get_iter_at_mark (out end, mark); - mark = buffer.get_mark (COMPLETION_END_MARK_NAME); - buffer.get_iter_at_mark (out end, mark); + mark = buff.get_mark (COMPLETION_START_MARK_NAME); + buff.get_iter_at_mark (out start, mark); - mark = buffer.get_mark (COMPLETION_START_MARK_NAME); - buffer.get_iter_at_mark (out start, mark); + buff.@delete (ref start, ref end); + buff.insert (ref start, completion_item.text, completion_item.text.length); + } - buffer.@delete (ref start, ref end); - buffer.insert (ref start, proposal.get_text (), proposal.get_text ().length); - return true; + public void refilter (GtkSource.CompletionContext context, ListModel model) { + //TODO Allow refiltering of the model } - public bool get_start_iter (Gtk.SourceCompletionContext context, - Gtk.SourceCompletionProposal proposal, + public bool get_start_iter (GtkSource.CompletionContext context, + GtkSource.CompletionProposal proposal, out Gtk.TextIter iter) { - var mark = buffer.get_insert (); + var mark = context.get_buffer ().get_insert (); Gtk.TextIter cursor_iter; - buffer.get_iter_at_mark (out cursor_iter, mark); + context.get_buffer ().get_iter_at_mark (out cursor_iter, mark); iter = cursor_iter; Euclide.Completion.Parser.back_to_word_start (ref iter); return true; } - private bool get_proposals (out GLib.List? props, bool no_minimum) { - string to_find = ""; - Gtk.TextBuffer temp_buffer = buffer; - props = null; + private async ListModel get_proposals (GtkSource.CompletionContext context, bool no_minimum) throws Error { + // Just throw IOERROR for now - not worth registering domain + var model = new ListStore (typeof (GtkSource.CompletionProposal)); + // string to_find = ""; + var buff = context.get_buffer (); + // props = null; Gtk.TextIter start, end; - buffer.get_selection_bounds (out start, out end); + context.get_bounds (out start, out end); - to_find = temp_buffer.get_text (start, end, true); + var to_find = context.get_word (); if (to_find.length == 0) { - temp_buffer.get_iter_at_offset (out end, buffer.cursor_position); - + buff.get_iter_at_offset (out end, buff.cursor_position); start = end; Euclide.Completion.Parser.back_to_word_start (ref start); - - to_find = buffer.get_text (start, end, false); } - buffer.move_mark_by_name (COMPLETION_END_MARK_NAME, end); - buffer.move_mark_by_name (COMPLETION_START_MARK_NAME, start); + // Do we need this? + buff.move_mark_by_name (COMPLETION_END_MARK_NAME, end); + buff.move_mark_by_name (COMPLETION_START_MARK_NAME, start); /* There is no minimum length of word to find if the user requested a completion */ - if (no_minimum || to_find.length >= Euclide.Completion.Parser.MINIMUM_WORD_LENGTH) { + if (!no_minimum && to_find.length < Euclide.Completion.Parser.MINIMUM_WORD_LENGTH) { + throw new IOError.INVALID_DATA ("Word to find shorter than minimum"); + } else { /* Get proposals, if any */ List prop_word_list; if (parser.get_for_word (to_find, out prop_word_list)) { foreach (var word in prop_word_list) { - var item = new Gtk.SourceCompletionItem (); - item.label = word; - item.text = word; - props.append (item); - } + var item = new CompletionItem () { + label = word, // What is displayed + text = word // What gets inserted + }; - return true; + model.append (item); + } + } else { + throw new IOError.NOT_FOUND ("No proposals found"); } } - return false; + + return model; + } + + private class CompletionItem : Object, GtkSource.CompletionProposal { + public string label { get; set construct; } + public string text { get; set construct; } } } diff --git a/plugins/word-completion/plugin.vala b/plugins/word-completion/plugin.vala index 81559c6f4..12e584f25 100644 --- a/plugins/word-completion/plugin.vala +++ b/plugins/word-completion/plugin.vala @@ -24,15 +24,16 @@ public class Scratch.Plugins.Completion : Peas.ExtensionBase, Scratch.Services.A public Object object { owned get; set construct; } - private List text_view_list = new List (); - private Gtk.EventControllerKey key_controller; + private List text_view_list = new List (); + // private Gtk.EventControllerKey key_controller; public Euclide.Completion.Parser parser {get; private set;} - public Gtk.SourceView? current_view {get; private set;} + public GtkSource.View? current_view {get; private set;} public Scratch.Services.Document current_document {get; private set;} private MainWindow main_window; private Scratch.Services.Interface plugins; private bool completion_in_progress = false; + private Scratch.Plugins.CompletionProvider comp_provider; private const uint [] ACTIVATE_KEYS = { Gdk.Key.Return, @@ -56,9 +57,10 @@ public class Scratch.Plugins.Completion : Peas.ExtensionBase, Scratch.Services.A plugins.hook_document.connect (on_new_source_view); plugins.hook_window.connect ((w) => { - key_controller = new Gtk.EventControllerKey (w) { + var key_controller = new Gtk.EventControllerKey () { propagation_phase = CAPTURE }; + ((Gtk.Widget) w).add_controller (key_controller); key_controller.key_pressed.connect (on_key_press); }); @@ -99,11 +101,10 @@ public class Scratch.Plugins.Completion : Peas.ExtensionBase, Scratch.Services.A if (text_view_list.find (current_view) == null) text_view_list.append (current_view); - var comp_provider = new Scratch.Plugins.CompletionProvider (parser, doc); + comp_provider = new Scratch.Plugins.CompletionProvider (parser, doc); try { current_view.completion.add_provider (comp_provider); - current_view.completion.show_headers = true; current_view.completion.show_icons = true; /* Wait a bit to allow text to load then run parser*/ timeout_id = Timeout.add (1000, on_timeout_update); @@ -136,11 +137,11 @@ public class Scratch.Plugins.Completion : Peas.ExtensionBase, Scratch.Services.A ) requires (current_view != null) { var kv = keyval; - if (!current_view.is_focus) { + if (!current_view.is_focus ()) { return false; } /* Pass through any modified keypress except Shift or Capslock */ - Gdk.ModifierType mods = state & Gdk.ModifierType.MODIFIER_MASK + Gdk.ModifierType mods = state & Gdk.MODIFIER_MASK & ~Gdk.ModifierType.SHIFT_MASK & ~Gdk.ModifierType.LOCK_MASK; if (mods > 0 ) { @@ -182,18 +183,8 @@ public class Scratch.Plugins.Completion : Peas.ExtensionBase, Scratch.Services.A return _("%s - Word Completion").printf (doc.get_basename ()); } - private void cleanup (Gtk.SourceView view) { - current_view.completion.get_providers ().foreach ((p) => { - try { - /* Only remove provider added by this plug in */ - if (p.get_name () == provider_name_from_document (current_document)) { - debug ("removing provider %s", p.get_name ()); - current_view.completion.remove_provider (p); - } - } catch (Error e) { - warning (e.message); - } - }); + private void cleanup (GtkSource.View view) { + current_view.completion.remove_provider (comp_provider); } } diff --git a/src/Application.vala b/src/Application.vala index 56581cb32..ee7b26008 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -170,8 +170,7 @@ namespace Scratch { // Create a new document if requested if (create_new_tab) { create_new_tab = false; - var active_window_action_group = active_window.get_action_group (MainWindow.ACTION_GROUP); - active_window_action_group.activate_action (MainWindow.ACTION_NEW_TAB, null); + ((MainWindow)active_window).document_view.new_document (); } } diff --git a/src/Dialogs/BranchActions/BranchActionDialog.vala b/src/Dialogs/BranchActions/BranchActionDialog.vala index ce95d7ad7..4c1a55e80 100644 --- a/src/Dialogs/BranchActions/BranchActionDialog.vala +++ b/src/Dialogs/BranchActions/BranchActionDialog.vala @@ -80,11 +80,10 @@ public class Scratch.Dialogs.BranchActionDialog : Granite.MessageDialog { }; var content_box = new Gtk.Box (HORIZONTAL, 12); - content_box.add (sidebar); - content_box.add (stack); + content_box.append (sidebar); + content_box.append (stack); - custom_bin.add (content_box); - custom_bin.show_all (); + custom_bin.append (content_box); } else { primary_text = _("'%s' is not a git repository").printf ( project.file.file.get_basename () @@ -93,7 +92,7 @@ public class Scratch.Dialogs.BranchActionDialog : Granite.MessageDialog { image_icon = new ThemedIcon ("dialog-error"); } - realize.connect (() => { + ((Gtk.Widget) this).realize.connect (() => { ((BranchActionPage)stack.get_visible_child ()).focus_start_widget (); }); diff --git a/src/Dialogs/BranchActions/BranchCheckoutPage.vala b/src/Dialogs/BranchActions/BranchCheckoutPage.vala index e1ed53e1e..f21972398 100644 --- a/src/Dialogs/BranchActions/BranchCheckoutPage.vala +++ b/src/Dialogs/BranchActions/BranchCheckoutPage.vala @@ -36,7 +36,7 @@ public class Scratch.Dialogs.BranchCheckoutPage : Gtk.Box, BranchActionPage { construct { list_box = new BranchListBox (dialog, true); - add (list_box); + append (list_box); list_box.branch_changed.connect ((text) => { dialog.can_apply = dialog.project.has_branch_name (text, null); }); diff --git a/src/Dialogs/BranchActions/BranchCreatePage.vala b/src/Dialogs/BranchActions/BranchCreatePage.vala index dbe895743..50745e176 100644 --- a/src/Dialogs/BranchActions/BranchCreatePage.vala +++ b/src/Dialogs/BranchActions/BranchCreatePage.vala @@ -47,8 +47,8 @@ public class Scratch.Dialogs.BranchCreatePage : Gtk.Box, BranchActionPage { placeholder_text = _("Enter new branch name") }; - add (label); - add (new_branch_name_entry); + append (label); + append (new_branch_name_entry); new_branch_name_entry.bind_property ("is-valid", dialog, "can-apply"); diff --git a/src/Dialogs/BranchActions/BranchListBox.vala b/src/Dialogs/BranchActions/BranchListBox.vala index 919da36ca..56e027b1d 100644 --- a/src/Dialogs/BranchActions/BranchListBox.vala +++ b/src/Dialogs/BranchActions/BranchListBox.vala @@ -19,9 +19,10 @@ private class Scratch.Dialogs.BranchListBox : Gtk.Box { private Gtk.ListBox list_box; private Gtk.SearchEntry search_entry; - private Gtk.Label local_header; - private Gtk.Label remote_header; - private Gtk.Label recent_header; + private Gtk.Text entry; + private Gtk.Widget local_header; + private Gtk.Widget remote_header; + private Gtk.Widget recent_header; public BranchListBox (BranchActionDialog dialog, bool show_remotes) { Object ( @@ -38,7 +39,7 @@ private class Scratch.Dialogs.BranchListBox : Gtk.Box { activate_on_single_click = false }; - var scrolled_window = new Gtk.ScrolledWindow (null, null) { + var scrolled_window = new Gtk.ScrolledWindow () { hscrollbar_policy = NEVER, vscrollbar_policy = AUTOMATIC, min_content_height = 200, @@ -47,9 +48,15 @@ private class Scratch.Dialogs.BranchListBox : Gtk.Box { scrolled_window.child = list_box; search_entry = new Gtk.SearchEntry () { - placeholder_text = _("Enter search term") + placeholder_text = _("Enter search term"), + search_delay = 300 }; + entry = new Gtk.Text (); + entry.set_parent (search_entry); + + search_entry.set_key_capture_widget (entry); + recent_header = new Granite.HeaderLabel (_("Recent Branches")); local_header = new Granite.HeaderLabel (_("Local Branches")); remote_header = new Granite.HeaderLabel (_("Remote Branches")); @@ -62,7 +69,7 @@ private class Scratch.Dialogs.BranchListBox : Gtk.Box { row.is_recent = true; } - list_box.add (row); + list_box.append (row); } } @@ -70,9 +77,9 @@ private class Scratch.Dialogs.BranchListBox : Gtk.Box { list_box.set_header_func (listbox_header_func); list_box.row_selected.connect ((listboxrow) => { //We want cursor to end up after the inserted text - search_entry.text = ((BranchNameRow)(listboxrow)).branch_name; - search_entry.grab_focus_without_selecting (); - search_entry.move_cursor (DISPLAY_LINE_ENDS, 1, false); + entry.text = ((BranchNameRow)(listboxrow)).branch_name; + entry.grab_focus_without_selecting (); + entry.move_cursor (DISPLAY_LINE_ENDS, 1, false); }); list_box.row_activated.connect ((listboxrow) => { dialog.page_activated (); @@ -81,7 +88,7 @@ private class Scratch.Dialogs.BranchListBox : Gtk.Box { return (((BranchNameRow)(listboxrow)).branch_name.contains (search_entry.text)); }); - search_entry.changed.connect (() => { + search_entry.search_changed.connect (() => { list_box.invalidate_filter (); branch_changed (text); }); @@ -89,8 +96,8 @@ private class Scratch.Dialogs.BranchListBox : Gtk.Box { dialog.page_activated (); }); - add (search_entry); - add (scrolled_window); + append (search_entry); + append (scrolled_window); } public BranchNameRow? get_selected_row () { diff --git a/src/Dialogs/CloneRepositoryDialog.vala b/src/Dialogs/CloneRepositoryDialog.vala index 80631c603..0f5a88870 100644 --- a/src/Dialogs/CloneRepositoryDialog.vala +++ b/src/Dialogs/CloneRepositoryDialog.vala @@ -57,7 +57,8 @@ public class Scratch.Dialogs.CloneRepositoryDialog : Granite.MessageDialog { var cancel_button = add_button (_("Cancel"), Gtk.ResponseType.CANCEL); clone_button = (Gtk.Button)add_button (_("Clone Repository"), Gtk.ResponseType.APPLY); - set_default (clone_button); + + set_default_response (Gtk.ResponseType.CANCEL); try { name_regex = new Regex (NAME_REGEX, OPTIMIZE, ANCHORED | NOTEMPTY); @@ -80,9 +81,9 @@ public class Scratch.Dialogs.CloneRepositoryDialog : Granite.MessageDialog { }; var folder_chooser_button_child = new Gtk.Box (HORIZONTAL, 6); - folder_chooser_button_child.add (projects_folder_label); - folder_chooser_button_child.add ( - new Gtk.Image.from_icon_name ("folder-open-symbolic", BUTTON) + folder_chooser_button_child.append (projects_folder_label); + folder_chooser_button_child.append ( + new Gtk.Image.from_icon_name ("folder-open-symbolic") ); var folder_chooser_button = new Gtk.Button () { @@ -96,10 +97,24 @@ public class Scratch.Dialogs.CloneRepositoryDialog : Granite.MessageDialog { _("Select"), _("Cancel") ); - chooser.set_current_folder (projects_folder_label.label); + + try { + chooser.set_current_folder (GLib.File.new_for_path (projects_folder_label.label)); + } catch (Error e) { + warning ("Could not set current folder. %s", e.message); + } + chooser.response.connect ((res) => { if (res == Gtk.ResponseType.ACCEPT) { - projects_folder_label.label = chooser.get_filename (); + var file = chooser.get_file (); + try { + var info = file.query_info (FileAttribute.STANDARD_DISPLAY_NAME, NONE, null); + projects_folder_label.label = info.get_attribute_as_string (FileAttribute.STANDARD_DISPLAY_NAME); + } catch (Error e) { + warning ("could not get display name attribute"); + projects_folder_label.label = file.get_basename (); + } + update_can_clone (); } @@ -115,9 +130,9 @@ public class Scratch.Dialogs.CloneRepositoryDialog : Granite.MessageDialog { local_project_name_entry.changed.connect (validate_local_name); var content_box = new Gtk.Box (VERTICAL, 0); - content_box.add (new CloneEntry (_("Repository URL"), remote_repository_uri_entry)); - content_box.add (new CloneEntry (_("Location"), folder_chooser_button)); - content_box.add (new CloneEntry (_("Name of Clone"), local_project_name_entry)); + content_box.append (new CloneEntry (_("Repository URL"), remote_repository_uri_entry)); + content_box.append (new CloneEntry (_("Location"), folder_chooser_button)); + content_box.append (new CloneEntry (_("Name of Clone"), local_project_name_entry)); var cloning_label = new Granite.HeaderLabel (_("Cloning in progress")); spinner = new Gtk.Spinner (); @@ -126,16 +141,15 @@ public class Scratch.Dialogs.CloneRepositoryDialog : Granite.MessageDialog { valign = CENTER, halign = CENTER }; - cloning_box.add (cloning_label); - cloning_box.add (spinner); + cloning_box.append (cloning_label); + cloning_box.append (spinner); stack = new Gtk.Stack (); stack.add_named (content_box, "entries"); stack.add_named (cloning_box, "cloning"); stack.visible_child_name = "entries"; - custom_bin.add (stack); - custom_bin.show_all (); + custom_bin.append (stack); bind_property ("can-clone", clone_button, "sensitive", DEFAULT | SYNC_CREATE); spinner.bind_property ("active", clone_button, "visible", INVERT_BOOLEAN); @@ -246,8 +260,8 @@ public class Scratch.Dialogs.CloneRepositoryDialog : Granite.MessageDialog { mnemonic_widget = entry }; - add (label); - add (entry); + append (label); + append (entry); } construct { diff --git a/src/Dialogs/CloseProjectsConfirmationDialog.vala b/src/Dialogs/CloseProjectsConfirmationDialog.vala index 54cf1f678..6d263d55f 100644 --- a/src/Dialogs/CloseProjectsConfirmationDialog.vala +++ b/src/Dialogs/CloseProjectsConfirmationDialog.vala @@ -63,6 +63,6 @@ public class Scratch.Dialogs.CloseProjectsConfirmationDialog : Granite.MessageDi add_button (_("Don't Open"), Gtk.ResponseType.REJECT); var ignore_button = (Gtk.Button) add_button (button_label, Gtk.ResponseType.ACCEPT); - ignore_button.get_style_context ().add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); + ignore_button.add_css_class (Granite.STYLE_CLASS_DESTRUCTIVE_ACTION); } } diff --git a/src/Dialogs/GlobalSearchDialog.vala b/src/Dialogs/GlobalSearchDialog.vala index 94438a976..2e35c3592 100644 --- a/src/Dialogs/GlobalSearchDialog.vala +++ b/src/Dialogs/GlobalSearchDialog.vala @@ -71,25 +71,22 @@ public class Scratch.Dialogs.GlobalSearchDialog : Granite.MessageDialog { var box = new Gtk.Box (VERTICAL, 0); if (!use_regex) { - box.add (new Gtk.Label (case_text) { halign = START }); + box.append (new Gtk.Label (case_text) { halign = START }); if (wholeword) { - box.add (new Gtk.Label (wholeword_text) { halign = START }); + box.append (new Gtk.Label (wholeword_text) { halign = START }); } } else { - box.add (new Gtk.Label (regex_text) { halign = START }); + box.append (new Gtk.Label (regex_text) { halign = START }); } - box.add (search_term_entry); + box.append (search_term_entry); - custom_bin.add (box); - custom_bin.show_all (); + custom_bin.append (box); add_button (_("Cancel"), Gtk.ResponseType.CANCEL); var search_button = (Gtk.Button) add_button (_("Search"), Gtk.ResponseType.ACCEPT); - search_button.can_default = true; - search_button.has_default = true; - search_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); + search_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); search_term_entry.bind_property ( "is-valid", search_button, "sensitive", BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE diff --git a/src/Dialogs/OverwriteUncommittedConfirmationDialog.vala b/src/Dialogs/OverwriteUncommittedConfirmationDialog.vala index 0c63bcbbf..a118d4794 100644 --- a/src/Dialogs/OverwriteUncommittedConfirmationDialog.vala +++ b/src/Dialogs/OverwriteUncommittedConfirmationDialog.vala @@ -43,6 +43,6 @@ public class Scratch.Dialogs.OverwriteUncommittedConfirmationDialog : Granite.Me var cancel_button = add_button (_("Do not Checkout"), Gtk.ResponseType.REJECT); var proceed_button = (Gtk.Button) add_button (_("Checkout and Overwrite"), Gtk.ResponseType.ACCEPT); - proceed_button.get_style_context ().add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); + proceed_button.add_css_class (Granite.STYLE_CLASS_DESTRUCTIVE_ACTION); } } diff --git a/src/Dialogs/PreferencesDialog.vala b/src/Dialogs/PreferencesDialog.vala index ee38c43a6..77dd9ed4a 100644 --- a/src/Dialogs/PreferencesDialog.vala +++ b/src/Dialogs/PreferencesDialog.vala @@ -21,14 +21,14 @@ public class Scratch.Dialogs.Preferences : Granite.Dialog { construct { var general_box = new Gtk.Box (VERTICAL, 12); - general_box.add (new Granite.HeaderLabel (_("General"))); - general_box.add (new SettingSwitch (_("Save files when changed"), "autosave")); - general_box.add (new SettingSwitch ( + general_box.append (new Granite.HeaderLabel (_("General"))); + general_box.append (new SettingSwitch (_("Save files when changed"), "autosave")); + general_box.append (new SettingSwitch ( _("Strip trailing whitespace on save"), "strip-trailing-on-save", _("Except Plain Text, Markdown and YAML") )); - general_box.add (new SettingSwitch ( + general_box.append (new SettingSwitch ( _("Smart cut/copy lines"), "smart-cut-copy", _("Cutting or copying without an active selection will cut or copy the entire current line") @@ -44,14 +44,14 @@ public class Scratch.Dialogs.Preferences : Granite.Dialog { }; var indent_width_box = new Gtk.Box (HORIZONTAL, 12); - indent_width_box.add (indent_width_label); - indent_width_box.add (indent_width); + indent_width_box.append (indent_width_label); + indent_width_box.append (indent_width); var indentation_box = new Gtk.Box (VERTICAL, 12); - indentation_box.add (new Granite.HeaderLabel (_("Indentation"))); - indentation_box.add (new SettingSwitch (_("Automatic indentation"), "auto-indent")); - indentation_box.add (new SettingSwitch (_("Insert spaces instead of tabs"), "spaces-instead-of-tabs")); - indentation_box.add (indent_width_box); + indentation_box.append (new Granite.HeaderLabel (_("Indentation"))); + indentation_box.append (new SettingSwitch (_("Automatic indentation"), "auto-indent")); + indentation_box.append (new SettingSwitch (_("Insert spaces instead of tabs"), "spaces-instead-of-tabs")); + indentation_box.append (indent_width_box); var build_dir_entry = new Gtk.Entry () { hexpand = true, @@ -65,17 +65,17 @@ public class Scratch.Dialogs.Preferences : Granite.Dialog { }; var build_dir_box = new Gtk.Box (HORIZONTAL, 12); - build_dir_box.add (buid_dir_label); - build_dir_box.add (build_dir_entry); + build_dir_box.append (buid_dir_label); + build_dir_box.append (build_dir_entry); var projects_box = new Gtk.Box (VERTICAL, 12); - projects_box.add (new Granite.HeaderLabel (_("Projects"))); - projects_box.add (build_dir_box); + projects_box.append (new Granite.HeaderLabel (_("Projects"))); + projects_box.append (build_dir_box); var behavior_box = new Gtk.Box (VERTICAL, 24); - behavior_box.add (general_box); - behavior_box.add (indentation_box); - behavior_box.add (projects_box); + behavior_box.append (general_box); + behavior_box.append (indentation_box); + behavior_box.append (projects_box); var drawspaces_combobox = new Gtk.ComboBoxText () { hexpand = true @@ -105,22 +105,22 @@ public class Scratch.Dialogs.Preferences : Granite.Dialog { }; var draw_spaces_box = new Gtk.Box (HORIZONTAL, 12); - draw_spaces_box.add (draw_spaces_label); - draw_spaces_box.add (drawspaces_combobox); + draw_spaces_box.append (draw_spaces_label); + draw_spaces_box.append (drawspaces_combobox); var right_margin_position = new Gtk.SpinButton.with_range (1, 250, 1); Scratch.settings.bind ("right-margin-position", right_margin_position, "value", DEFAULT); Scratch.settings.bind ("show-right-margin", right_margin_position, "sensitive", DEFAULT); var editor_box = new Gtk.Box (VERTICAL, 12); - editor_box.add (new Granite.HeaderLabel (_("Editor"))); - editor_box.add (new SettingSwitch (_("Highlight matching brackets"), "highlight-matching-brackets")); - editor_box.add (new SettingSwitch (_("Syntax highlighting"), "syntax-highlighting")); - editor_box.add (draw_spaces_box); - editor_box.add (new SettingSwitch (_("Mini Map"), "show-mini-map")); - editor_box.add (new SettingSwitch (_("Wrap lines"), "line-wrap")); - editor_box.add (new SettingSwitch (_("Line width guide"), "show-right-margin")); - editor_box.add (right_margin_position); + editor_box.append (new Granite.HeaderLabel (_("Editor"))); + editor_box.append (new SettingSwitch (_("Highlight matching brackets"), "highlight-matching-brackets")); + editor_box.append (new SettingSwitch (_("Syntax highlighting"), "syntax-highlighting")); + editor_box.append (draw_spaces_box); + editor_box.append (new SettingSwitch (_("Mini Map"), "show-mini-map")); + editor_box.append (new SettingSwitch (_("Wrap lines"), "line-wrap")); + editor_box.append (new SettingSwitch (_("Line width guide"), "show-right-margin")); + editor_box.append (right_margin_position); var application = ((Scratch.Application) (GLib.Application.get_default ())); @@ -135,13 +135,13 @@ public class Scratch.Dialogs.Preferences : Granite.Dialog { Scratch.settings.bind ("use-system-font", select_font, "sensitive", INVERT_BOOLEAN); var font_box = new Gtk.Box (VERTICAL, 12); - font_box.add (new Granite.HeaderLabel (_("Font"))); - font_box.add (font_switch); - font_box.add (select_font); + font_box.append (new Granite.HeaderLabel (_("Font"))); + font_box.append (font_switch); + font_box.append (select_font); var interface_box = new Gtk.Box (VERTICAL, 24); - interface_box.add (editor_box); - interface_box.add (font_box); + interface_box.append (editor_box); + interface_box.append (font_box); var stack = new Gtk.Stack () { margin_top = 12, @@ -158,8 +158,8 @@ public class Scratch.Dialogs.Preferences : Granite.Dialog { stackswitcher.halign = Gtk.Align.CENTER; var main_box = new Gtk.Box (VERTICAL, 12); - main_box.add (stackswitcher); - main_box.add (stack); + main_box.append (stackswitcher); + main_box.append (stack); plugins.hook_preferences_dialog (this); // Unused? @@ -170,8 +170,7 @@ public class Scratch.Dialogs.Preferences : Granite.Dialog { stack.add_titled (pbox, "extensions", _("Extensions")); } - border_width = 0; - get_content_area ().add (main_box); + get_content_area ().append (main_box); var close_button = (Gtk.Button) add_button (_("Close"), Gtk.ResponseType.CLOSE); close_button.clicked.connect (() => { @@ -179,11 +178,9 @@ public class Scratch.Dialogs.Preferences : Granite.Dialog { }); //Ensure appearance correct after using libpeas-2 - realize.connect (() => { + ((Gtk.Widget) this).realize.connect (() => { stack.set_visible_child_name ("behavior"); }); - - show_all (); } private class SettingSwitch : Gtk.Grid { @@ -219,12 +216,12 @@ public class Scratch.Dialogs.Preferences : Granite.Dialog { wrap = true, xalign = 0 }; - description_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); - description_label.get_style_context ().add_class (Granite.STYLE_CLASS_SMALL_LABEL); + description_label.add_css_class (Granite.STYLE_CLASS_DIM_LABEL); + description_label.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL); attach (description_label, 0, 1); - switch_widget.get_accessible ().accessible_description = description; + ((Gtk.Accessible)switch_widget).update_property (Gtk.AccessibleProperty.DESCRIPTION, description, -1); } Scratch.settings.bind (settings_key, switch_widget, "active", DEFAULT); diff --git a/src/Dialogs/RestoreConfirmationDialog.vala b/src/Dialogs/RestoreConfirmationDialog.vala index 938f60aee..8b4d09c56 100644 --- a/src/Dialogs/RestoreConfirmationDialog.vala +++ b/src/Dialogs/RestoreConfirmationDialog.vala @@ -35,6 +35,6 @@ public class Scratch.Dialogs.RestoreConfirmationDialog : Granite.MessageDialog { add_button (_("Don't Restore"), Gtk.ResponseType.REJECT); var ignore_button = (Gtk.Button) add_button (_("Restore Anyway"), Gtk.ResponseType.ACCEPT); - ignore_button.get_style_context ().add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); + ignore_button.add_css_class (Granite.STYLE_CLASS_DESTRUCTIVE_ACTION); } } diff --git a/src/FolderManager/FileItem.vala b/src/FolderManager/FileItem.vala index 065525a48..d75ff5841 100644 --- a/src/FolderManager/FileItem.vala +++ b/src/FolderManager/FileItem.vala @@ -27,9 +27,10 @@ namespace Scratch.FolderManager { Object (file: file, view: view); } - public override void activated () { - view.activate (file.path); - } + // The ListView has an activate signal + // public override void activated () { + // view.activate (file.path); + // } public override GLib.Menu? get_context_menu () { GLib.FileInfo info = null; diff --git a/src/FolderManager/FileView.vala b/src/FolderManager/FileView.vala index 2841e2715..fb9a814d8 100644 --- a/src/FolderManager/FileView.vala +++ b/src/FolderManager/FileView.vala @@ -21,7 +21,7 @@ /** * SourceList that displays folders and their contents. */ -public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.PaneSwitcher { +public class Scratch.FolderManager.FileView : Code.TreeList, Code.PaneSwitcher { public const string ACTION_GROUP = "file-view"; public const string ACTION_PREFIX = ACTION_GROUP + "."; public const string ACTION_LAUNCH_APP_WITH_FILE_PATH = "launch-app-with-file-path"; @@ -54,11 +54,10 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane private Scratch.Services.GitManager git_manager; private Scratch.Services.PluginsManager plugins; - public new signal void activate (string file); + public signal void file_activate (File file); public signal bool rename_request (File file); public SimpleActionGroup actions { get; private set; } - public ActionGroup toplevel_action_group { get; private set; } public string icon_name { get; set; } public string title { get; set; } @@ -67,7 +66,6 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane } construct { - activate_on_single_click = true; icon_name = "folder-symbolic"; title = _("Folders"); @@ -79,14 +77,16 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane actions.add_action_entries (ACTION_ENTRIES, this); insert_action_group (ACTION_GROUP, actions); - realize.connect (() => { - toplevel_action_group = get_action_group (MainWindow.ACTION_GROUP); - assert_nonnull (toplevel_action_group); - }); - Scratch.saved_state.changed["order-folders"].connect (() => { order_folders (); }); + + // Convert ListView signal into file_activate + item_activated.connect ((item) => { + if (item is FileItem) { + file_activate (((FileItem) item).file); + } + }); } private void action_close_folder (SimpleAction action, GLib.Variant? parameter) { @@ -95,7 +95,7 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane return; } - var project_item = find_path (root, path) as ProjectFolderItem; + var project_item = find_path (null, path) as ProjectFolderItem; if (project_item == null) { return; } @@ -109,22 +109,28 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane return; } - var folder_root = find_path (root, path) as ProjectFolderItem; + var folder_root = find_path (null, path) as ProjectFolderItem; if (folder_root == null) { return; } - foreach (var child in root.children) { + List to_remove = null; + iterate_children (null, (child) => { var project_folder_item = (ProjectFolderItem) child; if (project_folder_item != folder_root) { - toplevel_action_group.activate_action ( - MainWindow.ACTION_CLOSE_PROJECT_DOCS, - new Variant.string (project_folder_item.path) + activate_action ( + MainWindow.ACTION_PREFIX + MainWindow.ACTION_CLOSE_PROJECT_DOCS, + "s", + project_folder_item.path ); - root.remove (project_folder_item); + to_remove.prepend (project_folder_item); git_manager.remove_project (project_folder_item); } - } + + return Code.TreeList.ITERATE_CONTINUE; + }); + + remove_root_children (to_remove); //Make remaining project the active one set_project_active (path); } @@ -139,7 +145,7 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane } private ProjectFolderItem? set_active_project (string path) { - var folder_root = find_path (root, path) as ProjectFolderItem; + var folder_root = find_path (null, path) as ProjectFolderItem; if (folder_root == null) { return null; } @@ -152,9 +158,10 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane } private void set_project_active (string path) { - toplevel_action_group.activate_action ( - MainWindow.ACTION_SET_ACTIVE_PROJECT, - new Variant.string (path) + activate_action ( + MainWindow.ACTION_PREFIX + MainWindow.ACTION_SET_ACTIVE_PROJECT, + "s", + path ); } @@ -166,7 +173,7 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane public void open_folder (File folder) { if (is_open (folder)) { - var existing = find_path (root, folder.path); + var existing = find_path (null, folder.path); if (existing is Code.Widgets.SourceList.ExpandableItem) { ((Code.Widgets.SourceList.ExpandableItem)existing).expanded = true; } @@ -178,9 +185,10 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane } public void collapse_all () { - foreach (var child in root.children) { - ((ProjectFolderItem) child).collapse_all (); - } + iterate_children (null, (child) => { + child.collapse_all (true, true); + return Code.TreeList.ITERATE_CONTINUE; + }); } public void order_folders () { @@ -188,44 +196,50 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane return; } - var list = new Gee.ArrayList (); - - foreach (var child in root.children) { - root.remove (child as ProjectFolderItem); - list.add (child as ProjectFolderItem); - } - - list.sort ( (a, b) => { - return a.name.down () > b.name.down () ? 0 : -1; + sort_root_children ((a, b) => { + return strcmp ( + ((ProjectFolderItem)a).name.down (), + ((ProjectFolderItem)b).name.down () + ); }); - - foreach (var item in list) { - root.add (item); - } } public void select_path (string path) { - selected = find_path (root, path); + find_path (null, path); + } + + public void unselect_file (GLib.File file) { + //TODO Complete this } public void unselect_all () { - selected = null; + selection_model.unselect_all (); } public void collapse_other_projects () { unowned string path; path = git_manager.active_project_path; - foreach (var child in root.children) { + iterate_children (null, (child) => { var project_folder = ((ProjectFolderItem) child); if (project_folder.path != path) { - project_folder.expanded = false; - toplevel_action_group.activate_action (MainWindow.ACTION_HIDE_PROJECT_DOCS, new Variant.string (project_folder.path)); + project_folder.is_expanded = false; + activate_action ( + MainWindow.ACTION_PREFIX + MainWindow.ACTION_HIDE_PROJECT_DOCS, + "s", + project_folder.path + ); } else if (project_folder.path == path) { - project_folder.expanded = true; - toplevel_action_group.activate_action (MainWindow.ACTION_RESTORE_PROJECT_DOCS, new Variant.string (project_folder.path)); + project_folder.is_expanded = true; + activate_action ( + MainWindow.ACTION_PREFIX + MainWindow.ACTION_RESTORE_PROJECT_DOCS, + "s", + project_folder.path + ); } - } + + return Code.TreeList.ITERATE_CONTINUE; + }); } public void branch_actions (string path) { @@ -233,7 +247,7 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane //TODO Warn before switching active project? var active_project = set_active_project (path); if (active_project == null || !active_project.is_git_repo) { - Gdk.beep (); + Gdk.Display.get_default ().beep (); return; } @@ -274,46 +288,50 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane } } - private unowned Code.Widgets.SourceList.Item? find_path ( - Code.Widgets.SourceList.ExpandableItem list, - string path, - bool expand = false, - GLib.File? target_file = null) { + private Code.TreeListItem? find_path ( + Code.TreeListItem? list, // Starting point for search + string path, // File path to search fod + bool expand = false, // Whether to expsnd to show found item + GLib.File? target_file = null // Alternatively find this file + ) { + var model = list != null ? list.child_model : root_model; var target = target_file ?? GLib.File.new_for_path (path); + Code.TreeListItem? matched_item = null; - foreach (var item in list.children) { - if (item is Item) { - var code_item = (Item)item; - if (code_item.path == path) { - return (!)item; - } + iterate_children (null, (item) => { + if ((item is Item) && item.path == path) { + matched_item = item; + return Code.TreeList.ITERATE_STOP; + } - if (item is FolderItem) { - var folder = item as FolderItem; - var folder_root = folder.file.file; - if (folder_root.get_relative_path (target) == null) { - continue; - } + if (item is FolderItem) { + var folder = item as FolderItem; + var folder_root = folder.file.file; + if (folder_root.get_relative_path (target) == null) { + return Code.TreeList.ITERATE_CONTINUE; + } - if (!folder.expanded) { - if (expand) { - folder.load_children (); //Synchronous - folder.expanded = true; - } else { - continue; - } + if (!folder.is_expanded) { + if (expand) { + folder.load_children (); //Synchronous + folder.is_expanded = true; + } else { + return Code.TreeList.ITERATE_CONTINUE; } + } - unowned var recurse_item = find_path (folder, path, expand, target); - if (recurse_item != null) { - return recurse_item; - } + var recurse_item = find_path (folder, path, expand, target); + if (recurse_item != null) { + matched_item = recurse_item; + return Code.TreeList.ITERATE_STOP; } } - } - return null; + return Code.TreeList.ITERATE_CONTINUE; + }); + + return matched_item; } public bool project_is_open (string project_path) { @@ -321,20 +339,24 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane } public ProjectFolderItem? get_project_for_file (GLib.File file) { - foreach (var item in root.children) { + ProjectFolderItem? matched_project = null; + iterate_children (null, (item) => { if (item is ProjectFolderItem) { - var folder = (ProjectFolderItem)item; + var folder = (ProjectFolderItem) item; if (folder.file.file.equal (file) || folder.contains_file (file)) { - return folder; + matched_project = folder; + return Code.TreeList.ITERATE_STOP; } } - } - return null; + return Code.TreeList.ITERATE_CONTINUE; + }); + + return matched_project; } - public unowned Code.Widgets.SourceList.Item? expand_to_path (string path) { - return find_path (root, path, true); + public Code.TreeListItem? expand_to_path (string path) { + return find_path (null, path, true); } /* Do global search on project containing the file path supplied in parameter */ @@ -354,11 +376,13 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane } public void clear_badges () { - foreach (var child in root.children) { + iterate_children (null, (child) => { if (child is ProjectFolderItem) { ((FolderItem)child).remove_all_badges (); } - } + + return Code.TreeList.ITERATE_CONTINUE; + }); } public void folder_item_update_hook (GLib.File source, GLib.File? dest, GLib.FileMonitorEvent event) { @@ -367,80 +391,92 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane // This only works when the list is stable (nothing being added, expanded etc) private void rename_file (string path) { - this.select_path (path); - if (this.start_editing_item (selected)) { - ulong once = 0; - once = selected.edited.connect ((new_name) => { - selected.disconnect (once); - var new_path = Path.get_dirname (path) + Path.DIR_SEPARATOR_S + new_name; - this.toplevel_action_group.activate_action (MainWindow.ACTION_CLOSE_TAB, new Variant.string (path)); - - // RecentManager requires valid URI - var new_uri = "file://" + new_path; // Code only edits local files - Gtk.RecentManager.get_default ().add_item (new_uri); - - activate (new_path); - }); - } - - // Handle cancelled rename (which does not produce signal) - Timeout.add (200, () => { - if (this.editing) { - return Source.CONTINUE; - } else { - // Avoid selected but unopened item if rename cancelled (they would not open if clicked on) - this.unselect_all (); - return Source.REMOVE; - } - }); + // this.select_path (path); + // if (this.start_editing_item (selected)) { + // ulong once = 0; + // once = selected.edited.connect ((new_name) => { + // selected.disconnect (once); + // var new_path = Path.get_dirname (path) + Path.DIR_SEPARATOR_S + new_name; + // activate_action ( + // MainWindow.ACTION_PREFIX + MainWindow.ACTION_CLOSE_TAB, + // "s", + // path + // ); + + // // RecentManager requires valid URI + // var new_uri = "file://" + new_path; // Code only edits local files + // Gtk.RecentManager.get_default ().add_item (new_uri); + + // activate (new_path); + // }); + // } + + // // Handle cancelled rename (which does not produce signal) + // Timeout.add (200, () => { + // if (this.editing) { + // return Source.CONTINUE; + // } else { + // // Avoid selected but unopened item if rename cancelled (they would not open if clicked on) + // this.unselect_all (); + // return Source.REMOVE; + // } + // }); } private void rename_folder (string path) { - var folder_to_rename = find_path (root, path) as FolderItem; - if (folder_to_rename == null) { - critical ("Could not find folder from given path to rename: %s", path); - return; - } - - folder_to_rename.selectable = true; - if (start_editing_item (folder_to_rename)) { - // Need to poll view as no signal emited when editing cancelled and need to set - // selectable to false anyway. - Timeout.add (200, () => { - if (editing) { - return Source.CONTINUE; - } else { - unselect_all (); - // Must do this *after* unselecting all else sourcelist breaks - folder_to_rename.selectable = false; - } - - return Source.REMOVE; - }); - } else { - critical ("Could not rename %s", path); - folder_to_rename.selectable = false; - } + // var folder_to_rename = find_path (null, path) as FolderItem; + // if (folder_to_rename == null) { + // critical ("Could not find folder from given path to rename: %s", path); + // return; + // } + + // folder_to_rename.selectable = true; + // if (start_editing_item (folder_to_rename)) { + // // Need to poll view as no signal emited when editing cancelled and need to set + // // selectable to false anyway. + // Timeout.add (200, () => { + // if (editing) { + // return Source.CONTINUE; + // } else { + // unselect_all (); + // // Must do this *after* unselecting all else sourcelist breaks + // folder_to_rename.selectable = false; + // } + + // return Source.REMOVE; + // }); + // } else { + // critical ("Could not rename %s", path); + // folder_to_rename.selectable = false; + // } } private void rename_items_with_same_name (Item item) { - string item_name = item.file.name; - foreach (var child in this.root.children) { - string new_other_item_name, new_item_name; - var other_item = child as ProjectFolderItem; - - if (Utils.find_unique_path (item.file.file, other_item.file.file, out new_item_name, out new_other_item_name)) { - if (item_name.length < new_item_name.length) { - item_name = new_item_name; - } + // string item_name = item.file.name; + // iterate_children (null, (child) => { + // string new_other_item_name, new_item_name; + // var other_item = (ProjectFolderItem) child; - if (other_item.name.length < new_other_item_name.length) { - other_item.name = new_other_item_name; - } - } + // if (Utils.find_unique_path ( + // item.file.file, + // other_item.file.file, + // out new_item_name, + // out new_other_item_name + // ) + // ) { + // if (item_name.length < new_item_name.length) { + // item_name = new_item_name; + // } - } - item.name = item_name; + // if (other_item.name.length < new_other_item_name.length) { + // other_item.name = new_other_item_name; + // } + // } + + // return Code.TreeList.ITERATE_CONTINUE; + // }); + + // item.name = item_name; } private void add_new_folder (SimpleAction action, Variant? param) { @@ -451,7 +487,7 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane return; } - var folder = find_path (root, path) as FolderItem; + var folder = find_path (null, path) as FolderItem; if (folder == null) { return; } @@ -468,7 +504,7 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane return; } - var folder = find_path (root, path) as FolderItem; + var folder = find_path (null, path) as FolderItem; if (folder == null) { return; } @@ -487,7 +523,7 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane return; } - var folder = find_path (root, parent_path) as FolderItem; + var folder = find_path (null, parent_path) as FolderItem; if (folder == null) { return; } @@ -568,7 +604,7 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane return; } - var item = find_path (root, path); + var item = find_path (null, path); if (item != null) { var item_to_delete = item as Scratch.FolderManager.Item; @@ -599,7 +635,7 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane var parents = new List (); var children = new List (); - foreach (var child in root.children) { + iterate_children (null, (child) => { var item = (ProjectFolderItem) child; if (add_file.get_relative_path (item.file.file) != null) { debug ("Trying to add parent of existing project"); @@ -608,13 +644,15 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane debug ("Trying to add child of existing project"); parents.append (item); } - } + + return Code.TreeList.ITERATE_CONTINUE; + }); if (parents.length () > 0 || children.length () > 0) { assert (parents.length () <= 1); assert (parents.length () == 0 || children.length () == 0); var dialog = new Scratch.Dialogs.CloseProjectsConfirmationDialog ( - (MainWindow) get_toplevel (), + (MainWindow) get_root (), parents.length (), children.length () ); @@ -648,19 +686,28 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane // Process any closed signals emitted before proceeding Idle.add (() => { var folder_root = new ProjectFolderItem (folder, this); // Constructor adds project to GitManager - this.root.add (folder_root); + add_root_item (folder_root); rename_items_with_same_name (folder_root); - folder_root.expanded = expand; + folder_root.is_expanded = expand; folder_root.closed.connect (() => { - toplevel_action_group.activate_action (MainWindow.ACTION_CLOSE_PROJECT_DOCS, new Variant.string (folder_root.path)); - root.remove (folder_root); - foreach (var child in root.children) { + activate_action ( + MainWindow.ACTION_PREFIX + MainWindow.ACTION_CLOSE_PROJECT_DOCS, + "s", + folder_root.path + ); + + remove_root_item (folder_root); + + iterate_children (null, (child) => { var child_folder = (ProjectFolderItem) child; if (child_folder.name != child_folder.file.name) { rename_items_with_same_name (child_folder); } - } + + return Code.TreeList.ITERATE_CONTINUE; + }); + Scratch.Services.GitManager.get_instance ().remove_project (folder_root); write_settings (); }); @@ -682,19 +729,26 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane } private bool is_open (File folder) { - foreach (var child in root.children) - if (folder.path == ((Item) child).path) - return true; - return false; + bool open = false; + iterate_children (null, (child) => { + if (folder.path == ((Item) child).path) { + open = true; + return Code.TreeList.ITERATE_STOP; + } + + return Code.TreeList.ITERATE_CONTINUE; + }); + + return open; } private void write_settings () { string[] to_save = {}; - - foreach (var main_folder in root.children) { + iterate_children (null, (item) => { var saved = false; - var folder_path = ((Item) main_folder).path; + var folder_path = ((Item) item).path; + //Do we need to de-duplicate? Not possible to open a project twice? foreach (var saved_folder in to_save) { if (folder_path == saved_folder) { saved = true; @@ -705,7 +759,9 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane if (!saved) { to_save += folder_path; } - } + + return Code.TreeList.ITERATE_CONTINUE; + }); settings.set_strv ("opened-folders", to_save); } diff --git a/src/FolderManager/FolderItem.vala b/src/FolderManager/FolderItem.vala index 2ce097e57..bcd0e81fd 100644 --- a/src/FolderManager/FolderItem.vala +++ b/src/FolderManager/FolderItem.vala @@ -28,18 +28,21 @@ namespace Scratch.FolderManager { private GLib.FileMonitor monitor; private bool children_loaded = false; private bool has_dummy; - private Code.Widgets.SourceList.Item dummy; /* Blank item for expanded empty folders */ + private Code.TreeListItem dummy; /* Blank item for expanded empty folders */ public bool loading_required { get { - return !children_loaded && n_children <= 1 && file.children.size > 0; + return !children_loaded && file.children.size > 0; } } public signal void children_finished_loading (); public FolderItem (File file, FileView view) { - Object (file: file, view: view); + Object ( + file: file, + view: view + ); } ~FolderItem () { @@ -47,15 +50,16 @@ namespace Scratch.FolderManager { } construct { - selectable = false; + is_selectable = false; + is_expandable = true; - dummy = new Code.Widgets.SourceList.Item (""); + dummy = new Code.TreeListItem.dummy (); // Must add dummy on unexpanded folders else expander will not show - dummy.selectable = false; - ((Code.Widgets.SourceList.ExpandableItem)this).add (dummy); + add_child (dummy); has_dummy = true; - toggled.connect (on_toggled); + // Signal when expanded + notify["is-expanded"].connect (on_toggled); try { monitor = file.file.monitor_directory (GLib.FileMonitorFlags.NONE); @@ -65,34 +69,40 @@ namespace Scratch.FolderManager { } } - public void load_children () { - if (loading_required) { - foreach (var child in file.children) { - add_child (child); + private void create_child_items (File file) { + foreach (var child_file in file.children) { + if (child_file.is_valid_directory) { + add_child (new FolderItem (child_file, view)); + } else if (child_file.is_valid_textfile) { + add_child (new FileItem (child_file, view)); } + } + } + public void load_children () { + if (loading_required) { + create_child_items (file); after_children_loaded (); } } private async void load_children_async () { if (loading_required) { - foreach (var child in file.children) { - Idle.add (() => { - add_child (child); - load_children_async.callback (); - return Source.REMOVE; - }); - - yield; - } + // Do we need to yield after each child with dynamic view?? + Idle.add (() => { + create_child_items (file); + load_children_async.callback (); + return Source.REMOVE; + }); + + yield; } after_children_loaded (); } - private void add_child (File child) { - Code.Widgets.SourceList.Item item = null; + private void add_file (File child) { + Code.TreeListItem item = null; if (child.is_valid_directory) { item = new FolderItem (child, view); } else if (child.is_valid_textfile) { @@ -100,7 +110,7 @@ namespace Scratch.FolderManager { } if (item != null) { - add (item); + add_child (item); } } @@ -108,16 +118,15 @@ namespace Scratch.FolderManager { children_loaded = true; var root = get_root_folder (); if (root != null) { - root.child_folder_loaded (this); //Updates child status emblens + root.after_child_folder_loaded (this); //Updates child status emblens } children_finished_loading (); } private void on_toggled () { - if (expanded) { + if (is_expanded) { load_children_async.begin (); - return; } else { var root = get_root_folder (); if (root != null && @@ -264,7 +273,10 @@ namespace Scratch.FolderManager { // Recursively load templates from folder and subfolders keeping count of total menuitems const int MAX_TEMPLATES = 2048; - private uint load_templates_from_folder (GLib.File template_folder, Menu template_submenu) { + private uint load_templates_from_folder ( + GLib.File template_folder, + Menu template_submenu + ) { GLib.List template_list = null; GLib.List folder_list = null; @@ -343,12 +355,14 @@ namespace Scratch.FolderManager { } public void remove_all_badges () { - foreach (var child in children) { + view.iterate_children (this, (child) => { remove_badge (child); - } + return Code.TreeList.ITERATE_CONTINUE; + }); } - private void remove_badge (Code.Widgets.SourceList.Item item) { + private void remove_badge (Code.TreeListItem item) { + if (item is FolderItem) { ((FolderItem) item).remove_all_badges (); } @@ -356,37 +370,41 @@ namespace Scratch.FolderManager { item.badge = ""; } - public new void add (Code.Widgets.SourceList.Item item) { - if (has_dummy && n_children == 1) { - ((Code.Widgets.SourceList.ExpandableItem)this).remove (dummy); + public override void add_child (Code.TreeListItem item) { + if (has_dummy) { + base.remove_child (dummy); has_dummy = false; } - base.add (item); + base.add_child (item); } - public new void remove (Code.Widgets.SourceList.Item item) { + // Only for removing "real" items; dummy is added/removed directly + public override void remove_child (Code.TreeListItem item) requires (has_dummy == false) { if (item is FolderItem) { - var folder = (FolderItem)item; - foreach (var child in folder.children) { - folder.remove (child); - } + var folder = (FolderItem) item; + folder.remove_all_children (); } - ((Code.Widgets.SourceList.ExpandableItem)this).remove (item); + base.remove_child (item); + // Add back dummy if empty - if (!(has_dummy || n_children > 0)) { - ((Code.Widgets.SourceList.ExpandableItem)this).add (dummy); + if (has_no_children ()) { + base.add_child (dummy); has_dummy = true; } } - public new void clear () { - ((Code.Widgets.SourceList.ExpandableItem)this).clear (); - has_dummy = false; - } + // public new void clear () { + // ((Code.Widgets.SourceList.ExpandableItem)this).clear (); + // has_dummy = false; + // } - protected virtual void on_changed (GLib.File source, GLib.File? dest, GLib.FileMonitorEvent event) { + protected virtual void on_changed ( + GLib.File source, + GLib.File? dest, + GLib.FileMonitorEvent event + ) { if (source.get_basename ().has_prefix (".goutputstream")) { return; // Ignore changes due to temp files and streams } @@ -398,14 +416,15 @@ namespace Scratch.FolderManager { switch (event) { case GLib.FileMonitorEvent.DELETED: file.invalidate_cache (); //TODO Throttle if required - if (expanded) { - toggled (); + if (is_expanded) { + // Force refresh of child model? + notify_property ("is-expanded"); } break; case GLib.FileMonitorEvent.CREATED: file.invalidate_cache (); //TODO Throttle if required - if (expanded) { - toggled (); + if (is_expanded) { + notify_property ("is-expanded"); } break; case FileMonitorEvent.RENAMED: @@ -420,15 +439,19 @@ namespace Scratch.FolderManager { break; } - } else { // Child has been expanded ( but could be closed now) and items loaded (or dummy) - // No cache invalidation is needed here because the entire state is kept in the tree + } else { + // Child has been expanded ( but could be closed now) and + // items loaded (or dummy). + // No cache invalidation is needed here because the entire state + // is kept in the tree + //TODO Test for TreeList switch (event) { case GLib.FileMonitorEvent.DELETED: // Find item corresponding to deleted file // Note may not be found if deleted file is not valid for display var path_item = find_item_for_path (source.get_path ()); if (path_item != null) { - remove (path_item); + remove_child (path_item); } break; @@ -436,6 +459,7 @@ namespace Scratch.FolderManager { if (source.query_exists () == false) { return; } + var path_item = find_item_for_path (source.get_path ()); if (path_item == null) { var file = new File (source.get_path ()); @@ -445,7 +469,7 @@ namespace Scratch.FolderManager { path_item = new FileItem (file, view); } - add (path_item); // null parameter is silently ignored + add_child (path_item); // null parameter is silently ignored } break; @@ -474,20 +498,27 @@ namespace Scratch.FolderManager { } private FolderManager.Item? find_item_for_path (string path) { - foreach (var item in children) { + FolderManager.Item? found_item = null; + view.iterate_children (this, (item) => { // Item could be dummy - if ((item is FolderManager.Item) && ((FolderManager.Item) item).path == path) { - return (FolderManager.Item)item; + if (item is FolderManager.Item) { + var child = (FolderManager.Item) item; + if (child.path == path) { + found_item = child; + return Code.TreeList.ITERATE_STOP; + } } - } - return null; + return Code.TreeList.ITERATE_CONTINUE; + }); + + return found_item; } public void on_add_template (string template_path) { // Expand folder before trying to copy template so that child appears for renaming - if (!expanded) { - expanded = true; // causes async loading of children + if (!is_expanded) { + is_expanded = true; // causes async loading of children ulong once = 0; once = children_finished_loading.connect (() => { this.disconnect (once); @@ -568,62 +599,63 @@ namespace Scratch.FolderManager { name = new_file.get_basename (); // Expand folder before trying to rename - if (!expanded) { + if (!is_expanded) { ulong once = 0; once = children_finished_loading.connect (() => { this.disconnect (once); rename_new (name, is_folder); }); - expanded = true; // causes async loading of children + is_expanded = true; // causes async loading of children } else { rename_new (name, is_folder); } } - private void rename_new (string name, bool is_folder) requires (!view.editing) { - var rename_item = new RenameItem (name, is_folder); - add (rename_item); - - // Wait until can start editing - // For some reason using an Idle does not work properly here - the editable gets drawn in the wrong place - //TODO Find a way to detect when the sourcelist is stable and can be edited - Timeout.add (RENAME_AFTER_NEW_DELAY_MSEC, () => { - if (view.start_editing_item (rename_item)) { - ulong once = 0; - once = rename_item.edited.connect (() => { - rename_item.disconnect (once); - // A name was accepted so create the corresponding file - var new_name = rename_item.name; - try { - var gfile = file.file.get_child_for_display_name (new_name); - if (rename_item.is_folder) { - gfile.make_directory (); - } else { - gfile.create (FileCreateFlags.NONE); - view.activate (gfile.get_path ()); - } - } catch (Error e) { - warning (e.message); - } - }); - - /* Need to remove rename item even when editing cancelled so cannot use "edited" signal */ - Timeout.add (200, () => { - if (view.editing) { - return Source.CONTINUE; - } else { - remove (rename_item); - return Source.REMOVE; - } - }); - } else { - critical ("Failed to rename new item"); - remove (rename_item); - } - - return Source.REMOVE; - }); + private void rename_new (string name, bool is_folder) { + // assert (!view.editing); + // var rename_item = new RenameItem (name, is_folder); + // add_child (rename_item); + + // // Wait until can start editing + // // For some reason using an Idle does not work properly here - the editable gets drawn in the wrong place + // //TODO Find a way to detect when the sourcelist is stable and can be edited + // Timeout.add (RENAME_AFTER_NEW_DELAY_MSEC, () => { + // if (view.start_editing_item (rename_item)) { + // ulong once = 0; + // once = rename_item.edited.connect (() => { + // rename_item.disconnect (once); + // // A name was accepted so create the corresponding file + // var new_name = rename_item.name; + // try { + // var gfile = file.file.get_child_for_display_name (new_name); + // if (rename_item.is_folder) { + // gfile.make_directory (); + // } else { + // gfile.create (FileCreateFlags.NONE); + // view.activate (gfile.get_path ()); + // } + // } catch (Error e) { + // warning (e.message); + // } + // }); + + // /* Need to remove rename item even when editing cancelled so cannot use "edited" signal */ + // Timeout.add (200, () => { + // if (view.editing) { + // return Source.CONTINUE; + // } else { + // remove_child (rename_item); + // return Source.REMOVE; + // } + // }); + // } else { + // critical ("Failed to rename new item"); + // remove_child (rename_item); + // } + + // return Source.REMOVE; + // }); } } } diff --git a/src/FolderManager/Item.vala b/src/FolderManager/Item.vala index c5325fffe..f4621a1bf 100644 --- a/src/FolderManager/Item.vala +++ b/src/FolderManager/Item.vala @@ -22,19 +22,31 @@ namespace Scratch.FolderManager { /** * Common abstract class for file and folder items. */ - public abstract class Item: Code.Widgets.SourceList.ExpandableItem, Code.Widgets.SourceListSortable { + public abstract class Item: Code.TreeListItem { public File file { get; construct; } - public FileView view { get; construct; } + + public string name { + get { + return text; + } + + set { + text = value; + } + } + public string path { owned get { return file.path; } set { file.path = value; } } + public signal void edited (string new_name); + construct { - selectable = true; - editable = true; - name = file.name; + is_selectable = true; + is_editable = true; + text = file.name; icon = file.icon; edited.connect (rename); tooltip = Scratch.Utils.replace_home_with_tilde (file.path); @@ -42,7 +54,7 @@ namespace Scratch.FolderManager { notify["activatable-tooltip"].connect (() => { tooltip = ("%s\n" + Granite.TOOLTIP_SECONDARY_TEXT_MARKUP).printf ( Scratch.Utils.replace_home_with_tilde (file.path), - activatable_tooltip + secondary_icon_tooltip ); }); } @@ -59,12 +71,13 @@ namespace Scratch.FolderManager { file.trash (); } - public int compare (Code.Widgets.SourceList.Item a, Code.Widgets.SourceList.Item b) { - if (a is RenameItem) { - return -1; - } else if (b is RenameItem) { - return 1; - } + public int compare (Code.TreeListItem a, Code.TreeListItem b) { + // if (a is RenameItem) { + // return -1; + // } else + // if (b is RenameItem) { + // return 1; + // } if (a is FolderItem && b is FileItem) { return -1; @@ -81,7 +94,7 @@ namespace Scratch.FolderManager { return false; } - public ProjectFolderItem? get_root_folder (Code.Widgets.SourceList.ExpandableItem? start = null) { + public ProjectFolderItem? get_root_folder (Code.TreeListItem start = null) { if (start == null) { start = this; } @@ -97,33 +110,36 @@ namespace Scratch.FolderManager { } } - protected class RenameItem : Code.Widgets.SourceList.Item { - public bool is_folder { get; construct; } - - public RenameItem (string name, bool is_folder) { - Object ( - name: name, - is_folder: is_folder - ); - } - - construct { - editable = true; - selectable = true; - edited.connect (on_edited); - - if (is_folder) { - icon = GLib.ContentType.get_icon ("inode/directory"); - } else { - icon = GLib.ContentType.get_icon ("text"); - } - } - - private void on_edited (string new_name) { - if (new_name != "") { - name = new_name; - } - } - } + // protected class RenameItem : Code.TreeListItem { + // public bool is_folder { get; construct; } + // public string name { get; set construct; } + + // public RenameItem (string name, bool is_folder) { + // Object ( + // name: name + // is_folder: is_folder + // ); + // } + + // construct { + // is_editable = true; + // is_selectable = true; + // edited.connect (on_edited); + + // if (is_folder) { + // icon = GLib.ContentType.get_icon ("inode/directory"); + // } else { + // icon = GLib.ContentType.get_icon ("text"); + // } + // } + + // private void on_edited (string new_name) { + // if (new_name != "") { + // name = new_name; + // } + // } + // } + + public virtual GLib.Menu? get_context_menu () { return null; } } } diff --git a/src/FolderManager/ProjectFolderItem.vala b/src/FolderManager/ProjectFolderItem.vala index 4f44497cd..3f9437c06 100644 --- a/src/FolderManager/ProjectFolderItem.vala +++ b/src/FolderManager/ProjectFolderItem.vala @@ -60,16 +60,14 @@ namespace Scratch.FolderManager { if (monitored_repo != null) { //As SourceList items are not widgets we have to use markup to change appearance of text. if (monitored_repo.head_is_branch) { - markup = "%s\n%s".printf ( + text = "%s\n%s".printf ( name, monitored_repo.branch_name ); } else { //Distinguish detached heads visually - markup = "%s\n %s".printf ( + text = "%s\n %s".printf ( name, monitored_repo.branch_name ); } - - } } @@ -99,17 +97,19 @@ namespace Scratch.FolderManager { } } - public void child_folder_loaded (FolderItem folder) { - foreach (var child in folder.children) { + public void after_child_folder_loaded (FolderItem folder) { + view.iterate_children (folder, (child) => { if (child is Item) { var item = (Item)child; var rel_path = this.file.file.get_relative_path (item.file.file); - if (rel_path != null && rel_path != "") { visible_item_list.prepend ({rel_path, item}); } } - } + + return Code.TreeList.ITERATE_CONTINUE; + }); + if (monitored_repo != null) { monitored_repo.update_status_map (); @@ -196,7 +196,7 @@ namespace Scratch.FolderManager { FileView.ACTION_CLOSE_OTHER_FOLDERS, view.actions ); - close_other_folders_action.set_enabled (view.root.children.size > 1); + close_other_folders_action.set_enabled (view.n_root_items () > 1); var close_actions_section = new GLib.Menu (); close_actions_section.append_item (close_folder_item); @@ -314,7 +314,7 @@ namespace Scratch.FolderManager { } var item = visible_item.item; - item.activatable = null; + item.secondary_icon = null; monitored_repo.non_current_entries.@foreach ((entry) => { // Match non_current_path with parent folder as well as itself var match = entry.key.has_prefix (visible_item.rel_path); @@ -322,16 +322,16 @@ namespace Scratch.FolderManager { is_new = (entry.@value & (Ggit.StatusFlags.WORKING_TREE_NEW | Ggit.StatusFlags.INDEX_NEW)) > 0; // Only mark folders new if only contains new items otherwise mark modified if (item is FolderItem && - is_new && item.activatable == null) { + is_new && item.secondary_icon == null) { - item.activatable = added_icon; - item.activatable_tooltip = _("New"); + item.secondary_icon = added_icon; + item.secondary_icon_tooltip = _("New"); return true; // scan all children } - if (!(item is FolderItem) || !item.expanded) { //No need to show status when children shown - item.activatable = is_new ? added_icon : modified_icon; - item.activatable_tooltip = is_new ? _("New") : _("Modified"); + if (!(item is FolderItem) || !item.is_expanded) { //No need to show status when children shown + item.secondary_icon = is_new ? added_icon : modified_icon; + item.secondary_icon_tooltip = is_new ? _("New") : _("Modified"); } return false; } else { @@ -350,9 +350,9 @@ namespace Scratch.FolderManager { var item = visible_item.item; try { if (monitored_repo.path_is_ignored (visible_item.rel_path)) { - item.markup = Markup.printf_escaped ("%s", item.name); + item.text = Markup.printf_escaped ("%s", item.name); } else { - item.markup = item.name; + item.text = item.name; } } catch (Error e) { warning ("An error occurred while checking if item '%s' is git-ignored: %s", item.name, e.message); @@ -400,7 +400,7 @@ namespace Scratch.FolderManager { badge_icon = new ThemedIcon ("dialog-error"), modal = true }; - dialog.transient_for = (Gtk.Window)(view.get_toplevel ()); + dialog.transient_for = (Gtk.Window)(view.get_root ()); dialog.response.connect (() => { dialog.destroy (); }); @@ -520,7 +520,8 @@ namespace Scratch.FolderManager { if (search_term != null) { // Remove results of previous search before attempting a new one remove_all_badges (); - collapse_all (); + // Collapse everything + collapse_all (true, true); /* Put search term in search bar to help user locate the position of the matches in each doc */ var search_variant = new Variant.string (search_term); @@ -671,7 +672,7 @@ namespace Scratch.FolderManager { } if (match_count > 0) { - unowned var item = view.expand_to_path (target_path); + var item = view.expand_to_path (target_path); if (item != null) { item.badge = match_count.to_string (); } diff --git a/src/MainWindow.vala b/src/MainWindow.vala index ef4d6f6d2..36e36bc74 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -19,7 +19,7 @@ */ namespace Scratch { - public class MainWindow : Hdy.Window { + public class MainWindow : Adw.Window { public const int FONT_SIZE_MAX = 72; public const int FONT_SIZE_MIN = 7; private const uint MAX_SEARCH_TEXT_LENGTH = 255; @@ -48,7 +48,6 @@ namespace Scratch { private Code.Terminal terminal; private FolderManager.FileView folder_manager_view; private Scratch.Services.DocumentManager document_manager; - private Gtk.EventControllerKey key_controller; // Plugins private Scratch.Services.PluginsManager plugins; @@ -59,7 +58,7 @@ namespace Scratch { private Gtk.Paned vp; private Gtk.Stack content_stack; - public Gtk.Clipboard clipboard; + public Gdk.Clipboard clipboard; // Delegates delegate void HookFunc (); @@ -83,8 +82,6 @@ namespace Scratch { public const string ACTION_DUPLICATE_TAB = "action-duplicate-tab"; public const string ACTION_PREFERENCES = "preferences"; - public const string ACTION_UNDO = "action-undo"; - public const string ACTION_REDO = "action-redo"; public const string ACTION_REVERT = "action-revert"; public const string ACTION_SAVE = "action-save"; public const string ACTION_SAVE_AS = "action-save-as"; @@ -148,8 +145,6 @@ namespace Scratch { { ACTION_NEW_FROM_CLIPBOARD, action_new_tab_from_clipboard }, { ACTION_DUPLICATE_TAB, action_duplicate_tab }, { ACTION_PREFERENCES, action_preferences }, - { ACTION_UNDO, action_undo }, - { ACTION_REDO, action_redo }, { ACTION_SHOW_REPLACE, action_show_replace }, { ACTION_TO_LOWER_CASE, action_to_lower_case }, { ACTION_TO_UPPER_CASE, action_to_upper_case }, @@ -210,8 +205,6 @@ namespace Scratch { action_accelerators.set (ACTION_GO_TO, "i"); action_accelerators.set (ACTION_NEW_TAB, "n"); action_accelerators.set (ACTION_DUPLICATE_TAB, "k" ); - action_accelerators.set (ACTION_UNDO, "z"); - action_accelerators.set (ACTION_REDO, "z"); action_accelerators.set (ACTION_SHOW_REPLACE, "r"); action_accelerators.set (ACTION_TO_LOWER_CASE, "l"); action_accelerators.set (ACTION_TO_UPPER_CASE, "u"); @@ -246,8 +239,8 @@ namespace Scratch { var provider = new Gtk.CssProvider (); provider.load_from_resource ("io/elementary/code/Application.css"); - Gtk.StyleContext.add_provider_for_screen ( - Gdk.Screen.get_default (), provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + Gtk.StyleContext.add_provider_for_display ( + Gdk.Display.get_default (), provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION ); if (Constants.BRANCH != "") { @@ -255,8 +248,6 @@ namespace Scratch { } else { base_title = _("Code"); } - - Hdy.init (); } construct { @@ -265,7 +256,7 @@ namespace Scratch { is_first_window = application.get_windows ().length () == 1; title = base_title; - weak Gtk.IconTheme default_theme = Gtk.IconTheme.get_default (); + weak Gtk.IconTheme default_theme = Gtk.IconTheme.get_for_display (Gdk.Display.get_default ()); default_theme.add_resource_path ("/io/elementary/code"); document_manager = Scratch.Services.DocumentManager.get_instance (); @@ -283,7 +274,6 @@ namespace Scratch { } set_size_request (450, 400); - set_hide_titlebar_when_maximized (false); var rect = Gdk.Rectangle (); Scratch.saved_state.get ("window-size", "(ii)", out rect.width, out rect.height); @@ -296,13 +286,14 @@ namespace Scratch { update_style (); }); - clipboard = Gtk.Clipboard.get_for_display (get_display (), Gdk.SELECTION_CLIPBOARD); + clipboard = Gdk.Display.get_default ().get_clipboard (); plugins = new Scratch.Services.PluginsManager (this); - key_controller = new Gtk.EventControllerKey (this) { + var key_controller = new Gtk.EventControllerKey () { propagation_phase = TARGET }; + ((Gtk.Widget) this).add_controller (key_controller); key_controller.key_pressed.connect (on_key_pressed); // Set up layout @@ -323,7 +314,6 @@ namespace Scratch { } // Show/Hide widgets - show_all (); // Create folder for unsaved documents @@ -444,43 +434,41 @@ namespace Scratch { private void init_layout () { toolbar = new Scratch.HeaderBar (); - toolbar.title = base_title; // SearchBar search_bar = new Scratch.Widgets.SearchBar (this); welcome_view = new Code.WelcomeView (this); document_view = new Scratch.Widgets.DocumentView (this); // Handle Drag-and-drop for files functionality on welcome screen - Gtk.TargetEntry target = {"text/uri-list", 0, 0}; - Gtk.drag_dest_set (welcome_view, Gtk.DestDefaults.ALL, {target}, Gdk.DragAction.COPY); - - welcome_view.drag_data_received.connect ((ctx, x, y, sel, info, time) => { - var uris = sel.get_uris (); - if (uris.length > 0) { - for (var i = 0; i < uris.length; i++) { - string filename = uris[i]; - var file = File.new_for_uri (filename); - bool is_folder; - //TODO Handle folders dropped here - if (Scratch.Services.FileHandler.can_open_file (file, out is_folder) && !is_folder) { - Scratch.Services.Document doc = new Scratch.Services.Document (actions, file); - document_view.open_document.begin (doc); - } - } - - Gtk.drag_finish (ctx, true, false, time); - } - }); + // Gtk.TargetEntry target = {"text/uri-list", 0, 0}; + // Gtk.drag_dest_set (welcome_view, Gtk.DestDefaults.ALL, {target}, Gdk.DragAction.COPY); + + // welcome_view.drag_data_received.connect ((ctx, x, y, sel, info, time) => { + // var uris = sel.get_uris (); + // if (uris.length > 0) { + // for (var i = 0; i < uris.length; i++) { + // string filename = uris[i]; + // var file = File.new_for_uri (filename); + // bool is_folder; + // //TODO Handle folders dropped here + // if (Scratch.Services.FileHandler.can_open_file (file, out is_folder) && !is_folder) { + // Scratch.Services.Document doc = new Scratch.Services.Document (actions, file); + // document_view.open_document.begin (doc); + // } + // } + + // Gtk.drag_finish (ctx, true, false, time); + // } + // }); sidebar = new Code.Sidebar (); folder_manager_view = new FolderManager.FileView (plugins); sidebar.add_tab (folder_manager_view); - folder_manager_view.show_all (); - folder_manager_view.activate.connect ((a) => { - var file = new Scratch.FolderManager.File (a); + folder_manager_view.file_activate.connect ((file) => { + // var file = new Scratch.FolderManager.File (a); var doc = new Scratch.Services.Document (actions, file.file); if (file.is_valid_textfile) { @@ -507,15 +495,12 @@ namespace Scratch { }); terminal = new Code.Terminal () { - no_show_all = true, visible = false }; - var view_grid = new Gtk.Grid () { - orientation = Gtk.Orientation.VERTICAL - }; - view_grid.add (search_bar); - view_grid.add (document_view); + var view_grid = new Gtk.Box (VERTICAL, 0); + view_grid.append (search_bar); + view_grid.append (document_view); content_stack = new Gtk.Stack () { hexpand = true, @@ -523,34 +508,33 @@ namespace Scratch { width_request = 200 }; - content_stack.add (view_grid); // Must be added first to avoid terminal warnings - content_stack.add (welcome_view); + content_stack.add_child (view_grid); // Must be added first to avoid terminal warnings + content_stack.add_child (welcome_view); content_stack.visible_child = view_grid; // Must be visible while restoring - // The pane position is restored from settings vp = new Gtk.Paned (Gtk.Orientation.VERTICAL); - vp.pack1 (content_stack, true, false); - vp.pack2 (terminal, false, false); + vp.start_child = content_stack; + vp.end_child = terminal; var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); - box.add (toolbar); - box.add (vp); + box.append (toolbar.header_bar); + box.append (vp); hp1 = new Gtk.Paned (Gtk.Orientation.HORIZONTAL); - hp1.pack1 (sidebar, false, false); - hp1.pack2 (box, true, false); + hp1.start_child = sidebar; + hp1.end_child = box; - add (hp1); + content = hp1; - var header_group = new Hdy.HeaderGroup (); - header_group.add_header_bar (sidebar.headerbar); - header_group.add_header_bar (toolbar); + // var header_group = new Hdy.HeaderGroup (); + // header_group.add_header_bar (sidebar.headerbar); + // header_group.add_header_bar (toolbar.header_bar); var size_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.VERTICAL); size_group.add_widget (sidebar.headerbar); - size_group.add_widget (toolbar); + size_group.add_widget (toolbar.header_bar); - realize.connect (() => { + ((Gtk.Widget) this).realize.connect (() => { // Plugins hook HookFunc hook_func = () => { plugins.hook_window (this); @@ -598,11 +582,7 @@ namespace Scratch { document_view.tab_removed.connect ((doc) => { update_find_actions (); - var selected_item = (Scratch.FolderManager.Item?)(folder_manager_view.selected); - if (selected_item != null && selected_item.file.file.equal (doc.file)) { - // Do not leave removed tab selected - folder_manager_view.selected = null; - } + folder_manager_view.unselect_file (doc.file); }); document_view.document_change.connect ((doc) => { @@ -708,7 +688,7 @@ namespace Scratch { return false; } - protected override bool delete_event (Gdk.EventAny event) { + protected override bool close_request () { action_close_window (); return true; } @@ -722,8 +702,6 @@ namespace Scratch { // Toolbar Actions Utils.action_from_group (ACTION_SAVE, actions).set_enabled (val); Utils.action_from_group (ACTION_SAVE_AS, actions).set_enabled (val); - Utils.action_from_group (ACTION_UNDO, actions).set_enabled (val); - Utils.action_from_group (ACTION_REDO, actions).set_enabled (val); Utils.action_from_group (ACTION_REVERT, actions).set_enabled (val); search_bar.sensitive = val; toolbar.share_menu_button.sensitive = val; @@ -840,17 +818,15 @@ namespace Scratch { return; } - var state = get_window ().get_state (); - if (Gdk.WindowState.MAXIMIZED in state) { + var state = ((Gdk.Toplevel) this).state; + if (Gdk.ToplevelState.MAXIMIZED in state) { Scratch.saved_state.set_enum ("window-state", ScratchWindowState.MAXIMIZED); - } else if (Gdk.WindowState.FULLSCREEN in state) { + } else if (Gdk.ToplevelState.FULLSCREEN in state) { Scratch.saved_state.set_enum ("window-state", ScratchWindowState.FULLSCREEN); } else { Scratch.saved_state.set_enum ("window-state", ScratchWindowState.NORMAL); // Save window size - int width, height; - get_size (out width, out height); - Scratch.saved_state.set ("window-size", "(ii)", width, height); + Scratch.saved_state.set ("window-size", "(ii)", default_width, default_height); } // Plugin panes size @@ -980,19 +956,30 @@ namespace Scratch { file_chooser.add_filter (text_files_filter); file_chooser.add_filter (all_files_filter); file_chooser.select_multiple = true; - file_chooser.set_current_folder_uri (Utils.last_path ?? GLib.Environment.get_home_dir ()); + var current_folder = GLib.File.new_for_path ( + Utils.last_path ?? GLib.Environment.get_home_dir () + ); + try { + file_chooser.set_current_folder (current_folder); + } catch (Error e) { + warning ("Unable to set current folder %s", e.message); + } file_chooser.response.connect ((res) => { - var uris = file_chooser.get_uris (); + var files = file_chooser.get_files (); // Returns ListModel of GFile objects + // var uris = file_chooser.get_uris (); file_chooser.destroy (); // Close now so it does not stay open during lengthy or failed loading if (res == Gtk.ResponseType.ACCEPT) { - foreach (string uri in uris) { + var index = 0; + var obj = files.get_item (index++); + while (obj != null) { + var file = (GLib.File) obj; // Update last visited path - Utils.last_path = Path.get_dirname (uri); + Utils.last_path = Path.get_dirname (file.get_uri ()); // Open the file - var file = File.new_for_uri (uri); var doc = new Scratch.Services.Document (actions, file); open_document.begin (doc); + obj = files.get_item (index++); } } }); @@ -1031,10 +1018,14 @@ namespace Scratch { var files = chooser.get_files (); chooser.destroy (); if (res == Gtk.ResponseType.ACCEPT) { - files.foreach ((glib_file) => { - var foldermanager_file = new FolderManager.File (glib_file.get_path ()); +var index = 0; + var obj = files.get_item (index++); + while (obj != null) { + var file = (GLib.File) obj; + var foldermanager_file = new FolderManager.File (file.get_path ()); folder_manager_view.open_folder (foldermanager_file); - }); + obj = files.get_item (index++); + } } }); @@ -1147,19 +1138,7 @@ namespace Scratch { } } - private void action_undo () { - var doc = get_current_document (); - if (doc != null) { - doc.undo (); - } - } - private void action_redo () { - var doc = get_current_document (); - if (doc != null) { - doc.redo (); - } - } private void action_revert () { var confirmation_dialog = new Scratch.Dialogs.RestoreConfirmationDialog (this); @@ -1189,12 +1168,19 @@ namespace Scratch { } private void action_new_tab_from_clipboard () { - string text_from_clipboard = clipboard.wait_for_text (); - document_view.new_document_from_clipboard (text_from_clipboard); + try { + var text_val = Value (typeof (string)); + if (clipboard.content.get_value (ref text_val)) { + document_view.new_document_from_clipboard (text_val.get_string ()); + } + } catch (Error e) { + warning ("Failed to get clipboard content. %s", e.message); + } } private void action_fullscreen () { - if (Gdk.WindowState.FULLSCREEN in get_window ().get_state ()) { + var state = ((Gdk.Toplevel) this).state; + if (Gdk.ToplevelState.FULLSCREEN in state) { unfullscreen (); } else { fullscreen (); diff --git a/src/Services/CommentToggler.vala b/src/Services/CommentToggler.vala index 89ce6f7d4..f9ca49922 100644 --- a/src/Services/CommentToggler.vala +++ b/src/Services/CommentToggler.vala @@ -24,7 +24,7 @@ public class Scratch.CommentToggler { BLOCK } - private static CommentType get_comment_tags_for_lang (Gtk.SourceLanguage lang, + private static CommentType get_comment_tags_for_lang (GtkSource.Language lang, CommentType type, out string? start, out string? end) { @@ -64,7 +64,7 @@ public class Scratch.CommentToggler { return CommentType.NONE; } - public static bool language_has_comments (Gtk.SourceLanguage? lang) { + public static bool language_has_comments (GtkSource.Language? lang) { if (lang == null) { return false; } @@ -77,11 +77,11 @@ public class Scratch.CommentToggler { // This is to detect whether to toggle comments on or off. If all lines are commented, then we want to remove // those comments. If only some are commented, then the user likely selected a chunk of code that already contained // a couple of comments. In that case, we still want to insert comments. - private static CommentType lines_already_commented (Gtk.SourceBuffer buffer, + private static CommentType lines_already_commented (GtkSource.Buffer buffer, Gtk.TextIter start, Gtk.TextIter end, uint num_lines, - Gtk.SourceLanguage lang) { + GtkSource.Language lang) { string start_tag, end_tag; var type = get_comment_tags_for_lang (lang, CommentType.BLOCK, out start_tag, out end_tag); @@ -118,7 +118,7 @@ public class Scratch.CommentToggler { return CommentType.NONE; } - private static void remove_comments (Gtk.SourceBuffer buffer, + private static void remove_comments (GtkSource.Buffer buffer, Gtk.TextIter start, Gtk.TextIter end, uint num_lines, @@ -199,7 +199,7 @@ public class Scratch.CommentToggler { buffer.end_user_action (); } - private static void add_comments (Gtk.SourceBuffer buffer, + private static void add_comments (GtkSource.Buffer buffer, Gtk.TextIter start, Gtk.TextIter end, uint num_lines, @@ -297,7 +297,7 @@ public class Scratch.CommentToggler { buffer.delete_mark (emark); } - public static void toggle_comment (Gtk.SourceBuffer? buffer) { + public static void toggle_comment (GtkSource.Buffer? buffer) { if (buffer != null) { Gtk.TextIter start, end; var sel = buffer.get_selection_bounds (out start, out end); diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 137cc5f45..67ae2c9a2 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -37,7 +37,7 @@ namespace Scratch.Services { public unowned SimpleActionGroup actions { get; set construct; } // The TabPage that this document is a child of - public unowned Hdy.TabPage tab { get; private set; } + public unowned Adw.TabPage tab { get; private set; } public bool is_file_temporary { get { @@ -51,7 +51,7 @@ namespace Scratch.Services { } } - private Gtk.SourceFile source_file; + private GtkSource.File source_file; public GLib.File file { get { return source_file.location; @@ -167,7 +167,7 @@ namespace Scratch.Services { private Scratch.Services.SymbolOutline? outline = null; private Scratch.Widgets.DocumentView doc_view { get { - return ((MainWindow) get_toplevel ()).document_view; + return ((MainWindow) get_root ()).document_view; } } @@ -177,7 +177,7 @@ namespace Scratch.Services { private bool completion_shown = false; private Gtk.ScrolledWindow scroll; - private Gtk.SourceMap source_map; + private GtkSource.Map source_map; private Gtk.Paned outline_widget_pane; private GLib.Cancellable save_cancellable; @@ -188,7 +188,7 @@ namespace Scratch.Services { private Mount mount; private Icon locked_icon; - private Gtk.EventControllerScroll scroll_controller; + // private Gtk.EventControllerScroll scroll_controller; private static Pango.FontDescription? builder_blocks_font = null; private static Pango.FontMap? builder_font_map = null; @@ -224,36 +224,34 @@ namespace Scratch.Services { main_stack = new Gtk.Stack (); source_view = new Scratch.Widgets.SourceView (); - scroll = new Gtk.ScrolledWindow (null, null) { - hexpand = true, - vexpand = true + scroll = new Gtk.ScrolledWindow () { + child = source_view }; - scroll.add (source_view); - scroll_controller = new Gtk.EventControllerScroll (scroll, VERTICAL) { + var scroll_controller = new Gtk.EventControllerScroll (VERTICAL) { propagation_phase = CAPTURE }; + scroll.add_controller (scroll_controller); scroll_controller.scroll.connect ((dx, dy) => { - Gdk.ModifierType state; - Gtk.get_current_event_state (out state); + var state = scroll_controller.get_current_event_state (); if (Gdk.ModifierType.CONTROL_MASK in state) { total_delta += dy; if (total_delta < -SCROLL_THRESHOLD) { - get_action_group (MainWindow.ACTION_GROUP).activate_action (MainWindow.ACTION_ZOOM_IN, null); + activate_action (MainWindow.ACTION_PREFIX + MainWindow.ACTION_ZOOM_IN, null); total_delta = 0.0; } else if (total_delta > SCROLL_THRESHOLD) { - get_action_group (MainWindow.ACTION_GROUP).activate_action (MainWindow.ACTION_ZOOM_OUT, null); + activate_action (MainWindow.ACTION_PREFIX + MainWindow.ACTION_ZOOM_OUT, null); total_delta = 0.0; } - return; + return Gdk.EVENT_STOP; } - Gtk.propagate_event (scroll, Gtk.get_current_event ()); + return Gdk.EVENT_PROPAGATE; }); - source_file = new Gtk.SourceFile (); - source_map = new Gtk.SourceMap (); + source_file = new GtkSource.File (); + source_map = new GtkSource.Map (); outline_widget_pane = new Gtk.Paned (Gtk.Orientation.HORIZONTAL); if (builder_blocks_font != null && builder_font_map != null) { @@ -268,26 +266,25 @@ namespace Scratch.Services { settings.changed["show-mini-map"].connect (set_minimap); settings.changed["strip-trailing-on-save"].connect (set_strip_trailing_whitespace); - var source_grid = new Gtk.Grid () { - orientation = Gtk.Orientation.HORIZONTAL, - column_homogeneous = false + var source_grid = new Gtk.Box (HORIZONTAL, 0) { + homogeneous = false }; - source_grid.add (scroll); - source_grid.add (source_map); - outline_widget_pane.pack1 (source_grid, true, false); + source_grid.append (scroll); + source_grid.append (source_map); + outline_widget_pane.start_child = source_grid; - var doc_grid = new Gtk.Grid (); - doc_grid.orientation = Gtk.Orientation.VERTICAL; - doc_grid.add (outline_widget_pane); - doc_grid.show_all (); + var doc_grid = new Gtk.Box (VERTICAL, 0); + doc_grid.append (outline_widget_pane); main_stack.add_named (doc_grid, "content"); this.source_view.buffer.create_tag ("highlight_search_all", "background", "yellow", null); - this.source_view.notify["is-focus"].connect (() => { + var fc = new Gtk.EventControllerFocus (); + source_view.add_controller (fc); + fc.enter.connect (() => { return_if_fail (!locked); - if (source_view.is_focus) { + if (fc.is_focus) { if (!is_file_temporary) { check_undoable_actions (); check_file_status.begin (); @@ -329,19 +326,20 @@ namespace Scratch.Services { completion_shown = false; }); - source_view.enter_notify_event.connect (() => { - if (!source_view.has_focus) { + var focus_controller = new Gtk.EventControllerFocus (); + add_controller (focus_controller); + focus_controller.enter.connect (() => { + if (!source_view.has_focus) { source_view.grab_focus (); } }); loaded = file == null; - add (main_stack); - this.show_all (); + append (main_stack); } - public void init_tab (Hdy.TabPage tab) { + public void init_tab (Adw.TabPage tab) { this.tab = tab; tab.notify["loading"].connect (on_tab_loading_change); @@ -417,13 +415,23 @@ namespace Scratch.Services { || ContentType.is_a (content_type, "application/x-zerosize") // Empty files are valid text files )) { var title = _("%s Is Not a Text File").printf (get_basename ()); - var description = _("Code will not load this type of file."); - var alert_view = new Granite.Widgets.AlertView (title, description, "dialog-warning"); - alert_view.show_action (_("Load Anyway")); - alert_view.show_all (); + var alert_view = new Granite.Placeholder (title) { + description = _("Code will not load this type of file."), + icon = new ThemedIcon ("dialog-warning") + }; + var load_button = alert_view.append_button ( + new ThemedIcon ("document-open"), + _("Load Anyway"), + "" + ); + var cancel_button = alert_view.append_button ( + new ThemedIcon ("process-stop"), + _("Cancel"), + "" + ); main_stack.add_named (alert_view, "load_alert"); main_stack.set_visible_child (alert_view); - alert_view.action_activated.connect (() => { + load_button.clicked.connect (() => { open.begin (true); alert_view.destroy (); }); @@ -436,18 +444,23 @@ namespace Scratch.Services { MainContext.@default ().iteration (false); } - var buffer = new Gtk.SourceBuffer (null); /* Faster to load into a separate buffer */ + var buffer = new GtkSource.Buffer (null); /* Faster to load into a separate buffer */ load_timout_id = Timeout.add_seconds_full (GLib.Priority.HIGH, 5, () => { if (load_cancellable != null && !load_cancellable.is_cancelled ()) { var title = _("Loading File “%s” Is Taking a Long Time").printf (get_basename ()); - var description = _("Please wait while Code is loading the file."); - var alert_view = new Granite.Widgets.AlertView (title, description, "dialog-information"); - alert_view.show_action (_("Cancel Loading")); - alert_view.show_all (); + var alert_view = new Granite.Placeholder (title) { + description = _("Please wait while Code is loading the file."), + icon = new ThemedIcon ("dialog-information") + }; + var cancel_button = alert_view.append_button ( + new ThemedIcon ("process-stop"), + _("Cancel Loading"), + "" + ); main_stack.add_named (alert_view, "wait_alert"); main_stack.set_visible_child (alert_view); - alert_view.action_activated.connect (() => { + cancel_button.clicked.connect (() => { load_cancellable.cancel (); doc_closed (); }); @@ -461,13 +474,15 @@ namespace Scratch.Services { }); try { - var source_file_loader = new Gtk.SourceFileLoader (buffer, source_file); + var source_file_loader = new GtkSource.FileLoader (buffer, source_file); yield source_file_loader.load_async (GLib.Priority.LOW, load_cancellable, null); - var source_buffer = source_view.buffer as Gtk.SourceBuffer; + var source_buffer = source_view.buffer as GtkSource.Buffer; if (source_buffer != null) { - source_buffer.begin_not_undoable_action (); + source_buffer.enable_undo = false; + // source_buffer.begin_not_undoable_action (); source_buffer.text = buffer.text; - source_buffer.end_not_undoable_action (); + // source_buffer.end_not_undoable_action (); + source_buffer.enable_undo = false; } else { source_view.buffer.text = buffer.text; } @@ -509,7 +524,7 @@ namespace Scratch.Services { } private async bool ask_save_changes () { - var parent_window = source_view.get_toplevel () as Gtk.Window; + var parent_window = (Gtk.Window) (source_view.get_root ()); var dialog = new Granite.MessageDialog ( _("Save changes to “%s” before closing?").printf (this.get_basename ()), _("If you don't save, changes will be permanently lost."), @@ -521,7 +536,7 @@ namespace Scratch.Services { dialog.transient_for = parent_window; var no_save_button = (Gtk.Button) dialog.add_button (_("Close Without Saving"), Gtk.ResponseType.NO); - no_save_button.get_style_context ().add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); + no_save_button.add_css_class (Granite.STYLE_CLASS_DESTRUCTIVE_ACTION); dialog.add_button (_("Cancel"), Gtk.ResponseType.CANCEL); dialog.add_button (_("Save"), Gtk.ResponseType.YES); @@ -664,7 +679,7 @@ namespace Scratch.Services { save_cancellable.cancel (); save_cancellable = new GLib.Cancellable (); - var source_file_saver = new Gtk.SourceFileSaver ((Gtk.SourceBuffer) source_view.buffer, source_file); + var source_file_saver = new GtkSource.FileSaver ((GtkSource.Buffer) source_view.buffer, source_file); var success = false; var error = ""; try { @@ -728,15 +743,21 @@ namespace Scratch.Services { var file_chooser = new Gtk.FileChooserNative ( _("Save File"), - (Gtk.Window) this.get_toplevel (), + (Gtk.Window) this.get_root (), Gtk.FileChooserAction.SAVE, _("Save"), _("Cancel") ); file_chooser.add_filter (all_files_filter); file_chooser.add_filter (text_files_filter); - file_chooser.do_overwrite_confirmation = true; - file_chooser.set_current_folder_uri (Utils.last_path ?? GLib.Environment.get_home_dir ()); + try { + var current_folder = Utils.last_path != null ? + GLib.File.new_for_path (Utils.last_path) : + GLib.File.new_for_path (Environment.get_home_dir ()); + file_chooser.set_current_folder (current_folder); + } catch (Error e) { + warning ("Could not set current folder. %s", e.message); + } var success = false; var current_file = file.dup (); @@ -744,7 +765,6 @@ namespace Scratch.Services { file_chooser.response.connect ((res) => { if (res == Gtk.ResponseType.ACCEPT) { - file = File.new_for_uri (file_chooser.get_uri ()); // Update last visited path Utils.last_path = Path.get_dirname (file_chooser.get_file ().get_uri ()); success = true; @@ -797,7 +817,6 @@ namespace Scratch.Services { scroll.vscrollbar_policy = Gtk.PolicyType.EXTERNAL; } else { source_map.hide (); - source_map.no_show_all = true; scroll.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC; } } @@ -849,18 +868,18 @@ namespace Scratch.Services { } } - // SourceView related functions - // Undo - public void undo () { - this.source_view.undo (); - check_undoable_actions (); - } + // // SourceView related functions + // // Undo + // public void undo () { + // this.source_view.undo (); + // check_undoable_actions (); + // } - // Redo - public void redo () { - this.source_view.redo (); - check_undoable_actions (); - } + // // Redo + // public void redo () { + // this.source_view.redo (); + // check_undoable_actions (); + // } // Revert public void revert () { @@ -905,7 +924,7 @@ namespace Scratch.Services { // Get language name public string get_language_name () { - var source_buffer = (Gtk.SourceBuffer) source_view.buffer; + var source_buffer = (GtkSource.Buffer) source_view.buffer; var lang = source_buffer.language; if (lang != null) { return lang.name; @@ -916,7 +935,7 @@ namespace Scratch.Services { // Get language id public string get_language_id () { - var source_buffer = (Gtk.SourceBuffer) source_view.buffer; + var source_buffer = (GtkSource.Buffer) source_view.buffer; var lang = source_buffer.language; if (lang != null) { return lang.id; @@ -933,22 +952,29 @@ namespace Scratch.Services { // Show an error view which says "Hey, I cannot read that file!" private void show_default_load_error_view (string invalid_content = "") { var title = _("Cannot read text in file “%s”").printf (get_basename ()); - string description; + string detail; if (invalid_content == "") { - description = _("You may not have permission to read the file."); + detail = _("You may not have permission to read the file."); } else { - description = _("The file may be corrupt or may not be a text file"); + detail = _("The file may be corrupt or may not be a text file"); } - var alert_view = new Granite.Widgets.AlertView (title, description, "dialog-error"); + var alert_view = new Granite.Placeholder (title) { + description = detail, + icon = new ThemedIcon ("dialog-error") + }; // Lack of read permission results in empty content string. Do not give option to open // in new document in that case. if (invalid_content != "") { - alert_view.show_action (_("Show Anyway")); - alert_view.action_activated.connect (() => { + var show_button = alert_view.append_button ( + new ThemedIcon ("go-next"), + _("Show Anyway"), + "" + ); + show_button.clicked.connect (() => { main_stack.set_visible_child_name ("content"); Idle.add (() => { - var clipboard = Gtk.Clipboard.get_for_display (get_display (), Gdk.SELECTION_CLIPBOARD); - clipboard.set_text (invalid_content, -1); + var clipboard = Gdk.Display.get_default ().get_clipboard (); + clipboard.set_text (invalid_content); var clipboard_action = Utils.action_from_group (MainWindow.ACTION_NEW_FROM_CLIPBOARD, actions); clipboard_action.set_enabled (true); clipboard_action.activate (null); @@ -961,7 +987,6 @@ namespace Scratch.Services { }); } - alert_view.show_all (); main_stack.add_named (alert_view, "error_alert"); main_stack.set_visible_child (alert_view); } @@ -1001,8 +1026,8 @@ namespace Scratch.Services { // If user selects to continue regardless then no further // check made for this document // External changes will be overwritten on next (auto) save - var new_buffer = new Gtk.SourceBuffer (null); - var source_file_loader = new Gtk.SourceFileLoader ( + var new_buffer = new GtkSource.Buffer (null); + var source_file_loader = new GtkSource.FileLoader ( new_buffer, source_file ); @@ -1078,7 +1103,7 @@ namespace Scratch.Services { dialog.add_button (_("Ignore"), Gtk.ResponseType.REJECT); var saveas_button = (Gtk.Button) dialog.add_button (_("Save Duplicate…"), Gtk.ResponseType.ACCEPT); - saveas_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); + saveas_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); if (error_text != "") { dialog.show_error_details (error_text); @@ -1129,13 +1154,13 @@ namespace Scratch.Services { dialog.add_button (_("Continue"), Gtk.ResponseType.REJECT); var reload_button = (Gtk.Button) (dialog.add_button (_("Reload"), 0)); - reload_button.get_style_context ().add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); + reload_button.add_css_class (Granite.STYLE_CLASS_DESTRUCTIVE_ACTION); var overwrite_button = (Gtk.Button) (dialog.add_button (_("Overwrite"), 1)); - overwrite_button.get_style_context ().add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); + overwrite_button.add_css_class (Granite.STYLE_CLASS_DESTRUCTIVE_ACTION); var saveas_button = (Gtk.Button) (dialog.add_button (_("Save Document elsewhere"), Gtk.ResponseType.ACCEPT)); - saveas_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); + saveas_button.add_css_class (Granite.STYLE_CLASS_SUGGESTED_ACTION); dialog.response.connect ((id) => { dialog.destroy (); @@ -1185,9 +1210,7 @@ namespace Scratch.Services { } // Set Undo/Redo action sensitive property public void check_undoable_actions () { - var source_buffer = (Gtk.SourceBuffer) source_view.buffer; - Utils.action_from_group (MainWindow.ACTION_UNDO, actions).set_enabled (source_buffer.can_undo); - Utils.action_from_group (MainWindow.ACTION_REDO, actions).set_enabled (source_buffer.can_redo); + var source_buffer = (GtkSource.Buffer) source_view.buffer; Utils.action_from_group (MainWindow.ACTION_REVERT, actions).set_enabled ( original_content != source_buffer.text ); @@ -1316,7 +1339,8 @@ namespace Scratch.Services { } if (outline != null) { - outline_widget_pane.pack2 (outline.get_widget (), false, false); + // outline_widget_pane.pack2 (outline.get_widget (), false, false); + outline_widget_pane.end_child = outline.get_widget (); Idle.add (() => { set_outline_width (doc_view.outline_width); outline_widget_pane.notify["position"].connect (sync_outline_width); @@ -1329,7 +1353,7 @@ namespace Scratch.Services { } } else if (!show && outline != null) { outline_widget_pane.notify["position"].disconnect (sync_outline_width); - outline_widget_pane.get_child2 ().destroy (); + outline_widget_pane.end_child.destroy (); outline = null; } } @@ -1373,7 +1397,7 @@ namespace Scratch.Services { return; } - var source_buffer = (Gtk.SourceBuffer)source_view.buffer; + var source_buffer = (GtkSource.Buffer)source_view.buffer; Gtk.TextIter iter; var cursor_pos = source_buffer.cursor_position; @@ -1417,9 +1441,11 @@ namespace Scratch.Services { continue; } - source_buffer.begin_not_undoable_action (); + source_buffer.enable_undo = false; + // source_buffer.begin_not_undoable_action (); source_buffer.@delete (ref start_delete, ref end_delete); - source_buffer.end_not_undoable_action (); + // source_buffer.end_not_undoable_action (); + source_buffer.enable_undo = true; } } diff --git a/src/Services/PluginManager.vala b/src/Services/PluginManager.vala index 4509a74ed..3324a47c4 100644 --- a/src/Services/PluginManager.vala +++ b/src/Services/PluginManager.vala @@ -122,9 +122,9 @@ public class Scratch.Services.PluginsManager : GLib.Object { // Return an emulation of the discontinued libpeas-1.0 widget public Gtk.Widget get_view () { var list_box = new Gtk.ListBox (); - list_box.get_accessible ().accessible_name = _("Extensions"); + ((Gtk.Accessible)list_box).update_property (Gtk.AccessibleProperty.LABEL, _("Extensions"), -1); - var scrolled_window = new Gtk.ScrolledWindow (null, null) { + var scrolled_window = new Gtk.ScrolledWindow () { hscrollbar_policy = NEVER, child = list_box }; @@ -147,7 +147,6 @@ public class Scratch.Services.PluginsManager : GLib.Object { ); }); - frame.show_all (); return frame; } @@ -159,7 +158,7 @@ public class Scratch.Services.PluginsManager : GLib.Object { state = info.is_loaded () }; - var image = new Gtk.Image.from_icon_name (info.get_icon_name (), LARGE_TOOLBAR) { + var image = new Gtk.Image.from_icon_name (info.get_icon_name ()) { valign = START }; @@ -174,14 +173,14 @@ public class Scratch.Services.PluginsManager : GLib.Object { wrap = true, xalign = 0 }; - description_label.get_style_context ().add_class (Granite.STYLE_CLASS_SMALL_LABEL); - description_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); + description_label.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL); + description_label.add_css_class (Granite.STYLE_CLASS_DIM_LABEL); var description_box = new Gtk.Box (VERTICAL, 0) { hexpand = true }; - description_box.add (name_label); - description_box.add (description_label); + description_box.append (name_label); + description_box.append (description_label); var content = new Gtk.Box (HORIZONTAL, 6) { margin_top = 6, @@ -189,9 +188,9 @@ public class Scratch.Services.PluginsManager : GLib.Object { margin_bottom = 6, margin_start = 6 }; - content.add (image); - content.add (description_box); - content.add (load_switch); + content.append (image); + content.append (description_box); + content.append (load_switch); content.set_data ("name", info.get_name ()); load_switch.notify["active"].connect (() => { diff --git a/src/SymbolPane/SymbolOutline.vala b/src/SymbolPane/SymbolOutline.vala index 1e5fcce80..ae9e7374e 100644 --- a/src/SymbolPane/SymbolOutline.vala +++ b/src/SymbolPane/SymbolOutline.vala @@ -133,10 +133,7 @@ public class Scratch.Services.SymbolOutline : Gtk.Box { }; filter_button = new Gtk.MenuButton () { - image = new Gtk.Image.from_icon_name ( - "filter-symbolic", - Gtk.IconSize.SMALL_TOOLBAR - ), + icon_name = "filter-symbolic", tooltip_text = _("Filter symbol type"), }; @@ -174,17 +171,16 @@ public class Scratch.Services.SymbolOutline : Gtk.Box { spinner = new Gtk.Spinner (); stack = new Gtk.Stack (); - stack.add (filter_button); - stack.add (spinner); + stack.add_child (filter_button); + stack.add_child (spinner); stack.visible_child = filter_button; var tool_box = new Gtk.Box (HORIZONTAL, 3); - tool_box.add (search_entry); - tool_box.add (stack); - add (tool_box); - add (store); + tool_box.append (search_entry); + tool_box.append (stack); + append (tool_box); + append (store); set_up_css (); - show_all (); realize.connect (() => { store.set_filter_func (filter_func, false); @@ -271,18 +267,18 @@ public class Scratch.Services.SymbolOutline : Gtk.Box { protected void set_up_css () { source_list_style_provider = new Gtk.CssProvider (); - Gtk.StyleContext.add_provider_for_screen ( - Gdk.Screen.get_default (), + Gtk.StyleContext.add_provider_for_display ( + Gdk.Display.get_default (), source_list_style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION ); // Add a class to distinguish from foldermanager sourcelist - get_style_context ().add_class ("symbol-outline"); - update_style_scheme (((Gtk.SourceBuffer)(doc.source_view.buffer)).style_scheme); + add_css_class ("symbol-outline"); + update_style_scheme (((GtkSource.Buffer)(doc.source_view.buffer)).style_scheme); doc.source_view.style_changed.connect (update_style_scheme); } - protected void update_style_scheme (Gtk.SourceStyleScheme style_scheme) { + protected void update_style_scheme (GtkSource.StyleScheme style_scheme) { var text_color_data = style_scheme.get_style ("text"); // Default gtksourceview background color is white @@ -292,12 +288,7 @@ public class Scratch.Services.SymbolOutline : Gtk.Box { } var define = ".symbol-outline {background-color: %s;}".printf (color); - - try { - source_list_style_provider.load_from_data (define); - } catch (Error e) { - critical ("Unable to sourcelist styling, going back to classic styling"); - } + source_list_style_provider.load_from_string (define); } private void action_select_filters (SimpleAction action, Variant? param) { diff --git a/src/Utils.vala b/src/Utils.vala index 429e2376a..9307da5a2 100644 --- a/src/Utils.vala +++ b/src/Utils.vala @@ -261,9 +261,9 @@ namespace Scratch.Utils { var scratch_app = (Scratch.Application) (GLib.Application.get_default ()); if (scratch_app.is_running_in_flatpak || app_id == "") { var uri = Uri.join (UriFlags.NONE, "file", null, null, -1, path, null, null); - + var launcher = new Gtk.UriLauncher (uri); try { - Gtk.show_uri_on_window (scratch_app.get_active_window (), uri, Gdk.CURRENT_TIME); + launcher.launch (scratch_app.get_active_window (), null); } catch (Error e) { warning ("Error showing uri %s, %s", uri, e.message); } diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 830f4e61f..70ae55a05 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -16,21 +16,20 @@ * */ -public class Code.ChooseProjectButton : Gtk.MenuButton { +public class Code.ChooseProjectButton : Gtk.Box { public bool cloning_in_progress { get; set; } private const string NO_PROJECT_SELECTED = N_("No Project Selected"); private const string PROJECT_TOOLTIP = N_("Active Git Project: %s"); private Gtk.Label label_widget; private Gtk.ListBox project_listbox; + private Gtk.MenuButton menu_button; public signal void project_chosen (); construct { - - var img = new Gtk.Image () { - gicon = new ThemedIcon ("git-symbolic"), - icon_size = Gtk.IconSize.SMALL_TOOLBAR + var img = new Gtk.Image.from_gicon (new ThemedIcon ("git-symbolic")) { + icon_size = Gtk.IconSize.NORMAL }; label_widget = new Gtk.Label (_(NO_PROJECT_SELECTED)) { @@ -42,16 +41,19 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { var cloning_spinner = new Gtk.Spinner () { halign = END }; - bind_property ("cloning-in-progress", cloning_spinner, "active"); + bind_property ("cloning-in-progress", cloning_spinner, "spinning"); var box = new Gtk.Box (HORIZONTAL, 3) { hexpand = true, vexpand = false }; - box.add (img); - box.add (label_widget); - box.add (cloning_spinner); - add (box); + box.append (img); + box.append (label_widget); + box.append (cloning_spinner); + menu_button = new Gtk.MenuButton () { + child = box + }; + menu_button.set_parent (this); project_listbox = new Gtk.ListBox () { selection_mode = Gtk.SelectionMode.SINGLE @@ -73,18 +75,17 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { project_listbox.invalidate_filter (); }); - var project_scrolled = new Gtk.ScrolledWindow (null, null) { + var project_scrolled = new Gtk.ScrolledWindow () { hscrollbar_policy = Gtk.PolicyType.NEVER, hexpand = true, vexpand = true, margin_top = 3, margin_bottom = 3, max_content_height = 350, - propagate_natural_height = true + propagate_natural_height = true, + child = project_listbox }; - project_scrolled.add (project_listbox); - var add_folder_button = new PopoverMenuItem (_("Open Folder…")) { action_name = Scratch.MainWindow.ACTION_PREFIX + Scratch.MainWindow.ACTION_OPEN_PROJECT, icon_name = "folder-open-symbolic", @@ -96,21 +97,18 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { }; var popover_content = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); - popover_content.add (project_filter); - popover_content.add (project_scrolled); - popover_content.add (new Gtk.Separator (HORIZONTAL)); - popover_content.add (add_folder_button); - popover_content.add (clone_button); - - popover_content.show_all (); - - var project_popover = new Gtk.Popover (this) { - position = Gtk.PositionType.BOTTOM + popover_content.append (project_filter); + popover_content.append (project_scrolled); + popover_content.append (new Gtk.Separator (HORIZONTAL)); + popover_content.append (add_folder_button); + popover_content.append (clone_button); + + var project_popover = new Gtk.Popover () { + position = Gtk.PositionType.BOTTOM, + child = popover_content }; - project_popover.add (popover_content); - - popover = project_popover; + menu_button.popover = project_popover; // Initialise with any pre-existing projects (needed for second and subsequent window) var git_manager = Scratch.Services.GitManager.get_instance (); @@ -124,12 +122,7 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { } git_manager.project_liststore.items_changed.connect ((src, pos, n_removed, n_added) => { - var rows = project_listbox.get_children (); - for (int index = (int)pos; index < pos + n_removed; index++) { - var row = rows.nth_data (index); - row.destroy (); - } - + project_listbox.remove_all (); for (int index = (int)pos; index < pos + n_added; index++) { var item = src.get_object (index); if (item is Scratch.FolderManager.ProjectFolderItem) { @@ -139,13 +132,15 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { } }); - toggled.connect (() => { - if (active) { + menu_button.activate.connect (() => { + if (menu_button.active) { unowned var active_path = Scratch.Services.GitManager.get_instance ().active_project_path; - foreach (var child in project_listbox.get_children ()) { + var child = project_listbox.get_first_child (); + while (child != null) { var project_row = ((ProjectRow) child); // All paths must not end in directory separator so can be compared directly project_row.active = active_path == project_row.project_path; + child = child.get_next_sibling (); } } }); @@ -168,24 +163,12 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { private Gtk.Widget create_project_row (Scratch.FolderManager.ProjectFolderItem project_folder) { var project_path = project_folder.file.file.get_path (); - var project_row = new ProjectRow (project_path); - // Project folder items cannot be renamed in UI, no need to handle - - return project_row; + return new ProjectRow (project_path); } public class ProjectRow : Gtk.ListBoxRow { private Gtk.CheckButton check_button; - public bool active { - get { - return check_button.active; - } - - set { - check_button.active = value; - } - } - + public bool active { get; set; } public string project_path { get; construct; } public string project_name { get { @@ -199,10 +182,8 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { ); } - private Gtk.GestureMultiPress button_controller; - class construct { - set_css_name (Gtk.STYLE_CLASS_MENUITEM); + set_css_name (Granite.STYLE_CLASS_MENUITEM); } construct { @@ -210,20 +191,20 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { action_name = Scratch.MainWindow.ACTION_PREFIX + Scratch.MainWindow.ACTION_SET_ACTIVE_PROJECT; action_target = new Variant.string (project_path); - check_button = new Gtk.CheckButton.with_label (Path.get_basename (project_path)) { - can_focus = false - }; - add (check_button); + check_button = new Gtk.CheckButton.with_label (Path.get_basename (project_path)); + child = check_button; - button_controller = new Gtk.GestureMultiPress (check_button) { + var button_controller = new Gtk.GestureClick () { propagation_phase = CAPTURE, button = 0 }; - button_controller.released.connect (() => { + + check_button.add_controller (button_controller); + button_controller.released.connect ((n, dx, dy) => { activate (); }); - show_all (); + check_button.bind_property ("active", this, "active"); } } } diff --git a/src/Widgets/DocumentView.vala b/src/Widgets/DocumentView.vala index bcfa1aba8..828e3981a 100644 --- a/src/Widgets/DocumentView.vala +++ b/src/Widgets/DocumentView.vala @@ -60,11 +60,13 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { public bool outline_visible { get; set; default = false; } public int outline_width { get; set; } - private Hdy.TabView tab_view; - private Hdy.TabBar tab_bar; - private weak Hdy.TabPage? tab_menu_target = null; + private Adw.TabView tab_view; + private Adw.TabBar tab_bar; + private weak Adw.TabPage? tab_menu_target = null; private Gtk.CssProvider style_provider; private Gtk.MenuButton tab_history_button; + private double total_delta = 0.0; + private const double SCROLL_THRESHOLD = 1.0; public DocumentView (Scratch.MainWindow window) { Object ( @@ -78,7 +80,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { construct { docs = new GLib.List (); var app_instance = (Gtk.Application) GLib.Application.get_default (); - tab_view = new Hdy.TabView () { + tab_view = new Adw.TabView () { hexpand = true, vexpand = true }; @@ -94,7 +96,6 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { }); var new_tab_button = new Gtk.Button.from_icon_name ("list-add-symbolic") { - relief = Gtk.ReliefStyle.NONE, tooltip_markup = Granite.markup_accel_tooltip ( app_instance.get_accels_for_action (MainWindow.ACTION_PREFIX + MainWindow.ACTION_NEW_TAB), _("New Tab") @@ -106,12 +107,11 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { }); tab_history_button = new Gtk.MenuButton () { - image = new Gtk.Image.from_icon_name ("document-open-recent-symbolic", Gtk.IconSize.MENU), - tooltip_text = _("Closed Tabs"), - use_popover = false, + icon_name = "document-open-recent-symbolic", + tooltip_text = _("Closed Tabs") }; - tab_bar = new Hdy.TabBar () { + tab_bar = new Adw.TabBar () { autohide = false, expand_tabs = false, inverted = true, @@ -150,8 +150,8 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { tab_view.create_window.connect (on_doc_to_new_window); style_provider = new Gtk.CssProvider (); - Gtk.StyleContext.add_provider_for_screen ( - Gdk.Screen.get_default (), + Gtk.StyleContext.add_provider_for_display ( + Gdk.Display.get_default (), style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION ); @@ -171,12 +171,37 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { }); // Handle Drag-and-drop of files onto add-tab button to create document - Gtk.TargetEntry uris = {"text/uri-list", 0, TargetType.URI_LIST}; - Gtk.drag_dest_set (tab_bar, Gtk.DestDefaults.ALL, {uris}, Gdk.DragAction.COPY); - tab_bar.drag_data_received.connect (drag_received); + // Gtk.TargetEntry uris = {"text/uri-list", 0, TargetType.URI_LIST}; + // Gtk.drag_dest_set (tab_bar, Gtk.DestDefaults.ALL, {uris}, Gdk.DragAction.COPY); + // tab_bar.drag_data_received.connect (drag_received); + + append (tab_bar); + append (tab_view); + + var scroll_controller = new Gtk.EventControllerScroll (VERTICAL) { + propagation_phase = CAPTURE + }; + add_controller (scroll_controller); + + scroll_controller.scroll.connect ((dx, dy) => { + var state = scroll_controller.get_current_event_state (); + var mods = (state & Gtk.accelerator_get_default_mod_mask ()); + if (Gdk.ModifierType.CONTROL_MASK in mods) { + total_delta += dy; + if (total_delta < -SCROLL_THRESHOLD) { + activate_action (MainWindow.ACTION_PREFIX + MainWindow.ACTION_ZOOM_IN, null); + total_delta = 0.0; + } else if (total_delta > SCROLL_THRESHOLD) { + activate_action (MainWindow.ACTION_PREFIX + MainWindow.ACTION_ZOOM_OUT, null); + total_delta = 0.0; + } + + return true; + } + + return false; + }); - add (tab_bar); - add (tab_view); } private void update_inline_tab_colors () { @@ -192,7 +217,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { style_scheme = Scratch.settings.get_string ("style-scheme"); } - var sssm = Gtk.SourceStyleSchemeManager.get_default (); + var sssm = GtkSource.StyleSchemeManager.get_default (); if (style_scheme in sssm.scheme_ids) { var theme = sssm.get_scheme (style_scheme); var text_color_data = theme.get_style ("text"); @@ -205,11 +230,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { } var define = "@define-color tab_base_color %s;".printf (color); - try { - style_provider.load_from_data (define); - } catch (Error e) { - critical ("Unable to set inline tab styling, going back to classic notebook tabs"); - } + style_provider.load_from_string (define); } } @@ -424,7 +445,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { } // This is called when tab context menu is opened or closed - private void tab_view_setup_menu (Hdy.TabPage? page) { + private void tab_view_setup_menu (Adw.TabPage? page) { tab_menu_target = page; var close_other_tabs_action = Utils.action_from_group (MainWindow.ACTION_CLOSE_OTHER_TABS, window.actions); @@ -464,7 +485,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { return unsaved_file_path_builder (extension); } - private void on_page_detached (Hdy.TabPage tab, int position) { + private void on_page_detached (Adw.TabPage tab, int position) { var doc = tab.get_child () as Services.Document; if (doc == null) { return; @@ -504,7 +525,6 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { tab_removed (doc); Scratch.Services.DocumentManager.get_instance ().remove_open_document (doc); - if (docs.length () > 0) { if (!doc.is_file_temporary) { foreach (var d in docs) { @@ -534,7 +554,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { } } - private void on_doc_reordered (Hdy.TabPage tab, int new_position) { + private void on_doc_reordered (Adw.TabPage tab, int new_position) { var doc = tab.child as Services.Document; if (doc != null) { docs.remove (doc); @@ -545,12 +565,12 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { update_opened_files_setting (); } - private unowned Hdy.TabView? on_doc_to_new_window (Hdy.TabView tab_view) { + private unowned Adw.TabView? on_doc_to_new_window (Adw.TabView tab_view) { var other_window = new MainWindow (false); return other_window.document_view.tab_view; } - private void on_doc_added (Hdy.TabPage page, int position) { + private void on_doc_added (Adw.TabPage page, int position) { var doc = page.get_child () as Services.Document; doc.init_tab (page); @@ -623,23 +643,23 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { return menu; } - private void drag_received (Gtk.Widget w, - Gdk.DragContext ctx, - int x, - int y, - Gtk.SelectionData sel, - uint info, - uint time) { - - if (info == TargetType.URI_LIST) { - var uris = sel.get_uris (); - foreach (var filename in uris) { - var file = File.new_for_uri (filename); - var doc = new Services.Document (window.actions, file); - open_document.begin (doc); - } - - Gtk.drag_finish (ctx, true, false, time); - } - } + // private void drag_received (Gtk.Widget w, + // Gdk.DragContext ctx, + // int x, + // int y, + // Gtk.SelectionData sel, + // uint info, + // uint time) { + + // if (info == TargetType.URI_LIST) { + // var uris = sel.get_uris (); + // foreach (var filename in uris) { + // var file = File.new_for_uri (filename); + // var doc = new Services.Document (window.actions, file); + // open_document.begin (doc); + // } + + // Gtk.drag_finish (ctx, true, false, time); + // } + // } } diff --git a/src/Widgets/FormatBar.vala b/src/Widgets/FormatBar.vala index f60283275..cc32845b5 100644 --- a/src/Widgets/FormatBar.vala +++ b/src/Widgets/FormatBar.vala @@ -31,15 +31,15 @@ public class Code.FormatBar : Gtk.Box { private Gtk.Entry goto_entry; private Gtk.ListBox lang_selection_listbox; private Gtk.SearchEntry lang_selection_filter; - private Gtk.SourceLanguageManager manager; + private GtkSource.LanguageManager manager; private LangEntry normal_entry; private unowned Scratch.Services.Document? doc = null; construct { - get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED); + add_css_class (Granite.STYLE_CLASS_LINKED); - manager = Gtk.SourceLanguageManager.get_default (); + manager = GtkSource.LanguageManager.get_default (); tab_menubutton = new FormatButton () { icon = new ThemedIcon ("format-indent-more-symbolic") @@ -61,9 +61,9 @@ public class Code.FormatBar : Gtk.Box { ); homogeneous = true; - add (tab_menubutton); - add (lang_menubutton); - add (line_menubutton); + append (tab_menubutton); + append (lang_menubutton); + append (line_menubutton); create_tabulation_popover (); create_language_popover (); @@ -93,36 +93,35 @@ public class Code.FormatBar : Gtk.Box { lang_selection_listbox.invalidate_filter (); }); - var lang_scrolled = new Gtk.ScrolledWindow (null, null); - lang_scrolled.hscrollbar_policy = Gtk.PolicyType.NEVER; - lang_scrolled.height_request = 350; - lang_scrolled.expand = true; - lang_scrolled.margin_top = lang_scrolled.margin_bottom = 3; + var lang_scrolled = new Gtk.ScrolledWindow () { + hscrollbar_policy = Gtk.PolicyType.NEVER, + height_request = 350, + hexpand = true, + vexpand = true, + margin_top = margin_bottom = 3, + child = lang_selection_listbox + }; - lang_scrolled.add (lang_selection_listbox); + normal_entry = new LangEntry (null, _("Plain Text")); + lang_selection_listbox.append (normal_entry); unowned string[]? ids = manager.get_language_ids (); - unowned SList group = null; foreach (unowned string id in ids) { - weak Gtk.SourceLanguage lang = manager.get_language (id); - var entry = new LangEntry (id, lang.name, group); - group = entry.get_radio_group (); - lang_selection_listbox.add (entry); + weak GtkSource.Language lang = manager.get_language (id); + var entry = new LangEntry (id, lang.name) { + group = normal_entry.group + }; + lang_selection_listbox.append (entry); } - normal_entry = new LangEntry (null, _("Plain Text"), group); - lang_selection_listbox.add (normal_entry); - var popover_content = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); - popover_content.add (lang_selection_filter); - popover_content.add (lang_scrolled); - - popover_content.show_all (); - - var lang_popover = new Gtk.Popover (lang_menubutton); - lang_popover.position = Gtk.PositionType.BOTTOM; - lang_popover.add (popover_content); + popover_content.append (lang_selection_filter); + popover_content.append (lang_scrolled); + var lang_popover = new Gtk.Popover () { + position = Gtk.PositionType.BOTTOM, + child = popover_content + }; lang_menubutton.popover = lang_popover; lang_selection_listbox.row_activated.connect ((row) => { @@ -148,8 +147,8 @@ public class Code.FormatBar : Gtk.Box { margin_end = 9, margin_start = 9 }; - editorconfig_infobar.get_content_area ().add (new Gtk.Label (_("Some settings set by EditorConfig file"))); - editorconfig_infobar.get_style_context ().add_class (Gtk.STYLE_CLASS_FRAME); + editorconfig_infobar.add_child (new Gtk.Label (_("Some settings set by EditorConfig file"))); + editorconfig_infobar.add_css_class (Granite.STYLE_CLASS_FRAME); var autoindent_modelbutton = new Granite.SwitchModelButton (_("Automatic Indentation")); @@ -167,23 +166,21 @@ public class Code.FormatBar : Gtk.Box { margin_end = 12, margin_start = 12, }; - tab_box.add (width_label); - tab_box.add (width_spinbutton); + tab_box.append (width_label); + tab_box.append (width_spinbutton); var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0) { margin_bottom = 12 }; - box.add (editorconfig_infobar); - box.add (autoindent_modelbutton); - box.add (space_tab_modelbutton); - box.add (tab_box); - box.show_all (); - - var tab_popover = new Gtk.Popover (tab_menubutton) { - position = Gtk.PositionType.BOTTOM + box.append (editorconfig_infobar); + box.append (autoindent_modelbutton); + box.append (space_tab_modelbutton); + box.append (tab_box); + + var tab_popover = new Gtk.Popover () { + position = Gtk.PositionType.BOTTOM, + child = box }; - tab_popover.add (box); - tab_menubutton.popover = tab_popover; Scratch.settings.changed["indent-width"].connect (format_tab_header_from_global_settings); @@ -249,12 +246,11 @@ public class Code.FormatBar : Gtk.Box { line_grid.column_spacing = 12; line_grid.attach (goto_label, 0, 0, 1, 1); line_grid.attach (goto_entry, 1, 0, 1, 1); - line_grid.show_all (); - - var line_popover = new Gtk.Popover (line_menubutton); - line_popover.position = Gtk.PositionType.BOTTOM; - line_popover.add (line_grid); + var line_popover = new Gtk.Popover () { + position = Gtk.PositionType.BOTTOM, + child = line_grid + }; line_menubutton.popover = line_popover; // We need to connect_after because otherwise, the text isn't parsed into the "value" property and we only get the previous value @@ -305,18 +301,21 @@ public class Code.FormatBar : Gtk.Box { var language = doc.source_view.language; if (language != null) { var lang_id = language.id; - lang_selection_listbox.get_children ().foreach ((child) => { - var lang_entry = ((LangEntry) child); + var child = lang_selection_listbox.get_first_child (); + while (child != null) { + var lang_entry = ((LangEntry) child); if (lang_entry.lang_id == lang_id) { select_language (lang_entry, false); } - }); + + child = child.get_next_sibling (); + } } else { select_language (normal_entry, false); } } - public class FormatButton : Gtk.MenuButton { + public class FormatButton : Gtk.Box { public unowned string text { set { label_widget.label = "%s".printf (value); @@ -331,12 +330,16 @@ public class Code.FormatBar : Gtk.Box { } } + public Gtk.Popover popover { get; set; } + public bool active { get; set; } + private Gtk.Image img; private Gtk.Label label_widget; + private Gtk.MenuButton menu_button; construct { img = new Gtk.Image () { - icon_size = Gtk.IconSize.SMALL_TOOLBAR + icon_size = Gtk.IconSize.NORMAL }; label_widget = new Gtk.Label (null) { @@ -347,28 +350,35 @@ public class Code.FormatBar : Gtk.Box { var box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) { halign = Gtk.Align.CENTER }; - box.add (img); - box.add (label_widget); + box.append (img); + box.append (label_widget); + + menu_button = new Gtk.MenuButton () { + child = box + }; - add (box); + menu_button.set_parent (this); + bind_property ("popover", menu_button, "popover"); + bind_property ("active", menu_button, "active"); } } public class LangEntry : Gtk.ListBoxRow { public string? lang_id { get; construct; } public string lang_name { get; construct; } - public unowned SList group { get; construct; } - - public bool active { + private Gtk.CheckButton _group; + public Gtk.CheckButton group { get { - return lang_radio.active; + return _group; } set { - lang_radio.active = value; + _group = value; + lang_radio.group = _group; } } + public bool active { get; set; } public bool selected { get { return lang_radio.active; @@ -381,20 +391,21 @@ public class Code.FormatBar : Gtk.Box { } } - private Gtk.RadioButton lang_radio; - public LangEntry (string? lang_id, string lang_name, SList group) { - Object (group: group, lang_id: lang_id, lang_name: lang_name); + public Gtk.CheckButton lang_radio { get; private set; } + + public LangEntry (string? lang_id, string lang_name) { + Object (lang_id: lang_id, lang_name: lang_name); } class construct { - set_css_name (Gtk.STYLE_CLASS_MENUITEM); + set_css_name (Granite.STYLE_CLASS_MENUITEM); } construct { - lang_radio = new Gtk.RadioButton.with_label (group, lang_name); - - add (lang_radio); + lang_radio = new Gtk.CheckButton.with_label (lang_name); + child = lang_radio; lang_radio.toggled.connect (radio_toggled); + lang_radio.bind_property ("active", this, "active"); } private void radio_toggled () { @@ -402,9 +413,5 @@ public class Code.FormatBar : Gtk.Box { activate (); } } - - public unowned SList get_radio_group () { - return lang_radio.get_group (); - } } } diff --git a/src/Widgets/GitGutterRenderer.vala b/src/Widgets/GitGutterRenderer.vala index 9e63b4d8b..3e3f12ea5 100644 --- a/src/Widgets/GitGutterRenderer.vala +++ b/src/Widgets/GitGutterRenderer.vala @@ -5,7 +5,7 @@ * Authored by: Jeremy Wootten */ -public class Scratch.Widgets.GitGutterRenderer : Gtk.SourceGutterRenderer { +public class Scratch.Widgets.GitGutterRenderer : GtkSource.GutterRenderer { // These style_ids must be present in the "classic" SourceStyleScheme (or allowed Code SourceStyleSchemes) to avoid terminal spam) public const string ADDED_STYLE_ID = "diff:added-line"; public const string REMOVED_STYLE_ID = "diff:removed-line"; @@ -13,25 +13,24 @@ public class Scratch.Widgets.GitGutterRenderer : Gtk.SourceGutterRenderer { public const string REPLACES_DELETED_STYLE_ID = "diff:special-case"; public const string NONE_STYLE_ID = "background-pattern"; - private static Gtk.SourceStyleScheme? fallback_scheme; + private static GtkSource.StyleScheme? fallback_scheme; public Gee.HashMap line_status_map; public Gee.HashMap status_color_map; public FolderManager.ProjectFolderItem? project { get; set; default = null; } static construct { - fallback_scheme = Gtk.SourceStyleSchemeManager.get_default ().get_scheme ("classic"); // We can assume this always exists + fallback_scheme = GtkSource.StyleSchemeManager.get_default ().get_scheme ("classic"); // We can assume this always exists } construct { line_status_map = new Gee.HashMap (); status_color_map = new Gee.HashMap (); - set_size (5); set_visible (true); } - public void set_style_scheme (Gtk.SourceStyleScheme? scheme) { + public void set_style_scheme (GtkSource.StyleScheme? scheme) { update_status_color_map (Services.VCStatus.ADDED, scheme, ADDED_STYLE_ID); update_status_color_map (Services.VCStatus.REMOVED, scheme, REMOVED_STYLE_ID); update_status_color_map (Services.VCStatus.CHANGED, scheme, CHANGED_STYLE_ID); @@ -40,11 +39,11 @@ public class Scratch.Widgets.GitGutterRenderer : Gtk.SourceGutterRenderer { } private void update_status_color_map (Services.VCStatus status, - Gtk.SourceStyleScheme? scheme, + GtkSource.StyleScheme? scheme, string style_id, bool use_foreground = true) { - Gtk.SourceStyle style = null; + GtkSource.Style style = null; if (scheme != null) { style = scheme.get_style (style_id); if (style != null) { @@ -63,21 +62,39 @@ public class Scratch.Widgets.GitGutterRenderer : Gtk.SourceGutterRenderer { status_color_map.set (status, color); } - public override void draw (Cairo.Context cr, - Gdk.Rectangle bg, - Gdk.Rectangle area, - Gtk.TextIter start, - Gtk.TextIter end, - Gtk.SourceGutterRendererState state) { - + public override void snapshot_line (Gtk.Snapshot snapshot, GtkSource.GutterLines lines, uint line) { + warning ("snapshot_line"); //Gutter and diff lines numbers start at one, source lines start at 0 - var gutter_line_no = start.get_line () + 1; + var gutter_line_no = (int) lines.get_first (); + Gdk.RGBA? color; if (line_status_map.has_key (gutter_line_no)) { - set_background (status_color_map[line_status_map[gutter_line_no]]); + color = status_color_map[line_status_map[gutter_line_no]]; } else { - set_background (status_color_map [Services.VCStatus.NONE]); + color = status_color_map [Services.VCStatus.NONE]; } - base.draw (cr, bg, area, start, end, state); + var rect = Graphene.Rect () { + origin = Graphene.Point () { x = 0.0f, y = 0.0f }, + size = Graphene.Size () { width = 6.0f , height = 12.0f } + }; + snapshot.append_color (color, rect); } + + // public override void draw (Cairo.Context cr, + // Gdk.Rectangle bg, + // Gdk.Rectangle area, + // Gtk.TextIter start, + // Gtk.TextIter end, + // GtkSource.GutterRendererState state) { + + // //Gutter and diff lines numbers start at one, source lines start at 0 + // var gutter_line_no = start.get_line () + 1; + // if (line_status_map.has_key (gutter_line_no)) { + // set_background (status_color_map[line_status_map[gutter_line_no]]); + // } else { + // set_background (status_color_map [Services.VCStatus.NONE]); + // } + + // base.draw (cr, bg, area, start, end, state); + // } } diff --git a/src/Widgets/HeaderBar.vala b/src/Widgets/HeaderBar.vala index 98e69a437..866c067bb 100644 --- a/src/Widgets/HeaderBar.vala +++ b/src/Widgets/HeaderBar.vala @@ -4,8 +4,9 @@ * 2013 Mario Guerriero */ -public class Scratch.HeaderBar : Hdy.HeaderBar { +public class Scratch.HeaderBar : Object { // Plugins segfault without full access + public Gtk.HeaderBar header_bar; public Code.FormatBar format_bar; public GLib.Menu share_menu; public Gtk.MenuButton share_menu_button; @@ -19,17 +20,21 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { private const string STYLE_SCHEME_LIGHT = "elementary-light"; private const string STYLE_SCHEME_DARK = "elementary-dark"; - public HeaderBar () { - Object ( - has_subtitle: false, - show_close_button: true - ); - } + // public HeaderBar () { + // Object ( + // has_subtitle: false, + // show_close_button: true + // ); + // } construct { + header_bar = new Gtk.HeaderBar () { + decoration_layout = ":maximize" + }; + var app_instance = (Gtk.Application) GLib.Application.get_default (); - var open_button = new Gtk.Button.from_icon_name ("document-open", Gtk.IconSize.LARGE_TOOLBAR) { + var open_button = new Gtk.Button.from_icon_name ("document-open") { action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_OPEN }; open_button.tooltip_markup = Granite.markup_accel_tooltip ( @@ -38,7 +43,7 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { ); - var save_button = new Gtk.Button.from_icon_name ("document-save", Gtk.IconSize.LARGE_TOOLBAR) { + var save_button = new Gtk.Button.from_icon_name ("document-save") { action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_SAVE }; save_button.tooltip_markup = Granite.markup_accel_tooltip ( @@ -46,7 +51,7 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { _("Save this file") ); - var save_as_button = new Gtk.Button.from_icon_name ("document-save-as", Gtk.IconSize.LARGE_TOOLBAR) { + var save_as_button = new Gtk.Button.from_icon_name ("document-save-as") { action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_SAVE_AS }; save_as_button.tooltip_markup = Granite.markup_accel_tooltip ( @@ -54,7 +59,7 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { _("Save this file with a different name") ); - var revert_button = new Gtk.Button.from_icon_name ("document-revert", Gtk.IconSize.LARGE_TOOLBAR) { + var revert_button = new Gtk.Button.from_icon_name ("document-revert") { action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_REVERT }; revert_button.tooltip_markup = Granite.markup_accel_tooltip ( @@ -65,13 +70,12 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { share_menu = new GLib.Menu (); share_menu_button = new Gtk.MenuButton () { - image = new Gtk.Image.from_icon_name ("document-export", Gtk.IconSize.LARGE_TOOLBAR), - no_show_all = true, + icon_name = "document-export", menu_model = share_menu, tooltip_text = _("Share") }; - var zoom_out_button = new Gtk.Button.from_icon_name ("zoom-out-symbolic", Gtk.IconSize.MENU) { + var zoom_out_button = new Gtk.Button.from_icon_name ("zoom-out-symbolic") { action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_ZOOM_OUT }; zoom_out_button.tooltip_markup = Granite.markup_accel_tooltip ( @@ -87,7 +91,7 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { _("Zoom 1:1") ); - var zoom_in_button = new Gtk.Button.from_icon_name ("zoom-in-symbolic", Gtk.IconSize.MENU) { + var zoom_in_button = new Gtk.Button.from_icon_name ("zoom-in-symbolic") { action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_ZOOM_IN }; zoom_in_button.tooltip_markup = Granite.markup_accel_tooltip ( @@ -103,21 +107,21 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { margin_bottom = 6, margin_start = 12 }; - font_size_box.get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED); - font_size_box.add (zoom_out_button); - font_size_box.add (zoom_default_button); - font_size_box.add (zoom_in_button); + font_size_box.add_css_class (Granite.STYLE_CLASS_LINKED); + font_size_box.append (zoom_out_button); + font_size_box.append (zoom_default_button); + font_size_box.append (zoom_in_button); find_button = new Gtk.ToggleButton () { action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_TOGGLE_SHOW_FIND, - image = new Gtk.Image.from_icon_name ("edit-find-on-page-symbolic", Gtk.IconSize.MENU) + icon_name = "edit-find-on-page-symbolic" }; find_button.tooltip_markup = Granite.markup_accel_tooltip ( app_instance.get_accels_for_action (MainWindow.ACTION_PREFIX + MainWindow.ACTION_FIND + "::"), _("Find on Page…") ); - var search_button = new Gtk.Button.from_icon_name ("edit-find-symbolic", Gtk.IconSize.MENU) { + var search_button = new Gtk.Button.from_icon_name ("edit-find-symbolic") { action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_FIND_GLOBAL, action_target = new Variant.string ("") }; @@ -133,29 +137,32 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { margin_bottom = 12, margin_start = 12 }; - find_box.get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED); - find_box.add (find_button); - find_box.add (search_button); + find_box.add_css_class (Granite.STYLE_CLASS_LINKED); + find_box.append (find_button); + find_box.append (search_button); var follow_system_switchmodelbutton = new Granite.SwitchModelButton (_("Follow System Style")) { margin_top = 3 }; - // Intentionally never attached so we can have a non-selected state - var color_button_none = new Gtk.RadioButton (null); + // Intentionally never attached so we can have a none selected state + var color_button_none = new Gtk.CheckButton (); - var color_button_white = new Gtk.RadioButton.from_widget (color_button_none) { - halign = Gtk.Align.CENTER + var color_button_white = new Gtk.CheckButton () { + halign = Gtk.Align.CENTER, + group = color_button_none }; style_color_button (color_button_white, STYLE_SCHEME_HIGH_CONTRAST); - var color_button_light = new Gtk.RadioButton.from_widget (color_button_none) { - halign = Gtk.Align.CENTER + var color_button_light = new Gtk.CheckButton () { + halign = Gtk.Align.CENTER, + group = color_button_none }; style_color_button (color_button_light, STYLE_SCHEME_LIGHT); - var color_button_dark = new Gtk.RadioButton.from_widget (color_button_none) { - halign = Gtk.Align.CENTER + var color_button_dark = new Gtk.CheckButton () { + halign = Gtk.Align.CENTER, + group = color_button_none }; style_color_button (color_button_dark, STYLE_SCHEME_DARK); @@ -164,12 +171,12 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { margin_top = 6, margin_bottom = 6 }; - color_box.add (color_button_white); - color_box.add (color_button_light); - color_box.add (color_button_dark); + color_box.append (color_button_white); + color_box.append (color_button_light); + color_box.append (color_button_dark); var color_revealer = new Gtk.Revealer (); - color_revealer.add (color_box); + color_revealer.child = color_box; var menu_separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL) { margin_bottom = 3, @@ -178,12 +185,12 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { sidebar_button = new Gtk.ToggleButton () { action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_TOGGLE_SIDEBAR, - image = new Gtk.Image.from_icon_name ("panel-left-symbolic", Gtk.IconSize.MENU) + icon_name = "panel-left-symbolic" }; terminal_button = new Gtk.ToggleButton () { action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_TOGGLE_TERMINAL, - image = new Gtk.Image.from_icon_name ("panel-bottom-symbolic", Gtk.IconSize.MENU) + icon_name = "panel-bottom-symbolic" }; terminal_button.tooltip_markup = Granite.markup_accel_tooltip ( app_instance.get_accels_for_action (terminal_button.action_name), @@ -192,7 +199,7 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { outline_button = new Gtk.ToggleButton () { action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_TOGGLE_OUTLINE, - image = new Gtk.Image.from_icon_name ("panel-right-symbolic", Gtk.IconSize.MENU) + icon_name = "panel-right-symbolic" }; var panels_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) { @@ -202,54 +209,52 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { margin_bottom = 6, margin_start = 12 }; - panels_box.get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED); - panels_box.add (sidebar_button); - panels_box.add (terminal_button); - panels_box.add (outline_button); - - var preferences_menuitem = new Gtk.ModelButton () { - action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_PREFERENCES, - text = _("Preferences") + panels_box.add_css_class (Granite.STYLE_CLASS_LINKED); + panels_box.append (sidebar_button); + panels_box.append (terminal_button); + panels_box.append (outline_button); + + var preferences_menuitem = new Gtk.Button.with_label (_("Preferences")) { + action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_PREFERENCES }; var menu_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0) { margin_bottom = 3 }; - menu_box.add (font_size_box); - menu_box.add (find_box); - menu_box.add (new Gtk.Separator (Gtk.Orientation.HORIZONTAL)); - menu_box.add (follow_system_switchmodelbutton); - menu_box.add (color_revealer); - menu_box.add (panels_box); - menu_box.add (menu_separator); - menu_box.add (preferences_menuitem); - menu_box.show_all (); - - var menu = new Gtk.Popover (null); - menu.add (menu_box); + menu_box.append (font_size_box); + menu_box.append (find_box); + menu_box.append (new Gtk.Separator (Gtk.Orientation.HORIZONTAL)); + menu_box.append (follow_system_switchmodelbutton); + menu_box.append (color_revealer); + menu_box.append (panels_box); + menu_box.append (menu_separator); + menu_box.append (preferences_menuitem); + + var menu = new Gtk.Popover () { + child = menu_box + }; var app_menu = new Gtk.MenuButton () { - image = new Gtk.Image.from_icon_name ("open-menu", Gtk.IconSize.LARGE_TOOLBAR), + icon_name = "open-menu", popover = menu, tooltip_text = _("Menu") }; format_bar = new Code.FormatBar () { - no_show_all = true, valign = Gtk.Align.CENTER }; - set_custom_title (format_bar); - pack_start (open_button); - pack_start (save_button); - pack_start (save_as_button); - pack_start (revert_button); - pack_end (app_menu); - pack_end (share_menu_button); + header_bar.title_widget = format_bar; + header_bar.pack_start (open_button); + header_bar.pack_start (save_button); + header_bar.pack_start (save_as_button); + header_bar.pack_start (revert_button); + header_bar.pack_end (app_menu); + header_bar.pack_end (share_menu_button); share_menu.items_changed.connect (on_share_menu_changed); - realize.connect (() => { + header_bar.realize.connect (() => { save_button.visible = !Scratch.settings.get_boolean ("autosave"); }); @@ -294,31 +299,37 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { color_button_none.active = true; } - color_button_dark.clicked.connect (() => { - Scratch.settings.set_boolean ("prefer-dark-style", true); - Scratch.settings.set_string ("style-scheme", STYLE_SCHEME_DARK); - gtk_settings.gtk_application_prefer_dark_theme = true; + color_button_dark.toggled.connect (() => { + if (color_button_dark.active) { + Scratch.settings.set_boolean ("prefer-dark-style", true); + Scratch.settings.set_string ("style-scheme", STYLE_SCHEME_DARK); + gtk_settings.gtk_application_prefer_dark_theme = true; + } }); - color_button_light.clicked.connect (() => { - Scratch.settings.set_boolean ("prefer-dark-style", false); - Scratch.settings.set_string ("style-scheme", STYLE_SCHEME_LIGHT); - gtk_settings.gtk_application_prefer_dark_theme = false; + color_button_light.toggled.connect (() => { + if (color_button_light.active) { + Scratch.settings.set_boolean ("prefer-dark-style", false); + Scratch.settings.set_string ("style-scheme", STYLE_SCHEME_LIGHT); + gtk_settings.gtk_application_prefer_dark_theme = false; + } }); - color_button_white.clicked.connect (() => { - Scratch.settings.set_boolean ("prefer-dark-style", false); - Scratch.settings.set_string ("style-scheme", STYLE_SCHEME_HIGH_CONTRAST); - gtk_settings.gtk_application_prefer_dark_theme = false; + color_button_white.toggled.connect (() => { + if (color_button_white.active) { + Scratch.settings.set_boolean ("prefer-dark-style", false); + Scratch.settings.set_string ("style-scheme", STYLE_SCHEME_HIGH_CONTRAST); + gtk_settings.gtk_application_prefer_dark_theme = false; + } }); } - private void style_color_button (Gtk.ToggleButton color_button, string style_id) { + private void style_color_button (Gtk.CheckButton color_button, string style_id) { var background = ""; var foreground = ""; - Gtk.SourceStyleScheme? scheme = null; - var sssm = Gtk.SourceStyleSchemeManager.get_default (); + GtkSource.StyleScheme? scheme = null; + var sssm = GtkSource.StyleSchemeManager.get_default (); if (style_id in sssm.scheme_ids) { scheme = sssm.get_scheme (style_id); // We currently ship and hard-code the style schemes so can assume the "text" key @@ -368,16 +379,10 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { """.printf (background, foreground); var css_provider = new Gtk.CssProvider (); + css_provider.load_from_string (style_css); - try { - css_provider.load_from_data (style_css); - } catch (Error e) { - critical ("Unable to style color button: %s", e.message); - } - - unowned var style_context = color_button.get_style_context (); - style_context.add_class (Granite.STYLE_CLASS_COLOR_BUTTON); - style_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); + color_button.add_css_class (Granite.STYLE_CLASS_COLOR_BUTTON); + Gtk.StyleContext.add_provider_for_display (Gdk.Display.get_default (), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); color_button.tooltip_text = scheme.name; } else if (scheme != null || background == "" || foreground == "") { //Fallback to standard radio buttons (should not happen) @@ -399,11 +404,8 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { private void on_share_menu_changed () { if (share_menu.get_n_items () > 0) { - share_menu_button.no_show_all = false; share_menu_button.visible = true; - share_menu_button.show_all (); } else { - share_menu_button.no_show_all = true; share_menu_button.visible = false; share_menu_button.hide (); } @@ -411,10 +413,7 @@ public class Scratch.HeaderBar : Hdy.HeaderBar { public void document_available (bool has_document) { if (has_document) { - format_bar.no_show_all = false; - format_bar.show_all (); } else { - format_bar.no_show_all = true; format_bar.hide (); } } diff --git a/src/Widgets/NavMarkGutterRenderer.vala b/src/Widgets/NavMarkGutterRenderer.vala index 9ceb9a88b..6fad44461 100644 --- a/src/Widgets/NavMarkGutterRenderer.vala +++ b/src/Widgets/NavMarkGutterRenderer.vala @@ -1,4 +1,4 @@ -public class Scratch.Widgets.NavMarkGutterRenderer : Gtk.SourceGutterRendererPixbuf { +public class Scratch.Widgets.NavMarkGutterRenderer : GtkSource.GutterRendererPixbuf { static int navmark_number = 0; static int get_next_navmark_number () { return navmark_number++; @@ -22,7 +22,6 @@ public class Scratch.Widgets.NavMarkGutterRenderer : Gtk.SourceGutterRendererPix construct { mark_list = new Gee.ArrayList (); sorted_line_list = new Gee.ArrayList (); - set_size (16); set_visible (true); } @@ -127,20 +126,33 @@ public class Scratch.Widgets.NavMarkGutterRenderer : Gtk.SourceGutterRendererPix queue_draw (); } - public override void query_data ( - Gtk.TextIter start, - Gtk.TextIter end, - Gtk.SourceGutterRendererState state - ) { - var line = start.get_line (); - if (sorted_line_list.contains (line)) { + public override void query_data (Object lines, uint line) { + if (sorted_line_list.contains ((int) line)) { icon_name = "edit-symbolic"; } else { icon_name = ""; } } - - public override void activate (Gtk.TextIter iter, Gdk.Rectangle rect, Gdk.Event event) { + // public override void query_data ( + // Gtk.TextIter start, + // Gtk.TextIter end, + // GtkSource.GutterRendererState state + // ) { + // var line = start.get_line (); + // if (sorted_line_list.contains (line)) { + // icon_name = "edit-symbolic"; + // } else { + // icon_name = ""; + // } + // } + + public override void activate ( + Gtk.TextIter iter, + Gdk.Rectangle rect, + uint button, + Gdk.ModifierType state, + int n_presses + ) { if (has_mark_at_line (iter.get_line ())) { delete_mark_at_line (iter.get_line ()); } else { @@ -150,7 +162,7 @@ public class Scratch.Widgets.NavMarkGutterRenderer : Gtk.SourceGutterRendererPix queue_draw (); } - public override bool query_activatable (Gtk.TextIter iter, Gdk.Rectangle rect, Gdk.Event event) { + public override bool query_activatable (Gtk.TextIter iter, Gdk.Rectangle rect) { return true; } } diff --git a/src/Widgets/PopoverMenuItem.vala b/src/Widgets/PopoverMenuItem.vala index e9b15cd5f..09ca427e1 100644 --- a/src/Widgets/PopoverMenuItem.vala +++ b/src/Widgets/PopoverMenuItem.vala @@ -28,12 +28,12 @@ public class Code.PopoverMenuItem : Gtk.Button { var label = new Granite.AccelLabel (text); var box = new Gtk.Box (HORIZONTAL, 6); - box.add (image); - box.add (label); + box.append (image); + box.append (label); child = box; - get_accessible ().accessible_role = MENU_ITEM; + set_accessible_role (MENU_ITEM); clicked.connect (() => { var popover = (Gtk.Popover) get_ancestor (typeof (Gtk.Popover)); diff --git a/src/Widgets/SearchBar.vala b/src/Widgets/SearchBar.vala index 5ddc74d77..8f5ddd06b 100644 --- a/src/Widgets/SearchBar.vala +++ b/src/Widgets/SearchBar.vala @@ -44,16 +44,18 @@ namespace Scratch.Widgets { private Granite.SwitchModelButton regex_search_button; private Granite.SwitchModelButton whole_word_search_button; private Gtk.SearchEntry search_entry; - private Gtk.SearchEntry replace_entry; + private Gtk.Entry entry_for_search; + private Gtk.SearchEntry replace_search_entry; + private Gtk.Entry entry_for_replace; private Gtk.Label search_occurence_count_label; private Gtk.Button replace_tool_button; private Gtk.Button replace_all_tool_button; private Scratch.Widgets.SourceView? text_view = null; private Gtk.TextBuffer? text_buffer = null; - private Gtk.SourceSearchContext? search_context; + private GtkSource.SearchContext? search_context; private uint update_search_label_timeout_id = 0; private Gtk.Revealer revealer; - private Gtk.EventControllerKey key_controller; + // private Gtk.EventControllerKey key_controller; public bool is_focused { get { @@ -63,13 +65,13 @@ namespace Scratch.Widgets { public bool search_is_focused { get { - return search_entry.has_focus; + return entry_for_search.has_focus; } } public bool replace_is_focused { get { - return replace_entry.has_focus; + return entry_for_replace.has_focus; } } @@ -81,13 +83,13 @@ namespace Scratch.Widgets { public string entry_text { get { - return search_entry.text; + return entry_for_search.text; } } public bool has_search_term { get { - return search_entry.text != ""; + return entry_for_search.text != ""; } } @@ -115,17 +117,22 @@ namespace Scratch.Widgets { construct { this.orientation = HORIZONTAL; + search_entry = new Gtk.SearchEntry () { hexpand = true, - placeholder_text = _("Find") + placeholder_text = _("Find"), }; + entry_for_search = new Gtk.Entry (); + entry_for_search.set_parent (search_entry); + + search_entry.set_key_capture_widget (entry_for_search); search_occurence_count_label = new Gtk.Label (_("No Results")); - search_occurence_count_label.get_style_context ().add_class (Granite.STYLE_CLASS_SMALL_LABEL); + search_occurence_count_label.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL); var app_instance = (Scratch.Application) GLib.Application.get_default (); - tool_arrow_down = new Gtk.Button.from_icon_name ("go-down-symbolic", Gtk.IconSize.SMALL_TOOLBAR); + tool_arrow_down = new Gtk.Button.from_icon_name ("go-down-symbolic"); tool_arrow_down.clicked.connect (search_next); tool_arrow_down.sensitive = false; tool_arrow_down.tooltip_markup = Granite.markup_accel_tooltip ( @@ -135,7 +142,7 @@ namespace Scratch.Widgets { _("Search next") ); - tool_arrow_up = new Gtk.Button.from_icon_name ("go-up-symbolic", Gtk.IconSize.SMALL_TOOLBAR); + tool_arrow_up = new Gtk.Button.from_icon_name ("go-up-symbolic"); tool_arrow_up.clicked.connect (search_previous); tool_arrow_up.sensitive = false; tool_arrow_up.tooltip_markup = Granite.markup_accel_tooltip ( @@ -156,9 +163,9 @@ namespace Scratch.Widgets { var case_sensitive_search_label = new Gtk.Label (_("Case Sensitive")); var case_sensitive_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 12); - case_sensitive_box.add (case_sensitive_search_label); - case_sensitive_box.add (case_sensitive_search_button); - case_sensitive_box.get_style_context ().add_class (Gtk.STYLE_CLASS_MENUITEM); + case_sensitive_box.append (case_sensitive_search_label); + case_sensitive_box.append (case_sensitive_search_button); + case_sensitive_box.add_css_class (Granite.STYLE_CLASS_MENUITEM); regex_search_button = new Granite.SwitchModelButton (_("Use Regular Expressions")); whole_word_search_button = new Granite.SwitchModelButton (_("Match Whole Words")); @@ -167,24 +174,23 @@ namespace Scratch.Widgets { margin_top = 3, margin_bottom = 3 }; - search_option_box.add (cycle_search_button); - search_option_box.add (case_sensitive_box); - search_option_box.add (whole_word_search_button); - search_option_box.add (regex_search_button); - - var search_popover = new Gtk.Popover (null); - search_popover.add (search_option_box); - search_popover.show_all (); + search_option_box.append (cycle_search_button); + search_option_box.append (case_sensitive_box); + search_option_box.append (whole_word_search_button); + search_option_box.append (regex_search_button); + var search_popover = new Gtk.Popover () { + child = search_option_box + }; var search_buttonbox = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6); - search_buttonbox.add (search_occurence_count_label); - search_buttonbox.add (new Gtk.Image.from_icon_name ("pan-down-symbolic", Gtk.IconSize.SMALL_TOOLBAR)); + search_buttonbox.append (search_occurence_count_label); + search_buttonbox.append (new Gtk.Image.from_icon_name ("pan-down-symbolic")); var search_menubutton = new Gtk.MenuButton () { popover = search_popover, - tooltip_text = _("Search Options") + tooltip_text = _("Search Options"), + child = search_buttonbox }; - search_menubutton.add (search_buttonbox); cycle_search_button.toggled.connect (on_search_parameters_changed); case_sensitive_search_button.changed.connect (on_search_parameters_changed); @@ -207,81 +213,91 @@ namespace Scratch.Widgets { margin_bottom = 3, margin_start = 6 }; - search_box.get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED); - search_box.add (search_entry); - search_box.add (tool_arrow_down); - search_box.add (tool_arrow_up); - search_box.add (search_menubutton); + search_box.add_css_class (Granite.STYLE_CLASS_LINKED); + search_box.append (search_entry); + search_box.append (tool_arrow_down); + search_box.append (tool_arrow_up); + search_box.append (search_menubutton); var search_flow_box_child = new Gtk.FlowBoxChild (); search_flow_box_child.can_focus = false; - search_flow_box_child.add (search_box); + search_flow_box_child.child = search_box; + - replace_entry = new Gtk.SearchEntry (); - replace_entry.hexpand = true; - replace_entry.placeholder_text = _("Replace With"); - replace_entry.set_icon_from_icon_name (Gtk.EntryIconPosition.PRIMARY, "edit-symbolic"); + replace_search_entry = new Gtk.SearchEntry () { + hexpand = true, + placeholder_text = _("Replace With") + }; + entry_for_replace = new Gtk.Entry (); + entry_for_replace.set_parent (replace_search_entry); + entry_for_replace.set_icon_from_icon_name (Gtk.EntryIconPosition.PRIMARY, "edit-symbolic"); replace_tool_button = new Gtk.Button.with_label (_("Replace")); - replace_tool_button.clicked.connect (on_replace_entry_activate); + replace_tool_button.clicked.connect (on_replace_search_entry_activate); replace_all_tool_button = new Gtk.Button.with_label (_("Replace all")); replace_all_tool_button.clicked.connect (on_replace_all_entry_activate); - var replace_grid = new Gtk.Grid () { + var replace_grid = new Gtk.Box (HORIZONTAL, 0) { margin_top = 3, margin_end = 6, margin_bottom = 3, margin_start = 3 }; - replace_grid.get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED); - replace_grid.add (replace_entry); - replace_grid.add (replace_tool_button); - replace_grid.add (replace_all_tool_button); + replace_grid.add_css_class (Granite.STYLE_CLASS_LINKED); + replace_grid.append (replace_search_entry); + replace_grid.append (replace_tool_button); + replace_grid.append (replace_all_tool_button); var replace_flow_box_child = new Gtk.FlowBoxChild (); replace_flow_box_child.can_focus = false; - replace_flow_box_child.add (replace_grid); + replace_flow_box_child.child = replace_grid; // Connecting to some signals - search_entry.changed.connect (on_search_parameters_changed); + search_entry.search_changed.connect (on_search_parameters_changed); - search_entry.notify["is-focus"].connect (() => { - if (search_entry.is_focus && text_buffer != null) { + var search_focus_controller = new Gtk.EventControllerFocus (); + entry_for_search.add_controller (search_focus_controller); + search_focus_controller.enter.connect (() => { + if (search_focus_controller.is_focus && text_buffer != null) { Idle.add (() => { update_search_widgets (); - search_entry.select_region (0, -1); + entry_for_search.select_region (0, -1); return Source.REMOVE; }); } }); - search_entry.icon_release.connect ((p0, p1) => { - if (p0 == Gtk.EntryIconPosition.PRIMARY) { + + entry_for_search.icon_release.connect ((icon_pos) => { + if (icon_pos == Gtk.EntryIconPosition.PRIMARY) { search_next (); } }); - replace_entry.activate.connect (on_replace_entry_activate); + + replace_search_entry.activate.connect (on_replace_search_entry_activate); var flowbox = new Gtk.FlowBox () { selection_mode = Gtk.SelectionMode.NONE, column_spacing = 6, max_children_per_line = 2 }; - flowbox.get_style_context ().add_class ("search-bar"); - flowbox.add (search_flow_box_child); - flowbox.add (replace_flow_box_child); + flowbox.add_css_class ("search-bar"); + flowbox.append (search_flow_box_child); + flowbox.append (replace_flow_box_child); revealer = new Gtk.Revealer () { child = flowbox, reveal_child = false }; - add (revealer); + append (revealer); update_search_widgets (); - key_controller = new Gtk.EventControllerKey (window) { + var key_controller = new Gtk.EventControllerKey () { propagation_phase = CAPTURE }; + //TODO Use ShortcutController? + ((Gtk.Widget)window).add_controller (key_controller); key_controller.key_pressed.connect (on_key_pressed); } @@ -304,7 +320,7 @@ namespace Scratch.Widgets { this.text_view = text_view; this.text_buffer = text_view.get_buffer (); this.text_buffer.changed.connect (on_text_buffer_changed); - this.search_context = new Gtk.SourceSearchContext (text_buffer as Gtk.SourceBuffer, null); + this.search_context = new GtkSource.SearchContext (text_buffer as GtkSource.Buffer, null); search_context.settings.wrap_around = cycle_search_button.active; search_context.settings.regex_enabled = regex_search_button.active; search_context.settings.search_text = search_entry.text; @@ -315,7 +331,7 @@ namespace Scratch.Widgets { update_search_widgets (); } - private void on_replace_entry_activate () { + private void on_replace_search_entry_activate () { if (text_buffer == null) { warning ("No valid buffer to replace"); return; @@ -325,12 +341,12 @@ namespace Scratch.Widgets { text_buffer.get_iter_at_offset (out start_iter, text_buffer.cursor_position); if (search_for_iter (start_iter, out end_iter)) { - string replace_string = replace_entry.text; + string replace_string = replace_search_entry.text; try { cancel_update_search_widgets (); search_context.replace (start_iter, end_iter, replace_string, replace_string.length); update_search_widgets (); - debug ("Replaced \"%s\" with \"%s\"", search_entry.text, replace_entry.text); + debug ("Replaced \"%s\" with \"%s\"", search_entry.text, replace_search_entry.text); } catch (Error e) { critical (e.message); } @@ -343,7 +359,7 @@ namespace Scratch.Widgets { return; } - string replace_string = replace_entry.text; + string replace_string = replace_search_entry.text; this.window.get_current_document ().toggle_changed_handlers (false); try { cancel_update_search_widgets (); @@ -402,19 +418,19 @@ namespace Scratch.Widgets { text_buffer.get_iter_at_offset (out start_iter, text_buffer.cursor_position); if (search_for_iter (start_iter, out end_iter)) { - search_entry.get_style_context ().remove_class (Gtk.STYLE_CLASS_ERROR); - search_entry.primary_icon_name = "edit-find-symbolic"; + entry_for_search.remove_css_class (Granite.STYLE_CLASS_ERROR); + entry_for_search.primary_icon_name = "edit-find-symbolic"; } else { text_buffer.get_start_iter (out start_iter); if (search_for_iter (start_iter, out end_iter)) { - search_entry.get_style_context ().remove_class (Gtk.STYLE_CLASS_ERROR); - search_entry.primary_icon_name = "edit-find-symbolic"; + entry_for_search.remove_css_class (Granite.STYLE_CLASS_ERROR); + entry_for_search.primary_icon_name = "edit-find-symbolic"; } else { debug ("Not found: \"%s\"", search_entry.text); start_iter.set_offset (-1); text_buffer.select_range (start_iter, start_iter); - search_entry.get_style_context ().add_class (Gtk.STYLE_CLASS_ERROR); - search_entry.primary_icon_name = "dialog-error-symbolic"; + entry_for_search.add_css_class (Granite.STYLE_CLASS_ERROR); + entry_for_search.primary_icon_name = "dialog-error-symbolic"; return false; } } @@ -513,11 +529,11 @@ namespace Scratch.Widgets { } public void focus_search_entry () { - search_entry.grab_focus (); + entry_for_search.grab_focus (); } public void focus_replace_entry () { - replace_entry.grab_focus (); + entry_for_replace.grab_focus (); } public void reveal (bool to_reveal) { @@ -668,14 +684,12 @@ namespace Scratch.Widgets { } // Update appearance of search entry - var ctx = search_entry.get_style_context (); - - if (search_entry.text != "" && count_of_search == 0) { - ctx.add_class (Gtk.STYLE_CLASS_ERROR); - search_entry.primary_icon_name = "dialog-error-symbolic"; - } else if (ctx.has_class (Gtk.STYLE_CLASS_ERROR)) { - ctx.remove_class (Gtk.STYLE_CLASS_ERROR); - search_entry.primary_icon_name = "edit-find-symbolic"; + if (entry_for_search.text != "" && count_of_search == 0) { + entry_for_search.add_css_class (Granite.STYLE_CLASS_ERROR); + entry_for_search.primary_icon_name = "dialog-error-symbolic"; + } else if (entry_for_search.has_css_class (Granite.STYLE_CLASS_ERROR)) { + entry_for_search.remove_css_class (Granite.STYLE_CLASS_ERROR); + entry_for_search.primary_icon_name = "edit-find-symbolic"; } return Source.REMOVE; diff --git a/src/Widgets/Sidebar.vala b/src/Widgets/Sidebar.vala index 3bbaca899..500cec687 100644 --- a/src/Widgets/Sidebar.vala +++ b/src/Widgets/Sidebar.vala @@ -17,7 +17,7 @@ * Authored by: Corentin Noël */ -public class Code.Sidebar : Gtk.Grid { +public class Code.Sidebar : Gtk.Box { public enum TargetType { URI_LIST } @@ -26,7 +26,7 @@ public class Code.Sidebar : Gtk.Grid { public const string SIDEBAR_ACTION_PREFIX = SIDEBAR_ACTION_GROUP + "."; public Gtk.Stack stack { get; private set; } public Code.ChooseProjectButton choose_project_button { get; private set; } - public Hdy.HeaderBar headerbar { get; private set; } + public Adw.HeaderBar headerbar { get; private set; } public GLib.MenuModel project_menu_model { get; construct; } // May show progress in different way in future public bool cloning_in_progress { @@ -40,27 +40,27 @@ public class Code.Sidebar : Gtk.Grid { } private Gtk.StackSwitcher stack_switcher; - private Granite.Widgets.Toast cloning_success_toast; + private Granite.Toast cloning_success_toast; construct { orientation = Gtk.Orientation.VERTICAL; - get_style_context ().add_class (Gtk.STYLE_CLASS_SIDEBAR); + add_css_class (Granite.STYLE_CLASS_SIDEBAR); choose_project_button = new Code.ChooseProjectButton () { hexpand = true, valign = Gtk.Align.CENTER }; - cloning_success_toast = new Granite.Widgets.Toast (_("Cloning complete")) { + cloning_success_toast = new Granite.Toast (_("Cloning complete")) { halign = CENTER, valign = START }; - headerbar = new Hdy.HeaderBar () { - custom_title = choose_project_button, - show_close_button = true + headerbar = new Adw.HeaderBar () { + title_widget = choose_project_button, + decoration_layout = "close:" }; - headerbar.get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT); + headerbar.add_css_class (Granite.STYLE_CLASS_FLAT); stack = new Gtk.Stack (); stack.transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT; @@ -71,13 +71,11 @@ public class Code.Sidebar : Gtk.Grid { overlay.add_overlay (cloning_success_toast); stack_switcher = new Gtk.StackSwitcher (); - stack_switcher.no_show_all = true; stack_switcher.visible = false; stack_switcher.stack = stack; - stack_switcher.homogeneous = true; var actionbar = new Gtk.ActionBar (); - actionbar.get_style_context ().add_class (Gtk.STYLE_CLASS_INLINE_TOOLBAR); + actionbar.add_css_class (Granite.STYLE_CLASS_FLAT); var collapse_all_menu_item = new GLib.MenuItem (_("Collapse All"), Scratch.MainWindow.ACTION_PREFIX + Scratch.MainWindow.ACTION_COLLAPSE_ALL_FOLDERS); @@ -102,88 +100,72 @@ public class Code.Sidebar : Gtk.Grid { }; var project_menu_button = new Gtk.MenuButton () { hexpand = true, - use_popover = false, menu_model = project_menu_model, child = label }; actionbar.pack_start (project_menu_button); - add (headerbar); - add (stack_switcher); - add (overlay); - add (actionbar); + append (headerbar); + append (stack_switcher); + append (overlay); + append (actionbar); - stack.add.connect (() => { - if (stack.get_children ().length () > 1) { - stack_switcher.no_show_all = false; - stack_switcher.show_all (); - } + // stack.remove.connect (() => { - stack.no_show_all = false; - stack.show_all (); - }); + // }); - Gtk.TargetEntry uris = {"text/uri-list", 0, TargetType.URI_LIST}; - Gtk.drag_dest_set (this, Gtk.DestDefaults.ALL, {uris}, Gdk.DragAction.COPY); - drag_data_received.connect (drag_received); + // Gtk.TargetEntry uris = {"text/uri-list", 0, TargetType.URI_LIST}; + // Gtk.drag_dest_set (this, Gtk.DestDefaults.ALL, {uris}, Gdk.DragAction.COPY); + // drag_data_received.connect (drag_received); } - private void drag_received (Gtk.Widget w, - Gdk.DragContext ctx, - int x, - int y, - Gtk.SelectionData sel, - uint info, - uint time) { - - if (info == TargetType.URI_LIST) { - var uri_list = sel.get_uris (); - GLib.List folder_list = null; - foreach (unowned var uri in uri_list) { - var file = GLib.File.new_for_uri (uri); - // Blocking but for simplicity omit cancellable for now - var ftype = file.query_file_type (FileQueryInfoFlags.NOFOLLOW_SYMLINKS); - if (ftype == GLib.FileType.DIRECTORY) { - folder_list.prepend (file); - } - } - - foreach (var folder in folder_list) { - var win_group = get_action_group (Scratch.MainWindow.ACTION_GROUP); - win_group.activate_action ( - Scratch.MainWindow.ACTION_OPEN_FOLDER, - new Variant.string (folder.get_path ()) - ); - } - - Gtk.drag_finish (ctx, folder_list.length () > 0, false, time); - } - } + // private void drag_received (Gtk.Widget w, + // Gdk.DragContext ctx, + // int x, + // int y, + // Gtk.SelectionData sel, + // uint info, + // uint time) { + + // if (info == TargetType.URI_LIST) { + // var uri_list = sel.get_uris (); + // GLib.List folder_list = null; + // foreach (unowned var uri in uri_list) { + // var file = GLib.File.new_for_uri (uri); + // // Blocking but for simplicity omit cancellable for now + // var ftype = file.query_file_type (FileQueryInfoFlags.NOFOLLOW_SYMLINKS); + // if (ftype == GLib.FileType.DIRECTORY) { + // folder_list.prepend (file); + // } + // } + + // foreach (var folder in folder_list) { + // activate_action ( + // Scratch.MainWindow.ACTION_PREFIX + Scratch.MainWindow.ACTION_OPEN_FOLDER, + // "s", + // folder.get_path () + // ); + // } + + // Gtk.drag_finish (ctx, folder_list.length () > 0, false, time); + // } + // } public void add_tab (Code.PaneSwitcher tab) { - stack.add (tab); - stack.child_set_property (tab, "title", tab.title); - stack.child_set_property (tab, "icon-name", tab.icon_name); - - tab.notify["title"].connect (() => { - stack.child_set_property (tab, "title", tab.title); - }); - - tab.notify["icon-name"].connect (() => { - stack.child_set_property (tab, "icon-name", tab.icon_name); - }); + stack.add_child (tab); + var page = stack.get_page (tab); + tab.bind_property ("title", page, "title", DEFAULT | SYNC_CREATE); + tab.bind_property ("icon-name", page, "icon-name", DEFAULT | SYNC_CREATE); } public void remove_tab (Code.PaneSwitcher tab) { stack.remove (tab); - switch (stack.get_children ().length ()) { + switch (stack.pages.get_n_items ()) { case 0: - stack.no_show_all = true; stack.hide (); break; case 1: - stack_switcher.no_show_all = true; stack_switcher.hide (); break; } diff --git a/src/Widgets/SourceList/CellRendererBadge.vala b/src/Widgets/SourceList/CellRendererBadge.vala index 4117e0b47..6e71c1ac6 100644 --- a/src/Widgets/SourceList/CellRendererBadge.vala +++ b/src/Widgets/SourceList/CellRendererBadge.vala @@ -70,11 +70,11 @@ public class Code.Widgets.CellRendererBadge : Gtk.CellRenderer { // This is needed in order to fetch the proper style information. ctx.add_class (Granite.STYLE_CLASS_BADGE); - var state = ctx.get_state (); + // var state = ctx.get_state (); - margin = ctx.get_margin (state); - padding = ctx.get_padding (state); - border = ctx.get_border (state); + margin = ctx.get_margin (); + padding = ctx.get_padding (); + border = ctx.get_border (); text_layout = widget.create_pango_layout (text); @@ -84,13 +84,15 @@ public class Code.Widgets.CellRendererBadge : Gtk.CellRenderer { text_layout.get_pixel_extents (out ink_rect, out text_logical_rect); } - public override void render ( - Cairo.Context context, + public override void snapshot ( + Gtk.Snapshot snapshot, Gtk.Widget widget, Gdk.Rectangle bg_area, Gdk.Rectangle cell_area, Gtk.CellRendererState flags ) { + + warning ("snapshot badge"); update_layout_properties (widget); Gdk.Rectangle aligned_area = get_aligned_area (widget, flags, cell_area); @@ -106,11 +108,7 @@ public class Code.Widgets.CellRendererBadge : Gtk.CellRenderer { width -= margin.left + margin.right; height -= margin.top + margin.bottom; - var ctx = widget.get_style_context (); - ctx.add_class (Granite.STYLE_CLASS_BADGE); - - ctx.render_background (context, x, y, width, height); - ctx.render_frame (context, x, y, width, height); + widget.add_css_class (Granite.STYLE_CLASS_BADGE); //TODO Use CSS for frame and background // Apply border width and padding offsets x += border.right + padding.right; @@ -122,6 +120,6 @@ public class Code.Widgets.CellRendererBadge : Gtk.CellRenderer { x += text_logical_rect.x + (width - text_logical_rect.width) / 2; y += text_logical_rect.y + (height - text_logical_rect.height) / 2; - ctx.render_layout (context, x, y, text_layout); + snapshot.append_layout (text_layout, widget.get_color ()); } } diff --git a/src/Widgets/SourceList/CellRendererExpander.vala b/src/Widgets/SourceList/CellRendererExpander.vala index 82f676670..8ad49ee15 100644 --- a/src/Widgets/SourceList/CellRendererExpander.vala +++ b/src/Widgets/SourceList/CellRendererExpander.vala @@ -54,49 +54,58 @@ public class Code.Widgets.CellRendererExpander : Gtk.CellRenderer { * @since 0.2 */ public virtual int get_arrow_size (Gtk.Widget widget) { - int arrow_size; - widget.style_get ("expander-size", out arrow_size); - return arrow_size; + return 12; } - public override void render ( - Cairo.Context context, - Gtk.Widget widget, - Gdk.Rectangle bg_area, - Gdk.Rectangle cell_area, - Gtk.CellRendererState flags - ) { - if (!is_expander) { - return; - } + // public override void snapshot ( + // Gtk.Snapshot snapshot, + // Gtk.Widget widget, + // Gdk.Rectangle bg_area, + // Gdk.Rectangle cell_area, + // Gtk.CellRendererState flags + // ) { + // // No simple replacement for render_expander so leave for now + // // Renderers to be replaced with TreeListModel and TreeExpanders etc + // } - unowned Gtk.StyleContext ctx = apply_style_changes (widget); + // public override void render ( + // Cairo.Context context, + // Gtk.Widget widget, + // Gdk.Rectangle bg_area, + // Gdk.Rectangle cell_area, + // Gtk.CellRendererState flags + // ) { + // if (!is_expander) { + // return; + // } - Gdk.Rectangle aligned_area = get_aligned_area (widget, flags, cell_area); + // unowned Gtk.StyleContext ctx = apply_style_changes (widget); - int arrow_size = int.min (get_arrow_size (widget), aligned_area.width); + // Gdk.Rectangle aligned_area = get_aligned_area (widget, flags, cell_area); - int offset = arrow_size / 2; - int x = aligned_area.x + aligned_area.width / 2 - offset; - int y = aligned_area.y + aligned_area.height / 2 - offset; + // int arrow_size = int.min (get_arrow_size (widget), aligned_area.width); - var state = ctx.get_state (); - const Gtk.StateFlags EXPANDED_FLAG = Gtk.StateFlags.CHECKED; - ctx.set_state (is_expanded ? state | EXPANDED_FLAG : state & ~EXPANDED_FLAG); + // int offset = arrow_size / 2; + // int x = aligned_area.x + aligned_area.width / 2 - offset; + // int y = aligned_area.y + aligned_area.height / 2 - offset; - ctx.render_expander (context, x, y, arrow_size, arrow_size); + // var state = ctx.get_state (); + // const Gtk.StateFlags EXPANDED_FLAG = Gtk.StateFlags.CHECKED; + // ctx.set_state (is_expanded ? state | EXPANDED_FLAG : state & ~EXPANDED_FLAG); - revert_style_changes (widget); - } + // ctx.render_expander (context, x, y, arrow_size, arrow_size); + + // revert_style_changes (widget); + // } private unowned Gtk.StyleContext apply_style_changes (Gtk.Widget widget) { unowned Gtk.StyleContext ctx = widget.get_style_context (); ctx.save (); if (is_category_expander) - ctx.add_class (Granite.STYLE_CLASS_CATEGORY_EXPANDER); + ctx.add_class ("category-expander"); else - ctx.add_class (Gtk.STYLE_CLASS_EXPANDER); + ctx.add_class ("row-expander"); //TODO What Granite style is appropriate return ctx; } diff --git a/src/Widgets/SourceList/SourceList.vala b/src/Widgets/SourceList/SourceList.vala index 4137c1f71..aef0b8fd9 100644 --- a/src/Widgets/SourceList/SourceList.vala +++ b/src/Widgets/SourceList/SourceList.vala @@ -90,7 +90,7 @@ public interface SourceListDragSource : SourceList.Item { * @see Gtk.SelectionData.set_uris * @see Gtk.SelectionData.set_text */ - public abstract void prepare_selection_data (Gtk.SelectionData selection_data); + // public abstract void prepare_selection_data (Gtk.SelectionData selection_data); } /** @@ -107,7 +107,7 @@ public interface SourceListDragDest : SourceList.Item { * @return //true// if the drop is possible; //false// otherwise. * @since 0.3 */ - public abstract bool data_drop_possible (Gdk.DragContext context, Gtk.SelectionData data); + // public abstract bool data_drop_possible (Gdk.DragContext context, Gtk.SelectionData data); /** * If a data drop is deemed possible, then this method is called @@ -119,7 +119,7 @@ public interface SourceListDragDest : SourceList.Item { * @return The action taken, or //0// to indicate that the dropped data was not accepted. * @since 0.3 */ - public abstract Gdk.DragAction data_received (Gdk.DragContext context, Gtk.SelectionData data); + // public abstract Gdk.DragAction data_received (Gdk.DragContext context, Gtk.SelectionData data); } /** @@ -206,18 +206,8 @@ public interface SourceListDragDest : SourceList.Item { * {@link Code.Widgets.SourceList.item_selected} the most important, as it indicates that * the selection was modified. * - * Pack the source list into the GUI using the {@link Gtk.Paned} widget. - * This is usually done as follows: - * {{{ - * var pane = new Gtk.Paned (Gtk.Orientation.HORIZONTAL); - * pane.pack1 (source_list, false, false); - * pane.pack2 (content_area, true, false); - * }}} - * - * @since 0.2 - * @see Gtk.Paned */ -public class SourceList : Gtk.ScrolledWindow { +public class SourceList : Gtk.Box { /** * = WORKING INTERNALS = @@ -1131,8 +1121,9 @@ public class SourceList : Gtk.ScrolledWindow { } private void resort () { - child_tree.set_sort_column_id (Gtk.SortColumn.UNSORTED, Gtk.SortType.ASCENDING); - child_tree.set_sort_column_id (Gtk.SortColumn.DEFAULT, Gtk.SortType.ASCENDING); + //TODO Do not use deprecated model and view. + child_tree.set_sort_column_id (-1, Gtk.SortType.ASCENDING); + child_tree.set_sort_column_id (0, Gtk.SortType.ASCENDING); } private int child_model_sort_func (Gtk.TreeModel model, Gtk.TreeIter a, Gtk.TreeIter b) { @@ -1207,84 +1198,84 @@ public class SourceList : Gtk.ScrolledWindow { * TreeDragDest implementation */ - public bool drag_data_received (Gtk.TreePath dest, Gtk.SelectionData selection_data) { - Gtk.TreeModel model; - Gtk.TreePath src_path; - - // Check if the user is dragging a row: - // - // Due to Gtk.TreeModelFilter's implementation of drag_data_get the values returned by - // tree_row_drag_data for GtkModel and GtkPath correspond to the child model and not the filter. - if (Gtk.tree_get_row_drag_data (selection_data, out model, out src_path) && model == child_tree) { - // get a child path representation of dest - var child_dest = convert_path_to_child_path (dest); - - if (child_dest != null) { - // New GtkTreeIters will be assigned to the rows at child_dest and its children. - if (child_tree_drag_data_received (child_dest, src_path)) - return true; - } - } - - // no new row inserted - return false; - } - - private bool child_tree_drag_data_received (Gtk.TreePath dest, Gtk.TreePath src_path) { - bool retval = false; - Gtk.TreeIter src_iter, dest_iter; - - if (!child_tree.get_iter (out src_iter, src_path)) - return false; - - var prev = dest; - - // Get the path to insert _after_ (dest is the path to insert _before_) - if (!prev.prev ()) { - // dest was the first spot at the current depth; which means - // we are supposed to prepend. - - var parent = dest; - Gtk.TreeIter? dest_parent = null; - - if (parent.up () && parent.get_depth () > 0) - child_tree.get_iter (out dest_parent, parent); - - child_tree.prepend (out dest_iter, dest_parent); - retval = true; - } else if (child_tree.get_iter (out dest_iter, prev)) { - var tmp_iter = dest_iter; - child_tree.insert_after (out dest_iter, null, tmp_iter); - retval = true; - } - - // If we succeeded in creating dest_iter, walk src_iter tree branch, - // duplicating it below dest_iter. - if (retval) { - recursive_node_copy (src_iter, dest_iter); - - // notify that the item was moved - Item item; - child_tree.get (src_iter, Column.ITEM, out item, -1); - return_val_if_fail (item != null, retval); - - // XXX Workaround: - // GtkTreeView automatically collapses expanded items that - // are dragged to a new location. Oddly, GtkTreeView doesn't fire - // 'row-collapsed' for the respective path, so we cannot keep track - // of that behavior via standard means. For now we'll just have - // our tree view check the properties of item again and ensure - // they're honored - update_item (item); - - var parent = item.parent as SourceListSortable; - return_val_if_fail (parent != null, retval); - - parent.user_moved_item (item); - } - - return retval; - } + // public bool drag_data_received (Gtk.TreePath dest, Gtk.SelectionData selection_data) { + // Gtk.TreeModel model; + // Gtk.TreePath src_path; + + // // Check if the user is dragging a row: + // // + // // Due to Gtk.TreeModelFilter's implementation of drag_data_get the values returned by + // // tree_row_drag_data for GtkModel and GtkPath correspond to the child model and not the filter. + // if (Gtk.tree_get_row_drag_data (selection_data, out model, out src_path) && model == child_tree) { + // // get a child path representation of dest + // var child_dest = convert_path_to_child_path (dest); + + // if (child_dest != null) { + // // New GtkTreeIters will be assigned to the rows at child_dest and its children. + // if (child_tree_drag_data_received (child_dest, src_path)) + // return true; + // } + // } + + // // no new row inserted + // return false; + // } + + // private bool child_tree_drag_data_received (Gtk.TreePath dest, Gtk.TreePath src_path) { + // bool retval = false; + // Gtk.TreeIter src_iter, dest_iter; + + // if (!child_tree.get_iter (out src_iter, src_path)) + // return false; + + // var prev = dest; + + // // Get the path to insert _after_ (dest is the path to insert _before_) + // if (!prev.prev ()) { + // // dest was the first spot at the current depth; which means + // // we are supposed to prepend. + + // var parent = dest; + // Gtk.TreeIter? dest_parent = null; + + // if (parent.up () && parent.get_depth () > 0) + // child_tree.get_iter (out dest_parent, parent); + + // child_tree.prepend (out dest_iter, dest_parent); + // retval = true; + // } else if (child_tree.get_iter (out dest_iter, prev)) { + // var tmp_iter = dest_iter; + // child_tree.insert_after (out dest_iter, null, tmp_iter); + // retval = true; + // } + + // // If we succeeded in creating dest_iter, walk src_iter tree branch, + // // duplicating it below dest_iter. + // if (retval) { + // recursive_node_copy (src_iter, dest_iter); + + // // notify that the item was moved + // Item item; + // child_tree.get (src_iter, Column.ITEM, out item, -1); + // return_val_if_fail (item != null, retval); + + // // XXX Workaround: + // // GtkTreeView automatically collapses expanded items that + // // are dragged to a new location. Oddly, GtkTreeView doesn't fire + // // 'row-collapsed' for the respective path, so we cannot keep track + // // of that behavior via standard means. For now we'll just have + // // our tree view check the properties of item again and ensure + // // they're honored + // update_item (item); + + // var parent = item.parent as SourceListSortable; + // return_val_if_fail (parent != null, retval); + + // parent.user_moved_item (item); + // } + + // return retval; + // } private void recursive_node_copy (Gtk.TreeIter src_iter, Gtk.TreeIter dest_iter) { move_item (src_iter, dest_iter); @@ -1311,156 +1302,156 @@ public class SourceList : Gtk.ScrolledWindow { items.set (item, new NodeWrapper (child_tree, dest_iter)); } - public bool row_drop_possible (Gtk.TreePath dest, Gtk.SelectionData selection_data) { - Gtk.TreeModel model; - Gtk.TreePath src_path; + // public bool row_drop_possible (Gtk.TreePath dest, Gtk.SelectionData selection_data) { + // Gtk.TreeModel model; + // Gtk.TreePath src_path; - // Check if the user is dragging a row: - // Due to Gtk.TreeModelFilter's implementation of drag_data_get the values returned by - // tree_row_drag_data for GtkModel and GtkPath correspond to the child model and not the filter. - if (!Gtk.tree_get_row_drag_data (selection_data, out model, out src_path) || model != child_tree) - return false; + // // Check if the user is dragging a row: + // // Due to Gtk.TreeModelFilter's implementation of drag_data_get the values returned by + // // tree_row_drag_data for GtkModel and GtkPath correspond to the child model and not the filter. + // if (!Gtk.tree_get_row_drag_data (selection_data, out model, out src_path) || model != child_tree) + // return false; - // get a representation of dest in the child model - var child_dest = convert_path_to_child_path (dest); + // // get a representation of dest in the child model + // var child_dest = convert_path_to_child_path (dest); - // don't allow dropping an item into itself - if (child_dest == null || src_path.compare (child_dest) == 0) - return false; + // // don't allow dropping an item into itself + // if (child_dest == null || src_path.compare (child_dest) == 0) + // return false; - // Only allow DnD between items at the same depth (indentation level) - // This doesn't mean their parent is the same. - int src_depth = src_path.get_depth (); - int dest_depth = child_dest.get_depth (); + // // Only allow DnD between items at the same depth (indentation level) + // // This doesn't mean their parent is the same. + // int src_depth = src_path.get_depth (); + // int dest_depth = child_dest.get_depth (); + + // if (src_depth != dest_depth) + // return false; - if (src_depth != dest_depth) - return false; + // // no need to check dest_depth since we know its equal to src_depth + // if (src_depth < 1) + // return false; - // no need to check dest_depth since we know its equal to src_depth - if (src_depth < 1) - return false; + // Item? parent = null; - Item? parent = null; + // // if the depth is 1, we're talking about the items at root level, + // // and by definition they share the same parent (root). We don't + // // need to verify anything else for that specific case + // if (src_depth == 1) { + // parent = root; + // } else { + // // we verified equality above. this must be true + // assert (dest_depth > 1); - // if the depth is 1, we're talking about the items at root level, - // and by definition they share the same parent (root). We don't - // need to verify anything else for that specific case - if (src_depth == 1) { - parent = root; - } else { - // we verified equality above. this must be true - assert (dest_depth > 1); + // // Only allow reordering between siblings, i.e. items with the same + // // parent. We don't want items to change their parent through DnD + // // because that would complicate our existing APIs, and may introduce + // // unpredictable behavior. + // var src_indices = src_path.get_indices (); + // var dest_indices = child_dest.get_indices (); - // Only allow reordering between siblings, i.e. items with the same - // parent. We don't want items to change their parent through DnD - // because that would complicate our existing APIs, and may introduce - // unpredictable behavior. - var src_indices = src_path.get_indices (); - var dest_indices = child_dest.get_indices (); + // // parent index is given by indices[depth-2], where depth > 1 + // int src_parent_index = src_indices[src_depth - 2]; + // int dest_parent_index = dest_indices[dest_depth - 2]; - // parent index is given by indices[depth-2], where depth > 1 - int src_parent_index = src_indices[src_depth - 2]; - int dest_parent_index = dest_indices[dest_depth - 2]; + // if (src_parent_index != dest_parent_index) + // return false; - if (src_parent_index != dest_parent_index) - return false; + // // get parent. Note that we don't use the child path for this + // var dest_parent = dest; - // get parent. Note that we don't use the child path for this - var dest_parent = dest; + // if (!dest_parent.up () || dest_parent.get_depth () < 1) + // return false; - if (!dest_parent.up () || dest_parent.get_depth () < 1) - return false; + // parent = get_item_from_path (dest_parent); + // } - parent = get_item_from_path (dest_parent); - } + // var sortable = parent as SourceListSortable; - var sortable = parent as SourceListSortable; + // if (sortable == null || !sortable.allow_dnd_sorting ()) + // return false; - if (sortable == null || !sortable.allow_dnd_sorting ()) - return false; + // var dest_item = get_item_from_path (dest); - var dest_item = get_item_from_path (dest); + // if (dest_item == null) + // return true; - if (dest_item == null) - return true; + // Item? source_item = null; + // var filter_src_path = convert_child_path_to_path (src_path); - Item? source_item = null; - var filter_src_path = convert_child_path_to_path (src_path); + // if (filter_src_path != null) + // source_item = get_item_from_path (filter_src_path); - if (filter_src_path != null) - source_item = get_item_from_path (filter_src_path); + // if (source_item == null) + // return false; - if (source_item == null) - return false; + // // If order isn't indifferent (=0), 'dest' has to sort before 'source'. + // // Otherwise we'd allow the user to move the 'source_item' to a new + // // location before 'dest_item', but that location would be changed + // // later by the sort function, making the whole interaction poinless. + // // We better prevent such reorderings from the start by giving the + // // user a visual clue about the invalid drop location. + // if (sortable.compare (dest_item, source_item) >= 0) { + // if (!dest.prev ()) + // return true; - // If order isn't indifferent (=0), 'dest' has to sort before 'source'. - // Otherwise we'd allow the user to move the 'source_item' to a new - // location before 'dest_item', but that location would be changed - // later by the sort function, making the whole interaction poinless. - // We better prevent such reorderings from the start by giving the - // user a visual clue about the invalid drop location. - if (sortable.compare (dest_item, source_item) >= 0) { - if (!dest.prev ()) - return true; - - // 'source_item' also has to sort 'after' or 'equal' the item currently - // preceding 'dest_item' - var dest_item_prev = get_item_from_path (dest); - - return dest_item_prev != null - && dest_item_prev != source_item - && sortable.compare (dest_item_prev, source_item) <= 0; - } + // // 'source_item' also has to sort 'after' or 'equal' the item currently + // // preceding 'dest_item' + // var dest_item_prev = get_item_from_path (dest); - return false; - } + // return dest_item_prev != null + // && dest_item_prev != source_item + // && sortable.compare (dest_item_prev, source_item) <= 0; + // } + + // return false; + // } - /** - * Override default implementation of TreeDragSource - * - * drag_data_delete is not overriden because the default implementation - * does exactly what we need. - */ + // /** + // * Override default implementation of TreeDragSource + // * + // * drag_data_delete is not overriden because the default implementation + // * does exactly what we need. + // */ + + // public bool drag_data_get (Gtk.TreePath path, Gtk.SelectionData selection_data) { + // // If we're asked for a data about a row, just have the default implementation fill in + // // selection_data. Please note that it will provide information relative to child_model. + // if (selection_data.get_target () == Gdk.Atom.intern_static_string ("GTK_TREE_MODEL_ROW")) + // return base.drag_data_get (path, selection_data); - public bool drag_data_get (Gtk.TreePath path, Gtk.SelectionData selection_data) { - // If we're asked for a data about a row, just have the default implementation fill in - // selection_data. Please note that it will provide information relative to child_model. - if (selection_data.get_target () == Gdk.Atom.intern_static_string ("GTK_TREE_MODEL_ROW")) - return base.drag_data_get (path, selection_data); + // // check if the item at path provides DnD source data + // var drag_source_item = get_item_from_path (path) as SourceListDragSource; + // if (drag_source_item != null && drag_source_item.draggable ()) { + // drag_source_item.prepare_selection_data (selection_data); + // return true; + // } - // check if the item at path provides DnD source data - var drag_source_item = get_item_from_path (path) as SourceListDragSource; - if (drag_source_item != null && drag_source_item.draggable ()) { - drag_source_item.prepare_selection_data (selection_data); - return true; - } + // return false; + // } + + // public bool row_draggable (Gtk.TreePath path) { + // if (!base.row_draggable (path)) + // return false; + + // var item = get_item_from_path (path); + + // if (item != null) { + // // check if the item's parent allows DnD sorting + // var sortable_item = item.parent as SourceListSortable; - return false; - } + // if (sortable_item != null && sortable_item.allow_dnd_sorting ()) + // return true; - public bool row_draggable (Gtk.TreePath path) { - if (!base.row_draggable (path)) - return false; - - var item = get_item_from_path (path); - - if (item != null) { - // check if the item's parent allows DnD sorting - var sortable_item = item.parent as SourceListSortable; + // // Since the parent item does not allow DnD sorting, there's no + // // reason to allow dragging it unless the row is actually draggable. + // var drag_source_item = item as SourceListDragSource; - if (sortable_item != null && sortable_item.allow_dnd_sorting ()) - return true; + // if (drag_source_item != null && drag_source_item.draggable ()) + // return true; + // } - // Since the parent item does not allow DnD sorting, there's no - // reason to allow dragging it unless the row is actually draggable. - var drag_source_item = item as SourceListDragSource; - - if (drag_source_item != null && drag_source_item.draggable ()) - return true; - } - - return false; - } + // return false; + // } } @@ -1468,18 +1459,22 @@ public class SourceList : Gtk.ScrolledWindow { * Class responsible for rendering Item.icon and Item.activatable. It also * notifies about clicks through the activated() signal. */ - private class CellRendererIcon : Gtk.CellRendererPixbuf { + // private class CellRendererIcon : Gtk.CellRendererPixbuf { + private class CellRendererIcon : Gtk.CellRenderer { public signal void activated (string path); - - private const Gtk.IconSize ICON_SIZE = Gtk.IconSize.MENU; - + public Icon gicon { get; set; } + // private Gtk.CellRendererPixbuf renderer_pixbuf; public CellRendererIcon () { } construct { - mode = Gtk.CellRendererMode.ACTIVATABLE; - stock_size = ICON_SIZE; + // renderer_pixbuf = new Gtk.CellRendererPixbuf () { + // mode = Gtk.CellRendererMode.ACTIVATABLE, + // icon_size = Gtk.IconSize.NORMAL + // }; + + // bind_property ("gicon", renderer_pixbuf, "gicon"); } public override bool activate ( @@ -1493,6 +1488,45 @@ public class SourceList : Gtk.ScrolledWindow { activated (path); return true; } + + // public override Gdk.Rectangle get_aligned_area ( + // Gtk.Widget widget, + // Gtk.CellRendererState flags, + // Gdk.Rectangle cell_area + // ) { + // return renderer_pixbuf.get_aligned_area (widget, flags, cell_area); + // } + // public override void get_preferred_height (Gtk.Widget widget, out int minimum_size, out int natural_size) { + // int m, n; + // renderer_pixbuf.get_preferred_height (widget, out m, out n); + // minimum_size = m; + // natural_size = n; + // } + // public override void get_preferred_height_for_width (Gtk.Widget widget, int width, out int minimum_height, out int natural_height) { + // int m, n; + // renderer_pixbuf.get_preferred_height_for_width (widget, width, out m, out n); + // minimum_height = m; + // natural_height = n; + // } + // public virtual void get_preferred_width (Gtk.Widget widget, out int minimum_size, out int natural_size) { + // int m, n; + // renderer_pixbuf.get_preferred_width (widget, out m, out n); + // minimum_size = m; + // natural_size = n; + // } + // public virtual void get_preferred_width_for_height (Gtk.Widget widget, int height, out int minimum_width, out int natural_width) { + // int m, n; + // renderer_pixbuf.get_preferred_width_for_height (widget, height, out m, out n); + // minimum_width = m; + // natural_width = n; + // } + // public override Gtk.SizeRequestMode get_request_mode () { + // return renderer_pixbuf.get_request_mode (); + // } + + // public override void snapshot (Gtk.Snapshot snapshot, Gtk.Widget widget, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, Gtk.CellRendererState flags) { + // renderer_pixbuf.snapshot (snapshot, widget, background_area, cell_area, flags); + // } } @@ -1522,20 +1556,8 @@ public class SourceList : Gtk.ScrolledWindow { ) { min_height = natural_height = 2 * (int) ypad; } - - public override void render ( - Cairo.Context context, - Gtk.Widget widget, - Gdk.Rectangle bg_area, - Gdk.Rectangle cell_area, - Gtk.CellRendererState flags - ) { - // Nothing to do. This renderer only adds space. - } } - - /** * The tree that actually displays the items. * @@ -1572,7 +1594,7 @@ public class SourceList : Gtk.ScrolledWindow { private Gtk.Entry? editable_entry; private Gtk.CellRendererText text_cell; private Gtk.EventControllerKey key_controller; - private Gtk.GestureMultiPress button_controller; + private Gtk.GestureClick button_controller; private CellRendererIcon icon_cell; private CellRendererIcon activatable_cell; private CellRendererBadge badge_cell; @@ -1594,54 +1616,49 @@ public class SourceList : Gtk.ScrolledWindow { private const string STYLE_PROP_LEFT_PADDING = "left-padding"; private const string STYLE_PROP_EXPANDER_SPACING = "expander-spacing"; - static construct { - install_style_property (new ParamSpecInt ( - STYLE_PROP_LEVEL_INDENTATION, - "Level Indentation", - "Space to add at the beginning of every indentation level. Must be an even number.", - 1, - 50, - 6, - ParamFlags.READABLE - )); - - install_style_property (new ParamSpecInt ( - STYLE_PROP_LEFT_PADDING, - "Left Padding", - "Padding added to the left side of the tree. Must be an even number.", - 1, - 50, - 4, - ParamFlags.READABLE - )); - - install_style_property (new ParamSpecInt ( - STYLE_PROP_EXPANDER_SPACING, - "Expander Spacing", - "Space added between an item and its expander. Must be an even number.", - 1, - 50, - 4, - ParamFlags.READABLE - )); - } + // static construct { + // install_style_property (new ParamSpecInt ( + // STYLE_PROP_LEVEL_INDENTATION, + // "Level Indentation", + // "Space to add at the beginning of every indentation level. Must be an even number.", + // 1, + // 50, + // 6, + // ParamFlags.READABLE + // )); + + // install_style_property (new ParamSpecInt ( + // STYLE_PROP_LEFT_PADDING, + // "Left Padding", + // "Padding added to the left side of the tree. Must be an even number.", + // 1, + // 50, + // 4, + // ParamFlags.READABLE + // )); + + // install_style_property (new ParamSpecInt ( + // STYLE_PROP_EXPANDER_SPACING, + // "Expander Spacing", + // "Space added between an item and its expander. Must be an even number.", + // 1, + // 50, + // 4, + // ParamFlags.READABLE + // )); + // } public Tree (DataModel data_model) { Object (data_model: data_model); } construct { - unowned Gtk.StyleContext style_context = get_style_context (); - style_context.add_class (Gtk.STYLE_CLASS_SIDEBAR); - style_context.add_class ("source-list"); + add_css_class (Granite.STYLE_CLASS_SIDEBAR); + add_css_class ("source-list"); var css_provider = new Gtk.CssProvider (); - try { - css_provider.load_from_data (DEFAULT_STYLESHEET, -1); - style_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_FALLBACK); - } catch (Error e) { - warning ("Could not create CSS Provider: %s\nStylesheet:\n%s", e.message, DEFAULT_STYLESHEET); - } + css_provider.load_from_string (DEFAULT_STYLESHEET); + Gtk.StyleContext.add_provider_for_display (Gdk.Display.get_default (), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_FALLBACK); set_model (data_model); @@ -1704,8 +1721,7 @@ public class SourceList : Gtk.ScrolledWindow { // First expander. Used for normal expandable items primary_expander_cell = new CellRendererExpander (); - int expander_spacing; - style_get (STYLE_PROP_EXPANDER_SPACING, out expander_spacing); + int expander_spacing = 12; primary_expander_cell.xpad = expander_spacing / 2; item_column.pack_end (primary_expander_cell, false); @@ -1722,20 +1738,22 @@ public class SourceList : Gtk.ScrolledWindow { // Add root-level indentation. New levels will be added by update_item_expansion() add_spacer_cell_for_level (1); - // Enable basic row drag and drop - configure_drag_source (null); - configure_drag_dest (null, 0); + // // Enable basic row drag and drop + // configure_drag_source (null); + // configure_drag_dest (null, 0); query_tooltip.connect_after (on_query_tooltip); has_tooltip = true; - key_controller = new Gtk.EventControllerKey (this); + var key_controller = new Gtk.EventControllerKey (); + this.add_controller (key_controller); key_controller.key_released.connect (on_key_released); - button_controller = new Gtk.GestureMultiPress (this) { + var button_controller = new Gtk.GestureClick () { propagation_phase = CAPTURE, button = 0 }; + this.add_controller (button_controller); button_controller.pressed.connect (on_button_pressed); button_controller.released.connect (on_button_released); } @@ -1744,152 +1762,152 @@ public class SourceList : Gtk.ScrolledWindow { disable_item_property_monitor (); } - public override bool drag_motion (Gdk.DragContext context, int x, int y, uint time) { - // call the base signal to get rows with children to spring open - if (!base.drag_motion (context, x, y, time)) - return false; - - Gtk.TreePath suggested_path, current_path; - Gtk.TreeViewDropPosition suggested_pos, current_pos; - - if (get_dest_row_at_pos (x, y, out suggested_path, out suggested_pos)) { - // the base implementation of drag_motion was likely to set a drop - // destination row. If that's the case, we configure the row position - // to only allow drops before or after it, but not into it - get_drag_dest_row (out current_path, out current_pos); - - if (current_path != null && suggested_path.compare (current_path) == 0) { - // If the source widget is this treeview, we assume we're - // just dragging rows around, because at the moment dragging - // rows into other rows (re-parenting) is not implemented. - var source_widget = Gtk.drag_get_source_widget (context); - bool dragging_treemodel_row = (source_widget == this); - - if (dragging_treemodel_row) { - // we don't allow DnD into other rows, only in between them - // (no row is highlighted) - if (current_pos != Gtk.TreeViewDropPosition.BEFORE) { - if (current_pos == Gtk.TreeViewDropPosition.INTO_OR_BEFORE) - set_drag_dest_row (current_path, Gtk.TreeViewDropPosition.BEFORE); - else - set_drag_dest_row (null, Gtk.TreeViewDropPosition.AFTER); - } - } else { - // for DnD originated on a different widget, we don't want to insert - // between rows, only select the rows themselves - if (current_pos == Gtk.TreeViewDropPosition.BEFORE) - set_drag_dest_row (current_path, Gtk.TreeViewDropPosition.INTO_OR_BEFORE); - else if (current_pos == Gtk.TreeViewDropPosition.AFTER) - set_drag_dest_row (current_path, Gtk.TreeViewDropPosition.INTO_OR_AFTER); - - // determine if external DnD is supported by the item at destination - var dest = data_model.get_item_from_path (current_path) as SourceListDragDest; - - if (dest != null) { - var target_list = Gtk.drag_dest_get_target_list (this); - var target = Gtk.drag_dest_find_target (this, context, target_list); - - // have 'drag_get_data' call 'drag_data_received' to determine - // if the data can actually be dropped. - context.set_data ("suggested-dnd-action", context.get_suggested_action ()); - Gtk.drag_get_data (this, context, target, time); - } else { - // dropping data here is not supported. Unset dest row - set_drag_dest_row (null, Gtk.TreeViewDropPosition.BEFORE); - } - } - } - } else { - // dropping into blank areas of SourceList is not allowed - set_drag_dest_row (null, Gtk.TreeViewDropPosition.AFTER); - return false; - } - - return true; - } - - public override void drag_data_received ( - Gdk.DragContext context, - int x, - int y, - Gtk.SelectionData selection_data, - uint info, - uint time - ) { - var target_list = Gtk.drag_dest_get_target_list (this); - var target = Gtk.drag_dest_find_target (this, context, target_list); - - if (target == Gdk.Atom.intern_static_string ("GTK_TREE_MODEL_ROW")) { - base.drag_data_received (context, x, y, selection_data, info, time); - return; - } - - Gtk.TreePath path; - Gtk.TreeViewDropPosition pos; - - if (context.get_data ("suggested-dnd-action") != 0) { - context.set_data ("suggested-dnd-action", 0); - - get_drag_dest_row (out path, out pos); - - if (path != null) { - // determine if external DnD is allowed by the item at destination - var dest = data_model.get_item_from_path (path) as SourceListDragDest; - - if (dest == null || !dest.data_drop_possible (context, selection_data)) { - // dropping data here is not allowed. unset any previously - // selected destination row - set_drag_dest_row (null, Gtk.TreeViewDropPosition.BEFORE); - Gdk.drag_status (context, 0, time); - return; - } - } - - Gdk.drag_status (context, context.get_suggested_action (), time); - } else { - if (get_dest_row_at_pos (x, y, out path, out pos)) { - // Data coming from external source/widget was dropped into this item. - // selection_data contains something other than a tree row; most likely - // we're dealing with a DnD not originated within the Source List tree. - // Let's pass the data to the corresponding item, if there's a handler. - - var drag_dest = data_model.get_item_from_path (path) as SourceListDragDest; - - if (drag_dest != null) { - var action = drag_dest.data_received (context, selection_data); - Gtk.drag_finish (context, action != 0, action == Gdk.DragAction.MOVE, time); - return; - } - } - - // failure - Gtk.drag_finish (context, false, false, time); - } - } - - public void configure_drag_source (Gtk.TargetEntry[]? src_entries) { - // Append GTK_TREE_MODEL_ROW to src_entries and src_entries to enable row DnD. - var entries = append_row_target_entry (src_entries); - - unset_rows_drag_source (); - enable_model_drag_source (Gdk.ModifierType.BUTTON1_MASK, entries, Gdk.DragAction.MOVE); - } - - public void configure_drag_dest (Gtk.TargetEntry[]? dest_entries, Gdk.DragAction actions) { - // Append GTK_TREE_MODEL_ROW to dest_entries and dest_entries to enable row DnD. - var entries = append_row_target_entry (dest_entries); - - unset_rows_drag_dest (); - - // DragAction.MOVE needs to be enabled for row drag-and-drop to work properly - enable_model_drag_dest (entries, Gdk.DragAction.MOVE | actions); - } + // public override bool drag_motion (Gdk.DragContext context, int x, int y, uint time) { + // // call the base signal to get rows with children to spring open + // if (!base.drag_motion (context, x, y, time)) + // return false; + + // Gtk.TreePath suggested_path, current_path; + // Gtk.TreeViewDropPosition suggested_pos, current_pos; + + // if (get_dest_row_at_pos (x, y, out suggested_path, out suggested_pos)) { + // // the base implementation of drag_motion was likely to set a drop + // // destination row. If that's the case, we configure the row position + // // to only allow drops before or after it, but not into it + // get_drag_dest_row (out current_path, out current_pos); + + // if (current_path != null && suggested_path.compare (current_path) == 0) { + // // If the source widget is this treeview, we assume we're + // // just dragging rows around, because at the moment dragging + // // rows into other rows (re-parenting) is not implemented. + // var source_widget = Gtk.drag_get_source_widget (context); + // bool dragging_treemodel_row = (source_widget == this); + + // if (dragging_treemodel_row) { + // // we don't allow DnD into other rows, only in between them + // // (no row is highlighted) + // if (current_pos != Gtk.TreeViewDropPosition.BEFORE) { + // if (current_pos == Gtk.TreeViewDropPosition.INTO_OR_BEFORE) + // set_drag_dest_row (current_path, Gtk.TreeViewDropPosition.BEFORE); + // else + // set_drag_dest_row (null, Gtk.TreeViewDropPosition.AFTER); + // } + // } else { + // // for DnD originated on a different widget, we don't want to insert + // // between rows, only select the rows themselves + // if (current_pos == Gtk.TreeViewDropPosition.BEFORE) + // set_drag_dest_row (current_path, Gtk.TreeViewDropPosition.INTO_OR_BEFORE); + // else if (current_pos == Gtk.TreeViewDropPosition.AFTER) + // set_drag_dest_row (current_path, Gtk.TreeViewDropPosition.INTO_OR_AFTER); + + // // determine if external DnD is supported by the item at destination + // var dest = data_model.get_item_from_path (current_path) as SourceListDragDest; + + // if (dest != null) { + // var target_list = Gtk.drag_dest_get_target_list (this); + // var target = Gtk.drag_dest_find_target (this, context, target_list); + + // // have 'drag_get_data' call 'drag_data_received' to determine + // // if the data can actually be dropped. + // context.set_data ("suggested-dnd-action", context.get_suggested_action ()); + // Gtk.drag_get_data (this, context, target, time); + // } else { + // // dropping data here is not supported. Unset dest row + // set_drag_dest_row (null, Gtk.TreeViewDropPosition.BEFORE); + // } + // } + // } + // } else { + // // dropping into blank areas of SourceList is not allowed + // set_drag_dest_row (null, Gtk.TreeViewDropPosition.AFTER); + // return false; + // } + + // return true; + // } + + // public override void drag_data_received ( + // Gdk.DragContext context, + // int x, + // int y, + // Gtk.SelectionData selection_data, + // uint info, + // uint time + // ) { + // var target_list = Gtk.drag_dest_get_target_list (this); + // var target = Gtk.drag_dest_find_target (this, context, target_list); + + // if (target == Gdk.Atom.intern_static_string ("GTK_TREE_MODEL_ROW")) { + // base.drag_data_received (context, x, y, selection_data, info, time); + // return; + // } + + // Gtk.TreePath path; + // Gtk.TreeViewDropPosition pos; + + // if (context.get_data ("suggested-dnd-action") != 0) { + // context.set_data ("suggested-dnd-action", 0); + + // get_drag_dest_row (out path, out pos); + + // if (path != null) { + // // determine if external DnD is allowed by the item at destination + // var dest = data_model.get_item_from_path (path) as SourceListDragDest; + + // if (dest == null || !dest.data_drop_possible (context, selection_data)) { + // // dropping data here is not allowed. unset any previously + // // selected destination row + // set_drag_dest_row (null, Gtk.TreeViewDropPosition.BEFORE); + // Gdk.drag_status (context, 0, time); + // return; + // } + // } + + // Gdk.drag_status (context, context.get_suggested_action (), time); + // } else { + // if (get_dest_row_at_pos (x, y, out path, out pos)) { + // // Data coming from external source/widget was dropped into this item. + // // selection_data contains something other than a tree row; most likely + // // we're dealing with a DnD not originated within the Source List tree. + // // Let's pass the data to the corresponding item, if there's a handler. + + // var drag_dest = data_model.get_item_from_path (path) as SourceListDragDest; + + // if (drag_dest != null) { + // var action = drag_dest.data_received (context, selection_data); + // Gtk.drag_finish (context, action != 0, action == Gdk.DragAction.MOVE, time); + // return; + // } + // } + + // // failure + // Gtk.drag_finish (context, false, false, time); + // } + // } + + // public void configure_drag_source (Gtk.TargetEntry[]? src_entries) { + // // Append GTK_TREE_MODEL_ROW to src_entries and src_entries to enable row DnD. + // var entries = append_row_target_entry (src_entries); + + // unset_rows_drag_source (); + // enable_model_drag_source (Gdk.ModifierType.BUTTON1_MASK, entries, Gdk.DragAction.MOVE); + // } + + // public void configure_drag_dest (Gtk.TargetEntry[]? dest_entries, Gdk.DragAction actions) { + // // Append GTK_TREE_MODEL_ROW to dest_entries and dest_entries to enable row DnD. + // var entries = append_row_target_entry (dest_entries); + + // unset_rows_drag_dest (); + + // // DragAction.MOVE needs to be enabled for row drag-and-drop to work properly + // enable_model_drag_dest (entries, Gdk.DragAction.MOVE | actions); + // } private bool on_query_tooltip (int x, int y, bool keyboard_tooltip, Gtk.Tooltip tooltip) { Gtk.TreePath path; Gtk.TreeViewColumn column = get_column (Column.ITEM); - get_tooltip_context (ref x, ref y, keyboard_tooltip, null, out path, null); + get_tooltip_context (x, y, keyboard_tooltip, null, out path, null); if (path == null) { return false; } @@ -1934,23 +1952,23 @@ public class SourceList : Gtk.ScrolledWindow { return false; } - private static Gtk.TargetEntry[] append_row_target_entry (Gtk.TargetEntry[]? orig) { - const Gtk.TargetEntry row_target_entry = { // vala-lint=naming-convention - "GTK_TREE_MODEL_ROW", - Gtk.TargetFlags.SAME_WIDGET, - 0 - }; + // private static Gtk.TargetEntry[] append_row_target_entry (Gtk.TargetEntry[]? orig) { + // const Gtk.TargetEntry row_target_entry = { // vala-lint=naming-convention + // "GTK_TREE_MODEL_ROW", + // Gtk.TargetFlags.SAME_WIDGET, + // 0 + // }; - var entries = new Gtk.TargetEntry[0]; - entries += row_target_entry; + // var entries = new Gtk.TargetEntry[0]; + // entries += row_target_entry; - if (orig != null) { - foreach (var target_entry in orig) - entries += target_entry; - } + // if (orig != null) { + // foreach (var target_entry in orig) + // entries += target_entry; + // } - return entries; - } + // return entries; + // } private void enable_item_property_monitor () { data_model.item_updated.connect_after (on_model_item_updated); @@ -1990,8 +2008,7 @@ public class SourceList : Gtk.ScrolledWindow { // so we set the value to a half of actual (desired) value. switch (level) { case 1: // root - int left_padding; - style_get (STYLE_PROP_LEFT_PADDING, out left_padding); + int left_padding = 12; cell_xpadding = left_padding / 2; break; @@ -2000,8 +2017,7 @@ public class SourceList : Gtk.ScrolledWindow { break; default: // remaining levels - int level_indentation; - style_get (STYLE_PROP_LEVEL_INDENTATION, out level_indentation); + int level_indentation = 12; cell_xpadding = level_indentation / 2; break; } @@ -2245,11 +2261,12 @@ public class SourceList : Gtk.ScrolledWindow { enable_item_property_monitor (); } - public override void row_activated (Gtk.TreePath path, Gtk.TreeViewColumn column) { - if (column == get_column (Column.ITEM)) { + public override void row_activated (Gtk.TreePath path, Gtk.TreeViewColumn? column) { + if (column != null && column == get_column (Column.ITEM)) { var item = data_model.get_item_from_path (path); - if (item != null) + if (item != null) { item.activated (); + } } } @@ -2400,10 +2417,6 @@ public class SourceList : Gtk.ScrolledWindow { return min_req.width; } - public override bool popup_menu () { - return popup_context_menu (); - } - private bool popup_context_menu (Item? item = null, int px = 0, int py = 0) { if (item == null) { item = selected_item; @@ -2412,13 +2425,10 @@ public class SourceList : Gtk.ScrolledWindow { if (item != null) { var menu_model = item.get_context_menu (); if (menu_model != null) { - var menu = new Gtk.PopoverMenu () { - modal = true, - relative_to = this, + var menu = new Gtk.PopoverMenu.from_model (menu_model) { position = RIGHT }; - menu.bind_model (menu_model, null); menu.pointing_to = Gdk.Rectangle () { x = px, y = py }; menu.popup (); } @@ -2666,7 +2676,13 @@ public class SourceList : Gtk.ScrolledWindow { } } + public Gtk.Adjustment vadjustment { + get { + return scrolled_window.vadjustment; + } + } private Tree tree; + private Gtk.ScrolledWindow scrolled_window; private DataModel data_model = new DataModel (); /** * Creates a new {@link Code.Widgets.SourceList}. @@ -2680,11 +2696,11 @@ public class SourceList : Gtk.ScrolledWindow { construct { tree = new Tree (data_model); - - set_policy (Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); - add (tree); - show_all (); - + scrolled_window = new Gtk.ScrolledWindow () { + child = tree + }; + scrolled_window.set_policy (Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + append (scrolled_window); tree.item_selected.connect ((item) => item_selected (item)); } @@ -2777,9 +2793,9 @@ public class SourceList : Gtk.ScrolledWindow { * @see Code.Widgets.SourceList.disable_drag_source * @since 0.3 */ - public void enable_drag_source (Gtk.TargetEntry[] src_entries) { - tree.configure_drag_source (src_entries); - } + // public void enable_drag_source (Gtk.TargetEntry[] src_entries) { + // tree.configure_drag_source (src_entries); + // } /** * Undoes the effect of {@link Code.Widgets.SourceList.enable_drag_source} @@ -2787,9 +2803,9 @@ public class SourceList : Gtk.ScrolledWindow { * @see Code.Widgets.SourceList.enable_drag_source * @since 0.3 */ - public void disable_drag_source () { - tree.configure_drag_source (null); - } + // public void disable_drag_source () { + // tree.configure_drag_source (null); + // } /** * Turns Source List into a //drop destination//. @@ -2804,9 +2820,9 @@ public class SourceList : Gtk.ScrolledWindow { * @see Code.Widgets.SourceList.disable_drag_dest * @since 0.3 */ - public void enable_drag_dest (Gtk.TargetEntry[] dest_entries, Gdk.DragAction actions) { - tree.configure_drag_dest (dest_entries, actions); - } + // public void enable_drag_dest (Gtk.TargetEntry[] dest_entries, Gdk.DragAction actions) { + // tree.configure_drag_dest (dest_entries, actions); + // } /** * Undoes the effect of {@link Code.Widgets.SourceList.enable_drag_dest} @@ -2814,9 +2830,9 @@ public class SourceList : Gtk.ScrolledWindow { * @see Code.Widgets.SourceList.enable_drag_dest * @since 0.3 */ - public void disable_drag_dest () { - tree.configure_drag_dest (null, 0); - } + // public void disable_drag_dest () { + // tree.configure_drag_dest (null, 0); + // } /** * Scrolls the source list tree to make //item// visible. diff --git a/src/Widgets/SourceView.vala b/src/Widgets/SourceView.vala index 068e2e171..df88dd3f1 100644 --- a/src/Widgets/SourceView.vala +++ b/src/Widgets/SourceView.vala @@ -20,9 +20,9 @@ */ namespace Scratch.Widgets { - public class SourceView : Gtk.SourceView { - public Gtk.SourceLanguageManager manager; - public Gtk.SourceStyleSchemeManager style_scheme_manager; + public class SourceView : GtkSource.View { + public GtkSource.LanguageManager manager; + public GtkSource.StyleSchemeManager style_scheme_manager; public Gtk.CssProvider font_css_provider; public Gtk.TextTag warning_tag; public Gtk.TextTag error_tag; @@ -39,25 +39,25 @@ namespace Scratch.Widgets { private string selected_text = ""; private GitGutterRenderer git_diff_gutter_renderer; private NavMarkGutterRenderer navmark_gutter_renderer; - private Gtk.EventControllerKey key_controller; + // private Gtk.EventControllerKey key_controller; private const uint THROTTLE_MS = 400; protected static Scratch.Application application; - public signal void style_changed (Gtk.SourceStyleScheme style); + public signal void style_changed (GtkSource.StyleScheme style); // "selection_changed" signal now only emitted when the selected text changes (position ignored). // Listened to by searchbar and highlight word selection plugin public signal void selection_changed (Gtk.TextIter start_iter, Gtk.TextIter end_iter); //lang can be null, in the case of *No highlight style* aka Normal text - public Gtk.SourceLanguage? language { + public GtkSource.Language? language { set { - ((Gtk.SourceBuffer) buffer).language = value; + ((GtkSource.Buffer) buffer).language = value; } get { - return ((Gtk.SourceBuffer) buffer).language; + return ((GtkSource.Buffer) buffer).language; } } @@ -81,7 +81,7 @@ namespace Scratch.Widgets { Object ( show_line_numbers: true, smart_backspace: true, - smart_home_end: Gtk.SourceSmartHomeEndType.BEFORE, + smart_home_end: GtkSource.SmartHomeEndType.BEFORE, wrap_mode: Gtk.WrapMode.WORD ); } @@ -92,20 +92,20 @@ namespace Scratch.Widgets { hexpand = true; vexpand = true; - manager = Gtk.SourceLanguageManager.get_default (); - style_scheme_manager = new Gtk.SourceStyleSchemeManager (); + manager = GtkSource.LanguageManager.get_default (); + style_scheme_manager = new GtkSource.StyleSchemeManager (); font_css_provider = new Gtk.CssProvider (); - get_style_context ().add_provider (font_css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); + Gtk.StyleContext.add_provider_for_display (Gdk.Display.get_default (), font_css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); - var source_buffer = new Gtk.SourceBuffer (null); + var source_buffer = new GtkSource.Buffer (null); set_buffer (source_buffer); source_buffer.highlight_syntax = Scratch.settings.get_boolean ("syntax-highlighting"); source_buffer.mark_set.connect (on_mark_set); source_buffer.mark_deleted.connect (on_mark_deleted); highlight_current_line = true; - var draw_spaces_tag = new Gtk.SourceTag ("draw_spaces"); + var draw_spaces_tag = new GtkSource.Tag ("draw_spaces"); draw_spaces_tag.draw_spaces = true; source_buffer.tag_table.add (draw_spaces_tag); @@ -116,12 +116,12 @@ namespace Scratch.Widgets { get_gutter (Gtk.TextWindowType.LEFT).insert (git_diff_gutter_renderer, 10); get_gutter (Gtk.TextWindowType.LEFT).insert (navmark_gutter_renderer, -48); - smart_home_end = Gtk.SourceSmartHomeEndType.AFTER; + smart_home_end = GtkSource.SmartHomeEndType.AFTER; // Create common tags warning_tag = new Gtk.TextTag ("warning_bg"); warning_tag.underline = Pango.Underline.ERROR; - warning_tag.underline_rgba = Gdk.RGBA () { red = 0.13, green = 0.55, blue = 0.13, alpha = 1.0 }; + warning_tag.underline_rgba = Gdk.RGBA () { red = 0.13f, green = 0.55f, blue = 0.13f, alpha = 1.0f }; error_tag = new Gtk.TextTag ("error_bg"); error_tag.underline = Pango.Underline.ERROR; @@ -129,7 +129,7 @@ namespace Scratch.Widgets { source_buffer.tag_table.add (error_tag); source_buffer.tag_table.add (warning_tag); - Gtk.drag_dest_add_uri_targets (this); + // Gtk.drag_dest_add_uri_targets (this); restore_settings (); settings.changed.connect (restore_settings); @@ -137,7 +137,6 @@ namespace Scratch.Widgets { var granite_settings = Granite.Settings.get_default (); granite_settings.notify["prefers-color-scheme"].connect (restore_settings); - cut_clipboard.connect (() => { if (!Scratch.settings.get_boolean ("smart-cut-copy")) { return; @@ -148,11 +147,11 @@ namespace Scratch.Widgets { Gtk.TextIter iter_start, iter_end; if (get_current_line (out iter_start, out iter_end)) { - var clipboard = Gtk.Clipboard.get_for_display (get_display (), Gdk.SELECTION_CLIPBOARD); + var clipboard = Gdk.Display.get_default ().get_clipboard (); string cut_text = iter_start.get_slice (iter_end); buffer.begin_user_action (); - clipboard.set_text (cut_text, -1); + clipboard.set_text (cut_text); buffer.delete_range (iter_start, iter_end); buffer.end_user_action (); } @@ -169,10 +168,10 @@ namespace Scratch.Widgets { Gtk.TextIter iter_start, iter_end; if (get_current_line (out iter_start, out iter_end)) { - var clipboard = Gtk.Clipboard.get_for_display (get_display (), Gdk.SELECTION_CLIPBOARD); + var clipboard = Gdk.Display.get_default ().get_clipboard (); string copy_text = iter_start.get_slice (iter_end); - clipboard.set_text (copy_text, -1); + clipboard.set_text (copy_text); } } }); @@ -197,7 +196,7 @@ namespace Scratch.Widgets { next_mark_action.activate.connect (goto_next_mark); prev_mark_action.activate.connect (goto_previous_mark); toggle_comment_action.activate.connect (() => { - CommentToggler.toggle_comment (buffer as Gtk.SourceBuffer); + CommentToggler.toggle_comment (buffer as GtkSource.Buffer); }); var extra_menu = new Menu (); @@ -212,7 +211,7 @@ namespace Scratch.Widgets { sort_action.set_enabled (buffer.has_selection); }); buffer.notify["language"].connect (() => { - toggle_comment_action.set_enabled (CommentToggler.language_has_comments (((Gtk.SourceBuffer)buffer).language)); + toggle_comment_action.set_enabled (CommentToggler.language_has_comments (((GtkSource.Buffer)buffer).language)); }); buffer.notify_property ("has-selection"); buffer.notify_property ("language"); @@ -223,29 +222,29 @@ namespace Scratch.Widgets { }); navmark_gutter_renderer.notify_property ("has-marks"); - // For Gtk3 we need to convert extra_menu to additional Gtk.MenuItems. This is omitted in Gtk4 - populate_popup.connect_after ((menu) => { - scroll_mark_onscreen (buffer.get_mark ("insert")); //TODO Check if still needed in Gtk4 - for (int i = 0; i < extra_menu.get_n_items (); i++) { - var name = extra_menu.get_item_attribute_value (i, "label", VariantType.STRING).get_string (); - var action = extra_menu.get_item_attribute_value (i, "action", VariantType.STRING).get_string (); - // warning ("adding menuitem name %s, action_name %s", name, action); - menu.add ( - new Gtk.MenuItem.with_label (name) { - action_name = "sourceview." + action - } - ); - } - menu.show_all (); - }); + // // For Gtk3 we need to convert extra_menu to additional Gtk.MenuItems. This is omitted in Gtk4 + // populate_popup.connect_after ((menu) => { + // scroll_mark_onscreen (buffer.get_mark ("insert")); //TODO Check if still needed in Gtk4 + // for (int i = 0; i < extra_menu.get_n_items (); i++) { + // var name = extra_menu.get_item_attribute_value (i, "label", VariantType.STRING).get_string (); + // var action = extra_menu.get_item_attribute_value (i, "action", VariantType.STRING).get_string (); + // // warning ("adding menuitem name %s, action_name %s", name, action); + // menu.add ( + // new Gtk.MenuItem.with_label (name) { + // action_name = "sourceview." + action + // } + // ); + // } + // }); // Handle context menu shortcuts here. - // In Gtk3 we use a EventControllerKey but after porting to Gtk4 we can replace with Gtk.Shortcuts - key_controller = new Gtk.EventControllerKey (application.get_active_window ()) { + // For port keep the key controller After porting to Gtk4 we may replace with shortcutcontroller + var key_controller = new Gtk.EventControllerKey () { propagation_phase = CAPTURE }; + ((Gtk.Widget) application.get_active_window ()).add_controller (key_controller); key_controller.key_pressed.connect ((kv, kc, state) => { - if (!this.is_focus || !Gtk.accelerator_valid (kv, state)) { + if (!this.is_focus () || !Gtk.accelerator_valid (kv, state)) { return false; } @@ -266,7 +265,7 @@ namespace Scratch.Widgets { return true; case "m": case "slash": - CommentToggler.toggle_comment (buffer as Gtk.SourceBuffer); + CommentToggler.toggle_comment (buffer as GtkSource.Buffer); return true; default: break; @@ -275,17 +274,6 @@ namespace Scratch.Widgets { return false; }); - size_allocate.connect ((allocation) => { - // Throttle for performance - if (size_allocate_timer == 0) { - size_allocate_timer = Timeout.add (THROTTLE_MS, () => { - size_allocate_timer = 0; - bottom_margin = calculate_bottom_margin (allocation.height); - return GLib.Source.REMOVE; - }); - } - }); - application.notify["system-monospace-font"].connect (() => { if (Scratch.settings.get_boolean ("use-system-font")) { update_font (); @@ -293,6 +281,19 @@ namespace Scratch.Widgets { }); } + public override void size_allocate (int width, int height, int baseline) { + // Throttle for performance + if (size_allocate_timer == 0) { + size_allocate_timer = Timeout.add (THROTTLE_MS, () => { + size_allocate_timer = 0; + bottom_margin = calculate_bottom_margin (height); + return GLib.Source.REMOVE; + }); + } + + base.size_allocate (width, height, baseline); + } + private bool get_current_line (out Gtk.TextIter start, out Gtk.TextIter end) { buffer.get_iter_at_offset (out start, buffer.cursor_position); start.backward_chars (start.get_line_offset ()); @@ -327,32 +328,32 @@ namespace Scratch.Widgets { show_right_margin = Scratch.settings.get_boolean ("show-right-margin"); right_margin_position = Scratch.settings.get_int ("right-margin-position"); insert_spaces_instead_of_tabs = Scratch.settings.get_boolean ("spaces-instead-of-tabs"); - var source_buffer = (Gtk.SourceBuffer) buffer; + var source_buffer = (GtkSource.Buffer) buffer; source_buffer.highlight_matching_brackets = Scratch.settings.get_boolean ("highlight-matching-brackets"); source_buffer.highlight_syntax = Scratch.settings.get_boolean ("syntax-highlighting"); space_drawer.enable_matrix = false; switch ((ScratchDrawSpacesState) Scratch.settings.get_enum ("draw-spaces")) { case ScratchDrawSpacesState.ALWAYS: space_drawer.set_types_for_locations ( - Gtk.SourceSpaceLocationFlags.ALL, - Gtk.SourceSpaceTypeFlags.SPACE | Gtk.SourceSpaceTypeFlags.TAB + GtkSource.SpaceLocationFlags.ALL, + GtkSource.SpaceTypeFlags.SPACE | GtkSource.SpaceTypeFlags.TAB ); break; case ScratchDrawSpacesState.FOR_SELECTION: case ScratchDrawSpacesState.CURRENT: space_drawer.set_types_for_locations ( - Gtk.SourceSpaceLocationFlags.ALL, - Gtk.SourceSpaceTypeFlags.NONE + GtkSource.SpaceLocationFlags.ALL, + GtkSource.SpaceTypeFlags.NONE ); space_drawer.set_types_for_locations ( - Gtk.SourceSpaceLocationFlags.TRAILING, - Gtk.SourceSpaceTypeFlags.SPACE | Gtk.SourceSpaceTypeFlags.TAB + GtkSource.SpaceLocationFlags.TRAILING, + GtkSource.SpaceTypeFlags.SPACE | GtkSource.SpaceTypeFlags.TAB ); break; default: space_drawer.set_types_for_locations ( - Gtk.SourceSpaceLocationFlags.ALL, - Gtk.SourceSpaceTypeFlags.NONE + GtkSource.SpaceLocationFlags.ALL, + GtkSource.SpaceTypeFlags.NONE ); break; } @@ -400,11 +401,7 @@ namespace Scratch.Widgets { "}" ); - try { - font_css_provider.load_from_data (font_css); - } catch (Error e) { - critical (e.message); - } + font_css_provider.load_from_string (font_css); } public void go_to_line (int line, int offset = 0) { @@ -597,15 +594,17 @@ namespace Scratch.Widgets { } public void set_text (string text, bool opening = true) { - var source_buffer = (Gtk.SourceBuffer) buffer; + var source_buffer = (GtkSource.Buffer) buffer; if (opening) { - source_buffer.begin_not_undoable_action (); + source_buffer.enable_undo = false; + // source_buffer.begin_not_undoable_action (); } source_buffer.text = text; if (opening) { - source_buffer.end_not_undoable_action (); + source_buffer.enable_undo = true; + // source_buffer.end_not_undoable_action (); } Gtk.TextIter? start = null; diff --git a/src/Widgets/Terminal.vala b/src/Widgets/Terminal.vala index da6ea7897..1a29fbff6 100644 --- a/src/Widgets/Terminal.vala +++ b/src/Widgets/Terminal.vala @@ -24,8 +24,8 @@ public class Code.Terminal : Gtk.Box { private const string GNOME_BELL_KEY = "audible-bell"; public Vte.Terminal terminal { get; construct; } - private Gtk.EventControllerKey key_controller; - private Gtk.GestureMultiPress button_controller; + // private Gtk.EventControllerKey key_controller; + // private Gtk.GestureClick button_controller; private Settings? terminal_settings = null; private Settings? gnome_interface_settings = null; private Settings? gnome_wm_settings = null; @@ -33,7 +33,8 @@ public class Code.Terminal : Gtk.Box { public SimpleActionGroup actions { get; construct; } private GLib.Pid child_pid; - private Gtk.Clipboard current_clipboard; + private Gdk.Clipboard current_clipboard; + private Menu menu_model; private Scratch.Application application; @@ -110,8 +111,7 @@ public class Code.Terminal : Gtk.Box { terminal.child_exited.connect (() => { //Hide the exited terminal - var win_group = get_action_group (Scratch.MainWindow.ACTION_GROUP); - win_group.activate_action (Scratch.MainWindow.ACTION_TOGGLE_TERMINAL, null); + activate_action (Scratch.MainWindow.ACTION_PREFIX + Scratch.MainWindow.ACTION_TOGGLE_TERMINAL, null); //Get ready to resume at last saved location spawn_shell (Scratch.saved_state.get_string ("last-opened-path")); //Clear screen of new shell @@ -134,40 +134,40 @@ public class Code.Terminal : Gtk.Box { menu_model.append (_("Copy"), ACTION_COPY); menu_model.append (_("Paste"), ACTION_PASTE); - var menu = new Gtk.PopoverMenu () { - modal = true, - relative_to = terminal, + var menu = new Gtk.PopoverMenu.from_model (menu_model) { position = RIGHT }; - menu.bind_model (menu_model, ACTION_GROUP); - key_controller = new Gtk.EventControllerKey (terminal) { + var key_controller = new Gtk.EventControllerKey () { propagation_phase = BUBBLE }; + terminal.add_controller (key_controller); key_controller.key_pressed.connect (key_pressed); - // Cannot use event controller in Gtk3 because of https://gitlab.gnome.org/GNOME/gtk/-/issues/7225 - terminal.enter_notify_event.connect (() => { - if (!terminal.has_focus) { + var focus_controller = new Gtk.EventControllerFocus (); + add_controller (focus_controller); + focus_controller.enter.connect (() => { + if (!terminal.has_focus) { terminal.grab_focus (); } }); - button_controller = new Gtk.GestureMultiPress (terminal) { + var button_controller = new Gtk.GestureClick () { propagation_phase = CAPTURE, button = 0 }; + add_controller (button_controller); button_controller.pressed.connect ((n, x, y) => { var event = button_controller.get_last_event (null); if (event.triggers_context_menu ()) { - paste_action.set_enabled (current_clipboard.wait_is_text_available ()); + paste_action.set_enabled (current_clipboard.content != null); menu.pointing_to = Gdk.Rectangle () {x = (int)x, y = (int)y, height = 1, width = 1}; menu.popup (); } }); realize.connect (() => { - current_clipboard = terminal.get_clipboard (Gdk.SELECTION_CLIPBOARD); + current_clipboard = terminal.get_clipboard (); copy_action.set_enabled (terminal.get_has_selection ()); }); @@ -177,11 +177,11 @@ public class Code.Terminal : Gtk.Box { spawn_shell (Scratch.saved_state.get_string ("last-opened-path")); - var scrolled_window = new Gtk.ScrolledWindow (null, terminal.get_vadjustment ()); - scrolled_window.add (terminal); + var scrolled_window = new Gtk.ScrolledWindow () { + vadjustment = terminal.get_vadjustment () + }; - add (scrolled_window); - show_all (); + append (scrolled_window); } private void spawn_shell (string dir = GLib.Environment.get_current_dir ()) { @@ -317,36 +317,38 @@ public class Code.Terminal : Gtk.Box { terminal.font_scale = 1.0; } - private bool key_pressed (uint keyval, uint keycode, Gdk.ModifierType modifiers) { - // Use hardware keycodes so the key used is unaffected by internationalized layout - bool match_keycode (uint keyval, uint code) { - Gdk.KeymapKey[] keys; + private bool key_pressed (uint keyval, uint keycode, Gdk.ModifierType state) { + // // Use hardware keycodes so the key used is unaffected by internationalized layout + // bool match_keycode (uint keyval, uint code) { + // Gdk.KeymapKey[] keys; - var keymap = Gdk.Keymap.get_for_display (get_display ()); - if (keymap.get_entries_for_keyval (keyval, out keys)) { - foreach (var key in keys) { - if (code == key.keycode) { - return Gdk.EVENT_STOP; - } - } - } + // var keymap = Gdk.Keymap.get_for_display (get_display ()); + // if (keymap.get_entries_for_keyval (keyval, out keys)) { + // foreach (var key in keys) { + // if (code == key.keycode) { + // return Gdk.EVENT_STOP; + // } + // } + // } + + // return Gdk.EVENT_PROPAGATE; + // } - return Gdk.EVENT_PROPAGATE; - } - if (CONTROL_MASK in modifiers && (SHIFT_MASK in modifiers || + if (CONTROL_MASK in state && (SHIFT_MASK in state || terminal_settings != null && terminal_settings.get_boolean ("natural-copy-paste"))) { - if (match_keycode (Gdk.Key.c, keycode) && terminal.get_has_selection ()) { + // Assume actions already enabled/disabled as appropriate + if (keyval == Gdk.Key.c) { actions.activate_action (ACTION_COPY, null); - return Gdk.EVENT_STOP; - } else if (match_keycode (Gdk.Key.v, keycode) && current_clipboard.wait_is_text_available ()) { + return true; + } else if (keyval == Gdk.Key.v) { actions.activate_action (ACTION_PASTE, null); - return Gdk.EVENT_STOP; + return true; } } - return Gdk.EVENT_PROPAGATE; + return false; } } diff --git a/src/Widgets/TreeList/TreeList.vala b/src/Widgets/TreeList/TreeList.vala new file mode 100644 index 000000000..b5830733f --- /dev/null +++ b/src/Widgets/TreeList/TreeList.vala @@ -0,0 +1,197 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 20126 elementary, Inc. + */ + +public class Code.TreeList : Gtk.Box { + private Gtk.ListView list_view; + protected GLib.ListStore root_model; + private Gtk.TreeListModel tree_model; + protected Gtk.SelectionModel selection_model; + + public bool activate_on_single_click { get; set; } + + public signal void item_activated (TreeListItem item); + // public TreeListItem? selected { get; set; } // Selection handled by SelectionModel + + construct { + root_model = new GLib.ListStore (typeof (TreeListItem)); + // Passthrough false (create Gtk.TreeListRows), autoexpand false + tree_model = new Gtk.TreeListModel (root_model, false, false, create_model_func); + selection_model = new Gtk.SingleSelection (tree_model); + var tree_list_factory = new Gtk.SignalListItemFactory (); + var tree_header_factory = new Gtk.SignalListItemFactory (); + list_view = new Gtk.ListView (selection_model, tree_list_factory) { + header_factory = tree_header_factory + }; + + bind_property ("activate-on-single-click", list_view, "activate-on-single-click", BIDIRECTIONAL | SYNC_CREATE); + list_view.activate.connect ((pos) => { + item_activated ((TreeListItem) selection_model.get_item (pos)); + }); + // LIST ITEM FACTORY HANDLERS + tree_list_factory.setup.connect ((obj) => { + var listitem = (Gtk.ListItem) obj; + create_listitem_child (listitem); + // By default just create a use a label (not expandable) + }); + tree_list_factory.teardown.connect ((obj) => { + var listitem = (Gtk.ListItem) obj; + teardown_listitem_child (listitem); + }); + tree_list_factory.bind.connect ((obj) => { + var listitem = (Gtk.ListItem) obj; + var treelistrow = (Gtk.TreeListRow) (listitem.get_item ()); + var data = (Code.TreeListItem) (treelistrow.get_item ()); + bind_data_to_row (data, treelistrow, listitem); + }); + tree_list_factory.unbind.connect ((obj) => { + var listitem = (Gtk.ListItem) obj; + var treelistrow = (Gtk.TreeListRow) (listitem.item); + var data = (Code.TreeListItem) (treelistrow.item); + unbind_data_from_row (data, treelistrow, listitem); + }); + + // HEADER FACTORY HANDLERS + tree_header_factory.setup.connect ((obj) => { + // By default create header and subheader, expandable + var listitem = (Gtk.ListItem) obj; + create_headeritem_child (listitem); + }); + tree_header_factory.bind.connect ((obj) => { + var listitem = (Gtk.ListItem) obj; + var treelistrow = (Gtk.TreeListRow) listitem.item; + var data = (Code.TreeListItem) treelistrow.item; + }); + tree_header_factory.unbind.connect (() => {}); + tree_header_factory.teardown.connect (() => {}); + + append (list_view); + } + + protected virtual void create_listitem_child (Gtk.ListItem item) { + var label = new Gtk.Label ("") { + halign = START, + }; + label.add_css_class (Granite.STYLE_CLASS_H4_LABEL); + item.child = label; + } + protected virtual void teardown_listitem_child (Gtk.ListItem item) { + // Must be paired with create_listitem child + } + protected virtual void bind_data_to_row ( + TreeListItem data, + Gtk.TreeListRow row, + Gtk.ListItem item) { + // Must be matched with create item widget when overriding + var label = (Gtk.Label)(item.child); + label.label = data.text; + } + protected virtual void unbind_data_from_row ( + TreeListItem data, + Gtk.TreeListRow row, + Gtk.ListItem item + ) { + //Must undo any signal connections etc made in bind_data_to_row + } + + protected virtual void create_headeritem_child (Gtk.ListItem item) { + var text_label = new Gtk.Label ("") { + halign = START, + }; + text_label.add_css_class (Granite.STYLE_CLASS_H3_LABEL); + var subtext_label = new Gtk.Label ("") { + halign = START + }; + subtext_label.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL); + var box = new Gtk.Box (VERTICAL, 0); + box.append (text_label); + box.append (subtext_label); + var expander = new Gtk.TreeExpander () { + child = box, + }; + item.child = expander; + } + protected virtual void teardown_headeritem_child () { + // Must be paired with create_listitem child + } + protected virtual void bind_data_to_headeritem ( + TreeListItem data, + Gtk.TreeListRow row, + Gtk.ListItem item + ) { + var expander = (Gtk.TreeExpander) item.child; + var box = (Gtk.Box) expander.get_child (); + var text_label = (Gtk.Label) box.get_first_child (); + var subtext_label = (Gtk.Label) text_label.get_next_sibling (); + text_label.label = data.text; + subtext_label.label = data.sub_text; + } + + protected virtual void unbind_data_from_headerrow ( + TreeListItem data, + Gtk.TreeListRow row, + Gtk.ListItem item + ) { + //Must undo any signal connections etc made in bind_data_to_row + } + + public ListModel? create_model_func (Object item) { + var data = (TreeListItem) item; + if (data.is_expandable && data.child_model == null) { + data.child_model = new GLib.ListStore (typeof (TreeListItem)); + } + + return data.child_model; + } + + // Root items must generally be expandable + public TreeListItem add_root_item ( + TreeListItem item + ) { + root_model.append (item); + return item; + } + + public void remove_root_item (TreeListItem item) { + uint pos; + if (root_model.find (item, out pos)) { + root_model.remove (pos); + } + } + + public void remove_root_children (List to_remove) { + foreach (TreeListItem item in to_remove) { + uint pos; + if (root_model.find (item, out pos)) { + root_model.remove (pos); + } + } + } + + public void sort_root_children (CompareDataFunc sort_func) { + root_model.sort (sort_func); + } + + public uint n_root_items () { + return root_model.get_n_items (); + } + + public delegate bool ListIteratorCallback (TreeListItem item); + public static bool ITERATE_CONTINUE = true; + public static bool ITERATE_STOP = false; + public void iterate_children (TreeListItem? start, ListIteratorCallback cb) { + ListModel model; + if (start == null) { + model = root_model; + } else { + model = start.child_model; + } + + TreeListItem? item = null; + uint pos = 0; + do { + item = (TreeListItem?) (model.get_object (pos++)); + } while (item != null && cb (item)); + } + } diff --git a/src/Widgets/TreeList/TreeListItem.vala b/src/Widgets/TreeList/TreeListItem.vala new file mode 100644 index 000000000..296ba47bc --- /dev/null +++ b/src/Widgets/TreeList/TreeListItem.vala @@ -0,0 +1,118 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 20126 elementary, Inc. + */ + +// Subclass to provide additional functions required for project list, symbol list etc +public class Code.TreeListItem : Object { + public string text { get; set; default = ""; } //This can include markup + public string sub_text { get; set; default = ""; } //This can include markup? + public string tooltip { get; set; default = ""; } + public Icon? icon { get; set; default = null;} + public Icon? secondary_icon { get; set; default = null;} + public string secondary_icon_tooltip { get; set; default = ""; } + public string badge = ""; // Use label styled with Granite.STYLE_CLASS_BADGE? + + public ListStore? child_model { get; set; default = null; } + public TreeListItem? parent { get; set; default = null; } + public bool is_expandable { get; construct; } + public bool is_expanded { get; set; } // gets bound to the ListItem (temporarily) + public Binding expanded_binding { get; set; } // Need to save bind so we can unbind + public bool is_activatable { get; set; default = true; } + public bool is_selectable { get; set; default = true; } + public bool is_editable { get; set; default = false; } + public bool is_dummy { get; construct; } + + public signal void child_added (TreeListItem item); // To emulate source list + + public TreeListItem () { + Object ( + is_dummy: false, + is_expandable: false + ); + } + + public TreeListItem.dummy () { + Object ( + is_dummy: true, + is_expandable: false + ); + } + + public TreeListItem.expandable () { + Object ( + is_dummy: false, + is_expandable: true + ); + } + + public ListModel create_child_model () { + child_model = new ListStore (typeof (TreeListItem)); + return child_model; + } + + public virtual void add_child (TreeListItem child) { + if (child_model == null) { + create_child_model (); + } + + child_model.insert_sorted (child, (a, b) => { + return strcmp (((TreeListItem) a).text, ((TreeListItem) b).text); + }); + + child_added (child); + } + + public virtual void remove_child (TreeListItem child) requires (child_model != null) { + uint pos; + if (child_model.find (child, out pos)) { + child_model.remove (pos); + } + } + + public void remove_all_children () { + if (child_model != null) { + child_model.remove_all (); + } + } + + public bool has_no_children () requires (child_model != null) { + return child_model.n_items == 0; + } + + public TreeListItem? get_nth_child (uint pos) { + return (TreeListItem?) child_model.get_object (pos); + } + + /** + * Collapses the item and/or its children. + * + * @param inclusive Whether to also collapse this item (true), or only its children (false). + * @param recursive Whether to recursively collapse all the children (true), or only + * immediate children (false). + */ + public void collapse_all ( + bool inclusive, + bool recursive, + uint level = 0 + ) requires (child_model != null){ + TreeListItem? child = null; + uint pos = 0; + do { + child = (TreeListItem?) (child_model.get_object (pos++)); + if (child.is_expandable) { + if (recursive) { + child.collapse_all (true, true, level++); + } else { + child.is_expanded = false; + } + } + } while (child != null); + + if (level == 0 && inclusive) { + is_expanded = false; + } else { + level--; + } + } +} diff --git a/src/Widgets/WelcomeView.vala b/src/Widgets/WelcomeView.vala index 49975f03e..01094de99 100644 --- a/src/Widgets/WelcomeView.vala +++ b/src/Widgets/WelcomeView.vala @@ -17,31 +17,32 @@ * Authored by: Corentin Noël */ -public class Code.WelcomeView : Granite.Widgets.Welcome { +public class Code.WelcomeView : Granite.Placeholder { public unowned Scratch.MainWindow window { get; construct; } public WelcomeView (Scratch.MainWindow window) { Object ( window: window, title: _("No Files Open"), - subtitle: _("Open a file to begin editing.") + description: _("Open a file to begin editing.") ); } construct { - append ("document-new", _("New File"), _("Create a new empty file.")); - append ("document-open", _("Open File"), _("Open a saved file.")); - append ("open-project", _("Open Folder"), _("Add a project folder to the sidebar.")); + var new_button = append_button (new ThemedIcon ("document-new"), _("New File"), _("Create a new empty file.")); + var open_button = append_button (new ThemedIcon ("document-open"), _("Open File"), _("Open a saved file.")); + var project_button = append_button (new ThemedIcon ("open-project"), _("Open Folder"), _("Add a project folder to the sidebar.")); - activated.connect ((i) => { - // New file - if (i == 0) { - Scratch.Utils.action_from_group (Scratch.MainWindow.ACTION_NEW_TAB, window.actions).activate (null); - } else if (i == 1) { - Scratch.Utils.action_from_group (Scratch.MainWindow.ACTION_OPEN, window.actions).activate (null); - } else if (i == 2) { - Scratch.Utils.action_from_group (Scratch.MainWindow.ACTION_OPEN_PROJECT, window.actions).activate (null); - } + new_button.clicked.connect (() => { + Scratch.Utils.action_from_group (Scratch.MainWindow.ACTION_NEW_TAB, window.actions).activate (null); + }); + + open_button.clicked.connect (() => { + Scratch.Utils.action_from_group (Scratch.MainWindow.ACTION_OPEN, window.actions).activate (null); + }); + + project_button.clicked.connect (() => { + Scratch.Utils.action_from_group (Scratch.MainWindow.ACTION_OPEN_PROJECT, window.actions).activate (null); }); } } diff --git a/src/codecore.deps b/src/codecore.deps index dcfdbb461..97238c26a 100644 --- a/src/codecore.deps +++ b/src/codecore.deps @@ -1,8 +1,10 @@ codecore -gtksourceview-4 -gee-0.8 +glib-2.0 gobject-2.0 gio-2.0 -gtk+-3.0 -granite -libpeas-1.0 +libadwaita-1 +granite-7 +gee-0.8 +libpeas-2 +gtksourceview-5 + diff --git a/src/meson.build b/src/meson.build index e58f5eb72..66d547b2e 100644 --- a/src/meson.build +++ b/src/meson.build @@ -45,6 +45,8 @@ code_files = files( 'Services/PluginManager.vala', 'Services/RestoreOverride.vala', 'Services/Settings.vala', + 'Widgets/TreeList/TreeList.vala', + 'Widgets/TreeList/TreeListItem.vala', 'Widgets/ChooseProjectButton.vala', 'Widgets/DocumentView.vala', 'Widgets/FormatBar.vala',