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("<>", 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("<>", 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.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