예제 #1
0
    def _create_filters(self):
        filter_frame = LabelFrame(self)
        filter_frame.pack(side=LEFT, anchor=W, fill=X)
        self._create_range_filter(filter_frame)
        self._create_occurrence_filter(filter_frame)

        for child in filter_frame.winfo_children():
            child.grid_configure(padx=PAD_X, pady=PAD_Y, sticky=W)
예제 #2
0
class NetCalcGUI:
    def __init__(self):
        self.subnet = Subnet()

        self.net = Tk()
        self.net.wm_title('Network Address Calculator')

        self.net_from_cidr = LabelFrame(self.net,
                                        text='Network Address: CIDR Address')
        self.cidr_label = Label(self.net_from_cidr,
                                text='CIDR Address:',
                                width=20)
        self.cidr_entry = Entry(self.net_from_cidr, width=25)

        self.net_from_ip_range = LabelFrame(
            self.net, text='Network Address: Assignable IP Range')
        self.ip_range_label = Label(self.net_from_ip_range,
                                    text='Assignable IP Range:',
                                    width=20)
        self.ip_range_entry = Entry(self.net_from_ip_range, width=25)

        self.learning_steps = LabelFrame(self.net, text='Learning Steps')

        self.calculate = Button(self.net_from_cidr,
                                text='Calculate',
                                command=lambda: self.get_net_from_cidr())
        self.calculate2 = Button(self.net_from_ip_range,
                                 text='Calculate',
                                 command=lambda: self.get_net_from_ip_range())

        self.net_from_cidr.grid(row=0)
        self.net_from_ip_range.grid(row=1)
        self.learning_steps.grid(row=2, sticky='W')

        self.cidr_label.grid(row=0, column=0, sticky='W')
        self.cidr_entry.grid(row=0, column=1)
        self.calculate.grid(row=0, column=2)

        self.ip_range_label.grid(row=0, column=0, sticky='W')
        self.ip_range_entry.grid(row=0, column=1)
        self.calculate2.grid(row=0, column=2)

        # self.net.mainloop()

    def get_net_from_cidr(self):
        if self.subnet.network_address != '':
            self.clear_and_reset()
        else:
            self.subnet.cidr_address = self.cidr_entry.get()

            if self.subnet.verify_variables():
                self.subnet.calculate_network_address_from_cidr()

                step1 = Label(self.learning_steps, text='Step 1:')
                cidr_address = Label(self.learning_steps,
                                     text='CIDR Address: {}'.format(
                                         self.subnet.cidr_address))
                step2 = Label(self.learning_steps, text='Step 2:')
                network = Label(self.learning_steps,
                                text='Network Address: {}'.format(
                                    self.subnet.network_address))

                step1.grid(row=0, column=0, sticky='W')
                cidr_address.grid(row=0, column=1, sticky='W')
                step2.grid(row=1, column=0, sticky='W')
                network.grid(row=1, column=1, sticky='W')
            else:
                self.clear_and_reset()
                HelpGUI()

    def get_net_from_ip_range(self):
        if self.subnet.network_address != '':
            self.clear_and_reset()
        else:
            self.subnet.ip_range = self.ip_range_entry.get()

            if self.subnet.verify_variables():
                self.subnet.calculate_network_address_from_ip_range()
                steps = self.subnet.network_address_steps

                step1 = Label(self.learning_steps, text='Step 1:')
                ip_range = Label(self.learning_steps,
                                 text='Assignable IP Range: {}'.format(
                                     self.subnet.ip_range))
                step2 = Label(self.learning_steps, text='Step 2:')
                front = Label(self.learning_steps,
                              text='(Front - 1): {}'.format(
                                  steps[0]['Front - 1']))
                step3 = Label(self.learning_steps, text='Step 3:')
                network = Label(self.learning_steps,
                                text='Network Address: {}'.format(
                                    self.subnet.network_address))

                step1.grid(row=0, column=0, sticky='W')
                ip_range.grid(row=0, column=1, sticky='W')
                step2.grid(row=1, column=0, sticky='W')
                front.grid(row=1, column=1, sticky='W')
                step3.grid(row=2, column=0, sticky='W')
                network.grid(row=2, column=1, sticky='W')
            else:
                self.clear_and_reset()
                HelpGUI()

    def clear_and_reset(self):
        self.cidr_entry.delete(0, 'end')
        self.ip_range_entry.delete(0, 'end')
        self.subnet.reset_variables()
        for child in self.learning_steps.winfo_children():
            child.destroy()

    def generate_main(self):
        self.net.mainloop()
예제 #3
0
class NetmaskCalcGUI:
    def __init__(self):
        self.subnet = Subnet()

        self.net = Tk()
        self.net.wm_title('Netmask Calculator')

        self.netmask_from_cidr = LabelFrame(self.net,
                                            text='Netmask: CIDR Address')
        self.cidr_label = Label(self.netmask_from_cidr,
                                text='CIDR Address:',
                                width=20)
        self.cidr_entry = Entry(self.netmask_from_cidr, width=25)

        self.netmask_from_ip_range = LabelFrame(
            self.net, text='Netmask: Assignable IP Range')
        self.ip_range_label = Label(self.netmask_from_ip_range,
                                    text='Assignable IP Range:',
                                    width=20)
        self.ip_range_entry = Entry(self.netmask_from_ip_range, width=25)

        self.learning_steps = LabelFrame(self.net, text='Learning Steps')

        self.calculate = Button(self.netmask_from_cidr,
                                text='Calculate',
                                command=lambda: self.get_net_from_cidr())
        self.calculate2 = Button(self.netmask_from_ip_range,
                                 text='Calculate',
                                 command=lambda: self.get_net_from_ip_range())

        self.netmask_from_cidr.grid(row=0)
        self.netmask_from_ip_range.grid(row=1)
        self.learning_steps.grid(row=2, sticky='W')

        self.cidr_label.grid(row=0, column=0, sticky='W')
        self.cidr_entry.grid(row=0, column=1)
        self.calculate.grid(row=0, column=2)

        self.ip_range_label.grid(row=0, column=0, sticky='W')
        self.ip_range_entry.grid(row=0, column=1)
        self.calculate2.grid(row=0, column=2)

        # self.net.mainloop()

    def get_net_from_cidr(self):
        if self.subnet.netmask != '':
            self.clear_and_reset()
        else:
            self.subnet.cidr_address = self.cidr_entry.get()

            if self.subnet.verify_variables():
                self.subnet.calculate_netmask_from_cidr()
                steps = self.subnet.netmask_steps

                step1 = Label(self.learning_steps, text='Step 1:')
                cidr_address = Label(self.learning_steps,
                                     text='CIDR Address: {}'.format(
                                         self.subnet.cidr_address))
                step2 = Label(self.learning_steps, text='Step 2:')
                net_bits = Label(self.learning_steps,
                                 text='Network Bits: {}'.format(
                                     steps[0]['Network Bits']))
                host_bits = Label(self.learning_steps,
                                  text='Host Bits: {}'.format(
                                      steps[0]['Host Bits']))
                step3 = Label(self.learning_steps, text='Step 3:')
                mask_binary = Label(self.learning_steps,
                                    text='Netmask Binary: {}'.format(
                                        steps[1]['Netmask Binary']))
                step4 = Label(self.learning_steps, text='Step 4:')
                netmask = Label(self.learning_steps,
                                text='Netmask: {}'.format(self.subnet.netmask))

                step1.grid(row=0, column=0, sticky='W')
                cidr_address.grid(row=0, column=1, sticky='W')
                step2.grid(row=1, column=0, sticky='W')
                net_bits.grid(row=1, column=1, sticky='W')
                host_bits.grid(row=1, column=2, sticky='W')
                step3.grid(row=2, column=0, sticky='W')
                mask_binary.grid(row=2, column=1, columnspan=2, sticky='W')
                step4.grid(row=3, column=0, sticky='W')
                netmask.grid(row=3, column=1, sticky='W')
            else:
                self.clear_and_reset()
                HelpGUI()

    def get_net_from_ip_range(self):
        if self.subnet.netmask != '':
            self.clear_and_reset()
        else:
            self.subnet.ip_range = self.ip_range_entry.get()

            if self.subnet.verify_variables():
                self.subnet.calculate_netmask_from_ip_range()
                steps = self.subnet.netmask_steps

                step1 = Label(self.learning_steps, text='Step 1:')
                ip_range = Label(self.learning_steps,
                                 text='Assignable IP Range: {}'.format(
                                     self.subnet.ip_range))
                step2 = Label(self.learning_steps, text='Step 2:')
                front = Label(self.learning_steps,
                              text='Front: {}'.format(steps[0]['Front']))
                back = Label(self.learning_steps,
                             text=' Back: {}'.format(steps[0]['Back']))
                step3 = Label(self.learning_steps, text='Step 3:')
                comparison = Label(self.learning_steps,
                                   text='Comparison: {}'.format(
                                       steps[1]['Comparison']))
                step4 = Label(self.learning_steps, text='Step 4:')
                netmask = Label(self.learning_steps,
                                text='Netmask: {}'.format(self.subnet.netmask))

                step1.grid(row=0, column=0, sticky='W')
                ip_range.grid(row=0, column=1, sticky='W')
                step2.grid(row=1, column=0, sticky='W')
                front.grid(row=1, column=1, sticky='W')
                back.grid(row=2, column=1, sticky='W')
                step3.grid(row=3, column=0, sticky='W')
                comparison.grid(row=3, column=1, sticky='W')
                step4.grid(row=4, column=0, sticky='W')
                netmask.grid(row=4, column=1, sticky='W')
            else:
                self.clear_and_reset()
                HelpGUI()

    def clear_and_reset(self):
        self.cidr_entry.delete(0, 'end')
        self.ip_range_entry.delete(0, 'end')
        self.subnet.reset_variables()
        for child in self.learning_steps.winfo_children():
            child.destroy()

    def generate_main(self):
        self.net.mainloop()
예제 #4
0
class IPRangeCalcGUI:
    def __init__(self):
        self.subnet = Subnet()

        self.range = Tk()
        self.range.wm_title('Assignable IP Range Calculator')

        self.ip_range_from_cidr = LabelFrame(self.range, text='Assignable IP Range: CIDR Address')
        self.cidr_label = Label(self.ip_range_from_cidr, text='CIDR Address:', width=25)
        self.cidr_entry = Entry(self.ip_range_from_cidr, width=25)

        self.ip_range_from_network_broadcast = LabelFrame(self.range, text='Assignable IP Range: Network '
                                                                           'Address, Broadcast Address')
        self.network = Label(self.ip_range_from_network_broadcast, text='Network Address:', width=25)
        self.broadcast = Label(self.ip_range_from_network_broadcast, text='Broadcast Address:', width=25)
        self.network_entry = Entry(self.ip_range_from_network_broadcast, width=25)
        self.broadcast_entry = Entry(self.ip_range_from_network_broadcast, width=25)

        self.learning_steps = LabelFrame(self.range, text='Learning Steps')

        self.calculate = Button(self.ip_range_from_cidr, text='Calculate',
                                command=lambda: self.get_ip_range_from_cidr())
        self.calculate2 = Button(self.ip_range_from_network_broadcast, text='Calculate',
                                 command=lambda: self.get_ip_range_from_network_broadcast())

        self.ip_range_from_cidr.grid(row=0)
        self.ip_range_from_network_broadcast.grid(row=1)
        self.learning_steps.grid(row=2, sticky='W')

        self.cidr_label.grid(row=0, column=0, sticky='W')
        self.cidr_entry.grid(row=0, column=1)
        self.calculate.grid(row=0, column=2)

        self.network.grid(row=0, column=0, sticky='W')
        self.broadcast.grid(row=0, column=1, sticky='W')
        self.network_entry.grid(row=1, column=0)
        self.broadcast_entry.grid(row=1, column=1)
        self.calculate2.grid(row=1, column=2)

        # self.broadcast.mainloop()

    def get_ip_range_from_cidr(self):
        if self.subnet.ip_range != '':
            self.clear_and_reset()
        else:
            self.subnet.cidr_address = self.cidr_entry.get()

            if self.subnet.verify_variables():
                self.subnet.calculate_ip_range_from_cidr()
                steps = self.subnet.ip_range_steps

                step1 = Label(self.learning_steps, text='Step 1:')
                cidr_address = Label(self.learning_steps, text='CIDR Address: {}'.format(self.subnet.cidr_address))
                step2 = Label(self.learning_steps, text='Step 2:')
                front = Label(self.learning_steps, text='Front: {}'.format(steps[0]['Front']))
                step3 = Label(self.learning_steps, text='Step 3:')
                cidr = Label(self.learning_steps, text='CIDR: {}'.format(steps[1]['CIDR']))
                host = Label(self.learning_steps, text='Host Bits: 32 - {} = {}'.format(steps[1]['CIDR'],
                                                                                        (32 - int(steps[1]['CIDR']))))
                step4 = Label(self.learning_steps, text='Step 4:')
                net_binary = Label(self.learning_steps, text='Network Binary: {}'.format(steps[1]['Network Binary']))
                step5 = Label(self.learning_steps, text='Step 5:')
                back_binary = Label(self.learning_steps,
                                    text='Back Binary (Broadcast - 1): {}'.format(steps[2]['Back Binary']))
                step6 = Label(self.learning_steps, text='Step 6:')
                ip_range = Label(self.learning_steps, text='Assignable IP Range: {}'.format(self.subnet.ip_range))

                step1.grid(row=0, column=0, sticky='W')
                cidr_address.grid(row=0, column=1, columnspan=2, sticky='W')
                step2.grid(row=1, column=0, sticky='W')
                front.grid(row=1, column=1, columnspan=2, sticky='W')
                step3.grid(row=2, column=0, sticky='W')
                cidr.grid(row=2, column=1, sticky='W')
                host.grid(row=2, column=2, sticky='W')
                step4.grid(row=3, column=0, sticky='W')
                net_binary.grid(row=3, column=1, columnspan=2, sticky='W')
                step5.grid(row=4, column=0, sticky='W')
                back_binary.grid(row=4, column=1, columnspan=2, sticky='W')
                step6.grid(row=5, column=0, sticky='W')
                ip_range.grid(row=5, column=1, columnspan=2, sticky='W')
            else:
                self.clear_and_reset()
                HelpGUI()

    def get_ip_range_from_network_broadcast(self):
        if self.subnet.ip_range != '':
            self.clear_and_reset()
        else:
            self.subnet.network_address = self.network_entry.get()
            self.subnet.broadcast_address = self.broadcast_entry.get()

            if self.subnet.network_address != '' and self.subnet.broadcast_address != '' \
                    and self.subnet.verify_variables() \
                    and (ipaddress.IPv4Address(self.subnet.network_address) + 2) \
                            < ipaddress.IPv4Address(self.subnet.broadcast_address):
                self.subnet.calculate_ip_range_from_network_broadcast()
                steps = self.subnet.ip_range_steps

                step1 = Label(self.learning_steps, text='Step 1:')
                network = Label(self.learning_steps, text='Network Address: {}'.format(self.subnet.network_address))
                broadcast = Label(self.learning_steps,
                                  text='Broadcast Address: {}'.format(self.subnet.broadcast_address))
                step2 = Label(self.learning_steps, text='Step 2:')
                front = Label(self.learning_steps, text='Front: {}'.format(steps[0]['Front']))
                step3 = Label(self.learning_steps, text='Step 3:')
                back = Label(self.learning_steps, text='Back: {}'.format(steps[1]['Back']))
                step4 = Label(self.learning_steps, text='Step 4:')
                ip_range = Label(self.learning_steps, text='Assignable IP Range: {}'.format(self.subnet.ip_range))

                step1.grid(row=0, column=0, sticky='W')
                network.grid(row=0, column=1, sticky='W')
                broadcast.grid(row=0, column=2, sticky='W')
                step2.grid(row=1, column=0, sticky='W')
                front.grid(row=1, column=1, sticky='W')
                step3.grid(row=2, column=0, sticky='W')
                back.grid(row=2, column=1, sticky='W')
                step4.grid(row=3, column=0, sticky='W')
                ip_range.grid(row=3, column=1, columnspan=2, sticky='W')
            else:
                self.clear_and_reset()
                HelpGUI()

    def clear_and_reset(self):
        self.cidr_entry.delete(0, 'end')
        self.network_entry.delete(0, 'end')
        self.broadcast_entry.delete(0, 'end')
        self.subnet.reset_variables()
        for child in self.learning_steps.winfo_children():
            child.destroy()

    def generate_main(self):
        self.range.mainloop()
예제 #5
0
class TotalHostCalcGUI:
    def __init__(self):
        self.subnet = Subnet()

        self.total = Tk()
        self.total.wm_title('Total Host Count Calculator')

        self.count_from_cidr = LabelFrame(
            self.total, text='Total Host Count: CIDR Address')
        self.cidr_label = Label(self.count_from_cidr,
                                text='CIDR Address:',
                                width=20)
        self.cidr_entry = Entry(self.count_from_cidr, width=25)

        self.count_from_netmask = LabelFrame(self.total,
                                             text='Total Host Count: Netmask')
        self.netmask_label = Label(self.count_from_netmask,
                                   text='Netmask:',
                                   width=20)
        self.netmask_entry = Entry(self.count_from_netmask, width=25)

        self.count_from_ip_range = LabelFrame(
            self.total, text='Total Host Count: Assignable IP Range')
        self.ip_range_label = Label(self.count_from_ip_range,
                                    text='Assignable IP Range:',
                                    width=20)
        self.ip_range_entry = Entry(self.count_from_ip_range, width=25)

        self.learning_steps = LabelFrame(self.total, text='Learning Steps')

        self.calculate = Button(self.count_from_cidr,
                                text='Calculate',
                                command=lambda: self.get_count_from_cidr())
        self.calculate2 = Button(self.count_from_netmask,
                                 text='Calculate',
                                 command=lambda: self.get_count_from_netmask())
        self.calculate3 = Button(
            self.count_from_ip_range,
            text='Calculate',
            command=lambda: self.get_count_from_ip_range())

        self.count_from_cidr.grid(row=0)
        self.count_from_netmask.grid(row=1)
        self.count_from_ip_range.grid(row=2)
        self.learning_steps.grid(row=3, sticky='W')

        self.cidr_label.grid(row=0, column=0, sticky='W')
        self.cidr_entry.grid(row=0, column=1)
        self.calculate.grid(row=0, column=2)

        self.netmask_label.grid(row=0, column=0, sticky='W')
        self.netmask_entry.grid(row=0, column=1)
        self.calculate2.grid(row=0, column=2)

        self.ip_range_label.grid(row=0, column=0, sticky='W')
        self.ip_range_entry.grid(row=0, column=1)
        self.calculate3.grid(row=0, column=2)

        # self.total.mainloop()
        pass

    def get_count_from_cidr(self):
        if self.subnet.total_host_count != '':
            self.clear_and_reset()
        else:
            self.subnet.cidr_address = self.cidr_entry.get()

            if self.subnet.verify_variables():
                self.subnet.calculate_total_host_count_from_cidr()
                steps = self.subnet.total_host_count_steps

                step1 = Label(self.learning_steps, text='Step 1:')
                cidr_address = Label(self.learning_steps,
                                     text='CIDR Address: {}'.format(
                                         self.subnet.cidr_address))
                step2 = Label(self.learning_steps, text='Step 2:')
                cidr = Label(self.learning_steps,
                             text='CIDR: {}'.format(steps[0]['CIDR']))
                step3 = Label(self.learning_steps, text='Step 3:')
                host = Label(self.learning_steps,
                             text='Host Bits: {}'.format(
                                 steps[1]['Host Bits']))
                step4 = Label(self.learning_steps, text='Step 4:')
                count = Label(self.learning_steps,
                              text='Total Host Count: 2{} = {}'.format(
                                  exponent(
                                      steps[1]['Host Bits'].split(' ')[-1]),
                                  self.subnet.total_host_count))

                step1.grid(row=0, column=0, sticky='W')
                cidr_address.grid(row=0, column=1, sticky='W')
                step2.grid(row=1, column=0, sticky='W')
                cidr.grid(row=1, column=1, sticky='W')
                step3.grid(row=2, column=0, sticky='W')
                host.grid(row=2, column=1, sticky='W')
                step4.grid(row=3, column=0, sticky='W')
                count.grid(row=3, column=1, sticky='W')
            else:
                self.clear_and_reset()
                HelpGUI()

    def get_count_from_netmask(self):
        if self.subnet.total_host_count != '':
            self.clear_and_reset()
        else:
            self.subnet.netmask = self.netmask_entry.get()

            if self.subnet.verify_variables():
                self.subnet.calculate_total_host_count_from_netmask()
                steps = self.subnet.total_host_count_steps

                step1 = Label(self.learning_steps, text='Step 1:')
                netmask = Label(self.learning_steps,
                                text='Netmask: {}'.format(self.subnet.netmask))
                step2 = Label(self.learning_steps, text='Step 2:')
                netmask_binary = Label(self.learning_steps,
                                       text='Netmask Binary: {}'.format(
                                           steps[0]['Netmask Binary']))
                step3 = Label(self.learning_steps, text='Step 3:')
                host = Label(self.learning_steps,
                             text='Host Bits: {}'.format(
                                 steps[1]['Host Bits']))
                step4 = Label(self.learning_steps, text='Step 4:')
                count = Label(self.learning_steps,
                              text='Total Host Count: 2{} = {}'.format(
                                  exponent(str(steps[1]['Host Bits'])),
                                  self.subnet.total_host_count))

                step1.grid(row=0, column=0, sticky='W')
                netmask.grid(row=0, column=1, sticky='W')
                step2.grid(row=1, column=0, sticky='W')
                netmask_binary.grid(row=1, column=1, sticky='W')
                step3.grid(row=2, column=0, sticky='W')
                host.grid(row=2, column=1, sticky='W')
                step4.grid(row=3, column=0, sticky='W')
                count.grid(row=3, column=1, sticky='W')
            else:
                self.clear_and_reset()
                HelpGUI()

    def get_count_from_ip_range(self):
        if self.subnet.total_host_count != '':
            self.clear_and_reset()
        else:
            self.subnet.ip_range = self.ip_range_entry.get()

            if self.subnet.verify_variables():
                self.subnet.calculate_total_host_count_from_ip_range()
                steps = self.subnet.total_host_count_steps

                step1 = Label(self.learning_steps, text='Step 1:')
                ip_range = Label(self.learning_steps,
                                 text='Assignable IP Range: {}'.format(
                                     self.subnet.ip_range))
                step2 = Label(self.learning_steps, text='Step 2:')
                front = Label(self.learning_steps,
                              text='Front: {}'.format(steps[0]['Front']))
                back = Label(self.learning_steps,
                             text=' Back: {}'.format(steps[0]['Back']))
                step3 = Label(self.learning_steps, text='Step 3:')
                comparison = Label(self.learning_steps,
                                   text='Comparison: {}'.format(
                                       steps[1]['Comparison']))
                step4 = Label(self.learning_steps, text='Step 4:')
                host = Label(self.learning_steps,
                             text='Host Bits: {}'.format(
                                 steps[2]['Host Bits']))
                step5 = Label(self.learning_steps, text='Step 5:')
                count = Label(self.learning_steps,
                              text='Total Host Count: 2{} = {}'.format(
                                  exponent(str(steps[2]['Host Bits'])),
                                  self.subnet.total_host_count))

                step1.grid(row=0, column=0, sticky='W')
                ip_range.grid(row=0, column=1, sticky='W')
                step2.grid(row=1, column=0, sticky='W')
                front.grid(row=1, column=1, sticky='W')
                back.grid(row=2, column=1, sticky='W')
                step3.grid(row=3, column=0, sticky='W')
                comparison.grid(row=3, column=1, sticky='W')
                step4.grid(row=4, column=0, sticky='W')
                host.grid(row=4, column=1, sticky='W')
                step5.grid(row=5, column=0, sticky='W')
                count.grid(row=5, column=1, sticky='W')
            else:
                self.clear_and_reset()
                HelpGUI()

    def clear_and_reset(self):
        self.cidr_entry.delete(0, 'end')
        self.netmask_entry.delete(0, 'end')
        self.ip_range_entry.delete(0, 'end')
        self.subnet.reset_variables()
        for child in self.learning_steps.winfo_children():
            child.destroy()

    def generate_main(self):
        self.total.mainloop()
예제 #6
0
파일: main.py 프로젝트: kr1/roqba
class Application(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind((host, port))
        self.grid()
        self.columnconfigure(0, minsize=100)
        self.columnconfigure(1, minsize=200)
        self.columnconfigure(2, minsize=200)
        self.columnconfigure(3, minsize=150)
        self.columnconfigure(4, minsize=150)
        self.columnconfigure(5, minsize=150)
        self.columnconfigure(6, minsize=150)
        self.create_widgets()
        self.settables = self.assemble_settables()
        self.gui_logger = logging.getLogger('gui')
        self.request_update()

    def create_widgets(self):
        self.create_monitor()
        self.create_check_buttons()
        self.create_ranges()
        self.create_scales()
        self.create_radio_buttons()
        self.create_voices()
        self.quitButton = Button(self, text='Quit', command=self.quit)
        self.quitButton.grid(columnspan=7, sticky=E + W)

    def assemble_settables(self):
        settables = self.winfo_children()
        for w in settables:
            settables += w.winfo_children()
        return [w for w in settables if w.__class__.__name__ in ['Scale', 'Checkbutton']]

    def create_radio_buttons(self):
        # Scale related
        entries = ['DIATONIC', 'HARMONIC', 'MELODIC', 'PENTATONIC', 'PENTA_MINOR',
                   'GREEK_CHROMATIC', 'GREEK_ENHARMONIC']
        self.scale = StringVar()
        self.scale.set('DIATONIC')
        self.rb_frame = Frame(self)
        for e in entries:
            rb = Radiobutton(self.rb_frame, value=e, text=e, anchor=W,
                             command=self.send_scale, variable=self.scale)
            rb.grid(row=len(self.rb_frame.winfo_children()), sticky=W)
        self.rb_frame.grid(column=1, row=len(self.grid_slaves(column=1)), rowspan=3)

    def create_monitor(self):
        self.monitor_frame = LabelFrame(self, text="Monitor and Transport")
        this_cycle = Scale(self.monitor_frame, label='cycle_pos', orient=HORIZONTAL,
                           from_=1, to=16, resolution=1)
        this_cycle.disable, this_cycle.enable = (None, None)
        this_cycle.ref = 'cycle_pos'
        this_cycle.grid(column=0, row=0, sticky=E + W)
        self.updateButton = Button(self.monitor_frame,
                                   text='Reload all Settings',
                                   command=self.request_update)
        self.updateButton.grid(row=1, sticky=E + W)
        self.ForceCaesuraButton = Button(self.monitor_frame,
                                         text='Force Caesura',
                                         command=self.force_caesura)
        self.ForceCaesuraButton.grid(row=2, sticky=E + W)
        self.saveBehaviourButton = Button(self.monitor_frame,
                                          text='Save current behaviour',
                                          command=self.request_saving_behaviour)
        self.saveBehaviourButton.grid(row=3, sticky=E + W)
        self.saveBehaviourNameEntry = Entry(self.monitor_frame)
        self.saveBehaviourNameEntry.grid(row=4, sticky=E + W)
        self.saveBehaviourNameEntry.bind('<KeyRelease>', self.request_saving_behaviour)
        self.selected_behaviour = StringVar()
        self.selected_behaviour.trace('w', self.new_behaviour_chosen)
        self.savedBehavioursMenu = OptionMenu(self.monitor_frame,
                                              self.selected_behaviour, None,)
        self.savedBehavioursMenu.grid(row=5, sticky=E + W)
        self.monitor_frame.grid(column=0, row=10, sticky=E + W)

    def request_update(self):
        self.send({'sys': 'update'})

    def request_saving_behaviour(self, event=None):
        """callback for save behaviour button and textentry"""
        if event and event.widget == self.saveBehaviourNameEntry:
            if event.keysym == 'Return':
                name = self.saveBehaviourNameEntry.get()
                self.saveBehaviourNameEntry.delete(0, len(name))
            else:
                return
        else:  # button was pressed
            name = self.saveBehaviourNameEntry.get()
        if name:
            self.send({'sys': ['save_behaviour', name]})

    def force_caesura(self):
        self.send({'force_caesura': True})

    def create_voices(self):
        voice_ids = ['1', '2', '3', '4']
        SCALES = OrderedDict([
                  ('pan_pos', {'min': -1, 'max': 1, 'start': 0.5, 'res': 0.001}),
                  ('volume', {'min': 0, 'max': 1, 'start': 0.666, 'res': 0.001}),
                  ('slide_duration_msecs', {'min': 0, 'max': 2000, 'start': 60, 'res': 1}),
                  ('slide_duration_prop', {'min': 0, 'max': 2, 'start': 0.666, 'res': 0.001}),
                  ('binaural_diff', {'min': 0, 'max': 66, 'start': 0.2, 'res': 0.01})
                ])

        for vid in voice_ids:
            counter = 0
            for sca in SCALES:
                name = 'voice_' + vid + '_' + sca
                setattr(self, 'min_' + name, SCALES[sca]['min'])
                setattr(self, 'max_' + name, SCALES[sca]['max'])
                this_sca = Scale(self, label=sca, orient=HORIZONTAL,
                                 from_=getattr(self, 'min_' + name),
                                 to=getattr(self, 'max_' + name),
                                 resolution=SCALES[sca]['res'])
                this_sca.enable = ('enable' in list(SCALES[sca].keys()) and
                                   SCALES[sca]['enable'] or None)
                this_sca.disable = ('disable' in list(SCALES[sca].keys()) and
                                    SCALES[sca]['disable'] or None)
                this_sca.grid(column=int(2 + int(vid)), row=counter, sticky=E + W)
                this_sca.bind("<ButtonRelease>", self.scale_handler)
                this_sca.ref = name
                counter += 1
        CHECK_BUTTONS = OrderedDict(
                 [('mute', False),
                  ('automate_binaural_diffs', True),
                  ('automate_note_duration_prop', True),
                  ('use_proportional_slide_duration', {'val': True, 'label': 'proportional slide'}),
                  ('automate_pan', True),
                  ('automate_wavetables', True)])
        for vid in voice_ids:
            counter = 0
            cb_frame = LabelFrame(self, text="Voice {0} - Automation".format(vid))
            setattr(self, 'voice_' + vid + '_cb_frame', cb_frame)
            for cb in CHECK_BUTTONS:
                options = CHECK_BUTTONS[cb]
                name = 'voice_' + vid + '_' + cb
                if isinstance(options, dict) and 'label' in list(options.keys()):
                    label = options['label']
                else:
                    label = cb[9:] if cb[:9] == 'automate_' else cb
                setattr(self, name, IntVar(
                    value=type(options) == dict and options['val'] or options))
                self.this_cb = Checkbutton(cb_frame, text=label, variable=getattr(self, name))
                self.this_cb.bind('<Button-1>', self.check_boxes_handler)
                self.this_cb.disable = None
                self.this_cb.grid(sticky=W, column=0, row=counter)
                self.this_cb.ref = name
                counter += 1
            # add trigger wavetable-button
            trigWavetableButton = Button(cb_frame, text='Next Wavetable')
            trigWavetableButton.bind('<Button-1>', self.trigger_waveform_handler)
            trigWavetableButton.ref = 'voice_' + vid + "_trigger_wavetable"
            trigWavetableButton.grid(row=counter)
            cb_frame.grid(column=int(vid) + 2, row=5, sticky=E + W + N, rowspan=8)
        for vid in voice_ids:
            generation_types = ["random", "random_harmonic", "harmonic"]
            partial_pools = ["even", "odd", "all"]
            prefix = 'voice_' + vid + '_'
            types_name = prefix + 'wavetable_generation_type'
            pools_name = prefix + 'partial_pool'
            setattr(self, types_name, StringVar())
            getattr(self, types_name).set("random")
            setattr(self, pools_name, StringVar())
            getattr(self, pools_name).set("all")
            target_frame = getattr(self, 'voice_' + vid + '_cb_frame')
            gen_typ_frame = LabelFrame(target_frame, text="type")
            gen_typ_frame.grid(row=len(target_frame.winfo_children()), sticky=W)
            for gen_t in generation_types:
                gen_t_entry = Radiobutton(gen_typ_frame, value=gen_t, text=gen_t, anchor=W,
                                          variable=getattr(self, types_name))
                gen_t_entry.bind('<ButtonRelease-1>', self.wt_handler)
                gen_t_entry.ref = types_name
                gen_t_entry.grid(row=len(gen_typ_frame.winfo_children()), sticky=W)
            pp_frame = LabelFrame(target_frame, text="harmonics")
            for pp in partial_pools:
                pp_entry = Radiobutton(pp_frame, value=pp, text=pp, anchor=W,
                                       variable=getattr(self, pools_name))
                pp_entry.bind('<ButtonRelease-1>', self.wt_handler)
                pp_entry.ref = pools_name
                pp_entry.grid(row=len(pp_frame.winfo_children()), sticky=E + W)
            this_num_partials = Scale(pp_frame, label='number of harmonics', orient=HORIZONTAL,
                                      from_=1, to=24, resolution=1)
            this_num_partials.ref = prefix + 'num_partials'
            this_num_partials.grid(column=0, row=len(pp_frame.winfo_children()), sticky=E + W)
            this_num_partials.bind("<ButtonRelease>", self.scale_handler)
            pp_frame.grid(row=len(target_frame.winfo_children()), sticky=E + W)

    def wt_handler(self, event):
        print(event.widget.tk)
        ref = event.widget.ref
        self.send({ref: getattr(self, ref).get()})

    def create_check_buttons(self):
        self.cb_frame = LabelFrame(self, text="Global Settings")
        for cb in CHECK_BUTTONS:
            label = cb
            target_parent = self.cb_frame
            if isinstance(CHECK_BUTTONS[cb], dict) and 'sub_frame' in list(CHECK_BUTTONS[cb].keys()):
                target_parent = getattr(self, CHECK_BUTTONS[cb]['sub_frame'])
            setattr(self, cb, IntVar(value=type(CHECK_BUTTONS[cb]) == dict and
                                     CHECK_BUTTONS[cb]['val'] or
                                     CHECK_BUTTONS[cb]))
            self.this_cb = Checkbutton(target_parent, text=label, variable=getattr(self, cb))
            self.this_cb.bind('<Button-1>', self.check_boxes_handler)
            self.this_cb.disable = (type(CHECK_BUTTONS[cb]) == dict and
                                    'disable' in list(CHECK_BUTTONS[cb].keys()))
            self.this_cb.grid(sticky=W, column=0, row=len(target_parent.winfo_children()))
            self.this_cb.ref = cb
        for but in GLOBAL_BUTTONS:
            label = but
            ele = GLOBAL_BUTTONS[but]
            this_but = Button(self.cb_frame, text=but)
            this_but.bind('<ButtonRelease-1>', getattr(self, ele['handler']))
            this_but.ref = but
            this_but.grid(sticky=W, column=0, row=len(self.cb_frame.winfo_children()))
        self.cb_frame.grid(column=0, row=0, rowspan=10, sticky=N)

    def new_behaviour_chosen(self, a, b, c):
        self.send({'sys': ['change_behaviour', self.selected_behaviour.get()]})

    def set_value(self, name, val):
        '''sets a widget to the specified value

        various different widget types need custom setting functionality'''

        direct = ['scale', 'wavetable_generation_type', 'partial_pool']
        if [x for x in direct if match("(voice_\d_|)" + x, name)]:
            self.gui_logger.info("setting: '{0}' to '{1}' in GUI".format(name, val))
            getattr(self, name).set(val)
            return
        if name == 'saved_behaviours' and len(val):
            self.savedBehavioursMenu.destroy()
            self.savedBehavioursMenu = OptionMenu(self.monitor_frame,
                                                  self.selected_behaviour, *sorted(val))
            self.savedBehavioursMenu.grid(row=5, sticky=E + W)
            return
        for w in self.settables:
            typ = w.__class__.__name__
            if w.ref == name:
                # print "setting '{0}' of type: '{1}' to: {2}".format(name, typ, val)
                if typ == 'Scale':
                    w.set(val)
                elif typ == "Checkbutton":
                    w.select() if val else w.deselect()

    def check_boxes_handler(self, event):
        '''handles checkbox events.

        shows and hides gui elements according to their enable/disable fields'''
        # print event.__dict__
        # print event.widget.__dict__
        ref = event.widget.ref
        val = not getattr(self, ref).get()  # because is read before the var is changed
        self.send({ref: val})
        # print ref, val
        # handle gui elements
        # enable/disable functionality temporarily(?) commented on:
        # Wed Aug 17 09:39:54 CEST 2011
#        if event.widget.disable:
#            for w in self.children.values():
#
#                # this try clause is for debugging, remove when stable
#                try:
#                    w.ref
#                    #print w.ref
#                except:
#                    pass
#                if (w.__class__.__name__ == 'Scale' and
#                    (w.disable or w.enable)):
#                    if w.disable == ref:
#                        if val:
#                            w.grid()
#                        else:
#                            w.grid_remove()
#                    elif w.enable == ref:
#                        if val:
#                            w.grid_remove()
#                        else:
#                            w.grid()
#                    #print w.disable, w.enable

    def create_scales(self):
        counter = 0
        for sca in SCALES:
            label = SCALES[sca]['label'] if 'label' in list(SCALES[sca].keys()) else sca
            setattr(self, 'min_' + sca, SCALES[sca]['min'])
            setattr(self, 'max_' + sca, SCALES[sca]['max'])
            self.this_scale = Scale(self, label=label, orient=HORIZONTAL,
                                    from_=getattr(self, 'min_' + sca),
                                    to=getattr(self, 'max_' + sca),
                                    resolution=SCALES[sca]['res'])
            self.this_scale.set(SCALES[sca]['start'])
            self.this_scale.enable = ('enable' in list(SCALES[sca].keys()) and
                                      SCALES[sca]['enable'] or None)
            self.this_scale.disable = ('disable' in list(SCALES[sca].keys()) and
                                       SCALES[sca]['disable'] or None)
            if 'pos' in list(SCALES[sca].keys()):
                pos = SCALES[sca]['pos']
                col = pos['c']
                row = pos['r']
            else:
                row = counter
                col = 1
                counter += 1
            self.this_scale.grid(column=col, row=row, sticky=E + W)
            self.this_scale.ref = sca
            self.this_scale.bind("<ButtonRelease>", self.scale_handler)

    def scale_handler(self, event):
        self.send({event.widget.ref: event.widget.get()})
        self.gui_logger.info("handling scale: {0}, with new value: {1}".format(
                  event.widget.ref, event.widget.get()))

    def trigger_waveform_handler(self, event):
        self.send({event.widget.ref: True})
        # print event.widget.ref, "- triggering wavetable"

    def send_scale(self):
        do = {'scale': self.scale.get()}
        self.send(do)

    def send(self, msg):
        self.gui_logger.info("sending: {0}".format(msg))
        self.send_sock.sendto(json.dumps(msg), (remote_host, send_port))

    def create_ranges(self):
        counter = 0
        for ran in RANGES:
            setattr(self, 'min_' + ran, RANGES[ran]['min'])
            setattr(self, 'max_' + ran, RANGES[ran]['max'])
            self.this_min_scale = Scale(self, label='min ' + ran, orient=HORIZONTAL,
                                        from_=getattr(self, 'min_' + ran),
                                        to=getattr(self, 'max_' + ran),
                                        resolution=RANGES[ran]['res'])
            self.this_max_scale = Scale(self, label='max ' + ran, orient=HORIZONTAL,
                                        from_=getattr(self, 'min_' + ran),
                                        to=getattr(self, 'max_' + ran),
                                        resolution=RANGES[ran]['res'])
            self.this_min_scale.set(RANGES[ran]['min_start'])
            self.this_max_scale.set(RANGES[ran]['max_start'])
            self.this_min_scale.enable = ('enable' in list(RANGES[ran].keys()) and
                                          RANGES[ran]['enable'] or None)
            self.this_min_scale.disable = ('disable' in list(RANGES[ran].keys()) and
                                           RANGES[ran]['disable'] or None)
            self.this_max_scale.enable = ('enable' in list(RANGES[ran].keys()) and
                                          RANGES[ran]['enable'] or None)
            self.this_max_scale.disable = ('disable' in list(RANGES[ran].keys()) and
                                           RANGES[ran]['disable'] or None)
            self.this_min_scale.grid(column=2, row=counter, sticky=E + W)
            self.this_max_scale.grid(column=2, row=counter + 1, sticky=E + W)
            self.this_min_scale.ref = 'min_' + ran
            self.this_max_scale.ref = 'max_' + ran
            self.this_min_scale.bind("<ButtonRelease>", self.scale_handler)
            self.this_max_scale.bind("<ButtonRelease>", self.scale_handler)
            counter += 2

    def socket_read_handler(self, file, mask):
        data_object = json.loads(file.recv(1024))
        do = list(data_object.items())[0]
        self.set_value(do[0], do[1])
예제 #7
0
class DownloaderApp(Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.master.title("Youtube to MP3 GUI")
        self.pack()
        self.create_widgets()

    def create_widgets(self):
        # menu bar widgets
        self.menu = Menu(self.master)
        self.filemenu = Menu(self.menu, tearoff=0)
        self.filemenu.add_command(label="Help", command=self.helper)
        self.filemenu.add_command(label="Exit", command=self.master.quit)
        self.menu.add_cascade(label="File", menu=self.filemenu)
        self.about = Menu(self.menu, tearoff=0)
        self.about.add_command(label="Version 2")
        self.about.add_command(label="About...", command=self.aboutwindow)
        self.menu.add_cascade(label="About", menu=self.about)

        # string vars
        self.url = StringVar()
        self.message = StringVar()
        self.artist = StringVar()
        self.album = StringVar()
        self.art = None
        self.art_text = StringVar()

        # organizing frames
        self.frame1 = Frame(self.master)
        self.frame1.pack(side="bottom", fill="both", expand=True)
        self.frame2 = Frame(self.master)
        self.frame2.pack(side="top", fill="both", expand=True)
        self.frame3 = LabelFrame(self.frame1)
        self.frame3.pack(padx=5, pady=3)

        # user input widget
        self.url_label = Label(self.frame3, text="URL:").grid(row=0, column=0)
        self.url_entry = Entry(self.frame3, width=40,
                               textvariable=self.url).grid(row=0, column=1)
        self.artist_label = Label(self.frame3, text="Artist:").grid(row=1,
                                                                    column=0)
        self.artist_entry = Entry(self.frame3,
                                  width=40,
                                  textvariable=self.artist).grid(row=1,
                                                                 column=1)
        self.album_label = Label(self.frame3, text="Album:").grid(row=2,
                                                                  column=0)
        self.album_entry = Entry(self.frame3,
                                 width=40,
                                 textvariable=self.album).grid(row=2, column=1)

        # choose album art widgets
        self.art_button = Button(self.frame3,
                                 text="Choose Album Art",
                                 command=self.getArt).grid(row=3, column=0)
        self.art_label = Label(self.frame3,
                               textvariable=self.art_text).grid(row=3,
                                                                column=1)

        # padding around each user input widget
        for child in self.frame3.winfo_children():
            child.grid_configure(padx=5, pady=3)

        # status bar widget; added before download to sticky to bottom first
        self.statusbar = Label(self.frame1,
                               textvariable=self.message,
                               bd=1,
                               relief="sunken",
                               anchor="w")
        self.statusbar.pack(side="bottom", fill="x")

        # download button widget
        self.download_button = Button(self.frame2,
                                      text="Download",
                                      command=self.download)
        self.download_button.pack(side="bottom", padx=5, pady=3)

        self.master.bind('<Return>', self.download)
        self.master.config(menu=self.menu)

    def download(self, *args):
        #### change the direction of slashes for Windows ###
        self.folder = str(Path.home()) + '/Desktop/NewMusic'
        request = str(self.url.get())
        self.artist_text = str(self.artist.get())
        self.album_text = str(self.album.get())

        if request != EMPTY:
            try:
                if path.isdir(self.folder) != True:
                    mkdir(self.folder)
                else:
                    self.remove_temp()
                    mkdir(self.folder)

                output = self.folder + '/%(title)s.%(ext)s'
                ydl_opts = {
                    'format':
                    'bestaudio/best',
                    'outtmpl':
                    output,
                    'progress_hooks': [self.my_hook],
                    'quiet':
                    True,
                    'postprocessors': [{
                        'key': 'FFmpegExtractAudio',
                        'preferredcodec': 'mp3',
                        'preferredquality': '192'
                    }]
                }

                with YoutubeDL(ydl_opts) as ydl:
                    ydl.download([request])

                self.add_meta()
                self.itunes_import()

                self.remove_temp()
                if self.art != None:
                    remove(self.art)

                self.url.set(EMPTY)
                self.artist.set(EMPTY)
                self.album.set(EMPTY)
                self.art_text.set(EMPTY)
                self.master.update()
            except DownloadError:
                self.remove_temp()
                string = self.url.get()
                string = "Download Error..." + string + " is not a valid URL."
                self.message.set(string)
                self.url.set(EMPTY)
                self.master.update()

    def my_hook(self, d):
        if d['status'] == 'downloading':
            string = 'Downloading.....' + d['_percent_str']
            self.message.set(string)
            self.master.update()
        elif d['status'] == 'finished':
            string = 'Download Complete....'
            self.message.set(string)
            self.master.update()
        else:
            pass

    def getArt(self):
        # get rid of tilde for WINDOWS
        self.art = filedialog.askopenfilename(
            initialdir="~/Desktop",
            title="Select Image",
            filetypes=(("jpeg files", "*.jpg"), ("jpeg files", "*.jpeg")))
        self.art_text.set(self.art)

    def itunes_import(self):
        if path.isdir(ITUNES) == True:
            if path.isdir(self.folder) == True:
                for file in listdir(self.folder):
                    #removes unwanted title strings before move
                    #doesnt work right might need to eyed3 title of file
                    # still doesnt work with path rename
                    # need to idv3 the title
                    x = self.artist_text + " - "
                    y = "(Offical Video)"
                    newname = sub(x, EMPTY, file)
                    newname = sub(y, EMPTY, newname)
                    file_path = self.folder + "/" + file
                    new_path = self.folder + "/" + newname
                    rename(file_path, new_path)
                    import_path = ITUNES + '/' + file
                    move(new_path, import_path)

    def remove_temp(self):
        if path.isdir(self.folder) == True:
            for file in listdir(self.folder):
                file_path = self.folder + "/" + file
                remove(file_path)
        rmdir(self.folder)

    def add_meta(self):
        #test artist and album tags with mutagen
        if self.artist != EMPTY:
            for file in listdir(self.folder):
                file_path = self.folder + "/" + file
                audiofile = eyed3.load(file_path)
                audiofile.tag.artist = self.artist_text
                audiofile.tag.save()
        if self.album != EMPTY:
            for file in listdir(self.folder):
                file_path = self.folder + "/" + file
                audiofile = eyed3.load(file_path)
                audiofile.tag.album = self.album_text
                audiofile.tag.save()
        if self.art != None:
            for file in listdir(self.folder):
                file_path = self.folder + "/" + file
                audiofile = MP3(file_path, ID3=ID3)
                audiofile.tags.add(
                    APIC(mime='image/jpeg',
                         type=3,
                         desc=u'Cover',
                         data=open(self.art, 'rb').read()))
                audiofile.save()

    def helper(self):
        HELP_TEXT = """
        In the case of Errors or Failed Download:

            - Download Location:
                    - downloads are save the iTunes Automatic Import folder
                            - if the song is not in your itunes then the download failed
            - Check video URL:
                    - navigate directly to video/playlist and copy url from the web browser
                    - make sure you are not signed into Youtube Premium premium videos are unsupported
        """

        toplevel = Toplevel()
        label1 = Label(toplevel,
                       text=HELP_TEXT,
                       height=0,
                       width=100,
                       justify='left')
        label1.pack()

    def aboutwindow(self):
        ABOUT = """About"""
        ABOUT_TEXT = """
            Youtube to MP3 Downloader is a GUI interface that allows users to download high
        quality albums from Youtube and other music hosting sites directly to the users desktop.
        For a full list of support sites visit:"""
        SITES = "http://ytdl-org"
        DISCLAIMER = """
        Disclaimer"""
        DISCLAIMER_TEXT = """       Youtube to MP3 Downloader was created using Python 3
        and youtube-dl, an open sourced command line tool. This software is
        protected by the GNU General Public License and as such can be shared freely.
        """
        WARNING = """******* This software comes with no guarantee. Use at your own risk. *******

        Copyright 2011-2020 youtube-dl developers
        """
        toplevel = Toplevel()
        label0 = Label(toplevel, text=ABOUT, height=0, width=100)
        label0.pack()

        label1 = Label(toplevel,
                       text=ABOUT_TEXT,
                       height=0,
                       width=100,
                       justify="left")
        label1.pack()

        label2 = Label(toplevel,
                       text=SITES,
                       fg="blue",
                       cursor="hand2",
                       height=0,
                       width=100)
        label2.pack()

        label3 = Label(toplevel, text=DISCLAIMER, height=0, width=100)
        label3.pack()

        label4 = Label(toplevel,
                       text=DISCLAIMER_TEXT,
                       height=0,
                       width=100,
                       justify="left")
        label4.pack()

        label5 = Label(toplevel, text=WARNING, height=0, width=100)
        label5.pack()
예제 #8
0
파일: main.py 프로젝트: kr1/roqba
    def create_voices(self):
        voice_ids = ['1', '2', '3', '4']
        SCALES = OrderedDict([
                  ('pan_pos', {'min': -1, 'max': 1, 'start': 0.5, 'res': 0.001}),
                  ('volume', {'min': 0, 'max': 1, 'start': 0.666, 'res': 0.001}),
                  ('slide_duration_msecs', {'min': 0, 'max': 2000, 'start': 60, 'res': 1}),
                  ('slide_duration_prop', {'min': 0, 'max': 2, 'start': 0.666, 'res': 0.001}),
                  ('binaural_diff', {'min': 0, 'max': 66, 'start': 0.2, 'res': 0.01})
                ])

        for vid in voice_ids:
            counter = 0
            for sca in SCALES:
                name = 'voice_' + vid + '_' + sca
                setattr(self, 'min_' + name, SCALES[sca]['min'])
                setattr(self, 'max_' + name, SCALES[sca]['max'])
                this_sca = Scale(self, label=sca, orient=HORIZONTAL,
                                 from_=getattr(self, 'min_' + name),
                                 to=getattr(self, 'max_' + name),
                                 resolution=SCALES[sca]['res'])
                this_sca.enable = ('enable' in list(SCALES[sca].keys()) and
                                   SCALES[sca]['enable'] or None)
                this_sca.disable = ('disable' in list(SCALES[sca].keys()) and
                                    SCALES[sca]['disable'] or None)
                this_sca.grid(column=int(2 + int(vid)), row=counter, sticky=E + W)
                this_sca.bind("<ButtonRelease>", self.scale_handler)
                this_sca.ref = name
                counter += 1
        CHECK_BUTTONS = OrderedDict(
                 [('mute', False),
                  ('automate_binaural_diffs', True),
                  ('automate_note_duration_prop', True),
                  ('use_proportional_slide_duration', {'val': True, 'label': 'proportional slide'}),
                  ('automate_pan', True),
                  ('automate_wavetables', True)])
        for vid in voice_ids:
            counter = 0
            cb_frame = LabelFrame(self, text="Voice {0} - Automation".format(vid))
            setattr(self, 'voice_' + vid + '_cb_frame', cb_frame)
            for cb in CHECK_BUTTONS:
                options = CHECK_BUTTONS[cb]
                name = 'voice_' + vid + '_' + cb
                if isinstance(options, dict) and 'label' in list(options.keys()):
                    label = options['label']
                else:
                    label = cb[9:] if cb[:9] == 'automate_' else cb
                setattr(self, name, IntVar(
                    value=type(options) == dict and options['val'] or options))
                self.this_cb = Checkbutton(cb_frame, text=label, variable=getattr(self, name))
                self.this_cb.bind('<Button-1>', self.check_boxes_handler)
                self.this_cb.disable = None
                self.this_cb.grid(sticky=W, column=0, row=counter)
                self.this_cb.ref = name
                counter += 1
            # add trigger wavetable-button
            trigWavetableButton = Button(cb_frame, text='Next Wavetable')
            trigWavetableButton.bind('<Button-1>', self.trigger_waveform_handler)
            trigWavetableButton.ref = 'voice_' + vid + "_trigger_wavetable"
            trigWavetableButton.grid(row=counter)
            cb_frame.grid(column=int(vid) + 2, row=5, sticky=E + W + N, rowspan=8)
        for vid in voice_ids:
            generation_types = ["random", "random_harmonic", "harmonic"]
            partial_pools = ["even", "odd", "all"]
            prefix = 'voice_' + vid + '_'
            types_name = prefix + 'wavetable_generation_type'
            pools_name = prefix + 'partial_pool'
            setattr(self, types_name, StringVar())
            getattr(self, types_name).set("random")
            setattr(self, pools_name, StringVar())
            getattr(self, pools_name).set("all")
            target_frame = getattr(self, 'voice_' + vid + '_cb_frame')
            gen_typ_frame = LabelFrame(target_frame, text="type")
            gen_typ_frame.grid(row=len(target_frame.winfo_children()), sticky=W)
            for gen_t in generation_types:
                gen_t_entry = Radiobutton(gen_typ_frame, value=gen_t, text=gen_t, anchor=W,
                                          variable=getattr(self, types_name))
                gen_t_entry.bind('<ButtonRelease-1>', self.wt_handler)
                gen_t_entry.ref = types_name
                gen_t_entry.grid(row=len(gen_typ_frame.winfo_children()), sticky=W)
            pp_frame = LabelFrame(target_frame, text="harmonics")
            for pp in partial_pools:
                pp_entry = Radiobutton(pp_frame, value=pp, text=pp, anchor=W,
                                       variable=getattr(self, pools_name))
                pp_entry.bind('<ButtonRelease-1>', self.wt_handler)
                pp_entry.ref = pools_name
                pp_entry.grid(row=len(pp_frame.winfo_children()), sticky=E + W)
            this_num_partials = Scale(pp_frame, label='number of harmonics', orient=HORIZONTAL,
                                      from_=1, to=24, resolution=1)
            this_num_partials.ref = prefix + 'num_partials'
            this_num_partials.grid(column=0, row=len(pp_frame.winfo_children()), sticky=E + W)
            this_num_partials.bind("<ButtonRelease>", self.scale_handler)
            pp_frame.grid(row=len(target_frame.winfo_children()), sticky=E + W)
예제 #9
0
def _clear_frame(frame: tk.LabelFrame):
    for widget in frame.winfo_children():
        widget.destroy()
예제 #10
0
class WaltzGUI(lx.Lx200Commands):
    def __init__(self, master):
        """Class builds GUI to control Waltz Telescope.
           Uses Tkinter for GUI functionality.
           Inherits from lx200commands.Lx200Commands class.
           This class provides functionality to talk to serial connection 
           using the lx200 protocol.
        """
        
        super().__init__()
        
        self.master = master
        master.title("Waltz Control Panel")
       
        #Store CET and UCT
        self.CET = ''
        self.UTC = ''
        
        #Store if telescope is waiting for slew to finish
        self.waiting=True
        
        ## Building up GUI Widgets ##
        
        #Menubars
        menubar=Menu(self.master)
        
        #Connection menu
        connectionmenu = Menu(menubar, tearoff=0)
        connectionmenu.add_command(label="Open Connection", command=self.open_connection_buttonclick)
        connectionmenu.add_command(label="Close Connection", command=self.close_connection_buttonclick)
        menubar.add_cascade(label="Connection", menu=connectionmenu)
        
        #settings_menu
        settings_menu=Menu(menubar, tearoff=0)
        settings_menu.add_command(label="Enable buttons",command=self.stop_waiting)
        settings_menu.add_command(label="Toggle Precision",command=super().toggle_precision)
        menubar.add_cascade(label="Settings",menu=settings_menu)
        
        
        
        #Pointing_stars_menu
        pointing_stars_menu=Menu(menubar, tearoff=0)
        pointing_stars_menu.add_command(label="Pointing Star", command=self.save_pointing_star)
        menubar.add_cascade(label="Save as", menu= pointing_stars_menu)
        
        #Special_positions_menu
        special_positions_menu=Menu(menubar, tearoff=0)
        special_positions_menu.add_command(label="Slew to Primary Mirror Position",command=self.primary_mirror_pos_buttonclick)
        special_positions_menu.add_command(label="Slew to Secondary Mirror Position",command=self.secondary_mirror_pos_buttonclick)
        special_positions_menu.add_command(label="Slew to Park Position",command=self.park_telescope_buttonclick)
        menubar.add_cascade(label="Special Positions",menu=special_positions_menu)
        
        
        #Show menubar
        self.master.config(menu=menubar)
        
        #Output frame
        output_frame=Frame(master)
        output_frame.grid(row=0,columnspan=3)

        self.LST_label = Label(output_frame,
                               font=('arial', 15, 'bold'),
                               text="LST")
        self.LST_label.grid(row=0,column=0)
        
        self.LST_display = Label(output_frame,
                                 font=('arial', 20, 'bold'),
                                 bg='light green')
        self.LST_display.grid(row=0, column=1,padx=10, pady=10)
        
        self.local_time_label= Label(output_frame,
                              font=('arial', 15, 'bold'),
                              text='LT')
        self.local_time_label.grid(row=0, column=3)
        
        self.local_time_display = Label(output_frame,
                                 font=('arial', 20, 'bold'),
                                 bg='light green')
        self.local_time_display.grid(row=0, column=4,padx=10,pady=10)
        
        self.UTC_label= Label(output_frame,
                              font=('arial', 15, 'bold'),
                              text='UTC')
        self.UTC_label.grid(row=0, column=5)
        
        self.UTC_display = Label(output_frame,
                                 font=('arial', 20, 'bold'),
                                 bg='light green')
        self.UTC_display.grid(row=0, column=6,padx=10,pady=10)
        
        
        
        self.RA_label= Label(output_frame,
                             font=('arial', 15, 'bold'),
                             text= "RA")
        self.RA_label.grid(row=1, column =0)
        
        self.RA_display= Label(output_frame,
                               font=('arial', 20, 'bold'), 
                               bg='light green')
        self.RA_display.grid(row=1, column =1)
        
        self.DEC_label= Label(output_frame,
                              font=('arial', 15, 'bold'),
                              text= "DEC")
        self.DEC_label.grid(row=1, column =3)
        
        self.DEC_display= Label(output_frame,
                                font=('arial', 20, 'bold'),
                                bg='light green')
        self.DEC_display.grid(row=1, column =4)
        
        self.HA_label= Label(output_frame,
                              font=('arial', 15, 'bold'),
                              text= "HA")
        self.HA_label.grid(row=1, column =5)
        
        self.HA_display= Label(output_frame,
                                    font=('arial', 20, 'bold'),
                                    bg='light green')
        self.HA_display.grid(row=1, column=6)
        
        #Interchange_frame
        #To interchange W<->E buttons and N<->S
        self.interchange_frame=Frame(master)
        self.interchange_frame.grid(row=1, column=0,pady=10)
        #Define Variables
        self.inter_WE=IntVar()
        self.inter_NS=IntVar()
        self.inter_NS_checkbox=Checkbutton(self.interchange_frame,
                                           text='N <> S',
                                           font=('arial', 10, 'bold'),
                                           variable=self.inter_NS,
                                           command=self.interchange_north_south)
        self.inter_NS_checkbox.grid(row=0,column=0,sticky='w',pady=5)
        
        
        self.inter_WE_checkbox=Checkbutton(self.interchange_frame,
                                           text='W <> E',
                                           font=('arial', 10, 'bold'), 
                                           variable=self.inter_WE,
                                           command=self.interchange_west_east)
        self.inter_WE_checkbox.grid(row=1,column=0,sticky='w',pady=5)
        
        
        
        #Control frame
        self.control_frame=Frame(master)
        self.control_frame.grid(row=1,column=1,pady=10)


        self.south_button = Button(self.control_frame,
                                   text="S",
                                   font=('arial', 20, 'bold'),
                                   bg='LightGrey',
                                   height = 1, 
                                   width = 2)
        self.south_button.grid(row=0,column=1)
        
        self.west_button = Button(self.control_frame,
                                  text="W",
                                  font=('arial', 20, 'bold'),
                                  bg='LightGrey',
                                  height = 1,
                                  width = 2)
        self.west_button.grid(row=1,column=0)
        
        self.east_button = Button(self.control_frame,
                                  text="E",
                                  font=('arial', 20, 'bold'),
                                  bg='LightGrey',
                                  height = 1,
                                  width = 2)
        self.east_button.grid(row=1,column=2)
        
        
        self.north_button = Button(self.control_frame,
                                   text="N",
                                   font=('arial', 20, 'bold'),
                                   bg='LightGrey',
                                   height = 1,
                                   width = 2)
        self.north_button.grid(row=2,column=1)
        
        self.stop_button = Button(self.control_frame,
                                  text="STOP",
                                  font=('arial',20, 'bold'),
                                  fg='White',
                                  bg='Red',
                                  activeforeground='Red',
                                  activebackground='White',
                                  command=super().stop_at_current_pos)
        self.stop_button.grid(row=3,column=0, columnspan=3, pady=10)

        #Radiobutton frame
        self.radiobutton_frame=Frame(master)
        self.radiobutton_frame.grid(row=1,column=2,pady=10)
        
        
        radiobutton_parameters=[('Slew',0,self.set_speed_max),
                                ('Find',1, self.set_speed_find),
                                ('Center',2, self.set_speed_center),
                                ('Guide',3, self.set_speed_guide)]
        
        self.speed=StringVar()
        #Initialize speed to guiding speed
        self.speed.set('Guide')
        
        for keyword, position, execute in radiobutton_parameters:
            self.speed_radiobutton= Radiobutton(self.radiobutton_frame,
                                                text=keyword,
                                                variable=self.speed,
                                                value=keyword,
                                                command=execute,
                                                font=('arial', 10, 'bold'))
            self.speed_radiobutton.grid(row=position,column=0,sticky=W)
        
        #Options Frame
        self.options_frame=Frame(master)
        self.options_frame.grid(row=0,column=3,padx=20)
     
        self.sync_button = Button(self.options_frame,
                                       text="Synchronize \n with Target",
                                       font=('arial', 12, 'bold'),
                                       bg='LightGrey',
                                       command=self.sync_yes_no,
                                       state='disabled')
        self.sync_button.grid(row=0,column=0,padx=5)
        
        
        
        
        #Target Frame
        self.target_frame=LabelFrame(master,
                                text='Select Target (apparent position)',
                                font=('arial', 15))
        self.target_frame.grid(row=1,rowspan=1,column=3,padx=20)
        
        self.HIP_label = Label(self.target_frame,
                               font=('arial', 15),
                               text="Hipparcos")
        self.HIP_label.grid(row=0,column=0)
        
        self.HIP_entry= Entry(self.target_frame,
                              font=('arial', 15))
        self.HIP_entry.grid(row=0, column=1,pady=10)
        
        
        self.target_ra_label = Label(self.target_frame,
                                     font=('arial', 15),
                                     text="RA \n [hh mm ss]")
        self.target_ra_label.grid(row=1,column=0)
        
        self.target_ra_entry= Entry(self.target_frame,
                                    font=('arial', 15))
        self.target_ra_entry.grid(row=1, column=1,pady=10)

        
        self.target_dec_label = Label(self.target_frame,
                                      font=('arial', 15),
                                      text="""DEC \n [°° mm ss]""")
        self.target_dec_label.grid(row=2,column=0)
        
        self.target_dec_entry= Entry(self.target_frame,
                                     font=('arial', 15))
        self.target_dec_entry.grid(row=2, column=1,pady=10)
        
        self.target_time_label= Label(self.target_frame,
                                     font=('arial', 15),
                                     text=" Obs \n Time")
        self.target_time_label.grid(row=0,column=2,padx=10)
        
        self.target_time_display=Label(self.target_frame,
                                    font=('arial', 15),
                                    bg='red',
                                    width=10)
        self.target_time_display.grid(row=0,column=3,pady=10)
        
        self.target_alt_label = Label(self.target_frame,
                                     font=('arial', 15),
                                     text="ALT")
        self.target_alt_label.grid(row=1,column=2,padx=10)
        
        self.target_alt_display= Label(self.target_frame,
                                    font=('arial', 15),
                                    bg='red',
                                    width=10)
        self.target_alt_display.grid(row=1, column=3,pady=10)
        
        self.target_az_label = Label(self.target_frame,
                                     font=('arial', 15),
                                     text="AZ")
        self.target_az_label.grid(row=2,column=2,padx=10)
        
        self.target_az_display= Label(self.target_frame,
                                    font=('arial', 15),
                                    bg='red',
                                    width=10)
        self.target_az_display.grid(row=2, column=3,pady=10)
        
        self.slew_target_button = Button(self.target_frame,
                                         text="Slew to Target",
                                         font=('arial', 15),
                                         bg='LightGrey',
                                         state='disabled',
                                         command=self.slew_to_target_buttonclick)
        self.slew_target_button.grid(row=3,columnspan=4)
        
        #Plot Frame
        self.plot_frame=Frame(master)
        self.plot_frame.grid(row=2,columnspan=4)
        #Add instance variables to store the plot and the different axes,
        #and positions globally
        self.canvas=False
        self.ax1=False
        self.star_plot=False
        self.traj_plot=False
        self.pos_plot=False
        self.ax2=False
        
        #At first check if serial connection is open (also contains initial commands)
        self._respond_to_connection_state()
        
        #Message box for Warning
        caution=("CAUTION: THIS IS A FIRST ATTEMPT TO CONTROL THE WALTZ TELESCOPE.\n"+
                 "BAD INPUTS OR CRASHES OF THE PROGRAM COULD BE HARMFUL TO THE TELESCOPE.\n"+
                 "DO NOT USE THIS PROGRAM ALONE AND ALWAYS PREPARE FOR STOPING MOVEMENTS "+ 
                 "OF THE TELESCOPE VIA THE EMERGENCY STOPS IN THE DOME!")
        messagebox.showwarning("Warning",message=caution,parent=master)
    
    
    def close_connection_buttonclick(self):
        """ Closes the connection to serial and responds properly to it
        """
        #First check the connection state
        if self.connected==False:
            print('Connection already closed')
            return 0
        #Close serial connection
        super().close_connection()
        #Check if connection is realy closed
        #this will set self.connected=False
        #Respond to closed connection
        self._respond_to_connection_state()
        
        
    def open_connection_buttonclick(self):
        """ Closes the connection to serial and responds properly to it
        """
        #First check the connection state
        if self.connected==True:
            print('Connection already open')
            return 0
        #Open serial connection
        super().open_connection()
        #Respond to open connection
        self._respond_to_connection_state()
    
    
    def _start_commands(self):
        """ Contains all functions to be executed at start of program.
        """
        
        #Commands to be executed even without connection
        self.refresh_times()
        self.initialize_plot()
        
        #If connection is not open close program
        if not self.connected:
            return 0
        
        #Commands for initial settings
        self.set_speed_guide()
        #This is the StringVar defining which initial setting the speed Radiobuttons have
        self.speed.set('Guide')
        
        #Commands to be executed all the time (if connection is open)
        self.display_coordinates()
        self.refresh_target_alt_az_ha()
        
        #Check for format of coordinates and toggle automatically
        #We always want format DEC=dd mm ss
        if len(self.dec)==7:
            super().toggle_precision()
    def _respond_to_connection_state(self):
        """ Checks connection to serial port.
            Print Warning if not and closes program.
            Enables and binds all buttons if connection is set.
        """
        #If connection to Waltz is closed
        if not self.connected:
            #Disable all buttons
            self.disable_all_buttons()
            self.stop_button.config(state='disabled')
            #Message box if serial connection is not open
            caution=("Warning: No Connection to Waltz")
            messagebox.showwarning("Warning",message=caution,parent=self.master)
            #Start Commands 
            #(it will take care that only the ones that do not use the serial connection are executed)
            self._start_commands()
        if self.connected:
            #Enable all buttons
            self.enable_all_buttons()
            #Start Commands
            self._start_commands()
                    
    def refresh_times(self):
        """ Refreshs all times (LST, LT, UTC)
        
            Introduced to have only one function call in the background.
            Better to syn clocks
        """
        #Refresh individual times
        self.refresh_LST()
        self.refresh_local_time()
        self.refresh_UTC()
        
        #Also refresh hour_angle synced to times because it will change in the same pace
        super().calculate_hour_angle()
        self.HA_display.config(text=self.ha)
        #Calls itself all 200 ms
        self.master.after(200, self.refresh_times)
    
    def refresh_local_time(self):
        """ Displays the current Central Eruopean Time on CET_display.
            Calls itself all 200ms to refresh time.
        """
        
        # get the current local time from the PC
        local_time_now = time.strftime('%H:%M:%S')
        # if time string has changed, update it
        if local_time_now != self.CET:
            self.local_time = local_time_now
            self.local_time_display.config(text=self.local_time)
    
    def refresh_LST(self):
        """ Displays the current Local Sidereal Time on LST_display.
            Calls itself all 200ms to refresh time.
        """
        super().get_LST()
        self.LST_display.config(text=self.LST)
        
    def refresh_UTC(self):
        """ Displays the current Coordinated Universal Time on UTC_display.
            Calls itself all 200 ms to refresh time.
        """
        #Get current UTC from datetime
        UTC_now= datetime.datetime.utcnow()
        UTC_now=UTC_now.strftime("%H:%M:%S")
        #Check if UTC has changed since last call
        if UTC_now != self.UTC:
            #Save current UTC in self.UTC
            self.UTC = UTC_now
            #Display UTC
            self.UTC_display.config(text=self.UTC)
            
    def initialize_plot(self):
        """Refreshs Plot.
        """
        #Close all plots for safety reasons
        #plt.close('all')
        (fig,
         self.ax1) = plot_traj_limits_altaz_GUI(False,False,False,False)
        self.canvas = FigureCanvasTkAgg(fig, master = self.plot_frame)
        self.canvas._tkcanvas.grid(row=0,column=0)
        self.plot_current_pos()
        
    def plot_current_pos(self):
        """Overplots current position. Plot needs to already exist.
        """
        #First remove existing pos_plot (if it exists)
        if self.pos_plot:
            self.pos_plot.pop(0).remove()
        #Now add new pos_plot
        self.pos_plot=add_current_pos(self.ax1,self.ha_float,self.dec_float)
        self.canvas.draw()
        self.master.after(1000,self.plot_current_pos)
        
    def plot_star_and_traj(self):
        """Overplots star position and trajectory. Plot need to already exist.
        
           Will be called periodically with refresh_target_alt_az_ha.
        """
        #First remove existing star_plot/traj_plot (if they exists)
        if self.star_plot:
            self.star_plot.pop(0).remove()
            self.traj_plot.pop(0).remove()
            self.ax2.remove()
        if not self.target_ra_float or not self.target_dec_float:
            return 0
        #Now add new_star_plot
        (self.star_plot,
         self.traj_plot,
         self.ax2)=add_star_and_traj(self.ax1,
                                     self.target_ha_float,
                                     self.target_dec_float)
        self.canvas.draw()
        
        
    
    def display_coordinates(self):
        """ Displays Right ascension and Declination.
            
            Hour angle will be displayed synced to times.
            It should change at the same rate as LST.
            Look at refresh_times()
        """
        
        #If connection is not open close program
        if not self.connected:
            return 0
        
        self.get_coordinates()
        self.RA_display.config(text=self.ra)
        self.DEC_display.config(text=self.dec)
        if not self.connected:
            self._respond_to_connection_state()

        self.master.after(500,self.display_coordinates)
        
    def refresh_target_alt_az_ha(self,call_itself=True):
        """ Executes Lx200Commands.calculate_target_alt_az_ha every 500 ms.
        """
        #Calculate target alt and az and obs time
        super().calculate_target_alt_az_ha()
        #Display alt, az and obs time
        self.target_alt_display.config(text=self.target_alt)
        self.target_az_display.config(text=self.target_az)
        self.target_time_display.config(text=self.target_obs_time)
        #Check coordinates to reply with correct colors
        if check_coordinates(self.target_alt_float,
                                    self.target_az_float):
            self.display_alt_az('light green')
        else:
            self.display_alt_az('red')
        #Update the plot
        self.plot_star_and_traj()
        #Optionally call itself
        if call_itself:
            self.master.after(5000,self.refresh_target_alt_az_ha)
        
    def interchange_west_east(self):
        """Interchanges West and East Buttons.
        """
        #self.inter_WE.get() will return 1 if box is checked and 0 if not
        if self.inter_WE.get():
            #Grid Positions if checkbutton is checked
            self.west_button.grid(row=1,column=2)
            self.east_button.grid(row=1,column=0)  
        if not self.inter_WE.get():
            #Grid Position in default state
            self.west_button.grid(row=1,column=0)
            self.east_button.grid(row=1,column=2)
            
    def interchange_north_south(self):
        """Interchanges North and South Buttons.
        """
        #self.inter_WE.get() will return 1 if box is checked and 0 if not
        if self.inter_NS.get():
            #Grid Positions if checkbutton is checked
            self.south_button.grid(row=2,column=1)
            self.north_button.grid(row=0,column=1)  
        if not self.inter_NS.get():
            #Grid Position in default state
            self.south_button.grid(row=0,column=1)
            self.north_button.grid(row=2,column=1)
            
    def start_move_west_buttonclick(self, event):
        """ Sends move west LX200 command to serial connection
        """
        super().start_move_west()
        
    def stop_move_west_buttonclick(self, event):
        """ Sends stop move west LX200 command to serial connection
        """
        super().stop_move_west()
        
    def start_move_north_buttonclick(self, event):
        super().start_move_north()
        
    def stop_move_north_buttonclick(self, event):
        super().stop_move_north()
        
    def start_move_south_buttonclick(self, event):
        super().start_move_south()
        
    def stop_move_south_buttonclick(self, event):
        super().stop_move_south()
        
    def start_move_east_buttonclick(self, event):
        super().start_move_east()
        
    def stop_move_east_buttonclick(self, event):
        super().stop_move_east()
        
    def slew_to_target_buttonclick(self):
        """Slews to target.
           Target must be set before via set_target_dec_from_string and set_target_ra_from_string
        """
        super().set_target_coordinates()
        #Slew to target and wait for slew to finish
        super().slew_to_target()
        self.wait_for_slew_finish()
        
        #After slewing (and if something went wrong):
        #Set all valid_target entries to 0 (controller won't let you slew to
        #the same coordinates twice
        self.valid_target=[0,0]
        self.slew_target_button.config(state='disabled')
    
    #def continue_slew(self,initial_target_ra, initial_target_dec):
        """ Continues slewing after possible initial slew to medium position.
            Performs slewing if no slew to medium position is necessary.
        """
        #Check if slew is finished. Default Value of slew_done=True,
        #so it will also be True if no slew to medium position was necessary.)
        #if self.slew_done:
            #Set the initial target coordinates as normal target coordinates again
            #super().set_target_ra_from_string(initial_target_ra)
            #super().set_target_dec_from_string(initial_target_dec)
            #Slew to target
            #super().slew_to_target()
            #Wait for the slew to finish (disables all buttons etc.)
            #self.wait_for_slew_finish()
        #else:
            #If previous slew is not finished the funcion will call itself every second.
            #self.master.after(1000, self.continue_slew, initial_target_ra, initial_target_dec)
        
    def park_telescope_buttonclick(self,counter=1,park=True):
        """Parks telescope and waits for slew to finish.
           
           counter counts if parking is executed the first or 
           second time.
           park specifies if controller gets a parking command 
           or if the function just waits until first slew has finished.
        """
        #We need to call park telescope twice 
        #because the tracking will change RA while DEC is still adjusting
        #Park telescope for the first time
        if counter==1:
            #If parking is activated
            if park:
                print('Slew to Park Position the first time')
                #Slew telescope to parking position
                super().park_telescope()
                self.refresh_target_alt_az_ha(call_itself=False)
            #Start waiting: Call wait_for_slew_finish with call_itself=False
            #So the funtion will just check if slew has finished
            if not self.wait_for_slew_finish(call_itself=False):
                #If slew has not yet finished
                print('Waiting for First Parking to finish')
                #Call the park funtion after 1 sec with counter=1 and slew=False
                #So it will be in counter=1 loop but will not send 
                #a park command to the controller
                self.master.after(1000,self.park_telescope_buttonclick,
                                  1,False)
                return 0
            else:
                #If slewing has finished
                #Disable all buttons (need because it will otherwise wait
                #for one second until it disables again)
                self.disable_all_buttons()
                print('Finished First Parking')
                #Call park function again after 1 second but enter counter=2 loop
                #Also activate parking again with park=True
                #Useful to wait one second as safetiy that slewing has stopped
                self.master.after(1000,self.park_telescope_buttonclick,
                                  2,True)
                return 0
        #Second Parking loop
        if counter==2:
            if park:
                #If parking is activated
                print('Slew to Park Position the second time')
                #Slew telescope to parking position
                super().park_telescope()
                self.refresh_target_alt_az_ha(call_itself=False)
                #Wait again as above. But call counter=2 fpr second parking loop
            if not self.wait_for_slew_finish(call_itself=False):
                print('Waiting for Second Parking to finish')
                self.master.after(1000,self.park_telescope_buttonclick,
                                  2,False)
                return 0
            else:
                #When slewing is done
                print('Finished Second Parking')
                #Show message box to tell user to shut off the controller
                message=("Turn off the telescope controller to stop tracking"+
                 " and remain in park position!")
                messagebox.showinfo("Information",message=message,parent=self.master)
                return 0 
        
    def primary_mirror_pos_buttonclick(self):
        """Slew Telescope to Primary Mirror Cover Position.
        
           Uses LX200Commands primary_mirror_pos.
        """
        super().primary_mirror_pos()
        self.refresh_target_alt_az_ha(call_itself=False)
        self.wait_for_slew_finish()
        
    def secondary_mirror_pos_buttonclick(self):
        """Slew Telescope to Secondary Mirror Cover Position.
        
           Uses LX200Commands secondary_mirror_pos.
        """
        super().secondary_mirror_pos()
        self.refresh_target_alt_az_ha(call_itself=False)
        self.wait_for_slew_finish()
        
    def set_target_coordinates_gui(self):
        """ Calls set_target_coordinates() of Lx200Commands.
            Defines GUIs reaction to target_coordinates.
        """
        
        #Call set_target_coordinates
        if not self.set_target_coordinates():
            self.slew_target_button.config(state='disabled')
            self.display_alt_az('red')
            #Also plot target coordinates
            self.plot_star_and_traj()
            return 0
        else:
            #Display target_alt and az
            self.slew_target_button.config(state='normal')
            self.display_alt_az('light green')
            #Also plot target coordinates
            self.plot_star_and_traj()
            
    def display_alt_az(self,color):
        """Displays alt and az with given color.
        
           Convenience function.
        """
        self.target_alt_display.config(text=self.target_alt)
        self.target_alt_display.config(bg=color)
        self.target_az_display.config(text=self.target_az)
        self.target_az_display.config(bg=color)
        self.target_time_display.config(text=self.target_obs_time)
        self.target_time_display.config(bg=color)
        
      
    def set_hip_target_from_entry(self, event):
        """ Gets a HIP number from the HIP_entry widget and calculates the coordinates.
            Sets these coordinates as target_ra and target_dec 
            and displays them in the corresponding entry widgets.
        """
        hip_nr=self.HIP_entry.get()
        super().set_hip_target(hip_nr)
        self.target_ra_entry.delete(0, END)
        self.target_ra_entry.insert(0, self.target_ra)
        self.target_dec_entry.delete(0, END)
        self.target_dec_entry.insert(0, self.target_dec)
        self.set_target_coordinates_gui()
        
           
    def set_target_ra_from_entry(self, event):
        """ Gets a ra input from the target_ra_entry widget and sets it as target_ra.
            Accepted formats include hh mm ss and hh mm.t.
            
            Also tries to set set target dec from entry.
            Clears text of HIP_entry widget.
        """
        #Delete hip entry
        self.HIP_entry.delete(0, END)
        #Get ra input and set as target_ra
        ra_input=self.target_ra_entry.get()
        super().set_target_ra_from_string(ra_input)
        self.target_ra_entry.delete(0, END)
        self.target_ra_entry.insert(0, self.target_ra)
        
        #Try to get dec entry also
        dec_input=self.target_dec_entry.get()
        #If dec entry is empty do not try to set target_dec
        if not dec_input=='':
            super().set_target_dec_from_string(dec_input)
            self.target_dec_entry.delete(0, END)
            self.target_dec_entry.insert(0, self.target_dec)
        
        self.set_target_coordinates_gui()
        
    def set_target_dec_from_entry(self, event):
        """ Gets a dec input from the target_dec_entry widget and sets it as target_ra.
            Accepted formats include dd mm ss and dd mm.
            Clears text of HIP_entry widget.
        """
        #Delete hip entry
        #Get dec input and set as target_dec
        self.HIP_entry.delete(0, END)
        dec_input=self.target_dec_entry.get()
        super().set_target_dec_from_string(dec_input)
        self.target_dec_entry.delete(0, END)
        self.target_dec_entry.insert(0, self.target_dec)
        
        #Try to get ra entry also
        ra_input=self.target_ra_entry.get()
        #If ra entry is empty do not try to set target_ra
        if not ra_input=='':
            super().set_target_ra_from_string(ra_input)
            self.target_ra_entry.delete(0, END)
            self.target_ra_entry.insert(0, self.target_ra)
        
        self.set_target_coordinates_gui()
        
    def sync_yes_no(self):
        """Displays yes/no message if sync_button is clicked on.
        """
        result=messagebox.askyesno("Synchroniziation", 
                                     "Do you really want to synchronize coordinates with target coordinates?")
        if result:
            self.sync_on_target_buttonclick()
        
    def sync_on_target_buttonclick(self):
        """Gets target coordinates from entries.
           Synchronizes coordinates with target coordinates.
           In Case of Hipparcos target it will recalculate target coordinates
           at time of synchronization.
        """
        hip_nr=self.HIP_entry.get()
        if hip_nr!='':
            super().sync_on_hip(hip_nr)
            self.target_ra_entry.delete(0, END)
            self.target_ra_entry.insert(0, self.target_ra)
            self.target_dec_entry.delete(0, END)
            self.target_dec_entry.insert(0, self.target_dec)
        else:
            #If no Hip target_ get coordinates from entries
            #Calling one entry is enough since always both entries are checked
            #None refers to no event (such as Return)
            self.set_target_ra_from_entry(None)
            if hip_nr=='' and self.target_ra and self.target_dec:
                super().sync_on_coordinates()
            else:
                print('No valid coordinates set. Synchronisation stopped')
        #After sync (and if something went wrong):
        #Set all valid_target entries to 0 (controller won't let you slew to
        #the same coordinates twice
        self.valid_target=[0,0]
        self.slew_target_button.config(state='disabled')
            
    def wait_for_slew_finish(self,call_itself=True):
        """Waits until coordinates equal target coordinates within tolerance.
           Disables all (except STOP) buttons until target coordinates are reached.
           call_itself determines if funtion will call itself after 1 second.
           This is very useful to set to False if you want to call waiting from
           different function that should pause until waiting is over.
           
           Can be stopped by stop_waiting.
        """
        #Disable all buttons
        self.disable_all_buttons()
        #Check if slew has finished or self.stop_waiting parameter=True
        #Enable buttons if so.
        #self.stop_waiting parameter can be set by button in menubar
        #Then break the loop
        if super().slew_finished():
            #Enable all buttons again
            self.enable_all_buttons()
            return True
        else:
            #If variable call_itself is true
            #Calls itself after 1 second.
            #After call is asigned to global variable waiting 
            #to stop it via stop_waiting.
            if call_itself:
                global waiting
                waiting=self.master.after(1000,self.wait_for_slew_finish)
            return False
    
    def stop_waiting(self):
        """Stops Waiting for slew to finish and enables all buttons.
        
           Can be called in the menu.
        """
        #First disable all buttons to avoid binding events more than once.
        self.disable_all_buttons()
        #Enable all buttons 
        self.enable_all_buttons()
        #And try to stop waiting if waiting is going on.
        try:
            self.master.after_cancel(waiting)
        except NameError:
            return 0
        
    def delete_entries(self,event):
        """ Deletes entries of target_ra and target_dec.
        
            Used when entering new Hipparcos Number.
        """
        self.target_ra_entry.delete(0,END)
        self.target_dec_entry.delete(0,END)
            
        
    def disable_all_buttons(self):
        """ Disables all buttons and unbinds all bindings.
            Except of Stop Button
        """
        #Disable all buttons 
        #We also need to unbind the buttons which are called by events instead of commands
        for child in self.control_frame.winfo_children():
            child.config(state='disabled')
            child.unbind("<ButtonPress-1>")
            child.unbind("<ButtonRelease-1>")
        #Enable Stop Button again. It should always be enabled.
        self.stop_button.config(state='normal')
        
        #Disable and unbind entry widgets in target_frame
        for child in self.target_frame.winfo_children():
            child.config(state='disabled')
            child.unbind("<Return>")
            child.unbind("<Tab>")
        
        
        self.sync_button.config(state='disabled')
        
        #Radiobuttons
        for child in self.radiobutton_frame.winfo_children():
            child.config(state='disabled')
        
    def enable_all_buttons(self):
        """ Enables all buttons and binds all bindings.
            Except of Stop Button.
            All bindings are defined here, except of commands of buttons.
        """
        #Disable all buttons 
        #We also need to bind the buttons which are called by events instead of commands
        for child in self.control_frame.winfo_children():
            child.config(state='normal')
        #Add the bindings manually
        self.north_button.bind("<ButtonPress-1>",self.start_move_north_buttonclick)
        self.north_button.bind("<ButtonRelease-1>",self.stop_move_north_buttonclick)
        self.west_button.bind("<ButtonPress-1>",self.start_move_west_buttonclick)
        self.west_button.bind("<ButtonRelease-1>",self.stop_move_west_buttonclick)
        self.south_button.bind("<ButtonPress-1>",self.start_move_south_buttonclick)
        self.south_button.bind("<ButtonRelease-1>",self.stop_move_south_buttonclick)
        self.east_button.bind("<ButtonPress-1>",self.start_move_east_buttonclick)
        self.east_button.bind("<ButtonRelease-1>",self.stop_move_east_buttonclick)
        
        
        self.sync_button.config(state='normal')
        
        #Enable and bind entry widgets in target_frame
        for child in self.target_frame.winfo_children():
            child.config(state='normal')
        #Do not enable slew button
        self.slew_target_button.config(state='disabled')
        #Add the bindings manually
        #When entering any new number or char (also when deleting),
        #the entries of target_ra and target_dec should be deleted
        #Important to bind Return and Tab after this first binding to override this functionality
        #Otherwise it would also just delete the entries
        self.HIP_entry.bind("<Key>",
                            self.delete_entries,add='+')
        self.HIP_entry.bind("<Return>",
                            self.set_hip_target_from_entry, add="+")
        self.HIP_entry.bind("<Tab>",
                            self.set_hip_target_from_entry, add="+")

        
        self.target_ra_entry.bind("<Return>",
                                  self.set_target_ra_from_entry, add="+") 
        self.target_ra_entry.bind("<Tab>",
                                  self.set_target_ra_from_entry,add="+")
        
        
        self.target_dec_entry.bind("<Return>",
                                   self.set_target_dec_from_entry, add="+")
        self.target_dec_entry.bind("<Tab>", 
                                   self.set_target_dec_from_entry, add="+")
        
        
        #Radiobuttons
        for child in self.radiobutton_frame.winfo_children():
            child.config(state='normal')
    
    def save_pointing_star(self):
        """ Saves Pointings Stars Information to file.
            
            Takes Hipparcos Number, RA, DEC LST and Date and saves to file.
            
            Also Saves Hipparcos Number, RA, DEC, HA, 
            target_ra, target_dec, LST, UTC and Date to second file.
            This could lead to potentially new system of pointing_star data.
            This could be easier to handle.
            Not done yet.
        """
        ### Traditional File ###
        try:
            hipparcos=self.HIP_entry.get()
            #Need integer to catch errors and for formatting
            hipparcos=int(hipparcos)
            #Format Hipparcos Number to 000123
            hip_pointing="{:06d}".format(hipparcos)
        except ValueError:
            print('Invalid Hiparcos number')
            return 0
        
        #Format RA to hh mm ss
        (RA_hours,h,rest)=self.ra.partition('h')
        (RA_min,m,rest)=rest.partition('m')
        (RA_sec,s,rest)=rest.partition('s')
        RA_pointing="{} {} {}".format(RA_hours, RA_min, RA_sec)
        
        #Format DEC to +dd mm ss
        (DEC_deg,grad,rest)=self.dec.partition('°')
        (DEC_min,m,rest)=rest.partition("'")
        (DEC_sec,s,rest)=rest.partition('"')
        DEC_pointing="{} {} {}".format(DEC_deg, DEC_min, DEC_sec)
        
        #Format LST to hh mm ss
        (LST_hours,h,rest)=self.LST.partition(':')
        (LST_min,m,rest)=rest.partition(':')
        (LST_sec,s,rest)=rest.partition(':')
        LST_pointing="{} {} {}".format(LST_hours, LST_min, LST_sec)
        
        #Get Date in Format dd.mm.yyyy (using locale module)
        today = datetime.date.today()
        Date_pointing=today.strftime('%d.%m.%Y')
        
        line="{}    {}    {}    {}    {}\n".format(hip_pointing,
                                                 RA_pointing,
                                                 DEC_pointing,
                                                 LST_pointing,
                                                 Date_pointing)
        #Filename and path using pathlib module
        #File is in parrent_directory/pointing_stars/pointings_stars.txt
        current_path=pathlib.Path.cwd()
        parrent_path=current_path.parent
        file_path=parrent_path / 'pointing_stars' / 'pointing_stars.txt'
        #With automatically closes the file in the end
        with open(str(file_path), 'a') as ps_file:
            print('Saving pointing star to (old format) file')
            ps_file.write(line)
            
            
        ### New Format File ###
        
        #Format HA to hh mm ss
        (HA_hours,h,rest)=self.ha.partition('h')
        (HA_min,m,rest)=rest.partition('m')
        (HA_sec,s,rest)=rest.partition('s')
        HA_pointing="{} {} {}".format(HA_hours, HA_min, HA_sec)
        
        
        line=("{}    {}    {}    {}    {}    {}    {}    {}    {}"
            "    {}    {}    {}    {}    {}    {}\n")
        line=line.format(hip_pointing,
                         RA_pointing,
                         self.ra_float,
                         DEC_pointing,
                         self.dec_float,
                         HA_pointing,
                         self.ha_float,
                         self.target_ra,
                         self.target_ra_float,
                         self.target_dec,
                         self.target_dec_float,
                         self.target_ha_float,
                         self.LST,
                         self.UTC,
                         Date_pointing)
        
        #Filename and path using pathlib module
        #File is in parrent_directory/pointing_stars/pointings_stars_new_format.txt
        current_path=pathlib.Path.cwd()
        parrent_path=current_path.parent
        file_path=parrent_path / 'pointing_stars' / 'pointing_stars_new_format.txt'
        #With automatically closes the file in the end
        with open(str(file_path), 'a') as ps_file:
            print('Saving pointing star to (new format) file')
            ps_file.write(line)
예제 #11
0
class CIDRCalcGUI:
    def __init__(self):
        self.subnet = Subnet()

        self.cidr = Tk()
        self.cidr.wm_title('CIDR Calculator')

        self.cidr_from_netmask = LabelFrame(
            self.cidr, text='CIDR: Network Address & Netmask')
        self.net_address_label = Label(self.cidr_from_netmask,
                                       text='Network Address:')
        self.netmask_label = Label(self.cidr_from_netmask, text='Netmask:')
        self.net_address_entry = Entry(self.cidr_from_netmask, width=25)
        self.netmask_entry = Entry(self.cidr_from_netmask, width=25)

        self.cidr_from_ip_range = LabelFrame(
            self.cidr, text='CIDR: Network Address & Assignable IP Range')
        self.net_address_label2 = Label(self.cidr_from_ip_range,
                                        text='Network Address:')
        self.ip_range_label = Label(self.cidr_from_ip_range,
                                    text='Assignable IP Range:')
        self.net_address_entry2 = Entry(self.cidr_from_ip_range, width=25)
        self.ip_range_entry = Entry(self.cidr_from_ip_range, width=25)

        self.learning_steps = LabelFrame(self.cidr, text='Learning Steps')

        self.calculate = Button(self.cidr_from_netmask,
                                text='Calculate',
                                command=lambda: self.get_cidr_from_netmask())
        self.calculate2 = Button(self.cidr_from_ip_range,
                                 text='Calculate',
                                 command=lambda: self.get_cidr_from_ip_range())

        self.cidr_from_netmask.grid(row=0)
        self.cidr_from_ip_range.grid(row=1)
        self.learning_steps.grid(row=2, sticky='W')

        self.net_address_label.grid(row=0, column=0, sticky='W')
        self.net_address_entry.grid(row=1, column=0)
        self.netmask_label.grid(row=0, column=1, sticky='W')
        self.netmask_entry.grid(row=1, column=1)
        self.calculate.grid(row=1, column=2)

        self.net_address_label2.grid(row=0, column=0, sticky='W')
        self.net_address_entry2.grid(row=1, column=0)
        self.ip_range_label.grid(row=0, column=1, sticky='W')
        self.ip_range_entry.grid(row=1, column=1)
        self.calculate2.grid(row=1, column=2)

        # self.cidr.mainloop()

    def get_cidr_from_netmask(self):
        if self.subnet.cidr_address != '':
            self.clear_and_reset()
        else:
            self.subnet.network_address = self.net_address_entry.get()
            self.subnet.netmask = self.netmask_entry.get()

            if self.subnet.network_address != '' and self.subnet.netmask != '' and self.subnet.verify_variables(
            ):
                self.subnet.calculate_cidr_from_netmask()
                steps = self.subnet.cidr_address_steps

                step1 = Label(self.learning_steps, text='Step 1:')
                network = Label(self.learning_steps,
                                text='Network Address: {}'.format(
                                    self.subnet.network_address))
                netmask = Label(self.learning_steps,
                                text='NetMask: {}'.format(self.subnet.netmask))
                step2 = Label(self.learning_steps, text='Step 2:')
                binary = Label(self.learning_steps,
                               text='Netmask Binary: {}'.format(
                                   steps[0]['Netmask Binary']))
                step3 = Label(self.learning_steps, text='Step 3:')
                count = Label(self.learning_steps,
                              text="(Count 0's from Step 2)")
                cidr = Label(self.learning_steps,
                             text='CIDR: {}'.format(steps[1]['CIDR']))
                step4 = Label(self.learning_steps, text='Step 4:')
                cidr_address = Label(self.learning_steps,
                                     text='CIDR Address: {}'.format(
                                         self.subnet.cidr_address))

                step1.grid(row=0, column=0, sticky='W')
                network.grid(row=0, column=1, sticky='W')
                netmask.grid(row=0, column=2, sticky='W')
                step2.grid(row=1, column=0, sticky='W')
                binary.grid(row=1, column=1, columnspan=2, sticky='W')
                step3.grid(row=2, column=0, sticky='W')
                count.grid(row=2, column=1, sticky='W')
                cidr.grid(row=2, column=2, sticky='W')
                step4.grid(row=3, column=0, sticky='W')
                cidr_address.grid(row=3, column=1, sticky='W')
            else:
                self.clear_and_reset()
                HelpGUI()

    def get_cidr_from_ip_range(self):
        if self.subnet.cidr_address != '':
            self.clear_and_reset()
        else:
            self.subnet.network_address = self.net_address_entry2.get()
            self.subnet.ip_range = self.ip_range_entry.get()

            if self.subnet.network_address != '' and self.subnet.ip_range != '' and self.subnet.verify_variables(
            ):
                self.subnet.calculate_cidr_from_ip_range()
                steps = self.subnet.cidr_address_steps

                step1 = Label(self.learning_steps, text='Step 1:')
                network = Label(self.learning_steps,
                                text='Network Address: {}'.format(
                                    self.subnet.network_address))
                ip_range = Label(self.learning_steps,
                                 text='Assignable IP Range: {}'.format(
                                     self.subnet.ip_range))
                step2 = Label(self.learning_steps, text='Step 2:')
                front = Label(self.learning_steps,
                              text='Front: {}'.format(steps[0]['Front']))
                back = Label(self.learning_steps,
                             text=' Back: {}'.format(steps[0]['Back']))
                step3 = Label(self.learning_steps, text='Step 3:')
                comparison = Label(self.learning_steps,
                                   text='Comparison: {}'.format(
                                       steps[1]['Comparison']))
                step4 = Label(self.learning_steps, text='Step 4:')
                cidr = Label(self.learning_steps,
                             text='CIDR: {}'.format(steps[2]['CIDR']))
                step5 = Label(self.learning_steps, text='Step 5:')
                cidr_address = Label(self.learning_steps,
                                     text='CIDR Address: {}'.format(
                                         self.subnet.cidr_address))

                step1.grid(row=0, column=0, sticky='W')
                network.grid(row=0, column=1, sticky='W')
                ip_range.grid(row=1, column=1, sticky='W')
                step2.grid(row=2, column=0, sticky='W')
                front.grid(row=2, column=1, sticky='W')
                back.grid(row=3, column=1, sticky='W')
                step3.grid(row=4, column=0, sticky='W')
                comparison.grid(row=4, column=1, columnspan=2, sticky='W')
                step4.grid(row=5, column=0, sticky='W')
                cidr.grid(row=5, column=1, sticky='W')
                step5.grid(row=6, column=0, sticky='W')
                cidr_address.grid(row=6, column=1, sticky='W')
            else:
                self.clear_and_reset()
                HelpGUI()

    def clear_and_reset(self):
        self.net_address_entry.delete(0, 'end')
        self.netmask_entry.delete(0, 'end')
        self.net_address_entry2.delete(0, 'end')
        self.ip_range_entry.delete(0, 'end')
        self.subnet.reset_variables()
        for child in self.learning_steps.winfo_children():
            child.destroy()

    def generate_main(self):
        self.cidr.mainloop()
예제 #12
0
class Set:
    def __init__(self, parent):
        self.parent = parent
        parent.title("Set")
        parent.iconbitmap("assets/cardsIcon.ico")
        #parent.config(bg="#384d9c")

        ################### Instance Variables ###################
        self.numbers = {1: "one", 2: "two", 3: "three"}
        self.colors = {"r": "red", "g": "green", "p": "purple"}
        self.shadings = {"e": "non", "h": "half", "f": "fully"}
        self.shapes = {"S": "squiggle", "D": "diamond", "O": "oval"}
        self.deck = [
            Card(w, x, y, z) for w in self.numbers for x in self.colors
            for y in self.shadings for z in self.shapes
        ]
        # field is defined at the bottom since it requires the tk frame it's in
        self.helds = set()
        self.justDealt = False
        self.solutions = []
        self.puzField = []
        self.puzSols = []
        self.score = 0
        self.setsOnBoard = 0
        self.gameState = 0  #0 is no game currently being played, 1 is solitaire, 2 is puzzle
        self.startTime = 0
        self.imgDict = {
            str(w) + x + y + z:
            PhotoImage(file="assets/" + str(w) + x + y + z + ".png")
            for w in self.numbers for x in self.colors for y in self.shadings
            for z in self.shapes
        }
        self.empty = PhotoImage(file="assets/empty.png")

        ########################## GUI ##########################
        self.gameFrame = Frame(parent)
        self.fieldFrame = LabelFrame(self.gameFrame, text="")
        # the foundSets LabelFrame for puzzle mode will also go here

        self.lowerFrame = Frame(parent)
        self.foundSets = LabelFrame(self.lowerFrame, text="Sets Found")
        self.messageFrame = Frame(self.lowerFrame)
        self.message = Label(self.messageFrame, text="")
        self.msgUpdate = self.messageFrame.after(1, self.resetMessage, "")
        self.scoreboard = Label(self.lowerFrame, text="")
        self.deckStatus = Label(self.lowerFrame, text="")
        self.solsButton = Button(self.lowerFrame,
                                 text="Show current solutions.",
                                 command=self.showSolutions)
        self.field = [[
            Spot(
                i, j, None,
                Button(self.fieldFrame,
                       image=self.empty,
                       bg="white",
                       command=lambda i=i, j=j: self.bClick(i, j)))
            for j in range(7)
        ] for i in range(3)]
        #This is the game board, 21 spots max. A set is unavoidable with 20 spots. It is redefined in the startSolit method.
        #For puzzle mode the field will have only 4 columns and a seperate widget showing the found sets will be gridded into the fieldFrame ___TODO____

        self.solitButton = Button(self.lowerFrame,
                                  text="Start/Restart a Solitaire Game",
                                  command=lambda: solit.start(self))
        self.puzzleButton = Button(self.lowerFrame,
                                   text="Start/Restart a Puzzle Game",
                                   command=lambda: puz.start(self))

        self.gameFrame.pack()
        self.fieldFrame.grid(row=0, column=0, padx=40)  #.grid(row=0, column=0)
        for y in range(
                3
        ):  #grid 12 of the 21 possible field buttons, additional buttons will get gridded in only if they have a card
            for x in range(4):
                self.field[y][x].button.grid(row=y, column=x)

        self.lowerFrame.pack()
        self.messageFrame.pack()
        self.message.pack()
        self.scoreboard.pack()
        self.deckStatus.pack()
        self.solsButton.pack()
        self.solitButton.pack()
        self.puzzleButton.pack(pady=(0, 40))

    ######################## METHODS ########################
    def gameOver(self):
        timeDif = datetime.datetime.now(
        ) - self.startTime  # datetime timedelta object
        finTime = "Finished in {} minute{}, {}.{} second{}.".format(
            timeDif.seconds // 60,
            "s" if timeDif.seconds // 60 != 1 else "",
            timeDif.seconds % 60,
            str(timeDif)
            [8:
             11],  #this truncates to milliseconds, doesn't round, shouldn't ever really be an issue
            "s" if timeDif.seconds > 0 else "")
        for x in self.field:
            for y in x:
                y.button.config(state=DISABLED)
        if self.gameState == 1:
            self.message.config(text="No sets and deck is empty, game over! " +
                                finTime)
        else:
            self.message.config(text="All sets found, game over! " + finTime)
        self.gameState = 0

    def start_shared(self):
        self.deck = [
            Card(w, x, y, z) for w in self.numbers for x in self.colors
            for y in self.shadings for z in self.shapes
        ]
        self.helds = set()
        self.score = 0

        if self.buttonsInField() != 12:
            for button in self.fieldFrame.winfo_children():
                button.grid_forget()  #ungrid the buttons in the field
            for x in range(
                    3
            ):  #grid 12 of the 21 possible field buttons, additional buttons will get gridded in only if they have a card
                for y in range(4):
                    self.field[x][y].button.grid(row=x, column=y)
        for row in self.field:
            for spot in row:
                spot.card = None
                spot.button.config(state=NORMAL)
        self.startTime = datetime.datetime.now()

    def sets_finder(self, cardsList):
        self.solutions = []
        self.setsOnBoard = 99
        sets = []

        for i in cardsList:
            for j in cardsList:
                if j != i:
                    for k in cardsList:
                        if k != j and k != i and {
                                i, j, k
                        } not in sets and self.is_set([i, j, k]):
                            sets.append({i, j, k})
                            self.solutions.append({i, j, k})
        if self.gameState == 1:
            self.setsOnBoard = len(sets)
            solit.sets_finder_handler(self, self.setsOnBoard)
        if self.gameState == 2:
            return sets

    def is_set(self, givenCards, extraInfo="no"):
        """takes a set of exactly 3 card objects, extraInfo if called from having full helds in checkSet()), not if called from setsFinder()"""
        attrSwitcher = {
            "number": {x.number
                       for x in givenCards},
            "color": {x.color
                      for x in givenCards},
            "shading": {x.shading
                        for x in givenCards},
            "shape": {x.shape
                      for x in givenCards}
        }

        if extraInfo == "yes":
            for attribute in attrSwitcher:
                if len(attrSwitcher.get(attribute)) == 2:
                    falsRay = [False, "two of", "one of", attribute]

                    notSetAtts = [
                        eval(
                            "self." + attribute + "s.get(card." + attribute +
                            ")", {
                                "self": self,
                                "card": card
                            }) for card in givenCards
                    ]
                    #the above is hacky but the easiest way to reconcile with the dictionaries
                    print(notSetAtts)
                    for x in notSetAtts:
                        if notSetAtts.count(x) == 2 and x not in falsRay:
                            falsRay[1] = str(x)
                        if notSetAtts.count(x) == 1:
                            falsRay[2] = str(x)
                    print(falsRay)
                    return falsRay  #to show reason why it's not a set
            return [True]
        else:
            for attribute in attrSwitcher:
                if len(attrSwitcher.get(attribute)) == 2:
                    return False
            return True

    def checkSet(
        self
    ):  #TODO ___ this is convoluted, maybe store spots in helds instead of cards?
        infoRay = self.is_set(self.helds, extraInfo="yes")
        if infoRay[0]:
            if self.gameState == 1:
                solit.found_a_set(self)
            else:
                puz.found_a_set(self)
        else:
            #Make a grammatically correct string explaining why helds is not a set. Handles a few possible cases.
            #REMEMBER infoRay = [False, "two of", "one of", attribute]
            self.messageFrame.after_cancel(self.msgUpdate)
            whyNot = "two cards {} {} and the other {} {}."
            badAttr = infoRay[3]
            whyNotSwitcher = {
                "number": " symbol",
                "color": "",
                "shading": "-shaded",
                "shape": ""
            }
            switchText = whyNotSwitcher.get(badAttr)
            isNums = badAttr == "number"
            isShapes = badAttr == "shape"
            edgeCase = False

            if isShapes:
                for card in self.helds:
                    print(self.shapes[card.shape])
                    #print(infoRay[2])
                    if self.shapes[card.shape] == infoRay[
                            2] and card.number == 1:  #if the bat attr is shapes and the "one off" is a singular shape
                        edgeCase = True
                        print("edge case")
                        break
            if edgeCase:
                part4 = "a{} ".format("n" if infoRay[2] ==
                                      "oval" else "") + infoRay[2] + switchText
            elif isNums and infoRay[2] != "one" or isShapes:
                part4 = infoRay[2] + switchText + "s"
            else:
                part4 = infoRay[2] + switchText
            self.message.config(text="Not a set, " + whyNot.format(
                "have" if isNums or isShapes else "are", infoRay[1] +
                switchText + "s"
                if isNums and infoRay[1] != "one" or isShapes else infoRay[1] +
                switchText, "has" if isNums or isShapes else "is", part4))
            for x in self.field:
                for y in x:
                    if y.card in self.helds:
                        y.button.config(
                            bg="white"
                        )  #this is one reason to make helds spots instead of cards
            self.msgUpdate = self.messageFrame.after(
                5000, self.resetMessage, "There are " + str(self.setsOnBoard) +
                " sets on the board right now." if self.gameState == 1 else
                str(self.score) + " of 6 sets found.")
        self.helds = set()

    ##########################################################################################

    def bClick(self, i, j):
        if self.field[i][j].card not in self.helds:
            self.field[i][j].button.config(bg="orange")
            self.helds.add(self.field[i][j].card)
            if len(self.helds) > 2:
                self.checkSet()
        else:
            self.field[i][j].button.config(bg="white")
            self.helds.remove(self.field[i][j].card)

    def dealTo(self, i, j):
        self.field[i][j].card = self.deck.pop()
        self.update_card(i, j)

    def update_card(self, i, j):
        """updates the button image"""
        self.field[i][j].button.config(
            bg="white"
        )  #this is redundant for some calls but better than putting it everywhere
        self.field[i][j].button.config(
            image=self.imgDict[str(self.field[i][j].card.number) +
                               self.field[i][j].card.color +
                               self.field[i][j].card.shading +
                               self.field[i][j].card.shape])

    def showSolutions(self):
        msgText = ""
        for sol in self.solutions:
            for card in sol:
                msgText += str.capitalize(self.numbers[card.number] + " " +
                                          self.colors[card.color] + " " +
                                          self.shadings[card.shading] +
                                          "-shaded " +
                                          self.shapes[card.shape] + ", ")
            msgText = msgText[:-2]
            msgText += ".\n"
        self.message.config(text=msgText)

    def buttonsInField(self):
        i = 0
        for x in self.field:
            for y in x:
                if y.button.winfo_ismapped():
                    i += 1
        return i

    def resetMessage(self, msgText):
        """This only needs to be a separate method for timed event handling purposes"""
        self.message.config(text=msgText)