Example #1
0
    def __init__(self, c:ttk.Checkbutton, p:param) -> None:
        super().__init__(p)
        v = p.get_value()
        if isinstance(v,bool):
            v = 0 if v == False else 1
        self.var = tk.IntVar(master=c,name=p.name,value=v)
        self.c:ttk.Checkbutton = c
        c.configure(command=self.onSelectionChanged,variable=self.var)


        return
Example #2
0
class DestinationFrame(LabelFrame):
    def __init__(self, root, model: ConfigUIModel):
        super().__init__(root, text="Destination", padding=10)
        self.pack(side=LEFT, anchor=NW, fill=BOTH, expand=True)
        self.model = model

        self.txt_dest = Entry(self, textvariable=self.model.var_dest)
        self.txt_dest.pack(fill=X)

        self.chk_wrap = Checkbutton(self,
                                    text="Create Date Wrapper",
                                    variable=self.model.var_wrap,
                                    onvalue=True,
                                    offvalue=False)
        self.chk_wrap.pack()

        self.btn_dest_browse = Button(self,
                                      text="Browse",
                                      command=self.set_dest)
        self.btn_dest_browse.pack()

        def manage():
            self.model.var_managed.set(True)

        self.btn_make_managed = Button(self,
                                       text="Manage This Folder",
                                       command=manage)
        self.btn_make_managed.pack(side=BOTTOM)

        self.model.var_managed.trace_add("write", self.managed_changed)

    def managed_changed(self, *args):
        val = self.model.var_managed.get()
        if val:
            self.chk_wrap.configure(state="disabled")
            self.btn_make_managed.configure(text="Already Managed",
                                            state="disabled")
        else:
            self.chk_wrap.configure(state="normal")
            self.btn_make_managed.configure(text="Manage This Folder",
                                            state="normal")

    def set_dest(self):
        dest = filedialog.askdirectory(title="Choose Destination")
        if dest is not None:
            self.model.var_dest.set(dest)
            self.model.var_managed.set(MetaRecord.is_managed(dest))
Example #3
0
class MainWindow(mp.Process):
    """Defines the main control window and all its control logic.

    As Tkinter only allows to create root windwo (Tk()) in the main process, this is implemented as its own
    subprocess that will open the window with a call to self.run()

    Args:
        connector_dict: Dictionary create by calling multiprocessing.Manger().dict()
        message_q: Queue that will be polled every few seconds. Elements in queue will be plotted to the internal
            text field.
        start_analysis_e: Event signaling if analysis can be started
        connected_e: Event signaling that LSL streams are connected
        ready_for_connection_e: Event signaling that LSL streams have been selected in GUI
        save_e: Event signaling that data should be saved.

    """
    def __init__(self, connector_dict: Dict, message_q: mp.Queue,
                 start_recording_e: mp.Event, start_analysis_e: mp.Event,
                 connected_e: mp.Event, ready_for_connection_e: mp.Event,
                 save_e: mp.Event):
        super().__init__()
        self.connector_dict = connector_dict
        self.message_q = message_q
        self.start_recording_e = start_recording_e
        self.start_analysis_e = start_analysis_e
        self.ready_for_connection_e = ready_for_connection_e
        self.connected_e = connected_e
        self.save_e = save_e

        self.master = None

        # Parameters
        self.eeg_stream = None
        self.eeg_streams_dict = None
        self.marker_stream = None
        self.marker_streams_dict = None
        self.channel_select = None
        self.update_interval = None
        self.record_time = None
        self.y_min = None
        self.y_max = None
        self.save_filename = None
        self.filter_check = None
        self.squared_check = None
        self.connected = None

        # Widgets
        self.eeg_stream_label = None
        self.eeg_stream_combobox = None
        self.eeg_stream_button = None
        self.marker_stream_label = None
        self.marker_stream_combobox = None
        self.marker_stream_button = None
        self.filter_checkbutton_label = None
        self.filter_checkbutton = None
        self.connect_button = None
        self.seperator = None
        self.start_recording_btn = None
        self.record_time_label = None
        self.Separator_2 = None
        self.update_interval_label = None
        self.update_interval_combobox = None
        self.start_analysis_btn = None
        self.channel_select_label = None
        self.channel_select_combobox = None
        self.squared_label = None
        self.squared_checkbtn = None
        self.update_ylim_btn = None
        self.y_min_label = None
        self.y_min_entry = None
        self.y_max_label = None
        self.y_max_entry = None
        self.seperator = None
        self.save_label = None
        self.save_entry = None
        self.save_btn = None
        self.text_console = None

    def build_main_window(self):
        # Hack to make tkinter work in other process than main
        from tkinter import Tk, StringVar, Text, HORIZONTAL, EW, IntVar
        from tkinter.ttk import Separator, Combobox, Button, Label, Entry, Checkbutton

        self.master = Tk()

        # Parameters
        self.eeg_stream = StringVar()
        self.eeg_streams_dict = {}
        self.marker_stream = StringVar()
        self.marker_streams_dict = {}
        self.channel_select = IntVar()
        self.channel_select.set(0)
        self.update_interval = IntVar()
        self.update_interval.set(0)
        self.record_time = StringVar()
        self.record_time.set("00:00 minutes recorded")
        self.y_min = IntVar()
        self.y_min.set(-10)
        self.y_max = IntVar()
        self.y_max.set(10)
        self.save_filename = StringVar()
        self.save_filename.set("1")
        self.filter_check = IntVar()
        self.filter_check.set(1)
        self.squared_check = IntVar()
        self.squared_check.set(0)

        self.connected = False

        self.print_from_queue()

        # Widgets
        self.eeg_stream_label = Label(self.master, text='EEG LSL-stream:')
        self.eeg_stream_label.grid(row=0, column=0)

        self.eeg_stream_combobox = Combobox(self.master,
                                            textvariable=self.eeg_stream)
        self.eeg_stream_combobox.configure(state='disabled')
        self.eeg_stream_combobox.grid(row=0, column=1)

        self.eeg_stream_button = Button(
            self.master,
            text='Refresh',
            command=lambda: self.find_streams('EEG', self.eeg_stream_combobox,
                                              self.eeg_streams_dict, self.
                                              eeg_stream))
        self.eeg_stream_button.grid(row=0, column=2)

        self.marker_stream_label = Label(self.master,
                                         text='Marker LSL-stream:')
        self.marker_stream_label.grid(row=1, column=0)

        self.marker_stream_combobox = Combobox(self.master,
                                               textvariable=self.marker_stream)
        self.marker_stream_combobox.configure(state='disabled')
        self.marker_stream_combobox.grid(row=1, column=1)

        self.marker_stream_button = Button(
            self.master,
            text='Refresh',
            command=lambda: self.find_streams(
                'P300_Marker', self.marker_stream_combobox, self.
                marker_streams_dict, self.marker_stream))
        self.marker_stream_button.grid(row=1, column=2)

        self.filter_checkbutton_label = Label(
            self.master, text='Filter (Butter, Order 4, Cutoff: 1, 30):')
        self.filter_checkbutton_label.grid(row=2, column=0)

        self.filter_checkbutton = Checkbutton(self.master,
                                              variable=self.filter_check,
                                              text='')
        self.filter_checkbutton.grid(row=2, column=1)

        self.connect_button = Button(self.master,
                                     text='Connect',
                                     command=self.connect_streams)
        self.connect_button.grid(row=2, column=2)
        self.connect_button.configure(state='disabled')

        self.seperator = Separator(self.master, orient=HORIZONTAL)
        self.seperator.grid(row=3, column=0, columnspan=3, sticky=EW)

        self.start_recording_btn = Button(self.master,
                                          text='Start recoding',
                                          command=self.start_recording)
        self.start_recording_btn.grid(row=4, column=2)
        self.start_recording_btn.configure(state='disabled')

        self.record_time_label = Label(self.master,
                                       textvariable=self.record_time)
        self.record_time_label.grid(row=4, column=1)

        self.Separator_2 = Separator(self.master)
        self.Separator_2.grid(row=5, column=0, columnspan=3, sticky=EW)

        self.update_interval_label = Label(self.master,
                                           text='Update interval (seconds):')
        self.update_interval_label.grid(row=6, column=0)

        self.update_interval_combobox = Combobox(
            self.master, textvariable=self.update_interval)
        self.update_interval_combobox.bind('<<ComboboxSelected>>',
                                           self.update_connector_dict)
        self.update_interval_combobox.grid(row=6, column=1)
        self.update_interval_combobox['values'] = list(range(10))
        self.update_interval_combobox.configure(state='disabled')

        self.start_analysis_btn = Button(self.master,
                                         text='Start analysis',
                                         command=self.start_analysis)
        self.start_analysis_btn.grid(row=6, column=2)
        self.start_analysis_btn.configure(state='disabled')

        self.channel_select_label = Label(self.master,
                                          text='Channel to display:')
        self.channel_select_label.grid(row=7, column=0)

        self.channel_select_combobox = Combobox(
            self.master, textvariable=self.channel_select)
        self.channel_select_combobox.bind('<<ComboboxSelected>>',
                                          self.update_connector_dict)
        self.channel_select_combobox.grid(row=7, column=1)
        self.channel_select_combobox.configure(state='disabled')

        self.squared_label = Label(self.master, text='squared')
        self.squared_label.grid(row=8, column=0)

        self.squared_checkbtn = Checkbutton(self.master,
                                            variable=self.squared_check)
        self.squared_checkbtn.grid(row=8, column=1)
        self.squared_checkbtn.configure(state='disabled')

        self.update_ylim_btn = Button(self.master,
                                      text='Update',
                                      command=self.update_connector_dict)
        self.update_ylim_btn.grid(row=8, column=2)
        self.update_ylim_btn.configure(state='disabled')

        self.y_min_label = Label(self.master, text='Y min:')
        self.y_min_label.grid(row=9, column=0)

        self.y_min_entry = Entry(self.master, textvariable=self.y_min)
        self.y_min_entry.grid(row=9, column=1)
        self.y_min_entry.configure(state='disabled')

        self.y_max_label = Label(self.master, text='Y max:')
        self.y_max_label.grid(row=10, column=0)

        self.y_max_entry = Entry(self.master, textvariable=self.y_max)
        self.y_max_entry.grid(row=10, column=1)
        self.y_max_entry.configure(state='disabled')

        self.seperator = Separator(self.master, orient=HORIZONTAL)
        self.seperator.grid(row=11, column=0, columnspan=3, sticky=EW)

        self.save_label = Label(self.master, text='Filename:')
        self.save_label.grid(row=12, column=0)

        self.save_entry = Entry(self.master, textvariable=self.save_filename)
        self.save_entry.grid(row=12, column=1)
        self.save_entry.configure(state='disabled')

        self.save_btn = Button(self.master, text='Save', command=self.save)
        self.save_btn.grid(row=12, column=2)
        self.save_btn.configure(state='disabled')

        self.text_console = Text(self.master)
        self.text_console.grid(row=15, column=0, rowspan=3, columnspan=3)
        self.text_console.configure(state='disabled')

    def save(self):
        self.update_connector_dict()
        self.save_e.set()

    def update_channel_select(self):
        num_channels = self.connector_dict['number of channels']
        self.channel_select_combobox['values'] = list(range(num_channels))

    def start_recording(self):
        self.connect_button.configure(state='disabled')
        self.start_recording_btn.configure(state='disabled')
        self.channel_select_combobox.configure(state='normal')
        self.update_interval_combobox.configure(state='normal')
        self.y_min_entry.configure(state='normal')
        self.y_max_entry.configure(state='normal')
        self.update_ylim_btn.configure(state='normal')
        self.squared_checkbtn.configure(state='normal')

        self.update_channel_select()
        self.update_recording_time()

        self.start_recording_e.set()

        self.start_analysis_btn.configure(state='normal')

    def update_recording_time(self):
        num_samples = self.connector_dict['sample count']
        samplerate = self.connector_dict['samplerate']
        number_of_seconds = int(num_samples / samplerate)

        minutes = number_of_seconds // 60
        remaining_seconds = number_of_seconds % 60

        result_string = '{:02}:{:02} minutes recorded'.format(
            minutes, remaining_seconds)

        self.record_time.set(result_string)
        self.master.after(1000, self.update_recording_time)

    def start_analysis(self):
        self.start_analysis_btn.configure(state='disabled')
        self.save_btn.configure(state='normal')
        self.save_entry.configure(state='normal')

        self.update_connector_dict()
        self.start_analysis_e.set()

    def find_streams(self, stream_type, widget, stream_dict, var):
        stream_dict.clear()
        timeout = 3
        self.print_to_console('Searching for ' + stream_type +
                              ' streams... (timeout = ' + str(timeout) +
                              ' seconds)')

        streams = resolve_byprop('type', stream_type, timeout=timeout)
        if not streams:
            self.print_to_console('No stream found.')
            return

        widget.configure(state='normal')

        stream_list = []
        for stream in streams:
            stream_dict[stream.name()] = stream
            stream_list.append(stream.name())

        widget['values'] = stream_list

        if len(streams) >= 1:
            var.set(streams[0].name())

        self.print_to_console(str(len(streams)) + ' Stream(s) found!')
        self.test_if_two_streams()

    def test_if_two_streams(self):
        if self.eeg_stream.get() is not '' and self.marker_stream.get(
        ) is not '':
            self.connect_button.configure(state='normal')
        else:
            self.connect_button.configure(state='disabled')

    def print_to_console(self, text_to_print):
        text_to_print = str(text_to_print)

        self.text_console.configure(state='normal')
        self.text_console.insert('end', text_to_print + '\n')
        self.text_console.configure(state='disabled')

    def print_from_queue(self):
        if not self.message_q.empty():
            self.print_to_console(self.message_q.get())
        self.master.after(500, self.print_from_queue)

    # noinspection PyUnusedLocal
    def update_connector_dict(self, event=None):
        self.connector_dict['update interval'] = self.update_interval.get()
        self.connector_dict['channel select'] = self.channel_select.get()
        self.connector_dict['eeg streamname'] = self.eeg_stream.get()
        self.connector_dict['marker streamname'] = self.marker_stream.get()
        self.connector_dict['y lim'] = [self.y_min.get(), self.y_max.get()]
        self.connector_dict['savefile'] = self.save_filename.get()
        self.connector_dict['filter'] = self.filter_check.get()
        self.connector_dict['squared'] = self.squared_check.get()

    def connect_streams(self):
        self.eeg_stream_combobox.configure(state='disabled')
        self.eeg_stream_button.configure(state='disabled')
        self.marker_stream_combobox.configure(state='disabled')
        self.marker_stream_button.configure(state='disabled')
        self.filter_checkbutton.configure(state='disabled')
        self.connect_button.configure(state='disabled')

        self.update_connector_dict()
        self.ready_for_connection_e.set()

        self.connected_e.wait()

        self.start_recording_btn.configure(state='normal')

    def run(self):
        self.build_main_window()
        self.master.mainloop()
Example #4
0
styl.configure('.', background=_bgcolor)
styl.configure('.', foreground=_fgcolor)
styl.configure('.', sliderthickness='20')
styl.configure('.', font="TkDefaultFont")
styl.map('.', background=[('selected', _compcolor), ('active', _ana2color)])

Frame1 = Frame(root)
Frame1.place(relx=0.02, rely=0.02, relheight=0.27, relwidth=0.46)
Frame1.configure(relief=GROOVE)
Frame1.configure(borderwidth="2")
Frame1.configure(relief=GROOVE)
Frame1.configure(width=285)

Checkbutton1 = Checkbutton(Frame1)
Checkbutton1.place(relx=0.07, rely=0.43, relheight=0.22, relwidth=0.34)
Checkbutton1.configure(text='''Profile photo''')
Checkbutton1.configure(variable=check1)

Checkbutton3 = Checkbutton(Frame1)
Checkbutton3.place(relx=0.07, rely=0.7, relheight=0.22, relwidth=0.35)
Checkbutton3.configure(text='''Header photo''')
Checkbutton3.configure(variable=check2)

Label1 = Label(Frame1)
Label1.place(relx=0.04, rely=-0.04)
Label1.configure(text='''Upload''')

Button1 = Button(Frame1)
Button1.place(relx=0.74, rely=0.7, height=25, width=60)
Button1.configure(padding=(2, 0, 0, 0))
Button1.configure(text='''Upload''')
Example #5
0
class MainWindow:
    def __init__(self) -> None:
        self.Root = Tk()
        self.App = Frame(self.Root, padding=(5, 2))
        self.UpdatesFrame = LabelFrame(self.App, text='Обновление',
                                       borderwidth=2, relief='sunken', padding=(5, 2))
        self.upd_enabled = BooleanVar()  # Флаг обновлений
        self.upd_unit = StringVar()  # Единица измерения времени
        self.time_units = {Minutes: 'Минут', Hours: 'Часов',
                           Days: 'Дней', Weeks: 'Недель', Months: 'Месяцев'}
        self.size_units = {Bytes: 'Байт', KBytes: 'Кбайт', MBytes:'Мбайт',
                           GBytes:'Гбайт', TBytes:'Тбайт'}  # Список единиц измерения времени
        self.maxfsize = StringVar()  # Максимальный размер файла
        self.size_unit = StringVar()  # Единица измерения информации
        self.units_amount1 = StringVar()  # Количество единиц
        self.quar = BooleanVar()  # False - удалять, True - карантин
        self.quar_path = StringVar() # Расположение карантина
        self.rpt_enabled = BooleanVar()  # Флаг отправки отчета
        self.email = StringVar()  # Адрес отправки
        self.passwd = StringVar() # Пароль исходящего ящика
        self.rpt_unit = StringVar()  # Единица измерения времени
        self.units_amount2 = StringVar()  # Количество единиц

        self.Upd_Label1 = Label(self.UpdatesFrame, text='Проверять обновления антивирусных баз')
        self.Upd_Checkbutton1 = Checkbutton(self.UpdatesFrame, variable=self.upd_enabled)
        self.Upd_Label2 = Label(self.UpdatesFrame, text='Частота проверки:   каждые')
        self.Upd_Spinbox1 = Spinbox(self.UpdatesFrame, textvariable=self.units_amount1,
                                    from_=1, to=999999999, width=4)
        self.Upd_OptionMenu1 = OptionMenu(self.UpdatesFrame, self.upd_unit, *self.time_units.values())
        self.Upd_Button1 = Button(
            self.UpdatesFrame, text='Источники антивирусных сигнатур', command=EntryOptionsWindow('AV_SOURCES', self.Root).main)

        self.ScanFrame = LabelFrame(self.App, text='Сканирование',
                                    borderwidth=2, relief='sunken', padding=(5, 2))
        self.Scn_Label1 = Label(self.ScanFrame, text='Максимальный размер файла:')
        self.Scn_Spinbox1 = Spinbox(self.ScanFrame, textvariable=self.maxfsize,
                                    from_=0, to=999999999, width=8)

        self.Quar_Label = Label(self.ScanFrame, text='При обнаружении угрозы')
        self.Quar_RadButton1 = Radiobutton(self.ScanFrame, text='Удаление', variable=self.quar, value=False)
        self.Quar_RadButton2 = Radiobutton(self.ScanFrame, text='Карантин', variable=self.quar, value=True)

        self.Scn_OptionMenu1 = OptionMenu(self.ScanFrame, self.size_unit, *self.size_units.values())
        self.Scn_Edit_Targets = Button(self.ScanFrame, text='Цели сканирования', command=EntryOptionsWindow('SCAN_TARGETS', self.Root, select_path=True).main)
        self.Scn_Edit_Exceptions = Button(self.ScanFrame, text='Исключения', command=EntryOptionsWindow('SCAN_EXCLUDE', self.Root).main)
        self.Quar_Button1 = Button(self.ScanFrame, text='Расположение карантина',
                                   command=lambda: self.quar_path.set(filedialog.askdirectory()))

        self.ReportFrame = LabelFrame(self.App, text='Отправка отчета',
                                      borderwidth=2, relief='sunken', padding=(5, 2))

        self.Rpt_Label1 = Label(self.ReportFrame, text='Отправлять отчеты о сканировании')
        self.Rpt_Checkbutton1 = Checkbutton(self.ReportFrame, variable=self.rpt_enabled)
        self.Rpt_Label2 = Label(self.ReportFrame, text='Адрес отправки отчетов:')
        self.Rpt_Entry1 = Entry(self.ReportFrame, textvariable=self.email, width=32)
        self.Rpt_Label3 = Label(self.ReportFrame, text='Пароль:')
        self.Rpt_Entry2 = Entry(self.ReportFrame, textvariable=self.passwd, width=32, show='*')
        self.Rpt_Label4 = Label(self.ReportFrame, text='Частота:')
        self.Rpt_Spinbox1 = Spinbox(self.ReportFrame, textvariable=self.units_amount2,
                                    from_=1, to=999999999, width=4)
        self.Rpt_OptionMenu1 = OptionMenu(self.ReportFrame, self.rpt_unit, *self.time_units.values())
        self.Rpt_Button1 = Button(self.ReportFrame, text='Получатели', command=EntryOptionsWindow('SEND_TO', self.Root).main)

        self.Buttons = Frame(self.App, padding=(5, 2))
        self.Button1 = Button(self.Buttons, text='Готово', command=self.save_conf)
        self.Button2 = Button(self.Buttons, text='Отмена', command=self.Root.destroy)

    def main(self) -> None:
        self.upd_unit.set(self.time_units[type(UPDATE_FREQ)])
        self.units_amount1.set(UPDATE_FREQ.value)
        self.upd_enabled.set(CHECK_FOR_UPDATES)
        self.Upd_Checkbutton1.configure(command=(
            lambda: self.__change_state(
                self.upd_enabled, self.Upd_Label2, self.Upd_Spinbox1, self.Upd_OptionMenu1, self.Upd_Button1)
            and self.upd_enabled.set(not self.upd_enabled.get())))
        self.Rpt_Checkbutton1.configure(command=(
            lambda: self.__change_state(
                self.rpt_enabled, self.Rpt_Label2, self.Rpt_Entry1, self.Rpt_Label3, self.Rpt_Entry2,
                 self.Rpt_Label4, self. Rpt_Spinbox1, self.Rpt_OptionMenu1, self.Rpt_Button1)
                 and self.rpt_enabled.set(not self.rpt_enabled.get())))
        self.maxfsize.set(MAX_FILE_SIZE.value)
        self.size_unit.set(self.size_units[type(MAX_FILE_SIZE)])
        self.quar.set(REMOVE_THREATS)
        self.quar_path.set(QUARANTINE_PATH)
        self.rpt_enabled.set(SEND_SCAN_REPORTS)
        self.email.set(SEND_FROM)
        self.passwd.set(SEND_PASSWD)
        self.rpt_unit.set(self.time_units[type(SEND_FREQ)])
        self.units_amount2.set(SEND_FREQ.value)

        self.App.pack(fill='both', expand=True)
        center_win(self.Root, '500x500')
        self.Root.resizable(False, False)
        self.Root.title('CobraAV Configuration')

        self.UpdatesFrame.place(y=0, height=150, width=490)
        self.__change_state(self.upd_enabled, self.Upd_Label2,
                            self.Upd_Spinbox1, self.Upd_OptionMenu1)

        self.__change_state(self.rpt_enabled, self.Rpt_Label2, self.Rpt_Entry1, self.Rpt_Label3,
                            self.Rpt_Entry2, self.Rpt_Label4, self.Rpt_Spinbox1, self.Rpt_OptionMenu1, self.Rpt_Button1)

        self.Upd_Label1.place(relx=.01, rely=.05)  # Проверять обновления ?
        self.Upd_Checkbutton1.place(relx=.8, rely=.05)  # Да/Нет

        self.Upd_Label2.place(relx=.01, rely=.3)  # Частота проверки
        self.Upd_Spinbox1.place(relx=.55, rely=.3, width=60)  # Количество
        self.Upd_OptionMenu1.place(relx=.72, rely=.28)  # Единицы измерения
        self.Upd_Button1.place(relx=.01, rely=.65)  # Источники сигнатур

        self.ScanFrame.place(y=150, height=150, width=490)

        self.Scn_Label1.place(relx=.01, rely=.05)  # Максимальный размер файла
        self.Scn_Spinbox1.place(relx=.55, rely=.05, width=60)  # Количество

        self.Quar_Label.place(relx=.01, rely=.35)
        self.Quar_RadButton1.place(relx=.52, rely=.35)  # Переключатель на удаление угрозы
        self.Quar_RadButton2.place(relx=.72, rely=.35)  # Переключатель на добавление вкарантина угрозы
        self.Quar_Button1.place(relx=.56, rely=.65)  # Расположение карантина

        self.Scn_OptionMenu1.place(relx=.72, rely=.014)  # Единицы измерения
        self.Scn_Edit_Targets.place(relx=.01, rely=.65)  # Цели сканирования
        self.Scn_Edit_Exceptions.place(relx=.33, rely=.65)  # Исключения

        self.Rpt_Label1.place(relx=.01, rely=.05)  # Отправлять отчеты ?
        self.Rpt_Checkbutton1.place(relx=.8, rely=.05)  # Да/Нет

        self.ReportFrame.place(y=300, height=150, width=490)
        self.Rpt_Label2.place(relx=.01, rely=.35)  # Адрес отправки отчетов:
        self.Rpt_Entry1.place(relx=.35, rely=.35)  # Ввод адреса отправки отчетов
        self.Rpt_Label3.place(relx=.01, rely=.50) # Пароль:
        self.Rpt_Entry2.place(relx=.35, rely=.50) # Ввод пароля:
        self.Rpt_Label4.place(relx=.01, rely=.75)  # Частота отправки
        self.Rpt_Spinbox1.place(relx=.35, rely=.75, width=60)  # Количество
        self.Rpt_OptionMenu1.place(relx=.52, rely=.72)  # Единицы измерения
        self.Rpt_Button1.place(relx=.72, rely=.74) # Получатели

        self.Buttons.place(y=450, height=50, width=490)
        self.Button1.place(relx=.62, rely=.2) # Кнопка "Готово"
        self.Button2.place(relx=.82, rely=.2) # Кнопка "Отмена"

        self.Root.mainloop()

    @staticmethod
    def __change_state(state: BooleanVar, *args: Widget) -> None:
        for i in args:
            i.configure(state=('disabled', 'normal')[state.get()])

    def save_conf(self) -> None:
        size_units = {v: k for k, v in self.size_units.items()}
        time_units = {v: k for k, v in self.time_units.items()}

        def wrap_list(a: 'list[str]') -> str:
            return '[' + ', '.join(f"r'{i}'" for i in a) + ']'

        def wrap_cls(_unit: Variable, amount: Variable) -> str:
            unit = _unit.get()
            if unit in size_units:
                return size_units[unit].__name__ + f'({amount.get()})'
            elif unit in time_units:
                return time_units[unit].__name__ + f'({amount.get()})'
            else:
                raise NotImplementedError

        with open(CONF_PATH, 'w') as f:
            f.write(
                f"""from libunits import *

CHECK_FOR_UPDATES = {int(self.upd_enabled.get())}  # Check for updates
UPDATE_FREQ = {wrap_cls(self.upd_unit, self.units_amount1)}  # Check interval
MAX_FILE_SIZE = {wrap_cls(self.size_unit, self.maxfsize)}  # Max file size

# Antivirus database sources
AV_SOURCES = {wrap_list(AV_SOURCES)}

# Antivirus database path
DB_PATH = r'{DB_PATH}'

# On threat:
# 0 - quarantine
# 1 - remove
REMOVE_THREATS = {int(self.quar.get())}

# Directories to scan
SCAN_TARGETS = {wrap_list(SCAN_TARGETS)}

# Exclude from scanning
SCAN_EXCLUDE = {wrap_list(SCAN_EXCLUDE)}

# quarantine location
QUARANTINE_PATH = r'{self.quar_path.get() or QUARANTINE_PATH}'

# Send scan reports
SEND_SCAN_REPORTS = {int(self.rpt_enabled.get())}

# Scan reports frequency
SEND_FREQ = {wrap_cls(self.rpt_unit, self.units_amount2)}

# Send from this email
SEND_FROM = r'{self.email.get()}'

# Sender email password
SEND_PASSWD = r'{self.passwd.get()}'

# Send to these emails
SEND_TO = {wrap_list(SEND_TO)}
""")
        self.Root.destroy()