alfrix d3281379ee gtk: change scaling of images
This reduces the amount of magic numbers used, some images will scale to bigger sizes, most of the icons and images in vertical mode will be bigger, thumbnails should be bigger in both modes.
2022-10-26 22:36:52 -03:00

422 lines
15 KiB
Python

# -*- coding: utf-8 -*-
import gi
import logging
import os
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, Pango
from datetime import datetime
from ks_includes.screen_panel import ScreenPanel
def create_panel(*args):
return PrintPanel(*args)
class PrintPanel(ScreenPanel):
cur_directory = "gcodes"
dir_panels = {}
filelist = {'gcodes': {'directories': [], 'files': []}}
def __init__(self, screen, title, back=True):
super().__init__(screen, title, back)
sortdir = self._config.get_main_config().get("print_sort_dir", "name_asc")
sortdir = sortdir.split('_')
if sortdir[0] not in ["name", "date"] or sortdir[1] not in ["asc", "desc"]:
sortdir = ["name", "asc"]
self.sort_current = [sortdir[0], 0 if sortdir[1] == "asc" else 1] # 0 for asc, 1 for desc
self.sort_items = {
"name": _("Name"),
"date": _("Date")
}
self.sort_icon = ["arrow-up", "arrow-down"]
self.scroll = self._gtk.ScrolledWindow()
self.files = {}
self.directories = {}
self.labels['directories'] = {}
self.labels['files'] = {}
def initialize(self, panel_name):
sort = Gtk.Label(_("Sort:"))
sbox = Gtk.Box(spacing=0)
sbox.set_vexpand(False)
sbox.pack_start(sort, False, False, 5)
for i, (name, val) in enumerate(self.sort_items.items(), start=1):
s = self._gtk.ButtonImage(None, val, f"color{i % 4}", .5, Gtk.PositionType.RIGHT, 1)
if name == self.sort_current[0]:
s.set_image(self._gtk.Image(self.sort_icon[self.sort_current[1]], self._gtk.img_scale * .5))
s.connect("clicked", self.change_sort, name)
self.labels[f'sort_{name}'] = s
sbox.add(s)
refresh = self._gtk.ButtonImage("refresh", scale=.66)
refresh.connect('clicked', self._refresh_files)
sbox.add(refresh)
sbox.set_hexpand(True)
sbox.set_vexpand(False)
pbox = Gtk.Box(spacing=0)
pbox.set_hexpand(True)
pbox.set_vexpand(False)
self.labels['path'] = Gtk.Label(" /")
pbox.add(self.labels['path'])
self.labels['path_box'] = pbox
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
box.set_vexpand(True)
box.pack_start(sbox, False, False, 0)
box.pack_start(pbox, False, False, 0)
box.pack_start(self.scroll, True, True, 0)
self.dir_panels['gcodes'] = Gtk.Grid()
GLib.idle_add(self.reload_files)
self.scroll.add(self.dir_panels['gcodes'])
self.content.add(box)
self._screen.files.add_file_callback(self._callback)
def activate(self):
if self.cur_directory != "gcodes":
self.change_dir(None, "gcodes")
def add_directory(self, directory, show=True):
parent_dir = '/'.join(directory.split('/')[:-1])
if directory not in self.filelist:
self.filelist[directory] = {'directories': [], 'files': [], 'modified': 0}
self.filelist[parent_dir]['directories'].append(directory)
if directory not in self.labels['directories']:
self._create_frame(directory)
reverse = self.sort_current[1] != 0
dirs = sorted(
self.filelist[parent_dir]['directories'],
reverse=reverse, key=lambda item: self.filelist[item]['modified']
) if self.sort_current[0] == "date" else sorted(self.filelist[parent_dir]['directories'], reverse=reverse)
pos = dirs.index(directory)
self.dir_panels[parent_dir].insert_row(pos)
self.dir_panels[parent_dir].attach(self.directories[directory], 0, pos, 1, 1)
if show is True:
self.dir_panels[parent_dir].show_all()
def add_file(self, filepath, show=True):
fileinfo = self._screen.files.get_file_info(filepath)
if fileinfo is None:
return
d = f"gcodes/{filepath}".split('/')[:-1]
directory = '/'.join(d)
filename = filepath.split('/')[-1]
if filename.startswith("."):
return
for i in range(1, len(d)):
curdir = "/".join(d[:i])
newdir = "/".join(d[:i + 1])
if newdir not in self.filelist[curdir]['directories']:
if d[i].startswith("."):
return
self.add_directory(newdir)
if filename not in self.filelist[directory]['files']:
for i in range(1, len(d)):
curdir = "/".join(d[:i + 1])
if curdir != "gcodes" and fileinfo['modified'] > self.filelist[curdir]['modified']:
self.filelist[curdir]['modified'] = fileinfo['modified']
self.labels['directories'][curdir]['info'].set_markup(
'<small>' + _("Modified")
+ f' <b>{datetime.fromtimestamp(fileinfo["modified"]):%Y-%m-%d %H:%M}</b></small>'
)
self.filelist[directory]['files'].append(filename)
if filepath not in self.files:
self._create_frame_file(filename, filepath)
reverse = self.sort_current[1] != 0
files = sorted(
self.filelist[directory]['files'],
reverse=reverse,
key=lambda item: self._screen.files.get_file_info(f"{directory}/{item}"[7:])['modified']
) if self.sort_current[0] == "date" else sorted(self.filelist[directory]['files'], reverse=reverse)
pos = files.index(filename)
pos += len(self.filelist[directory]['directories'])
self.dir_panels[directory].insert_row(pos)
self.dir_panels[directory].attach(self.files[filepath], 0, pos, 1, 1)
if show is True:
self.dir_panels[directory].show_all()
def _create_frame(self, directory):
frame = Gtk.Frame()
frame.get_style_context().add_class("frame-item")
name = Gtk.Label()
name.set_markup(f"<big><b>{directory.split('/')[-1]}</b></big>")
name.set_hexpand(True)
name.set_halign(Gtk.Align.START)
name.set_line_wrap(True)
name.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR)
info = Gtk.Label()
info.set_halign(Gtk.Align.START)
labels = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
labels.add(name)
labels.add(info)
labels.set_vexpand(True)
labels.set_valign(Gtk.Align.CENTER)
labels.set_halign(Gtk.Align.START)
actions = self._gtk.ButtonImage("load", style="color3")
actions.connect("clicked", self.change_dir, directory)
actions.set_hexpand(False)
actions.set_halign(Gtk.Align.END)
file = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
file.set_hexpand(True)
file.set_vexpand(False)
icon = self._gtk.Image("folder")
file.add(icon)
file.add(labels)
file.add(actions)
frame.add(file)
self.directories[directory] = frame
self.labels['directories'][directory] = {
"icon": icon,
"info": info,
"name": name
}
self.dir_panels[directory] = Gtk.Grid()
def _create_frame_file(self, filename, filepath):
frame = Gtk.Frame()
frame.get_style_context().add_class("frame-item")
name = Gtk.Label()
name.set_markup(f'<big><b>{os.path.splitext(filename)[0].replace("_", " ")}</b></big>')
name.set_hexpand(True)
name.set_halign(Gtk.Align.START)
name.set_line_wrap(True)
name.set_line_wrap_mode(Pango.WrapMode.CHAR)
info = Gtk.Label()
info.set_halign(Gtk.Align.START)
info.set_markup(self.get_file_info_str(filepath))
labels = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
labels.add(name)
labels.add(info)
labels.set_vexpand(True)
labels.set_valign(Gtk.Align.CENTER)
labels.set_halign(Gtk.Align.START)
actions = self._gtk.ButtonImage("print", style="color3")
actions.connect("clicked", self.confirm_print, filepath)
actions.set_hexpand(False)
actions.set_halign(Gtk.Align.END)
file = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
file.set_hexpand(True)
file.set_vexpand(False)
pixbuf = self.get_file_image(filepath, small=True)
if pixbuf is not None:
icon = Gtk.Image.new_from_pixbuf(pixbuf)
else:
icon = self._gtk.Image("file")
img = Gtk.Button()
img.set_image(icon)
img.connect("clicked", self.confirm_delete_file, f"gcodes/{filepath}")
file.add(img)
file.add(labels)
if os.path.splitext(filename)[1] in [".gcode", ".g", ".gco"]:
file.add(actions)
frame.add(file)
self.files[filepath] = frame
self.labels['files'][filepath] = {
"icon": icon,
"info": info,
"name": name
}
def confirm_delete_file(self, widget, filepath):
logging.debug(f"Sending delete_file {filepath}")
params = {"path": f"{filepath}"}
self._screen._confirm_send_action(
None,
_("Delete File?") + "\n\n" + filepath,
"server.files.delete_file",
params
)
def back(self):
if len(self.cur_directory.split('/')) > 1:
self.change_dir(None, '/'.join(self.cur_directory.split('/')[:-1]))
return True
return False
def change_dir(self, widget, directory):
if directory not in self.dir_panels:
return
logging.debug(f"Changing dir to {directory}")
for child in self.scroll.get_children():
self.scroll.remove(child)
self.cur_directory = directory
self.labels['path'].set_text(f" /{self.cur_directory[7:]}")
self.scroll.add(self.dir_panels[directory])
self.content.show_all()
def change_sort(self, widget, key):
if self.sort_current[0] == key:
self.sort_current[1] = (self.sort_current[1] + 1) % 2
else:
oldkey = self.sort_current[0]
logging.info(f"Changing sort_{oldkey} to {self.sort_items[self.sort_current[0]]}")
self.labels[f'sort_{oldkey}'].set_image(None)
self.labels[f'sort_{oldkey}'].show_all()
self.sort_current = [key, 0]
self.labels[f'sort_{key}'].set_image(self._gtk.Image(self.sort_icon[self.sort_current[1]],
self._gtk.img_scale * .5))
self.labels[f'sort_{key}'].show()
GLib.idle_add(self.reload_files)
self._config.set("main", "print_sort_dir", f'{key}_{"asc" if self.sort_current[1] == 0 else "desc"}')
self._config.save_user_config_options()
def confirm_print(self, widget, filename):
buttons = [
{"name": _("Print"), "response": Gtk.ResponseType.OK},
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL}
]
label = Gtk.Label()
label.set_markup(f"<b>{filename}</b>\n")
label.set_hexpand(True)
label.set_halign(Gtk.Align.CENTER)
label.set_vexpand(True)
label.set_valign(Gtk.Align.CENTER)
label.set_line_wrap(True)
label.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR)
grid = Gtk.Grid()
grid.set_vexpand(True)
grid.set_halign(Gtk.Align.CENTER)
grid.set_valign(Gtk.Align.CENTER)
grid.add(label)
pixbuf = self.get_file_image(filename, self._screen.width * .9, self._screen.height * .6)
if pixbuf is not None:
image = Gtk.Image.new_from_pixbuf(pixbuf)
image.set_vexpand(False)
grid.attach_next_to(image, label, Gtk.PositionType.BOTTOM, 1, 1)
self._gtk.Dialog(self._screen, buttons, grid, self.confirm_print_response, filename)
def confirm_print_response(self, widget, response_id, filename):
widget.destroy()
if response_id == Gtk.ResponseType.CANCEL:
return
logging.info(f"Starting print: {filename}")
self._screen._ws.klippy.print_start(filename)
def delete_file(self, filename):
dir_parts = f"gcodes/{filename}".split('/')[:-1]
directory = '/'.join(dir_parts)
if directory not in self.filelist or filename.split('/')[-1].startswith("."):
return
self.filelist[directory]["files"].pop(self.filelist[directory]["files"].index(filename.split('/')[-1]))
i = len(dir_parts)
while i > 1:
cur_dir = '/'.join(dir_parts[:i])
if len(self.filelist[cur_dir]['directories']) > 0 or len(self.filelist[cur_dir]['files']) > 0:
break
par_dir = '/'.join(cur_dir.split('/')[:-1])
if self.cur_directory == cur_dir:
self.change_dir(None, par_dir)
del self.filelist[cur_dir]
self.filelist[par_dir]['directories'].pop(self.filelist[par_dir]['directories'].index(cur_dir))
self.dir_panels[par_dir].remove(self.directories[cur_dir])
del self.directories[cur_dir]
del self.labels['directories'][cur_dir]
self.dir_panels[par_dir].show_all()
i -= 1
self.dir_panels[directory].remove(self.files[filename])
self.dir_panels[directory].show_all()
self.files.pop(filename)
def get_file_info_str(self, filename):
fileinfo = self._screen.files.get_file_info(filename)
if fileinfo is None:
return
info = '<small>' + _("Uploaded") + f': <b>{datetime.fromtimestamp(fileinfo["modified"]):%Y-%m-%d %H:%M}</b>\n'
if "size" in fileinfo:
info += _("Size") + f': <b>{self.format_size(fileinfo["size"])}</b>\n'
if "estimated_time" in fileinfo:
info += _("Print Time") + f': <b>{self.format_time(fileinfo["estimated_time"])}</b>'
info += "</small>"
return info
def reload_files(self, widget=None):
self.filelist = {'gcodes': {'directories': [], 'files': []}}
for dirpan in self.dir_panels:
for child in self.dir_panels[dirpan].get_children():
self.dir_panels[dirpan].remove(child)
flist = sorted(self._screen.files.get_file_list(), key=lambda item: '/' in item)
for file in flist:
GLib.idle_add(self.add_file, file)
def update_file(self, filename):
if filename not in self.labels['files']:
logging.debug(f"Cannot update file, file not in labels: {filename}")
return
logging.info(f"Updating file {filename}")
self.labels['files'][filename]['info'].set_markup(self.get_file_info_str(filename))
# Update icon
pixbuf = self.get_file_image(filename)
if pixbuf is not None:
self.labels['files'][filename]['icon'].set_from_pixbuf(pixbuf)
def _callback(self, newfiles, deletedfiles, updatedfiles=None):
logging.debug(f"newfiles: {newfiles}")
for file in newfiles:
self.add_file(file)
logging.debug(f"deletedfiles: {deletedfiles}")
for file in deletedfiles:
self.delete_file(file)
if updatedfiles is not None:
logging.debug(f"updatefiles: {updatedfiles}")
for file in updatedfiles:
self.update_file(file)
def _refresh_files(self, widget):
self._files.refresh_files()
def process_update(self, action, data):
if action == "notify_gcode_response" and "unknown" in data.lower():
self._screen.show_popup_message(data)
return