Merge Stable Changesto Master #9
@@ -7,12 +7,12 @@ gi.require_version('Gtk', '3.0')
 | 
				
			|||||||
from gi.repository import Gtk, GLib
 | 
					from gi.repository import Gtk, GLib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Application imports
 | 
					# Application imports
 | 
				
			||||||
 | 
					from widgets.context_menu_widget import ContextMenuWidget
 | 
				
			||||||
from .mixins.exception_hook_mixin import ExceptionHookMixin
 | 
					from .mixins.exception_hook_mixin import ExceptionHookMixin
 | 
				
			||||||
from .mixins.ui_mixin import UIMixin
 | 
					from .mixins.ui_mixin import UIMixin
 | 
				
			||||||
from .signals.ipc_signals_mixin import IPCSignalsMixin
 | 
					from .signals.ipc_signals_mixin import IPCSignalsMixin
 | 
				
			||||||
from .signals.keyboard_signals_mixin import KeyboardSignalsMixin
 | 
					from .signals.keyboard_signals_mixin import KeyboardSignalsMixin
 | 
				
			||||||
from .controller_data import Controller_Data
 | 
					from .controller_data import Controller_Data
 | 
				
			||||||
from .context_menu import ContextMenu
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,7 +23,7 @@ class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMi
 | 
				
			|||||||
        self.setup_controller_data()
 | 
					        self.setup_controller_data()
 | 
				
			||||||
        self.generate_windows(self.fm_controller_data)
 | 
					        self.generate_windows(self.fm_controller_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        cm = ContextMenu()
 | 
					        cm = ContextMenuWidget()
 | 
				
			||||||
        cm.build_context_menu()
 | 
					        cm.build_context_menu()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if args.no_plugins == "false":
 | 
					        if args.no_plugins == "false":
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,8 +9,9 @@ gi.require_version('Gdk', '3.0')
 | 
				
			|||||||
from gi.repository import Gtk, Gdk, GLib, Gio, GdkPixbuf
 | 
					from gi.repository import Gtk, Gdk, GLib, Gio, GdkPixbuf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Application imports
 | 
					# Application imports
 | 
				
			||||||
 | 
					from widgets.tab_header import TabHeader
 | 
				
			||||||
 | 
					from widgets.icon_grid_widget import IconGridWidget
 | 
				
			||||||
 | 
					from widgets.icon_tree_widget import IconTreeWidget
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# NOTE: Consider trying to use Gtk.TreeView with css that turns it into a grid...
 | 
					# NOTE: Consider trying to use Gtk.TreeView with css that turns it into a grid...
 | 
				
			||||||
@@ -47,7 +48,7 @@ class Icon(Gtk.HBox):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GridMixin:
 | 
					class GridMixin:
 | 
				
			||||||
    """docstring for WidgetMixin"""
 | 
					    """docstring for GridMixin"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def load_store(self, tab, store, save_state=False):
 | 
					    def load_store(self, tab, store, save_state=False):
 | 
				
			||||||
        store.clear()
 | 
					        store.clear()
 | 
				
			||||||
@@ -95,127 +96,50 @@ class GridMixin:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_tab_widget(self, tab):
 | 
					    def create_tab_widget(self, tab):
 | 
				
			||||||
        tab_widget = Gtk.ButtonBox()
 | 
					        return TabHeader(tab, self.close_tab)
 | 
				
			||||||
        label = Gtk.Label()
 | 
					 | 
				
			||||||
        tid   = Gtk.Label()
 | 
					 | 
				
			||||||
        close = Gtk.Button()
 | 
					 | 
				
			||||||
        icon  = Gtk.Image(stock=Gtk.STOCK_CLOSE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        label.set_label(f"{tab.get_end_of_path()}")
 | 
					 | 
				
			||||||
        label.set_width_chars(len(tab.get_end_of_path()))
 | 
					 | 
				
			||||||
        label.set_xalign(0.0)
 | 
					 | 
				
			||||||
        tid.set_label(f"{tab.get_id()}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        close.add(icon)
 | 
					 | 
				
			||||||
        tab_widget.add(label)
 | 
					 | 
				
			||||||
        tab_widget.add(close)
 | 
					 | 
				
			||||||
        tab_widget.add(tid)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        close.connect("released", self.close_tab)
 | 
					 | 
				
			||||||
        tab_widget.show_all()
 | 
					 | 
				
			||||||
        tid.hide()
 | 
					 | 
				
			||||||
        return tab_widget
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_scroll_and_store(self, tab, wid, use_tree_view=False):
 | 
					    def create_scroll_and_store(self, tab, wid, use_tree_view=False):
 | 
				
			||||||
 | 
					        scroll = Gtk.ScrolledWindow()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not use_tree_view:
 | 
					        if not use_tree_view:
 | 
				
			||||||
            scroll, store = self.create_icon_grid_widget(tab, wid)
 | 
					            grid = self.create_icon_grid_widget()
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            # TODO: Fix global logic to make the below work too
 | 
					            # TODO: Fix global logic to make the below work too
 | 
				
			||||||
            scroll, store = self.create_icon_tree_widget(tab, wid)
 | 
					            grid = self.create_icon_tree_widget()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return scroll, store
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def create_icon_grid_widget(self, tab, wid):
 | 
					 | 
				
			||||||
        scroll = Gtk.ScrolledWindow()
 | 
					 | 
				
			||||||
        grid   = Gtk.IconView()
 | 
					 | 
				
			||||||
        store  = Gtk.ListStore(GdkPixbuf.Pixbuf or GdkPixbuf.PixbufAnimation or None, str or None)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        grid.set_model(store)
 | 
					 | 
				
			||||||
        grid.set_pixbuf_column(0)
 | 
					 | 
				
			||||||
        grid.set_text_column(1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        grid.set_item_orientation(1)
 | 
					 | 
				
			||||||
        grid.set_selection_mode(3)
 | 
					 | 
				
			||||||
        grid.set_item_width(96)
 | 
					 | 
				
			||||||
        grid.set_item_padding(8)
 | 
					 | 
				
			||||||
        grid.set_margin(12)
 | 
					 | 
				
			||||||
        grid.set_row_spacing(18)
 | 
					 | 
				
			||||||
        grid.set_columns(-1)
 | 
					 | 
				
			||||||
        grid.set_spacing(12)
 | 
					 | 
				
			||||||
        grid.set_column_spacing(18)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        grid.connect("button_release_event", self.grid_icon_single_click)
 | 
					 | 
				
			||||||
        grid.connect("item-activated",       self.grid_icon_double_click)
 | 
					 | 
				
			||||||
        grid.connect("selection-changed",    self.grid_set_selected_items)
 | 
					 | 
				
			||||||
        grid.connect("drag-data-get",        self.grid_on_drag_set)
 | 
					 | 
				
			||||||
        grid.connect("drag-data-received",   self.grid_on_drag_data_received)
 | 
					 | 
				
			||||||
        grid.connect("drag-motion",          self.grid_on_drag_motion)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        URI_TARGET_TYPE  = 80
 | 
					 | 
				
			||||||
        uri_target       = Gtk.TargetEntry.new('text/uri-list', Gtk.TargetFlags(0), URI_TARGET_TYPE)
 | 
					 | 
				
			||||||
        targets          = [ uri_target ]
 | 
					 | 
				
			||||||
        action           = Gdk.DragAction.COPY
 | 
					 | 
				
			||||||
        grid.enable_model_drag_dest(targets, action)
 | 
					 | 
				
			||||||
        grid.enable_model_drag_source(0, targets, action)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        grid.show_all()
 | 
					 | 
				
			||||||
        scroll.add(grid)
 | 
					        scroll.add(grid)
 | 
				
			||||||
        grid.set_name(f"{wid}|{tab.get_id()}")
 | 
					 | 
				
			||||||
        scroll.set_name(f"{wid}|{tab.get_id()}")
 | 
					        scroll.set_name(f"{wid}|{tab.get_id()}")
 | 
				
			||||||
 | 
					        grid.set_name(f"{wid}|{tab.get_id()}")
 | 
				
			||||||
        self.builder.expose_object(f"{wid}|{tab.get_id()}|icon_grid", grid)
 | 
					        self.builder.expose_object(f"{wid}|{tab.get_id()}|icon_grid", grid)
 | 
				
			||||||
        self.builder.expose_object(f"{wid}|{tab.get_id()}", scroll)
 | 
					        self.builder.expose_object(f"{wid}|{tab.get_id()}", scroll)
 | 
				
			||||||
        return scroll, store
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_icon_tree_widget(self, tab, wid):
 | 
					        return scroll, grid.get_store()
 | 
				
			||||||
        scroll = Gtk.ScrolledWindow()
 | 
					 | 
				
			||||||
        grid   = Gtk.TreeView()
 | 
					 | 
				
			||||||
        store  = Gtk.TreeStore(GdkPixbuf.Pixbuf or GdkPixbuf.PixbufAnimation or None, str or None)
 | 
					 | 
				
			||||||
        column = Gtk.TreeViewColumn("Icons")
 | 
					 | 
				
			||||||
        icon   = Gtk.CellRendererPixbuf()
 | 
					 | 
				
			||||||
        name   = Gtk.CellRendererText()
 | 
					 | 
				
			||||||
        selec  = grid.get_selection()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        grid.set_model(store)
 | 
					    def create_icon_grid_widget(self):
 | 
				
			||||||
        selec.set_mode(3)
 | 
					        grid = IconGridWidget()
 | 
				
			||||||
        column.pack_start(icon, False)
 | 
					        grid._setup_additional_signals(
 | 
				
			||||||
        column.pack_start(name, True)
 | 
					            self.grid_icon_single_click,
 | 
				
			||||||
        column.add_attribute(icon, "pixbuf", 0)
 | 
					            self.grid_icon_double_click,
 | 
				
			||||||
        column.add_attribute(name, "text", 1)
 | 
					            self.grid_set_selected_items,
 | 
				
			||||||
        column.set_expand(False)
 | 
					            self.grid_on_drag_set,
 | 
				
			||||||
        column.set_sizing(2)
 | 
					            self.grid_on_drag_data_received,
 | 
				
			||||||
        column.set_min_width(120)
 | 
					            self.grid_on_drag_motion
 | 
				
			||||||
        column.set_max_width(74)
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        grid.append_column(column)
 | 
					        return grid
 | 
				
			||||||
        grid.set_search_column(1)
 | 
					 | 
				
			||||||
        grid.set_rubber_banding(True)
 | 
					 | 
				
			||||||
        grid.set_headers_visible(False)
 | 
					 | 
				
			||||||
        grid.set_enable_tree_lines(False)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        grid.connect("button_release_event", self.grid_icon_single_click)
 | 
					    def create_icon_tree_widget(self):
 | 
				
			||||||
        grid.connect("row-activated",        self.grid_icon_double_click)
 | 
					        grid = IconTreeWidget()
 | 
				
			||||||
        grid.connect("drag-data-get",        self.grid_on_drag_set)
 | 
					        grid._setup_additional_signals(
 | 
				
			||||||
        grid.connect("drag-data-received",   self.grid_on_drag_data_received)
 | 
					            self.grid_icon_single_click,
 | 
				
			||||||
        grid.connect("drag-motion",          self.grid_on_drag_motion)
 | 
					            self.grid_icon_double_click,
 | 
				
			||||||
 | 
					            self.grid_on_drag_set,
 | 
				
			||||||
 | 
					            self.grid_on_drag_data_received,
 | 
				
			||||||
 | 
					            self.grid_on_drag_motion
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        URI_TARGET_TYPE  = 80
 | 
					 | 
				
			||||||
        uri_target       = Gtk.TargetEntry.new('text/uri-list', Gtk.TargetFlags(0), URI_TARGET_TYPE)
 | 
					 | 
				
			||||||
        targets          = [ uri_target ]
 | 
					 | 
				
			||||||
        action           = Gdk.DragAction.COPY
 | 
					 | 
				
			||||||
        grid.enable_model_drag_dest(targets, action)
 | 
					 | 
				
			||||||
        grid.enable_model_drag_source(0, targets, action)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        grid.show_all()
 | 
					 | 
				
			||||||
        scroll.add(grid)
 | 
					 | 
				
			||||||
        grid.set_name(f"{wid}|{tab.get_id()}")
 | 
					 | 
				
			||||||
        scroll.set_name(f"{wid}|{tab.get_id()}")
 | 
					 | 
				
			||||||
        self.builder.expose_object(f"{wid}|{tab.get_id()}|icon_grid", grid)
 | 
					 | 
				
			||||||
        self.builder.expose_object(f"{wid}|{tab.get_id()}", scroll)
 | 
					 | 
				
			||||||
        grid.columns_autosize()
 | 
					        grid.columns_autosize()
 | 
				
			||||||
 | 
					        return grid
 | 
				
			||||||
        self.builder.expose_object(f"{wid}|{tab.get_id()}", scroll)
 | 
					 | 
				
			||||||
        return scroll, store
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_store_and_label_from_notebook(self, notebook, _name):
 | 
					    def get_store_and_label_from_notebook(self, notebook, _name):
 | 
				
			||||||
        icon_grid = None
 | 
					        icon_grid = None
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ gi.require_version('Gtk', '3.0')
 | 
				
			|||||||
from gi.repository import Gtk, GObject, GLib, Gio
 | 
					from gi.repository import Gtk, GObject, GLib, Gio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Application imports
 | 
					# Application imports
 | 
				
			||||||
 | 
					from widgets.io_widget import IOWidget
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -306,7 +307,6 @@ class WidgetFileActionMixin:
 | 
				
			|||||||
                    file.make_directory(cancellable=None)
 | 
					                    file.make_directory(cancellable=None)
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
                type = file.query_file_type(flags=Gio.FileQueryInfoFlags.NONE)
 | 
					                type = file.query_file_type(flags=Gio.FileQueryInfoFlags.NONE)
 | 
				
			||||||
                if type == Gio.FileType.DIRECTORY:
 | 
					                if type == Gio.FileType.DIRECTORY:
 | 
				
			||||||
                    wid, tid  = self.fm_controller.get_active_wid_and_tid()
 | 
					                    wid, tid  = self.fm_controller.get_active_wid_and_tid()
 | 
				
			||||||
@@ -320,79 +320,33 @@ class WidgetFileActionMixin:
 | 
				
			|||||||
                    if action == "move" or action == "rename":
 | 
					                    if action == "move" or action == "rename":
 | 
				
			||||||
                        tab.move_file(fPath, tPath)
 | 
					                        tab.move_file(fPath, tPath)
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    if action == "copy":
 | 
					                    io_widget = IOWidget(action, file)
 | 
				
			||||||
                        container, cancle_eve, update_progress, finish_callback = self.create_io_widget(action, file)
 | 
					 | 
				
			||||||
                        file.copy_async(destination=target, flags=Gio.FileCopyFlags.BACKUP,
 | 
					 | 
				
			||||||
                                        io_priority=98, cancellable=cancle_eve,
 | 
					 | 
				
			||||||
                                        progress_callback=update_progress, callback=finish_callback)
 | 
					 | 
				
			||||||
                        self.builder.get_object("io_list").add(container)
 | 
					 | 
				
			||||||
                    if action == "move" or action == "rename":
 | 
					 | 
				
			||||||
                        container, cancle_eve, update_progress, finish_callback = self.create_io_widget(action, file)
 | 
					 | 
				
			||||||
                        file.move_async(destination=target, flags=Gio.FileCopyFlags.BACKUP,
 | 
					 | 
				
			||||||
                                        io_priority=98, cancellable=cancle_eve,
 | 
					 | 
				
			||||||
                                        progress_callback=None, callback=finish_callback) # NOTE: progress_callback causes seg fault when set
 | 
					 | 
				
			||||||
                        self.builder.get_object("io_list").add(container)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if action == "copy":
 | 
				
			||||||
 | 
					                        file.copy_async(destination=target,
 | 
				
			||||||
 | 
					                                        flags=Gio.FileCopyFlags.BACKUP,
 | 
				
			||||||
 | 
					                                        io_priority=98,
 | 
				
			||||||
 | 
					                                        cancellable=io_widget.cancle_eve,
 | 
				
			||||||
 | 
					                                        progress_callback=io_widget.update_progress,
 | 
				
			||||||
 | 
					                                        callback=io_widget.finish_callback)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        self.builder.get_object("io_list").add(io_widget)
 | 
				
			||||||
 | 
					                    if action == "move" or action == "rename":
 | 
				
			||||||
 | 
					                        file.move_async(destination=target,
 | 
				
			||||||
 | 
					                                        flags=Gio.FileCopyFlags.BACKUP,
 | 
				
			||||||
 | 
					                                        io_priority=98,
 | 
				
			||||||
 | 
					                                        cancellable=io_widget.cancle_eve,
 | 
				
			||||||
 | 
					                                        progress_callback=None,
 | 
				
			||||||
 | 
					                                        # NOTE: progress_callback here causes seg fault when set
 | 
				
			||||||
 | 
					                                        callback=io_widget.finish_callback)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        self.builder.get_object("io_list").add(io_widget)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            except GObject.GError as e:
 | 
					            except GObject.GError as e:
 | 
				
			||||||
                raise OSError(e)
 | 
					                raise OSError(e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.exists_file_rename_bttn.set_sensitive(False)
 | 
					        self.exists_file_rename_bttn.set_sensitive(False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_io_widget(self, action, file):
 | 
					 | 
				
			||||||
        cancle_eve  = Gio.Cancellable.new()
 | 
					 | 
				
			||||||
        container   = Gtk.Box()
 | 
					 | 
				
			||||||
        stats       = Gtk.Box()
 | 
					 | 
				
			||||||
        label       = Gtk.Label()
 | 
					 | 
				
			||||||
        progress    = Gtk.ProgressBar()
 | 
					 | 
				
			||||||
        cncl_button = Gtk.Button(label="Cancel")
 | 
					 | 
				
			||||||
        del_button  = Gtk.Button(label="Clear")
 | 
					 | 
				
			||||||
        io_list     = self.builder.get_object("io_list")
 | 
					 | 
				
			||||||
        label.set_label(file.get_basename())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        progress.set_show_text(True)
 | 
					 | 
				
			||||||
        progress.set_text(f"{action.upper()}ING")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def do_cancel(widget, container, eve):
 | 
					 | 
				
			||||||
            print(f"Canceling: [{action}] of {file.get_basename()} ...")
 | 
					 | 
				
			||||||
            eve.cancel()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def update_progress(current, total, eve=None):
 | 
					 | 
				
			||||||
            progress.set_fraction(current/total)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def finish_callback(file, task=None, eve=None):
 | 
					 | 
				
			||||||
            if action == "move":
 | 
					 | 
				
			||||||
                status = file.move_finish(task)
 | 
					 | 
				
			||||||
            if action == "copy":
 | 
					 | 
				
			||||||
                status = file.copy_finish(task)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if status:
 | 
					 | 
				
			||||||
                self.builder.get_object("io_list").remove(container)
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                print(f"{action} of {file.get_basename()} failed...")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def delete_container(widget, eve):
 | 
					 | 
				
			||||||
            io_list.remove(container)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        stats.pack_end(del_button, False, False, 5)
 | 
					 | 
				
			||||||
        del_button.connect("clicked", delete_container, ())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if not action in ("create", "rename"):
 | 
					 | 
				
			||||||
            stats.pack_end(cncl_button, False, False, 5)
 | 
					 | 
				
			||||||
            cncl_button.connect("clicked", do_cancel, *(container, cancle_eve))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        container.set_orientation(1)
 | 
					 | 
				
			||||||
        stats.set_orientation(0)
 | 
					 | 
				
			||||||
        stats.add(progress)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        container.add(label)
 | 
					 | 
				
			||||||
        container.add(stats)
 | 
					 | 
				
			||||||
        container.show_all()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return container, cancle_eve, update_progress, finish_callback
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setup_exists_data(self, from_file, to_file):
 | 
					    def setup_exists_data(self, from_file, to_file):
 | 
				
			||||||
        from_info             = from_file.query_info("standard::*,time::modified", 0, cancellable=None)
 | 
					        from_info             = from_file.query_info("standard::*,time::modified", 0, cancellable=None)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					"""
 | 
				
			||||||
 | 
					    Widgets module
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
@@ -9,9 +9,11 @@ from gi.repository import GLib
 | 
				
			|||||||
# Application imports
 | 
					# Application imports
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ContextMenu(Gtk.Menu):
 | 
					class ContextMenuWidget(Gtk.Menu):
 | 
				
			||||||
 | 
					    """docstring for ContextMenuWidget"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
        super(ContextMenu, self).__init__()
 | 
					        super(ContextMenuWidget, self).__init__()
 | 
				
			||||||
        self._builder           = settings.get_builder()
 | 
					        self._builder           = settings.get_builder()
 | 
				
			||||||
        self._context_menu_data = settings.get_context_menu_data()
 | 
					        self._context_menu_data = settings.get_context_menu_data()
 | 
				
			||||||
        self._window            = settings.get_main_window()
 | 
					        self._window            = settings.get_main_window()
 | 
				
			||||||
@@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					# Python imports
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Lib imports
 | 
				
			||||||
 | 
					import gi
 | 
				
			||||||
 | 
					gi.require_version('Gtk', '3.0')
 | 
				
			||||||
 | 
					gi.require_version('Gdk', '3.0')
 | 
				
			||||||
 | 
					from gi.repository import Gtk, Gdk, GdkPixbuf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Application imports
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IconGridWidget(Gtk.IconView):
 | 
				
			||||||
 | 
					    """docstring for IconGridWidget"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        super(IconGridWidget, self).__init__()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._store = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._setup_styling()
 | 
				
			||||||
 | 
					        self._setup_signals()
 | 
				
			||||||
 | 
					        self._set_up_dnd()
 | 
				
			||||||
 | 
					        self._load_widgets()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.show_all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_store(self):
 | 
				
			||||||
 | 
					        return self._store
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _setup_styling(self):
 | 
				
			||||||
 | 
					        self.set_pixbuf_column(0)
 | 
				
			||||||
 | 
					        self.set_text_column(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.set_item_orientation(1)
 | 
				
			||||||
 | 
					        self.set_selection_mode(3)
 | 
				
			||||||
 | 
					        self.set_item_width(96)
 | 
				
			||||||
 | 
					        self.set_item_padding(8)
 | 
				
			||||||
 | 
					        self.set_margin(12)
 | 
				
			||||||
 | 
					        self.set_row_spacing(18)
 | 
				
			||||||
 | 
					        self.set_columns(-1)
 | 
				
			||||||
 | 
					        self.set_spacing(12)
 | 
				
			||||||
 | 
					        self.set_column_spacing(18)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _setup_signals(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _setup_additional_signals(self, grid_icon_single_click,
 | 
				
			||||||
 | 
					                                        grid_icon_double_click,
 | 
				
			||||||
 | 
					                                        grid_set_selected_items,
 | 
				
			||||||
 | 
					                                        grid_on_drag_set,
 | 
				
			||||||
 | 
					                                        grid_on_drag_data_received,
 | 
				
			||||||
 | 
					                                        grid_on_drag_motion):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.connect("button_release_event", grid_icon_single_click)
 | 
				
			||||||
 | 
					        self.connect("item-activated",       grid_icon_double_click)
 | 
				
			||||||
 | 
					        self.connect("selection-changed",    grid_set_selected_items)
 | 
				
			||||||
 | 
					        self.connect("drag-data-get",        grid_on_drag_set)
 | 
				
			||||||
 | 
					        self.connect("drag-data-received",   grid_on_drag_data_received)
 | 
				
			||||||
 | 
					        self.connect("drag-motion",          grid_on_drag_motion)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _load_widgets(self):
 | 
				
			||||||
 | 
					        self._store = Gtk.ListStore(GdkPixbuf.Pixbuf or GdkPixbuf.PixbufAnimation or None, str or None)
 | 
				
			||||||
 | 
					        self.set_model(self._store)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _set_up_dnd(self):
 | 
				
			||||||
 | 
					        URI_TARGET_TYPE  = 80
 | 
				
			||||||
 | 
					        uri_target       = Gtk.TargetEntry.new('text/uri-list', Gtk.TargetFlags(0), URI_TARGET_TYPE)
 | 
				
			||||||
 | 
					        targets          = [ uri_target ]
 | 
				
			||||||
 | 
					        action           = Gdk.DragAction.COPY
 | 
				
			||||||
 | 
					        self.enable_model_drag_dest(targets, action)
 | 
				
			||||||
 | 
					        self.enable_model_drag_source(0, targets, action)
 | 
				
			||||||
@@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					# Python imports
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Lib imports
 | 
				
			||||||
 | 
					import gi
 | 
				
			||||||
 | 
					gi.require_version('Gtk', '3.0')
 | 
				
			||||||
 | 
					gi.require_version('Gdk', '3.0')
 | 
				
			||||||
 | 
					from gi.repository import Gtk, Gdk, GdkPixbuf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Application imports
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IconTreeWidget(Gtk.TreeView):
 | 
				
			||||||
 | 
					    """docstring for IconTreeWidget"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        super(IconTreeWidget, self).__init__()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._store = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._setup_styling()
 | 
				
			||||||
 | 
					        self._setup_signals()
 | 
				
			||||||
 | 
					        self._set_up_dnd()
 | 
				
			||||||
 | 
					        self._load_widgets()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.show_all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_store(self):
 | 
				
			||||||
 | 
					        return self._store
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _setup_styling(self):
 | 
				
			||||||
 | 
					        self.set_search_column(1)
 | 
				
			||||||
 | 
					        self.set_rubber_banding(True)
 | 
				
			||||||
 | 
					        self.set_headers_visible(False)
 | 
				
			||||||
 | 
					        self.set_enable_tree_lines(False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _setup_signals(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _setup_additional_signals(self, grid_icon_single_click,
 | 
				
			||||||
 | 
					                                        grid_icon_double_click,
 | 
				
			||||||
 | 
					                                        grid_on_drag_set,
 | 
				
			||||||
 | 
					                                        grid_on_drag_data_received,
 | 
				
			||||||
 | 
					                                        grid_on_drag_motion):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.connect("button_release_event", self.grid_icon_single_click)
 | 
				
			||||||
 | 
					        self.connect("row-activated",        self.grid_icon_double_click)
 | 
				
			||||||
 | 
					        self.connect("drag-data-get",        self.grid_on_drag_set)
 | 
				
			||||||
 | 
					        self.connect("drag-data-received",   self.grid_on_drag_data_received)
 | 
				
			||||||
 | 
					        self.connect("drag-motion",          self.grid_on_drag_motion)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _load_widgets(self):
 | 
				
			||||||
 | 
					        self._store = Gtk.TreeStore(GdkPixbuf.Pixbuf or GdkPixbuf.PixbufAnimation or None, str or None)
 | 
				
			||||||
 | 
					        column = Gtk.TreeViewColumn("Icons")
 | 
				
			||||||
 | 
					        icon   = Gtk.CellRendererPixbuf()
 | 
				
			||||||
 | 
					        name   = Gtk.CellRendererText()
 | 
				
			||||||
 | 
					        selec  = self.get_selection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.set_model(store)
 | 
				
			||||||
 | 
					        selec.set_mode(3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        column.pack_start(icon, False)
 | 
				
			||||||
 | 
					        column.pack_start(name, True)
 | 
				
			||||||
 | 
					        column.add_attribute(icon, "pixbuf", 0)
 | 
				
			||||||
 | 
					        column.add_attribute(name, "text", 1)
 | 
				
			||||||
 | 
					        column.set_expand(False)
 | 
				
			||||||
 | 
					        column.set_sizing(2)
 | 
				
			||||||
 | 
					        column.set_min_width(120)
 | 
				
			||||||
 | 
					        column.set_max_width(74)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.append_column(column)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _set_up_dnd(self):
 | 
				
			||||||
 | 
					        URI_TARGET_TYPE  = 80
 | 
				
			||||||
 | 
					        uri_target       = Gtk.TargetEntry.new('text/uri-list', Gtk.TargetFlags(0), URI_TARGET_TYPE)
 | 
				
			||||||
 | 
					        targets          = [ uri_target ]
 | 
				
			||||||
 | 
					        action           = Gdk.DragAction.COPY
 | 
				
			||||||
 | 
					        self.enable_model_drag_dest(targets, action)
 | 
				
			||||||
 | 
					        self.enable_model_drag_source(0, targets, action)
 | 
				
			||||||
@@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					# Python imports
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Lib imports
 | 
				
			||||||
 | 
					import gi
 | 
				
			||||||
 | 
					gi.require_version('Gtk', '3.0')
 | 
				
			||||||
 | 
					from gi.repository import Gtk, Gio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Application imports
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IOWidget(Gtk.Box):
 | 
				
			||||||
 | 
					    """docstring for IOWidget"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, action, file):
 | 
				
			||||||
 | 
					        super(IOWidget, self).__init__()
 | 
				
			||||||
 | 
					        self._action    = action
 | 
				
			||||||
 | 
					        self._file      = file
 | 
				
			||||||
 | 
					        self._basename  = self._file.get_basename()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.cancle_eve = Gio.Cancellable.new()
 | 
				
			||||||
 | 
					        self.progress   = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._setup_styling()
 | 
				
			||||||
 | 
					        self._setup_signals()
 | 
				
			||||||
 | 
					        self._load_widgets()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.show_all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _setup_styling(self):
 | 
				
			||||||
 | 
					        self.set_orientation(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _setup_signals(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _load_widgets(self):
 | 
				
			||||||
 | 
					        stats         = Gtk.Box()
 | 
				
			||||||
 | 
					        label         = Gtk.Label()
 | 
				
			||||||
 | 
					        cncl_button   = Gtk.Button(label="Cancel")
 | 
				
			||||||
 | 
					        del_button    = Gtk.Button(label="Clear")
 | 
				
			||||||
 | 
					        self.progress = Gtk.ProgressBar()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        label.set_label(self._basename)
 | 
				
			||||||
 | 
					        self.progress.set_show_text(True)
 | 
				
			||||||
 | 
					        self.progress.set_text(f"{self._action.upper()}ING")
 | 
				
			||||||
 | 
					        stats.set_orientation(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        stats.pack_end(del_button, False, False, 5)
 | 
				
			||||||
 | 
					        del_button.connect("clicked", self.delete_self, ())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not self._action in ("create", "rename"):
 | 
				
			||||||
 | 
					            stats.pack_end(cncl_button, False, False, 5)
 | 
				
			||||||
 | 
					            cncl_button.connect("clicked", self.do_cancel, *(self, self.cancle_eve))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        stats.add(self.progress)
 | 
				
			||||||
 | 
					        self.add(label)
 | 
				
			||||||
 | 
					        self.add(stats)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def do_cancel(self, widget, container, eve):
 | 
				
			||||||
 | 
					        print(f"Canceling: [{self._action}] of {self._basename} ...")
 | 
				
			||||||
 | 
					        eve.cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_progress(self, current, total, eve=None):
 | 
				
			||||||
 | 
					        self.progress.set_fraction(current/total)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def finish_callback(self, file, task=None, eve=None):
 | 
				
			||||||
 | 
					        if self._action == "move" and self._action == "rename":
 | 
				
			||||||
 | 
					            status = self._file.move_finish(task)
 | 
				
			||||||
 | 
					        if self._action == "copy":
 | 
				
			||||||
 | 
					            status = self._file.copy_finish(task)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if status:
 | 
				
			||||||
 | 
					            self.delete_self()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            print(f"{self._action} of {self._basename} failed...")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete_self(self, widget=None, eve=None):
 | 
				
			||||||
 | 
					        self.get_parent().remove(self)
 | 
				
			||||||
@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					# Python imports
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Lib imports
 | 
				
			||||||
 | 
					import gi
 | 
				
			||||||
 | 
					gi.require_version('Gtk', '3.0')
 | 
				
			||||||
 | 
					from gi.repository import Gtk, Gio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Application imports
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TabHeader(Gtk.ButtonBox):
 | 
				
			||||||
 | 
					    """docstring for TabHeader"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, tab, close_tab):
 | 
				
			||||||
 | 
					        super(TabHeader, self).__init__()
 | 
				
			||||||
 | 
					        self._tab       = tab
 | 
				
			||||||
 | 
					        self._close_tab = close_tab # NOTE: Close method in tab_mixin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._setup_styling()
 | 
				
			||||||
 | 
					        self._setup_signals()
 | 
				
			||||||
 | 
					        self._load_widgets()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _setup_styling(self):
 | 
				
			||||||
 | 
					        self.set_orientation(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _setup_signals(self):
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _load_widgets(self):
 | 
				
			||||||
 | 
					        label = Gtk.Label()
 | 
				
			||||||
 | 
					        tid   = Gtk.Label()
 | 
				
			||||||
 | 
					        close = Gtk.Button()
 | 
				
			||||||
 | 
					        icon  = Gtk.Image(stock=Gtk.STOCK_CLOSE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        label.set_label(f"{self._tab.get_end_of_path()}")
 | 
				
			||||||
 | 
					        label.set_width_chars(len(self._tab.get_end_of_path()))
 | 
				
			||||||
 | 
					        label.set_xalign(0.0)
 | 
				
			||||||
 | 
					        tid.set_label(f"{self._tab.get_id()}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        close.connect("released", self._close_tab)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        close.add(icon)
 | 
				
			||||||
 | 
					        self.add(label)
 | 
				
			||||||
 | 
					        self.add(close)
 | 
				
			||||||
 | 
					        self.add(tid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.show_all()
 | 
				
			||||||
 | 
					        tid.hide()
 | 
				
			||||||
@@ -828,22 +828,6 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
 | 
				
			|||||||
                <property name="can-focus">False</property>
 | 
					                <property name="can-focus">False</property>
 | 
				
			||||||
                <property name="spacing">5</property>
 | 
					                <property name="spacing">5</property>
 | 
				
			||||||
                <property name="layout-style">start</property>
 | 
					                <property name="layout-style">start</property>
 | 
				
			||||||
                <child>
 | 
					 | 
				
			||||||
                  <object class="GtkButton" id="io_button">
 | 
					 | 
				
			||||||
                    <property name="label" translatable="yes">I/O</property>
 | 
					 | 
				
			||||||
                    <property name="visible">True</property>
 | 
					 | 
				
			||||||
                    <property name="can-focus">True</property>
 | 
					 | 
				
			||||||
                    <property name="receives-default">True</property>
 | 
					 | 
				
			||||||
                    <property name="image">io_img</property>
 | 
					 | 
				
			||||||
                    <property name="always-show-image">True</property>
 | 
					 | 
				
			||||||
                    <signal name="released" handler="show_io_popup" swapped="no"/>
 | 
					 | 
				
			||||||
                  </object>
 | 
					 | 
				
			||||||
                  <packing>
 | 
					 | 
				
			||||||
                    <property name="expand">True</property>
 | 
					 | 
				
			||||||
                    <property name="fill">True</property>
 | 
					 | 
				
			||||||
                    <property name="position">0</property>
 | 
					 | 
				
			||||||
                  </packing>
 | 
					 | 
				
			||||||
                </child>
 | 
					 | 
				
			||||||
                <child>
 | 
					                <child>
 | 
				
			||||||
                  <object class="GtkButton" id="plugins_button">
 | 
					                  <object class="GtkButton" id="plugins_button">
 | 
				
			||||||
                    <property name="label" translatable="yes">Plugins</property>
 | 
					                    <property name="label" translatable="yes">Plugins</property>
 | 
				
			||||||
@@ -855,7 +839,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
 | 
				
			|||||||
                  <packing>
 | 
					                  <packing>
 | 
				
			||||||
                    <property name="expand">True</property>
 | 
					                    <property name="expand">True</property>
 | 
				
			||||||
                    <property name="fill">True</property>
 | 
					                    <property name="fill">True</property>
 | 
				
			||||||
                    <property name="position">1</property>
 | 
					                    <property name="position">0</property>
 | 
				
			||||||
                  </packing>
 | 
					                  </packing>
 | 
				
			||||||
                </child>
 | 
					                </child>
 | 
				
			||||||
                <child>
 | 
					                <child>
 | 
				
			||||||
@@ -871,7 +855,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
 | 
				
			|||||||
                  <packing>
 | 
					                  <packing>
 | 
				
			||||||
                    <property name="expand">True</property>
 | 
					                    <property name="expand">True</property>
 | 
				
			||||||
                    <property name="fill">True</property>
 | 
					                    <property name="fill">True</property>
 | 
				
			||||||
                    <property name="position">2</property>
 | 
					                    <property name="position">1</property>
 | 
				
			||||||
                  </packing>
 | 
					                  </packing>
 | 
				
			||||||
                </child>
 | 
					                </child>
 | 
				
			||||||
                <child>
 | 
					                <child>
 | 
				
			||||||
@@ -887,7 +871,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
 | 
				
			|||||||
                  <packing>
 | 
					                  <packing>
 | 
				
			||||||
                    <property name="expand">True</property>
 | 
					                    <property name="expand">True</property>
 | 
				
			||||||
                    <property name="fill">True</property>
 | 
					                    <property name="fill">True</property>
 | 
				
			||||||
                    <property name="position">3</property>
 | 
					                    <property name="position">2</property>
 | 
				
			||||||
                  </packing>
 | 
					                  </packing>
 | 
				
			||||||
                </child>
 | 
					                </child>
 | 
				
			||||||
                <child>
 | 
					                <child>
 | 
				
			||||||
@@ -903,7 +887,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
 | 
				
			|||||||
                  <packing>
 | 
					                  <packing>
 | 
				
			||||||
                    <property name="expand">True</property>
 | 
					                    <property name="expand">True</property>
 | 
				
			||||||
                    <property name="fill">True</property>
 | 
					                    <property name="fill">True</property>
 | 
				
			||||||
                    <property name="position">4</property>
 | 
					                    <property name="position">3</property>
 | 
				
			||||||
                  </packing>
 | 
					                  </packing>
 | 
				
			||||||
                </child>
 | 
					                </child>
 | 
				
			||||||
                <child>
 | 
					                <child>
 | 
				
			||||||
@@ -916,6 +900,22 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe
 | 
				
			|||||||
                    <property name="always-show-image">True</property>
 | 
					                    <property name="always-show-image">True</property>
 | 
				
			||||||
                    <signal name="released" handler="toggle_notebook_pane" swapped="no"/>
 | 
					                    <signal name="released" handler="toggle_notebook_pane" swapped="no"/>
 | 
				
			||||||
                  </object>
 | 
					                  </object>
 | 
				
			||||||
 | 
					                  <packing>
 | 
				
			||||||
 | 
					                    <property name="expand">True</property>
 | 
				
			||||||
 | 
					                    <property name="fill">True</property>
 | 
				
			||||||
 | 
					                    <property name="position">4</property>
 | 
				
			||||||
 | 
					                  </packing>
 | 
				
			||||||
 | 
					                </child>
 | 
				
			||||||
 | 
					                <child>
 | 
				
			||||||
 | 
					                  <object class="GtkButton" id="io_button">
 | 
				
			||||||
 | 
					                    <property name="label" translatable="yes">I/O</property>
 | 
				
			||||||
 | 
					                    <property name="visible">True</property>
 | 
				
			||||||
 | 
					                    <property name="can-focus">True</property>
 | 
				
			||||||
 | 
					                    <property name="receives-default">True</property>
 | 
				
			||||||
 | 
					                    <property name="image">io_img</property>
 | 
				
			||||||
 | 
					                    <property name="always-show-image">True</property>
 | 
				
			||||||
 | 
					                    <signal name="released" handler="show_io_popup" swapped="no"/>
 | 
				
			||||||
 | 
					                  </object>
 | 
				
			||||||
                  <packing>
 | 
					                  <packing>
 | 
				
			||||||
                    <property name="expand">True</property>
 | 
					                    <property name="expand">True</property>
 | 
				
			||||||
                    <property name="fill">True</property>
 | 
					                    <property name="fill">True</property>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user