Ising iconview instead of grid

This commit is contained in:
Maxim Stewart 2019-06-14 21:48:32 -05:00
parent 36d45d1bdf
commit 035d485129
11 changed files with 264 additions and 336 deletions

Binary file not shown.

View File

@ -1,19 +1,10 @@
# Gtk Imports # Gtk Imports
import gi, threading
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk as gtk
from gi.repository import Gdk as gdk
# Python imports # Python imports
from .Grid import Grid from .Grid import Grid
from .Dragging import Dragging from .Dragging import Dragging
from threading import Thread
class Events: class Events:
def __init__(self, settings): def __init__(self, settings):
self.settings = settings self.settings = settings
@ -32,14 +23,12 @@ class Events:
selectedDirDialog.set_filename(self.desktopPath) selectedDirDialog.set_filename(self.desktopPath)
self.grid = None self.grid = None
self.setDir(selectedDirDialog) self.setIconViewDir(selectedDirDialog)
def setDir(self, widget, data=None): def setIconViewDir(self, widget, data=None):
newPath = widget.get_filename() newPath = widget.get_filename()
self.grid = Grid(self.desktop, self.settings) Grid(self.desktop, self.settings, newPath)
Thread(target=self.grid.generateDirectoryGrid, args=(newPath,)).start()
# Grid(self.desktop, self.settings).generateDirectoryGrid(newPath)
def showGridControlMenu(self, widget, data=None): def showGridControlMenu(self, widget, data=None):
popover = self.builder.get_object("gridControlMenu") popover = self.builder.get_object("gridControlMenu")
@ -70,6 +59,8 @@ class Events:
def pasteFile(self): def pasteFile(self):
pass pass
def test(self, widget, data=None):
print(widget)
# Webview events # Webview events
def showWebview(self, widget): def showWebview(self, widget):

View File

@ -1,5 +1,11 @@
import os, shutil, subprocess import os, shutil, subprocess, threading
def threaded(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs).start()
return wrapper
class FileHandler: class FileHandler:
def __init__(self): def __init__(self):
@ -22,7 +28,7 @@ class FileHandler:
self.MPLAYER_WH = " -xy 1600 -geometry 50%:50% "; self.MPLAYER_WH = " -xy 1600 -geometry 50%:50% ";
self.MPV_WH = " -geometry 50%:50% "; self.MPV_WH = " -geometry 50%:50% ";
@threaded
def openFile(self, file): def openFile(self, file):
print("Opening: " + file) print("Opening: " + file)
if file.lower().endswith(self.vids): if file.lower().endswith(self.vids):

View File

@ -7,44 +7,55 @@ gi.require_version('Gdk', '3.0')
from gi.repository import Gtk as gtk from gi.repository import Gtk as gtk
from gi.repository import Gdk as gdk from gi.repository import Gdk as gdk
from gi.repository import GdkPixbuf
from gi.repository import GObject as gobject from gi.repository import GObject as gobject
# Python imports # Python imports
import os, subprocess, threading, hashlib import os, threading
from os.path import isdir, isfile, join from os.path import isdir, isfile, join
from os import listdir from os import listdir
from threading import Thread
from .Icon import Icon from .Icon import Icon
from .FileHandler import FileHandler from .FileHandler import FileHandler
gdk.threads_init() gdk.threads_init()
def threaded(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs).start()
return wrapper
class Grid: class Grid:
def __init__(self, desktop, settings): def __init__(self, desktop, settings, newPath):
self.desktop = desktop self.desktop = desktop
self.settings = settings self.settings = settings
self.filehandler = FileHandler() self.filehandler = FileHandler()
self.usrHome = settings.returnUserHome()
self.builder = self.settings.returnBuilder()
self.ColumnSize = self.settings.returnColumnSize()
self.thubnailGen = self.settings.getThumbnailGenerator()
self.store = gtk.ListStore(GdkPixbuf.Pixbuf, str)
self.usrHome = settings.returnUserHome()
self.builder = self.settings.returnBuilder()
self.ColumnSize = self.settings.returnColumnSize()
self.currentPath = "" self.currentPath = ""
self.selectedFile = "" self.selectedFile = ""
self.desktop.set_model(self.store)
self.desktop.set_pixbuf_column(0)
self.desktop.set_text_column(1)
self.desktop.connect("item-activated", self.iconLeftClickEventManager)
self.desktop.connect("button_press_event", self.iconRightClickEventManager, (self.desktop,))
def generateDirectoryGrid(self, dirPath): self.setIconViewDir(newPath)
loadProgress = self.builder.get_object('loadProgress')
loadProgress.set_text("Loading...") @threaded
loadProgress.set_fraction(0.0) def setIconViewDir(self, path):
self.clearGrid(self.desktop) self.store.clear()
self.currentPath = dirPath
self.currentPath = path
dirPaths = ['.', '..'] dirPaths = ['.', '..']
files = [] files = []
for f in listdir(dirPath): for f in listdir(path):
file = join(dirPath, f) file = join(path, f)
if self.settings.isHideHiddenFiles(): if self.settings.isHideHiddenFiles():
if f.startswith('.'): if f.startswith('.'):
continue continue
@ -53,7 +64,12 @@ class Grid:
else: else:
dirPaths.append(f) dirPaths.append(f)
vidsList = ('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv', '.mpeg', '.mp4', '.webm') dirPaths.sort()
files.sort()
files = dirPaths + files
self.generateDirectoryGrid(path, files)
def generateDirectoryGrid(self, dirPath, files):
fractionTick = 1.0 / 1.0 if len(files) == 0 else len(files) fractionTick = 1.0 / 1.0 if len(files) == 0 else len(files)
tickCount = 0.0 tickCount = 0.0
row = 0 row = 0
@ -61,100 +77,65 @@ class Grid:
x = 0 x = 0
y = 0 y = 0
dirPaths.sort() loadProgress = self.builder.get_object('loadProgress')
files.sort() loadProgress.set_text("Loading...")
files = dirPaths + files loadProgress.set_fraction(0.0)
for file in files: for file in files:
eveBox = gtk.EventBox() imgBuffer = Icon(self.settings).createIcon(dirPath, file)
gobject.idle_add(self.addToGrid, (imgBuffer, file,))
# Generate any thumbnails beforehand... tickCount += fractionTick
if file.lower().endswith(vidsList):
fullPathFile = dirPath + "/" + file
fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest()
hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png"
if isfile(hashImgpth) == False:
self.generateVideoThumbnail(fullPathFile, hashImgpth)
eveBox = self.generateIcon(dirPath, file, col, row)
else:
eveBox = self.generateIcon(dirPath, file, col, row)
eveBox.show_all()
gobject.idle_add(self.addToGrid, (self.desktop, eveBox, col, row,))
tickCount = tickCount + fractionTick
loadProgress.set_fraction(tickCount) loadProgress.set_fraction(tickCount)
col += 1
if col == self.ColumnSize:
col = 0
row += 1
loadProgress.set_text("Finished...") loadProgress.set_text("Finished...")
def generateIcon(self, dirPath, file, col, row):
eveBox = Icon(self.settings).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, ())
return eveBox
def addToGrid(self, args): def addToGrid(self, args):
args[0].attach(args[1], args[2], args[3], 1, 1) self.store.append([args[0], args[1]])
def clearGrid(self, object): def iconLeftClickEventManager(self, widget, item):
while True:
if object.get_child_at(0,0)!= None:
object.remove_row(0)
else:
break
def iconClickEventManager(self, widget, eve, params):
try: try:
self.settings.setSelected(params[0]) model = widget.get_model()
children = widget.get_children()[0].get_children() fileName = model[item][1]
fileName = children[1].get_text()
dir = self.currentPath dir = self.currentPath
file = dir + "/" + fileName file = dir + "/" + fileName
if eve.type == gdk.EventType.DOUBLE_BUTTON_PRESS: if fileName == ".":
if fileName == ".": self.setIconViewDir(dir)
self.setNewPath(dir) elif fileName == "..":
elif fileName == "..": parentDir = os.path.abspath(os.path.join(dir, os.pardir))
parentDir = os.path.abspath(os.path.join(dir, os.pardir)) self.currentPath = parentDir
self.currentPath = parentDir self.setIconViewDir(parentDir)
self.setNewPath(parentDir) elif isdir(file):
elif isdir(file): self.currentPath = file
self.currentPath = file self.setIconViewDir(self.currentPath)
self.setNewPath(self.currentPath) elif isfile(file):
elif isfile(file): self.filehandler.openFile(file)
self.filehandler.openFile(file) except Exception as e:
elif eve.type == gdk.EventType.BUTTON_PRESS and eve.button == 3: print(e)
input = self.builder.get_object("iconRenameInput")
popover = self.builder.get_object("iconControlsWindow")
self.selectedFile = file # Used for return to caller
input.set_text(fileName) def iconRightClickEventManager(self, widget, eve, params):
popover.set_relative_to(children[1]) try:
if eve.type == gdk.EventType.BUTTON_PRESS and eve.button == 3:
# # NOTE: Need to change name of listview box...
# children = widget.get_children()[0].get_children()
# fileName = children[1].get_text()
# dir = self.currentPath
# file = dir + "/" + fileName
#
# input = self.builder.get_object("iconRenameInput")
popover = self.builder.get_object("iconControlsWindow")
# self.selectedFile = file # Used for return to caller
#
# input.set_text(fileName)
popover.set_relative_to(widget)
popover.set_position(gtk.PositionType.RIGHT) popover.set_position(gtk.PositionType.RIGHT)
popover.show_all() popover.show_all()
popover.popup() popover.popup()
except Exception as e: except Exception as e:
print(e) print(e)
def generateVideoThumbnail(self, fullPathFile, hashImgpth):
subprocess.call([self.thubnailGen, "-t", "65%", "-s", "300", "-c", "jpg", "-i", fullPathFile, "-o", hashImgpth])
def setNewPath(self, path): # Passthrough file control events
self.generateDirectoryGrid(path)
# NOTE: Threading here causes seg faults. My theory is that
# the calling threading dies b/c the grid itself is cleard
# of children and the child is the one that has the 'thread'
#
# Thread(target=self.generateDirectoryGrid, args=(path,)).start()
# Pass through file control events
def createFile(arg): def createFile(arg):
pass pass

View File

@ -8,40 +8,30 @@ from gi.repository import Gtk as gtk
from gi.repository import Gio as gio from gi.repository import Gio as gio
from gi.repository import GdkPixbuf from gi.repository import GdkPixbuf
import os, hashlib import os, subprocess, hashlib, threading
from os.path import isdir, isfile, join from os.path import isdir, isfile, join
def threaded(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs).start()
return wrapper
class Icon: class Icon:
def __init__(self, settings): def __init__(self, settings):
self.usrHome = settings.returnUserHome() self.settings = settings
self.thubnailGen = self.settings.getThumbnailGenerator()
self.GTK_ORIENTATION = settings.returnIconImagePos() self.GTK_ORIENTATION = settings.returnIconImagePos()
self.usrHome = settings.returnUserHome()
self.iconContainerWxH = settings.returnContainerWH() self.iconContainerWxH = settings.returnContainerWH()
self.systemIconImageWxH = settings.returnSystemIconImageWH() self.systemIconImageWxH = settings.returnSystemIconImageWH()
self.viIconWxH = settings.returnVIIconWH() self.viIconWxH = settings.returnVIIconWH()
def createIcon(self, dir, file): def createIcon(self, dir, file):
fullPathFile = dir + "/" + file fullPathFile = dir + "/" + file
eveBox = gtk.EventBox()
icon = gtk.Box()
label = gtk.Label()
thumbnl = self.getIconImage(file, fullPathFile) thumbnl = self.getIconImage(file, fullPathFile)
return thumbnl
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_text(file)
icon.set_size_request(self.iconContainerWxH[0], self.iconContainerWxH[1]);
icon.set_property('orientation', self.GTK_ORIENTATION)
icon.add(thumbnl)
icon.add(label)
eveBox.add(icon)
eveBox.show_all()
return eveBox
def getIconImage(self, file, fullPathFile): def getIconImage(self, file, fullPathFile):
thumbnl = gtk.Image() thumbnl = gtk.Image()
@ -51,16 +41,31 @@ class Icon:
if file.lower().endswith(vidsList): if file.lower().endswith(vidsList):
fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest() fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest()
hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png" hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png"
thumbnl = self.createIconImageFromBuffer(hashImgpth, self.viIconWxH)
# Generate any thumbnails beforehand...
try:
if isfile(hashImgpth) == False:
self.generateVideoThumbnail(fullPathFile, hashImgpth)
thumbnl = self.createIconImageBuffer(hashImgpth, self.viIconWxH)
else:
thumbnl = self.createIconImageBuffer(hashImgpth, self.viIconWxH)
except Exception as e:
print(e)
thumbPth = self.getSystemThumbnail(fullPathFile, self.systemIconImageWxH[0])
thumbnl = self.createIconImageBuffer(thumbPth, self.systemIconImageWxH)
elif file.lower().endswith(imagesList): elif file.lower().endswith(imagesList):
thumbnl = self.createIconImageFromBuffer(fullPathFile, self.viIconWxH) thumbnl = self.createIconImageBuffer(fullPathFile, self.viIconWxH)
else: else:
thumbPth = self.getSystemThumbnail(fullPathFile, self.systemIconImageWxH[0]) thumbPth = self.getSystemThumbnail(fullPathFile, self.systemIconImageWxH[0])
thumbnl = self.createIconImageFromBuffer(thumbPth, self.systemIconImageWxH) thumbnl = self.createIconImageBuffer(thumbPth, self.systemIconImageWxH)
return thumbnl # NOTE: Returning pixbuf through retreval to keep this file more universaly usable.
# We can just remove get_pixbuf to get a gtk image
return thumbnl.get_pixbuf()
def createIconImageFromBuffer(self, path, wxh): def createIconImageBuffer(self, path, wxh):
pixbuf = None
try: try:
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
filename = path, filename = path,
@ -86,3 +91,7 @@ class Icon:
final_filename = icon_file.get_filename() final_filename = icon_file.get_filename()
return final_filename return final_filename
def generateVideoThumbnail(self, fullPathFile, hashImgpth):
proc = subprocess.Popen([self.thubnailGen, "-t", "65%", "-s", "300", "-c", "jpg", "-i", fullPathFile, "-o", hashImgpth])
proc.wait()

View File

@ -9,17 +9,15 @@ from gi.repository import Gdk as gdk
class Settings: class Settings:
def __init__(self): def __init__(self):
self.builder = None self.builder = None
self.hoveredFile = None
self.selectedFile = None
self.DEFAULTCOLOR = gdk.RGBA(0.0, 0.0, 0.0, 0.0) # ~#00000000
self.MOUSEOVERCOLOR = gdk.RGBA(0.0, 0.9, 1.0, 0.64) # ~#00e8ff
self.SELECTEDCOLOR = gdk.RGBA(0.4, 0.5, 0.1, 0.84)
self.GTK_ORIENTATION = 1 # HORIZONTAL (0) VERTICAL (1)
self.THUMB_GENERATOR = "ffmpegthumbnailer"
self.hideHiddenFiles = True self.hideHiddenFiles = True
self.GTK_ORIENTATION = 1 # HORIZONTAL (0) VERTICAL (1)
self.THUMB_GENERATOR = "ffmpegthumbnailer"
self.DEFAULTCOLOR = gdk.RGBA(0.0, 0.0, 0.0, 0.0) # ~#00000000
self.MOUSEOVERCOLOR = gdk.RGBA(0.0, 0.9, 1.0, 0.64) # ~#00e8ff
self.SELECTEDCOLOR = gdk.RGBA(0.4, 0.5, 0.1, 0.84)
self.webHome = 'http://webfm.com/' self.webHome = 'http://webfm.com/'
self.usrHome = os.path.expanduser('~') self.usrHome = os.path.expanduser('~')
self.desktopPath = self.usrHome + "/Desktop" self.desktopPath = self.usrHome + "/Desktop"
@ -80,27 +78,6 @@ class Settings:
def returnWebHome(self): return self.webHome def returnWebHome(self): return self.webHome
def isHideHiddenFiles(self): return self.hideHiddenFiles 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)
if widget != self.selectedFile:
widget.override_background_color(gtk.StateType.NORMAL, self.MOUSEOVERCOLOR)
def mouseOut(self, widget, eve, args):
watch_cursor = gdk.Cursor(gdk.CursorType.LEFT_PTR)
self.builder.get_object("Window").get_window().set_cursor(watch_cursor)
if widget != self.selectedFile:
widget.override_background_color(gtk.StateType.NORMAL, self.DEFAULTCOLOR)
def setSelected(self, eveBox):
if self.selectedFile:
self.selectedFile.override_background_color(gtk.StateType.NORMAL, self.DEFAULTCOLOR)
eveBox.override_background_color(gtk.StateType.NORMAL, self.SELECTEDCOLOR)
self.selectedFile = eveBox
def setDefaultWebviewSettings(self, widget, settings=None): def setDefaultWebviewSettings(self, widget, settings=None):
# Usability # Usability
settings.set_property('enable-fullscreen', True) settings.set_property('enable-fullscreen', True)

View File

@ -1,19 +1,10 @@
# Gtk Imports # Gtk Imports
import gi, threading
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk as gtk
from gi.repository import Gdk as gdk
# Python imports # Python imports
from .Grid import Grid from .Grid import Grid
from .Dragging import Dragging from .Dragging import Dragging
from threading import Thread
class Events: class Events:
def __init__(self, settings): def __init__(self, settings):
self.settings = settings self.settings = settings
@ -32,14 +23,12 @@ class Events:
selectedDirDialog.set_filename(self.desktopPath) selectedDirDialog.set_filename(self.desktopPath)
self.grid = None self.grid = None
self.setDir(selectedDirDialog) self.setIconViewDir(selectedDirDialog)
def setDir(self, widget, data=None): def setIconViewDir(self, widget, data=None):
newPath = widget.get_filename() newPath = widget.get_filename()
self.grid = Grid(self.desktop, self.settings) Grid(self.desktop, self.settings, newPath)
Thread(target=self.grid.generateDirectoryGrid, args=(newPath,)).start()
# Grid(self.desktop, self.settings).generateDirectoryGrid(newPath)
def showGridControlMenu(self, widget, data=None): def showGridControlMenu(self, widget, data=None):
popover = self.builder.get_object("gridControlMenu") popover = self.builder.get_object("gridControlMenu")
@ -70,6 +59,8 @@ class Events:
def pasteFile(self): def pasteFile(self):
pass pass
def test(self, widget, data=None):
print(widget)
# Webview events # Webview events
def showWebview(self, widget): def showWebview(self, widget):

View File

@ -1,5 +1,11 @@
import os, shutil, subprocess import os, shutil, subprocess, threading
def threaded(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs).start()
return wrapper
class FileHandler: class FileHandler:
def __init__(self): def __init__(self):
@ -22,7 +28,7 @@ class FileHandler:
self.MPLAYER_WH = " -xy 1600 -geometry 50%:50% "; self.MPLAYER_WH = " -xy 1600 -geometry 50%:50% ";
self.MPV_WH = " -geometry 50%:50% "; self.MPV_WH = " -geometry 50%:50% ";
@threaded
def openFile(self, file): def openFile(self, file):
print("Opening: " + file) print("Opening: " + file)
if file.lower().endswith(self.vids): if file.lower().endswith(self.vids):

View File

@ -7,44 +7,55 @@ gi.require_version('Gdk', '3.0')
from gi.repository import Gtk as gtk from gi.repository import Gtk as gtk
from gi.repository import Gdk as gdk from gi.repository import Gdk as gdk
from gi.repository import GdkPixbuf
from gi.repository import GObject as gobject from gi.repository import GObject as gobject
# Python imports # Python imports
import os, subprocess, threading, hashlib import os, threading
from os.path import isdir, isfile, join from os.path import isdir, isfile, join
from os import listdir from os import listdir
from threading import Thread
from .Icon import Icon from .Icon import Icon
from .FileHandler import FileHandler from .FileHandler import FileHandler
gdk.threads_init() gdk.threads_init()
def threaded(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs).start()
return wrapper
class Grid: class Grid:
def __init__(self, desktop, settings): def __init__(self, desktop, settings, newPath):
self.desktop = desktop self.desktop = desktop
self.settings = settings self.settings = settings
self.filehandler = FileHandler() self.filehandler = FileHandler()
self.usrHome = settings.returnUserHome()
self.builder = self.settings.returnBuilder()
self.ColumnSize = self.settings.returnColumnSize()
self.thubnailGen = self.settings.getThumbnailGenerator()
self.store = gtk.ListStore(GdkPixbuf.Pixbuf, str)
self.usrHome = settings.returnUserHome()
self.builder = self.settings.returnBuilder()
self.ColumnSize = self.settings.returnColumnSize()
self.currentPath = "" self.currentPath = ""
self.selectedFile = "" self.selectedFile = ""
self.desktop.set_model(self.store)
self.desktop.set_pixbuf_column(0)
self.desktop.set_text_column(1)
self.desktop.connect("item-activated", self.iconLeftClickEventManager)
self.desktop.connect("button_press_event", self.iconRightClickEventManager, (self.desktop,))
def generateDirectoryGrid(self, dirPath): self.setIconViewDir(newPath)
loadProgress = self.builder.get_object('loadProgress')
loadProgress.set_text("Loading...") @threaded
loadProgress.set_fraction(0.0) def setIconViewDir(self, path):
self.clearGrid(self.desktop) self.store.clear()
self.currentPath = dirPath
self.currentPath = path
dirPaths = ['.', '..'] dirPaths = ['.', '..']
files = [] files = []
for f in listdir(dirPath): for f in listdir(path):
file = join(dirPath, f) file = join(path, f)
if self.settings.isHideHiddenFiles(): if self.settings.isHideHiddenFiles():
if f.startswith('.'): if f.startswith('.'):
continue continue
@ -53,7 +64,12 @@ class Grid:
else: else:
dirPaths.append(f) dirPaths.append(f)
vidsList = ('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv', '.mpeg', '.mp4', '.webm') dirPaths.sort()
files.sort()
files = dirPaths + files
self.generateDirectoryGrid(path, files)
def generateDirectoryGrid(self, dirPath, files):
fractionTick = 1.0 / 1.0 if len(files) == 0 else len(files) fractionTick = 1.0 / 1.0 if len(files) == 0 else len(files)
tickCount = 0.0 tickCount = 0.0
row = 0 row = 0
@ -61,100 +77,65 @@ class Grid:
x = 0 x = 0
y = 0 y = 0
dirPaths.sort() loadProgress = self.builder.get_object('loadProgress')
files.sort() loadProgress.set_text("Loading...")
files = dirPaths + files loadProgress.set_fraction(0.0)
for file in files: for file in files:
eveBox = gtk.EventBox() imgBuffer = Icon(self.settings).createIcon(dirPath, file)
gobject.idle_add(self.addToGrid, (imgBuffer, file,))
# Generate any thumbnails beforehand... tickCount += fractionTick
if file.lower().endswith(vidsList):
fullPathFile = dirPath + "/" + file
fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest()
hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png"
if isfile(hashImgpth) == False:
self.generateVideoThumbnail(fullPathFile, hashImgpth)
eveBox = self.generateIcon(dirPath, file, col, row)
else:
eveBox = self.generateIcon(dirPath, file, col, row)
eveBox.show_all()
gobject.idle_add(self.addToGrid, (self.desktop, eveBox, col, row,))
tickCount = tickCount + fractionTick
loadProgress.set_fraction(tickCount) loadProgress.set_fraction(tickCount)
col += 1
if col == self.ColumnSize:
col = 0
row += 1
loadProgress.set_text("Finished...") loadProgress.set_text("Finished...")
def generateIcon(self, dirPath, file, col, row):
eveBox = Icon(self.settings).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, ())
return eveBox
def addToGrid(self, args): def addToGrid(self, args):
args[0].attach(args[1], args[2], args[3], 1, 1) self.store.append([args[0], args[1]])
def clearGrid(self, object): def iconLeftClickEventManager(self, widget, item):
while True:
if object.get_child_at(0,0)!= None:
object.remove_row(0)
else:
break
def iconClickEventManager(self, widget, eve, params):
try: try:
self.settings.setSelected(params[0]) model = widget.get_model()
children = widget.get_children()[0].get_children() fileName = model[item][1]
fileName = children[1].get_text()
dir = self.currentPath dir = self.currentPath
file = dir + "/" + fileName file = dir + "/" + fileName
if eve.type == gdk.EventType.DOUBLE_BUTTON_PRESS: if fileName == ".":
if fileName == ".": self.setIconViewDir(dir)
self.setNewPath(dir) elif fileName == "..":
elif fileName == "..": parentDir = os.path.abspath(os.path.join(dir, os.pardir))
parentDir = os.path.abspath(os.path.join(dir, os.pardir)) self.currentPath = parentDir
self.currentPath = parentDir self.setIconViewDir(parentDir)
self.setNewPath(parentDir) elif isdir(file):
elif isdir(file): self.currentPath = file
self.currentPath = file self.setIconViewDir(self.currentPath)
self.setNewPath(self.currentPath) elif isfile(file):
elif isfile(file): self.filehandler.openFile(file)
self.filehandler.openFile(file) except Exception as e:
elif eve.type == gdk.EventType.BUTTON_PRESS and eve.button == 3: print(e)
input = self.builder.get_object("iconRenameInput")
popover = self.builder.get_object("iconControlsWindow")
self.selectedFile = file # Used for return to caller
input.set_text(fileName) def iconRightClickEventManager(self, widget, eve, params):
popover.set_relative_to(children[1]) try:
if eve.type == gdk.EventType.BUTTON_PRESS and eve.button == 3:
# # NOTE: Need to change name of listview box...
# children = widget.get_children()[0].get_children()
# fileName = children[1].get_text()
# dir = self.currentPath
# file = dir + "/" + fileName
#
# input = self.builder.get_object("iconRenameInput")
popover = self.builder.get_object("iconControlsWindow")
# self.selectedFile = file # Used for return to caller
#
# input.set_text(fileName)
popover.set_relative_to(widget)
popover.set_position(gtk.PositionType.RIGHT) popover.set_position(gtk.PositionType.RIGHT)
popover.show_all() popover.show_all()
popover.popup() popover.popup()
except Exception as e: except Exception as e:
print(e) print(e)
def generateVideoThumbnail(self, fullPathFile, hashImgpth):
subprocess.call([self.thubnailGen, "-t", "65%", "-s", "300", "-c", "jpg", "-i", fullPathFile, "-o", hashImgpth])
def setNewPath(self, path): # Passthrough file control events
self.generateDirectoryGrid(path)
# NOTE: Threading here causes seg faults. My theory is that
# the calling threading dies b/c the grid itself is cleard
# of children and the child is the one that has the 'thread'
#
# Thread(target=self.generateDirectoryGrid, args=(path,)).start()
# Pass through file control events
def createFile(arg): def createFile(arg):
pass pass

View File

@ -8,40 +8,30 @@ from gi.repository import Gtk as gtk
from gi.repository import Gio as gio from gi.repository import Gio as gio
from gi.repository import GdkPixbuf from gi.repository import GdkPixbuf
import os, hashlib import os, subprocess, hashlib, threading
from os.path import isdir, isfile, join from os.path import isdir, isfile, join
def threaded(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs).start()
return wrapper
class Icon: class Icon:
def __init__(self, settings): def __init__(self, settings):
self.usrHome = settings.returnUserHome() self.settings = settings
self.thubnailGen = self.settings.getThumbnailGenerator()
self.GTK_ORIENTATION = settings.returnIconImagePos() self.GTK_ORIENTATION = settings.returnIconImagePos()
self.usrHome = settings.returnUserHome()
self.iconContainerWxH = settings.returnContainerWH() self.iconContainerWxH = settings.returnContainerWH()
self.systemIconImageWxH = settings.returnSystemIconImageWH() self.systemIconImageWxH = settings.returnSystemIconImageWH()
self.viIconWxH = settings.returnVIIconWH() self.viIconWxH = settings.returnVIIconWH()
def createIcon(self, dir, file): def createIcon(self, dir, file):
fullPathFile = dir + "/" + file fullPathFile = dir + "/" + file
eveBox = gtk.EventBox()
icon = gtk.Box()
label = gtk.Label()
thumbnl = self.getIconImage(file, fullPathFile) thumbnl = self.getIconImage(file, fullPathFile)
return thumbnl
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_text(file)
icon.set_size_request(self.iconContainerWxH[0], self.iconContainerWxH[1]);
icon.set_property('orientation', self.GTK_ORIENTATION)
icon.add(thumbnl)
icon.add(label)
eveBox.add(icon)
eveBox.show_all()
return eveBox
def getIconImage(self, file, fullPathFile): def getIconImage(self, file, fullPathFile):
thumbnl = gtk.Image() thumbnl = gtk.Image()
@ -51,16 +41,31 @@ class Icon:
if file.lower().endswith(vidsList): if file.lower().endswith(vidsList):
fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest() fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest()
hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png" hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png"
thumbnl = self.createIconImageFromBuffer(hashImgpth, self.viIconWxH)
# Generate any thumbnails beforehand...
try:
if isfile(hashImgpth) == False:
self.generateVideoThumbnail(fullPathFile, hashImgpth)
thumbnl = self.createIconImageBuffer(hashImgpth, self.viIconWxH)
else:
thumbnl = self.createIconImageBuffer(hashImgpth, self.viIconWxH)
except Exception as e:
print(e)
thumbPth = self.getSystemThumbnail(fullPathFile, self.systemIconImageWxH[0])
thumbnl = self.createIconImageBuffer(thumbPth, self.systemIconImageWxH)
elif file.lower().endswith(imagesList): elif file.lower().endswith(imagesList):
thumbnl = self.createIconImageFromBuffer(fullPathFile, self.viIconWxH) thumbnl = self.createIconImageBuffer(fullPathFile, self.viIconWxH)
else: else:
thumbPth = self.getSystemThumbnail(fullPathFile, self.systemIconImageWxH[0]) thumbPth = self.getSystemThumbnail(fullPathFile, self.systemIconImageWxH[0])
thumbnl = self.createIconImageFromBuffer(thumbPth, self.systemIconImageWxH) thumbnl = self.createIconImageBuffer(thumbPth, self.systemIconImageWxH)
return thumbnl # NOTE: Returning pixbuf through retreval to keep this file more universaly usable.
# We can just remove get_pixbuf to get a gtk image
return thumbnl.get_pixbuf()
def createIconImageFromBuffer(self, path, wxh): def createIconImageBuffer(self, path, wxh):
pixbuf = None
try: try:
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
filename = path, filename = path,
@ -86,3 +91,7 @@ class Icon:
final_filename = icon_file.get_filename() final_filename = icon_file.get_filename()
return final_filename return final_filename
def generateVideoThumbnail(self, fullPathFile, hashImgpth):
proc = subprocess.Popen([self.thubnailGen, "-t", "65%", "-s", "300", "-c", "jpg", "-i", fullPathFile, "-o", hashImgpth])
proc.wait()

View File

@ -9,17 +9,15 @@ from gi.repository import Gdk as gdk
class Settings: class Settings:
def __init__(self): def __init__(self):
self.builder = None self.builder = None
self.hoveredFile = None
self.selectedFile = None
self.DEFAULTCOLOR = gdk.RGBA(0.0, 0.0, 0.0, 0.0) # ~#00000000
self.MOUSEOVERCOLOR = gdk.RGBA(0.0, 0.9, 1.0, 0.64) # ~#00e8ff
self.SELECTEDCOLOR = gdk.RGBA(0.4, 0.5, 0.1, 0.84)
self.GTK_ORIENTATION = 1 # HORIZONTAL (0) VERTICAL (1)
self.THUMB_GENERATOR = "ffmpegthumbnailer"
self.hideHiddenFiles = True self.hideHiddenFiles = True
self.GTK_ORIENTATION = 1 # HORIZONTAL (0) VERTICAL (1)
self.THUMB_GENERATOR = "ffmpegthumbnailer"
self.DEFAULTCOLOR = gdk.RGBA(0.0, 0.0, 0.0, 0.0) # ~#00000000
self.MOUSEOVERCOLOR = gdk.RGBA(0.0, 0.9, 1.0, 0.64) # ~#00e8ff
self.SELECTEDCOLOR = gdk.RGBA(0.4, 0.5, 0.1, 0.84)
self.webHome = 'http://webfm.com/' self.webHome = 'http://webfm.com/'
self.usrHome = os.path.expanduser('~') self.usrHome = os.path.expanduser('~')
self.desktopPath = self.usrHome + "/Desktop" self.desktopPath = self.usrHome + "/Desktop"
@ -80,27 +78,6 @@ class Settings:
def returnWebHome(self): return self.webHome def returnWebHome(self): return self.webHome
def isHideHiddenFiles(self): return self.hideHiddenFiles 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)
if widget != self.selectedFile:
widget.override_background_color(gtk.StateType.NORMAL, self.MOUSEOVERCOLOR)
def mouseOut(self, widget, eve, args):
watch_cursor = gdk.Cursor(gdk.CursorType.LEFT_PTR)
self.builder.get_object("Window").get_window().set_cursor(watch_cursor)
if widget != self.selectedFile:
widget.override_background_color(gtk.StateType.NORMAL, self.DEFAULTCOLOR)
def setSelected(self, eveBox):
if self.selectedFile:
self.selectedFile.override_background_color(gtk.StateType.NORMAL, self.DEFAULTCOLOR)
eveBox.override_background_color(gtk.StateType.NORMAL, self.SELECTEDCOLOR)
self.selectedFile = eveBox
def setDefaultWebviewSettings(self, widget, settings=None): def setDefaultWebviewSettings(self, widget, settings=None):
# Usability # Usability
settings.set_property('enable-fullscreen', True) settings.set_property('enable-fullscreen', True)