From a675ed05f73753798f57d983113e6149ad8b1238 Mon Sep 17 00:00:00 2001 From: Maxim Stewart Date: Sun, 9 Jun 2019 16:03:38 -0500 Subject: [PATCH] Modularized a lot of parts --- bin/pytop-0-0-1-x64.deb | Bin 18428 -> 18724 bytes src/debs/pytop-0-0-1-x64/opt/Pytop/PyTop.py | 150 +----------------- .../opt/Pytop/resources/PyTop.glade | 40 +++-- .../pytop-0-0-1-x64/opt/Pytop/utils/Events.py | 60 +++++++ .../pytop-0-0-1-x64/opt/Pytop/utils/Grid.py | 122 ++++++++++++++ .../pytop-0-0-1-x64/opt/Pytop/utils/Icon.py | 60 ++++--- .../opt/Pytop/utils/Settings.py | 8 +- .../opt/Pytop/utils/__init__.py | 2 + src/versions/pytop-0.0.1/Pytop/PyTop.py | 150 +----------------- .../pytop-0.0.1/Pytop/resources/PyTop.glade | 40 +++-- .../pytop-0.0.1/Pytop/utils/Events.py | 60 +++++++ src/versions/pytop-0.0.1/Pytop/utils/Grid.py | 122 ++++++++++++++ src/versions/pytop-0.0.1/Pytop/utils/Icon.py | 60 ++++--- .../pytop-0.0.1/Pytop/utils/Settings.py | 8 +- .../pytop-0.0.1/Pytop/utils/__init__.py | 2 + 15 files changed, 490 insertions(+), 394 deletions(-) mode change 100644 => 100755 src/debs/pytop-0-0-1-x64/opt/Pytop/PyTop.py create mode 100644 src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Events.py create mode 100644 src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Grid.py create mode 100644 src/versions/pytop-0.0.1/Pytop/utils/Events.py create mode 100644 src/versions/pytop-0.0.1/Pytop/utils/Grid.py diff --git a/bin/pytop-0-0-1-x64.deb b/bin/pytop-0-0-1-x64.deb index 5de58c6dd6f4c5f372dd799ccc53af25ebdb203e..6e9f1beb0d311d4fed1acf8599e88dbf8b350633 100644 GIT binary patch delta 16701 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 Yi~)dv1qW%cX|cp-`vL#}000D8T3!-JCjbBd delta 16403 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 diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/PyTop.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/PyTop.py old mode 100644 new mode 100755 index b49dd21..f3d859c --- a/src/debs/pytop-0-0-1-x64/opt/Pytop/PyTop.py +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/PyTop.py @@ -3,24 +3,13 @@ # Gtk Imports import gi gi.require_version('Gtk', '3.0') -gi.require_version('Gdk', '3.0') gi.require_version('WebKit2', '4.0') from gi.repository import Gtk as gtk -from gi.repository import Gdk as gdk -from gi.repository import GObject as gobject from gi.repository import WebKit2 as webkit - # Python imports -import os, threading, subprocess, hashlib -from utils import Settings, Icon, FileHandler, Dragging -from os.path import isdir, isfile, join -from threading import Thread -from os import listdir - - -gdk.threads_init() +from utils import Settings, Events class Main: @@ -29,152 +18,19 @@ class Main: webkit.WebView() self.builder = gtk.Builder() - self.filehandler = FileHandler() self.settings = Settings() - # self.drag = Dragging() self.settings.attachBuilder(self.builder) - self.builder.connect_signals(self) + self.builder.connect_signals(Events(self.builder, self.settings)) - self.currentPath = "" - window = self.settings.createWindow() - self.usrHome = self.settings.returnUserHome() - self.desktopPath = self.settings.returnDesktopPath() - self.ColumnSize = self.settings.returnColumnSize() - self.desktop = self.builder.get_object("Desktop") - - # Add filter to allow only folders to be selected - self.loadProgress = self.builder.get_object("loadProgress") - selectedDirDialog = self.builder.get_object("selectedDirDialog") - filefilter = self.builder.get_object("Folders") - selectedDirDialog.add_filter(filefilter) - selectedDirDialog.set_filename(self.desktopPath) - self.setDir(selectedDirDialog) - - self.webview = self.builder.get_object("webview") - self.settings.setDefaultWebviewSettings(self.webview, self.webview.get_settings()) - self.webview.load_uri(self.settings.returnWebHome()) + window = self.settings.createWindow() window.fullscreen() window.show_all() - def setDir(self, widget, data=None): - self.currentPath = widget.get_filename() - self.getDirectoryList(self.currentPath) - # Thread(target=self.getDirectoryList, args=(self.currentPath,)).start() - - def getDirectoryList(self, dir): - dirs = ['.', '..'] - files = [] - - for f in listdir(dir): - file = join(dir, f) - if self.settings.isHideHiddenFiles(): - if f.startswith('.'): - continue - - if isfile(file): - files.append(f) - else: - dirs.append(f) - - dirs.sort() - files.sort() - - files = dirs + files - fractionTick = 1.0 / 1.0 if len(files) == 0 else len(files) - tickCount = 0.0 - row = 0 - col = 0 - x = 0 - y = 0 - - self.loadProgress.set_text("Loading...") - self.loadProgress.set_fraction(0.0) - self.clear(self.desktop) - for file in files: - eveBox = Icon().createIcon(dir, file) - # self.drag.connectEvents(self.desktop, eveBox) - eveBox.connect("button_press_event", self.clickManager, (eveBox,)) - eveBox.connect("enter_notify_event", self.settings.mouseOver, ()) - eveBox.connect("leave_notify_event", self.settings.mouseOut, ()) - - gobject.idle_add(self.addToGrid, (self.desktop, eveBox, col, row,)) - tickCount = tickCount + fractionTick - self.loadProgress.set_fraction(tickCount) - - col += 1 - if col == self.ColumnSize: - col = 0 - row += 1 - - self.desktop.show_all() - self.loadProgress.set_text("Finished...") - - def addToGrid(self, args): - args[0].attach(args[1], args[2], args[3], 1, 1) - - def clickManager(self, widget, eve, params): - self.settings.setSelected(params[0]) - if eve.type == gdk.EventType.DOUBLE_BUTTON_PRESS: - box = widget.get_children()[0] - children = box.get_children() - fileName = children[1].get_text() - dir = self.currentPath - file = dir + "/" + fileName - - if fileName == ".": - self.getDirectoryList(dir) - elif fileName == "..": - parentDir = os.path.abspath(os.path.join(dir, os.pardir)) - self.currentPath = parentDir - self.getDirectoryList(parentDir) - elif isdir(file): - self.currentPath = file - self.getDirectoryList(file) - # Thread(target=self.getDirectoryList, args=(file,)).start() - else: - self.filehandler.openFile(file) - elif eve.type == gdk.EventType.BUTTON_PRESS and eve.button == 3: - box = widget.get_children()[0] - children = box.get_children() - - popover = self.builder.get_object("controlsWindow") - popover.set_relative_to(children[1]) - popover.set_position(gtk.PositionType.RIGHT) - popover.show_all() - - input = self.builder.get_object("renamerInput") - input.set_text(children[1].get_text()) - - popover.popup() - def showWebview(self, widget): - self.builder.get_object("webViewer").popup() - - def loadHome(self, widget): - self.webview.load_uri(self.settings.returnWebHome()) - - def runSearchWebview(self, widget, data=None): - if data.keyval == 65293: - self.webview.load_uri(widget.get_text().strip()) - - def refreshPage(self, widget, data=None): - self.webview.load_uri(self.webview.get_uri()) - - def setUrlBar(self, widget, data=None): - self.builder.get_object("webviewSearch").set_text(widget.get_uri()) - - - def clear(self, object): - while True: - if object.get_child_at(0,0)!= None: - object.remove_row(0) - else: - break - if __name__ == "__main__": main = Main() diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/PyTop.glade b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/PyTop.glade index 4cafb45..9bebfe5 100644 --- a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/PyTop.glade +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/PyTop.glade @@ -8,7 +8,24 @@ inode/directory - + + False + bottom + + + gtk-paste + True + True + True + True + True + + + main + + + + False @@ -16,7 +33,7 @@ False vertical - + 300 26 True @@ -64,19 +81,7 @@ - - gtk-paste - True - True - True - True - True - - - False - True - 2 - + @@ -119,11 +124,12 @@ desktop False center + - + 256 True False @@ -133,7 +139,7 @@ True False - + True True edit-find-symbolic diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Events.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Events.py new file mode 100644 index 0000000..c0d17b2 --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Events.py @@ -0,0 +1,60 @@ + +# Gtk Imports +import gi +gi.require_version('Gdk', '3.0') + +from gi.repository import Gdk as gdk + +# Python imports +import os, threading +from .Grid import Grid +from .Dragging import Dragging +from threading import Thread + + +gdk.threads_init() +class Events: + def __init__(self, builder, settings): + self.builder = builder + self.settings = settings + self.desktop = self.builder.get_object("Desktop") + self.desktopPath = self.settings.returnDesktopPath() + + self.webview = self.builder.get_object("webview") + self.settings.setDefaultWebviewSettings(self.webview, self.webview.get_settings()) + self.webview.load_uri(self.settings.returnWebHome()) + + # Add filter to allow only folders to be selected + selectedDirDialog = self.builder.get_object("selectedDirDialog") + filefilter = self.builder.get_object("Folders") + selectedDirDialog.add_filter(filefilter) + selectedDirDialog.set_filename(self.desktopPath) + + self.setDir(selectedDirDialog) + + + def setDir(self, widget, data=None): + newPath = widget.get_filename() + Thread(target=Grid(self.desktop, self.settings).generateDirectoryGrid, args=(newPath,)).start() + + + def showGridControlMenu(self, widget, data=None): + popover = self.builder.get_object("gridControlMenu") + popover.show_all() + popover.popup() + + def showWebview(self, widget): + self.builder.get_object("webViewer").popup() + + def loadHome(self, widget): + self.webview.load_uri(self.settings.returnWebHome()) + + def runSearchWebview(self, widget, data=None): + if data.keyval == 65293: + self.webview.load_uri(widget.get_text().strip()) + + def refreshPage(self, widget, data=None): + self.webview.load_uri(self.webview.get_uri()) + + def setUrlBar(self, widget, data=None): + self.builder.get_object("webviewSearch").set_text(widget.get_uri()) diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Grid.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Grid.py new file mode 100644 index 0000000..b33edf9 --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Grid.py @@ -0,0 +1,122 @@ + + +# Gtk Imports +import gi +gi.require_version('Gtk', '3.0') +gi.require_version('Gdk', '3.0') +gi.require_version('WebKit2', '4.0') + +from gi.repository import Gtk as gtk +from gi.repository import Gdk as gdk +from gi.repository import GObject as gobject + + +# Python imports +from .Icon import Icon +from .FileHandler import FileHandler +import os, subprocess +from os.path import isdir, isfile, join +from os import listdir + + +class Grid: + def __init__(self, desktop, settings): + self.desktop = desktop + self.settings = settings + self.filehandler = FileHandler() + + self.currentPath = "" + self.builder = self.settings.returnBuilder() + self.ColumnSize = self.settings.returnColumnSize() + + + def generateDirectoryGrid(self, dirPath): + dirPaths = ['.', '..'] + files = [] + + # self.desktop.connect("button_press_event", self.showGridControlMenu, ()) + + for f in listdir(dirPath): + file = join(dirPath, f) + if self.settings.isHideHiddenFiles(): + if f.startswith('.'): + continue + + if isfile(file): + files.append(f) + else: + dirPaths.append(f) + + dirPaths.sort() + files.sort() + + files = dirPaths + files + fractionTick = 1.0 / 1.0 if len(files) == 0 else len(files) + tickCount = 0.0 + row = 0 + col = 0 + x = 0 + y = 0 + + loadProgress = self.builder.get_object('loadProgress') + loadProgress.set_text("Loading...") + loadProgress.set_fraction(0.0) + self.clearGrid(self.desktop) + for file in files: + eveBox = Icon().createIcon(dirPath, file) + # self.drag.connectEvents(self.desktop, eveBox) + eveBox.connect("button_press_event", self.iconClickEventManager, (eveBox,)) + eveBox.connect("enter_notify_event", self.settings.mouseOver, ()) + eveBox.connect("leave_notify_event", self.settings.mouseOut, ()) + + gobject.idle_add(self.addToGrid, (self.desktop, eveBox, col, row,)) + tickCount = tickCount + fractionTick + loadProgress.set_fraction(tickCount) + + col += 1 + if col == self.ColumnSize: + col = 0 + row += 1 + + self.desktop.show_all() + loadProgress.set_text("Finished...") + + def addToGrid(self, args): + args[0].attach(args[1], args[2], args[3], 1, 1) + + def clearGrid(self, object): + while True: + if object.get_child_at(0,0)!= None: + object.remove_row(0) + else: + break + + def iconClickEventManager(self, widget, eve, params): + self.settings.setSelected(params[0]) + if eve.type == gdk.EventType.DOUBLE_BUTTON_PRESS: + children = widget.get_children()[0].get_children() + fileName = children[1].get_text() + dir = self.currentPath + file = dir + "/" + fileName + + if fileName == ".": + self.generateDirectoryGrid(dir) + elif fileName == "..": + parentDir = os.path.abspath(os.path.join(dir, os.pardir)) + self.currentPath = parentDir + self.generateDirectoryGrid(parentDir) + elif isdir(file): + self.currentPath = file + Thread(target=self.generateDirectoryGrid, args=(self.currentPath,)).start() + else: + self.filehandler.openFile(file) + elif eve.type == gdk.EventType.BUTTON_PRESS and eve.button == 3: + children = widget.get_children()[0].get_children() + input = self.builder.get_object("iconRenameInput") + popover = self.builder.get_object("iconControlsWindow") + + input.set_text(children[1].get_text()) + popover.set_relative_to(children[1]) + popover.set_position(gtk.PositionType.RIGHT) + popover.show_all() + popover.popup() diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Icon.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Icon.py index 75c8c5b..69cf464 100644 --- a/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Icon.py +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Icon.py @@ -14,12 +14,11 @@ from os.path import isdir, isfile, join class Icon: def __init__(self): - self.GTK_ORIENTATION = 1 # HORIZONTAL (0) VERTICAL (1) - self.iconImageWxH = [128, -1] - self.iconSystem = [72, 72] - self.iconWxH = [128, -1] - self.iconMargins = 8 - self.usrHome = os.path.expanduser('~') + self.GTK_ORIENTATION = 1 # HORIZONTAL (0) VERTICAL (1) + self.iconContainerWxH = [128, -1] + self.systemIconImageWxH = [72, 72] + self.viIconWxH = [128, -1] + self.usrHome = os.path.expanduser('~') def createIcon(self, dir, file): @@ -27,17 +26,16 @@ class Icon: eveBox = gtk.EventBox() icon = gtk.Box() label = gtk.Label() - thumbnl = self.defineIconImage(file, fullPathFile) + thumbnl = self.getIconImage(file, fullPathFile) label.set_max_width_chars(1) label.set_ellipsize(3) # ELLIPSIZE_END (3) label.set_lines(2) label.set_line_wrap(True) label.set_line_wrap_mode(2) # WRAP_WORD (0) WRAP_CHAR (1) WRAP_WORD_CHAR (2) - label.set_width_chars(1) label.set_text(file) - icon.set_size_request(self.iconWxH[0], self.iconWxH[1]); + icon.set_size_request(self.iconContainerWxH[0], self.iconContainerWxH[1]); icon.set_property('orientation', self.GTK_ORIENTATION) icon.add(thumbnl) icon.add(label) @@ -46,7 +44,7 @@ class Icon: eveBox.show_all() return eveBox - def defineIconImage(self, file, fullPathFile): + def getIconImage(self, file, fullPathFile): thumbnl = gtk.Image() vidsList = ('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv', '.mpeg', '.mp4', '.webm') imagesList = ('.png', '.jpg', '.jpeg', '.gif') @@ -55,17 +53,33 @@ class Icon: fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest() hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png" if isfile(hashImgpth) == False: - self.generateThumbnail(fullPathFile, hashImgpth) + self.generateVideoThumbnail(fullPathFile, hashImgpth) - thumbnl = self.createGtkImage(hashImgpth, self.iconImageWxH) + thumbnl = self.createIconImageFromBuffer(hashImgpth, self.viIconWxH) elif file.lower().endswith(imagesList): - thumbnl = self.createGtkImage(fullPathFile, self.iconImageWxH) + thumbnl = self.createIconImageFromBuffer(fullPathFile, self.viIconWxH) else: - thumbPth = self.getSystemThumbnail(fullPathFile, self.iconSystem[0]) - thumbnl = self.createGtkImage(thumbPth, self.iconSystem) + thumbPth = self.getSystemThumbnail(fullPathFile, self.systemIconImageWxH[0]) + thumbnl = self.createIconImageFromBuffer(thumbPth, self.systemIconImageWxH) return thumbnl + def createIconImageFromBuffer(self, path, wxh): + try: + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( + filename = path, + width = wxh[0], + height = wxh[1], + preserve_aspect_ratio = True) + return gtk.Image.new_from_pixbuf(pixbuf) + except Exception as e: + print(e) + + return gtk.Image() + + def generateVideoThumbnail(self, fullPathFile, hashImgpth): + subprocess.call(["ffmpegthumbnailer", "-t", "65%", "-s", "300", "-c", "jpg", "-i", fullPathFile, "-o", hashImgpth]) + def getSystemThumbnail(self, filename,size): final_filename = "" if os.path.exists(filename): @@ -79,19 +93,3 @@ class Icon: final_filename = icon_file.get_filename() return final_filename - - def generateThumbnail(self, fullPathFile, hashImgpth): - subprocess.call(["ffmpegthumbnailer", "-t", "65%", "-s", "300", "-c", "jpg", "-i", fullPathFile, "-o", hashImgpth]) - - def createGtkImage(self, path, wxh): - try: - pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( - filename = path, - width = wxh[0], - height = wxh[1], - preserve_aspect_ratio = True) - return gtk.Image.new_from_pixbuf(pixbuf) - except Exception as e: - print(e) - - return gtk.Image() diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Settings.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Settings.py index a114522..e0d2f3a 100644 --- a/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Settings.py +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Settings.py @@ -62,8 +62,9 @@ class Settings: return monitors - def isHideHiddenFiles(self): - return self.hideHiddenFiles + + def returnBuilder(self): + return self.builder def returnUserHome(self): return self.usrHome @@ -77,6 +78,9 @@ class Settings: def returnWebHome(self): return self.webHome + def isHideHiddenFiles(self): + return self.hideHiddenFiles + def mouseOver(self, widget, eve, args): hand_cursor = gdk.Cursor(gdk.CursorType.HAND2) self.builder.get_object("Window").get_window().set_cursor(hand_cursor) diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/__init__.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/__init__.py index d623701..e291f0f 100644 --- a/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/__init__.py +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/__init__.py @@ -1,4 +1,6 @@ from utils.Dragging import Dragging from utils.Settings import Settings +from utils.Events import Events +from utils.Grid import Grid from utils.Icon import Icon from utils.FileHandler import FileHandler diff --git a/src/versions/pytop-0.0.1/Pytop/PyTop.py b/src/versions/pytop-0.0.1/Pytop/PyTop.py index b49dd21..f3d859c 100755 --- a/src/versions/pytop-0.0.1/Pytop/PyTop.py +++ b/src/versions/pytop-0.0.1/Pytop/PyTop.py @@ -3,24 +3,13 @@ # Gtk Imports import gi gi.require_version('Gtk', '3.0') -gi.require_version('Gdk', '3.0') gi.require_version('WebKit2', '4.0') from gi.repository import Gtk as gtk -from gi.repository import Gdk as gdk -from gi.repository import GObject as gobject from gi.repository import WebKit2 as webkit - # Python imports -import os, threading, subprocess, hashlib -from utils import Settings, Icon, FileHandler, Dragging -from os.path import isdir, isfile, join -from threading import Thread -from os import listdir - - -gdk.threads_init() +from utils import Settings, Events class Main: @@ -29,152 +18,19 @@ class Main: webkit.WebView() self.builder = gtk.Builder() - self.filehandler = FileHandler() self.settings = Settings() - # self.drag = Dragging() self.settings.attachBuilder(self.builder) - self.builder.connect_signals(self) + self.builder.connect_signals(Events(self.builder, self.settings)) - self.currentPath = "" - window = self.settings.createWindow() - self.usrHome = self.settings.returnUserHome() - self.desktopPath = self.settings.returnDesktopPath() - self.ColumnSize = self.settings.returnColumnSize() - self.desktop = self.builder.get_object("Desktop") - - # Add filter to allow only folders to be selected - self.loadProgress = self.builder.get_object("loadProgress") - selectedDirDialog = self.builder.get_object("selectedDirDialog") - filefilter = self.builder.get_object("Folders") - selectedDirDialog.add_filter(filefilter) - selectedDirDialog.set_filename(self.desktopPath) - self.setDir(selectedDirDialog) - - self.webview = self.builder.get_object("webview") - self.settings.setDefaultWebviewSettings(self.webview, self.webview.get_settings()) - self.webview.load_uri(self.settings.returnWebHome()) + window = self.settings.createWindow() window.fullscreen() window.show_all() - def setDir(self, widget, data=None): - self.currentPath = widget.get_filename() - self.getDirectoryList(self.currentPath) - # Thread(target=self.getDirectoryList, args=(self.currentPath,)).start() - - def getDirectoryList(self, dir): - dirs = ['.', '..'] - files = [] - - for f in listdir(dir): - file = join(dir, f) - if self.settings.isHideHiddenFiles(): - if f.startswith('.'): - continue - - if isfile(file): - files.append(f) - else: - dirs.append(f) - - dirs.sort() - files.sort() - - files = dirs + files - fractionTick = 1.0 / 1.0 if len(files) == 0 else len(files) - tickCount = 0.0 - row = 0 - col = 0 - x = 0 - y = 0 - - self.loadProgress.set_text("Loading...") - self.loadProgress.set_fraction(0.0) - self.clear(self.desktop) - for file in files: - eveBox = Icon().createIcon(dir, file) - # self.drag.connectEvents(self.desktop, eveBox) - eveBox.connect("button_press_event", self.clickManager, (eveBox,)) - eveBox.connect("enter_notify_event", self.settings.mouseOver, ()) - eveBox.connect("leave_notify_event", self.settings.mouseOut, ()) - - gobject.idle_add(self.addToGrid, (self.desktop, eveBox, col, row,)) - tickCount = tickCount + fractionTick - self.loadProgress.set_fraction(tickCount) - - col += 1 - if col == self.ColumnSize: - col = 0 - row += 1 - - self.desktop.show_all() - self.loadProgress.set_text("Finished...") - - def addToGrid(self, args): - args[0].attach(args[1], args[2], args[3], 1, 1) - - def clickManager(self, widget, eve, params): - self.settings.setSelected(params[0]) - if eve.type == gdk.EventType.DOUBLE_BUTTON_PRESS: - box = widget.get_children()[0] - children = box.get_children() - fileName = children[1].get_text() - dir = self.currentPath - file = dir + "/" + fileName - - if fileName == ".": - self.getDirectoryList(dir) - elif fileName == "..": - parentDir = os.path.abspath(os.path.join(dir, os.pardir)) - self.currentPath = parentDir - self.getDirectoryList(parentDir) - elif isdir(file): - self.currentPath = file - self.getDirectoryList(file) - # Thread(target=self.getDirectoryList, args=(file,)).start() - else: - self.filehandler.openFile(file) - elif eve.type == gdk.EventType.BUTTON_PRESS and eve.button == 3: - box = widget.get_children()[0] - children = box.get_children() - - popover = self.builder.get_object("controlsWindow") - popover.set_relative_to(children[1]) - popover.set_position(gtk.PositionType.RIGHT) - popover.show_all() - - input = self.builder.get_object("renamerInput") - input.set_text(children[1].get_text()) - - popover.popup() - def showWebview(self, widget): - self.builder.get_object("webViewer").popup() - - def loadHome(self, widget): - self.webview.load_uri(self.settings.returnWebHome()) - - def runSearchWebview(self, widget, data=None): - if data.keyval == 65293: - self.webview.load_uri(widget.get_text().strip()) - - def refreshPage(self, widget, data=None): - self.webview.load_uri(self.webview.get_uri()) - - def setUrlBar(self, widget, data=None): - self.builder.get_object("webviewSearch").set_text(widget.get_uri()) - - - def clear(self, object): - while True: - if object.get_child_at(0,0)!= None: - object.remove_row(0) - else: - break - if __name__ == "__main__": main = Main() diff --git a/src/versions/pytop-0.0.1/Pytop/resources/PyTop.glade b/src/versions/pytop-0.0.1/Pytop/resources/PyTop.glade index 4cafb45..9bebfe5 100644 --- a/src/versions/pytop-0.0.1/Pytop/resources/PyTop.glade +++ b/src/versions/pytop-0.0.1/Pytop/resources/PyTop.glade @@ -8,7 +8,24 @@ inode/directory - + + False + bottom + + + gtk-paste + True + True + True + True + True + + + main + + + + False @@ -16,7 +33,7 @@ False vertical - + 300 26 True @@ -64,19 +81,7 @@ - - gtk-paste - True - True - True - True - True - - - False - True - 2 - + @@ -119,11 +124,12 @@ desktop False center + - + 256 True False @@ -133,7 +139,7 @@ True False - + True True edit-find-symbolic diff --git a/src/versions/pytop-0.0.1/Pytop/utils/Events.py b/src/versions/pytop-0.0.1/Pytop/utils/Events.py new file mode 100644 index 0000000..c0d17b2 --- /dev/null +++ b/src/versions/pytop-0.0.1/Pytop/utils/Events.py @@ -0,0 +1,60 @@ + +# Gtk Imports +import gi +gi.require_version('Gdk', '3.0') + +from gi.repository import Gdk as gdk + +# Python imports +import os, threading +from .Grid import Grid +from .Dragging import Dragging +from threading import Thread + + +gdk.threads_init() +class Events: + def __init__(self, builder, settings): + self.builder = builder + self.settings = settings + self.desktop = self.builder.get_object("Desktop") + self.desktopPath = self.settings.returnDesktopPath() + + self.webview = self.builder.get_object("webview") + self.settings.setDefaultWebviewSettings(self.webview, self.webview.get_settings()) + self.webview.load_uri(self.settings.returnWebHome()) + + # Add filter to allow only folders to be selected + selectedDirDialog = self.builder.get_object("selectedDirDialog") + filefilter = self.builder.get_object("Folders") + selectedDirDialog.add_filter(filefilter) + selectedDirDialog.set_filename(self.desktopPath) + + self.setDir(selectedDirDialog) + + + def setDir(self, widget, data=None): + newPath = widget.get_filename() + Thread(target=Grid(self.desktop, self.settings).generateDirectoryGrid, args=(newPath,)).start() + + + def showGridControlMenu(self, widget, data=None): + popover = self.builder.get_object("gridControlMenu") + popover.show_all() + popover.popup() + + def showWebview(self, widget): + self.builder.get_object("webViewer").popup() + + def loadHome(self, widget): + self.webview.load_uri(self.settings.returnWebHome()) + + def runSearchWebview(self, widget, data=None): + if data.keyval == 65293: + self.webview.load_uri(widget.get_text().strip()) + + def refreshPage(self, widget, data=None): + self.webview.load_uri(self.webview.get_uri()) + + def setUrlBar(self, widget, data=None): + self.builder.get_object("webviewSearch").set_text(widget.get_uri()) diff --git a/src/versions/pytop-0.0.1/Pytop/utils/Grid.py b/src/versions/pytop-0.0.1/Pytop/utils/Grid.py new file mode 100644 index 0000000..b33edf9 --- /dev/null +++ b/src/versions/pytop-0.0.1/Pytop/utils/Grid.py @@ -0,0 +1,122 @@ + + +# Gtk Imports +import gi +gi.require_version('Gtk', '3.0') +gi.require_version('Gdk', '3.0') +gi.require_version('WebKit2', '4.0') + +from gi.repository import Gtk as gtk +from gi.repository import Gdk as gdk +from gi.repository import GObject as gobject + + +# Python imports +from .Icon import Icon +from .FileHandler import FileHandler +import os, subprocess +from os.path import isdir, isfile, join +from os import listdir + + +class Grid: + def __init__(self, desktop, settings): + self.desktop = desktop + self.settings = settings + self.filehandler = FileHandler() + + self.currentPath = "" + self.builder = self.settings.returnBuilder() + self.ColumnSize = self.settings.returnColumnSize() + + + def generateDirectoryGrid(self, dirPath): + dirPaths = ['.', '..'] + files = [] + + # self.desktop.connect("button_press_event", self.showGridControlMenu, ()) + + for f in listdir(dirPath): + file = join(dirPath, f) + if self.settings.isHideHiddenFiles(): + if f.startswith('.'): + continue + + if isfile(file): + files.append(f) + else: + dirPaths.append(f) + + dirPaths.sort() + files.sort() + + files = dirPaths + files + fractionTick = 1.0 / 1.0 if len(files) == 0 else len(files) + tickCount = 0.0 + row = 0 + col = 0 + x = 0 + y = 0 + + loadProgress = self.builder.get_object('loadProgress') + loadProgress.set_text("Loading...") + loadProgress.set_fraction(0.0) + self.clearGrid(self.desktop) + for file in files: + eveBox = Icon().createIcon(dirPath, file) + # self.drag.connectEvents(self.desktop, eveBox) + eveBox.connect("button_press_event", self.iconClickEventManager, (eveBox,)) + eveBox.connect("enter_notify_event", self.settings.mouseOver, ()) + eveBox.connect("leave_notify_event", self.settings.mouseOut, ()) + + gobject.idle_add(self.addToGrid, (self.desktop, eveBox, col, row,)) + tickCount = tickCount + fractionTick + loadProgress.set_fraction(tickCount) + + col += 1 + if col == self.ColumnSize: + col = 0 + row += 1 + + self.desktop.show_all() + loadProgress.set_text("Finished...") + + def addToGrid(self, args): + args[0].attach(args[1], args[2], args[3], 1, 1) + + def clearGrid(self, object): + while True: + if object.get_child_at(0,0)!= None: + object.remove_row(0) + else: + break + + def iconClickEventManager(self, widget, eve, params): + self.settings.setSelected(params[0]) + if eve.type == gdk.EventType.DOUBLE_BUTTON_PRESS: + children = widget.get_children()[0].get_children() + fileName = children[1].get_text() + dir = self.currentPath + file = dir + "/" + fileName + + if fileName == ".": + self.generateDirectoryGrid(dir) + elif fileName == "..": + parentDir = os.path.abspath(os.path.join(dir, os.pardir)) + self.currentPath = parentDir + self.generateDirectoryGrid(parentDir) + elif isdir(file): + self.currentPath = file + Thread(target=self.generateDirectoryGrid, args=(self.currentPath,)).start() + else: + self.filehandler.openFile(file) + elif eve.type == gdk.EventType.BUTTON_PRESS and eve.button == 3: + children = widget.get_children()[0].get_children() + input = self.builder.get_object("iconRenameInput") + popover = self.builder.get_object("iconControlsWindow") + + input.set_text(children[1].get_text()) + popover.set_relative_to(children[1]) + popover.set_position(gtk.PositionType.RIGHT) + popover.show_all() + popover.popup() diff --git a/src/versions/pytop-0.0.1/Pytop/utils/Icon.py b/src/versions/pytop-0.0.1/Pytop/utils/Icon.py index 75c8c5b..69cf464 100644 --- a/src/versions/pytop-0.0.1/Pytop/utils/Icon.py +++ b/src/versions/pytop-0.0.1/Pytop/utils/Icon.py @@ -14,12 +14,11 @@ from os.path import isdir, isfile, join class Icon: def __init__(self): - self.GTK_ORIENTATION = 1 # HORIZONTAL (0) VERTICAL (1) - self.iconImageWxH = [128, -1] - self.iconSystem = [72, 72] - self.iconWxH = [128, -1] - self.iconMargins = 8 - self.usrHome = os.path.expanduser('~') + self.GTK_ORIENTATION = 1 # HORIZONTAL (0) VERTICAL (1) + self.iconContainerWxH = [128, -1] + self.systemIconImageWxH = [72, 72] + self.viIconWxH = [128, -1] + self.usrHome = os.path.expanduser('~') def createIcon(self, dir, file): @@ -27,17 +26,16 @@ class Icon: eveBox = gtk.EventBox() icon = gtk.Box() label = gtk.Label() - thumbnl = self.defineIconImage(file, fullPathFile) + thumbnl = self.getIconImage(file, fullPathFile) label.set_max_width_chars(1) label.set_ellipsize(3) # ELLIPSIZE_END (3) label.set_lines(2) label.set_line_wrap(True) label.set_line_wrap_mode(2) # WRAP_WORD (0) WRAP_CHAR (1) WRAP_WORD_CHAR (2) - label.set_width_chars(1) label.set_text(file) - icon.set_size_request(self.iconWxH[0], self.iconWxH[1]); + icon.set_size_request(self.iconContainerWxH[0], self.iconContainerWxH[1]); icon.set_property('orientation', self.GTK_ORIENTATION) icon.add(thumbnl) icon.add(label) @@ -46,7 +44,7 @@ class Icon: eveBox.show_all() return eveBox - def defineIconImage(self, file, fullPathFile): + def getIconImage(self, file, fullPathFile): thumbnl = gtk.Image() vidsList = ('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv', '.mpeg', '.mp4', '.webm') imagesList = ('.png', '.jpg', '.jpeg', '.gif') @@ -55,17 +53,33 @@ class Icon: fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest() hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png" if isfile(hashImgpth) == False: - self.generateThumbnail(fullPathFile, hashImgpth) + self.generateVideoThumbnail(fullPathFile, hashImgpth) - thumbnl = self.createGtkImage(hashImgpth, self.iconImageWxH) + thumbnl = self.createIconImageFromBuffer(hashImgpth, self.viIconWxH) elif file.lower().endswith(imagesList): - thumbnl = self.createGtkImage(fullPathFile, self.iconImageWxH) + thumbnl = self.createIconImageFromBuffer(fullPathFile, self.viIconWxH) else: - thumbPth = self.getSystemThumbnail(fullPathFile, self.iconSystem[0]) - thumbnl = self.createGtkImage(thumbPth, self.iconSystem) + thumbPth = self.getSystemThumbnail(fullPathFile, self.systemIconImageWxH[0]) + thumbnl = self.createIconImageFromBuffer(thumbPth, self.systemIconImageWxH) return thumbnl + def createIconImageFromBuffer(self, path, wxh): + try: + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( + filename = path, + width = wxh[0], + height = wxh[1], + preserve_aspect_ratio = True) + return gtk.Image.new_from_pixbuf(pixbuf) + except Exception as e: + print(e) + + return gtk.Image() + + def generateVideoThumbnail(self, fullPathFile, hashImgpth): + subprocess.call(["ffmpegthumbnailer", "-t", "65%", "-s", "300", "-c", "jpg", "-i", fullPathFile, "-o", hashImgpth]) + def getSystemThumbnail(self, filename,size): final_filename = "" if os.path.exists(filename): @@ -79,19 +93,3 @@ class Icon: final_filename = icon_file.get_filename() return final_filename - - def generateThumbnail(self, fullPathFile, hashImgpth): - subprocess.call(["ffmpegthumbnailer", "-t", "65%", "-s", "300", "-c", "jpg", "-i", fullPathFile, "-o", hashImgpth]) - - def createGtkImage(self, path, wxh): - try: - pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( - filename = path, - width = wxh[0], - height = wxh[1], - preserve_aspect_ratio = True) - return gtk.Image.new_from_pixbuf(pixbuf) - except Exception as e: - print(e) - - return gtk.Image() diff --git a/src/versions/pytop-0.0.1/Pytop/utils/Settings.py b/src/versions/pytop-0.0.1/Pytop/utils/Settings.py index a114522..e0d2f3a 100644 --- a/src/versions/pytop-0.0.1/Pytop/utils/Settings.py +++ b/src/versions/pytop-0.0.1/Pytop/utils/Settings.py @@ -62,8 +62,9 @@ class Settings: return monitors - def isHideHiddenFiles(self): - return self.hideHiddenFiles + + def returnBuilder(self): + return self.builder def returnUserHome(self): return self.usrHome @@ -77,6 +78,9 @@ class Settings: def returnWebHome(self): return self.webHome + def isHideHiddenFiles(self): + return self.hideHiddenFiles + def mouseOver(self, widget, eve, args): hand_cursor = gdk.Cursor(gdk.CursorType.HAND2) self.builder.get_object("Window").get_window().set_cursor(hand_cursor) diff --git a/src/versions/pytop-0.0.1/Pytop/utils/__init__.py b/src/versions/pytop-0.0.1/Pytop/utils/__init__.py index d623701..e291f0f 100644 --- a/src/versions/pytop-0.0.1/Pytop/utils/__init__.py +++ b/src/versions/pytop-0.0.1/Pytop/utils/__init__.py @@ -1,4 +1,6 @@ from utils.Dragging import Dragging from utils.Settings import Settings +from utils.Events import Events +from utils.Grid import Grid from utils.Icon import Icon from utils.FileHandler import FileHandler