463 lines
19 KiB
Python
463 lines
19 KiB
Python
import Tkinter as tk
|
|
import sys
|
|
import tkFont
|
|
import ttk
|
|
import locale
|
|
import os
|
|
|
|
|
|
class StreamFrame(object):
|
|
def __init__(self, app, uri):
|
|
self.app = app
|
|
self.uri = uri
|
|
self.stream_hash = None
|
|
self.cancel_func = None
|
|
|
|
self.stream_frame = ttk.Frame(self.app.streams_frame, style="B.TFrame")
|
|
|
|
self.stream_frame.pack(fill=tk.X, side=tk.BOTTOM, pady=(30, 0))
|
|
|
|
self.stream_frame_header = ttk.Frame(self.stream_frame, style="C.TFrame")
|
|
self.stream_frame_header.grid(sticky=tk.E + tk.W)
|
|
|
|
self.uri_font = tkFont.Font(size=8)
|
|
self.uri_label = ttk.Label(
|
|
self.stream_frame_header, text=self.uri, font=self.uri_font, foreground="#666666"
|
|
)
|
|
self.uri_label.grid(row=0, column=0, sticky=tk.W)
|
|
|
|
if os.name == "nt":
|
|
self.button_cursor = ""
|
|
else:
|
|
self.button_cursor = "hand1"
|
|
|
|
close_file_name = "close2.gif"
|
|
if os.name == "nt":
|
|
close_file = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), close_file_name)
|
|
else:
|
|
close_file = os.path.join(os.path.dirname(__file__), close_file_name)
|
|
|
|
self.close_picture = tk.PhotoImage(
|
|
file=close_file
|
|
)
|
|
self.close_button = ttk.Button(
|
|
self.stream_frame_header, command=self.cancel, style="Stop.TButton", cursor=self.button_cursor
|
|
)
|
|
self.close_button.config(image=self.close_picture)
|
|
self.close_button.grid(row=0, column=1, sticky=tk.E + tk.N)
|
|
|
|
self.stream_frame_header.grid_columnconfigure(0, weight=1)
|
|
|
|
self.stream_frame.grid_columnconfigure(0, weight=1)
|
|
|
|
self.stream_frame_body = ttk.Frame(self.stream_frame, style="C.TFrame")
|
|
self.stream_frame_body.grid(row=1, column=0, sticky=tk.E + tk.W)
|
|
|
|
self.name_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
|
|
self.name_frame.grid(sticky=tk.W + tk.E)
|
|
self.name_frame.grid_columnconfigure(0, weight=16)
|
|
self.name_frame.grid_columnconfigure(1, weight=1)
|
|
|
|
self.stream_frame_body.grid_columnconfigure(0, weight=1)
|
|
|
|
self.metadata_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
|
|
self.metadata_frame.grid(sticky=tk.W + tk.E, row=1)
|
|
self.metadata_frame.grid_columnconfigure(0, weight=1)
|
|
|
|
self.options_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
|
|
|
|
self.outer_button_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
|
|
self.outer_button_frame.grid(sticky=tk.W + tk.E, row=4)
|
|
|
|
#show_options_picture_file_name = "show_options.gif"
|
|
#if os.name == "nt":
|
|
# show_options_picture_file = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),
|
|
# "lbrynet", "lbrynet_downloader_gui",
|
|
# show_options_picture_file_name)
|
|
#else:
|
|
# show_options_picture_file = os.path.join(os.path.dirname(__file__),
|
|
# show_options_picture_file_name)
|
|
|
|
#self.show_options_picture = tk.PhotoImage(
|
|
# file=show_options_picture_file
|
|
#)
|
|
|
|
#hide_options_picture_file_name = "hide_options.gif"
|
|
#if os.name == "nt":
|
|
# hide_options_picture_file = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),
|
|
# "lbrynet", "lbrynet_downloader_gui",
|
|
# hide_options_picture_file_name)
|
|
#else:
|
|
# hide_options_picture_file = os.path.join(os.path.dirname(__file__),
|
|
# hide_options_picture_file_name)
|
|
|
|
#self.hide_options_picture = tk.PhotoImage(
|
|
# file=hide_options_picture_file
|
|
#)
|
|
|
|
#self.show_options_button = None
|
|
|
|
self.status_label = None
|
|
#self.name_label = None
|
|
self.name_text = None
|
|
self.estimated_cost_frame = None
|
|
self.bytes_downloaded_label = None
|
|
self.button_frame = None
|
|
self.download_buttons = []
|
|
self.option_frames = []
|
|
self.name_font = None
|
|
self.description_text = None
|
|
#self.description_label = None
|
|
self.file_name_frame = None
|
|
self.cost_frame = None
|
|
self.cost_description = None
|
|
self.remaining_cost_description = None
|
|
self.cost_label = None
|
|
self.remaining_cost_label = None
|
|
self.progress_frame = None
|
|
|
|
def cancel(self):
|
|
if self.cancel_func is not None:
|
|
self.cancel_func() # pylint: disable=not-callable
|
|
self.stream_frame.destroy()
|
|
self.app.stream_removed()
|
|
|
|
def _resize_text(self, text_widget):
|
|
actual_height = text_widget.tk.call(text_widget._w, "count", "-displaylines", "0.0", "end")
|
|
text_widget.config(height=int(actual_height))
|
|
|
|
def show_name(self, name):
|
|
self.name_font = tkFont.Font(size=16)
|
|
#self.name_label = ttk.Label(
|
|
# self.name_frame, text=name, font=self.name_font
|
|
#)
|
|
#self.name_label.grid(row=0, column=0, sticky=tk.W)
|
|
self.name_text = tk.Text(
|
|
self.name_frame, font=self.name_font, wrap=tk.WORD, relief=tk.FLAT, borderwidth=0,
|
|
highlightthickness=0, width=1, height=1
|
|
)
|
|
self.name_text.insert(tk.INSERT, name)
|
|
self.name_text.config(state=tk.DISABLED)
|
|
self.name_text.grid(row=0, column=0, sticky=tk.W+tk.E+tk.N+tk.S)
|
|
self.name_text.update()
|
|
self._resize_text(self.name_text)
|
|
|
|
def show_description(self, description):
|
|
#if os.name == "nt":
|
|
# wraplength = 580
|
|
#else:
|
|
# wraplength = 600
|
|
#self.description_label = ttk.Label(
|
|
# self.name_frame, text=description, wraplength=wraplength
|
|
#)
|
|
#self.description_label.grid(row=1, column=0, sticky=tk.W)
|
|
self.description_text = tk.Text(
|
|
self.name_frame, wrap=tk.WORD, relief=tk.FLAT, borderwidth=0,
|
|
highlightthickness=0, width=1, height=1
|
|
)
|
|
self.description_text.insert(tk.INSERT, description)
|
|
self.description_text.config(state=tk.DISABLED)
|
|
self.description_text.grid(row=1, column=0, sticky=tk.W+tk.E+tk.N+tk.S)
|
|
self.description_text.update()
|
|
self._resize_text(self.description_text)
|
|
|
|
def show_thumbnail(self, url=None):
|
|
thumbnail = None
|
|
if url is not None:
|
|
import urllib2
|
|
import base64
|
|
response = urllib2.urlopen(url)
|
|
thumbnail_data = base64.b64encode(response.read())
|
|
thumbnail = tk.PhotoImage(data=thumbnail_data)
|
|
current_width = thumbnail.width()
|
|
current_height = thumbnail.height()
|
|
max_width = 130
|
|
max_height = 90
|
|
scale_ratio = max(1.0 * current_width / max_width, 1.0 * current_height / max_height)
|
|
if scale_ratio < 1:
|
|
scale_ratio = 1
|
|
else:
|
|
scale_ratio = int(scale_ratio + 1)
|
|
thumbnail = thumbnail.subsample(scale_ratio)
|
|
if thumbnail is not None:
|
|
label = ttk.Label(self.name_frame, image=thumbnail)
|
|
label.safekeeping = thumbnail
|
|
label.grid(row=0, column=1, rowspan=2, sticky=tk.E+tk.N+tk.W+tk.S)
|
|
label.update()
|
|
self.description_text.update()
|
|
self.name_text.update()
|
|
self._resize_text(self.description_text)
|
|
self._resize_text(self.name_text)
|
|
|
|
def show_metadata_status(self, value):
|
|
if self.status_label is None:
|
|
self.status_label = ttk.Label(
|
|
self.metadata_frame, text=value
|
|
)
|
|
self.status_label.grid()
|
|
self.metadata_frame.grid_columnconfigure(0, weight=1)
|
|
else:
|
|
self.status_label.config(text=value)
|
|
|
|
@staticmethod
|
|
def get_formatted_stream_size(stream_size):
|
|
if isinstance(stream_size, (int, long)):
|
|
if stream_size >= 2**40:
|
|
units = "TB"
|
|
factor = 2**40
|
|
elif stream_size >= 2**30:
|
|
units = "GB"
|
|
factor = 2**30
|
|
elif stream_size >= 2**20:
|
|
units = "MB"
|
|
factor = 2**20
|
|
elif stream_size >= 2**10:
|
|
units = "KB"
|
|
factor = 2**10
|
|
else:
|
|
return str(stream_size) + " B"
|
|
return "%.1f %s" % (round((stream_size * 1.0 / factor), 1), units)
|
|
return stream_size
|
|
|
|
def show_stream_metadata(self, stream_name, stream_size, stream_cost):
|
|
if self.status_label is not None:
|
|
self.status_label.destroy()
|
|
|
|
self.file_name_frame = ttk.Frame(self.metadata_frame, style="F.TFrame")
|
|
self.file_name_frame.grid(row=0, column=0, sticky=tk.W)
|
|
self.metadata_frame.grid_columnconfigure(0, weight=1, uniform="metadata")
|
|
|
|
file_size_label = ttk.Label(
|
|
self.file_name_frame,
|
|
text=self.get_formatted_stream_size(stream_size)
|
|
)
|
|
file_size_label.grid(row=0, column=2)
|
|
|
|
file_name_label = ttk.Label(
|
|
self.file_name_frame,
|
|
text=" - " + stream_name,
|
|
)
|
|
file_name_label.grid(row=0, column=3)
|
|
|
|
self.estimated_cost_frame = ttk.Frame(self.metadata_frame, style="F.TFrame")
|
|
self.estimated_cost_frame.grid(row=1, column=0, sticky=tk.W)
|
|
|
|
estimated_cost_label = ttk.Label(
|
|
self.estimated_cost_frame,
|
|
text=locale.format_string("%.2f LBC",
|
|
(round(stream_cost, 2)), grouping=True),
|
|
foreground="red"
|
|
)
|
|
estimated_cost_label.grid(row=1, column=2)
|
|
|
|
self.button_frame = ttk.Frame(self.outer_button_frame, style="E.TFrame")
|
|
self.button_frame.grid(row=0, column=1)
|
|
|
|
self.outer_button_frame.grid_columnconfigure(0, weight=1, uniform="buttons")
|
|
self.outer_button_frame.grid_columnconfigure(1, weight=2, uniform="buttons1")
|
|
self.outer_button_frame.grid_columnconfigure(2, weight=1, uniform="buttons")
|
|
|
|
def add_download_factory(self, factory, download_func):
|
|
download_button = ttk.Button(
|
|
self.button_frame, text=factory.get_description(), command=download_func,
|
|
style='LBRY.TButton', cursor=self.button_cursor
|
|
)
|
|
self.download_buttons.append(download_button)
|
|
download_button.grid(row=0, column=len(self.download_buttons) - 1, padx=5, pady=(1, 2))
|
|
|
|
def disable_download_buttons(self):
|
|
for download_button in self.download_buttons:
|
|
download_button.config(state=tk.DISABLED)
|
|
|
|
def remove_download_buttons(self):
|
|
for download_button in self.download_buttons:
|
|
download_button.destroy()
|
|
self.download_buttons = []
|
|
|
|
def get_option_widget(self, option_type, option_frame):
|
|
if option_type.value == float:
|
|
entry_frame = ttk.Frame(
|
|
option_frame,
|
|
style="H.TFrame"
|
|
)
|
|
entry_frame.grid()
|
|
col = 0
|
|
if option_type.short_description is not None:
|
|
entry_label = ttk.Label(
|
|
entry_frame,
|
|
#text=option_type.short_description
|
|
text=""
|
|
)
|
|
entry_label.grid(row=0, column=0, sticky=tk.W)
|
|
col = 1
|
|
entry = ttk.Entry(
|
|
entry_frame,
|
|
width=10,
|
|
style="Float.TEntry"
|
|
)
|
|
entry_frame.entry = entry
|
|
entry.grid(row=0, column=col, sticky=tk.W)
|
|
return entry_frame
|
|
if option_type.value == bool:
|
|
bool_frame = ttk.Frame(
|
|
option_frame,
|
|
style="H.TFrame"
|
|
)
|
|
bool_frame.chosen_value = tk.BooleanVar()
|
|
true_text = "True"
|
|
false_text = "False"
|
|
if option_type.bool_options_description is not None:
|
|
true_text, false_text = option_type.bool_options_description
|
|
true_radio_button = ttk.Radiobutton(
|
|
bool_frame, text=true_text, variable=bool_frame.chosen_value, value=True
|
|
)
|
|
true_radio_button.grid(row=0, sticky=tk.W)
|
|
false_radio_button = ttk.Radiobutton(
|
|
bool_frame, text=false_text, variable=bool_frame.chosen_value, value=False
|
|
)
|
|
false_radio_button.grid(row=1, sticky=tk.W)
|
|
return bool_frame
|
|
label = ttk.Label(
|
|
option_frame,
|
|
text=""
|
|
)
|
|
return label
|
|
|
|
def show_download_options(self, options):
|
|
left_padding = 20
|
|
for option in options:
|
|
f = ttk.Frame(
|
|
self.options_frame,
|
|
style="E.TFrame"
|
|
)
|
|
f.grid(sticky=tk.W + tk.E, padx=left_padding)
|
|
self.option_frames.append((option, f))
|
|
description_label = ttk.Label(
|
|
f,
|
|
text=option.long_description
|
|
)
|
|
description_label.grid(row=0, sticky=tk.W)
|
|
if len(option.option_types) > 1:
|
|
f.chosen_type = tk.IntVar()
|
|
choices_frame = ttk.Frame(
|
|
f,
|
|
style="F.TFrame"
|
|
)
|
|
f.choices_frame = choices_frame
|
|
choices_frame.grid(row=1, sticky=tk.W, padx=left_padding)
|
|
choices_frame.choices = []
|
|
for i, option_type in enumerate(option.option_types):
|
|
choice_frame = ttk.Frame(
|
|
choices_frame,
|
|
style="G.TFrame"
|
|
)
|
|
choice_frame.grid(sticky=tk.W)
|
|
option_text = ""
|
|
if option_type.short_description is not None:
|
|
option_text = option_type.short_description
|
|
option_radio_button = ttk.Radiobutton(
|
|
choice_frame, text=option_text, variable=f.chosen_type, value=i
|
|
)
|
|
option_radio_button.grid(row=0, column=0, sticky=tk.W)
|
|
option_widget = self.get_option_widget(option_type, choice_frame)
|
|
option_widget.grid(row=0, column=1, sticky=tk.W)
|
|
choices_frame.choices.append(option_widget)
|
|
if i == 0:
|
|
option_radio_button.invoke()
|
|
else:
|
|
choice_frame = ttk.Frame(
|
|
f,
|
|
style="F.TFrame"
|
|
)
|
|
choice_frame.grid(sticky=tk.W, padx=left_padding)
|
|
option_widget = self.get_option_widget(option.option_types[0], choice_frame)
|
|
option_widget.grid(row=0, column=0, sticky=tk.W)
|
|
f.option_widget = option_widget
|
|
#self.show_options_button = ttk.Button(
|
|
# self.stream_frame_body, command=self._toggle_show_options, style="Stop.TButton",
|
|
# cursor=self.button_cursor
|
|
#)
|
|
#self.show_options_button.config(image=self.show_options_picture)
|
|
#self.show_options_button.grid(sticky=tk.W, row=2, column=0)
|
|
|
|
def _get_chosen_option(self, option_type, option_widget):
|
|
if option_type.value == float:
|
|
return float(option_widget.entry.get())
|
|
if option_type.value == bool:
|
|
return option_widget.chosen_value.get()
|
|
return option_type.value
|
|
|
|
def get_chosen_options(self):
|
|
chosen_options = []
|
|
for o, f in self.option_frames:
|
|
if len(o.option_types) > 1:
|
|
chosen_index = f.chosen_type.get()
|
|
option_type = o.option_types[chosen_index]
|
|
option_widget = f.choices_frame.choices[chosen_index]
|
|
chosen_options.append(self._get_chosen_option(option_type, option_widget))
|
|
else:
|
|
option_type = o.option_types[0]
|
|
option_widget = f.option_widget
|
|
chosen_options.append(self._get_chosen_option(option_type, option_widget))
|
|
return chosen_options
|
|
|
|
#def _toggle_show_options(self):
|
|
# if self.options_frame.winfo_ismapped():
|
|
# self.show_options_button.config(image=self.show_options_picture)
|
|
# self.options_frame.grid_forget()
|
|
# else:
|
|
# self.show_options_button.config(image=self.hide_options_picture)
|
|
# self.options_frame.grid(sticky=tk.W + tk.E, row=3)
|
|
|
|
def show_progress(self, total_bytes, bytes_left_to_download, points_paid,
|
|
points_remaining):
|
|
if self.bytes_downloaded_label is None:
|
|
self.remove_download_buttons()
|
|
self.button_frame.destroy()
|
|
self.estimated_cost_frame.destroy()
|
|
for option, frame in self.option_frames:
|
|
frame.destroy()
|
|
self.options_frame.destroy()
|
|
#self.show_options_button.destroy()
|
|
|
|
self.progress_frame = ttk.Frame(self.outer_button_frame, style="F.TFrame")
|
|
self.progress_frame.grid(row=0, column=0, sticky=tk.W, pady=(0, 8))
|
|
|
|
self.bytes_downloaded_label = ttk.Label(
|
|
self.progress_frame,
|
|
text=""
|
|
)
|
|
self.bytes_downloaded_label.grid(row=0, column=0)
|
|
|
|
self.cost_frame = ttk.Frame(self.outer_button_frame, style="F.TFrame")
|
|
self.cost_frame.grid(row=1, column=0, sticky=tk.W, pady=(0, 4))
|
|
|
|
self.cost_label = ttk.Label(
|
|
self.cost_frame,
|
|
text="",
|
|
foreground="red"
|
|
)
|
|
self.cost_label.grid(row=0, column=1, padx=(1, 0))
|
|
self.outer_button_frame.grid_columnconfigure(2, weight=0, uniform="")
|
|
|
|
if self.bytes_downloaded_label.winfo_exists():
|
|
percent_done = 0
|
|
if total_bytes > 0:
|
|
percent_done = 100.0 * (total_bytes - bytes_left_to_download) / total_bytes
|
|
percent_done_string = locale.format_string(" (%.2f%%)", percent_done)
|
|
self.bytes_downloaded_label.config(
|
|
text=self.get_formatted_stream_size(total_bytes - bytes_left_to_download) + percent_done_string
|
|
)
|
|
if self.cost_label.winfo_exists():
|
|
total_points = points_remaining + points_paid
|
|
self.cost_label.config(text=locale.format_string("%.2f/%.2f LBC",
|
|
(round(points_paid, 2), round(total_points, 2)),
|
|
grouping=True))
|
|
|
|
def show_download_done(self, total_points_paid):
|
|
if self.bytes_downloaded_label is not None and self.bytes_downloaded_label.winfo_exists():
|
|
self.bytes_downloaded_label.destroy()
|
|
if self.cost_label is not None and self.cost_label.winfo_exists():
|
|
self.cost_label.config(text=locale.format_string("%.2f LBC",
|
|
(round(total_points_paid, 2),),
|
|
grouping=True))
|