From 221d46a28e02167778b59abeec30452587b591bc Mon Sep 17 00:00:00 2001 From: Alain Date: Mon, 30 Sep 2024 05:28:10 -0500 Subject: [PATCH] feat: add new filerow widget --- src/Frontend/Widgets/FilePane.vala | 106 +++------------- src/Frontend/Widgets/FileRow.vala | 195 +++++++++++++++++++++++++++++ src/Frontend/Widgets/PathBar.vala | 19 ++- src/meson.build | 1 + 4 files changed, 228 insertions(+), 93 deletions(-) create mode 100644 src/Frontend/Widgets/FileRow.vala diff --git a/src/Frontend/Widgets/FilePane.vala b/src/Frontend/Widgets/FilePane.vala index b258c7d..2a6611c 100644 --- a/src/Frontend/Widgets/FilePane.vala +++ b/src/Frontend/Widgets/FilePane.vala @@ -21,7 +21,6 @@ namespace Taxi { private PathBar path_bar; private Gtk.ListBox list_box; private Gtk.Stack stack; - private Gtk.Popover menu_popover; public signal void file_dragged (string uri); public signal void transfer (string uri); @@ -80,9 +79,11 @@ namespace Taxi { child = toolbar; - list_box.row_activated.connect ((row) => { - var uri = row.get_data ("uri"); - var type = row.get_data ("type"); + list_box.row_activated.connect ((value) => { + var row = (FileRow) value; + + var uri = row.uri; + var type = row.file_type; if (type == FileType.DIRECTORY) { navigate (uri); } else { @@ -93,11 +94,11 @@ namespace Taxi { path_bar.navigate.connect (uri => navigate (uri)); path_bar.transfer.connect (on_pathbar_transfer); - var drop_target = new Gtk.DropTarget (typeof (Gtk.ListBoxRow), Gdk.DragAction.COPY); + var drop_target = new Gtk.DropTarget (typeof (FileRow), Gdk.DragAction.COPY); list_box.add_controller (drop_target); drop_target.drop.connect ((value, x, y) => { - var row = (Gtk.ListBoxRow) value; - var uri = row.get_data ("uri"); + var row = (FileRow) value; + var uri = row.uri; if (uri != null) { file_dragged (uri.to_string ()); @@ -121,8 +122,8 @@ namespace Taxi { do { row = list_box.get_row_at_index (row_index); - if (row.get_data ("checkbutton").get_active ()) { - uri_list.add (current_uri.to_string () + "/" + row.get_data ("name")); + if (((FileRow)row).active) { + uri_list.add (current_uri.to_string () + "/" + ((FileRow)row).file_name); } row_index++; @@ -135,14 +136,20 @@ namespace Taxi { clear_children (list_box); // Have to convert to gee list because glib list sort function is buggy // (it randomly removes items...) - var gee_list = glib_to_gee (file_list); + var gee_list = glib_to_gee (file_list); alphabetical_order (gee_list); - foreach (FileInfo file_info in gee_list) { + foreach (GLib.FileInfo file_info in gee_list) { if (file_info.get_name ().get_char (0) == '.') { continue; } - var row = new_row (file_info); + var row = new FileRow (file_info); + row.current_uri = current_uri; + row.on_checkbutton_toggle.connect (on_checkbutton_toggle); + row.on_delete.connect (() => { + + }); + if (row != null) { list_box.append (row); } @@ -173,71 +180,6 @@ namespace Taxi { }); } - private Gtk.ListBoxRow? new_row (FileInfo file_info) { - var checkbox = new Gtk.CheckButton (); - checkbox.toggled.connect (on_checkbutton_toggle); - - var icon = new Gtk.Image.from_gicon (file_info.get_icon ()); - - var name = new Gtk.Label (file_info.get_name ()); - name.halign = Gtk.Align.START; - name.hexpand = true; - - var row = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6) { - hexpand = true, - margin_top = 6, - margin_bottom = 6, - margin_start = 12, - margin_end = 12 - }; - row.append (checkbox); - row.append (icon); - row.append (name); - - if (file_info.get_file_type () == FileType.REGULAR) { - var size = new Gtk.Label (bit_string_format (file_info.get_size ())); - size.add_css_class (Granite.STYLE_CLASS_DIM_LABEL); - row.append (size); - } - - GLib.Uri uri; - try { - uri = GLib.Uri.parse_relative (current_uri, file_info.get_name (), PARSE_RELAXED); - } catch (Error e) { - message (e.message); - return null; - } - - var ebrow = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); - ebrow.append (row); - ebrow.set_data ("name", file_info.get_name ()); - ebrow.set_data ("type", file_info.get_file_type ()); - - var lbrow = new Gtk.ListBoxRow () { - hexpand = true, - child = ebrow - }; - lbrow.set_data ("uri", uri); - lbrow.set_data ("name", file_info.get_name ()); - lbrow.set_data ("type", file_info.get_file_type ()); - lbrow.set_data ("checkbutton", checkbox); - - var drag_source = new Gtk.DragSource (); - drag_source.set_actions (Gdk.DragAction.COPY); - lbrow.add_controller (drag_source); - - drag_source.prepare.connect ((x, y) => { - return new Gdk.ContentProvider.for_value (lbrow); - }); - - drag_source.drag_begin.connect ((source, drag) => { - var paintable = new Gtk.WidgetPaintable (lbrow); - source.set_icon (paintable, 0, 0); - }); - - return lbrow; - } - private void on_checkbutton_toggle () { if (get_marked_row_uris ().size > 0) { path_bar.transfer_button_sensitive = true; @@ -262,15 +204,5 @@ namespace Taxi { public void stop_spinner () { stack.visible_child_name = "list"; } - - private string bit_string_format (int64 bytes) { - var floatbytes = (float) bytes; - int i; - for (i = 0; floatbytes >= 1000.0f || i > 6; i++) { - floatbytes /= 1000.0f; - } - string[] measurement = { "bytes", "kB", "MB", "GB", "TB", "PB", "EB" }; - return "%.3g %s".printf (floatbytes, measurement [i]); - } } } diff --git a/src/Frontend/Widgets/FileRow.vala b/src/Frontend/Widgets/FileRow.vala new file mode 100644 index 0000000..9a4f0dd --- /dev/null +++ b/src/Frontend/Widgets/FileRow.vala @@ -0,0 +1,195 @@ +/*** + Copyright (C) 2014 Kiran John Hampal + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License version 3, as published + by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranties of + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program. If not, see +***/ + +namespace Taxi { + + class FileRow : Gtk.ListBoxRow { + public GLib.FileInfo file_info { get; construct; } + + private Gtk.CheckButton checkbox; + private Gtk.Popover menu_popover; + + GLib.Uri _current_uri; + public GLib.Uri current_uri { + get { + return _current_uri; + } + + set { + _current_uri = value; + } + } + + GLib.Uri _uri; + public GLib.Uri? uri { + get { + try { + _uri = GLib.Uri.parse_relative (current_uri, file_info.get_name (), PARSE_RELAXED); + } catch (Error e) { + message (e.message); + } + + return _uri; + } + } + + public string file_name { + get { + return file_info.get_name (); + } + } + + public GLib.FileType file_type { + get { + return file_info.get_file_type (); + } + } + + public bool active { + get { + return checkbox.active; + } + } + + public signal void on_checkbutton_toggle (); + public signal void on_delete (); + + public FileRow (GLib.FileInfo file_info) { + Object ( + file_info: file_info + ); + } + + construct { + checkbox = new Gtk.CheckButton (); + checkbox.toggled.connect (() => { + on_checkbutton_toggle (); + }); + + var icon = new Gtk.Image.from_gicon (file_info.get_icon ()) { + pixel_size = 24 + }; + + var name = new Gtk.Label (file_info.get_name ()); + name.halign = Gtk.Align.START; + name.hexpand = true; + + var row = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6) { + hexpand = true, + margin_top = 6, + margin_bottom = 6, + margin_start = 12, + margin_end = 12 + }; + row.append (checkbox); + row.append (icon); + row.append (name); + + if (file_info.get_file_type () == FileType.REGULAR) { + var size = new Gtk.Label (bit_string_format (file_info.get_size ())); + size.add_css_class (Granite.STYLE_CLASS_DIM_LABEL); + row.append (size); + } + + child = row; + build_dnd (); + + var menu_gesture = new Gtk.GestureClick () { + button = 3 + }; + add_controller (menu_gesture); + menu_gesture.pressed.connect ((n_press, x, y) => { + build_context_menu (x, y); + }); + } + + private void build_context_menu (double x, double y) { + if (menu_popover != null) { + menu_popover.pointing_to = { ((int) x), (int) y, 1, 1 }; + menu_popover.popup (); + return; + } + + var open_menu = new Gtk.Button () { + child = new Gtk.Label (_("Open")) { + halign = START + }, + css_classes = { Granite.STYLE_CLASS_MENUITEM } + }; + + var delete_menu = new Gtk.Button () { + child = new Gtk.Label (_("Delete")) { + halign = START + }, + css_classes = { Granite.STYLE_CLASS_MENUITEM } + }; + + var menu_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0) { + margin_top = 3, + margin_bottom = 3 + }; + + menu_box.append (open_menu); + menu_box.append (delete_menu); + + menu_popover = new Gtk.Popover () { + has_arrow = false, + halign = Gtk.Align.START, + child = menu_box, + width_request = 250 + }; + + menu_popover.set_parent (this); + menu_popover.pointing_to = { ((int) x), (int) y, 1, 1 }; + menu_popover.popup (); + + open_menu.clicked.connect (() => { + menu_popover.popdown (); + open_menu.activate_action_variant ("win.open", new Variant.string (uri.to_string ())); + }); + + delete_menu.clicked.connect (() => { + menu_popover.popdown (); + open_menu.activate_action_variant ("win.delete", new Variant.string (uri.to_string ())); + }); + } + + private void build_dnd () { + var drag_source = new Gtk.DragSource (); + drag_source.set_actions (Gdk.DragAction.COPY); + add_controller (drag_source); + + drag_source.prepare.connect ((x, y) => { + return new Gdk.ContentProvider.for_value (this); + }); + + drag_source.drag_begin.connect ((source, drag) => { + var paintable = new Gtk.WidgetPaintable (this); + source.set_icon (paintable, 0, 0); + }); + } + + private string bit_string_format (int64 bytes) { + var floatbytes = (float) bytes; + int i; + for (i = 0; floatbytes >= 1000.0f || i > 6; i++) { + floatbytes /= 1000.0f; + } + string[] measurement = { "bytes", "kB", "MB", "GB", "TB", "PB", "EB" }; + return "%.3g %s".printf (floatbytes, measurement [i]); + } + } +} \ No newline at end of file diff --git a/src/Frontend/Widgets/PathBar.vala b/src/Frontend/Widgets/PathBar.vala index 1805166..b966994 100644 --- a/src/Frontend/Widgets/PathBar.vala +++ b/src/Frontend/Widgets/PathBar.vala @@ -41,7 +41,9 @@ namespace Taxi { } private void add_path_frag (string child, string path) { - var button = new Gtk.Button (); + var button = new Gtk.Button () { + valign = CENTER + }; if (path == "/") { button.child = new Gtk.Image.from_icon_name (child); @@ -61,9 +63,8 @@ namespace Taxi { append (sep); } - var button_style_context = button.get_style_context (); - button_style_context.add_class (Granite.STYLE_CLASS_FLAT); - button_style_context.add_class ("path-button"); + button.add_css_class (Granite.STYLE_CLASS_FLAT); + button.add_css_class ("path-button"); button.clicked.connect (() => { try { @@ -96,12 +97,18 @@ namespace Taxi { } set_path_helper (uri.get_path ()); - var transfer_button = new Gtk.Button.from_icon_name (transfer_icon_name); + var transfer_button = new Gtk.Button.from_icon_name (transfer_icon_name) { + valign = CENTER + }; transfer_button.halign = Gtk.Align.END; transfer_button.hexpand = true; transfer_button.sensitive = false; transfer_button.tooltip_text = _("Transfer"); - transfer_button.bind_property ("sensitive", this, "transfer-button-sensitive", GLib.BindingFlags.BIDIRECTIONAL); + transfer_button.bind_property ( + "sensitive", this, + "transfer-button-sensitive", + GLib.BindingFlags.BIDIRECTIONAL + ); transfer_button.add_css_class (Granite.STYLE_CLASS_FLAT); transfer_button.clicked.connect (() => transfer ()); diff --git a/src/meson.build b/src/meson.build index af54f39..183aa46 100644 --- a/src/meson.build +++ b/src/meson.build @@ -19,6 +19,7 @@ executable( 'Frontend/Widgets/FilePane.vala', 'Frontend/Widgets/OperationsPopover.vala', 'Frontend/Widgets/PathBar.vala', + 'Frontend/Widgets/FileRow.vala', gresource, dependencies: [ dependency('glib-2.0'),