Atlas-Install/source/Gui/TrackSelection.py

284 lines
12 KiB
Python

from tkinter import *
from tkinter import ttk
class Orderbox(Listbox):
def order_up(self, *args, **kwargs):
self.order_change(delta_start=1)
def order_down(self, *args, **kwargs):
self.order_change(delta_end=1)
def order_change(self, delta_start: int = 0, delta_end: int = 0):
selection = self.curselection()
if len(selection) < 1: return
index = selection[0]
values = self.get(index - delta_start, index + delta_end)
if len(values) < 2: return
self.delete(index - delta_start, index + delta_end)
self.insert(index - delta_start, *reversed(values))
self.selection_set(index - delta_start + delta_end)
class TrackSelection:
def __init__(self, common):
self.common = common
self.root = Toplevel(self.common.gui_main.root)
self.root.title("Track selection")
self.root.iconbitmap("./icon.ico")
self.root.resizable(False, False)
self.root.grab_set()
self.text_is_equal_to = "is equal to"
self.text_is_in = "is in"
self.text_is_between = "is between"
self.text_contains = "contains"
self.text_and = "and"
self.text_nand = "nand"
self.text_or = "or"
self.text_nor = "nor"
self.text_xor = "xor"
self.text_xnor = "xnor"
self.condition_link_end = "end"
track_filter_row_start = 10
self.condition_links = {
self.text_and: lambda a, b: lambda track: a(track) and b(track),
self.text_nand: lambda a, b: lambda track: not (a(track) and b(track)),
self.text_or: lambda a, b: lambda track: a(track) or b(track),
self.text_nor: lambda a, b: lambda track: not (a(track) or b(track)),
self.text_xor: lambda a, b: lambda track: a(track) != b(track),
self.text_xnor: lambda a, b: lambda track: a(track) == b(track),
self.condition_link_end: -1
}
def del_frame_track_filter(frames_filter: list, index: int = 0):
for elem in frames_filter[index:]: # remove all track filter after this one
elem["frame"].destroy()
del frames_filter[index:]
def add_frame_track_filter(root: Frame, frames_filter: list, index: int = 0):
frame = Frame(root)
frame.grid(row=index + track_filter_row_start, column=1, sticky="NEWS")
Label(frame, text="If track's").grid(row=1, column=1)
track_property = ttk.Combobox(frame, values=list(self.common.ct_config.get_all_track_possibilities().keys()))
track_property.current(0)
track_property.grid(row=1, column=2)
frame_equal = Frame(frame)
entry_equal = Entry(frame_equal, width=20)
entry_equal.grid(row=1, column=1)
entry_equal.insert(END, "value")
frame_in = Frame(frame)
entry_in = Entry(frame_in, width=30)
entry_in.grid(row=1, column=1)
entry_in.insert(END, "value1, value2, ...")
frame_between = Frame(frame)
entry_start = Entry(frame_between, width=10)
entry_start.grid(row=1, column=1)
entry_start.insert(END, "value1")
Label(frame_between, text="and").grid(row=1, column=2)
entry_end = Entry(frame_between, width=10)
entry_end.insert(END, "value2")
entry_end.grid(row=1, column=3)
frame_contains = Frame(frame)
entry_contains = Entry(frame_contains, width=20)
entry_contains.grid(row=1, column=1)
entry_contains.insert(END, "value")
condition_frames = {
self.text_is_equal_to: frame_equal,
self.text_is_in: frame_in,
self.text_is_between: frame_between,
self.text_contains: frame_contains,
}
def change_condition_type(event: Event = None):
condition = combobox_condition_type.get()
for frame in condition_frames.values(): frame.grid_forget()
condition_frames[condition].grid(row=1, column=10)
combobox_condition_type = ttk.Combobox(frame, values=list(condition_frames.keys()), width=10)
combobox_condition_type.current(0)
combobox_condition_type.bind("<<ComboboxSelected>>", change_condition_type)
change_condition_type()
combobox_condition_type.grid(row=1, column=3)
def change_condition_link(event: Event = None):
link = next_condition_link.get()
if link == self.condition_link_end:
del_frame_track_filter(frames_filter, index=index + 1)
else:
if frames_filter[-1]["frame"] == frame: # if this is the last filter available
add_frame_track_filter(root=root, frames_filter=frames_filter, index=index + 1)
next_condition_link = ttk.Combobox(frame, values=list(self.condition_links.keys()), width=10)
next_condition_link.bind("<<ComboboxSelected>>", change_condition_link)
next_condition_link.set(self.condition_link_end)
next_condition_link.grid(row=1, column=100)
frames_filter.append({
"frame": frame,
"track_property": track_property,
"condition_type": combobox_condition_type,
"value_equal": entry_equal,
"value_in": entry_in,
"value_between_start": entry_start,
"value_between_end": entry_end,
"value_contains": entry_contains,
"next_condition_link": next_condition_link
})
def get_change_enable_track_filter_func(root: [Frame, LabelFrame], frames_filter: list, variable_enable: BooleanVar):
def change_enable_track_filter(event: Event = None):
if variable_enable.get(): add_frame_track_filter(root=root, frames_filter=frames_filter)
else: del_frame_track_filter(frames_filter=frames_filter)
return change_enable_track_filter
self.track_sort = LabelFrame(self.root, text="Sort Track")
self.track_sort.grid(row=1, column=1, sticky="NEWS")
Label(self.track_sort, text="Sort track by : ").grid(row=1, column=1)
self.combobox_track_sort = ttk.Combobox(
self.track_sort,
values=list(self.common.ct_config.get_all_track_possibilities().keys())
)
self.combobox_track_sort.grid(row=1, column=2, sticky="NEWS")
self.combobox_track_sort.insert(END, self.common.ct_config.sort_track_attr)
self.track_filter = LabelFrame(self.root, text="Filter Track")
self.track_filter.grid(row=2, column=1, sticky="NEWS")
self.variable_enable_track_filter = BooleanVar(value=False)
self.frames_track_filter = []
self.checkbutton_track_filter = ttk.Checkbutton(
self.track_filter,
text="Enable track filter",
variable=self.variable_enable_track_filter,
command=get_change_enable_track_filter_func(
self.track_filter,
self.frames_track_filter,
self.variable_enable_track_filter
)
)
self.checkbutton_track_filter.grid(row=1, column=1)
self.track_highlight = LabelFrame(self.root, text="Highlight Track")
self.track_highlight.grid(row=3, column=1, sticky="NEWS")
self.variable_enable_track_highlight = BooleanVar(value=False)
self.frames_track_highlight = []
self.checkbutton_track_highlight = ttk.Checkbutton(
self.track_highlight,
text="Enable track highlight",
variable=self.variable_enable_track_highlight,
command=get_change_enable_track_filter_func(
self.track_highlight,
self.frames_track_highlight,
self.variable_enable_track_highlight
)
)
self.checkbutton_track_highlight.grid(row=1, column=1)
self.track_random_new = LabelFrame(self.root, text="Overwrite random cup new")
self.track_random_new.grid(row=4, column=1, sticky="NEWS")
self.variable_enable_track_random_new = BooleanVar(value=False)
self.frames_track_random_new = []
self.checkbutton_track_random_new = ttk.Checkbutton(
self.track_random_new,
text="Enable overwriting random \"new\" track",
variable=self.variable_enable_track_random_new,
command=get_change_enable_track_filter_func(
self.track_random_new,
self.frames_track_random_new,
self.variable_enable_track_random_new
)
)
self.checkbutton_track_random_new.grid(row=1, column=1)
Button(
self.root,
text="Save configuration",
relief=RIDGE,
command=self.save_configuration
).grid(row=100, column=1, sticky="E")
def save_configuration(self):
self.common.gui_main.is_track_configuration_edited = True
self.common.ct_config.sort_track_attr = self.combobox_track_sort.get()
self.common.ct_config.filter_track_selection = self.get_filter(
self.variable_enable_track_filter,
self.frames_track_filter
)
self.common.ct_config.filter_track_highlight = self.get_filter(
self.variable_enable_track_highlight,
self.frames_track_highlight
)
self.common.ct_config.filter_track_random_new = self.get_filter(
self.variable_enable_track_random_new,
self.frames_track_random_new
)
def get_filter(self, condition_enabled: BooleanVar, frames_filter: list):
s = lambda x: str(x).strip()
filter_condition = lambda track: True
if not condition_enabled.get(): return filter_condition
next_condition_link_func = lambda a, b: lambda track: a(track) and b(track)
for frame_filter in frames_filter:
track_property = frame_filter["track_property"].get()
value_equal = frame_filter["value_equal"].get()
value_in = frame_filter["value_in"].get()
value_contains = frame_filter["value_contains"].get()
value_between_start = frame_filter["value_between_start"].get()
value_between_end = frame_filter["value_between_end"].get()
def _is_between_func_wrapper(property):
def _is_between_func(track):
from_ = s(value_between_start)
to = s(value_between_end)
prop = s(getattr(track, property, None))
if from_.isnumeric() and prop.isnumeric() and to.isnumeric(): return int(from_) <= int(prop) <= int(to)
else: return from_ <= prop <= to
return _is_between_func
track_conditions_filter = {
self.text_is_equal_to: lambda property: lambda track:
s(getattr(track, property, None)) == s(value_equal),
self.text_is_in: lambda property: lambda track:
s(getattr(track, property, None)) in [s(v) for v in value_in.split(",")],
self.text_is_between:
_is_between_func_wrapper,
self.text_contains: lambda property: lambda track:
s(value_contains) in s(getattr(track, property, None))
}
track_condition_type = frame_filter["condition_type"].get()
track_condition_filter = track_conditions_filter[track_condition_type]
filter_condition = next_condition_link_func(
filter_condition,
track_condition_filter(track_property)
)
next_condition_link = frame_filter["next_condition_link"].get()
next_condition_link_func = self.condition_links[next_condition_link]
return filter_condition