Implemented GUI for syng #2

Merged
christofsteel merged 18 commits from gui into main 2023-12-18 19:48:28 +01:00
Showing only changes of commit 9fdb9ef76d - Show all commits

View file

@ -1,5 +1,4 @@
import builtins import builtins
from functools import partial
from json import load from json import load
import customtkinter import customtkinter
import qrcode import qrcode
@ -12,7 +11,88 @@ from syng.client import default_config
from .sources import available_sources from .sources import available_sources
class SourceTab(customtkinter.CTkFrame): class OptionFrame(customtkinter.CTkFrame):
def add_option_label(self, text):
customtkinter.CTkLabel(self, text=text, justify="left").grid(
column=0, row=self.number_of_options, padx=5, pady=5
)
def add_bool_option(self, name, description, value=False):
self.add_option_label(description)
self.bool_options[name] = customtkinter.CTkCheckBox(
self,
text="",
onvalue=True,
offvalue=False,
)
if value:
self.bool_options[name].select()
else:
self.bool_options[name].deselect()
self.bool_options[name].grid(column=1, row=self.number_of_options)
self.number_of_options += 1
def add_string_option(self, name, description, value="", callback=None):
self.add_option_label(description)
if value is None:
value = ""
self.string_options[name] = customtkinter.CTkTextbox(
self, wrap="none", height=1
)
self.string_options[name].grid(column=1, row=self.number_of_options)
self.string_options[name].insert("0.0", value)
if callback is not None:
self.string_options[name].bind("<KeyRelease>", callback)
self.string_options[name].bind("<ButtonRelease>", callback)
self.number_of_options += 1
def add_list_option(self, name, description, value=[], callback=None):
self.add_option_label(description)
self.list_options[name] = customtkinter.CTkTextbox(self, wrap="none", height=1)
self.list_options[name].grid(column=1, row=self.number_of_options)
self.list_options[name].insert("0.0", ", ".join(value))
if callback is not None:
self.list_options[name].bind("<KeyRelease>", callback)
self.list_options[name].bind("<ButtonRelease>", callback)
self.number_of_options += 1
def add_choose_option(self, name, description, values, value=""):
self.add_option_label(description)
self.choose_options[name] = customtkinter.CTkOptionMenu(self, values=values)
self.choose_options[name].grid(column=1, row=self.number_of_options)
self.choose_options[name].set(value)
self.number_of_options += 1
def __init__(self, parent):
super().__init__(parent)
self.number_of_options = 0
self.string_options = {}
self.choose_options = {}
self.bool_options = {}
self.list_options = {}
def get_config(self):
config = {}
for name, textbox in self.string_options.items():
config[name] = textbox.get("0.0", "end").strip()
for name, optionmenu in self.choose_options.items():
config[name] = optionmenu.get().strip()
for name, checkbox in self.bool_options.items():
config[name] = checkbox.get() == 1
for name, textbox in self.list_options.items():
config[name] = [
v.strip() for v in textbox.get("0.0", "end").strip().split(",")
]
return config
class SourceTab(OptionFrame):
def updateStrVar(self, var: str, element: customtkinter.CTkTextbox, event): def updateStrVar(self, var: str, element: customtkinter.CTkTextbox, event):
value = element.get("0.0", "end").strip() value = element.get("0.0", "end").strip()
self.vars[var] = value self.vars[var] = value
@ -33,90 +113,32 @@ class SourceTab(customtkinter.CTkFrame):
source.config_schema.items() source.config_schema.items()
): ):
value = config[name] if name in config else default value = config[name] if name in config else default
self.vars[name] = value
label = customtkinter.CTkLabel(self, text=f"{desc} ({name})")
label.grid(column=0, row=row)
match typ: match typ:
case builtins.bool: case builtins.bool:
checkbox = customtkinter.CTkCheckBox( self.add_bool_option(name, desc, value=value)
self,
text="",
onvalue=True,
offvalue=False,
)
checkbox.bind(
"<ButtonRelease>", partial(self.updateBoolVar, name, checkbox)
)
checkbox.bind(
"<KeyRelease>", partial(self.updateBoolVar, name, checkbox)
)
if value:
checkbox.select()
else:
checkbox.deselect()
checkbox.grid(column=1, row=row)
case builtins.list: case builtins.list:
inputfield = customtkinter.CTkTextbox(self, wrap="none", height=1) self.add_list_option(name, desc, value=value)
inputfield.bind(
"<KeyRelease>", partial(self.updateStrVar, name, inputfield)
)
inputfield.bind(
"<ButtonRelease>", partial(self.updateStrVar, name, inputfield)
)
inputfield.insert("0.0", ", ".join(value))
inputfield.grid(column=1, row=row)
case builtins.str: case builtins.str:
inputfield = customtkinter.CTkTextbox(self, wrap="none", height=1) self.add_string_option(name, desc, value=value)
inputfield.bind(
"<KeyRelease>", partial(self.updateStrVar, name, inputfield)
)
inputfield.bind(
"<ButtonRelease>", partial(self.updateStrVar, name, inputfield)
)
inputfield.insert("0.0", value)
inputfield.grid(column=1, row=row)
def get_config(self):
return self.vars
class GeneralConfig(customtkinter.CTkFrame): class GeneralConfig(OptionFrame):
def add_option_label(self, text):
customtkinter.CTkLabel(self, text=text, justify="left").grid(
column=0, row=self.number_of_options, padx=5, pady=5
)
def add_string_option(self, name, description, callback=None):
self.add_option_label(description)
self.string_options[name] = customtkinter.CTkTextbox(
self, wrap="none", height=1
)
self.string_options[name].grid(column=1, row=self.number_of_options)
if callback is not None:
self.string_options[name].bind("<KeyRelease>", callback)
self.number_of_options += 1
def add_choose_option(self, name, description, values):
self.add_option_label(description)
self.choose_options[name] = customtkinter.CTkOptionMenu(self, values=values)
self.choose_options[name].grid(column=1, row=self.number_of_options)
self.number_of_options += 1
def __init__(self, parent, config, callback): def __init__(self, parent, config, callback):
super().__init__(parent) super().__init__(parent)
self.number_of_options = 0
self.string_options = {}
self.choose_options = {}
self.add_string_option("server", "Server", callback) self.add_string_option("server", "Server", config["server"], callback)
self.add_string_option("room", "Room", callback) self.add_string_option("room", "Room", config["room"], callback)
self.add_string_option("secret", "Secret") self.add_string_option("secret", "Secret", config["secret"])
self.add_choose_option( self.add_choose_option(
"waiting_room_policy", "Waiting room policy", ["forced", "optional", "none"] "waiting_room_policy",
"Waiting room policy",
["forced", "optional", "none"],
config["waiting_room_policy"],
)
self.add_string_option("last_song", "Time of last song", config["last_song"])
self.add_string_option(
"preview_duration", "Preview Duration", config["preview_duration"]
) )
self.add_string_option("last_song", "Time of last song")
self.add_string_option("preview_duration", "Preview Duration")
for name, textbox in self.string_options.items(): for name, textbox in self.string_options.items():
if config[name]: if config[name]:
@ -126,17 +148,12 @@ class GeneralConfig(customtkinter.CTkFrame):
optionmenu.set(str(config[name]).lower()) optionmenu.set(str(config[name]).lower())
def get_config(self): def get_config(self):
config = {} config = super().get_config()
for name, textbox in self.string_options.items():
config[name] = textbox.get("0.0", "end").strip()
for name, optionmenu in self.choose_options.items():
config[name] = optionmenu.get().strip()
try: try:
config["preview_duration"] = int(config["preview_duration"]) config["preview_duration"] = int(config["preview_duration"])
except ValueError: except ValueError:
config["preview_duration"] = 0 config["preview_duration"] = 0
return config return config
@ -159,13 +176,6 @@ class SyngGui(customtkinter.CTk):
) )
self.wm_title("Syng") self.wm_title("Syng")
tabview = customtkinter.CTkTabview(self)
tabview.pack(side="top")
tabview.add("General")
for source in available_sources:
tabview.add(source)
tabview.set("General")
fileframe = customtkinter.CTkFrame(self) fileframe = customtkinter.CTkFrame(self)
fileframe.pack(side="bottom") fileframe.pack(side="bottom")
@ -182,14 +192,24 @@ class SyngGui(customtkinter.CTk):
) )
startbutton.pack(side="right") startbutton.pack(side="right")
frm = customtkinter.CTkFrame(tabview.tab("General")) frm = customtkinter.CTkFrame(self)
frm.grid(ipadx=10) frm.pack(ipadx=10, padx=10, fill="both", expand=True)
tabview = customtkinter.CTkTabview(frm)
tabview.pack(side="right", padx=10, pady=10, fill="both", expand=True)
tabview.add("General")
for source in available_sources:
tabview.add(source)
tabview.set("General")
self.qrlabel = customtkinter.CTkLabel(frm, text="") self.qrlabel = customtkinter.CTkLabel(frm, text="")
self.qrlabel.grid(column=0, row=0) self.qrlabel.pack(side="left")
self.general_config = GeneralConfig(frm, config["config"], self.updateQr) self.general_config = GeneralConfig(
self.general_config.grid(column=1, row=0) tabview.tab("General"), config["config"], self.updateQr
)
self.general_config.pack(ipadx=10, fill="y")
self.tabs = {} self.tabs = {}
@ -202,7 +222,7 @@ class SyngGui(customtkinter.CTk):
self.tabs[source_name] = SourceTab( self.tabs[source_name] = SourceTab(
tabview.tab(source_name), source_name, source_config tabview.tab(source_name), source_name, source_config
) )
self.tabs[source_name].grid(ipadx=10) self.tabs[source_name].pack(ipadx=10)
self.updateQr() self.updateQr()