This commit is contained in:
faroukbmiled 2023-09-04 15:39:55 +01:00
parent 8eb8690493
commit f62ad9aae9
8 changed files with 348 additions and 93 deletions

11
CTkToolTip/__init__.py Normal file
View File

@ -0,0 +1,11 @@
"""
CustomTkinter ToolTip
Author: Akash Bora
This is a tooltip/pop-up widget made with customtkinter.
Homepage: https://github.com/Akascape/CTkToolTip
"""
__version__ = '0.8'
from .ctk_tooltip import CTkToolTip

Binary file not shown.

Binary file not shown.

227
CTkToolTip/ctk_tooltip.py Normal file
View File

@ -0,0 +1,227 @@
"""
CTkToolTip Widget
version: 0.8
"""
import time
import sys
import customtkinter
import threading
from tkinter import Toplevel, Frame
class CTkToolTip(Toplevel):
"""
Creates a ToolTip (pop-up) widget for customtkinter.
"""
def __init__(
self,
widget: any = None,
message: str = None,
delay: float = 0.2,
follow: bool = True,
x_offset: int = +20,
y_offset: int = +10,
bg_color: str = None,
corner_radius: int = 10,
border_width: int = 0,
border_color: str = None,
alpha: float = 0.95,
padding: tuple = (10, 2),
is_noti: bool = False,
noti_event: any = None,
noti_dur: float = 3.0,
**message_kwargs):
super().__init__()
self.widget = widget
if not is_noti:
self.withdraw()
# Disable ToolTip's title bar
self.overrideredirect(True)
if sys.platform.startswith("win"):
self.transparent_color = self.widget._apply_appearance_mode(
customtkinter.ThemeManager.theme["CTkToplevel"]["fg_color"])
self.attributes("-transparentcolor", self.transparent_color)
self.transient()
elif sys.platform.startswith("darwin"):
self.transparent_color = 'systemTransparent'
self.attributes("-transparent", True)
self.transient(self.master)
else:
self.transparent_color = '#000001'
corner_radius = 0
self.transient()
self.resizable(width=True, height=True)
# Make the background transparent
self.config(background=self.transparent_color)
# StringVar instance for msg string
self.messageVar = customtkinter.StringVar()
self.message = message
self.messageVar.set(self.message)
self.noti_dur = noti_dur
self.is_noti = is_noti
self.delay = delay
self.follow = follow
self.x_offset = x_offset
self.y_offset = y_offset
self.corner_radius = corner_radius
self.alpha = alpha
self.border_width = border_width
self.padding = padding
self.bg_color = customtkinter.ThemeManager.theme["CTkFrame"]["fg_color"] if bg_color is None else bg_color
self.border_color = border_color
self.disable = False
# visibility status of the ToolTip inside|outside|visible
self.status = "outside"
self.last_moved = 0
self.attributes('-alpha', self.alpha)
if sys.platform.startswith("win"):
if self.widget._apply_appearance_mode(self.bg_color) == self.transparent_color:
self.transparent_color = "#000001"
self.config(background=self.transparent_color)
self.attributes("-transparentcolor", self.transparent_color)
# Add the message widget inside the tooltip
self.transparent_frame = Frame(self, bg=self.transparent_color)
self.transparent_frame.pack(padx=0, pady=0, fill="both", expand=True)
self.frame = customtkinter.CTkFrame(self.transparent_frame, bg_color=self.transparent_color,
corner_radius=self.corner_radius,
border_width=self.border_width, fg_color=self.bg_color,
border_color=self.border_color)
self.frame.pack(padx=0, pady=0, fill="both", expand=True)
self.message_label = customtkinter.CTkLabel(self.frame, textvariable=self.messageVar, **message_kwargs)
self.message_label.pack(fill="both", padx=self.padding[0] + self.border_width,
pady=self.padding[1] + self.border_width, expand=True)
if self.widget.winfo_name() != "tk":
if self.frame.cget("fg_color") == self.widget.cget("bg_color"):
if not bg_color:
self._top_fg_color = self.frame._apply_appearance_mode(
customtkinter.ThemeManager.theme["CTkFrame"]["top_fg_color"])
if self._top_fg_color != self.transparent_color:
self.frame.configure(fg_color=self._top_fg_color)
# Add bindings to the widget without overriding the existing ones
if self.is_noti:
if noti_event:
self.on_enter(noti_event)
else:
self.widget.bind("<Button-1>", self.on_enter, add="+")
else:
self.widget.bind("<Enter>", self.on_enter, add="+")
self.widget.bind("<Leave>", self.on_leave, add="+")
self.widget.bind("<Motion>", self.on_enter, add="+")
self.widget.bind("<B1-Motion>", self.on_enter, add="+")
self.widget.bind("<Destroy>", lambda _: self.hide(), add="+")
def show(self) -> None:
"""
Enable the widget.
"""
self.disable = False
def on_enter(self, event) -> None:
"""
Processes motion within the widget including entering and moving.
"""
if self.disable:
return
self.last_moved = time.time()
# Set the status as inside for the very first time
if self.status == "outside":
self.status = "inside"
# If the follow flag is not set, motion within the widget will make the ToolTip dissapear
if not self.follow:
self.status = "inside"
self.withdraw()
# Calculate available space on the right side of the widget relative to the screen
root_width = self.winfo_screenwidth()
widget_x = event.x_root
space_on_right = root_width - widget_x
# Calculate the width of the tooltip's text based on the length of the message string
text_width = self.message_label.winfo_reqwidth()
# Calculate the offset based on available space and text width to avoid going off-screen on the right side
offset_x = self.x_offset
if space_on_right < text_width + 20: # Adjust the threshold as needed
offset_x = -text_width - 20 # Negative offset when space is limited on the right side
# Offsets the ToolTip using the coordinates od an event as an origin
self.geometry(f"+{event.x_root + offset_x}+{event.y_root + self.y_offset}")
# Time is in integer: milliseconds
self.after(int(self.delay * 1000), self._show)
if self.is_noti:
threading.Timer(self.noti_dur, self.destroy).start()
def on_leave(self, event=None) -> None:
"""
Hides the ToolTip temporarily.
"""
if self.disable: return
self.status = "outside"
self.withdraw()
def _show(self) -> None:
"""
Displays the ToolTip.
"""
if not self.widget.winfo_exists():
self.hide()
self.destroy()
if self.status == "inside" and time.time() - self.last_moved >= self.delay:
self.status = "visible"
self.deiconify()
def hide(self) -> None:
"""
Disable the widget from appearing.
"""
if not self.winfo_exists():
return
self.withdraw()
self.disable = True
def is_disabled(self) -> None:
"""
Return the window state
"""
return self.disable
def get(self) -> None:
"""
Returns the text on the tooltip.
"""
return self.messageVar.get()
def configure(self, message: str = None, delay: float = None, bg_color: str = None, **kwargs):
"""
Set new message or configure the label parameters.
"""
if delay: self.delay = delay
if bg_color: self.frame.configure(fg_color=bg_color)
self.messageVar.set(message)
self.message_label.configure(**kwargs)

View File

@ -549,9 +549,10 @@ class LibraryTab(ctk.CTkScrollableFrame):
except:
pass
def open_folder_location(self,folder, event=None):
def open_folder_location(self, folder, event=None):
if os.path.exists(folder):
os.startfile(folder)
show_noti(self, "Opening folder", event, 1.0)
def filter_items(self, event):
filter_text = self.filter_entry.get().lower()
@ -1218,7 +1219,7 @@ class BOIIIWD(ctk.CTk):
self.queuetextarea = ctk.CTkTextbox(master=self.qeueuframe, font=("", 15))
self.queuetextarea.grid(row=1, column=0, columnspan=4, padx=(20, 20), pady=(0, 20), sticky="nwse")
self.status_text = ctk.CTkLabel(self.qeueuframe, text="Status: Not Downloading")
self.status_text = ctk.CTkLabel(self.qeueuframe, text="Status: Standby!")
self.status_text.grid(row=3, column=0, padx=(20, 20), pady=(0, 20), sticky="ws")
self.skip_boutton = ctk.CTkButton(master=self.qeueuframe, text="Skip", command=self.skip_current_queue_item, width=10, height=10, fg_color="#585858")
@ -1246,14 +1247,14 @@ class BOIIIWD(ctk.CTk):
self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10))
self.txt_label = ctk.CTkLabel(self.sidebar_frame, text="- Sidebar -", font=(font, 17))
self.txt_label.grid(row=1, column=0, padx=20, pady=(20, 10))
self.sidebar_main = ctk.CTkButton(self.sidebar_frame)
self.sidebar_main.grid(row=2, column=0, padx=20, pady=10)
self.sidebar_queue = ctk.CTkButton(self.sidebar_frame)
self.sidebar_queue.grid(row=3, column=0, padx=20, pady=10)
self.sidebar_library = ctk.CTkButton(self.sidebar_frame)
self.sidebar_library.grid(row=4, column=0, padx=20, pady=10, sticky="n")
self.sidebar_settings = ctk.CTkButton(self.sidebar_frame)
self.sidebar_settings.grid(row=5, column=0, padx=20, pady=10, sticky="n")
self.sidebar_main = ctk.CTkButton(self.sidebar_frame, height=28)
self.sidebar_main.grid(row=2, column=0, padx=10, pady=(20, 6))
self.sidebar_queue = ctk.CTkButton(self.sidebar_frame, height=28)
self.sidebar_queue.grid(row=3, column=0, padx=10, pady=6)
self.sidebar_library = ctk.CTkButton(self.sidebar_frame, height=28)
self.sidebar_library.grid(row=4, column=0, padx=10, pady=6, sticky="n")
self.sidebar_settings = ctk.CTkButton(self.sidebar_frame, height=28)
self.sidebar_settings.grid(row=5, column=0, padx=10, pady=6, sticky="n")
# create optionsframe
self.optionsframe = ctk.CTkFrame(self)
@ -1276,12 +1277,10 @@ class BOIIIWD(ctk.CTk):
# self.spacer = ctk.CTkLabel(master=self.slider_progressbar_frame, text="")
# self.spacer.grid(row=0, column=0, columnspan=1)
self.label_speed = ctk.CTkLabel(master=self.slider_progressbar_frame, text="Network Speed: 0 KB/s")
self.label_speed = ctk.CTkLabel(master=self.slider_progressbar_frame, text="Awaiting Download!")
self.label_speed.grid(row=1, column=0, padx=20, pady=(0, 10), sticky="w")
self.elapsed_time = ctk.CTkLabel(master=self.slider_progressbar_frame, text="")
self.elapsed_time.grid(row=1, column=1, padx=20, pady=(0, 10), sticky="nsew", columnspan=1)
self.elapsed_time = ctk.CTkLabel(master=self.slider_progressbar_frame, text="", anchor="center")
self.elapsed_time.grid(row=1, column=1, padx=20, pady=(0, 10), sticky="nsew") # Use "nsew" to center label
self.label_file_size = ctk.CTkLabel(master=self.slider_progressbar_frame, text="File size: 0KB")
self.label_file_size.grid(row=1, column=2, padx=(0, 20), pady=(0, 10), sticky="e")
@ -1915,7 +1914,7 @@ class BOIIIWD(ctk.CTk):
def skip_current_queue_item(self):
if self.button_download._state == "normal":
self.skip_boutton.grid_remove()
self.after(1, self.status_text.configure(text=f"Status: Not Downloading"))
self.after(1, self.status_text.configure(text=f"Status: Standby!"))
return
self.settings_tab.stopped = True
self.item_skipped = True
@ -1958,7 +1957,7 @@ class BOIIIWD(ctk.CTk):
self.settings_tab.stopped = True
self.queue_stop_button = True
show_message("Error", f"Couldn't remove {map_folder}, please do so manually\n{e}", icon="cancel")
self.stop_download
self.stop_download()
return
if self.settings_tab.continuous:
@ -2074,6 +2073,7 @@ class BOIIIWD(ctk.CTk):
self.is_downloading = False
self.fail_threshold = 0
if not self.is_pressed:
self.after(1, self.label_speed.configure(text=f"Loading..."))
self.is_pressed = True
self.library_tab.load_items(self.edit_destination_folder.get())
if self.queue_enabled:
@ -2112,19 +2112,19 @@ class BOIIIWD(ctk.CTk):
if not items:
show_message("Warning", "Please enter valid Workshop IDs/Links.", icon="warning")
self.stop_download
self.stop_download()
return
destination_folder = self.edit_destination_folder.get().strip()
if not destination_folder or not os.path.exists(destination_folder):
show_message("Error", "Please select a valid destination folder => in the main tab!.")
self.stop_download
self.stop_download()
return
if not steamcmd_path or not os.path.exists(steamcmd_path):
show_message("Error", "Please enter a valid SteamCMD path => in the main tab!.")
self.stop_download
self.stop_download()
return
self.total_queue_size = 0
@ -2139,15 +2139,15 @@ class BOIIIWD(ctk.CTk):
workshop_id = extract_workshop_id(workshop_id).strip()
else:
show_message("Warning", "Please enter valid Workshop IDs/Links.", icon="warning")
self.stop_download
self.stop_download()
return
except:
show_message("Warning", "Please enter valid Workshop IDs/Links.", icon="warning")
self.stop_download
self.stop_download()
return
if not valid_id(workshop_id):
show_message("Warning", "Please enter valid Workshop IDs/Links.", icon="warning")
self.stop_download
self.stop_download()
return
ws_file_size = get_workshop_file_size(workshop_id)
@ -2156,7 +2156,7 @@ class BOIIIWD(ctk.CTk):
if file_size is None:
show_message("Error", "Failed to retrieve file size.", icon="cancel")
self.stop_download
self.stop_download()
return
if any(workshop_id in item for item in self.library_tab.added_items):
@ -2170,7 +2170,7 @@ class BOIIIWD(ctk.CTk):
items.remove(item)
show_message("Heads up!, map/s skipped => skip is on in settings", f"These item IDs may already be installed and are skipped:\n{item_ids}", icon="info")
if not any(isinstance(item, int) for item in items):
self.stop_download
self.stop_download()
return
else:
show_message("Heads up! map/s not skipped => skip is off in settings", f"These item IDs may already be installed:\n{item_ids}", icon="info")
@ -2182,7 +2182,7 @@ class BOIIIWD(ctk.CTk):
current_number = index + 1
total_items = len(items)
if self.queue_stop_button:
self.stop_download
self.stop_download()
break
item.strip()
self.settings_tab.stopped = False
@ -2193,11 +2193,11 @@ class BOIIIWD(ctk.CTk):
workshop_id = extract_workshop_id(workshop_id).strip()
else:
show_message("Warning", "Please enter valid Workshop IDs/Links.", icon="warning")
self.stop_download
self.stop_download()
return
except:
show_message("Warning", "Please enter valid Workshop IDs/Links.", icon="warning")
self.stop_download
self.stop_download()
return
ws_file_size = get_workshop_file_size(workshop_id)
file_size = ws_file_size
@ -2341,7 +2341,6 @@ class BOIIIWD(ctk.CTk):
update_ui_thread.start()
update_ui_thread.join()
self.label_speed.configure(text="Network Speed: 0 KB/s")
self.progress_text.configure(text="0%")
self.progress_bar.set(0.0)
@ -2350,6 +2349,7 @@ class BOIIIWD(ctk.CTk):
json_file_path = os.path.join(map_folder, "workshop.json")
if os.path.exists(json_file_path):
self.label_speed.configure(text="Installing...")
mod_type = extract_json_data(json_file_path, "Type")
folder_name = extract_json_data(json_file_path, "FolderName")
@ -2377,6 +2377,12 @@ class BOIIIWD(ctk.CTk):
if index == len(items) - 1:
self.after(1, self.status_text.configure(text=f"Status: Done! => Please press stop only if you see no popup window (rare bug)"))
self.show_complete_message(message=f"All files were downloaded\nYou can run the game now!\nPS: You have to restart the game \n(pressing launch will launch/restarts)")
self.label_speed.configure(text="Awaiting Download!")
elif os.path.exists(json_file_path) and not self.settings_tab.stopped:
show_message("Error", "Failed to find workshop.json, please try again.", icon="cancel")
if index == len(items) - 1:
self.stop_download()
return
self.button_download.configure(state="disabled")
self.button_stop.configure(state="normal")
@ -2392,15 +2398,14 @@ class BOIIIWD(ctk.CTk):
self.skip_boutton.grid_remove()
self.after(1, self.label_file_size.configure(text=f"File size: 0KB"))
self.settings_tab.stopped = True
self.stop_download
self.stop_download()
return
finally:
self.settings_tab.steam_fail_counter = 0
self.after(1, self.label_file_size.configure(text=f"File size: 0KB"))
self.stop_download
self.stop_download()
self.is_pressed = False
def download_thread(self):
try:
self.settings_tab.stopped = False
@ -2424,12 +2429,12 @@ class BOIIIWD(ctk.CTk):
if not destination_folder or not os.path.exists(destination_folder):
show_message("Error", "Please select a valid destination folder.")
self.stop_download
self.stop_download()
return
if not steamcmd_path or not os.path.exists(steamcmd_path):
show_message("Error", "Please enter a valid SteamCMD path.")
self.stop_download
self.stop_download()
return
if not workshop_id.isdigit():
@ -2438,11 +2443,11 @@ class BOIIIWD(ctk.CTk):
workshop_id = extract_workshop_id(workshop_id).strip()
else:
show_message("Warning", "Please enter a valid Workshop ID/Link.", icon="warning")
self.stop_download
self.stop_download()
return
except:
show_message("Warning", "Please enter a valid Workshop ID/Link.", icon="warning")
self.stop_download
self.stop_download()
return
ws_file_size = get_workshop_file_size(workshop_id)
@ -2450,18 +2455,18 @@ class BOIIIWD(ctk.CTk):
if not valid_id(workshop_id):
show_message("Warning", "Please enter a valid Workshop ID/Link.", icon="warning")
self.stop_download
self.stop_download()
return
if file_size is None:
show_message("Error", "Failed to retrieve file size.", icon="cancel")
self.stop_download
self.stop_download()
return
if any(workshop_id in item for item in self.library_tab.added_items):
if self.settings_tab.skip_already_installed:
show_message("Heads up!, map skipped => Skip is on in settings", f"This item may already be installed, Stopping: {workshop_id}", icon="info")
self.stop_download
self.stop_download()
return
show_message("Heads up! map not skipped => Skip is off in settings", f"This item may already be installed: {workshop_id}", icon="info")
@ -2578,8 +2583,6 @@ class BOIIIWD(ctk.CTk):
update_ui_thread.join()
self.settings_tab.stopped = True
self.label_speed.configure(text="Network Speed: 0 KB/s")
self.progress_text.configure(text="0%")
self.progress_bar.set(0.0)
@ -2588,6 +2591,7 @@ class BOIIIWD(ctk.CTk):
json_file_path = os.path.join(map_folder, "workshop.json")
if os.path.exists(json_file_path):
self.label_speed.configure(text="Installing...")
mod_type = extract_json_data(json_file_path, "Type")
folder_name = extract_json_data(json_file_path, "FolderName")
@ -2599,7 +2603,7 @@ class BOIIIWD(ctk.CTk):
folder_name_path = os.path.join(usermaps_folder, folder_name, "zone")
else:
show_message("Error", "Invalid workshop type in workshop.json, are you sure this is a map or a mod?.", icon="cancel")
self.stop_download
self.stop_download()
return
os.makedirs(folder_name_path, exist_ok=True)
@ -2616,16 +2620,21 @@ class BOIIIWD(ctk.CTk):
self.show_complete_message(message=f"{mod_type.capitalize()} files were downloaded\nYou can run the game now!\nPS: You have to restart the game \n(pressing launch will launch/restarts)")
self.button_download.configure(state="normal")
self.button_stop.configure(state="disabled")
elif os.path.exists(json_file_path) and not self.settings_tab.stopped:
show_message("Error", "Failed to find workshop.json, please try again.", icon="cancel")
self.stop_download()
return
update_wait_thread = threading.Thread(target=wait_for_threads)
update_wait_thread.start()
self.button_download.configure(state="disabled")
self.button_stop.configure(state="normal")
steamcmd_thread.join()
update_wait_thread.join()
finally:
self.settings_tab.steam_fail_counter = 0
self.stop_download
self.stop_download()
self.is_pressed = False
def copy_with_progress(self, src, dst):
@ -2668,11 +2677,11 @@ class BOIIIWD(ctk.CTk):
self.button_download.configure(state="normal")
self.button_stop.configure(state="disabled")
self.label_speed.configure(text="Network Speed: 0 KB/s")
self.progress_text.configure(text="0%")
self.elapsed_time.configure(text=f"")
self.progress_bar.set(0.0)
self.after(50, self.status_text.configure(text=f"Status: Not Downloading"))
self.after(50, self.status_text.configure(text=f"Status: Standby!"))
self.after(1, self.label_speed.configure(text=f"Awaiting Download!"))
self.skip_boutton.grid_remove()
if __name__ == "__main__":

View File

@ -70,9 +70,10 @@ class LibraryTab(ctk.CTkScrollableFrame):
except:
pass
def open_folder_location(self,folder, event=None):
def open_folder_location(self, folder, event=None):
if os.path.exists(folder):
os.startfile(folder)
show_noti(self, "Opening folder", event, 1.0)
def filter_items(self, event):
filter_text = self.filter_entry.get().lower()

View File

@ -89,7 +89,7 @@ class BOIIIWD(ctk.CTk):
self.queuetextarea = ctk.CTkTextbox(master=self.qeueuframe, font=("", 15))
self.queuetextarea.grid(row=1, column=0, columnspan=4, padx=(20, 20), pady=(0, 20), sticky="nwse")
self.status_text = ctk.CTkLabel(self.qeueuframe, text="Status: Not Downloading")
self.status_text = ctk.CTkLabel(self.qeueuframe, text="Status: Standby!")
self.status_text.grid(row=3, column=0, padx=(20, 20), pady=(0, 20), sticky="ws")
self.skip_boutton = ctk.CTkButton(master=self.qeueuframe, text="Skip", command=self.skip_current_queue_item, width=10, height=10, fg_color="#585858")
@ -117,14 +117,14 @@ class BOIIIWD(ctk.CTk):
self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10))
self.txt_label = ctk.CTkLabel(self.sidebar_frame, text="- Sidebar -", font=(font, 17))
self.txt_label.grid(row=1, column=0, padx=20, pady=(20, 10))
self.sidebar_main = ctk.CTkButton(self.sidebar_frame)
self.sidebar_main.grid(row=2, column=0, padx=20, pady=10)
self.sidebar_queue = ctk.CTkButton(self.sidebar_frame)
self.sidebar_queue.grid(row=3, column=0, padx=20, pady=10)
self.sidebar_library = ctk.CTkButton(self.sidebar_frame)
self.sidebar_library.grid(row=4, column=0, padx=20, pady=10, sticky="n")
self.sidebar_settings = ctk.CTkButton(self.sidebar_frame)
self.sidebar_settings.grid(row=5, column=0, padx=20, pady=10, sticky="n")
self.sidebar_main = ctk.CTkButton(self.sidebar_frame, height=28)
self.sidebar_main.grid(row=2, column=0, padx=10, pady=(20, 6))
self.sidebar_queue = ctk.CTkButton(self.sidebar_frame, height=28)
self.sidebar_queue.grid(row=3, column=0, padx=10, pady=6)
self.sidebar_library = ctk.CTkButton(self.sidebar_frame, height=28)
self.sidebar_library.grid(row=4, column=0, padx=10, pady=6, sticky="n")
self.sidebar_settings = ctk.CTkButton(self.sidebar_frame, height=28)
self.sidebar_settings.grid(row=5, column=0, padx=10, pady=6, sticky="n")
# create optionsframe
self.optionsframe = ctk.CTkFrame(self)
@ -147,12 +147,10 @@ class BOIIIWD(ctk.CTk):
# self.spacer = ctk.CTkLabel(master=self.slider_progressbar_frame, text="")
# self.spacer.grid(row=0, column=0, columnspan=1)
self.label_speed = ctk.CTkLabel(master=self.slider_progressbar_frame, text="Network Speed: 0 KB/s")
self.label_speed = ctk.CTkLabel(master=self.slider_progressbar_frame, text="Awaiting Download!")
self.label_speed.grid(row=1, column=0, padx=20, pady=(0, 10), sticky="w")
self.elapsed_time = ctk.CTkLabel(master=self.slider_progressbar_frame, text="")
self.elapsed_time.grid(row=1, column=1, padx=20, pady=(0, 10), sticky="nsew", columnspan=1)
self.elapsed_time = ctk.CTkLabel(master=self.slider_progressbar_frame, text="", anchor="center")
self.elapsed_time.grid(row=1, column=1, padx=20, pady=(0, 10), sticky="nsew") # Use "nsew" to center label
self.label_file_size = ctk.CTkLabel(master=self.slider_progressbar_frame, text="File size: 0KB")
self.label_file_size.grid(row=1, column=2, padx=(0, 20), pady=(0, 10), sticky="e")
@ -786,7 +784,7 @@ class BOIIIWD(ctk.CTk):
def skip_current_queue_item(self):
if self.button_download._state == "normal":
self.skip_boutton.grid_remove()
self.after(1, self.status_text.configure(text=f"Status: Not Downloading"))
self.after(1, self.status_text.configure(text=f"Status: Standby!"))
return
self.settings_tab.stopped = True
self.item_skipped = True
@ -829,7 +827,7 @@ class BOIIIWD(ctk.CTk):
self.settings_tab.stopped = True
self.queue_stop_button = True
show_message("Error", f"Couldn't remove {map_folder}, please do so manually\n{e}", icon="cancel")
self.stop_download
self.stop_download()
return
if self.settings_tab.continuous:
@ -945,6 +943,7 @@ class BOIIIWD(ctk.CTk):
self.is_downloading = False
self.fail_threshold = 0
if not self.is_pressed:
self.after(1, self.label_speed.configure(text=f"Loading..."))
self.is_pressed = True
self.library_tab.load_items(self.edit_destination_folder.get())
if self.queue_enabled:
@ -983,19 +982,19 @@ class BOIIIWD(ctk.CTk):
if not items:
show_message("Warning", "Please enter valid Workshop IDs/Links.", icon="warning")
self.stop_download
self.stop_download()
return
destination_folder = self.edit_destination_folder.get().strip()
if not destination_folder or not os.path.exists(destination_folder):
show_message("Error", "Please select a valid destination folder => in the main tab!.")
self.stop_download
self.stop_download()
return
if not steamcmd_path or not os.path.exists(steamcmd_path):
show_message("Error", "Please enter a valid SteamCMD path => in the main tab!.")
self.stop_download
self.stop_download()
return
self.total_queue_size = 0
@ -1010,15 +1009,15 @@ class BOIIIWD(ctk.CTk):
workshop_id = extract_workshop_id(workshop_id).strip()
else:
show_message("Warning", "Please enter valid Workshop IDs/Links.", icon="warning")
self.stop_download
self.stop_download()
return
except:
show_message("Warning", "Please enter valid Workshop IDs/Links.", icon="warning")
self.stop_download
self.stop_download()
return
if not valid_id(workshop_id):
show_message("Warning", "Please enter valid Workshop IDs/Links.", icon="warning")
self.stop_download
self.stop_download()
return
ws_file_size = get_workshop_file_size(workshop_id)
@ -1027,7 +1026,7 @@ class BOIIIWD(ctk.CTk):
if file_size is None:
show_message("Error", "Failed to retrieve file size.", icon="cancel")
self.stop_download
self.stop_download()
return
if any(workshop_id in item for item in self.library_tab.added_items):
@ -1041,7 +1040,7 @@ class BOIIIWD(ctk.CTk):
items.remove(item)
show_message("Heads up!, map/s skipped => skip is on in settings", f"These item IDs may already be installed and are skipped:\n{item_ids}", icon="info")
if not any(isinstance(item, int) for item in items):
self.stop_download
self.stop_download()
return
else:
show_message("Heads up! map/s not skipped => skip is off in settings", f"These item IDs may already be installed:\n{item_ids}", icon="info")
@ -1053,7 +1052,7 @@ class BOIIIWD(ctk.CTk):
current_number = index + 1
total_items = len(items)
if self.queue_stop_button:
self.stop_download
self.stop_download()
break
item.strip()
self.settings_tab.stopped = False
@ -1064,11 +1063,11 @@ class BOIIIWD(ctk.CTk):
workshop_id = extract_workshop_id(workshop_id).strip()
else:
show_message("Warning", "Please enter valid Workshop IDs/Links.", icon="warning")
self.stop_download
self.stop_download()
return
except:
show_message("Warning", "Please enter valid Workshop IDs/Links.", icon="warning")
self.stop_download
self.stop_download()
return
ws_file_size = get_workshop_file_size(workshop_id)
file_size = ws_file_size
@ -1211,8 +1210,6 @@ class BOIIIWD(ctk.CTk):
update_ui_thread.daemon = True
update_ui_thread.start()
update_ui_thread.join()
self.label_speed.configure(text="Network Speed: 0 KB/s")
self.progress_text.configure(text="0%")
self.progress_bar.set(0.0)
@ -1221,6 +1218,7 @@ class BOIIIWD(ctk.CTk):
json_file_path = os.path.join(map_folder, "workshop.json")
if os.path.exists(json_file_path):
self.label_speed.configure(text="Installing...")
mod_type = extract_json_data(json_file_path, "Type")
folder_name = extract_json_data(json_file_path, "FolderName")
@ -1248,6 +1246,12 @@ class BOIIIWD(ctk.CTk):
if index == len(items) - 1:
self.after(1, self.status_text.configure(text=f"Status: Done! => Please press stop only if you see no popup window (rare bug)"))
self.show_complete_message(message=f"All files were downloaded\nYou can run the game now!\nPS: You have to restart the game \n(pressing launch will launch/restarts)")
self.label_speed.configure(text="Awaiting Download!")
elif os.path.exists(json_file_path) and not self.settings_tab.stopped:
show_message("Error", "Failed to find workshop.json, please try again.", icon="cancel")
if index == len(items) - 1:
self.stop_download()
return
self.button_download.configure(state="disabled")
self.button_stop.configure(state="normal")
@ -1263,15 +1267,14 @@ class BOIIIWD(ctk.CTk):
self.skip_boutton.grid_remove()
self.after(1, self.label_file_size.configure(text=f"File size: 0KB"))
self.settings_tab.stopped = True
self.stop_download
self.stop_download()
return
finally:
self.settings_tab.steam_fail_counter = 0
self.after(1, self.label_file_size.configure(text=f"File size: 0KB"))
self.stop_download
self.stop_download()
self.is_pressed = False
def download_thread(self):
try:
self.settings_tab.stopped = False
@ -1295,12 +1298,12 @@ class BOIIIWD(ctk.CTk):
if not destination_folder or not os.path.exists(destination_folder):
show_message("Error", "Please select a valid destination folder.")
self.stop_download
self.stop_download()
return
if not steamcmd_path or not os.path.exists(steamcmd_path):
show_message("Error", "Please enter a valid SteamCMD path.")
self.stop_download
self.stop_download()
return
if not workshop_id.isdigit():
@ -1309,11 +1312,11 @@ class BOIIIWD(ctk.CTk):
workshop_id = extract_workshop_id(workshop_id).strip()
else:
show_message("Warning", "Please enter a valid Workshop ID/Link.", icon="warning")
self.stop_download
self.stop_download()
return
except:
show_message("Warning", "Please enter a valid Workshop ID/Link.", icon="warning")
self.stop_download
self.stop_download()
return
ws_file_size = get_workshop_file_size(workshop_id)
@ -1321,18 +1324,18 @@ class BOIIIWD(ctk.CTk):
if not valid_id(workshop_id):
show_message("Warning", "Please enter a valid Workshop ID/Link.", icon="warning")
self.stop_download
self.stop_download()
return
if file_size is None:
show_message("Error", "Failed to retrieve file size.", icon="cancel")
self.stop_download
self.stop_download()
return
if any(workshop_id in item for item in self.library_tab.added_items):
if self.settings_tab.skip_already_installed:
show_message("Heads up!, map skipped => Skip is on in settings", f"This item may already be installed, Stopping: {workshop_id}", icon="info")
self.stop_download
self.stop_download()
return
show_message("Heads up! map not skipped => Skip is off in settings", f"This item may already be installed: {workshop_id}", icon="info")
@ -1449,8 +1452,6 @@ class BOIIIWD(ctk.CTk):
update_ui_thread.join()
self.settings_tab.stopped = True
self.label_speed.configure(text="Network Speed: 0 KB/s")
self.progress_text.configure(text="0%")
self.progress_bar.set(0.0)
@ -1459,6 +1460,7 @@ class BOIIIWD(ctk.CTk):
json_file_path = os.path.join(map_folder, "workshop.json")
if os.path.exists(json_file_path):
self.label_speed.configure(text="Installing...")
mod_type = extract_json_data(json_file_path, "Type")
folder_name = extract_json_data(json_file_path, "FolderName")
@ -1470,7 +1472,7 @@ class BOIIIWD(ctk.CTk):
folder_name_path = os.path.join(usermaps_folder, folder_name, "zone")
else:
show_message("Error", "Invalid workshop type in workshop.json, are you sure this is a map or a mod?.", icon="cancel")
self.stop_download
self.stop_download()
return
os.makedirs(folder_name_path, exist_ok=True)
@ -1487,16 +1489,21 @@ class BOIIIWD(ctk.CTk):
self.show_complete_message(message=f"{mod_type.capitalize()} files were downloaded\nYou can run the game now!\nPS: You have to restart the game \n(pressing launch will launch/restarts)")
self.button_download.configure(state="normal")
self.button_stop.configure(state="disabled")
elif os.path.exists(json_file_path) and not self.settings_tab.stopped:
show_message("Error", "Failed to find workshop.json, please try again.", icon="cancel")
self.stop_download()
return
update_wait_thread = threading.Thread(target=wait_for_threads)
update_wait_thread.start()
self.button_download.configure(state="disabled")
self.button_stop.configure(state="normal")
steamcmd_thread.join()
update_wait_thread.join()
finally:
self.settings_tab.steam_fail_counter = 0
self.stop_download
self.stop_download()
self.is_pressed = False
def copy_with_progress(self, src, dst):
@ -1539,9 +1546,9 @@ class BOIIIWD(ctk.CTk):
self.button_download.configure(state="normal")
self.button_stop.configure(state="disabled")
self.label_speed.configure(text="Network Speed: 0 KB/s")
self.progress_text.configure(text="0%")
self.elapsed_time.configure(text=f"")
self.progress_bar.set(0.0)
self.after(50, self.status_text.configure(text=f"Status: Not Downloading"))
self.after(50, self.status_text.configure(text=f"Status: Standby!"))
self.after(1, self.label_speed.configure(text=f"Awaiting Download!"))
self.skip_boutton.grid_remove()

BIN
dist/BOIIIWD.exe vendored

Binary file not shown.