mirror of
https://github.com/blw1138/Zordon.git
synced 2025-12-17 16:58:12 +00:00
Added preview image and action buttons to UI
This commit is contained in:
@@ -1,9 +1,12 @@
|
|||||||
|
import subprocess
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
from tkinter import ttk
|
from tkinter import ttk
|
||||||
|
from PIL import Image, ImageTk
|
||||||
from new_job_window import NewJobWindow
|
from new_job_window import NewJobWindow
|
||||||
from server_proxy import RenderServerProxy
|
from server_proxy import RenderServerProxy
|
||||||
|
|
||||||
@@ -36,11 +39,17 @@ class ZordonClient:
|
|||||||
|
|
||||||
# Create a Treeview widget
|
# Create a Treeview widget
|
||||||
self.root = tk.Tk()
|
self.root = tk.Tk()
|
||||||
self.tree = ttk.Treeview(self.root, show="headings")
|
self.root.title("Zordon Render Client")
|
||||||
self.server_proxy = RenderServerProxy(hostname='localhost')
|
self.server_proxy = RenderServerProxy(hostname='localhost')
|
||||||
self.job_cache = []
|
self.job_cache = []
|
||||||
|
|
||||||
# Define the columns
|
# Setup photo preview
|
||||||
|
self.photo_label = tk.Label(self.root, width=400, height=300)
|
||||||
|
self.photo_label.pack()
|
||||||
|
|
||||||
|
# Setup the Tree
|
||||||
|
self.tree = ttk.Treeview(self.root, show="headings")
|
||||||
|
self.tree.bind("<<TreeviewSelect>>", self.on_row_select)
|
||||||
self.tree["columns"] = ("id", "Name", "Renderer", "Priority", "Status", "Time Elapsed", "Frames")
|
self.tree["columns"] = ("id", "Name", "Renderer", "Priority", "Status", "Time Elapsed", "Frames")
|
||||||
|
|
||||||
# Format the columns
|
# Format the columns
|
||||||
@@ -57,10 +66,22 @@ class ZordonClient:
|
|||||||
self.tree.heading(name, text=name)
|
self.tree.heading(name, text=name)
|
||||||
|
|
||||||
# Pack the Treeview widget
|
# Pack the Treeview widget
|
||||||
self.tree.pack(fill=tk.BOTH, expand=False)
|
self.tree.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
new_job_button = tk.Button(self.root, text="New Job", command=self.show_new_job_window)
|
button_frame = tk.Frame(self.root)
|
||||||
new_job_button.pack()
|
button_frame.pack(pady=10)
|
||||||
|
|
||||||
|
# Create buttons
|
||||||
|
logs_button = tk.Button(button_frame, text="Logs", command=self.open_logs)
|
||||||
|
finder_button = tk.Button(button_frame, text="Reveal in Finder", command=self.reveal_in_finder)
|
||||||
|
self.stop_button = tk.Button(button_frame, text="Stop Job", command=self.stop_job)
|
||||||
|
add_job_button = tk.Button(button_frame, text="Add Job", command=self.show_new_job_window)
|
||||||
|
|
||||||
|
# Pack the buttons in the frame
|
||||||
|
self.stop_button.pack(side=tk.LEFT)
|
||||||
|
finder_button.pack(side=tk.LEFT)
|
||||||
|
logs_button.pack(side=tk.LEFT)
|
||||||
|
add_job_button.pack(side=tk.RIGHT)
|
||||||
|
|
||||||
# Start the Tkinter event loop
|
# Start the Tkinter event loop
|
||||||
self.root.geometry("500x600+300+300")
|
self.root.geometry("500x600+300+300")
|
||||||
@@ -68,8 +89,57 @@ class ZordonClient:
|
|||||||
self.root.minsize(width=600, height=600)
|
self.root.minsize(width=600, height=600)
|
||||||
|
|
||||||
make_sortable(self.tree)
|
make_sortable(self.tree)
|
||||||
|
|
||||||
|
self.update_jobs()
|
||||||
|
selected_item = self.tree.get_children()[0]
|
||||||
|
self.tree.selection_set(selected_item)
|
||||||
self.start_update_thread()
|
self.start_update_thread()
|
||||||
|
|
||||||
|
def stop_job(self):
|
||||||
|
selected_item = self.tree.selection()[0] # Get the selected item
|
||||||
|
row_data = self.tree.item(selected_item) # Get the text of the selected item
|
||||||
|
job_id = row_data['values'][0]
|
||||||
|
self.server_proxy.request_data(f'job/{job_id}/cancel?confirm=true')
|
||||||
|
|
||||||
|
def on_row_select(self, event):
|
||||||
|
selected_item = self.tree.selection()[0] # Get the selected item
|
||||||
|
row_data = self.tree.item(selected_item) # Get the text of the selected item
|
||||||
|
job_id = row_data['values'][0]
|
||||||
|
|
||||||
|
# update thumb
|
||||||
|
thumb_url = f'http://{self.server_proxy.hostname}:{self.server_proxy.port}/ui/job/{job_id}/thumbnail'
|
||||||
|
response = requests.get(thumb_url)
|
||||||
|
if response.status_code == 200:
|
||||||
|
import io
|
||||||
|
image_data = response.content
|
||||||
|
image = Image.open(io.BytesIO(image_data))
|
||||||
|
thumb_image = ImageTk.PhotoImage(image)
|
||||||
|
if thumb_image:
|
||||||
|
self.photo_label.configure(image=thumb_image)
|
||||||
|
self.photo_label.image = thumb_image
|
||||||
|
|
||||||
|
# update button status
|
||||||
|
job = next((d for d in self.job_cache if d.get('id') == job_id), None)
|
||||||
|
button_state = 'normal' if job['status'] == 'running' else 'disabled'
|
||||||
|
self.stop_button.config(state=button_state)
|
||||||
|
|
||||||
|
def reveal_in_finder(self):
|
||||||
|
selected_item = self.tree.selection()[0] # Get the selected item
|
||||||
|
row_data = self.tree.item(selected_item) # Get the text of the selected item
|
||||||
|
job_id = row_data['values'][0]
|
||||||
|
|
||||||
|
job = next((d for d in self.job_cache if d.get('id') == job_id), None)
|
||||||
|
output_dir = os.path.dirname(job['output_path'])
|
||||||
|
subprocess.run(['open', output_dir])
|
||||||
|
|
||||||
|
def open_logs(self):
|
||||||
|
selected_item = self.tree.selection()[0] # Get the selected item
|
||||||
|
row_data = self.tree.item(selected_item) # Get the text of the selected item
|
||||||
|
job_id = row_data['values'][0]
|
||||||
|
|
||||||
|
job = next((d for d in self.job_cache if d.get('id') == job_id), None)
|
||||||
|
subprocess.run(['open', job['log_path']])
|
||||||
|
|
||||||
def mainloop(self):
|
def mainloop(self):
|
||||||
self.root.mainloop()
|
self.root.mainloop()
|
||||||
|
|
||||||
@@ -93,12 +163,18 @@ class ZordonClient:
|
|||||||
break
|
break
|
||||||
if clear_table:
|
if clear_table:
|
||||||
self.tree.delete(*self.tree.get_children())
|
self.tree.delete(*self.tree.get_children())
|
||||||
self.job_cache = self.server_proxy.get_jobs()
|
job_fetch = self.server_proxy.get_jobs()
|
||||||
all_jobs = self.job_cache
|
if job_fetch:
|
||||||
for job in all_jobs:
|
self.job_cache = job_fetch # update the cache only if its good data
|
||||||
|
for job in self.job_cache:
|
||||||
display_status = job['status'] if job['status'] != 'running' else job['percent_complete']
|
display_status = job['status'] if job['status'] != 'running' else job['percent_complete']
|
||||||
values = (job['id'], job['name'] or os.path.basename(job['input_path']), job['renderer'] + "-" + job['renderer_version'], job['priority'],
|
values = (job['id'],
|
||||||
display_status, job['time_elapsed'], job['total_frames'])
|
job['name'] or os.path.basename(job['input_path']),
|
||||||
|
job['renderer'] + "-" + job['renderer_version'],
|
||||||
|
job['priority'],
|
||||||
|
display_status,
|
||||||
|
job['time_elapsed'],
|
||||||
|
job['total_frames'])
|
||||||
if self.tree.exists(job['id']):
|
if self.tree.exists(job['id']):
|
||||||
update_row(self.tree, job['id'], new_values=values)
|
update_row(self.tree, job['id'], new_values=values)
|
||||||
else:
|
else:
|
||||||
@@ -108,7 +184,7 @@ class ZordonClient:
|
|||||||
new_window = tk.Toplevel(self.root)
|
new_window = tk.Toplevel(self.root)
|
||||||
new_window.title("New Window")
|
new_window.title("New Window")
|
||||||
new_window.geometry("500x600+300+300")
|
new_window.geometry("500x600+300+300")
|
||||||
new_window.resizable(False, False)
|
new_window.resizable(False, height=True)
|
||||||
x = NewJobWindow(parent=new_window, hostname=self.server_proxy.hostname)
|
x = NewJobWindow(parent=new_window, hostname=self.server_proxy.hostname)
|
||||||
x.pack()
|
x.pack()
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class NewJobWindow(Frame):
|
|||||||
self.renderer_info = {}
|
self.renderer_info = {}
|
||||||
self.priority = IntVar(value=2)
|
self.priority = IntVar(value=2)
|
||||||
|
|
||||||
self.master.title("Schedule Job")
|
self.master.title("New Job")
|
||||||
self.pack(fill=BOTH, expand=True)
|
self.pack(fill=BOTH, expand=True)
|
||||||
|
|
||||||
# project frame
|
# project frame
|
||||||
|
|||||||
@@ -324,7 +324,8 @@ class BaseRenderWorker(Base):
|
|||||||
'renderer_version': self.renderer_version,
|
'renderer_version': self.renderer_version,
|
||||||
'errors': getattr(self, 'errors', None),
|
'errors': getattr(self, 'errors', None),
|
||||||
'total_frames': self.total_frames,
|
'total_frames': self.total_frames,
|
||||||
'last_output': getattr(self, 'last_output', None)
|
'last_output': getattr(self, 'last_output', None),
|
||||||
|
'log_path': self.log_path()
|
||||||
}
|
}
|
||||||
|
|
||||||
# convert to json and back to auto-convert dates to iso format
|
# convert to json and back to auto-convert dates to iso format
|
||||||
|
|||||||
Reference in New Issue
Block a user