Example #1
0
class TimerDemo:
    """Controller"""
    def __init__(self):
        self.root = Tk()
        self.root.title('Timer')
        left = (self.root.winfo_screenwidth() - WIDTH) // 2
        top = (self.root.winfo_screenheight() - HEIGHT) // 2
        self.root.geometry(f'{WIDTH}x{HEIGHT}+{left}+{top}')
        self.root.resizable(False, False)

        # variables
        self.count_start = IntVar()
        self.count_start.trace_add('write', self.count_start_changed)
        self.count = IntVar()
        self.count.trace_add('write', self.count_changed)
        self.time = StringVar()
        self.timer_id = None

        self.ui = TimerUi(self)
        self.count_start.set(DEFAULT_COUNT)

    def run(self):
        self.root.mainloop()

    def count_changed(self, *args):
        self.draw_time()

    def count_start_changed(self, *args):
        # Countdown中には呼ばれないようにすること
        self.count.set(self.count_start.get())

    def draw_time(self):
        count = self.count.get()
        m, s = count // 60, count % 60
        self.time.set(f'{m:0>2}:{s:0>2}')

    def start_timer(self):
        if self.count.get() == 0:
            self.count_start_changed()
        self.ui.state_started()
        self.timer_id = self.root.after(1000, self.countdown)

    def stop_timer(self):
        if self.timer_id:
            self.root.after_cancel(self.timer_id)
        self.ui.state_stopped()

    def countdown(self):
        self.count.set(self.count.get() - 1)
        if self.count.get() > 0:
            self.timer_id = self.root.after(1000, self.countdown)  # recursive
        else:
            self.root.bell()
            self.ui.state_stopped()
Example #2
0
class UITk(UI):
    """TODO doc for UITk"""

    def __init__(self, rogue):
        """Constructor for UITk"""
        super().__init__(rogue)
        self.window = Tk()
        self.screen = StringVar()
        self.draw_from_rogue()
        self.label = Label(self.window, textvariable=self.screen, fg="white", bg="black", font=("monospace", 11))
        self.label.focus_set()
        self.label.pack()

    def start_ui(self):
        """TODO docs"""
        self.window.mainloop()

    def on_timer_end(self, timer, callback):
        """TODO docs"""
        return self.window.after(timer, callback)

    def cancel_timer(self, timer):
        """TODO docs"""
        if timer is not None:
            self.window.after_cancel(timer)

    def on_key_press(self, callback):
        """TODO docs"""
        self.label.bind("<Key>", callback)

    def draw(self, string):
        """Draw on the screen the provided string"""
        self.screen.set(string)

    def read_rogue(self):
        """Return the string on the rogue process screen"""
        return self.rb.get_screen_string()

    def draw_from_rogue(self):
        """Draw on the screen whats on rogue"""
        self.draw(self.read_rogue())

    def draw_log(self, string):
        pass
Example #3
0
class CollocationsView:
    _BACKGROUND_COLOUR = "#FFF"  # white

    def __init__(self):
        self.queue = q.Queue()
        self.model = CollocationsModel(self.queue)
        self.top = Tk()
        self._init_top(self.top)
        self._init_menubar()
        self._init_widgets(self.top)
        self.load_corpus(self.model.DEFAULT_CORPUS)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def _init_top(self, top):
        top.geometry("550x650+50+50")
        top.title("NLTK Collocations List")
        top.bind("<Control-q>", self.destroy)
        top.protocol("WM_DELETE_WINDOW", self.destroy)
        top.minsize(550, 650)

    def _init_widgets(self, parent):
        self.main_frame = Frame(
            parent,
            dict(background=self._BACKGROUND_COLOUR, padx=1, pady=1, border=1))
        self._init_corpus_select(self.main_frame)
        self._init_results_box(self.main_frame)
        self._init_paging(self.main_frame)
        self._init_status(self.main_frame)
        self.main_frame.pack(fill="both", expand=True)

    def _init_corpus_select(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.var = StringVar(innerframe)
        self.var.set(self.model.DEFAULT_CORPUS)
        Label(
            innerframe,
            justify=LEFT,
            text=" Corpus: ",
            background=self._BACKGROUND_COLOUR,
            padx=2,
            pady=1,
            border=0,
        ).pack(side="left")

        other_corpora = list(self.model.CORPORA.keys()).remove(
            self.model.DEFAULT_CORPUS)
        om = OptionMenu(innerframe,
                        self.var,
                        self.model.DEFAULT_CORPUS,
                        command=self.corpus_selected,
                        *self.model.non_default_corpora())
        om["borderwidth"] = 0
        om["highlightthickness"] = 1
        om.pack(side="left")
        innerframe.pack(side="top", fill="x", anchor="n")

    def _init_status(self, parent):
        self.status = Label(
            parent,
            justify=LEFT,
            relief=SUNKEN,
            background=self._BACKGROUND_COLOUR,
            border=0,
            padx=1,
            pady=0,
        )
        self.status.pack(side="top", anchor="sw")

    def _init_menubar(self):
        self._result_size = IntVar(self.top)
        menubar = Menu(self.top)

        filemenu = Menu(menubar, tearoff=0, borderwidth=0)
        filemenu.add_command(label="Exit",
                             underline=1,
                             command=self.destroy,
                             accelerator="Ctrl-q")
        menubar.add_cascade(label="File", underline=0, menu=filemenu)

        editmenu = Menu(menubar, tearoff=0)
        rescntmenu = Menu(editmenu, tearoff=0)
        rescntmenu.add_radiobutton(
            label="20",
            variable=self._result_size,
            underline=0,
            value=20,
            command=self.set_result_size,
        )
        rescntmenu.add_radiobutton(
            label="50",
            variable=self._result_size,
            underline=0,
            value=50,
            command=self.set_result_size,
        )
        rescntmenu.add_radiobutton(
            label="100",
            variable=self._result_size,
            underline=0,
            value=100,
            command=self.set_result_size,
        )
        rescntmenu.invoke(1)
        editmenu.add_cascade(label="Result Count",
                             underline=0,
                             menu=rescntmenu)

        menubar.add_cascade(label="Edit", underline=0, menu=editmenu)
        self.top.config(menu=menubar)

    def set_result_size(self, **kwargs):
        self.model.result_count = self._result_size.get()

    def _init_results_box(self, parent):
        innerframe = Frame(parent)
        i1 = Frame(innerframe)
        i2 = Frame(innerframe)
        vscrollbar = Scrollbar(i1, borderwidth=1)
        hscrollbar = Scrollbar(i2, borderwidth=1, orient="horiz")
        self.results_box = Text(
            i1,
            font=Font(family="courier", size="16"),
            state="disabled",
            borderwidth=1,
            yscrollcommand=vscrollbar.set,
            xscrollcommand=hscrollbar.set,
            wrap="none",
            width="40",
            height="20",
            exportselection=1,
        )
        self.results_box.pack(side="left", fill="both", expand=True)
        vscrollbar.pack(side="left", fill="y", anchor="e")
        vscrollbar.config(command=self.results_box.yview)
        hscrollbar.pack(side="left", fill="x", expand=True, anchor="w")
        hscrollbar.config(command=self.results_box.xview)
        # there is no other way of avoiding the overlap of scrollbars while using pack layout manager!!!
        Label(i2, text="   ",
              background=self._BACKGROUND_COLOUR).pack(side="left", anchor="e")
        i1.pack(side="top", fill="both", expand=True, anchor="n")
        i2.pack(side="bottom", fill="x", anchor="s")
        innerframe.pack(side="top", fill="both", expand=True)

    def _init_paging(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.prev = prev = Button(
            innerframe,
            text="Previous",
            command=self.previous,
            width="10",
            borderwidth=1,
            highlightthickness=1,
            state="disabled",
        )
        prev.pack(side="left", anchor="center")
        self.next = next = Button(
            innerframe,
            text="Next",
            command=self.__next__,
            width="10",
            borderwidth=1,
            highlightthickness=1,
            state="disabled",
        )
        next.pack(side="right", anchor="center")
        innerframe.pack(side="top", fill="y")
        self.reset_current_page()

    def reset_current_page(self):
        self.current_page = -1

    def _poll(self):
        try:
            event = self.queue.get(block=False)
        except q.Empty:
            pass
        else:
            if event == CORPUS_LOADED_EVENT:
                self.handle_corpus_loaded(event)
            elif event == ERROR_LOADING_CORPUS_EVENT:
                self.handle_error_loading_corpus(event)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def handle_error_loading_corpus(self, event):
        self.status["text"] = "Error in loading " + self.var.get()
        self.unfreeze_editable()
        self.clear_results_box()
        self.freeze_editable()
        self.reset_current_page()

    def handle_corpus_loaded(self, event):
        self.status["text"] = self.var.get() + " is loaded"
        self.unfreeze_editable()
        self.clear_results_box()
        self.reset_current_page()
        # self.next()
        collocations = self.model.next(self.current_page + 1)
        self.write_results(collocations)
        self.current_page += 1

    def corpus_selected(self, *args):
        new_selection = self.var.get()
        self.load_corpus(new_selection)

    def previous(self):
        self.freeze_editable()
        collocations = self.model.prev(self.current_page - 1)
        self.current_page = self.current_page - 1
        self.clear_results_box()
        self.write_results(collocations)
        self.unfreeze_editable()

    def __next__(self):
        self.freeze_editable()
        collocations = self.model.next(self.current_page + 1)
        self.clear_results_box()
        self.write_results(collocations)
        self.current_page += 1
        self.unfreeze_editable()

    def load_corpus(self, selection):
        if self.model.selected_corpus != selection:
            self.status["text"] = "Loading " + selection + "..."
            self.freeze_editable()
            self.model.load_corpus(selection)

    def freeze_editable(self):
        self.prev["state"] = "disabled"
        self.next["state"] = "disabled"

    def clear_results_box(self):
        self.results_box["state"] = "normal"
        self.results_box.delete("1.0", END)
        self.results_box["state"] = "disabled"

    def fire_event(self, event):
        # Firing an event so that rendering of widgets happen in the mainloop thread
        self.top.event_generate(event, when="tail")

    def destroy(self, *e):
        if self.top is None:
            return
        self.top.after_cancel(self.after)
        self.top.destroy()
        self.top = None

    def mainloop(self, *args, **kwargs):
        if in_idle():
            return
        self.top.mainloop(*args, **kwargs)

    def unfreeze_editable(self):
        self.set_paging_button_states()

    def set_paging_button_states(self):
        if self.current_page == -1 or self.current_page == 0:
            self.prev["state"] = "disabled"
        else:
            self.prev["state"] = "normal"
        if self.model.is_last_page(self.current_page):
            self.next["state"] = "disabled"
        else:
            self.next["state"] = "normal"

    def write_results(self, results):
        self.results_box["state"] = "normal"
        row = 1
        for each in results:
            self.results_box.insert(
                str(row) + ".0", each[0] + " " + each[1] + "\n")
            row += 1
        self.results_box["state"] = "disabled"
Example #4
0
class Game:
    def __init__(self):
        self.in_game = False
        self.add = False
        self.job = None
        self.score = 0
        self.keys = {
            'j': 'Down',
            'k': 'Up',
            'h': 'Left',
            'l': 'Right',
        }

        self.root = Tk()
        self.root.title('Python Snake')
        self.canvas = Canvas(self.root,
                             width=WIDTH + 250,
                             height=HEIGHT,
                             bg=BG_SIDE)
        self.canvas.grid()
        self.score_label = Label(self.canvas,
                                 width=8,
                                 height=2,
                                 font='Impact 36',
                                 bg=BG_SIDE)
        self.score_label.place(x=WIDTH + 10, y=100)
        self.score_label.configure(text='Очки:\n0')
        self.hint_label = Label(self.canvas,
                                width=11,
                                height=7,
                                font='Impact 36',
                                bg=BG_SIDE)
        self.hint_label.place(x=WIDTH + 10, y=200)
        self.canvas.focus_set()
        self.draw_field()
        self.snake = Snake(self.canvas, SEG)
        self.apple = None
        self.create_apple()
        self.in_menu()
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)

    def run(self):
        self.root.mainloop()

    def in_menu(self):
        self.in_game = False
        self.canvas.bind("<KeyPress>", self.menu_keypress_handler)
        self.hint_label.configure(text='Управление:\n'
                                  'Q: Выход\n'
                                  'I: Режим игры\n')

    def menu_keypress_handler(self, event):
        if event.keysym == 'i':
            self.game_mode()
        if event.keysym == 'q':
            self.root.destroy()

    def game_mode(self):
        self.canvas.bind("<KeyPress>", self.game_keypress_handler)
        self.in_game = True
        self.job = self.root.after(100, self.main_loop)
        self.hint_label.configure(text='Управление:\n'
                                  'H: Влево\n'
                                  'J: Вниз\n'
                                  'K: Вверх\n'
                                  'L: Вправо\n'
                                  'Esc: Меню\n')

    def game_keypress_handler(self, event):
        if event.keysym in self.keys:
            self.snake.change_direction(self.keys[event.keysym])
        if event.keysym == 'Escape':
            self.root.after_cancel(self.job)
            self.in_menu()

    def snake_intersection(self):
        head = self.canvas.coords(self.snake.segments[-1].instance)
        return any(
            self.canvas.coords(segment.instance) == head
            for segment in self.snake.segments[:-1])

    def main_loop(self):
        if self.in_game:
            self.snake.move(self.add)
            if self.add:
                self.delete_apple()
                self.create_apple()
                self.update_score()
                self.add = False
            x1, y1, x2, y2 = self.canvas.coords(
                self.snake.segments[-1].instance)
            if x2 > WIDTH or x1 < 0 or y1 < 0 or y2 > HEIGHT or self.snake_intersection(
            ):
                self.in_game = False
            if self.apple in self.canvas.find_overlapping(
                    x1 + 1, y1 + 1, x2 - 1, y2 - 1):
                self.add = True
        self.job = self.root.after(100, self.main_loop)

    def delete_apple(self):
        self.canvas.delete(self.apple)
        self.apple = None

    def create_apple(self):
        while not self.apple or any(self.apple in self.canvas.find_overlapping(
                *self.canvas.coords(x.instance)) for x in self.snake.segments):
            if self.apple:
                self.canvas.delete(self.apple)
            x = SEG * randint(1, WIDTH // SEG - 1)
            y = SEG * randint(1, HEIGHT // SEG - 1)
            self.apple = self.canvas.create_oval(x,
                                                 y,
                                                 x + SEG,
                                                 y + SEG,
                                                 fill='red')

    def draw_field(self):
        self.canvas.create_rectangle(0, 0, WIDTH, HEIGHT, fill=BG_FIELD)

    def update_score(self):
        self.score += 1
        self.score_label.configure(text=f'Очки:\n{self.score}')

    def on_close(self):
        if self.job:
            self.root.after_cancel(self.job)
        self.root.destroy()
Example #5
0
class ShiftApp():  ### In-progress Shift application ###
    def __init__(self, db, job_name):
        self.db = db
        self.events = {}

        self.job_name = job_name
        self.start_time = time.time()
        self.break_start = 0
        self.break_time = 0
        self.id = self.db.add_shift(self.job_name, self.start_time, None,
                                    self.break_time, None)
        self.tasks = {}
        self.task_index = []
        self.cur_task = 0

        self.root = Tk()
        self.root.title(f'Shift - {job_name}')
        self.root.resizable(False, False)
        self.root.overrideredirect(0)

        self.tm1_selection = StringVar(self.root)
        self.tm2_selection = StringVar(self.root)

        self.container = ttk.Frame(self.root)
        self.frame = ttk.Frame(self.container)

        self.job_label = ttk.Label(self.frame, text=f'Job: {job_name}')
        self.elapsed_time_label = ttk.Label(self.frame, width=18)

        self.task_frame = ttk.Frame(self.frame)
        self.task_label = ttk.Label(self.task_frame, text="Tasks:")
        self.tm1_options, self.tm2_options = ('All Job Tasks',
                                              'Shift Tasks Only'), ()
        self.task_menu1 = ttk.OptionMenu(self.frame, self.tm1_selection,
                                         self.tm1_options[0],
                                         *self.tm1_options)
        self.task_entry = ttk.Entry(self.frame)
        self.task_list = Listbox(self.task_frame,
                                 selectmode=SINGLE,
                                 width=20,
                                 height=12,
                                 relief='sunken')
        vbar = ttk.Scrollbar(self.task_frame,
                             orient='vertical',
                             command=self.task_list.yview)
        self.task_list.config(yscrollcommand=vbar.set)
        self.new_task_button = ttk.Button(self.frame,
                                          text="New Task",
                                          command=self.new_task)

        self.button_frame = ttk.Frame(self.frame)
        self.pause_button = ttk.Button(self.button_frame,
                                       text='Pause',
                                       command=self.toggle_break,
                                       width=7)
        # TODO: Add info button
        self.cancel_button = ttk.Button(self.frame,
                                        text='Cancel',
                                        command=self.cancel_prompt)
        self.notes = ScrolledText(self.frame,
                                  undo=True,
                                  width=60,
                                  height=15,
                                  relief='sunken')
        self.report_job_button = ttk.Button(self.frame,
                                            text='Prior Shifts',
                                            command=self.launch_report_edit)
        self.save_button = ttk.Button(self.frame,
                                      text='Stop and Save',
                                      command=self.end_prompt)

        self.job_label.grid(column=2, columnspan=2, row=1, sticky=W, pady=5)
        self.elapsed_time_label.grid(column=4, row=1, sticky=E)
        self.task_menu1.grid(column=1, row=1, sticky=(E, W), padx=(0, 15))
        self.task_entry.grid(column=1, row=2, sticky=(E, W), padx=(0, 15))
        self.task_list.grid(column=1, row=1, sticky=(N, S))
        vbar.grid(column=2, row=1, sticky=(N, S))
        self.task_frame.grid(column=1, row=3, sticky=(N, S), pady=(5, 5))
        self.new_task_button.grid(column=1, row=4, sticky=W)
        self.button_frame.grid(column=2, columnspan=2, row=2, sticky=W)
        self.pause_button.grid(column=2, row=1, sticky=W)
        self.cancel_button.grid(column=4, row=2, sticky=E)
        self.notes.grid(column=2, columnspan=3, row=3, pady=(5, 5))
        self.report_job_button.grid(column=2, row=4, sticky=W)
        self.save_button.grid(column=4, row=4, sticky=E)
        self.frame.grid(column=0, row=0, padx=5, pady=5)
        self.container.grid(column=0, row=0)

        self.root.protocol("WM_DELETE_WINDOW", self.cancel_prompt)
        self.task_menu1.bind("<ButtonRelease-1>",
                             self.filter_tasks)  # filter_tasks clears notes
        self.task_entry.bind("<KeyRelease>", self.filter_tasks)
        self.task_list.bind("<ButtonRelease-1>", self.focus_task)
        self.task_list.bind("<Double-Button-1>", self.copy_task_title)
        self.notes.bind("<Command-Z>", self.edit_undo)

        self.time_counter()
        self.auto_save()
        self.get_tasks()

    def edit_undo(self, event=None):
        try:
            self.notes.edit_undo()
        except TclError as e:
            print(e)

    def get_tasks(self,
                  event=None,
                  **kwargs):  ## Gets set of filtered tasks from db ##
        if "Job" in self.tm1_selection.get():
            kwargs["job_name"] = self.job_name
        else:
            kwargs["shift_id"] = self.id
        tasks = self.db.report_tasks(**kwargs)
        self.tasks.clear()
        for task in tasks:
            self.tasks[task["id"]] = task
        self.task_list.delete(0, END)
        self.cur_task = 0
        self.task_index = []
        self.task_list.insert(END, "Shift Notes")
        self.task_index.append(None)
        for _, task in self.tasks.items():
            self.task_list.insert(END, task['title'])
            self.task_index.append(task["id"])

    def filter_tasks(self, event=None):
        # TODO: set focus to 'Shift Notes'
        search_term = self.task_entry.get()
        if search_term in ('', ' '):
            search_term = None
        self.get_tasks(search_term=search_term)
        notes = self.db.get_shift(self.id)["notes"]
        self.notes.delete("0.0", END)
        self.notes.insert(END, notes)

    def new_task(self):
        task_title = self.task_entry.get()
        if task_title not in ('', ' '):
            task = self.db.add_task(self.id, self.job_name, task_title)
            self.task_entry.delete(0, END)
            self.get_tasks()
            self.task_list.activate(self.task_index.index(task["id"]))

    def focus_task(
            self,
            event=None):  ## displays notes for the currently selected task ##
        if self.task_list.curselection():
            new_cur = self.task_list.curselection()[0]
            if new_cur == self.cur_task:
                return
            notes = self.notes.get(0.0, END).strip('\n')
            if self.cur_task:  # if the notes being displayed belong to a task
                task_id = self.task_index[self.cur_task]
                self.tasks[task_id]["notes"] = notes
            else:
                self.db.update_shift(self.id, notes=notes)
            if new_cur:  # if the new notes to be displayed belong to a task
                task_id = self.task_index[new_cur]
                notes = self.tasks[task_id]["notes"]
            else:
                shift = self.db.report_shifts(shift_id=self.id)[0]
                notes = shift["notes"]
            self.notes.delete('0.0', END)
            self.notes.insert(END, notes)
            self.cur_task = new_cur

    def copy_task_title(
        self,
        event=None
    ):  ## Copies title from current selection in task_list to task_entry ##
        cur = self.task_list.curselection()[0]
        if cur:
            task = self.tasks[self.task_index[cur]]
            self.task_entry.delete(0, END)
            self.task_entry.insert(0, task["title"])
            self.filter_tasks()

    def time_counter(self):
        if not self.break_start:
            elapsed_time = time.gmtime(time.time() - self.start_time -
                                       self.break_time)
            elapsed_hours = time.strftime('%H', elapsed_time)
            elapsed_minutes = time.strftime('%M', elapsed_time)
            elapsed_seconds = time.strftime('%S', elapsed_time)
            self.elapsed_time_label[
                'text'] = f'Elapsed Time: {elapsed_hours}:{elapsed_minutes}:{elapsed_seconds}'
        self.events['time_counter'] = self.root.after(200, self.time_counter)

    def auto_save(self):
        self.save_update()
        self.events['auto_save'] = self.root.after(5000, self.auto_save)

    def save_update(
            self):  ## Commits current state for shift and tasks to db ##
        if self.break_start:
            break_time = self.break_time + (time.time() - self.break_start)
        else:
            break_time = self.break_time
        end_time = time.time()
        notes = self.notes.get(0.0, END).strip('\n')
        if self.cur_task:  # if the notes being displayed belong to a task
            task_id = self.task_index[self.cur_task]
            self.tasks[task_id]["notes"] = notes
            notes = None
        self.db.update_shift(self.id,
                             end_time=end_time,
                             break_time=break_time,
                             notes=notes)
        for _, task in self.tasks.items():
            self.db.update_task(**task)

    def toggle_break(self):
        if not self.break_start:
            self.break_start = time.time()
            self.job_label['text'] = f'{self.job_name} - Paused'
            self.pause_button['text'] = 'Resume'
        else:
            self.break_time += time.time() - self.break_start
            self.break_start = 0
            self.job_label['text'] = self.job_name
            self.pause_button['text'] = 'Pause'

    def end_prompt(self):
        popup = PopConfirm("Save and exit shift?", self.end_shift)
        popup.root.mainloop()

    def cancel_prompt(self):
        popup = PopConfirm("Cancel and delete shift?", self.cancel_shift)
        popup.root.mainloop()

    def end_shift(self):
        self.save_update()
        self.db.complete_shift(self.id)
        self.close()

    def cancel_shift(self):
        self.db.remove_shift(self.id)
        self.close()

    def launch_report_edit(self):
        self.report_edit_window = ReportEditApp(self.db,
                                                job_name=self.job_name)
        self.report_edit_window.root.mainloop()

    def close(self):
        for val in self.events.values():
            self.root.after_cancel(val)
        self.root.destroy()
Example #6
0
class puzzle():
    # x is number of rows, y = number of columns
    def __init__(self, x=3, y=3):
        #name of the window
        self.root = Tk()
        self.root.title('Number Puzzle')
        self.root.iconphoto(False, PhotoImage(file='info.png'))
        #name of canvas = 'puzz'
        self.puzz = Canvas(self.root, width=720, height=550, bg='#cccccc')
        self.puzz.pack()

        self.ids = {}
        self.timer = [0, 0]
        self.timejob = None  #after function
        self.timeshuffle = None  #after function
        self.shufflepoints = 0  #counting shuffles

        self.x = x
        self.y = y
        self.grids = {}

        self.allowables = {}  # this gives the allowable swap

        self.__grid_creator__()
        self.__clock_creator__()
        #self.__timer_clock__()
        self.__get_allowables__()
        self.root.mainloop()

    ##get allowables swap positions
    def __get_allowables__(self):
        for i in self.allowables:
            if i % self.y != 0:
                self.allowables[i].append(i - 1)
            if i % self.y != self.y - 1:
                self.allowables[i].append(i + 1)
            if i >= self.y:
                self.allowables[i].append(i - self.y)
            if i // self.y != self.x - 1:
                self.allowables[i].append(i + self.y)

    #refreshes the time_text
    def __timer_clock__(self):
        self.timer[1] += 1
        #getting mis and secs
        if self.timer[1] >= 60:
            self.timer[1] = 0
            self.timer[0] += 1
        #converting them into displayanle format
        if self.timer[1] <= 9:
            secs = '0' + str(self.timer[1])
        else:
            secs = str(self.timer[1])
        if self.timer[0] <= 9:
            mins = '0' + str(self.timer[0])
        else:
            mins = str(self.timer[0])
        timer = mins + ':' + secs
        #time over condition
        if self.timer[0] >= 59:
            self.__time_stopper__("Stop")
        else:
            self.puzz.itemconfig(self.ids['clock_time'],
                                 text=timer,
                                 fill='#000000')
            self.timejob = self.root.after(1000, self.__timer_clock__)

    def __time_stopper__(self, msg):
        self.root.after_cancel(self.timejob)
        self.timejob = None
        self.puzz.itemconfig(self.ids['clock_time'], text=msg, fill='#ff4444')

    def __clock_creator__(self):
        ##for creating clock and other button
        #name used for clock_text = 'clock_time' and box is = 'clock_box'
        self.ids['clock_box'] = self.puzz.create_rectangle(520,
                                                           300,
                                                           700,
                                                           350,
                                                           fill='#eeeeee',
                                                           tag='clock_box')
        self.ids['clock_time'] = self.puzz.create_text(610,
                                                       325,
                                                       text='Timer',
                                                       font='tester 20',
                                                       tag='clock_time')

        self.ids['shuffle_box'] = self.puzz.create_rectangle(520,
                                                             200,
                                                             700,
                                                             250,
                                                             fill='#eeeeee',
                                                             tag='shuffle_box')
        self.ids['shuffle_text'] = self.puzz.create_text(610,
                                                         225,
                                                         text='shuffle',
                                                         font='tester 20',
                                                         tag='shuffle_text')
        self.puzz.tag_bind(self.ids['shuffle_box'], "<Enter>",
                           lambda event: self.Entered('shuffle_box'))
        self.puzz.tag_bind(self.ids['shuffle_box'], "<Leave>",
                           lambda event: self.Leaved('shuffle_box'))
        self.puzz.tag_bind(self.ids['shuffle_text'], "<Enter>",
                           lambda event: self.Entered('shuffle_box'))
        self.puzz.tag_bind(self.ids['shuffle_text'], "<Leave>",
                           lambda event: self.Leaved('shuffle_box'))
        self.puzz.tag_bind(self.ids['shuffle_box'], "<Button-1>",
                           self.__shuffler__)
        self.puzz.tag_bind(self.ids['shuffle_text'], "<Button-1>",
                           self.__shuffler__)

    def clock_reset(self):
        self.timer[0] = 0
        self.timer[1] = 0

    def __grid_creator__(self):
        #getting row and column number
        for i in range(self.x):
            for j in range(self.y):
                self.grids[i * self.y + j] = [i, j]

        #for getting the coordinates
        for i in self.grids:
            x1 = self.grids[i][1] * 500 / self.y + 20
            x1 = floor(x1)
            x2 = x1 + 500 / self.y - 5
            x2 = floor(x2)
            y1 = self.grids[i][0] * 500 / self.x + 20
            y1 = floor(y1)
            y2 = y1 + 500 / self.x - 5
            y2 = floor(y2)
            self.grids[i].append(x1)
            self.grids[i].append(y1)
            self.grids[i].append(x2)
            self.grids[i].append(y2)
            bname = 'slot_' + str(i)
            tname = 'text_' + str(i)
            self.ids[bname] = self.puzz.create_rectangle(self.grids[i][2],
                                                         self.grids[i][3],
                                                         self.grids[i][4],
                                                         self.grids[i][5],
                                                         tags=bname,
                                                         fill='#eeeeee')
            self.ids[tname] = self.puzz.create_text(
                (self.grids[i][2] + self.grids[i][4]) / 2,
                (self.grids[i][3] + self.grids[i][5]) / 2,
                text=i,
                tags=tname,
                font='tester 20')
            bname = 'slot_' + str(i)
            tname = 'text_' + str(i)
            self.event_binder(bname, tname)
            self.grids[i].append(i)
            self.allowables[i] = []

    # with the last box made empty
        self.puzz.itemconfig(self.ids['slot_' + str(self.x * self.y - 1)],
                             fill='',
                             outline='')
        self.puzz.delete('text_' + str(self.x * self.y - 1))

    #to bind the slots with the Enter and leave events and click

    def event_binder(self, x, y):
        self.puzz.tag_bind(self.ids[x], "<Enter>",
                           lambda event: self.Entered(x))
        self.puzz.tag_bind(self.ids[x], "<Leave>",
                           lambda event: self.Leaved(x))
        self.puzz.tag_bind(self.ids[y], "<Enter>",
                           lambda event: self.Entered(x))
        self.puzz.tag_bind(self.ids[y], "<Leave>",
                           lambda event: self.Leaved(x))
        self.puzz.tag_bind(self.ids[x], "<Button-1>",
                           lambda event: self.clicked(x))
        self.puzz.tag_bind(self.ids[y], "<Button-1>",
                           lambda event: self.clicked(x))

    #when cursor hovers over the slot
    def Entered(self, x):
        if x != 'slot_' + str(self.x * self.y - 1):
            self.puzz.itemconfig(self.ids[x], fill='#ffffff')
        else:
            self.puzz.itemconfig(self.ids['slot_' + str(self.x * self.y - 1)],
                                 fill='',
                                 outline='')

    #when cursor leaved the slot
    def Leaved(self, x):
        if x != 'slot_' + str(self.x * self.y - 1):
            self.puzz.itemconfig(self.ids[x], fill='#eeeeee')
        else:
            self.puzz.itemconfig(self.ids['slot_' + str(self.x * self.y - 1)],
                                 fill='',
                                 outline='')

    # notices the click and decides if the swapper fuction is to be called
    def clicked(self, x):
        cid = int(x[5:])  #it is the actual name of the box that is clicked on
        cpos = self.grids[cid][6]  #it is its position on the canvas
        bpos = self.grids[self.x * self.y -
                          1][6]  # it is postion of blank in canvas
        if cpos in self.allowables[bpos]:
            self.swapper(cid)

    #swappes the clicked slot with the blank slot
    def swapper(self, x):
        ##print(x,self.grids[x][6], '\t',self.grids[self.x*self.y-1][6])
        ccoor = self.puzz.coords('slot_' + str(x))
        bcoor = self.puzz.coords('slot_' + str(self.x * self.y - 1))
        #now moving the slots
        # and changing their data respectively
        #blank moving left
        if ccoor[0] < bcoor[0]:
            self.puzz.move(self.ids['slot_' + str(self.x * self.y - 1)], -100,
                           0)
            self.puzz.move(self.ids['slot_' + str(x)], 100, 0)
            self.puzz.move(self.ids['text_' + str(x)], 100, 0)
            self.grids[self.x * self.y -
                       1][6] = self.grids[self.x * self.y - 1][6] - 1
            self.grids[x][6] = self.grids[x][6] + 1
        elif ccoor[1] < bcoor[1]:
            self.puzz.move(self.ids['slot_' + str(self.x * self.y - 1)], 0,
                           -100)
            self.puzz.move(self.ids['slot_' + str(x)], 0, 100)
            self.puzz.move(self.ids['text_' + str(x)], 0, 100)
            self.grids[self.x * self.y -
                       1][6] = self.grids[self.x * self.y - 1][6] - self.y
            self.grids[x][6] = self.grids[x][6] + self.y
        elif ccoor[0] > bcoor[0]:
            self.puzz.move(self.ids['slot_' + str(self.x * self.y - 1)], 100,
                           0)
            self.puzz.move(self.ids['slot_' + str(x)], -100, 0)
            self.puzz.move(self.ids['text_' + str(x)], -100, 0)
            self.grids[self.x * self.y -
                       1][6] = self.grids[self.x * self.y - 1][6] + 1
            self.grids[x][6] = self.grids[x][6] - 1
        elif ccoor[1] > bcoor[1]:
            self.puzz.move(self.ids['slot_' + str(self.x * self.y - 1)], 0,
                           100)
            self.puzz.move(self.ids['slot_' + str(x)], 0, -100)
            self.puzz.move(self.ids['text_' + str(x)], 0, -100)
            self.grids[self.x * self.y -
                       1][6] = self.grids[self.x * self.y - 1][6] + self.y
            self.grids[x][6] = self.grids[x][6] - self.y

        ###checking if all the slots are in positions
        self.__checker__()

    def __shuffler__(self, x):
        #print('shuffle was called')
        self.timer = [0, 0]
        try:
            self.__time_stopper__('wait')
        except:
            self.__timer_clock__()
            self.__time_stopper__('wait')
        #current poition of blanks          self.grids[24][6]
        #getting available swapsposition    self.allowables[self.grids[24][6]]
        if self.timeshuffle == None:
            self.shuffler2()

    def shuffler2(self):
        if self.shufflepoints <= 10:
            ch = []
            for i in self.allowables[self.grids[24][6]]:
                for j in range(25):
                    if self.grids[j][6] == i:
                        ch.append(j)
            ch = choice(ch)
            ch = 'slot_' + str(ch)
            self.clicked(ch)
            ##print(self.timeshuffle)
            self.shufflepoints += 1
            self.timeshuffle = self.root.after(100, self.shuffler2)
        else:
            self.root.after_cancel(self.timeshuffle)
            self.shufflepoints = 0
            self.timeshuffle = None
            self.__timer_clock__()

    def __checker__(self):
        'checking if the grid has been restored'
        if self.timeshuffle == None:
            correct = 0
            for i in range(25):
                if i == self.grids[i][6]:
                    correct += 1
            if correct == 25:
                #print('completed')
                #converting them into displayanle format
                if self.timer[1] <= 9:
                    secs = '0' + str(self.timer[1])
                else:
                    secs = str(self.timer[1])
                if self.timer[0] <= 9:
                    mins = '0' + str(self.timer[0])
                else:
                    mins = str(self.timer[0])
                timer = mins + ':' + secs
                try:
                    self.__time_stopper__(timer)
                except:
                    pass

    def __reset__(self, x):
        pass
        #del game
        #print('game deleted')
        #still working on it

    def __del__(self):
        pass
class ConcordanceSearchView(object):
    _BACKGROUND_COLOUR='#FFF' #white

    #Colour of highlighted results
    _HIGHLIGHT_WORD_COLOUR='#F00' #red
    _HIGHLIGHT_WORD_TAG='HL_WRD_TAG'

    _HIGHLIGHT_LABEL_COLOUR='#C0C0C0' # dark grey
    _HIGHLIGHT_LABEL_TAG='HL_LBL_TAG'


    #Percentage of text left of the scrollbar position
    _FRACTION_LEFT_TEXT=0.30

    def __init__(self):
        self.queue = q.Queue()
        self.model = ConcordanceSearchModel(self.queue)
        self.top = Tk()
        self._init_top(self.top)
        self._init_menubar()
        self._init_widgets(self.top)
        self.load_corpus(self.model.DEFAULT_CORPUS)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def _init_top(self, top):
        top.geometry('950x680+50+50')
        top.title('NLTK Concordance Search')
        top.bind('<Control-q>', self.destroy)
        top.protocol('WM_DELETE_WINDOW', self.destroy)
        top.minsize(950,680)

    def _init_widgets(self, parent):
        self.main_frame = Frame(parent, dict(background=self._BACKGROUND_COLOUR, padx=1, pady=1, border=1))
        self._init_corpus_select(self.main_frame)
        self._init_query_box(self.main_frame)
        self._init_results_box(self.main_frame)
        self._init_paging(self.main_frame)
        self._init_status(self.main_frame)
        self.main_frame.pack(fill='both', expand=True)

    def _init_menubar(self):
        self._result_size = IntVar(self.top)
        self._cntx_bf_len = IntVar(self.top)
        self._cntx_af_len = IntVar(self.top)
        menubar = Menu(self.top)

        filemenu = Menu(menubar, tearoff=0, borderwidth=0)
        filemenu.add_command(label='Exit', underline=1,
                             command=self.destroy, accelerator='Ctrl-q')
        menubar.add_cascade(label='File', underline=0, menu=filemenu)

        editmenu = Menu(menubar, tearoff=0)
        rescntmenu = Menu(editmenu, tearoff=0)
        rescntmenu.add_radiobutton(label='20', variable=self._result_size,
                                   underline=0, value=20,
                                   command=self.set_result_size)
        rescntmenu.add_radiobutton(label='50', variable=self._result_size,
                                   underline=0, value=50,
                                   command=self.set_result_size)
        rescntmenu.add_radiobutton(label='100', variable=self._result_size,
                                   underline=0, value=100,
                                   command=self.set_result_size)
        rescntmenu.invoke(1)
        editmenu.add_cascade(label='Result Count', underline=0, menu=rescntmenu)

        cntxmenu = Menu(editmenu, tearoff=0)
        cntxbfmenu = Menu(cntxmenu, tearoff=0)
        cntxbfmenu.add_radiobutton(label='60 characters',
                                   variable=self._cntx_bf_len,
                                   underline=0, value=60,
                                   command=self.set_cntx_bf_len)
        cntxbfmenu.add_radiobutton(label='80 characters',
                                   variable=self._cntx_bf_len,
                                   underline=0, value=80,
                                   command=self.set_cntx_bf_len)
        cntxbfmenu.add_radiobutton(label='100 characters',
                                   variable=self._cntx_bf_len,
                                   underline=0, value=100,
                                   command=self.set_cntx_bf_len)
        cntxbfmenu.invoke(1)
        cntxmenu.add_cascade(label='Before', underline=0, menu=cntxbfmenu)

        cntxafmenu = Menu(cntxmenu, tearoff=0)
        cntxafmenu.add_radiobutton(label='70 characters',
                                   variable=self._cntx_af_len,
                                   underline=0, value=70,
                                   command=self.set_cntx_af_len)
        cntxafmenu.add_radiobutton(label='90 characters',
                                   variable=self._cntx_af_len,
                                   underline=0, value=90,
                                   command=self.set_cntx_af_len)
        cntxafmenu.add_radiobutton(label='110 characters',
                                   variable=self._cntx_af_len,
                                   underline=0, value=110,
                                   command=self.set_cntx_af_len)
        cntxafmenu.invoke(1)
        cntxmenu.add_cascade(label='After', underline=0, menu=cntxafmenu)

        editmenu.add_cascade(label='Context', underline=0, menu=cntxmenu)

        menubar.add_cascade(label='Edit', underline=0, menu=editmenu)

        self.top.config(menu=menubar)

    def set_result_size(self, **kwargs):
        self.model.result_count = self._result_size.get()

    def set_cntx_af_len(self, **kwargs):
        self._char_after = self._cntx_af_len.get()

    def set_cntx_bf_len(self, **kwargs):
        self._char_before = self._cntx_bf_len.get()

    def _init_corpus_select(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.var = StringVar(innerframe)
        self.var.set(self.model.DEFAULT_CORPUS)
        Label(innerframe, justify=LEFT, text=' Corpus: ',
              background=self._BACKGROUND_COLOUR, padx = 2, pady = 1, border = 0).pack(side='left')

        other_corpora = list(self.model.CORPORA.keys()).remove(self.model.DEFAULT_CORPUS)
        om = OptionMenu(innerframe, self.var, self.model.DEFAULT_CORPUS, command=self.corpus_selected, *self.model.non_default_corpora())
        om['borderwidth'] = 0
        om['highlightthickness'] = 1
        om.pack(side='left')
        innerframe.pack(side='top', fill='x', anchor='n')

    def _init_status(self, parent):
        self.status = Label(parent, justify=LEFT, relief=SUNKEN, background=self._BACKGROUND_COLOUR, border=0, padx = 1, pady = 0)
        self.status.pack(side='top', anchor='sw')

    def _init_query_box(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        another = Frame(innerframe, background=self._BACKGROUND_COLOUR)
        self.query_box = Entry(another, width=60)
        self.query_box.pack(side='left', fill='x', pady=25, anchor='center')
        self.search_button = Button(another, text='Search', command=self.search, borderwidth=1, highlightthickness=1)
        self.search_button.pack(side='left', fill='x', pady=25, anchor='center')
        self.query_box.bind('<KeyPress-Return>', self.search_enter_keypress_handler)
        another.pack()
        innerframe.pack(side='top', fill='x', anchor='n')

    def search_enter_keypress_handler(self, *event):
        self.search()

    def _init_results_box(self, parent):
        innerframe = Frame(parent)
        i1 = Frame(innerframe)
        i2 = Frame(innerframe)
        vscrollbar = Scrollbar(i1, borderwidth=1)
        hscrollbar = Scrollbar(i2, borderwidth=1, orient='horiz')
        self.results_box = Text(i1,
                                font=tkinter.font.Font(family='courier', size='16'),
                                state='disabled', borderwidth=1,
                                                            yscrollcommand=vscrollbar.set,
                                xscrollcommand=hscrollbar.set, wrap='none', width='40', height = '20', exportselection=1)
        self.results_box.pack(side='left', fill='both', expand=True)
        self.results_box.tag_config(self._HIGHLIGHT_WORD_TAG, foreground=self._HIGHLIGHT_WORD_COLOUR)
        self.results_box.tag_config(self._HIGHLIGHT_LABEL_TAG, foreground=self._HIGHLIGHT_LABEL_COLOUR)
        vscrollbar.pack(side='left', fill='y', anchor='e')
        vscrollbar.config(command=self.results_box.yview)
        hscrollbar.pack(side='left', fill='x', expand=True, anchor='w')
        hscrollbar.config(command=self.results_box.xview)
        #there is no other way of avoiding the overlap of scrollbars while using pack layout manager!!!
        Label(i2, text='   ', background=self._BACKGROUND_COLOUR).pack(side='left', anchor='e')
        i1.pack(side='top', fill='both', expand=True, anchor='n')
        i2.pack(side='bottom', fill='x', anchor='s')
        innerframe.pack(side='top', fill='both', expand=True)

    def _init_paging(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.prev = prev = Button(innerframe, text='Previous', command=self.previous, width='10', borderwidth=1, highlightthickness=1, state='disabled')
        prev.pack(side='left', anchor='center')
        self.next = next = Button(innerframe, text='Next', command=self.__next__, width='10', borderwidth=1, highlightthickness=1, state='disabled')
        next.pack(side='right', anchor='center')
        innerframe.pack(side='top', fill='y')
        self.current_page = 0

    def previous(self):
        self.clear_results_box()
        self.freeze_editable()
        self.model.prev(self.current_page - 1)

    def __next__(self):
        self.clear_results_box()
        self.freeze_editable()
        self.model.next(self.current_page + 1)

    def about(self, *e):
        ABOUT = ("NLTK Concordance Search Demo\n")
        TITLE = 'About: NLTK Concordance Search Demo'
        try:
            from tkinter.messagebox import Message
            Message(message=ABOUT, title=TITLE, parent=self.main_frame).show()
        except:
            ShowText(self.top, TITLE, ABOUT)

    def _bind_event_handlers(self):
        self.top.bind(CORPUS_LOADED_EVENT, self.handle_corpus_loaded)
        self.top.bind(SEARCH_TERMINATED_EVENT, self.handle_search_terminated)
        self.top.bind(SEARCH_ERROR_EVENT, self.handle_search_error)
        self.top.bind(ERROR_LOADING_CORPUS_EVENT, self.handle_error_loading_corpus)

    def _poll(self):
        try:
            event = self.queue.get(block=False)
        except q.Empty:
            pass
        else:
            if event == CORPUS_LOADED_EVENT:
                self.handle_corpus_loaded(event)
            elif event == SEARCH_TERMINATED_EVENT:
                self.handle_search_terminated(event)
            elif event == SEARCH_ERROR_EVENT:
                self.handle_search_error(event)
            elif event == ERROR_LOADING_CORPUS_EVENT:
                self.handle_error_loading_corpus(event)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def handle_error_loading_corpus(self, event):
        self.status['text'] = 'Error in loading ' + self.var.get()
        self.unfreeze_editable()
        self.clear_all()
        self.freeze_editable()

    def handle_corpus_loaded(self, event):
        self.status['text'] = self.var.get() + ' is loaded'
        self.unfreeze_editable()
        self.clear_all()
        self.query_box.focus_set()

    def handle_search_terminated(self, event):
        #todo: refactor the model such that it is less state sensitive
        results = self.model.get_results()
        self.write_results(results)
        self.status['text'] = ''
        if len(results) == 0:
            self.status['text'] = 'No results found for ' + self.model.query
        else:
                self.current_page = self.model.last_requested_page
        self.unfreeze_editable()
        self.results_box.xview_moveto(self._FRACTION_LEFT_TEXT)

    def handle_search_error(self, event):
        self.status['text'] = 'Error in query ' + self.model.query
        self.unfreeze_editable()

    def corpus_selected(self, *args):
        new_selection = self.var.get()
        self.load_corpus(new_selection)

    def load_corpus(self, selection):
        if self.model.selected_corpus != selection:
            self.status['text'] = 'Loading ' + selection + '...'
            self.freeze_editable()
            self.model.load_corpus(selection)

    def search(self):
        self.current_page = 0
        self.clear_results_box()
        self.model.reset_results()
        query = self.query_box.get()
        if (len(query.strip()) == 0): return
        self.status['text']  = 'Searching for ' + query
        self.freeze_editable()
        self.model.search(query, self.current_page + 1, )


    def write_results(self, results):
        self.results_box['state'] = 'normal'
        row = 1
        for each in results:
            sent, pos1, pos2 = each[0].strip(), each[1], each[2]
            if len(sent) != 0:
                if (pos1 < self._char_before):
                    sent, pos1, pos2 = self.pad(sent, pos1, pos2)
                sentence = sent[pos1-self._char_before:pos1+self._char_after]
                if not row == len(results):
                    sentence += '\n'
                self.results_box.insert(str(row) + '.0', sentence)
                word_markers, label_markers = self.words_and_labels(sent, pos1, pos2)
                for marker in word_markers: self.results_box.tag_add(self._HIGHLIGHT_WORD_TAG, str(row) + '.' + str(marker[0]), str(row) + '.' + str(marker[1]))
                for marker in label_markers: self.results_box.tag_add(self._HIGHLIGHT_LABEL_TAG, str(row) + '.' + str(marker[0]), str(row) + '.' + str(marker[1]))
                row += 1
        self.results_box['state'] = 'disabled'

    def words_and_labels(self, sentence, pos1, pos2):
        search_exp = sentence[pos1:pos2]
        words, labels = [], []
        labeled_words = search_exp.split(' ')
        index = 0
        for each in labeled_words:
            if each == '':
                index += 1
            else:
                word, label = each.split('/')
                words.append((self._char_before + index, self._char_before + index + len(word)))
                index += len(word) + 1
                labels.append((self._char_before + index, self._char_before + index + len(label)))
                index += len(label)
            index += 1
        return words, labels

    def pad(self, sent, hstart, hend):
        if hstart >= self._char_before:
            return sent, hstart, hend
        d = self._char_before - hstart
        sent = ''.join([' '] * d) + sent
        return sent, hstart + d, hend + d

    def destroy(self, *e):
        if self.top is None: return
        self.top.after_cancel(self.after)
        self.top.destroy()
        self.top = None

    def clear_all(self):
        self.query_box.delete(0, END)
        self.model.reset_query()
        self.clear_results_box()

    def clear_results_box(self):
        self.results_box['state'] = 'normal'
        self.results_box.delete("1.0", END)
        self.results_box['state'] = 'disabled'

    def freeze_editable(self):
        self.query_box['state'] = 'disabled'
        self.search_button['state'] = 'disabled'
        self.prev['state'] = 'disabled'
        self.next['state'] = 'disabled'

    def unfreeze_editable(self):
        self.query_box['state'] = 'normal'
        self.search_button['state'] = 'normal'
        self.set_paging_button_states()

    def set_paging_button_states(self):
        if self.current_page == 0 or self.current_page == 1:
            self.prev['state'] = 'disabled'
        else:
            self.prev['state'] = 'normal'
        if self.model.has_more_pages(self.current_page):
            self.next['state'] = 'normal'
        else:
            self.next['state'] = 'disabled'

    def fire_event(self, event):
        #Firing an event so that rendering of widgets happen in the mainloop thread
        self.top.event_generate(event, when='tail')

    def mainloop(self, *args, **kwargs):
        if in_idle(): return
        self.top.mainloop(*args, **kwargs)
Example #8
0
class TkViewer(Viewer):
    """Graphical viewer using Tk."""
    # size of a tile
    w_tile = 50
    # width of a wall
    w_wall = 20
    # size of a cell (including the walls)
    w = w_tile + w_wall
    # diameter of a pawn
    w_pawn = 4 * w_tile / 5
    # length of a wall
    l_wall = 2 * w_tile + w_wall
    # the x offset before the board begins
    x_offset = 20
    # the y offset before the board begins
    y_offset = 20
    # the separation between the tiles and the unused walls
    y_separa = 10
    # the width of the scoreboard
    scoreboard_width = 300
    # the y distance between the walls on the scoreboard
    y_wall_scoreboard_offset = y_offset
    # the x distance between the walls on the scoreboard
    x_wall_scoreboard_offset = 25
    # the x offset of the scoreboard
    x_scoreboard_offset = (scoreboard_width - 5 * w_wall -
                           4 * x_wall_scoreboard_offset) / 2
    # the y offset of the scoreboard
    y_scoreboard_offset = y_offset / 2
    # the fontsize used in the scoreboard
    scoreboard_font_size = 14
    # the total x offset on the left
    left_off_x = x_offset + w_wall / 2
    # the total y offset on the left
    left_off_y = y_offset + w_wall / 2
    # the total x offset on the right
    right_off_x = left_off_x + w_tile * 9 + w_wall * 8
    # the total y offset on the right
    right_off_y = left_off_y + w_tile * 9 + w_wall * 8

    names = ('Blue', 'Red', 'Teal', 'Yellow')  # player names
    pawn_colors = ('#3465A4', '#EF2929', '#008080', '#ffff00'
                   )  # pawn player colors
    pawn_outlin = ('#C2D0E3', '#FABEBE', '#000000', '#000000')
    tile_color = '#EEEEEC'
    tile_backg = '#631919'
    wall_color = '#F1E2BE'
    wall_outli = ('#3465A4', '#EF2929', '#008080', '#ffff00')
    wall_backg = '#999999'

    # these defaults are all overwritten during the normal game flow.
    # it was hacked around so that we could type-hint without refactoring.
    canvas_width: int = 0
    canvas_height: int = 0
    canvas: Canvas = None  # type: ignore
    tile_ids: List[List[int]] = []
    bg_h_wall_ids: List[List[int]] = []
    bg_v_wall_ids: List[List[int]] = []
    h_wall_ids: List[List[int]] = []
    v_wall_ids: List[List[int]] = []
    scoreboard_wall_ids: List[List[int]] = []
    pawn_ids: List[int] = []
    scoreboard: Canvas = None  # type: ignore
    wall_titles: List[int] = []
    status: Label = None  # type: ignore
    status_text: str = ""
    substatus_text: str = ""
    buttons: Frame = None  # type: ignore
    action: Action = None  # type: ignore
    player: int = None  # type: ignore
    selection: TkObject = None  # type: ignore

    # these are used during replays
    trace: Trace = None  # type: ignore
    speed: float = 0
    boards: List[Board] = []

    ###########################################################################
    # Helper functions

    def get_tile_xy(self, i: XY, j: XY) -> Coordinates:
        y = self.y_offset + (i + .5) * self.w
        x = self.x_offset + (j + .5) * self.w
        return x, y

    def get_wall_xy(self, i: XY, j: XY) -> Coordinates:
        y = self.y_offset + (i + 1) * self.w
        x = self.x_offset + (j + 1) * self.w
        return x, y

    def get_wall_scoreboard_xy(self, player: int,
                               wall_num: int) -> Coordinates:
        y = (self.scoreboard_font_size + self.y_scoreboard_offset +
             self.y_wall_scoreboard_offset + 0.5 * self.l_wall)
        y += (self.canvas_height / len(self.board.pawns)) * player

        if wall_num >= 5:
            y += self.l_wall + self.y_wall_scoreboard_offset
        x = (self.x_scoreboard_offset + (wall_num % 5 + 0.5) * self.w_wall +
             (wall_num % 5) * self.x_wall_scoreboard_offset)
        return x, y

    def get_object(self, x: XY, y: XY) -> TkObject:
        if (x < self.left_off_x) or (y < self.left_off_y) or (
                x >= self.right_off_x) or (y >= self.right_off_y):
            return -1, -1, 'border'

        x_rest = (x - self.left_off_x) % self.w
        y_rest = (y - self.left_off_y) % self.w

        if x_rest < self.w_tile and y_rest < self.w_tile:
            column = int((x - self.left_off_x) / self.w)
            row = int((y - self.left_off_y) / self.w)
            return row, column, 'tile'

        if x_rest > self.w_tile > y_rest:
            column = int((x - self.left_off_x) / self.w)
            if (y - self.left_off_y) < (self.w + self.w_tile / 2):
                row = 0
            elif (y - self.left_off_y) >= (self.w * 7 + self.w_tile / 2):
                row = 7
            else:
                row = 1 + int(
                    (y - (self.left_off_y + self.w + self.w_tile / 2)) /
                    (self.w_tile + self.w_wall))
            return row, column, 'bg_v_wall'

        else:
            row = int((y - self.left_off_y) / self.w)
            if (x - self.x_offset) < (self.w + self.w_tile / 2):
                column = 0
            elif (x - self.x_offset) >= (self.w * 7 + self.w_tile / 2):
                column = 7
            else:
                column = 1 + int(
                    (x - (self.left_off_x + self.w + self.w_tile / 2)) /
                    (self.w_tile + self.w_wall))

            return row, column, 'bg_h_wall'

    ###########################################################################
    # UI construction

    def __init__(self) -> None:
        super().__init__()
        self.running = False
        self.root = Tk()
        self.barrier = threading.Event()
        self.barrier.clear()

        self.b_prev: Button = None  # type: ignore
        self.b_play: Button = None  # type: ignore
        self.b_next: Button = None  # type: ignore
        self.is_playing: bool = False
        self.step: int = 0
        self.after_id = None

    def init_viewer(self, board: Board) -> None:
        super().init_viewer(board)
        self.barrier.set()

    def run(self) -> None:
        """Launch the GUI."""
        if self.running:
            return

        self.running = True
        self.barrier.wait()

        # Create UI
        self.canvas_width = 2 * self.x_offset + self.w * self.board.cols
        self.canvas_height = 2 * self.y_offset + self.w * self.board.rows

        # Root window
        self.root.title('Quoridor')
        self.root.resizable(False, False)
        self.root.bind_all('<Escape>', self.close)
        mainframe = Frame(self.root)
        mainframe.pack()

        # Canvas board
        self.canvas = Canvas(mainframe,
                             width=self.canvas_width,
                             height=self.canvas_height)
        self.canvas.pack(side=LEFT)

        # tile_ids is filled by _update_gui
        self.tile_ids = [[0] * self.board.cols for _ in range(self.board.rows)]
        wall_ids = [[0] * (self.board.cols - 1)
                    for _ in range(self.board.rows - 1)]
        self.bg_h_wall_ids = wall_ids
        self.bg_v_wall_ids = deepcopy(wall_ids)
        self.h_wall_ids = deepcopy(wall_ids)
        self.v_wall_ids = deepcopy(wall_ids)
        self.scoreboard_wall_ids = [[
            0 for _ in range(self.board.starting_wall_count)
        ] for _ in range(len(self.board.pawns))]
        self.pawn_ids = [0 for _ in range(len(self.board.pawns))]

        for i in range(self.board.rows):
            for j in range(self.board.cols):
                x, y = self.get_tile_xy(i, j)
                self.canvas.create_rectangle(x - self.w_tile / 2,
                                             y - self.w_tile / 2,
                                             x + self.w_tile / 2,
                                             y + self.w_tile / 2,
                                             width=2,
                                             outline='grey')

        # Score board
        medfont = Font(size=self.scoreboard_font_size)
        self.scoreboard = Canvas(mainframe,
                                 width=self.scoreboard_width,
                                 height=self.canvas_height)
        self.scoreboard.pack(side=RIGHT)
        self.wall_titles = [
            self.scoreboard.create_text(self.scoreboard_width / 2,
                                        self.y_scoreboard_offset,
                                        font=medfont,
                                        anchor='n'),
            self.scoreboard.create_text(
                self.scoreboard_width / 2,
                self.y_scoreboard_offset +
                self.canvas_height / len(self.board.pawns),
                font=medfont,
                anchor='n'),
            self.scoreboard.create_text(
                self.scoreboard_width / 2,
                self.y_scoreboard_offset +
                (self.canvas_height / len(self.board.pawns)) * 2,
                font=medfont,
                anchor='n'),
            self.scoreboard.create_text(
                self.scoreboard_width / 2,
                self.y_scoreboard_offset +
                (self.canvas_height / len(self.board.pawns)) * 3,
                font=medfont,
                anchor='n')
        ]

        self.scoreboard.itemconfigure(self.wall_titles[0],
                                      fill=self.pawn_colors[0],
                                      text='Walls of player 1')
        self.scoreboard.itemconfigure(self.wall_titles[1],
                                      fill=self.pawn_colors[1],
                                      text='Walls of player 2')
        self.scoreboard.itemconfigure(self.wall_titles[2],
                                      fill=self.pawn_colors[2],
                                      text='Walls of player 3')
        self.scoreboard.itemconfigure(self.wall_titles[3],
                                      fill=self.pawn_colors[3],
                                      text='Walls of player 4')

        # Status bar
        self.status = Label(self.root, height=2, justify=LEFT)
        self.status.pack(side=LEFT)
        self.status_text = ""
        self.substatus_text = ""
        self.buttons = Frame(self.root)
        self.buttons.pack(side=RIGHT)

        # Draw board
        self.draw_board(self.board)

        # Launch event loop
        try:
            self.root.mainloop()
        except KeyboardInterrupt:
            pass

        # ensure the main thread exits when closing viewer during human action
        self.root = None  # type: ignore
        self.action = None  # type: ignore  # generate invalid action
        self.barrier.set()

    ###########################################################################
    # General UI

    def close(self, event: TkEvent = None) -> None:
        """Close the GUI."""
        if self.root is not None:
            self.root.destroy()

    def set_status(self, new_status: str) -> None:
        """Set the first line of the status bar."""
        s = self.status_text = new_status
        if self.substatus_text:
            s += '\n' + self.substatus_text
        self.status['text'] = s

    def set_substatus(self, new_substatus: str) -> None:
        """Set the second line of the status bar."""
        self.substatus_text = new_substatus
        self.set_status(self.status_text)

    ###########################################################################
    # Viewer UI

    def playing(self, step: int, player: int) -> None:
        if self.root is None:
            return
        self.root.after_idle(self._playing, step, player)

    def _playing(self, step: int, player: int) -> None:
        # This method may only be called from the gui thread.
        self.set_status(f'Step {step}: {self.names[player]}\'s turn.')
        self.set_substatus("")

    def update(self, step: int, action: Action, player: int) -> None:
        self.board.play_action(action, player)
        if self.root is not None:
            self.root.after_idle(self.redraw_board, self.board)

    def draw_board(self, board: Board) -> None:
        # creating the background
        self.canvas.create_rectangle(self.x_offset,
                                     self.y_offset,
                                     self.x_offset + self.w * self.board.cols,
                                     self.y_offset + self.w * self.board.rows,
                                     fill=self.wall_backg,
                                     outline=self.wall_backg)

        # creating the walls (on the board)
        for i in range(board.rows - 1):
            for j in range(board.cols - 1):
                x, y = self.get_wall_xy(i, j)
                self.canvas.create_rectangle(x - self.l_wall / 2,
                                             y - self.w_wall / 2,
                                             x + self.l_wall / 2,
                                             y + self.w_wall / 2,
                                             fill=self.wall_backg,
                                             outline=self.wall_backg,
                                             tags=['bg_h_walls'])
                self.bg_h_wall_ids[i][j] = self.canvas.create_rectangle(
                    x - self.l_wall / 2,
                    y - self.w_wall / 2 + 2,
                    x + self.l_wall / 2,
                    y + self.w_wall / 2 - 3,
                    tags=['bg_h_walls'],
                    width=0)
                self.mark_object((i, j, 'bg_h_wall'))
                self.canvas.create_rectangle(x - self.w_wall / 2,
                                             y - self.l_wall / 2,
                                             x + self.w_wall / 2,
                                             y + self.l_wall / 2,
                                             fill=self.wall_backg,
                                             outline=self.wall_backg,
                                             tags=['bg_v_walls'])
                self.bg_v_wall_ids[i][j] = self.canvas.create_rectangle(
                    x - self.w_wall / 2 + 2,
                    y - self.l_wall / 2,
                    x + self.w_wall / 2 - 3,
                    y + self.l_wall / 2,
                    tags=['bg_v_walls'],
                    width=0)
                self.mark_object((i, j, 'bg_v_wall'))

        # creating the tiles
        for i in range(board.rows):
            for j in range(board.cols):
                x, y = self.get_tile_xy(i, j)
                self.canvas.create_rectangle(x - self.w_tile / 2,
                                             y - self.w_tile / 2,
                                             x + self.w_tile / 2,
                                             y + self.w_tile / 2,
                                             fill=self.tile_backg,
                                             tags=['tiles'])
                self.tile_ids[i][j] = self.canvas.create_rectangle(
                    x - self.w_tile / 2,
                    y - self.w_tile / 2,
                    x + self.w_tile / 2,
                    y + self.w_tile / 2,
                    tags=['tiles'])
                # ensure coherent unselected appearance
                self.mark_object((i, j, 'tile'))

        # creating the wall slots (on the scoreboard)
        for player in range(self.board.player_count):
            i, j = self.board.pawns[player]
            x, y = self.get_tile_xy(i, j)
            self.pawn_ids[player] = self.canvas.create_oval(
                x - self.w_pawn / 2,
                y - self.w_pawn / 2,
                x + self.w_pawn / 2,
                y + self.w_pawn / 2,
                fill=self.pawn_colors[player],
                outline=self.pawn_outlin[player],
                width=2,
                tags=['pawns'])
            for wall_num in range(self.board.player_walls[player]):
                x, y = self.get_wall_scoreboard_xy(player, wall_num)
                self.scoreboard.create_rectangle(x - self.w_wall / 2,
                                                 y - self.l_wall / 2,
                                                 x + self.w_wall / 2,
                                                 y + self.l_wall / 2,
                                                 fill=self.wall_backg,
                                                 outline=self.wall_backg)
                self.scoreboard_wall_ids[player][
                    wall_num] = self.scoreboard.create_rectangle(
                        x - self.w_wall / 2 + 1,
                        y - self.l_wall / 2 + 1,
                        x + self.w_wall / 2,
                        y + self.l_wall / 2,
                        fill=self.wall_color,
                        outline=self.wall_outli[player],
                        width=2,
                        tags=['scoreboard_walls'])

        for i, j in self.board.horiz_walls:
            x, y = self.get_wall_xy(i, j)
            self.h_wall_ids[i][j] = self.canvas.create_rectangle(
                x - self.l_wall / 2,
                y - self.w_wall / 2 + 2,
                x + self.l_wall / 2,
                y + self.w_wall / 2 - 3,
                fill=self.wall_color,
                width=2,
                tags=['h_walls'])

        for i, j in self.board.verti_walls:
            x, y = self.get_wall_xy(i, j)
            self.v_wall_ids[i][j] = self.canvas.create_rectangle(
                x - self.w_wall / 2 + 2,
                y - self.l_wall / 2,
                x + self.w_wall / 2 - 3,
                y + self.l_wall / 2,
                fill=self.wall_color,
                width=2,
                tags=['v_walls'])

    def redraw_board(self, board: Board) -> None:
        """Draw a board with all unselected tiles."""
        self.canvas.delete('pawns')
        self.canvas.delete('h_walls')
        self.canvas.delete('v_walls')
        self.scoreboard.delete('scoreboard_walls')

        for i in range(board.rows):
            for j in range(board.cols):
                # ensure coherent unselected appearance
                self.mark_object((i, j, 'tile'))

        for player in range(self.board.player_count):
            i, j = self.board.pawns[player]
            x, y = self.get_tile_xy(i, j)
            self.pawn_ids[player] = self.canvas.create_oval(
                x - self.w_pawn / 2,
                y - self.w_pawn / 2,
                x + self.w_pawn / 2,
                y + self.w_pawn / 2,
                fill=self.pawn_colors[player],
                outline=self.pawn_outlin[player],
                width=2,
                tags=['pawns'])
            for wall_num in range(self.board.player_walls[player]):
                x, y = self.get_wall_scoreboard_xy(player, wall_num)
                self.scoreboard_wall_ids[player][
                    wall_num] = self.scoreboard.create_rectangle(
                        x - self.w_wall / 2 + 1,
                        y - self.l_wall / 2 + 1,
                        x + self.w_wall / 2,
                        y + self.l_wall / 2,
                        fill=self.wall_color,
                        outline=self.wall_outli[player],
                        width=2,
                        tags=['scoreboard_walls'])

        for i in range(board.rows - 1):
            for j in range(board.cols - 1):
                self.mark_object((i, j, 'bg_h_wall'))
                self.mark_object((i, j, 'bg_v_wall'))

        for i, j in self.board.horiz_walls:
            x, y = self.get_wall_xy(i, j)
            self.canvas.create_rectangle(x - self.l_wall / 2,
                                         y - self.w_wall / 2 + 2,
                                         x + self.l_wall / 2,
                                         y + self.w_wall / 2 - 3,
                                         fill=self.wall_color,
                                         width=2,
                                         tags=['h_walls'])

        for i, j in self.board.verti_walls:
            x, y = self.get_wall_xy(i, j)
            self.canvas.create_rectangle(x - self.w_wall / 2 + 2,
                                         y - self.l_wall / 2,
                                         x + self.w_wall / 2 - 3,
                                         y + self.l_wall / 2,
                                         fill=self.wall_color,
                                         width=2,
                                         tags=['v_walls'])

    def mark_object(self,
                    selection: Tuple[int, int, str],
                    style: str = 'unselected') -> None:
        """Mark tile as unselected, hover or moving."""
        i, j, object_type = selection

        if object_type == 'tile':
            o = self.tile_ids[i][j]
            if style == 'unselected':
                self.canvas.itemconfigure(o, outline=self.tile_color, width=2)
            elif style == 'hover':
                self.canvas.itemconfigure(o, outline='#008000', width=3)
            else:
                assert False

        if object_type == 'bg_h_wall':
            o = self.bg_h_wall_ids[i][j]
            if style == 'unselected':
                self.canvas.tag_lower(o, 'tiles')
                self.canvas.itemconfigure(o, width=0)
            elif style == 'hover':
                self.canvas.tag_raise(o, 'tiles')
                self.canvas.itemconfigure(o, outline='#008000', width=3)
            else:
                assert False

        if object_type == 'bg_v_wall':
            o = self.bg_v_wall_ids[i][j]
            if style == 'unselected':
                self.canvas.tag_lower(o, 'tiles')
                self.canvas.itemconfigure(o, width=0)
            elif style == 'hover':
                self.canvas.tag_raise(o, 'tiles')
                self.canvas.itemconfigure(o, outline='#008000', width=3)
            else:
                assert False

    def put_wall(self, player: int) -> None:
        """Deduct a wall from player."""
        self.scoreboard.delete(
            self.scoreboard_wall_ids[player][self.board.player_walls[player] -
                                             1])

    def finished(self, steps: int, winner: int, reason: str = "") -> None:
        if self.root is None:
            return
        self.root.after_idle(self._finished, steps, winner, reason)

    def _finished(self, step: int, winner: int, reason: str = "") -> None:
        # This method may only be called from the gui thread.
        if not winner:
            s = 'Draw game'
        elif winner > 0:
            s = f'{"/".join(n for p, n in enumerate(self.names) if p % 2 == 0)} has won'
        else:
            s = f'{"/".join(n for p, n in enumerate(self.names) if p % 2 == 1)} has won'

        s += f' after {step} steps.'
        self.set_status(s)
        if reason:
            self.set_substatus(reason)
        self.canvas.unbind('<Motion>')
        self.canvas.unbind('<Button-1>')

    ###########################################################################
    # Human player UI

    def play(self, percepts: Board, player: int, step: int,
             time_left: float) -> Optional[Action]:
        if self.root is None:
            return None
        self.player = player
        self.barrier.clear()
        self.root.after_idle(self._play_start)
        self.barrier.wait()
        return self.action

    def _play_start(self) -> None:
        """Configure GUI to accept user input."""
        self.canvas.bind('<Leave>', self._play_leave)
        self.canvas.bind('<Motion>', self._play_motion)
        self.canvas.bind('<Button-1>', self._play_click)
        self._play_reset()

    def _play_reset(self, event: TkEvent = None) -> None:
        self.action = None  # type: ignore
        self.selection = None  # type: ignore
        self.set_substatus('Select a tile to move.')
        self.canvas.event_generate('<Motion>')

    def _play_leave(self, event: TkEvent) -> None:
        if event.state & 0x100:  # leave event is also called on mouse click
            return
        if self.selection is not None:
            self.mark_object(self.selection)
            self.selection = None  # type: ignore

    def _play_motion(self, event: TkEvent) -> None:
        self._play_leave(event)
        i, j, object_type = self.get_object(event.x, event.y)

        if i < 0 or i >= self.board.rows or j < 0 or j >= self.board.cols:
            return

        if object_type == 'tile' and self.board.can_move_here(
                i, j, self.player):
            self.selection = (i, j, object_type)
            self.mark_object(self.selection, 'hover')

        elif object_type == 'bg_h_wall' and self.board.is_wall_possible_here(
            (i, j), True) and (self.board.player_walls[self.player] > 0):
            self.selection = (i, j, object_type)
            self.mark_object(self.selection, 'hover')

        elif object_type == 'bg_v_wall' and self.board.is_wall_possible_here(
            (i, j), False) and (self.board.player_walls[self.player] > 0):
            self.selection = (i, j, object_type)
            self.mark_object(self.selection, 'hover')

    def _play_click(self, event: TkEvent) -> None:
        if self.selection is not None:
            i, j, object_type = self.selection

            if object_type == 'tile':
                self.set_substatus("")
                self.barrier.set()
                self.action = (MOVE, i, j)

            elif object_type == 'bg_h_wall':
                self.put_wall(self.player)
                self.set_substatus("")
                self.barrier.set()
                self.action = (WALL_H, i, j)

            elif object_type == 'bg_v_wall':
                self.put_wall(self.player)
                self.set_substatus("")
                self.barrier.set()
                self.action = (WALL_V, i, j)

    ###########################################################################
    # Replay UI

    def replay(self,
               trace: Trace,
               speed: float = 1.0,
               show_end: bool = False) -> None:
        """Replay a game given its saved trace.

        Attributes:
        trace -- trace of the game
        speed -- speed scale of the replay
        show_end -- start with the final state instead of the initial state
        """
        self.trace = trace
        self.speed = speed
        # generate all boards to access them backwards
        self.boards = [trace.get_initial_board()]
        for player, action, t in trace.actions:
            b = self.boards[-1].clone()
            b.play_action(action, player)
            self.boards.append(b)
        if self.root is not None:
            self.root.after_idle(self._replay_gui, show_end)
        self._board = self.boards[0]
        self.barrier.set()
        self.run()

    def _replay_gui(self, show_end: bool) -> None:
        """Initialize replay UI."""
        self.b_prev = Button(self.buttons, text='<', command=self._replay_prev)
        self.b_play = Button(self.buttons,
                             text='Play',
                             command=self._replay_play)
        self.b_next = Button(self.buttons, text='>', command=self._replay_next)
        self.b_prev.pack(side=LEFT)
        self.b_play.pack(side=LEFT)
        self.b_next.pack(side=LEFT)
        self.root.bind_all('<Left>', self._replay_prev)
        self.root.bind_all('<Right>', self._replay_next)
        self.root.bind_all('<Home>', self._replay_first)
        self.root.bind_all('<End>', self._replay_last)
        self.root.bind_all('<space>', self._replay_play)
        self.is_playing = False
        if show_end:
            # Only used when replaying right after a game, so use the hack to
            # keep the last played action on screen
            self._replay_goto(len(self.boards) - 1)
        else:
            self._replay_goto(0)

    def _replay_goto(self, step: int) -> None:
        """Update UI to show one step."""
        self.step = step
        self._board = self.boards[step]
        self.redraw_board(self.board)
        if step == len(self.boards) - 1:
            self._finished(step, self.trace.winner, self.trace.reason)
            if self.is_playing:
                self.is_playing = False
                self.b_play['text'] = 'Play'
        else:
            player, _, t = self.trace.actions[step]
            self._playing(step, player)

        if self.is_playing:
            if self.speed < 0:
                step_time = -self.trace.actions[step][2] / self.speed
            else:
                step_time = self.speed
            self.after_id = self.root.after(int(step_time * 1000),
                                            self._replay_goto, step + 1)
        else:
            if not step:
                self.b_prev['state'] = DISABLED
            else:
                self.b_prev['state'] = NORMAL

            if step == len(self.boards) - 1:
                self.b_next['state'] = DISABLED
            else:
                self.b_next['state'] = NORMAL

    def _replay_next(self, event: TkEvent = None) -> None:
        if not self.is_playing and self.step < len(self.boards) - 1:
            self._replay_goto(self.step + 1)

    def _replay_prev(self, event: TkEvent = None) -> None:
        if not self.is_playing and self.step > 0:
            self._replay_goto(self.step - 1)

    def _replay_first(self, event: TkEvent = None) -> None:
        if not self.is_playing:
            self._replay_goto(0)

    def _replay_last(self, event: TkEvent = None) -> None:
        if not self.is_playing:
            self._replay_goto(len(self.boards) - 1)

    def _replay_play(self, event: TkEvent = None) -> None:
        if self.is_playing:
            self.root.after_cancel(self.after_id)
            self.is_playing = False
            self.b_play['text'] = 'Play'
            self._replay_goto(self.step)
        else:
            self.is_playing = True
            self.b_prev['state'] = DISABLED
            self.b_next['state'] = DISABLED
            self.b_play['text'] = 'Pause'
            if self.step < len(self.boards) - 1:
                self._replay_goto(self.step)
            else:
                self._replay_goto(0)
Example #9
0
class HOPSWindow:
    def __init__(self,
                 log=HOPSLog,
                 name='HOPS - window',
                 sizex=None,
                 sizey=None,
                 position=5):

        self.log = log

        self.root = Tk()
        self.mainloop_on = False
        self.exit = False
        self.name = name
        self.jobs = []
        self.root.wm_title(name)
        if sizex and sizey:
            self.root.geometry('{0}x{1}'.format(
                int(self.root.winfo_screenwidth() / sizex),
                int(self.root.winfo_screenheight() / sizey)))

        self.hide()

        self.finalised = False
        self.position = position

        self.DISABLED = DISABLED
        self.NORMAL = NORMAL
        self.END = END
        self.RIGHT = RIGHT
        self.LEFT = LEFT
        self.TOP = TOP
        self.BOTTOM = BOTTOM
        self.BOTH = BOTH
        self.Y = Y
        self.HORIZONTAL = HORIZONTAL
        self.VERTICAL = VERTICAL

        # # create a canvas object and a vertical scrollbar for scrolling it
        # self.vscrollbar = Scrollbar(self.root, orient=VERTICAL)
        # self.vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
        # self.canvas = Canvas(self.root, bd=0, highlightthickness=0,
        #                 yscrollcommand=self.vscrollbar.set)
        # self.canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
        # self.vscrollbar.config(command=self.canvas.yview)
        #
        # # reset the view
        # self.canvas.xview_moveto(0)
        # self.canvas.yview_moveto(0)
        #
        # # create a frame inside the canvas which will be scrolled with it
        # self.interior = Frame(self.canvas)
        # self.interior_id = self.canvas.create_window(0, 0, window=self.interior,
        #                                    anchor=NW)
        #
        # # track changes to the canvas and frame width and sync them,
        # # also updating the scrollbar
        # def _configure_interior(event):
        #     # update the scrollbars to match the size of the inner frame
        #     size = (self.interior.winfo_reqwidth(), self.interior.winfo_reqheight())
        #     self.canvas.config(scrollregion="0 0 %s %s" % size)
        #     if self.interior.winfo_reqwidth() != self.canvas.winfo_width():
        #         # update the canvas's width to fit the inner frame
        #         self.canvas.config(width=self.interior.winfo_reqwidth())
        #
        # self.interior.bind('<Configure>', _configure_interior)
        #
        # def _configure_canvas(event):
        #     if self.interior.winfo_reqwidth() != self.canvas.winfo_width():
        #         # update the inner frame's width to fill the canvas
        #         self.canvas.itemconfigure(self.interior_id, width=self.canvas.winfo_width())
        #
        # self.canvas.bind('<Configure>', _configure_canvas)

        # self.main_frame = self.interior
        self.main_frame = self.root

        self.widgets = []

        self.root.protocol('WM_DELETE_WINDOW', self.close)

    def no_action(self):
        pass

    def update(self):

        self.root.update()

    def after(self, function):

        xx = self.root.after(5, function)
        self.jobs.append(xx)
        self.update_idletasks()

    def update_idletasks(self):

        self.root.update_idletasks()

    def finalise(self):

        if not self.finalised:

            self.update_idletasks()

            # print(self.interior.winfo_reqwidth(), self.interior.winfo_reqheight())
            # self.canvas.config(width=self.interior.winfo_reqwidth(), height=self.interior.winfo_reqheight())
            # self.canvas.itemconfigure(self.interior_id, width=self.interior.winfo_reqwidth(), height=self.interior.winfo_reqheight())

            if self.position == 1:
                x = 0
                y = 0

            elif self.position == 2:
                x = (self.root.winfo_screenwidth() -
                     self.root.winfo_reqwidth()) / 2
                y = 0

            elif self.position == 3:
                x = self.root.winfo_screenwidth() - self.root.winfo_reqwidth()
                y = 0

            elif self.position == 4:
                x = 0
                y = (self.root.winfo_screenheight() -
                     self.root.winfo_reqheight()) / 2

            elif self.position == 5:
                x = (self.root.winfo_screenwidth() -
                     self.root.winfo_reqwidth()) / 2
                y = (self.root.winfo_screenheight() -
                     self.root.winfo_reqheight()) / 2

            elif self.position == 6:
                x = self.root.winfo_screenwidth() - self.root.winfo_reqwidth()
                y = (self.root.winfo_screenheight() -
                     self.root.winfo_reqheight()) / 2

            elif self.position == 7:
                x = 0
                y = self.root.winfo_screenheight() - self.root.winfo_reqheight(
                )

            elif self.position == 8:
                x = (self.root.winfo_screenwidth() -
                     self.root.winfo_reqwidth()) / 2
                y = self.root.winfo_screenheight() - self.root.winfo_reqheight(
                )

            elif self.position == 9:
                x = self.root.winfo_screenwidth() - self.root.winfo_reqwidth()
                y = self.root.winfo_screenheight() - self.root.winfo_reqheight(
                )

            elif self.position == 10:
                x = self.root.winfo_screenwidth(
                ) / 2 - self.root.winfo_reqwidth()
                y = (self.root.winfo_screenheight() -
                     self.root.winfo_reqheight()) / 2

            elif self.position == 11:
                x = self.root.winfo_screenwidth() / 2
                y = (self.root.winfo_screenheight() -
                     self.root.winfo_reqheight()) / 2

            else:
                x = 0
                y = 0

            self.root.geometry('+%d+%d' % (int(x), int(y)))

            self.update_idletasks()

            self.finalised = True

    def show(self):

        self.finalise()

        self.root.wm_attributes("-topmost", 1)
        self.root.after_idle(self.root.attributes, '-topmost', 0)

        self.root.deiconify()
        self.update_idletasks()

    def loop(self, f_after=None):

        self.mainloop_on = True

        if f_after:
            self.root.after(500, f_after)

        self.root.mainloop()

    def hide(self):

        self.root.withdraw()

    def def_run(self):

        self.show()

    def run(self, f_after=None):

        print('\nStarting window: ', self.name)

        self.def_run()
        self.loop(f_after)

    def trigger_exit(self):
        self.exit = True

    def def_close(self):

        if self.mainloop_on:
            self.root.quit()

        for job in self.jobs:
            self.root.after_cancel(job)

        self.root.destroy()

    def close(self):

        self.def_close()

    # widgets

    def register(self, widget):

        self.widgets.append(widget)

    def disable(self):

        self.root.protocol('WM_DELETE_WINDOW', self.no_action)

        for widget in self.widgets:
            widget.disable()

    def activate(self):

        self.root.protocol('WM_DELETE_WINDOW', self.close)

        for widget in self.widgets:
            widget.activate()

    # help pop ups

    def askdirectory(self):

        return askdirectory()

    def askyesno(self, *args, **kwargs):

        return askyesno(*args, **kwargs)

    def askyesnocancel(self, *args, **kwargs):

        return askyesnocancel(*args, **kwargs)

    def showinfo(self, *args, **kwargs):

        return showinfo(*args, **kwargs)

    # tk variables initiated directly in - and linked with - the hops window

    def StringVar(self, value):
        return StringVar(self.root, value=value)

    def BooleanVar(self, value):
        return BooleanVar(self.root, value=value)

    def DoubleVar(self, value):
        return DoubleVar(self.root, value=value)

    def IntVar(self, value):
        return IntVar(self.root, value=value)

    # tk widgwts initiated directly in - and linked with - the hops window

    def Label(self, **kwargs):
        return HOPSLabel(self, **kwargs)

    def Entry(self, **kwargs):
        return HOPSEntry(self, **kwargs)

    def Button(self, **kwargs):
        return HOPSButton(self, **kwargs)

    def DropDown(self, **kwargs):
        return HOPSDropDown(self, **kwargs)

    def CheckButton(self, **kwargs):
        return HOPSCheckButton(self, **kwargs)

    def ListDisplay(self, **kwargs):
        return HOPSListDisplay(self, **kwargs)

    def Progressbar(self, **kwargs):
        return HOPSProgressbar(self, **kwargs)

    def FigureWindow(self, **kwargs):
        return HOPSFigureWindow(self, **kwargs)

    def FitsWindow(self, **kwargs):
        return HOPSFitsWindow(self, **kwargs)

    def Frame(self, *args, **kwargs):
        return Frame(self.main_frame, *args, **kwargs)

    def Radiobutton(self, *args, **kwargs):
        return Radiobutton(self.main_frame, *args, **kwargs)

    def setup_window(self,
                     objects,
                     title_font='times',
                     main_font='times',
                     button_font='times',
                     entries_wd=20,
                     entries_bd=3,
                     buttons_bd=5):

        ff = min(
            1,
            (self.root.winfo_screenheight() / self.root.winfo_fpixels('1i')) /
            13)
        font_size = 15 * ff

        button_font = (button_font, int(1.1 * font_size), 'bold')
        main_font = (main_font, int(font_size))
        title_font = (title_font, int(1.5 * font_size), 'bold')

        for row in range(len(objects)):
            if len(objects[row]) == 0:
                label_empty = Label(self.main_frame, text='')
                label_empty.grid(row=row, column=100)
            else:
                for obj in objects[row]:

                    if obj[0].winfo_class() == 'Button':
                        obj[0].config(borderwidth=buttons_bd,
                                      font=button_font,
                                      padx=1,
                                      pady=1)
                    elif obj[0].winfo_class() == 'Entry':
                        obj[0].configure(width=entries_wd,
                                         bd=entries_bd,
                                         font=main_font)
                    elif obj[0].winfo_class() in [
                            'Label', 'Radiobutton', 'Checkbutton'
                    ]:
                        if len(obj) == 5:
                            if obj[4] == 'title':
                                obj[0].configure(font=title_font,
                                                 padx=0,
                                                 pady=0)
                            else:
                                obj[0].configure(font=main_font,
                                                 padx=0,
                                                 pady=0)
                        else:
                            obj[0].configure(font=main_font, padx=0, pady=0)

                    if len(obj) >= 4:
                        obj[0].grid(row=row,
                                    column=obj[1],
                                    columnspan=obj[2],
                                    rowspan=obj[3])
                    elif len(obj) == 3:
                        obj[0].grid(row=row, column=obj[1], columnspan=obj[2])
                    else:
                        obj[0].grid(row=row, column=obj[1])
Example #10
0
class Game():
    def __init__(self):
        self.tk = Tk()
        self.tk.title('Connect 4')
        self.tk.resizable(False, False)
        self.tk.wm_attributes('-topmost', 1)

        self.update()

        self.canvas = Canvas(self.tk, width=600, height=600)
        self.canvas.pack()

        self.update()

        self.screenwidth = self.tk.winfo_screenwidth()
        self.screenheight = self.tk.winfo_screenheight()
        self.x_calc = int(self.screenwidth / 2 - 300)
        self.y_calc = int(self.screenheight / 2 - 300)

        self.tk.geometry('+{}+{}'.format(self.x_calc, self.y_calc))
        self.update()

        self.column = Entry(self.tk, font=('Courier', -15), width=20)
        self.column.place(x=5, y=5)

        self.column.insert(0, 'Enter your move here')

        self.sprites = []
        self.running = True

        self.tk.bind_all('<Return>', self.clear)

        self.update()

    def update(self):
        self.tk.update()
        self.tk.update_idletasks()

    def say(self, *args):
        self.otk = Tk()
        self.otk.title('Message')
        self.otk.resizable(False, False)
        self.otk.wm_attributes('-topmost', 1)

        time = -1
        messages = []

        for message in args:
            time += 1
            messages.append(Label(self.otk, text=message, \
                                  font=('Courier', 12)))

        done = Button(self.otk, text='OK', command=self.otk.quit)

        for label in messages:
            label.pack()

        done.pack()

        self.update()

        ww = self.otk.winfo_width()
        wh = self.otk.winfo_height()
        sw = self.otk.winfo_screenwidth()
        sh = self.otk.winfo_screenheight()

        x = int(sw / 2 - ww / 2)
        y = int(sh / 2 - wh / 2)

        self.otk.geometry('+{}+{}'.format(x, y))

        self.otk.mainloop()
        self.otk.destroy()

    def clear(self, event):
        self.pl_mv = self.column.get()
        print(self.pl_mv)
        self.column.delete(0, 'end')

    def mainloop(self):
        self.timers = []

        def forloop():
            for sprite in self.sprites:
                if self.running:
                    sprite.todo()
                    self.update()

                else:
                    for tmr in self.timers:
                        self.tk.after_cancel(tmr)

            self.timers.append(self.tk.after(10, forloop))

        self.timers.append(self.tk.after(10, forloop))

        self.tk.mainloop()
        self.tk.destroy()
Example #11
0
class App:
    canvas_animation_options = {'width': 720, 'height': 720, 'bg': '#2B2B2B'}

    canvas_data_options = {'width': 420, 'height': 500, 'bg': '#2B2B2B'}

    canvas_chart_options = {'width': 420, 'height': 220, 'bg': '#2B2B2B'}

    quarter_circle_options = {
        'start': 0,
        'extent': -90,
        'width': 2,
        'outline': 'gray',
        'fill': '#3C3F41'
    }

    chart = None
    chart_factor = 1

    _all_lists = {
        '_canvas_points_ids': [],
        '_canvas_data_ids': [],
        '_canvas_middle_line_ids': [],
        '_canvas_data_middle_line_ids': [],
        '_canvas_text_ids': [],
        '_caught_points': set(),
        '_canvas_text_math_error_id': [],
        '_all_values_pi': []
    }

    _quarter_circle_descriptor = 0
    canvas_size_error = 3
    amount_points = 100
    multiplicity = 1000
    coord_y_for_table = 70

    def __init__(self):
        self.root = Tk()
        self.root.resizable(width=False, height=False)

        # Полотно с математической моделью:
        self.animation_canvas = Canvas(self.root,
                                       **self.canvas_animation_options)
        self.animation_canvas.pack(side='left')

        # Полотно с исследуемыми данными:
        self.data_canvas = Canvas(self.root, **self.canvas_data_options)
        self.data_canvas.pack(side='top')

        # Полотно с диаграммой:
        self.chart_canvas = Canvas(self.root, **self.canvas_chart_options)
        self.chart_canvas.pack(side='bottom')

        self.draw_stationary_objects()
        self._physics_process()
        self._process()

    def draw_stationary_objects(self):
        """
        Отрисовка всех неподвижных объектов
        """
        self._quarter_circle_descriptor = self._draw_quarter_circle()
        self.print_data_about_pi_line()
        self.draw_pi_line()
        self.draw_table()

    def _draw_quarter_circle(self):
        """
        Отрисовка четверти круга
        Returns: дескриптор четверти круга
        """
        quarter_circle_descriptor = self.animation_canvas.create_arc(
            -self.canvas_animation_options['width'],
            -self.canvas_animation_options['height'],
            self.canvas_animation_options['width'],
            self.canvas_animation_options['height'],
            **self.quarter_circle_options)
        return quarter_circle_descriptor

    def print_data_about_pi_line(self):
        """
        Печать точного значения числа pi.
        """
        self.chart_canvas.create_text(100 +
                                      self.canvas_chart_options['width'] // 4,
                                      30,
                                      text=f'Истинное pi = {pi}',
                                      font=('Comic Sans MS', 15),
                                      fill='#648658')

    def draw_pi_line(self):
        """
        Отрисовка линии, которая соответствует точному значению числа pi.
        """
        self.chart_canvas.create_line(0, (pi / 4) * 130,
                                      self.canvas_chart_options['width'],
                                      (pi / 4) * 130,
                                      fill='#499C54')

    def draw_table(self):
        for coord_x in range(self.canvas_data_options['width'] // 3,
                             self.canvas_data_options['width'],
                             self.canvas_data_options['width'] // 3):
            self.data_canvas.create_line(coord_x,
                                         0,
                                         coord_x,
                                         self.canvas_data_options['height'],
                                         fill='#AFB9BA')

        for coord_y in range(self.canvas_data_options['height'] // 11,
                             self.canvas_data_options['height'],
                             self.canvas_data_options['height'] // 11):
            self.data_canvas.create_line(0,
                                         coord_y,
                                         self.canvas_data_options['width'],
                                         coord_y,
                                         fill='#AFB9BA')

        self.data_canvas.create_text(70,
                                     25,
                                     text='Кол-во точек',
                                     font=('Comic Sans MS', 15),
                                     fill='#AFB9BA')
        self.data_canvas.create_text(210,
                                     25,
                                     text='Число pi',
                                     font=('Comic Sans MS', 15),
                                     fill='#AFB9BA')
        self.data_canvas.create_text(350,
                                     25,
                                     text='Погрешность',
                                     font=('Comic Sans MS', 15),
                                     fill='#AFB9BA')
        # for i in range(70, 500, 45):
        #     self.data_canvas.create_text(350, i, text='Погрешность', font=('Comic Sans MS', 15), fill='#AFB9BA')

    def _physics_process(self):
        """
        Создание экземпляра класса Point, т.е. создаётся
        конечное множество рандомно расположенных на полотне точек определённого цвета.
        """
        self.points = RandomPoints(self.animation_canvas, self.amount_points)
        self.points.points_options['fill'] = '#ECBB06'
        self.points.points_options['outline'] = '#ECBB06'

    def _process(self):
        self.update_math_error()
        self.update_middle_line()
        self.update_data_middle_line()
        self.update_other_values_data_on_chart_canvas()
        process = self.root.after(100, self._process)

        self._draw_points()
        self._paint_points()
        self.print_math_error()
        self.draw_current_value_line()
        self.print_data_about_middle_line()
        self.print_other_data_on_chart_canvas()
        self.draw_chart(
            (self.points.drawed_points, self.count_probability * 130))
        if self.points.drawed_points <= self.multiplicity * 10:
            self.fill_table()
        self.stop_process(process)

    def update_middle_line(self):
        """
        Обновить среднюю линию.
        """
        self.clean_canvas('_canvas_middle_line_ids')

    def update_data_middle_line(self):
        """
        Обновление данных, стоящих рядом со средней линией
        """
        self.clean_canvas('_canvas_data_middle_line_ids')

    def update_other_values_data_on_chart_canvas(self):
        self.clean_canvas('_canvas_text_ids')

    def update_math_error(self):
        self.clean_canvas('_canvas_text_math_error_id')

    def _draw_points(self):
        """
        Рисовать точки
        """
        self.points.draw()
        while len(self.points.canvas_points_ids) > 500:
            self.animation_canvas.delete(self.points.canvas_points_ids.pop(0))

    def _paint_points(self):
        """
        Перекрашывает точки, которые пересклись с кругом
        """
        for point in self.points.canvas_points_ids:
            point_coord = self.animation_canvas.coords(point)
            if point_coord[0]**2 + point_coord[1]**2 <= (
                    self.canvas_animation_options['height'])**2:
                self.animation_canvas.itemconfig(point,
                                                 fill='#4096C1',
                                                 outline='#4096C1')
                self._all_lists['_caught_points'].add(point)

    def print_math_error(self):
        self._all_lists['_canvas_text_math_error_id'] = [
            self.chart_canvas.create_text(
                100 + self.canvas_chart_options['width'] // 4,
                60,
                text=f'Поргрешность:'
                f' {abs(round(100 * (1 - pi / (4 * self.count_probability)), 5))} %',
                font=('Comic Sans MS', 15),
                fill='#648658')
        ]

    def draw_current_value_line(self):
        """
        Отрисовка текущей линии, абсциса кординат которой
        соответствует значению вероятности попадания точек в круг
        """
        self._all_lists['_canvas_middle_line_ids'] = [
            self.chart_canvas.create_line(0,
                                          self.count_probability * 130,
                                          self.canvas_chart_options['width'],
                                          self.count_probability * 130,
                                          fill='#ECBB06')
        ]

    def print_data_about_middle_line(self):
        """
        Печатать нужную информацию рядом со средней линией.
        В данном случае печатается текущее значение числа pi.
        """
        self._all_lists['_canvas_data_middle_line_ids'] = [
            self.chart_canvas.create_text(
                3 * self.canvas_data_options['width'] // 4,
                10 + self.count_probability * 130,
                text=f'{round(4 * self.count_probability, 5)}',
                font=('Comic Sans MS', 15),
                fill='#ECBB06')
        ]

        # print(f'Вероятность: {self.count_probability()}')
        # print(f'Число pi: {4 * self.count_probability()}')

    def print_other_data_on_chart_canvas(self):
        self._all_lists['_canvas_text_ids'] = [
            self.chart_canvas.create_text(
                self.canvas_chart_options['width'] // 2,
                (4 * self.canvas_chart_options['height']) // 6 + 25,
                text=f'Общее число точек: {self.points.drawed_points}\n'
                f'    Точки в круге: {len(self._all_lists["_caught_points"])}',
                font=('Comic Sans MS', 15),
                fill='#AFB9BA')
        ]

    def draw_chart(self, coordinates):
        """
        Отрисовка диаграммы
        Args:
            coordinates:
        """
        def scale_coordinates(coords):
            """Скалирует координаты по оси x"""
            for no, coord in enumerate(coords):
                yield coord * self.chart_factor if no % 2 == 0 else coord

        if self.chart is None:
            self.chart = self.chart_canvas.create_line(coordinates,
                                                       coordinates[0] + 4,
                                                       coordinates[1] + 4,
                                                       fill='#4096C1',
                                                       width=4)
        else:
            old_coords = self.chart_canvas.coords(self.chart)
            scaled_coordinates = scale_coordinates(coordinates)
            if self.chart_canvas.coords(
                    self.chart)[-2] >= self.chart_canvas.winfo_width() - 100:
                self.chart_factor /= 2
                old_coords = list(scale_coordinates(old_coords))
            self.chart_canvas.coords(self.chart,
                                     *(old_coords + list(scaled_coordinates)))

    def fill_table(self):
        if self.points.drawed_points % self.multiplicity == 0:
            self.data_canvas.create_text(70,
                                         self.coord_y_for_table,
                                         text=f'{self.points.drawed_points}',
                                         font=('Comic Sans MS', 15),
                                         fill='#AFB9BA')
            self.data_canvas.create_text(
                210,
                self.coord_y_for_table,
                text=f'{round(4 * self.count_probability, 7)}',
                font=('Comic Sans MS', 15),
                fill='#AFB9BA')
            self.data_canvas.create_text(
                350,
                self.coord_y_for_table,
                text=
                f'{abs(round(100 * (1 - pi / (4 * self.count_probability)), 5))} %',
                font=('Comic Sans MS', 15),
                fill='#AFB9BA')

            self.coord_y_for_table += 45

    def stop_process(self, process):
        """
        Останавливает процесс при определённом условии
        (в данном случае при достижении общего кол-ва точек 3000)
        """
        if len(self.points.canvas_points_ids) == 20000:
            self.root.after_cancel(process)

    def clean_canvas(self, group: str):
        """
        Очистка элементов определённоой группы
        Args:
            group: список с дескрипторами удаляемой группы элементов
        """
        for canvas_obj in self._all_lists[group]:
            self.chart_canvas.delete(canvas_obj)
        self._all_lists[group] = []

    def run(self):
        self.root.mainloop()

    @property
    def count_probability(self):
        """
        Вероятностт попадания точки в круг
        Returns: вероятность попадания точки в круг
        """
        return len(
            self._all_lists['_caught_points']) / self.points.drawed_points
Example #12
0
def welcome(o=""):
    """Function to open WELCOME SCREEN - Login screen that opens when you
        run."""

    global clock
    global welcome_screen
    global home_screen
    global truth
    truth = True
    global home
    if o != "f":
        home.after_cancel(Home.AFTER)
        home.destroy()

    def show():
        """Show button function"""

        global sh
        if not sh:
            e["show"] = ""
            sh = True
            shbtn.config(text="Hide")
        elif sh:
            e["show"] = "*"
            sh = False
            shbtn.config(text="Show")

    def try_again():
        output_label["text"] = "Try again."
        confirmbtn["bg"] = "cyan"
        confirmbtn["state"] = "normal"

    def confirm(event=None):
        """Confirm button function"""

        global welcome_screen
        global password
        global tries
        global truth
        global AFTER
        global home_screen
        global clock
        p = e.get()
        if p == password:
            truth = False
            welcome_screen.after_cancel(AFTER)
            clock = None
            """Argument "y" tells that welcome screen exists and needs to be
            destroyed"""
            home_screen = Home("y")
        elif p != password:
            tries -= 1
            output_label.place(x=0, y=320)
            output_label["text"] = ("Incorrect password, " + str(tries) +
                                    " tries remaining")
            if p != "":
                e.delete(0, END)
            e.focus_set()
            if tries == 0:
                output_label[
                    "text"] = "5 incorrect attempts, Try again after 30 seconds! "
                tries = 6
                confirmbtn["bg"] = "black"
                confirmbtn["state"] = "disabled"
                t = threading.Timer(30.0, try_again)
                t.start()

    welcome_screen = Tk()  # welcome screen
    truth = True
    welcome_screen.geometry(WINDOW_DIM)
    welcome_screen.resizable(False, False)
    welcome_screen.title("MarvellOS")
    welcome_screen.config(bg=background)

    title_label = Label(
        welcome_screen,
        text="MarvellOS",
        bg=background,
        fg="dark blue",
        font=("Curlz MT", 35),
    )
    title_label.place(x=47, y=100)

    shbtn = Button(
        welcome_screen,
        text="Show",
        bg="light blue",
        fg="black",
        font=("Agency", 8),
        command=show,
    )
    shbtn.place(x=265, y=237)

    confirmbtn = Button(
        welcome_screen,
        text="Confirm",
        bg="cyan",
        fg="black",
        font=("Arial black", 9),
        command=confirm,
        width=20,
        height=2,
    )  # confirm button
    confirmbtn.place(x=71, y=263)

    # Binding Enter key for login confirmation
    welcome_screen.bind("<Return>", confirm)

    welcome_frame = Frame(welcome_screen, relief=RIDGE, borderwidth=2)
    welcome_frame.pack()

    enterpass = Label(
        welcome_screen,
        text="Enter password:"******"Century"),
        bg=background,
        fg="black",
    )
    enterpass.place(x=96, y=215)
    e = Entry(welcome_screen, show="*", width=27)
    e.focus_set()  # password entry field
    e.place(x=45, y=240)

    output_label = Label(welcome_screen,
                         bg="red",
                         fg="black",
                         width=41,
                         font=("Calibri", 12))  # output label
    """----------------VERSION UPDATE LABEL----------------"""
    t = "MarvellOS v1.3"

    inf = Label(
        welcome_screen,
        text=t,
        bg=background,
        fg="red",
        font=("Century", 10, "bold"),
    )
    inf.place(x=5, y=375)
    """Clock on the home screen"""
    global clock
    clock = Label(
        welcome_screen,
        font=("TIMES NEW ROMAN", 10),
        anchor="e",
        bg="black",
        fg="white",
        width=46,
        height=2,
    )  # clock label
    clock.place(x=0, y=0)
    if truth:
        try:
            tick()
        except Exception:
            welcome_screen.after_cancel(tick)

    welcome_screen.mainloop()
Example #13
0
class Game:
    def __init__(self):
        self.root = Tk()
        self.area = Canvas(self.root, width=500, height=500, bg='lightgreen')
        self.area.pack()
        self.ballid = self.area.create_oval(30, 50, 50, 70, fill='red')
        self.paddleid = self.area.create_rectangle(210,
                                                   400,
                                                   310,
                                                   410,
                                                   fill="blue")
        self.points_text = self.area.create_text(250,
                                                 450,
                                                 text='0',
                                                 font=('times', 20))
        self.speed = 12.0  ##speed of ball
        self.xspeed = self.speed * sin(
            radians(40))  ##speed of ball horizontally
        self.yspeed = self.speed * sin(radians(40))  ##speed of ball vertically
        self.pspeed = 0  ##speed of paddle
        self.recall = ''  ##for AFTER method
        self.points = 0  ##ponits counter
        self.gameon = True

        self.redraw_screen()
        ##controls for paddle
        self.area.bind_all('<KeyPress-Left>', self.turn_left)
        self.area.bind_all('<KeyPress-Right>', self.turn_right)
        #self.area.bind_all('<Control-n>', self.new_game)
        self.root.mainloop()

    def draw_points(self):
        self.points = self.points + self.speed / 50
        self.area.itemconfig(self.points_text,
                             text=round(self.points),
                             fill="#991122")

    def redraw_screen(self):
        self.draw_ball()
        self.paddle_hit()
        self.draw_paddle()
        self.draw_points()
        if self.gameon:
            self.recall = self.root.after(17, self.redraw_screen)
        else:
            self.root.after_cancel(self.recall)

    def draw_ball(self):
        #left or right boundary
        if self.area.coords(self.ballid)[0] < 0 or self.area.coords(
                self.ballid)[2] > 500:
            self.xspeed = -self.xspeed
        ##top and bottom boundary
        if self.area.coords(self.ballid)[1] < 0:
            self.yspeed = -self.yspeed
        if self.area.coords(self.ballid)[3] > 500:
            self.xspeed = 0
            self.yspeed = 0
            self.game_over()
        self.area.move(self.ballid, self.xspeed, self.yspeed)
        #ball location
        #print(self.area.coords(self.ballid))
        #canvas
        #print(self.area.winfo_height(), self.area.winfo_width())

    def draw_paddle(self):
        self.area.move(self.paddleid, self.pspeed, 0)
        if self.area.coords(self.paddleid)[0] <= 0 or self.area.coords(
                self.paddleid)[2] >= 500:
            self.pspeed = 0

    def paddle_hit(self):
        cb = self.area.coords(self.ballid)[0] + 10
        cp = self.area.coords(self.paddleid)[0] + 50
        ##to check if paddle is is paddle level
        if self.area.coords(self.ballid)[3] >= 400:
            ##if paddle is hit
            if cb > self.area.coords(
                    self.paddleid)[0] and cb < self.area.coords(
                        self.paddleid)[2] and self.area.coords(
                            self.ballid)[3] < 405:
                dis = cp - cb
                self.xspeed = -self.speed * sin(radians(dis * 1.3))
                self.yspeed = -self.speed * cos(radians(dis * 1.3))

    def turn_left(self, arg):
        self.pspeed = -5

    def turn_right(self, arg):
        self.pspeed = 5

    def game_over(self):
        self.area.create_text(250, 250, text="Game over!", font=("times", 30))
        #self.area.create_text(250,300, text="Press Ctrl+N for new game!", font=("times", 10))
        self.gameon = False
Example #14
0
class CollocationsView:
    _BACKGROUND_COLOUR = "#FFF"  # white

    def __init__(self):
        self.queue = q.Queue()
        self.model = CollocationsModel(self.queue)
        self.top = Tk()
        self._init_top(self.top)
        self._init_menubar()
        self._init_widgets(self.top)
        self.load_corpus(self.model.DEFAULT_CORPUS)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def _init_top(self, top):
        top.geometry("550x650+50+50")
        top.title("NLTK Collocations List")
        top.bind("<Control-q>", self.destroy)
        top.protocol("WM_DELETE_WINDOW", self.destroy)
        top.minsize(550, 650)

    def _init_widgets(self, parent):
        self.main_frame = Frame(parent, dict(background=self._BACKGROUND_COLOUR, padx=1, pady=1, border=1))
        self._init_corpus_select(self.main_frame)
        self._init_results_box(self.main_frame)
        self._init_paging(self.main_frame)
        self._init_status(self.main_frame)
        self.main_frame.pack(fill="both", expand=True)

    def _init_corpus_select(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.var = StringVar(innerframe)
        self.var.set(self.model.DEFAULT_CORPUS)
        Label(
            innerframe, justify=LEFT, text=" Corpus: ", background=self._BACKGROUND_COLOUR, padx=2, pady=1, border=0
        ).pack(side="left")

        other_corpora = list(self.model.CORPORA.keys()).remove(self.model.DEFAULT_CORPUS)
        om = OptionMenu(
            innerframe,
            self.var,
            self.model.DEFAULT_CORPUS,
            command=self.corpus_selected,
            *self.model.non_default_corpora()
        )
        om["borderwidth"] = 0
        om["highlightthickness"] = 1
        om.pack(side="left")
        innerframe.pack(side="top", fill="x", anchor="n")

    def _init_status(self, parent):
        self.status = Label(
            parent, justify=LEFT, relief=SUNKEN, background=self._BACKGROUND_COLOUR, border=0, padx=1, pady=0
        )
        self.status.pack(side="top", anchor="sw")

    def _init_menubar(self):
        self._result_size = IntVar(self.top)
        menubar = Menu(self.top)

        filemenu = Menu(menubar, tearoff=0, borderwidth=0)
        filemenu.add_command(label="Exit", underline=1, command=self.destroy, accelerator="Ctrl-q")
        menubar.add_cascade(label="File", underline=0, menu=filemenu)

        editmenu = Menu(menubar, tearoff=0)
        rescntmenu = Menu(editmenu, tearoff=0)
        rescntmenu.add_radiobutton(
            label="20", variable=self._result_size, underline=0, value=20, command=self.set_result_size
        )
        rescntmenu.add_radiobutton(
            label="50", variable=self._result_size, underline=0, value=50, command=self.set_result_size
        )
        rescntmenu.add_radiobutton(
            label="100", variable=self._result_size, underline=0, value=100, command=self.set_result_size
        )
        rescntmenu.invoke(1)
        editmenu.add_cascade(label="Result Count", underline=0, menu=rescntmenu)

        menubar.add_cascade(label="Edit", underline=0, menu=editmenu)
        self.top.config(menu=menubar)

    def set_result_size(self, **kwargs):
        self.model.result_count = self._result_size.get()

    def _init_results_box(self, parent):
        innerframe = Frame(parent)
        i1 = Frame(innerframe)
        i2 = Frame(innerframe)
        vscrollbar = Scrollbar(i1, borderwidth=1)
        hscrollbar = Scrollbar(i2, borderwidth=1, orient="horiz")
        self.results_box = Text(
            i1,
            font=tkinter.font.Font(family="courier", size="16"),
            state="disabled",
            borderwidth=1,
            yscrollcommand=vscrollbar.set,
            xscrollcommand=hscrollbar.set,
            wrap="none",
            width="40",
            height="20",
            exportselection=1,
        )
        self.results_box.pack(side="left", fill="both", expand=True)
        vscrollbar.pack(side="left", fill="y", anchor="e")
        vscrollbar.config(command=self.results_box.yview)
        hscrollbar.pack(side="left", fill="x", expand=True, anchor="w")
        hscrollbar.config(command=self.results_box.xview)
        # there is no other way of avoiding the overlap of scrollbars while using pack layout manager!!!
        Label(i2, text="   ", background=self._BACKGROUND_COLOUR).pack(side="left", anchor="e")
        i1.pack(side="top", fill="both", expand=True, anchor="n")
        i2.pack(side="bottom", fill="x", anchor="s")
        innerframe.pack(side="top", fill="both", expand=True)

    def _init_paging(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.prev = prev = Button(
            innerframe,
            text="Previous",
            command=self.previous,
            width="10",
            borderwidth=1,
            highlightthickness=1,
            state="disabled",
        )
        prev.pack(side="left", anchor="center")
        self.next = next = Button(
            innerframe,
            text="Next",
            command=self.__next__,
            width="10",
            borderwidth=1,
            highlightthickness=1,
            state="disabled",
        )
        next.pack(side="right", anchor="center")
        innerframe.pack(side="top", fill="y")
        self.reset_current_page()

    def reset_current_page(self):
        self.current_page = -1

    def _poll(self):
        try:
            event = self.queue.get(block=False)
        except q.Empty:
            pass
        else:
            if event == CORPUS_LOADED_EVENT:
                self.handle_corpus_loaded(event)
            elif event == ERROR_LOADING_CORPUS_EVENT:
                self.handle_error_loading_corpus(event)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def handle_error_loading_corpus(self, event):
        self.status["text"] = "Error in loading " + self.var.get()
        self.unfreeze_editable()
        self.clear_results_box()
        self.freeze_editable()
        self.reset_current_page()

    def handle_corpus_loaded(self, event):
        self.status["text"] = self.var.get() + " is loaded"
        self.unfreeze_editable()
        self.clear_results_box()
        self.reset_current_page()
        # self.next()
        collocations = self.model.next(self.current_page + 1)
        self.write_results(collocations)
        self.current_page += 1

    def corpus_selected(self, *args):
        new_selection = self.var.get()
        self.load_corpus(new_selection)

    def previous(self):
        self.freeze_editable()
        collocations = self.model.prev(self.current_page - 1)
        self.current_page = self.current_page - 1
        self.clear_results_box()
        self.write_results(collocations)
        self.unfreeze_editable()

    def __next__(self):
        self.freeze_editable()
        collocations = self.model.next(self.current_page + 1)
        self.clear_results_box()
        self.write_results(collocations)
        self.current_page += 1
        self.unfreeze_editable()

    def load_corpus(self, selection):
        if self.model.selected_corpus != selection:
            self.status["text"] = "Loading " + selection + "..."
            self.freeze_editable()
            self.model.load_corpus(selection)

    def freeze_editable(self):
        self.prev["state"] = "disabled"
        self.next["state"] = "disabled"

    def clear_results_box(self):
        self.results_box["state"] = "normal"
        self.results_box.delete("1.0", END)
        self.results_box["state"] = "disabled"

    def fire_event(self, event):
        # Firing an event so that rendering of widgets happen in the mainloop thread
        self.top.event_generate(event, when="tail")

    def destroy(self, *e):
        if self.top is None:
            return
        self.top.after_cancel(self.after)
        self.top.destroy()
        self.top = None

    def mainloop(self, *args, **kwargs):
        if in_idle():
            return
        self.top.mainloop(*args, **kwargs)

    def unfreeze_editable(self):
        self.set_paging_button_states()

    def set_paging_button_states(self):
        if self.current_page == -1 or self.current_page == 0:
            self.prev["state"] = "disabled"
        else:
            self.prev["state"] = "normal"
        if self.model.is_last_page(self.current_page):
            self.next["state"] = "disabled"
        else:
            self.next["state"] = "normal"

    def write_results(self, results):
        self.results_box["state"] = "normal"
        row = 1
        for each in results:
            self.results_box.insert(str(row) + ".0", each[0] + " " + each[1] + "\n")
            row += 1
        self.results_box["state"] = "disabled"
Example #15
0
class Client:
    """Base client class.
    """

    def __init__(self, trace_path):
        """Initialising values and creating the window with game world
        """
        self.trace_path = trace_path
        self.game_data = json.loads(open(trace_path, 'r').read())
        self.rootpath = Path(__file__).parent

        self.root = Tk()
        self.root.title("RAINBOW hit")
        self.canvas = Canvas(self.root, width=WIDTH * 1.8, height=HEIGHT, bg="#f0f7f6")
        for i in range(GRID_SIZE):
            for j in range(GRID_SIZE):
                if i == 0 or j == 0 or i == GRID_SIZE - 1 or j == GRID_SIZE - 1:
                    continue
                self.canvas.create_rectangle(i * CELL_SIZE, j * CELL_SIZE,
                                             i * CELL_SIZE + CELL_SIZE,
                                             j * CELL_SIZE + CELL_SIZE, fill='#c4badb', outline='#999090')
        self.canvas.create_rectangle(32, 32, HEIGHT - 32, HEIGHT - 32, outline='gray', width=2)
        self.canvas.grid(column=0, row=0)
        pilImage1 = Image.open(self.rootpath / "assets/ufo1.png")
        self.image1 = ImageTk.PhotoImage(pilImage1)
        self.canvas.create_image(592, 48, image=self.image1)
        self.health1 = self.canvas.create_rectangle(630, 36, 1010, 58, fill='#3ab03e', outline='gray')
        pilImage2 = Image.open(self.rootpath / "assets/ufo2.png")
        self.image2 = ImageTk.PhotoImage(pilImage2)
        self.canvas.create_image(592, 90, image=self.image2)
        self.health2 = self.canvas.create_rectangle(630, 78, 1010, 99, fill='#3ab03e', outline='gray')
        self.canvas.create_rectangle(630, 36, 1010, 58, width=2, outline='gray')
        self.canvas.create_rectangle(630, 78, 1010, 100, width=2, outline='gray')
        self.game_over = False
        self.step = 0
        self.steps_text = self.canvas.create_text(632, 138, font="Times", text='Current step: 0')

        self.updater_job = None
        # message_entry = Text(width=56, height=22)
        # message_entry.place(x=566, y=168)
        # self.window = self.canvas.create_rectangle(566, 168, 1018, 524, width=5, outline='#f21d1d')
        self.start_button = Button(self.root, text="start", width=32, command=self.updater, bg="#3fbfbf")
        self.start_button.place(x=564, y=200)

        self.step_button = Button(self.root, text="step", width=32, command=self.step_once, bg="#3fbfbf")
        self.step_button.place(x=564, y=240)

        self.pause_btn = Button(self.root, text="pause", bg="#3fbfbf", activeforeground='#3fbfbf',
                                activebackground='#3fbfbf', width=32, command=self.pause)
        self.pause_btn.place(x=564, y=280)

        message_entry = self.canvas.create_text(635, 335, font="Times", text='Step delay')

        self.scale = Scale(self.root, from_=25, to=400, length=200, orient=HORIZONTAL)
        self.scale.set(UPDATE_TIME)
        self.scale.place(x=564, y=350)

    def get_object(self, x, y):
        '''Get object by coordinates

        Parameters
        ----------
        x : int
        y : int

        Returns
        -------
            Optional[Gameobject]
        '''
        for obj in self.objects:
            objx, objy = self.canvas.coords(obj.sprite)
            if objx == 48 + x * 32.0 and objy == 32.0 * 18 - (48 + y * 32):
                return obj
        return None

    def pop_object(self, x, y):
        '''Return object from objects list
        and remove it from list

        Parameters
        ----------
        x : int
        y : int

        Returns
        -------
            Optional[Gameobject]
        '''
        for idx in range(len(self.objects)):
            objx, objy = self.canvas.coords(self.objects[idx].sprite)
            if objx == 48 + x * 32.0 and objy == 32.0 * 18 - (48 + y * 32):
                return self.objects.pop(idx)
        return None

    def get_ufo_by_name(self, name):
        '''Get UFO-object by name attribute

        Parameters
        ----------
        name : str

        Returns
        -------
            Optional[Gameobject]
        '''
        for obj in self.objects:
            if isinstance(obj, Ufo):
                if obj.name == name:
                    return obj
        return None

    def creating_game_objects(self):
        """Creating Ufos and clouds
        """
        self.objects = []
        for k, v in self.game_data[0]['init_world'].items():
            x, y = eval(k)
            if v[0] == 'Bot' and v[1] == 'player1':
                self.objects.append(
                    Ufo(48 + x * 32, 32 * 18 - (48 + y * 32), self.canvas, self.rootpath / "assets/ufo1.png", 'player1', v[2],
                        v[3]))
            elif v[0] == 'Bot' and v[1] == 'player2':
                self.objects.append(
                    Ufo(48 + x * 32, 32 * 18 - (48 + y * 32), self.canvas, self.rootpath / "assets/ufo2.png", 'player2', v[2],
                        v[3]))
            else:
                self.objects.append(
                    Cloud(48 + x * 32, 32 * 18 - (48 + y * 32), self.canvas, self.rootpath / "assets/Cloud.png"))

        self.game_data.pop(0)

    def actions(self):
        """Commands processing and visualising actions: move, fire
        """
        self.root.bind('1' + '<Right>', self.ufo_1.move)
        self.root.bind('2' + '<Right>', self.ufo_2.move)
        self.root.bind('<Down>', self.ufo_2.laser)
        self.root.bind('<Up>', self.ufo_2.deleter)

    def pause(self, event=None):
        if self.updater_job != None:
            self.root.after_cancel(self.updater_job)

    def updater(self, event=None):
        self.step_once()
        self.updater_job = self.root.after(self.scale.get(), self.updater)

    def step_once(self, event=None):
        if self.game_over:
            return None

        cmd = self.game_data.pop(0)
        if list(cmd.keys())[0] == 'sleep':
            pass
        elif list(cmd.keys())[0] == 'step':
            player = cmd['step']['player']
            newx = cmd['step']['new_x']
            newy = cmd['step']['new_y']

            player_ufo = self.get_ufo_by_name(player)
            player_ufo.move(newx, newy)

        elif list(cmd.keys())[0] == 'shoot':
            player = cmd['shoot']['player']
            x_end = cmd['shoot']['x_end']
            y_end = cmd['shoot']['y_end']
            destroyed = cmd['shoot']['destroyed']

            player_ufo = self.get_ufo_by_name(player)
            player_ufo.laser(x_end, y_end)

            shooted_obj = self.get_object(x_end, y_end)
            if isinstance(shooted_obj, Ufo):
                shooted_obj.health -= player_ufo.damage

                # if player == 'player1':
                #     self.health_line(2, 100 - (shooted_obj.health / shooted_obj.max_health) * 100)
                # else:
                #     self.health_line(1, 100 - (shooted_obj.health / shooted_obj.max_health) * 100)

            if destroyed:
                obj = self.pop_object(x_end, y_end)
                self.root.after(70, func=obj.deleter)

        elif list(cmd.keys())[0] == 'bot_state':
            name = cmd['bot_state']['name']
            hp = cmd['bot_state']['hp']

            if name == 'player1':
                self.health_line(1, 100 - hp * 10)  # TODO no hardcode
            else:
                self.health_line(2, 100 - hp * 10)


        elif list(cmd.keys())[0] == 'game_over':
            self.game_over = True
            if cmd['game_over']['draw'] == True:
                messagebox.showinfo("GAME OVER", "Draw!")
            else:
                messagebox.showinfo("GAME OVER", f"Winner is: {cmd['game_over']['winner']}")

        if not self.game_over:
            self.step += 1
            self.canvas.itemconfigure(self.steps_text, text=f'Current step: {self.step}')

    def health_line(self, ufo_number, percent):
        """Reduce life string

        Parameters
        ----------
        ufo_number : int
        percent : int

        Returns
        -------
        None
        """
        if ufo_number == 1:
            ufo_health = self.health1
            self.canvas.delete(ufo_health)
            ufo_health = self.canvas.create_rectangle(630, 36, 1010 - (1010 - 630) * percent * 0.01, 58, fill='green')
            self.health1 = ufo_health
        else:
            ufo_health = self.health2
            self.canvas.delete(ufo_health)
            ufo_health = self.canvas.create_rectangle(630, 78, 1010 - (1010 - 630) * percent * 0.01, 99, fill='green')
            self.health2 = ufo_health

    def main_loop(self):
        self.root.mainloop()
Example #16
0
class minesweeper:
    def __init__(self, difficulty):
        self.difficulty = difficulty
        self.root = Tk()
        self.root.title('MineSweeper')
        self.ms = Canvas(self.root, height=475, width=475)
        self.ms.pack()

        self.ids = {}
        #key= 'name of widgets', 'box_0'
        ##these are values ain list
        #0. rectangle id number - int
        #1. text id number
        #2. mines list - bool
        #3. number list - int
        #4. active list - bool
        #5. flag list - bool
        #6. unknown flags - bool
        self.time_min = 0
        self.time_sec = 0
        self.mines_rem = 40
        self.game_on = False
        self.first_click = False

        self.timer = None

        self.creator()
        self.ui_creator()
        self.reset()
        self.root.mainloop()

    #removes all bombs and reset states
    def mine_setter(self):
        i = 0
        while i < 40:
            ch = choice(range(225))
            if self.ids['box_' + str(ch)][2] == False:
                self.ids['box_' + str(ch)][2] = True
                i += 1
        self.number_setter()

    #number around the mines
    def number_setter(self):
        for i in range(225):
            name = 'box_' + str(i)
            if self.ids[name][2]:
                if i % 15 > 0:
                    self.ids['box_' + str(i - 1)][3] += 1  #left
                    if i > 14:
                        self.ids['box_' + str(i - 16)][3] += 1  #topleft
                    if i < 210:
                        self.ids['box_' + str(i + 14)][3] += 1  #bottomleft
                if i % 15 < 14:
                    self.ids['box_' + str(i + 1)][3] += 1  #right
                    if i > 14:
                        self.ids['box_' + str(i - 14)][3] += 1  #topright
                    if i < 210:
                        self.ids['box_' + str(i + 16)][3] += 1  #bottomright
                if i > 14:
                    self.ids['box_' + str(i - 15)][3] += 1  #top
                if i < 210:
                    self.ids['box_' + str(i + 15)][3] += 1  #bottom

    def reset(self):
        self.game_on = True
        self.first_click = False
        self.time_min = 0
        self.time_sec = 0
        self.mines_rem = 40
        self.ms.itemconfig(self.ids['mine_box'][1], text=str(self.mines_rem))
        self.ms.itemconfig(self.ids['timer_box'][1], text=str('00:00'))
        for i in range(225):
            name = 'box_' + str(i)
            ## resetting the variables
            self.ids[name][2] = False
            self.ids[name][3] = 0
            self.ids[name][4] = False
            self.ids[name][5] = False
            self.ids[name][5] = False

            ##reset the grids to back
            self.ms.itemconfig(self.ids[name][0],
                               fill='#dddddd',
                               outline='#000000')
            self.ms.itemconfig(self.ids[name][1], text='')
        try:
            self.time_stopper()
        except:
            pass
        self.mine_setter()
        #self.time_starter()

    ##call this to loop with time
    def time_starter(self):
        if self.game_on:
            mins = str(self.time_min)
            secs = str(self.time_sec)
            if self.time_min <= 9:
                mins = '0' + mins
            if self.time_sec <= 9:
                secs = '0' + secs
            clock = mins + ':' + secs
            self.ms.itemconfig(self.ids['timer_box'][1], text=clock)
            self.timer = self.root.after(1000, self.time_starter)
            self.time_sec += 1
            if self.time_sec >= 60:
                self.time_sec = 0
                self.time_min += 1
        else:
            self.time_stopper()

    def time_stopper(self):
        self.root.after_cancel(self.timer)
        self.timer = None

    def ui_creator(self):
        ##mines counter area
        num = self.ms.create_rectangle(50,
                                       15,
                                       150,
                                       60,
                                       fill='#888888',
                                       tags='mine_box')
        text = self.ms.create_text(99,
                                   37,
                                   text='030',
                                   font=('Fixedsys', 25),
                                   fill='#ff2222',
                                   tags='mine_text')
        self.ids['mine_box'] = []
        self.ids['mine_box'].append(num)
        self.ids['mine_box'].append(text)

        ##reset button area
        num = self.ms.create_rectangle(170,
                                       18,
                                       270,
                                       57,
                                       fill='#888888',
                                       tags='reset_box')
        text = self.ms.create_text(220,
                                   37,
                                   text='New',
                                   font=('Fixedsys', 25),
                                   fill='#2222ff',
                                   tags='reset_text')
        self.ids['reset_box'] = []
        self.ids['reset_box'].append(num)
        self.ids['reset_box'].append(text)
        ##thes for rectangle
        self.ms.tag_bind(self.ids['reset_box'][0], "<Enter>",
                         lambda event: self.cursor_hover('reset_box'))
        self.ms.tag_bind(self.ids['reset_box'][0], "<Leave>",
                         lambda event: self.cursor_leave('reset_box'))
        self.ms.tag_bind(self.ids['reset_box'][0], "<Button-1>",
                         lambda event: self.reset())
        ##these for the text
        self.ms.tag_bind(self.ids['reset_box'][1], "<Enter>",
                         lambda event: self.cursor_hover('reset_box'))
        self.ms.tag_bind(self.ids['reset_box'][1], "<Leave>",
                         lambda event: self.cursor_leave('reset_box'))
        self.ms.tag_bind(self.ids['reset_box'][1], "<Button-1>",
                         lambda event: self.reset())

        ##timer box area
        num = self.ms.create_rectangle(290,
                                       15,
                                       425,
                                       60,
                                       fill='#888888',
                                       tags='time_box')
        text = self.ms.create_text(357,
                                   37,
                                   text='00:00',
                                   font=('Fixedsys', 25),
                                   fill='#22ff22',
                                   tags='timer_text')
        self.ids['timer_box'] = []
        self.ids['timer_box'].append(num)
        self.ids['timer_box'].append(text)

    def creator(self):
        ##easy is     9x9 grid
        #box size = 24x24
        #distance b/w them = 1
        for i in range(15):
            for j in range(15):
                num = i * 15 + j
                name = 'box_' + str(num)
                x1 = 50 + j * 25
                x2 = x1 + 23
                y1 = 75 + i * 25
                y2 = y1 + 23
                #print(name,x1,x2,y1,y2)
                self.ids[name] = []
                num = self.ms.create_rectangle(x1,
                                               y1,
                                               x2,
                                               y2,
                                               fill='#dddddd',
                                               tags=name)
                text = self.ms.create_text((x1 + x2) / 2, (y1 + y2) / 2,
                                           text='',
                                           font=('', 15))
                self.ids[name].append(num)  #0 added the ID in 0
                self.ids[name].append(text)  #1 text id number
                self.ids[name].append(False)  #2 mines
                self.ids[name].append(0)  #3 numbers
                self.ids[name].append(False)  #4 active
                self.ids[name].append(False)  #5 flags
                self.ids[name].append(False)  #6 unknown

        for i in self.ids:
            self.anims(i)
            #print(i)

    #for binding all the 255 boxes with events like hover and clicks
    def anims(self, x):
        ##these for the box
        self.ms.tag_bind(self.ids[x][0], "<Enter>",
                         lambda event: self.cursor_hover(x))
        self.ms.tag_bind(self.ids[x][0], "<Leave>",
                         lambda event: self.cursor_leave(x))
        self.ms.tag_bind(self.ids[x][0], "<Button-1>",
                         lambda event: self.left_clicked(x))
        self.ms.tag_bind(self.ids[x][0], "<Button-3>",
                         lambda event: self.right_clicked(x))
        ##these for the text
        self.ms.tag_bind(self.ids[x][1], "<Enter>",
                         lambda event: self.cursor_hover(x))
        self.ms.tag_bind(self.ids[x][1], "<Leave>",
                         lambda event: self.cursor_leave(x))
        self.ms.tag_bind(self.ids[x][1], "<Button-1>",
                         lambda event: self.left_clicked(x))
        self.ms.tag_bind(self.ids[x][1], "<Button-3>",
                         lambda event: self.right_clicked(x))

    def cursor_hover(self, name):
        if self.game_on:
            if name == 'reset_box':
                self.ms.itemconfig(self.ids[name][0], fill='#aaaaaa')
            elif not self.ids[name][4]:
                self.ms.itemconfig(self.ids[name][0], fill='#eeffee')

    def cursor_leave(self, name):
        if self.game_on:
            if name == 'reset_box':
                self.ms.itemconfig(self.ids[name][0], fill='#888888')
            elif not self.ids[name][4]:
                self.ms.itemconfig(self.ids[name][0], fill='#dddddd')

    def left_clicked(self, name):
        if self.game_on:
            if not self.ids[name][5] and not self.ids[name][
                    6]:  #to not accept click over flag or mark
                if self.ids[name][
                        2] == True and not self.first_click:  #iif clicked on mine
                    self.reset()
                elif self.ids[name][2] and self.first_click:
                    self.stepped_on_mine(name)
                    return
                else:
                    if not self.first_click:
                        self.first_click = True
                        self.time_starter()
                    #print('left', name)
                    if not self.ids[name][4]:
                        self.ids[name][4] = True
                        self.ms.itemconfig(self.ids[name][0],
                                           fill='#eeeeee',
                                           outline='#777777')
                        if self.ids[name][3] != 0:
                            self.ms.itemconfig(self.ids[name][1],
                                               text=str(self.ids[name][3]))
                        num = int(name[name.index('_') + 1:])
                        if self.ids[name][3] == 0:
                            #print(num//15, num%15)
                            self.stepped_on_blank(num)

    def right_clicked(self, name):
        if not self.ids[name][4]:
            if self.ids[name][5] == False and self.ids[name][6] == False:
                self.ms.itemconfig(self.ids[name][1], text='⚐')
                self.ids[name][5] = True
                self.mines_rem -= 1
                self.ms.itemconfig(self.ids['mine_box'][1],
                                   text=str(self.mines_rem))
                self.win_check()

            elif self.ids[name][5] == True and self.ids[name][6] == False:
                self.ms.itemconfig(self.ids[name][1], text='?')
                self.ids[name][5] = False
                self.ids[name][6] = True
                self.mines_rem += 1
                self.ms.itemconfig(self.ids['mine_box'][1],
                                   text=str(self.mines_rem))

            elif self.ids[name][5] == False and self.ids[name][6] == True:
                self.ms.itemconfig(self.ids[name][1], text='')
                self.ids[name][5] = False
                self.ids[name][6] = False

            else:  #if any other case arrises
                self.ms.itemconfig(self.ids[name][1], text='')
                self.ids[name][5] = False
                self.ids[name][6] = False

    #this function would find the nearby blank positions and activate them
    def stepped_on_blank(self, i):
        ##in 'i' position the [name][3] == 0
        #print(i)
        if i % 15 < 14:  ##rights boxes
            if not self.ids['box_' + str(i + 1)][4]:
                print(i // 15, i % 15)
                self.left_clicked('box_' + str(i + 1))
        if i % 15 > 0:  ##left boxes
            if not self.ids['box_' + str(i - 1)][4]:
                print(i // 15, i % 15)
                self.left_clicked('box_' + str(i - 1))
        if i > 14:  ##up boxes
            if not self.ids['box_' + str(i - 15)][4]:
                print(i // 15, i % 15)
                self.left_clicked('box_' + str(i - 15))
        if i < 210:  ##down boxes
            if not self.ids['box_' + str(i + 15)][4]:
                print(i // 15, i % 15)
                self.left_clicked('box_' + str(i + 15))
        if i > 14 and i % 15 > 0:  ##up left
            if not self.ids['box_' + str(i - 16)][4]:
                print(i // 15, i % 15)
                self.left_clicked('box_' + str(i - 16))
        if i > 14 and i % 14 < 14:  ##up right
            if not self.ids['box_' + str(i - 14)][4]:
                print(i // 15, i % 15)
                self.left_clicked('box_' + str(i - 14))
        if i < 210 and i % 15 > 0:  #down left
            if not self.ids['box_' + str(i + 14)][4]:
                print(i // 15, i % 15)
                self.left_clicked('box_' + str(i + 14))
        if i < 210 and i % 15 < 14:  #down left
            if not self.ids['box_' + str(i + 16)][4]:
                print(i // 15, i % 15)
                self.left_clicked('box_' + str(i + 16))

    def win_check(self):
        check = 40
        if self.mines_rem == 0:
            for i in range(225):
                if self.ids['box_' + str(i)][2] and self.ids['box_' +
                                                             str(i)][5]:
                    check -= 1
                    print(self.mines_rem, check)

        if check == 0:
            self.game_on = False
            self.win_game()

    def win_game(self):
        for i in range(225):
            if self.ids['box_' + str(i)][2]:
                self.ms.itemconfig(self.ids['box_' + str(i)][0],
                                   fill='#7777ff')
                self.ms.itemconfig(self.ids['mine_box'][0], fill='#33ff33')
                self.ms.itemconfig(self.ids['mine_box'][1], text='Won')

    def stepped_on_mine(self, name):
        self.game_on = False
        for i in range(225):
            if self.ids['box_' + str(i)][2]:
                self.ms.itemconfig(self.ids['box_' + str(i)][0],
                                   fill='#cc0000')
        self.ms.itemconfig(self.ids[name][0], fill='#ff0000')
Example #17
0
class CollocationsView:
    _BACKGROUND_COLOUR='#FFF' #white

    def __init__(self):
        self.queue = q.Queue()
        self.model = CollocationsModel(self.queue)
        self.top = Tk()
        self._init_top(self.top)
        self._init_menubar()
        self._init_widgets(self.top)
        self.load_corpus(self.model.DEFAULT_CORPUS)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def _init_top(self, top):
        top.geometry('550x650+50+50')
        top.title('NLTK Collocations List')
        top.bind('<Control-q>', self.destroy)
        top.protocol('WM_DELETE_WINDOW', self.destroy)
        top.minsize(550,650)

    def _init_widgets(self, parent):
        self.main_frame = Frame(parent, dict(background=self._BACKGROUND_COLOUR, padx=1, pady=1, border=1))
        self._init_corpus_select(self.main_frame)
        self._init_results_box(self.main_frame)
        self._init_paging(self.main_frame)
        self._init_status(self.main_frame)
        self.main_frame.pack(fill='both', expand=True)

    def _init_corpus_select(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.var = StringVar(innerframe)
        self.var.set(self.model.DEFAULT_CORPUS)
        Label(innerframe, justify=LEFT, text=' Corpus: ', background=self._BACKGROUND_COLOUR, padx = 2, pady = 1, border = 0).pack(side='left')

        other_corpora = list(self.model.CORPORA.keys()).remove(self.model.DEFAULT_CORPUS)
        om = OptionMenu(innerframe, self.var, self.model.DEFAULT_CORPUS, command=self.corpus_selected, *self.model.non_default_corpora())
        om['borderwidth'] = 0
        om['highlightthickness'] = 1
        om.pack(side='left')
        innerframe.pack(side='top', fill='x', anchor='n')

    def _init_status(self, parent):
        self.status = Label(parent, justify=LEFT, relief=SUNKEN, background=self._BACKGROUND_COLOUR, border=0, padx = 1, pady = 0)
        self.status.pack(side='top', anchor='sw')

    def _init_menubar(self):
        self._result_size = IntVar(self.top)
        menubar = Menu(self.top)

        filemenu = Menu(menubar, tearoff=0, borderwidth=0)
        filemenu.add_command(label='Exit', underline=1,
                   command=self.destroy, accelerator='Ctrl-q')
        menubar.add_cascade(label='File', underline=0, menu=filemenu)

        editmenu = Menu(menubar, tearoff=0)
        rescntmenu = Menu(editmenu, tearoff=0)
        rescntmenu.add_radiobutton(label='20', variable=self._result_size,
                     underline=0, value=20, command=self.set_result_size)
        rescntmenu.add_radiobutton(label='50', variable=self._result_size,
                     underline=0, value=50, command=self.set_result_size)
        rescntmenu.add_radiobutton(label='100', variable=self._result_size,
                     underline=0, value=100, command=self.set_result_size)
        rescntmenu.invoke(1)
        editmenu.add_cascade(label='Result Count', underline=0, menu=rescntmenu)

        menubar.add_cascade(label='Edit', underline=0, menu=editmenu)
        self.top.config(menu=menubar)

    def set_result_size(self, **kwargs):
        self.model.result_count = self._result_size.get()

    def _init_results_box(self, parent):
        innerframe = Frame(parent)
        i1 = Frame(innerframe)
        i2 = Frame(innerframe)
        vscrollbar = Scrollbar(i1, borderwidth=1)
        hscrollbar = Scrollbar(i2, borderwidth=1, orient='horiz')
        self.results_box = Text(i1,
                    font=tkinter.font.Font(family='courier', size='16'),
                    state='disabled', borderwidth=1,
                    yscrollcommand=vscrollbar.set,
                    xscrollcommand=hscrollbar.set, wrap='none', width='40', height = '20', exportselection=1)
        self.results_box.pack(side='left', fill='both', expand=True)
        vscrollbar.pack(side='left', fill='y', anchor='e')
        vscrollbar.config(command=self.results_box.yview)
        hscrollbar.pack(side='left', fill='x', expand=True, anchor='w')
        hscrollbar.config(command=self.results_box.xview)
        #there is no other way of avoiding the overlap of scrollbars while using pack layout manager!!!
        Label(i2, text='   ', background=self._BACKGROUND_COLOUR).pack(side='left', anchor='e')
        i1.pack(side='top', fill='both', expand=True, anchor='n')
        i2.pack(side='bottom', fill='x', anchor='s')
        innerframe.pack(side='top', fill='both', expand=True)

    def _init_paging(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.prev = prev = Button(innerframe, text='Previous', command=self.previous, width='10', borderwidth=1, highlightthickness=1, state='disabled')
        prev.pack(side='left', anchor='center')
        self.next = next = Button(innerframe, text='Next', command=self.__next__, width='10', borderwidth=1, highlightthickness=1, state='disabled')
        next.pack(side='right', anchor='center')
        innerframe.pack(side='top', fill='y')
        self.reset_current_page()

    def reset_current_page(self):
        self.current_page = -1

    def _poll(self):
        try:
            event = self.queue.get(block=False)
        except q.Empty:
            pass
        else:
            if event == CORPUS_LOADED_EVENT:
                self.handle_corpus_loaded(event)
            elif event == ERROR_LOADING_CORPUS_EVENT:
                self.handle_error_loading_corpus(event)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def handle_error_loading_corpus(self, event):
        self.status['text'] = 'Error in loading ' + self.var.get()
        self.unfreeze_editable()
        self.clear_results_box()
        self.freeze_editable()
        self.reset_current_page()

    def handle_corpus_loaded(self, event):
        self.status['text'] = self.var.get() + ' is loaded'
        self.unfreeze_editable()
        self.clear_results_box()
        self.reset_current_page()
        #self.next()
        collocations = self.model.next(self.current_page + 1)
        self.write_results(collocations)
        self.current_page += 1

    def corpus_selected(self, *args):
        new_selection = self.var.get()
        self.load_corpus(new_selection)

    def previous(self):
        self.freeze_editable()
        collocations = self.model.prev(self.current_page - 1)
        self.current_page= self.current_page - 1
        self.clear_results_box()
        self.write_results(collocations)
        self.unfreeze_editable()

    def __next__(self):
        self.freeze_editable()
        collocations = self.model.next(self.current_page + 1)
        self.clear_results_box()
        self.write_results(collocations)
        self.current_page += 1
        self.unfreeze_editable()

    def load_corpus(self, selection):
        if self.model.selected_corpus != selection:
            self.status['text'] = 'Loading ' + selection + '...'
            self.freeze_editable()
            self.model.load_corpus(selection)

    def freeze_editable(self):
        self.prev['state'] = 'disabled'
        self.next['state'] = 'disabled'

    def clear_results_box(self):
        self.results_box['state'] = 'normal'
        self.results_box.delete("1.0", END)
        self.results_box['state'] = 'disabled'

    def fire_event(self, event):
        #Firing an event so that rendering of widgets happen in the mainloop thread
        self.top.event_generate(event, when='tail')

    def destroy(self, *e):
        if self.top is None: return
        self.top.after_cancel(self.after)
        self.top.destroy()
        self.top = None

    def mainloop(self, *args, **kwargs):
        if in_idle(): return
        self.top.mainloop(*args, **kwargs)

    def unfreeze_editable(self):
        self.set_paging_button_states()

    def set_paging_button_states(self):
        if self.current_page == -1 or self.current_page == 0:
            self.prev['state'] = 'disabled'
        else:
            self.prev['state'] = 'normal'
        if self.model.is_last_page(self.current_page):
            self.next['state'] = 'disabled'
        else:
            self.next['state'] = 'normal'

    def write_results(self, results):
        self.results_box['state'] = 'normal'
        row = 1
        for each in results:
            self.results_box.insert(str(row) + '.0', each[0] + " " + each[1] + "\n")
            row += 1
        self.results_box['state'] = 'disabled'
Example #18
0
class ConcordanceSearchView(object):
    _BACKGROUND_COLOUR = "#FFF"  # white

    # Colour of highlighted results
    _HIGHLIGHT_WORD_COLOUR = "#F00"  # red
    _HIGHLIGHT_WORD_TAG = "HL_WRD_TAG"

    _HIGHLIGHT_LABEL_COLOUR = "#C0C0C0"  # dark grey
    _HIGHLIGHT_LABEL_TAG = "HL_LBL_TAG"

    # Percentage of text left of the scrollbar position
    _FRACTION_LEFT_TEXT = 0.30

    def __init__(self):
        self.queue = q.Queue()
        self.model = ConcordanceSearchModel(self.queue)
        self.top = Tk()
        self._init_top(self.top)
        self._init_menubar()
        self._init_widgets(self.top)
        self.load_corpus(self.model.DEFAULT_CORPUS)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def _init_top(self, top):
        top.geometry("950x680+50+50")
        top.title("NLTK Concordance Search")
        top.bind("<Control-q>", self.destroy)
        top.protocol("WM_DELETE_WINDOW", self.destroy)
        top.minsize(950, 680)

    def _init_widgets(self, parent):
        self.main_frame = Frame(parent, dict(background=self._BACKGROUND_COLOUR, padx=1, pady=1, border=1))
        self._init_corpus_select(self.main_frame)
        self._init_query_box(self.main_frame)
        self._init_results_box(self.main_frame)
        self._init_paging(self.main_frame)
        self._init_status(self.main_frame)
        self.main_frame.pack(fill="both", expand=True)

    def _init_menubar(self):
        self._result_size = IntVar(self.top)
        self._cntx_bf_len = IntVar(self.top)
        self._cntx_af_len = IntVar(self.top)
        menubar = Menu(self.top)

        filemenu = Menu(menubar, tearoff=0, borderwidth=0)
        filemenu.add_command(label="Exit", underline=1, command=self.destroy, accelerator="Ctrl-q")
        menubar.add_cascade(label="File", underline=0, menu=filemenu)

        editmenu = Menu(menubar, tearoff=0)
        rescntmenu = Menu(editmenu, tearoff=0)
        rescntmenu.add_radiobutton(
            label="20", variable=self._result_size, underline=0, value=20, command=self.set_result_size
        )
        rescntmenu.add_radiobutton(
            label="50", variable=self._result_size, underline=0, value=50, command=self.set_result_size
        )
        rescntmenu.add_radiobutton(
            label="100", variable=self._result_size, underline=0, value=100, command=self.set_result_size
        )
        rescntmenu.invoke(1)
        editmenu.add_cascade(label="Result Count", underline=0, menu=rescntmenu)

        cntxmenu = Menu(editmenu, tearoff=0)
        cntxbfmenu = Menu(cntxmenu, tearoff=0)
        cntxbfmenu.add_radiobutton(
            label="60 characters", variable=self._cntx_bf_len, underline=0, value=60, command=self.set_cntx_bf_len
        )
        cntxbfmenu.add_radiobutton(
            label="80 characters", variable=self._cntx_bf_len, underline=0, value=80, command=self.set_cntx_bf_len
        )
        cntxbfmenu.add_radiobutton(
            label="100 characters", variable=self._cntx_bf_len, underline=0, value=100, command=self.set_cntx_bf_len
        )
        cntxbfmenu.invoke(1)
        cntxmenu.add_cascade(label="Before", underline=0, menu=cntxbfmenu)

        cntxafmenu = Menu(cntxmenu, tearoff=0)
        cntxafmenu.add_radiobutton(
            label="70 characters", variable=self._cntx_af_len, underline=0, value=70, command=self.set_cntx_af_len
        )
        cntxafmenu.add_radiobutton(
            label="90 characters", variable=self._cntx_af_len, underline=0, value=90, command=self.set_cntx_af_len
        )
        cntxafmenu.add_radiobutton(
            label="110 characters", variable=self._cntx_af_len, underline=0, value=110, command=self.set_cntx_af_len
        )
        cntxafmenu.invoke(1)
        cntxmenu.add_cascade(label="After", underline=0, menu=cntxafmenu)

        editmenu.add_cascade(label="Context", underline=0, menu=cntxmenu)

        menubar.add_cascade(label="Edit", underline=0, menu=editmenu)

        self.top.config(menu=menubar)

    def set_result_size(self, **kwargs):
        self.model.result_count = self._result_size.get()

    def set_cntx_af_len(self, **kwargs):
        self._char_after = self._cntx_af_len.get()

    def set_cntx_bf_len(self, **kwargs):
        self._char_before = self._cntx_bf_len.get()

    def _init_corpus_select(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.var = StringVar(innerframe)
        self.var.set(self.model.DEFAULT_CORPUS)
        Label(
            innerframe, justify=LEFT, text=" Corpus: ", background=self._BACKGROUND_COLOUR, padx=2, pady=1, border=0
        ).pack(side="left")

        other_corpora = list(self.model.CORPORA.keys()).remove(self.model.DEFAULT_CORPUS)
        om = OptionMenu(
            innerframe,
            self.var,
            self.model.DEFAULT_CORPUS,
            command=self.corpus_selected,
            *self.model.non_default_corpora()
        )
        om["borderwidth"] = 0
        om["highlightthickness"] = 1
        om.pack(side="left")
        innerframe.pack(side="top", fill="x", anchor="n")

    def _init_status(self, parent):
        self.status = Label(
            parent, justify=LEFT, relief=SUNKEN, background=self._BACKGROUND_COLOUR, border=0, padx=1, pady=0
        )
        self.status.pack(side="top", anchor="sw")

    def _init_query_box(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        another = Frame(innerframe, background=self._BACKGROUND_COLOUR)
        self.query_box = Entry(another, width=60)
        self.query_box.pack(side="left", fill="x", pady=25, anchor="center")
        self.search_button = Button(another, text="Search", command=self.search, borderwidth=1, highlightthickness=1)
        self.search_button.pack(side="left", fill="x", pady=25, anchor="center")
        self.query_box.bind("<KeyPress-Return>", self.search_enter_keypress_handler)
        another.pack()
        innerframe.pack(side="top", fill="x", anchor="n")

    def search_enter_keypress_handler(self, *event):
        self.search()

    def _init_results_box(self, parent):
        innerframe = Frame(parent)
        i1 = Frame(innerframe)
        i2 = Frame(innerframe)
        vscrollbar = Scrollbar(i1, borderwidth=1)
        hscrollbar = Scrollbar(i2, borderwidth=1, orient="horiz")
        self.results_box = Text(
            i1,
            font=tkinter.font.Font(family="courier", size="16"),
            state="disabled",
            borderwidth=1,
            yscrollcommand=vscrollbar.set,
            xscrollcommand=hscrollbar.set,
            wrap="none",
            width="40",
            height="20",
            exportselection=1,
        )
        self.results_box.pack(side="left", fill="both", expand=True)
        self.results_box.tag_config(self._HIGHLIGHT_WORD_TAG, foreground=self._HIGHLIGHT_WORD_COLOUR)
        self.results_box.tag_config(self._HIGHLIGHT_LABEL_TAG, foreground=self._HIGHLIGHT_LABEL_COLOUR)
        vscrollbar.pack(side="left", fill="y", anchor="e")
        vscrollbar.config(command=self.results_box.yview)
        hscrollbar.pack(side="left", fill="x", expand=True, anchor="w")
        hscrollbar.config(command=self.results_box.xview)
        # there is no other way of avoiding the overlap of scrollbars while using pack layout manager!!!
        Label(i2, text="   ", background=self._BACKGROUND_COLOUR).pack(side="left", anchor="e")
        i1.pack(side="top", fill="both", expand=True, anchor="n")
        i2.pack(side="bottom", fill="x", anchor="s")
        innerframe.pack(side="top", fill="both", expand=True)

    def _init_paging(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.prev = prev = Button(
            innerframe,
            text="Previous",
            command=self.previous,
            width="10",
            borderwidth=1,
            highlightthickness=1,
            state="disabled",
        )
        prev.pack(side="left", anchor="center")
        self.next = next = Button(
            innerframe,
            text="Next",
            command=self.__next__,
            width="10",
            borderwidth=1,
            highlightthickness=1,
            state="disabled",
        )
        next.pack(side="right", anchor="center")
        innerframe.pack(side="top", fill="y")
        self.current_page = 0

    def previous(self):
        self.clear_results_box()
        self.freeze_editable()
        self.model.prev(self.current_page - 1)

    def __next__(self):
        self.clear_results_box()
        self.freeze_editable()
        self.model.next(self.current_page + 1)

    def about(self, *e):
        ABOUT = "NLTK Concordance Search Demo\n"
        TITLE = "About: NLTK Concordance Search Demo"
        try:
            from tkinter.messagebox import Message

            Message(message=ABOUT, title=TITLE, parent=self.main_frame).show()
        except:
            ShowText(self.top, TITLE, ABOUT)

    def _bind_event_handlers(self):
        self.top.bind(CORPUS_LOADED_EVENT, self.handle_corpus_loaded)
        self.top.bind(SEARCH_TERMINATED_EVENT, self.handle_search_terminated)
        self.top.bind(SEARCH_ERROR_EVENT, self.handle_search_error)
        self.top.bind(ERROR_LOADING_CORPUS_EVENT, self.handle_error_loading_corpus)

    def _poll(self):
        try:
            event = self.queue.get(block=False)
        except q.Empty:
            pass
        else:
            if event == CORPUS_LOADED_EVENT:
                self.handle_corpus_loaded(event)
            elif event == SEARCH_TERMINATED_EVENT:
                self.handle_search_terminated(event)
            elif event == SEARCH_ERROR_EVENT:
                self.handle_search_error(event)
            elif event == ERROR_LOADING_CORPUS_EVENT:
                self.handle_error_loading_corpus(event)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def handle_error_loading_corpus(self, event):
        self.status["text"] = "Error in loading " + self.var.get()
        self.unfreeze_editable()
        self.clear_all()
        self.freeze_editable()

    def handle_corpus_loaded(self, event):
        self.status["text"] = self.var.get() + " is loaded"
        self.unfreeze_editable()
        self.clear_all()
        self.query_box.focus_set()

    def handle_search_terminated(self, event):
        # todo: refactor the model such that it is less state sensitive
        results = self.model.get_results()
        self.write_results(results)
        self.status["text"] = ""
        if len(results) == 0:
            self.status["text"] = "No results found for " + self.model.query
        else:
            self.current_page = self.model.last_requested_page
        self.unfreeze_editable()
        self.results_box.xview_moveto(self._FRACTION_LEFT_TEXT)

    def handle_search_error(self, event):
        self.status["text"] = "Error in query " + self.model.query
        self.unfreeze_editable()

    def corpus_selected(self, *args):
        new_selection = self.var.get()
        self.load_corpus(new_selection)

    def load_corpus(self, selection):
        if self.model.selected_corpus != selection:
            self.status["text"] = "Loading " + selection + "..."
            self.freeze_editable()
            self.model.load_corpus(selection)

    def search(self):
        self.current_page = 0
        self.clear_results_box()
        self.model.reset_results()
        query = self.query_box.get()
        if len(query.strip()) == 0:
            return
        self.status["text"] = "Searching for " + query
        self.freeze_editable()
        self.model.search(query, self.current_page + 1)

    def write_results(self, results):
        self.results_box["state"] = "normal"
        row = 1
        for each in results:
            sent, pos1, pos2 = each[0].strip(), each[1], each[2]
            if len(sent) != 0:
                if pos1 < self._char_before:
                    sent, pos1, pos2 = self.pad(sent, pos1, pos2)
                sentence = sent[pos1 - self._char_before : pos1 + self._char_after]
                if not row == len(results):
                    sentence += "\n"
                self.results_box.insert(str(row) + ".0", sentence)
                word_markers, label_markers = self.words_and_labels(sent, pos1, pos2)
                for marker in word_markers:
                    self.results_box.tag_add(
                        self._HIGHLIGHT_WORD_TAG, str(row) + "." + str(marker[0]), str(row) + "." + str(marker[1])
                    )
                for marker in label_markers:
                    self.results_box.tag_add(
                        self._HIGHLIGHT_LABEL_TAG, str(row) + "." + str(marker[0]), str(row) + "." + str(marker[1])
                    )
                row += 1
        self.results_box["state"] = "disabled"

    def words_and_labels(self, sentence, pos1, pos2):
        search_exp = sentence[pos1:pos2]
        words, labels = [], []
        labeled_words = search_exp.split(" ")
        index = 0
        for each in labeled_words:
            if each == "":
                index += 1
            else:
                word, label = each.split("/")
                words.append((self._char_before + index, self._char_before + index + len(word)))
                index += len(word) + 1
                labels.append((self._char_before + index, self._char_before + index + len(label)))
                index += len(label)
            index += 1
        return words, labels

    def pad(self, sent, hstart, hend):
        if hstart >= self._char_before:
            return sent, hstart, hend
        d = self._char_before - hstart
        sent = "".join([" "] * d) + sent
        return sent, hstart + d, hend + d

    def destroy(self, *e):
        if self.top is None:
            return
        self.top.after_cancel(self.after)
        self.top.destroy()
        self.top = None

    def clear_all(self):
        self.query_box.delete(0, END)
        self.model.reset_query()
        self.clear_results_box()

    def clear_results_box(self):
        self.results_box["state"] = "normal"
        self.results_box.delete("1.0", END)
        self.results_box["state"] = "disabled"

    def freeze_editable(self):
        self.query_box["state"] = "disabled"
        self.search_button["state"] = "disabled"
        self.prev["state"] = "disabled"
        self.next["state"] = "disabled"

    def unfreeze_editable(self):
        self.query_box["state"] = "normal"
        self.search_button["state"] = "normal"
        self.set_paging_button_states()

    def set_paging_button_states(self):
        if self.current_page == 0 or self.current_page == 1:
            self.prev["state"] = "disabled"
        else:
            self.prev["state"] = "normal"
        if self.model.has_more_pages(self.current_page):
            self.next["state"] = "normal"
        else:
            self.next["state"] = "disabled"

    def fire_event(self, event):
        # Firing an event so that rendering of widgets happen in the mainloop thread
        self.top.event_generate(event, when="tail")

    def mainloop(self, *args, **kwargs):
        if in_idle():
            return
        self.top.mainloop(*args, **kwargs)
Example #19
0
class CollocationsView:
    _BACKGROUND_COLOUR = '#FFF'  #white

    def __init__(self):
        self.queue = q.Queue()
        self.model = CollocationsModel(self.queue)
        self.top = Tk()
        self._init_top(self.top)
        self._init_menubar()
        self._init_widgets(self.top)
        self.load_corpus(self.model.DEFAULT_CORPUS)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def _init_top(self, top):
        top.geometry('550x650+50+50')
        top.title('NLTK Collocations List')
        top.bind('<Control-q>', self.destroy)
        top.protocol('WM_DELETE_WINDOW', self.destroy)
        top.minsize(550, 650)

    def _init_widgets(self, parent):
        self.main_frame = Frame(
            parent,
            dict(background=self._BACKGROUND_COLOUR, padx=1, pady=1, border=1))
        self._init_corpus_select(self.main_frame)
        self._init_results_box(self.main_frame)
        self._init_paging(self.main_frame)
        self._init_status(self.main_frame)
        self.main_frame.pack(fill='both', expand=True)

    def _init_corpus_select(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.var = StringVar(innerframe)
        self.var.set(self.model.DEFAULT_CORPUS)
        Label(innerframe,
              justify=LEFT,
              text=' Corpus: ',
              background=self._BACKGROUND_COLOUR,
              padx=2,
              pady=1,
              border=0).pack(side='left')

        other_corpora = list(self.model.CORPORA.keys()).remove(
            self.model.DEFAULT_CORPUS)
        om = OptionMenu(innerframe,
                        self.var,
                        self.model.DEFAULT_CORPUS,
                        command=self.corpus_selected,
                        *self.model.non_default_corpora())
        om['borderwidth'] = 0
        om['highlightthickness'] = 1
        om.pack(side='left')
        innerframe.pack(side='top', fill='x', anchor='n')

    def _init_status(self, parent):
        self.status = Label(parent,
                            justify=LEFT,
                            relief=SUNKEN,
                            background=self._BACKGROUND_COLOUR,
                            border=0,
                            padx=1,
                            pady=0)
        self.status.pack(side='top', anchor='sw')

    def _init_menubar(self):
        self._result_size = IntVar(self.top)
        menubar = Menu(self.top)

        filemenu = Menu(menubar, tearoff=0, borderwidth=0)
        filemenu.add_command(label='Exit',
                             underline=1,
                             command=self.destroy,
                             accelerator='Ctrl-q')
        menubar.add_cascade(label='File', underline=0, menu=filemenu)

        editmenu = Menu(menubar, tearoff=0)
        rescntmenu = Menu(editmenu, tearoff=0)
        rescntmenu.add_radiobutton(label='20',
                                   variable=self._result_size,
                                   underline=0,
                                   value=20,
                                   command=self.set_result_size)
        rescntmenu.add_radiobutton(label='50',
                                   variable=self._result_size,
                                   underline=0,
                                   value=50,
                                   command=self.set_result_size)
        rescntmenu.add_radiobutton(label='100',
                                   variable=self._result_size,
                                   underline=0,
                                   value=100,
                                   command=self.set_result_size)
        rescntmenu.invoke(1)
        editmenu.add_cascade(label='Result Count',
                             underline=0,
                             menu=rescntmenu)

        menubar.add_cascade(label='Edit', underline=0, menu=editmenu)
        self.top.config(menu=menubar)

    def set_result_size(self, **kwargs):
        self.model.result_count = self._result_size.get()

    def _init_results_box(self, parent):
        innerframe = Frame(parent)
        i1 = Frame(innerframe)
        i2 = Frame(innerframe)
        vscrollbar = Scrollbar(i1, borderwidth=1)
        hscrollbar = Scrollbar(i2, borderwidth=1, orient='horiz')
        self.results_box = Text(i1,
                                font=tkinter.font.Font(family='courier',
                                                       size='16'),
                                state='disabled',
                                borderwidth=1,
                                yscrollcommand=vscrollbar.set,
                                xscrollcommand=hscrollbar.set,
                                wrap='none',
                                width='40',
                                height='20',
                                exportselection=1)
        self.results_box.pack(side='left', fill='both', expand=True)
        vscrollbar.pack(side='left', fill='y', anchor='e')
        vscrollbar.config(command=self.results_box.yview)
        hscrollbar.pack(side='left', fill='x', expand=True, anchor='w')
        hscrollbar.config(command=self.results_box.xview)
        #there is no other way of avoiding the overlap of scrollbars while using pack layout manager!!!
        Label(i2, text='   ',
              background=self._BACKGROUND_COLOUR).pack(side='left', anchor='e')
        i1.pack(side='top', fill='both', expand=True, anchor='n')
        i2.pack(side='bottom', fill='x', anchor='s')
        innerframe.pack(side='top', fill='both', expand=True)

    def _init_paging(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.prev = prev = Button(innerframe,
                                  text='Previous',
                                  command=self.previous,
                                  width='10',
                                  borderwidth=1,
                                  highlightthickness=1,
                                  state='disabled')
        prev.pack(side='left', anchor='center')
        self.next = next = Button(innerframe,
                                  text='Next',
                                  command=self.__next__,
                                  width='10',
                                  borderwidth=1,
                                  highlightthickness=1,
                                  state='disabled')
        next.pack(side='right', anchor='center')
        innerframe.pack(side='top', fill='y')
        self.reset_current_page()

    def reset_current_page(self):
        self.current_page = -1

    def _poll(self):
        try:
            event = self.queue.get(block=False)
        except q.Empty:
            pass
        else:
            if event == CORPUS_LOADED_EVENT:
                self.handle_corpus_loaded(event)
            elif event == ERROR_LOADING_CORPUS_EVENT:
                self.handle_error_loading_corpus(event)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def handle_error_loading_corpus(self, event):
        self.status['text'] = 'Error in loading ' + self.var.get()
        self.unfreeze_editable()
        self.clear_results_box()
        self.freeze_editable()
        self.reset_current_page()

    def handle_corpus_loaded(self, event):
        self.status['text'] = self.var.get() + ' is loaded'
        self.unfreeze_editable()
        self.clear_results_box()
        self.reset_current_page()
        #self.next()
        collocations = self.model.next(self.current_page + 1)
        self.write_results(collocations)
        self.current_page += 1

    def corpus_selected(self, *args):
        new_selection = self.var.get()
        self.load_corpus(new_selection)

    def previous(self):
        self.freeze_editable()
        collocations = self.model.prev(self.current_page - 1)
        self.current_page = self.current_page - 1
        self.clear_results_box()
        self.write_results(collocations)
        self.unfreeze_editable()

    def __next__(self):
        self.freeze_editable()
        collocations = self.model.next(self.current_page + 1)
        self.clear_results_box()
        self.write_results(collocations)
        self.current_page += 1
        self.unfreeze_editable()

    def load_corpus(self, selection):
        if self.model.selected_corpus != selection:
            self.status['text'] = 'Loading ' + selection + '...'
            self.freeze_editable()
            self.model.load_corpus(selection)

    def freeze_editable(self):
        self.prev['state'] = 'disabled'
        self.next['state'] = 'disabled'

    def clear_results_box(self):
        self.results_box['state'] = 'normal'
        self.results_box.delete("1.0", END)
        self.results_box['state'] = 'disabled'

    def fire_event(self, event):
        #Firing an event so that rendering of widgets happen in the mainloop thread
        self.top.event_generate(event, when='tail')

    def destroy(self, *e):
        if self.top is None: return
        self.top.after_cancel(self.after)
        self.top.destroy()
        self.top = None

    def mainloop(self, *args, **kwargs):
        if in_idle(): return
        self.top.mainloop(*args, **kwargs)

    def unfreeze_editable(self):
        self.set_paging_button_states()

    def set_paging_button_states(self):
        if self.current_page == -1 or self.current_page == 0:
            self.prev['state'] = 'disabled'
        else:
            self.prev['state'] = 'normal'
        if self.model.is_last_page(self.current_page):
            self.next['state'] = 'disabled'
        else:
            self.next['state'] = 'normal'

    def write_results(self, results):
        self.results_box['state'] = 'normal'
        row = 1
        for each in results:
            self.results_box.insert(
                str(row) + '.0', each[0] + " " + each[1] + "\n")
            row += 1
        self.results_box['state'] = 'disabled'
Example #20
0
class GameApp:
    def __init__(self):
        self.model = Game()
        self.job = None
        self.speed = 1
        self.root = Tk()
        self.canvas = Field(self.root, self.model)
        self.toolbar = Toolbar(self.root)
        self.toolbar.add_button(text='Load', command=self.load)
        self.toolbar.add_button(text='Save', command=self.save)
        self.toolbar.add_button(text='Origin', command=self.canvas.origin)
        self.toolbar.add_radio_button_group(buttons={
            1: 'Pause',
            2: 'Play'
        },
                                            command=self.on_state_changed)
        self.toolbar.add_radio_button_group(buttons={
            1: 'x1',
            2: 'x2',
            4: 'x4',
            8: 'x8',
            16: 'x16'
        },
                                            command=self.on_speed_changed)
        self.toolbar.pack(side=TOP, fill=X)
        self.canvas.pack()
        self.root.resizable(False, False)

    def load(self):
        filename = filedialog.askopenfilename(initialdir="./data/",
                                              title="Select file",
                                              filetypes=(("Life files",
                                                          "*.life"),
                                                         ("All files", "*.*")))
        try:
            with open(filename, 'r') as file:
                field = FieldSerializer.deserialize(file)
                self.model.field = field
                self.canvas.update()
        except IOError as error:
            print(error, file=sys.stderr)

    def save(self):
        filename = filedialog.asksaveasfilename(
            initialdir="./data/",
            title="Save file as",
            filetypes=(("Life files", "*.life"), ("All files", "*.*")))
        try:
            with open(filename, 'w') as file:
                buffer = FieldSerializer.serialize(self.model.field)
                buffer.seek(0)
                shutil.copyfileobj(buffer, file)
                buffer.close()
        except IOError as error:
            print(error, file=sys.stderr)

    def play(self):
        self.model.next_state()
        self.job = self.root.after(int(self.speed * 1000), self.play)

    def pause(self):
        if self.job:
            self.root.after_cancel(self.job)

    def on_speed_changed(self, value):
        self.speed = 1 / value

    def on_state_changed(self, value):
        if value == 1:
            self.pause()
        elif value == 2:
            self.play()
Example #21
0
class ConcordanceSearchView(object):
    _BACKGROUND_COLOUR = '#FFF'  #white

    #Colour of highlighted results
    _HIGHLIGHT_WORD_COLOUR = '#F00'  #red
    _HIGHLIGHT_WORD_TAG = 'HL_WRD_TAG'

    _HIGHLIGHT_LABEL_COLOUR = '#C0C0C0'  # dark grey
    _HIGHLIGHT_LABEL_TAG = 'HL_LBL_TAG'

    #Percentage of text left of the scrollbar position
    _FRACTION_LEFT_TEXT = 0.30

    def __init__(self):
        self.queue = q.Queue()
        self.model = ConcordanceSearchModel(self.queue)
        self.top = Tk()
        self._init_top(self.top)
        self._init_menubar()
        self._init_widgets(self.top)
        self.load_corpus(self.model.DEFAULT_CORPUS)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def _init_top(self, top):
        top.geometry('950x680+50+50')
        top.title('NLTK Concordance Search')
        top.bind('<Control-q>', self.destroy)
        top.protocol('WM_DELETE_WINDOW', self.destroy)
        top.minsize(950, 680)

    def _init_widgets(self, parent):
        self.main_frame = Frame(
            parent,
            dict(background=self._BACKGROUND_COLOUR, padx=1, pady=1, border=1))
        self._init_corpus_select(self.main_frame)
        self._init_query_box(self.main_frame)
        self._init_results_box(self.main_frame)
        self._init_paging(self.main_frame)
        self._init_status(self.main_frame)
        self.main_frame.pack(fill='both', expand=True)

    def _init_menubar(self):
        self._result_size = IntVar(self.top)
        self._cntx_bf_len = IntVar(self.top)
        self._cntx_af_len = IntVar(self.top)
        menubar = Menu(self.top)

        filemenu = Menu(menubar, tearoff=0, borderwidth=0)
        filemenu.add_command(label='Exit',
                             underline=1,
                             command=self.destroy,
                             accelerator='Ctrl-q')
        menubar.add_cascade(label='File', underline=0, menu=filemenu)

        editmenu = Menu(menubar, tearoff=0)
        rescntmenu = Menu(editmenu, tearoff=0)
        rescntmenu.add_radiobutton(label='20',
                                   variable=self._result_size,
                                   underline=0,
                                   value=20,
                                   command=self.set_result_size)
        rescntmenu.add_radiobutton(label='50',
                                   variable=self._result_size,
                                   underline=0,
                                   value=50,
                                   command=self.set_result_size)
        rescntmenu.add_radiobutton(label='100',
                                   variable=self._result_size,
                                   underline=0,
                                   value=100,
                                   command=self.set_result_size)
        rescntmenu.invoke(1)
        editmenu.add_cascade(label='Result Count',
                             underline=0,
                             menu=rescntmenu)

        cntxmenu = Menu(editmenu, tearoff=0)
        cntxbfmenu = Menu(cntxmenu, tearoff=0)
        cntxbfmenu.add_radiobutton(label='60 characters',
                                   variable=self._cntx_bf_len,
                                   underline=0,
                                   value=60,
                                   command=self.set_cntx_bf_len)
        cntxbfmenu.add_radiobutton(label='80 characters',
                                   variable=self._cntx_bf_len,
                                   underline=0,
                                   value=80,
                                   command=self.set_cntx_bf_len)
        cntxbfmenu.add_radiobutton(label='100 characters',
                                   variable=self._cntx_bf_len,
                                   underline=0,
                                   value=100,
                                   command=self.set_cntx_bf_len)
        cntxbfmenu.invoke(1)
        cntxmenu.add_cascade(label='Before', underline=0, menu=cntxbfmenu)

        cntxafmenu = Menu(cntxmenu, tearoff=0)
        cntxafmenu.add_radiobutton(label='70 characters',
                                   variable=self._cntx_af_len,
                                   underline=0,
                                   value=70,
                                   command=self.set_cntx_af_len)
        cntxafmenu.add_radiobutton(label='90 characters',
                                   variable=self._cntx_af_len,
                                   underline=0,
                                   value=90,
                                   command=self.set_cntx_af_len)
        cntxafmenu.add_radiobutton(label='110 characters',
                                   variable=self._cntx_af_len,
                                   underline=0,
                                   value=110,
                                   command=self.set_cntx_af_len)
        cntxafmenu.invoke(1)
        cntxmenu.add_cascade(label='After', underline=0, menu=cntxafmenu)

        editmenu.add_cascade(label='Context', underline=0, menu=cntxmenu)

        menubar.add_cascade(label='Edit', underline=0, menu=editmenu)

        self.top.config(menu=menubar)

    def set_result_size(self, **kwargs):
        self.model.result_count = self._result_size.get()

    def set_cntx_af_len(self, **kwargs):
        self._char_after = self._cntx_af_len.get()

    def set_cntx_bf_len(self, **kwargs):
        self._char_before = self._cntx_bf_len.get()

    def _init_corpus_select(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.var = StringVar(innerframe)
        self.var.set(self.model.DEFAULT_CORPUS)
        Label(innerframe,
              justify=LEFT,
              text=' Corpus: ',
              background=self._BACKGROUND_COLOUR,
              padx=2,
              pady=1,
              border=0).pack(side='left')

        other_corpora = list(self.model.CORPORA.keys()).remove(
            self.model.DEFAULT_CORPUS)
        om = OptionMenu(innerframe,
                        self.var,
                        self.model.DEFAULT_CORPUS,
                        command=self.corpus_selected,
                        *self.model.non_default_corpora())
        om['borderwidth'] = 0
        om['highlightthickness'] = 1
        om.pack(side='left')
        innerframe.pack(side='top', fill='x', anchor='n')

    def _init_status(self, parent):
        self.status = Label(parent,
                            justify=LEFT,
                            relief=SUNKEN,
                            background=self._BACKGROUND_COLOUR,
                            border=0,
                            padx=1,
                            pady=0)
        self.status.pack(side='top', anchor='sw')

    def _init_query_box(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        another = Frame(innerframe, background=self._BACKGROUND_COLOUR)
        self.query_box = Entry(another, width=60)
        self.query_box.pack(side='left', fill='x', pady=25, anchor='center')
        self.search_button = Button(another,
                                    text='Search',
                                    command=self.search,
                                    borderwidth=1,
                                    highlightthickness=1)
        self.search_button.pack(side='left',
                                fill='x',
                                pady=25,
                                anchor='center')
        self.query_box.bind('<KeyPress-Return>',
                            self.search_enter_keypress_handler)
        another.pack()
        innerframe.pack(side='top', fill='x', anchor='n')

    def search_enter_keypress_handler(self, *event):
        self.search()

    def _init_results_box(self, parent):
        innerframe = Frame(parent)
        i1 = Frame(innerframe)
        i2 = Frame(innerframe)
        vscrollbar = Scrollbar(i1, borderwidth=1)
        hscrollbar = Scrollbar(i2, borderwidth=1, orient='horiz')
        self.results_box = Text(i1,
                                font=tkinter.font.Font(family='courier',
                                                       size='16'),
                                state='disabled',
                                borderwidth=1,
                                yscrollcommand=vscrollbar.set,
                                xscrollcommand=hscrollbar.set,
                                wrap='none',
                                width='40',
                                height='20',
                                exportselection=1)
        self.results_box.pack(side='left', fill='both', expand=True)
        self.results_box.tag_config(self._HIGHLIGHT_WORD_TAG,
                                    foreground=self._HIGHLIGHT_WORD_COLOUR)
        self.results_box.tag_config(self._HIGHLIGHT_LABEL_TAG,
                                    foreground=self._HIGHLIGHT_LABEL_COLOUR)
        vscrollbar.pack(side='left', fill='y', anchor='e')
        vscrollbar.config(command=self.results_box.yview)
        hscrollbar.pack(side='left', fill='x', expand=True, anchor='w')
        hscrollbar.config(command=self.results_box.xview)
        #there is no other way of avoiding the overlap of scrollbars while using pack layout manager!!!
        Label(i2, text='   ',
              background=self._BACKGROUND_COLOUR).pack(side='left', anchor='e')
        i1.pack(side='top', fill='both', expand=True, anchor='n')
        i2.pack(side='bottom', fill='x', anchor='s')
        innerframe.pack(side='top', fill='both', expand=True)

    def _init_paging(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.prev = prev = Button(innerframe,
                                  text='Previous',
                                  command=self.previous,
                                  width='10',
                                  borderwidth=1,
                                  highlightthickness=1,
                                  state='disabled')
        prev.pack(side='left', anchor='center')
        self.next = next = Button(innerframe,
                                  text='Next',
                                  command=self.__next__,
                                  width='10',
                                  borderwidth=1,
                                  highlightthickness=1,
                                  state='disabled')
        next.pack(side='right', anchor='center')
        innerframe.pack(side='top', fill='y')
        self.current_page = 0

    def previous(self):
        self.clear_results_box()
        self.freeze_editable()
        self.model.prev(self.current_page - 1)

    def __next__(self):
        self.clear_results_box()
        self.freeze_editable()
        self.model.next(self.current_page + 1)

    def about(self, *e):
        ABOUT = ("NLTK Concordance Search Demo\n")
        TITLE = 'About: NLTK Concordance Search Demo'
        try:
            from tkinter.messagebox import Message
            Message(message=ABOUT, title=TITLE, parent=self.main_frame).show()
        except:
            ShowText(self.top, TITLE, ABOUT)

    def _bind_event_handlers(self):
        self.top.bind(CORPUS_LOADED_EVENT, self.handle_corpus_loaded)
        self.top.bind(SEARCH_TERMINATED_EVENT, self.handle_search_terminated)
        self.top.bind(SEARCH_ERROR_EVENT, self.handle_search_error)
        self.top.bind(ERROR_LOADING_CORPUS_EVENT,
                      self.handle_error_loading_corpus)

    def _poll(self):
        try:
            event = self.queue.get(block=False)
        except q.Empty:
            pass
        else:
            if event == CORPUS_LOADED_EVENT:
                self.handle_corpus_loaded(event)
            elif event == SEARCH_TERMINATED_EVENT:
                self.handle_search_terminated(event)
            elif event == SEARCH_ERROR_EVENT:
                self.handle_search_error(event)
            elif event == ERROR_LOADING_CORPUS_EVENT:
                self.handle_error_loading_corpus(event)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def handle_error_loading_corpus(self, event):
        self.status['text'] = 'Error in loading ' + self.var.get()
        self.unfreeze_editable()
        self.clear_all()
        self.freeze_editable()

    def handle_corpus_loaded(self, event):
        self.status['text'] = self.var.get() + ' is loaded'
        self.unfreeze_editable()
        self.clear_all()
        self.query_box.focus_set()

    def handle_search_terminated(self, event):
        #todo: refactor the model such that it is less state sensitive
        results = self.model.get_results()
        self.write_results(results)
        self.status['text'] = ''
        if len(results) == 0:
            self.status['text'] = 'No results found for ' + self.model.query
        else:
            self.current_page = self.model.last_requested_page
        self.unfreeze_editable()
        self.results_box.xview_moveto(self._FRACTION_LEFT_TEXT)

    def handle_search_error(self, event):
        self.status['text'] = 'Error in query ' + self.model.query
        self.unfreeze_editable()

    def corpus_selected(self, *args):
        new_selection = self.var.get()
        self.load_corpus(new_selection)

    def load_corpus(self, selection):
        if self.model.selected_corpus != selection:
            self.status['text'] = 'Loading ' + selection + '...'
            self.freeze_editable()
            self.model.load_corpus(selection)

    def search(self):
        self.current_page = 0
        self.clear_results_box()
        self.model.reset_results()
        query = self.query_box.get()
        if (len(query.strip()) == 0): return
        self.status['text'] = 'Searching for ' + query
        self.freeze_editable()
        self.model.search(
            query,
            self.current_page + 1,
        )

    def write_results(self, results):
        self.results_box['state'] = 'normal'
        row = 1
        for each in results:
            sent, pos1, pos2 = each[0].strip(), each[1], each[2]
            if len(sent) != 0:
                if (pos1 < self._char_before):
                    sent, pos1, pos2 = self.pad(sent, pos1, pos2)
                sentence = sent[pos1 - self._char_before:pos1 +
                                self._char_after]
                if not row == len(results):
                    sentence += '\n'
                self.results_box.insert(str(row) + '.0', sentence)
                word_markers, label_markers = self.words_and_labels(
                    sent, pos1, pos2)
                for marker in word_markers:
                    self.results_box.tag_add(self._HIGHLIGHT_WORD_TAG,
                                             str(row) + '.' + str(marker[0]),
                                             str(row) + '.' + str(marker[1]))
                for marker in label_markers:
                    self.results_box.tag_add(self._HIGHLIGHT_LABEL_TAG,
                                             str(row) + '.' + str(marker[0]),
                                             str(row) + '.' + str(marker[1]))
                row += 1
        self.results_box['state'] = 'disabled'

    def words_and_labels(self, sentence, pos1, pos2):
        search_exp = sentence[pos1:pos2]
        words, labels = [], []
        labeled_words = search_exp.split(' ')
        index = 0
        for each in labeled_words:
            if each == '':
                index += 1
            else:
                word, label = each.split('/')
                words.append((self._char_before + index,
                              self._char_before + index + len(word)))
                index += len(word) + 1
                labels.append((self._char_before + index,
                               self._char_before + index + len(label)))
                index += len(label)
            index += 1
        return words, labels

    def pad(self, sent, hstart, hend):
        if hstart >= self._char_before:
            return sent, hstart, hend
        d = self._char_before - hstart
        sent = ''.join([' '] * d) + sent
        return sent, hstart + d, hend + d

    def destroy(self, *e):
        if self.top is None: return
        self.top.after_cancel(self.after)
        self.top.destroy()
        self.top = None

    def clear_all(self):
        self.query_box.delete(0, END)
        self.model.reset_query()
        self.clear_results_box()

    def clear_results_box(self):
        self.results_box['state'] = 'normal'
        self.results_box.delete("1.0", END)
        self.results_box['state'] = 'disabled'

    def freeze_editable(self):
        self.query_box['state'] = 'disabled'
        self.search_button['state'] = 'disabled'
        self.prev['state'] = 'disabled'
        self.next['state'] = 'disabled'

    def unfreeze_editable(self):
        self.query_box['state'] = 'normal'
        self.search_button['state'] = 'normal'
        self.set_paging_button_states()

    def set_paging_button_states(self):
        if self.current_page == 0 or self.current_page == 1:
            self.prev['state'] = 'disabled'
        else:
            self.prev['state'] = 'normal'
        if self.model.has_more_pages(self.current_page):
            self.next['state'] = 'normal'
        else:
            self.next['state'] = 'disabled'

    def fire_event(self, event):
        #Firing an event so that rendering of widgets happen in the mainloop thread
        self.top.event_generate(event, when='tail')

    def mainloop(self, *args, **kwargs):
        if in_idle(): return
        self.top.mainloop(*args, **kwargs)
Example #22
0
class PyCube:
    
    def __init__(self):
        self.root = Tk()
        self.root.title("PyCube")
        
        self.session = Session()
        
        # init UI
        self.initMenu()
        self.leftframe = Frame(self.root)
        self.leftframe.pack(side=LEFT, fill=BOTH, expand=1)
        
        self.rightframe = Frame(self.root)
        self.rightframe.pack(side=RIGHT, fill=BOTH, expand=1)
        
        self.cubesize = 3
        scrambler.parse(self.cubesize, 30, False, False)
        scrambler.scramble()
        self.scramble = Label(self.leftframe, text=scrambler.scramblestring(0))
        self.scramble.pack()

        self.time_label = Label(self.leftframe, text="0.000")
        self.time_label.pack()
        
        self.plus2_button = Button(self.leftframe, text="+2", command=self.plus2)
        self.plus2_button.pack()
        
        self.dnf_button = Button(self.leftframe, text="DNF", command=self.dnf)
        self.dnf_button.pack()
        
        self.delete_button = Button(self.leftframe, text="Delete", command=self.delete)
        self.delete_button.pack()
        
        self.scramble_img = Label(self.leftframe)
        self.scramble_img.pack()
        self.update_image()
        
        self.grid = Treeview(self.rightframe)
        self.grid["columns"] = ("times", "avg5", "avg12", "mean", "sd")
        self.grid.heading("#0", text='Time', anchor='w')
        self.grid.column("#0", stretch=NO, width=0, anchor="w")
        self.grid.heading("times", text="Times")
        self.grid.column('times', anchor='center', width=70)
        self.grid.heading("avg5", text="Avg. of 5")
        self.grid.column('avg5', anchor='center', width=70)
        self.grid.heading("avg12", text="Avg. of 12")
        self.grid.column('avg12', anchor='center', width=70)
        self.grid.heading("mean", text="Session mean")
        self.grid.column('mean', anchor='center', width=80)
        self.grid.heading("sd", text="SD")
        self.grid.column('sd', anchor='center', width=70)
        
        self.gridscroll = Scrollbar()
        self.gridscroll.configure(command=self.grid.yview)
        
        self.grid.configure(yscrollcommand=self.gridscroll.set)
        self.grid.pack(side=TOP)
        
        self.root.bind("<KeyRelease-space>", self.start_inspection)
        self._job = None
        self.running = False
        
        self.root.mainloop()
        
    def initMenu(self):
        menubar = Menu(self.root)
        self.root.config(menu=menubar)
        
        fileMenu = Menu(menubar)
        fileMenu.add_command(label="New", command=self.session_new)
        fileMenu.add_separator()
        fileMenu.add_command(label="Import", command=self.session_import)
        fileMenu.add_command(label="Export", command=self.session_export)
        menubar.add_cascade(label="File", menu=fileMenu)
        
    def start_timer(self, event=None):
        if not self.running:
            self.root.after_cancel(self._job)
            self._job = None
            self.t0 = float("%.3f" % time.time())
            self.update_timer()
            self.running = True
            self.root.bind("<KeyPress-space>", self.reset_timer)
    
    def reset_timer(self, event=None):
        if self.running:
            self.root.after_cancel(self._job)
            self._job = None
            self.running = False
            self.root.bind("<KeyRelease-space>", self.rebind)
            
            t = self.time_label.cget("text")
            if ":" in str(t):
                mins, secs = t.split(":")
                t = (mins * 60) + secs
            self.session.addtime(t, 0, scrambler.scramblestring(0))
            
            entry = self.session.data[-1][1:]
            self.grid.insert("", "end", values=(entry))
            
            scrambler.parse(self.cubesize, 30, False, False)
            scrambler.scramble()
            scramblestr = scrambler.scramblestring(0)
            self.scramble.configure(text=scramblestr)
            self.update_image()
            
    def rebind(self, event=None):
        self.root.bind("<KeyRelease-space>", self.start_inspection)
        
    def update_timer(self):
        now = float("%.3f" % (time.time() - self.t0))
        if now > 60:
            mins = math.floor(now / 60)
            secs = now - (mins * 60)
            now = f"{mins}:{secs}"
        self.time_label.configure(text=now, fg="black")
        self._job = self.root.after(10, self.update_timer)
    
    def start_inspection(self, event=None):
        self.inspect_time = 16
        self.root.bind("<KeyRelease-space>", self.start_timer)
        self.update_inspection()
    
    def update_inspection(self):
        if self.inspect_time == 0:
            self.time_label.configure(text="DNF", fg="red")
            
            # Really ugly was to add a straight DNF, should fix later
            # NOTE: Known bug when first time is DNF. MUST FIX
            self.session.addtime(0, 2, scrambler.scramblestring(0))
            entry = self.session.data[-1][1:]
            self.grid.insert("", "end", values=(entry))
            self.dnf()
        else:
            self.inspect_time -= 1
            self.time_label.configure(text=self.inspect_time, fg="red")
            self._job = self.root.after(1000, self.update_inspection)
        
    def update_image(self):
        img = ImageTk.PhotoImage(genimage(scrambler.imagestring(0), self.cubesize))
        self.scramble_img.configure(image=img)
        self.scramble_img.image = img
    
    def delete(self, event=None):
        if len(self.session.data) > 0:
            last = self.session.getlastitemid()
            self.grid.delete(last)
            self.session.removetime(last) 
    
    def plus2(self, event=None):
        if len(self.session.data) > 0:
            last = self.session.getlastitemid()
            index = len(self.session.data) - 1
            entry = self.session.data[index]
            
            # Check if time isn't already +2 or DNF9
            if entry[6] != 0:
                return
            
            entry[1] = float("%.3f" % (entry[1] + 2))
            entry[6] = 1
            entry = self.session.calcstats()
            vals = entry[1:] + [scrambler.scramblestring(0)]
            vals[0] = str(vals[0]) + "(+2)"
            self.grid.item(last, values=(vals))
            
    def dnf(self, event=None):
        if len(self.session.data) > 0:
            last = self.session.getlastitemid()
            index = len(self.session.data) - 1
            entry = self.session.data[index]
            
            entry[1] = "DNF"
            entry[6] = 2
            
            entry = self.session.calcstats()
            vals = entry[1:]
            self.grid.item(last, values=(vals))
            
    def session_new(self):
        self.session.clear()
        self.grid.delete(*self.grid.get_children())
    
    def session_import(self):
        f = filedialog.askopenfilename(initialdir="../data/",
                                       title="Import session",
                                       filetypes=(("Text Documents", "*.txt"), ("All Files", "*.*")))
        if f == '':
            return
        with open(f) as file:
            self.session_new()
            self.session = Session(file.read())
            
            for entry in self.session.data:
                self.grid.insert("", "end", values=(entry[1:]))
    
    def session_export(self):
        if not os.path.isdir("../data/"):
            os.makedirs("../data/")
            
        name = str(datetime.now())[:-7].replace('-', '').replace(':', '').replace(' ', '')
        f = filedialog.asksaveasfilename(initialfile=name,
                                         initialdir="../data/",
                                         defaultextension="*.txt",
                                         title="Export session",
                                         filetypes=(("Text Documents","*.txt"), ("All Files","*.*")))
        if f == '':
            return
        with open(f, 'w') as file:
            file.write(str(self.session))
Example #23
0
class ConcordanceSearchView(object):
    _BACKGROUND_COLOUR = "#FFF"  # white

    # Colour of highlighted results
    _HIGHLIGHT_WORD_COLOUR = "#F00"  # red
    _HIGHLIGHT_WORD_TAG = "HL_WRD_TAG"

    _HIGHLIGHT_LABEL_COLOUR = "#C0C0C0"  # dark grey
    _HIGHLIGHT_LABEL_TAG = "HL_LBL_TAG"

    # Percentage of text left of the scrollbar position
    _FRACTION_LEFT_TEXT = 0.30

    def __init__(self):
        self.queue = q.Queue()
        self.model = ConcordanceSearchModel(self.queue)
        self.top = Tk()
        self._init_top(self.top)
        self._init_menubar()
        self._init_widgets(self.top)
        self.load_corpus(self.model.DEFAULT_CORPUS)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def _init_top(self, top):
        top.geometry("950x680+50+50")
        top.title("NLTK Concordance Search")
        top.bind("<Control-q>", self.destroy)
        top.protocol("WM_DELETE_WINDOW", self.destroy)
        top.minsize(950, 680)

    def _init_widgets(self, parent):
        self.main_frame = Frame(
            parent,
            dict(background=self._BACKGROUND_COLOUR, padx=1, pady=1, border=1))
        self._init_corpus_select(self.main_frame)
        self._init_query_box(self.main_frame)
        self._init_results_box(self.main_frame)
        self._init_paging(self.main_frame)
        self._init_status(self.main_frame)
        self.main_frame.pack(fill="both", expand=True)

    def _init_menubar(self):
        self._result_size = IntVar(self.top)
        self._cntx_bf_len = IntVar(self.top)
        self._cntx_af_len = IntVar(self.top)
        menubar = Menu(self.top)

        filemenu = Menu(menubar, tearoff=0, borderwidth=0)
        filemenu.add_command(label="Exit",
                             underline=1,
                             command=self.destroy,
                             accelerator="Ctrl-q")
        menubar.add_cascade(label="File", underline=0, menu=filemenu)

        editmenu = Menu(menubar, tearoff=0)
        rescntmenu = Menu(editmenu, tearoff=0)
        rescntmenu.add_radiobutton(
            label="20",
            variable=self._result_size,
            underline=0,
            value=20,
            command=self.set_result_size,
        )
        rescntmenu.add_radiobutton(
            label="50",
            variable=self._result_size,
            underline=0,
            value=50,
            command=self.set_result_size,
        )
        rescntmenu.add_radiobutton(
            label="100",
            variable=self._result_size,
            underline=0,
            value=100,
            command=self.set_result_size,
        )
        rescntmenu.invoke(1)
        editmenu.add_cascade(label="Result Count",
                             underline=0,
                             menu=rescntmenu)

        cntxmenu = Menu(editmenu, tearoff=0)
        cntxbfmenu = Menu(cntxmenu, tearoff=0)
        cntxbfmenu.add_radiobutton(
            label="60 characters",
            variable=self._cntx_bf_len,
            underline=0,
            value=60,
            command=self.set_cntx_bf_len,
        )
        cntxbfmenu.add_radiobutton(
            label="80 characters",
            variable=self._cntx_bf_len,
            underline=0,
            value=80,
            command=self.set_cntx_bf_len,
        )
        cntxbfmenu.add_radiobutton(
            label="100 characters",
            variable=self._cntx_bf_len,
            underline=0,
            value=100,
            command=self.set_cntx_bf_len,
        )
        cntxbfmenu.invoke(1)
        cntxmenu.add_cascade(label="Before", underline=0, menu=cntxbfmenu)

        cntxafmenu = Menu(cntxmenu, tearoff=0)
        cntxafmenu.add_radiobutton(
            label="70 characters",
            variable=self._cntx_af_len,
            underline=0,
            value=70,
            command=self.set_cntx_af_len,
        )
        cntxafmenu.add_radiobutton(
            label="90 characters",
            variable=self._cntx_af_len,
            underline=0,
            value=90,
            command=self.set_cntx_af_len,
        )
        cntxafmenu.add_radiobutton(
            label="110 characters",
            variable=self._cntx_af_len,
            underline=0,
            value=110,
            command=self.set_cntx_af_len,
        )
        cntxafmenu.invoke(1)
        cntxmenu.add_cascade(label="After", underline=0, menu=cntxafmenu)

        editmenu.add_cascade(label="Context", underline=0, menu=cntxmenu)

        menubar.add_cascade(label="Edit", underline=0, menu=editmenu)

        self.top.config(menu=menubar)

    def set_result_size(self, **kwargs):
        self.model.result_count = self._result_size.get()

    def set_cntx_af_len(self, **kwargs):
        self._char_after = self._cntx_af_len.get()

    def set_cntx_bf_len(self, **kwargs):
        self._char_before = self._cntx_bf_len.get()

    def _init_corpus_select(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.var = StringVar(innerframe)
        self.var.set(self.model.DEFAULT_CORPUS)
        Label(
            innerframe,
            justify=LEFT,
            text=" Corpus: ",
            background=self._BACKGROUND_COLOUR,
            padx=2,
            pady=1,
            border=0,
        ).pack(side="left")

        other_corpora = list(self.model.CORPORA.keys()).remove(
            self.model.DEFAULT_CORPUS)
        om = OptionMenu(innerframe,
                        self.var,
                        self.model.DEFAULT_CORPUS,
                        command=self.corpus_selected,
                        *self.model.non_default_corpora())
        om["borderwidth"] = 0
        om["highlightthickness"] = 1
        om.pack(side="left")
        innerframe.pack(side="top", fill="x", anchor="n")

    def _init_status(self, parent):
        self.status = Label(
            parent,
            justify=LEFT,
            relief=SUNKEN,
            background=self._BACKGROUND_COLOUR,
            border=0,
            padx=1,
            pady=0,
        )
        self.status.pack(side="top", anchor="sw")

    def _init_query_box(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        another = Frame(innerframe, background=self._BACKGROUND_COLOUR)
        self.query_box = Entry(another, width=60)
        self.query_box.pack(side="left", fill="x", pady=25, anchor="center")
        self.search_button = Button(
            another,
            text="Search",
            command=self.search,
            borderwidth=1,
            highlightthickness=1,
        )
        self.search_button.pack(side="left",
                                fill="x",
                                pady=25,
                                anchor="center")
        self.query_box.bind("<KeyPress-Return>",
                            self.search_enter_keypress_handler)
        another.pack()
        innerframe.pack(side="top", fill="x", anchor="n")

    def search_enter_keypress_handler(self, *event):
        self.search()

    def _init_results_box(self, parent):
        innerframe = Frame(parent)
        i1 = Frame(innerframe)
        i2 = Frame(innerframe)
        vscrollbar = Scrollbar(i1, borderwidth=1)
        hscrollbar = Scrollbar(i2, borderwidth=1, orient="horiz")
        self.results_box = Text(
            i1,
            font=Font(family="courier", size="16"),
            state="disabled",
            borderwidth=1,
            yscrollcommand=vscrollbar.set,
            xscrollcommand=hscrollbar.set,
            wrap="none",
            width="40",
            height="20",
            exportselection=1,
        )
        self.results_box.pack(side="left", fill="both", expand=True)
        self.results_box.tag_config(self._HIGHLIGHT_WORD_TAG,
                                    foreground=self._HIGHLIGHT_WORD_COLOUR)
        self.results_box.tag_config(self._HIGHLIGHT_LABEL_TAG,
                                    foreground=self._HIGHLIGHT_LABEL_COLOUR)
        vscrollbar.pack(side="left", fill="y", anchor="e")
        vscrollbar.config(command=self.results_box.yview)
        hscrollbar.pack(side="left", fill="x", expand=True, anchor="w")
        hscrollbar.config(command=self.results_box.xview)
        # there is no other way of avoiding the overlap of scrollbars while using pack layout manager!!!
        Label(i2, text="   ",
              background=self._BACKGROUND_COLOUR).pack(side="left", anchor="e")
        i1.pack(side="top", fill="both", expand=True, anchor="n")
        i2.pack(side="bottom", fill="x", anchor="s")
        innerframe.pack(side="top", fill="both", expand=True)

    def _init_paging(self, parent):
        innerframe = Frame(parent, background=self._BACKGROUND_COLOUR)
        self.prev = prev = Button(
            innerframe,
            text="Previous",
            command=self.previous,
            width="10",
            borderwidth=1,
            highlightthickness=1,
            state="disabled",
        )
        prev.pack(side="left", anchor="center")
        self.next = next = Button(
            innerframe,
            text="Next",
            command=self.__next__,
            width="10",
            borderwidth=1,
            highlightthickness=1,
            state="disabled",
        )
        next.pack(side="right", anchor="center")
        innerframe.pack(side="top", fill="y")
        self.current_page = 0

    def previous(self):
        self.clear_results_box()
        self.freeze_editable()
        self.model.prev(self.current_page - 1)

    def __next__(self):
        self.clear_results_box()
        self.freeze_editable()
        self.model.next(self.current_page + 1)

    def about(self, *e):
        ABOUT = "NLTK Concordance Search Demo\n"
        TITLE = "About: NLTK Concordance Search Demo"
        try:
            from tkinter.messagebox import Message

            Message(message=ABOUT, title=TITLE, parent=self.main_frame).show()
        except:
            ShowText(self.top, TITLE, ABOUT)

    def _bind_event_handlers(self):
        self.top.bind(CORPUS_LOADED_EVENT, self.handle_corpus_loaded)
        self.top.bind(SEARCH_TERMINATED_EVENT, self.handle_search_terminated)
        self.top.bind(SEARCH_ERROR_EVENT, self.handle_search_error)
        self.top.bind(ERROR_LOADING_CORPUS_EVENT,
                      self.handle_error_loading_corpus)

    def _poll(self):
        try:
            event = self.queue.get(block=False)
        except q.Empty:
            pass
        else:
            if event == CORPUS_LOADED_EVENT:
                self.handle_corpus_loaded(event)
            elif event == SEARCH_TERMINATED_EVENT:
                self.handle_search_terminated(event)
            elif event == SEARCH_ERROR_EVENT:
                self.handle_search_error(event)
            elif event == ERROR_LOADING_CORPUS_EVENT:
                self.handle_error_loading_corpus(event)
        self.after = self.top.after(POLL_INTERVAL, self._poll)

    def handle_error_loading_corpus(self, event):
        self.status["text"] = "Error in loading " + self.var.get()
        self.unfreeze_editable()
        self.clear_all()
        self.freeze_editable()

    def handle_corpus_loaded(self, event):
        self.status["text"] = self.var.get() + " is loaded"
        self.unfreeze_editable()
        self.clear_all()
        self.query_box.focus_set()

    def handle_search_terminated(self, event):
        # todo: refactor the model such that it is less state sensitive
        results = self.model.get_results()
        self.write_results(results)
        self.status["text"] = ""
        if len(results) == 0:
            self.status["text"] = "No results found for " + self.model.query
        else:
            self.current_page = self.model.last_requested_page
        self.unfreeze_editable()
        self.results_box.xview_moveto(self._FRACTION_LEFT_TEXT)

    def handle_search_error(self, event):
        self.status["text"] = "Error in query " + self.model.query
        self.unfreeze_editable()

    def corpus_selected(self, *args):
        new_selection = self.var.get()
        self.load_corpus(new_selection)

    def load_corpus(self, selection):
        if self.model.selected_corpus != selection:
            self.status["text"] = "Loading " + selection + "..."
            self.freeze_editable()
            self.model.load_corpus(selection)

    def search(self):
        self.current_page = 0
        self.clear_results_box()
        self.model.reset_results()
        query = self.query_box.get()
        if len(query.strip()) == 0:
            return
        self.status["text"] = "Searching for " + query
        self.freeze_editable()
        self.model.search(query, self.current_page + 1)

    def write_results(self, results):
        self.results_box["state"] = "normal"
        row = 1
        for each in results:
            sent, pos1, pos2 = each[0].strip(), each[1], each[2]
            if len(sent) != 0:
                if pos1 < self._char_before:
                    sent, pos1, pos2 = self.pad(sent, pos1, pos2)
                sentence = sent[pos1 - self._char_before:pos1 +
                                self._char_after]
                if not row == len(results):
                    sentence += "\n"
                self.results_box.insert(str(row) + ".0", sentence)
                word_markers, label_markers = self.words_and_labels(
                    sent, pos1, pos2)
                for marker in word_markers:
                    self.results_box.tag_add(
                        self._HIGHLIGHT_WORD_TAG,
                        str(row) + "." + str(marker[0]),
                        str(row) + "." + str(marker[1]),
                    )
                for marker in label_markers:
                    self.results_box.tag_add(
                        self._HIGHLIGHT_LABEL_TAG,
                        str(row) + "." + str(marker[0]),
                        str(row) + "." + str(marker[1]),
                    )
                row += 1
        self.results_box["state"] = "disabled"

    def words_and_labels(self, sentence, pos1, pos2):
        search_exp = sentence[pos1:pos2]
        words, labels = [], []
        labeled_words = search_exp.split(" ")
        index = 0
        for each in labeled_words:
            if each == "":
                index += 1
            else:
                word, label = each.split("/")
                words.append((self._char_before + index,
                              self._char_before + index + len(word)))
                index += len(word) + 1
                labels.append((self._char_before + index,
                               self._char_before + index + len(label)))
                index += len(label)
            index += 1
        return words, labels

    def pad(self, sent, hstart, hend):
        if hstart >= self._char_before:
            return sent, hstart, hend
        d = self._char_before - hstart
        sent = "".join([" "] * d) + sent
        return sent, hstart + d, hend + d

    def destroy(self, *e):
        if self.top is None:
            return
        self.top.after_cancel(self.after)
        self.top.destroy()
        self.top = None

    def clear_all(self):
        self.query_box.delete(0, END)
        self.model.reset_query()
        self.clear_results_box()

    def clear_results_box(self):
        self.results_box["state"] = "normal"
        self.results_box.delete("1.0", END)
        self.results_box["state"] = "disabled"

    def freeze_editable(self):
        self.query_box["state"] = "disabled"
        self.search_button["state"] = "disabled"
        self.prev["state"] = "disabled"
        self.next["state"] = "disabled"

    def unfreeze_editable(self):
        self.query_box["state"] = "normal"
        self.search_button["state"] = "normal"
        self.set_paging_button_states()

    def set_paging_button_states(self):
        if self.current_page == 0 or self.current_page == 1:
            self.prev["state"] = "disabled"
        else:
            self.prev["state"] = "normal"
        if self.model.has_more_pages(self.current_page):
            self.next["state"] = "normal"
        else:
            self.next["state"] = "disabled"

    def fire_event(self, event):
        # Firing an event so that rendering of widgets happen in the mainloop thread
        self.top.event_generate(event, when="tail")

    def mainloop(self, *args, **kwargs):
        if in_idle():
            return
        self.top.mainloop(*args, **kwargs)
Example #24
0
class Game:
    def __init__(self, data, best_score, q_table, score, missed, ai_best_score,
                 ai_trained_time):
        self.window = Tk()
        self.frame = Frame(self.window)
        self.canvas = Canvas(self.frame)
        self.state = "gameRunning"
        self.run_type = data
        self.ai_q_table = q_table
        self.ai_score = score
        self.ai_missed = missed
        self.ai_best = ai_best_score
        self.play_speed = 10
        self.train_speed = 1000000000
        self.ai_trained_time = ai_trained_time
        self.ai_timer = time()

        # AI Observer
        self.ai_observer_key = ""
        # AI Observer

        print("")
        print("------------------------------")
        if self.run_type == "playTheGame":
            print("Game Created for player to play.")
        elif self.run_type == "trainTheAI":
            print("Game Created for AI to train.")
        print("---------------")

        self.X, self.Y = (10, 10)
        ''' X, Y --> Count of blocks in window. '''
        self.BLOCK_SIZE = 75
        ''' BLOCK_SIZE --> Size of one block. '''

        self.BACKGROUND_COLOR = '#303030'
        self.SNAKE_COLOR = '#0f0'
        self.SNAKE_HEAD_COLOR = '#003300'
        self.FOOD_COLOR = '#f00'
        self.INITIAL_SPEED = 10
        self.BEST_SCORE = best_score
        self.PAUSED = 0

        self.KEY_LEFT = 'Left'
        self.KEY_RIGHT = 'Right'
        self.KEY_UP = 'Up'
        self.KEY_DOWN = 'Down'
        self.KEY_QUIT = 'q'
        self.KEY_PAUSE = 'p'
        self.KEY_SPEED = 's'

        self.VALID_DIRECTIONS = {
            self.KEY_LEFT: {self.KEY_LEFT, self.KEY_UP, self.KEY_DOWN},
            self.KEY_RIGHT: {self.KEY_RIGHT, self.KEY_UP, self.KEY_DOWN},
            self.KEY_UP: {self.KEY_UP, self.KEY_LEFT, self.KEY_RIGHT},
            self.KEY_DOWN: {self.KEY_DOWN, self.KEY_LEFT, self.KEY_RIGHT}
        }

        self.MOVEMENTS = {
            self.KEY_LEFT: lambda x, y: (x - 1, y),
            self.KEY_RIGHT: lambda x, y: (x + 1, y),
            self.KEY_UP: lambda x, y: (x, y - 1),
            self.KEY_DOWN: lambda x, y: (x, y + 1)
        }

        self.INITIAL_SPEED = self.play_speed

        self.game = self.create_game()
        self.snake_ai = None
        self.avg_score = 0
        self.ai_current_score = 0
        self.ai_gen = 1
        self.reward = 0
        self.tickID = None
        self.main()

    def on_closing(self):
        if self.ai_current_score > 0:
            self.snake_ai.score -= self.ai_current_score
        self.window.after_cancel(self.tickID)
        self.window.destroy()
        self.state = "gameClosed"

        self.snake_ai.save_informations()
        del self.snake_ai

    def __del__(self):
        if self.run_type == "playTheGame":
            print("---------------")
        print("Game Closed.")
        print("------------------------------")
        print("")

    def save_informations(self):
        pass

    def setup_game(self):
        self.window.focus_force()
        window_width, window_height = (self.X * self.BLOCK_SIZE,
                                       self.Y * self.BLOCK_SIZE)
        ''' window_width, window_height --> Width and height of window. '''
        screen_width, screen_height = (self.window.winfo_screenwidth(),
                                       self.window.winfo_screenheight())
        ''' screen_width, screen_height --> Width and height of screen. '''
        x_coordinate, y_coordinate = (int((screen_width / 2) -
                                          (window_width / 2)),
                                      int((screen_height / 2) -
                                          (window_height / 2)))
        ''' x_coordinate, y_coordinate --> The starting points of window. '''

        self.window.geometry("{}x{}+{}+{}".format(window_width, window_height,
                                                  x_coordinate, y_coordinate))
        self.window.resizable(False, False)

        self.frame.master.title(
            "Snake Game   |   SCORE : 0   |   Best Score : 0    |   Best AI Score : 0 "
        )
        self.frame.pack(fill=BOTH, expand=1)
        self.canvas.pack(fill=BOTH, expand=1)

    def create_game(self):
        snake_randX = randint(0, self.X - 1)
        snake_randY = randint(0, self.Y - 1)

        direction_selector = randint(0, len(self.VALID_DIRECTIONS) - 1)

        food_randX = randint(0, self.X - 1)
        food_randY = randint(0, self.Y - 1)
        while (food_randX, food_randY) == (snake_randX, snake_randY):
            food_randX = randint(0, self.X - 1)
            food_randY = randint(0, self.Y - 1)

        # AI Observer
        self.ai_observer_key = list(
            self.VALID_DIRECTIONS.keys())[direction_selector]
        # AI Observer

        return {
            'snake':
            deque(((snake_randX, snake_randY), (snake_randX, snake_randY))),
            'food': (food_randX, food_randY),
            'direction':
            list(self.VALID_DIRECTIONS.keys())[direction_selector],
            'moves':
            deque(),
            'points':
            0,
            'speed':
            self.INITIAL_SPEED
        }

    def reset(self):
        current_speed = self.game['speed']
        self.game = self.create_game()
        self.game['speed'] = current_speed

    def message_box(self, subject, content):
        root = Tk()
        root.attributes("-topmost", True)
        root.withdraw()
        messagebox.showinfo(subject, content)
        try:
            root.destroy()
        except:
            pass

    def draw_rect(self, x, y, color=None):
        if color is None:
            color = self.SNAKE_COLOR
        x1 = x * self.BLOCK_SIZE
        y1 = y * self.BLOCK_SIZE
        x2 = x1 + self.BLOCK_SIZE
        y2 = y1 + self.BLOCK_SIZE
        return self.canvas.create_rectangle(x1,
                                            y1,
                                            x2,
                                            y2,
                                            outline='',
                                            fill=color)

    def render(self):
        self.canvas.delete('all')
        self.canvas.configure(background=self.BACKGROUND_COLOR)

        for i in range((len(self.game['snake']) - 1), 0, -1):
            if i == (len(self.game['snake']) - 1):
                self.draw_rect(self.game['snake'][i][0],
                               self.game['snake'][i][1], self.SNAKE_HEAD_COLOR)
            else:
                self.draw_rect(self.game['snake'][i][0],
                               self.game['snake'][i][1])

        x, y = self.game['food']
        self.draw_rect(x, y, color=self.FOOD_COLOR)

    def gen_food(self, snake):
        while True:
            food = randint(0, self.X - 1), randint(0, self.Y - 1)
            if food not in snake:
                return food

    def eat(self, snake):
        self.game['food'] = self.gen_food(snake)
        self.game['points'] += 1

        if self.run_type == "trainTheAI":
            self.reward = 1
            self.ai_current_score += 1

            if self.ai_current_score > self.ai_best:
                self.ai_best = self.ai_current_score

        if self.run_type == "playTheGame":
            if self.game['points'] > self.BEST_SCORE:
                self.BEST_SCORE = self.game['points']

            # AI Observer
            self.reward = 1
            # AI Observer

    def move_snake(self, direction):
        snake = set(self.game['snake'])
        u, w = self.game['snake'][-1]
        next_point = self.MOVEMENTS[direction](u, w)

        x, y = next_point

        if x < 0:
            x = x + self.X
        if x >= self.X:
            x = x - self.X
        if y < 0:
            y = y + self.Y
        if y >= self.Y:
            y = y - self.Y

        next_point = x, y

        if next_point == self.game['food'] or self.game['snake'][
                -1] == self.game['food']:
            self.eat(snake)
        else:
            self.game['snake'].popleft()
            self.reward = -0.1

        self.frame.master.title("Snake Game   |   SCORE : " +
                                str(self.game['points']) +
                                "   |   Best Score : " + str(self.BEST_SCORE) +
                                "   |   Best AI Score : " + str(self.ai_best))

        in_snake = 0

        if len(self.game['snake']) > 1:
            for i in range(1, len(self.game['snake'])):
                if next_point == self.game['snake'][i]:
                    in_snake = 1

            if in_snake == 1:
                if self.run_type == "playTheGame":
                    self.message_box('You Lost!', 'Play again...')
                    print("Player Score: " + str(self.game['points']) +
                          "   |   Best Player Score: " + str(self.BEST_SCORE))

                    # AI Observer
                    self.reward = -1
                    # AI Observer

                if self.run_type == "trainTheAI":
                    if self.snake_ai.missed != 0:
                        self.ai_gen = abs(self.snake_ai.missed) + 1
                    if self.ai_current_score != 0 and self.ai_gen != 0:
                        self.avg_score = self.snake_ai.score / self.ai_gen

                    ai_training_time = time() - self.ai_timer
                    self.ai_trained_time = ai_training_time

                    ai_training_time_seconds = int(
                        (ai_training_time % 3600) % 60)
                    ai_training_time_minutes = int((
                        (ai_training_time - ai_training_time_seconds) % 3600) /
                                                   60)
                    ai_training_time_hours = int(
                        (ai_training_time - 60 * ai_training_time_minutes -
                         ai_training_time_seconds) / 3600)

                    hours = str(ai_training_time_hours)
                    if ai_training_time_hours < 10:
                        hours = "0" + str(ai_training_time_hours)

                    minutes = str(ai_training_time_minutes)
                    if ai_training_time_minutes < 10:
                        minutes = "0" + str(ai_training_time_minutes)

                    seconds = str(ai_training_time_seconds)
                    if ai_training_time_seconds < 10:
                        seconds = "0" + str(ai_training_time_seconds)

                    fixed_ai_gen = ""
                    while len(fixed_ai_gen) < 7 - len(str(self.ai_gen)):
                        fixed_ai_gen += "0"
                    fixed_ai_gen += str(self.ai_gen)

                    fixed_ai_current_score = ""
                    while len(fixed_ai_current_score) < 7 - len(
                            str(self.ai_current_score)):
                        fixed_ai_current_score += "0"
                    fixed_ai_current_score += str(self.ai_current_score)

                    fixed_ai_best = ""
                    while len(fixed_ai_best) < 7 - len(str(self.ai_best)):
                        fixed_ai_best += "0"
                    fixed_ai_best += str(self.ai_best)

                    fixed_avg_score = str(self.avg_score)
                    if len(fixed_avg_score) > 7:
                        fixed_avg_score = str(self.avg_score)[:7]
                    else:
                        while len(fixed_avg_score) < 7:
                            fixed_avg_score += "0"

                    print("AI Training Time: " + hours + ":" + minutes + ":" +
                          seconds + "   |   AI Generation: " + fixed_ai_gen +
                          "   |   AI Current Score: " +
                          fixed_ai_current_score + "   |   AI Best Score: " +
                          fixed_ai_best + "   |   AI Average Score: " +
                          fixed_avg_score)
                    self.reward = -1
                    self.ai_current_score = 0
                self.reset()
            else:
                self.game['snake'].append(next_point)
        else:
            self.game['snake'].append(next_point)

    def handle_next_movement(self):
        direction = self.game['moves'].popleft(
        ) if self.game['moves'] else self.game['direction']
        self.game['direction'] = direction
        self.move_snake(direction)

    def on_press(self, event):
        key = event.keysym
        if self.PAUSED == 0 and self.run_type == "playTheGame":
            prev_direction = self.game['moves'][-1] if self.game[
                'moves'] else self.game['direction']
            if key in self.VALID_DIRECTIONS[prev_direction]:
                self.game['moves'].append(key)

            # AI Observer
            self.ai_observer_key = key
            # AI Observer

        if self.run_type == "trainTheAI":
            if key.lower() == self.KEY_SPEED:
                if self.game['speed'] == self.play_speed:
                    self.game['speed'] = self.train_speed
                else:
                    self.game['speed'] = self.play_speed
        if key.lower() == self.KEY_QUIT:
            self.on_closing()
        elif key.lower() == self.KEY_PAUSE:
            if self.PAUSED == 0:
                self.PAUSED = 1
                self.frame.master.title("Snake Game   |   PAUSED.")
            else:
                self.PAUSED = 0
                self.frame.master.title("Snake Game   |   SCORE : " +
                                        str(self.game['points']) +
                                        "   |   Best Score : " +
                                        str(self.BEST_SCORE) +
                                        "   |   Best AI Score : " +
                                        str(self.ai_best))

    def tick(self):
        if self.PAUSED == 0:
            if self.run_type == "playTheGame":
                # AI Observer
                currentState = self.snake_ai.whichStateNow()
                key = self.ai_observer_key
                # AI Observer
                self.handle_next_movement()
                self.render()

                # AI Observer
                instantReward = self.reward
                nextState = self.snake_ai.whichStateNow()
                if key == "Left" or key == "Right" or key == "Up" or key == "Down":
                    self.snake_ai.updateQTable(currentState, nextState,
                                               instantReward, key)
                # AI Observer

            elif self.run_type == "trainTheAI":
                self.Algorithm()

        self.tickID = self.window.after(int(1000 / self.game['speed']),
                                        self.tick)

    def Algorithm(self):
        currentState = self.snake_ai.whichStateNow()
        key = self.snake_ai.bestAction(currentState)
        prev_direction = self.game['moves'][-1] if self.game[
            'moves'] else self.game['direction']
        if key in self.VALID_DIRECTIONS[prev_direction]:
            self.game['moves'].append(key)

        self.handle_next_movement()
        self.render()

        instantReward = self.reward
        nextState = self.snake_ai.whichStateNow()
        self.snake_ai.updateQTable(currentState, nextState, instantReward, key)

        if instantReward > 0:
            self.snake_ai.score += trunc(instantReward)
        if instantReward < 0:
            self.snake_ai.missed += trunc(instantReward)

    def main(self):
        self.setup_game()
        if self.run_type == "trainTheAI":
            self.snake_ai = AI(self)
            self.snake_ai.qTable = self.ai_q_table
            self.snake_ai.score = self.ai_score
            self.snake_ai.missed = self.ai_missed
            self.ai_timer = time() - self.ai_trained_time
        else:
            self.snake_ai = AI(self)
            self.snake_ai.qTable = self.ai_q_table
        self.tick()
        self.window.bind('<Key>', self.on_press)
        self.window.protocol("WM_DELETE_WINDOW", self.on_closing)
        self.window.mainloop()