예제 #1
0
파일: __main__.py 프로젝트: Aesonus/TkLife
    def _create_widgets(self):
        Label(self, text='Example Entry:')
        Entry(self, textvariable=self.entry_var)
        button = Button(self, text='Show Dialog')
        button.configure(command=self.show_dialog_for(button))
        button = Button(
            self,
            text='Show For This Button',
        )
        button.configure(command=show_dialog_for(button))

        def get_widget_text(widget: Entry):
            return widget.get()

        table = NewTable(self,
                         headers=(
                             ('Test', get_widget_text),
                             ('The', get_widget_text),
                             ('Table', get_widget_text),
                         ))
        widgets_ = []
        for row in range(4):
            for col in range(3):
                widgets_.append(Entry(table.table))
                widgets_[-1].insert(0, 'Row {}; Col {}'.format(row, col))
        table.cell_widgets = widgets_
예제 #2
0
        def save(event=None):
            name = name_entry.get().strip()
            if not mailbox:
                # new mailbox
                i = self.b_add.grid_info()['row']
                self.b_add.grid_configure(row=i + 1)
                c = Checkbutton(self.frame)
                c.state(('selected',))
                c.grid(row=i, column=0, pady=4, padx=(4, 0))
                l = Label(self.frame, text=name)
                l.grid(row=i, column=1, padx=4, pady=4)
                b_edit = Button(self.frame, image=self.im_edit, width=1,
                                command=lambda m=name: self.mailbox_info(m))
                b_edit.grid(row=i, column=2, padx=4, pady=4)
                b_del = Button(self.frame, image=self.im_del, width=1,
                               command=lambda m=name: self.del_mailbox(m))
                b_del.grid(row=i, column=3, padx=4, pady=4)
                self.mailboxes[name] = [c, l, b_edit, b_del]
            elif name != mailbox:
                # change name of mailbox
                os.remove(os.path.join(LOCAL_PATH, mailbox))
                c, l, b_edit, b_del = self.mailboxes[mailbox]
                del(self.mailboxes[mailbox])
                l.configure(text=name)
                b_edit.configure(command=lambda m=name: self.mailbox_info(m))
                b_del.configure(command=lambda m=name: self.del_mailbox(m))
                self.mailboxes[name] = [c, l, b_edit, b_del]

            encrypt(name, self.pwd, server_entry.get().strip(),
                    login_entry.get().strip(), password_entry.get().strip(),
                    folder_entry.get().strip())
            top.destroy()
예제 #3
0
 def update_button(self, button: ttk.Button, image: "ImageTk",
                   node_draw: NodeDraw):
     logging.debug("update button(%s): %s", button, node_draw)
     self.hide_pickers()
     button.configure(image=image)
     button.image = image
     self.app.canvas.mode = GraphMode.NODE
     self.app.canvas.node_draw = node_draw
예제 #4
0
class Page1(Frame):
    def on_recommend_btn_click(self):
        selected_index = self.item_lst_box.curselection()
        user_preferences = [
            self.item_lst_box.get(indx) for indx in selected_index
        ]
        print(f'User preferences are {user_preferences}')
        if len(user_preferences) > 3:
            messagebox.showwarning(
                "Warning", "Currently doesnt support for than 3 preferences")
        else:
            self.business_logic.set_preferences(user_preferences)
            Page2(self.master, self).show()

    def get_appliances(self):
        selected = self.radio_btn_var.get()
        print(f'Selected option is {selected}')
        if selected in (0, 1):
            self.business_logic.set_choice(selected)
            for index, item in enumerate(self.business_logic.items[
                    self.business_logic.selected_choice]):
                self.item_lst_box.insert(index, item)
            self.recommend_btn.configure(state=ACTIVE)
        else:
            self.recommend_btn.configure(state=DISABLED)
            self.item_lst_box.delete(0, 'end')

    def __init__(self, master):
        super().__init__(master, relief='flat', borderwidth=40)
        self.business_logic = MLLogic()
        self.radio_btn_var = IntVar()
        self.master.title(self.business_logic.title)
        self.pack(fill=None, expand=False)
        Label(self, text="Select the type of appliances you want to buy").grid(
            row=1, columnspan=2, sticky='NW')
        for index, appliance_type in enumerate(
                self.business_logic.appliance_choices):
            rdo_btn = Radiobutton(self,
                                  text=appliance_type,
                                  variable=self.radio_btn_var,
                                  value=index,
                                  command=self.get_appliances)
            rdo_btn.select()
            rdo_btn.grid(row=index + 2, column=2)
        Label(self, text="Preferences").grid(row=7, columnspan=2, sticky='NW')
        self.item_lst_box = Listbox(self, selectmode='multiple')
        self.item_lst_box.delete(0, 'end')
        self.item_lst_box.grid(row=7, column=2)
        self.recommend_btn = Button(self,
                                    text='Recommend',
                                    command=self.on_recommend_btn_click)
        self.recommend_btn.grid(row=9, column=2, sticky='NW')
        self.recommend_btn.configure(state=DISABLED)
예제 #5
0
파일: toolbar.py 프로젝트: q9512268/core
 def update_button(
     self,
     button: ttk.Button,
     node_draw: NodeDraw,
     type_enum: NodeTypeEnum,
     image: PhotoImage,
 ) -> None:
     logging.debug("update button(%s): %s", button, node_draw)
     button.configure(image=image)
     button.image = image
     self.app.canvas.node_draw = node_draw
     if type_enum == NodeTypeEnum.NODE:
         self.current_node = node_draw
     elif type_enum == NodeTypeEnum.NETWORK:
         self.current_network = node_draw
예제 #6
0
class DestinationFrame(LabelFrame):
    def __init__(self, root, model: ConfigUIModel):
        super().__init__(root, text="Destination", padding=10)
        self.pack(side=LEFT, anchor=NW, fill=BOTH, expand=True)
        self.model = model

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

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

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

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

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

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

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

    def set_dest(self):
        dest = filedialog.askdirectory(title="Choose Destination")
        if dest is not None:
            self.model.var_dest.set(dest)
            self.model.var_managed.set(MetaRecord.is_managed(dest))
예제 #7
0
    def _create_widgets(self):
        """Create widgets"""
        self.table_frame = Frame(self)
        self.scrollable_canvas = Canvas(self.table_frame)
        self.x_scroll = Scrollbar(
            self, orient=HORIZONTAL, command=self.scrollable_canvas.xview)
        self.y_scroll = Scrollbar(
            self.table_frame, orient=VERTICAL, command=self.scrollable_canvas.yview)
        self.scrollable_canvas.configure(yscrollcommand=self.y_scroll.set,
                                         xscrollcommand=self.x_scroll.set)
        self.table = Frame(self.scrollable_canvas)
        for header_text in self.column_headers:
            widget = Frame(self.table)
            button = Button(widget, text=header_text)
            button.configure(
                command=lambda button=button: self._sort_command(button))

        self._create_data_widgets()
예제 #8
0
파일: toolbar.py 프로젝트: montag451/core
 def update_button(
     self,
     button: ttk.Button,
     image: "ImageTk",
     node_draw: NodeDraw,
     type_enum,
     image_enum,
 ):
     logging.debug("update button(%s): %s", button, node_draw)
     self.hide_pickers()
     button.configure(image=image)
     button.image = image
     self.app.canvas.mode = GraphMode.NODE
     self.app.canvas.node_draw = node_draw
     if type_enum == NodeTypeEnum.NODE:
         self.node_enum = image_enum
     elif type_enum == NodeTypeEnum.NETWORK:
         self.network_enum = image_enum
예제 #9
0
    def initUI(self):
        self.parent.title("GUI Controls Test")
        self.style = Style()
        self.style.theme_use("default")
        self.pack(fill=BOTH, expand=1)
        #--------------------------------------------

        #--------------------create menus------------
        menuBar = Menu(self.parent)
        mnuFile = Menu(menuBar, tearoff=0)
        menuBar.add_cascade(label="File", menu=mnuFile)
        mnuFile.add_command(label="Open", command=self.mnuOpenFileClick)
        mnuFile.add_command(label="Save", command=self.mnuSaveFileClick)
        mnuFile.add_separator()
        mnuFile.add_command(label="Exit", command=self.exitButtonClick)
        mnuCustomers = Menu(menuBar, tearoff=0)
        menuBar.add_cascade(label="Loan Processing", menu=mnuCustomers)
        mnuCustomers.add_command(label="Loan Calculator",
                                 command=self.loanCalcButtonClick)
        mnuCustomers.add_separator()
        mnuCustomers.add_command(label="Provide Feedback",
                                 command=self.mnuShowFeedbackClick)
        self.parent.config(menu=menuBar)
        #--------------------------------------------

        xpos = 30
        ypos = 40
        xpos2 = xpos + 90
        #------------styling----------------------------------
        style = Style()
        style.configure("Exit.TButton", foreground="red", background="white")
        style.configure("MainButton.TButton",
                        foreground="yellow",
                        background="red")
        #-----------------------------------------------------

        testButton = Button(self,
                            text="Get StudentID",
                            command=self.btnGetStudentIDClick)
        testButton.configure(style="MainButton.TButton")
        testButton.place(x=xpos, y=ypos)
        self.txtID = Entry(self,
                           text="",
                           foreground="#ff0000",
                           background="light blue",
                           font="Arial 9")  # Arial 12 bold italic
        self.txtID.place(x=xpos2, y=ypos)
        self.txtID.configure(state="readonly")

        ypos += 30
        btnLoanCalc = Button(self,
                             text="Loan Calculator",
                             command=self.loanCalcButtonClick)
        btnLoanCalc.configure(style="Exit.TButton")
        btnLoanCalc.place(x=xpos, y=ypos)
        ypos += 30
        exitButton = Button(self, text="Exit", command=self.exitButtonClick)
        exitButton.configure(style="Exit.TButton")
        exitButton.place(x=xpos, y=ypos)
예제 #10
0
class P300Window(object):
    def __init__(self, master: Tk):
        self.master = master
        master.title('P300 speller')

        #Parameters
        self.imagesize = 125
        self.images_folder_path = '../utils/images/'  #use utils/char_generator to generate any image you want
        self.flash_image_path = '../utils/images/flash_images/einstein.jpg'
        self.number_of_rows = 6
        self.number_of_columns = 6  #make sure you have 6 x 6 amount of images in the images_folder_path
        self.flash_mode = 2  #single element  #1 for columns and rows; currently is NOT working yet; if I have time, will revisit
        self.flash_duration = 100  #soa
        self.break_duration = 125  #iti

        self.trials = 6  #number of letters
        self.delay = 2500  #interval between trial
        self.letter_idx = 0

        #did not include numbers yet!
        self.random_letter = random.choices(
            string.ascii_lowercase,
            k=self.trials)  #randomize [self.trials] number letters
        self.word = ''.join(self.random_letter)

        # Variables
        self.usable_images = []
        self.image_labels = []
        self.flash_sequence = []
        self.flash_image = None
        self.sequence_number = 0
        self.lsl_output = None

        self.running = 0  #for pause

        self.image_frame = Frame(self.master)
        self.image_frame.grid(row=0,
                              column=0,
                              rowspan=self.number_of_rows,
                              columnspan=self.number_of_columns)

        self.start_btn_text = StringVar()
        self.start_btn_text.set('Start')
        self.start_btn = Button(self.master,
                                textvariable=self.start_btn_text,
                                command=self.start)
        self.start_btn.grid(row=self.number_of_rows + 3,
                            column=self.number_of_columns - 1)

        self.pause_btn = Button(self.master, text='Pause', command=self.pause)
        self.pause_btn.grid(row=self.number_of_rows + 3,
                            column=self.number_of_columns - 4)  #-4 for center
        self.pause_btn.configure(state='disabled')

        self.close_btn = Button(self.master, text='Close', command=master.quit)
        self.close_btn.grid(row=self.number_of_rows + 3, column=0)

        fontStyle = tkFont.Font(family="Courier", size=40)

        self.output = Text(root, height=1, font=fontStyle)
        self.output.tag_configure("red", foreground="red")
        self.output.tag_configure("green", foreground="green")
        self.output.configure(width=10)
        self.output.insert("end", "  ")
        self.output.grid(row=self.number_of_rows + 2,
                         column=self.number_of_columns - 4)

        self.outputlabel = Label(root, text="Output: ", font=fontStyle)
        self.outputlabel.grid(row=self.number_of_rows + 2,
                              column=self.number_of_columns - 5)

        self.targetlabel = Label(root, text="Target: ", font=fontStyle)
        self.targetlabel.grid(row=self.number_of_rows + 1,
                              column=self.number_of_columns - 5)

        self.show_highlight_letter(0)

        # Initialization
        self.show_images()
        self.create_flash_sequence()
        self.lsl_output = self.create_lsl_output()

    def open_images(self):
        self.usable_images = []
        self.highlight_letter_images = []

        letter_images = sorted(
            glob.glob(
                os.path.join(self.images_folder_path, 'letter_images/*.png')))

        #currently, still did not flash number yet!
        number_images = sorted(
            glob.glob(
                os.path.join(self.images_folder_path, 'number_images/*.png')))
        letter_highlight_images = sorted(
            glob.glob(
                os.path.join(self.images_folder_path,
                             'letter_highlight_images/*.png')))
        number_highlight_images = sorted(
            glob.glob(
                os.path.join(self.images_folder_path,
                             'number_highlight_images/*.png')))

        for number_image in number_images:
            letter_images.append(number_image)
        #print("Paths: ", letter_images)
        min_number_of_images = self.number_of_columns * self.number_of_rows
        if len(letter_images) < min_number_of_images:
            print('To few images in folder: ' + self.images_folder_path)
            return

        # Convert and resize images
        for image_path in letter_images:
            image = Image.open(image_path)
            resized = image.resize((self.imagesize, self.imagesize),
                                   Image.BICUBIC)
            Tkimage = ImageTk.PhotoImage(resized)
            self.usable_images.append(Tkimage)

        # Convert and resize images
        for image_path in letter_highlight_images:
            image = Image.open(image_path)
            resized = image.resize((self.imagesize, self.imagesize),
                                   Image.BICUBIC)
            Tkimage = ImageTk.PhotoImage(resized)
            self.highlight_letter_images.append(Tkimage)

        flash_img = Image.open(self.flash_image_path)
        flash_img_res = flash_img.resize((self.imagesize, self.imagesize),
                                         Image.BICUBIC)
        self.flash_image = ImageTk.PhotoImage(flash_img_res)

    def show_images(self):
        self.open_images()

        if self.usable_images == []:
            print('No images opened')
            return

        num_rows = self.number_of_rows
        num_cols = self.number_of_columns

        # Arrange images
        for r in range(0, num_rows):
            for c in range(0, num_cols):
                current_image = self.usable_images[r * num_cols + c]
                label = Label(self.image_frame, image=current_image)
                label.image = current_image
                label.grid(row=r, column=c)
                self.image_labels.append(label)

    def create_lsl_output(self):
        """Creates an LSL Stream outlet"""
        info = StreamInfo(name='LetterMarkerStream',
                          type='LetterFlashMarkers',
                          channel_count=1,
                          channel_format='int8',
                          nominal_srate=IRREGULAR_RATE,
                          source_id='lettermarker_stream',
                          handle=None)

        return StreamOutlet(info)  #for sending the predicted classes

    def create_flash_sequence(self):
        self.flash_sequence = []
        num_rows = self.number_of_rows
        num_cols = self.number_of_columns
        maximum_number = num_rows * num_cols

        flash_sequence = []

        for i in range(10000):
            seq = list(range(maximum_number))  #generate 0 to maximum_number
            random.shuffle(seq)  #shuffle
            flash_sequence.extend(seq)

        self.flash_sequence = flash_sequence

    def start(self):
        self.read_lsl_marker()
        self.running = 1
        letter = self.word[0]
        image_index = string.ascii_lowercase.index(letter)
        self.highlight_image(image_index)
        self.start_btn.configure(state='disabled')
        self.pause_btn.configure(state='normal')

    def pause(self):
        self.running = 0
        self.start_btn_text.set('Resume')
        self.start_btn.configure(state='normal')
        self.pause_btn.configure(state='disabled')

    def start_flashing(self):
        if self.sequence_number == len(
                self.flash_sequence
        ):  #stop flashing if all generated sequence number runs out
            print('All elements had flashed - run out of juice')
            self.running = 0
            self.sequence_number = 0
            return

        if self.running == 0:
            print('Flashing paused at sequence number ' +
                  str(self.sequence_number))
            return

        result = self.marker_result()
        if (result):
            print("Marker received: ", result[0][0])
            receive = result[0][0]
        else:
            receive = 0

        element_to_flash = self.flash_sequence[self.sequence_number]
        letter = self.word[self.letter_idx]
        image_index = string.ascii_lowercase.index(letter)

        #pushed markers to LSL stream
        timestamp = local_clock()
        print("Letter: ", image_index, " Element flash: ",
              [element_to_flash + 1], timestamp)
        self.lsl_output.push_sample([element_to_flash + 1],
                                    timestamp)  # add 1 to prevent 0 in markers
        self.flash_single_element(element_to_flash)

        if not (receive):
            self.master.after(self.break_duration, self.start_flashing)
        else:
            if ((image_index + 1) == receive):
                self.output.insert("end", self.pos_to_char(receive), "green")
            else:
                self.output.insert("end", self.pos_to_char(receive), "red")

            self.letter_idx += 1
            if (self.letter_idx == len(self.word)):
                return
            letter = self.word[self.letter_idx]
            image_index = string.ascii_lowercase.index(letter)
            self.master.after(self.break_duration, self.highlight_target,
                              image_index)

        self.sequence_number = self.sequence_number + 1  #change flash position

    def pos_to_char(self, pos):
        return chr(pos - 1 + 97)

    def highlight_target(self, image_index):
        self.show_highlight_letter(self.letter_idx)
        self.highlight_image(image_index)

    def change_image(self, label, img):
        label.configure(image=img)
        label.image = img

    def highlight_image(self, element_no):
        self.change_image(self.image_labels[element_no],
                          self.highlight_letter_images[element_no])
        self.master.after(self.delay, self.unhighlight_image, element_no)

    def unhighlight_image(self, element_no):
        self.change_image(self.image_labels[element_no],
                          self.usable_images[element_no])
        self.master.after(self.flash_duration, self.start_flashing)

    def show_highlight_letter(self, pos):

        fontStyle = tkFont.Font(family="Courier", size=40)
        fontStyleBold = tkFont.Font(family="Courier bold", size=40)

        text = Text(root, height=1, font=fontStyle)
        text.tag_configure("bold", font=fontStyleBold)
        text.tag_configure("center", justify='center')

        for i in range(0, len(self.word)):
            if (i != pos):
                text.insert("end", self.word[i])
            else:
                text.insert("end", self.word[i], "bold")

        text.configure(state="disabled", width=10)
        text.tag_add("center", "1.0", "end")

        text.grid(row=self.number_of_rows + 1,
                  column=self.number_of_columns - 4)

    def flash_row_or_col(self, rc_number):
        num_rows = self.number_of_rows
        num_cols = self.number_of_columns

        if rc_number < num_rows:
            for c in range(0, num_cols):  #flash row
                cur_idx = rc_number * num_cols + c
                self.change_image(self.image_labels[cur_idx], self.flash_image)
        else:
            current_column = rc_number - num_rows
            for r in range(0, num_rows):  #flash column
                cur_idx = current_column + r * num_cols
                self.change_image(self.image_labels[cur_idx], self.flash_image)

        self.master.after(self.flash_duration, self.unflash_row_or_col,
                          rc_number)

    def unflash_row_or_col(self, rc_number):
        num_rows = self.number_of_rows
        num_cols = self.number_of_columns
        if rc_number < num_rows:
            for c in range(0, num_cols):  #flash row
                cur_idx = rc_number * num_cols + c
                self.change_image(self.image_labels[cur_idx],
                                  self.usable_images[cur_idx])
        else:
            current_column = rc_number - num_rows
            for r in range(0, num_rows):  #flash column
                cur_idx = current_column + r * num_cols
                self.change_image(self.image_labels[cur_idx],
                                  self.usable_images[cur_idx])

    def flash_single_element(self, element_no):
        self.change_image(self.image_labels[element_no], self.flash_image)
        self.master.after(self.flash_duration, self.unflash_single_element,
                          element_no)

    def unflash_single_element(self, element_no):
        self.change_image(self.image_labels[element_no],
                          self.usable_images[element_no])

    def marker_result(self):
        marker, timestamp = self.inlet_marker.pull_chunk()
        return marker

    def read_lsl_marker(self):
        print("looking for a Markers stream...")
        marker_streams = resolve_byprop('name', 'ResultMarkerStream')
        if marker_streams:
            self.inlet_marker = StreamInlet(marker_streams[0])
            marker_time_correction = self.inlet_marker.time_correction()
            print("Found Markers stream")
class UploadPage(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        self.controller = controller
        self.outputState = False
        self.sem = threading.Semaphore()
        self.lock = 1

        frame1 = Frame(self, relief=RAISED, borderwidth=1)
        frame1.pack(fill=BOTH, expand=True)
        frame2 = Frame(self, relief=RAISED, borderwidth=1)
        frame2.pack(fill=BOTH, expand=True)

        self.outputBox = Text(self, height=15, width=40)
        self.outputBox.tag_config('error',
                                  background="yellow",
                                  foreground="red")
        self.vsb = Scrollbar(self,
                             orient="vertical",
                             command=self.outputBox.yview)
        self.outputBox.configure(yscrollcommand=self.vsb.set, state="disabled")
        self.vsb.pack(side="right", fill="y")
        self.outputBox.pack(side="left", fill="both", expand=True)

        self.filePath_entry = Entry(frame1, width=35)
        self.filePath_label = Label(frame1, text="Blueprints .zip File Path:")

        self.fileButton = Button(frame1, text="Upload Blueprints", width=30)
        self.fileButton.configure(command=self.threader_upload)
        self.returnButton = Button(
            frame2,
            text="Go Back",
            command=lambda: self.controller.show_frame("MainPage"))

        self.filePath_label.pack(padx=5, pady=5)
        self.filePath_entry.pack(padx=5, pady=5)

        self.fileButton.pack(padx=5, pady=5)
        self.returnButton.pack(padx=5, pady=10)

    def threader_upload(self):
        if self.lock == 1:
            self.lock = 0
            thread = threading.Thread(target=self.upload_blueprints)
            thread.daemon = True
            thread.start()
        return

    def upload_blueprints(self):
        """
        Uploads blueprints (downloaded with this tool) to vRA server
        Creates:
            services.json 		-JSON file with all Catalog Services info
                                *used to check fo service duplicates

            blueprintLog.txt	-TEXT file with blueprints' names
                                *used when uploading blueprints to sort into proper service categories
        """
        if len(self.filePath_entry.get()) == 0:
            self.lock = 1
            return

        blueprintID = []
        file = self.filePath_entry.get()

        show_output(self, "Reading blueprintLog.txt")
        try:
            with open("blueprintLog.txt", 'r') as f:
                blueprintID = f.read().splitlines()
        except IOError:
            show_output(
                self,
                "blueprintLog.txt not found, blueprints will not be sorted",
                error=True)

        if file[-4:] != ".zip":
            file += ".zip"

        zipPath = "\'" + os.path.dirname(os.path.realpath(__file__)) + "\\"
        importBlueprints = "cloudclient.bat vra content import --path {}\' --resolution SKIP --precheck WARN"\
            .format(zipPath + file)

        # TODO: Need to find a way to ensure all blueprints were imported
        uploadRep = int(len(blueprintID) / 25)
        if uploadRep == 0:
            uploadRep = 1
        for x in range(0, uploadRep):
            cloud_client_run(self,
                             importBlueprints,
                             "Importing Blueprints to vRA ({}/{})".format(
                                 x + 1, uploadRep),
                             newLog=True)
        close_output(self)

        show_output(self, "\nUpload Complete")
        self.lock = 1
        return
예제 #12
0
class AutoCorrectConfig(Frame):
    """Configuration window for autocorrect."""
    def __init__(self, master, app, **kwargs):
        Frame.__init__(self, master, padding=4, **kwargs)
        self.rowconfigure(2, weight=1)
        self.columnconfigure(0, weight=1)
        self.columnconfigure(1, weight=1)

        self.tree = Treeview(self,
                             columns=('replace', 'by'),
                             show='',
                             selectmode='browse')
        scroll_x = AutoScrollbar(self,
                                 orient='horizontal',
                                 command=self.tree.xview)
        scroll_y = AutoScrollbar(self,
                                 orient='vertical',
                                 command=self.tree.yview)
        self.tree.configure(xscrollcommand=scroll_x.set,
                            yscrollcommand=scroll_y.set)

        self.reset()

        self.replace = StringVar(self)
        self.by = StringVar(self)

        add_trace(self.replace, 'write', self._trace_replace)
        add_trace(self.by, 'write', self._trace_by)

        b_frame = Frame(self)
        self.b_add = Button(b_frame, text=_('New'), command=self.add)
        self.b_rem = Button(b_frame, text=_('Delete'), command=self.remove)
        self.b_add.state(('disabled', ))
        self.b_rem.state(('disabled', ))
        self.b_add.pack(pady=4, fill='x')
        self.b_rem.pack(pady=4, fill='x')
        Button(b_frame, text=_('Reset'), command=self.reset).pack(pady=8,
                                                                  fill='x')

        Label(self, text=_('Replace')).grid(row=0,
                                            column=0,
                                            sticky='w',
                                            pady=4)
        Label(self, text=_('By')).grid(row=0, column=1, sticky='w', pady=4)
        Entry(self, textvariable=self.replace).grid(row=1,
                                                    column=0,
                                                    sticky='ew',
                                                    pady=4,
                                                    padx=(0, 4))
        Entry(self, textvariable=self.by).grid(row=1,
                                               column=1,
                                               sticky='ew',
                                               pady=4)
        self.tree.grid(row=2, columnspan=2, sticky='ewsn', pady=(4, 0))
        scroll_x.grid(row=3, columnspan=2, sticky='ew', pady=(0, 4))
        scroll_y.grid(row=2, column=2, sticky='ns', pady=(4, 0))
        b_frame.grid(row=1, rowspan=2, padx=(4, 0), sticky='nw', column=3)

        self.tree.bind('<<TreeviewSelect>>', self._on_treeview_select)

    def _trace_by(self, *args):
        key = self.replace.get().strip()
        val = self.by.get().strip()
        self.by.set(val)
        if key in self.tree.get_children(''):
            if val != self.tree.set(key, 'by'):
                self.b_add.state(('!disabled', ))
            else:
                self.b_add.state(('disabled', ))
        else:
            self.b_add.state(('!disabled', ))
        if not val:
            self.b_add.state(('disabled', ))

    def _trace_replace(self, *args):
        key = self.replace.get().strip()
        val = self.by.get().strip()
        self.replace.set(key)
        if not key:
            self.b_add.state(('disabled', ))
            self.b_rem.state(('disabled', ))
        else:
            self.b_add.state(('!disabled', ))
            sel = self.tree.selection()
            if key in self.tree.get_children(''):
                if key not in sel:
                    self.tree.selection_set(key)
                self.b_add.configure(text=_('Replace'))
                self.b_rem.state(('!disabled', ))
                if val != self.tree.set(key, 'by'):
                    self.b_add.state(('!disabled', ))
                else:
                    self.b_add.state(('disabled', ))
            else:
                self.b_rem.state(('disabled', ))
                self.b_add.configure(text=_('New'))
                if sel:
                    self.tree.selection_remove(*sel)
        if not val:
            self.b_add.state(('disabled', ))

    def _on_treeview_select(self, event):
        sel = self.tree.selection()
        if sel:
            key, val = self.tree.item(sel[0], 'values')
            self.replace.set(key)
            self.by.set(val)

    def reset(self):
        self.tree.delete(*self.tree.get_children(''))
        keys = list(AUTOCORRECT.keys())
        keys.sort()
        for key in keys:
            self.tree.insert('', 'end', key, values=(key, AUTOCORRECT[key]))

    def add(self):
        key = self.replace.get().strip()
        val = self.by.get().strip()
        if key in self.tree.get_children(''):
            self.tree.item(key, values=(key, val))
        elif key and val:
            self.tree.insert('', 'end', key, values=(key, val))

    def remove(self):
        key = self.replace.get()
        if key in self.tree.get_children(''):
            self.tree.delete(key)

    def ok(self):
        keys = self.tree.get_children('')
        AUTOCORRECT.clear()
        for key in keys:
            AUTOCORRECT[key] = self.tree.set(key, 'by')
class Window(Frame):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.master.title("UDPSendListenerGUI")
        self.pack(fill=BOTH, expand=True)

        self.master.protocol("WM_DELETE_WINDOW", self.on_closing)

        self.columnconfigure(1, weight=1)
        self.columnconfigure(3, pad=7)
        self.rowconfigure(3, weight=1)
        self.rowconfigure(5, pad=7)

        self.is_connect = False

        self.client_ip_label = Label(self, text="Client IP")
        self.client_ip_label.grid(row=0, column=0, padx=10, sticky=E + W + S + N)

        self.client_ip_entry = Entry(self)
        self.client_ip_entry.grid(row=0, column=1, padx=10, sticky=E + W + S + N)

        self.client_port_label = Label(self, text="Client Port")
        self.client_port_label.grid(row=0, column=2, padx=10, sticky=E + W + S + N)

        self.client_port_entry = Entry(self, width=5)
        self.client_port_entry.grid(row=0, column=3, padx=10, sticky=E + W + S + N)

        self.local_port_label = Label(self, text="Local Port")
        self.local_port_label.grid(row=0, column=4, padx=10, sticky=E + W + S + N)

        self.local_port_entry = Entry(self, width=5)
        self.local_port_entry.grid(row=0, column=5, padx=10, sticky=E + W + S + N)

        self.connect_button = Button(self, text="Connect", command=self.connect)
        self.connect_button.grid(row=0, column=6, padx=10, sticky=E + W + S + N)

        self.received_label = Label(self, text="Received data")
        self.received_label.grid(row=1, column=0, padx=10, sticky=E + W + S + N)

        self.received_text = Text(self, height=10)
        self.received_text.grid(row=2, column=0, columnspan=7, padx=10, sticky=E + W + S + N)

        self.sent_label = Label(self, text="Sent data")
        self.sent_label.grid(row=3, column=0, padx=10, sticky=E + W + S + N)

        self.sent_text = Text(self, height=10)
        self.sent_text.grid(row=4, column=0, columnspan=7, padx=10, sticky=E + W + S + N)

        self.send1_entry = Entry(self)
        self.send1_entry.grid(row=5, column=0, padx=10, columnspan=5, sticky=E + W + S + N)

        self.send1_button = Button(self, text="Send 1", command=self.send_1, state=DISABLED)
        self.send1_button.grid(row=5, column=5, padx=10, columnspan=2, sticky=E + W + S + N)

        self.send2_entry = Entry(self)
        self.send2_entry.grid(row=6, column=0, padx=10, columnspan=5, sticky=E + W + S + N)

        self.send2_button = Button(self, text="Send 2", command=self.send_2, state=DISABLED)
        self.send2_button.grid(row=6, column=5, padx=10, columnspan=2, sticky=E + W + S + N)

        self.send3_entry = Entry(self)
        self.send3_entry.grid(row=7, column=0, padx=10, columnspan=5, sticky=E + W + S + N)

        self.send3_button = Button(self, text="Send 3", command=self.send_3, state=DISABLED)
        self.send3_button.grid(row=7, column=5, padx=10, columnspan=2, sticky=E + W + S + N)

        self.cfg_file = "udp.ini"
        try:
            config = configparser.ConfigParser()
            config.read_file(open(self.cfg_file))

            self.client_ip = config['SETTINGS']['client_ip']
            self.client_port = config['SETTINGS']['client_port']
            self.local_port = config['SETTINGS']['local_port']

            self.client_ip_entry.insert(END, self.client_ip)
            self.client_port_entry.insert(END, self.client_port)
            self.local_port_entry.insert(END, self.local_port)

            self.send1_entry.insert(END, config['SETTINGS']['send1'])
            self.send2_entry.insert(END, config['SETTINGS']['send2'])
            self.send3_entry.insert(END, config['SETTINGS']['send3'])
        except:
            pass

    def get_ip_x(self):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        try:
            s.connect(('10.255.255.255', 1))
            IP = s.getsockname()[0]
        except:
            IP = '127.0.0.1'
        finally:
            s.close()
        return IP

    def thread_function(self):
        while True:
            if not self.is_connect:
                del self.sock_server
                del self.sock_client
                break
            else:
                data, addr = self.sock_server.recvfrom(1024)
                self.received_text.insert(END, data)

    def connect(self):
        self.client_ip = self.client_ip_entry.get()
        self.client_port = self.client_port_entry.get()
        self.local_port = self.local_port_entry.get()

        try:
            self.sock_server.close()
        except:
            pass

        if not self.is_connect and self.client_ip and self.client_port and self.local_port:
            self.sock_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            self.sock_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            self.sock_server.bind((self.get_ip_x(), int(self.local_port_entry.get())))

            self.is_connect = True

            self.x = threading.Thread(target=self.thread_function, daemon=True)
            self.x.start()

            self.send1_button.configure(state=NORMAL)
            self.send2_button.configure(state=NORMAL)
            self.send3_button.configure(state=NORMAL)

            self.client_ip_entry.configure(state=DISABLED)
            self.client_port_entry.configure(state=DISABLED)
            self.local_port_entry.configure(state=DISABLED)

            self.connect_button['text'] = "Close"

        else:
            self.send1_button.configure(state=DISABLED)
            self.send2_button.configure(state=DISABLED)
            self.send3_button.configure(state=DISABLED)

            self.client_ip_entry.configure(state=NORMAL)
            self.client_port_entry.configure(state=NORMAL)
            self.local_port_entry.configure(state=NORMAL)

            self.is_connect = False
            self.connect_button['text'] = "Connect"

    def send_1(self):
        msg = self.send1_entry.get()
        if msg:
            self.sent_text.insert(END, msg)
            self.sock_server.sendto(bytes(msg, encoding='utf-8'), (
            bytes(self.client_ip_entry.get(), encoding='utf-8'), int(self.client_port_entry.get())))

    def send_2(self):
        msg = self.send2_entry.get()
        if msg:
            self.sent_text.insert(END, msg)
            self.sock_server.sendto(bytes(msg, encoding='utf-8'), (
            bytes(self.client_ip_entry.get(), encoding='utf-8'), int(self.client_port_entry.get())))

    def send_3(self):
        msg = self.send3_entry.get()
        if msg:
            self.sent_text.insert(END, msg)
            self.sock_server.sendto(bytes(msg, encoding='utf-8'), (
            bytes(self.client_ip_entry.get(), encoding='utf-8'), int(self.client_port_entry.get())))

    def on_closing(self):
        config = configparser.ConfigParser()
        config['SETTINGS'] = {}
        config['SETTINGS']['client_ip'] = self.client_ip
        config['SETTINGS']['client_port'] = self.client_port
        config['SETTINGS']['local_port'] = self.local_port
        config['SETTINGS']['send1'] = self.send1_entry.get()
        config['SETTINGS']['send2'] = self.send2_entry.get()
        config['SETTINGS']['send3'] = self.send3_entry.get()

        with open(self.cfg_file, 'w') as configfile:
            config.write(configfile)

        self.master.destroy()
예제 #14
0
class P300Window(object):
    """All logic for the image flashing window.

    Args:
        master: Tkinter Toplevel element
        parent: Parent that opened the window
        config: ConfigParams instance

    """

    def __init__(self, master: Toplevel, parent: MainWindow, config: ConfigParams):
        self.master = master
        self.parent = parent

        self.master.protocol('WM_DELETE_WINDOW', self.close_window)

        self.config = config
        self.running = 0

        self.image_labels = []
        self.sequence_number = 0
        self.lsl_output = None
        self.usable_images = []
        self.flash_sequence = []

        self.image_frame = Frame(self.master)
        self.image_frame.grid(row=0, column=0, rowspan=self.config.number_of_rows.get(),
                              columnspan=self.config.number_of_columns.get())

        self.start_btn_text = StringVar()
        self.start_btn_text.set('Start')
        self.start_btn = Button(self.master, textvariable=self.start_btn_text, command=self.start)
        self.start_btn.grid(row=self.config.number_of_rows.get() + 1, column=self.config.number_of_columns.get() - 1)

        self.pause_btn = Button(self.master, text='Pause', command=self.pause)
        self.pause_btn.grid(row=self.config.number_of_rows.get() + 1, column=self.config.number_of_columns.get() - 2)
        self.pause_btn.configure(state='disabled')

        self.close_btn = Button(self.master, text='Close', command=self.close_window)
        self.close_btn.grid(row=self.config.number_of_rows.get() + 1, column=0)

        # Initialization
        self.show_images()
        self.create_flash_sequence()
        self.lsl_output = self.create_lsl_output()

    def open_images(self):
        self.usable_images = []
        image_paths = glob.glob(os.path.join(self.config.images_folder_path.get(), '*.jpg'))
        png_images = glob.glob(os.path.join(self.config.images_folder_path.get(), '*.png'))
        for png_image in png_images:
            image_paths.append(png_image)
        min_number_of_images = self.config.number_of_columns.get() * self.config.number_of_rows.get()
        if len(image_paths) < min_number_of_images:
            self.parent.print_to_console('To few images in folder: ' + self.config.images_folder_path.get())
            return

        # Convert and resize images
        for image_path in image_paths:
            image = Image.open(image_path)
            resized = image.resize((self.config.imagesize.get(), self.config.imagesize.get()), Image.ANTIALIAS)
            Tkimage = ImageTk.PhotoImage(resized)
            self.usable_images.append(Tkimage)

        flash_img = Image.open(self.config.flash_image_path.get())
        flash_img_res = flash_img.resize((self.config.imagesize.get(), self.config.imagesize.get()), Image.ANTIALIAS)
        self.flash_image = ImageTk.PhotoImage(flash_img_res)

    def show_images(self):
        self.open_images()

        if self.usable_images == []:
            self.parent.print_to_console('No images opened')
            return

        num_rows = self.config.number_of_rows.get()
        num_cols = self.config.number_of_columns.get()

        # Arrange images
        for r in range(0, num_rows):
            for c in range(0, num_cols):
                current_image = self.usable_images[r * num_cols + c]
                label = Label(self.image_frame, image=current_image)
                label.image = current_image
                label.grid(row=r, column=c)
                self.image_labels.append(label)

    def create_lsl_output(self):
        """Creates an LSL Stream outlet"""
        info = StreamInfo(name=self.config.lsl_streamname.get(), type='P300_Marker',
                          channel_count=1, channel_format='int8', nominal_srate=IRREGULAR_RATE,
                          source_id='marker_stream', handle=None)

        if self.config.flash_mode == 1:
            info.desc().append_child_value('flash_mode', 'Row and Column')
        elif self.config.flash_mode == 2:
            info.desc().append_child_value('flash_mode', 'Single Value')

        info.desc().append_child_value('num_rows', str(self.config.number_of_rows.get()))
        info.desc().append_child_value('num_cols', str(self.config.number_of_columns.get()))

        return StreamOutlet(info)

    def create_flash_sequence(self):
        self.flash_sequence = []
        num_rows = self.config.number_of_rows.get()
        num_cols = self.config.number_of_columns.get()

        sequence_length = 700  # ms
        distance_between_similar_elements = int((sequence_length / self.config.break_duration.get()) + 1)

        if self.config.flash_mode.get() == 1:
            self.parent.print_to_console('CAUTION: Row and Column flash mode currently uses only random samples!')
            self.flash_sequence = np.random.randint(0, num_rows + num_cols, 3000)
        elif self.config.flash_mode.get() == 2:
            flash_sequence = []
            maximum_number = num_rows * num_cols

            if maximum_number * 0.7 < distance_between_similar_elements:
                self.parent.print_to_console('No sequence could be created because the break duration is too short')
                return

            number_buffer = deque(maxlen=distance_between_similar_elements)

            for _ in range(0, MAX_FLASHES):
                while True:
                    new_number = np.random.randint(0, maximum_number, 1)
                    if bool(number_buffer.count(new_number[0])) is False:
                        number_buffer.append(new_number[0])
                        flash_sequence.append(new_number[0])
                        break
            self.flash_sequence = flash_sequence

    def start(self):
        self.running = 1
        self.start_flashing()
        self.start_btn.configure(state='disabled')
        self.pause_btn.configure(state='normal')

    def pause(self):
        self.running = 0
        self.start_btn_text.set('Resume')
        self.start_btn.configure(state='normal')
        self.pause_btn.configure(state='disabled')

    def start_flashing(self):
        if self.sequence_number == len(self.flash_sequence):
            self.parent.print_to_console('All elements flashed')
            self.running = 0
            self.sequence_number = 0
            return

        if self.running == 0:
            self.parent.print_to_console('Flashing paused at sequence number ' + str(self.sequence_number))
            return

        element_to_flash = self.flash_sequence[self.sequence_number]
        self.sequence_number = self.sequence_number + 1

        timestamp = local_clock()
        print([element_to_flash + 1], timestamp)
        self.lsl_output.push_sample([element_to_flash + 1], timestamp)  # add 1 to prevent 0 in markers

        if self.config.flash_mode.get() == 1:
            self.flash_row_or_col(element_to_flash)
        elif self.config.flash_mode.get() == 2:
            self.flash_single_element(element_to_flash)

        self.master.after(self.config.break_duration.get(), self.start_flashing)

    def change_image(self, label, img):
        label.configure(image=img)
        label.image = img

    def flash_row_or_col(self, rc_number):
        num_rows = self.config.number_of_rows.get()
        num_cols = self.config.number_of_columns.get()

        if rc_number < num_rows:
            for c in range(0, num_cols):
                cur_idx = rc_number * num_cols + c
                self.change_image(self.image_labels[cur_idx], self.flash_image)
        else:
            current_column = rc_number - num_rows
            for r in range(0, num_rows):
                cur_idx = current_column + r * num_cols
                self.change_image(self.image_labels[cur_idx], self.flash_image)

        self.master.after(self.config.flash_duration.get(), self.unflash_row_or_col, rc_number)

    def unflash_row_or_col(self, rc_number):
        num_rows = self.config.number_of_rows.get()
        num_cols = self.config.number_of_columns.get()
        if rc_number < num_rows:
            for c in range(0, num_cols):
                cur_idx = rc_number * num_cols + c
                self.change_image(self.image_labels[cur_idx], self.usable_images[cur_idx])
        else:
            current_column = rc_number - num_rows
            for r in range(0, num_rows):
                cur_idx = current_column + r * num_cols
                self.change_image(self.image_labels[cur_idx], self.usable_images[cur_idx])

    def flash_single_element(self, element_no):
        self.change_image(self.image_labels[element_no], self.flash_image)
        self.master.after(self.config.flash_duration.get(), self.unflash_single_element, element_no)

    def unflash_single_element(self, element_no):
        self.change_image(self.image_labels[element_no], self.usable_images[element_no])

    def close_window(self):
        self.parent.enable_all_widgets()
        self.master.destroy()
예제 #15
0
    def listchans(self,
                  index=None,
                  tagsearch="",
                  archived=0,
                  ob=Channel.displayname,
                  so=asc):
        self.center = Frame(root,
                            bg=config.bgcolor,
                            width=50,
                            height=40,
                            padx=3,
                            pady=3)

        # layout all of the main containers
        root.grid_rowconfigure(1, weight=1)
        root.grid_columnconfigure(0, weight=1)
        self.center.grid(row=1, sticky="nsew")

        channels = database.get_channels(archived, ob, so)
        if so == desc:
            so = asc
        else:
            so = desc

        tree = Treeview(self.center)

        sstring = Entry(self.center, width=config.textBoxWidth)
        sstring.bind(
            "<KeyRelease-Return>",
            lambda e: self.listchans(None, sstring.get(), archived, ob, so))
        sstring.grid(column=0, row=0)
        if len(tagsearch) >= 1:
            sstring.focus()
            sstring.insert(0, tagsearch)
        searchbutton = Button(self.center,
                              text="Search",
                              command=lambda: self.listchans(
                                  None, sstring.get(), archived, ob, so))
        searchbutton.grid(column=1, row=0)

        clearbutton = Button(self.center, text="Clear Search")
        clearbutton.configure(command=lambda: self.listchans(archived))
        clearbutton.grid(column=3, row=0)

        tree["columns"] = ("one", "two")

        tree.column("#0", width=210, minwidth=10, stretch=YES)
        tree.column("one", width=350, minwidth=250, stretch=YES)
        tree.column("two", width=210, minwidth=10, stretch=YES)

        tree.heading("#0",
                     text="Last Check",
                     anchor=W,
                     command=lambda: self.listchans(None, sstring.get(
                     ), archived, Channel.lastcheck, so))

        tree.heading("one",
                     text="Channel Name",
                     anchor=E,
                     command=lambda: self.listchans(None, sstring.get(
                     ), archived, Channel.displayname, so))
        tree.heading("two",
                     text="Last Published",
                     command=lambda: self.listchans(None, sstring.get(
                     ), archived, Channel.lastpub, so))
        i = 0
        tree.tag_configure('oddrow', background='#88DD88')
        tree.tag_configure('evenrow', background='#FFFFFF')
        tree.tag_configure('archivedodd',
                           background="#88DD88",
                           foreground="#aaaaaa")
        tree.tag_configure('archivedeven',
                           background='#FFFFFF',
                           foreground="#cccccc")

        for item in channels:
            foldername = "folder" + str(i)

            if i % 2 == 0:
                color = "evenrow"
            else:
                color = "oddrow"

            if item.archive == True:
                if i % 2 == 0:
                    color = "archivedeven"
                else:
                    color = "archivedodd"

            if tagsearch.lower() in str(
                    item.displayname).lower() or tagsearch.lower() in str(
                        item.dldir).lower() or tagsearch.lower() in str(
                            item.yt_channelid).lower():
                if item.lastpub == None:
                    lastpub = "N/A"
                else:
                    lastpub = time.ctime(item.lastpub)

                foldername = tree.insert("",
                                         "end",
                                         text=time.ctime(item.lastcheck),
                                         values=(item.displayname, lastpub),
                                         tags=(color, item.displayname,
                                               item.dldir, item.yt_channelid))

                tree.insert(foldername,
                            "end",
                            text="Directory",
                            values=(item.dldir, ),
                            tags=(color))

                tree.insert(foldername,
                            "end",
                            text="Last Published",
                            values=(lastpub, ),
                            tags=(color))

                i = i + 1

        vertscroll = Scrollbar(self.center)
        vertscroll.config(command=tree.yview)
        tree.config(yscrollcommand=vertscroll.set, height=20)
        vertscroll.grid(column=4, row=1, sticky='NSE')
        tree.bind("<Double-1>", self.item_selected)

        tree.grid(row=1, columnspan=4, sticky="NSEW")
        tree.focus(index)
        tree.selection_set(index)
        tree.see(index)
예제 #16
0
class SignInView(Frame):
    def __init__(self, master):
        super().__init__(master=master)
        self.layout_components()
        # Setup Callbacks
        self.show_register: Callable = None
        self.sign_in: Callable = None
        self.user_Entry.focus()

    def layout_components(self):
        self.pack(fill=tk.BOTH, expand=False, padx=PADX, pady=PADY)
        error_font = font.Font(family="Ariel", size=8)

        # Variables
        self.username = tk.StringVar()
        self.username.set("")

        self.password = tk.StringVar()
        self.password.set("")

        # Username Row
        user_Frame = Frame(self)
        user_Frame.pack(fill=tk.X)
        user_Label = Label(user_Frame, text="Username:"******"<FocusOut>", self.enable_sign_in)
        self.user_Entry.pack(fill=tk.X, padx=PADX, pady=PADY, expand=True)

        # Password Row
        pass_Frame = Frame(self)
        pass_Frame.pack(fill=tk.X)
        pass_Label = Label(pass_Frame, text="Password:"******"*")
        self.pass_Entry.bind("<FocusOut>", self.enable_sign_in)
        self.pass_Entry.pack(fill=tk.X, padx=PADX, pady=PADY, expand=True)

        # Error Row
        err_Frame = Frame(self)
        err_Frame.pack(fill=tk.X)
        self.err_Label = Label(err_Frame,
                               text="",
                               foreground="red",
                               font=error_font)
        self.err_Label.pack(side=tk.LEFT,
                            anchor="center",
                            expand=True,
                            padx=PADX,
                            pady=PADY)

        # Button Row
        button_Frame = Frame(self)
        button_Frame.pack(fill=tk.X)
        # Cancel Button
        cncl_Button = Button(button_Frame, text="Cancel", command=self.cancel)
        cncl_Button.pack(side=tk.RIGHT, padx=PADX, pady=PADY, expand=False)
        # Sign in Button
        self.sgnn_Button = Button(button_Frame,
                                  text="Sign in",
                                  state="disabled",
                                  command=self._sign_in)
        self.sgnn_Button.pack(side=tk.RIGHT,
                              padx=PADX,
                              pady=PADY,
                              expand=False)

        # Register Row
        register_Frame = Frame(self)
        register_Frame.pack(fill=tk.X)
        register_Button = Button(register_Frame,
                                 text="Register",
                                 command=self._show_register)
        register_Button.pack(side=tk.RIGHT, padx=PADX, pady=PADY, expand=False)
        register_Label = Label(register_Frame,
                               text="Not a Member of ExchangeGram?")
        register_Label.pack(side=tk.RIGHT, padx=PADX, pady=PADY)

    def _sign_in(self):
        if self.sign_in is not None:
            self.sign_in()

    def enable_sign_in(self, event):
        if self.username.get() != "" and self.password.get() != "":
            self.sgnn_Button.configure(state="normal")
        else:
            self.sgnn_Button.configure(state="disabled")

    def failed_sign_in(self):
        self.err_Label.configure(text="Username/Password Incorrect")

    def cancel(self):
        self.username.set("")
        self.password.set("")
        self.user_Entry.focus()

    def _show_register(self):
        if self.show_register is not None:
            self.cancel()
            self.show_register()
        else:
            pass
예제 #17
0
class ErrorSurfaceFrame(LabelFrame):
	
	def __init__(self,parent):
		LabelFrame.__init__(self, parent, borderwidth=0)
		
		entryWidth = 7
		xPad1 = 30
		xPad2 = 5
		
		self.errorXLowerLimitL = Label(self)
		self.errorXLowerLimitE = CustomEntry(self,width=entryWidth,justify="right")
		self.errorXLowerLimitL.grid(row=0,column=0,padx=(10,xPad2),pady=5,sticky="W")
		self.errorXLowerLimitE.grid(row=0,column=1,padx=(xPad2,xPad1),pady=5)
		
		self.errorXUpperLimitL = Label(self)
		self.errorXUpperLimitE = CustomEntry(self,width=entryWidth,justify="right")
		self.errorXUpperLimitL.grid(row=1,column=0,padx=(10,xPad2),pady=5,sticky="W")
		self.errorXUpperLimitE.grid(row=1,column=1,padx=(xPad2,xPad1),pady=5)
		
		self.errorYLowerLimitL = Label(self)
		self.errorYLowerLimitE = CustomEntry(self,width=entryWidth,justify="right")
		self.errorYLowerLimitL.grid(row=0,column=2,padx=(xPad1,xPad2),pady=5,sticky="W")
		self.errorYLowerLimitE.grid(row=0,column=3,padx=(xPad2,xPad1),pady=5)
		
		self.errorYUpperLimitL = Label(self)
		self.errorYUpperLimitE = CustomEntry(self,width=entryWidth,justify="right")
		self.errorYUpperLimitL.grid(row=1,column=2,padx=(xPad1,xPad2),pady=5,sticky="W")
		self.errorYUpperLimitE.grid(row=1,column=3,padx=(xPad2,xPad1),pady=5)
		
		self.errorResolutionL = Label(self,text="Resolution: ")
		self.errorResolutionE = CustomEntry(self,width=entryWidth,justify="right")
		self.errorResolutionE.insert(0,ERROR_SURFACE_DEFAULT_RESOLUTION)
		self.errorResolutionL.grid(row=0,column=4,padx=(xPad1,xPad2),pady=5,sticky="W")
		self.errorResolutionE.grid(row=0,column=5,padx=(xPad2,xPad1),pady=5,sticky="E")
		
		self.errorSurfaceB = Button(self,text=" Calculate error surface ")
		self.errorSurfaceB.grid(row=1,column=4,columnspan=2,padx=(xPad1,xPad1),sticky="EW")
		self.errorSurfaceB.configure(state=tkinter.ACTIVE)
		
	def update(self,xSymbol,ySymbol,xLL,xUL,yLL,yUL):
		
		self.xSymbol = xSymbol
		self.ySymbol = ySymbol
		
		self.errorXLowerLimitL.configure(text="Lower limit ("+self.xSymbol+"): ")
		self.errorXLowerLimitE.insertNew(xLL)
		
		self.errorXUpperLimitL.configure(text="Upper limit ("+self.xSymbol+"): ")
		self.errorXUpperLimitE.insertNew(xUL)
		
		self.errorYLowerLimitL.configure(text="Lower limit ("+self.ySymbol+"): ")
		self.errorYLowerLimitE.insertNew(yLL)
		
		self.errorYUpperLimitL.configure(text="Upper limit ("+self.ySymbol+"): ")
		self.errorYUpperLimitE.insertNew(yUL)
		
	def getSurfaceParameters(self):
		
		xLowerLimit = helper_functions.validateValue(self.errorXLowerLimitE.get(),
									self.xSymbol + " lower limit must be a positive number",
									"float",
									lowerBound=0)
		xUpperLimit = helper_functions.validateValue(self.errorXUpperLimitE.get(),
									self.xSymbol + " upper limit must be greater than the lower limit",
									"float",
									strictLowerBound=xLowerLimit)
		yLowerLimit = helper_functions.validateValue(self.errorYLowerLimitE.get(),
									self.ySymbol + " lower limit must be a positive number",
									"float",
									lowerBound=0)
		yUpperLimit = helper_functions.validateValue(self.errorYUpperLimitE.get(),
									self.ySymbol + " upper limit must be greater than the lower limit",
									"float",
									strictLowerBound=yLowerLimit)
		resolution = helper_functions.validateValue(self.errorResolutionE.get(),
								   "Resolution must be " + str(ERROR_SURFACE_MIN_RESOLUTION) + " \u2264 x \u2264 " + str(ERROR_SURFACE_MAX_RESOLUTION),
								   "int",
								   lowerBound=ERROR_SURFACE_MIN_RESOLUTION,
								   upperBound=ERROR_SURFACE_MAX_RESOLUTION)
		
		return [xLowerLimit,xUpperLimit,yLowerLimit,yUpperLimit,resolution]
		
	def clear(self):
		self.errorXLowerLimitE.insertNew("")
		self.errorXUpperLimitE.insertNew("")
		self.errorYLowerLimitE.insertNew("")
		self.errorYUpperLimitE.insertNew("")
예제 #18
0
class Example(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)

        self.parent = parent
        self.initUI()

    def initUI(self):
        self.parent.title("")
        #self.style = Style()
        #self.style.theme_use("clam")
        #self.pack(fill=BOTH, expand = 1)

        self.quitbutton = Button(self,
                                 text="Quit",
                                 command=lambda: self.quit())

        self.quitbutton.grid(row=3, column=1, pady=4)

        self.labelErrorPointer = Label(self, text="◀")

        self.labellist = []
        self.entrylist = []
        self.verifylist = []
        self.misclist = []

        self.optionCreate = "Create"
        self.optionUpcoming = "Upcoming"
        self.optionPast = "Past"

        self.prevmode = self.optionCreate
        self.curmode = self.optionCreate
        self.optionvar = tkinter.StringVar(self)
        self.optionvar.trace("w", self.permaloop)
        self.optionvar.set(self.optionCreate)
        self.option = OptionMenu(self, self.optionvar, self.optionCreate,
                                 self.optionUpcoming, self.optionPast)

        self.optionpostmodevar = tkinter.StringVar(self)
        self.optionpostmodevar.trace("w", self.permaloop)
        self.optionpostmodevar.set('url')
        self.optionpostmode = OptionMenu(self, self.optionpostmodevar, 'url',
                                         'text')

        self.labelText = Label(self, text='Selftext:')
        self.entryText = Text(self)
        self.labelURL = Label(self, text='URL:')
        self.entryURL = Entry(self)
        self.entryURL.configure(width=60)

        self.sql = sqlite3.connect('sql.db')
        print('Loaded SQL Database')
        self.cur = self.sql.cursor()

        self.cur.execute(
            'CREATE TABLE IF NOT EXISTS upcoming(ID TEXT, SUBREDDIT TEXT, TIME INT, TITLE TEXT, URL TEXT, BODY TEXT)'
        )
        self.cur.execute(
            'CREATE TABLE IF NOT EXISTS past(ID TEXT, SUBREDDIT TEXT, TIME INT, TITLE TEXT, URL TEXT, BODY TEXT, POSTLINK TEXT)'
        )
        self.cur.execute(
            'CREATE TABLE IF NOT EXISTS internal(NAME TEXT, ID INT)')
        print('Loaded Completed table')
        self.cur.execute('SELECT * FROM internal')
        f = self.cur.fetchone()
        if not f:
            print('Database is new. Adding ID counter')
            self.cur.execute('INSERT INTO internal VALUES(?, ?)',
                             ['counter', 1])
            self.idcounter = 1
        else:
            self.idcounter = f[1]
            print('Current ID counter: ' + str(self.idcounter))

        self.sql.commit()

        sw = self.parent.winfo_screenwidth()
        sh = self.parent.winfo_screenheight()

        w = 853
        h = 480
        x = (sw - w) / 2
        y = (sh - h) / 2

        self.parent.geometry('%dx%d+%d+%d' % (w, h, x, y - 50))

        self.login()

    def login(self):

        try:
            self.quitbutton.grid_forget()
            self.quitbutton.grid(row=9000, column=0, columnspan=20)

            self.option.grid(row=1, column=0, columnspan=80, pady=8)

            self.updategui(fullclean=True)
        except praw.errors.InvalidUserPass:
            pass
            print('Invalid username or password')
            self.entryPassword.delete(0, 200)
            self.labelErrorPointer.grid(row=1, column=2)

    def permaloop(self, *args):
        self.curmode = self.optionvar.get()
        print('Was: ' + self.prevmode + ' | Now: ' + self.curmode)
        if self.curmode != self.prevmode:
            self.prevmode = self.curmode
            self.updategui(fullclean=True)
        else:
            self.updategui(False)

    def getTime(self, bool):
        timeNow = datetime.datetime.now(datetime.timezone.utc)
        timeUnix = timeNow.timestamp()
        if bool == False:
            return timeNow
        else:
            return timeUnix

    def addentrytobase(self,
                       subreddit,
                       title,
                       url="",
                       body="",
                       mode="",
                       ptime=""):
        curtime = round(self.getTime(True))
        try:
            t = self.entryMo.get() + ' ' + self.entryDa.get(
            ) + ' ' + self.entryYr.get() + ' ' + self.entryHH.get(
            ) + ':' + self.entryMM.get()
            plandate = datetime.datetime.strptime(t, "%B %d %Y %H:%M")
            plandate = plandate.timestamp()
        except ValueError:
            print('Invalid Day')
            return False

        if mode == 'url':
            url = self.entryURL.get()
            body = ""
            if 'http://' not in url and 'https://' not in url:
                print('Please enter a proper URL')
                return False
        if mode == 'text':
            body = self.entryText.get("1.0", "end")
            url = ""

        if plandate < curtime:
            print('Please enter a time in the future')
            return False

        if not all(char in string.ascii_letters + string.digits + '_-'
                   for char in subreddit):
            print('Subreddit contains invalid characters')
            return False

        if len(subreddit) == 0:
            print('You must enter a subreddit')
            return False

        if len(title) == 0:
            print('You must enter a title')
            return False
        if len(title) > 300:
            print('Title is too long. ' + str(len(title)) + '/300 char max')
            return False
        if len(body) > 15000:
            print('Body is too long. ' + str(len(body)) + '/15,000 char max')

        print('Timestamp:', plandate)
        self.cur.execute(
            'INSERT INTO upcoming VALUES(?, ?, ?, ?, ?, ?)',
            [self.idcounter, subreddit,
             int(plandate), title, url, body])
        self.idcounter += 1
        self.cur.execute('UPDATE internal SET ID=? WHERE NAME=?',
                         [self.idcounter, 'counter'])
        self.sql.commit()
        print('\nPost Saved!')
        print(self.idcounter, subreddit, self.timestamptoday(int(plandate)))
        print(title)
        print(url, body)
        print()
        self.entryText.delete("1.0", "end")
        self.entryURL.delete(0, 'end')
        self.entryTitle.delete(0, 'end')
        #self.updategui(halfclean=True)

    def timestamptoday(self, timestamp):
        d = datetime.datetime.fromtimestamp(timestamp)
        info = datetime.datetime.strftime(d, "%b %d %H:%M")
        return info

    def dropentryfrombase(self, ID):
        if '-' not in ID:
            try:
                ID = int(ID)
                l = [ID]
            except ValueError:
                print('You must enter a number')
                return
        else:
            if ID.count('-') == 1:
                try:
                    ID = ID.replace(' ', '')
                    ID = ID.split('-')
                    ID[0] = int(ID[0])
                    ID[1] = int(ID[1])
                    if ID[1] > ID[0]:
                        l = list(range(ID[0], ID[1] + 1))
                    else:
                        return
                except ValueError:
                    return

        for item in l:
            item = str(item)
            print('Dropping Item ' + item + ' from Upcoming')
            self.cur.execute('DELETE FROM upcoming WHERE ID=?', [item])
            self.sql.commit()
        self.updategui(fullclean=True)

    def printbasetofile(self, db):
        filea = open(db + '.txt', 'w')
        if db == 'past':
            self.cur.execute('SELECT * FROM past')
        if db == 'upcoming':
            self.cur.execute('SELECT * FROM upcoming')
        f = self.cur.fetchall()
        print('Printed ' + db + ' unimpeded to file')
        for item in f:
            i = list(item)
            i[2] = self.timestamptoday(i[2])
            i.remove('')

            print(str(i)[1:-1], file=filea)
        filea.close()

    def updategui(self, halfclean=False, fullclean=False):

        if self.curmode == self.optionCreate:
            try:
                print(self.optionpostmodevar.get())

                if self.optionpostmodevar.get() == 'url':
                    self.entryText.delete("1.0", 'end')
                    self.labelText.grid_forget()
                    self.entryText.grid_forget()

                    self.labelURL.grid(row=8, column=0, columnspan=30)
                    self.entryURL.grid(row=9, column=0, columnspan=12, pady=10)

                if self.optionpostmodevar.get() == 'text':
                    self.entryURL.delete(0, 'end')
                    self.labelURL.grid_forget()
                    self.entryURL.grid_forget()

                    self.labelText.grid(row=8, column=0, columnspan=30)
                    self.entryText.configure(width=40, height=8)
                    self.entryText.grid(row=9, column=0, columnspan=12)
            except AttributeError:
                pass

        if fullclean == True:
            print('Cleaning GUI')
            for item in self.labellist:
                item.grid_forget()
            for item in self.entrylist:
                item.grid_forget()
            for item in self.verifylist:
                item.grid_forget()
            for item in self.misclist:
                item.grid_forget()
            self.labellist = []
            self.entrylist = []
            self.verifylist = []
            self.misclist = []

            if self.curmode == self.optionCreate:
                self.newrowindex = 6
                self.labelSubreddit = Label(self, text="Subreddit:    /r/")
                self.labelTitle = Label(self, text="Post title:  ")
                self.entrySubreddit = Entry(self)
                self.entryTitle = Entry(self)

                self.labelHH = Label(self,
                                     text="Schedule time (Local timezone):")
                nowlist = datetime.datetime.strftime(datetime.datetime.now(),
                                                     "%B %d %Y %H %M").split()

                self.entryMo = Spinbox(self, width=9, values=('January', 'February', 'March', 'April', 'May', 'June', 'July', \
                    'August', 'September', 'October', 'November', 'December'))
                self.entryMo.delete(0, 'end')
                self.entryMo.insert(0, nowlist[0])

                self.entryDa = Spinbox(self, width=2, from_=1, to=31)
                self.entryDa.delete(0, 'end')
                self.entryDa.insert(0, nowlist[1])

                self.entryYr = Spinbox(self, width=4, from_=2014, to=2500)
                self.entryYr.delete(0, 'end')
                self.entryYr.insert(0, nowlist[2])

                self.entryHH = Spinbox(self, from_=0, to=23, width=2)
                self.entryHH.delete(0, 'end')
                self.entryHH.insert(0, nowlist[3])

                self.entryMM = Spinbox(self, from_=0, to=59, width=2)
                self.entryMM.delete(0, 'end')
                self.entryMM.insert(0, nowlist[4])

                self.buttonAddentry = Button(self, text='Save', command=lambda: self.addentrytobase(self.entrySubreddit.get(), self.entryTitle.get(),\
                    mode=self.optionpostmodevar.get()))

                self.misclist.append(self.labelSubreddit)
                self.misclist.append(self.entrySubreddit)
                self.misclist.append(self.labelHH)
                self.misclist.append(self.entryHH)
                self.misclist.append(self.entryMM)
                self.misclist.append(self.entryMo)
                self.misclist.append(self.entryDa)
                self.misclist.append(self.entryYr)
                self.misclist.append(self.labelTitle)
                self.misclist.append(self.entryTitle)
                self.misclist.append(self.buttonAddentry)
                self.misclist.append(self.optionpostmode)
                self.misclist.append(self.labelText)
                self.misclist.append(self.entryText)
                self.misclist.append(self.labelURL)
                self.misclist.append(self.entryURL)

                self.labelSubreddit.grid(row=2, column=0, sticky="e")
                self.labelTitle.grid(row=3, column=0, sticky="e")
                self.entrySubreddit.grid(row=2,
                                         column=1,
                                         columnspan=3,
                                         sticky="w")
                self.entryTitle.grid(row=3, column=1, columnspan=3, sticky="w")
                self.entryMo.grid(row=4, column=1, sticky="e")
                self.entryDa.grid(row=4, column=2)
                self.entryYr.grid(row=4, column=3)
                self.labelHH.grid(row=4, column=0, sticky="se", pady=5)
                self.entryHH.grid(row=5, column=1, sticky="e")
                self.entryMM.grid(row=5, column=2, sticky="w")
                self.optionpostmode.grid(row=6,
                                         column=0,
                                         columnspan=20,
                                         pady=10)
                self.buttonAddentry.grid(row=200, column=0, columnspan=20)

            if self.curmode == self.optionUpcoming:
                self.cur.execute('SELECT * FROM upcoming')
                dobutton = True

            if self.curmode == self.optionPast:
                self.cur.execute('SELECT * FROM past')
                dobutton = False

            if self.curmode == self.optionPast or self.curmode == self.optionUpcoming:

                self.listboxId = Listbox(self)
                self.listboxId.configure(width=118,
                                         height=20,
                                         font=("Courier 8"))
                self.misclist.append(self.listboxId)

                self.listboxScroller = Scrollbar(self,
                                                 orient='horizontal',
                                                 command=self.listboxId.xview)
                self.listboxScroller.grid(row=4, column=0, columnspan=900)
                self.listboxId.grid(row=3, column=0, columnspan=10)

                self.listboxId.configure(
                    xscrollcommand=self.listboxScroller.set)
                self.misclist.append(self.listboxScroller)

                self.buttonPrinter = Button(self, text="Print to .txt file")
                if self.curmode == self.optionPast:
                    self.buttonPrinter.configure(
                        command=lambda: self.printbasetofile('past'))
                if self.curmode == self.optionUpcoming:
                    self.buttonPrinter.configure(
                        command=lambda: self.printbasetofile('upcoming'))

                self.buttonPrinter.grid(row=6, column=0, columnspan=90)
                self.misclist.append(self.buttonPrinter)

                if dobutton == True:
                    self.entryDelete = Entry(self)
                    self.buttonDelete = Button(
                        self,
                        text="Delete Item: ",
                        command=lambda: self.dropentryfrombase(self.entryDelete
                                                               .get()))
                    self.buttonDelete.grid(row=5, column=0, sticky='e')
                    self.entryDelete.grid(row=5, column=1, sticky='w')
                    self.misclist.append(self.entryDelete)
                    self.misclist.append(self.buttonDelete)

                fetched = self.cur.fetchall()
                for item in fetched:

                    info = self.timestamptoday(item[2])

                    if item[4] == '':
                        infx = item[5]
                    if item[5] == '':
                        infx = item[4]
                    if self.curmode == self.optionPast:
                        infy = '.' + item[6]
                    else:
                        infy = ''

                    self.listboxId.insert('end', \
                        item[0] + '.'*(6 - len(item[0])) \
                        + item[1][:10] + '.'*(12 - len(item[1][:10])) \
                        + info + '.'*(15 - len(info[:14])) \
                        + item[3][:18] + '.'*(20 - len(item[3][:14])) \
                        + infx[:45] + '.'*(47-len(infx[:45])) \
                        + infy)

    def morerows(self, label, columnm, columnn, limit, *args):
        self.redditlabel = Label(self, text=label)
        self.redditlabel.grid(row=self.newrowindex, column=columnm, sticky="e")
        self.labellist.append(self.redditlabel)

        self.redditentry = Entry(self)
        self.redditentry.grid(row=self.newrowindex,
                              column=columnn,
                              columnspan=9)
        self.entrylist.append(self.redditentry)

        self.newrowindex += 1
        if self.newrowindex >= limit:
            self.morerowbutton.grid_forget()
        print(self.newrowindex)
예제 #19
0
class Example(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)

        self.parent = parent
        self.initUI()

    def initUI(self):
        self.parent.title("")
        # self.style = Style()
        # self.style.theme_use("clam")
        # self.pack(fill=BOTH, expand = 1)

        self.quitbutton = Button(self, text="Quit", command=lambda: self.quit())

        self.quitbutton.grid(row=3, column=1, pady=4)

        self.labelErrorPointer = Label(self, text="◀")

        self.labellist = []
        self.entrylist = []
        self.verifylist = []
        self.misclist = []

        self.optionCreate = "Create"
        self.optionUpcoming = "Upcoming"
        self.optionPast = "Past"

        self.prevmode = self.optionCreate
        self.curmode = self.optionCreate
        self.optionvar = tkinter.StringVar(self)
        self.optionvar.trace("w", self.permaloop)
        self.optionvar.set(self.optionCreate)
        self.option = OptionMenu(self, self.optionvar, self.optionCreate, self.optionUpcoming, self.optionPast)

        self.optionpostmodevar = tkinter.StringVar(self)
        self.optionpostmodevar.trace("w", self.permaloop)
        self.optionpostmodevar.set("url")
        self.optionpostmode = OptionMenu(self, self.optionpostmodevar, "url", "text")

        self.labelText = Label(self, text="Selftext:")
        self.entryText = Text(self)
        self.labelURL = Label(self, text="URL:")
        self.entryURL = Entry(self)
        self.entryURL.configure(width=60)

        self.sql = sqlite3.connect("sql.db")
        print("Loaded SQL Database")
        self.cur = self.sql.cursor()

        self.cur.execute(
            "CREATE TABLE IF NOT EXISTS upcoming(ID TEXT, SUBREDDIT TEXT, TIME INT, TITLE TEXT, URL TEXT, BODY TEXT)"
        )
        self.cur.execute(
            "CREATE TABLE IF NOT EXISTS past(ID TEXT, SUBREDDIT TEXT, TIME INT, TITLE TEXT, URL TEXT, BODY TEXT, POSTLINK TEXT)"
        )
        self.cur.execute("CREATE TABLE IF NOT EXISTS internal(NAME TEXT, ID INT)")
        print("Loaded Completed table")
        self.cur.execute("SELECT * FROM internal")
        f = self.cur.fetchone()
        if not f:
            print("Database is new. Adding ID counter")
            self.cur.execute("INSERT INTO internal VALUES(?, ?)", ["counter", 1])
            self.idcounter = 1
        else:
            self.idcounter = f[1]
            print("Current ID counter: " + str(self.idcounter))

        self.sql.commit()

        sw = self.parent.winfo_screenwidth()
        sh = self.parent.winfo_screenheight()

        w = 853
        h = 480
        x = (sw - w) / 2
        y = (sh - h) / 2

        self.parent.geometry("%dx%d+%d+%d" % (w, h, x, y - 50))

        self.login()

    def login(self):

        try:
            self.quitbutton.grid_forget()
            self.quitbutton.grid(row=9000, column=0, columnspan=20)

            self.option.grid(row=1, column=0, columnspan=8, pady=8)

            self.updategui(fullclean=True)
        except praw.errors.InvalidUserPass:
            pass
            print("Invalid username or password")
            self.entryPassword.delete(0, 200)
            self.labelErrorPointer.grid(row=1, column=2)

    def permaloop(self, *args):
        self.curmode = self.optionvar.get()
        print("Was: " + self.prevmode + " | Now: " + self.curmode)
        if self.curmode != self.prevmode:
            self.prevmode = self.curmode
            self.updategui(fullclean=True)
        else:
            self.updategui(False)

    def getTime(self, bool):
        timeNow = datetime.datetime.now(datetime.timezone.utc)
        timeUnix = timeNow.timestamp()
        if bool == False:
            return timeNow
        else:
            return timeUnix

    def addentrytobase(self, subreddit, title, url="", body="", mode="", ptime=""):
        curtime = round(self.getTime(True))
        try:
            t = (
                self.entryMo.get()
                + " "
                + self.entryDa.get()
                + " "
                + self.entryYr.get()
                + " "
                + self.entryHH.get()
                + ":"
                + self.entryMM.get()
            )
            plandate = datetime.datetime.strptime(t, "%B %d %Y %H:%M")
            plandate = plandate.timestamp()
        except ValueError:
            print("Invalid Day")
            return False

        if mode == "url":
            url = self.entryURL.get()
            body = ""
            if "http://" not in url and "https://" not in url:
                print("Please enter a proper URL")
                return False
        if mode == "text":
            body = self.entryText.get("1.0", "end")
            url = ""

        if plandate < curtime:
            print("Please enter a time in the future")
            return False

        if not all(char in string.ascii_letters + string.digits + "_-" for char in subreddit):
            print("Subreddit contains invalid characters")
            return False

        if len(subreddit) == 0:
            print("You must enter a subreddit")
            return False

        if len(title) == 0:
            print("You must enter a title")
            return False
        if len(title) > 300:
            print("Title is too long. " + str(len(title)) + "/300 char max")
            return False
        if len(body) > 15000:
            print("Body is too long. " + str(len(body)) + "/15,000 char max")

        print("Timestamp:", plandate)
        self.cur.execute(
            "INSERT INTO upcoming VALUES(?, ?, ?, ?, ?, ?)",
            [self.idcounter, subreddit, int(plandate), title, url, body],
        )
        self.idcounter += 1
        self.cur.execute("UPDATE internal SET ID=? WHERE NAME=?", [self.idcounter, "counter"])
        self.sql.commit()
        print("Post Saved!")
        self.entryText.delete("1.0", "end")
        self.entryURL.delete(0, "end")
        self.entryTitle.delete(0, "end")
        # self.updategui(halfclean=True)

    def dropentryfrombase(self, ID):
        try:
            ID = int(ID)
        except ValueError:
            print("You must enter a number")
            return
        print("Dropping Item " + str(ID) + " from Upcoming")
        self.cur.execute("DELETE FROM upcoming WHERE ID=?", [ID])
        self.sql.commit()
        self.updategui(fullclean=True)

    def printbasetofile(self, db):
        filea = open(db + ".txt", "w")
        if db == "past":
            self.cur.execute("SELECT * FROM past")
        if db == "upcoming":
            self.cur.execute("SELECT * FROM upcoming")
        f = self.cur.fetchall()
        print("Printed " + db + " unimpeded to file")
        for item in f:
            i = list(item)
            d = datetime.datetime.fromtimestamp(i[2])
            i[2] = datetime.datetime.strftime(d, "%b %d %H:%M")
            i.remove("")

            print(str(i)[1:-1], file=filea)
        filea.close()

    def updategui(self, halfclean=False, fullclean=False):

        if self.curmode == self.optionCreate:
            try:
                print(self.optionpostmodevar.get())

                if self.optionpostmodevar.get() == "url":
                    self.entryText.delete("1.0", "end")
                    self.labelText.grid_forget()
                    self.entryText.grid_forget()

                    self.labelURL.grid(row=8, column=0, columnspan=30)
                    self.entryURL.grid(row=9, column=0, columnspan=12, pady=10)

                if self.optionpostmodevar.get() == "text":
                    self.entryURL.delete(0, "end")
                    self.labelURL.grid_forget()
                    self.entryURL.grid_forget()

                    self.labelText.grid(row=8, column=0, columnspan=30)
                    self.entryText.configure(width=40, height=8)
                    self.entryText.grid(row=9, column=0, columnspan=12)
            except AttributeError:
                pass

        if fullclean == True:
            print("Cleaning GUI")
            for item in self.labellist:
                item.grid_forget()
            for item in self.entrylist:
                item.grid_forget()
            for item in self.verifylist:
                item.grid_forget()
            for item in self.misclist:
                item.grid_forget()
            self.labellist = []
            self.entrylist = []
            self.verifylist = []
            self.misclist = []

            if self.curmode == self.optionCreate:
                self.newrowindex = 6
                self.labelSubreddit = Label(self, text="Subreddit:    /r/")
                self.labelTitle = Label(self, text="Post title:  ")
                self.entrySubreddit = Entry(self)
                self.entryTitle = Entry(self)

                self.labelHH = Label(self, text="Schedule time (Local timezone):")
                nowlist = datetime.datetime.strftime(datetime.datetime.now(), "%B %d %Y %H %M").split()

                self.entryMo = Spinbox(
                    self,
                    width=9,
                    values=(
                        "January",
                        "February",
                        "March",
                        "April",
                        "May",
                        "June",
                        "July",
                        "August",
                        "September",
                        "October",
                        "November",
                        "December",
                    ),
                )
                self.entryMo.delete(0, "end")
                self.entryMo.insert(0, nowlist[0])

                self.entryDa = Spinbox(self, width=2, from_=1, to=31)
                self.entryDa.delete(0, "end")
                self.entryDa.insert(0, nowlist[1])

                self.entryYr = Spinbox(self, width=4, from_=2014, to=2500)
                self.entryYr.delete(0, "end")
                self.entryYr.insert(0, nowlist[2])

                self.entryHH = Spinbox(self, from_=0, to=23, width=2)
                self.entryHH.delete(0, "end")
                self.entryHH.insert(0, nowlist[3])

                self.entryMM = Spinbox(self, from_=0, to=59, width=2)
                self.entryMM.delete(0, "end")
                self.entryMM.insert(0, nowlist[4])

                self.buttonAddentry = Button(
                    self,
                    text="Save",
                    command=lambda: self.addentrytobase(
                        self.entrySubreddit.get(), self.entryTitle.get(), mode=self.optionpostmodevar.get()
                    ),
                )

                self.misclist.append(self.labelSubreddit)
                self.misclist.append(self.entrySubreddit)
                self.misclist.append(self.labelHH)
                self.misclist.append(self.entryHH)
                self.misclist.append(self.entryMM)
                self.misclist.append(self.entryMo)
                self.misclist.append(self.entryDa)
                self.misclist.append(self.entryYr)
                self.misclist.append(self.labelTitle)
                self.misclist.append(self.entryTitle)
                self.misclist.append(self.buttonAddentry)
                self.misclist.append(self.optionpostmode)
                self.misclist.append(self.labelText)
                self.misclist.append(self.entryText)
                self.misclist.append(self.labelURL)
                self.misclist.append(self.entryURL)

                self.labelSubreddit.grid(row=2, column=0, sticky="e")
                self.labelTitle.grid(row=3, column=0, sticky="e")
                self.entrySubreddit.grid(row=2, column=1, columnspan=3, sticky="w")
                self.entryTitle.grid(row=3, column=1, columnspan=3, sticky="w")
                self.entryMo.grid(row=4, column=1, sticky="e")
                self.entryDa.grid(row=4, column=2)
                self.entryYr.grid(row=4, column=3)
                self.labelHH.grid(row=4, column=0, sticky="se", pady=5)
                self.entryHH.grid(row=5, column=1, sticky="e")
                self.entryMM.grid(row=5, column=2, sticky="w")
                self.optionpostmode.grid(row=6, column=0, columnspan=20, pady=10)
                self.buttonAddentry.grid(row=200, column=0, columnspan=20)

            if self.curmode == self.optionUpcoming:
                self.cur.execute("SELECT * FROM upcoming")
                dobutton = True

            if self.curmode == self.optionPast:
                self.cur.execute("SELECT * FROM past")
                dobutton = False

            if self.curmode == self.optionPast or self.curmode == self.optionUpcoming:

                self.listboxId = Listbox(self)
                self.listboxId.configure(width=118, height=20, font=("Courier 8"))
                self.misclist.append(self.listboxId)

                self.listboxScroller = Scrollbar(self, orient="horizontal", command=self.listboxId.xview)
                self.listboxScroller.grid(row=4, column=0, columnspan=900)
                self.listboxId.grid(row=3, column=0, columnspan=10)

                self.listboxId.configure(xscrollcommand=self.listboxScroller.set)
                self.misclist.append(self.listboxScroller)

                self.buttonPrinter = Button(self, text="Print to .txt file")
                if self.curmode == self.optionPast:
                    self.buttonPrinter.configure(command=lambda: self.printbasetofile("past"))
                if self.curmode == self.optionUpcoming:
                    self.buttonPrinter.configure(command=lambda: self.printbasetofile("upcoming"))

                self.buttonPrinter.grid(row=6, column=0, columnspan=90)
                self.misclist.append(self.buttonPrinter)

                if dobutton == True:
                    self.entryDelete = Entry(self)
                    self.buttonDelete = Button(
                        self, text="Delete Item: ", command=lambda: self.dropentryfrombase(self.entryDelete.get())
                    )
                    self.buttonDelete.grid(row=5, column=0, sticky="e")
                    self.entryDelete.grid(row=5, column=1, sticky="w")
                    self.misclist.append(self.entryDelete)
                    self.misclist.append(self.buttonDelete)

                fetched = self.cur.fetchall()
                for item in fetched:
                    d = datetime.datetime.fromtimestamp(item[2])
                    info = datetime.datetime.strftime(d, "%b %d %H:%M")

                    if item[4] == "":
                        infx = item[5]
                    if item[5] == "":
                        infx = item[4]
                    if self.curmode == self.optionPast:
                        infy = "." + item[6]
                    else:
                        infy = ""

                    self.listboxId.insert(
                        "end",
                        item[0]
                        + "." * (6 - len(item[0]))
                        + item[1][:10]
                        + "." * (12 - len(item[1][:10]))
                        + info
                        + "." * (15 - len(info[:14]))
                        + item[3][:18]
                        + "." * (20 - len(item[3][:14]))
                        + infx[:45]
                        + "." * (47 - len(infx[:45]))
                        + infy,
                    )

    def morerows(self, label, columnm, columnn, limit, *args):
        self.redditlabel = Label(self, text=label)
        self.redditlabel.grid(row=self.newrowindex, column=columnm, sticky="e")
        self.labellist.append(self.redditlabel)

        self.redditentry = Entry(self)
        self.redditentry.grid(row=self.newrowindex, column=columnn, columnspan=9)
        self.entrylist.append(self.redditentry)

        self.newrowindex += 1
        if self.newrowindex >= limit:
            self.morerowbutton.grid_forget()
        print(self.newrowindex)
예제 #20
0
class Application(tkinter.Tk):
    def __init__(self):
        tkinter.Tk.__init__(self)

        # Menu Setup
        menuBar = Menu(self)

        fileMenu = Menu(menuBar, tearoff=False)
        fileMenu.add_command(label="Open...", command=self.loadSequence)
        fileMenu.add_command(label="Close", command=self.closeSequence)
        fileMenu.add_separator()
        fileMenu.add_command(label="Exit", command=self.destroy)

        aboutMenu = Menu(menuBar, tearoff=False)
        aboutMenu.add_command(label="Help", command=self.showHelp)
        aboutMenu.add_command(label="About...", command=self.showAbout)

        menuBar.add_cascade(label="File", menu=fileMenu)
        menuBar.add_cascade(label="About", menu=aboutMenu)

        # Window Setup
        self.title("Rotostitch " + __version__)
        self.config(menu=menuBar)
        self.iconbitmap(default=os.path.join(RESOURCE_DIR, "rotostitch-icon.ico"))

        masterFrame = Frame(self)
        masterFrame.pack(expand=1, fill=Tkc.BOTH, padx=2, pady=2)

        self.status = StatusBar(self)
        self.status.pack(anchor=Tkc.W, fill=Tkc.X, side=Tkc.BOTTOM)

        # Image review panels frame
        imgFrame = Frame(masterFrame, borderwidth=2, relief=Tkc.GROOVE)
        imgFrame.pack(expand=1, fill=Tkc.BOTH)
        imgFrame.columnconfigure(0, weight=1)
        imgFrame.columnconfigure(1, weight=0)
        imgFrame.columnconfigure(2, weight=1)
        imgFrame.rowconfigure(0, weight=1)
        imgFrame.rowconfigure(1, weight=0, pad=3)

        # Creation options frame
        settingsFrame = Frame(masterFrame, borderwidth=2, relief=Tkc.GROOVE)
        settingsFrame.pack(fill=Tkc.X)
        settingsFrame.columnconfigure(1, weight=1, pad=4)

        create = Button(masterFrame, text="Create", command=self.merge)
        create.pack(anchor='se', pady=2)

        self.previewStart = ZoomImage(imgFrame,
                                      width=200,
                                      height=200,
                                      borderwidth=2,
                                      relief=Tkc.RIDGE,
                                      cursor="crosshair")
        self.previewStart.grid(row=0, column=0, sticky=Tkc.NSEW)
        self.previewEnd = ZoomImage(imgFrame, width=200, height=200, borderwidth=2, relief=Tkc.RIDGE)
        self.previewEnd.grid(row=0, column=2, sticky=Tkc.NSEW)

        self.previewStart.bind("<Button>", self._startPreviewClicked)
        self.previewStart.bind("<<Dragged>>", self._previewDragged)
        self.previewEnd.bind("<<Dragged>>", self._previewDragged)

        # Binding just the previews to the MouseWheel event should work but doesn't.
        # The workaround is to bind everything to the mousewheel event 
        # and filter it for just our previews in our callback...
        self.bind_all("<MouseWheel>", self.previewsScrollZoom)

        zoomFrame = Frame(imgFrame)
        zoomFrame.grid(row=0, column=1)

        self.zoomInImg = PhotoImage(file=os.path.join(RESOURCE_DIR, "plus.gif"))
        zoomIn = Button(zoomFrame, image=self.zoomInImg, command=self.previewsZoomIn)
        zoomIn.pack()
        self.zoomResetImg = PhotoImage(file=os.path.join(RESOURCE_DIR, "refresh.gif"))
        zoomReset = Button(zoomFrame, image=self.zoomResetImg, command=self.previewsResetZoom)
        zoomReset.pack()
        self.zoomOutImg = PhotoImage(file=os.path.join(RESOURCE_DIR, "minus.gif"))
        zoomOut = Button(zoomFrame, image=self.zoomOutImg, command=self.previewsZoomOut)
        zoomOut.pack()

        self.differenceImg = PhotoImage(file=os.path.join(RESOURCE_DIR, "difference.gif"))
        self.differenceBtn = ToggleButton(imgFrame, image=self.differenceImg)
        self.differenceBtn.grid(row=1, column=1)
        self.differenceBtn.bind("<Button1-ButtonRelease>", self.toggleDifference)

        startSpinFrame = Frame(imgFrame)
        startSpinFrame.grid(row=1, column=0)
        endSpinFrame = Frame(imgFrame)
        endSpinFrame.grid(row=1, column=2)

        startLabel = Label(startSpinFrame, text="Start Frame:")
        startLabel.pack(side=Tkc.LEFT)

        self.startSpin = Spinbox(startSpinFrame)
        self.startSpin.pack()
        self.startSpin.changedCallback = self.updateStartPreview

        endLabel = Label(endSpinFrame, text="End Frame:")
        endLabel.pack(side=Tkc.LEFT)

        self.endSpin = Spinbox(endSpinFrame)
        self.endSpin.pack()
        self.endSpin.changedCallback = self.updateEndPreview

        widthHeightFrame = Frame(settingsFrame)
        widthHeightFrame.grid(row=0, column=1, columnspan=2, sticky=Tkc.E+Tkc.W)

        widthLabel = Label(settingsFrame, text="Width:")
        widthLabel.grid(row=0, column=0, sticky=Tkc.W)
        self.activePic = PhotoImage(file=os.path.join(RESOURCE_DIR, "go.gif"))
        self.widthSetButton = Button(widthHeightFrame,
                                     text="Set",
                                     command=self.activateSetWidth,
                                     image=self.activePic,
                                     compound=Tkc.LEFT)
        self.widthSetButton.grid(row=0, column=1, sticky=Tkc.W)

        heightLabel = Label(widthHeightFrame, text="Height:")
        heightLabel.grid(row=0, column=2, padx=10, sticky=Tkc.E)
        self.unactivePic = PhotoImage(file=os.path.join(RESOURCE_DIR, "stop.gif"))
        self.heightSetButton = Button(widthHeightFrame,
                                      text="Set",
                                      command=self.activateSetHeight,
                                      image=self.unactivePic,
                                      compound=Tkc.LEFT)
        self.heightSetButton.grid(row=0, column=3, sticky=Tkc.W)

        rotationLabel = Label(settingsFrame, text="Rotation:")
        rotationLabel.grid(row=1, column=0, sticky=Tkc.W)
        rotFrame = Frame(settingsFrame)
        rotFrame.grid(row=1, column=1, sticky=Tkc.W)
        self.rotVar = IntVar()
        self.rotVar.set(1)
        rotLeft = Radiobutton(rotFrame, text="Counter Clockwise", value=1, variable=self.rotVar)
        rotLeft.pack(side=Tkc.LEFT, padx=4)
        rotRight = Radiobutton(rotFrame, text="Clockwise", value=2, variable=self.rotVar)
        rotRight.pack(padx=4)

        outputLabel = Label(settingsFrame, text="Save As:")
        outputLabel.grid(row=2, column=0, sticky=Tkc.W)
        self.outputPathVar = StringVar()
        outputEntry = Entry(settingsFrame, textvariable=self.outputPathVar)
        outputEntry.grid(row=2, column=1, sticky=Tkc.EW)
        self.outputImg = PhotoImage(file=os.path.join(RESOURCE_DIR, "folder.gif"))
        outputSearch = Button(settingsFrame, image=self.outputImg, command=self.setSavePath)
        outputSearch.grid(row=2, column=2, sticky=Tkc.W)

        # Object variables
        self.sequenceLoaded = False
        self.currentSequence = None
        self.startImage = None
        self.endImage = None
        self.differenceOn = False
        self.overlayTag = "OverlayItems"
        self.settingWidth = True
        self.settingHeight = False
        self.width = {'start': Coord(), 'end': Coord()}
        self.height = {'start1': Coord(), 'end1': Coord(), 'start2': Coord(), 'end2': Coord()}

    def showAbout(self):
        pass

    def showHelp(self):
        pass

    def loadSequence(self):
        path = filedialog.askopenfilename(title="Select image from image sequence...")
        if path and os.path.isfile(path):
            self.status.showText("Loading sequence: '{}'".format(path))
            s = self.currentSequence = FrameSequence(path)
            self.sequenceLoaded = True
            self.setupForSequence()
            self.status.showText("Finished loading: '{}'".format(''.join([s.name, "#" * s.frameDigits, s.ext])))
        else:
            self.status.showText("No sequence at: '{}'".format(path))

    def closeSequence(self):
        self.currentSequence = None
        self.sequenceLoaded = False
        self.previewStart.delete(self.overlayTag)
        self.width = {'start': Coord(), 'end': Coord()}
        self.height = {'start1': Coord(), 'end1': Coord(), 'start2': Coord(), 'end2': Coord()}
        self.previewStart.reset()
        self.previewEnd.reset()
        self.startSpin.reset()
        self.endSpin.reset()

    def setSavePath(self):
        path = filedialog.asksaveasfilename(title="Select save location...")
        if path:
            self.outputPathVar.set(path)

    def setupForSequence(self):
        s = self.currentSequence

        if self.differenceOn:
            self.differenceBtn.setSelected(False)
            self.differenceOn = False

        start = s.start
        end = s.end
        self.setStartPreview(start)
        self.setEndPreview(end)

        self.startSpin.min(start)
        self.startSpin.set(start)

        self.endSpin.max(end)
        self.endSpin.set(end)

        self.startSpin.max(end)
        self.endSpin.min(start)

    def setStartPreview(self, frame):
        self.startImage = self.currentSequence.image(frame)
        if self.startImage:
            if self.startImage.mode != "RGBA":
                self.startImage = self.startImage.convert("RGBA")
            self._refreshStartPreview()

    def _refreshStartPreview(self):
        im = self.startImage.copy()
        if self.differenceOn:
            endIm = self.previewEnd.getImage()
            im = ImageChops.difference(im, endIm)
            im.putalpha(255)
        self.previewStart.setImage(im)

    def setEndPreview(self, frame):
        self.endImage = self.currentSequence.image(frame)
        if self.endImage:
            if self.endImage.mode != "RGBA":
                self.endImage = self.endImage.convert("RGBA")
            self._refreshEndPreview()

    def _refreshEndPreview(self):
        im = self.endImage
        if self.differenceOn:
            dif = ImageChops.difference(self.startImage, im)
            dif.putalpha(255)
            self.previewStart.setImage(dif)
        self.previewEnd.setImage(im)

    def updateStartPreview(self):
        i = self.startSpin.get()
        self.endSpin.min(i)
        if self.sequenceLoaded:
            self.setStartPreview(i)

    def updateEndPreview(self):
        i = self.endSpin.get()
        self.startSpin.max(i)
        if self.sequenceLoaded:
            self.setEndPreview(i)

    def previewsScrollZoom(self, event):
        w = self.winfo_containing(event.x_root, event.y_root)
        if w == self.previewStart or w == self.previewEnd:
            center = (event.x_root - w.winfo_rootx(), event.y_root - w.winfo_rooty())
            if event.delta < 0:
                self.adjustZoom("out", center)
            else:
                self.adjustZoom("in", center)

    def previewsZoomIn(self):
        self.adjustZoom("in")

    def previewsZoomOut(self):
        self.adjustZoom("out")

    def adjustZoom(self, direction, center=None):
        if self.sequenceLoaded:
            x, y = center if center else (self.previewStart.size[0] / 2, self.previewStart.size[1] / 2)
            if direction == "in":
                self.previewStart.zoomIn(center)
                self.previewEnd.zoomIn(center)
                self.previewStart.scale(self.overlayTag, x, y, 2.0, 2.0)
            elif direction == "out":
                self.previewStart.zoomOut(center)
                self.previewEnd.zoomOut(center)
                self.previewStart.scale(self.overlayTag, x, y, .5, .5)
            self.drawOverlay()

    def previewsResetZoom(self):
        self.previewStart.resetZoom()
        self.previewEnd.resetZoom()
        self.drawOverlay()

    def _previewDragged(self, event):
        if event.widget == self.previewStart:
            self.previewEnd.moveImage(event.x, event.y)
        else:
            self.previewStart.moveImage(event.x, event.y)
        self.previewStart.move(self.overlayTag, -event.x, -event.y)

    def toggleDifference(self, event):
        if not self.differenceBtn.selected():
            self.differenceOn = True
        else:
            self.differenceOn = False
        self.setDifference()

    def setDifference(self):
        if self.sequenceLoaded:
            if self.differenceOn:
                startIm = self.previewStart.getImage()
                endIm = self.previewEnd.getImage()
                dif = ImageChops.difference(startIm, endIm)
                dif.putalpha(255)
                self.previewStart.setImage(dif)
                self.differenceOn = True
            else:
                self.previewStart.setImage(self.startImage)
                self.differenceOn = False

    def activateSetWidth(self):
        self.widthSetButton.configure(image=self.activePic)
        self.heightSetButton.configure(image=self.unactivePic)
        self.settingWidth = True
        self.settingHeight = False

    def activateSetHeight(self):
        self.widthSetButton.configure(image=self.unactivePic)
        self.heightSetButton.configure(image=self.activePic)
        self.settingWidth = False
        self.settingHeight = True

    def _startPreviewClicked(self, event):
        if self.sequenceLoaded and (event.num == 1 or event.num == 3):
            x, y = self.previewStart.screenToWorld((event.x, event.y))
            if self.settingWidth:
                self._setWidth(event.num, x, y)
            elif self.settingHeight:
                self._setHeight(event.num, x, y, event.state)

    def _setWidth(self, button, x, y):
        if button == 1:
            self.width['start'].set(x, y)
        else:
            self.width['end'].set(x, y)
        self.drawOverlay()

    def _setHeight(self, button, x, y, mod):
        shift = 0x0001
        if button == 1:
            if mod & shift == shift:
                self.height['start2'].set(x, y)
            else:
                self.height['start1'].set(x, y)
        else:
            if mod & shift == shift:
                self.height['end2'].set(x, y)
            else:
                self.height['end1'].set(x, y)
        self.drawOverlay()

    def drawOverlay(self):
        prev = self.previewStart

        # Draw the width line and center line
        x, y = prev.worldToScreen(self.width['start'].get())  # Width line and dot start point
        x2, y2 = prev.worldToScreen(self.width['end'].get())  # Width line and dot end point
        x3 = (x + x2) / 2  # Rotation center line x
        __, y3 = prev.worldToScreen((0, 0))  # Rotation center line top y
        __, y4 = prev.worldToScreen(prev.getImage().size)  # Rotation center line bottom y
        prev.delete(self.overlayTag)
        prev.create_line(x3, y3, x3, y4, tags=self.overlayTag, fill="blue")
        prev.create_line(x, y, x2, y2, tags=self.overlayTag, fill="red")
        prev.create_oval(x - 2, y - 2, x + 3, y + 3, tags=self.overlayTag, fill="green")
        prev.create_oval(x2 - 2, y2 - 2, x2 + 3, y2 + 3, tags=self.overlayTag, fill="green")

        # Draw the height lines
        x, y = prev.worldToScreen(self.height['start1'].get())
        x2, y2 = prev.worldToScreen(self.height['end1'].get())
        prev.create_line(x, y, x2, y2, tags=self.overlayTag, fill="violet")
        prev.create_oval(x - 2, y - 2, x + 3, y + 3, tags=self.overlayTag, fill="green")
        prev.create_oval(x2 - 2, y2 - 2, x2 + 3, y2 + 3, tags=self.overlayTag, fill="green")

        x, y = prev.worldToScreen(self.height['start2'].get())
        x2, y2 = prev.worldToScreen(self.height['end2'].get())
        prev.create_line(x, y, x2, y2, tags=self.overlayTag, fill="cyan")
        prev.create_oval(x - 2, y - 2, x + 3, y + 3, tags=self.overlayTag, fill="green")
        prev.create_oval(x2 - 2, y2 - 2, x2 + 3, y2 + 3, tags=self.overlayTag, fill="green")

    def merge(self):
        path = self.outputPathVar.get()
        if self.sequenceLoaded and path != "":
            self.status.showProgress()
            start = self.startSpin.get()
            end = self.endSpin.get()

            s = self.currentSequence
            rotationCenter = int((self.width['start'].x + self.width['end'].x) / 2)
            height = s.frameSize[1]

            frameCount = end - start
            self.status.setProgressMax(frameCount)

            h = self.height
            len1 = abs(h['start1'].y - h['end1'].y)
            len2 = abs(h['start2'].y - h['end2'].y)
            if len1 > len2:
                adjustmentRatio = len1/len2
            else:
                adjustmentRatio = len2/len1
            crossSection = abs(self.width['start'].x - self.width['end'].x)
            idealWidth = crossSection * math.pi * adjustmentRatio
            arcLen = (1.0 / frameCount) * idealWidth
            stripWidth = int(round(arcLen))
            width = stripWidth * frameCount
            mergeIm = Image.new("RGB", (width, height), None)

            if self.rotVar.get() == 1:
                x = width - stripWidth
                dx = -1
            else:
                x = 0
                dx = 1

            self.status.setProgress(0)
            for fnum in range(start, end):
                frame = s.image(fnum)
                if frame:
                    frameStrip = frame.crop((rotationCenter, 0, rotationCenter + stripWidth, height))

                    mergeIm.paste(frameStrip, (x, 0))
                    x += (dx * stripWidth)
                self.status.setProgress(fnum)

            mergeIm = mergeIm.resize((int(idealWidth), height), Image.ANTIALIAS)
            try:
                mergeIm.save(path)
            except IOError:
                messagebox.showerror("Sorry...", message="Unable to save the final image.")
                self.status.showText("Finished merging. Unable to save to '{}'".format(path))
            self.status.showText("Finished merging. Saved to '{}'".format(path))
예제 #21
0
class P300Window(object):
    def __init__(self, master: Tk):
        self.master = master
        master.title('P300 speller')

        #Parameters
        self.imagesize = 125
        self.images_folder_path = '../utils/images/'  #use utils/char_generator to generate any image you want
        self.flash_image_path = '../utils/images/flash_images/einstein.jpg'
        self.number_of_rows = 6
        self.number_of_columns = 6  #make sure you have 6 x 6 amount of images in the images_folder_path
        self.flash_mode = 2  #single element  #1 for columns and rows; currently is NOT working yet; if I have time, will revisit
        self.flash_duration = 100  #flash duration
        self.break_duration = 150  #isi

        self.trials = 6  #number of letters
        self.delay = 1000  #interval between trial
        self.letter_idx = 0

        # Param for creating sequence
        self.num_sequence = 100

        #Parameter for random
        # self.number_of_symbols =36
        # self.fashed_per_iteration = 2
        # self.number_of_iterations = 6
        # self.stimuli_per_iteration = self.number_of_symbols * self.fashed_per_iteration / self.number_of_iterations

        #did not include numbers yet!
        self.random_letter = random.choices(
            string.ascii_lowercase,
            k=self.trials)  #randomize [self.trials] number letters
        self.word = ''.join(self.random_letter)

        # Variables
        self.usable_images = []
        self.image_labels = []
        self.flash_sequence = []
        self.flash_image = None
        self.sequence_number = 0
        self.lsl_output = None

        # self.running = 0  #for pause

        self.image_frame = Frame(self.master)
        self.image_frame.grid(row=0,
                              column=0,
                              rowspan=self.number_of_rows,
                              columnspan=self.number_of_columns)

        self.start_btn_text = StringVar()
        self.start_btn_text.set('Start')
        self.start_btn = Button(self.master,
                                textvariable=self.start_btn_text,
                                command=self.start)
        self.start_btn.grid(row=self.number_of_rows + 3,
                            column=self.number_of_columns - 1)

        # self.pause_btn = Button(self.master, text='Pause', command=self.pause)
        # self.pause_btn.grid(row=self.number_of_rows + 3, column=self.number_of_columns - 4)  #-4 for center
        # self.pause_btn.configure(state='disabled')

        self.close_btn = Button(self.master, text='Close', command=master.quit)
        self.close_btn.grid(row=self.number_of_rows + 3, column=0)

        fontStyle = tkFont.Font(family="Courier", size=40)

        self.output = Text(root, height=1, font=fontStyle)
        self.output.tag_configure("red", foreground="red")
        self.output.tag_configure("green", foreground="green")
        self.output.configure(width=10)
        self.output.insert("end", "  ")
        self.output.grid(row=self.number_of_rows + 2,
                         column=self.number_of_columns - 4)

        self.outputlabel = Label(root, text="Output: ", font=fontStyle)
        self.outputlabel.grid(row=self.number_of_rows + 2,
                              column=self.number_of_columns - 5)

        self.targetlabel = Label(root, text="Target: ", font=fontStyle)
        self.targetlabel.grid(row=self.number_of_rows + 1,
                              column=self.number_of_columns - 5)

        self.show_highlight_letter(0)

        # Initialization
        self.show_images()
        self.create_flash_sequence()
        self.lsl_output = self.create_lsl_output()

    def open_images(self):
        self.usable_images = []
        self.highlight_letter_images = []

        letter_images = sorted(
            glob.glob(
                os.path.join(self.images_folder_path, 'letter_images/*.png')))

        #currently, still did not flash number yet!
        number_images = sorted(
            glob.glob(
                os.path.join(self.images_folder_path, 'number_images/*.png')))
        letter_highlight_images = sorted(
            glob.glob(
                os.path.join(self.images_folder_path,
                             'letter_highlight_images/*.png')))
        number_highlight_images = sorted(
            glob.glob(
                os.path.join(self.images_folder_path,
                             'number_highlight_images/*.png')))

        for number_image in number_images:
            letter_images.append(number_image)
        #print("Paths: ", letter_images)
        min_number_of_images = self.number_of_columns * self.number_of_rows
        if len(letter_images) < min_number_of_images:
            print('To few images in folder: ' + self.images_folder_path)
            return

        # Convert and resize images
        for image_path in letter_images:
            image = Image.open(image_path)
            resized = image.resize((self.imagesize, self.imagesize),
                                   Image.BICUBIC)
            Tkimage = ImageTk.PhotoImage(resized)
            self.usable_images.append(Tkimage)

        # Convert and resize images
        for image_path in letter_highlight_images:
            image = Image.open(image_path)
            resized = image.resize((self.imagesize, self.imagesize),
                                   Image.BICUBIC)
            Tkimage = ImageTk.PhotoImage(resized)
            self.highlight_letter_images.append(Tkimage)

        flash_img = Image.open(self.flash_image_path)
        flash_img_res = flash_img.resize((self.imagesize, self.imagesize),
                                         Image.BICUBIC)
        self.flash_image = ImageTk.PhotoImage(flash_img_res)

    def show_images(self):
        self.open_images()

        if self.usable_images == []:
            print('No images opened')
            return

        num_rows = self.number_of_rows
        num_cols = self.number_of_columns

        # Arrange images
        for r in range(0, num_rows):
            for c in range(0, num_cols):
                current_image = self.usable_images[r * num_cols + c]
                label = Label(self.image_frame, image=current_image)
                label.image = current_image
                label.grid(row=r, column=c)
                self.image_labels.append(label)

    def create_lsl_output(self):
        """Creates an LSL Stream outlet"""
        info = StreamInfo(name='LetterMarkerStream',
                          type='LetterFlashMarkers',
                          channel_count=1,
                          channel_format='int8',
                          nominal_srate=IRREGULAR_RATE,
                          source_id='lettermarker_stream',
                          handle=None)

        return StreamOutlet(info)  #for sending the predicted classes

    # def create_flash_sequence_old(self):
    #     num_rows = 6
    #     num_cols = 6
    #     maximum_number = num_rows * num_cols
    #     number_count = np.array([0] * maximum_number)
    #     seq = []
    #     next_number = [random.randint(0, maximum_number)]

    #     count = 1
    #     while (len(seq) / 6 < 100):
    #         if (len(seq) > 0):
    #             neighbor_list = seq[-count:]   #the same set, with size of -1 to -6
    #             left_list = [x-1 for x in neighbor_list]   # neighbor of each neighbor in neighbor_list
    #             right_list = [x+1 for x in neighbor_list]
    #             up_list = [x-6 for x in neighbor_list]
    #             bot_list = [x+6 for x in neighbor_list]
    #             combine_list =[]
    #             combine_list.extend(left_list)
    #             combine_list.extend(right_list)
    #             combine_list.extend(up_list)
    #             combine_list.extend(bot_list)
    #             #should not be same element as previous set (*2), and should not be same element in the combine_list
    #             if (next_number not in seq[-CONCURRENT_ELEMENTS*2:] and next_number not in combine_list):
    #                 seq.extend(next_number)
    #                 count = ((count) % 6) + 1  #this count makes sure we have one set of 6
    #         else:
    #             seq.extend(next_number)
    #         left_over = np.argwhere(number_count == np.argmin(number_count))
    #         selectMax = len(left_over) - 1
    #         next_number = left_over[random.randint(0, selectMax)]
    #     self.flash_sequence = seq

    def find_replacement(self, nextelem, seq):
        length = CONCURRENT_ELEMENTS if len(
            self.flash_sequence) > CONCURRENT_ELEMENTS - 1 else len(
                self.flash_sequence)
        for i in range(1, length + 1):
            prev_seq = self.flash_sequence[-i:][0]
            for j in range(len(prev_seq)):
                previous_seq_elem = self.flash_sequence[-i:][0][j]
                prev_seq_without_prevelem = [
                    x for x in prev_seq if x != previous_seq_elem
                ]
                nl_prev = self.get_neighbors(prev_seq_without_prevelem)
                nl_current = self.get_neighbors(seq)
                if (nextelem not in prev_seq and  #a
                        nextelem not in nl_prev and  #b
                        nextelem not in self.flash_sequence[-i - 1:][0]
                        and  #c1  left consecutive
                        nextelem not in self.flash_sequence[-i + 1:][
                            0]  #c2  right consecutive
                        and previous_seq_elem not in seq and  #a
                        previous_seq_elem not in nl_current and  #b  
                        previous_seq_elem
                        not in self.flash_sequence[-1:][0]):  #c
                    self.flash_sequence[-i:][0][j] = nextelem
                    seq.append(previous_seq_elem)
                    return seq
        print("Can't swap..Restarting everything...")
        create_flash_sequence()

    def get_neighbors(self, seq):
        right = [x + 1 for x in seq]
        left = [x - 1 for x in seq]
        top = [x - 6 for x in seq]
        bottom = [x + 6 for x in seq]
        neighbors = list(chain(right, left, top, bottom))
        return neighbors

    def create_flash_sequence(self):
        num_rows = self.number_of_rows
        num_cols = self.number_of_columns
        total = num_rows * num_cols
        num_sequence = self.num_sequence

        li = list(range(total))

        while len(self.flash_sequence) < num_sequence:
            seq = []
            failcount = 0
            if not li:
                #if li is exhausted
                li = list(range(36))
            while len(seq) < CONCURRENT_ELEMENTS:
                nextelem = random.choice(li)
                if len(seq) > 0:
                    nl = self.get_neighbors(seq)
                    #prevent stuck
                    if failcount > 20:
                        seq = self.find_replacement(nextelem, seq)
                        li.remove(nextelem)
                        failcount = 0
                    elif nextelem not in nl and nextelem not in seq:
                        if len(self.flash_sequence):
                            if nextelem not in self.flash_sequence[-1:][
                                    0]:  #0 remove the outer list [[]] becomes []
                                seq.append(nextelem)
                                li.remove(nextelem)
                            else:
                                failcount += 1
                        else:
                            seq.append(nextelem)
                            li.remove(nextelem)
                    else:
                        failcount += 1
                else:  #first element, just insert
                    if len(self.flash_sequence):
                        if nextelem not in self.flash_sequence[-1:][0]:
                            seq.append(nextelem)
                            li.remove(nextelem)
                    else:
                        seq.append(nextelem)
                        li.remove(nextelem)
            self.flash_sequence.append(seq)

        self.flash_sequence = list(chain(*self.flash_sequence))

    def start(self):
        if not (TEST_UI):
            self.read_lsl_marker()
        self.running = 1
        letter = self.word[0]
        image_index = string.ascii_lowercase.index(letter)
        self.highlight_image(image_index)
        self.start_btn.configure(state='disabled')
        self.pause_btn.configure(state='normal')

    # def pause(self):
    #     self.running = 0
    #     self.start_btn_text.set('Resume')
    #     self.start_btn.configure(state='normal')
    #     self.pause_btn.configure(state='disabled')

    # def check_pause(self):
    #     if self.running == 0:
    #         print('Flashing paused at sequence number ' + str(self.sequence_number))
    #         return

    def check_sequence_end(self):
        if self.sequence_number == len(
                self.flash_sequence
        ):  #stop flashing if all generated sequence number runs out
            print('All elements had flashed - run out of juice')
            self.running = 0
            self.sequence_number = 0
            return

    def get_marker_result(self):
        result = self.marker_result()
        if (result):
            print("Marker received: ", result[0][0])
            receive = result[0][0]
        else:
            receive = 0

        return receive

    def output_letter(self, receive, image_index):
        # receive = [9,10,13]
        if not receive:
            if FLASH_CONCURRENT:
                self.master.after(self.break_duration,
                                  self.start_concurrent_flashing)
            else:
                self.master.after(self.break_duration, self.start_flashing)

        elif isinstance(receive, int):
            if (image_index + 1) == receive:
                self.output.insert("end", self.pos_to_char(receive), "green")
            else:
                self.output.insert("end", self.pos_to_char(receive), "red")

            self.letter_idx += 1
            if self.letter_idx == len(self.word):
                return
            letter = self.word[self.letter_idx]
            image_index = string.ascii_lowercase.index(letter)
            self.master.after(self.break_duration, self.highlight_target,
                              image_index)

        else:
            if FLASH_CONCURRENT:
                self.candidate_flash_sequence(receive)
                self.master.after(self.break_duration,
                                  self.start_concurrent_flashing)
            else:
                self.master.after(self.break_duration, self.start_flashing)

    def candidate_flash_sequence(self, candidates):
        print("got candidate")
        num_rows = self.number_of_rows
        num_col = self.number_of_columns
        current_elements = self.flash_sequence[self.sequence_number:self.
                                               sequence_number +
                                               CONCURRENT_ELEMENTS]
        next_elements = self.flash_sequence[self.sequence_number +
                                            CONCURRENT_ELEMENTS:self.
                                            sequence_number +
                                            CONCURRENT_ELEMENTS * 2]

        # Step 1 check if the candidate is included in the next list
        # Step 2 check if there is multiple candidate in the next list ~ else just continue
        count_contain_candidate = 0
        for target_candidate in candidates:
            if target_candidate in next_elements:
                count_contain_candidate += 1

        if count_contain_candidate > 1 or count_contain_candidate == 0:
            # Step 3 check previous i length of sequence to know lease used candidate where i = candidate length
            start_check_index = 0
            previous_flashes_count = []
            if CONCURRENT_ELEMENTS * len(candidates) > self.sequence_number:
                start_check_index = self.sequence_number - CONCURRENT_ELEMENTS * len(
                    candidates) - 1
            for target_candidate in candidates:
                previous_flashes = self.flash_sequence[start_check_index:self.
                                                       sequence_number - 1]
                previous_flashes_count.append([
                    target_candidate,
                    previous_flashes.count(target_candidate)
                ])
            least_index = np.argmin(previous_flashes_count, axis=0)[1]
            choosen_candidate = previous_flashes_count[least_index][0]

            # generate new flash_sequence
            new_sequence = [choosen_candidate]
            li = list(range(num_rows * num_col))

            print("new_sequence1 :", new_sequence)
            #generate sequence
            while len(new_sequence) < 6:
                nextelem = random.choice(li)
                print("nextelem :", nextelem)
                nl = self.get_neighbors(new_sequence)
                #random until get the flasshes sequence
                while (nextelem in nl or nextelem in current_elements
                       or nextelem in next_elements):
                    nextelem = random.choice(li)
                    print("nextelem :", nextelem)
                new_sequence.append(nextelem)
            print("new_sequence2: ", new_sequence)

            print("self.sequence_number: ", self.sequence_number)

            # update flashing sequences
            print(self.sequence_number)

            self.flash_sequence = self.flash_sequence[
                0:self.sequence_number +
                CONCURRENT_ELEMENTS] + new_sequence + self.flash_sequence[
                    self.sequence_number + CONCURRENT_ELEMENTS:]

        # Step 4 generate new list where
        #       1 no duplicate
        #       2 no multiple candidate
        #       3 no neighbors
        #       4 no previous list if possible (maybe all candidate is in the previous)
        #       5 no next list if possible (maybe all candidate is in the next)
        #       6 use the least use candidate

    def start_concurrent_flashing(self):

        self.check_sequence_end()
        # self.check_pause()
        receive = self.get_marker_result()

        element_to_flash = self.flash_sequence[self.sequence_number:self.
                                               sequence_number +
                                               CONCURRENT_ELEMENTS]
        letter = self.word[self.letter_idx]
        image_index = string.ascii_lowercase.index(letter)

        #pushed markers to LSL stream

        print("Letter: ", image_index, " Element flash: ",
              [x + 1 for x in element_to_flash])
        for e in element_to_flash:
            self.lsl_output.push_sample([e + 1
                                         ])  # add 1 to prevent 0 in markers

        self.flash_multiple_elements(element_to_flash)
        self.output_letter(receive, image_index)

        self.sequence_number = self.sequence_number + CONCURRENT_ELEMENTS  #change flash position

    def start_flashing(self):
        self.check_sequence_end()
        # self.check_pause()
        receive = self.get_marker_result()

        element_to_flash = self.flash_sequence[self.sequence_number]
        letter = self.word[self.letter_idx]
        image_index = string.ascii_lowercase.index(letter)

        #pushed markers to LSL stream

        print("Letter: ", image_index, " Element flash: ",
              [element_to_flash + 1])
        self.lsl_output.push_sample([element_to_flash + 1
                                     ])  # add 1 to prevent 0 in markers
        self.flash_single_element(element_to_flash)

        self.output_letter(receive, image_index)

        self.sequence_number = self.sequence_number + 1  #change flash position

    def pos_to_char(self, pos):
        return chr(pos + 97)

    def highlight_target(self, image_index):
        self.show_highlight_letter(self.letter_idx)
        self.highlight_image(image_index)

    def change_image(self, label, img):
        label.configure(image=img)
        label.image = img

    def highlight_image(self, element_no):
        self.change_image(self.image_labels[element_no],
                          self.highlight_letter_images[element_no])
        self.master.after(self.delay, self.unhighlight_image, element_no)

    def unhighlight_image(self, element_no):
        self.change_image(self.image_labels[element_no],
                          self.usable_images[element_no])

        if (FLASH_CONCURRENT):
            self.master.after(self.flash_duration,
                              self.start_concurrent_flashing)
        else:
            self.master.after(self.flash_duration, self.start_flashing)

    def show_highlight_letter(self, pos):

        fontStyle = tkFont.Font(family="Courier", size=40)
        fontStyleBold = tkFont.Font(family="Courier bold", size=40)

        text = Text(root, height=1, font=fontStyle)
        text.tag_configure("bold", font=fontStyleBold)
        text.tag_configure("center", justify='center')

        for i in range(0, len(self.word)):
            if (i != pos):
                text.insert("end", self.word[i])
            else:
                text.insert("end", self.word[i], "bold")

        text.configure(state="disabled", width=10)
        text.tag_add("center", "1.0", "end")

        text.grid(row=self.number_of_rows + 1,
                  column=self.number_of_columns - 4)

    def flash_row_or_col(self, rc_number):
        num_rows = self.number_of_rows
        num_cols = self.number_of_columns

        if rc_number < num_rows:
            for c in range(0, num_cols):  #flash row
                cur_idx = rc_number * num_cols + c
                self.change_image(self.image_labels[cur_idx], self.flash_image)
        else:
            current_column = rc_number - num_rows
            for r in range(0, num_rows):  #flash column
                cur_idx = current_column + r * num_cols
                self.change_image(self.image_labels[cur_idx], self.flash_image)

        self.master.after(self.flash_duration, self.unflash_row_or_col,
                          rc_number)

    def unflash_row_or_col(self, rc_number):
        num_rows = self.number_of_rows
        num_cols = self.number_of_columns
        if rc_number < num_rows:
            for c in range(0, num_cols):  #flash row
                cur_idx = rc_number * num_cols + c
                self.change_image(self.image_labels[cur_idx],
                                  self.usable_images[cur_idx])
        else:
            current_column = rc_number - num_rows
            for r in range(0, num_rows):  #flash column
                cur_idx = current_column + r * num_cols
                self.change_image(self.image_labels[cur_idx],
                                  self.usable_images[cur_idx])

    def flash_multiple_elements(self, element_array):
        for element_no in element_array:
            self.change_image(self.image_labels[element_no], self.flash_image)

        self.master.after(self.flash_duration, self.unflash_multiple_elements,
                          element_array)

    def unflash_multiple_elements(self, element_array):
        for element_no in element_array:
            self.change_image(self.image_labels[element_no],
                              self.usable_images[element_no])

    def flash_single_element(self, element_no):
        self.change_image(self.image_labels[element_no], self.flash_image)
        self.master.after(self.flash_duration, self.unflash_single_element,
                          element_no)

    def unflash_single_element(self, element_no):
        self.change_image(self.image_labels[element_no],
                          self.usable_images[element_no])

    def marker_result(self):
        if not (TEST_UI):
            marker, timestamp = self.inlet_marker.pull_chunk()
            return marker
        else:
            return 0

    def read_lsl_marker(self):
        print("looking for a Markers stream...")
        marker_streams = resolve_byprop('name', 'ResultMarkerStream')
        if marker_streams:
            self.inlet_marker = StreamInlet(marker_streams[0])
            marker_time_correction = self.inlet_marker.time_correction()
            print("Found Markers stream")
예제 #22
0
class Example(Frame):

    def __init__(self, parent):
        Frame.__init__(self, parent)

        self.parent = parent
        self.initUI()

    def initUI(self):
        self.parent.title("")
        #self.style = Style()
        #self.style.theme_use("clam")
        #self.pack(fill=BOTH, expand = 1)


        self.quitbutton = Button(self, text="Quit", command= lambda: self.quit())

        self.quitbutton.grid(row=3, column=1, pady=4)

        self.labelErrorPointer = Label(self, text="◀")

        self.labellist = []
        self.entrylist = []
        self.verifylist = []
        self.misclist = []
                
        self.optionCreate = "Create"
        self.optionUpcoming = "Upcoming"
        self.optionPast = "Past"

        self.prevmode = self.optionCreate
        self.curmode = self.optionCreate
        self.optionvar = tkinter.StringVar(self)
        self.optionvar.trace("w",self.permaloop)
        self.optionvar.set(self.optionCreate)
        self.option = OptionMenu(self, self.optionvar, self.optionCreate, self.optionUpcoming, self.optionPast)

        self.optionpostmodevar = tkinter.StringVar(self)
        self.optionpostmodevar.trace("w",self.permaloop)
        self.optionpostmodevar.set('url')
        self.optionpostmode = OptionMenu(self, self.optionpostmodevar, 'url', 'text')

        self.labelText = Label(self, text='Selftext:')
        self.entryText = Text(self)
        self.labelURL = Label(self, text='URL:')
        self.entryURL = Entry(self)
        self.entryURL.configure(width=60)  

        self.sql = sqlite3.connect('sql.db')
        print('Loaded SQL Database')
        self.cur = self.sql.cursor()

        self.cur.execute('CREATE TABLE IF NOT EXISTS upcoming(ID TEXT, SUBREDDIT TEXT, TIME INT, TITLE TEXT, URL TEXT, BODY TEXT)')
        self.cur.execute('CREATE TABLE IF NOT EXISTS past(ID TEXT, SUBREDDIT TEXT, TIME INT, TITLE TEXT, URL TEXT, BODY TEXT, POSTLINK TEXT)')
        self.cur.execute('CREATE TABLE IF NOT EXISTS internal(NAME TEXT, ID INT)')
        print('Loaded Completed table')
        self.cur.execute('SELECT * FROM internal')
        f = self.cur.fetchone()
        if not f:
            print('Database is new. Adding ID counter')
            self.cur.execute('INSERT INTO internal VALUES(?, ?)', ['counter', 1])
            self.idcounter = 1
        else:
            self.idcounter = f[1]
            print('Current ID counter: ' + str(self.idcounter))

        self.sql.commit()
        

        
        sw = self.parent.winfo_screenwidth()
        sh = self.parent.winfo_screenheight()


        w=853
        h=480
        x = (sw - w) / 2
        y = (sh - h) / 2

        self.parent.geometry('%dx%d+%d+%d' % (w, h, x, y-50))

        self.login()
        

    def login(self):

        try:
            self.quitbutton.grid_forget()
            self.quitbutton.grid(row=9000, column=0, columnspan=20)          

            self.option.grid(row=1,column=0,columnspan=80,pady=8)

            self.updategui(fullclean=True)
        except praw.errors.InvalidUserPass:
            pass
            print('Invalid username or password')
            self.entryPassword.delete(0,200)
            self.labelErrorPointer.grid(row=1, column=2)

    def permaloop(self, *args):
        self.curmode = self.optionvar.get()
        print('Was: ' + self.prevmode + ' | Now: ' + self.curmode)
        if self.curmode != self.prevmode:
            self.prevmode = self.curmode
            self.updategui(fullclean=True)
        else:
            self.updategui(False)

    def getTime(self, bool):
        timeNow = datetime.datetime.now(datetime.timezone.utc)
        timeUnix = timeNow.timestamp()
        if bool is False:
            return timeNow
        else:
            return timeUnix

    def addentrytobase(self, subreddit, title, url="", body="", mode="", ptime=""):
        curtime = round(self.getTime(True))
        try:
            t = self.entryMo.get() + ' ' + self.entryDa.get() + ' ' + self.entryYr.get() + ' ' + self.entryHH.get() + ':' + self.entryMM.get()
            plandate = datetime.datetime.strptime(t, "%B %d %Y %H:%M")
            plandate = plandate.timestamp()
        except ValueError:
            print('Invalid Day')
            return False

        if mode == 'url':
            url = self.entryURL.get()
            body = ""
            if 'http://' not in url and 'https://' not in url:
                print('Please enter a proper URL')
                return False
        if mode == 'text':
            body = self.entryText.get("1.0", "end")
            url = ""

        if plandate < curtime:
            print('Please enter a time in the future')
            return False

        if not all(char in string.ascii_letters+string.digits+'_-' for char in subreddit):
            print('Subreddit contains invalid characters')
            return False

        if len(subreddit) == 0:
            print('You must enter a subreddit')
            return False

        if len(title) == 0:
            print('You must enter a title')
            return False
        if len(title) > 300:
            print('Title is too long. ' + str(len(title)) + '/300 char max')
            return False
        if len(body) > 15000:
            print('Body is too long. ' + str(len(body)) + '/15,000 char max')

        print('Timestamp:', plandate)
        self.cur.execute('INSERT INTO upcoming VALUES(?, ?, ?, ?, ?, ?)', [self.idcounter, subreddit, int(plandate), title, url, body])
        self.idcounter += 1
        self.cur.execute('UPDATE internal SET ID=? WHERE NAME=?', [self.idcounter, 'counter'])
        self.sql.commit()
        print('\nPost Saved!')
        print(self.idcounter, subreddit, self.timestamptoday(int(plandate)))
        print(title)
        print(url, body)
        print()
        self.entryText.delete("1.0", "end")
        self.entryURL.delete(0, 'end')
        self.entryTitle.delete(0, 'end')
        #self.updategui(halfclean=True)

    def timestamptoday(self, timestamp):
        d = datetime.datetime.fromtimestamp(timestamp)
        info = datetime.datetime.strftime(d, "%b %d %H:%M")
        return info


    def dropentryfrombase(self, ID):
        if '-' not in ID:
            try:
                ID = int(ID)
                l = [ID]
            except ValueError:
                print('You must enter a number')
                return
        else:
            if ID.count('-') == 1:
                try:
                    ID = ID.replace(' ', '')
                    ID = ID.split('-')
                    ID[0] = int(ID[0])
                    ID[1] = int(ID[1])
                    if ID[1] > ID[0]:
                        l = list(range(ID[0], ID[1]+1))
                    else:
                        return
                except ValueError:
                    return

        for item in l:
            item = str(item)
            print('Dropping Item ' + item + ' from Upcoming')
            self.cur.execute('DELETE FROM upcoming WHERE ID=?', [item])
            self.sql.commit()
        self.updategui(fullclean=True)

    def printbasetofile(self, db):
        filea = open(db + '.txt', 'w')
        if db == 'past':
            self.cur.execute('SELECT * FROM past')
        if db == 'upcoming':
            self.cur.execute('SELECT * FROM upcoming')
        f = self.cur.fetchall()
        print('Printed ' + db + ' unimpeded to file')
        for item in f:
            i = list(item)
            i[2] = self.timestamptoday(i[2])
            i.remove('')

            print(str(i)[1:-1], file=filea)
        filea.close()

        


    def updategui(self, halfclean=False, fullclean=False):

        if self.curmode == self.optionCreate:
            try:
                print(self.optionpostmodevar.get())

                if self.optionpostmodevar.get() == 'url':
                    self.entryText.delete("1.0", 'end')
                    self.labelText.grid_forget()
                    self.entryText.grid_forget()
    
                    self.labelURL.grid(row=8, column=0, columnspan=30)
                    self.entryURL.grid(row=9, column=0, columnspan=12, pady=10)
    
                if self.optionpostmodevar.get() == 'text':
                    self.entryURL.delete(0, 'end')
                    self.labelURL.grid_forget()
                    self.entryURL.grid_forget()
    
                    self.labelText.grid(row=8, column=0, columnspan=30)
                    self.entryText.configure(width=40, height=8)
                    self.entryText.grid(row=9, column=0, columnspan=12)
            except AttributeError:
                pass

        if fullclean is True:
            print('Cleaning GUI')
            for item in self.labellist:
                item.grid_forget()
            for item in self.entrylist:
                item.grid_forget()
            for item in self.verifylist:
                item.grid_forget()
            for item in self.misclist:
                item.grid_forget()
            self.labellist = []
            self.entrylist = []
            self.verifylist = []
            self.misclist = []

            if self.curmode == self.optionCreate:
                self.newrowindex = 6
                self.labelSubreddit = Label(self, text="Subreddit:    /r/")
                self.labelTitle = Label(self, text="Post title:  ")
                self.entrySubreddit = Entry(self)
                self.entryTitle = Entry(self)


                self.labelHH = Label(self, text="Schedule time (Local timezone):")
                nowlist = datetime.datetime.strftime(datetime.datetime.now(), "%B %d %Y %H %M").split()

                self.entryMo = Spinbox(self, width=9, values=('January', 'February', 'March', 'April', 'May', 'June', 'July', \
                    'August', 'September', 'October', 'November', 'December'))
                self.entryMo.delete(0,'end')
                self.entryMo.insert(0, nowlist[0])


                self.entryDa = Spinbox(self, width=2, from_=1, to=31)
                self.entryDa.delete(0,'end')
                self.entryDa.insert(0, nowlist[1])

                self.entryYr = Spinbox(self, width=4, from_=2014, to=2500)
                self.entryYr.delete(0,'end')
                self.entryYr.insert(0, nowlist[2])

                self.entryHH = Spinbox(self, from_=0, to=23, width=2)
                self.entryHH.delete(0,'end')
                self.entryHH.insert(0, nowlist[3])

                self.entryMM = Spinbox(self, from_=0, to=59, width=2)
                self.entryMM.delete(0,'end')
                self.entryMM.insert(0, nowlist[4])

                self.buttonAddentry = Button(self, text='Save', command=lambda: self.addentrytobase(self.entrySubreddit.get(), self.entryTitle.get(),\
                    mode=self.optionpostmodevar.get()))


                self.misclist.append(self.labelSubreddit)
                self.misclist.append(self.entrySubreddit)
                self.misclist.append(self.labelHH)
                self.misclist.append(self.entryHH)
                self.misclist.append(self.entryMM)
                self.misclist.append(self.entryMo)
                self.misclist.append(self.entryDa)
                self.misclist.append(self.entryYr)
                self.misclist.append(self.labelTitle)
                self.misclist.append(self.entryTitle)
                self.misclist.append(self.buttonAddentry)
                self.misclist.append(self.optionpostmode)
                self.misclist.append(self.labelText)
                self.misclist.append(self.entryText)
                self.misclist.append(self.labelURL)
                self.misclist.append(self.entryURL)

                self.labelSubreddit.grid(row=2, column=0, sticky="e")
                self.labelTitle.grid(row=3, column=0, sticky="e")
                self.entrySubreddit.grid(row=2, column=1, columnspan=3, sticky="w")
                self.entryTitle.grid(row=3, column=1, columnspan=3, sticky="w")
                self.entryMo.grid(row=4, column=1,sticky="e")
                self.entryDa.grid(row=4, column=2)
                self.entryYr.grid(row=4, column=3)
                self.labelHH.grid(row=4, column=0, sticky="se", pady=5)
                self.entryHH.grid(row=5, column=1, sticky="e")
                self.entryMM.grid(row=5, column=2, sticky="w")
                self.optionpostmode.grid(row=6, column=0, columnspan=20, pady=10)
                self.buttonAddentry.grid(row=200, column=0, columnspan=20)

            if self.curmode == self.optionUpcoming:
                self.cur.execute('SELECT * FROM upcoming')
                dobutton = True

            if self.curmode == self.optionPast:
                self.cur.execute('SELECT * FROM past')
                dobutton = False

            if self.curmode == self.optionPast or self.curmode == self.optionUpcoming:

                
                self.listboxId = Listbox(self)
                self.listboxId.configure(width=118, height=20, font=("Courier 8"))
                self.misclist.append(self.listboxId)

                self.listboxScroller = Scrollbar(self, orient='horizontal', command=self.listboxId.xview)
                self.listboxScroller.grid(row=4, column=0, columnspan=900)
                self.listboxId.grid(row=3, column=0, columnspan=10)

                self.listboxId.configure(xscrollcommand=self.listboxScroller.set)
                self.misclist.append(self.listboxScroller)

                self.buttonPrinter = Button(self, text="Print to .txt file")
                if self.curmode == self.optionPast:
                    self.buttonPrinter.configure(command=lambda: self.printbasetofile('past'))
                if self.curmode == self.optionUpcoming:
                    self.buttonPrinter.configure(command=lambda: self.printbasetofile('upcoming'))   

                self.buttonPrinter.grid(row = 6, column=0, columnspan=90)
                self.misclist.append(self.buttonPrinter)

                if dobutton is True:
                    self.entryDelete = Entry(self)
                    self.buttonDelete = Button(self, text="Delete Item: ", command=lambda: self.dropentryfrombase(self.entryDelete.get()))
                    self.buttonDelete.grid(row=5, column=0, sticky='e')
                    self.entryDelete.grid(row=5, column=1, sticky='w')
                    self.misclist.append(self.entryDelete)
                    self.misclist.append(self.buttonDelete)


                fetched = self.cur.fetchall()
                for item in fetched:

                    info = self.timestamptoday(item[2])

                    if item[4] == '':
                        infx = item[5]
                    if item[5] == '':
                        infx = item[4]
                    if self.curmode == self.optionPast:
                        infy = '.' + item[6]
                    else:
                        infy = ''

                    self.listboxId.insert('end', \
                        item[0] + '.'*(6 - len(item[0])) \
                        + item[1][:10] + '.'*(12 - len(item[1][:10])) \
                        + info + '.'*(15 - len(info[:14])) \
                        + item[3][:18] + '.'*(20 - len(item[3][:14])) \
                        + infx[:45] + '.'*(47-len(infx[:45])) \
                        + infy)

                    
                



    def morerows(self, label, columnm, columnn, limit, *args):
        self.redditlabel = Label(self,text=label)
        self.redditlabel.grid(row=self.newrowindex,column=columnm, sticky="e")
        self.labellist.append(self.redditlabel)

        self.redditentry = Entry(self)
        self.redditentry.grid(row=self.newrowindex,column=columnn, columnspan=9)
        self.entrylist.append(self.redditentry)

        self.newrowindex += 1
        if self.newrowindex >= limit:
            self.morerowbutton.grid_forget()
        print(self.newrowindex)
예제 #23
0
class GUI(Tk):
    """This app allows for easy editing of circular datatrees"""
    dataset: dict[str, dict[str, list[str]]] = dict()
    datapth = Path(__file__).with_name('dataset.json')
    imgcanvas: Canvas
    image: Image
    imagetk: PhotoImage
    cnvimg: int
    saveBtn: Button
    dataScrl: SFrame
    dataFrm: Frame
    datadict: dict[Entry, dict[Entry, list[Entry]]]
    imgargs: tuple[StringVar, StringVar, StringVar, StringVar]

    def __init__(self):
        Tk.__init__(self)
        self.protocol("WM_DELETE_WINDOW", self.on_exit)
        wd = (self.winfo_screenwidth() // 2)
        ht = (self.winfo_screenheight() // 2)
        self.geometry(f'{wd * 1.5:.0f}'
                      f'x{ht * 1.5:.0f}'
                      f'+{wd - wd * 0.75:.0f}'
                      f'+{ht - ht * 0.75:.0f}')

        self.columnconfigure(1, weight=1)
        self.rowconfigure(1, weight=1)
        self.option_add('*font', 'Ebrima 12')
        self.option_add('*Entry.width', 15)
        s = Style()
        s.configure('TButton', font='Ebrima 12')
        s.configure('sm.TButton', width=6, font='Ebrima 8')
        self.datadict = dict()
        self.build()

    def on_exit(self):
        self.quit()
        self.destroy()

    def build(self):
        # data buttons
        dataBtns = LFrame(master=self, text="Dataset")
        dataBtns.grid(column=0, row=0)
        self.buildDataBtns(dataBtns)
        # data
        self.dataScrl = SFrame(master=self)
        self.dataScrl.grid(column=0, row=1, sticky='nsew')
        self.buildData()
        # image buttons
        imgBtns = LFrame(master=self, text="Image")
        imgBtns.grid(column=0, row=2, pady=3)
        self.buildImgBtns(imgBtns)
        # canvas
        cnvfrm = SFrame(master=self, padding=3)
        cnvfrm.grid(column=1, row=0, rowspan=3, sticky='nsew')
        self.buildCanvas(cnvfrm)

#  ___ _   _ _____ _____ ___  _  _ ___
# | _ ) | | |_   _|_   _/ _ \| \| / __|
# | _ \ |_| | | |   | || (_) | .` \__ \
# |___/\___/  |_|   |_| \___/|_|\_|___/

#    ___  ___ _________
#   / _ \/ _ /_  __/ _ |
#  / // / __ |/ / / __ |
# /____/_/ |_/_/ /_/ |_|

    def buildDataBtns(self, parent):
        loadBtn = Button(master=parent, text="Load", command=self.loadData)
        loadBtn.grid(column=0, row=0, padx=3)
        clearBtn = Button(master=parent, text="Clear", command=self.clearData)
        clearBtn.grid(column=1, row=0, padx=3)
        saveBtn = Button(master=parent, text="Save", command=self.saveData)
        saveBtn.grid(column=2, row=0, padx=3)

    def loadData(self):
        with self.datapth.open('r') as f:
            self.dataset = json.load(f)
        self.datadict.clear()
        for w in self.dataFrm.winfo_children():
            w.destroy()
        for inr, sub in self.dataset.items():
            mfrm, k = self.addInner(inr)
            for mid, items in sub.items():
                ofrm, v = self.addMid(mfrm, k, mid)
                for out in items:
                    self.addOuter(ofrm, k, v, out)

    def clearData(self):
        self.dataset.clear()
        self.datadict.clear()
        for w in self.dataScrl.winfo_children():
            w.destroy()
        self.buildData()

    def saveData(self):
        self.getData()
        with self.datapth.open('w') as f:
            json.dump(self.dataset, f, indent=4)

#    ______  ______  _________
#   /  _/  |/  / _ |/ ___/ __/
#  _/ // /|_/ / __ / (_ / _/
# /___/_/  /_/_/ |_\___/___/

    def buildImgBtns(self, parent):
        def lblent(txt, var, col, row) -> None:
            lfrm = LFrame(master=parent, text=txt, font='Ebrima 8')
            lfrm.grid(column=col, row=row, padx=3)
            ent = Entry(master=lfrm, textvariable=var)
            ent.pack()

        cmapnm = StringVar()
        offset = StringVar()
        ffamily = StringVar()
        fsize = StringVar()
        self.imgargs = (cmapnm, offset, ffamily, fsize)
        cmapnm.set('hsv')
        offset.set('20')
        ffamily.set('Ebrima')
        fsize.set('8, 7, 6.5')

        lblent("Colormap Name", cmapnm, 0, 0)
        lblent("Color Offset", offset, 1, 0)
        lblent("Font Family", ffamily, 0, 1)
        lblent("Font Size (inner, mid, outer)", fsize, 1, 1)
        drawBtn = Button(master=parent, text="Draw", command=self.drawImg)
        drawBtn.grid(column=0, row=2, padx=3)
        self.saveBtn = Button(master=parent,
                              text="Save",
                              command=self.saveImg,
                              state='disabled')
        self.saveBtn.grid(column=1, row=2, padx=3)

    def drawImg(self):
        self.getData()
        cm, off, fam, sz = self.imgargs
        self.image = DataChart(
            dataset=self.dataset,
            colormap_name=cm.get(),
            offset=float(off.get()),
            fontfamily=fam.get(),
            fontsize=[float(n) for n in split(r', ?| ', sz.get())])
        self.imagetk = PhotoImage(self.image)
        self.imgcanvas.itemconfigure(self.cnvimg, image=self.imagetk)
        self.saveBtn.configure(state='normal')

    def saveImg(self):
        saveas = Askfile(parent=self,
                         title="Save image as...",
                         filetypes=[('PNG Image (*.png)', '*.png'),
                                    ('JPG Image (*.jpg)', '*.jpg')],
                         defaultextension='.png')
        if saveas:
            file = Path(saveas)
            if file.suffix == '.jpg':
                self.image.convert('RGB').save(file)
            else:
                self.image.save(file)

#  ___   _ _____ _
# |   \ /_\_   _/_\
# | |) / _ \| |/ _ \
# |___/_/ \_\_/_/ \_\

    def buildData(self):
        self.dataFrm = Frame(self.dataScrl)
        self.dataFrm.grid(column=0, row=0)
        addBtn = Button(master=self.dataScrl,
                        text="Add Category",
                        command=self.addInner)
        addBtn.grid(column=0, row=1, sticky='w', padx=3, pady=3)
        self.addInner()

    def addInner(self, name: str = None) -> O[tuple[Frame, Entry]]:
        def remInner():
            frm.destroy()
            self.datadict.pop(Entry)

        frm = Frame(master=self.dataFrm)
        frm.grid()
        remBtn = Button(master=frm,
                        text='Delete',
                        style='sm.TButton',
                        command=remInner)
        remBtn.grid(column=0, row=0, sticky='ne', pady=3)
        ent = Entry()
        lfrm = LFrame(master=frm, labelwidget=ent, bd=3, padx=5, pady=5)
        lfrm.grid(column=1, row=0, sticky='w')
        subfrm = Frame(master=lfrm)
        subfrm.grid(column=0, row=0)
        addBtn = Button(master=lfrm,
                        text="Add Subcategory",
                        command=(lambda a=(subfrm, ent): self.addMid(*a)))
        addBtn.grid(column=0, row=1, sticky='w', padx=3, pady=3)
        self.datadict[ent] = dict()
        self.dataScrl.redraw()
        if name:
            ent.insert(0, name)
            return (subfrm, ent)
        else:
            self.addMid(subfrm, ent)

    def addMid(self,
               parent: Frame,
               key: Entry,
               name: str = None) -> O[tuple[Frame, Entry]]:
        def remMid():
            frm.destroy()
            self.datadict[key].pop(ent)

        frm = Frame(master=parent)
        frm.grid()
        remBtn = Button(master=frm,
                        text='Delete',
                        style='sm.TButton',
                        command=remMid)
        remBtn.grid(column=0, row=0, sticky='ne', pady=3)
        ent = Entry()
        lfrm = LFrame(master=frm, labelwidget=ent, bd=3, padx=5, pady=5)
        lfrm.grid(column=1, row=0, sticky='w')
        subfrm = Frame(master=lfrm)
        subfrm.grid(column=0, row=0)
        addBtn = Button(
            master=lfrm,
            text="Add Item",
            command=(lambda a=(subfrm, key, ent): self.addOuter(*a)))
        addBtn.grid(column=0, row=1, sticky='w', padx=3, pady=3)
        self.datadict[key][ent] = list()
        self.dataScrl.redraw()
        if name:
            ent.insert(0, name)
            return (subfrm, ent)
        else:
            self.addOuter(subfrm, key, ent)

    def addOuter(self,
                 parent: Frame,
                 key: Entry,
                 val: Entry,
                 name: str = '') -> None:
        def remOuter():
            frm.destroy()
            i = self.datadict[key][val].index(ent)
            self.datadict[key][val].pop(i)

        frm = Frame(master=parent, pady=1)
        frm.grid()
        remBtn = Button(master=frm,
                        text='Delete',
                        style='sm.TButton',
                        command=remOuter)
        remBtn.grid(column=0, row=0, sticky='ne', pady=3)
        ent = Entry(master=frm)
        ent.insert(0, name)
        ent.grid(column=1, row=0, sticky='w', padx=3, pady=3)
        self.datadict[key][val].append(ent)
        self.dataScrl.redraw()

    def getData(self):
        self.dataset = {
            inr.get(): {
                mid.get(): [out.get() for out in items]
                for mid, items in sub.items()
            }
            for inr, sub in self.datadict.items()
        }

        #   ___   _   _  ___   ___   ___
        #  / __| /_\ | \| \ \ / /_\ / __|
        # | (__ / _ \| .` |\ V / _ \\__ \
        #  \___/_/ \_\_|\_| \_/_/ \_\___/

    def buildCanvas(self, parent):
        self.imgcanvas = Canvas(master=parent, width=1440, height=1440)
        self.imgcanvas.pack()
        self.cnvimg = self.imgcanvas.create_image(0, 0, anchor='nw')
        self.image = None
        self.imagetk = None
예제 #24
0
파일: sudoku.py 프로젝트: j4321/Sudoku-Tk
class Sudoku(Tk):
    def __init__(self, file=None):
        Tk.__init__(self, className="Sudoku-Tk")
        self.title("Sudoku-Tk")
        self.resizable(0, 0)
        self.protocol("WM_DELETE_WINDOW", self.quitter)
        cst.set_icon(self)
        self.columnconfigure(3, weight=1)

        # --- style
        bg = '#dddddd'
        activebg = '#efefef'
        pressedbg = '#c1c1c1'
        lightcolor = '#ededed'
        darkcolor = '#cfcdc8'
        bordercolor = '#888888'
        focusbordercolor = '#5E5E5E'
        disabledfg = '#999999'
        disabledbg = bg

        button_style_config = {'bordercolor': bordercolor,
                               'background': bg,
                               'lightcolor': lightcolor,
                               'darkcolor': darkcolor}

        button_style_map = {'background': [('active', activebg),
                                           ('disabled', disabledbg),
                                           ('pressed', pressedbg)],
                            'lightcolor': [('pressed', darkcolor)],
                            'darkcolor': [('pressed', lightcolor)],
                            'bordercolor': [('focus', focusbordercolor)],
                            'foreground': [('disabled', disabledfg)]}

        style = Style(self)
        style.theme_use(cst.STYLE)
        style.configure('TFrame', background=bg)
        style.configure('TLabel', background=bg)
        style.configure('TScrollbar', gripcount=0, troughcolor=pressedbg,
                        **button_style_config)
        style.map('TScrollbar', **button_style_map)
        style.configure('TButton', **button_style_config)
        style.map('TButton', **button_style_map)
        style.configure('TCheckutton', **button_style_config)
        style.map('TCheckutton', **button_style_map)
        self.option_add('*Toplevel.background', bg)
        self.option_add('*Menu.background', bg)
        self.option_add('*Menu.activeBackground', activebg)
        self.option_add('*Menu.activeForeground', "black")
        self.configure(bg=bg)

        style.configure("bg.TFrame", background="grey")
        style.configure("case.TFrame", background="white")
        style.configure("case.TLabel", background="white", foreground="black")
        style.configure("case_init.TFrame", background="lightgrey")
        style.configure("case_init.TLabel", background="lightgrey", foreground="black")
        style.configure("erreur.TFrame", background="white")
        style.configure("erreur.TLabel", background="white", foreground="red")
        style.configure("solution.TFrame", background="white")
        style.configure("solution.TLabel", background="white", foreground="blue")
        style.configure("pause.TLabel", foreground="grey", background='white')

        # --- images
        self.im_erreur = open_image(cst.ERREUR)
        self.im_pause = open_image(cst.PAUSE)
        self.im_restart = open_image(cst.RESTART)
        self.im_play = open_image(cst.PLAY)
        self.im_info = open_image(cst.INFO)
        self.im_undo = open_image(cst.UNDO)
        self.im_redo = open_image(cst.REDO)
        self.im_question = open_image(cst.QUESTION)

        # --- timer
        self.chrono = [0, 0]
        self.tps = Label(self, text=" %02i:%02i" % tuple(self.chrono),
                         font="Arial 16")
        self.debut = False  # la partie a-t-elle commencée ?
        self.chrono_on = False  # le chrono est-il en marche ?

        # --- buttons
        self.b_pause = Button(self, state="disabled", image=self.im_pause,
                              command=self.play_pause)
        self.b_restart = Button(self, state="disabled", image=self.im_restart,
                                command=self.recommence)
        self.b_undo = Button(self, image=self.im_undo, command=self.undo)
        self.b_redo = Button(self, image=self.im_redo, command=self.redo)

        # --- tooltips
        self.tooltip_wrapper = TooltipWrapper(self)
        self.tooltip_wrapper.add_tooltip(self.b_pause, _("Pause game"))
        self.tooltip_wrapper.add_tooltip(self.b_restart, _("Restart game"))
        self.tooltip_wrapper.add_tooltip(self.b_undo, _("Undo"))
        self.tooltip_wrapper.add_tooltip(self.b_redo, _("Redo"))

        # --- numbers
        frame_nb = Frame(self, style='bg.TFrame', width=36)
        self.progression = []
        for i in range(1, 10):
            self.progression.append(Progression(frame_nb, i))
            self.progression[-1].pack(padx=1, pady=1)

        # --- level indication
        frame = Frame(self)
        frame.grid(row=0, columnspan=5, padx=(30, 10), pady=10)
        Label(frame, text=_("Level") + ' - ', font="Arial 16").pack(side='left')
        self.label_level = Label(frame, font="Arial 16", text=_("Unknown"))
        self.label_level.pack(side='left')
        self.level = "unknown"  # puzzle level

        # --- frame contenant la grille de sudoku
        self.frame_puzzle = Frame(self, style="bg.TFrame")
        self.frame_pause = Frame(self, style="case.TFrame")
        self.frame_pause.grid_propagate(False)
        self.frame_pause.columnconfigure(0, weight=1)
        self.frame_pause.rowconfigure(0, weight=1)
        Label(self.frame_pause, text='PAUSE', style='pause.TLabel',
              font='Arial 30 bold').grid()

        # --- placement
        frame_nb.grid(row=1, column=6, sticky='en', pady=0, padx=(0, 30))
        self.frame_puzzle.grid(row=1, columnspan=5, padx=(30, 15))
        self.tps.grid(row=2, column=0, sticky="e", padx=(30, 10), pady=30)
        self.b_pause.grid(row=2, column=1, sticky="w", padx=2, pady=30)
        self.b_restart.grid(row=2, column=2, sticky="w", padx=2, pady=30)
        self.b_undo.grid(row=2, column=3, sticky="e", pady=30, padx=2)
        self.b_redo.grid(row=2, column=4, sticky="w", pady=30, padx=(2, 10))

        # --- menu
        menu = Menu(self, tearoff=0)

        menu_nouveau = Menu(menu, tearoff=0)

        menu_levels = Menu(menu_nouveau, tearoff=0)
        menu_levels.add_command(label=_("Easy"), command=self.new_easy)
        menu_levels.add_command(label=_("Medium"), command=self.new_medium)
        menu_levels.add_command(label=_("Difficult"), command=self.new_difficult)

        menu_nouveau.add_cascade(label=_("Level"), menu=menu_levels)
        menu_nouveau.add_command(label=_("Generate a puzzle"),
                                 command=self.genere_grille,
                                 accelerator="Ctrl+G")
        menu_nouveau.add_command(label=_("Empty grid"),
                                 command=self.grille_vide,
                                 accelerator="Ctrl+N")

        menu_ouvrir = Menu(menu, tearoff=0)
        menu_ouvrir.add_command(label=_("Game"), command=self.import_partie,
                                accelerator="Ctrl+O")
        menu_ouvrir.add_command(label=_("Puzzle"), command=self.import_grille,
                                accelerator="Ctrl+Shift+O")

        menu_game = Menu(menu, tearoff=0)
        menu_game.add_command(label=_("Restart"), command=self.recommence)
        menu_game.add_command(label=_("Solve"), command=self.resolution)
        menu_game.add_command(label=_("Save"), command=self.sauvegarde,
                              accelerator="Ctrl+S")
        menu_game.add_command(label=_("Export"), command=self.export_impression,
                              accelerator="Ctrl+E")
        menu_game.add_command(label=_("Evaluate level"),
                              command=self.evaluate_level)

        menu_language = Menu(menu, tearoff=0)
        self.langue = StringVar(self)
        self.langue.set(cst.LANGUE[:2])
        menu_language.add_radiobutton(label="Français",
                                      variable=self.langue,
                                      value="fr", command=self.translate)
        menu_language.add_radiobutton(label="English", variable=self.langue,
                                      value="en", command=self.translate)

        menu_help = Menu(menu, tearoff=0)
        menu_help.add_command(label=_("Help"), command=self.aide, accelerator='F1')
        menu_help.add_command(label=_("About"), command=self.about)

        menu.add_cascade(label=_("New"), menu=menu_nouveau)
        menu.add_cascade(label=_("Open"), menu=menu_ouvrir)
        menu.add_cascade(label=_("Game"), menu=menu_game)
        menu.add_cascade(label=_("Language"), menu=menu_language)
        menu.add_command(label=_("Statistics"), command=self.show_stat)
        menu.add_cascade(label=_("Help"), menu=menu_help)

        self.configure(menu=menu)

        # --- clavier popup
        self.clavier = None

        # --- cases
        self.nb_cases_remplies = 0
        self.blocs = np.zeros((9, 9), dtype=object)
        for i in range(9):
            for j in range(9):
                self.blocs[i, j] = Case(self.frame_puzzle, i, j, self.update_nbs, width=50, height=50)
                px, py = 1, 1
                if i % 3 == 2 and i != 8:
                    py = (1, 3)
                if j % 3 == 2 and j != 8:
                    px = (1, 3)
                self.blocs[i, j].grid(row=i, column=j, padx=px, pady=py)
                self.blocs[i, j].grid_propagate(0)

        # --- undo/redo stacks
        self._undo_stack = []
        self._redo_stack = []

        # --- raccourcis clavier et actions de la souris
        self.bind("<Button>", self.edit_case)
        self.bind("<Control-z>", lambda e: self.undo())
        self.bind("<Control-y>", lambda e: self.redo())
        self.bind("<Control-s>", lambda e: self.sauvegarde())
        self.bind("<Control-e>", lambda e: self.export_impression())
        self.bind("<Control-o>", lambda e: self.import_partie())
        self.bind("<Control-Shift-O>", lambda e: self.import_grille())
        self.bind("<Control-n>", lambda e: self.grille_vide())
        self.bind("<Control-g>", lambda e: self.genere_grille())
        self.bind("<FocusOut>", self.focus_out)
        self.bind("<F1>", self.aide)

        # --- open game
        if file:
            try:
                self.load_sudoku(file)
            except FileNotFoundError:
                one_button_box(self, _("Error"),
                               _("The file %(file)r does not exist.") % file,
                               image=self.im_erreur)
            except (KeyError, EOFError, UnpicklingError):
                try:
                    self.load_grille(file)
                except Exception:
                    one_button_box(self, _("Error"),
                                   _("This file is not a valid sudoku file."),
                                   image=self.im_erreur)
        elif exists(cst.PATH_SAVE):
            self.load_sudoku(cst.PATH_SAVE)
            remove(cst.PATH_SAVE)

    @property
    def level(self):
        return self._level

    @level.setter
    def level(self, level):
        self._level = level
        self.label_level.configure(text=_(level.capitalize()))

    def update_nbs(self, nb, delta):
        self.progression[nb - 1].nb += delta

    def reset_nbs(self):
        for p in self.progression:
            p.nb = 0

    def evaluate_level(self):
        grille = Grille()
        for i in range(9):
            for j in range(9):
                val = self.blocs[i, j].get_val()
                if val:
                    grille.ajoute_init(i, j, val)
        self.level = difficulte_grille(grille)

    def show_stat(self):
        """ show best times """
        def reset():
            """ reset best times """
            for level in ["easy", "medium", "difficult"]:
                CONFIG.set("Statistics", level, "")
            top.destroy()

        if self.chrono_on:
            self.play_pause()
        top = Toplevel(self)
        top.transient(self)
        top.columnconfigure(1, weight=1)
        top.resizable(0, 0)

        top.title(_("Statistics"))
        top.grab_set()

        Label(top, text=_("Best times"), font="Sans 12 bold").grid(row=0, columnspan=2,
                                                                   padx=30, pady=10)

        for i, level in enumerate(["easy", "medium", "difficult"]):
            Label(top, text=_(level.capitalize()),
                  font="Sans 10 bold").grid(row=i + 1, column=0, padx=(20, 4),
                                            pady=4, sticky="e")
            tps = CONFIG.get("Statistics", level)
            if tps:
                tps = int(tps)
                m = tps // 60
                s = tps % 60
                Label(top, text=" %i min %i s" % (m, s),
                      font="Sans 10").grid(row=i + 1, column=1,
                                           sticky="w", pady=4,
                                           padx=(4, 20))
        Button(top, text=_("Close"), command=top.destroy).grid(row=4, column=0, padx=(10, 4), pady=10)
        Button(top, text=_("Clear"), command=reset).grid(row=4, column=1, padx=(4, 10), pady=10)

    def new_easy(self):
        nb = np.random.randint(1, 101)
        fichier = join(cst.PUZZLES_LOCATION, "easy", "puzzle_easy_%i.txt" % nb)
        self.import_grille(fichier)
        self.level = "easy"

    def new_medium(self):
        nb = np.random.randint(1, 101)
        fichier = join(cst.PUZZLES_LOCATION, "medium", "puzzle_medium_%i.txt" % nb)
        self.import_grille(fichier)
        self.level = "medium"

    def new_difficult(self):
        nb = np.random.randint(1, 101)
        fichier = join(cst.PUZZLES_LOCATION, "difficult", "puzzle_difficult_%i.txt" % nb)
        self.import_grille(fichier)
        self.level = "difficult"

    def translate(self):
        """ changement de la langue de l'interface """
        one_button_box(self, _("Information"),
                       _("The language setting will take effect after restarting the application"),
                       image=self.im_info)
        CONFIG.set("General", "language", self.langue.get())

    def focus_out(self, event):
        """ met en pause si la fenêtre n'est plus au premier plan """
        try:
            if not self.focus_get() and self.chrono_on:
                self.play_pause()
        except KeyError:
            # erreur déclenchée par la présence d'une tkMessagebox
            if self.chrono_on:
                self.play_pause()

    def stacks_reinit(self):
        """efface l'historique des actions"""
        self._undo_stack.clear()
        self._redo_stack.clear()
        self.b_undo.configure(state="disabled")
        self.b_redo.configure(state="disabled")

    def stacks_modif(self, action):
        """Record action and clear redo stack."""
        self._undo_stack.append(action)
        self.b_undo.configure(state="normal")
        self.b_redo.configure(state="disabled")
        self._redo_stack.clear()

    def about(self):
        if self.chrono_on:
            self.play_pause()
        About(self)

    def aide(self, event=None):
        if self.chrono_on:
            self.play_pause()
        Aide(self)

    def quitter(self):
        rep = _("Yes")
        if self.debut:
            rep = two_button_box(self, _("Confirmation"),
                                 _("Do you want to interrupt the current puzzle?"),
                                 _("Yes"), _("No"), image=self.im_question)
        if rep == _("Yes"):
            if self.debut:
                self.save(cst.PATH_SAVE)
            self.destroy()

    def undo(self):
        if self._undo_stack and self.chrono_on:
            self.b_redo.configure(state="normal")
            i, j, val_prec, pos_prec, modifs, val, pos = self._undo_stack.pop(-1)
            self._redo_stack.append((i, j, val_prec, pos_prec, modifs, val, pos))
            if not self._undo_stack:
                self.b_undo.configure(state="disabled")

            if self.blocs[i, j].get_val():
                self.modifie_nb_cases_remplies(-1)
                self.update_nbs(self.blocs[i, j].get_val(), -1)
            self.blocs[i, j].efface_case()
            if val_prec:
                self.modifie_nb_cases_remplies(self.blocs[i, j].edit_chiffre(val_prec))
                if not self.test_case(i, j, val):
                    self.update_grille(i, j, val)
            else:
                for nb in pos_prec:
                    v = int(nb)
                    self.modifie_nb_cases_remplies(self.blocs[i, j].edit_possibilite(v))
                    self.test_possibilite(i, j, v)
            for k, l in modifs:
                self.blocs[k, l].edit_possibilite(val)

    def redo(self):
        if self._redo_stack and self.chrono_on:
            self.b_undo.configure(state="normal")
            i, j, val_prec, pos_prec, modifs, val, pos = self._redo_stack.pop(-1)
            self._undo_stack.append((i, j, val_prec, pos_prec, modifs, val, pos))
            if not self._redo_stack:
                self.b_redo.configure(state="disabled")
            val_prec = self.blocs[i, j].get_val()
            if val_prec:
                self.modifie_nb_cases_remplies(-1)
                self.update_nbs(val_prec, -1)
            self.blocs[i, j].efface_case()
            if val:
                self.modifie_nb_cases_remplies(self.blocs[i, j].edit_chiffre(val))
                if not self.test_case(i, j, val_prec):
                    self.update_grille(i, j, val_prec)
            else:
                for nb in pos:
                    v = int(nb)
                    self.modifie_nb_cases_remplies(self.blocs[i, j].edit_possibilite(v))
                    self.test_possibilite(i, j, v)

    def restart(self, m=0, s=0):
        """ réinitialise le chrono et les boutons """
        self.chrono = [m, s]
        self.chrono_on = False
        self.debut = False
        self.tps.configure(text=" %02i:%02i" % tuple(self.chrono))
        self.b_undo.configure(state="disabled")
        self.b_pause.configure(state="disabled", image=self.im_pause)
        self.b_redo.configure(state="disabled")
        self.b_restart.configure(state="disabled")
        self.stacks_reinit()
        self.frame_pause.place_forget()

    def play_pause(self):
        """ Démarre le chrono s'il était arrêté, le met en pause sinon """
        if self.debut:
            if self.chrono_on:
                self.chrono_on = False
                self.b_pause.configure(image=self.im_play)
                self.b_redo.configure(state="disabled")
                self.b_undo.configure(state="disabled")
                self.tooltip_wrapper.set_tooltip_text(self.b_pause, _("Resume game"))
                self.frame_pause.place(in_=self.frame_puzzle, x=0, y=0, anchor='nw',
                                       relwidth=1, relheight=1)
            elif self.nb_cases_remplies != 81:
                self.chrono_on = True
                self.b_pause.configure(image=self.im_pause)
                self.tps.after(1000, self.affiche_chrono)
                if self._undo_stack:
                    self.b_undo.configure(state="normal")
                if self._redo_stack:
                    self.b_redo.configure(state="normal")
                self.tooltip_wrapper.set_tooltip_text(self.b_pause, _("Pause game"))
                self.frame_pause.place_forget()

    def affiche_chrono(self):
        """ Met à jour l'affichage du temps """
        if self.chrono_on:
            self.chrono[1] += 1
            if self.chrono[1] == 60:
                self.chrono[0] += 1
                self.chrono[1] = 0
            self.tps.configure(text=" %02i:%02i" % tuple(self.chrono))
            self.tps.after(1000, self.affiche_chrono)

    def modifie_nb_cases_remplies(self, nb):
        self.nb_cases_remplies += nb

    def edit_case(self, event):
        if event.num in [1, 3]:
            if not self.debut and self.nb_cases_remplies != 81:
                self.debut = True
                self.b_pause.configure(state="normal")
                self.b_restart.configure(state="normal")
                self.play_pause()
            if str(event.widget) != "." and self.chrono_on:
                if self.clavier:
                    self.clavier.quitter()
                ref = self.blocs[0, 0].winfo_parent()
                case = event.widget.grid_info().get("in", None)
                if str(case) == ref:
                    case = event.widget
                try:
                    if case.is_modifiable():
                        if event.num == 1:
                            self.clavier = Clavier(self, case, "val")
                        elif event.num == 3:
                            self.clavier = Clavier(self, case, "possibilite")
                        self.clavier.display("+%i+%i" % (case.winfo_rootx() - 25, case.winfo_rooty() + 50))
                except AttributeError:
                    if self.clavier:
                        self.clavier.quitter()

            elif self.clavier:
                self.clavier.quitter()

    def test_case(self, i, j, val_prec=0):
        """ Teste si la valeur de la case est en contradiction avec celles des
            autres cases de la ligne / colonne / bloc et renvoie True s'il y a une erreur."""
        val = self.blocs[i, j].get_val()
        a, b = i // 3, j // 3
        error = False
        if val:
            if ((self.blocs[i, :] == val).sum() > 1 or (self.blocs[:, j] == val).sum() > 1 or
               (self.blocs[3 * a: 3 * (a + 1), 3 * b: 3 * (b + 1)] == val).sum() > 1):
                # erreur !
                self.blocs[i, j].affiche_erreur()
                error = True
        if val_prec:
            # a number was removed, remove obsolete errors
            line = self.blocs[i, :] == val_prec
            column = self.blocs[:, j] == val_prec
            bloc = self.blocs[3 * a: 3 * (a + 1), 3 * b: 3 * (b + 1)] == val_prec
            if line.sum() == 1:
                self.blocs[i, line.argmax()].no_error()
                self.test_case(i, line.argmax())
            if column.sum() == 1:
                self.blocs[column.argmax(), j].no_error()
                self.test_case(column.argmax(), j)
            if bloc.sum() == 1:
                x, y = divmod(bloc.argmax(), 3)
                self.blocs[3 * a + x, 3 * b + y].no_error()
                self.test_case(3 * a + x, 3 * b + y)
        return error

    def test_possibilite(self, i, j, val):
        """ Teste si la possibilité val de la case est en contradiction avec les valeurs des
            autres cases de la ligne / colonne / bloc """
        a, b = i // 3, j // 3
        if ((self.blocs[i, :] == val).sum() > 0 or (self.blocs[:, j] == val).sum() > 0 or
           (self.blocs[3 * a: 3 * (a + 1), 3 * b: 3 * (b + 1)] == val).sum() > 0):
            # erreur !
            self.blocs[i, j].affiche_erreur_possibilite(val)

    def test_remplie(self):
        """ Test si la grille est remplie """
        if self.nb_cases_remplies == 81:
            grille = Grille()
            for i in range(9):
                for j in range(9):
                    val = self.blocs[i, j].get_val()
                    if val:
                        grille.ajoute_init(i, j, val)
            sol = grille.solve()
            if type(sol) == np.ndarray:
                self.play_pause()
                self.frame_pause.place_forget()
                one_button_box(self, _("Information"),
                               _("You solved the puzzle in %(min)i minutes and %(sec)i secondes.") % {"min": self.chrono[0], "sec": self.chrono[1]},
                               image=self.im_info)
                if self.level != "unknown":
                    best = CONFIG.get("Statistics", self.level)
                    current = self.chrono[0] * 60 + self.chrono[1]
                    if best:
                        best = int(best)
                        if current < best:
                            CONFIG.set("Statistics", self.level, str(current))
                    else:
                        CONFIG.set("Statistics", self.level, str(current))
                self.b_pause.configure(state="disabled")
                self.debut = False

            else:
                i, j = sol[1]
                if self.blocs[i, j].get_val():
                    self.blocs[i, j].affiche_erreur()
                one_button_box(self, _("Information"), _("There is a mistake."),
                               image=self.im_info)

    def update_grille(self, i, j, val_prec=0):
        """ Enlève les possibilités devenues impossibles suite à l'ajout d'une
            valeur dans la case (i, j) """
        val = self.blocs[i, j].get_val()
        modif = []
        a, b = i // 3, j // 3
        if val_prec:
            x, y = divmod(val_prec - 1, 3)
        for k, (line, column, bloc) in enumerate(zip(self.blocs[i, :], self.blocs[:, j], self.blocs[3 * a: 3 * (a + 1), 3 * b: 3 * (b + 1)].flatten())):
            # works because if line is bloc then pos1 is pos3 and both are edited at once
            pos1 = line.get_possibilites()
            pos2 = column.get_possibilites()
            pos3 = bloc.get_possibilites()
            if val in pos1:
                self.blocs[i, k].edit_possibilite(val)
                modif.append((i, k))
            if val in pos2:
                self.blocs[k, j].edit_possibilite(val)
                modif.append((k, j))
            if val in pos3:
                m, n = divmod(k, 3)
                self.blocs[3 * a + m, 3 * b + n].edit_possibilite(val)
                modif.append((3 * a + m, 3 * b + n))
            if val_prec:
                if val_prec in pos1:
                    self.blocs[i, k].pas_erreur(x, y)
                    self.test_possibilite(i, k, val_prec)
                if val_prec in pos2:
                    self.blocs[k, j].pas_erreur(x, y)
                    self.test_possibilite(k, j, val_prec)
                if val_prec in pos3:
                    m, n = divmod(k, 3)
                    m, n = 3 * a + m, 3 * b + n
                    if m != i and n != j:
                        self.blocs[m, n].pas_erreur(x, y)
                        self.test_possibilite(m, n, val_prec)
        return modif

    def set_clavier(self, c):
        self.clavier = c

    def grille_vide(self):
        rep = _("Yes")
        if self.debut:
            rep = two_button_box(self, _("Confirmation"),
                                 _("Do you want to abandon the current puzzle?"),
                                 _("Yes"), _("No"), self.im_question)
        if rep == _("Yes"):
            self.nb_cases_remplies = 0
            self.restart()
            self.level = "unknown"
            self.reset_nbs()
            for i in range(9):
                for j in range(9):
                    self.blocs[i, j].set_modifiable(True)
                    self.blocs[i, j].efface_case()

    def genere_grille(self):
        """ Génère une nouvelle grille """
        if self.chrono_on:
            self.play_pause()
        rep = _("Yes")
        if self.debut:
            rep = two_button_box(self, _("Confirmation"),
                                 _("Do you want to abandon the current puzzle?"),
                                 _("Yes"), _("No"), self.im_question)

        if rep == _("Yes"):
            self.configure(cursor="watch")
            self.update()
            rep2 = _("Retry")
            while rep2 == _("Retry"):
                grille = genere_grille()
                diff = difficulte_grille(grille)
                nb = grille.nb_cases_remplies()
                self.configure(cursor="")
                rep2 = two_button_box(self, _("Information"),
                                      _("The generated puzzle contains %(nb)i numbers and its level is %(difficulty)s.") % ({"nb": nb, "difficulty": _(diff.capitalize())}),
                                      _("Play"), _("Retry"), image=self.im_info)
            if rep2 == _("Play"):
                self.level = diff
                self.affiche_grille(grille.get_sudoku())

    def recommence(self):
        if self.chrono_on:
            self.play_pause()
        rep = _("Yes")
        if self.debut:
            rep = two_button_box(self, _("Confirmation"),
                                 _("Do you really want to start again?"),
                                 _("Yes"), _("No"), self.im_question)
        if rep == _("Yes"):
            self.reset_nbs()
            for i in range(9):
                for j in range(9):
                    if self.blocs[i, j].is_modifiable():
                        if self.blocs[i, j].get_val():
                            self.nb_cases_remplies -= 1
                        self.blocs[i, j].efface_case()
                    else:
                        self.update_nbs(self.blocs[i, j].get_val(), 1)
            self.restart()
        elif self.debut:
            self.play_pause()

    def save(self, path):
        grille = np.zeros((9, 9), dtype=int)
        modif = np.zeros((9, 9), dtype=bool)
        possibilites = []
        for i in range(9):
            possibilites.append([])
            for j in range(9):
                grille[i, j] = self.blocs[i, j].get_val()
                modif[i, j] = self.blocs[i, j].is_modifiable()
                possibilites[i].append(self.blocs[i, j].get_possibilites())
        with open(path, "wb") as fich:
            p = Pickler(fich)
            p.dump(grille)
            p.dump(modif)
            p.dump(possibilites)
            p.dump(self.chrono)
            p.dump(self.level)

    def sauvegarde(self):
        if self.chrono_on:
            self.play_pause()
        fichier = asksaveasfilename(initialdir=cst.INITIALDIR,
                                    defaultextension='.sudoku',
                                    filetypes=[('Sudoku', '*.sudoku')])
        if fichier:
            self.save(fichier)

    def affiche_grille(self, grille):
        """ Affiche la grille """
        self.nb_cases_remplies = 0
        self.restart()
        self.reset_nbs()
        for i in range(9):
            for j in range(9):
                nb = grille[i, j]
                self.blocs[i, j].efface_case()
                if nb:
                    self.blocs[i, j].set_modifiable(False)
                    self.nb_cases_remplies += 1
                    self.blocs[i, j].edit_chiffre(nb)
                else:
                    self.blocs[i, j].set_modifiable(True)

    def load_sudoku(self, file):
        with open(file, "rb") as fich:
            dp = Unpickler(fich)
            grille = dp.load()
            modif = dp.load()
            possibilites = dp.load()
            chrono = dp.load()
            self.level = dp.load()
        self.nb_cases_remplies = 0
        self.reset_nbs()
        self.restart(*chrono)
        for i in range(9):
            for j in range(9):
                self.blocs[i, j].efface_case()
                if grille[i, j]:
                    self.nb_cases_remplies += 1
                    self.blocs[i, j].edit_chiffre(grille[i, j])
                else:
                    for pos in possibilites[i][j]:
                        self.blocs[i, j].edit_possibilite(pos)
                self.blocs[i, j].set_modifiable(modif[i, j])

    def import_partie(self):
        """ importe une partie stockée dans un fichier .sudoku """
        if self.chrono_on:
            self.play_pause()
        rep = _("Yes")
        if self.debut:
            rep = two_button_box(self, _("Confirmation"),
                                 _("Do you want to abandon the current puzzle?"),
                                 _("Yes"), _("No"), self.im_question)
        if rep == _("Yes"):
            fichier = askopenfilename(initialdir=cst.INITIALDIR,
                                      defaultextension='.sudoku',
                                      filetypes=[('Sudoku', '*.sudoku')])
            if fichier:
                try:
                    self.load_sudoku(fichier)
                except FileNotFoundError:
                    one_button_box(self, _("Error"),
                                   _("The file %(file)r does not exist.") % fichier,
                                   image=self.im_erreur)
                except (KeyError, EOFError, UnpicklingError):
                    one_button_box(self, _("Error"),
                                   _("This file is not a valid sudoku file."),
                                   image=self.im_erreur)
        elif self.debut:
            self.play_pause()

    def resolution_init(self):
        """ Résolution de la grille initiale (sans tenir compte des valeurs rentrées par l'utilisateur. """
        grille = Grille()
        for i in range(9):
            for j in range(9):
                if not self.blocs[i, j].is_modifiable():
                    val = self.blocs[i, j].get_val()
                    grille.ajoute_init(i, j, val)
        self.configure(cursor="watch")
        self.update()
        sol = grille.solve()
        self.configure(cursor="")
        if type(sol) == np.ndarray:
            for i in range(9):
                for j in range(9):
                    val = self.blocs[i, j].get_val()
                    if not val:
                        self.blocs[i, j].edit_chiffre(sol[i, j])
                        self.blocs[i, j].affiche_solution()
                    elif self.blocs[i, j].is_modifiable():
                        if val != sol[i, j]:
                            self.blocs[i, j].edit_chiffre(sol[i, j])
                            self.blocs[i, j].affiche_erreur()
            self.restart()
            self.nb_cases_remplies = 81

        elif sol[1]:
            i, j = sol[1]
            if self.blocs[i, j].get_val():
                self.blocs[i, j].affiche_erreur()
            one_button_box(self, _("Error"), _("The grid is wrong. It cannot be solved."),
                           image=self.im_erreur)
        else:
            one_button_box(self, _("Error"), _("Resolution failed."),
                           image=self.im_erreur)

    def resolution(self):
        if self.chrono_on:
            self.play_pause()
        rep = two_button_box(self, _("Confirmation"),
                             _("Do you really want to get the solution?"),
                             _("Yes"), _("No"), image=self.im_question)
        if rep == _("Yes"):
            self.frame_pause.place_forget()
            grille = Grille()
            for i in range(9):
                for j in range(9):
                    val = self.blocs[i, j].get_val()
                    if val:
                        grille.ajoute_init(i, j, val)
            self.configure(cursor="watch")
            self.update()
            sol = grille.solve()
            self.configure(cursor="")
            if type(sol) == np.ndarray:
                for i in range(9):
                    for j in range(9):
                        val = self.blocs[i, j].get_val()
                        if not val:
                            self.blocs[i, j].edit_chiffre(sol[i, j])
                            self.blocs[i, j].affiche_solution()
                self.restart()
                self.b_restart.configure(state="normal")
                self.nb_cases_remplies = 81
            elif sol[1]:
                i, j = sol[1]
                if self.blocs[i, j].get_val():
                    self.blocs[i, j].affiche_erreur()
                i, j = 0, 0
                while i < 9 and self.blocs[i, j].is_modifiable():
                    j += 1
                    if j == 9:
                        i += 1
                        j = 0
                if i < 9:
                    # il y a au moins une case de type "initial"
                    rep = two_button_box(self, _("Error"),
                                         _("The grid is wrong. It cannot be solved. Do you want the solution of the initial grid?"),
                                         _("Yes"), _("No"), image=self.im_erreur)
                    if rep == _("Yes"):
                        self.resolution_init()
                else:
                    one_button_box(self, _("Error"), _("The grid is wrong. It cannot be solved."),
                                   image=self.im_erreur)
            else:
                one_button_box(self, _("Error"), _("Resolution failed."),
                               image=self.im_erreur)

    def load_grille(self, file):
        gr = np.loadtxt(file, dtype=int)
        if gr.shape == (9, 9):
            self.affiche_grille(gr)
            self.level = "unknown"
        else:
            one_button_box(self, _("Error"), _("This is not a 9x9 sudoku grid."),
                           image=self.im_erreur)

    def import_grille(self, fichier=None):
        """ importe une grille stockée dans un fichier txt sous forme de
            chiffres séparés par des espaces (0 = case vide) """
        if self.chrono_on:
            self.play_pause()
        rep = _("Yes")
        if self.debut:
            rep = two_button_box(self, _("Confirmation"),
                                 _("Do you want to abandon the current puzzle?"),
                                 _("Yes"), _("No"), self.im_question)
        if rep == _("Yes"):
            if not fichier:
                fichier = askopenfilename(initialdir=cst.INITIALDIR,
                                          defaultextension='.txt',
                                          filetypes=[('Text', '*.txt'), ('Tous les fichiers', "*")])
            if fichier:
                try:
                    self.load_grille(fichier)
                except (ValueError, UnicodeDecodeError):
                    one_button_box(self, _("Error"),
                                   _("The file does not have the right format. It should be a .txt file with cell values separated by one space. 0 means empty cell."),
                                   image=self.im_erreur)
                except FileNotFoundError:
                    one_button_box(self, _("Error"),
                                   _("The file %(file)r does not exist.") % fichier,
                                   image=self.im_erreur)
        elif self.debut:
            self.play_pause()

    def export_impression(self):
        """ exporte la grille en image (pour pouvoir l'imprimer) """
        if self.chrono_on:
            self.play_pause()
        fichier = asksaveasfilename(title=_("Export"),
                                    initialdir=cst.INITIALDIR,
                                    defaultextension='.png',
                                    filetypes=[('PNG', '*.png'),
                                               ('JPEG', 'jpg')])
        if fichier:
            grille = np.zeros((9, 9), dtype=int)
            for i in range(9):
                for j in range(9):
                    grille[i, j] = self.blocs[i, j].get_val()
            font = ImageFont.truetype("arial.ttf", 64)
            im = Image.new("RGB", (748, 748), "white")
            draw = ImageDraw.Draw(im)
            i = 0
            l = 1
            while i < 10:
                if i % 3 == 0:
                    w = 4
                else:
                    w = 2
                draw.line((l, 1, l, 748), width=w, fill="black")
                draw.line((1, l, 748, l), width=w, fill="black")
                l += 80 + w
                i += 1

            for i in range(9):
                for j in range(9):
                    if grille[i, j]:
                        draw.text((26 + j * 82 + 2 * (j // 3),
                                   10 + i * 82 + 2 * (i // 3)),
                                  " %i" % grille[i, j], fill="black", font=font)

            del draw
            im.save(fichier)
예제 #25
0
class P300Window(object):
    def __init__(self, master: Tk):
        self.master = master
        master.title('P300 speller')

        #Parameters
        self.imagesize = 125
        self.images_folder_path = '../utils/images/'  #use utils/char_generator to generate any image you want
        self.flash_image_path = '../utils/images/flash_images/einstein.jpg'
        self.number_of_rows = 6
        self.number_of_columns = 6  #make sure you have 6 x 6 amount of images in the images_folder_path
        self.lsl_streamname = 'P300_stream'
        self.flash_mode = 2  #single element  #1 for columns and rows; currently is NOT working yet; if I have time, will revisit
        self.flash_duration = 100  #soa
        self.break_duration = 250  #iti
        self.set_of_repetition = 12
        self.number_of_flashes_per_repetition = 10
        self.total_repetitions_per_trial = self.set_of_repetition * self.number_of_flashes_per_repetition  #30 repetitions per letters

        self.trials = 6  #number of letters
        self.delay = 2500  #interval between trial
        self.letter_idx = 0

        #did not include numbers yet!
        self.random_letter = random.choices(
            string.ascii_lowercase,
            k=self.trials)  #randomize [self.trials] number letters
        self.word = ''.join(self.random_letter)

        # Variables
        self.usable_images = []
        self.image_labels = []
        self.flash_sequence = []
        self.flash_image = None
        self.sequence_number = 0
        self.lsl_output = None

        self.running = 0  #for pause

        self.image_frame = Frame(self.master)
        self.image_frame.grid(row=0,
                              column=0,
                              rowspan=self.number_of_rows,
                              columnspan=self.number_of_columns)

        self.start_btn_text = StringVar()
        self.start_btn_text.set('Start')
        self.start_btn = Button(self.master,
                                textvariable=self.start_btn_text,
                                command=self.start)
        self.start_btn.grid(row=self.number_of_rows + 2,
                            column=self.number_of_columns - 1)

        self.pause_btn = Button(self.master, text='Pause', command=self.pause)
        self.pause_btn.grid(row=self.number_of_rows + 2,
                            column=self.number_of_columns - 4)  #-4 for center
        self.pause_btn.configure(state='disabled')

        self.close_btn = Button(self.master, text='Close', command=master.quit)
        self.close_btn.grid(row=self.number_of_rows + 2, column=0)

        self.show_highlight_letter(0)

        # Initialization
        self.show_images()
        self.create_flash_sequence()
        self.lsl_output = self.create_lsl_output()

    def open_images(self):
        self.usable_images = []
        self.highlight_letter_images = []

        letter_images = sorted(
            glob.glob(
                os.path.join(self.images_folder_path, 'letter_images/*.png')))

        #currently, still did not flash number yet!
        number_images = sorted(
            glob.glob(
                os.path.join(self.images_folder_path, 'number_images/*.png')))
        letter_highlight_images = sorted(
            glob.glob(
                os.path.join(self.images_folder_path,
                             'letter_highlight_images/*.png')))
        number_highlight_images = sorted(
            glob.glob(
                os.path.join(self.images_folder_path,
                             'number_highlight_images/*.png')))

        for number_image in number_images:
            letter_images.append(number_image)
        #print("Paths: ", letter_images)
        min_number_of_images = self.number_of_columns * self.number_of_rows
        if len(letter_images) < min_number_of_images:
            print('To few images in folder: ' + self.images_folder_path)
            return

        # Convert and resize images
        for image_path in letter_images:
            image = Image.open(image_path)
            resized = image.resize((self.imagesize, self.imagesize),
                                   Image.BICUBIC)
            Tkimage = ImageTk.PhotoImage(resized)
            self.usable_images.append(Tkimage)

        # Convert and resize images
        for image_path in letter_highlight_images:
            image = Image.open(image_path)
            resized = image.resize((self.imagesize, self.imagesize),
                                   Image.BICUBIC)
            Tkimage = ImageTk.PhotoImage(resized)
            self.highlight_letter_images.append(Tkimage)

        flash_img = Image.open(self.flash_image_path)
        flash_img_res = flash_img.resize((self.imagesize, self.imagesize),
                                         Image.BICUBIC)
        self.flash_image = ImageTk.PhotoImage(flash_img_res)

    def show_images(self):
        self.open_images()

        if self.usable_images == []:
            print('No images opened')
            return

        num_rows = self.number_of_rows
        num_cols = self.number_of_columns

        # Arrange images
        for r in range(0, num_rows):
            for c in range(0, num_cols):
                current_image = self.usable_images[r * num_cols + c]
                label = Label(self.image_frame, image=current_image)
                label.image = current_image
                label.grid(row=r, column=c)
                self.image_labels.append(label)

    def create_lsl_output(self):
        """Creates an LSL Stream outlet"""
        info = StreamInfo(name=self.lsl_streamname,
                          type='Markers',
                          channel_count=1,
                          channel_format='int8',
                          nominal_srate=IRREGULAR_RATE,
                          source_id='marker_stream',
                          handle=None)

        if self.flash_mode == 1:
            info.desc().append_child_value('flash_mode', 'Row and Column')
        elif self.flash_mode == 2:
            info.desc().append_child_value('flash_mode', 'Single Value')

        info.desc().append_child_value('num_rows', str(self.number_of_rows))
        info.desc().append_child_value('num_cols', str(self.number_of_columns))

        return StreamOutlet(info)

    def create_flash_sequence(self):
        self.flash_sequence = []
        num_rows = self.number_of_rows
        num_cols = self.number_of_columns

        if self.flash_mode == 1:
            print(
                'CAUTION: Row and Column flash mode currently uses only random samples!'
            )
            self.flash_sequence = np.random.randint(
                0, num_rows + num_cols, 3000)  #3000 should be enough
        elif self.flash_mode == 2:
            maximum_number = num_rows * num_cols
            for i in range(len(self.word)):
                for j in range(self.set_of_repetition):  #generate three sets
                    seq = list(
                        range(maximum_number))  #generate 0 to maximum_number
                    random.shuffle(seq)  #shuffle

                    index = string.ascii_lowercase.index(self.word[i])
                    allowed_values = list(range(0, maximum_number))
                    allowed_values.remove(
                        index
                    )  #reduce number of flashed by first excluding the actual letter
                    #print("Index: ", index)

                    while (len(seq) > self.number_of_flashes_per_repetition
                           ):  #cut down array until there is only 10 values
                        choice = random.choice(allowed_values)
                        if choice in seq:
                            seq.remove(choice)

                    #make sure no repeating element in consecutive order
                    #the consecutive happens when we combine the next array, thus we simply check the tail of seq and head of the array
                    try:
                        if seq[0] == flash_sequence[-1]:
                            seq[0], seq[-6] = seq[-6], seq[
                                0]  #swap the consecutive to some other places, here i choose -6
                    except NameError:
                        flash_sequence = []
                    flash_sequence.extend(seq)

        self.flash_sequence = flash_sequence

    def start(self):
        self.running = 1
        letter = self.word[0]
        image_index = string.ascii_lowercase.index(letter)
        self.highlight_image(image_index)
        self.start_btn.configure(state='disabled')
        self.pause_btn.configure(state='normal')
        self.master.quit

    def pause(self):
        self.running = 0
        self.start_btn_text.set('Resume')
        self.start_btn.configure(state='normal')
        self.pause_btn.configure(state='disabled')

    def start_flashing(self):
        if self.sequence_number == len(
                self.flash_sequence
        ):  #stop flashing if all generated sequence number runs out
            print('All elements had flashed - run out of juice')
            self.running = 0
            self.sequence_number = 0
            return

        if self.running == 0:
            print('Flashing paused at sequence number ' +
                  str(self.sequence_number))
            return

        element_to_flash = self.flash_sequence[self.sequence_number]
        letter = self.word[self.letter_idx]
        image_index = string.ascii_lowercase.index(letter)

        #pushed markers to LSL stream
        timestamp = local_clock()
        if (element_to_flash == image_index):
            print("Pushed to the LSL: ", "Marker: ", [2], "; Timestamp: ",
                  timestamp, "Seq: ", self.sequence_number,
                  "Target letter - [Letter#]: ", self.letter_idx,
                  " [Image index]: ", image_index, " [Character]: ", letter,
                  "Flash element: ", element_to_flash)
            self.lsl_output.push_sample([2], timestamp)  #2 for targets
        else:
            #print("Pushed to the LSL: ", "Marker: ", [1], "; Timestamp: ", timestamp)
            self.lsl_output.push_sample([1], timestamp)  #1 for non-targets

        #flashing
        if self.flash_mode == 1:
            self.flash_row_or_col(element_to_flash)
        elif self.flash_mode == 2:
            self.flash_single_element(element_to_flash)

        if (self.letter_idx < len(self.word)):
            if (
                (self.sequence_number + 1) %
                    self.total_repetitions_per_trial == 0
            ):  #every self.repetitions, change letter (0 - 29, 30 - 59, 60 - 89 etc.)
                self.letter_idx += 1
                if (self.letter_idx == len(self.word)):
                    return
                letter = self.word[self.letter_idx]
                image_index = string.ascii_lowercase.index(letter)
                self.master.after(self.break_duration, self.highlight_target,
                                  image_index)
            else:
                self.master.after(self.break_duration, self.start_flashing)

        self.sequence_number = self.sequence_number + 1  #change flash position

    def highlight_target(self, image_index):
        self.show_highlight_letter(self.letter_idx)
        self.highlight_image(image_index)

    def change_image(self, label, img):
        label.configure(image=img)
        label.image = img

    def highlight_image(self, element_no):
        self.change_image(self.image_labels[element_no],
                          self.highlight_letter_images[element_no])
        self.master.after(self.delay, self.unhighlight_image, element_no)

    def unhighlight_image(self, element_no):
        self.change_image(self.image_labels[element_no],
                          self.usable_images[element_no])
        self.master.after(self.flash_duration, self.start_flashing)

    def show_highlight_letter(self, pos):

        fontStyle = tkFont.Font(family="Courier", size=40)
        fontStyleBold = tkFont.Font(family="Courier bold", size=40)

        text = Text(root, height=1, font=fontStyle)
        text.tag_configure("bold", font=fontStyleBold)
        text.tag_configure("center", justify='center')

        for i in range(0, len(self.word)):
            if (i != pos):
                text.insert("end", self.word[i])
            else:
                text.insert("end", self.word[i], "bold")

        text.configure(state="disabled", width=10)
        text.tag_add("center", "1.0", "end")

        text.grid(row=self.number_of_rows + 1,
                  column=self.number_of_columns - 4)

    def flash_row_or_col(self, rc_number):
        num_rows = self.number_of_rows
        num_cols = self.number_of_columns

        if rc_number < num_rows:
            for c in range(0, num_cols):  #flash row
                cur_idx = rc_number * num_cols + c
                self.change_image(self.image_labels[cur_idx], self.flash_image)
        else:
            current_column = rc_number - num_rows
            for r in range(0, num_rows):  #flash column
                cur_idx = current_column + r * num_cols
                self.change_image(self.image_labels[cur_idx], self.flash_image)

        self.master.after(self.flash_duration, self.unflash_row_or_col,
                          rc_number)

    def unflash_row_or_col(self, rc_number):
        num_rows = self.number_of_rows
        num_cols = self.number_of_columns
        if rc_number < num_rows:
            for c in range(0, num_cols):  #flash row
                cur_idx = rc_number * num_cols + c
                self.change_image(self.image_labels[cur_idx],
                                  self.usable_images[cur_idx])
        else:
            current_column = rc_number - num_rows
            for r in range(0, num_rows):  #flash column
                cur_idx = current_column + r * num_cols
                self.change_image(self.image_labels[cur_idx],
                                  self.usable_images[cur_idx])

    def flash_single_element(self, element_no):
        self.change_image(self.image_labels[element_no], self.flash_image)
        self.master.after(self.flash_duration, self.unflash_single_element,
                          element_no)

    def unflash_single_element(self, element_no):
        self.change_image(self.image_labels[element_no],
                          self.usable_images[element_no])
예제 #26
0
 def _create_header_button(self, text) -> Button:
     button = Button(self.table, text=text)
     button.configure(command=lambda index=len(
         self.__headers): self.sort_data(index))
     return button
예제 #27
0
class GUI(Tk):
    def __init__(self, master=None):
        Tk.__init__(self, master)
        self.b1 = Button(self, text="Start A*", command=self.start_alg)
        self.b1.grid(row=0, column=0)
        self.b1.configure(state="disabled")
        self.load_thread = threading.Thread(target=self.initImage)
        self.load_thread.start()

    def initImage(self):
        """
        Loads the image from the file, using the appropriate function.
        """
        if LAB_PATH is None:
            print("Generating labyrinth...")
            self.labyrinth = maze(*MAZE_SIZE, size=SIZE)
            self.im = lab_to_im(self.labyrinth)
        else:
            print("Reading labyrinth from {}...".format(LAB_PATH))
            if LAB_PATH.endswith("map"):
                load_fun = load_from_map_file
            else:
                load_fun = load_from_img
            self.labyrinth, self.im = load_fun(LAB_PATH)

        self.pix = self.im.load()
        print("Read!")
        self.b1.configure(state="normal")

    def setImage(self, im):
        im2 = im.resize(self.newsize, Image.NEAREST)
        self.image = ImageTk.PhotoImage(im2)
        self.panel.configure(image=self.image)

    def gui_callback(self, queue, path=None):
        """
        Draws the A* queue, and eventually the path computed.
        """
        path = path or []
        queue = queue or []

        for node in queue:
            x, y = [int(x) for x in node[1]]  # convert numpy.int32 to int
            h = self.heur_goal((x, y))
            v = h / self.max_heur
            r = int(v * 255)
            g = int((1 - v) * 255)
            self.pix[x, y] = r, g, 0
        for node in path:
            x, y = node
            self.pix[x, y] = 0, 0, 255
        start = self.labyrinth.start
        self.pix[start[0], start[1]] = 255, 0, 0
        self.setImage(self.im)

    def start_alg(self):
        children = list(self.children.values())
        for child in children:
            child.destroy()  # removes the button
        self.panel = Label(self)
        self.panel.pack()
        self.newsize = tuple([int(i * SCALE) for i in self.im.size])
        self.geometry("{}x{}+200+200".format(*self.newsize))
        self.update()
        threading.Thread(target=self.compute).start()  # start the computation

    def compute(self):
        if not self.labyrinth.start or not self.labyrinth.goal:
            raise ValueError("Start or goal not found")

        self.children_gen = NeighborsGeneratorJPS(self.labyrinth)
        self.heur = heur_diag
        self.heur_goal = self.heur(self.labyrinth.goal, self.labyrinth.start)
        self.max_heur = int(self.heur_goal(self.labyrinth.start))

        print("Start detected:\t{}".format(self.labyrinth.start))
        print("Goal detected:\t{}".format(self.labyrinth.goal))
        print("Starting search...")

        eq_to_goal = lambda p: np.array_equal(p, self.labyrinth.goal)
        c_time = time.perf_counter()
        path, *_, info = a_star(self.labyrinth.start,
                                eq_to_goal,
                                self.heur_goal, self.children_gen,
                                self.gui_callback)
        c_time = (time.perf_counter() - c_time)

        if path:
            path, cost = self.reconstruct_path(path)
        else:
            cost = float("inf")

        # print(path)

        print("Search ended")
        print("Time:", round(c_time, 2), "s")
        print("Nodes searched:", info.nodes)
        print("Maximum list size:", info.maxl)
        print("Path cost:", cost)

        if path is None:
            print("Path not found")
        else:
            print("Found path of", len(path), "nodes")
            print("Path generation completed")
            print("*" * 100)
            if PATH_DELAY_TIME:
                for i in range(len(path)):
                    self.gui_callback(None, path[:i])
                    time.sleep(PATH_DELAY_TIME)
            else:
                self.gui_callback(None, path)

    def reconstruct_path(self, path):
        """
        Reconstructs the complete path inserting nodes which
        were "jumped" by the generating function. This is possible
        because JPS generates jump only in straight or diagonal lines.

        For example:
        [(0,0),(4,4)] -> [(0,0),(1,1),(2,2),(3,3),(4,4)].
        """

        def pairwise(iterable):
            a, b = it.tee(iterable)
            next(b, None)
            return zip(a, b)

        cost = 0
        expanded_path = [path[0]]
        sqrt_2 = 2 ** 0.5
        for cur_node, next_node in pairwise(path):
            cur_node = np.array(cur_node)
            next_node = np.array(next_node)
            direction = normalize(next_node - cur_node)
            cost_unit = sqrt_2 if np.all(direction) else 1
            while not np.array_equal(cur_node, next_node):
                cur_node = tuple(int(x) for x in cur_node + direction)
                expanded_path.append(cur_node)
                cost += cost_unit
        return expanded_path, cost
예제 #28
0
class MainWindow(mp.Process):
    """Defines the main control window and all its control logic.

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

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

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

        self.master = None

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

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

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

        self.master = Tk()

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

        self.connected = False

        self.print_from_queue()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.update_channel_select()
        self.update_recording_time()

        self.start_recording_e.set()

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

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

        minutes = number_of_seconds // 60
        remaining_seconds = number_of_seconds % 60

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

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

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

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

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

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

        widget.configure(state='normal')

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

        widget['values'] = stream_list

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

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

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

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

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

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

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

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

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

        self.connected_e.wait()

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

    def run(self):
        self.build_main_window()
        self.master.mainloop()
예제 #29
0
class Update(ThemedTk):
    def __init__(self):
        ThemedTk.__init__(self, theme='black')
        self.title('Обновление F_Reference_H')
        self.geometry('500x140')
        x = (self.winfo_screenwidth() - self.winfo_reqwidth()) / 2
        y = (self.winfo_screenheight() - self.winfo_reqheight()) / 2
        self.wm_geometry("+%d+%d" % (x - 150, y))
        self.resizable(width=False, height=False)
        self.iconphoto(True, PhotoImage(file='settings/ico/ico_main.png'))
        flow_hack_png = Image.open(f'settings/ico/mini_flowhack.png')
        flow_hack_png = ImageTk.PhotoImage(flow_hack_png)
        self.frame = Frame(self)
        self.frame.place(relwidth=1, relheight=1)

        flow_1 = Label(self.frame, image=flow_hack_png, cursor='heart')
        flow_1.bind('<Button-1>', lambda no_matter: webopen(VK))
        flow_1.place(relx=.09, rely=.085, anchor='center')
        flow_2 = Label(self.frame, image=flow_hack_png, cursor='heart')
        flow_2.bind('<Button-1>', lambda no_matter: webopen(VK))
        flow_2.place(relx=.91, rely=.085, anchor='center')
        self.lbl_done = Label(self.frame,
                              text='ОБНОВЛЕНИЕ',
                              font=('Times New Roman', 12, 'bold italic'))
        self.lbl_done.place(relx=.5, rely=.1, anchor='c')
        self.lable_second = Label(
            self.frame,
            text='Нам понадобится интернет!\nМы всё сделаем сами, это не '
            'займё много времени!',
            font=('Times New Roman', 10, 'bold italic'),
            justify='center')
        self.lable_second.place(relx=.5, rely=.35, anchor='c')
        self.btn_update = Button(self.frame,
                                 text='Обновить',
                                 cursor='hand1',
                                 command=self.updater_window)
        self.btn_update.place(relx=.5, rely=.65, anchor='c')
        self.license = Label(
            self.frame,
            cursor='hand1',
            text='Нажимая "Обновить" вы принимаете лицензионное соглашение',
            font=('Times New Roman', 10, 'bold italic'),
            foreground='black')
        self.license.bind('<Button-1>', lambda no_matter: webopen(SAIT))
        self.license.place(relx=.5, rely=.92, anchor='c')

        self.mainloop()

    def updater_window(self):
        try:
            if name == 'nt':
                with open(NAME_FILE, "wb") as f:
                    response = requests.get(URL_FILE, stream=True)
                    total_length = int(response.headers.get('content-length'))
                    self.btn_update.configure(
                        text=f'Размер: {total_length / 1024 / 1024:0.2f} Mb')
                    self.btn_update.update()

                    if total_length is None:
                        f.write(response.content)
                    else:
                        dl = 0
                        for data in response.iter_content(chunk_size=4096):
                            dl += len(data)
                            f.write(data)
                            done = int(50 * dl / total_length)
                            self.license.configure(
                                text=f'\r{"=" * done}{" " * (50 - done)}')
                            self.license.update()
                            sys.stdout.flush()
                        self.lbl_done.configure(text='Готово!',
                                                foreground='#DA9958')
                        self.btn_update.configure(text='Открыть программу',
                                                  command=open_app)
            elif name == 'posix':
                showerror('Error',
                          'К сожалению на Linux пока нельзя обновиться')
                self.btn_update.configure(text='Закрыть', command=open_app)
        except requests.exceptions.ConnectionError:
            showerror(
                'Error', 'Произошла ошибка!\n\nПохоже, что у вас отсутствует '
                'подключение к интернету!\n\nЕсли не получается решить '
                'проблему, то напишите мне в блоке "Обратная связь" ')
예제 #30
0
class AppRow(MagicSession, Frame):
    """
    Row for each app in mixer.
    handles refreshing the gui if session is changed external.
    handles user input and changing session volume/mute.
    """
    def __init__(self, root_frame_instance):
        super().__init__(volume_callback=self.update_volume,
                         mute_callback=self.update_mute,
                         state_callback=self.update_state)

        self.root_frame_instance = root_frame_instance

        # ______________ DISPLAY NAME ______________
        self.app_name = self.magic_root_session.app_exec

        print(f":: new session: {self.app_name}")
        # ______________ CREATE FRAME ______________
        # super(MagicSession, self).__init__(root_frame_instance)
        Frame.__init__(self, root_frame_instance)

        # _______________ NAME LABEL _______________
        self.name_label = Label(self,
                                text=self.app_name,
                                font=("Consolas", 12, "italic"))

        # _____________ VOLUME SLIDER _____________
        self.volume_slider_state = DoubleVar()

        self.volume_slider = Scale(self,
                                   variable=self.volume_slider_state,
                                   command=self._slide_volume,
                                   from_=0,
                                   to=100,
                                   takefocus=False,
                                   orient=HORIZONTAL)

        # set initial:
        self.volume_slider_state.set(self.volume * 100)

        # ______________ MUTE BUTTON ______________

        self.mute_button_state = StringVar()

        self.mute_button = Button(self,
                                  style="",
                                  textvariable=self.mute_button_state,
                                  command=self._toogle_mute,
                                  takefocus=False)

        # set initial:
        self.update_mute(self.mute)

        # _____________ SESSION STATUS _____________
        self.status_line = Frame(self, style="", width=6)

        # set initial:
        self.update_state(self.state)

        # ________________ SEPARATE ________________
        self.separate = Separator(self, orient=HORIZONTAL)

        # ____________ ARRANGE ELEMENTS ____________
        # set column[1] to take the most space
        # and make all others as small as possible:
        self.columnconfigure(1, weight=1)

        # grid
        self.name_label.grid(row=0, column=0, columnspan=2, sticky="EW")
        self.mute_button.grid(row=1, column=0)
        self.volume_slider.grid(row=1, column=1, sticky="EW", pady=10, padx=20)
        self.separate.grid(row=2, column=0, columnspan=3, sticky="EW", pady=10)
        self.status_line.grid(row=0, rowspan=2, column=2, sticky="NS")

        # _____________ DISPLAY FRAME _____________
        self.pack(pady=0, padx=15, fill='x')

    def update_volume(self, new_volume):
        """
        when volume is changed externally
        (see callback -> AudioSessionEvents -> OnSimpleVolumeChanged )
        """
        # compare if the windows callback is because we set the slider:
        # if so drop update since we made the change
        # and all is already up to date - this will prevent lagg
        print(f"{self.app_name} volume: {new_volume}")
        self.volume_slider_state.set(new_volume * 100)

    def update_mute(self, new_mute):
        """ when mute state is changed by user or through other app """
        if new_mute:
            icon = "🔈"
            self.mute_button.configure(style="Muted.TButton")
        else:
            icon = "🔊"
            self.mute_button.configure(style="Unmuted.TButton")

        # .set is a method of tkinters variables
        # it will change the button text
        print(f"{self.app_name} mute: {icon}")
        self.mute_button_state.set(icon)

    def update_state(self, new_state):
        """
        when status changed
        (see callback -> AudioSessionEvents -> OnStateChanged)
        """
        print(f"{self.app_name} state: {new_state}")
        if new_state == AudioSessionState.Inactive:
            # AudioSessionStateInactive
            self.status_line.configure(style="Inactive.TFrame")

        elif new_state == AudioSessionState.Active:
            # AudioSessionStateActive
            self.status_line.configure(style="Active.TFrame")

        elif new_state == AudioSessionState.Expired:
            # AudioSessionStateExpired
            self.status_line.configure(style="TFrame")
            """when session expires"""
            print(f":: closed session: {self.app_name}")
            self.destroy()

    def _slide_volume(self, value):
        """ when slider moved by user """
        new_volume = float(value) / 100
        # check if new user value really is new: (ttk bug)
        if self.volume != new_volume:
            # since self.volume is true data through windows
            # it will generally differ, but 1.0 == 1
            print(f"with pycaw: {self.app_name} volume: {new_volume}")
            self.volume = new_volume

    def _toogle_mute(self):
        """ when mute button pressed """
        new_mute = self.toggle_mute()

        self.update_mute(new_mute)
예제 #31
0
class Register(Frame):
    def __init__(self, master):
        super().__init__(master=master)
        self.layout_components()
        # Setup Callbacks
        self.show_sign_in: Callable = None
        self.sign_in: Callable = None
        self.search_email: Callable = None
        self.search_username: Callable = None
        self.search_password: Callable = None
        self.register: Callable = None

        self.username_valid: bool = False
        self.email_valid: bool = False
        self.password_valid: bool = False
        self.passcnfm_valid: bool = False
        # Refocus to Email Entry
        self.email_Entry.focus()

    def layout_components(self):
        self.pack(fill=tk.BOTH, expand=False, padx=PADX, pady=PADY)
        error_font = font.Font(family="Ariel", size=8)

        # Variables
        self.username = tk.StringVar()
        self.username.set("")

        self.email = tk.StringVar()
        self.email.set("")

        self.password = tk.StringVar()
        self.password.set("")

        self.passcnfm = tk.StringVar()
        self.passcnfm.set("")

        # Email Row
        email_Frame = Frame(self)
        email_Frame.pack(fill=tk.X)
        email_Label = Label(email_Frame, text="Email:", width=LABEL_WIDTH)
        email_Label.pack(side=tk.LEFT, padx=PADX, pady=PADY)
        self.email_Entry = Entry(email_Frame,
                                 width=ENTRY_WIDTH,
                                 textvariable=self.email)
        self.email_Entry.pack(fill=tk.X, padx=PADX, pady=PADY, expand=True)
        self.email_Entry.bind("<FocusOut>", self._validate_email)
        # Email Error Row
        email_errFrame = Frame(self)
        email_errFrame.pack(fill=tk.X)
        self.email_errLabel = Label(email_errFrame,
                                    text="",
                                    foreground="red",
                                    font=error_font)
        self.email_errLabel.pack(side=tk.LEFT,
                                 anchor="center",
                                 expand=True,
                                 padx=PADX,
                                 pady=PADY)

        # Username Row
        user_Frame = Frame(self)
        user_Frame.pack(fill=tk.X)
        user_Label = Label(user_Frame, text="Username:"******"<FocusOut>", self._validate_username)

        # Username Error Row
        user_errFrame = Frame(self)
        user_errFrame.pack(fill=tk.X)
        self.user_errLabel = Label(user_errFrame,
                                   text="",
                                   foreground="red",
                                   font=error_font)
        self.user_errLabel.pack(side=tk.LEFT,
                                anchor="center",
                                expand=True,
                                padx=PADX,
                                pady=PADY)

        # Original Password Row
        pass_Frame = Frame(self)
        pass_Frame.pack(fill=tk.X)
        pass_Label = Label(pass_Frame, text="Password:"******"*")
        self.pass_Entry.pack(fill=tk.X, padx=PADX, pady=PADY, expand=True)
        self.pass_Entry.bind("<FocusOut>", self._validate_password)
        # Confirming Password Row
        pass_cnfmFrame = Frame(self)
        pass_cnfmFrame.pack(fill=tk.X)
        pass_cnfmLabel = Label(pass_cnfmFrame,
                               text="Confirm:",
                               width=LABEL_WIDTH)
        pass_cnfmLabel.pack(side=tk.LEFT, padx=PADX, pady=PADY)
        self.pass_cnfmEntry = Entry(pass_cnfmFrame,
                                    width=ENTRY_WIDTH,
                                    textvariable=self.passcnfm,
                                    show="*")
        self.pass_cnfmEntry.pack(fill=tk.X, padx=PADX, pady=PADY, expand=True)
        self.pass_cnfmEntry.bind("<FocusOut>", self._validate_password)
        # Password Error Row
        pass_errFrame = Frame(self)
        pass_errFrame.pack(fill=tk.X)
        self.pass_errLabel = Label(pass_errFrame,
                                   text="",
                                   foreground="red",
                                   font=error_font)
        self.pass_errLabel.pack(side=tk.LEFT,
                                anchor="center",
                                expand=True,
                                padx=PADX,
                                pady=PADY)

        # Button Row
        button_Frame = Frame(self)
        button_Frame.pack(fill=tk.X)
        # Cancel Button
        cncl_Button = Button(button_Frame, text="Cancel", command=self.cancel)
        cncl_Button.pack(side=tk.RIGHT, padx=PADX, pady=PADY, expand=False)
        # Register Button
        self.register_Button = Button(button_Frame,
                                      text="Register",
                                      state="disabled",
                                      command=self._register)
        self.register_Button.pack(side=tk.RIGHT,
                                  padx=PADX,
                                  pady=PADY,
                                  expand=False)
        # View Password Button
        self.view_pass_Button = Button(button_Frame,
                                       text="View Password",
                                       command=self.view_password)
        self.view_pass_Button.pack(side=tk.LEFT, padx=PADX, pady=PADY)

        # Go Back Button Row
        gbck_Frame = Frame(self)
        gbck_Frame.pack(fill=tk.X)
        gbck_Label = Label(gbck_Frame, text="Have an Account? Go Ahead and ")
        gbck_Label.pack(side=tk.LEFT, padx=PADX, pady=PADY, expand=False)
        gbck_Button = Button(gbck_Frame,
                             text="Sign In",
                             command=self._show_sign_in)
        gbck_Button.pack(side=tk.RIGHT, padx=PADX, pady=PADY, expand=False)

    def cancel(self):
        self.email.set("")
        self.username.set("")
        self.password.set("")
        self.passcnfm.set("")
        self.email_Entry.focus()
        self.email_errLabel.configure(text="")
        self.user_errLabel.configure(text="")
        self.pass_errLabel.configure(text="")

    def view_password(self):
        self.pass_Entry.configure(show="")
        self.pass_cnfmEntry.configure(show="")
        self.view_pass_Button.configure(text="Hide Password",
                                        command=self.hide_password)

    def hide_password(self):
        self.pass_Entry.configure(show="*")
        self.pass_cnfmEntry.configure(show="*")
        self.view_pass_Button.configure(text="View Passwrod",
                                        command=self.view_password)

    def _show_sign_in(self):
        if self.show_sign_in is not None:
            self.show_sign_in()
            self.cancel()

    def _register(self):
        if self.register is not None:
            self.register()

    def _validate_email(self, event):
        email = self.email.get()
        if len(email) == 0:
            self.email_errLabel.configure(text="Email Must not be Empty...")
            self.email_valid = False
        elif not validate_email(email):
            self.email_errLabel.configure(text="Email Format Invalide...")
            self.email_valid = False
        elif self.search_email is not None and not self.search_email(email):
            self.email_errLabel.configure(text="Email Already Registered...")
            self.email_valid = False
        else:
            self.email_errLabel.configure(text="")
            self.email_valid = True
        self.enable_register()

    def _validate_username(self, event):
        username = self.username.get()
        if len(username) == 0:
            self.user_errLabel.configure(text="Username Must not be Empty...")
            self.username_valid = False
        elif self.search_username is not None and not self.search_username(
                username):
            self.username_valid = False
        else:
            self.user_errLabel.configure(text="")
            self.username_valid = True
        self.enable_register()

    def _validate_password(self, event):
        password = self.password.get()
        passcnfm = self.passcnfm.get()
        if len(password) == 0:
            self.pass_errLabel.configure(text="Password Must Not be Empty...")
            self.password_valid = False
        elif len(password) < 8:
            self.pass_errLabel.configure(
                text="Password Must be Longer than 8 Characters...")
            self.password_valid = False
        elif password != passcnfm:
            self.pass_errLabel.configure(text="Password Must Match...   ")
            self.passcnfm_valid = False
        elif self.search_password is not None and not self.search_password(
                password):
            self.pass_errLabel.configure(text="")
            self.password_valid = False
        else:
            self.pass_errLabel.configure(text="")
            self.passcnfm_valid = True
            self.password_valid = True
        self.enable_register()

    def enable_register(self):
        if (self.email_valid and self.username_valid and self.password_valid
                and self.passcnfm_valid):
            self.register_Button.configure(state="normal")

    def failed_register(self):
        self.email.set("")
        self.username.set("")
        self.pass_errLabel.configure(text="Email or Username Already used")
        self.email_Entry.focus()
예제 #32
0
class Timer(Tk):
    """ Chronométre de temps de travail pour plus d'efficacité """
    def __init__(self):
        Tk.__init__(self, className="WorkHourGlass")
        self.on = False  # is the timer on?

        if not CONFIG.options("Tasks"):
            CONFIG.set("Tasks", _("Work"), CMAP[0])
        # colors
        self.background = {
            _("Work"): CONFIG.get("Work", "bg"),
            _("Break"): CONFIG.get("Break", "bg"),
            _("Rest"): CONFIG.get("Rest", "bg")
        }
        self.foreground = {
            _("Work"): CONFIG.get("Work", "fg"),
            _("Break"): CONFIG.get("Break", "fg"),
            _("Rest"): CONFIG.get("Rest", "fg")
        }
        # window configuration
        if PL[0] == "w":
            self.iconbitmap(ICON_WIN, default=ICON_WIN)
        else:
            self.icon = PhotoImage(master=self, file=ICON)
            self.iconphoto(True, self.icon)

        self.title("WorkHourGlass")
        self.protocol("WM_DELETE_WINDOW", self.exit)
        self.rowconfigure(1, weight=1)
        self.columnconfigure(0, weight=1)
        self.columnconfigure(1, weight=1)
        self.minsize(181, 190)
        self.geometry("200x190+%i+%i" %
                      ((self.winfo_screenwidth() - 200) // 2,
                       (self.winfo_screenheight() - 190) // 2))
        self.configure(background=self.background[_("Work")])

        # style
        self.style = Style(self)
        self.style.theme_use(STYLE)
        self.style.configure('fen.TLabel',
                             foreground=self.foreground[_("Work")],
                             background=self.background[_("Work")])

        # nombre de séquence de travail effectuées d'affilée (pour
        # faire des pauses plus longues tous les 4 cycles)
        self.nb_cycles = 0
        self.pomodori = IntVar(self, 0)

        # images
        self.im_go = PhotoImage(master=self, file=GO)
        self.im_stop = PhotoImage(master=self, file=STOP)
        self.im_plus = PhotoImage(master=self, file=PLUS)
        self.im_moins = PhotoImage(master=self, file=MOINS)
        self.im_params = PhotoImage(master=self, file=PARAMS)
        self.im_tomate = PhotoImage(master=self, file=TOMATE)
        self.im_graph = PhotoImage(master=self, file=GRAPH)

        # tasks list
        tasks_frame = Frame(self)
        tasks_frame.grid(row=3, column=0, columnspan=3, sticky="wnse")
        tasks = [t.capitalize() for t in CONFIG.options("Tasks")]
        self.task = StringVar(self, tasks[0])
        self.menu_tasks = Menu(tasks_frame, tearoff=False)
        for task in tasks:
            self.menu_tasks.add_radiobutton(label=task,
                                            value=task,
                                            variable=self.task)
        self.menu_tasks.add_command(label=_("New task"),
                                    image=self.im_plus,
                                    compound="left",
                                    command=self.add_task)
        self.menu_tasks.add_command(label=_("Remove task"),
                                    image=self.im_moins,
                                    compound="left",
                                    command=self.del_task)
        self.menu_tasks.add_command(label=_("Statistics"),
                                    image=self.im_graph,
                                    compound="left",
                                    command=self.display_stats)
        self.choose_task = Menubutton(tasks_frame,
                                      textvariable=self.task,
                                      menu=self.menu_tasks)
        Label(tasks_frame,
              text=_("Task: "),
              font="CMU\ Sans\ Serif\ Demi\ Condensed 12",
              width=6,
              anchor="e").pack(side="left")
        self.choose_task.pack(side="right", fill="x")

        # display
        self.tps = [CONFIG.getint("Work", "time"), 0]  # time: min, sec
        self.activite = StringVar(self, _("Work"))
        self.titre = Label(self,
                           textvariable=self.activite,
                           font='CMU\ Sans\ Serif\ Demi\ Condensed 14',
                           style='fen.TLabel',
                           anchor="center")
        self.titre.grid(row=0, column=0, columnspan=2, sticky="we")
        self.temps = Label(
            self,
            text="{0:02}:{1:02}".format(self.tps[0], self.tps[1]),
            font="%s %i" % (CONFIG.get(
                "General", "font"), CONFIG.getint("General", "fontsize")),
            style='fen.TLabel',
            anchor="center")
        self.temps.grid(row=1,
                        column=0,
                        columnspan=2,
                        sticky="nswe",
                        pady=(0, 10))

        self.aff_pomodori = Label(self,
                                  textvariable=self.pomodori,
                                  image=self.im_tomate,
                                  compound="left",
                                  style='fen.TLabel',
                                  font='CMU\ Sans\ Serif\ Demi\ Condensed 14')
        self.aff_pomodori.grid(row=2, columnspan=2, sticky="e", padx=20)

        # buttons
        self.b_go = Button(self, image=self.im_go, command=self.go)
        self.b_go.grid(row=4, column=0, sticky="ew")
        self.b_params = Button(self, image=self.im_params, command=self.params)
        self.b_params.grid(row=4, column=1, sticky="ew")

        # --- make window sticky
        self.update_idletasks()
        e = EWMH()
        try:
            for w in e.getClientList():
                if w.get_wm_name() == self.title():
                    e.setWmState(w, 1, '_NET_WM_STATE_STICKY')
            e.display.flush()
        except ewmh.display.error.BadWindow:
            pass

    def set_config(self):
        self.background = {
            _("Work"): CONFIG.get("Work", "bg"),
            _("Break"): CONFIG.get("Break", "bg"),
            _("Rest"): CONFIG.get("Rest", "bg")
        }
        self.foreground = {
            _("Work"): CONFIG.get("Work", "fg"),
            _("Break"): CONFIG.get("Break", "fg"),
            _("Rest"): CONFIG.get("Rest", "fg")
        }
        act = self.activite.get()
        self.configure(background=self.background[act])
        self.style.configure('fen.TLabel',
                             foreground=self.foreground[act],
                             background=self.background[act])
        self.temps.configure(font="%s %i" %
                             (CONFIG.get("General", "font"),
                              CONFIG.getint("General", "fontsize")))

    def add_task(self):
        def ajoute(event=None):
            task = nom.get()
            if task and not CONFIG.has_option("Tasks", task):
                index = len(CONFIG.options("Tasks"))
                self.menu_tasks.insert_radiobutton(index,
                                                   label=task,
                                                   value=task,
                                                   variable=self.task)
                CONFIG.set("Tasks", task, CMAP[index % len(CMAP)])
                top.destroy()
                with open(PATH_CONFIG, "w") as file:
                    CONFIG.write(file)
                self.menu_tasks.invoke(index)
            else:
                nom.delete(0, "end")

        top = Toplevel(self)
        top.title(_("New task"))
        top.transient(self)
        top.grab_set()
        nom = Entry(top, width=20)
        nom.grid(row=0, columnspan=2, sticky="ew")
        nom.focus_set()
        nom.bind('<Key-Return>', ajoute)
        Button(top, text=_("Cancel"), command=top.destroy).grid(row=1,
                                                                column=0)
        Button(top, text=_("Ok"), command=ajoute).grid(row=1, column=1)
        top.wait_window(top)

    def del_task(self):
        """ Suppression de tâches """
        def supprime():
            rep = askyesno(_("Confirmation"),
                           _("Are you sure you want to delete these tasks?"))
            if rep:
                for i in range(len(boutons) - 1, -1, -1):
                    # l'ordre de parcours permet de supprimer les derniers
                    # éléments en premier afin de ne pas modifier les index des
                    # autres éléments lors des suppressions
                    task = tasks[i]
                    if "selected" in boutons[i].state():
                        # suppression de la tâche de la liste des tâches
                        CONFIG.remove_option("Tasks", task)
                        tasks.remove(task)
                        # suppression de l'entrée correspondante dans le menu
                        self.menu_tasks.delete(i)
                        if not tasks:
                            CONFIG.set("Tasks", _("Work"), CMAP[0])
                            tasks.append(_("Work"))
                            self.menu_tasks.insert_radiobutton(
                                0,
                                label=_("Work"),
                                value=_("Work"),
                                variable=self.task)
                        if self.task.get() == task:
                            self.task.set(tasks[0])
                        # suppression des stats associées
                        chemin = PATH_STATS + "_" + "_".join(task.split(" "))
                        if os.path.exists(chemin):
                            os.remove(chemin)

                top.destroy()
                with open(PATH_CONFIG, "w") as file:
                    CONFIG.write(file)
            else:
                top.destroy()

        tasks = [t.capitalize() for t in CONFIG.options("Tasks")]
        top = Toplevel(self)
        top.title(_("Remove task"))
        top.transient(self)
        top.grab_set()
        style = Style(top)
        style.theme_use(STYLE)
        boutons = []
        for i, task in enumerate(tasks):
            boutons.append(Checkbutton(top, text=task))
            boutons[-1].grid(row=i, columnspan=2, sticky="w")
        Button(top, text=_("Cancel"), command=top.destroy).grid(row=i + 1,
                                                                column=0)
        Button(top, text=_("Delete"), command=supprime).grid(row=i + 1,
                                                             column=1)

    def stats(self):
        """ Enregistre la durée de travail (en min) effectuée ce jour pour la
            tâche qui vient d'être interrompue.
            Seul les pomodori complets sont pris en compte. """
        # TODO: translate, correct date/time format
        pom = self.pomodori.get()
        if pom:
            # la tâche en cours a été travaillée, il faut enregistrer les stats
            date = dt.date.today()
            task = self.task.get()
            chemin = PATH_STATS + "_" + "_".join(task.split(" "))
            if not os.path.exists(chemin):
                with open(chemin, 'w') as fich:
                    fich.write(
                        "# tâche : %s\n# jour\tmois\tannée\ttemps de travail (min)\n"
                        % task)
            with open(chemin, 'r') as fich:
                stats = fich.readlines()
            if len(stats) > 2:
                last = stats[-1][:10], stats[-1][:-1].split("\t")[-1]
            else:
                last = "", 0
            if last[0] != date.strftime("%d\t%m\t%Y"):
                with open(chemin, 'a') as fich:
                    fich.write("%s\t%i\n" % (date.strftime("%d\t%m\t%Y"), pom *
                                             CONFIG.getint("Work", "time")))
            else:
                # un nombre a déjà été enregistré plus tôt dans la journée
                # il faut les additioner
                with open(chemin, 'w') as fich:
                    fich.writelines(stats[:-1])
                    fich.write(
                        "%s\t%i\n" %
                        (date.strftime("%d\t%m\t%Y"),
                         pom * CONFIG.getint("Work", "time") + int(last[1])))

    def display_stats(self):
        """ affiche les statistiques """
        plt.figure("Statistiques")
        tasks = [t.capitalize() for t in CONFIG.options("Tasks")]
        coul = [CONFIG.get("Tasks", task) for task in tasks]
        stats_x = []
        stats_y = []

        demain = dt.date.today().toordinal() + 1
        min_x = demain

        # récupération des données
        no_data = True
        for i, task in enumerate(tasks):
            chemin = PATH_STATS + "_" + "_".join(task.split(" "))
            if os.path.exists(chemin):
                no_data = False
                stat = loadtxt(chemin, dtype=int)
                if len(stat.shape) == 1:
                    stat = stat.reshape(1, 4)
                x = [
                    dt.date(an, mois, jour).toordinal()
                    for jour, mois, an in stat[:, :3]
                ]
                y = stat[:, -1] / 60  # temps de travail
                min_x = min(x[0], min_x)
                stats_x.append(x)
                stats_y.append(y)
            else:
                # la taĉhe n'a jamais été travaillée
                stats_x.append([demain - 1])
                stats_y.append(array([0]))

        # plots
        xx = arange(min_x, demain, dtype=float)
        yy0 = zeros_like(xx)  # pour empiler les stats
        if not no_data:
            for (i, task), x, y in zip(enumerate(tasks), stats_x, stats_y):
                ax0 = plt.subplot(111)
                plt.ylabel(_("time (h)"))
                plt.xlabel(_("date"))
                yy = array([], dtype=int)
                # comble les trous par des 0
                # ainsi, les jours où une tâche n'a pas été travaillée correspondent
                # à des 0 sur le graph
                xxx = arange(min_x, x[0])
                yy = concatenate((yy, zeros_like(xxx, dtype=int)))
                for j in range(len(x) - 1):
                    xxx = arange(x[j], x[j + 1])
                    yy = concatenate((yy, [y[j]], zeros(len(xxx) - 1,
                                                        dtype=int)))
                xxx = arange(x[-1], demain)
                yy = concatenate((yy, [y[-1]], zeros(len(xxx) - 1, dtype=int)))
                plt.bar(xx - 0.4,
                        yy,
                        bottom=yy0,
                        width=0.8,
                        label=task,
                        color=coul[i])
                yy0 += yy
            axx = array(
                [int(xt) for xt in ax0.get_xticks() if xt.is_integer()])
            ax0.set_xticks(axx)
            ax0.set_xticklabels(
                [dt.date.fromordinal(i).strftime("%x") for i in axx])
            plt.gcf().autofmt_xdate()
            ax0.set_xlim(min_x - 0.5, demain - 0.5)
            lgd = plt.legend(fontsize=10)
            lgd.draggable()
            plt.subplots_adjust(top=0.95)
            max_y = yy0.max()
            ax0.set_ylim(0, max_y + 0.1 * max_y)
        plt.show()

    def go(self):
        if self.on:
            self.on = False
            if self.activite.get() == _("Work"):
                #                rep = askyesno(title=_("Confirmation"),
                #                               message=_("You should not interrupt your work if you want to be efficient. Do you still want to suspend the timer?"),
                #                               icon="warning")
                #            else:
                #                rep = True
                self.stop()
#            if rep:
#                self.b_go.configure(image=self.im_go)
#            else:
#                self.on = True
#                self.affiche()
        else:
            self.on = True
            self.choose_task.config(state="disabled")
            self.b_go.configure(image=self.im_stop)
            self.after(1000, self.affiche)

    def stop(self, confirmation=True):
        """ Arrête le décompte du temps et le réinitialise,
            demande une confirmation avant de le faire si confirmation=True """
        self.on = False
        if confirmation:
            rep = askyesno(
                title=_("Confirmation"),
                message=_(
                    "Are you sure you want to give up the current session?"))
        else:
            rep = True
        if rep:
            self.stats()
            self.pomodori.set(0)
            self.nb_cycles = 0
            self.b_go.configure(image=self.im_go)
            self.tps = [CONFIG.getint("Work", "time"), 0]
            self.temps.configure(
                text="{0:02}:{1:02}".format(self.tps[0], self.tps[1]))
            act = _("Work")
            self.activite.set(act)
            self.style.configure('fen.TLabel',
                                 background=self.background[act],
                                 foreground=self.foreground[act])
            self.configure(background=self.background[act])
            self.choose_task.config(state="normal")
        else:
            self.on = True
            self.affiche()

    def ting(self):
        """ joue le son marquant le changement de période """
        if not CONFIG.getboolean("Sound", "mute", fallback=False):
            if PL[0] == "w":
                Popen([
                    "powershell", "-c",
                    '(New-Object Media.SoundPlayer "%s").PlaySync();' %
                    (CONFIG.get("Sound", "beep"))
                ])
            else:
                Popen([
                    CONFIG.get("Sound", "player"),
                    CONFIG.get("Sound", "beep")
                ])

    def affiche(self):
        if self.on:
            self.tps[1] -= 1
            if self.tps[1] == 0:
                if self.tps[0] == 0:
                    self.ting()
                    if self.activite.get() == _("Work"):
                        self.pomodori.set(self.pomodori.get() + 1)
                        self.nb_cycles += 1
                        if self.nb_cycles % 4 == 0:
                            # pause longue
                            self.activite.set(_("Rest"))
                            self.tps = [CONFIG.getint("Rest", "time"), 0]
                        else:
                            # pause courte
                            self.activite.set(_("Break"))
                            self.tps = [CONFIG.getint("Break", "time"), 0]
                    else:
                        self.activite.set(_("Work"))
                        self.tps = [CONFIG.getint("Work", "time"), 0]
                    act = self.activite.get()
                    self.style.configure('fen.TLabel',
                                         background=self.background[act],
                                         foreground=self.foreground[act])
                    self.configure(background=self.background[act])
            elif self.tps[1] == -1:
                self.tps[0] -= 1
                self.tps[1] = 59
            self.temps.configure(
                text="{0:02}:{1:02}".format(self.tps[0], self.tps[1]))
            self.after(1000, self.affiche)

    def params(self):
        on = self.on
        self.on = False
        self.b_go.configure(image=self.im_go)
        p = Params(self)
        self.wait_window(p)
        if on:
            self.on = True
            self.choose_task.config(state="disabled")
            self.b_go.configure(image=self.im_stop)
            self.after(1000, self.affiche)

    def exit(self):
        self.stats()
        plt.close()
        self.destroy()
class DownloadPage(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        self.controller = controller
        self.outputState = False
        self.sem = threading.Semaphore()
        self.lock = 1

        frame1 = Frame(self, relief=RAISED, borderwidth=1)
        frame1.pack(fill=BOTH, expand=True)
        frame2 = Frame(self, relief=RAISED, borderwidth=1)
        frame2.pack(fill=BOTH, expand=True)
        frame3 = Frame(self, relief=RAISED, borderwidth=1)
        frame3.pack(fill=BOTH, expand=True)
        frame4 = Frame(self, relief=RAISED, borderwidth=1)
        frame4.pack(fill=BOTH, expand=True)

        self.outputBox = Text(self, height=15, width=40)
        self.outputBox.tag_config('error',
                                  background="yellow",
                                  foreground="red")
        self.vsb = Scrollbar(self,
                             orient="vertical",
                             command=self.outputBox.yview)
        self.outputBox.configure(yscrollcommand=self.vsb.set, state="disabled")
        self.vsb.pack(side="right", fill="y")
        self.outputBox.pack(side="left", fill="both", expand=True)

        self.oneBPName_entry = Entry(frame2, width=35)
        self.listBPPath_entry = Entry(frame3, width=35)

        self.oneBPNAme_label = Label(frame2, text="Blueprint Name:")
        self.listBPPath_label = Label(frame3, text="Blueprint List File Path:")

        self.allButton = Button(frame1,
                                text="Download All Blueprints",
                                width=30)
        self.allButton.configure(command=self.threader_all)
        self.oneButton = Button(frame2,
                                text="Download One Blueprint",
                                width=30)
        self.oneButton.configure(command=self.threader_one)
        self.listButton = Button(frame3,
                                 text="Download Blueprints From List",
                                 width=30)
        self.listButton.configure(command=self.threader_list)
        self.returnButton = Button(
            frame4,
            text="Go Back",
            command=lambda: self.controller.show_frame("MainPage"))

        self.oneBPNAme_label.pack(padx=5, pady=5)
        self.listBPPath_label.pack(padx=5, pady=5)

        self.oneBPName_entry.pack(padx=5, pady=5)
        self.listBPPath_entry.pack(padx=5, pady=5)

        self.allButton.pack(padx=5, pady=5)
        self.oneButton.pack(padx=5, pady=5)
        self.listButton.pack(padx=5, pady=5)
        self.returnButton.pack(padx=5, pady=10)

    # Starts thread for background process (also keeps lock so only one option may run at a time)
    def threader_all(self):
        if self.lock == 1:
            self.lock = 0
            thread = threading.Thread(target=self.download_all_blueprints)
            thread.daemon = True
            thread.start()
        return

    def threader_one(self):
        if self.lock == 1:
            self.lock = 0
            thread = threading.Thread(target=self.download_one_blueprint)
            thread.daemon = True
            thread.start()
        return

    def threader_list(self):
        if self.lock == 1:
            self.lock = 0
            thread = threading.Thread(target=self.download_blueprints)
            thread.daemon = True
            thread.start()
        return

    def download_all_blueprints(self):
        """
        Downloads all published blueprints from vRA
        Creates:
            output.json 		-JSON file with all published blueprints info (name, id, type, etc.)
                                *used to get all blueprint names to add to a vRA package

            blueprintLog.txt	-TEXT file with blueprints' names
                                *used when uploading blueprints to sort into proper service categories

            pkg.json            -JSON file with all packages in vRA (name, info, etc.)
                                *used to get the pkgId to download (with all blueprints contained)

            .zip of blueprints	-ZIP file with all downloaded blueprints
        """

        packageName = "vRAScriptPackage"
        packageID = ""
        dirPath = "\'" + os.path.dirname(os.path.realpath(__file__)) + "\\"
        getList = "cloudclient.bat vra content list --format JSON --export {}output.json\'".format(
            dirPath)
        makePackage = "cloudclient.bat vra package create --name {} --ids ".format(
            packageName)
        getPkgID = "cloudclient.bat vra package list --format JSON --export {}pkg.json\'".format(
            dirPath)
        blueprintLog = []

        cloud_client_run(self,
                         getList,
                         "Getting list of all blueprints in vRA",
                         newLog=True)

        show_output(self, "Saving list of all blueprints as \'output.json\'")
        data = json.load(open('output.json'))

        show_output(self, "Creating list of blueprints")
        start_output(self, "Creating list of blueprints to download")
        for blueprint in data:
            makePackage += blueprint['id'] + ","
            blueprintLog.append(blueprint['name'])
        close_output(self)

        show_output(self,
                    "Saving list of blueprints names as \'blueprintLog.txt\'")
        with open("blueprintLog.txt", 'w') as f:
            for BP in blueprintLog:
                f.write(BP + "\n")
            f.close()

        cloud_client_run(self, makePackage[:-1],
                         "Making package of useful blueprints from vRA")

        # vRA sometimes takes a second or two to create package and update list
        time.sleep(5)

        cloud_client_run(
            self, getPkgID,
            "Getting blueprint packages from vRA as \'pkg.json\'")

        # Gets package ID to download (Can't download with package name)
        start_output(self, "Sorting packages and retrieving one for download")
        data = json.load(open('pkg.json'))
        for pkg in data:
            if pkg['name'] == packageName:
                packageID = str(pkg['id'])
        close_output(self)

        dirPath = "\'" + os.path.dirname(os.path.realpath(__file__)) + "\'"
        BPDownload = "cloudclient.bat vra package export --path {} --pkgId {}".format(
            dirPath, packageID)
        deletePkg = "cloudclient.bat vra package delete --pkgId {}".format(
            packageID)

        cloud_client_run(self, BPDownload, "Downloading blueprints")

        cloud_client_run(self, deletePkg, "Deleting package in vRA")

        show_output(self, "\nDownload Complete")
        self.lock = 1
        return

    def download_one_blueprint(self):
        """
        Downloads single inputted blueprint
        Creates:
            output.json 		-JSON file with all published blueprints info (name, id, type, etc.)
                                *used to get all blueprint names to add to a vRA package

            blueprintLog.txt	-TEXT file with blueprints' names
                                *used when uploading blueprints to sort into proper service categories

            pkg.json            -JSON file with all packages in vRA (name, info, etc.)
                                *used to get the pkgId to download (with all blueprints contained)

            .zip of blueprints	-ZIP file with all downloaded blueprints
        """

        if len(self.oneBPName_entry.get()) == 0:
            self.lock = 1
            return

        dirPath = "\'" + os.path.dirname(os.path.realpath(__file__)) + "\\"
        getList = "cloudclient.bat vra content list --format JSON --export {}output.json\'".format(
            dirPath)
        BPID = None

        cloud_client_run(self,
                         getList,
                         "Getting list of all blueprints in vRA",
                         newLog=True)

        show_output(self, "Saving list of all blueprints as \'output.json\'")
        data = json.load(open('output.json'))

        start_output(self,
                     "Searching for {}".format(self.oneBPName_entry.get()))
        for BP in data:
            if BP['name'].lower() == self.oneBPName_entry.get().lower():
                BPID = BP['id']
        close_output(self)

        with open("blueprintLog.txt", 'w') as f:
            f.write(self.oneBPName_entry.get() + "\n")
            f.close()

        dirPath = "\'" + os.path.dirname(os.path.realpath(__file__)) + "\'"
        if BPID is not None:
            contentBP = "cloudclient.bat vra content export --path {} --id {}".format(
                dirPath, BPID)
            cloud_client_run(
                self, contentBP,
                "Downloading {}".format(self.oneBPName_entry.get()))
            show_output(self, "\nDownload Complete")
        else:
            show_output(self,
                        "\"{}\" not found in vRA\n".format(
                            self.oneBPName_entry.get()),
                        error=True)

        self.lock = 1
        return

    def download_blueprints(self):
        """
        Downloads blueprints from a text file
        Creates:
            output.json 		-JSON file with all published blueprints info (name, id, type, etc.)
                                *used to get all blueprint names to add to a vRA package

            blueprintLog.txt	-TEXT file with blueprints' names
                                *used when uploading blueprints to sort into proper service categories

            pkg.json            -JSON file with all packages in vRA (name, info, etc.)
                                *used to get the pkgId to download (with all blueprints contained)

            .zip of blueprints	-ZIP file with all downloaded blueprints
        """

        if len(self.listBPPath_entry.get()) == 0:
            self.lock = 1
            return

        packageName = "vRAScriptPackage"
        packageID = ""
        dirPath = "\'" + os.path.dirname(os.path.realpath(__file__)) + "\\"
        getList = "cloudclient.bat vra content list --format JSON --export {}output.json\'".format(
            dirPath)
        makePackage = "cloudclient.bat vra package create --name {} --ids ".format(
            packageName)
        getPkgID = "cloudclient.bat vra package list --format JSON --export {}pkg.json\'".format(
            dirPath)
        blueprintLog = []

        show_output(self, "Reading in list")
        try:
            with open(self.listBPPath_entry.get(), 'r') as f:
                blueprintsToGet = f.read().splitlines()
                f.close()
            blueprintsToGet = [element.lower() for element in blueprintsToGet]
        except IOError:
            show_output(self, "File not found", error=True)
            self.lock = 1
            return

        cloud_client_run(self,
                         getList,
                         "Getting list of all blueprints in vRA",
                         newLog=True)

        show_output(self, "Saving list of all blueprints as \'output.json\'")
        data = json.load(open('output.json'))

        start_output(self, "Creating package list of blueprints to download")
        for blueprint in data:
            if str(blueprint['name']).lower() in blueprintsToGet:
                blueprintsToGet.remove(str(blueprint['name']).lower())
                blueprintLog.append(blueprint['name'])
                makePackage += blueprint['id'] + ","
        close_output(self)

        cloud_client_run(self, makePackage[:-1],
                         "Making package of useful blueprints from vRA")

        show_output(
            self,
            "Saving list of useful blueprints names as \'blueprintLog.txt\'")
        with open("blueprintLog.txt", 'w') as f:
            for BP in blueprintLog:
                f.write(BP + "\n")
            f.close()

        # vRA sometimes takes a second or two to create package and update list
        time.sleep(5)

        cloud_client_run(
            self, getPkgID,
            "Getting blueprint packages from vRA as \'pkg.json\'")

        start_output(self, "Sorting packages and retrieving one for download")
        data = json.load(open('pkg.json'))
        for pkg in data:
            if pkg['name'] == packageName:
                packageID = str(pkg['id'])
        close_output(self)

        path = "\'" + os.path.dirname(os.path.realpath(__file__)) + "\'"
        BPDownload = "cloudclient.bat vra package export --path {} --pkgId {}".format(
            path, packageID)
        deletePkg = "cloudclient.bat vra package delete --pkgId {}".format(
            packageID)

        cloud_client_run(self, BPDownload, "Downloading blueprints")

        cloud_client_run(self, deletePkg, "Deleting package in vRA")

        if len(blueprintsToGet) != 0:
            show_output(
                self,
                "Following blueprints either misspelled or are not in vRA:")
            for missing in blueprintsToGet:
                show_output(self, "-{}".format(str(missing)), error=True)

        show_output(self, "\nDownload Complete")
        self.lock = 1
        return
예제 #34
0
class ErrorSurfaceFrame(LabelFrame):

	def __init__(self,parent):
		LabelFrame.__init__(self, parent, borderwidth=0)

		entryWidth = 7
		xPad1 = 30
		xPad2 = 5

		self.errorXLowerLimitL = Label(self)
		self.errorXLowerLimitE = CustomEntry(self,width=entryWidth,justify="right")
		self.errorXLowerLimitL.grid(row=0,column=0,padx=(10,xPad2),pady=5,sticky="W")
		self.errorXLowerLimitE.grid(row=0,column=1,padx=(xPad2,xPad1),pady=5)

		self.errorXUpperLimitL = Label(self)
		self.errorXUpperLimitE = CustomEntry(self,width=entryWidth,justify="right")
		self.errorXUpperLimitL.grid(row=1,column=0,padx=(10,xPad2),pady=5,sticky="W")
		self.errorXUpperLimitE.grid(row=1,column=1,padx=(xPad2,xPad1),pady=5)

		self.errorYLowerLimitL = Label(self)
		self.errorYLowerLimitE = CustomEntry(self,width=entryWidth,justify="right")
		self.errorYLowerLimitL.grid(row=0,column=2,padx=(xPad1,xPad2),pady=5,sticky="W")
		self.errorYLowerLimitE.grid(row=0,column=3,padx=(xPad2,xPad1),pady=5)

		self.errorYUpperLimitL = Label(self)
		self.errorYUpperLimitE = CustomEntry(self,width=entryWidth,justify="right")
		self.errorYUpperLimitL.grid(row=1,column=2,padx=(xPad1,xPad2),pady=5,sticky="W")
		self.errorYUpperLimitE.grid(row=1,column=3,padx=(xPad2,xPad1),pady=5)

		self.errorResolutionL = Label(self,text="Resolution: ")
		self.errorResolutionE = CustomEntry(self,width=entryWidth,justify="right")
		self.errorResolutionE.insert(0,ERROR_SURFACE_DEFAULT_RESOLUTION)
		self.errorResolutionL.grid(row=0,column=4,padx=(xPad1,xPad2),pady=5,sticky="W")
		self.errorResolutionE.grid(row=0,column=5,padx=(xPad2,xPad1),pady=5,sticky="E")

		self.errorSurfaceB = Button(self,text=" Calculate error surface ")
		self.errorSurfaceB.grid(row=1,column=4,columnspan=2,padx=(xPad1,xPad1),sticky="EW")
		self.errorSurfaceB.configure(state=tkinter.ACTIVE)

	def update(self,xSymbol,ySymbol,xLL,xUL,yLL,yUL):

		self.xSymbol = xSymbol
		self.ySymbol = ySymbol

		self.errorXLowerLimitL.configure(text="Lower limit ("+self.xSymbol+"): ")
		self.errorXLowerLimitE.insertNew(xLL)

		self.errorXUpperLimitL.configure(text="Upper limit ("+self.xSymbol+"): ")
		self.errorXUpperLimitE.insertNew(xUL)

		self.errorYLowerLimitL.configure(text="Lower limit ("+self.ySymbol+"): ")
		self.errorYLowerLimitE.insertNew(yLL)

		self.errorYUpperLimitL.configure(text="Upper limit ("+self.ySymbol+"): ")
		self.errorYUpperLimitE.insertNew(yUL)

	def getSurfaceParameters(self):

		xLowerLimit = helper_functions.validateValue(self.errorXLowerLimitE.get(),
									self.xSymbol + " lower limit must be a positive number",
									"float",
									lowerBound=0)
		xUpperLimit = helper_functions.validateValue(self.errorXUpperLimitE.get(),
									self.xSymbol + " upper limit must be greater than the lower limit",
									"float",
									strictLowerBound=xLowerLimit)
		yLowerLimit = helper_functions.validateValue(self.errorYLowerLimitE.get(),
									self.ySymbol + " lower limit must be a positive number",
									"float",
									lowerBound=0)
		yUpperLimit = helper_functions.validateValue(self.errorYUpperLimitE.get(),
									self.ySymbol + " upper limit must be greater than the lower limit",
									"float",
									strictLowerBound=yLowerLimit)
		resolution = helper_functions.validateValue(self.errorResolutionE.get(),
								   "Resolution must be " + str(ERROR_SURFACE_MIN_RESOLUTION) + " \u2264 x \u2264 " + str(ERROR_SURFACE_MAX_RESOLUTION),
								   "int",
								   lowerBound=ERROR_SURFACE_MIN_RESOLUTION,
								   upperBound=ERROR_SURFACE_MAX_RESOLUTION)

		return [xLowerLimit,xUpperLimit,yLowerLimit,yUpperLimit,resolution]

	def clear(self):
		self.errorXLowerLimitE.insertNew("")
		self.errorXUpperLimitE.insertNew("")
		self.errorYLowerLimitE.insertNew("")
		self.errorYUpperLimitE.insertNew("")
예제 #35
0
class Root(Frame):
    '''
    The root window
    '''
    def __init__(self,parent,csvpath="",rosterpath=""):
        '''
        Initilization of the window, assigning height
        centering the window, and starting the interface.
        '''
        self.queue       = Queue()
        self.parent      = parent
        self.interface   = GuiInterface()
        self.loadWindow  = None
        self.remember    = False
        self.initialized = False
        self.csvpathh    = csvpath
        self.rosterpathh = rosterpath
        self.outpathh    = ""
        self.teamsizeh   = ""

        self.startMainUI()

    def centerWindow(self,notself=None):
        '''
        This centers the window into place
        if notself is set, then it centers
        the notself window

        @param:
            notself - TKobject
        '''

        if notself != None: #notself is primarly for progressbar
            sw = self.parent.winfo_screenwidth()
            sh = self.parent.winfo_screenheight()
            x = (sw - self.w/2) / 2
            y = (sh - self.h/2) / 2
            notself.geometry('%dx%d+%d+%d' % (self.w/1.8,self.h/1.8, x,y))
        else:
            sw = self.parent.winfo_screenwidth()
            sh = self.parent.winfo_screenheight()
            x = (sw - self.w) / 2
            y = (sh - self.h) / 2
            self.parent.geometry('%dx%d+%d+%d' % (self.w,self.h, x ,y))

    def startWindow(self):
        '''
        This method starts/creates the window for
        the UI
        '''
        Frame.__init__(self, self.parent, background="white")
        self.style = Style()
        self.style.theme_use("default")
        self.pack(fill=BOTH, expand=1)
        if(not self.initialized):
            self.centerWindow()
        else:
            self.parent.geometry('%dx%d' % (self.w,self.h))
        self.initialized = True

    def resetWindow(self):
        '''
        Resets the window
        '''
        if(self.initialized):
            self.destroy()
        if(self.loadWindow != None):
            self.loadWindow.destroy()

        self.startWindow()

    def startMainUI(self):
        '''
        Starting the main UI takes some work, this creates the buttons
        labels and entrys. Also puts them into place, and adds
        function calls to the buttons
        '''
        #RESETING WINDOW
        self.h           = 290
        self.w           = 600
        self.resetWindow()
        self.parent.title("Input")

        #CREATING CSV FRAME
        csvFrame = Frame(self)
        csvFrame.pack(fill=X, side=TOP)

        csvLabel = Label(csvFrame, text="Path to csv:", background="white")
        csvLabel.pack(side=LEFT, padx=15, pady=10)

        self.csvEntry = Entry(csvFrame, width=30)
        self.csvEntry.insert(0,self.csvpathh)
        self.csvEntry.pack(side=LEFT, padx=35, pady=10)

        csvButton = Button(csvFrame, command=self.csvstartfilebrowser, text="Browse...")
        csvButton.pack(side=LEFT, padx=10, pady=10)
        #DONE CSV FRAME

        #CREATING ROSTER FRAME
        rosterFrame = Frame(self)
        rosterFrame.pack(fill=X, side=TOP)

        rosterLabel = Label(rosterFrame, text="Path to roster:", background="white")
        rosterLabel.pack(side=LEFT, padx=17, pady=10)

        self.rosterEntry = Entry(rosterFrame, width=30)
        self.rosterEntry.insert(0,self.rosterpathh)
        self.rosterEntry.pack(side=LEFT, padx=15, pady=10)

        rosterButton = Button(rosterFrame, command=self.rosterstartfilebrowser, text="Browse...")
        rosterButton.pack(side=LEFT, padx=28, pady=10)
        #DONE ROSTER FRAME

        #CREATING OUTPUT FRAME
        outputFrame = Frame(self)
        outputFrame.pack(fill=X, side=TOP)

        outputLabel = Label(outputFrame, text="Path to output:", background="white")
        outputLabel.pack(side=LEFT, padx=15, pady=10)

        self.outputEntry = Entry(outputFrame, width=30)
        self.outputEntry.insert(0,self.outpathh)
        self.outputEntry.pack(side=LEFT, padx=15, pady=10)

        outputButton = Button(outputFrame, command=self.outputstartfilebrowser, text="Browse...")
        outputButton.pack(side=LEFT, padx=28, pady=10)
        #DONE OUTPUT FRAME

        #CREATING TEAMSIZE FRAME
        teamsizeFrame= Frame(self)
        teamsizeFrame.pack(fill=X, side=TOP)

        teamsizeLabel = Label(teamsizeFrame, text="Team size:", background="white")
        teamsizeLabel.pack(side=LEFT, padx=15, pady=10)

        self.teamsizeEntry = Entry(teamsizeFrame, width=5)
        self.teamsizeEntry.insert(0,self.teamsizeh)
        self.teamsizeEntry.pack(side=LEFT, padx=43, pady=10)
        #DONE TEAMSIZE FRAME

        #CREATING BOTTOM BUTTONS
        frame = Frame(self, borderwidth=1)
        frame.pack(fill=BOTH, expand=True)
        self.pack(fill=BOTH, expand=True)

        exitButton = Button(self,text="Exit",command=self.parent.destroy)
        exitButton.pack(side=RIGHT, padx=5, pady=5)
        self.submitButton = Button(self,text="Submit",command=self.submitFiles)
        self.submitButton.pack(side=RIGHT)
        #DONE BOTTOM BUTTONS

    def optionUI(self):
        '''
        This creates the option window which
        presents the user with the generated
        teams and their options
        '''
        #RESETING WINDOW
        self.h = 400
        self.w = 800
        self.resetWindow()
        self.parent.title("Options")

        #CREATING SCROLL AREA
        scrollFrame = Frame(self)
        scrollFrame.pack(fill=X, side=TOP)

        self.teamlisting = Listbox(scrollFrame, width=self.w, height=18, \
                                selectmode=MULTIPLE)

        count = 1
        for team in self.interface.teams:
            teamstring  = "Team: " + str(count)
            teamstring += " score: " + "%.4f " % team.rating
            teamstring += " members: "
            for student in team.members:
                teamstring += student.name + " | "
            count += 1
            self.teamlisting.insert(END, teamstring)

        self.teamlisting.pack(padx=5, pady=5)
        #DONE SCROLL AREA

        #This will enable double-clicking
        self.teamlisting.bind('<Double-1>', lambda x: self.inspectTeamUI(self.teamlisting.curselection()))

        #CREATING BOTTOM BUTTONS
        frame = Frame(self, borderwidth=1)
        frame.pack(fill=BOTH, expand=True)
        self.pack(fill=BOTH, expand=True)

        backButton = Button(self,text="Back",command=self.startMainUI)
        backButton.pack(side=LEFT, padx=5, pady=5)
        exitButton = Button(self,text="Exit",command=lambda: self.parent.destroy() and exit())
        exitButton.pack(side=RIGHT, padx=5, pady=5)
        saveButton = Button(self,text="Save",command=self.interface.writeFile)
        saveButton.pack(side=RIGHT)
        rerunButton = Button(self,text="Rerun",command=self.reRun)
        rerunButton.pack(side=RIGHT, padx=5, pady=5)
        shuffleTeamsButton = Button(self,text="Shuffle Selected",command=self.shuffleSelected)
        shuffleTeamsButton.pack(side=RIGHT)
        swappingMembersButton = Button(self,text="Swap Members",command=self.memberSwap)
        swappingMembersButton.pack(side=RIGHT,padx=5, pady=5)
        emailscreenButton = Button(self,text="Email Team(s)",command=self.emailScreen)
        emailscreenButton.pack(side=RIGHT)
        #DONE BOTTOM BUTTONS

    def inspectTeamUI(self,selection):
        '''
        This page will allow the user to see info on the team that was double clicked.
        '''
        #RESETING WINDOW
        self.h = 400
        self.w = 800
        self.resetWindow()
        self.parent.title("About This Team")

        #CREATING SCROLL AREA
        scrollFrame = Frame(self)
        scrollFrame.pack(fill=X, side=TOP)

        self.inspectedTeamStudentListing = Listbox(scrollFrame, width=self.w, height=9)
        self.inspectedTeamScheduleListing = Listbox(scrollFrame, width=self.w, height=9)

        if selection:
            inspectedTeamIndex = selection[0]
            inspectedTeam = self.interface.teams[inspectedTeamIndex]
            for student in inspectedTeam.members:
                studentstring  = "Name: " + student.name
                studentstring += " |Languages: " + str(student.filters.get("Languages")[0]).strip('[]')
                studentstring += " |Pref. Teammates: " + str(student.filters.get("Teammates")[0]).strip('[]')
                self.inspectedTeamStudentListing.insert(END, studentstring)
                studentstring  = "Schedule for " + student.name + " = "
                for time_and_day in student.filters.get("Schedule")[0]:
                    studentstring += str(time_and_day.name) + " " + str(time_and_day.times) + " | "
                self.inspectedTeamScheduleListing.insert(END, studentstring)

        else:
            self.inspectedTeamStudentListing.insert(END, "Please try again")

        self.inspectedTeamStudentListing.pack(padx=5, pady=5)
        self.inspectedTeamScheduleListing.pack(padx=5, pady=5)
        #DONE SCROLL AREA

        #CREATING BOTTOM BUTTONS
        frame = Frame(self, borderwidth=1)
        frame.pack(fill=BOTH, expand=True)
        self.pack(fill=BOTH, expand=True)

        closeButton = Button(self,text="Close",command=self.optionUI)
        closeButton.pack(side=RIGHT,padx=5, pady=5)
        #DONE BOTTOM BUTTONS


    def memberSwapUI(self,indexes):
        '''
        This creates the window which
        allows the user to swap
        individual members and reweigh
        teams.

        @param:
            indexes = int[]
        '''
        #RESETING WINDOW
        self.h = 400
        self.w = 800
        self.resetWindow()
        self.parent.title("Swapping Members")

        #CREATING SCROLL AREA
        scrollFrame = Frame(self)
        scrollFrame.pack(fill=X, side=TOP)

        self.teamlisting1 = Listbox(scrollFrame, width=self.w, height=9)

        self.teamlisting2 = Listbox(scrollFrame, width=self.w, height=9)

        count = 1
        team = self.interface.teams[indexes[0]]
        for student in team.members:
            teamstring = ""
            teamstring += student.name
            self.teamlisting1.insert(END, teamstring)
        count += 1

        team = self.interface.teams[indexes[1]]
        for student in team.members:
            teamstring = ""
            teamstring += student.name
            self.teamlisting2.insert(END, teamstring)
        count += 1

        self.teamlisting1.pack(padx=5, pady=5)
        self.teamlisting2.pack(padx=5, pady=5)
        #DONE SCROLL AREA

        #CREATING BOTTOM BUTTONS
        frame = Frame(self, borderwidth=1)
        frame.pack(fill=BOTH, expand=True)
        self.pack(fill=BOTH, expand=True)

        backButton = Button(self,text="Back",command=lambda: self.swapSizeCheck(indexes))
        backButton.pack(side=LEFT, padx=5, pady=5)
        exitButton = Button(self,text="Exit",command=self.parent.destroy)
        exitButton.pack(side=RIGHT, padx=5, pady=5)
        swapButton = Button(self,text="Swap Team",command= lambda: self.switchTeams(indexes))
        swapButton.pack(side=RIGHT,padx=5, pady=5)
        #DONE BOTTOM BUTTONS

    def emailScreen(self):
        '''
        This starts the email login screen
        '''
        if(len(self.teamlisting.curselection()) < 1):
            messagebox.showinfo("Error","Please select one or more teams")
            return

        if(self.remember):
            self.emailTeams()
            return

        self.emailWindow = Toplevel(self.parent)
        self.centerWindow(self.emailWindow)

        #CREATING EMAIL FRAME
        emailFrame = Frame(self.emailWindow)
        emailFrame.pack(fill=X, side=TOP)
        emailLabel = Label(emailFrame, text="Email address:", background="white")
        emailLabel.pack(side=LEFT, padx=15, pady=10)

        self.emailEntry = Entry(emailFrame, width=20)
        self.emailEntry.insert(0,"")
        self.emailEntry.pack(side=LEFT, padx=43, pady=10)
        #EMAIL FRAME DONE

        #CREATING PASSWORD FRAME
        passwordFrame = Frame(self.emailWindow)
        passwordFrame.pack(fill=X, side=TOP)
        passwordLabel = Label(passwordFrame, text="Password:"******"white")
        passwordLabel.pack(side=LEFT, padx=17, pady=10)

        self.passwordEntry = Entry(passwordFrame, width=20, show="*")
        self.passwordEntry.insert(0,"")
        self.passwordEntry.pack(side=LEFT, padx=65, pady=10)
        #PASSWORD FRAME DONE

        #CREATING REMEMBER FRAME
        rememberFrame = Frame(self.emailWindow)
        rememberFrame.pack(fill=X, side=TOP)
        rememberLabel = Label(rememberFrame, text="Remember Username/Password", background="white")
        rememberLabel.pack(side=LEFT, padx=15, pady=10)

        self.rememberCheck = Checkbutton(rememberFrame)
        self.rememberCheck.pack(side=LEFT, padx=15, pady=10)
        #REMEMBER FRAME DONE

        #CREATING BOTTOM BUTTONS
        frame = Frame(self.emailWindow, borderwidth=1)
        frame.pack(fill=BOTH, expand=True)

        exitButton = Button(self.emailWindow,text="Cancel",command=self.emailWindow.destroy)
        exitButton.pack(side=RIGHT, padx=5, pady=5)
        submitButton = Button(self.emailWindow,text="Submit",command=self.emailTeams)
        submitButton.pack(side=RIGHT,padx=5, pady=5)
        #DONE BOTTOM BUTTONS

    def emailTeams(self):
        '''
        This invokes emailing the selected teams
        '''
        success = True

        if(not self.remember):
            selection = self.teamlisting.curselection()
            email     = self.emailEntry.get()
            password  = self.passwordEntry.get()

            if(email == "" or password == ""):
                messagebox.showinfo("Error","Cannot leave fields empty")
                return

            if(len(self.rememberCheck.state()) != 0 and self.rememberCheck.state()[0] == "selected"):
                self.remember = True
                success = self.interface.sendEmail(selection,email,password,True)
            else:
                success = self.interface.sendEmail(selection,email,password)

        else:
           success = self.interface.sendEmail(self.teamlisting.curselection())

        if not success:
            self.remember = False
            messagebox.showinfo("Error","Sending the email was unsuccessful, check your email and password")
            return

        if success:
            messagebox.showinfo("Success","Email was sent successfully")
            self.emailWindow.destroy()
            return

    def loadingScreen(self):
        '''
        This starts the loading screen
        and disables all buttons
        '''
        for i in self.winfo_children():
            if Button == type(i):
                i.configure(state=DISABLED)

        self.loadWindow = Toplevel(self.parent)
        loadingstring   = "Please wait while we run the algorithm"
        loadinglabel    = Label(self.loadWindow, text=loadingstring, background="white")
        progressbar     = Progressbar(self.loadWindow, orient= "horizontal", \
                                    length=300, mode="indeterminate")
        progressbar.pack(pady=self.h/10)
        loadinglabel.pack()

        self.centerWindow(self.loadWindow)
        self.loadWindow.title("Wait")
        progressbar.start()

    def memberSwap(self):
        '''
        This will setup the call for memberSwapUI
        and check for improper/missing selections
        '''
        indexes = []
        selection = self.teamlisting.curselection()
        for i in selection:
            indexes.append(i)
        if len(indexes) == 2:
            self.memberSwapUI(indexes);
        else:
            messagebox.showinfo("Error","Please select 2 teams")

    def switchTeams(self, indexes):
        '''
        Puts selected members into the other team in
        the memberSwapUI
        @param:
            indexes = int[]
        '''
        student1 = self.teamlisting1.curselection()
        student2 = self.teamlisting2.curselection()

        if student1:
            if len(self.interface.teams[indexes[1]].members) < self.interface.teams[indexes[1]].maxsize:
                student = self.interface.teams[indexes[0]].members[int(student1[0])]
                newTeam = self.interface.teams[indexes[1]]
                oldTeam = self.interface.teams[indexes[0]]
                newTeam.insertStudent(student)
                oldTeam.remStudent(student)
                self.memberSwapUI(indexes)
            else:
                messagebox.showinfo("Max Capacity", "Group is at maximum capacity")

        if student2:
            if len(self.interface.teams[indexes[0]].members) < self.interface.teams[indexes[0]].maxsize:
                student = self.interface.teams[indexes[1]].members[int(student2[0])]
                newTeam = self.interface.teams[indexes[0]]
                oldTeam = self.interface.teams[indexes[1]]
                newTeam.insertStudent(student)
                oldTeam.remStudent(student)
                self.memberSwapUI(indexes)
            else:
                messagebox.showinfo("Max Capacity", "Group is at maximum capacity")

    def swapSizeCheck(self,indexes):
        '''
        This is a check to make sure before you back up from the
        memberSwapUI that the sizes are still correct

        @param:
            indexes = int[]
        '''
        if len(self.interface.teams[indexes[0]].members) < self.interface.teams[indexes[0]].maxsize \
                or len(self.interface.teams[indexes[1]].members) < self.interface.teams[indexes[1]].maxsize:
            if messagebox.askokcancel("WARNING", "Warning: A group is shorthanded. You sure you want to proceed?"):
                for index in indexes:
                    self.interface.algorithm.weightCalc(self.interface.teams[index])
                self.optionUI();
        else:
            for index in indexes:
                self.interface.algorithm.weightCalc(self.interface.teams[index])
            self.optionUI();

    def shuffleSelected(self):
        '''
        This is a wrapper function that
        shuffles the selected teams
        '''
        #Gets selected values
        indexes   = []
        selection = self.teamlisting.curselection()
        for i in selection:
            indexes.append(i)

        self.interface.reShuffleSelectedTeams(indexes)
        self.optionUI()

    def reRun(self):
        '''
        A wrapper function to rerun the
        algorithm
        '''

        thread = ThreadedTask(self.queue,\
            self.interface.reShuffleAll)
        thread.start()
        ThreadedTask(self.queue,self.loadingScreen).start()
        self.checkThread(thread,self.optionUI)

    def submitFiles(self):
        '''
        Checks the validity of the entry feilds for
        After checks it runs our python script.
        '''
        csvtext     = self.csvEntry.get()
        teamsize    = self.teamsizeEntry.get()
        rostertext  = self.rosterEntry.get()
        outputtext  = self.outputEntry.get()

        #Checking existance of paths and extensions
        if(not os.path.exists(csvtext) and csvtext[-4:] != ".csv"):
            messagebox.showinfo("Error","Not a CSV or the file does not exist")
            return

        #Checking existance of paths and extensions
        if(not os.path.exists(rostertext) and rostertext[-4:] != ".txt"):
           messagebox.showinfo("Error","Not a roster or the file does not exist")
           return

        #Checking existance of path
        if(not os.path.exists(outputtext)):
           messagebox.showinfo("Error","Directory dosen't exists for output")
           return

        #Checking if the string is an int and in range
        if(not self.testNumber(teamsize)):
            messagebox.showinfo("Error","Please enter a positive integer for teamsize(2,5)")
            return

        self.csvpathh    = csvtext
        self.rosterpathh = rostertext
        self.outpathh    = outputtext
        self.teamsizeh   = teamsize

        self.interface.setOutputPath(outputtext)

        self.submitButton.configure(state=DISABLED)
        runalgorithm = lambda: self.interface.runGeneral(\
                        rostertext,csvtext,int(teamsize))
        thread1 = ThreadedTask(self.queue,runalgorithm)
        thread2 = ThreadedTask(self.queue,self.loadingScreen)
        thread2.start()
        thread1.start()

        self.checkThread(thread1,self.optionUI)

    def checkThread(self,thread,function):
        '''
        This function checks to see if
        the given thread is dead, if it
        is not, it recalls a new checkThread.
        After the thread is dead, it calls the
        given function

        @param:
            thread   - ThreadedTask
            functoin - a function
        '''
        if thread.is_alive():
            self.parent.after(1000, lambda: self.checkThread(thread,function))
        else:
            function()

    def testNumber(self,i,minimum=0,maximum=5):
        '''
        Checks if i is an integer and between
        a certain range

        @param:
            i (string)
            minimum (optional int)
            maximum (optional int)
        '''
        try:
            i = int(i)
            return (i >= minimum) and (i <= maximum)
        except:
            return False

    def csvstartfilebrowser(self):
        '''
        Starts the filebrowser for the csv file
        '''
        currdir = os.getcwd()
        fileopt = [('csv files', '*.csv')]
        directo = filedialog.askopenfilename(parent=self, filetypes=fileopt, \
                                         initialdir=currdir, title="Select file")
        #clearning and setting csventry
        self.csvEntry.delete(0,'end')
        self.csvEntry.insert(0,str(directo))

    def rosterstartfilebrowser(self):
        '''
        Starts the filebrowser for the text file
        '''
        currdir = os.getcwd()
        fileopt = [('text files', '*.txt')]
        directo = filedialog.askopenfilename(parent=self, filetypes=fileopt, \
                                         initialdir=currdir, title="Select file")
        #clearning and setting rosterentry
        self.rosterEntry.delete(0,'end')
        self.rosterEntry.insert(0,str(directo))

    def outputstartfilebrowser(self):
        '''
        Starts the filebrowser for the output
        '''
        currdir = os.getcwd()
        directo = filedialog.askdirectory(parent=self,\
                                    initialdir=currdir, title="Select file")

        #clearning and setting outputentry
        self.outputEntry.delete(0,'end')
        self.outputEntry.insert(0,str(directo))