def make_widgets(self):
        tkd.Label(self.root, text='This is a test application').pack()

        # Create a test row
        lf1 = tkd.LabelFrame(self.root)
        lf1.pack(expand=True, fill=tk.X)
        svar = tk.IntVar(value=0)

        tkd.Label(lf1, text='Option 1').pack(side=tk.LEFT)
        tkd.Radiobutton(lf1,
                        text='Off',
                        indicatoron=False,
                        value=0,
                        variable=svar).pack(side=tk.RIGHT)
        tkd.Radiobutton(lf1,
                        text='On',
                        indicatoron=False,
                        value=1,
                        variable=svar).pack(side=tk.RIGHT)

        # Create choice to change theme
        lf2 = tkd.LabelFrame(self.root)
        lf2.pack(expand=True, fill=tk.X)

        tkd.Label(lf2, text='Active theme').pack(side=tk.LEFT)
        theme_choices = ttk.Combobox(lf2,
                                     textvariable=self.theme_var,
                                     state='readonly',
                                     values=themes)
        theme_choices.bind("<FocusOut>",
                           lambda e: theme_choices.selection_clear())
        theme_choices.bind("<<ComboboxSelected>>",
                           lambda e: self._change_theme())
        theme_choices.config(width=11)
        theme_choices.pack(side=tk.RIGHT, fill=tk.X, padx=2)
Exemplo n.º 2
0
    def _extra_info_label(self, text, var):
        frame = tkd.Frame(self, height=12, width=238)
        frame.propagate(False)
        frame.pack(expand=True, fill=tk.X)

        tkd.Label(frame, text='%s:' % text, font='helvetica 8', anchor=tk.W, justify=tk.LEFT).pack(side=tk.LEFT)
        tkd.Label(frame, textvariable=var, font='helvetica 8 bold', anchor=tk.W, justify=tk.LEFT).pack(side=tk.LEFT)
Exemplo n.º 3
0
    def __init__(self, main_frame, timer_frame, drop_frame, parent=None, **kw):
        tkd.Frame.__init__(self, parent, kw)
        self.main_frame = main_frame
        self.modifier_options = system_hotkey.modifier_options
        self.character_options = system_hotkey.character_options
        self.hk = system_hotkey.SystemHotkey()

        lf = tkd.Frame(self, height=20, width=179)
        lf.pack(expand=True, fill=tk.BOTH)
        lf.propagate(False)
        tkd.Label(lf, text='Action', font='Helvetica 11 bold',
                  justify=tk.LEFT).pack(side=tk.LEFT)
        tkd.Label(lf,
                  text='Key          ',
                  font='Helvetica 11 bold',
                  justify=tk.LEFT,
                  width=9).pack(side=tk.RIGHT)
        tkd.Label(lf,
                  text=' Modifier',
                  font='Helvetica 11 bold',
                  justify=tk.LEFT,
                  width=7).pack(side=tk.RIGHT)

        self.add_hotkey(label_name='Start new run',
                        keys=other_utils.safe_eval(
                            main_frame.cfg['KEYBINDS']['start_key']),
                        func=timer_frame.stop_start)
        self.add_hotkey(label_name='End run',
                        keys=other_utils.safe_eval(
                            main_frame.cfg['KEYBINDS']['end_key']),
                        func=timer_frame.stop)
        self.add_hotkey(label_name='Delete prev',
                        keys=other_utils.safe_eval(
                            main_frame.cfg['KEYBINDS']['delete_prev_key']),
                        func=timer_frame.delete_prev)
        self.add_hotkey(label_name='Pause',
                        keys=other_utils.safe_eval(
                            main_frame.cfg['KEYBINDS']['pause_key']),
                        func=timer_frame.pause)
        self.add_hotkey(label_name='Add drop',
                        keys=other_utils.safe_eval(
                            main_frame.cfg['KEYBINDS']['drop_key']),
                        func=drop_frame.add_drop)
        self.add_hotkey(label_name='Reset lap',
                        keys=other_utils.safe_eval(
                            main_frame.cfg['KEYBINDS']['reset_key']),
                        func=timer_frame.reset_lap)
        self.add_hotkey(label_name='Make unclickable',
                        keys=other_utils.safe_eval(
                            main_frame.cfg['KEYBINDS']['make_unclickable']),
                        func=main_frame.set_clickthrough)
Exemplo n.º 4
0
    def create_row(svar, label_name, lf):
        fr = tkd.Frame(lf, height=22, width=236)
        fr.propagate(False)
        fr.pack(expand=False, fill=tk.X)

        tkd.Label(fr,
                  text='%s:' % label_name,
                  font='helvetica 10',
                  anchor=tk.W,
                  justify=tk.LEFT).pack(side=tk.LEFT)
        tkd.Label(fr,
                  textvariable=svar,
                  font='helvetica 12 bold',
                  anchor=tk.E,
                  justify=tk.RIGHT).pack(side=tk.RIGHT)
Exemplo n.º 5
0
    def __init__(self, main_frame, **kw):
        tkd.Toplevel.__init__(self, **kw)
        self.main_frame = main_frame

        self.title('Archive Browser')
        self.wm_attributes('-topmost', self.main_frame.always_on_top)

        disp_coords = tk_utils.get_displaced_geom(self.main_frame.root, 790,
                                                  500)
        self.geometry(disp_coords)
        self.focus_get()

        self.iconbitmap(media_path + 'icon.ico')
        self.minsize(790, 500)

        tkd.Label(self, text='Archive browser', font='Helvetica 14').pack()

        self.tabcontrol = ttk.Notebook(self)
        self.tabcontrol.pack(expand=True, fill=tk.BOTH)

        collected_data = self.collect_data()

        self.statistics(**collected_data)
        self.run_table(laps=collected_data['laps'])
        self.drop_table(drops=collected_data['drops'])

        self.main_frame.theme.update_colors()
Exemplo n.º 6
0
    def add_flag(self, flag_name, comment=None, pack=True, config_section='OPTIONS'):
        lf = tkd.LabelFrame(self, height=LAB_HEIGHT, width=LAB_WIDTH)
        lf.propagate(False)
        if pack:
            lf.pack(expand=False, fill=tk.X)

        lab = tkd.Label(lf, text=flag_name)
        lab.pack(side=tk.LEFT)
        if comment is not None:
            tkd.create_tooltip(lab, comment)

        flag_attr = flag_name.lower().replace(' ', '_').replace('-', '_')
        setattr(self, flag_attr, tk.StringVar(lf))
        sv = getattr(self, flag_attr)
        off_button = tkd.Radiobutton(lf, text='Off', variable=sv, indicatoron=False, value=False, width=4, padx=4)
        on_button = tkd.Radiobutton(lf, text='On', variable=sv, indicatoron=False, value=True, width=4, padx=3)

        if other_utils.safe_eval(self.main_frame.cfg[config_section][flag_attr]):
            on_button.invoke()
            setattr(self, flag_attr + '_invoked', True)
        else:
            off_button.invoke()
            setattr(self, flag_attr + '_invoked', False)

        off_button.config(command=lambda: self.toggle_button(flag_attr))
        on_button.config(command=lambda: self.toggle_button(flag_attr))
        on_button.pack(side=tk.RIGHT)
        off_button.pack(side=tk.RIGHT)
        return lf
Exemplo n.º 7
0
    def add_hotkey(self, label_name, keys, func):
        if keys[0].lower() not in map(lambda x: x.lower(), self.modifier_options) or keys[1].lower() not in map(lambda x: x.lower(), self.character_options):
            messagebox.showerror('Invalid hotkey', 'One or several hotkeys are invalid. Please edit/delete mf_config.ini')
            sys.exit()
        default_modifier, default_key = keys
        action = label_name.replace(' ', '_').lower()
        setattr(self, '_' + action, keys)
        lf = tkd.LabelFrame(self, height=30, width=179)
        lf.propagate(False)
        lf.pack(expand=True, fill=tk.BOTH)

        lab = tkd.Label(lf, text=label_name)
        lab.pack(side=tk.LEFT)

        setattr(self, action + '_e', tk.StringVar())
        key = getattr(self, action + '_e')
        key.set(default_key)
        drop2 = ttk.Combobox(lf, textvariable=key, state='readonly', values=self.character_options)
        drop2.bind("<FocusOut>", lambda e: drop2.selection_clear())
        drop2.config(width=9)
        drop2.pack(side=tk.RIGHT, fill=tk.X, padx=2)

        setattr(self, action + '_m', tk.StringVar())
        mod = getattr(self, action + '_m')
        mod.set(default_modifier)
        drop1 = ttk.Combobox(lf, textvariable=mod, state='readonly', values=self.modifier_options)
        drop1.bind("<FocusOut>", lambda e: drop1.selection_clear())
        drop1.config(width=7)
        drop1.pack(side=tk.RIGHT)

        mod.trace_add('write', lambda name, index, mode: self.re_register(action, getattr(self, '_' + action), func))
        key.trace_add('write', lambda name, index, mode: self.re_register(action, getattr(self, '_' + action), func))
        if default_key.lower() != 'no_bind':
            reg_key = [keys[1].lower()] if keys[0] == '' else list(map(lambda x: x.lower(), keys))
            self.hk.register(reg_key, callback=lambda event: '' if win32gui.FindWindow(None, 'Add drop') else self.main_frame.queue.put(func))
Exemplo n.º 8
0
    def __init__(self, main_fr, parent=None, **kw):
        tkd.Frame.__init__(self, parent, kw)
        top_fr = tkd.Frame(self)
        top_fr.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
        tkd.Label(top_fr, text="MF Run Counter",
                  font=('Segoe UI', 11, 'bold')).pack(pady=[0, 2])

        self.img = tk.PhotoImage(file=media_path + 'about_icon.png')
        tkd.Label(top_fr, image=self.img, borderwidth=0).pack(pady=0)

        btm_fr = tkd.Frame(self)
        btm_fr.pack(side=tk.BOTTOM, fill=tk.X, expand=True, anchor=tk.S)

        tkd.Label(btm_fr,
                  text='New releases & README info',
                  borderwidth=0,
                  highlightthickness=0,
                  justify=tk.LEFT).pack(anchor=tk.W)
        tkd.Hyperlink(btm_fr,
                      hyperlink=release_repo.rstrip('releases'),
                      text="           Github Repository",
                      borderwidth=0,
                      highlightthickness=0,
                      justify=tk.LEFT).pack(anchor=tk.W, pady=[0, 7])

        tkd.Label(btm_fr,
                  text='Created by:',
                  justify=tk.LEFT,
                  borderwidth=0,
                  highlightthickness=0).pack(anchor=tk.W)
        tkd.Label(btm_fr,
                  text='           oskros#1889',
                  font=('Segoe UI', 9, 'bold'),
                  borderwidth=0,
                  highlightthickness=0,
                  justify=tk.LEFT).pack(anchor=tk.W)

        tkd.Label(btm_fr,
                  text='Find me here:',
                  justify=tk.LEFT,
                  borderwidth=0,
                  highlightthickness=0).pack(anchor=tk.W, pady=[7, 0])
        tkd.Hyperlink(btm_fr,
                      hyperlink='https://discord.gg/JhkTF2g',
                      text='           https://discord.gg/JhkTF2g',
                      justify=tk.LEFT,
                      borderwidth=0,
                      highlightthickness=0).pack(anchor=tk.W)

        v_fr = tkd.Frame(btm_fr)
        v_fr.pack(side=tk.BOTTOM, fill=tk.X, expand=True, anchor=tk.S)
        tkd.Label(v_fr, text="v.%s" % version,
                  justify=tk.RIGHT).pack(side=tk.RIGHT, anchor=tk.E)
        tkd.Label(v_fr,
                  text='Downloads: %s' % main_fr.dl_count,
                  justify=tk.LEFT).pack(side=tk.LEFT, anchor=tk.W)
Exemplo n.º 9
0
    def create_row(var_name, lf, default_val='0'):
        fr = tkd.Frame(lf, height=22, width=236)
        fr.propagate(False)
        fr.pack(expand=False, fill=tk.X)

        sv = tk.StringVar(fr, value=default_val)
        tkd.Label(fr,
                  text='%s:' % var_name,
                  font='helvetica 10',
                  anchor=tk.W,
                  justify=tk.LEFT).pack(side=tk.LEFT)
        tkd.Label(fr,
                  textvariable=sv,
                  font='helvetica 12 bold',
                  anchor=tk.E,
                  justify=tk.RIGHT).pack(side=tk.RIGHT)

        return sv
Exemplo n.º 10
0
    def _make_widgets(self):
        tkd.Label(self, text='Drops', font='helvetica 14').pack()
        lf = tkd.Frame(self)
        lf.pack(expand=1, fill=tk.BOTH)
        scrollbar = ttk.Scrollbar(lf, orient=tk.VERTICAL)

        self.m = tkd.Text(lf, height=8, width=23, yscrollcommand=scrollbar.set, font='courier 11', wrap=tk.WORD, state=tk.DISABLED, cursor='', exportselection=1, name='droplist', borderwidth=2)

        self.m.pack(side=tk.LEFT, fill=tk.BOTH, expand=1, pady=(1, 2), padx=1)
        scrollbar.config(command=self.m.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y, pady=(2, 1), padx=0)
Exemplo n.º 11
0
    def add_automode_flag(self):
        lf = tkd.LabelFrame(self, height=LAB_HEIGHT, width=LAB_WIDTH)
        lf.propagate(False)
        lf.pack(expand=False, fill=tk.X)

        lab = tkd.Label(
            lf,
            text='Automode',
            tooltip=
            'Enable automode for monitoring when you enter and exit games')
        lab.pack(side=tk.LEFT)

        self.automode_var = tk.StringVar(lf)
        off_btn = tkd.Radiobutton(lf,
                                  text='Off',
                                  variable=self.automode_var,
                                  indicatoron=False,
                                  value=0,
                                  width=5,
                                  padx=4)
        simple_btn = tkd.Radiobutton(lf,
                                     text='Simple',
                                     variable=self.automode_var,
                                     indicatoron=False,
                                     value=1,
                                     width=5,
                                     padx=3)
        adv_btn = tkd.Radiobutton(lf,
                                  text='Advanced',
                                  variable=self.automode_var,
                                  indicatoron=False,
                                  value=2,
                                  width=7,
                                  padx=3)

        cfg_mode = other_utils.safe_eval(
            self.main_frame.cfg['AUTOMODE']['automode'])
        if cfg_mode == 2:
            adv_btn.invoke()
        elif cfg_mode == 1:
            simple_btn.invoke()
        else:
            off_btn.invoke()

        off_btn.config(command=self.toggle_automode_btn)
        simple_btn.config(command=self.toggle_automode_btn)
        adv_btn.config(command=self.toggle_automode_btn)
        adv_btn.pack(side=tk.RIGHT)
        simple_btn.pack(side=tk.RIGHT)
        off_btn.pack(side=tk.RIGHT)
        return off_btn, simple_btn, adv_btn
Exemplo n.º 12
0
    def _make_widgets(self):
        tkd.Label(self, text='Select active profile', justify=tk.LEFT).pack(anchor=tk.W)

        profile_dropdown_frame = tkd.Frame(self, height=28, width=238, pady=2, padx=2)
        profile_dropdown_frame.propagate(False)
        profile_dropdown_frame.pack()

        self.active_profile.set(self.main_frame.active_profile)
        self.profile_dropdown = tkd.Combobox(profile_dropdown_frame, textvariable=self.active_profile, state='readonly', values=self.main_frame.profiles)
        self.profile_dropdown.bind("<<ComboboxSelected>>", lambda e: self._change_active_profile())
        self.profile_dropdown.bind("<FocusOut>", lambda e: self.profile_dropdown.selection_clear())
        self.profile_dropdown.pack(side=tk.LEFT, expand=True, fill=tk.X)

        tkd.Button(profile_dropdown_frame, text='New...', command=self._add_new_profile).pack(side=tk.LEFT)
        tkd.Button(profile_dropdown_frame, text='Delete', command=self._delete_profile).pack(side=tk.LEFT)

        self.run_type = tk.StringVar(self, value=self.extra_data.get('Run type', ''))
        self.game_mode = tk.StringVar(self, value=self.extra_data.get('Game mode', 'Single Player'))
        self.char_name = tk.StringVar(self, value=self.extra_data.get('Character name', ''))
        self._extra_info_label('Run type', self.run_type)
        # self._extra_info_label('Game mode', self.game_mode)
        self._extra_info_label('Character name', self.char_name)

        tkd.Label(self, text='Select an archived run for this profile', justify=tk.LEFT).pack(anchor=tk.W, pady=(6, 0))
        sel_frame = tkd.Frame(self, height=28, width=238, pady=2, padx=2)
        sel_frame.propagate(False)
        sel_frame.pack()
        self.archive_dropdown = tkd.Combobox(sel_frame, textvariable=self.selected_archive, state='readonly', values=self.available_archive)
        self.archive_dropdown.bind("<<ComboboxSelected>>", lambda e: self.update_descriptive_statistics())
        self.archive_dropdown.bind("<FocusOut>", lambda e: self.archive_dropdown.selection_clear())
        self.archive_dropdown.pack(side=tk.LEFT, expand=True, fill=tk.X)

        tkd.Button(sel_frame, text='Open', command=lambda: archive_browser.ArchiveBrowser(self.main_frame)).pack(side=tk.LEFT)
        tkd.Button(sel_frame, text='Delete', command=self.delete_archived_session).pack(side=tk.LEFT)

        self.descr = tkd.Listbox(self, selectmode=tk.EXTENDED, height=8, activestyle='none', font=('courier', 8))
        self.descr.bind('<FocusOut>', lambda e: self.descr.selection_clear(0, tk.END))
        self.descr.pack(side=tk.BOTTOM, fill=tk.X, expand=1, anchor=tk.S)
Exemplo n.º 13
0
    def add_num_entry(self, flag_name, comment=None):
        lf = tkd.LabelFrame(self, height=LAB_HEIGHT, width=LAB_WIDTH)
        lf.propagate(False)
        lf.pack(expand=False, fill=tk.X)

        lab = tkd.Label(lf, text=flag_name)
        lab.pack(side=tk.LEFT)
        if comment is not None:
            tkd.create_tooltip(lab, comment)

        flag_attr = flag_name.lower().replace(' ', '_').replace('-', '_').replace('(', '').replace(')', '')
        setattr(self, flag_attr + '_sv', tk.StringVar())
        sv = getattr(self, flag_attr + '_sv')
        sv.set(other_utils.safe_eval(self.main_frame.cfg['OPTIONS'][flag_attr]))
        tkd.RestrictedEntry(lf, textvariable=sv, num_only=True, width=13).pack(side=tk.RIGHT, padx=3)
        sv.trace_add('write', lambda name, index, mode: setattr(self.main_frame, flag_attr, float('0' + sv.get())))
Exemplo n.º 14
0
    def _make_widgets(self):
        flt = tkd.Frame(self)
        flt.pack(fill=tk.X, expand=tk.NO)
        self.c1, self.circ_id = tk_utils.add_circle(flt, 14, 'red')
        self.c1.grid(row=0, column=0, padx=3, pady=3)
        tkd.Label(flt, textvariable=self.sessionstr,
                  font='arial 10').grid(row=0, column=1, sticky=tk.N, padx=20)
        self._set_time(self.session_time, for_session=True)

        tkd.Label(self, textvariable=self.timestr,
                  font='arial 20').pack(fill=tk.X, expand=False, pady=4)
        self._set_time(0, for_session=False)

        l2f = tkd.Frame(self)
        l2f.pack(pady=2)
        tkd.Label(l2f, text='---- Run count:',
                  font='arial 12').pack(side=tk.LEFT)
        tkd.RunLabel(l2f, textvariable=self.no_of_laps,
                     font='arial 17').pack(side=tk.LEFT)
        tkd.RunLabel(l2f, textvariable=self.total_laps,
                     font='helvetica 12').pack(side=tk.LEFT)
        tkd.Label(l2f, text='----', font='arial 12').pack(side=tk.LEFT)
        self._set_laps(add_lap=False)

        tkd.Label(self, textvariable=self.min_lap,
                  font='arial 11').pack(fill=tk.X,
                                        expand=False,
                                        pady=1,
                                        padx=2)
        self._set_fastest()

        tkd.Label(self, textvariable=self.avg_lap,
                  font='arial 11').pack(fill=tk.X,
                                        expand=False,
                                        pady=1,
                                        padx=2)
        self._set_average()

        lf0 = tkd.Frame(self)
        lf0.pack()
        scrollbar = ttk.Scrollbar(lf0, orient=tk.VERTICAL)
        self.m = tkd.Listbox(lf0,
                             selectmode=tk.BROWSE,
                             height=5,
                             yscrollcommand=scrollbar.set,
                             font='courier 12',
                             activestyle=tk.NONE)
        self.m.bind('<FocusOut>', lambda e: self.m.selection_clear(0, tk.END))
        self.m.bind(
            '<MouseWheel>',
            lambda e: self.m.yview_scroll(int(-1 * (e.delta / 120)), "units"))
        self.m.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, pady=5)
        scrollbar.config(command=self.m.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y, pady=5, padx=1)
Exemplo n.º 15
0
        def rec_checkbox_add(master, frame, dct, rows=4, depth=None):
            # Default arguments cannot be mutable
            if depth is None:
                depth = []

            # Init count to determine number of rows before adding a new column
            cnt = 0
            for k, v in dct.items():
                # Bottom of tree nodes are either empty dicts or has the 'wasFound' key
                if v == dict() or 'wasFound' in v:
                    found = v.get('wasFound', False)

                    # Due to weird handling of rainbow facets in herokuapp, we utilise the saved stack of keys (in the
                    # 'depth' variable) to determine the appropriate item name
                    if k in ['Cold', 'Fire', 'Light', 'Poison']:
                        i_name = 'Rainbow Facet (%s %s)' % (k, depth[-1].title())
                        var_name = 'grail_item_' + i_name.replace("'", "1").replace(' ', '_')
                    else:
                        # Replace characters that cannot be used in variable names
                        var_name = 'grail_item_' + k.replace("'", "1").replace(' ', '_')
                        i_name = k

                    # Define an IntVar as a class attribute that we can later call when needed. Then build the
                    # checkbutton, noting that the lambda needs to be passed a default argument, otherwise it will
                    # overwrite its own definition at each iteration
                    setattr(master, var_name, tk.IntVar(value=found))
                    tkd.Checkbutton(frame, text=k, variable=getattr(master, var_name), command=lambda _k=i_name: master.update_grail_from_name(_k)).pack(expand=True, anchor=tk.W)
                # We are not at the bottom of tree node, thus we will create a child node and call recursively
                else:
                    # When at top node, determine if a new column should be made or not, based on number of rows
                    if len(depth) == 0:
                        if cnt % rows == 0:
                            topframe = tkd.Frame(frame)
                            topframe.pack(side=tk.LEFT, expand=True, anchor=tk.NW)
                        new_frame = tkd.Frame(topframe)
                        new_frame.pack(side=tk.TOP, expand=True, anchor=tk.NW, fill=tk.Y, pady=[0, 30])
                        cnt += 1
                    else:
                        new_frame = tkd.Frame(frame)
                        new_frame.pack(side=tk.LEFT, expand=True, anchor=tk.N)

                    # .title() function bugs out with apostrophes. Handle the specific issues hardcoded here
                    # Also, there is a spelling mistake in herokuapp that we fix: Hsaru's -> Hsarus'
                    txt = k.title().replace("'S", "'s").replace("'A", "'a").replace("Hsaru's", "Hsarus'")
                    tkd.Label(new_frame, text=txt, font='Arial 15 bold').pack(expand=True, anchor=tk.N)
                    rec_checkbox_add(master, new_frame, v, rows, depth + [k])
Exemplo n.º 16
0
    def add_theme_choice(self, comment=None):
        lf = tkd.LabelFrame(self, height=LAB_HEIGHT, width=LAB_WIDTH)
        lf.propagate(False)
        lf.pack(expand=False, fill=tk.X)

        lab = tkd.Label(lf, text='Active theme')
        lab.pack(side=tk.LEFT)
        if comment is not None:
            tkd.create_tooltip(lab, comment)

        self.active_theme = tk.StringVar()
        self.active_theme.set(self.main_frame.active_theme)
        theme_choices = tkd.Combobox(lf, textvariable=self.active_theme, state='readonly', values=available_themes)
        theme_choices.bind("<FocusOut>", lambda e: theme_choices.selection_clear())
        theme_choices.bind("<<ComboboxSelected>>", lambda e: self._change_theme())
        theme_choices.config(width=11)
        theme_choices.pack(side=tk.RIGHT, fill=tk.X, padx=2)
Exemplo n.º 17
0
    def make_widgets(self):
        tkd.Label(self, text='Advanced stats tracker',
                  font='Helvetica 15').pack()

        lf0 = tkd.LabelFrame(self)
        lf0.pack(expand=False, fill=tk.X, padx=1)
        self.create_row(self.mf_sv, label_name='MF', lf=lf0)
        self.create_row(self.players_x_sv, label_name='Players X', lf=lf0)

        lf1 = tkd.LabelFrame(self)
        lf1.pack(expand=False, fill=tk.X, padx=1, pady=[8, 0])
        self.create_row(self.unique_kills_sv,
                        label_name='Unique kills',
                        lf=lf1)
        self.create_row(self.champ_kills_sv,
                        label_name='Champion kills',
                        lf=lf1)

        self.xp_lf1 = tkd.LabelFrame(self)
        self.xp_lf1.pack(expand=False, fill=tk.X, padx=1, pady=8)
        self.create_row(self.exp_perc_sv, label_name='Exp %', lf=self.xp_lf1)
        self.create_row(self.exp_session_sv,
                        label_name='Exp (session)',
                        lf=self.xp_lf1)
        self.create_row(self.exp_run_sv,
                        label_name='Exp (run)',
                        lf=self.xp_lf1)
        self.create_row(self.exp_hour_sv,
                        label_name='Exp / hour',
                        lf=self.xp_lf1)

        self.xp_lf2 = tkd.LabelFrame(self)
        self.xp_lf2.pack(expand=False, fill=tk.X, padx=1)
        self.create_row(self.exp_level_sv,
                        label_name='Exp to level',
                        lf=self.xp_lf2)
        self.create_row(self.hours_level_sv,
                        label_name='Time to level',
                        lf=self.xp_lf2)
        self.create_row(self.runs_level_sv,
                        label_name='Runs to level',
                        lf=self.xp_lf2)
Exemplo n.º 18
0
    def __init__(self, main_frame, **kw):
        tkd.Frame.__init__(self, main_frame.root, **kw)
        self.main_frame = main_frame

        self.session_char_xp_start = 0
        self.session_char_xp = 0
        self.session_char_time_start = time.time()
        self.session_char_xp_missing = 0
        self.avg_run = 0
        self.session_xp_runs = set()

        # ==================================== WIDGETS ==================================== #
        tkd.Label(self, text='Advanced stats tracker',
                  font='Helvetica 15').pack()

        lf1 = tkd.LabelFrame(self)
        lf1.pack(expand=False, fill=tk.X, padx=1)
        self.name_sv = self.create_row('Name', lf=lf1, default_val='-----')
        self.level_sv = self.create_row('Level', lf=lf1, default_val='-----')
        self.mf_sv = self.create_row('MF', lf=lf1, default_val='-----')
        self.players_x_sv = self.create_row('Players X',
                                            lf=lf1,
                                            default_val='-----')

        lf2 = tkd.LabelFrame(self)
        lf2.pack(expand=False, fill=tk.X, padx=1, pady=8)
        self.exp_sv = self.create_row('Exp %', lf=lf2)
        self.exp_session_sv = self.create_row('Exp (session)', lf=lf2)
        self.exp_run_sv = self.create_row('Exp (run)', lf=lf2)
        self.exp_hour_sv = self.create_row('Exp / hour', lf=lf2)

        lf3 = tkd.LabelFrame(self)
        lf3.pack(expand=False, fill=tk.X, padx=1)
        self.exp_level_sv = self.create_row('Exp to level', lf=lf3)
        self.hours_level_sv = self.create_row('Time to level', lf=lf3)
        self.runs_level_sv = self.create_row('Runs to level', lf=lf3)
        # ==================================== WIDGETS ==================================== #

        color_themes.Theme(main_frame.active_theme).update_colors()
Exemplo n.º 19
0
    def open_archive_browser(self):
        chosen = self.archive_dropdown.get()
        if chosen == '':
            # If nothing is selected the function returns
            return

        # We build the new tkinter window to be opened
        new_win = tkd.Toplevel()
        new_win.title('Archive browser')
        new_win.wm_attributes('-topmost', 1)

        disp_coords = tk_utils.get_displaced_geom(self.main_frame.root, 400, 460)
        new_win.geometry(disp_coords)
        new_win.focus_get()
        new_win.iconbitmap(os.path.join(getattr(sys, '_MEIPASS', os.path.abspath('.')), media_path + 'icon.ico'))
        new_win.minsize(400, 460)
        title = tkd.Label(new_win, text='Archive browser', font='Helvetica 14')

        # Handle how loading of session data should be treated in the 3 different cases
        if chosen == 'Active session':
            # Load directly from timer module
            session_time = self.main_frame.timer_tab.session_time
            laps = self.main_frame.timer_tab.laps
            drops = self.main_frame.drops_tab.drops
        elif chosen == 'Profile history':
            # Load everything from profile .json, and append data from timer module
            active = self.main_frame.load_state_file()
            laps = []
            session_time = 0
            drops = dict()
            # Concatenate information from each available session
            for key in [x for x in active.keys() if x not in ['active_state', 'extra_data']]:
                session_drops = active[key].get('drops', dict())
                for run_no, run_drop in session_drops.items():
                    drops[str(int(run_no)+len(laps))] = run_drop
                laps.extend(active[key].get('laps', []))
                session_time += active[key].get('session_time', 0)

            # Append data for active session from timer module
            for run_no, run_drop in self.main_frame.drops_tab.drops.items():
                drops[str(int(run_no) + len(laps))] = run_drop
            laps.extend(self.main_frame.timer_tab.laps)
            session_time += self.main_frame.timer_tab.session_time
        else:
            # Load selected session data from profile .json
            active = self.main_frame.load_state_file()
            chosen_archive = active.get(chosen, dict())
            session_time = chosen_archive.get('session_time', 0)
            laps = chosen_archive.get('laps', [])
            drops = chosen_archive.get('drops', dict())

        # Ensure no division by zero errors by defaulting to displaying 0
        avg_lap = sum(laps) / len(laps) if laps else 0
        pct = sum(laps) * 100 / session_time if session_time > 0 else 0

        # Configure the list frame with scrollbars which displays the archive of the chosen session
        list_win = tkd.Frame(new_win)
        list_frame = tkd.Frame(list_win)
        vscroll = ttk.Scrollbar(list_frame, orient=tk.VERTICAL)
        hscroll = ttk.Scrollbar(list_win, orient=tk.HORIZONTAL)
        txt_list = tkd.Text(list_frame, yscrollcommand=vscroll.set, xscrollcommand=hscroll.set, font='courier 10', wrap=tk.WORD, state=tk.NORMAL, cursor='', exportselection=1, name='archivebrowser')
        # txt_list.bind('<FocusOut>', lambda e: txt_list.tag_remove(tk.SEL, "1.0", tk.END))  # Lose selection when shifting focus
        vscroll.pack(side=tk.RIGHT, fill=tk.Y)
        txt_list.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
        txt_list.tag_configure("HEADER", font=tkFont(family='courier', size=12, weight='bold', underline=True))
        hscroll.config(command=txt_list.xview)
        vscroll.config(command=txt_list.yview)

        # Build header for output file with information and descriptive statistics
        output = [['Statistics'],
                  ['Character name: ', self.extra_data.get('Character name', '')],
                  ['Run type:       ', self.extra_data.get('Run type', '')],
                  ['Game mode:      ', self.extra_data.get('Game mode', 'Single Player')],
                  [''],
                  ['Total session time:   ', utils.other_utils.build_time_str(session_time)],
                  ['Total run time:       ', utils.other_utils.build_time_str(sum(laps))],
                  ['Average run time:     ', utils.other_utils.build_time_str(avg_lap)],
                  ['Fastest run time:     ', utils.other_utils.build_time_str(min(laps, default=0))],
                  ['Number of runs:       ', str(len(laps))],
                  ['Time spent in runs:   ', str(round(pct, 2)) + '%'],
                  ['']]

        # Backwards compatibility with old drop format
        for k, v in drops.items():
            for i in range(len(v)):
                if not isinstance(v[i], dict):
                    drops[k][i] = {'item_name': None, 'input': v[i], 'extra': ''}

        # List all drops collected
        if drops:
            if any(drop for drop in drops.values()):
                output.append(['Collected drops'])
            for run_no, drop in drops.items():
                if drop:
                    str_n = ' ' * max(len(str(len(laps))) - len(str(run_no)), 0) + str(run_no)
                    output.append(['Run ' + str_n, '', *[x['input'] for x in drop]])
            output.append([''])

        if laps:
            output.append(['Run times'])

        # Loop through all runs and add run times and drops for each run
        for n, lap in enumerate(laps, 1):
            str_n = ' ' * max(len(str(len(laps))) - len(str(n)), 0) + str(n)
            droplst = drops.get(str(n), [])
            tmp = ['Run ' + str_n + ': ', utils.other_utils.build_time_str(lap)]
            if droplst:
                tmp += [d['input'] for d in droplst]
            output.append(tmp)

        # Format string list to be shown in the archive browser
        for i, op in enumerate(output, 1):
            tmpstr = ''.join(op[:2])
            if len(op) > 2:
                tmpstr += ' --- ' + ', '.join(op[2:])
            if txt_list.get('1.0', tk.END) != '\n':
                tmpstr = '\n' + tmpstr
            txt_list.insert(tk.END, tmpstr)
            if op[0] in ['Statistics', 'Collected drops', 'Run times']:
                txt_list.tag_add("HEADER", str(i) + ".0", str(i) + ".0 lineend")

        # Add bold tags
        # txt_list.tag_add("BOLD", "1.0", "1.15")
        # txt_list.tag_add("BOLD", "2.0", "2.9")
        # txt_list.tag_add("BOLD", "3.0", "3.10")
        # txt_list.tag_add("BOLD", "5.0", "5.19")
        # txt_list.tag_add("BOLD", "6.0", "6.15")
        # txt_list.tag_add("BOLD", "7.0", "7.17")
        # txt_list.tag_add("BOLD", "8.0", "8.17")
        # txt_list.tag_add("BOLD", "9.0", "9.15")
        # txt_list.tag_add("BOLD", "10.0", "10.19")
        # txt_list.tag_add("BOLD", "1.16", "1.0 lineend")
        # txt_list.tag_add("BOLD", "2.16", "2.0 lineend")
        # txt_list.tag_add("BOLD", "3.16", "3.0 lineend")
        # txt_list.tag_add("BOLD", "5.20", "5.0 lineend")
        # txt_list.tag_add("BOLD", "6.20", "6.0 lineend")
        # txt_list.tag_add("BOLD", "7.20", "7.0 lineend")
        # txt_list.tag_add("BOLD", "8.20", "8.0 lineend")
        # txt_list.tag_add("BOLD", "9.20", "9.0 lineend")
        # txt_list.tag_add("BOLD", "10.20", "10.0 lineend")

        txt_list.tag_add("HEADER", "12.0", "12.0 lineend")

        txt_list.config(state=tk.DISABLED)

        button_frame = tkd.Frame(new_win)
        tkd.Button(button_frame, text='Copy to clipboard', command=lambda: self.copy_to_clipboard(new_win, txt_list.get(1.0, tk.END))).pack(side=tk.LEFT, fill=tk.X)
        tkd.Button(button_frame, text='Save as .txt', command=lambda: self.save_to_txt(txt_list.get(1.0, tk.END))).pack(side=tk.LEFT, fill=tk.X)
        tkd.Button(button_frame, text='Save as .csv', command=lambda: self.save_to_csv(output)).pack(side=tk.LEFT, fill=tk.X)

        # Packs all the buttons and UI in the archive browser. Packing order is very important:
        # TOP: Title first (furthest up), then list frame
        # BOTTOM: Buttons first (furthest down) and then horizontal scrollbar
        title.pack(side=tk.TOP)
        list_win.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
        list_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
        hscroll.pack(side=tk.BOTTOM, fill=tk.X)
        button_frame.pack(side=tk.BOTTOM)


        theme = Theme(self.main_frame.active_theme)
        theme.update_colors()
Exemplo n.º 20
0
    def make_widgets(self):
        self.gamemode_frame = tkd.LabelFrame(self,
                                             height=LAB_HEIGHT,
                                             width=LAB_WIDTH)
        self.gamemode_frame.propagate(False)

        self.gamemode_lab = tkd.Label(
            self.gamemode_frame,
            text='Game mode',
            tooltip=
            'If Multiplayer is selected, the .map file is used to check for updates.\n'
            'Thus, new runs begin every time you enter a new game (since your local .map files will be updated by this)\n\n'
            'If Single Player is selected the .d2s file is used to check for updates.\n'
            'Thus, a new run begins every time you leave a game (since your .d2s files are saved upon exit)'
        )

        self.game_mode = tk.StringVar()
        self.game_mode.set(self.main_frame.profile_tab.game_mode.get())
        self.gamemode_cb = ttk.Combobox(
            self.gamemode_frame,
            textvariable=self.game_mode,
            state='readonly',
            values=['Single Player', 'Multiplayer'])
        self.gamemode_cb.bind("<FocusOut>",
                              lambda e: self.gamemode_cb.selection_clear())
        self.gamemode_cb.config(width=11)
        self.game_mode.trace_add(
            'write', lambda name, index, mode: self.update_game_mode())

        self.charname_frame = tkd.LabelFrame(self,
                                             height=LAB_HEIGHT,
                                             width=LAB_WIDTH)
        self.charname_frame.propagate(False)

        self.char_var = tk.StringVar()
        self.char_var.set(self.main_frame.profile_tab.char_name.get())
        self.charname_text_lab = tkd.Label(
            self.charname_frame,
            text='Character name',
            tooltip='Your character name is inferred from the active profile.\n'
            'Make sure the character name in your profile is matching your in-game character name'
        )
        self.charname_val_lab = tkd.Label(self.charname_frame,
                                          textvariable=self.char_var)

        self.sp_path_lab = tkd.Label(self, text='Game path (Single Player)')
        self.SP_game_path = tk.StringVar()
        self.SP_game_path.set(self.main_frame.SP_game_path)
        self.sp_path_entry = tkd.Entry(self, textvariable=self.SP_game_path)

        self.sp_path_frame = tkd.Frame(self)
        self.sp_path_get = tkd.Button(
            self.sp_path_frame,
            text='Get',
            command=lambda: self.get_game_path(is_sp=True),
            tooltip=
            'The app tries to automatically find your game path for single player\n'
            'If nothing is returned you have to type it in manually')
        self.sp_path_apply = tkd.Button(
            self.sp_path_frame,
            text='Apply',
            command=self.apply_path_ch,
            tooltip='Apply the current specified path')

        self.mp_path_lab = tkd.Label(self, text='Game path (Multiplayer)')
        self.MP_game_path = tk.StringVar()
        self.MP_game_path.set(self.main_frame.MP_game_path)
        self.mp_path_entry = tkd.Entry(self, textvariable=self.MP_game_path)
        self.mp_path_frame = tkd.Frame(self)

        self.mp_path_get = tkd.Button(
            self.mp_path_frame,
            text='Get',
            command=lambda: self.get_game_path(is_sp=False),
            tooltip=
            'The app tries to automatically find your game path for multiplayer\n'
            'If nothing is returned you have to type it in manually')
        self.mp_path_apply = tkd.Button(
            self.mp_path_frame,
            text='Apply',
            command=self.apply_path_ch,
            tooltip='Apply the current specified path')

        # Stuff for advanced mode
        self.advanced_mode_stop = self.add_flag(
            flag_name='Stop when leaving',
            comment=
            'On: Stops the current run when you exit to menu.\nOff: The run counter will continue ticking until you enter a new game',
            pack=False,
            config_section='AUTOMODE')
        self.advanced_pause_on_esc_menu = self.add_flag(
            flag_name='Pause on ESC menu',
            comment=
            'When activated, the counter will be paused when ESC menu\nis open inside d2 (not working for 1.14b and 1.14c)',
            pack=False,
            config_section='AUTOMODE')
        self.advanced_automode_warning = tkd.Label(
            self,
            text='"Advanced automode" is highly \n'
            'discouraged when playing\n'
            'multiplayer, as it might result\n'
            'in a ban.\n'
            'Explanation: Advanced automode\n'
            'utilizes "memory reading" of the\n'
            'D2 process to discover information\n'
            'about the current game state,\n'
            'and this could be deemed cheating.',
            justify=tk.LEFT)

        self.toggle_automode_btn(first=True)
Exemplo n.º 21
0
    def __init__(self):
        # Check if application is already open
        self.title = 'MF run counter'

        # Create error logger
        lh = logging.FileHandler(filename='mf_timer.log', mode='w', delay=True)
        logging.basicConfig(handlers=[lh],
                            format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
                            datefmt='%H:%M:%S',
                            level=logging.WARNING)

        # Check OS
        self.os_platform = platform.system()
        self.os_release = platform.release()
        if not self.os_platform == 'Windows':
            raise SystemError("MF Run Counter only supports windows")

        # Create root
        self.root = tkd.Tk()

        # Ensure errors are handled with an exception pop-up if encountered
        self.root.report_callback_exception = self.report_callback_exception

        # Build/load config file
        self.cfg = self.load_config_file()
        if hasattr(logging, self.cfg['DEFAULT']['logging_level']):
            logging.getLogger().setLevel(getattr(logging, self.cfg['DEFAULT']['logging_level']))
        self.SP_game_path = self.cfg['DEFAULT']['SP_game_path']
        self.MP_game_path = self.cfg['DEFAULT']['MP_game_path']
        self.herokuapp_username = self.cfg['DEFAULT']['herokuapp_username']
        self.herokuapp_password = base64.b64decode(self.cfg['DEFAULT']['herokuapp_password']).decode('utf-8')
        self.webproxies = other_utils.safe_eval(self.cfg['DEFAULT']['webproxies'])
        self.automode = other_utils.safe_eval(self.cfg['AUTOMODE']['automode'])
        self.end_run_in_menu = other_utils.safe_eval(self.cfg['AUTOMODE']['end_run_in_menu'])
        self.pause_on_esc_menu = other_utils.safe_eval(self.cfg['AUTOMODE']['pause_on_esc_menu'])
        self.always_on_top = other_utils.safe_eval(self.cfg['OPTIONS']['always_on_top'])
        self.tab_switch_keys_global = other_utils.safe_eval(self.cfg['OPTIONS']['tab_switch_keys_global'])
        self.check_for_new_version = other_utils.safe_eval(self.cfg['OPTIONS']['check_for_new_version'])
        self.enable_sound_effects = other_utils.safe_eval(self.cfg['OPTIONS']['enable_sound_effects'])
        self.start_run_delay_seconds = other_utils.safe_eval(self.cfg['OPTIONS']['start_run_delay_seconds'])
        self.show_drops_tab_below = other_utils.safe_eval(self.cfg['OPTIONS']['show_drops_tab_below'])
        self.active_theme = self.cfg['OPTIONS']['active_theme'].lower()
        self.auto_upload_herokuapp = other_utils.safe_eval(self.cfg['OPTIONS']['auto_upload_herokuapp'])
        self.auto_archive_hours = other_utils.safe_eval(self.cfg['OPTIONS']['auto_archive_hours'])
        self.autocompletion_unids = other_utils.safe_eval(self.cfg['OPTIONS']['autocompletion_unids'])
        self.add_to_last_run = other_utils.safe_eval(self.cfg['OPTIONS']['add_to_last_run'])
        self.disable_scaling = other_utils.safe_eval(self.cfg['OPTIONS']['disable_dpi_scaling'])

        # UI config
        self.show_buttons = other_utils.safe_eval(self.cfg['UI']['show_buttons'])
        self.show_drops_section = other_utils.safe_eval(self.cfg['UI']['show_drops_section'])
        self.show_advanced_tracker = other_utils.safe_eval(self.cfg['UI']['show_advanced_tracker'])
        self.show_xp_tracker = other_utils.safe_eval(self.cfg['UI']['show_xp_tracker'])

        # Initiate variables for memory reading
        self.is_user_admin = reader_utils.is_user_admin()
        self.advanced_error_thrown = False
        self.d2_reader = None

        # Load theme
        if self.active_theme not in available_themes:
            self.active_theme = 'vista'
        self.theme = Theme(used_theme=self.active_theme)

        # Create hotkey queue and initiate process for monitoring the queue
        self.queue = queue.Queue(maxsize=1)
        self.process_queue()

        # Check for version update
        if self.check_for_new_version:
            self.dl_count = github_releases.check_newest_version(release_repo)
        else:
            self.dl_count = ''

        # Load profile info
        self.make_profile_folder()
        self.profiles = [x[:-5] for x in os.listdir('Profiles') if x.endswith('.json') and not x == 'grail.json']
        self.active_profile = self.cfg['DEFAULT']['active_profile']
        if len(self.profiles) == 0:
            self.active_profile = ''
        elif len(self.profiles) > 0 and self.active_profile not in self.profiles:
            self.active_profile = self.profiles[0]

        self.profiles = self.sorted_profiles()

        # Modify root window
        self.root.title(self.title)
        self.clickable = True
        self.root.resizable(False, False)
        self.root.geometry('+%d+%d' % other_utils.safe_eval(self.cfg['DEFAULT']['window_start_position']))
        self.root.config(borderwidth=2, height=365, width=240, relief='raised')
        # self.root.wm_attributes("-transparentcolor", "purple")
        self.root.wm_attributes("-topmost", self.always_on_top)
        self.root.focus_get()
        self.root.protocol("WM_DELETE_WINDOW", self.Quit)
        self.root.iconbitmap(media_path + 'icon.ico')
        self.root.pack_propagate(False)

        # Build banner image and make window draggable on the banner
        d2banner = media_path + 'd2icon.png'
        img = tk.PhotoImage(file=d2banner)
        self.img_panel = tkd.Label(self.root, image=img, borderwidth=0)
        self.img_panel.pack()
        self.img_panel.bind("<ButtonPress-1>", self.root.start_move)
        self.img_panel.bind("<ButtonRelease-1>", self.root.stop_move)
        self.img_panel.bind("<B1-Motion>", self.root.on_motion)
        self.root.bind("<Delete>", self.delete_selection)
        self.root.bind("<Left>", self.root.moveleft)
        self.root.bind("<Right>", self.root.moveright)
        self.root.bind("<Up>", self.root.moveup)
        self.root.bind("<Down>", self.root.movedown)

        # Add buttons to main widget
        self.btn_frame = tkd.Frame(self.root)
        tkd.Button(self.btn_frame, text='Delete selection', command=self.delete_selection).pack(side=tk.LEFT, expand=True, fill=tk.BOTH, padx=[2, 1], pady=1)
        tkd.Button(self.btn_frame, text='Archive session', command=self.ArchiveReset).pack(side=tk.LEFT, expand=True, fill=tk.BOTH, padx=[0, 1], pady=1)

        # Build tabs
        self.caret_frame = tkd.Frame(self.root)
        self.drops_frame = tkd.Frame(self.caret_frame)
        self.adv_stats_frame = tkd.Frame(self.caret_frame)

        self.tabcontrol = tkd.Notebook(self.root)
        self.tabcontrol.pack(expand=False, fill=tk.BOTH)
        self.profile_tab = Profile(self, parent=self.tabcontrol)
        self.timer_tab = MFRunTimer(self, parent=self.tabcontrol)
        self.drops_tab = Drops(self, parent=self.drops_frame)
        self.options_tab = Options(self, self.timer_tab, self.drops_tab, parent=self.tabcontrol)
        self.grail_tab = Grail(self, parent=self.tabcontrol)
        self.about_tab = About(self, parent=self.tabcontrol)

        self.tabcontrol.add(self.timer_tab, text='Timer')
        self.tabcontrol.add(self.options_tab, text='Options')
        self.tabcontrol.add(self.profile_tab, text='Profile')
        self.tabcontrol.add(self.grail_tab, text='Grail')
        self.tabcontrol.add(self.about_tab, text='About')

        self.root.bind("<<NotebookTabChanged>>", lambda _e: self.notebook_tab_change())
        self.profile_tab.update_descriptive_statistics()

        self.toggle_drops_frame(show=self.show_drops_tab_below)
        self.drops_caret = tkd.CaretButton(self.drops_frame, active=self.show_drops_tab_below, command=self.toggle_drops_frame, text='Drops', compound=tk.RIGHT, height=13)
        self.drops_caret.propagate(False)
        self.drops_caret.pack(side=tk.BOTTOM, fill=tk.X, expand=True, padx=[2, 1], pady=[0, 1])

        tracker_is_active = other_utils.safe_eval(self.cfg['AUTOMODE']['advanced_tracker_open']) and self.automode == 2 and self.is_user_admin
        self.advanced_stats_tracker = StatsTracker(self, self.adv_stats_frame)
        self.advanced_stats_caret = tkd.CaretButton(self.adv_stats_frame, active=tracker_is_active, text='Advanced stats', compound=tk.RIGHT, height=13, command=self.toggle_advanced_stats_frame)
        self.advanced_stats_caret.propagate(False)
        self.advanced_stats_caret.pack(side=tk.BOTTOM, fill=tk.X, expand=True, padx=[2, 1], pady=[0, 1])

        # Register binds for changing tabs
        if self.tab_switch_keys_global:
            self.options_tab.tab2.hk.register(['control', 'shift', 'next'], callback=lambda event: self.queue.put(self.tabcontrol.next_tab))
            self.options_tab.tab2.hk.register(['control', 'shift', 'prior'], callback=lambda event: self.queue.put(self.tabcontrol.prev_tab))
        else:
            self.root.bind_all('<Control-Shift-Next>', lambda event: self.tabcontrol.next_tab())
            self.root.bind_all('<Control-Shift-Prior>', lambda event: self.tabcontrol.prev_tab())

        # Load save state and start autosave process
        active_state = self.load_state_file()
        self.LoadActiveState(active_state)
        self.root.after(30000, self._autosave_state)

        # Apply styling options
        self.theme.apply_theme_style()
        self.theme.update_colors()

        # Automode and advanced stats loop
        self.am_lab = tk.Text(self.root, height=1, width=13, wrap=tk.NONE, bg="black", font=('Segoe UI', 9), cursor='', borderwidth=0)
        self.am_lab.tag_configure("am", foreground="white", background="black")
        self.am_lab.tag_configure("on", foreground="lawn green", background="black")
        self.am_lab.tag_configure("off", foreground="red", background="black")
        self.am_lab.place(x=1, y=0.4)
        self.toggle_automode()
        self.toggle_advanced_stats_frame(show=tracker_is_active)

        # A trick to disable windows DPI scaling - the app doesnt work well with scaling, unfortunately
        if self.os_release == '10' and self.disable_scaling:
            ctypes.windll.shcore.SetProcessDpiAwareness(2)

        # Used if "auto archive session" is activated
        self.profile_tab.auto_reset_session()

        # Pressing ALT_L paused UI updates when in focus, disable (probably hooked to opening menus)
        self.root.unbind_all('<Alt_L>')

        # Start the program
        self.root.mainloop()