Ejemplo n.º 1
0
class SettingsOBDView(Frame):        
    settings_list = ["SAE J1850 PWM","SAE J1850 VPW","AUTO, ISO 9141-2","ISO 14230-4 (KWP 5BAUD)","ISO 14230-4 (KWP FAST)","ISO 15765-4 (CAN 11/500)","ISO 15765-4 (CAN 29/500)","ISO 15765-4 (CAN 11/250)","ISO 15765-4 (CAN 29/250)","SAE J1939 (CAN 29/250)"]
    def __init__(self, ui_cont, *args, **kwargs):
        Frame.__init__(self, *args, **kwargs)
        self.initializeGauges()
        self.placeGauges()
        self.ui_cont = ui_cont
        
    def initializeGauges(self):
        self.title_font = font.Font(family="FreeMono", size=15, weight="bold")
        self.list_font = font.Font(family="FreeMono", size=13)
        self.settings_text = Label(self, text="OBD Connection", background="white", font=self.title_font)
        self.listbox = Listbox(self, font=self.list_font, selectmode="single", borderwidth=0, relief="flat", highlightthickness=0)
        self.listbox.bind('<ButtonRelease-1>', self.item_deselected)
        for item in self.settings_list:
            self.listbox.insert(10, item)
            

    def placeGauges(self):
        self.settings_text.pack(fill="x")
        self.listbox.pack(fill="both", expand=1)

    def item_deselected(self, event):
        curr_selct = self.listbox.curselection()
        if len(curr_selct) > 0:
            item_id = self.listbox.curselection()[0]
            item_name = self.settings_list[item_id]
            self.listbox.selection_clear(item_id)
Ejemplo n.º 2
0
class SelectMultiple(TwoCells):
    def __init__(self, parent, text, values, **kwargs):
        super().__init__(parent, **kwargs)
        self.label = Label(self.frame, text=text)
        self.label.grid(column=0, row=0, padx=5, pady=5, sticky=W)
        self.selected_options = StringVar(self.frame)
        self.selected_options.set(values)
        self.listbox = Listbox(self.frame,
                               listvariable=self.selected_options,
                               selectmode=MULTIPLE)
        self.listbox.grid(column=1, row=0, padx=5, pady=5, sticky=E)

    def disable(self):
        self.listbox.configure(state=DISABLED)
        return self

    def enable(self):
        self.listbox.configure(state=NORMAL)
        return self

    def set(self, values):
        if values:
            self.enable()
        else:
            self.disable()
        self.listbox.selection_clear(0, self.listbox.size())
        for value in values:
            for index in range(self.listbox.size()):
                if value == self.listbox.get(index):
                    self.listbox.selection_set(index)
                    self.listbox.event_generate("<<ListboxSelect>>")

    def get(self):
        return [self.listbox.get(i) for i in self.listbox.curselection()]
Ejemplo n.º 3
0
class AlexListBox(Frame):
    def __init__(self,
                 parent,
                 items=[],
                 width=20,
                 height=10,
                 selectioncommand=None):

        super().__init__(parent)

        self.selectioncommand = selectioncommand

        self.listbox = Listbox(self, width=width, height=height)
        self.listbox.grid(row=0, column=0)
        scrollbar_y = AlexScrollbar(self, command=self.listbox.yview)
        scrollbar_y.grid(row=0, column=1, sticky=N + S)
        self.listbox.configure(yscrollcommand=scrollbar_y.set)
        scrollbar_x = AlexScrollbar(self,
                                    command=self.listbox.xview,
                                    orient=HORIZONTAL)
        scrollbar_x.grid(row=1, column=0, sticky=E + W)
        self.listbox.configure(xscrollcommand=scrollbar_x.set)
        if self.selectioncommand is not None:
            self.listbox.bind('<<ListboxSelect>>', self._select_callback)
        self.set_items(items)

    def _select_callback(self, event):

        selection = self.get()
        # ignore unselect
        if selection != None:
            self.selectioncommand(selection)

    def set_items(self, items):

        self.listbox.delete(0, END)
        self.items = []
        for item in items:
            self.items.append(item)
            self.listbox.insert(END, "%s" % item)

    def get_items(self):

        return self.items

    def get(self):

        selections = self.listbox.curselection()
        if len(selections) > 0:
            return self.items[selections[0]]
        else:
            return None

    def set(self, selection):

        self.listbox.selection_clear(0, len(self.items))
        for i in range(0, len(self.items)):
            if self.items[i] == selection:
                self.listbox.selection_set(i)
Ejemplo n.º 4
0
class SettingsView(Frame):
    settings_list = [
        "General", "Wi-Fi", "Appearance", "GPS Chip", "OBD Connection"
    ]

    def __init__(self, ui_cont, *args, **kwargs):
        Frame.__init__(self, *args, **kwargs)
        self.initializeGauges()
        self.placeGauges()
        self.ui_cont = ui_cont
        self.gps_chip_view = SettingsGPSView(ui_cont, self.ui_cont.root)
        self.general_view = SettingsGeneralView(ui_cont, self.ui_cont.root)
        self.wifi_view = SettingsWifiView(ui_cont, self.ui_cont.root)
        self.appearance_view = SettingsAppearanceView(ui_cont,
                                                      self.ui_cont.root)
        self.obd_view = SettingsOBDView(ui_cont, self.ui_cont.root)

    def initializeGauges(self):
        self.title_font = font.Font(family="FreeMono", size=15, weight="bold")
        self.list_font = font.Font(family="FreeMono", size=28)
        self.settings_text = Label(self,
                                   text="Settings",
                                   background="white",
                                   font=self.title_font)
        self.listbox = Listbox(self,
                               font=self.list_font,
                               selectmode="single",
                               borderwidth=0,
                               relief="flat",
                               highlightthickness=0)
        self.listbox.bind('<ButtonRelease-1>', self.item_deselected)
        for item in self.settings_list:
            self.listbox.insert(10, item)

    def placeGauges(self):
        self.settings_text.pack(fill="x")
        self.listbox.pack(fill="both", expand=1)

    def item_deselected(self, event):
        curr_selct = self.listbox.curselection()
        if len(curr_selct) > 0:
            item_id = self.listbox.curselection()[0]
            item_name = self.settings_list[item_id]
            if item_name == "General":
                self.ui_cont.display_view(self.general_view)
            if item_name == "Wi-Fi":
                self.ui_cont.display_view(self.wifi_view)
            if item_name == "Appearance":
                self.ui_cont.display_view(self.appearance_view)
            if item_name == "GPS Chip":
                self.ui_cont.display_view(self.gps_chip_view)
            if item_name == "OBD Connection":
                self.ui_cont.display_view(self.obd_view)
            self.listbox.selection_clear(item_id)
Ejemplo n.º 5
0
class ListBoxChoice(object):
    def __init__(self, master=None, title="Title", message="Message", list=[]):

        self.selected_list = []
        self.master = master
        self.list = list[:]
        self.master.geometry("300x250")  # Width x Height
        self.master.grab_set()
        self.master.bind("<Return>", self._select)
        self.master.bind("<Escape>", self._cancel)
        self.master.title(title)
        Label(self.master, text=message).pack(padx=5, pady=5)

        self.listBox = Listbox(self.master, selectmode=MULTIPLE)
        self.listBox.pack(fill=BOTH)
        self.list.sort()
        for item in self.list:
            self.listBox.insert(END, item)

        buttonFrame = Frame(self.master)
        buttonFrame.pack(side=BOTTOM)

        chooseButton = Button(buttonFrame, text="Select", command=self._select)
        chooseButton.pack()

        cancelButton = Button(buttonFrame, text="Cancel", command=self._cancel)
        cancelButton.pack(side=RIGHT)

    def _select(self, event=None):
        try:
            self.selected_list = [self.listBox.get(i) for i in self.listBox.curselection()]
        except IndexError:
            self.selected_list = None

        self.master.destroy()

    def _cancel(self, event=None):
        self.listBox.selection_clear(0, END)

    def returnValue(self):
        self.master.wait_window()
        return self.selected_list
Ejemplo n.º 6
0
class CompetitorTable(Frame):
    def __init__(self, parent, db, *args, **kwargs):
        Frame.__init__(self, parent, *args, **kwargs)
        self.parent = parent
        self.db = db

        self.labelfont = ['Arial', -0.017, 'bold']
        self.font = ['Arial', -0.017]
        self.labelfont[1] = round(self.font[1] * self.parent.parent.parent.SCREEN_HEIGHT)
        self.font[1] = round(self.font[1] * self.parent.parent.parent.SCREEN_HEIGHT)

        self.config(bg=LLBLUE)

        self.tablebg = 'white'
        self.tableborder = LLBLUE
        self.labelfg = 'white'
        self.labelbg = LBLUE

        self.scrollbar = Scrollbar(self)
        self.idLabel = Label(self, text='ID', fg=self.labelfg, bg=self.labelbg, font=self.labelfont, height=1, anchor='sw', highlightbackground=self.labelfg)
        self.fnameLabel = Label(self, text='First Name', fg=self.labelfg, bg=self.labelbg, font=self.labelfont, height=1, anchor='sw')
        self.lnameLabel = Label(self, text='Last Name', fg=self.labelfg, bg=self.labelbg, font=self.labelfont, height=1, anchor='sw')
        self.levelLabel = Label(self, text='Level', fg=self.labelfg, bg=self.labelbg, font=self.labelfont, height=1, anchor='sw')
        self.sexLabel = Label(self, text='Sex', fg=self.labelfg, bg=self.labelbg, font=self.labelfont, height=1, anchor='sw')
        self.ageLabel = Label(self, text='Age', fg=self.labelfg, bg=self.labelbg, font=self.labelfont, height=1, anchor='sw')
        self.idLB = Listbox(self, yscrollcommand=self.y_scroll, background=self.tablebg, highlightbackground=self.tableborder, borderwidth=0, width=5, font=self.font)
        self.fnameLB = Listbox(self, yscrollcommand=self.y_scroll, background=self.tablebg, highlightbackground=self.tableborder, borderwidth=0, width=25, font=self.font)
        self.lnameLB = Listbox(self, yscrollcommand=self.y_scroll, background=self.tablebg, highlightbackground=self.tableborder, borderwidth=0, width=25, font=self.font)
        self.levelLB = Listbox(self, yscrollcommand=self.y_scroll, background=self.tablebg, highlightbackground=self.tableborder, borderwidth=0, width=12, font=self.font)
        self.sexLB = Listbox(self, yscrollcommand=self.y_scroll, background=self.tablebg, highlightbackground=self.tableborder, borderwidth=0, width=2, font=self.font)
        self.ageLB = Listbox(self, yscrollcommand=self.y_scroll, background=self.tablebg, highlightbackground=self.tableborder, borderwidth=0, width=3, font=self.font)
        #self.registerButton = Button(self, bg=BLUE, fg='white', text="REGISTER\n\nNEW", font=self.font, width=5, wraplength=1,
        #                             borderwidth=1, command=self.register_new)
        #self.deleteButton = Button(self, bg=BLUE, fg='white', text="DELETE\n\nSELECTED", font=self.font, width=5, wraplength=1,
        #                           borderwidth=1, command=self.delete_competitor)
        #self.editButton = Button(self, bg=BLUE, fg='white', text="EDIT\n\nSELECTED", font=self.font, width=5, wraplength=1,
        #                         borderwidth=1, command=self.edit_competitor)

        self.listboxes = (self.idLB, self.fnameLB, self.lnameLB, self.levelLB, self.sexLB, self.ageLB)
        for lb in self.listboxes:
            lb.bind('<Delete>', self.delete_competitor)
            lb.bind('<Double-Button-1>', self.edit_competitor)

        self.idLB.bind('<FocusOut>', lambda e: self.idLB.selection_clear(0, 'end'))  # these binds ensure that when
        self.fnameLB.bind('<FocusOut>', lambda e: self.fnameLB.selection_clear(0, 'end'))  # leaving the table there
        self.lnameLB.bind('<FocusOut>', lambda e: self.lnameLB.selection_clear(0, 'end'))  # doesn't remain a selection
        self.levelLB.bind('<FocusOut>', lambda e: self.levelLB.selection_clear(0, 'end'))  # despite not having focus
        self.sexLB.bind('<FocusOut>', lambda e: self.sexLB.selection_clear(0, 'end'))
        self.ageLB.bind('<FocusOut>', lambda e: self.ageLB.selection_clear(0, 'end'))

        self.scrollbar.config(command=self.set_scrollables)

        self.idLabel.grid(row=0, column=0, sticky='nsew')
        self.fnameLabel.grid(row=0, column=1, sticky='nsew')
        self.lnameLabel.grid(row=0, column=2, sticky='nsew')
        self.levelLabel.grid(row=0, column=3, sticky='nsew')
        self.sexLabel.grid(row=0, column=4, sticky='nsew')
        self.ageLabel.grid(row=0, column=5, sticky='nsew')
        self.idLB.grid(row=1, column=0, sticky='nsew')
        self.fnameLB.grid(row=1, column=1, sticky='nsew')
        self.lnameLB.grid(row=1, column=2, sticky='nsew')
        self.levelLB.grid(row=1, column=3, sticky='nsew')
        self.sexLB.grid(row=1, column=4, sticky='nsew')
        self.ageLB.grid(row=1, column=5, sticky='nsew')
        #self.editButton.grid(row=0, column=6, sticky='nsew')
        #self.registerButton.grid(row=1, column=6, sticky='nsew')
        #self.deleteButton.grid(row=2, column=6, sticky='nsew')
        self.scrollbar.grid(row=0, column=7, sticky='nsew', rowspan=2)
        self.rowconfigure(0, weight=1)
        self.rowconfigure(1, weight=100)
        self.columnconfigure(0, weight=5)
        self.columnconfigure(1, weight=25)
        self.columnconfigure(2, weight=25)
        self.columnconfigure(3, weight=12)
        self.columnconfigure(4, weight=2)
        self.columnconfigure(5, weight=3)

        self.competitorRegistrationWindow = None

    def register_new(self, *args):
        if not self.competitorRegistrationWindow:
            self.competitorRegistrationWindow = CompetitorRegistrationWindow(self, self.db)
            self.competitorRegistrationWindow.protocol('WM_DELETE_WINDOW', self.close_competitor_registration_window)
        else:
            print('competitor registration window already open')

    def close_competitor_registration_window(self):
        self.competitorRegistrationWindow.destroy()
        self.competitorRegistrationWindow = None

    def get_selected_competitor(self):
        if len(self.idLB.curselection()) > 0:
            row = self.idLB.curselection()
        elif len(self.fnameLB.curselection()) > 0:
            row = self.fnameLB.curselection()
        elif len(self.lnameLB.curselection()) > 0:
            row = self.lnameLB.curselection()
        elif len(self.levelLB.curselection()) > 0:
            row = self.levelLB.curselection()
        elif len(self.sexLB.curselection()) > 0:
            row = self.sexLB.curselection()
        elif len(self.ageLB.curselection()) > 0:
            row = self.ageLB.curselection()  # this block searches for any selection in all the list boxes

        return row

    def delete_competitor(self, *args):
        try:
            competitor_id = self.idLB.get(self.get_selected_competitor())
        except UnboundLocalError:  # occurs when there is no competitor selected
            print('cannot delete a competitor when there is none selected')
            return
        self.db.delete_row(competitor_id)

    def edit_competitor(self, *args):
        try:
            id = self.get_selected_competitor()
        except UnboundLocalError:  # occurs when there is no competitor selected
            print('cannot edit a competitor when there is none selected')
            return

        if id:
            entrytab = self.parent.parent.parent.entryTab

            entrytab.routeAttemptsEntryFrame.reset()
            enable_frame(entrytab.competitorInfoFrame)
            enable_frame(entrytab.routeAttemptsEntryFrame)
            entrytab.competitorInfoFrame.fill_competitor(self.idLB.get(id))  # fills info to entry

    def set_scrollables(self, *args):
        self.idLB.yview(*args)
        self.fnameLB.yview(*args)
        self.lnameLB.yview(*args)
        self.levelLB.yview(*args)
        self.sexLB.yview(*args)
        self.ageLB.yview(*args)
        
    def y_scroll(self, *args):  # keeps all listboxes at same scroll position always
        for lb in self.listboxes:
            lb.yview_moveto(args[0])
        self.scrollbar.set(*args)

    def update_table(self, pattern=None):
        self.clear_table()
        if pattern and not pattern == 'Search competitors...':
            rows = self.db.get_specific(pattern)
        else:
            rows = self.db.get_all()
        for i, row in enumerate(rows):
            self.idLB.insert(i, row[0])
            self.fnameLB.insert(i, row[1])
            self.lnameLB.insert(i, row[2])
            self.levelLB.insert(i, row[3])
            self.sexLB.insert(i, row[4])
            self.ageLB.insert(i, row[5])

    def clear_table(self):
        self.idLB.delete(0, 'end')
        self.fnameLB.delete(0, 'end')
        self.lnameLB.delete(0, 'end')
        self.levelLB.delete(0, 'end')
        self.sexLB.delete(0, 'end')
        self.ageLB.delete(0, 'end')
Ejemplo n.º 7
0
class Widgets:
    def __init__(self, root):
        self.setup = Setup(self)
        json_data = Json()
        self.update = Update(self, self.setup)
        self.db = LocalSqlite3()
        self.tracks = Tracks()

        self.top_menu = TopMenu(self, root)

        self.preset_setups = json_data.preset_setups
        self.game_modes = json_data.game_modes
        self.weatherTypes = json_data.weather
        self.cars = ('All Cars', '')
        self.raceSettings = json_data.cars
        #self.game_versions = json_data.game_versions

        self.c = Frame(root, padding=(5, 5, 12, 0))
        self.c.grid(column=0, row=0, sticky=(N, W, E, S))
        root.grid_columnconfigure(0, weight=1)
        root.grid_rowconfigure(0, weight=1)
        self.bg = "#33393b"  # backgroundcolor
        self.fg = "white"  # forgroundcolor

        self.status_message = StringVar()

        self.tracks_sorted = StringVar(value=self.tracks.track_sorted_list)

        self.sliderFrame = LabelFrame(
            self.c,
            text="Setup",
            labelanchor='nw',
            padding=5)

        self.track_box = Listbox(
            self.c,
            listvariable=self.tracks_sorted,
            height=len(self.tracks.track_sorted_list),
            bg=self.bg,
            fg=self.fg,
            highlightcolor="black",
            selectbackground="darkred",
            selectforeground="white")
        self.track_box.selection_clear(1, last=None)

        # self.game_version_box = self.create_combobox(list(self.game_versions))
        self.race_box = self.create_combobox(list(self.raceSettings))
        self.cars_box = self.create_combobox(self.cars)
        self.weather_box = self.create_combobox(list(self.weatherTypes))
        self.game_mode_box = self.create_combobox(list(self.game_modes))
        self.preset_box = self.create_combobox(list(self.preset_setups.values()))


        """
        self.sort_tracks_box = self.create_checkbox(
            'Order Tracks', self.sort_tracks, lambda: self.toggle_track_list(self.sort_tracks.get()))
        self.auto_use_changes_box = self.create_checkbox(
            'Auto Use Changes', self.auto_use_changes, lambda: self.update_auto_use(self.auto_use_changes.get()))
        self.auto_save_changes_box = self.create_checkbox(
            'Auto Save Changes',
            self.auto_save_changes,
            lambda: self.update_auto_save(self.auto_save_changes.get()))
        self.auto_use_track_box = self.create_checkbox(
            'Auto Use track', self.auto_use_track,
            lambda: self.update_auto_use_track(self.auto_use_track.get()))
        """

        # self.upload_button = self.create_button("Upload", self.upload)
        # self.community_button = self.create_button("Community", community.Community)
        # self.import_setups = self.create_button("import previous setups", self.update.populate_db_from_setups_dir)
        self.useButton = self.create_button("Use", self.use_cmd)
        # self.useSaveButton = self.create_button("Save & Use", self.use_save_cmd)
        # self.saveButton = self.create_button("Save", self.save_cmd)
        # self.saveAsButton = self.create_button("Save As", self.save_as_cmd)
        # self.openButton = self.create_button("Open", self.open_cmd)
        # self.tipBtn = self.create_button("Tip Scruffe",
        #                                  lambda: self.open_url("https://paypal.me/valar"))
        self.status_bar = Label(
            self.c,
            textvariable=self.status_message,
            anchor=W)

        scales = MakeScale(self.sliderFrame)
        self.front_wing_Scale = scales.make("Front wing")
        self.rear_wing_Scale = scales.make("Rear wing")
        self.on_throttle_Scale = scales.make("On throttle", from_=50, to=100)
        self.off_throttle_Scale = scales.make("Off throttle", from_=50, to=100)
        self.front_camber_Scale = scales.make("Front camber", step=0.1, offset=-3.5)
        self.rear_camber_Scale = scales.make("Rear camber", step=0.1, offset=-2)
        self.front_toe_Scale = scales.make("Front toe", step=0.01, offset=0.05, res=2)
        self.rear_toe_Scale = scales.make("Rear toe", step=0.03, offset=0.20, res=2)  # there is an offset
        self.front_suspension_Scale = scales.make("Front suspension")
        self.rear_suspension_Scale = scales.make("Rear suspension")
        self.front_antiroll_bar_Scale = scales.make("Front antiroll bar")
        self.rear_antiroll_bar_Scale = scales.make("Rear antiroll bar")
        self.front_suspension_height_Scale = scales.make("Front suspension height")
        self.rear_suspension_height_Scale = scales.make("Rear suspension height")
        self.brake_pressure_Scale = scales.make("Brake pressure", from_=50, to=100)
        self.brake_bias_Scale = scales.make("Brake bias", from_=70, to=50)
        self.front_right_tyre_pressure_Scale = scales.make("Front right tyre pressure", step=.4, offset=21)  # , 0.4)
        self.front_left_tyre_pressure_Scale = scales.make("Front left tyre pressure", step=.4, offset=21)
        self.rear_right_tyre_pressure_Scale = scales.make("Rear right tyre pressure", step=.4, offset=19.5)
        self.rear_left_tyre_pressure_Scale = scales.make("Rear left tyre pressure", step=.4, offset=19.5)
        self.ballast_Scale = scales.make("Ballast")
        self.ramp_differential_Scale = scales.make("Ramp differential", from_=50, to=70)
        self.fuel_load_Scale = scales.make("Fuel load", from_=5, to=110)
        self.grid()
        self.enable_free_widgets()

    @property
    def boxes(self):
        return [self.track_box,
                self.race_box,
                self.cars_box,
                self.weather_box,
                self.game_mode_box,
                self.preset_box]


    """@property
    def check_boxes(self):
        return [self.sort_tracks_box,
                self.auto_use_changes_box,
                self.auto_save_changes_box,
                self.auto_use_track_box,
                # self.import_setups
                ]"""

    @property
    def league_id(self):
        return self.race_box.get()

    @property
    def team_id(self):
        """returns the ingame f1game team_id"""
        team_ids = [  # https://forums.codemasters.com/topic/50942-f1-2020-udp-specification/
            "Mercedes",
            "Ferrari",
            "Red Bull",
            "Williams",
            "Racing Point",
            "Renault",
            "AlphaTauri",
            "Haas",
            "McLaren",
            "Alfa Romeo",

            "McLaren 1988",
            "McLaren 1991",
            "Williams 1992",
            "Ferrari 1995",
            "Williams 1996",
            "McLaren 1998",
            "Ferrari 2002",
            "Ferrari 2004",
            "Renault 2006",
            "Ferrari 2007",

            "McLaren 2008",
            "Red Bull 2010",
            "Ferrari 1976",

            "ART Grand Prix",
            "Campos Vexatec Racing",
            "Carlin",
            "Charouz Racing System",
            "Dams",
            "Uni-Virtuosi Racing",  # changed russiantime
            "MP Motorsport",

            "Pertamina",  #
            "McLaren 1990",
            "Trident",
            "BWT HWA Racelab",
            "McLaren 1976",
            "Lotus 1972",
            "Ferrari 1979",
            "McLaren 1982",
            "Williams 2003",
            "Brawn 2009",

            "Lotus 1978",
            "F1 Generic car",
            "Art GP ’19",
            "Campos ’19",
            "Carlin ’19",
            "Sauber Junior Charouz ’19",
            "Dams '19",
            "Uni-Virtuosi ‘19",
            "MP Motorsport ‘19",
            "Prema ’19",

            "Trident ’19",
            "Arden ’19",
            "Benetton 1994",
            "Benetton 1995",
            "Ferrari 2000",
            "Jordan 1991",
            "All Cars",
            "My Team"]  # 255
        """
        f2 does not comply with udp specification some examples:
        
        69 =multiplayer
        76= mpmotersport
        77 perta
        78 trident
        79 bwt
        80 hitech
        
        81 jordan91
        82 benet
        """

        team = self.cars_box.get()
        if team == "All Cars":
            return 41  # multiplayer car
        return team_ids.index(team)

    @property
    def game_mode_id(self):
        return self.game_modes[self.game_mode_box.get()]

    @property
    def weather_id(self):
        if self.weather_box.get() == "Wet":
            return 0
        return 1

    @property
    def sliders(self):
        """list of sliders"""
        return [
            self.front_wing_Scale,
            self.rear_wing_Scale,
            self.on_throttle_Scale,
            self.off_throttle_Scale,
            self.front_camber_Scale,
            self.rear_camber_Scale,
            self.front_toe_Scale,
            self.rear_toe_Scale,
            self.front_suspension_Scale,
            self.rear_suspension_Scale,
            self.front_suspension_height_Scale,
            self.rear_suspension_height_Scale,
            self.front_antiroll_bar_Scale,
            self.rear_antiroll_bar_Scale,
            self.brake_pressure_Scale,
            self.brake_bias_Scale,
            self.front_right_tyre_pressure_Scale,
            self.front_left_tyre_pressure_Scale,
            self.rear_right_tyre_pressure_Scale,
            self.rear_left_tyre_pressure_Scale,
            self.ballast_Scale,
            self.fuel_load_Scale,
            self.ramp_differential_Scale]

    @sliders.setter
    def sliders(self, unpacked_setup):
        print(' - - - - - - - - setting sliders - - - - - - - - ')
        print(unpacked_setup)
        database_setup = unpacked_setup[0]
        if database_setup is True:
            i = 8
            for slider in self.sliders:
                if slider.offset != 1:
                    value = unpacked_setup[i]
                    p = round(value - slider.offset, slider.res)
                    product = round(p / slider.step, slider.res) + 1
                    slider.set(product)
                else:
                    slider.set(unpacked_setup[i])
                i += 1
            print('loaded : ', unpacked_setup[1:8])
            print('sliders values : ', unpacked_setup[8:])
        else:
            # .bin file
            create_slider = SliderCounter(unpacked_setup)
            for slider in self.sliders:
                create_slider.set_slider_value(slider)
        print(" - - - - - - - - - - - - - - - - ")

    def create_combobox(self, _values):
        return Combobox(
            self.c,
            justify="center",
            values=_values,
            state="readonly")

    def create_checkbox(self, text, variable, command=None):
        return Checkbutton(
            self.c,
            text=text,
            variable=variable,
            command=command)

    def create_checkbutton(self, txt, var, cmd):
        return Checkbutton(
            self.c,
            text=txt,
            variable=var,
            command=lambda: cmd)

    def create_button(self, text, command=None):
        return Button(
            self.c,
            text=text,
            command=command)

    def grid(self):
        self.sliderFrame.grid(
            row=0,
            rowspan=15,
            column=2,
            columnspan=5)

        box_grid = GridWidgets()
        for box in self.boxes:
            box_grid.grid_box(box)

        check_box_grid = GridWidgets(startrow=8, padx=10)


        """for check_box in self.check_boxes:
            check_box_grid.grid_box(check_box)"""

        buttons = GridWidgets(startrow=check_box_grid.row, increment_horizontal=True)

        buttons.grid_box(self.useButton, columnspan=2)
        # buttons.grid_box(self.saveButton)
        # buttons.grid_box(self.saveAsButton)
        # buttons.grid_box(self.openButton)
        # buttons.grid_box(self.tipBtn, columnspan=2)
        # buttons.grid_box(self.community_button)
        # buttons.grid_box(self.upload_button)

        status = GridWidgets(startrow=(buttons.row + 16))
        status.grid_box(self.status_bar, columnspan=7)

        self.c.grid_columnconfigure(0, weight=1)
        self.c.grid_rowconfigure(11, weight=1)

    def use_cmd(self):
        print(" - - - - - - - - using  - - - - - - - - ")
        self.setup.use_setup()
        self.status_message.set("Using current setup")
        print(" - - - - - - - - - - - - - - - - ")

    def open_cmd(self):
        print(" - - - - - - - - opening file - - - - - - - - ")
        try:
            path = self.setup.open_setup()
            self.status_message.set(" Opened (" + str(path) + ")")
        except FileNotFoundError:
            self.status_message.set(" Can't find file)")
        print(" - - - - - - - - - - - - - - - - ")

    def use_save_cmd(self):
        self.setup.use_setup()
        self.save_cmd()

    def save_cmd(self):
        print(" - - - - - - - - saving  - - - - - - - - ")
        car_setup = self.create_car_setup_from_widgets()
        print("car setup info: ", car_setup.info)
        print("car setup values: ", car_setup.values)
        self.setup.save_setup(car_setup)
        self.status_message.set("Saved")
        print(" - - - - - - - - - - - - - - - - ")

    def save_as_cmd(self):
        print(" - - - - - - - - save as  - - - - - - - - ")
        try:
            path = self.setup.save_as_setup()
            self.status_message.set("Saved: " + path)
        except FileNotFoundError:
            self.status_message.set("File not found")

    def upload(self):
        print(" - - - - - - - - uploading  - - - - - - - - ")
        car_setup = self.create_car_setup_from_widgets()
        print(car_setup.info)
        # commands.Commands().upload(car_setup)

    def toggle_track_list_order(self, sort_bool):
        print(" - - - - - - - - sorting track list  - - - - - - - - ")
        """sort track list based on calendar or Alphabet"""
        # save new value to config file
        Config().sort_tracks = sort_bool

        # update track list
        self.tracks.toggle_track_sort(sort_bool)
        self.track_box.delete(0, END)
        self.track_box.insert(END, *self.tracks.track_sorted_list)

        # redo background color
        self.tracks_background_color()

        # show the previous selected track
        Events(self).box_event()

    def tracks_background_color(self):
        for i in range(0, len(self.tracks.track_sorted_list), 2):
            self.track_box.itemconfigure(i, background='#576366', fg=self.fg)

    def set_starting_values(self):
        print(" - - - - - - - - set starting values  - - - - - - - - ")
        race = Config().race
        self.track_box.selection_set(0)
        self.race_box.set(race)
        self.cars_box['values'] = self.raceSettings[race]
        self.cars_box.set(Config().cars)
        self.weather_box.set(Config().weather)
        self.game_mode_box.set(Config().game_mode)
        self.preset_box.set("Load Preset")
        self.status_message.set('')
        self.top_menu.set_starting_values()

        self.toggle_race_sliders(race)
        Events(self).show_track_selection()

    def toggle_race_sliders(self, race):
        print(" - - - - - - - - toggle race sliders  - - - - - - - - ")
        on_throttle = 'enabled'
        off_throttle = 'enabled'
        brake_pressure = 'enabled'
        fuel_load = 'enabled'
        ballast = 'enabled'
        ramp_differential = 'enabled'

        if race == 'F1 2021' or race == 'F1 2020' or race == 'classic':
            ramp_differential = 'disabled'
            if race == 'F1 2021' or race == 'F1 2020':
                ballast = 'disabled'

        elif race == 'F2 2021' or race == 'F2 2020' or race == 'F2 2019':
            on_throttle = 'disabled'
            off_throttle = 'disabled'
            brake_pressure = 'disabled'
            fuel_load = 'disabled'

        self.on_throttle_Scale.config(state=on_throttle)
        self.off_throttle_Scale.config(state=off_throttle)
        self.brake_pressure_Scale.config(state=brake_pressure)
        self.fuel_load_Scale.config(state=fuel_load)
        self.ballast_Scale.config(state=ballast)
        self.ramp_differential_Scale.config(state=ramp_differential)

    def create_car_setup_from_widgets(self):
        print("... creating car setup from widgets")
        current_track = Config().current_track
        league_id = league_sql.LeagueSql().get_id_from_name(self.league_id)
        track_id = TrackSql().get_track_id_by_country(current_track)
        print("self.config.current_track", current_track)
        print("track id", track_id)
        team_id = self.db.teams.get_team_id(self.cars_box.get(), league_id)

        car_setup = CarSetup(
            league_id=league_id,
            save_name=" save name test",
            team_id=team_id,
            track_id=track_id,
            game_mode_id=self.game_mode_id,
            weather_id=self.weather_id,

            front_wing=self.front_wing_Scale.get(),
            rear_wing=self.rear_wing_Scale.get(),
            on_throttle=self.on_throttle_Scale.get(),
            off_throttle=self.off_throttle_Scale.get(),
            front_camber=self.front_camber_Scale.get(),
            rear_camber=self.rear_camber_Scale.get(),
            front_toe=self.front_toe_Scale.get(),
            rear_toe=self.rear_toe_Scale.get(),
            front_suspension=self.front_suspension_Scale.get(),
            rear_suspension=self.rear_suspension_Scale.get(),
            front_suspension_height=self.front_suspension_height_Scale.get(),
            rear_suspension_height=self.rear_suspension_height_Scale.get(),
            front_antiroll_bar=self.front_antiroll_bar_Scale.get(),
            rear_antiroll_bar=self.rear_antiroll_bar_Scale.get(),
            brake_pressure=self.brake_pressure_Scale.get(),
            brake_bias=self.brake_bias_Scale.get(),
            front_right_tyre_pressure=self.front_right_tyre_pressure_Scale.get(),
            front_left_tyre_pressure=self.front_left_tyre_pressure_Scale.get(),
            rear_right_tyre_pressure=self.rear_right_tyre_pressure_Scale.get(),
            rear_left_tyre_pressure=self.rear_left_tyre_pressure_Scale.get(),
            ballast=self.ballast_Scale.get(),
            fuel_load=self.fuel_load_Scale.get(),
            ramp_differential=self.ramp_differential_Scale.get()
        )
        return car_setup

    @staticmethod
    def open_url(url):
        open_new(url)

    def enable_free_widgets(self):
        self.race_box.configure(state="readonly")
        self.preset_box.configure(state='readonly')

    def premium(self):
        """enables premium content"""
Ejemplo n.º 8
0
class AlbumsPanel(Frame):

    def __init__(self, parent, albumsController: IAlbumsController):
        super().__init__(parent)
        self.albumsController = albumsController

        self.albumList: List[AlbumDb] = []
        self.selectedAlbumName: str = None

        self.musicFromDisc: List[Music] = []

        self.displayedMusicOnComputer = None
        self.displayedMusicInAlbum = None

        self.__initView()

    def __initView(self):
        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(3, weight=1)

        self.albumsListBox = Listbox(self, exportselection=0)
        self.albumsListBox.grid(row=0, column=0, sticky='WE', padx=(10, 0), pady=10)
        self.albumsListBox.bind('<Double-1>', self.__albumDoubleClicked)
        self.albumsListBox.bind("<<ListboxSelect>>", self.__albumSelected)

        albumsScrollbar = Scrollbar(self, command=self.albumsListBox.yview)
        albumsScrollbar.grid(row=0, column=1, sticky='NS', padx=(0, 10), pady=10)

        self.albumsListBox.configure(yscrollcommand=albumsScrollbar.set)

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

        buttonsFrame = Frame(self)
        buttonsFrame.grid(row=1, column=0, sticky='W', padx=10)

        self.albumDeleteButton = Button(buttonsFrame, text=ALBUM_DELETE_TEXT, command=self.__deleteAlbum)
        self.albumDeleteButton.grid(row=0, column=0, padx=5)

        self.albumExportButton = Button(buttonsFrame, text=ALBUM_EXPORT_TEXT, command=self.__exportAlbumClicked)
        self.albumExportButton.grid(row=0, column=1, padx=5)

        self.albumImportButton = Button(buttonsFrame, text=ALBUM_IMPORT_TEXT, command=self.__importAlbumClicked)
        self.albumImportButton.grid(row=0, column=2, padx=5)

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

        createFrame = Frame(self)
        createFrame.grid(row=2, column=0, sticky='W', padx=10)

        label = Label(createFrame, text=ALBUM_CREATE_LABEL_TEXT)
        label.grid(row=0, column=0)

        self.createAlbumNameEntry = Entry(createFrame)
        self.createAlbumNameEntry.grid(row=0, column=1)

        self.createAlbumButton = Button(createFrame, text=ALBUM_CREATE_BUTTON_TEXT, command=self.__createAlbum)
        self.createAlbumButton.grid(row=0, column=2)

        ######################################################################################################
        # Music on computer

        musicFrame = Frame(self, padx=10, pady=10)
        musicFrame.grid(row=3, column=0, columnspan=2, sticky='WENS')
        musicFrame.grid_columnconfigure(0, weight=1)
        musicFrame.grid_columnconfigure(3, weight=1)
        musicFrame.grid_rowconfigure(1, weight=1)

        label = Label(musicFrame, text=MUSIC_ON_COMPUTER_TEXT)
        label.grid(row=0, column=0, sticky='W')

        self.musicOnComputerListBox = Listbox(musicFrame)
        self.musicOnComputerListBox.grid(row=1, column=0, sticky='WENS')

        musicOnComputerScrollbar = Scrollbar(musicFrame, command=self.musicOnComputerListBox.yview)
        musicOnComputerScrollbar.grid(row=1, column=1, sticky='NS')

        self.musicOnComputerListBox.configure(yscrollcommand=musicOnComputerScrollbar.set)

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

        buttonFrame = Frame(musicFrame, padx=10)
        buttonFrame.grid(row=1, column=2)

        self.removeFromAlbumButton = Button(buttonFrame, text='<<', command=self.__removeMusicFromAlbumClicked)
        self.removeFromAlbumButton.grid(row=0, column=0)

        self.addToAlbumButton = Button(buttonFrame, text='>>', command=self.__addMusicToAlbumClicked)
        self.addToAlbumButton.grid(row=1, column=0)

        ######################################################################################################
        #Music in album

        label = Label(musicFrame, text=MUSIC_IN_ALBUM_TEXT)
        label.grid(row=0, column=3, sticky='W')

        self.musicInAlbumListBox = Listbox(musicFrame)
        self.musicInAlbumListBox.grid(row=1, column=3, sticky='WENS')

        musicInAlbumScrollbar = Scrollbar(musicFrame, command=self.musicInAlbumListBox.yview)
        musicInAlbumScrollbar.grid(row=1, column=4, sticky='NS')

        self.musicInAlbumListBox.configure(yscrollcommand=musicInAlbumScrollbar.set)

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

    def displayAlbums(self, albums: List[AlbumDb], musicFromDisc: List[Music]):
        self.albumList = albums
        self.musicFromDisc = musicFromDisc

        self.albumsListBox.delete(0, 'end')
        for i in range(len(self.albumList)):
            a = self.albumList[i]
            self.albumsListBox.insert(i, a.name)

        if self.selectedAlbumName is not None:
            selectedIndex = -1
            for i in range(len(self.albumList)):
                if self.albumList[i].name == self.selectedAlbumName:
                    selectedIndex = i
                    break

            if selectedIndex >= 0:
                self.albumsListBox.select_set(selectedIndex)
                self.albumsListBox.event_generate("<<ListboxSelect>>")

    def __deleteAlbum(self):
        selection = self.albumsListBox.curselection()

        if len(selection) <= 0:
            messagebox.showwarning('Warning', DELETE_ALBUM_SELECT_TEXT)
            return

        self.albumsListBox.selection_clear(0, END)
        self.albumsListBox.event_generate("<<ListboxSelect>>")

        album = self.albumList[selection[0]]
        self.albumsController.deleteAlbum(album.name)

    def __createAlbum(self):
        name = self.createAlbumNameEntry.get()

        if name is None or name == '':
            messagebox.showwarning('Warning', CRATE_ALBUM_INSERT_NAME_TEXT)
            return

        self.albumsController.createAlbum(name)

    def __albumSelected(self, event):
        self.musicOnComputerListBox.delete(0, 'end')
        self.musicInAlbumListBox.delete(0, 'end')

        selection = self.albumsListBox.curselection()
        if len(selection) <= 0:
            return

        selectedAlbum = self.albumList[selection[0]]
        self.selectedAlbumName = selectedAlbum.name

        self.__lisMusicOnComputer(selectedAlbum)
        self.__lisMusicInAlbum(selectedAlbum)

    def __lisMusicOnComputer(self, album):
        musicInAlbum = set()
        for m in album.music:
            musicInAlbum.add(m.path)

        if self.musicFromDisc is None:
            return

        music = self.musicFromDisc.copy()
        music = filter(lambda m: m.path not in musicInAlbum, music)
        self.displayedMusicOnComputer = list(music)

        i = 0
        for m in self.displayedMusicOnComputer:
            self.musicOnComputerListBox.insert(i, m.filename)
            i = i + 1

    def __lisMusicInAlbum(self, album):
        musicOnDisc = set()
        if self.musicFromDisc is not None:
            for m in self.musicFromDisc:
                musicOnDisc.add(m.path)

        self.displayedMusicInAlbum = list(album.music)

        i = 0
        for m in self.displayedMusicInAlbum:
            description = os.path.basename(m.path)
            if m.path not in musicOnDisc:
                description = '<missing> ' + m.path

            self.musicInAlbumListBox.insert(i, description)
            i = i + 1

    def __addMusicToAlbumClicked(self):
        selection = self.albumsListBox.curselection()
        if len(selection) <= 0:
            return

        selectedAlbum = self.albumList[selection[0]]

        selection = self.musicOnComputerListBox.curselection()
        if len(selection) <= 0:
            messagebox.showwarning('Warning', ADD_TO_ALBUM_SELECT_TEXT)
            return

        selectedMusic = self.displayedMusicOnComputer[selection[0]]

        self.albumsController.addMusicToAlbum(selectedAlbum.name, selectedMusic.path)

    def __removeMusicFromAlbumClicked(self):
        selection = self.albumsListBox.curselection()
        if len(selection) <= 0:
            return

        selectedAlbum = self.albumList[selection[0]]

        selection = self.musicInAlbumListBox.curselection()
        if len(selection) <= 0:
            messagebox.showwarning('Warning', REMOVE_FROM_ALBUM_SELECT_TEXT)
            return

        selectedMusic = self.displayedMusicInAlbum[selection[0]]

        self.albumsController.removeMusicFromAlbum(selectedAlbum.name, selectedMusic.path)

    def __exportAlbumClicked(self):
        selection = self.albumsListBox.curselection()
        if len(selection) <= 0:
            messagebox.showwarning('Warning', EXPORT_ALBUM_SELECT_TEXT)
            return

        selectedAlbum = self.albumList[selection[0]]
        self.albumsController.exportAlbum(selectedAlbum.name)

    def __importAlbumClicked(self):
        self.albumsController.importAlbum()

    def __albumDoubleClicked(self, event):
        album = self.albumList[self.albumsListBox.curselection()[0]]
        self.albumsController.addAlbumToQueue(album)
Ejemplo n.º 9
0
class RecursiveDescentApp(object):
    """
    A graphical tool for exploring the recursive descent parser.  The tool
    displays the parser's tree and the remaining text, and allows the
    user to control the parser's operation.  In particular, the user
    can expand subtrees on the frontier, match tokens on the frontier
    against the text, and backtrack.  A "step" button simply steps
    through the parsing process, performing the operations that
    ``RecursiveDescentParser`` would use.
    """
    def __init__(self, grammar, sent, trace=0):
        self._sent = sent
        self._parser = SteppingRecursiveDescentParser(grammar, trace)

        # Set up the main window.
        self._top = Tk()
        self._top.title('Recursive Descent Parser Application')

        # Set up key bindings.
        self._init_bindings()

        # Initialize the fonts.
        self._init_fonts(self._top)

        # Animations.  animating_lock is a lock to prevent the demo
        # from performing new operations while it's animating.
        self._animation_frames = IntVar(self._top)
        self._animation_frames.set(5)
        self._animating_lock = 0
        self._autostep = 0

        # The user can hide the grammar.
        self._show_grammar = IntVar(self._top)
        self._show_grammar.set(1)

        # Create the basic frames.
        self._init_menubar(self._top)
        self._init_buttons(self._top)
        self._init_feedback(self._top)
        self._init_grammar(self._top)
        self._init_canvas(self._top)

        # Initialize the parser.
        self._parser.initialize(self._sent)

        # Resize callback
        self._canvas.bind('<Configure>', self._configure)

    #########################################
    ##  Initialization Helpers
    #########################################

    def _init_fonts(self, root):
        # See: <http://www.astro.washington.edu/owen/ROTKFolklore.html>
        self._sysfont = tkinter.font.Font(font=Button()["font"])
        root.option_add("*Font", self._sysfont)

        # TWhat's our font size (default=same as sysfont)
        self._size = IntVar(root)
        self._size.set(self._sysfont.cget('size'))

        self._boldfont = tkinter.font.Font(family='helvetica',
                                           weight='bold',
                                           size=self._size.get())
        self._font = tkinter.font.Font(family='helvetica',
                                       size=self._size.get())
        if self._size.get() < 0: big = self._size.get() - 2
        else: big = self._size.get() + 2
        self._bigfont = tkinter.font.Font(family='helvetica',
                                          weight='bold',
                                          size=big)

    def _init_grammar(self, parent):
        # Grammar view.
        self._prodframe = listframe = Frame(parent)
        self._prodframe.pack(fill='both', side='left', padx=2)
        self._prodlist_label = Label(self._prodframe,
                                     font=self._boldfont,
                                     text='Available Expansions')
        self._prodlist_label.pack()
        self._prodlist = Listbox(self._prodframe,
                                 selectmode='single',
                                 relief='groove',
                                 background='white',
                                 foreground='#909090',
                                 font=self._font,
                                 selectforeground='#004040',
                                 selectbackground='#c0f0c0')

        self._prodlist.pack(side='right', fill='both', expand=1)

        self._productions = list(self._parser.grammar().productions())
        for production in self._productions:
            self._prodlist.insert('end', ('  %s' % production))
        self._prodlist.config(height=min(len(self._productions), 25))

        # Add a scrollbar if there are more than 25 productions.
        if len(self._productions) > 25:
            listscroll = Scrollbar(self._prodframe, orient='vertical')
            self._prodlist.config(yscrollcommand=listscroll.set)
            listscroll.config(command=self._prodlist.yview)
            listscroll.pack(side='left', fill='y')

        # If they select a production, apply it.
        self._prodlist.bind('<<ListboxSelect>>', self._prodlist_select)

    def _init_bindings(self):
        # Key bindings are a good thing.
        self._top.bind('<Control-q>', self.destroy)
        self._top.bind('<Control-x>', self.destroy)
        self._top.bind('<Escape>', self.destroy)
        self._top.bind('e', self.expand)
        #self._top.bind('<Alt-e>', self.expand)
        #self._top.bind('<Control-e>', self.expand)
        self._top.bind('m', self.match)
        self._top.bind('<Alt-m>', self.match)
        self._top.bind('<Control-m>', self.match)
        self._top.bind('b', self.backtrack)
        self._top.bind('<Alt-b>', self.backtrack)
        self._top.bind('<Control-b>', self.backtrack)
        self._top.bind('<Control-z>', self.backtrack)
        self._top.bind('<BackSpace>', self.backtrack)
        self._top.bind('a', self.autostep)
        #self._top.bind('<Control-a>', self.autostep)
        self._top.bind('<Control-space>', self.autostep)
        self._top.bind('<Control-c>', self.cancel_autostep)
        self._top.bind('<space>', self.step)
        self._top.bind('<Delete>', self.reset)
        self._top.bind('<Control-p>', self.postscript)
        #self._top.bind('<h>', self.help)
        #self._top.bind('<Alt-h>', self.help)
        self._top.bind('<Control-h>', self.help)
        self._top.bind('<F1>', self.help)
        #self._top.bind('<g>', self.toggle_grammar)
        #self._top.bind('<Alt-g>', self.toggle_grammar)
        #self._top.bind('<Control-g>', self.toggle_grammar)
        self._top.bind('<Control-g>', self.edit_grammar)
        self._top.bind('<Control-t>', self.edit_sentence)

    def _init_buttons(self, parent):
        # Set up the frames.
        self._buttonframe = buttonframe = Frame(parent)
        buttonframe.pack(fill='none', side='bottom', padx=3, pady=2)
        Button(
            buttonframe,
            text='Step',
            background='#90c0d0',
            foreground='black',
            command=self.step,
        ).pack(side='left')
        Button(
            buttonframe,
            text='Autostep',
            background='#90c0d0',
            foreground='black',
            command=self.autostep,
        ).pack(side='left')
        Button(buttonframe,
               text='Expand',
               underline=0,
               background='#90f090',
               foreground='black',
               command=self.expand).pack(side='left')
        Button(buttonframe,
               text='Match',
               underline=0,
               background='#90f090',
               foreground='black',
               command=self.match).pack(side='left')
        Button(buttonframe,
               text='Backtrack',
               underline=0,
               background='#f0a0a0',
               foreground='black',
               command=self.backtrack).pack(side='left')
        # Replace autostep...
#         self._autostep_button = Button(buttonframe, text='Autostep',
#                                        underline=0, command=self.autostep)
#         self._autostep_button.pack(side='left')

    def _configure(self, event):
        self._autostep = 0
        (x1, y1, x2, y2) = self._cframe.scrollregion()
        y2 = event.height - 6
        self._canvas['scrollregion'] = '%d %d %d %d' % (x1, y1, x2, y2)
        self._redraw()

    def _init_feedback(self, parent):
        self._feedbackframe = feedbackframe = Frame(parent)
        feedbackframe.pack(fill='x', side='bottom', padx=3, pady=3)
        self._lastoper_label = Label(feedbackframe,
                                     text='Last Operation:',
                                     font=self._font)
        self._lastoper_label.pack(side='left')
        lastoperframe = Frame(feedbackframe, relief='sunken', border=1)
        lastoperframe.pack(fill='x', side='right', expand=1, padx=5)
        self._lastoper1 = Label(lastoperframe,
                                foreground='#007070',
                                background='#f0f0f0',
                                font=self._font)
        self._lastoper2 = Label(lastoperframe,
                                anchor='w',
                                width=30,
                                foreground='#004040',
                                background='#f0f0f0',
                                font=self._font)
        self._lastoper1.pack(side='left')
        self._lastoper2.pack(side='left', fill='x', expand=1)

    def _init_canvas(self, parent):
        self._cframe = CanvasFrame(
            parent,
            background='white',
            #width=525, height=250,
            closeenough=10,
            border=2,
            relief='sunken')
        self._cframe.pack(expand=1, fill='both', side='top', pady=2)
        canvas = self._canvas = self._cframe.canvas()

        # Initially, there's no tree or text
        self._tree = None
        self._textwidgets = []
        self._textline = None

    def _init_menubar(self, parent):
        menubar = Menu(parent)

        filemenu = Menu(menubar, tearoff=0)
        filemenu.add_command(label='Reset Parser',
                             underline=0,
                             command=self.reset,
                             accelerator='Del')
        filemenu.add_command(label='Print to Postscript',
                             underline=0,
                             command=self.postscript,
                             accelerator='Ctrl-p')
        filemenu.add_command(label='Exit',
                             underline=1,
                             command=self.destroy,
                             accelerator='Ctrl-x')
        menubar.add_cascade(label='File', underline=0, menu=filemenu)

        editmenu = Menu(menubar, tearoff=0)
        editmenu.add_command(label='Edit Grammar',
                             underline=5,
                             command=self.edit_grammar,
                             accelerator='Ctrl-g')
        editmenu.add_command(label='Edit Text',
                             underline=5,
                             command=self.edit_sentence,
                             accelerator='Ctrl-t')
        menubar.add_cascade(label='Edit', underline=0, menu=editmenu)

        rulemenu = Menu(menubar, tearoff=0)
        rulemenu.add_command(label='Step',
                             underline=1,
                             command=self.step,
                             accelerator='Space')
        rulemenu.add_separator()
        rulemenu.add_command(label='Match',
                             underline=0,
                             command=self.match,
                             accelerator='Ctrl-m')
        rulemenu.add_command(label='Expand',
                             underline=0,
                             command=self.expand,
                             accelerator='Ctrl-e')
        rulemenu.add_separator()
        rulemenu.add_command(label='Backtrack',
                             underline=0,
                             command=self.backtrack,
                             accelerator='Ctrl-b')
        menubar.add_cascade(label='Apply', underline=0, menu=rulemenu)

        viewmenu = Menu(menubar, tearoff=0)
        viewmenu.add_checkbutton(label="Show Grammar",
                                 underline=0,
                                 variable=self._show_grammar,
                                 command=self._toggle_grammar)
        viewmenu.add_separator()
        viewmenu.add_radiobutton(label='Tiny',
                                 variable=self._size,
                                 underline=0,
                                 value=10,
                                 command=self.resize)
        viewmenu.add_radiobutton(label='Small',
                                 variable=self._size,
                                 underline=0,
                                 value=12,
                                 command=self.resize)
        viewmenu.add_radiobutton(label='Medium',
                                 variable=self._size,
                                 underline=0,
                                 value=14,
                                 command=self.resize)
        viewmenu.add_radiobutton(label='Large',
                                 variable=self._size,
                                 underline=0,
                                 value=18,
                                 command=self.resize)
        viewmenu.add_radiobutton(label='Huge',
                                 variable=self._size,
                                 underline=0,
                                 value=24,
                                 command=self.resize)
        menubar.add_cascade(label='View', underline=0, menu=viewmenu)

        animatemenu = Menu(menubar, tearoff=0)
        animatemenu.add_radiobutton(label="No Animation",
                                    underline=0,
                                    variable=self._animation_frames,
                                    value=0)
        animatemenu.add_radiobutton(label="Slow Animation",
                                    underline=0,
                                    variable=self._animation_frames,
                                    value=10,
                                    accelerator='-')
        animatemenu.add_radiobutton(label="Normal Animation",
                                    underline=0,
                                    variable=self._animation_frames,
                                    value=5,
                                    accelerator='=')
        animatemenu.add_radiobutton(label="Fast Animation",
                                    underline=0,
                                    variable=self._animation_frames,
                                    value=2,
                                    accelerator='+')
        menubar.add_cascade(label="Animate", underline=1, menu=animatemenu)

        helpmenu = Menu(menubar, tearoff=0)
        helpmenu.add_command(label='About', underline=0, command=self.about)
        helpmenu.add_command(label='Instructions',
                             underline=0,
                             command=self.help,
                             accelerator='F1')
        menubar.add_cascade(label='Help', underline=0, menu=helpmenu)

        parent.config(menu=menubar)

    #########################################
    ##  Helper
    #########################################

    def _get(self, widget, treeloc):
        for i in treeloc:
            widget = widget.subtrees()[i]
        if isinstance(widget, TreeSegmentWidget):
            widget = widget.label()
        return widget

    #########################################
    ##  Main draw procedure
    #########################################

    def _redraw(self):
        canvas = self._canvas

        # Delete the old tree, widgets, etc.
        if self._tree is not None:
            self._cframe.destroy_widget(self._tree)
        for twidget in self._textwidgets:
            self._cframe.destroy_widget(twidget)
        if self._textline is not None:
            self._canvas.delete(self._textline)

        # Draw the tree.
        helv = ('helvetica', -self._size.get())
        bold = ('helvetica', -self._size.get(), 'bold')
        attribs = {
            'tree_color': '#000000',
            'tree_width': 2,
            'node_font': bold,
            'leaf_font': helv,
        }
        tree = self._parser.tree()
        self._tree = tree_to_treesegment(canvas, tree, **attribs)
        self._cframe.add_widget(self._tree, 30, 5)

        # Draw the text.
        helv = ('helvetica', -self._size.get())
        bottom = y = self._cframe.scrollregion()[3]
        self._textwidgets = [
            TextWidget(canvas, word, font=self._font) for word in self._sent
        ]
        for twidget in self._textwidgets:
            self._cframe.add_widget(twidget, 0, 0)
            twidget.move(0, bottom - twidget.bbox()[3] - 5)
            y = min(y, twidget.bbox()[1])

        # Draw a line over the text, to separate it from the tree.
        self._textline = canvas.create_line(-5000,
                                            y - 5,
                                            5000,
                                            y - 5,
                                            dash='.')

        # Highlight appropriate nodes.
        self._highlight_nodes()
        self._highlight_prodlist()

        # Make sure the text lines up.
        self._position_text()

    def _redraw_quick(self):
        # This should be more-or-less sufficient after an animation.
        self._highlight_nodes()
        self._highlight_prodlist()
        self._position_text()

    def _highlight_nodes(self):
        # Highlight the list of nodes to be checked.
        bold = ('helvetica', -self._size.get(), 'bold')
        for treeloc in self._parser.frontier()[:1]:
            self._get(self._tree, treeloc)['color'] = '#20a050'
            self._get(self._tree, treeloc)['font'] = bold
        for treeloc in self._parser.frontier()[1:]:
            self._get(self._tree, treeloc)['color'] = '#008080'

    def _highlight_prodlist(self):
        # Highlight the productions that can be expanded.
        # Boy, too bad tkinter doesn't implement Listbox.itemconfig;
        # that would be pretty useful here.
        self._prodlist.delete(0, 'end')
        expandable = self._parser.expandable_productions()
        untried = self._parser.untried_expandable_productions()
        productions = self._productions
        for index in range(len(productions)):
            if productions[index] in expandable:
                if productions[index] in untried:
                    self._prodlist.insert(index, ' %s' % productions[index])
                else:
                    self._prodlist.insert(index,
                                          ' %s (TRIED)' % productions[index])
                self._prodlist.selection_set(index)
            else:
                self._prodlist.insert(index, ' %s' % productions[index])

    def _position_text(self):
        # Line up the text widgets that are matched against the tree
        numwords = len(self._sent)
        num_matched = numwords - len(self._parser.remaining_text())
        leaves = self._tree_leaves()[:num_matched]
        xmax = self._tree.bbox()[0]
        for i in range(0, len(leaves)):
            widget = self._textwidgets[i]
            leaf = leaves[i]
            widget['color'] = '#006040'
            leaf['color'] = '#006040'
            widget.move(leaf.bbox()[0] - widget.bbox()[0], 0)
            xmax = widget.bbox()[2] + 10

        # Line up the text widgets that are not matched against the tree.
        for i in range(len(leaves), numwords):
            widget = self._textwidgets[i]
            widget['color'] = '#a0a0a0'
            widget.move(xmax - widget.bbox()[0], 0)
            xmax = widget.bbox()[2] + 10

        # If we have a complete parse, make everything green :)
        if self._parser.currently_complete():
            for twidget in self._textwidgets:
                twidget['color'] = '#00a000'

        # Move the matched leaves down to the text.
        for i in range(0, len(leaves)):
            widget = self._textwidgets[i]
            leaf = leaves[i]
            dy = widget.bbox()[1] - leaf.bbox()[3] - 10.0
            dy = max(dy, leaf.parent().label().bbox()[3] - leaf.bbox()[3] + 10)
            leaf.move(0, dy)

    def _tree_leaves(self, tree=None):
        if tree is None: tree = self._tree
        if isinstance(tree, TreeSegmentWidget):
            leaves = []
            for child in tree.subtrees():
                leaves += self._tree_leaves(child)
            return leaves
        else:
            return [tree]

    #########################################
    ##  Button Callbacks
    #########################################

    def destroy(self, *e):
        self._autostep = 0
        if self._top is None: return
        self._top.destroy()
        self._top = None

    def reset(self, *e):
        self._autostep = 0
        self._parser.initialize(self._sent)
        self._lastoper1['text'] = 'Reset Application'
        self._lastoper2['text'] = ''
        self._redraw()

    def autostep(self, *e):
        if self._animation_frames.get() == 0:
            self._animation_frames.set(2)
        if self._autostep:
            self._autostep = 0
        else:
            self._autostep = 1
            self._step()

    def cancel_autostep(self, *e):
        #self._autostep_button['text'] = 'Autostep'
        self._autostep = 0

    # Make sure to stop auto-stepping if we get any user input.
    def step(self, *e):
        self._autostep = 0
        self._step()

    def match(self, *e):
        self._autostep = 0
        self._match()

    def expand(self, *e):
        self._autostep = 0
        self._expand()

    def backtrack(self, *e):
        self._autostep = 0
        self._backtrack()

    def _step(self):
        if self._animating_lock: return

        # Try expanding, matching, and backtracking (in that order)
        if self._expand(): pass
        elif self._parser.untried_match() and self._match(): pass
        elif self._backtrack(): pass
        else:
            self._lastoper1['text'] = 'Finished'
            self._lastoper2['text'] = ''
            self._autostep = 0

        # Check if we just completed a parse.
        if self._parser.currently_complete():
            self._autostep = 0
            self._lastoper2['text'] += '    [COMPLETE PARSE]'

    def _expand(self, *e):
        if self._animating_lock: return
        old_frontier = self._parser.frontier()
        rv = self._parser.expand()
        if rv is not None:
            self._lastoper1['text'] = 'Expand:'
            self._lastoper2['text'] = rv
            self._prodlist.selection_clear(0, 'end')
            index = self._productions.index(rv)
            self._prodlist.selection_set(index)
            self._animate_expand(old_frontier[0])
            return True
        else:
            self._lastoper1['text'] = 'Expand:'
            self._lastoper2['text'] = '(all expansions tried)'
            return False

    def _match(self, *e):
        if self._animating_lock: return
        old_frontier = self._parser.frontier()
        rv = self._parser.match()
        if rv is not None:
            self._lastoper1['text'] = 'Match:'
            self._lastoper2['text'] = rv
            self._animate_match(old_frontier[0])
            return True
        else:
            self._lastoper1['text'] = 'Match:'
            self._lastoper2['text'] = '(failed)'
            return False

    def _backtrack(self, *e):
        if self._animating_lock: return
        if self._parser.backtrack():
            elt = self._parser.tree()
            for i in self._parser.frontier()[0]:
                elt = elt[i]
            self._lastoper1['text'] = 'Backtrack'
            self._lastoper2['text'] = ''
            if isinstance(elt, Tree):
                self._animate_backtrack(self._parser.frontier()[0])
            else:
                self._animate_match_backtrack(self._parser.frontier()[0])
            return True
        else:
            self._autostep = 0
            self._lastoper1['text'] = 'Finished'
            self._lastoper2['text'] = ''
            return False

    def about(self, *e):
        ABOUT = ("NLTK Recursive Descent Parser Application\n" +
                 "Written by Edward Loper")
        TITLE = 'About: Recursive Descent Parser Application'
        try:
            from tkinter.messagebox import Message
            Message(message=ABOUT, title=TITLE).show()
        except:
            ShowText(self._top, TITLE, ABOUT)

    def help(self, *e):
        self._autostep = 0
        # The default font's not very legible; try using 'fixed' instead.
        try:
            ShowText(self._top,
                     'Help: Recursive Descent Parser Application',
                     (__doc__ or '').strip(),
                     width=75,
                     font='fixed')
        except:
            ShowText(self._top,
                     'Help: Recursive Descent Parser Application',
                     (__doc__ or '').strip(),
                     width=75)

    def postscript(self, *e):
        self._autostep = 0
        self._cframe.print_to_file()

    def mainloop(self, *args, **kwargs):
        """
        Enter the Tkinter mainloop.  This function must be called if
        this demo is created from a non-interactive program (e.g.
        from a secript); otherwise, the demo will close as soon as
        the script completes.
        """
        if in_idle(): return
        self._top.mainloop(*args, **kwargs)

    def resize(self, size=None):
        if size is not None: self._size.set(size)
        size = self._size.get()
        self._font.configure(size=-(abs(size)))
        self._boldfont.configure(size=-(abs(size)))
        self._sysfont.configure(size=-(abs(size)))
        self._bigfont.configure(size=-(abs(size + 2)))
        self._redraw()

    #########################################
    ##  Expand Production Selection
    #########################################

    def _toggle_grammar(self, *e):
        if self._show_grammar.get():
            self._prodframe.pack(fill='both',
                                 side='left',
                                 padx=2,
                                 after=self._feedbackframe)
            self._lastoper1['text'] = 'Show Grammar'
        else:
            self._prodframe.pack_forget()
            self._lastoper1['text'] = 'Hide Grammar'
        self._lastoper2['text'] = ''


#     def toggle_grammar(self, *e):
#         self._show_grammar = not self._show_grammar
#         if self._show_grammar:
#             self._prodframe.pack(fill='both', expand='y', side='left',
#                                  after=self._feedbackframe)
#             self._lastoper1['text'] = 'Show Grammar'
#         else:
#             self._prodframe.pack_forget()
#             self._lastoper1['text'] = 'Hide Grammar'
#         self._lastoper2['text'] = ''

    def _prodlist_select(self, event):
        selection = self._prodlist.curselection()
        if len(selection) != 1: return
        index = int(selection[0])
        old_frontier = self._parser.frontier()
        production = self._parser.expand(self._productions[index])

        if production:
            self._lastoper1['text'] = 'Expand:'
            self._lastoper2['text'] = production
            self._prodlist.selection_clear(0, 'end')
            self._prodlist.selection_set(index)
            self._animate_expand(old_frontier[0])
        else:
            # Reset the production selections.
            self._prodlist.selection_clear(0, 'end')
            for prod in self._parser.expandable_productions():
                index = self._productions.index(prod)
                self._prodlist.selection_set(index)

    #########################################
    ##  Animation
    #########################################

    def _animate_expand(self, treeloc):
        oldwidget = self._get(self._tree, treeloc)
        oldtree = oldwidget.parent()
        top = not isinstance(oldtree.parent(), TreeSegmentWidget)

        tree = self._parser.tree()
        for i in treeloc:
            tree = tree[i]

        widget = tree_to_treesegment(self._canvas,
                                     tree,
                                     node_font=self._boldfont,
                                     leaf_color='white',
                                     tree_width=2,
                                     tree_color='white',
                                     node_color='white',
                                     leaf_font=self._font)
        widget.label()['color'] = '#20a050'

        (oldx, oldy) = oldtree.label().bbox()[:2]
        (newx, newy) = widget.label().bbox()[:2]
        widget.move(oldx - newx, oldy - newy)

        if top:
            self._cframe.add_widget(widget, 0, 5)
            widget.move(30 - widget.label().bbox()[0], 0)
            self._tree = widget
        else:
            oldtree.parent().replace_child(oldtree, widget)

        # Move the children over so they don't overlap.
        # Line the children up in a strange way.
        if widget.subtrees():
            dx = (oldx + widget.label().width() / 2 -
                  widget.subtrees()[0].bbox()[0] / 2 -
                  widget.subtrees()[0].bbox()[2] / 2)
            for subtree in widget.subtrees():
                subtree.move(dx, 0)

        self._makeroom(widget)

        if top:
            self._cframe.destroy_widget(oldtree)
        else:
            oldtree.destroy()

        colors = [
            'gray%d' % (10 * int(10 * x / self._animation_frames.get()))
            for x in range(self._animation_frames.get(), 0, -1)
        ]

        # Move the text string down, if necessary.
        dy = widget.bbox()[3] + 30 - self._canvas.coords(self._textline)[1]
        if dy > 0:
            for twidget in self._textwidgets:
                twidget.move(0, dy)
            self._canvas.move(self._textline, 0, dy)

        self._animate_expand_frame(widget, colors)

    def _makeroom(self, treeseg):
        """
        Make sure that no sibling tree bbox's overlap.
        """
        parent = treeseg.parent()
        if not isinstance(parent, TreeSegmentWidget): return

        index = parent.subtrees().index(treeseg)

        # Handle siblings to the right
        rsiblings = parent.subtrees()[index + 1:]
        if rsiblings:
            dx = treeseg.bbox()[2] - rsiblings[0].bbox()[0] + 10
            for sibling in rsiblings:
                sibling.move(dx, 0)

        # Handle siblings to the left
        if index > 0:
            lsibling = parent.subtrees()[index - 1]
            dx = max(0, lsibling.bbox()[2] - treeseg.bbox()[0] + 10)
            treeseg.move(dx, 0)

        # Keep working up the tree.
        self._makeroom(parent)

    def _animate_expand_frame(self, widget, colors):
        if len(colors) > 0:
            self._animating_lock = 1
            widget['color'] = colors[0]
            for subtree in widget.subtrees():
                if isinstance(subtree, TreeSegmentWidget):
                    subtree.label()['color'] = colors[0]
                else:
                    subtree['color'] = colors[0]
            self._top.after(50, self._animate_expand_frame, widget, colors[1:])
        else:
            widget['color'] = 'black'
            for subtree in widget.subtrees():
                if isinstance(subtree, TreeSegmentWidget):
                    subtree.label()['color'] = 'black'
                else:
                    subtree['color'] = 'black'
            self._redraw_quick()
            widget.label()['color'] = 'black'
            self._animating_lock = 0
            if self._autostep: self._step()

    def _animate_backtrack(self, treeloc):
        # Flash red first, if we're animating.
        if self._animation_frames.get() == 0: colors = []
        else: colors = ['#a00000', '#000000', '#a00000']
        colors += [
            'gray%d' % (10 * int(10 * x / (self._animation_frames.get())))
            for x in range(1,
                           self._animation_frames.get() + 1)
        ]

        widgets = [self._get(self._tree, treeloc).parent()]
        for subtree in widgets[0].subtrees():
            if isinstance(subtree, TreeSegmentWidget):
                widgets.append(subtree.label())
            else:
                widgets.append(subtree)

        self._animate_backtrack_frame(widgets, colors)

    def _animate_backtrack_frame(self, widgets, colors):
        if len(colors) > 0:
            self._animating_lock = 1
            for widget in widgets:
                widget['color'] = colors[0]
            self._top.after(50, self._animate_backtrack_frame, widgets,
                            colors[1:])
        else:
            for widget in widgets[0].subtrees():
                widgets[0].remove_child(widget)
                widget.destroy()
            self._redraw_quick()
            self._animating_lock = 0
            if self._autostep: self._step()

    def _animate_match_backtrack(self, treeloc):
        widget = self._get(self._tree, treeloc)
        node = widget.parent().label()
        dy = (1.0 * (node.bbox()[3] - widget.bbox()[1] + 14) /
              max(1, self._animation_frames.get()))
        self._animate_match_backtrack_frame(self._animation_frames.get(),
                                            widget, dy)

    def _animate_match(self, treeloc):
        widget = self._get(self._tree, treeloc)

        dy = ((self._textwidgets[0].bbox()[1] - widget.bbox()[3] - 10.0) /
              max(1, self._animation_frames.get()))
        self._animate_match_frame(self._animation_frames.get(), widget, dy)

    def _animate_match_frame(self, frame, widget, dy):
        if frame > 0:
            self._animating_lock = 1
            widget.move(0, dy)
            self._top.after(10, self._animate_match_frame, frame - 1, widget,
                            dy)
        else:
            widget['color'] = '#006040'
            self._redraw_quick()
            self._animating_lock = 0
            if self._autostep: self._step()

    def _animate_match_backtrack_frame(self, frame, widget, dy):
        if frame > 0:
            self._animating_lock = 1
            widget.move(0, dy)
            self._top.after(10, self._animate_match_backtrack_frame, frame - 1,
                            widget, dy)
        else:
            widget.parent().remove_child(widget)
            widget.destroy()
            self._animating_lock = 0
            if self._autostep: self._step()

    def edit_grammar(self, *e):
        CFGEditor(self._top, self._parser.grammar(), self.set_grammar)

    def set_grammar(self, grammar):
        self._parser.set_grammar(grammar)
        self._productions = list(grammar.productions())
        self._prodlist.delete(0, 'end')
        for production in self._productions:
            self._prodlist.insert('end', (' %s' % production))

    def edit_sentence(self, *e):
        sentence = " ".join(self._sent)
        title = 'Edit Text'
        instr = 'Enter a new sentence to parse.'
        EntryDialog(self._top, sentence, instr, self.set_sentence, title)

    def set_sentence(self, sentence):
        self._sent = sentence.split()  #[XX] use tagged?
        self.reset()
Ejemplo n.º 10
0
Archivo: tkui.py Proyecto: mindhog/mawb
class TextSelect(Frame):

    def __init__(self, client, anchor, items, destroyAnchor=False):
        """
        Args:
            client: [SelectionClient] The window that text is returned to.
            anchor: A window that the text selection popup is created
                relative to.
            items: [str], items to display in the listbox.
            destroyAnchor: [bool] if true, destroy the anchor after
                positioning the window.
        """
        self.top = Toplevel()
        self.anchor = anchor
        self.top.overrideredirect(1)
        self.top.wm_geometry('+%s+%s' % (anchor.winfo_rootx() + anchor.winfo_x(),
                                         anchor.winfo_rooty() + anchor.winfo_y()
                                         )
                             )
        super(TextSelect, self).__init__(self.top)
        self.entry = Entry(self)
        self.client = client
        self.items = items
        self.place(x = 0.5, y = 0.5, height = 100, width = 100)
        self.entry.bind('<Return>', self.close)
        self.entry.bind('<KeyPress>', self.filter)
        self.entry.bind('<Escape>', self.abort)
        self.entry.bind('<Up>', self.up)
        self.entry.bind('<Down>', self.down)
        self.entry.pack()

        # Create the list of items.
        self.list = Listbox(self)
        for item in self.items:
            self.list.insert('end', item)
        self.list.pack()
        self.grid()
        self.entry.focus()

        # Reposition the select button against the anchor.  We defer this
        # until after idle so that the anchor has a chance to get rendered.
        def reposition(*args):
            self.top.wm_geometry('+%s+%s' % (
                anchor.winfo_rootx(),
                anchor.winfo_rooty())
            )
            if destroyAnchor:
                anchor.destroy()
        self.after_idle(reposition)

    def close(self, event):
        sel = self.list.curselection()
        if sel:
            item = self.list.get(sel[0])
        else:
            item = self.entry.get()

        # Note that the order of this appears to be significant: destroying
        # before selecting leaves the focus in a weird state.
        self.client.selected(item)
        self.top.destroy()
        return 'braek'

    def abort(self, event):
        self.top.destroy()
        self.client.aborted()
        return 'break'

    def up(self, event):
        sel = self.list.curselection()
        if not sel:
            self.list.selection_set(0)
            return 'break'
        sel = sel[0]

        print('sel is %s size is %s' % (sel, self.list.size()))
        if sel > 0:
            print('setting selection to %s' % sel)
            self.list.selection_clear(sel)
            self.list.selection_set(sel - 1)
            self.list.see(sel)
        return 'break'

    def down(self, event):
        sel = self.list.curselection()
        if not sel:
            self.list.selection_set(0)
            return 'break'
        sel = sel[0]

        print('sel is %s size is %s' % (sel, self.list.size()))
        if sel < self.list.size() - 1:
            print('setting selection to %s' % (sel + 1))
            self.list.selection_clear(sel)
            self.list.selection_set(sel + 1)
            self.list.see(sel)
        return 'break'

    def filter(self, event):
        """Filter the listbox based on the contents of the entryfield."""
        # first add the character to the entry.
        currentText = self.entry.get()
        print(event.keysym)
        if event.keysym == 'BackSpace':
            # Handle backspace specially.
            if currentText:
                currentText = currentText[:-1]
                self.entry.delete(0, 'end')
                self.entry.insert(0, currentText)
            else:
                return 'break'
        else:
            # Assume normal character. Insert it.
            self.entry.insert('insert', event.char)
            currentText += event.char

        self.list.delete(0, 'end')
        pattern = currentText.upper()
        for item in self.items:
            if pattern in item.upper():
                self.list.insert('end', item)

        return 'break'
Ejemplo n.º 11
0
class ListboxVidget(Vidget, Eventor):
    """
    ListboxVidget contains a Listbox widget. It adds the following abilities:
    - Store items of any type, unlike Listbox widget that only stores texts.
    - Remember selected item even if the listbox widget lost focus.
    - Notify pre-change and post-change events.
    """

    # Error raised when trying to change the listbox while a change is going on
    class CircularCallError(ValueError):
        pass

    # Error raised when trying to change the listbox while it is disabled
    class DisabledError(ValueError):
        pass

    # Event notified when the listbox's items are to be changed
    ITEMS_CHANGE_SOON = 'ITEMS_CHANGE_SOON'

    # Event notified when the listbox's items are changed
    ITEMS_CHANGE_DONE = 'ITEMS_CHANGE_DONE'

    # Event notified when the listbox's active item is to be changed
    ITEMCUR_CHANGE_SOON = 'ITEMCUR_CHANGE_SOON'

    # Event notified when the listbox's active item is changed
    ITEMCUR_CHANGE_DONE = 'ITEMCUR_CHANGE_DONE'

    # Events list
    EVENTS = (
        ITEMS_CHANGE_SOON,
        ITEMS_CHANGE_DONE,
        ITEMCUR_CHANGE_SOON,
        ITEMCUR_CHANGE_DONE,
    )

    def __init__(
        self,
        items=None,
        item_to_text=None,
        normal_bg='',
        normal_fg='',
        active_bg='sky blue',
        active_fg='white',
        selected_bg='steel blue',
        selected_fg='white',
        master=None,
    ):
        """
        Initialize object.

        @param items: Items list.

        @param item_to_text: Item-to-text function. Default is `str`.

        @param normal_bg: Unselected item background color.

        @param normal_fg: Unselected item foreground color.

        @param active_bg: Active item background color. `Active` means the item
        is selected (in general meaning) but the listbox has no focus.

        @param active_fg: Active item foreground color. `Active` means the item
        is selected (in general meaning) but the listbox has no focus.

        @param selected_bg: Selected item background color. `Selected` means
        the item is selected (in general meaning) and the listbox has focus.

        @param selected_fg: Selected item foreground color. `Selected` means
        the item is selected (in general meaning) and the listbox has focus.

        @param master: Master widget.

        @return: None.
        """
        # Initialize Vidget.
        # Create main frame widget.
        Vidget.__init__(
            self,
            master=master,
        )

        # Initialize Eventor
        Eventor.__init__(self)

        # If items list is given
        if items is not None:
            # If items list is not list
            if not isinstance(items, list):
                # Raise error
                raise TypeError(items)

            # If items list is list.

        # If items list is not given, or items list is given and is list

        # Items list
        self._items = items if items is not None else []

        # Item-to-text function. Default is `str`.
        self._item_to_text = item_to_text if item_to_text is not None else str

        # Unselected item background color
        self._normal_fg = normal_fg

        # Unselected item foreground color
        self._normal_bg = normal_bg

        # Active item background color
        self._active_fg = active_fg

        # Active item foreground color
        self._active_bg = active_bg

        # Selected item background color
        self._selected_fg = selected_fg

        # Selected item foreground color
        self._selected_bg = selected_bg

        # Whether the listbox is changing
        self._is_changing = False

        # Active index. `-1` means void, i.e. no item is active.
        self._indexcur = -1

        # Whether active index is being reset to same value
        self._is_resetting = False

        # Create listbox widget
        self._listbox = Listbox(
            master=self.widget(),
            relief='groove',
            activestyle='none',
            highlightthickness=0,
            # Active index cache only supports single-selection mode for now.
            # See 2N6OR.
            selectmode='single',
        )

        # Set the listbox widget as config target
        self.config_target_set(self._listbox)

        # Create x-axis scrollbar
        self._scrollbar_xview = _HiddenScrollbar(
            self.widget(),
            orient=HORIZONTAL,
        )

        # Create y-axis scrollbar
        self._scrollbar_yview = _HiddenScrollbar(
            self.widget(),
            orient=VERTICAL,
        )

        # Mount scrollbars
        self._listbox.config(xscrollcommand=self._scrollbar_xview.set)

        self._listbox.config(yscrollcommand=self._scrollbar_yview.set)

        self._scrollbar_xview.config(command=self._listbox.xview)

        self._scrollbar_yview.config(command=self._listbox.yview)

        # Bind single-click event handler
        self._listbox.bind('<Button-1>', self._on_single_click)

        # Bind double-click event handler
        self._listbox.bind('<Double-Button-1>', self._on_double_click)

        # Update listbox widget
        self._listbox_widget_update(keep_active=False)

        # Update widget
        self._widget_update()

    def _widget_update(self):
        """
        Update widget.

        @return: None.
        """
        # Row 0 for listbox and y-axis scrollbar
        self.widget().rowconfigure(0, weight=1)

        # Row 1 for x-axis scrollbar
        self.widget().rowconfigure(1, weight=0)

        # Column 0 for listbox and x-axis scrollbar
        self.widget().columnconfigure(0, weight=1)

        # Column 1 for y-axis scrollbar
        self.widget().columnconfigure(1, weight=0)

        # Lay out listbox
        self._listbox.grid(row=0, column=0, sticky='NSEW')

        # Lay out x-axis scrollbar
        self._scrollbar_xview.grid(row=1, column=0, sticky='EW')

        # Lay out y-axis scrollbar
        self._scrollbar_yview.grid(row=0, column=1, sticky='NS')

    def is_enabled(self):
        """
        Test whether the listbox is enabled.

        @return: Boolean.
        """
        # Return whether the listbox is enabled
        return self._listbox.config('state')[4] != DISABLED

    def is_changing(self):
        """
        Test whether the listbox is changing.

        @return: Boolean.
        """
        # Return whether the listbox is changing
        return self._is_changing

    def is_resetting(self):
        """
        Test whether the listbox is setting active index to the same value.

        @return: Boolean.
        """
        # Return whether the listbox is setting active index to the same value
        return self._is_resetting

    def size(self):
        """
        Get number of items.

        @return: Number of items.
        """
        # Return number of items
        return len(self._items)

    def items(self):
        """
        Get items list.
        Notice do not change the list outside.

        @return: Items list.
        """
        # Return items list
        return self._items

    def items_set(
        self,
        items,
        notify=True,
        keep_active=False,
    ):
        """
        Set items list.

        Notice do not change the list outside.

        @param items: Items list.

        @param notify: Whether notify pre-change and post-change events.

        @param keep_active: Whether keep or clear active index.

        @return: None.
        """
        # If the items is not list
        if not isinstance(items, list):
            # Raise error
            raise TypeError(items)

        # If the items is list.

        # If the listbox is disabled
        if not self.is_enabled():
            # Raise error
            raise ListboxVidget.DisabledError()

        # If the listbox is not disabled.

        # If the listbox is changing
        if self._is_changing:
            # Raise error
            raise ListboxVidget.CircularCallError()

        # If the listbox is not changing.

        # Set changing flag on
        self._is_changing = True

        # If notify events
        if notify:
            # Notify pre-change event
            self.handler_notify(self.ITEMS_CHANGE_SOON)

        # Store the new items
        self._items = items

        # Update listbox widget
        self._listbox_widget_update(
            keep_active=keep_active
        )

        # If notify events
        if notify:
            # Notify post-change event
            self.handler_notify(self.ITEMS_CHANGE_DONE)

        # Set changing flag off
        self._is_changing = False

    def index_is_valid(self, index):
        """
        Test whether given index is valid. Notice -1 is not valid.

        @param index: Index to test.

        @return: Boolean.
        """
        # Test whether given index is valid
        return 0 <= index and index < self.size()

    def index_is_valid_or_void(self, index):
        """
        Test whether given index is valid or is -1.

        @param index: Index to test.

        @return: Boolean.
        """
        # Test whether given index is valid or is -1
        return index == -1 or self.index_is_valid(index)

    def index_first(self):
        """
        Get the first item's index.

        @return: First item's index, or -1 if the listbox is empty.
        """
        # Return the first item's index
        return 0 if self.size() > 0 else -1

    def index_last(self):
        """
        Get the last item's index.

        @return: Last item's index, or -1 if the listbox is empty.
        """
        # Return the last item's index
        return self.size() - 1

    def indexcur(self, internal=False, raise_error=False):
        """
        Get the active index.

        @param internal: See 2N6OR.

        @return: The active index. If no active active, either return -1, or
        raise IndexError if `raise_error` is True.
        """
        # Get active indexes
        indexcurs = self._indexcurs(internal=internal)

        # If have active indexes
        if indexcurs:
            # Return the first active index
            return indexcurs[0]

        # If no active indexes
        else:
            # If raise error
            if raise_error:
                # Raise error
                raise IndexError(-1)

            # If not raise error
            else:
                # Return -1
                return -1

    def _indexcurs(self, internal=False):
        """
        Get active indexes list.

        2N6OR
        @param internal: Whether use listbox widget's selected indexes, instead
        of cached active index.
        Notice listbox widget has no selected indexes if it has no focus.
        Notice using cached active index only supports single-selection mode,
        which means the result list has at most one index.

        @return: Active indexes list.
        """
        # If use listbox widget's selected indexes
        if internal:
            # Return listbox widget's selected indexes list
            return [int(x) for x in self._listbox.curselection()]

        # If not use listbox widget's selected indexes
        else:
            # If cached active index is valid
            if self.index_is_valid(self._indexcur):
                # Return a list with the cached active index
                return [self._indexcur]

            # If cached active index is not valid
            else:
                # Return empty list
                return []

    def indexcur_set(
        self,
        index,
        focus=False,
        notify=True,
        notify_arg=None,
    ):
        """
        Set active index.

        @param index: The index to set.

        @param focus: Whether set focus on the listbox widget.

        @param notify: Whether notify pre-change and post-change events.

        @param notify_arg: Event argument.

        @return: None.
        """
        # If the index is not valid or -1
        if not self.index_is_valid_or_void(index):
            # Raise error
            raise IndexError(index)

        # If the index is valid or is -1.

        # If the listbox is not enabled
        if not self.is_enabled():
            # Raise error
            raise ListboxVidget.DisabledError()

        # If the listbox is enabled.

        # If the listbox is changing
        if self._is_changing:
            # Raise error
            raise ListboxVidget.CircularCallError()

        # If the listbox is not changing.

        # Set changing flag on
        self._is_changing = True

        # Get old active index
        old_indexcur = self._indexcur

        # Set resetting flag on if new and old indexes are equal
        self._is_resetting = (index == old_indexcur)

        # If notify events
        if notify:
            # Notify pre-change event
            self.handler_notify(self.ITEMCUR_CHANGE_SOON, notify_arg)

        # If old active index is valid
        if self.index_is_valid(old_indexcur):
            # Set old active item's background color to normal color
            self._listbox.itemconfig(old_indexcur, background=self._normal_bg)

            # Set old active item's foreground color to normal color
            self._listbox.itemconfig(old_indexcur, foreground=self._normal_fg)

        # Cache new active index
        self._indexcur = index

        # Clear listbox widget's selection
        self._listbox.selection_clear(0, END)

        # Set listbox widget's selection
        self._listbox.selection_set(index)

        # Set listbox widget's activated index
        self._listbox.activate(index)

        # If new active index is valid
        if index != -1:
            # Set new active item's background color to active color
            self._listbox.itemconfig(index, background=self._active_bg)

            # Set new active item's foreground color to active color
            self._listbox.itemconfig(index, foreground=self._active_fg)

        # If set focus
        if focus:
            # Set focus on the listbox widget
            self._listbox.focus_set()

        # If new active index is valid
        if index != -1:
            # Make the active item visible
            self._listbox.see(index)

        # If notify events
        if notify:
            # Notify post-change event
            self.handler_notify(self.ITEMCUR_CHANGE_DONE, notify_arg)

        # Set resetting flag off
        self._is_resetting = False

        # Set changing flag off
        self._is_changing = False

    def indexcur_set_by_event(
        self,
        event,
        focus=False,
        notify=True,
        notify_arg=None,
    ):
        """
        Set active index using a Tkinter event object that contains coordinates
        of the active item.

        @param event: Tkinter event object.

        @param focus: Whether set focus on the listbox widget.

        @param notify: Whether notify pre-change and post-change events.

        @param notify_arg: Event argument.

        @return: None.
        """
        # Get the event's y co-ordinate's nearest listbox item index
        index = self._listbox.nearest(event.y)

        # If the index is not valid
        if not self.index_is_valid_or_void(index):
            # Ignore the event
            return

        # If the index is valid
        else:
            # Set the index as active index
            self.indexcur_set(
                index=index,
                focus=focus,
                notify=notify,
                notify_arg=notify_arg,
            )

    def item(self, index):
        """
        Get item at given index.

        @return: Item at given index, or IndexError if the index is not valid.
        """
        return self.items()[index]

    def itemcur(self, internal=False, raise_error=False):
        """
        Get the active item.

        @param internal: See 2N6OR.

        @param raise_error: Whether raise error if no active item.

        @return: The active item. If no active item, if `raise_error` is
        True, raise IndexError, otherwise return None.
        """
        # Get active index.
        # May raise IndexError if `raise_error` is True.
        indexcur = self.indexcur(
            internal=internal,
            raise_error=raise_error,
        )

        # If no active index
        if indexcur == -1:
            # Return None
            return None

        # If have active index
        else:
            # Return the active item
            return self.items()[indexcur]

    def item_insert(
        self,
        item,
        index=None,
        notify=True,
        keep_active=True,
    ):
        """
        Insert item at given index.

        @param item: Item to insert.

        @param index: Index to insert. `None` means active index, and if no
        active index, insert at the end.

        @param notify: Whether notify pre-change and post-change events.

        @param keep_active: Whether keep or clear active index.

        @return: None.
        """
        # If notify events
        if notify:
            # Notify pre-change events
            self.handler_notify(self.ITEMCUR_CHANGE_SOON)

            self.handler_notify(self.ITEMS_CHANGE_SOON)

        # Get old active index
        active_index = self.indexcur()

        # If the index is None,
        # it means use active index.
        if index is None:
            # Use active index.
            # `-1` works and means appending.
            index = active_index

        # Insert the item to the items list
        self._items.insert(index, item)

        # If old active index is valid
        if active_index != -1:
            # If old active index is GE the inserted index
            if active_index >= index:
                # Shift active index by one
                active_index += 1

            # If old active index is not GE the inserted index, use it as-is.

        # Set new active index
        self.indexcur_set(index=active_index, notify=False)

        # Update listbox widget
        self._listbox_widget_update(
            keep_active=keep_active
        )

        # If notify events
        if notify:
            # Notify post-change events
            self.handler_notify(self.ITEMS_CHANGE_DONE)

            self.handler_notify(self.ITEMCUR_CHANGE_DONE)

    def item_remove(
        self,
        index,
        notify=True,
        keep_active=True,
    ):
        """
        Remove item at given index.

        @param index: Index to remove.

        @param notify: Whether notify pre-change and post-change events.

        @param keep_active: Whether keep or clear active index.

        @return: None.
        """
        # If the index is not valid
        if not self.index_is_valid(index):
            # Raise error
            raise ValueError(index)

        # If the index is valid.

        # If notify events
        if notify:
            # Notify pre-change events
            self.handler_notify(self.ITEMCUR_CHANGE_SOON)

            self.handler_notify(self.ITEMS_CHANGE_SOON)

        # Get old active index
        active_index = self.indexcur()

        # Remove item at the index
        del self._items[index]

        # If old active index is valid
        if active_index != -1:
            # Get the last index
            index_last = self.index_last()

            # If old active index is GT the last index
            if active_index > index_last:
                # Use the last index as new active index
                active_index = index_last

            # If old active index is not GT the last index, use it as-is.

        # Set new active index
        self.indexcur_set(index=active_index, notify=False)

        # Update listbox widget
        self._listbox_widget_update(
            keep_active=keep_active
        )

        # If notify events
        if notify:
            # Notify post-change events
            self.handler_notify(self.ITEMS_CHANGE_DONE)

            self.handler_notify(self.ITEMCUR_CHANGE_DONE)

    def handler_add(
        self,
        event,
        handler,
        need_arg=False,
    ):
        """
        Add event handler for an event.
        If the event is ListboxVidget event, add the event handler to Eventor.
        If the event is not ListboxVidget event, add the event handler to
        listbox widget.

        Notice this method overrides `Eventor.handler_add` in order to add
        non-ListboxVidget event handler to listbox widget.

        @param event: Event name.

        @param handler: Event handler.

        @param need_arg: Whether the event handler needs event argument.

        @return: None.
        """
        # If the event is ListboxVidget event
        if event in self.EVENTS:
            # Add the event handler to Eventor
            return Eventor.handler_add(
                self,
                event=event,
                handler=handler,
                need_arg=need_arg,
            )

        # If the event is not ListboxVidget event,
        # it is assumed to be Tkinter widget event.
        else:
            # Add the event handler to listbox widget
            return self.bind(
                event=event,
                handler=handler,
            )

    def bind(
        self,
        event,
        handler,
    ):
        """
        Add event handler to listbox widget.

        ListboxVidget internally uses `<Button-1>` and `<Double-Button-1>` to
        capture active index changes. So if the given event is `<Button-1>` or
        `<Double-Button-1>`, the given handler will be wrapped.

        @param event: Event name.

        @param handler: Event handler.

        @return: None.
        """
        # If the event is not `<Button-1>` or `<Double-Button-1>`
        if event not in ['<Button-1>', '<Double-Button-1>']:
            # Add the event handler to listbox widget
            self._listbox.bind(event, handler)

        # If the event is `<Button-1>` or `<Double-Button-1>`
        else:
            # Create event handler wrapper
            def handler_wrapper(e):
                """
                Event handler wrapper that sets new active index and then calls
                the wrapped event handler.

                Setting new active index is needed because when this handler is
                called by Tkinter, the active index of the listbox is still
                old.

                @param e: Tkinter event object.

                @return: None.
                """
                # Set new active index
                self.indexcur_set_by_event(e, notify=True)

                # Call the wrapped event handler
                handler(e)

            # Add the event handler wrapper to the listbox widget
            self._listbox.bind(event, handler_wrapper)

    def _on_single_click(self, event):
        """
        `<Button-1>` event handler that updates active index.

        @param event: Tkinter event object.

        @return: None.
        """
        # Updates active index
        self.indexcur_set_by_event(event, notify=True)

    def _on_double_click(self, event):
        """
        `<Double-Button-1>` event handler that updates active index.

        @param event: Tkinter event object.

        @return: None.
        """
        # Updates active index
        self.indexcur_set_by_event(event, notify=True)

    def _listbox_widget_update(
        self,
        keep_active,
    ):
        """
        Update listbox widget's items and selection.

        @param keep_active: Whether keep or clear active index.

        @return: None.
        """
        # Remove old items from listbox widget
        self._listbox.delete(0, END)

        # Insert new items into listbox widget.
        # For each ListboxVidget items.
        for index, item in enumerate(self.items()):
            # Get item text
            item_text = self._item_to_text(item)

            # Insert the item text into listbox widget
            self._listbox.insert(index, item_text)

            # Set the item's normal background color
            self._listbox.itemconfig(index, background=self._normal_bg)

            # Set the item's normal foreground color
            self._listbox.itemconfig(index, foreground=self._normal_fg)

            # Set the item's selected background color
            self._listbox.itemconfig(index, selectbackground=self._selected_bg)

            # Set the item's selected foreground color
            self._listbox.itemconfig(index, selectforeground=self._selected_fg)

        # If keep active index
        if keep_active:
            # Use old active index
            indexcur = self._indexcur

        # If not keep active index
        else:
            # Set active index to -1
            indexcur = self._indexcur = -1

        # Clear old selection
        self._listbox.selection_clear(0, END)

        # Set new selection.
        # `-1` works.
        self._listbox.selection_set(indexcur)

        # Set new active index.
        # `-1` works.
        self._listbox.activate(indexcur)

        # If new active index is valid
        if indexcur != -1:
            # Set active background color
            self._listbox.itemconfig(indexcur, background=self._active_bg)

            # Set active foreground color
            self._listbox.itemconfig(indexcur, foreground=self._active_fg)

            # Make the active item visible
            self._listbox.see(indexcur)
Ejemplo n.º 12
0
class AutocompleteEntry(Entry):

    def __init__(self, *args, **kwargs):
        Entry.__init__(self, width=100, *args, **kwargs)

        self.focus_set()
        self.pack()

        self.var = self["textvariable"]
        if self.var == '':
            self.var = self["textvariable"] = StringVar()

        self.var.trace('w', self.changed)
        self.bind("<Right>", self.selection)
        self.bind("<Up>", self.up)
        self.bind("<Down>", self.down)
        self.bind("<Return>", self.enter)
        self.lb_up = False
        self.lb = None

    def enter(self, event):
        print(event)

    def changed(self, name, index, mode):

        if self.var.get() == '':
            if self.lb:
                self.lb.destroy()
            self.lb_up = False
        else:
            words = self.comparison()
            if words:
                if not self.lb_up:
                    self.lb = Listbox(master=root, width=100)

                    self.lb.bind("<Double-Button-1>", self.selection)
                    self.lb.bind("<Right>", self.selection)
                    self.lb.place(x=self.winfo_x(), y=self.winfo_y()+self.winfo_height())
                    self.lb_up = True

                self.lb.delete(0, END)
                for w in words:
                    self.lb.insert(END,w)
            else:
                if self.lb_up:
                    self.lb.destroy()
                    self.lb_up = False

    def selection(self, _):

        if self.lb_up:
            self.var.set(self.lb.get(ACTIVE))
            self.lb.destroy()
            self.lb_up = False
            self.icursor(END)

    def up(self, _):

        if self.lb_up:
            if self.lb.curselection() == ():
                index = '0'
            else:
                index = self.lb.curselection()[0]
            if index != '0':
                self.lb.selection_clear(first=index)
                index = str(int(index)-1)
                self.lb.selection_set(first=index)
                self.lb.activate(index)

    def down(self, _):

        if self.lb_up:
            if self.lb.curselection() == ():
                index = '0'
            else:
                index = self.lb.curselection()[0]
            if index != END:
                self.lb.selection_clear(first=index)
                index = str(int(index)+1)
                self.lb.selection_set(first=index)
                self.lb.activate(index)

    def comparison(self):
        q = self.var.get()
        q = str(q.decode('utf8'))
        for hit in searcher.search(qp.parse(q), limit=50):
            if hit['author']:
                yield '%s. "%s"' % (hit['author'], hit['title'])
            else:
                yield hit['title']
Ejemplo n.º 13
0
class Editor:

    # Info Defaults
    LOG_FILE = 'editor.log'

    devices = []
    vidPK = []
    vidPATH = []
    vidNAME = []
    uuid = []
    uuidFK = []

    def __init__(self, master, soundGenerator, rfidScanner):
        self.environment = Environment()
        self.soundProvider = SoundProvider(soundGenerator)
        self.configureScannerProvider(rfidScanner)
        self.load()
        frame = Frame(master)
        frame.pack()
        self.activeCardNumber = StringVar()
        self.usbSpin = StringVar()
        self.usbSpin.set(self.environment.Usb)
        Label(frame, text='RFID Card').grid(row=0, column=0)
        Label(frame, text='Video').grid(row=0, column=2)
        self.ee = Entry(frame, textvariable=self.activeCardNumber,
                        state=DISABLED, disabledforeground='black')
        self.ee.grid(row=1, column=0)
        self.r = Button(frame, text='Read Card', command=self.startCardProcess)
        self.r.grid(row=1, column=1)
        self.box = Listbox(frame)
        for entry in self.vidNAME:
            self.box.insert(END, entry)
        self.box.bind("<<ListboxSelect>>", self.newselection)
        self.box.grid(row=1, rowspan=5, column=2, columnspan=2)
        self.scroll = Scrollbar(self.box, orient=VERTICAL)
        self.box.config(yscrollcommand=self.scroll.set)
        self.scroll.config(command=self.box.yview)
        Button(frame, text='Assign Kill Code',
               command=self.createKiller).grid(row=2, column=0)
        Label(frame, text='Source USB').grid(row=4, column=0)
        self.spin = Spinbox(frame, values=self.devices)
        self.spin.delete(0, END)
        self.spin.insert(0, self.environment.Usb)
        self.spin.grid(row=5, column=0)
        self.status = Button(frame, text='Update Device Repository',
                             command=self.updateDevice, disabledforeground='blue')
        self.status.grid(row=6, column=0)
        Button(frame, text='Save', command=self.save).grid(row=6, column=2)
        Button(frame, text='Quit', command=self.closeWithSavePrompt).grid(
            row=6, column=3)
    
    def configureScannerProvider(self, rfidScanner):
        provider = RFIDScannerProvider(rfidScanner)
        self.RFIDScannerProvider = provider.PN532(
            int(self.environment.CHIP_SELECT_PIN),
            int(self.environment.MASTER_OUTPUT_SLAVE_INPUT_PIN),
            int(self.environment.MASTER_INPUT_SLAVE_OUTPUT_PIN),
            int(self.environment.SERIAL_CLOCK_PIN))

    def closeWithSavePrompt(self):
        ans = messagebox.askquestion(
            'Save And Quit', 'Would you like to save your changes?')
        if ans == 'yes':
            self.save()
        sys.exit(0)

    def startCardProcess(self):
        # Disable button to prevent event stacking
        self.r.config(state=DISABLED)
        self.processCard()
        self.r.config(state=NORMAL)

    def processCard(self):
        # Scans RFID cards and sets them to text box
        try:
            self.processCardUnchecked()
        except Exception as e:
            self.displayScanError(e)

    def processCardUnchecked(self):
        cardScan = CardScanWrapper(self.soundS, self.RFIDScannerProvider)
        cardScan.runScan()
        self.processResult(cardScan.getFormattedResult())

    def processResult(self, scanResult):
        if scanResult == None:
            return
        self.activeCardNumber.set(scanResult)     # Populate text box
        self.deselectActiveListboxItems()
        self.linkCardWithListbox(scanResult)

    def deselectActiveListboxItems(self):
        # De-select any active items in listbox
        self.box.selection_clear(0, END)

    def linkCardWithListbox(self, scanResult):
        index = self.verifyCard(scanResult)
        if str(self.uuidFK[index]) == self.environment.KillCommand:
            messagebox.showinfo(
                'Kill Card', 'This card is currently assigned to kill the application.')
            return
        self.highlightItemInListbox(index)

    def highlightItemInListbox(self, index):
        try:
            i = self.vidPK.index(self.uuidFK[index])
        except:
            messagebox.showinfo('Card Unassigned',
                                'Card is not currently assigned to a video')
        else:
            self.box.see(i)
            self.box.selection_clear(0, END)
            self.box.selection_set(i)
            self.box.activate(i)

    def verifyCard(self, uidt):
        try:
            uuidIndex = self.uuid.index(uidt)
        except:
            uuidIndex = self.addNewCard(uidt)
        return uuidIndex

    def addNewCard(self, uidt):
        self.uuid.append(uidt)
        self.uuidFK.append(-1)
        newIndex = len(self.uuid) - 1
        return newIndex

    def displayScanError(self, e):
        messagebox.showerror('Error Occurred', 'Error: ' + str(e))
        logging.error('Scan Failed: ' + str(e))

    def save(self):
        toSaveList = self.makePairedList(
            self.vidPK, self.vidNAME, self.vidPATH)
        self.safeSaveToFile(self.environment.VideoList, toSaveList)
        toSaveList = self.makePairedList(self.uuid, self.uuidFK)
        self.safeSaveToFile(self.environment.UuidTable, toSaveList)

    def makePairedList(self, *itemLists):
        stop = len(itemLists)
        subList = []
        listAll = []
        for listIndex in range(len(itemLists[0])):
            del subList[:]
            for indice in range(stop):
                subList.append(itemLists[indice][listIndex])
            listAll.append(list(subList))
        return listAll

    def safeSaveToFile(self, fileName, pairList):
        try:
            self.writePairedListToTempFile(fileName, pairList)
        except Exception as e:
            logging.error('Failed to create video list: ' + str(e))
        else:
            self.replaceOriginalFileWithItsTemp(fileName)

    def replaceOriginalFileWithItsTemp(self, fileName):
        try:
            if os.path.isfile(fileName):
                os.remove(fileName)
            os.rename(fileName + '.temp', fileName)
        except Exception as e:
            logging.error('Failed to replace old video list: ' + str(e))

    def writePairedListToTempFile(self, fileName, pairedList):
        f = open(fileName + '.temp', 'w')
        self.writePairedListGivenFile(f, pairedList)
        f.close()

    def writePairedListGivenFile(self, f, pairedList):
        i = 0
        while(i < len(pairedList) - 1):
            self.writeSingleLineOfPairedListToOpenFile(f, pairedList, i)
            f.write('\n')
            i = i+1
        self.writeSingleLineOfPairedListToOpenFile(f, pairedList, i)

    def writeSingleLineOfPairedListToOpenFile(self, f, pairedList, itemIndex):
        fLine = ""
        for item in range(len(pairedList[itemIndex])):
            fLine = fLine + str(pairedList[itemIndex][item]) + ','
        f.write(fLine[:-1])

    def updateDevice(self):
        scan = self.safeScan()
        if scan != None:
            self.safeProcessScan(scan)
        self.status.config(text='Update Device Repository', state=NORMAL)
        self.status.update_idletasks()

    def safeScan(self):
        scan = None
        try:
            scan = self.runScannerWithNotification()
        except Exception as e:
            self.showScanErrorMessage(e)
        return scan

    def runScannerWithNotification(self):
        self.status.config(text='Scanning...', state=DISABLED)
        self.status.update_idletasks()
        scan = ScriptedFileSearch(subprocess)
        scan.scan("scanner.sh")
        return scan

    def showScanErrorMessage(self, e):
        messagebox.showerror('Scan Failed', 'Scan error: ' + str(e))
        logging.error(str(e))

    def safeProcessScan(self, scan):
        try:
            self.processScan(scan)
        except Exception as e:
            self.showErrorMessage(e)

    def showErrorMessage(self, e):
        messagebox.showerror('Error', 'Error: ' + str(e))
        logging.error(str(e))

    def refreshListBox(self):
        self.box.delete(0, END)
        for entry in self.vidNAME:
            self.box.insert(END, entry)

    def processScan(self, scan):
        # Check if a scan turned up any results
        if self.scanIsEmpty(scan):
            self.showAbortScanMessage()
            return
        self.verifyUSB()
        self.processScanFiles(scan)
        self.refreshListBox()

    def showAbortScanMessage(self):
        messagebox.showwarning(
            'No Files Found', 'A scan failed to find any files.')
        logging.warning('Empty Scan occurred when attempting a merge')

    def scanIsEmpty(self, scan):
        return len(scan.NAME) == 0

    def verifyUSB(self):
        if self.environment.Usb != self.spin.get():
            self.Usb = self.spin.get()
            self.environment.update()

    def processScanFiles(self, scan):
        i = 0
        j = 0
        newPK = []
        newName = []
        newPath = []
        self.status.config(text='Reading Files...')
        self.status.update_idletasks()
        # Iterate through list
        while i < len(scan.NAME):
            # Verifiy File
            try:
                if scan.PATH[i].find(self.environment.Usb) >= 0:
                    # File resides on repository - update FK
                    try:
                        # Locate matching entry
                        fkk = self.vidNAME.index(scan.NAME[i])
                    except Exception as e:
                        # No matching entry
                        logging.info('New file found in repository: ' + str(e))
                        pass
                    else:
                        # Update FK on uuid table
                        for uu in self.uuidFK:
                            if uu == self.vidPK[fkk]:
                                uu = scan.PK[i]
                    # Store entry in new Tables
                    newPK.append(scan.PK[i])
                    newName.append(scan.NAME[i])
                    newPath.append(scan.PATH[i])
                else:
                    # Video resides on updating device - check if file already copied
                    found = False
                    while j < len(scan.NAME):
                        if str(scan.NAME[i]) == str(scan.NAME[j]) and scan.PATH[j].find(self.environment.Usb) >= 0:
                            found = True
                            break
                        j = j + 1
                    if not found:
                        # Copy file and append
                        try:
                            # Get device name
                            device = scan.PATH[i].replace('/media/pi/', '')
                            device = device[0:device.find('/')]
                            # Copy
                            self.status.config(
                                text='Copying ' + scan.NAME[i] + '...')
                            self.status.update_idletasks()
                            shutil.copyfile(
                                scan.PATH[i], scan.PATH[i].replace(device, self.environment.Usb))
                        except Exception as e:
                            logging.error('Failed to copy' +
                                          scan.NAME[i] + ': ' + str(e))
                        else:
                            # Add to new array
                            newPK.append(scan.PK[i])
                            newName.append(scan.NAME[i])
                            newPath.append(
                                scan.PATH[i].replace(device, self.environment.Usb))
            except Exception as e:
                logging.error(str(e))
            i = i+1
        del self.vidNAME[:]
        del self.vidPATH[:]
        del self.vidPK[:]
        self.vidNAME = newName
        self.vidPATH = newPath
        self.vidPK = newPK

    def newselection(self, event):
        # Fires when a new item is selected in the listbox
        selection = event.widget.curselection()
        try:
            txt = self.ee.get()
            if txt == '':
                return
            i = self.uuid.index(txt)
            self.uuidFK[i] = self.vidPK[selection[0]]
        except Exception as e:
            messagebox.showerror('Error During Set', 'Error: ' + str(e))
            logging.error(str(e))

    def createKiller(self):
        try:
            self.assignCurrentCardAsKiller()
            self.box.selection_clear(0, END)
        except Exception as e:
            self.handleCardNotScannedError(e)

    def assignCurrentCardAsKiller(self):
        i = self.uuid.index(self.ee.get())
        self.uuidFK[i] = int(self.environment.KillCommand)

    def handleCardNotScannedError(self, e):
        messagebox.showinfo(
            'Card Not Scanned', 'Please scan a card to assign it a [Kill Application] code.' + str(e))
        logging.error(str(e))

    def load(self):
        # Generate Log
        logging.basicConfig(filename=self.LOG_FILE, level=logging.INFO)
        # Load Sound file
        self.soundProvider.init()
        self.soundProvider.mixer.pre_init(44100, -16, 12, 512)
        # pygame.init() IS this only for linux distribution?
        self.soundS = self.soundProvider.mixer.Sound(self.environment.SCAN_SOUND)
        self.soundS.set_volume(1)
        # Create an instance of the PN532 class.
        self.RFIDScannerProvider.begin())
        # Configure PN532 to communicate with MiFare cards.
        self.RFIDScannerProvider.SAM_configuration()
        self.loadFiles()
        self.locateDevices()
        self.loadDevice()

    def loadFiles(self):
        self.readCSV(self.environment.VideoList, (int, self.vidPK),
                     (str, self.vidNAME), (str, self.vidPATH))
        self.readCSV(self.environment.UuidTable,
                     (str, self.uuid), (int, self.uuidFK))
Ejemplo n.º 14
0
class Combobox_Autocomplete(Entry, object):
    def __init__(self, master, list_of_items=None, autocomplete_function=None,
                 listbox_width=None, listbox_height=7, ignorecase_match=False,
                 startswith_match=True, vscrollbar=True, hscrollbar=True, **kwargs):
        if hasattr(self, "autocomplete_function"):
            if autocomplete_function is not None:
                raise ValueError(
                    "Combobox_Autocomplete subclass has 'autocomplete_function' implemented")
        else:
            if autocomplete_function is not None:
                self.autocomplete_function = autocomplete_function
            else:
                if list_of_items is None:
                    raise ValueError(
                        "If not given complete function, list_of_items can't be 'None'")
                elif ignorecase_match:
                    if startswith_match:
                        def matches_function(entry_data, item):
                            return item.startswith(entry_data)
                    else:
                        def matches_function(entry_data, item):
                            return item in entry_data
                    self.autocomplete_function = lambda entry_data: [
                        item for item in self.list_of_items if matches_function(entry_data, item)]
                else:
                    if startswith_match:
                        def matches_function(escaped_entry_data, item):
                            if re.match(escaped_entry_data, item, re.IGNORECASE):
                                return True
                            else:
                                return False
                    else:
                        def matches_function(escaped_entry_data, item):
                            if re.search(escaped_entry_data, item, re.IGNORECASE):
                                return True
                            else:
                                return False
                    def autocomplete_function2(entry_data):
                        escaped_entry_data = re.escape(entry_data)
                        return [item for item in self.list_of_items if matches_function(escaped_entry_data, item)]
                    self.autocomplete_function = autocomplete_function2
        self._listbox_height = int(listbox_height)
        self._listbox_width = listbox_width
        self.list_of_items = list_of_items
        self._use_vscrollbar = vscrollbar
        self._use_hscrollbar = hscrollbar
        kwargs.setdefault("background", "white")
        if "textvariable" in kwargs:
            self._entry_var = kwargs["textvariable"]
        else:
            self._entry_var = kwargs["textvariable"] = StringVar()
        Entry.__init__(self, master, **kwargs)
        self._trace_id = self._entry_var.trace('w', self._on_change_entry_var)
        self._listbox = None
        self.bind("<Tab>", self._on_tab)
        self.bind("<Up>", self._previous)
        self.bind("<Down>", self._next)
        self.bind('<Control-n>', self._next)
        self.bind('<Control-p>', self._previous)
        self.bind("<Return>", self._update_entry_from_listbox)
        self.bind("<Escape>", lambda event: self.unpost_listbox())
    def _on_tab(self, event):
        self.post_listbox()
        return "break"
    def _on_change_entry_var(self, name, index, mode):
        entry_data = self._entry_var.get()
        if entry_data == '':
            self.unpost_listbox()
            self.focus()
        else:
            values = self.autocomplete_function(entry_data)
            if values:
                if self._listbox is None:
                    self._build_listbox(values)
                else:
                    self._listbox.delete(0, END)
                    height = min(self._listbox_height, len(values))
                    self._listbox.configure(height=height)
                    for item in values:
                        self._listbox.insert(END, item)
            else:
                self.unpost_listbox()
                self.focus()
    def _build_listbox(self, values):
        listbox_frame = Frame()
        self._listbox = Listbox(listbox_frame, background="white",
                                selectmode=SINGLE, activestyle="none",
                                exportselection=False)
        self._listbox.grid(row=0, column=0, sticky=N+E+W+S)
        self._listbox.bind("<ButtonRelease-1>",
                           self._update_entry_from_listbox)
        self._listbox.bind("<Return>", self._update_entry_from_listbox)
        self._listbox.bind("<Escape>", lambda event: self.unpost_listbox())
        self._listbox.bind('<Control-n>', self._next)
        self._listbox.bind('<Control-p>', self._previous)
        if self._use_vscrollbar:
            vbar = Scrollbar(listbox_frame, orient=VERTICAL,
                             command=self._listbox.yview)
            vbar.grid(row=0, column=1, sticky=N+S)
            self._listbox.configure(
                yscrollcommand=lambda f, l: autoscroll(vbar, f, l))
        elif self._use_hscrollbar:
            hbar = Scrollbar(listbox_frame, orient=HORIZONTAL,
                             command=self._listbox.xview)
            hbar.grid(row=1, column=0, sticky=E+W)
            self._listbox.configure(
                xscrollcommand=lambda f, l: autoscroll(hbar, f, l))
            listbox_frame.grid_columnconfigure(0, weight=1)
            listbox_frame.grid_rowconfigure(0, weight=1)
            x = -self.cget("borderwidth") - self.cget("highlightthickness")
            y = self.winfo_height()-self.cget("borderwidth") - \
            self.cget("highlightthickness")
        elif self._listbox_width:
            width = self._listbox_width
        else:
            width = self.winfo_width()
        listbox_frame.place(in_=self, x=x, y=y, width=width)
        height = min(self._listbox_height, len(values))
        self._listbox.configure(height=height)
        for item in values:
            self._listbox.insert(END, item)
    def post_listbox(self):
        if self._listbox is not None:
            return
        entry_data = self._entry_var.get()
        if entry_data == '':
            return
        values = self.autocomplete_function(entry_data)
        if values:
            self._build_listbox(values)
    def unpost_listbox(self):
        if self._listbox is not None:
            self._listbox.master.destroy()
            self._listbox = None
    def get_value(self):
        return self._entry_var.get()
    def set_value(self, text, close_dialog=False):
        self._set_var(text)
        if close_dialog:
            self.unpost_listbox()
        self.icursor(END)
        self.xview_moveto(1.0)
    def _set_var(self, text):
        self._entry_var.trace_vdelete("w", self._trace_id)
        self._entry_var.set(text)
        self._trace_id = self._entry_var.trace('w', self._on_change_entry_var)
    def _update_entry_from_listbox(self, event):
        if self._listbox is not None:
            current_selection = self._listbox.curselection()
            if current_selection:
                text = self._listbox.get(current_selection)
                self._set_var(text)
            self._listbox.master.destroy()
            self._listbox = None
            self.focus()
            self.icursor(END)
            self.xview_moveto(1.0)
        return "break"
    def _previous(self, event):
        if self._listbox is not None:
            current_selection = self._listbox.curselection()
            if len(current_selection) == 0:
                self._listbox.selection_set(0)
                self._listbox.activate(0)
            else:
                index = int(current_selection[0])
                self._listbox.selection_clear(index)
                if index == 0:
                    index = END
                else:
                    index -= 1
                self._listbox.see(index)
                self._listbox.selection_set(first=index)
                self._listbox.activate(index)
        return "break"
    def _next(self, event):
        if self._listbox is not None:
            current_selection = self._listbox.curselection()
            if len(current_selection) == 0:
                self._listbox.selection_set(0)
                self._listbox.activate(0)
            else:
                index = int(current_selection[0])
                self._listbox.selection_clear(index)
                if index == self._listbox.size() - 1:
                    index = 0
                else:
                    index += 1
                self._listbox.see(index)
                self._listbox.selection_set(index)
                self._listbox.activate(index)
        return "break"
Ejemplo n.º 15
0
class Window:
    FONT = ('Monospace', 11)
    ITEM_HEIGHT = 22
    MAX_FOUND = 10
    BG_COLOR = '#202b3a'
    FG_COLOR = '#ced0db'

    def resize(self, items):
        if self.resized:
            return

        self.root.geometry('{0}x{1}'.format(
            self.width, self.height + items * Window.ITEM_HEIGHT))
        self.resized = True

    def __init__(self, root, width, height):
        self.root = root
        self.width = width
        self.height = height
        self.all_windows = []
        self.resized = False

        # master.geometry(500)
        root.title("window switcher")
        root.resizable(width=False, height=False)
        root.configure(background=Window.BG_COLOR)

        # ugly tkinter code below
        sv = StringVar()
        sv.trace("w", lambda name, index, mode, sv=sv: self.on_entry(sv))

        self.main_entry = Entry(root,
                                font=Window.FONT,
                                width=1000,
                                textvariable=sv,
                                bg=Window.BG_COLOR,
                                fg=Window.FG_COLOR,
                                insertbackground=Window.FG_COLOR,
                                bd=0)
        self.main_entry.grid(row=0, column=0, padx=10)
        self.main_entry.focus_set()

        self.listbox = Listbox(root,
                               height=Window.ITEM_HEIGHT,
                               font=Window.FONT,
                               highlightthickness=0,
                               borderwidth=0,
                               bg=Window.BG_COLOR,
                               fg=Window.FG_COLOR,
                               selectbackground='#2c3c51',
                               selectforeground='#cedaed')
        self.listbox.grid(row=1, column=0, sticky='we', padx=10, pady=10)

        # key bindings
        self.main_entry.bind('<Control-a>', self.select_all)
        self.main_entry.bind('<Up>', self.select_prev)
        self.main_entry.bind('<Down>', self.select_next)
        self.main_entry.bind('<Return>', self.select_window)
        self.root.bind('<Escape>', lambda e: sys.exit())

        # self.resize(Window.MAX_FOUND)
        self.initial_get(None)

    def initial_get(self, event):
        self.all_windows = get_windows()
        self.find_windows('')

    def select_all(self, event):
        # select text
        self.main_entry.select_clear()
        self.main_entry.select_range(0, 'end')
        # move cursor to the end
        self.main_entry.icursor('end')

        return 'break'

    def find_windows(self, text):
        text = text.lower()

        found = [
            window for window in self.all_windows
            if window['name'].find(text) != -1
        ]
        # print(found)

        self.found = found

        self.listbox.delete(0, 'end')

        for i, item in enumerate(found):
            if i >= Window.MAX_FOUND:
                break
            self.listbox.insert('end', item['name'])

        self.resize(min(len(found), Window.MAX_FOUND))

        # select first element
        self.listbox.selection_set(0)

    def select_next(self, event):
        if len(self.found) == 0:
            return

        idx = self.listbox.curselection()[0]
        max = self.listbox.size()
        idx += 1
        if idx >= max:
            idx = 0

        self.listbox.selection_clear(0, 'end')
        self.listbox.selection_set(idx)

    def select_prev(self, event):
        if len(self.found) == 0:
            return

        idx = self.listbox.curselection()[0]
        max = self.listbox.size()
        idx -= 1
        if idx < 0:
            idx = max - 1

        self.listbox.selection_clear(0, 'end')
        self.listbox.selection_set(idx)

    def select_window(self, event):
        idx = self.listbox.curselection()[0]
        id = self.found[idx]['id']

        # switch to window and exit
        # wmctrl -ia <id`>
        subprocess.call(['wmctrl', '-ia', id])
        # print(subprocess.check_output(['wmctrl', '-ia', id]).decode('utf-8'))

        sys.exit(0)

    def on_entry(self, newtext):
        search_test = newtext.get()
        self.find_windows(search_test)
        return True
Ejemplo n.º 16
0
class AutocompleteEntry(Entry):
    def __init__(self, autocompleteList, *args, **kwargs):

        # Listbox length
        if 'listboxLength' in kwargs:
            self.listboxLength = kwargs['listboxLength']
            del kwargs['listboxLength']
        else:
            self.listboxLength = 8

        # Custom matches function
        if 'matchesFunction' in kwargs:
            self.matchesFunction = kwargs['matchesFunction']
            del kwargs['matchesFunction']
        else:

            def matches(fieldValue, acListEntry):
                pattern = re.compile('.*' + re.escape(fieldValue) + '.*',
                                     re.IGNORECASE)
                return re.match(pattern, acListEntry)

            self.matchesFunction = matches

        Entry.__init__(self, *args, **kwargs)
        self.focus()

        self.autocompleteList = autocompleteList

        self.var = self["textvariable"]
        if self.var == '':
            self.var = self["textvariable"] = StringVar()

        self.var.trace('w', self.changed)
        self.bind("<Right>", self.selection)
        self.bind("<Up>", self.moveUp)
        self.bind("<Down>", self.moveDown)

        self.listboxUp = False

    def changed(self, name, index, mode):
        if self.var.get() == '':
            if self.listboxUp:
                self.listbox.destroy()
                self.listboxUp = False
        else:
            words = self.comparison()
            if words:
                if not self.listboxUp:
                    self.listbox = Listbox(width=self["width"],
                                           height=self.listboxLength)
                    self.listbox.bind("<Button-1>", self.selection)
                    self.listbox.bind("<Right>", self.selection)
                    self.listbox.place(x=self.winfo_x(),
                                       y=self.winfo_y() + self.winfo_height())
                    self.listboxUp = True

                self.listbox.delete(0, END)
                for w in words:
                    self.listbox.insert(END, w)
            else:
                if self.listboxUp:
                    self.listbox.destroy()
                    self.listboxUp = False

    def selection(self, event):
        if self.listboxUp:
            self.var.set(self.listbox.get(ACTIVE))
            self.listbox.destroy()
            self.listboxUp = False
            self.icursor(END)

    def moveUp(self, event):
        if self.listboxUp:
            if self.listbox.curselection() == ():
                index = '0'
            else:
                index = self.listbox.curselection()[0]

            if index != '0':
                self.listbox.selection_clear(first=index)
                index = str(int(index) - 1)

                self.listbox.see(index)  # Scroll!
                self.listbox.selection_set(first=index)
                self.listbox.activate(index)

    def moveDown(self, event):
        if self.listboxUp:
            if self.listbox.curselection() == ():
                index = '0'
            else:
                index = self.listbox.curselection()[0]

            if index != END:
                self.listbox.selection_clear(first=index)
                index = str(int(index) + 1)

                self.listbox.see(index)  # Scroll!
                self.listbox.selection_set(first=index)
                self.listbox.activate(index)

    def comparison(self):
        return [
            w for w in self.autocompleteList
            if self.matchesFunction(self.var.get(), w)
        ]
Ejemplo n.º 17
0
class Application(Frame):
    """Container class, encapsulates app"""

    # this class inherits from Tkinter.parent
    def __init__(self, path, master=None):
        """Constructor"""
        # call parent class constructor
        Frame.__init__(self, master)

        self.path = path
        self.image_filenames = find_image_files(path)

        # necessary to make the application actually appear on the screen
        self.grid(sticky=N + S + E + W)

        # PIL image, for loading from file and for resizing
        self.image_pil = None

        # Tk photoimage, for display
        self.image_tk = None

        # list of coords (2-element lists) of current selection's pts
        self.points_orig = []

        # points_canvas is 'points_orig', in canvas coordinates
        self.points_canvas = []

        # x- and y-coords of displayed image in canvas coordinate frame
        self.x_offset = -1
        self.y_offset = -1

        # font in listbox text
        self.font = Font(family='Helvetica', size=10, weight='normal')

        # crosshair line size , as fraction of
        # min(displayed-imagewidth, displayed-image-height)
        self.crosshair_fraction = 0.05

        # color for drawing first crosshair - the origin
        self.crosshair1_color = 'red'

        # color for drawing second crosshair - (together with the first
        # crosshair, these two points define a coordinate frame) -
        self.crosshair2_color = 'green'

        # color for drawing third and on crosshairs - all points other
        # than the first and second, have this color
        self.crosshair3_color = 'cyan'

        # the width, in pixels, of crosshairs
        self.crosshair_thickness = 2

        # length of crosshair (updated upon display)
        self.crosshair_radius = -1

        # the scale of currently displayed image (updated upon display)
        self.image_scaling = 1.0

        # create all widges and set their initial conditions
        self.create_widgets()

    def create_widgets(self):
        """Set up all application graphics"""
        # get the top level winddow
        top = self.winfo_toplevel()

        # set the title of the top level window
        top.title('Image Point Tagging Tool')

        # make row 0 of the top level window's grid stretchable
        top.rowconfigure(0, weight=1)

        # make column 0 of the top level window's grid stretchable
        top.columnconfigure(0, weight=1)

        # bind keys for entire app
        top.bind_all('<Up>', self.select_prev)
        top.bind_all('<Down>', self.select_next)

        # make row 0 of Application's widget's grid stretchable
        self.rowconfigure(0, weight=1)

        # make column 0 of Application's widget's grid stretchable
        self.columnconfigure(0, weight=1)

        self.canvas = Canvas(self, bg='gray')
        self.canvas.grid(row=0, column=0, rowspan=2, sticky=N + S + E + W)
        self.canvas.rowconfigure(0, weight=1)
        self.canvas.columnconfigure(0, weight=1)

        # bind resize events (need -4 here bec. event gives 4+(real_size))
        self.canvas.bind(
            '<Configure>',
            lambda e, s=self: s.on_resize_canvas(e.width - 2, e.height - 2))

        # bind canvas mouse clicks
        self.canvas.bind('<Button-1>', self.on_click_button1)
        self.canvas.bind('<Button-3>', self.on_click_button3)

        # create scrollbars
        self.scrollbar_x = Scrollbar(self, orient=HORIZONTAL, width=10)
        self.scrollbar_y = Scrollbar(self, orient=VERTICAL, width=10)

        self.scrollbar_x.grid(row=1, column=1, columnspan=2, sticky=E + W)
        self.scrollbar_y.grid(row=0, column=3, sticky=N + S)

        # create lb for showing labeled/not-labeled images
        self.listbox_marks = Listbox(self,
                                     width=1,
                                     takefocus=0,
                                     exportselection=0,
                                     font=self.font)

        self.listbox_marks.grid(row=0, column=1, sticky=N + S + E + W)

        # create lb for showing image filenames
        self.lisbox_filenames = Listbox(self,
                                        width=30,
                                        selectmode=SINGLE,
                                        xscrollcommand=self.scrollbar_x.set,
                                        yscrollcommand=self.scrollbar_y.set,
                                        exportselection=0,
                                        font=self.font)
        self.lisbox_filenames.grid(row=0, column=2, sticky=N + S + E + W)

        # bind scrollbar movement
        self.scrollbar_x['command'] = self.lisbox_filenames.xview
        self.scrollbar_y['command'] = self.on_scrollbar_y

        # bind left mouse click selection
        self.lisbox_filenames.bind(
            '<Button-1>',
            lambda e, s=self: s.select(self.lisbox_filenames.nearest(e.y)))
        self.listbox_marks.bind(
            '<Button-1>',
            lambda e, s=self: s.select(self.lisbox_filenames.nearest(e.y)))

        # bind wheel scroll
        self.lisbox_filenames.bind(
            '<Button-4>',
            lambda e, s=self: on_mousewheel(self.listbox_marks, 4))
        self.lisbox_filenames.bind(
            '<Button-5>',
            lambda e, s=self: on_mousewheel(self.listbox_marks, 5))
        self.listbox_marks.bind(
            '<Button-4>',
            lambda e, s=self: on_mousewheel(self.lisbox_filenames, 4))
        self.listbox_marks.bind(
            '<Button-5>',
            lambda e, s=self: on_mousewheel(self.lisbox_filenames, 5))

        # skip is # of chars to skip in path string so that only the
        # part of the path that was not supplied is displayed
        skip = len(self.path)
        if self.path[skip - 1] != '/':
            skip += 1

        # insert image filenames plus marks into lists and
        # select first image that does not have pts file
        i = 0
        index_of_image_with_no_pts_file = -1
        for image_filename in self.image_filenames:
            self.lisbox_filenames.insert(END, image_filename[skip:])
            if self.has_pts_file(i):
                self.listbox_marks.insert(END, '+')
            else:
                self.listbox_marks.insert(END, '')
                if index_of_image_with_no_pts_file < 0:
                    index_of_image_with_no_pts_file = i
            i += 1

        if index_of_image_with_no_pts_file < 0:
            self.select(0)
        else:
            self.select(index_of_image_with_no_pts_file)

    def on_scrollbar_y(self, *args):
        """Vertical scrollbar motion callback"""
        apply(self.lisbox_filenames.yview, args)
        apply(self.listbox_marks.yview, args)

    def on_click_button1(self, event):
        """Button 1 click callback: adds a crosshair at click location"""
        if self.coord_in_img(event.x, event.y):
            point = [(event.x - self.x_offset) / self.image_scaling,
                     (event.y - self.y_offset) / self.image_scaling]
            point_scaled = [float(event.x), float(event.y)]
            self.points_orig.append(point)
            self.points_canvas.append(point_scaled)
            if len(self.points_orig) == 1:
                self.mark_labeled()
            self.on_resize_canvas(int(self.canvas['width']),
                                  int(self.canvas['height']))
            self.save_points()

    def on_click_button3(self, event):
        """Button 3 click callback: deletes landmark near click location"""
        if not self.coord_in_img(event.x, event.y):
            return
        i = self.find_point_near_crosshair(event.x, event.y)
        if i >= 0:
            del self.points_orig[i]
            del self.points_canvas[i]
            if len(self.points_orig) == 0:
                self.mark_unlabeled()
            self.on_resize_canvas(int(self.canvas['width']),
                                  int(self.canvas['height']))
            self.save_points()

    def select(self, i):
        """Select the i'th image to work with - make current selection = i"""
        # uncomment the following line if you are only dealing with
        # faces that have three points labeled on them and you want to
        # automatically reorder a previously tagged database so that
        # the person's right eye is the first point, left eye is
        # second point and mouth is third point
        self.sort_points()
        self.lisbox_filenames.selection_clear(0, END)
        self.listbox_marks.selection_clear(0, END)
        self.lisbox_filenames.selection_set(i)
        self.listbox_marks.selection_set(i)
        self.lisbox_filenames.see(i)
        self.listbox_marks.see(i)
        self.image_pil = PIL.Image.open(self.get_image_filename())
        self.points_orig = self.read_pts_file()
        self.on_resize_canvas(int(self.canvas['width']),
                              int(self.canvas['height']))

    def select_prev(self, *args):
        #pylint: disable=unused-argument
        """Select entry that comes before current selection"""
        i = self.get_selected_index()
        if i > 0:
            self.select(i - 1)

    def select_next(self, *args):
        #pylint: disable=unused-argument
        """Select entry that comes after current selection"""
        i = self.get_selected_index()
        if i < len(self.image_filenames) - 1:
            self.select(i + 1)

    def on_resize_canvas(self, width, height):
        """Called when canvas is resized"""
        if width <= 0 or height <= 0:
            return
        # maximize image width or height depending on aspect ratios
        image_width = self.image_pil.size[0]
        image_height = self.image_pil.size[1]
        image_aspect_ratio = float(image_width) / float(image_height)

        self.canvas['width'] = width
        self.canvas['height'] = height
        canvas_width = int(self.canvas['width'])
        canvas_height = int(self.canvas['height'])
        canvas_aspect_ratio = float(canvas_width) / float(canvas_height)

        if image_aspect_ratio < canvas_aspect_ratio:
            new_image_width = int(image_aspect_ratio * float(canvas_height))
            new_image_height = canvas_height
        else:
            new_image_width = canvas_width
            new_image_height = int(float(canvas_width) / image_aspect_ratio)

        self.image_tk = PhotoImage(
            self.image_pil.resize((new_image_width, new_image_height),
                                  PIL.Image.BILINEAR))

        self.x_offset = 0.5 * (float(canvas_width) - float(new_image_width))
        self.y_offset = 0.5 * (float(canvas_height) - float(new_image_height))

        self.crosshair_radius = 0.5 * self.crosshair_fraction * float(
            min(new_image_width, new_image_height))

        self.canvas.delete('image')
        self.canvas.create_image(self.x_offset,
                                 self.y_offset,
                                 anchor=NW,
                                 image=self.image_tk,
                                 tags='image')

        width_scale = float(new_image_width) / float(image_width)
        height_scale = float(new_image_height) / float(image_height)
        self.image_scaling = 0.5 * (width_scale + height_scale)
        self.points_canvas = [[
            x[0] * self.image_scaling + self.x_offset,
            x[1] * self.image_scaling + self.y_offset
        ] for x in self.points_orig]
        self.redraw_points()

    def redraw_points(self):
        """redraw points in current entry's .pts file"""
        self.canvas.delete('line')

        # draw first crosshair in color1
        if len(self.points_canvas) > 0:
            point1 = self.points_canvas[0]
            self.draw_crosshair(point1[0], point1[1], self.crosshair1_color)

        # draw second crosshair in color2
        if len(self.points_canvas) > 1:
            point2 = self.points_canvas[1]
            self.draw_crosshair(point2[0], point2[1], self.crosshair2_color)

        # draw third or higher crosshair in color3
        if len(self.points_canvas) > 2:
            for point in self.points_canvas[2:]:
                self.draw_crosshair(point[0], point[1], self.crosshair3_color)

    def draw_crosshair(self, x_coord, y_coord, fill_color):
        """Draw a cross at (x_coord, y_coord) in the currently selected image"""
        start_x = x_coord - self.crosshair_radius
        start_y = y_coord - self.crosshair_radius

        end_x = x_coord + self.crosshair_radius
        end_y = y_coord + self.crosshair_radius

        min_x = self.x_offset
        min_y = self.y_offset

        max_x = self.x_offset + self.image_tk.width() - 1
        max_y = self.y_offset + self.image_tk.height() - 1

        if start_x < min_x:
            start_x = min_x
        if start_y < min_y:
            start_y = min_y

        if end_x > max_x:
            end_x = max_x
        if end_y > max_y:
            end_y = max_y

        self.canvas.create_line(x_coord,
                                start_y,
                                x_coord,
                                end_y,
                                width=self.crosshair_thickness,
                                tags='line',
                                fill=fill_color)
        self.canvas.create_line(start_x,
                                y_coord,
                                end_x,
                                y_coord,
                                width=self.crosshair_thickness,
                                tags='line',
                                fill=fill_color)

    def get_selected_index(self):
        """Returns index of current selection"""
        return int(self.lisbox_filenames.curselection()[0])

    def coord_in_img(self, x_coord, y_coord):
        """Returns whether (x_coord, y_coord) is inside the shown image"""
        return (x_coord >= self.x_offset and y_coord >= self.y_offset
                and x_coord < self.x_offset + self.image_tk.width()
                and y_coord < self.y_offset + self.image_tk.height())

    def find_point_near_crosshair(self, x_coord, y_coord):
        """Returns index of landmark point near (x_coord, y_coord), or -1"""
        i = 0
        i_min = -1
        min_dist = self.image_tk.width() + self.image_tk.height()
        for pair in self.points_canvas:
            x_dist = x_coord - pair[0]
            y_dist = y_coord - pair[1]
            dist = sqrt(x_dist * x_dist + y_dist * y_dist)
            if dist <= self.crosshair_radius and dist < min_dist:
                i_min = i
            i += 1
        return i_min

    def save_points(self):
        """Save current points to pts file"""
        # remove whatever was there before
        if self.has_pts_file():
            os.remove(self.get_pts_filename())
        # save current result
        if len(self.points_orig) > 0:
            filehandle = open(self.get_pts_filename(), 'w')
            for pair in self.points_orig:
                message = str(pair[0]) + ', ' + str(pair[1]) + '\n'
                filehandle.write(message)
            filehandle.close()

    def sort_points(self):
        """
        Reorder points, assuming face labeling, so that the first point
        is always the person's right eye, the second point is the person's
        left eye and the third point is the mouth.  NB: this function only
        (destructively) works on self.points_orig
        """
        if len(self.points_orig) != 3:
            return
        # step 1 sort the points according to y-value
        self.points_orig.sort(key=lambda pt: pt[1])
        # step 2: from the top-most two points, call the leftmost one
        # the person's right eye and call the other the person's left eye
        if self.points_orig[0][0] > self.points_orig[1][0]:
            # swap first and second points' x-coordinate
            tmp = self.points_orig[0][0]
            self.points_orig[0][0] = self.points_orig[1][0]
            self.points_orig[1][0] = tmp
            # swap first and second points' y-coordinate
            tmp = self.points_orig[0][1]
            self.points_orig[0][1] = self.points_orig[1][1]
            self.points_orig[1][1] = tmp
            # order changed, so re-save
            self.save_points()

    def has_pts_file(self, i=None):
        """Returns whether (i'th) selection has a pts file with landmarks"""
        if i is None:
            i = self.get_selected_index()
        return os.path.exists(self.get_pts_filename(i))

    def get_pts_filename(self, i=None):
        """Returns filename of selected (or i'th) .pts file"""
        if i is None:
            i = self.get_selected_index()
        image_filename = self.image_filenames[i]
        return os.path.splitext(image_filename)[0] + '.pts'

    def get_image_filename(self, i=None):
        """Returns filename of (i'th) selection's image"""
        if i is None:
            i = self.get_selected_index()
        return self.image_filenames[i]

    def read_pts_file(self, i=None):
        """Returns list of points (lists) in (i'th) selection's .pts file"""
        if i is None:
            i = self.get_selected_index()
        if self.has_pts_file(i):
            filehandle = open(self.get_pts_filename(i), 'r')
            lines = filehandle.readlines()
            filehandle.close()
            return [[float(pair[0]), float(pair[1])]
                    for pair in [line.split(',') for line in lines]]
        else:
            return []

    def mark_labeled(self, i=None):
        """Mark (i'th) selection as having a .pts file"""
        if i is None:
            i = self.get_selected_index()
        self.listbox_marks.insert(i, '+')
        self.listbox_marks.delete(i + 1)
        self.listbox_marks.selection_set(i)

    def mark_unlabeled(self, i=None):
        """Unmark (i'th) selection as having a .pts file"""
        if i is None:
            i = self.get_selected_index()
        self.listbox_marks.insert(i, '')
        self.listbox_marks.delete(i + 1)
        self.listbox_marks.selection_set(i)
Ejemplo n.º 18
0
class TagWindow:
    def __init__(self, parent):
        self.window = Toplevel(parent.window)
        self.window.withdraw()
        self.parent = parent
        self.tags = deepcopy(parent.tags)
        self.activeFrame = Frame(self.window)
        self.upDownButtonFrame = Frame(self.window)
        self.inactiveFrame = Frame(self.window)
        self.okCancelFrame = Frame(self.window)

        self.selectedActive = None
        self.selectedInactive = None

        self.activeListbox = None
        self.inactiveListbox = None

        WindowHelper.initializeWindow(self.window, self.parent, 460, 514, 30, 50, LabelConstants.TAG_WINDOW)
        self.gridFrames()
        self.addActiveListbox()
        self.addMoveButtons()
        self.addInactiveListbox()
        self.addOkCancelButtons()
        self.populateListboxes()
        WindowHelper.finalizeWindow(self.window, self.parent)

    def gridFrames(self):
        self.activeFrame.grid(row=0, sticky=NSEW, padx=4, pady=4)
        self.upDownButtonFrame.grid(row=1, sticky=NSEW, padx=4, pady=4)
        self.inactiveFrame.grid(row=2, sticky=NSEW, padx=4, pady=4)
        self.okCancelFrame.grid(row=3, sticky=E, padx=4, pady=4)

    def addActiveListbox(self):
        labelExplain = Label(self.activeFrame, text=LabelConstants.EXTENDED_MODE)
        labelExplain.grid(row=0, column=0, sticky=W, padx=4, pady=(0,4))
        labelActiveListbox = Label(self.activeFrame, text=LabelConstants.ACTIVE_TAGS)
        labelActiveListbox.grid(row=1, column=0, sticky=W, padx=4, pady=4)
        scrollbarActive = Scrollbar(self.activeFrame)
        scrollbarActive.grid(row=2, column=1, sticky="NWS")
        self.activeListbox = Listbox(self.activeFrame, selectmode=EXTENDED, yscrollcommand=scrollbarActive.set, activestyle=NONE, width=70)
        scrollbarActive.config(command=self.activeListbox.yview)
        self.activeListbox.bind('<<ListboxSelect>>', self.onSelectActiveListbox)
        self.activeListbox.grid(row=2, column=0, sticky=NSEW, padx=(4, 0))

    def addMoveButtons(self):
        buttonUp = Button(self.upDownButtonFrame, text=LabelConstants.UP, width=13, command=lambda: self.moveUp())
        buttonUp.grid(row=0, column=0, sticky=NSEW, padx=(116, 4), pady=4)
        buttonDown = Button(self.upDownButtonFrame, text=LabelConstants.DOWN, width=13, command=lambda: self.moveDown())
        buttonDown.grid(row=0, column=1, sticky=NSEW, padx=(20, 4), pady=4)

    def addInactiveListbox(self):
        labelInactiveListbox = Label(self.inactiveFrame, text=LabelConstants.INACTIVE_TAGS)
        labelInactiveListbox.grid(row=0, column=0, sticky=W, padx=4, pady=4)
        scrollbarInactive = Scrollbar(self.inactiveFrame)
        scrollbarInactive.grid(row=1, column=1, sticky="NWS")
        self.inactiveListbox = Listbox(self.inactiveFrame, selectmode=EXTENDED, yscrollcommand=scrollbarInactive.set, activestyle=NONE, width=70)
        scrollbarInactive.config(command=self.inactiveListbox.yview)
        self.inactiveListbox.bind('<<ListboxSelect>>', self.onSelectInactiveListbox)
        self.inactiveListbox.grid(row=1, column=0, sticky=NSEW, padx=(4, 0))

    def addOkCancelButtons(self):
        buttonUpdateTags = Button(self.okCancelFrame, text=LabelConstants.UPDATE_TAGS, width=26, command=lambda: self.updateTagLibrary())
        buttonUpdateTags.grid(row=0, column=1, sticky=E, padx=4, pady=4)
        buttonOk = Button(self.okCancelFrame, text=LabelConstants.OK, width=13, command=lambda: self.ok())
        buttonOk.grid(row=0, column=2, sticky=E, padx=4, pady=4)
        buttonCancel = Button(self.okCancelFrame, text=LabelConstants.CANCEL, width=13, command=lambda: self.close())
        buttonCancel.grid(row=0, column=3, sticky=E, padx=(4, 0), pady=4)

    def populateListboxes(self):
        self.activeListbox.delete(0, END)
        self.inactiveListbox.delete(0, END)
        descriptions = []
        for tag in filter(lambda t: t.isActive, self.tags):
            descriptions.append(tag.localizationNames["en-us"])
        for desc in sorted(descriptions, key=str.casefold):
            self.activeListbox.insert(END, desc)
        descriptions = []
        for tag in filter(lambda t: not t.isActive, self.tags):
            descriptions.append(tag.localizationNames["en-us"])
        for desc in sorted(descriptions, key=str.casefold):
            self.inactiveListbox.insert(END, desc)

    def updateTagLibrary(self):
        UpdatingTwitchTagsWindow(self)
        self.populateListboxes()

    def ok(self):
        for tag in self.tags:
            if tag.localizationNames["en-us"] in self.inactiveListbox.get(0, END):
                tag.isActive = False
            else:
                tag.isActive = True
        self.close()

    def close(self):
        self.parent.setTags(self.tags)
        self.window.destroy()

    def moveUp(self):
        if self.selectedInactive:
            for tag in self.selectedInactive:
                alphabeticallyInsert(self.activeListbox, self.inactiveListbox.get(tag))
            for tag in reversed(self.selectedInactive):
                self.inactiveListbox.delete(tag)
            self.inactiveListbox.selection_clear(0, END)
            self.selectedInactive = None

    def moveDown(self):
        if self.selectedActive:
            for tag in self.selectedActive:
                alphabeticallyInsert(self.inactiveListbox, self.activeListbox.get(tag))
            for tag in reversed(self.selectedActive):
                self.activeListbox.delete(tag)
            self.activeListbox.selection_clear(0, END)
            self.selectedActive = None

    def onSelectActiveListbox(self, event):
        w = event.widget
        self.selectedActive = w.curselection()

    def onSelectInactiveListbox(self, event):
        w = event.widget
        self.selectedInactive = w.curselection()
Ejemplo n.º 19
0
class AutomateCenter(Toplevel):
    def __init__(self, parent, dir=""):
        super().__init__(parent, height=100)
        self.parent = parent
        self.attributes('-topmost', 'true')
        self.resizable(width=False, height=False)
        self.title('Automate Center')
        self.dir = dir
        self.files = []
        self.filesToInsert = []

        print('Current dir received by Automate Center: ' + self.dir)
        for file in os.listdir(self.dir):
            self.files.append(
                os.path.join(self.dir,
                             file).replace('\\', '/').replace('//', '/')[2:])


        self.lbl = Label(self, text = ' Select the files for which you \nwish' \
         + ' to automate PPT Insert' )
        self.lbl.pack()

        selectFrame = Frame(self)
        selectFrame.pack(pady=5)
        self.selectAllButton = Button(selectFrame, text="ALL")
        self.selectNoneButton = Button(selectFrame, text="NONE")
        self.selectAllButton.grid(row=0, column=1, padx=2)
        self.selectNoneButton.grid(row=0, column=0, padx=2)
        self.selectAllButton.bind('<ButtonRelease-1>', self.onAllClick)
        self.selectNoneButton.bind('<ButtonRelease-1>', self.onNoneClick)

        self.lb = Listbox(self, selectmode=MULTIPLE)
        for i in self.files:
            self.lb.insert(END, i)

        self.lb.bind("<<ListboxSelect>>", self.onSelect)
        self.lb.pack(pady=5)

        self.cancelBtn = Button(self, text='Cancel', width=12, height=1)
        self.cancelBtn.pack()
        self.okBtn = Button(self, text='OK', width=12, height=1)
        self.okBtn.pack(pady=2)
        self.okBtn.bind('<ButtonRelease-1>', self.onOkClick)
        self.cancelBtn.bind('<ButtonRelease-1>', self.onCancelClick)

        self.NABtn = Button(self, text='No Automation', width=12, height=1)
        self.NABtn.pack(pady=2)
        self.NABtn.bind('<ButtonRelease-1>', self.onNAClick)

    def onCancelClick(self, event):
        self.destroy()

    def onNAClick(self, event):
        log.writeEvent('Cancel Automate')
        self.parent.automate = False
        self.parent.slides.append(self.parent.blank)
        self.destroy()

    def onOkClick(self, event):

        if self.filesToInsert == []:
            return
        for idx in range(len(self.files)):
            if idx in self.filesToInsert:
                self.parent.slides.append(PPTImage('OS/' + self.files[idx]))

        self.parent.show.configure(image=self.parent.slides[-1].original)
        self.parent.show.image = self.parent.slides[-1].original
        self.parent.populate()
        self.destroy()

    def onSelect(self, event):
        self.filesToInsert = list(self.lb.curselection())

    def onAllClick(self, event):
        self.filesToInsert = []
        self.lb.selection_set(0, END)
        for idx in range(len(self.files)):
            self.filesToInsert.append(idx)

    def onNoneClick(self, event):
        self.lb.selection_clear(0, END)
        self.filesToInsert = []
Ejemplo n.º 20
0
class Window2(Frame):
    def __init__(self, parent, context):
        super(Window2, self).__init__(parent.Frame)
        context.add_observer(self)
        self.parent = parent
        self.context = context
        self.controller = parent.controller
        self._initialize()

        self.build()

    def _initialize(self):
        self.id = 'task'
        #画面遷移の順番を示す指示物
        self.unit_name_list = []

    def update(self, msg):
        self._gid = msg['gid']
        self.unit_name_list = _global_group[msg['gid'] - 1]

        self._update_unit_name_list()
        self.task_lbx.delete(0, END)

    def convert(self):

        units = self._task_box.get(0, END)
        if not units:
            self.context.notify('root', 'info', "처리할 작업이 없습니다.")
            return

        working_dir = self.context.get('directory')
        if not working_dir:
            self.context.directory()
            working_dir = self.context.get('directory')
            if not working_dir:
                messagebox.showwarning("경고", '작업디렉토리가 설정되어 있지 않습니다.')
                return

        # html변환여부 체크옵션
        _html = self.context.get('html')
        _gid = self._gid

        try:
            self.controller.convert(working_dir, _html, units, _gid)

            self.context.notify('root', 'info', "작업완료")
            messagebox.showinfo("알림", message="작업이 완료되었습니다.")

        except Exception as e:
            print(e)
            messagebox.showerror('포맷오류', '잘못된 포맷을 적용하였습니다.')
            self.context.notify('root', 'info', "작업오류")

    def build(self):
        componets = self.component_list()
        tasks = self.task_list()

        componets.pack(side="left", fill='y')
        componets.config(bg='steel blue3')
        tasks.pack(side='right', fill='both', expand=True)
        tasks.config(bg='light grey', padx=3)

    def _update_unit_name_list(self):
        self._list.delete(0, END)

        for i, name in enumerate(self.unit_name_list):
            self._list.insert(i, name)

    def component_list(self):
        #sandy brown
        fr1 = Frame(self)
        scrollbar = Scrollbar(fr1)
        scrollbar.pack(side="right", fill="y")

        self._list = Listbox(fr1,
                             bg="dim grey",
                             fg="white",
                             width=20,
                             yscrollcommand=scrollbar.set)

        mb1 = Menubutton(fr1, text='선택메뉴', relief='flat', bg='steel blue3')
        mb1.menu = Menu(mb1, tearoff=0)
        mb1['menu'] = mb1.menu
        mb1.menu.add_command(label='등록', command=self.choose_all)
        mb1.pack(side='bottom')
        mb1.menu.add_command(label='선택',
                             command=lambda: self._list.select_set(0, END))
        mb1.menu.add_command(
            label='해제', command=lambda: self._list.selection_clear(0, 'end'))

        self._list.pack(anchor="center",
                        fill="both",
                        expand=True,
                        padx=3,
                        pady=3)

        scrollbar.config(command=self._list.yview)
        self._list.config(highlightcolor='green',
                          font=('나눔고딕', 10),
                          activestyle='none',
                          selectmode='extended')

        self._list.bind('<<ListboxSelect>>', self.select_item)
        self._list.bind('<Button-3>', self.sub_menu1)
        self._list.exportselection = 0

        return fr1

    def select_item(self, event):
        self.clear_submenu()

        widget = event.widget
        #print("select item",widget.curselection())
        # if isinstance(widget,Listbox):
        v = widget.curselection()
        t = [widget.get(i) for i in v]

        self.context.notify('root', 'info', t)

    def clear_submenu(self):
        if hasattr(self, 'sub_fr'):
            self.sub_fr.destroy()

    def _setActivate(self, obj, index):
        obj.selection_set(index)
        # obj.see(index)
        # obj.activate(index)
        # obj.selection_anchor(index)

    def sub_menu1(self, event):
        self.clear_submenu()
        x, y = event.x, event.y

        self._setActivate(self._list, self._list.nearest(y))

        self.sub_fr = Frame(self, height=10)
        b1 = Button(self.sub_fr,
                    text='reg',
                    command=self.choose_task,
                    relief='flat')
        b1.pack(side='top', fill='both')
        self.sub_fr.place(x=x + 15, y=y)

    def choose_all(self):
        self.clear_submenu()
        for el in self._list.get(0, END):
            if not self._isduplicate(el):
                self._task_box.insert(END, el)

    def choose_task(self):
        self.clear_submenu()
        ixs = self._list.curselection()
        for ix in ixs:
            el = self._list.get(ix)
            if not self._isduplicate(el):
                self._task_box.insert(END, el)

    def _isduplicate(self, txt):
        for v in list(self._task_box.get(0, 'end')):
            if v == txt: return True
        return False

    def task_list(self):
        fr = Frame(self)
        fr_top = Frame(fr)
        task_lbx = Listbox(fr_top)
        task_lbx.pack(anchor="center",
                      fill="both",
                      expand=True,
                      padx=3,
                      pady=3)
        self._task_box = task_lbx

        fr_bot = Frame(fr, height='2')
        b1 = Menubutton(fr_bot, text='실행메뉴')
        b1.menu = Menu(b1, tearoff=0)
        b1['menu'] = b1.menu
        b1.menu.add_command(label='실행', command=self.convert)
        b1.menu.add_command(label='비우기', command=self.delete_task_item)
        b1.pack()

        fr_top.pack(side='top', fill='both', expand=True)
        fr_bot.pack(side='bottom', fill='x')
        task_lbx.config(highlightcolor='green',
                        font=('굴림체', 10),
                        activestyle='none',
                        selectmode='extended')

        self.task_lbx = task_lbx

        return fr

    def delete_task_item(self):
        v = self.task_lbx.curselection()
        #print(v)
        if not v:
            self.task_lbx.delete(0, END)
        elif len(v) == 1:
            self.task_lbx.delete(v)
        else:
            self.task_lbx.delete(v[0], v[-1])
Ejemplo n.º 21
0
class BanqueGraphique(Tk):
    """Classe principale de l'interface de la banque. Nous héritons de "Tk", la classe représentant la fenêtre principale
    d'une application tkinter.

    Attributes:
        banque (Banque): La banque liée à l'interface
        compte_selectionne (Compte): Référence vers le compte actuellement sélectionnée dans l'interface.

    """
    def __init__(self):
        # On appelle le constructeur de la classe Tk.
        super().__init__()

        # On crée une instance de la banque. On pourra donc utiliser ses attributs et méthodes avec self.banque.attribut, self.banque.methode, etc.
        self.banque = Banque()

        # On crée également un attribut qui servira à se "rappeler" du compte sélectionné.
        self.compte_selectionne = None

        # Manière intéressante de changer la police de caractères pour tous les widgets de l'interface.
        self.option_add("*Font", "DejaVu")

        # On change le titre de la fenêtre. La méthode "title" est une méthode de la classe mère (Tk).
        self.title("Banque")

        # Liste des clients. Mettre à jour en appelant la méthode mise_a_jour_interface().
        Label(self, text="Clients").grid(row=0, column=0, padx=10, pady=10)
        self.widget_clients = Listbox(self, exportselection=False)
        self.widget_clients.grid(row=1, column=0, padx=10, pady=10)

        # On lie l'événement de sélection à la méthode qui affiche les comptes du client.
        self.widget_clients.bind('<<ListboxSelect>>',
                                 self.mettre_a_jour_comptes)

        # Liste des comptes pour un client donné.
        Label(self, text="Comptes").grid(row=0, column=1, padx=10, pady=10)
        self.widget_comptes = Listbox(self, exportselection=False)
        self.widget_comptes.grid(row=1, column=1, padx=10, pady=10)

        # On lie l'événement de sélection à la méthode qui affiche le contenu du compte.
        self.widget_comptes.bind('<<ListboxSelect>>',
                                 self.mettre_a_jour_info_compte)

        # Contenu d'un compte.
        Label(self, text="Gestion du compte").grid(row=0,
                                                   column=3,
                                                   padx=10,
                                                   pady=10)
        cadre_compte = Frame(self)
        cadre_compte.grid(row=1, column=3, padx=10, pady=10)
        Label(cadre_compte, text="Numéro: ").grid(row=0,
                                                  column=0,
                                                  padx=10,
                                                  sticky=E)
        Label(cadre_compte, text="Type: ").grid(row=1,
                                                column=0,
                                                padx=10,
                                                sticky=E)
        Label(cadre_compte, text="Solde: ").grid(row=2,
                                                 column=0,
                                                 padx=10,
                                                 sticky=E)
        self.entree_numero = Entry(cadre_compte, state="readonly")
        self.entree_numero.grid(row=0, column=1)
        self.entree_type = Entry(cadre_compte, state="readonly")
        self.entree_type.grid(row=1, column=1)
        self.entree_solde = Entry(cadre_compte, state="readonly")
        self.entree_solde.grid(row=2, column=1)

        # Boutons de dépôt et retrait. Non disponibles tant que nous n'avons pas sélectionné un compte.
        cadre_boutons = Frame(cadre_compte)
        cadre_boutons.grid(row=3, column=1, pady=10)
        self.bouton_depot = Button(cadre_boutons,
                                   text="Dépôt",
                                   state=DISABLED,
                                   command=self.deposer)
        self.bouton_depot.grid(row=3, column=0)
        self.bouton_retrait = Button(cadre_boutons,
                                     text="Retrait",
                                     state=DISABLED,
                                     command=self.retirer)
        self.bouton_retrait.grid(row=3, column=1)

        # On ajoute les clients de la banque (pour tests seulement).
        # Dans la "vraie vie", on pourrait par exemple avoir un fichier (ou une base de données) contenant
        # ces informations et les charger à l'ouverture de la fenêtre.
        self.initialiser_clients_bidons()

        # On remplit l'interface avec des clients bidon.
        self.mettre_a_jour_interface()

    def initialiser_clients_bidons(self):
        """Ajoute des clients bidon à la banque. Dans la "vraie vie", on ajouterait la
        possiblité de sauvegarder et charger les informations d'une banque à partir d'un
        fichier, par exemple.

        """
        c_1 = Client("Jane Doe")
        c_1.ajouter_compte(1)
        c_1.ajouter_compte(2)
        c_1.deposer_dans_compte(1, 1000)
        c_1.retirer_dans_compte(2, 500)
        c_1.deposer_dans_compte(2, 250.25)

        c_2 = Client("John Doe")
        c_2.ajouter_compte(1)
        c_2.deposer_dans_compte(1, 10000)

        self.banque.ajouter_client(c_1)
        self.banque.ajouter_client(c_2)
        self.banque.recuperer_client("Jane Doe").ajouter_compte_sans_dette(3)
        self.banque.recuperer_client("Jane Doe").deposer_dans_compte(3, 1000)

    def mettre_a_jour_interface(self):
        """Méthode appelée pour mettre à jour les différents éléments de l'interface en fonction
        du contenu de la banque, puis de ce qui est sélectionné dans l'interface.

        """
        # Mise à jour de la liste de clients.
        self.widget_clients.delete(0, END)

        for client in self.banque.clients:
            self.widget_clients.insert(END, client.nom)

        # On déselectionne.
        self.widget_clients.selection_clear(0, END)

        # On vide la liste des comptes.
        self.widget_comptes.delete(0, END)

        # On vide le contenu de la gestion du compte
        self.desactiver_gestion_compte()

    def mettre_a_jour_comptes(self, evenement=None):
        """Met à jour la liste des comptes affichés. Réinitialise le compte affiché.

        Args:
            evenement (Event): Objet reçu de la part de tkinter. Nous n'en avons pas besoin, alors on
                met sa valeur par défaut à None.

        """
        # On récupère quel client est sélectionné.
        index_clique = int(self.widget_clients.curselection()[0])
        valeur = self.widget_clients.get(index_clique)

        # Mise à jour de la liste de comptes (en fonction du client sélectionné)
        self.widget_comptes.delete(0, END)

        client = self.banque.recuperer_client(valeur)
        for numero, compte in client.comptes.items():
            self.widget_comptes.insert(END, str(numero))

        # On désactive la gestion du compte.
        self.desactiver_gestion_compte()

    def desactiver_gestion_compte(self):
        """Désactive les éléments d'interface liés à la gestion du compte, et remet à None
        le compte sélectionné.

        """
        self.compte_selectionne = None

        self.entree_numero['state'] = NORMAL
        self.entree_type['state'] = NORMAL
        self.entree_solde['state'] = NORMAL

        self.entree_numero.delete(0, END)
        self.entree_type.delete(0, END)
        self.entree_solde.delete(0, END)

        self.entree_numero['state'] = 'readonly'
        self.entree_type['state'] = 'readonly'
        self.entree_solde['state'] = 'readonly'
        self.bouton_depot['state'] = DISABLED
        self.bouton_retrait['state'] = DISABLED

    def mettre_a_jour_info_compte(self, evenement=None):
        """En fonction des autres éléments d'interface, met à jour le contenu lié au compte
        sélectionné. Met à jour l'attribut self.compte_selectionne pour usage futur.

        Args:
            evenement (Event): Objet reçu de la part de tkinter. Nous n'en avons pas besoin, alors on
                met sa valeur par défaut à None.

        """
        # On récupère quel client et quel compte est sélectionné.
        index_client = self.widget_clients.curselection()[0]
        nom_client = self.widget_clients.get(index_client)
        index_compte = int(self.widget_comptes.curselection()[0])
        numero_compte = int(self.widget_comptes.get(index_compte))

        # On récupère l'objet de type Compte, et on place sa référence dans L'attribut
        # self.compte_selectionne. Note: modifier le compte via cet attribut modifiera
        # également le compte dans la hiérarchie d'objets de la banque!
        objet_compte = self.banque.recuperer_client(
            nom_client).comptes[numero_compte]
        self.compte_selectionne = objet_compte

        # Gestion des éléments d'interface.
        self.entree_numero['state'] = NORMAL
        self.entree_type['state'] = NORMAL
        self.entree_solde['state'] = NORMAL

        self.entree_numero.delete(0, END)
        self.entree_type.delete(0, END)
        self.entree_solde.delete(0, END)
        self.entree_numero.insert(END, numero_compte)
        self.entree_type.insert(END, objet_compte.__class__.__name__)
        self.entree_solde.insert(END, objet_compte.solde)

        self.entree_numero['state'] = 'readonly'
        self.entree_type['state'] = 'readonly'
        self.entree_solde['state'] = 'readonly'

        # On active les boutons de dépôt et de retrait
        self.bouton_depot['state'] = NORMAL
        self.bouton_retrait['state'] = NORMAL

    def deposer(self):
        """Effectue un dépôt dans le compte sélectionné.

        """
        # On demande le montant à l'utilisateur.
        fenetre_depot = FenetreDepotRetrait(self, sorte="dépôt")
        self.wait_window(fenetre_depot)

        # On fait le dépôt dans le compte sélectionné.
        if self.compte_selectionne is not None:
            # TODO: Lorsque nous connaîtrons la gestion des erreurs,
            # TODO: nous pourrons faire des validations supplémentaires ici.
            self.compte_selectionne.deposer(fenetre_depot.valeur)

        # On met à jour l'interface.
        self.mettre_a_jour_info_compte(evenement=None)

    def retirer(self):
        """Effectue un retrait dans le compte sélectionné.

        """
        # On demande le montant à l'utilisateur.
        fenetre_retrait = FenetreDepotRetrait(self, sorte="retrait")
        self.wait_window(fenetre_retrait)

        # On fait le dépôt dans le compte sélectionné.
        if self.compte_selectionne is not None:
            # TODO: Lorsque nous connaîtrons la gestion des erreurs,
            # TODO: nous pourrons faire des validations supplémentaires ici.
            self.compte_selectionne.retirer(fenetre_retrait.valeur)

        # On met à jour l'interface.
        self.mettre_a_jour_info_compte(evenement=None)
class DMselector(ttk.Frame):
    """Listbox for DM Creation, Selection, and Sorting."""
    def __init__(self, master, conflict):
        """Initialize DM selection/creation Widget."""
        ttk.Frame.__init__(self, master)
        self.conflict = conflict
        self.dms = conflict.decisionMakers
        # variables
        self.listVariable = StringVar(
            value=tuple(['Double Click to Add Item']))
        self.selIdx = None
        self.selectedDM = None

        # widgets
        self.label = ttk.Label(self, text="Decision Makers")
        self.dmListDisp = Listbox(self, listvariable=self.listVariable)
        self.scrollY = ttk.Scrollbar(self,
                                     orient=VERTICAL,
                                     command=self.dmListDisp.yview)
        self.upBtn = ttk.Button(self, width=10, text='Up', command=self.upCmd)
        self.downBtn = ttk.Button(self,
                                  width=10,
                                  text='Down',
                                  command=self.downCmd)
        self.delBtn = ttk.Button(self,
                                 width=10,
                                 text='Delete',
                                 command=self.delCmd)

        # configuration
        self.dmListDisp.configure(yscrollcommand=self.scrollY.set)
        self.columnconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)

        self.label.grid(column=0, row=0, columnspan=5, sticky=NSEW)
        self.dmListDisp.grid(column=0, row=1, columnspan=5, sticky=NSEW)
        self.scrollY.grid(column=5, row=1, sticky=NSEW)
        self.upBtn.grid(column=2, row=2, sticky=NSEW)
        self.downBtn.grid(column=3, row=2, sticky=NSEW)
        self.delBtn.grid(column=4, row=2, sticky=NSEW)

        self.dmListDisp.bind('<<ListboxSelect>>', self.selChgCmd)
        self.dmListDisp.bind('<Double-1>', self.editCmd)
        self.dmListDisp.bind('<Delete>', self.delCmd)
        self.dmListDisp.bind('<Return>', self.editCmd)

    def refresh(self, event=None):
        """Refresh widget contents."""
        self.updateList()
        for idx in range(len(self.dms)):
            self.dmListDisp.itemconfigure(idx, foreground='black')
        self.dmListDisp.itemconfigure(len(self.dms), foreground='#A0A0A0')

    def updateList(self, event=None):
        """Update the value in the displayed listVariable."""
        self.listVariable.set(
            tuple(self.dms.names() + ['Double Click to Add Item']))

    def moveEntry(self, idx, idx2):
        """Move an item from idx to idx2."""
        self.dms.insert(idx2, self.dms.pop(idx))
        self.updateList()
        self.dmListDisp.selection_clear(idx)
        self.dmListDisp.selection_set(idx2)
        self.selChgCmd()
        self.event_generate("<<dmOptChg>>")

    def upCmd(self, event=None):
        """Move the selected element up one space in the list."""
        idx = self.selIdx
        # check that there is an entry selected, and it isn't the first entry.
        if idx not in [-1, 0, len(self.dms)]:
            self.moveEntry(idx, idx - 1)

    def downCmd(self, event=None):
        """Move the selected element down one space in the list."""
        idx = self.selIdx
        # check that there is an entry selected, and it isn't the last entry
        if idx not in [-1, len(self.dms) - 1, len(self.dms)]:
            self.moveEntry(idx, idx + 1)

    def delCmd(self, *args):
        """Delete the selected element from the list."""
        idx = self.selIdx
        if idx != len(self.dms):  # check that a valid entry is selected
            del self.dms[idx]
            self.refresh()
            self.event_generate("<<dmOptChg>>")

    def selChgCmd(self, *args):
        """Called when the selection changes."""
        self.selIdx = int(self.dmListDisp.curselection()[0])
        if self.selIdx != len(self.conflict.decisionMakers):
            self.selectedDM = self.conflict.decisionMakers[self.selIdx]
        else:
            self.selectedDM = None
        self.event_generate('<<DMselected>>')

    def editCmd(self, *args):
        """Called when a list entry is selected for editing."""
        self.event_generate('<<EditDM>>')

    def reselect(self, event=None):
        """Return selection focus to a dm after an action is completed."""
        if self.selIdx is not None:
            self.dmListDisp.selection_set(self.selIdx)
            self.dmListDisp.event_generate('<<ListboxSelect>>')
Ejemplo n.º 23
0
class RecursiveDescentApp(object):
    """
    A graphical tool for exploring the recursive descent parser.  The tool
    displays the parser's tree and the remaining text, and allows the
    user to control the parser's operation.  In particular, the user
    can expand subtrees on the frontier, match tokens on the frontier
    against the text, and backtrack.  A "step" button simply steps
    through the parsing process, performing the operations that
    ``RecursiveDescentParser`` would use.
    """
    def __init__(self, grammar, sent, trace=0):
        self._sent = sent
        self._parser = SteppingRecursiveDescentParser(grammar, trace)

        # Set up the main window.
        self._top = Tk()
        self._top.title('Recursive Descent Parser Application')

        # Set up key bindings.
        self._init_bindings()

        # Initialize the fonts.
        self._init_fonts(self._top)

        # Animations.  animating_lock is a lock to prevent the demo
        # from performing new operations while it's animating.
        self._animation_frames = IntVar(self._top)
        self._animation_frames.set(5)
        self._animating_lock = 0
        self._autostep = 0

        # The user can hide the grammar.
        self._show_grammar = IntVar(self._top)
        self._show_grammar.set(1)

        # Create the basic frames.
        self._init_menubar(self._top)
        self._init_buttons(self._top)
        self._init_feedback(self._top)
        self._init_grammar(self._top)
        self._init_canvas(self._top)

        # Initialize the parser.
        self._parser.initialize(self._sent)

        # Resize callback
        self._canvas.bind('<Configure>', self._configure)

    #########################################
    ##  Initialization Helpers
    #########################################

    def _init_fonts(self, root):
        # See: <http://www.astro.washington.edu/owen/ROTKFolklore.html>
        self._sysfont = tkinter.font.Font(font=Button()["font"])
        root.option_add("*Font", self._sysfont)

        # TWhat's our font size (default=same as sysfont)
        self._size = IntVar(root)
        self._size.set(self._sysfont.cget('size'))

        self._boldfont = tkinter.font.Font(family='helvetica', weight='bold',
                                    size=self._size.get())
        self._font = tkinter.font.Font(family='helvetica',
                                    size=self._size.get())
        if self._size.get() < 0: big = self._size.get()-2
        else: big = self._size.get()+2
        self._bigfont = tkinter.font.Font(family='helvetica', weight='bold',
                                    size=big)

    def _init_grammar(self, parent):
        # Grammar view.
        self._prodframe = listframe = Frame(parent)
        self._prodframe.pack(fill='both', side='left', padx=2)
        self._prodlist_label = Label(self._prodframe, font=self._boldfont,
                                     text='Available Expansions')
        self._prodlist_label.pack()
        self._prodlist = Listbox(self._prodframe, selectmode='single',
                                 relief='groove', background='white',
                                 foreground='#909090', font=self._font,
                                 selectforeground='#004040',
                                 selectbackground='#c0f0c0')

        self._prodlist.pack(side='right', fill='both', expand=1)

        self._productions = list(self._parser.grammar().productions())
        for production in self._productions:
            self._prodlist.insert('end', ('  %s' % production))
        self._prodlist.config(height=min(len(self._productions), 25))

        # Add a scrollbar if there are more than 25 productions.
        if len(self._productions) > 25:
            listscroll = Scrollbar(self._prodframe,
                                   orient='vertical')
            self._prodlist.config(yscrollcommand = listscroll.set)
            listscroll.config(command=self._prodlist.yview)
            listscroll.pack(side='left', fill='y')

        # If they select a production, apply it.
        self._prodlist.bind('<<ListboxSelect>>', self._prodlist_select)

    def _init_bindings(self):
        # Key bindings are a good thing.
        self._top.bind('<Control-q>', self.destroy)
        self._top.bind('<Control-x>', self.destroy)
        self._top.bind('<Escape>', self.destroy)
        self._top.bind('e', self.expand)
        #self._top.bind('<Alt-e>', self.expand)
        #self._top.bind('<Control-e>', self.expand)
        self._top.bind('m', self.match)
        self._top.bind('<Alt-m>', self.match)
        self._top.bind('<Control-m>', self.match)
        self._top.bind('b', self.backtrack)
        self._top.bind('<Alt-b>', self.backtrack)
        self._top.bind('<Control-b>', self.backtrack)
        self._top.bind('<Control-z>', self.backtrack)
        self._top.bind('<BackSpace>', self.backtrack)
        self._top.bind('a', self.autostep)
        #self._top.bind('<Control-a>', self.autostep)
        self._top.bind('<Control-space>', self.autostep)
        self._top.bind('<Control-c>', self.cancel_autostep)
        self._top.bind('<space>', self.step)
        self._top.bind('<Delete>', self.reset)
        self._top.bind('<Control-p>', self.postscript)
        #self._top.bind('<h>', self.help)
        #self._top.bind('<Alt-h>', self.help)
        self._top.bind('<Control-h>', self.help)
        self._top.bind('<F1>', self.help)
        #self._top.bind('<g>', self.toggle_grammar)
        #self._top.bind('<Alt-g>', self.toggle_grammar)
        #self._top.bind('<Control-g>', self.toggle_grammar)
        self._top.bind('<Control-g>', self.edit_grammar)
        self._top.bind('<Control-t>', self.edit_sentence)

    def _init_buttons(self, parent):
        # Set up the frames.
        self._buttonframe = buttonframe = Frame(parent)
        buttonframe.pack(fill='none', side='bottom', padx=3, pady=2)
        Button(buttonframe, text='Step',
               background='#90c0d0', foreground='black',
               command=self.step,).pack(side='left')
        Button(buttonframe, text='Autostep',
               background='#90c0d0', foreground='black',
               command=self.autostep,).pack(side='left')
        Button(buttonframe, text='Expand', underline=0,
               background='#90f090', foreground='black',
               command=self.expand).pack(side='left')
        Button(buttonframe, text='Match', underline=0,
               background='#90f090', foreground='black',
               command=self.match).pack(side='left')
        Button(buttonframe, text='Backtrack', underline=0,
               background='#f0a0a0', foreground='black',
               command=self.backtrack).pack(side='left')
        # Replace autostep...
#         self._autostep_button = Button(buttonframe, text='Autostep',
#                                        underline=0, command=self.autostep)
#         self._autostep_button.pack(side='left')

    def _configure(self, event):
        self._autostep = 0
        (x1, y1, x2, y2) = self._cframe.scrollregion()
        y2 = event.height - 6
        self._canvas['scrollregion'] = '%d %d %d %d' % (x1,y1,x2,y2)
        self._redraw()

    def _init_feedback(self, parent):
        self._feedbackframe = feedbackframe = Frame(parent)
        feedbackframe.pack(fill='x', side='bottom', padx=3, pady=3)
        self._lastoper_label = Label(feedbackframe, text='Last Operation:',
                                     font=self._font)
        self._lastoper_label.pack(side='left')
        lastoperframe = Frame(feedbackframe, relief='sunken', border=1)
        lastoperframe.pack(fill='x', side='right', expand=1, padx=5)
        self._lastoper1 = Label(lastoperframe, foreground='#007070',
                                background='#f0f0f0', font=self._font)
        self._lastoper2 = Label(lastoperframe, anchor='w', width=30,
                                foreground='#004040', background='#f0f0f0',
                                font=self._font)
        self._lastoper1.pack(side='left')
        self._lastoper2.pack(side='left', fill='x', expand=1)

    def _init_canvas(self, parent):
        self._cframe = CanvasFrame(parent, background='white',
                                   #width=525, height=250,
                                   closeenough=10,
                                   border=2, relief='sunken')
        self._cframe.pack(expand=1, fill='both', side='top', pady=2)
        canvas = self._canvas = self._cframe.canvas()

        # Initially, there's no tree or text
        self._tree = None
        self._textwidgets = []
        self._textline = None

    def _init_menubar(self, parent):
        menubar = Menu(parent)

        filemenu = Menu(menubar, tearoff=0)
        filemenu.add_command(label='Reset Parser', underline=0,
                             command=self.reset, accelerator='Del')
        filemenu.add_command(label='Print to Postscript', underline=0,
                             command=self.postscript, accelerator='Ctrl-p')
        filemenu.add_command(label='Exit', underline=1,
                             command=self.destroy, accelerator='Ctrl-x')
        menubar.add_cascade(label='File', underline=0, menu=filemenu)

        editmenu = Menu(menubar, tearoff=0)
        editmenu.add_command(label='Edit Grammar', underline=5,
                             command=self.edit_grammar,
                             accelerator='Ctrl-g')
        editmenu.add_command(label='Edit Text', underline=5,
                             command=self.edit_sentence,
                             accelerator='Ctrl-t')
        menubar.add_cascade(label='Edit', underline=0, menu=editmenu)

        rulemenu = Menu(menubar, tearoff=0)
        rulemenu.add_command(label='Step', underline=1,
                             command=self.step, accelerator='Space')
        rulemenu.add_separator()
        rulemenu.add_command(label='Match', underline=0,
                             command=self.match, accelerator='Ctrl-m')
        rulemenu.add_command(label='Expand', underline=0,
                             command=self.expand, accelerator='Ctrl-e')
        rulemenu.add_separator()
        rulemenu.add_command(label='Backtrack', underline=0,
                             command=self.backtrack, accelerator='Ctrl-b')
        menubar.add_cascade(label='Apply', underline=0, menu=rulemenu)

        viewmenu = Menu(menubar, tearoff=0)
        viewmenu.add_checkbutton(label="Show Grammar", underline=0,
                                 variable=self._show_grammar,
                                 command=self._toggle_grammar)
        viewmenu.add_separator()
        viewmenu.add_radiobutton(label='Tiny', variable=self._size,
                                 underline=0, value=10, command=self.resize)
        viewmenu.add_radiobutton(label='Small', variable=self._size,
                                 underline=0, value=12, command=self.resize)
        viewmenu.add_radiobutton(label='Medium', variable=self._size,
                                 underline=0, value=14, command=self.resize)
        viewmenu.add_radiobutton(label='Large', variable=self._size,
                                 underline=0, value=18, command=self.resize)
        viewmenu.add_radiobutton(label='Huge', variable=self._size,
                                 underline=0, value=24, command=self.resize)
        menubar.add_cascade(label='View', underline=0, menu=viewmenu)

        animatemenu = Menu(menubar, tearoff=0)
        animatemenu.add_radiobutton(label="No Animation", underline=0,
                                    variable=self._animation_frames,
                                    value=0)
        animatemenu.add_radiobutton(label="Slow Animation", underline=0,
                                    variable=self._animation_frames,
                                    value=10, accelerator='-')
        animatemenu.add_radiobutton(label="Normal Animation", underline=0,
                                    variable=self._animation_frames,
                                    value=5, accelerator='=')
        animatemenu.add_radiobutton(label="Fast Animation", underline=0,
                                    variable=self._animation_frames,
                                    value=2, accelerator='+')
        menubar.add_cascade(label="Animate", underline=1, menu=animatemenu)


        helpmenu = Menu(menubar, tearoff=0)
        helpmenu.add_command(label='About', underline=0,
                             command=self.about)
        helpmenu.add_command(label='Instructions', underline=0,
                             command=self.help, accelerator='F1')
        menubar.add_cascade(label='Help', underline=0, menu=helpmenu)

        parent.config(menu=menubar)

    #########################################
    ##  Helper
    #########################################

    def _get(self, widget, treeloc):
        for i in treeloc: widget = widget.subtrees()[i]
        if isinstance(widget, TreeSegmentWidget):
            widget = widget.label()
        return widget

    #########################################
    ##  Main draw procedure
    #########################################

    def _redraw(self):
        canvas = self._canvas

        # Delete the old tree, widgets, etc.
        if self._tree is not None:
            self._cframe.destroy_widget(self._tree)
        for twidget in self._textwidgets:
            self._cframe.destroy_widget(twidget)
        if self._textline is not None:
            self._canvas.delete(self._textline)

        # Draw the tree.
        helv = ('helvetica', -self._size.get())
        bold = ('helvetica', -self._size.get(), 'bold')
        attribs = {'tree_color': '#000000', 'tree_width': 2,
                   'node_font': bold, 'leaf_font': helv,}
        tree = self._parser.tree()
        self._tree = tree_to_treesegment(canvas, tree, **attribs)
        self._cframe.add_widget(self._tree, 30, 5)

        # Draw the text.
        helv = ('helvetica', -self._size.get())
        bottom = y = self._cframe.scrollregion()[3]
        self._textwidgets = [TextWidget(canvas, word, font=self._font)
                             for word in self._sent]
        for twidget in self._textwidgets:
            self._cframe.add_widget(twidget, 0, 0)
            twidget.move(0, bottom-twidget.bbox()[3]-5)
            y = min(y, twidget.bbox()[1])

        # Draw a line over the text, to separate it from the tree.
        self._textline = canvas.create_line(-5000, y-5, 5000, y-5, dash='.')

        # Highlight appropriate nodes.
        self._highlight_nodes()
        self._highlight_prodlist()

        # Make sure the text lines up.
        self._position_text()


    def _redraw_quick(self):
        # This should be more-or-less sufficient after an animation.
        self._highlight_nodes()
        self._highlight_prodlist()
        self._position_text()

    def _highlight_nodes(self):
        # Highlight the list of nodes to be checked.
        bold = ('helvetica', -self._size.get(), 'bold')
        for treeloc in self._parser.frontier()[:1]:
            self._get(self._tree, treeloc)['color'] = '#20a050'
            self._get(self._tree, treeloc)['font'] = bold
        for treeloc in self._parser.frontier()[1:]:
            self._get(self._tree, treeloc)['color'] = '#008080'

    def _highlight_prodlist(self):
        # Highlight the productions that can be expanded.
        # Boy, too bad tkinter doesn't implement Listbox.itemconfig;
        # that would be pretty useful here.
        self._prodlist.delete(0, 'end')
        expandable = self._parser.expandable_productions()
        untried = self._parser.untried_expandable_productions()
        productions = self._productions
        for index in range(len(productions)):
            if productions[index] in expandable:
                if productions[index] in untried:
                    self._prodlist.insert(index, ' %s' % productions[index])
                else:
                    self._prodlist.insert(index, ' %s (TRIED)' %
                                          productions[index])
                self._prodlist.selection_set(index)
            else:
                self._prodlist.insert(index, ' %s' % productions[index])

    def _position_text(self):
        # Line up the text widgets that are matched against the tree
        numwords = len(self._sent)
        num_matched = numwords - len(self._parser.remaining_text())
        leaves = self._tree_leaves()[:num_matched]
        xmax = self._tree.bbox()[0]
        for i in range(0, len(leaves)):
            widget = self._textwidgets[i]
            leaf = leaves[i]
            widget['color'] = '#006040'
            leaf['color'] = '#006040'
            widget.move(leaf.bbox()[0] - widget.bbox()[0], 0)
            xmax = widget.bbox()[2] + 10

        # Line up the text widgets that are not matched against the tree.
        for i in range(len(leaves), numwords):
            widget = self._textwidgets[i]
            widget['color'] = '#a0a0a0'
            widget.move(xmax - widget.bbox()[0], 0)
            xmax = widget.bbox()[2] + 10

        # If we have a complete parse, make everything green :)
        if self._parser.currently_complete():
            for twidget in self._textwidgets:
                twidget['color'] = '#00a000'

        # Move the matched leaves down to the text.
        for i in range(0, len(leaves)):
            widget = self._textwidgets[i]
            leaf = leaves[i]
            dy = widget.bbox()[1] - leaf.bbox()[3] - 10.0
            dy = max(dy, leaf.parent().label().bbox()[3] - leaf.bbox()[3] + 10)
            leaf.move(0, dy)

    def _tree_leaves(self, tree=None):
        if tree is None: tree = self._tree
        if isinstance(tree, TreeSegmentWidget):
            leaves = []
            for child in tree.subtrees(): leaves += self._tree_leaves(child)
            return leaves
        else:
            return [tree]

    #########################################
    ##  Button Callbacks
    #########################################

    def destroy(self, *e):
        self._autostep = 0
        if self._top is None: return
        self._top.destroy()
        self._top = None

    def reset(self, *e):
        self._autostep = 0
        self._parser.initialize(self._sent)
        self._lastoper1['text'] = 'Reset Application'
        self._lastoper2['text'] = ''
        self._redraw()

    def autostep(self, *e):
        if self._animation_frames.get() == 0:
            self._animation_frames.set(2)
        if self._autostep:
            self._autostep = 0
        else:
            self._autostep = 1
            self._step()

    def cancel_autostep(self, *e):
        #self._autostep_button['text'] = 'Autostep'
        self._autostep = 0

    # Make sure to stop auto-stepping if we get any user input.
    def step(self, *e): self._autostep = 0; self._step()
    def match(self, *e): self._autostep = 0; self._match()
    def expand(self, *e): self._autostep = 0; self._expand()
    def backtrack(self, *e): self._autostep = 0; self._backtrack()

    def _step(self):
        if self._animating_lock: return

        # Try expanding, matching, and backtracking (in that order)
        if self._expand(): pass
        elif self._parser.untried_match() and self._match(): pass
        elif self._backtrack(): pass
        else:
            self._lastoper1['text'] = 'Finished'
            self._lastoper2['text'] = ''
            self._autostep = 0

        # Check if we just completed a parse.
        if self._parser.currently_complete():
            self._autostep = 0
            self._lastoper2['text'] += '    [COMPLETE PARSE]'

    def _expand(self, *e):
        if self._animating_lock: return
        old_frontier = self._parser.frontier()
        rv = self._parser.expand()
        if rv is not None:
            self._lastoper1['text'] = 'Expand:'
            self._lastoper2['text'] = rv
            self._prodlist.selection_clear(0, 'end')
            index = self._productions.index(rv)
            self._prodlist.selection_set(index)
            self._animate_expand(old_frontier[0])
            return 1
        else:
            self._lastoper1['text'] = 'Expand:'
            self._lastoper2['text'] = '(all expansions tried)'
            return 0

    def _match(self, *e):
        if self._animating_lock: return
        old_frontier = self._parser.frontier()
        rv = self._parser.match()
        if rv is not None:
            self._lastoper1['text'] = 'Match:'
            self._lastoper2['text'] = rv
            self._animate_match(old_frontier[0])
            return 1
        else:
            self._lastoper1['text'] = 'Match:'
            self._lastoper2['text'] = '(failed)'
            return 0

    def _backtrack(self, *e):
        if self._animating_lock: return
        if self._parser.backtrack():
            elt = self._parser.tree()
            for i in self._parser.frontier()[0]:
                elt = elt[i]
            self._lastoper1['text'] = 'Backtrack'
            self._lastoper2['text'] = ''
            if isinstance(elt, Tree):
                self._animate_backtrack(self._parser.frontier()[0])
            else:
                self._animate_match_backtrack(self._parser.frontier()[0])
            return 1
        else:
            self._autostep = 0
            self._lastoper1['text'] = 'Finished'
            self._lastoper2['text'] = ''
            return 0

    def about(self, *e):
        ABOUT = ("NLTK Recursive Descent Parser Application\n"+
                 "Written by Edward Loper")
        TITLE = 'About: Recursive Descent Parser Application'
        try:
            from tkinter.messagebox import Message
            Message(message=ABOUT, title=TITLE).show()
        except:
            ShowText(self._top, TITLE, ABOUT)

    def help(self, *e):
        self._autostep = 0
        # The default font's not very legible; try using 'fixed' instead.
        try:
            ShowText(self._top, 'Help: Recursive Descent Parser Application',
                     (__doc__ or '').strip(), width=75, font='fixed')
        except:
            ShowText(self._top, 'Help: Recursive Descent Parser Application',
                     (__doc__ or '').strip(), width=75)

    def postscript(self, *e):
        self._autostep = 0
        self._cframe.print_to_file()

    def mainloop(self, *args, **kwargs):
        """
        Enter the Tkinter mainloop.  This function must be called if
        this demo is created from a non-interactive program (e.g.
        from a secript); otherwise, the demo will close as soon as
        the script completes.
        """
        if in_idle(): return
        self._top.mainloop(*args, **kwargs)

    def resize(self, size=None):
        if size is not None: self._size.set(size)
        size = self._size.get()
        self._font.configure(size=-(abs(size)))
        self._boldfont.configure(size=-(abs(size)))
        self._sysfont.configure(size=-(abs(size)))
        self._bigfont.configure(size=-(abs(size+2)))
        self._redraw()

    #########################################
    ##  Expand Production Selection
    #########################################

    def _toggle_grammar(self, *e):
        if self._show_grammar.get():
            self._prodframe.pack(fill='both', side='left', padx=2,
                                 after=self._feedbackframe)
            self._lastoper1['text'] = 'Show Grammar'
        else:
            self._prodframe.pack_forget()
            self._lastoper1['text'] = 'Hide Grammar'
        self._lastoper2['text'] = ''

#     def toggle_grammar(self, *e):
#         self._show_grammar = not self._show_grammar
#         if self._show_grammar:
#             self._prodframe.pack(fill='both', expand='y', side='left',
#                                  after=self._feedbackframe)
#             self._lastoper1['text'] = 'Show Grammar'
#         else:
#             self._prodframe.pack_forget()
#             self._lastoper1['text'] = 'Hide Grammar'
#         self._lastoper2['text'] = ''

    def _prodlist_select(self, event):
        selection = self._prodlist.curselection()
        if len(selection) != 1: return
        index = int(selection[0])
        old_frontier = self._parser.frontier()
        production = self._parser.expand(self._productions[index])

        if production:
            self._lastoper1['text'] = 'Expand:'
            self._lastoper2['text'] = production
            self._prodlist.selection_clear(0, 'end')
            self._prodlist.selection_set(index)
            self._animate_expand(old_frontier[0])
        else:
            # Reset the production selections.
            self._prodlist.selection_clear(0, 'end')
            for prod in self._parser.expandable_productions():
                index = self._productions.index(prod)
                self._prodlist.selection_set(index)

    #########################################
    ##  Animation
    #########################################

    def _animate_expand(self, treeloc):
        oldwidget = self._get(self._tree, treeloc)
        oldtree = oldwidget.parent()
        top = not isinstance(oldtree.parent(), TreeSegmentWidget)

        tree = self._parser.tree()
        for i in treeloc:
            tree = tree[i]

        widget = tree_to_treesegment(self._canvas, tree,
                                     node_font=self._boldfont,
                                     leaf_color='white',
                                     tree_width=2, tree_color='white',
                                     node_color='white',
                                     leaf_font=self._font)
        widget.label()['color'] = '#20a050'

        (oldx, oldy) = oldtree.label().bbox()[:2]
        (newx, newy) = widget.label().bbox()[:2]
        widget.move(oldx-newx, oldy-newy)

        if top:
            self._cframe.add_widget(widget, 0, 5)
            widget.move(30-widget.label().bbox()[0], 0)
            self._tree = widget
        else:
            oldtree.parent().replace_child(oldtree, widget)

        # Move the children over so they don't overlap.
        # Line the children up in a strange way.
        if widget.subtrees():
            dx = (oldx + widget.label().width()/2 -
                  widget.subtrees()[0].bbox()[0]/2 -
                  widget.subtrees()[0].bbox()[2]/2)
            for subtree in widget.subtrees(): subtree.move(dx, 0)

        self._makeroom(widget)

        if top:
            self._cframe.destroy_widget(oldtree)
        else:
            oldtree.destroy()

        colors = ['gray%d' % (10*int(10*x/self._animation_frames.get()))
                  for x in range(self._animation_frames.get(),0,-1)]

        # Move the text string down, if necessary.
        dy = widget.bbox()[3] + 30 - self._canvas.coords(self._textline)[1]
        if dy > 0:
            for twidget in self._textwidgets: twidget.move(0, dy)
            self._canvas.move(self._textline, 0, dy)

        self._animate_expand_frame(widget, colors)

    def _makeroom(self, treeseg):
        """
        Make sure that no sibling tree bbox's overlap.
        """
        parent = treeseg.parent()
        if not isinstance(parent, TreeSegmentWidget): return

        index = parent.subtrees().index(treeseg)

        # Handle siblings to the right
        rsiblings = parent.subtrees()[index+1:]
        if rsiblings:
            dx = treeseg.bbox()[2] - rsiblings[0].bbox()[0] + 10
            for sibling in rsiblings: sibling.move(dx, 0)

        # Handle siblings to the left
        if index > 0:
            lsibling = parent.subtrees()[index-1]
            dx = max(0, lsibling.bbox()[2] - treeseg.bbox()[0] + 10)
            treeseg.move(dx, 0)

        # Keep working up the tree.
        self._makeroom(parent)

    def _animate_expand_frame(self, widget, colors):
        if len(colors) > 0:
            self._animating_lock = 1
            widget['color'] = colors[0]
            for subtree in widget.subtrees():
                if isinstance(subtree, TreeSegmentWidget):
                    subtree.label()['color'] = colors[0]
                else:
                    subtree['color'] = colors[0]
            self._top.after(50, self._animate_expand_frame,
                            widget, colors[1:])
        else:
            widget['color'] = 'black'
            for subtree in widget.subtrees():
                if isinstance(subtree, TreeSegmentWidget):
                    subtree.label()['color'] = 'black'
                else:
                    subtree['color'] = 'black'
            self._redraw_quick()
            widget.label()['color'] = 'black'
            self._animating_lock = 0
            if self._autostep: self._step()

    def _animate_backtrack(self, treeloc):
        # Flash red first, if we're animating.
        if self._animation_frames.get() == 0: colors = []
        else: colors = ['#a00000', '#000000', '#a00000']
        colors += ['gray%d' % (10*int(10*x/(self._animation_frames.get())))
                   for x in range(1, self._animation_frames.get()+1)]

        widgets = [self._get(self._tree, treeloc).parent()]
        for subtree in widgets[0].subtrees():
            if isinstance(subtree, TreeSegmentWidget):
                widgets.append(subtree.label())
            else:
                widgets.append(subtree)

        self._animate_backtrack_frame(widgets, colors)

    def _animate_backtrack_frame(self, widgets, colors):
        if len(colors) > 0:
            self._animating_lock = 1
            for widget in widgets: widget['color'] = colors[0]
            self._top.after(50, self._animate_backtrack_frame,
                            widgets, colors[1:])
        else:
            for widget in widgets[0].subtrees():
                widgets[0].remove_child(widget)
                widget.destroy()
            self._redraw_quick()
            self._animating_lock = 0
            if self._autostep: self._step()

    def _animate_match_backtrack(self, treeloc):
        widget = self._get(self._tree, treeloc)
        node = widget.parent().label()
        dy = (1.0 * (node.bbox()[3] - widget.bbox()[1] + 14) /
              max(1, self._animation_frames.get()))
        self._animate_match_backtrack_frame(self._animation_frames.get(),
                                            widget, dy)

    def _animate_match(self, treeloc):
        widget = self._get(self._tree, treeloc)

        dy = ((self._textwidgets[0].bbox()[1] - widget.bbox()[3] - 10.0) /
              max(1, self._animation_frames.get()))
        self._animate_match_frame(self._animation_frames.get(), widget, dy)

    def _animate_match_frame(self, frame, widget, dy):
        if frame > 0:
            self._animating_lock = 1
            widget.move(0, dy)
            self._top.after(10, self._animate_match_frame,
                            frame-1, widget, dy)
        else:
            widget['color'] = '#006040'
            self._redraw_quick()
            self._animating_lock = 0
            if self._autostep: self._step()

    def _animate_match_backtrack_frame(self, frame, widget, dy):
        if frame > 0:
            self._animating_lock = 1
            widget.move(0, dy)
            self._top.after(10, self._animate_match_backtrack_frame,
                            frame-1, widget, dy)
        else:
            widget.parent().remove_child(widget)
            widget.destroy()
            self._animating_lock = 0
            if self._autostep: self._step()

    def edit_grammar(self, *e):
        CFGEditor(self._top, self._parser.grammar(), self.set_grammar)

    def set_grammar(self, grammar):
        self._parser.set_grammar(grammar)
        self._productions = list(grammar.productions())
        self._prodlist.delete(0, 'end')
        for production in self._productions:
            self._prodlist.insert('end', (' %s' % production))

    def edit_sentence(self, *e):
        sentence = " ".join(self._sent)
        title = 'Edit Text'
        instr = 'Enter a new sentence to parse.'
        EntryDialog(self._top, sentence, instr, self.set_sentence, title)

    def set_sentence(self, sentence):
        self._sent = sentence.split() #[XX] use tagged?
        self.reset()
Ejemplo n.º 24
0
class ChooseFiles(tk.Frame):
    '''The main frame for adding/removing files, accessing setttings
       and parsing.'''

    from seebeck.parse import GUIParse

    opts = SimpleNamespace(in_files=[],
                           out_dir=os.path.join(os.getcwd(), 'parsed'),
                           out_file='',
                           plot=True,
                           write=True,
                           truetemp=False,
                           col_to_parse=1,
                           dTn=[],
                           cuttoff_to_toss=100)  # TODO: Make this a user option
    raw_data = {}
    gothreads = []
    plots = []
    outdir = ''
    boolmap = {1: True, 0: False}
    colmap = {1:'Raw Voltage (uV)',
              2:'Corrected Voltage (uV)',
              3:'Top T',
              4:'Bottom T',
              5:'Delta-T (°C)',
              6:'Seebeck (uV/K)'}

    FileListBoxFrameLabelVar = None
    FileListBoxFrameLabel = None
    filelist = None
    FileListBox = None
    checks = []
    OutputFileName = None
    DeltaTn = None
    OptionsColString = None
    OptionCol = None

    def __init__(self, master=None):
        if master is None:
            master = Tk()
        super().__init__(master)
        bgimg = PhotoImage(file=os.path.join(absdir, 'gui', 'RCCLabFluidic.png'))
        limg = Label(self.master, i=bgimg, background=GREY)
        limg.pack(side=TOP)
        try:
            self.last_input_path = os.getcwd()
        except KeyError:
            self.last_input_path = os.path.expanduser('~')
        master.tk_setPalette(background=GREY, activeBackground=GREY)
        master.title("RCCLab Rick-9000 Parser")
        master.geometry('800x850+250+250')
        self.pack(fill=BOTH)
        if len(sys.argv) > 1:
            self.opts.in_files = sys.argv[1:]
        self.__createWidgets()
        self.ToFront()

    def __createWidgets(self):

        self.ButtonFrame = tk.Frame(self)
        self.LoggingFrame = tk.Frame(self)
        self.RightOptionsFrame = tk.Frame(self)
        self.FileListBoxFrame = tk.Frame(self)

        # ScrolledText widget to display logging output
        stlogger = ScrolledText.ScrolledText(self.LoggingFrame, state='disabled')
        stlogger.configure(font='TkFixedFont')
        stlogger.pack(side=LEFT, fill=BOTH, expand=True)
        # Create textLogger
        text_handler = TextHandler(stlogger)

        # Logging configuration
        logging.basicConfig(filename='Rick-9000.log',
                            level=logging.INFO,
                            format='%(asctime)s - %(levelname)s - %(message)s')

        # Add the handler to logger
        logger = logging.getLogger(__package__)
        logger.addHandler(text_handler)

        self.__createButtons()
        self.__createFileListBox()
        self.__createOptions()

        self.ButtonFrame.pack(side=BOTTOM, fill=None)
        self.FileListBoxFrame.pack(side=TOP, fill=BOTH, expand=True)
        self.RightOptionsFrame.pack(side=RIGHT, fill=Y)
        self.LoggingFrame.pack(side=BOTTOM, fill=BOTH)

        # self.logger.setLevel(getattr(logging, self.opts.loglevel.upper()))
        self.updateFileListBox()
        self.checkOptions()
        logging.info('Select some files to get started.')

    def __createButtons(self):

        buttons = [{'name': 'Quit', 'text': 'QUIT', 'command': 'Quit', 'side': BOTTOM},
                   {'name': 'SpawnInputDialog', 'text': 'Add Input Files', 'side': LEFT},
                   {'name': 'RemoveFile', 'text': 'Remove Files', 'side': LEFT},
                   {'name': 'SpawnOutputDialog', 'text': 'Choose Output Directory', 'side': LEFT},
                   {'name': 'Parse', 'text': 'Parse!', 'side': LEFT}
                   ]

        for b in buttons:
            button = tk.Button(self.ButtonFrame)
            button.config(text=b['text'], command=getattr(self, b['name']+'Click'))
            button.pack(side=b['side'])
            setattr(self, 'Button'+b['name'], button)

    def __createFileListBox(self):
        self.FileListBoxFrameLabelVar = StringVar()
        self.FileListBoxFrameLabel = tk.Label(self.FileListBoxFrame,
                                              textvariable=self.FileListBoxFrameLabelVar,
                                              font=Font(size=10, weight="bold"))
        self.FileListBoxFrameLabel.pack(side=TOP, fill=X)

        yScroll = tk.Scrollbar(self.FileListBoxFrame, orient=VERTICAL)
        yScroll.pack(side=RIGHT, fill=Y)
        xScroll = tk.Scrollbar(self.FileListBoxFrame, orient=HORIZONTAL)
        xScroll.pack(side=BOTTOM, fill=X)
        self.filelist = StringVar()
        self.FileListBox = Listbox(self.FileListBoxFrame,
                                   listvariable=self.filelist, selectmode=EXTENDED,
                                   height=20, width=0, relief=RAISED, bd=1,
                                   bg=WHITE,
                                   # font=Font(size=10),
                                   xscrollcommand=xScroll.set,
                                   yscrollcommand=yScroll.set)
        xScroll['command'] = self.FileListBox.xview
        yScroll['command'] = self.FileListBox.yview
        self.FileListBox.pack(side=LEFT, fill=BOTH, expand=True)
        self.UpdateFileListBoxFrameLabel()

    def __createOptions(self):
        '''Create the widgets for options and use setattr to assign them to self.'''
        self.checks = [{'name': 'plot', 'text': 'Plot', 'row': 1,
                        'tooltip': "Show summary plots after parsing."},
                       {'name': 'write', 'text': 'Write', 'row': 2,
                        'tooltip': "Write results to text files after parsing."},
                       {'name': 'truetemp', 'text': 'Use Real T', 'row': 3,
                        'tooltip': "Use the measured ΔT instead the ΔT field values."}
                       ]

        for _c in self.checks:
            setattr(self, _c['name'], IntVar())
            check = tk.Checkbutton(self.RightOptionsFrame, text=_c['text'],
                                   variable=getattr(self, _c['name']),
                                   command=self.checkOptions)
            check.grid(column=0, row=_c['row'], sticky=W)
            createToolTip(check, _c['tooltip'])
            setattr(self, 'Check_'+_c['name'], check)
            if getattr(self.opts, _c['name']):
                getattr(self, _c['name']).set(1)

        rowidx = len(self.checks)+1

        tk.Label(self.RightOptionsFrame, text="Output file base name:").grid(
            column=0, row=rowidx)
        self.OutputFileName = tk.Entry(self.RightOptionsFrame, width=20,
                                       font=Font(size=10, slant='italic'))
        for n in ('<Return>', '<Leave>', '<Enter>'):
            self.OutputFileName.bind(n, self.checkOutputFileName)
        self.OutputFileName.grid(column=0, row=rowidx+1)

        if self.opts.out_file:
            self.OutputFileName.insert(0, self.opts.out_file)

        tk.Label(self.RightOptionsFrame, text="ΔT values:").grid(
            column=0, row=rowidx+2, sticky=W)
        self.DeltaTn = tk.Entry(self.RightOptionsFrame, width=20,
                                font=Font(size=10))
        self.DeltaTn.insert(0, '4,8,12')
        for n in ('<Return>', '<Leave>', '<Enter>'):
            self.DeltaTn.bind(None, self.checkOptions)
        self.DeltaTn.grid(column=0, row=rowidx+3, sticky=W)

        tk.Label(self.RightOptionsFrame, text="Column to plot:").grid(
            column=0, row=rowidx+4, sticky=W)
        self.OptionsColString = StringVar()
        self.OptionsColString.set(self.opts.col_to_parse)
        self.OptionCol = tk.OptionMenu(self.RightOptionsFrame,
                                       self.OptionsColString,
                                       self.colmap[self.opts.col_to_parse],
                                       command=self.checkOptions,
                                       *list(self.colmap.values()))
        # __menu = self.nametowidget(self.OptionCol)
        # __menu.config(font=Font(size=10))  # Set the dropdown menu's font
        self.OptionCol.grid(column=0, row=rowidx+5, sticky=W)

        # tk.Label(self.RightOptionsFrame, text="ΔT values:").grid(
        #     column=0, row=rowidx+2, sticky=W)
        # self.OptionsdTnString = StringVar()
        # self.OptionsdTnString.set('.'.join(self.opts.dTn))
        # self.OptionPlots = tk.OptionMenu(self.RightOptionsFrame,
        #                                  self.OptionsdTnString, self.opts.dTn, 'J', 'R',
        #                                  command=self.checkOptions)
        # self.OptionPlots.grid(column=0, row=rowidx+3, sticky=W)

    def RemoveFileClick(self):
        self.checkOptions()
        selected = [self.FileListBox.get(x) for x in self.FileListBox.curselection()]
        todel = []
        filelist = []
        for i in range(0, len(self.opts.in_files)):
            for _s in selected:
                if self.opts.in_files[i].replace(" ", "_") == _s:
                    todel.append(i)

        for i in range(0, len(self.opts.in_files)):
            if i not in todel:
                filelist.append(self.opts.in_files[i])
        self.opts.in_files = filelist
        self.updateFileListBox()
        self.FileListBox.selection_clear(0, END)

    def SpawnInputDialogClick(self):
        # self.checkOptions()
        self.opts.in_files += filedialog.askopenfilename(
            title="Files to parse",
            multiple=True,
            initialdir=self.last_input_path,
            filetypes=[('LabView Files', '*.lvm'), ('Data files', '*_data.txt'),
                       ('Text files', '*.txt'), ('All files', '*')])
        if self.opts.in_files:
            self.last_input_path = os.path.split(self.opts.in_files[0])[0]
            if not self.outdir:
                self.opts.out_dir = self.last_input_path
            self.updateFileListBox()
            if not self.opts.out_file:
                self.OutputFileName.delete(0, END)
                self.OutputFileName.insert(0, os.path.basename(
                    self.opts.in_files[-1]).lower().replace('.lvm', ''))
                self.checkOutputFileName()
        self.updateFileListBox()

    def ParseClick(self):
        self.checkOptions()
        self.GUIParse()

    def checkOptions(self, m=None):
        for c in self.checks:
            setattr(self.opts, c['name'], self.boolmap[getattr(self, c['name']).get()])
        if self.opts.truetemp:
            self.DeltaTn['state'] = DISABLED
        else:
            self.DeltaTn['state'] = NORMAL
        self.opts.dTn = self.DeltaTn.get().split(',')

        for __key in self.colmap:
            if self.colmap[__key] == self.OptionsColString.get():
                self.opts.col_to_parse = __key

    def updateFileListBox(self):
        self.filelist.set(" ".join([x.replace(" ", "_") for x in self.opts.in_files]))

    def SpawnOutputDialogClick(self):
        outdir = filedialog.askdirectory(title="Select Output File(s)",
                                         initialdir=self.opts.out_dir)
        if not outdir:
            return
        if os.path.exists(outdir):
            self.opts.out_dir = outdir
            self.outdir = self.opts.out_dir  # So we know the user set the output dir
            self.UpdateFileListBoxFrameLabel()

    def UpdateFileListBoxFrameLabel(self):
        self.FileListBoxFrameLabelVar.set(
            f"Output to: {self.opts.out_dir}/{self.opts.out_file}_*.txt")

    def checkOutputFileName(self, event=None):
        self.opts.out_file = self.OutputFileName.get()
        self.UpdateFileListBoxFrameLabel()

    def QuitClick(self):
        self.Quit()

    def Quit(self):
        self.master.destroy()

    def ToFront(self):
        '''Try to bring the main window to the front on different platforms'''
        if platform.system() == "Darwin":
            os.system(
                '''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''')
        else:
            self.master.attributes('-topmost', 1)
            self.master.attributes('-topmost', 0)
        self.master.lift()
class index_select(Frame):
    def __init__(self,controller,current_model,master,*args,**kwargs):
        self.controller = controller
        self.current_model = current_model
        self.filtered_list = None
        self.saved_selection = None

        from tkinter import EXTENDED,Scrollbar,Y

        #dibujar widget
        super().__init__(master, *args, **kwargs)

        f_st=Frame(self)
        Label(f_st,text="Current_index: ").pack()
        Label(f_st, text="Current_filter: ").pack()
        f_st.pack()

        frame_index_listbox = Frame(self)
        self.listbox = Listbox(frame_index_listbox, exportselection=False,selectmode=EXTENDED)
        self.listbox.pack(side=LEFT)

        scrollbar = Scrollbar(frame_index_listbox)
        scrollbar.pack(side=LEFT, fill=Y)
        frame_index_listbox.pack()


        # attach listbox to scrollbar
        self.listbox.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.listbox.yview)

        f=Frame(self)
        Label(f,text="Filtro: ").pack(side=LEFT)
        self.entry_w = Entry(f)
        self.entry_w.pack(side=LEFT)
        f.pack()

        f2=Frame(self)
        Button(f2, text='Filter',command=self.filter_indexs).pack(side=LEFT)
        Button(f2,text='Clean Filter',command=self.clean_filter).pack(side=LEFT)
        Button(f2, text='Export sel for gen',command=self.export_selection).pack(side=LEFT)
        f2.pack()

        f3=Frame(self)
        Button(self, text='<<',command=self.next_prev(-1)).pack(side=LEFT)
        Button(self, text='>>',command=self.next_prev(1)).pack(side=LEFT)
        f3.pack()

        self.update_model(current_model)
        self.listbox.select_set(0)
        self.listbox.event_generate("<<ListboxSelect>>")
        self.listbox.bind('<<ListboxSelect>>', self.selection)

    def filter_indexs(self):
        import random
        path_filter = self.entry_w.get()
        with open(path_filter,'r') as f:
            indexs_list_str = f.read().strip()
        random.seed(3)
        indexs_list = list(set(indexs_list_str.split('\n')))
        print(len(indexs_list))
        random.shuffle(indexs_list)

        self.filtered_list = indexs_list
        self.listbox.delete(0, END)
        for item in indexs_list:
            self.listbox.insert(END, item)

    def clean_filter(self):
        self.filtered_list = None
        self.update_model(self.current_model)
        self.listbox.delete(0, END)
        for item in sorted(self.index_list):
            self.listbox.insert(END, item)
        self.saved_selection = None

    def export_selection(self):
        sel_files_folder = os.path.join('config_files','select_files')
        os.makedirs(sel_files_folder,exist_ok=True)

        sel_list = self.listbox.curselection()
        index_list = [self.listbox.get(ind) for ind in sel_list]
        print("Exporting list for image generator. List: {0}".format(index_list))
        now_s = now_string()
        out_selection_file = {'index_list' : index_list,
                              'train_result_path': self.current_model.current_config_file,
                              'details' : '',
                              'mask_file' : self.current_model.current_mask_file}
        sel_file_name = "{0}_{1}_{2}_selection.json".format(self.current_model.classifier_key,self.current_model.dataset_key,now_s)
        sel_path = os.path.join(sel_files_folder,sel_file_name)
        with open(sel_path,'w') as f:
            json.dump(out_selection_file,f)
        print("Select in {0}".format(sel_path))

    def update_model(self, current_model):
        self.model = current_model
        self.index_list = self.model.get_index_list()
        self.current_index = self.model.get_current_index()
        self.mask_list = self.model.get_current_mask_index_list()

        indexs_list = self.filtered_list if self.filtered_list else sorted(self.index_list)

        self.listbox.delete(0, END)
        for item in indexs_list:
            self.listbox.insert(END, item)

        if self.saved_selection:
            ind,ypos = self.saved_selection
            self.listbox.selection_set(ind)
            self.listbox.yview_moveto(ypos[0])  # go back to that position

    def next_prev(self,x):
        def selection():
            ind_l = self.index_list.index(self.current_index)
            n = len(self.index_list)
            n_ind_l = (ind_l+x) % n
            next = self.index_list[n_ind_l]
            self.current_index = next
            self.listbox.selection_clear(0, END)
            self.listbox.select_set(n_ind_l)
            self.controller.event_change_index(next)

        return selection

    def selection(self,event):
        w = event.widget
        index = int(w.curselection()[0])
        value = w.get(index)
        print("v: {0}".format(value))
        selected_index = value
        self.current_index = selected_index
        self.controller.event_change_index(selected_index)
        self.saved_selection = (index,self.listbox.yview())

        pass
Ejemplo n.º 26
0
class DrtGlueDemo:
    def __init__(self, examples):
        # Set up the main window.
        self._top = Tk()
        self._top.title("DRT Glue Demo")

        # Set up key bindings.
        self._init_bindings()

        # Initialize the fonts.self._error = None
        self._init_fonts(self._top)

        self._examples = examples
        self._readingCache = [None for example in examples]

        # The user can hide the grammar.
        self._show_grammar = IntVar(self._top)
        self._show_grammar.set(1)

        # Set the data to None
        self._curExample = -1
        self._readings = []
        self._drs = None
        self._drsWidget = None
        self._error = None

        self._init_glue()

        # Create the basic frames.
        self._init_menubar(self._top)
        self._init_buttons(self._top)
        self._init_exampleListbox(self._top)
        self._init_readingListbox(self._top)
        self._init_canvas(self._top)

        # Resize callback
        self._canvas.bind("<Configure>", self._configure)

    #########################################
    ##  Initialization Helpers
    #########################################

    def _init_glue(self):
        tagger = RegexpTagger([
            ("^(David|Mary|John)$", "NNP"),
            (
                "^(walks|sees|eats|chases|believes|gives|sleeps|chases|persuades|tries|seems|leaves)$",
                "VB",
            ),
            ("^(go|order|vanish|find|approach)$", "VB"),
            ("^(a)$", "ex_quant"),
            ("^(every)$", "univ_quant"),
            ("^(sandwich|man|dog|pizza|unicorn|cat|senator)$", "NN"),
            ("^(big|gray|former)$", "JJ"),
            ("^(him|himself)$", "PRP"),
        ])

        depparser = MaltParser(tagger=tagger)
        self._glue = DrtGlue(depparser=depparser, remove_duplicates=False)

    def _init_fonts(self, root):
        # See: <http://www.astro.washington.edu/owen/ROTKFolklore.html>
        self._sysfont = Font(font=Button()["font"])
        root.option_add("*Font", self._sysfont)

        # TWhat's our font size (default=same as sysfont)
        self._size = IntVar(root)
        self._size.set(self._sysfont.cget("size"))

        self._boldfont = Font(family="helvetica",
                              weight="bold",
                              size=self._size.get())
        self._font = Font(family="helvetica", size=self._size.get())
        if self._size.get() < 0:
            big = self._size.get() - 2
        else:
            big = self._size.get() + 2
        self._bigfont = Font(family="helvetica", weight="bold", size=big)

    def _init_exampleListbox(self, parent):
        self._exampleFrame = listframe = Frame(parent)
        self._exampleFrame.pack(fill="both", side="left", padx=2)
        self._exampleList_label = Label(self._exampleFrame,
                                        font=self._boldfont,
                                        text="Examples")
        self._exampleList_label.pack()
        self._exampleList = Listbox(
            self._exampleFrame,
            selectmode="single",
            relief="groove",
            background="white",
            foreground="#909090",
            font=self._font,
            selectforeground="#004040",
            selectbackground="#c0f0c0",
        )

        self._exampleList.pack(side="right", fill="both", expand=1)

        for example in self._examples:
            self._exampleList.insert("end", ("  %s" % example))
        self._exampleList.config(height=min(len(self._examples), 25), width=40)

        # Add a scrollbar if there are more than 25 examples.
        if len(self._examples) > 25:
            listscroll = Scrollbar(self._exampleFrame, orient="vertical")
            self._exampleList.config(yscrollcommand=listscroll.set)
            listscroll.config(command=self._exampleList.yview)
            listscroll.pack(side="left", fill="y")

        # If they select a example, apply it.
        self._exampleList.bind("<<ListboxSelect>>", self._exampleList_select)

    def _init_readingListbox(self, parent):
        self._readingFrame = listframe = Frame(parent)
        self._readingFrame.pack(fill="both", side="left", padx=2)
        self._readingList_label = Label(self._readingFrame,
                                        font=self._boldfont,
                                        text="Readings")
        self._readingList_label.pack()
        self._readingList = Listbox(
            self._readingFrame,
            selectmode="single",
            relief="groove",
            background="white",
            foreground="#909090",
            font=self._font,
            selectforeground="#004040",
            selectbackground="#c0f0c0",
        )

        self._readingList.pack(side="right", fill="both", expand=1)

        # Add a scrollbar if there are more than 25 examples.
        listscroll = Scrollbar(self._readingFrame, orient="vertical")
        self._readingList.config(yscrollcommand=listscroll.set)
        listscroll.config(command=self._readingList.yview)
        listscroll.pack(side="right", fill="y")

        self._populate_readingListbox()

    def _populate_readingListbox(self):
        # Populate the listbox with integers
        self._readingList.delete(0, "end")
        for i in range(len(self._readings)):
            self._readingList.insert("end", ("  %s" % (i + 1)))
        self._readingList.config(height=min(len(self._readings), 25), width=5)

        # If they select a example, apply it.
        self._readingList.bind("<<ListboxSelect>>", self._readingList_select)

    def _init_bindings(self):
        # Key bindings are a good thing.
        self._top.bind("<Control-q>", self.destroy)
        self._top.bind("<Control-x>", self.destroy)
        self._top.bind("<Escape>", self.destroy)
        self._top.bind("n", self.next)
        self._top.bind("<space>", self.next)
        self._top.bind("p", self.prev)
        self._top.bind("<BackSpace>", self.prev)

    def _init_buttons(self, parent):
        # Set up the frames.
        self._buttonframe = buttonframe = Frame(parent)
        buttonframe.pack(fill="none", side="bottom", padx=3, pady=2)
        Button(
            buttonframe,
            text="Prev",
            background="#90c0d0",
            foreground="black",
            command=self.prev,
        ).pack(side="left")
        Button(
            buttonframe,
            text="Next",
            background="#90c0d0",
            foreground="black",
            command=self.next,
        ).pack(side="left")

    def _configure(self, event):
        self._autostep = 0
        (x1, y1, x2, y2) = self._cframe.scrollregion()
        y2 = event.height - 6
        self._canvas["scrollregion"] = "%d %d %d %d" % (x1, y1, x2, y2)
        self._redraw()

    def _init_canvas(self, parent):
        self._cframe = CanvasFrame(
            parent,
            background="white",
            # width=525, height=250,
            closeenough=10,
            border=2,
            relief="sunken",
        )
        self._cframe.pack(expand=1, fill="both", side="top", pady=2)
        canvas = self._canvas = self._cframe.canvas()

        # Initially, there's no tree or text
        self._tree = None
        self._textwidgets = []
        self._textline = None

    def _init_menubar(self, parent):
        menubar = Menu(parent)

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

        actionmenu = Menu(menubar, tearoff=0)
        actionmenu.add_command(label="Next",
                               underline=0,
                               command=self.next,
                               accelerator="n, Space")
        actionmenu.add_command(label="Previous",
                               underline=0,
                               command=self.prev,
                               accelerator="p, Backspace")
        menubar.add_cascade(label="Action", underline=0, menu=actionmenu)

        optionmenu = Menu(menubar, tearoff=0)
        optionmenu.add_checkbutton(
            label="Remove Duplicates",
            underline=0,
            variable=self._glue.remove_duplicates,
            command=self._toggle_remove_duplicates,
            accelerator="r",
        )
        menubar.add_cascade(label="Options", underline=0, menu=optionmenu)

        viewmenu = Menu(menubar, tearoff=0)
        viewmenu.add_radiobutton(
            label="Tiny",
            variable=self._size,
            underline=0,
            value=10,
            command=self.resize,
        )
        viewmenu.add_radiobutton(
            label="Small",
            variable=self._size,
            underline=0,
            value=12,
            command=self.resize,
        )
        viewmenu.add_radiobutton(
            label="Medium",
            variable=self._size,
            underline=0,
            value=14,
            command=self.resize,
        )
        viewmenu.add_radiobutton(
            label="Large",
            variable=self._size,
            underline=0,
            value=18,
            command=self.resize,
        )
        viewmenu.add_radiobutton(
            label="Huge",
            variable=self._size,
            underline=0,
            value=24,
            command=self.resize,
        )
        menubar.add_cascade(label="View", underline=0, menu=viewmenu)

        helpmenu = Menu(menubar, tearoff=0)
        helpmenu.add_command(label="About", underline=0, command=self.about)
        menubar.add_cascade(label="Help", underline=0, menu=helpmenu)

        parent.config(menu=menubar)

    #########################################
    ##  Main draw procedure
    #########################################

    def _redraw(self):
        canvas = self._canvas

        # Delete the old DRS, widgets, etc.
        if self._drsWidget is not None:
            self._drsWidget.clear()

        if self._drs:
            self._drsWidget = DrsWidget(self._canvas, self._drs)
            self._drsWidget.draw()

        if self._error:
            self._drsWidget = DrsWidget(self._canvas, self._error)
            self._drsWidget.draw()

    #########################################
    ##  Button Callbacks
    #########################################

    def destroy(self, *e):
        self._autostep = 0
        if self._top is None:
            return
        self._top.destroy()
        self._top = None

    def prev(self, *e):
        selection = self._readingList.curselection()
        readingListSize = self._readingList.size()

        # there are readings
        if readingListSize > 0:
            # if one reading is currently selected
            if len(selection) == 1:
                index = int(selection[0])

                # if it's on (or before) the first item
                if index <= 0:
                    self._select_previous_example()
                else:
                    self._readingList_store_selection(index - 1)

            else:
                # select its first reading
                self._readingList_store_selection(readingListSize - 1)

        else:
            self._select_previous_example()

    def _select_previous_example(self):
        # if the current example is not the first example
        if self._curExample > 0:
            self._exampleList_store_selection(self._curExample - 1)
        else:
            # go to the last example
            self._exampleList_store_selection(len(self._examples) - 1)

    def next(self, *e):
        selection = self._readingList.curselection()
        readingListSize = self._readingList.size()

        # if there are readings
        if readingListSize > 0:
            # if one reading is currently selected
            if len(selection) == 1:
                index = int(selection[0])

                # if it's on (or past) the last item
                if index >= (readingListSize - 1):
                    self._select_next_example()
                else:
                    self._readingList_store_selection(index + 1)

            else:
                # select its first reading
                self._readingList_store_selection(0)

        else:
            self._select_next_example()

    def _select_next_example(self):
        # if the current example is not the last example
        if self._curExample < len(self._examples) - 1:
            self._exampleList_store_selection(self._curExample + 1)
        else:
            # go to the first example
            self._exampleList_store_selection(0)

    def about(self, *e):
        ABOUT = (
            "NLTK Discourse Representation Theory (DRT) Glue Semantics Demo\n"
            + "Written by Daniel H. Garrette")
        TITLE = "About: NLTK DRT Glue Demo"
        try:
            from tkinter.messagebox import Message

            Message(message=ABOUT, title=TITLE).show()
        except:
            ShowText(self._top, TITLE, ABOUT)

    def postscript(self, *e):
        self._autostep = 0
        self._cframe.print_to_file()

    def mainloop(self, *args, **kwargs):
        """
        Enter the Tkinter mainloop.  This function must be called if
        this demo is created from a non-interactive program (e.g.
        from a secript); otherwise, the demo will close as soon as
        the script completes.
        """
        if in_idle():
            return
        self._top.mainloop(*args, **kwargs)

    def resize(self, size=None):
        if size is not None:
            self._size.set(size)
        size = self._size.get()
        self._font.configure(size=-(abs(size)))
        self._boldfont.configure(size=-(abs(size)))
        self._sysfont.configure(size=-(abs(size)))
        self._bigfont.configure(size=-(abs(size + 2)))
        self._redraw()

    def _toggle_remove_duplicates(self):
        self._glue.remove_duplicates = not self._glue.remove_duplicates

        self._exampleList.selection_clear(0, "end")
        self._readings = []
        self._populate_readingListbox()
        self._readingCache = [None for ex in self._examples]
        self._curExample = -1
        self._error = None

        self._drs = None
        self._redraw()

    def _exampleList_select(self, event):
        selection = self._exampleList.curselection()
        if len(selection) != 1:
            return
        self._exampleList_store_selection(int(selection[0]))

    def _exampleList_store_selection(self, index):
        self._curExample = index
        example = self._examples[index]

        self._exampleList.selection_clear(0, "end")
        if example:
            cache = self._readingCache[index]
            if cache:
                if isinstance(cache, list):
                    self._readings = cache
                    self._error = None
                else:
                    self._readings = []
                    self._error = cache
            else:
                try:
                    self._readings = self._glue.parse_to_meaning(example)
                    self._error = None
                    self._readingCache[index] = self._readings
                except Exception as e:
                    self._readings = []
                    self._error = DrtVariableExpression(
                        Variable("Error: " + str(e)))
                    self._readingCache[index] = self._error

                    # add a star to the end of the example
                    self._exampleList.delete(index)
                    self._exampleList.insert(index, ("  %s *" % example))
                    self._exampleList.config(height=min(
                        len(self._examples), 25),
                                             width=40)

            self._populate_readingListbox()

            self._exampleList.selection_set(index)

            self._drs = None
            self._redraw()

    def _readingList_select(self, event):
        selection = self._readingList.curselection()
        if len(selection) != 1:
            return
        self._readingList_store_selection(int(selection[0]))

    def _readingList_store_selection(self, index):
        reading = self._readings[index]

        self._readingList.selection_clear(0, "end")
        if reading:
            self._readingList.selection_set(index)

            self._drs = reading.simplify().normalize().resolve_anaphora()

            self._redraw()
Ejemplo n.º 27
0
class Trace(Module):
    '''
    Module to manage all of the different traces (with unique names/colors) and the
    Crosshairs objects associated to each one.  In particular, handles creation/modfication
    of traces and crosshairs.
    '''
    def __init__(self, app):
        info(' - initializing module: Trace')

        self.app = app

        # some images for the buttons
        # Source for icons: https://material.io/tools/icons/?style=outline
        # License: Apache Version 2.0 www.apache.org/licenses/LICENSE-2.0.txt
        data_copy = '''R0lGODlhGAAYAPAAAAAAAAAAACH5BAEAAAEALAAAAAAYABgAAAJHjI+pCe3/1oHUSdOunmDvHFTWBYrjUnbMuWIqAqEqCMdt+HI25yrVTZMEcT3NMPXJEZckJdKorCWbU2H0JqvKTBErl+XZFAAAOw'''
        data_paste = '''R0lGODlhGAAYAPAAAAAAAAAAACH5BAEAAAEALAAAAAAYABgAAAJBjI+pq+DAonlPToqza7rv9FlBeJCSOUJpd3EXm7piDKoi+nkqvnttPaMhUAzeiwJMapJDm8U44+kynCkmiM1qZwUAOw'''

        self.img_copy = PhotoImage(data=data_copy)
        self.img_paste = PhotoImage(data=data_paste)

        self.displayedColour = None
        #self.app.Data.getCurrentTraceColor()

        # array of trace names for this directory
        self.available = self.app.Data.getTopLevel('traces')
        self.available = [] if self.available == None else self.available

        # dictionary to hold trace -> [crosshairs] data
        self.crosshairs = {}

        # set of currently selected crosshairs
        self.selected = set()

        # set of copied crosshairs
        self.copied = []

        # declare & init trace string variable
        self.traceSV = StringVar()
        self.traceSV.set('')

        # frame for (most of) our widgets
        self.frame = Frame(self.app.LEFT)  #, pady=7, padx=7)
        self.frame.grid(row=4)

        # listbox to contain all of our traces
        lbframe = Frame(self.frame)
        self.scrollbar = Scrollbar(lbframe)
        self.listbox = Listbox(lbframe,
                               yscrollcommand=self.scrollbar.set,
                               width=12,
                               exportselection=False,
                               takefocus=0)
        self.scrollbar.config(command=self.listbox.yview)
        for trace in self.available:
            self.listbox.insert('end', trace)
        for i, item in enumerate(self.listbox.get(0, 'end')):
            # select our "default trace"
            if item == self.app.Data.getTopLevel('defaultTraceName'):
                self.listbox.selection_clear(0, 'end')
                self.listbox.select_set(i)

        # this module is responsible for so many widgets that we need a different
        # strategy for keeping track of everything that needs constistent grid() /
        # grid_remove() behavior
        self.TkWidgets = [
            self.getWidget(Header(self.frame, text="Choose a trace"),
                           row=5,
                           column=0,
                           columnspan=4),
            self.getWidget(lbframe, row=10, column=0, rowspan=50),
            self.getWidget(Button(self.frame,
                                  text='Set as default',
                                  command=self.setDefaultTraceName,
                                  takefocus=0),
                           row=10,
                           column=2,
                           columnspan=2),
            self.getWidget(Button(self.frame,
                                  text='Select all',
                                  command=self.selectAll,
                                  takefocus=0),
                           row=11,
                           column=2,
                           columnspan=2),
            self.getWidget(Button(self.frame,
                                  image=self.img_copy,
                                  command=self.copy,
                                  takefocus=0),
                           row=12,
                           column=2),  # FIXME: add tooltip for "Copy"
            self.getWidget(Button(self.frame,
                                  image=self.img_paste,
                                  command=self.paste,
                                  takefocus=0),
                           row=12,
                           column=3),  # FIXME: add tooltip for "Paste"
            self.getWidget(Entry(self.frame,
                                 width=8,
                                 textvariable=self.displayedColour),
                           row=13,
                           column=1,
                           columnspan=2,
                           sticky='w'),
            self.getWidget(Button(self.frame,
                                  text='Recolor',
                                  command=self.recolor,
                                  takefocus=0),
                           row=13,
                           column=3),
            self.getWidget(Button(self.frame,
                                  text='Clear',
                                  command=self.clear,
                                  takefocus=0),
                           row=15,
                           column=2,
                           columnspan=2),
            self.getWidget(Entry(self.frame,
                                 width=12,
                                 textvariable=self.traceSV),
                           row=100,
                           column=0,
                           sticky='w'),
            self.getWidget(Button(self.frame,
                                  text='New',
                                  command=self.newTrace,
                                  takefocus=0),
                           row=100,
                           column=2),
            self.getWidget(Button(self.frame,
                                  text='Rename',
                                  command=self.renameTrace,
                                  takefocus=0),
                           row=100,
                           column=3)
        ]

        # there's probably a better way to do this than indexing into self.TkWidgets
        self.TkWidgets[6]['widget'].bind(
            '<Return>', lambda ev: self.TkWidgets[0]['widget'].focus())
        self.TkWidgets[6]['widget'].bind(
            '<Escape>', lambda ev: self.TkWidgets[0]['widget'].focus())
        self.TkWidgets[9]['widget'].bind(
            '<Return>', lambda ev: self.TkWidgets[0]['widget'].focus())
        self.TkWidgets[9]['widget'].bind(
            '<Escape>', lambda ev: self.TkWidgets[0]['widget'].focus())

        if util.get_platform() == 'Linux':
            self.app.bind('<Control-r>', self.recolor)
            self.app.bind('<Control-c>', self.copy)
            self.app.bind('<Control-v>', self.paste)
        else:
            self.app.bind('<Command-r>', self.recolor)
            self.app.bind('<Command-c>', self.copy)
            self.app.bind('<Command-v>', self.paste)
        self.grid()

    def update(self):
        ''' on change frames '''
        # self.grid()
        #NOTE this is called during zoom and pan
        #this means the crosshairs are redrawn for every <Motion> call, which is a lot
        #we could probably just move them instead
        self.reset()  # clear our crosshairs
        self.read()  # read from file
        #self.frame.update()
        #debug("TraceModule", self.frame.winfo_width())
    def reset(self):
        ''' on change files '''
        # undraw all the crosshairs
        for trace in self.crosshairs:
            for ch in self.crosshairs[trace]:
                ch.undraw()
        # and empty out our trackers
        self.crosshairs = {}
        self.selected = set()

    def add(self, x, y, _trace=None, transform=True):
        '''
        add a crosshair to the zoom frame canvas
        '''

        trace = self.getCurrentTraceName() if _trace == None else _trace
        color = self.available[trace]['color']
        ch = Crosshairs(self.app.Dicom.zframe, x, y, color, transform)
        if trace not in self.crosshairs:
            self.crosshairs[trace] = []
        self.crosshairs[trace].append(ch)
        return ch

    def remove(self, ch, write=True):
        '''
        remove a crosshair from the zoom frame canvas ... doesn't actually remove it
        but instead just makes it "invisible"
        '''

        ch.undraw()
        if write:
            self.write()
        return ch

    def move(self):
        ''' called when window resizes to move to correct relative locations'''
        # trace = self.getCurrentTraceName()
        if self.crosshairs:
            for trace in self.crosshairs:
                for ch in self.crosshairs[trace]:
                    truex, truey = ch.getTrueCoords()
                    ch.x, ch.y = ch.transformTrueToCoords(truex, truey)
                    ch.dragTo((ch.x, ch.y))

    def read(self):
        '''
        read a list of crosshair coordinates from the metadata file
        '''
        frame = self.app.frame
        for trace in self.available:
            try:
                newCrosshairs = []
                for item in self.app.Data.getTraceCurrentFrame(trace):
                    ch = self.add(item['x'],
                                  item['y'],
                                  _trace=trace,
                                  transform=False)
                    if trace not in self.crosshairs:
                        self.crosshairs[trace] = []
                    self.crosshairs[trace].append(ch)
                    newCrosshairs.append(ch)
                self.app.Control.push({'type': 'add', 'chs': newCrosshairs})
            except KeyError:
                pass

    def write(self):
        '''
        write out the coordinates of all of our crosshairs to the metadata file:
        '''

        trace = self.getCurrentTraceName()
        traces = []

        # prepare trace data in format for metadata array
        if trace in self.crosshairs:
            for ch in self.crosshairs[trace]:
                if ch.isVisible:
                    x, y = ch.getTrueCoords()
                    data = {'x': x, 'y': y}
                    if data not in traces:
                        # add trace to temporary array for including in metadata array
                        traces.append(data)
        # add to metadata array and update file
        self.app.Data.setCurrentTraceCurrentFrame(traces)
        # update tier labels for number of annotated frames
        self.app.TextGrid.updateTierLabels()

    def getCurrentTraceName(self):
        '''
        return string of current trace name
        '''

        try:
            return self.listbox.get(self.listbox.curselection())
        except Exception as e:  # tkinter.TclError?
            error('Can\'t select from empty listbox!', e)

    def setDefaultTraceName(self):
        '''
        wrapper for changing the default trace
        '''
        self.app.Data.setTopLevel('defaultTraceName',
                                  self.getCurrentTraceName())

    def select(self, ch):
        ''' select a crosshairs '''
        ch.select()
        self.selected.add(ch)

    def selectAll(self):
        ''' select all crosshairs '''
        if self.getCurrentTraceName() in self.crosshairs:
            for ch in self.crosshairs[self.getCurrentTraceName()]:
                self.select(ch)

    def unselect(self, ch):
        ''' unselect a crosshairs '''
        ch.unselect()
        self.selected.remove(ch)

    def unselectAll(self):
        ''' unselect all crosshairs '''
        for ch in self.selected:
            ch.unselect()
        self.selected = set()

    def getNearClickAllTraces(self, click):
        '''
        takes a click object ( (x,y) tuple ) and returns a list of crosshairs
        within _CROSSHAIR_SELECT_RADIUS

        first searches for crosshairs matching the current trace iterates
        thru the other traces if it doesnt find anything

        if nothing is found for any trace, returns None
        '''
        # get nearby crosshairs from this trace
        nearby = self.getNearClickOneTrace(click, self.getCurrentTraceName())
        if nearby != None:
            return nearby

        # otherwise
        else:
            # ... check our other traces to see if they contain any nearby guys
            for trace in self.available:
                nearby = self.getNearClickOneTrace(click, trace)
                # if we got something
                if nearby != None:
                    # switch to that trace and exit the loop
                    for i, item in enumerate(self.listbox.get(0, 'end')):
                        if item == trace:
                            self.listbox.selection_clear(0, 'end')
                            self.listbox.select_set(i)
                    return nearby

        return None

    def getNearClickOneTrace(self, click, trace):
        '''
        takes a click object and a trace and returns a list of crosshairs within
        util.CROSSHAIR_SELECT_RADIUS of that click
        '''

        # see if we clicked near any existing crosshairs
        possibleSelections = {}
        if trace in self.crosshairs:
            for ch in self.crosshairs[trace]:
                d = ch.getDistance(click)
                if d < util.CROSSHAIR_SELECT_RADIUS:
                    if d in possibleSelections:
                        possibleSelections[d].append(ch)
                    else:
                        possibleSelections[d] = [ch]

        # if we did ...
        if possibleSelections != {}:
            # ... get the closest one ...
            dMin = sorted(possibleSelections.keys())[0]
            # ... in case of a tie, select a random one
            ch = random.choice(possibleSelections[dMin])
            return ch

        return None

    def copy(self, event=None):
        ''' copies relative positions of selected crosshairs for pasting'''
        # debug('copy')
        self.copied = []
        if len(self.selected) > 0:
            for ch in self.selected:
                self.copied.append(ch.getTrueCoords())

    def paste(self, event=None):
        ''' pastes copied crosshairs and add them to undo/redo buffer '''
        if len(self.copied) > 0:
            newChs = []
            for xy in self.copied:
                ch = self.add(xy[0], xy[1], transform=False)
                newChs.append(ch)
            self.write()
            self.app.Control.push({'type': 'add', 'chs': newChs})

    def recolor(self, event=None, trace=None, color=None):
        ''' change the color of a particular trace '''

        trace = self.getCurrentTraceName() if trace == None else trace

        # grab a new color and save our old color (for generating Control data)
        newColor = self.getRandomHexColor() if color == None else color
        oldColor = self.app.Data.getCurrentTraceColor()

        self.available[trace]['color'] = newColor
        self.app.Data.setTraceColor(trace, newColor)

        if trace in self.crosshairs:
            for ch in self.crosshairs[trace]:
                ch.recolor(newColor)

        if trace == None or color == None:
            self.app.Control.push({
                'type': 'recolor',
                'trace': self.getCurrentTraceName(),
                'color': oldColor
            })
            self.redoQueue = []
            # FIXME: get this to update the widget
            self.app.Trace.displayedColour = newColor
            # FIXME: also get the widget to update the colour!

        return oldColor

    def clear(self):
        ''' remove all crosshairs for the current trace '''

        # now we remove all the traces and save
        deleted = []
        trace = self.getCurrentTraceName()
        if trace in self.crosshairs:
            for ch in self.crosshairs[trace]:
                if ch.isVisible:
                    deleted.append(ch)
                self.remove(ch, write=False)
            self.write()

        self.app.Control.push({'type': 'delete', 'chs': deleted})

    def newTrace(self):
        ''' add a new trace to our listbox '''

        # max length 12 chars (so it displays nicely)
        name = self.traceSV.get()[:12]

        # don't want to add traces we already have or empty strings
        if name not in self.available and len(name) > 0:

            # choose a random color
            color = self.getRandomHexColor()

            # save the new trace name and color to metadata & update vars
            self.available[name] = {'color': color, 'files': {}}
            self.app.Data.setTopLevel('traces', self.available)
            self.traceSV.set('')

            # update our listbox
            self.listbox.insert('end', name)
            self.listbox.selection_clear(0, 'end')
            self.listbox.select_set(len(self.available) - 1)

    def renameTrace(self, oldName=None, newName=None):
        ''' change a trace name from oldName -> newName '''

        fromUndo = (oldName != None or newName != None)
        oldName = self.getCurrentTraceName() if oldName == None else oldName
        newName = self.traceSV.get()[:12] if newName == None else newName

        # don't overwrite anything
        if newName not in self.available and len(newName) > 0:

            # get data from the old name and change the dictionary key in the metadata
            data = self.available.pop(oldName)
            self.available[newName] = data
            self.app.Data.setTopLevel('traces', self.available)
            if oldName == self.app.Data.getTopLevel('defaultTraceName'):
                self.app.Data.setTopLevel('defaultTraceName', newName)
            self.traceSV.set('')

            # update our listbox
            index = self.listbox.curselection()
            self.listbox.delete(index)
            self.listbox.insert(index, newName)
            self.listbox.selection_clear(0, 'end')
            self.listbox.select_set(index)

            if not (fromUndo):
                self.app.Control.push({
                    'type': 'rename',
                    'old': oldName,
                    'new': newName
                })

    def getRandomHexColor(self):
        ''' helper for getting a random color '''
        return '#%06x' % random.randint(0, 0xFFFFFF)

    def getWidget(self,
                  widget,
                  row=0,
                  column=0,
                  rowspan=1,
                  columnspan=1,
                  sticky=()):
        ''' helper for managing all of our widgets '''
        return {
            'widget': widget,
            'row': row,
            'rowspan': rowspan,
            'column': column,
            'columnspan': columnspan,
            'sticky': sticky
        }

    def grid(self):
        ''' grid all of our widgets '''
        for item in self.TkWidgets:
            item['widget'].grid(row=item['row'],
                                column=item['column'],
                                rowspan=item['rowspan'],
                                columnspan=item['columnspan'],
                                sticky=item['sticky'])
        self.listbox.pack(side='left', fill='y')
        self.scrollbar.pack(side='right', fill='y')

    def grid_remove(self):
        ''' remove all of our widgets from the grid '''
        for item in self.TkWidgets:
            item['widget'].grid_remove()
        self.listbox.packforget()
        self.scrollbar.packforget()
Ejemplo n.º 28
0
class ShiftReduceApp(object):
    """
    A graphical tool for exploring the shift-reduce parser.  The tool
    displays the parser's stack and the remaining text, and allows the
    user to control the parser's operation.  In particular, the user
    can shift tokens onto the stack, and can perform reductions on the
    top elements of the stack.  A "step" button simply steps through
    the parsing process, performing the operations that
    ``nltk.parse.ShiftReduceParser`` would use.
    """
    def __init__(self, grammar, sent, trace=0):
        self._sent = sent
        self._parser = SteppingShiftReduceParser(grammar, trace)

        # Set up the main window.
        self._top = Tk()
        self._top.title('Shift Reduce Parser Application')

        # Animations.  animating_lock is a lock to prevent the demo
        # from performing new operations while it's animating.
        self._animating_lock = 0
        self._animate = IntVar(self._top)
        self._animate.set(10) # = medium

        # The user can hide the grammar.
        self._show_grammar = IntVar(self._top)
        self._show_grammar.set(1)

        # Initialize fonts.
        self._init_fonts(self._top)

        # Set up key bindings.
        self._init_bindings()

        # Create the basic frames.
        self._init_menubar(self._top)
        self._init_buttons(self._top)
        self._init_feedback(self._top)
        self._init_grammar(self._top)
        self._init_canvas(self._top)

        # A popup menu for reducing.
        self._reduce_menu = Menu(self._canvas, tearoff=0)

        # Reset the demo, and set the feedback frame to empty.
        self.reset()
        self._lastoper1['text'] = ''

    #########################################
    ##  Initialization Helpers
    #########################################

    def _init_fonts(self, root):
        # See: <http://www.astro.washington.edu/owen/ROTKFolklore.html>
        self._sysfont = tkinter.font.Font(font=Button()["font"])
        root.option_add("*Font", self._sysfont)

        # TWhat's our font size (default=same as sysfont)
        self._size = IntVar(root)
        self._size.set(self._sysfont.cget('size'))

        self._boldfont = tkinter.font.Font(family='helvetica', weight='bold',
                                    size=self._size.get())
        self._font = tkinter.font.Font(family='helvetica',
                                    size=self._size.get())

    def _init_grammar(self, parent):
        # Grammar view.
        self._prodframe = listframe = Frame(parent)
        self._prodframe.pack(fill='both', side='left', padx=2)
        self._prodlist_label = Label(self._prodframe,
                                     font=self._boldfont,
                                     text='Available Reductions')
        self._prodlist_label.pack()
        self._prodlist = Listbox(self._prodframe, selectmode='single',
                                 relief='groove', background='white',
                                 foreground='#909090',
                                 font=self._font,
                                 selectforeground='#004040',
                                 selectbackground='#c0f0c0')

        self._prodlist.pack(side='right', fill='both', expand=1)

        self._productions = list(self._parser.grammar().productions())
        for production in self._productions:
            self._prodlist.insert('end', (' %s' % production))
        self._prodlist.config(height=min(len(self._productions), 25))

        # Add a scrollbar if there are more than 25 productions.
        if 1:#len(self._productions) > 25:
            listscroll = Scrollbar(self._prodframe,
                                   orient='vertical')
            self._prodlist.config(yscrollcommand = listscroll.set)
            listscroll.config(command=self._prodlist.yview)
            listscroll.pack(side='left', fill='y')

        # If they select a production, apply it.
        self._prodlist.bind('<<ListboxSelect>>', self._prodlist_select)

        # When they hover over a production, highlight it.
        self._hover = -1
        self._prodlist.bind('<Motion>', self._highlight_hover)
        self._prodlist.bind('<Leave>', self._clear_hover)

    def _init_bindings(self):
        # Quit
        self._top.bind('<Control-q>', self.destroy)
        self._top.bind('<Control-x>', self.destroy)
        self._top.bind('<Alt-q>', self.destroy)
        self._top.bind('<Alt-x>', self.destroy)

        # Ops (step, shift, reduce, undo)
        self._top.bind('<space>', self.step)
        self._top.bind('<s>', self.shift)
        self._top.bind('<Alt-s>', self.shift)
        self._top.bind('<Control-s>', self.shift)
        self._top.bind('<r>', self.reduce)
        self._top.bind('<Alt-r>', self.reduce)
        self._top.bind('<Control-r>', self.reduce)
        self._top.bind('<Delete>', self.reset)
        self._top.bind('<u>', self.undo)
        self._top.bind('<Alt-u>', self.undo)
        self._top.bind('<Control-u>', self.undo)
        self._top.bind('<Control-z>', self.undo)
        self._top.bind('<BackSpace>', self.undo)

        # Misc
        self._top.bind('<Control-p>', self.postscript)
        self._top.bind('<Control-h>', self.help)
        self._top.bind('<F1>', self.help)
        self._top.bind('<Control-g>', self.edit_grammar)
        self._top.bind('<Control-t>', self.edit_sentence)

        # Animation speed control
        self._top.bind('-', lambda e,a=self._animate:a.set(20))
        self._top.bind('=', lambda e,a=self._animate:a.set(10))
        self._top.bind('+', lambda e,a=self._animate:a.set(4))

    def _init_buttons(self, parent):
        # Set up the frames.
        self._buttonframe = buttonframe = Frame(parent)
        buttonframe.pack(fill='none', side='bottom')
        Button(buttonframe, text='Step',
               background='#90c0d0', foreground='black',
               command=self.step,).pack(side='left')
        Button(buttonframe, text='Shift', underline=0,
               background='#90f090', foreground='black',
               command=self.shift).pack(side='left')
        Button(buttonframe, text='Reduce', underline=0,
               background='#90f090', foreground='black',
               command=self.reduce).pack(side='left')
        Button(buttonframe, text='Undo', underline=0,
               background='#f0a0a0', foreground='black',
               command=self.undo).pack(side='left')

    def _init_menubar(self, parent):
        menubar = Menu(parent)

        filemenu = Menu(menubar, tearoff=0)
        filemenu.add_command(label='Reset Parser', underline=0,
                             command=self.reset, accelerator='Del')
        filemenu.add_command(label='Print to Postscript', underline=0,
                             command=self.postscript, accelerator='Ctrl-p')
        filemenu.add_command(label='Exit', underline=1,
                             command=self.destroy, accelerator='Ctrl-x')
        menubar.add_cascade(label='File', underline=0, menu=filemenu)

        editmenu = Menu(menubar, tearoff=0)
        editmenu.add_command(label='Edit Grammar', underline=5,
                             command=self.edit_grammar,
                             accelerator='Ctrl-g')
        editmenu.add_command(label='Edit Text', underline=5,
                             command=self.edit_sentence,
                             accelerator='Ctrl-t')
        menubar.add_cascade(label='Edit', underline=0, menu=editmenu)

        rulemenu = Menu(menubar, tearoff=0)
        rulemenu.add_command(label='Step', underline=1,
                             command=self.step, accelerator='Space')
        rulemenu.add_separator()
        rulemenu.add_command(label='Shift', underline=0,
                             command=self.shift, accelerator='Ctrl-s')
        rulemenu.add_command(label='Reduce', underline=0,
                             command=self.reduce, accelerator='Ctrl-r')
        rulemenu.add_separator()
        rulemenu.add_command(label='Undo', underline=0,
                             command=self.undo, accelerator='Ctrl-u')
        menubar.add_cascade(label='Apply', underline=0, menu=rulemenu)

        viewmenu = Menu(menubar, tearoff=0)
        viewmenu.add_checkbutton(label="Show Grammar", underline=0,
                                 variable=self._show_grammar,
                                 command=self._toggle_grammar)
        viewmenu.add_separator()
        viewmenu.add_radiobutton(label='Tiny', variable=self._size,
                                 underline=0, value=10, command=self.resize)
        viewmenu.add_radiobutton(label='Small', variable=self._size,
                                 underline=0, value=12, command=self.resize)
        viewmenu.add_radiobutton(label='Medium', variable=self._size,
                                 underline=0, value=14, command=self.resize)
        viewmenu.add_radiobutton(label='Large', variable=self._size,
                                 underline=0, value=18, command=self.resize)
        viewmenu.add_radiobutton(label='Huge', variable=self._size,
                                 underline=0, value=24, command=self.resize)
        menubar.add_cascade(label='View', underline=0, menu=viewmenu)

        animatemenu = Menu(menubar, tearoff=0)
        animatemenu.add_radiobutton(label="No Animation", underline=0,
                                    variable=self._animate, value=0)
        animatemenu.add_radiobutton(label="Slow Animation", underline=0,
                                    variable=self._animate, value=20,
                                    accelerator='-')
        animatemenu.add_radiobutton(label="Normal Animation", underline=0,
                                    variable=self._animate, value=10,
                                    accelerator='=')
        animatemenu.add_radiobutton(label="Fast Animation", underline=0,
                                    variable=self._animate, value=4,
                                    accelerator='+')
        menubar.add_cascade(label="Animate", underline=1, menu=animatemenu)


        helpmenu = Menu(menubar, tearoff=0)
        helpmenu.add_command(label='About', underline=0,
                             command=self.about)
        helpmenu.add_command(label='Instructions', underline=0,
                             command=self.help, accelerator='F1')
        menubar.add_cascade(label='Help', underline=0, menu=helpmenu)

        parent.config(menu=menubar)

    def _init_feedback(self, parent):
        self._feedbackframe = feedbackframe = Frame(parent)
        feedbackframe.pack(fill='x', side='bottom', padx=3, pady=3)
        self._lastoper_label = Label(feedbackframe, text='Last Operation:',
                                     font=self._font)
        self._lastoper_label.pack(side='left')
        lastoperframe = Frame(feedbackframe, relief='sunken', border=1)
        lastoperframe.pack(fill='x', side='right', expand=1, padx=5)
        self._lastoper1 = Label(lastoperframe, foreground='#007070',
                                background='#f0f0f0', font=self._font)
        self._lastoper2 = Label(lastoperframe, anchor='w', width=30,
                                foreground='#004040', background='#f0f0f0',
                                font=self._font)
        self._lastoper1.pack(side='left')
        self._lastoper2.pack(side='left', fill='x', expand=1)

    def _init_canvas(self, parent):
        self._cframe = CanvasFrame(parent, background='white',
                                   width=525, closeenough=10,
                                   border=2, relief='sunken')
        self._cframe.pack(expand=1, fill='both', side='top', pady=2)
        canvas = self._canvas = self._cframe.canvas()

        self._stackwidgets = []
        self._rtextwidgets = []
        self._titlebar = canvas.create_rectangle(0,0,0,0, fill='#c0f0f0',
                                                 outline='black')
        self._exprline = canvas.create_line(0,0,0,0, dash='.')
        self._stacktop = canvas.create_line(0,0,0,0, fill='#408080')
        size = self._size.get()+4
        self._stacklabel = TextWidget(canvas, 'Stack', color='#004040',
                                      font=self._boldfont)
        self._rtextlabel = TextWidget(canvas, 'Remaining Text',
                                      color='#004040', font=self._boldfont)
        self._cframe.add_widget(self._stacklabel)
        self._cframe.add_widget(self._rtextlabel)

    #########################################
    ##  Main draw procedure
    #########################################

    def _redraw(self):
        scrollregion = self._canvas['scrollregion'].split()
        (cx1, cy1, cx2, cy2) = [int(c) for c in scrollregion]

        # Delete the old stack & rtext widgets.
        for stackwidget in self._stackwidgets:
            self._cframe.destroy_widget(stackwidget)
        self._stackwidgets = []
        for rtextwidget in self._rtextwidgets:
            self._cframe.destroy_widget(rtextwidget)
        self._rtextwidgets = []

        # Position the titlebar & exprline
        (x1, y1, x2, y2) = self._stacklabel.bbox()
        y = y2-y1+10
        self._canvas.coords(self._titlebar, -5000, 0, 5000, y-4)
        self._canvas.coords(self._exprline, 0, y*2-10, 5000, y*2-10)

        # Position the titlebar labels..
        (x1, y1, x2, y2) = self._stacklabel.bbox()
        self._stacklabel.move(5-x1, 3-y1)
        (x1, y1, x2, y2) = self._rtextlabel.bbox()
        self._rtextlabel.move(cx2-x2-5, 3-y1)

        # Draw the stack.
        stackx = 5
        for tok in self._parser.stack():
            if isinstance(tok, Tree):
                attribs = {'tree_color': '#4080a0', 'tree_width': 2,
                           'node_font': self._boldfont,
                           'node_color': '#006060',
                           'leaf_color': '#006060', 'leaf_font':self._font}
                widget = tree_to_treesegment(self._canvas, tok,
                                             **attribs)
                widget.label()['color'] = '#000000'
            else:
                widget = TextWidget(self._canvas, tok,
                                    color='#000000', font=self._font)
            widget.bind_click(self._popup_reduce)
            self._stackwidgets.append(widget)
            self._cframe.add_widget(widget, stackx, y)
            stackx = widget.bbox()[2] + 10

        # Draw the remaining text.
        rtextwidth = 0
        for tok in self._parser.remaining_text():
            widget = TextWidget(self._canvas, tok,
                                color='#000000', font=self._font)
            self._rtextwidgets.append(widget)
            self._cframe.add_widget(widget, rtextwidth, y)
            rtextwidth = widget.bbox()[2] + 4

        # Allow enough room to shift the next token (for animations)
        if len(self._rtextwidgets) > 0:
            stackx += self._rtextwidgets[0].width()

        # Move the remaining text to the correct location (keep it
        # right-justified, when possible); and move the remaining text
        # label, if necessary.
        stackx = max(stackx, self._stacklabel.width()+25)
        rlabelwidth = self._rtextlabel.width()+10
        if stackx >= cx2-max(rtextwidth, rlabelwidth):
            cx2 = stackx + max(rtextwidth, rlabelwidth)
        for rtextwidget in self._rtextwidgets:
            rtextwidget.move(4+cx2-rtextwidth, 0)
        self._rtextlabel.move(cx2-self._rtextlabel.bbox()[2]-5, 0)

        midx = (stackx + cx2-max(rtextwidth, rlabelwidth))/2
        self._canvas.coords(self._stacktop, midx, 0, midx, 5000)
        (x1, y1, x2, y2) = self._stacklabel.bbox()

        # Set up binding to allow them to shift a token by dragging it.
        if len(self._rtextwidgets) > 0:
            def drag_shift(widget, midx=midx, self=self):
                if widget.bbox()[0] < midx: self.shift()
                else: self._redraw()
            self._rtextwidgets[0].bind_drag(drag_shift)
            self._rtextwidgets[0].bind_click(self.shift)

        # Draw the stack top.
        self._highlight_productions()

    def _draw_stack_top(self, widget):
        # hack..
        midx = widget.bbox()[2]+50
        self._canvas.coords(self._stacktop, midx, 0, midx, 5000)

    def _highlight_productions(self):
        # Highlight the productions that can be reduced.
        self._prodlist.selection_clear(0, 'end')
        for prod in self._parser.reducible_productions():
            index = self._productions.index(prod)
            self._prodlist.selection_set(index)

    #########################################
    ##  Button Callbacks
    #########################################

    def destroy(self, *e):
        if self._top is None: return
        self._top.destroy()
        self._top = None

    def reset(self, *e):
        self._parser.initialize(self._sent)
        self._lastoper1['text'] = 'Reset App'
        self._lastoper2['text'] = ''
        self._redraw()

    def step(self, *e):
        if self.reduce(): return True
        elif self.shift(): return True
        else:
            if list(self._parser.parses()):
                self._lastoper1['text'] = 'Finished:'
                self._lastoper2['text'] = 'Success'
            else:
                self._lastoper1['text'] = 'Finished:'
                self._lastoper2['text'] = 'Failure'

    def shift(self, *e):
        if self._animating_lock: return
        if self._parser.shift():
            tok = self._parser.stack()[-1]
            self._lastoper1['text'] = 'Shift:'
            self._lastoper2['text'] = '%r' % tok
            if self._animate.get():
                self._animate_shift()
            else:
                self._redraw()
            return True
        return False

    def reduce(self, *e):
        if self._animating_lock: return
        production = self._parser.reduce()
        if production:
            self._lastoper1['text'] = 'Reduce:'
            self._lastoper2['text'] = '%s' % production
            if self._animate.get():
                self._animate_reduce()
            else:
                self._redraw()
        return production

    def undo(self, *e):
        if self._animating_lock: return
        if self._parser.undo():
            self._redraw()

    def postscript(self, *e):
        self._cframe.print_to_file()

    def mainloop(self, *args, **kwargs):
        """
        Enter the Tkinter mainloop.  This function must be called if
        this demo is created from a non-interactive program (e.g.
        from a secript); otherwise, the demo will close as soon as
        the script completes.
        """
        if in_idle(): return
        self._top.mainloop(*args, **kwargs)

    #########################################
    ##  Menubar callbacks
    #########################################

    def resize(self, size=None):
        if size is not None: self._size.set(size)
        size = self._size.get()
        self._font.configure(size=-(abs(size)))
        self._boldfont.configure(size=-(abs(size)))
        self._sysfont.configure(size=-(abs(size)))

        #self._stacklabel['font'] = ('helvetica', -size-4, 'bold')
        #self._rtextlabel['font'] = ('helvetica', -size-4, 'bold')
        #self._lastoper_label['font'] = ('helvetica', -size)
        #self._lastoper1['font'] = ('helvetica', -size)
        #self._lastoper2['font'] = ('helvetica', -size)
        #self._prodlist['font'] = ('helvetica', -size)
        #self._prodlist_label['font'] = ('helvetica', -size-2, 'bold')
        self._redraw()

    def help(self, *e):
        # The default font's not very legible; try using 'fixed' instead.
        try:
            ShowText(self._top, 'Help: Shift-Reduce Parser Application',
                     (__doc__ or '').strip(), width=75, font='fixed')
        except:
            ShowText(self._top, 'Help: Shift-Reduce Parser Application',
                     (__doc__ or '').strip(), width=75)

    def about(self, *e):
        ABOUT = ("NLTK Shift-Reduce Parser Application\n"+
                 "Written by Edward Loper")
        TITLE = 'About: Shift-Reduce Parser Application'
        try:
            from tkinter.messagebox import Message
            Message(message=ABOUT, title=TITLE).show()
        except:
            ShowText(self._top, TITLE, ABOUT)

    def edit_grammar(self, *e):
        CFGEditor(self._top, self._parser.grammar(), self.set_grammar)

    def set_grammar(self, grammar):
        self._parser.set_grammar(grammar)
        self._productions = list(grammar.productions())
        self._prodlist.delete(0, 'end')
        for production in self._productions:
            self._prodlist.insert('end', (' %s' % production))

    def edit_sentence(self, *e):
        sentence = " ".join(self._sent)
        title = 'Edit Text'
        instr = 'Enter a new sentence to parse.'
        EntryDialog(self._top, sentence, instr, self.set_sentence, title)

    def set_sentence(self, sent):
        self._sent = sent.split() #[XX] use tagged?
        self.reset()

    #########################################
    ##  Reduce Production Selection
    #########################################

    def _toggle_grammar(self, *e):
        if self._show_grammar.get():
            self._prodframe.pack(fill='both', side='left', padx=2,
                                 after=self._feedbackframe)
            self._lastoper1['text'] = 'Show Grammar'
        else:
            self._prodframe.pack_forget()
            self._lastoper1['text'] = 'Hide Grammar'
        self._lastoper2['text'] = ''

    def _prodlist_select(self, event):
        selection = self._prodlist.curselection()
        if len(selection) != 1: return
        index = int(selection[0])
        production = self._parser.reduce(self._productions[index])
        if production:
            self._lastoper1['text'] = 'Reduce:'
            self._lastoper2['text'] = '%s' % production
            if self._animate.get():
                self._animate_reduce()
            else:
                self._redraw()
        else:
            # Reset the production selections.
            self._prodlist.selection_clear(0, 'end')
            for prod in self._parser.reducible_productions():
                index = self._productions.index(prod)
                self._prodlist.selection_set(index)

    def _popup_reduce(self, widget):
        # Remove old commands.
        productions = self._parser.reducible_productions()
        if len(productions) == 0: return

        self._reduce_menu.delete(0, 'end')
        for production in productions:
            self._reduce_menu.add_command(label=str(production),
                                          command=self.reduce)
        self._reduce_menu.post(self._canvas.winfo_pointerx(),
                               self._canvas.winfo_pointery())

    #########################################
    ##  Animations
    #########################################

    def _animate_shift(self):
        # What widget are we shifting?
        widget = self._rtextwidgets[0]

        # Where are we shifting from & to?
        right = widget.bbox()[0]
        if len(self._stackwidgets) == 0: left = 5
        else: left = self._stackwidgets[-1].bbox()[2]+10

        # Start animating.
        dt = self._animate.get()
        dx = (left-right)*1.0/dt
        self._animate_shift_frame(dt, widget, dx)

    def _animate_shift_frame(self, frame, widget, dx):
        if frame > 0:
            self._animating_lock = 1
            widget.move(dx, 0)
            self._top.after(10, self._animate_shift_frame,
                            frame-1, widget, dx)
        else:
            # but: stacktop??

            # Shift the widget to the stack.
            del self._rtextwidgets[0]
            self._stackwidgets.append(widget)
            self._animating_lock = 0

            # Display the available productions.
            self._draw_stack_top(widget)
            self._highlight_productions()

    def _animate_reduce(self):
        # What widgets are we shifting?
        numwidgets = len(self._parser.stack()[-1]) # number of children
        widgets = self._stackwidgets[-numwidgets:]

        # How far are we moving?
        if isinstance(widgets[0], TreeSegmentWidget):
            ydist = 15 + widgets[0].label().height()
        else:
            ydist = 15 + widgets[0].height()

        # Start animating.
        dt = self._animate.get()
        dy = ydist*2.0/dt
        self._animate_reduce_frame(dt/2, widgets, dy)

    def _animate_reduce_frame(self, frame, widgets, dy):
        if frame > 0:
            self._animating_lock = 1
            for widget in widgets: widget.move(0, dy)
            self._top.after(10, self._animate_reduce_frame,
                            frame-1, widgets, dy)
        else:
            del self._stackwidgets[-len(widgets):]
            for widget in widgets:
                self._cframe.remove_widget(widget)
            tok = self._parser.stack()[-1]
            if not isinstance(tok, Tree): raise ValueError()
            label = TextWidget(self._canvas, str(tok.label()), color='#006060',
                               font=self._boldfont)
            widget = TreeSegmentWidget(self._canvas, label, widgets,
                                       width=2)
            (x1, y1, x2, y2) = self._stacklabel.bbox()
            y = y2-y1+10
            if not self._stackwidgets: x = 5
            else: x = self._stackwidgets[-1].bbox()[2] + 10
            self._cframe.add_widget(widget, x, y)
            self._stackwidgets.append(widget)

            # Display the available productions.
            self._draw_stack_top(widget)
            self._highlight_productions()

#             # Delete the old widgets..
#             del self._stackwidgets[-len(widgets):]
#             for widget in widgets:
#                 self._cframe.destroy_widget(widget)
#
#             # Make a new one.
#             tok = self._parser.stack()[-1]
#             if isinstance(tok, Tree):
#                 attribs = {'tree_color': '#4080a0', 'tree_width': 2,
#                            'node_font': bold, 'node_color': '#006060',
#                            'leaf_color': '#006060', 'leaf_font':self._font}
#                 widget = tree_to_treesegment(self._canvas, tok.type(),
#                                              **attribs)
#                 widget.node()['color'] = '#000000'
#             else:
#                 widget = TextWidget(self._canvas, tok.type(),
#                                     color='#000000', font=self._font)
#             widget.bind_click(self._popup_reduce)
#             (x1, y1, x2, y2) = self._stacklabel.bbox()
#             y = y2-y1+10
#             if not self._stackwidgets: x = 5
#             else: x = self._stackwidgets[-1].bbox()[2] + 10
#             self._cframe.add_widget(widget, x, y)
#             self._stackwidgets.append(widget)

            #self._redraw()
            self._animating_lock = 0

    #########################################
    ##  Hovering.
    #########################################

    def _highlight_hover(self, event):
        # What production are we hovering over?
        index = self._prodlist.nearest(event.y)
        if self._hover == index: return

        # Clear any previous hover highlighting.
        self._clear_hover()

        # If the production corresponds to an available reduction,
        # highlight the stack.
        selection = [int(s) for s in self._prodlist.curselection()]
        if index in selection:
            rhslen = len(self._productions[index].rhs())
            for stackwidget in self._stackwidgets[-rhslen:]:
                if isinstance(stackwidget, TreeSegmentWidget):
                    stackwidget.label()['color'] = '#00a000'
                else:
                    stackwidget['color'] = '#00a000'

        # Remember what production we're hovering over.
        self._hover = index

    def _clear_hover(self, *event):
        # Clear any previous hover highlighting.
        if self._hover == -1: return
        self._hover = -1
        for stackwidget in self._stackwidgets:
            if isinstance(stackwidget, TreeSegmentWidget):
                stackwidget.label()['color'] = 'black'
            else:
                stackwidget['color'] = 'black'
class AutocompleteEntry(Entry):
    def __init__(self, lista, *args, **kwargs):

        Entry.__init__(self, *args, **kwargs)
        self.lista = lista
        self.var = self["textvariable"]
        if self.var == '':
            self.var = self["textvariable"] = StringVar()

        self.var.trace('w', self.changed)
        self.bind("<Right>", self.selection)
        self.bind("<Up>", self.up)
        self.bind("<Down>", self.down)

        self.lb_up = False

    def changed(self, name, index, mode):

        if self.var.get() == '':
            self.lb.destroy()
            self.lb_up = False
        else:
            words = self.comparison()
            if words:
                if not self.lb_up:
                    self.lb = Listbox()
                    self.lb.bind("<Double-Button-1>", self.selection)
                    self.lb.bind("<Right>", self.selection)
                    self.lb.place(x=self.winfo_x(),
                                  y=self.winfo_y() + self.winfo_height())
                    self.lb_up = True

                self.lb.delete(0, END)
                for w in words:
                    self.lb.insert(END, w)
            else:
                if self.lb_up:
                    self.lb.destroy()
                    self.lb_up = False

    def selection(self, event):

        if self.lb_up:
            self.var.set(self.lb.get(ACTIVE))
            self.lb.destroy()
            self.lb_up = False
            self.icursor(END)

    def up(self, event):

        if self.lb_up:
            if self.lb.curselection() == ():
                index = '0'
            else:
                index = self.lb.curselection()[0]
            if index != '0':
                self.lb.selection_clear(first=index)
                index = str(int(index) - 1)
                self.lb.selection_set(first=index)
                self.lb.activate(index)

    def down(self, event):

        if self.lb_up:
            if self.lb.curselection() == ():
                index = '0'
            else:
                index = self.lb.curselection()[0]
            if index != END:
                self.lb.selection_clear(first=index)
                index = str(int(index) + 1)
                self.lb.selection_set(first=index)
                self.lb.activate(index)

    def comparison(self):
        pattern = re.compile('.*' + self.var.get() + '.*')
        return [w for w in self.lista if re.match(pattern, w)]
Ejemplo n.º 30
0
class Ufd:
    """
        Universal File Dialog - "UFD"
        
        Unopinionated, minimalist, reusable, slightly configurable,
        general-purpose file-dialog.
    """
    def __init__(self,
                 title: str = "Universal File Dialog",
                 icon: str = "",
                 show_hidden: bool = False,
                 include_files: bool = True,
                 multiselect: bool = True,
                 select_dirs: bool = True,
                 select_files: bool = True,
                 unix_delimiter: bool = True,
                 stdout: bool = False):
        """
            Init kwargs as object attributes, save references to 
            Tk PhotoImages, & define the widgets + layout
        """

        if not isinstance(title, str):
            raise TypeError("Argument title must be type string.")

        self.title = title

        if icon:
            if not isinstance(icon, str):
                raise TypeError("Argument icon must be type string.")

            if not isfile(icon):
                raise FileNotFoundError(f"File not found: {icon}")

            self.icon = icon

        else:
            self.icon = ""

        if show_hidden:
            self.show_hidden = True
        else:
            self.show_hidden = False

        if include_files:
            self.include_files = True
        else:
            self.include_files = False

        if multiselect:
            self.multiselect = True
        else:
            self.multiselect = False

        if select_dirs:
            self.select_dirs = True
        else:
            self.select_dirs = False

        if select_files:
            self.select_files = True
        else:
            self.select_files = False

        if unix_delimiter:
            self.unix_delimiter = True
        else:
            self.unix_delimiter = False

        if stdout:
            self.stdout = True
        else:
            self.stdout = False

        # Tkinter:
        self.dialog = Tk()
        self.dialog.withdraw()
        self.dialog.title(self.title)
        self.dialog.minsize(width=300, height=200)
        self.dialog.geometry("500x300")
        self.dialog.update_idletasks()

        self.file_icon = PhotoImage(file=f"{dirname(__file__)}/file.gif",
                                    master=self.dialog).subsample(50)

        self.folder_icon = PhotoImage(file=f"{dirname(__file__)}/folder.gif",
                                      master=self.dialog).subsample(15)

        self.disk_icon = PhotoImage(file=f"{dirname(__file__)}/disk.gif",
                                    master=self.dialog).subsample(15)

        if self.icon:
            self.dialog.iconbitmap(self.icon)
        else:
            self.dialog.iconbitmap(f"{dirname(__file__)}/icon.ico")

        # Widgets:
        self.paneview = PanedWindow(
            self.dialog,
            sashwidth=7,
            bg="#cccccc",
            bd=0,
        )

        self.left_pane = PanedWindow(self.paneview)
        self.right_pane = PanedWindow(self.paneview)
        self.paneview.add(self.left_pane)
        self.paneview.add(self.right_pane)

        self.treeview_x_scrollbar = Scrollbar(self.left_pane,
                                              orient="horizontal")
        self.treeview_y_scrollbar = Scrollbar(self.left_pane,
                                              orient="vertical")
        self.list_box_x_scrollbar = Scrollbar(self.right_pane,
                                              orient="horizontal")
        self.list_box_y_scrollbar = Scrollbar(self.right_pane,
                                              orient="vertical")

        # tstyle = Style().configure(".", )

        self.treeview = Treeview(
            self.left_pane,
            xscrollcommand=self.treeview_x_scrollbar.set,
            yscrollcommand=self.treeview_y_scrollbar.set,
            show="tree",
            selectmode="browse",
            # style=tstyle
        )

        self.list_box = Listbox(self.right_pane,
                                xscrollcommand=self.list_box_x_scrollbar.set,
                                yscrollcommand=self.list_box_y_scrollbar.set,
                                width=34,
                                highlightthickness=0,
                                bd=2,
                                relief="ridge")

        if self.multiselect:
            self.list_box.config(selectmode="extended")
        else:
            self.list_box.config(selectmode="browse")

        self.cancel_button = Button(self.left_pane,
                                    text="Cancel",
                                    command=self.cancel)

        self.submit_button = Button(self.right_pane,
                                    text="Submit",
                                    command=self.submit)

        self.treeview_x_scrollbar.config(command=self.treeview.xview)
        self.treeview_y_scrollbar.config(command=self.treeview.yview)
        self.list_box_x_scrollbar.config(command=self.list_box.xview)
        self.list_box_y_scrollbar.config(command=self.list_box.yview)

        #Layout:
        self.dialog.rowconfigure(0, weight=1)
        self.dialog.columnconfigure(0, weight=1)

        self.left_pane.grid_rowconfigure(0, weight=1)
        self.left_pane.grid_columnconfigure(0, weight=1)
        self.right_pane.grid_rowconfigure(0, weight=1)
        self.right_pane.grid_columnconfigure(0, weight=1)

        self.paneview.paneconfigure(
            self.left_pane,
            minsize=100,
            #Start off w/ the sash centered in the GUI:
            width=(self.dialog.winfo_width() / 2) - ceil(
                (self.paneview.cget("sashwidth") * 1.5)),
        )
        self.paneview.paneconfigure(self.right_pane, minsize=100)

        self.paneview.grid(row=0, column=0, sticky="nsew")

        self.treeview.grid(row=0, column=0, sticky="nsew")
        self.treeview_y_scrollbar.grid(row=0, column=1, sticky="ns")
        self.treeview_x_scrollbar.grid(row=1,
                                       column=0,
                                       columnspan=2,
                                       sticky="ew")

        self.list_box.grid(row=0, column=0, sticky="nsew")
        self.list_box_y_scrollbar.grid(row=0, column=1, sticky="ns")
        self.list_box_x_scrollbar.grid(row=1,
                                       column=0,
                                       columnspan=2,
                                       sticky="ew")

        self.cancel_button.grid(row=2, column=0, sticky="w", padx=10, pady=10)
        self.submit_button.grid(row=2,
                                column=0,
                                columnspan=2,
                                sticky="e",
                                padx=10,
                                pady=10)

        #Bindings, Protocols, & Misc:
        self.dialog.bind("<Control-w>", self.cancel)
        self.treeview.bind("<<TreeviewSelect>>", self.treeview_select)
        self.treeview.bind("<Double-Button-1>", self.dialog_populate)
        self.treeview.bind("<Return>", self.dialog_populate)
        self.treeview.bind("<Right>", self.dialog_populate)
        self.list_box.bind("<<ListboxSelect>>", self.list_box_select)
        self.list_box.bind("<Return>", self.submit)
        self.dialog.protocol("WM_DELETE_WINDOW", self.cancel)

        self.dialog_selection = deque()
        self.selection_paths = deque()

        for disk in self.get_disks():
            self.treeview.insert(
                "",
                index="end",
                text=disk,
                image=self.disk_icon,
            )

        self.dialog.focus()

    def __call__(self):
        """
            Display dialog & return selection
        """

        (width_offset, height_offset) = self.get_offset(self.dialog)
        self.dialog.geometry(f"+{width_offset}+{height_offset}")
        self.dialog.update_idletasks()
        self.dialog.deiconify()

        self.dialog.wait_window()

        for i, path in enumerate(self.dialog_selection):
            if self.unix_delimiter:
                self.dialog_selection[i] = sub("\\\\", "/", path)
            else:
                self.dialog_selection[i] = sub("/", "\\\\", path)

        if self.stdout:
            [print(item) for item in self.dialog_selection]

        return list(self.dialog_selection)

    def __str__(self):
        """
            Return own address
        """

        return "Universal File Dialog"\
        f" @ {hex(id(self))}"

    def __repr__(self):
        """
            Return full string representation of constructor signature
        """

        return f"Ufd("\
        f"title=\"{self.title}\","\
        f" icon=\"{self.icon}\","\
        f" show_hidden={self.show_hidden},"\
        f" include_files={self.include_files},"\
        f" multiselect={self.multiselect},"\
        f" select_dirs={self.select_dirs},"\
        f" select_files={self.select_files},"\
        f" unix_delimiter={self.unix_delimiter})"\
        f" stdout={self.stdout})"\
        f" @ {hex(id(self))}"

    @staticmethod
    def get_offset(tk_window):
        """
            Returns an appropriate offset for a given tkinter toplevel,
            such that it always is created center screen on the primary display.
        """

        width_offset = int((tk_window.winfo_screenwidth() / 2) -
                           (tk_window.winfo_width() / 2))

        height_offset = int((tk_window.winfo_screenheight() / 2) -
                            (tk_window.winfo_height() / 2))

        return (width_offset, height_offset)

    @staticmethod
    def get_disks():
        """
            Returns all mounted disks (for Windows)

            >> ["A:", "B:", "C:"]
        """

        if system() != "Windows":
            raise OSError("For use with Windows platforms.")

        logicaldisks = run(["wmic", "logicaldisk", "get", "name"],
                           capture_output=True)

        return findall("[A-Z]:", str(logicaldisks.stdout))

    @staticmethod
    def list_dir(path, force=False):
        """
            Reads a directory with a shell call to dir.
            Truthiness of bool force determines whether 
            hidden items are returned or not. (For Windows)
        """

        path = sub("/", "\\\\", path)

        if force:
            dir_listing = run(["dir", path, "/b", "/a"],
                              shell=True,
                              capture_output=True)

        else:
            dir_listing = run(["dir", path, "/b"],
                              shell=True,
                              capture_output=True)

        output = dir_listing.stdout
        err = dir_listing.stderr

        if not output:
            return []

        if err:
            err = err.decode("utf-8")
            raise Exception(err)

        str_output = output.decode("utf-8")
        list_output = re_split("\r\n", str_output)

        return sorted([item for item in list_output if item])

    def climb(self, item):
        """
            Builds & returns a complete path to root directory,
            including the item name itself as the path tail.
            An extra delimiter is appeneded for the subsequent
            child node, which is normalized in dialog_populate()
        """

        item_text = self.treeview.item(item)["text"]
        parent = self.treeview.parent(item)
        path = ""
        parents = deque()

        while parent:
            parents.append(self.treeview.item(parent)["text"] + "/")
            parent = self.treeview.parent(parent)

        for parent in reversed(parents):
            path += parent

        path += item_text + "/"
        return path

    def dialog_populate(self, event=None):
        """
            Dynamically populates & updates the treeview, listbox,
            and keeps track of the full paths corresponding to each
            item in the listbox
        """
        if not self.treeview.focus():
            return

        self.treeview.column("#0", width=1000)

        existing_children = self.treeview.get_children(self.treeview.focus())
        [self.treeview.delete(child) for child in existing_children]

        self.list_box.delete(0, "end")
        self.selection_paths.clear()

        focus_item = self.treeview.focus()
        path = self.climb(focus_item)

        if self.show_hidden:
            children = self.list_dir(path, force=True)
        else:
            children = self.list_dir(path)

        for child in children:
            if isdir(path + child):

                self.treeview.insert(focus_item,
                                     index="end",
                                     text=child,
                                     image=self.folder_icon)

                if self.select_dirs:
                    self.list_box.insert("end", child)
                    self.selection_paths.append(path + child)

            elif isfile(path + child):

                if self.include_files:
                    self.treeview.insert(focus_item,
                                         index="end",
                                         text=child,
                                         image=self.file_icon)

                if self.select_files:
                    self.list_box.insert("end", child)
                    self.list_box.itemconfig("end", {"bg": "#EAEAEA"})
                    self.selection_paths.append(path + child)

        if isfile(normpath(path)):
            (head, tail) = path_split(normpath(path))
            head = sub("\\\\", "/", head)

            self.list_box.insert("end", tail)
            self.selection_paths.append(head + "/" + tail)
            self.list_box.itemconfig("end", {"bg": "#EAEAEA"})

    def list_box_select(self, event=None):
        """
            Dynamically refresh the dialog selection with
            what's selected in the listbox
            (Callback for <<ListboxSelect>>).
        """

        self.dialog_selection.clear()

        for i in self.list_box.curselection():
            self.dialog_selection.append(self.selection_paths[i])

    def treeview_select(self, event=None):
        """
            Dynamically refresh the dialog selection with
            what's selected in the treeview
            (Callback for <<TreeviewSelect>>).
        """

        for i in self.list_box.curselection():
            self.list_box.selection_clear(i)

        self.dialog_selection.clear()

        item = normpath(self.climb(self.treeview.focus()))
        self.dialog_selection.append(item)

    def submit(self, event=None):
        """
            Satisfies wait_window() in self.__call__() and validates selection

            (Callback for <Return>, <Button-1> on file_list, submit_button)
        """

        if self.select_dirs == False:
            for item in self.dialog_selection:
                if isdir(item):
                    messagebox.showwarning(
                        "Error - Invalid Selection",
                        "Unable to select directory. Please select a file(s).")
                    return

        if self.select_files == False:
            for item in self.dialog_selection:
                if isfile(item):
                    messagebox.showwarning(
                        "Error - Invalid Selection",
                        "Unable to select file. Please select a folder(s)")
                    return

        self.dialog.destroy()

    def cancel(self, event=None):
        """
            Satisfies wait_window() in self.__call__() 

            (Callback for <Button-1> on cancel_button)
            (Callback for protocol "WM_DELETE_WINDOW" on self.dialog)
        """

        self.dialog_selection.clear()
        self.dialog.destroy()
Ejemplo n.º 31
0
class DrtGlueDemo(object):
    def __init__(self, examples):
        # Set up the main window.
        self._top = Tk()
        self._top.title("DRT Glue Demo")

        # Set up key bindings.
        self._init_bindings()

        # Initialize the fonts.self._error = None
        self._init_fonts(self._top)

        self._examples = examples
        self._readingCache = [None for example in examples]

        # The user can hide the grammar.
        self._show_grammar = IntVar(self._top)
        self._show_grammar.set(1)

        # Set the data to None
        self._curExample = -1
        self._readings = []
        self._drs = None
        self._drsWidget = None
        self._error = None

        self._init_glue()

        # Create the basic frames.
        self._init_menubar(self._top)
        self._init_buttons(self._top)
        self._init_exampleListbox(self._top)
        self._init_readingListbox(self._top)
        self._init_canvas(self._top)

        # Resize callback
        self._canvas.bind("<Configure>", self._configure)

    #########################################
    ##  Initialization Helpers
    #########################################

    def _init_glue(self):
        tagger = RegexpTagger(
            [
                ("^(David|Mary|John)$", "NNP"),
                ("^(walks|sees|eats|chases|believes|gives|sleeps|chases|persuades|tries|seems|leaves)$", "VB"),
                ("^(go|order|vanish|find|approach)$", "VB"),
                ("^(a)$", "ex_quant"),
                ("^(every)$", "univ_quant"),
                ("^(sandwich|man|dog|pizza|unicorn|cat|senator)$", "NN"),
                ("^(big|gray|former)$", "JJ"),
                ("^(him|himself)$", "PRP"),
            ]
        )

        depparser = MaltParser(tagger=tagger)
        self._glue = DrtGlue(depparser=depparser, remove_duplicates=False)

    def _init_fonts(self, root):
        # See: <http://www.astro.washington.edu/owen/ROTKFolklore.html>
        self._sysfont = Font(font=Button()["font"])
        root.option_add("*Font", self._sysfont)

        # TWhat's our font size (default=same as sysfont)
        self._size = IntVar(root)
        self._size.set(self._sysfont.cget("size"))

        self._boldfont = Font(family="helvetica", weight="bold", size=self._size.get())
        self._font = Font(family="helvetica", size=self._size.get())
        if self._size.get() < 0:
            big = self._size.get() - 2
        else:
            big = self._size.get() + 2
        self._bigfont = Font(family="helvetica", weight="bold", size=big)

    def _init_exampleListbox(self, parent):
        self._exampleFrame = listframe = Frame(parent)
        self._exampleFrame.pack(fill="both", side="left", padx=2)
        self._exampleList_label = Label(self._exampleFrame, font=self._boldfont, text="Examples")
        self._exampleList_label.pack()
        self._exampleList = Listbox(
            self._exampleFrame,
            selectmode="single",
            relief="groove",
            background="white",
            foreground="#909090",
            font=self._font,
            selectforeground="#004040",
            selectbackground="#c0f0c0",
        )

        self._exampleList.pack(side="right", fill="both", expand=1)

        for example in self._examples:
            self._exampleList.insert("end", ("  %s" % example))
        self._exampleList.config(height=min(len(self._examples), 25), width=40)

        # Add a scrollbar if there are more than 25 examples.
        if len(self._examples) > 25:
            listscroll = Scrollbar(self._exampleFrame, orient="vertical")
            self._exampleList.config(yscrollcommand=listscroll.set)
            listscroll.config(command=self._exampleList.yview)
            listscroll.pack(side="left", fill="y")

        # If they select a example, apply it.
        self._exampleList.bind("<<ListboxSelect>>", self._exampleList_select)

    def _init_readingListbox(self, parent):
        self._readingFrame = listframe = Frame(parent)
        self._readingFrame.pack(fill="both", side="left", padx=2)
        self._readingList_label = Label(self._readingFrame, font=self._boldfont, text="Readings")
        self._readingList_label.pack()
        self._readingList = Listbox(
            self._readingFrame,
            selectmode="single",
            relief="groove",
            background="white",
            foreground="#909090",
            font=self._font,
            selectforeground="#004040",
            selectbackground="#c0f0c0",
        )

        self._readingList.pack(side="right", fill="both", expand=1)

        # Add a scrollbar if there are more than 25 examples.
        listscroll = Scrollbar(self._readingFrame, orient="vertical")
        self._readingList.config(yscrollcommand=listscroll.set)
        listscroll.config(command=self._readingList.yview)
        listscroll.pack(side="right", fill="y")

        self._populate_readingListbox()

    def _populate_readingListbox(self):
        # Populate the listbox with integers
        self._readingList.delete(0, "end")
        for i in range(len(self._readings)):
            self._readingList.insert("end", ("  %s" % (i + 1)))
        self._readingList.config(height=min(len(self._readings), 25), width=5)

        # If they select a example, apply it.
        self._readingList.bind("<<ListboxSelect>>", self._readingList_select)

    def _init_bindings(self):
        # Key bindings are a good thing.
        self._top.bind("<Control-q>", self.destroy)
        self._top.bind("<Control-x>", self.destroy)
        self._top.bind("<Escape>", self.destroy)
        self._top.bind("n", self.next)
        self._top.bind("<space>", self.next)
        self._top.bind("p", self.prev)
        self._top.bind("<BackSpace>", self.prev)

    def _init_buttons(self, parent):
        # Set up the frames.
        self._buttonframe = buttonframe = Frame(parent)
        buttonframe.pack(fill="none", side="bottom", padx=3, pady=2)
        Button(buttonframe, text="Prev", background="#90c0d0", foreground="black", command=self.prev).pack(side="left")
        Button(buttonframe, text="Next", background="#90c0d0", foreground="black", command=self.next).pack(side="left")

    def _configure(self, event):
        self._autostep = 0
        (x1, y1, x2, y2) = self._cframe.scrollregion()
        y2 = event.height - 6
        self._canvas["scrollregion"] = "%d %d %d %d" % (x1, y1, x2, y2)
        self._redraw()

    def _init_canvas(self, parent):
        self._cframe = CanvasFrame(
            parent,
            background="white",
            # width=525, height=250,
            closeenough=10,
            border=2,
            relief="sunken",
        )
        self._cframe.pack(expand=1, fill="both", side="top", pady=2)
        canvas = self._canvas = self._cframe.canvas()

        # Initially, there's no tree or text
        self._tree = None
        self._textwidgets = []
        self._textline = None

    def _init_menubar(self, parent):
        menubar = Menu(parent)

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

        actionmenu = Menu(menubar, tearoff=0)
        actionmenu.add_command(label="Next", underline=0, command=self.next, accelerator="n, Space")
        actionmenu.add_command(label="Previous", underline=0, command=self.prev, accelerator="p, Backspace")
        menubar.add_cascade(label="Action", underline=0, menu=actionmenu)

        optionmenu = Menu(menubar, tearoff=0)
        optionmenu.add_checkbutton(
            label="Remove Duplicates",
            underline=0,
            variable=self._glue.remove_duplicates,
            command=self._toggle_remove_duplicates,
            accelerator="r",
        )
        menubar.add_cascade(label="Options", underline=0, menu=optionmenu)

        viewmenu = Menu(menubar, tearoff=0)
        viewmenu.add_radiobutton(label="Tiny", variable=self._size, underline=0, value=10, command=self.resize)
        viewmenu.add_radiobutton(label="Small", variable=self._size, underline=0, value=12, command=self.resize)
        viewmenu.add_radiobutton(label="Medium", variable=self._size, underline=0, value=14, command=self.resize)
        viewmenu.add_radiobutton(label="Large", variable=self._size, underline=0, value=18, command=self.resize)
        viewmenu.add_radiobutton(label="Huge", variable=self._size, underline=0, value=24, command=self.resize)
        menubar.add_cascade(label="View", underline=0, menu=viewmenu)

        helpmenu = Menu(menubar, tearoff=0)
        helpmenu.add_command(label="About", underline=0, command=self.about)
        menubar.add_cascade(label="Help", underline=0, menu=helpmenu)

        parent.config(menu=menubar)

    #########################################
    ##  Main draw procedure
    #########################################

    def _redraw(self):
        canvas = self._canvas

        # Delete the old DRS, widgets, etc.
        if self._drsWidget is not None:
            self._drsWidget.clear()

        if self._drs:
            self._drsWidget = DrsWidget(self._canvas, self._drs)
            self._drsWidget.draw()

        if self._error:
            self._drsWidget = DrsWidget(self._canvas, self._error)
            self._drsWidget.draw()

    #########################################
    ##  Button Callbacks
    #########################################

    def destroy(self, *e):
        self._autostep = 0
        if self._top is None:
            return
        self._top.destroy()
        self._top = None

    def prev(self, *e):
        selection = self._readingList.curselection()
        readingListSize = self._readingList.size()

        # there are readings
        if readingListSize > 0:
            # if one reading is currently selected
            if len(selection) == 1:
                index = int(selection[0])

                # if it's on (or before) the first item
                if index <= 0:
                    self._select_previous_example()
                else:
                    self._readingList_store_selection(index - 1)

            else:
                # select its first reading
                self._readingList_store_selection(readingListSize - 1)

        else:
            self._select_previous_example()

    def _select_previous_example(self):
        # if the current example is not the first example
        if self._curExample > 0:
            self._exampleList_store_selection(self._curExample - 1)
        else:
            # go to the last example
            self._exampleList_store_selection(len(self._examples) - 1)

    def next(self, *e):
        selection = self._readingList.curselection()
        readingListSize = self._readingList.size()

        # if there are readings
        if readingListSize > 0:
            # if one reading is currently selected
            if len(selection) == 1:
                index = int(selection[0])

                # if it's on (or past) the last item
                if index >= (readingListSize - 1):
                    self._select_next_example()
                else:
                    self._readingList_store_selection(index + 1)

            else:
                # select its first reading
                self._readingList_store_selection(0)

        else:
            self._select_next_example()

    def _select_next_example(self):
        # if the current example is not the last example
        if self._curExample < len(self._examples) - 1:
            self._exampleList_store_selection(self._curExample + 1)
        else:
            # go to the first example
            self._exampleList_store_selection(0)

    def about(self, *e):
        ABOUT = "NLTK Discourse Representation Theory (DRT) Glue Semantics Demo\n" + "Written by Daniel H. Garrette"
        TITLE = "About: NLTK DRT Glue Demo"
        try:
            from tkMessageBox import Message

            Message(message=ABOUT, title=TITLE).show()
        except:
            ShowText(self._top, TITLE, ABOUT)

    def postscript(self, *e):
        self._autostep = 0
        self._cframe.print_to_file()

    def mainloop(self, *args, **kwargs):
        """
        Enter the Tkinter mainloop.  This function must be called if
        this demo is created from a non-interactive program (e.g.
        from a secript); otherwise, the demo will close as soon as
        the script completes.
        """
        if in_idle():
            return
        self._top.mainloop(*args, **kwargs)

    def resize(self, size=None):
        if size is not None:
            self._size.set(size)
        size = self._size.get()
        self._font.configure(size=-(abs(size)))
        self._boldfont.configure(size=-(abs(size)))
        self._sysfont.configure(size=-(abs(size)))
        self._bigfont.configure(size=-(abs(size + 2)))
        self._redraw()

    def _toggle_remove_duplicates(self):
        self._glue.remove_duplicates = not self._glue.remove_duplicates

        self._exampleList.selection_clear(0, "end")
        self._readings = []
        self._populate_readingListbox()
        self._readingCache = [None for ex in self._examples]
        self._curExample = -1
        self._error = None

        self._drs = None
        self._redraw()

    def _exampleList_select(self, event):
        selection = self._exampleList.curselection()
        if len(selection) != 1:
            return
        self._exampleList_store_selection(int(selection[0]))

    def _exampleList_store_selection(self, index):
        self._curExample = index
        example = self._examples[index]

        self._exampleList.selection_clear(0, "end")
        if example:
            cache = self._readingCache[index]
            if cache:
                if isinstance(cache, list):
                    self._readings = cache
                    self._error = None
                else:
                    self._readings = []
                    self._error = cache
            else:
                try:
                    self._readings = self._glue.parse_to_meaning(example)
                    self._error = None
                    self._readingCache[index] = self._readings
                except Exception as e:
                    self._readings = []
                    self._error = DrtVariableExpression(Variable("Error: " + str(e)))
                    self._readingCache[index] = self._error

                    # add a star to the end of the example
                    self._exampleList.delete(index)
                    self._exampleList.insert(index, ("  %s *" % example))
                    self._exampleList.config(height=min(len(self._examples), 25), width=40)

            self._populate_readingListbox()

            self._exampleList.selection_set(index)

            self._drs = None
            self._redraw()

    def _readingList_select(self, event):
        selection = self._readingList.curselection()
        if len(selection) != 1:
            return
        self._readingList_store_selection(int(selection[0]))

    def _readingList_store_selection(self, index):
        reading = self._readings[index]

        self._readingList.selection_clear(0, "end")
        if reading:
            self._readingList.selection_set(index)

            self._drs = reading.simplify().normalize().resolve_anaphora()

            self._redraw()
Ejemplo n.º 32
0
class ShiftReduceApp(object):
    """
    A graphical tool for exploring the shift-reduce parser.  The tool
    displays the parser's stack and the remaining text, and allows the
    user to control the parser's operation.  In particular, the user
    can shift tokens onto the stack, and can perform reductions on the
    top elements of the stack.  A "step" button simply steps through
    the parsing process, performing the operations that
    ``nltk.parse.ShiftReduceParser`` would use.
    """
    def __init__(self, grammar, sent, trace=0):
        self._sent = sent
        self._parser = SteppingShiftReduceParser(grammar, trace)

        # Set up the main window.
        self._top = Tk()
        self._top.title('Shift Reduce Parser Application')

        # Animations.  animating_lock is a lock to prevent the demo
        # from performing new operations while it's animating.
        self._animating_lock = 0
        self._animate = IntVar(self._top)
        self._animate.set(10)  # = medium

        # The user can hide the grammar.
        self._show_grammar = IntVar(self._top)
        self._show_grammar.set(1)

        # Initialize fonts.
        self._init_fonts(self._top)

        # Set up key bindings.
        self._init_bindings()

        # Create the basic frames.
        self._init_menubar(self._top)
        self._init_buttons(self._top)
        self._init_feedback(self._top)
        self._init_grammar(self._top)
        self._init_canvas(self._top)

        # A popup menu for reducing.
        self._reduce_menu = Menu(self._canvas, tearoff=0)

        # Reset the demo, and set the feedback frame to empty.
        self.reset()
        self._lastoper1['text'] = ''

    #########################################
    ##  Initialization Helpers
    #########################################

    def _init_fonts(self, root):
        # See: <http://www.astro.washington.edu/owen/ROTKFolklore.html>
        self._sysfont = tkinter.font.Font(font=Button()["font"])
        root.option_add("*Font", self._sysfont)

        # TWhat's our font size (default=same as sysfont)
        self._size = IntVar(root)
        self._size.set(self._sysfont.cget('size'))

        self._boldfont = tkinter.font.Font(family='helvetica',
                                           weight='bold',
                                           size=self._size.get())
        self._font = tkinter.font.Font(family='helvetica',
                                       size=self._size.get())

    def _init_grammar(self, parent):
        # Grammar view.
        self._prodframe = listframe = Frame(parent)
        self._prodframe.pack(fill='both', side='left', padx=2)
        self._prodlist_label = Label(self._prodframe,
                                     font=self._boldfont,
                                     text='Available Reductions')
        self._prodlist_label.pack()
        self._prodlist = Listbox(self._prodframe,
                                 selectmode='single',
                                 relief='groove',
                                 background='white',
                                 foreground='#909090',
                                 font=self._font,
                                 selectforeground='#004040',
                                 selectbackground='#c0f0c0')

        self._prodlist.pack(side='right', fill='both', expand=1)

        self._productions = list(self._parser.grammar().productions())
        for production in self._productions:
            self._prodlist.insert('end', (' %s' % production))
        self._prodlist.config(height=min(len(self._productions), 25))

        # Add a scrollbar if there are more than 25 productions.
        if 1:  #len(self._productions) > 25:
            listscroll = Scrollbar(self._prodframe, orient='vertical')
            self._prodlist.config(yscrollcommand=listscroll.set)
            listscroll.config(command=self._prodlist.yview)
            listscroll.pack(side='left', fill='y')

        # If they select a production, apply it.
        self._prodlist.bind('<<ListboxSelect>>', self._prodlist_select)

        # When they hover over a production, highlight it.
        self._hover = -1
        self._prodlist.bind('<Motion>', self._highlight_hover)
        self._prodlist.bind('<Leave>', self._clear_hover)

    def _init_bindings(self):
        # Quit
        self._top.bind('<Control-q>', self.destroy)
        self._top.bind('<Control-x>', self.destroy)
        self._top.bind('<Alt-q>', self.destroy)
        self._top.bind('<Alt-x>', self.destroy)

        # Ops (step, shift, reduce, undo)
        self._top.bind('<space>', self.step)
        self._top.bind('<s>', self.shift)
        self._top.bind('<Alt-s>', self.shift)
        self._top.bind('<Control-s>', self.shift)
        self._top.bind('<r>', self.reduce)
        self._top.bind('<Alt-r>', self.reduce)
        self._top.bind('<Control-r>', self.reduce)
        self._top.bind('<Delete>', self.reset)
        self._top.bind('<u>', self.undo)
        self._top.bind('<Alt-u>', self.undo)
        self._top.bind('<Control-u>', self.undo)
        self._top.bind('<Control-z>', self.undo)
        self._top.bind('<BackSpace>', self.undo)

        # Misc
        self._top.bind('<Control-p>', self.postscript)
        self._top.bind('<Control-h>', self.help)
        self._top.bind('<F1>', self.help)
        self._top.bind('<Control-g>', self.edit_grammar)
        self._top.bind('<Control-t>', self.edit_sentence)

        # Animation speed control
        self._top.bind('-', lambda e, a=self._animate: a.set(20))
        self._top.bind('=', lambda e, a=self._animate: a.set(10))
        self._top.bind('+', lambda e, a=self._animate: a.set(4))

    def _init_buttons(self, parent):
        # Set up the frames.
        self._buttonframe = buttonframe = Frame(parent)
        buttonframe.pack(fill='none', side='bottom')
        Button(
            buttonframe,
            text='Step',
            background='#90c0d0',
            foreground='black',
            command=self.step,
        ).pack(side='left')
        Button(buttonframe,
               text='Shift',
               underline=0,
               background='#90f090',
               foreground='black',
               command=self.shift).pack(side='left')
        Button(buttonframe,
               text='Reduce',
               underline=0,
               background='#90f090',
               foreground='black',
               command=self.reduce).pack(side='left')
        Button(buttonframe,
               text='Undo',
               underline=0,
               background='#f0a0a0',
               foreground='black',
               command=self.undo).pack(side='left')

    def _init_menubar(self, parent):
        menubar = Menu(parent)

        filemenu = Menu(menubar, tearoff=0)
        filemenu.add_command(label='Reset Parser',
                             underline=0,
                             command=self.reset,
                             accelerator='Del')
        filemenu.add_command(label='Print to Postscript',
                             underline=0,
                             command=self.postscript,
                             accelerator='Ctrl-p')
        filemenu.add_command(label='Exit',
                             underline=1,
                             command=self.destroy,
                             accelerator='Ctrl-x')
        menubar.add_cascade(label='File', underline=0, menu=filemenu)

        editmenu = Menu(menubar, tearoff=0)
        editmenu.add_command(label='Edit Grammar',
                             underline=5,
                             command=self.edit_grammar,
                             accelerator='Ctrl-g')
        editmenu.add_command(label='Edit Text',
                             underline=5,
                             command=self.edit_sentence,
                             accelerator='Ctrl-t')
        menubar.add_cascade(label='Edit', underline=0, menu=editmenu)

        rulemenu = Menu(menubar, tearoff=0)
        rulemenu.add_command(label='Step',
                             underline=1,
                             command=self.step,
                             accelerator='Space')
        rulemenu.add_separator()
        rulemenu.add_command(label='Shift',
                             underline=0,
                             command=self.shift,
                             accelerator='Ctrl-s')
        rulemenu.add_command(label='Reduce',
                             underline=0,
                             command=self.reduce,
                             accelerator='Ctrl-r')
        rulemenu.add_separator()
        rulemenu.add_command(label='Undo',
                             underline=0,
                             command=self.undo,
                             accelerator='Ctrl-u')
        menubar.add_cascade(label='Apply', underline=0, menu=rulemenu)

        viewmenu = Menu(menubar, tearoff=0)
        viewmenu.add_checkbutton(label="Show Grammar",
                                 underline=0,
                                 variable=self._show_grammar,
                                 command=self._toggle_grammar)
        viewmenu.add_separator()
        viewmenu.add_radiobutton(label='Tiny',
                                 variable=self._size,
                                 underline=0,
                                 value=10,
                                 command=self.resize)
        viewmenu.add_radiobutton(label='Small',
                                 variable=self._size,
                                 underline=0,
                                 value=12,
                                 command=self.resize)
        viewmenu.add_radiobutton(label='Medium',
                                 variable=self._size,
                                 underline=0,
                                 value=14,
                                 command=self.resize)
        viewmenu.add_radiobutton(label='Large',
                                 variable=self._size,
                                 underline=0,
                                 value=18,
                                 command=self.resize)
        viewmenu.add_radiobutton(label='Huge',
                                 variable=self._size,
                                 underline=0,
                                 value=24,
                                 command=self.resize)
        menubar.add_cascade(label='View', underline=0, menu=viewmenu)

        animatemenu = Menu(menubar, tearoff=0)
        animatemenu.add_radiobutton(label="No Animation",
                                    underline=0,
                                    variable=self._animate,
                                    value=0)
        animatemenu.add_radiobutton(label="Slow Animation",
                                    underline=0,
                                    variable=self._animate,
                                    value=20,
                                    accelerator='-')
        animatemenu.add_radiobutton(label="Normal Animation",
                                    underline=0,
                                    variable=self._animate,
                                    value=10,
                                    accelerator='=')
        animatemenu.add_radiobutton(label="Fast Animation",
                                    underline=0,
                                    variable=self._animate,
                                    value=4,
                                    accelerator='+')
        menubar.add_cascade(label="Animate", underline=1, menu=animatemenu)

        helpmenu = Menu(menubar, tearoff=0)
        helpmenu.add_command(label='About', underline=0, command=self.about)
        helpmenu.add_command(label='Instructions',
                             underline=0,
                             command=self.help,
                             accelerator='F1')
        menubar.add_cascade(label='Help', underline=0, menu=helpmenu)

        parent.config(menu=menubar)

    def _init_feedback(self, parent):
        self._feedbackframe = feedbackframe = Frame(parent)
        feedbackframe.pack(fill='x', side='bottom', padx=3, pady=3)
        self._lastoper_label = Label(feedbackframe,
                                     text='Last Operation:',
                                     font=self._font)
        self._lastoper_label.pack(side='left')
        lastoperframe = Frame(feedbackframe, relief='sunken', border=1)
        lastoperframe.pack(fill='x', side='right', expand=1, padx=5)
        self._lastoper1 = Label(lastoperframe,
                                foreground='#007070',
                                background='#f0f0f0',
                                font=self._font)
        self._lastoper2 = Label(lastoperframe,
                                anchor='w',
                                width=30,
                                foreground='#004040',
                                background='#f0f0f0',
                                font=self._font)
        self._lastoper1.pack(side='left')
        self._lastoper2.pack(side='left', fill='x', expand=1)

    def _init_canvas(self, parent):
        self._cframe = CanvasFrame(parent,
                                   background='white',
                                   width=525,
                                   closeenough=10,
                                   border=2,
                                   relief='sunken')
        self._cframe.pack(expand=1, fill='both', side='top', pady=2)
        canvas = self._canvas = self._cframe.canvas()

        self._stackwidgets = []
        self._rtextwidgets = []
        self._titlebar = canvas.create_rectangle(0,
                                                 0,
                                                 0,
                                                 0,
                                                 fill='#c0f0f0',
                                                 outline='black')
        self._exprline = canvas.create_line(0, 0, 0, 0, dash='.')
        self._stacktop = canvas.create_line(0, 0, 0, 0, fill='#408080')
        size = self._size.get() + 4
        self._stacklabel = TextWidget(canvas,
                                      'Stack',
                                      color='#004040',
                                      font=self._boldfont)
        self._rtextlabel = TextWidget(canvas,
                                      'Remaining Text',
                                      color='#004040',
                                      font=self._boldfont)
        self._cframe.add_widget(self._stacklabel)
        self._cframe.add_widget(self._rtextlabel)

    #########################################
    ##  Main draw procedure
    #########################################

    def _redraw(self):
        scrollregion = self._canvas['scrollregion'].split()
        (cx1, cy1, cx2, cy2) = [int(c) for c in scrollregion]

        # Delete the old stack & rtext widgets.
        for stackwidget in self._stackwidgets:
            self._cframe.destroy_widget(stackwidget)
        self._stackwidgets = []
        for rtextwidget in self._rtextwidgets:
            self._cframe.destroy_widget(rtextwidget)
        self._rtextwidgets = []

        # Position the titlebar & exprline
        (x1, y1, x2, y2) = self._stacklabel.bbox()
        y = y2 - y1 + 10
        self._canvas.coords(self._titlebar, -5000, 0, 5000, y - 4)
        self._canvas.coords(self._exprline, 0, y * 2 - 10, 5000, y * 2 - 10)

        # Position the titlebar labels..
        (x1, y1, x2, y2) = self._stacklabel.bbox()
        self._stacklabel.move(5 - x1, 3 - y1)
        (x1, y1, x2, y2) = self._rtextlabel.bbox()
        self._rtextlabel.move(cx2 - x2 - 5, 3 - y1)

        # Draw the stack.
        stackx = 5
        for tok in self._parser.stack():
            if isinstance(tok, Tree):
                attribs = {
                    'tree_color': '#4080a0',
                    'tree_width': 2,
                    'node_font': self._boldfont,
                    'node_color': '#006060',
                    'leaf_color': '#006060',
                    'leaf_font': self._font
                }
                widget = tree_to_treesegment(self._canvas, tok, **attribs)
                widget.label()['color'] = '#000000'
            else:
                widget = TextWidget(self._canvas,
                                    tok,
                                    color='#000000',
                                    font=self._font)
            widget.bind_click(self._popup_reduce)
            self._stackwidgets.append(widget)
            self._cframe.add_widget(widget, stackx, y)
            stackx = widget.bbox()[2] + 10

        # Draw the remaining text.
        rtextwidth = 0
        for tok in self._parser.remaining_text():
            widget = TextWidget(self._canvas,
                                tok,
                                color='#000000',
                                font=self._font)
            self._rtextwidgets.append(widget)
            self._cframe.add_widget(widget, rtextwidth, y)
            rtextwidth = widget.bbox()[2] + 4

        # Allow enough room to shift the next token (for animations)
        if len(self._rtextwidgets) > 0:
            stackx += self._rtextwidgets[0].width()

        # Move the remaining text to the correct location (keep it
        # right-justified, when possible); and move the remaining text
        # label, if necessary.
        stackx = max(stackx, self._stacklabel.width() + 25)
        rlabelwidth = self._rtextlabel.width() + 10
        if stackx >= cx2 - max(rtextwidth, rlabelwidth):
            cx2 = stackx + max(rtextwidth, rlabelwidth)
        for rtextwidget in self._rtextwidgets:
            rtextwidget.move(4 + cx2 - rtextwidth, 0)
        self._rtextlabel.move(cx2 - self._rtextlabel.bbox()[2] - 5, 0)

        midx = (stackx + cx2 - max(rtextwidth, rlabelwidth)) / 2
        self._canvas.coords(self._stacktop, midx, 0, midx, 5000)
        (x1, y1, x2, y2) = self._stacklabel.bbox()

        # Set up binding to allow them to shift a token by dragging it.
        if len(self._rtextwidgets) > 0:

            def drag_shift(widget, midx=midx, self=self):
                if widget.bbox()[0] < midx: self.shift()
                else: self._redraw()

            self._rtextwidgets[0].bind_drag(drag_shift)
            self._rtextwidgets[0].bind_click(self.shift)

        # Draw the stack top.
        self._highlight_productions()

    def _draw_stack_top(self, widget):
        # hack..
        midx = widget.bbox()[2] + 50
        self._canvas.coords(self._stacktop, midx, 0, midx, 5000)

    def _highlight_productions(self):
        # Highlight the productions that can be reduced.
        self._prodlist.selection_clear(0, 'end')
        for prod in self._parser.reducible_productions():
            index = self._productions.index(prod)
            self._prodlist.selection_set(index)

    #########################################
    ##  Button Callbacks
    #########################################

    def destroy(self, *e):
        if self._top is None: return
        self._top.destroy()
        self._top = None

    def reset(self, *e):
        self._parser.initialize(self._sent)
        self._lastoper1['text'] = 'Reset App'
        self._lastoper2['text'] = ''
        self._redraw()

    def step(self, *e):
        if self.reduce(): return True
        elif self.shift(): return True
        else:
            if list(self._parser.parses()):
                self._lastoper1['text'] = 'Finished:'
                self._lastoper2['text'] = 'Success'
            else:
                self._lastoper1['text'] = 'Finished:'
                self._lastoper2['text'] = 'Failure'

    def shift(self, *e):
        if self._animating_lock: return
        if self._parser.shift():
            tok = self._parser.stack()[-1]
            self._lastoper1['text'] = 'Shift:'
            self._lastoper2['text'] = '%r' % tok
            if self._animate.get():
                self._animate_shift()
            else:
                self._redraw()
            return True
        return False

    def reduce(self, *e):
        if self._animating_lock: return
        production = self._parser.reduce()
        if production:
            self._lastoper1['text'] = 'Reduce:'
            self._lastoper2['text'] = '%s' % production
            if self._animate.get():
                self._animate_reduce()
            else:
                self._redraw()
        return production

    def undo(self, *e):
        if self._animating_lock: return
        if self._parser.undo():
            self._redraw()

    def postscript(self, *e):
        self._cframe.print_to_file()

    def mainloop(self, *args, **kwargs):
        """
        Enter the Tkinter mainloop.  This function must be called if
        this demo is created from a non-interactive program (e.g.
        from a secript); otherwise, the demo will close as soon as
        the script completes.
        """
        if in_idle(): return
        self._top.mainloop(*args, **kwargs)

    #########################################
    ##  Menubar callbacks
    #########################################

    def resize(self, size=None):
        if size is not None: self._size.set(size)
        size = self._size.get()
        self._font.configure(size=-(abs(size)))
        self._boldfont.configure(size=-(abs(size)))
        self._sysfont.configure(size=-(abs(size)))

        #self._stacklabel['font'] = ('helvetica', -size-4, 'bold')
        #self._rtextlabel['font'] = ('helvetica', -size-4, 'bold')
        #self._lastoper_label['font'] = ('helvetica', -size)
        #self._lastoper1['font'] = ('helvetica', -size)
        #self._lastoper2['font'] = ('helvetica', -size)
        #self._prodlist['font'] = ('helvetica', -size)
        #self._prodlist_label['font'] = ('helvetica', -size-2, 'bold')
        self._redraw()

    def help(self, *e):
        # The default font's not very legible; try using 'fixed' instead.
        try:
            ShowText(self._top,
                     'Help: Shift-Reduce Parser Application', (__doc__
                                                               or '').strip(),
                     width=75,
                     font='fixed')
        except:
            ShowText(self._top,
                     'Help: Shift-Reduce Parser Application', (__doc__
                                                               or '').strip(),
                     width=75)

    def about(self, *e):
        ABOUT = ("NLTK Shift-Reduce Parser Application\n" +
                 "Written by Edward Loper")
        TITLE = 'About: Shift-Reduce Parser Application'
        try:
            from tkinter.messagebox import Message
            Message(message=ABOUT, title=TITLE).show()
        except:
            ShowText(self._top, TITLE, ABOUT)

    def edit_grammar(self, *e):
        CFGEditor(self._top, self._parser.grammar(), self.set_grammar)

    def set_grammar(self, grammar):
        self._parser.set_grammar(grammar)
        self._productions = list(grammar.productions())
        self._prodlist.delete(0, 'end')
        for production in self._productions:
            self._prodlist.insert('end', (' %s' % production))

    def edit_sentence(self, *e):
        sentence = " ".join(self._sent)
        title = 'Edit Text'
        instr = 'Enter a new sentence to parse.'
        EntryDialog(self._top, sentence, instr, self.set_sentence, title)

    def set_sentence(self, sent):
        self._sent = sent.split()  #[XX] use tagged?
        self.reset()

    #########################################
    ##  Reduce Production Selection
    #########################################

    def _toggle_grammar(self, *e):
        if self._show_grammar.get():
            self._prodframe.pack(fill='both',
                                 side='left',
                                 padx=2,
                                 after=self._feedbackframe)
            self._lastoper1['text'] = 'Show Grammar'
        else:
            self._prodframe.pack_forget()
            self._lastoper1['text'] = 'Hide Grammar'
        self._lastoper2['text'] = ''

    def _prodlist_select(self, event):
        selection = self._prodlist.curselection()
        if len(selection) != 1: return
        index = int(selection[0])
        production = self._parser.reduce(self._productions[index])
        if production:
            self._lastoper1['text'] = 'Reduce:'
            self._lastoper2['text'] = '%s' % production
            if self._animate.get():
                self._animate_reduce()
            else:
                self._redraw()
        else:
            # Reset the production selections.
            self._prodlist.selection_clear(0, 'end')
            for prod in self._parser.reducible_productions():
                index = self._productions.index(prod)
                self._prodlist.selection_set(index)

    def _popup_reduce(self, widget):
        # Remove old commands.
        productions = self._parser.reducible_productions()
        if len(productions) == 0: return

        self._reduce_menu.delete(0, 'end')
        for production in productions:
            self._reduce_menu.add_command(label=str(production),
                                          command=self.reduce)
        self._reduce_menu.post(self._canvas.winfo_pointerx(),
                               self._canvas.winfo_pointery())

    #########################################
    ##  Animations
    #########################################

    def _animate_shift(self):
        # What widget are we shifting?
        widget = self._rtextwidgets[0]

        # Where are we shifting from & to?
        right = widget.bbox()[0]
        if len(self._stackwidgets) == 0: left = 5
        else: left = self._stackwidgets[-1].bbox()[2] + 10

        # Start animating.
        dt = self._animate.get()
        dx = (left - right) * 1.0 / dt
        self._animate_shift_frame(dt, widget, dx)

    def _animate_shift_frame(self, frame, widget, dx):
        if frame > 0:
            self._animating_lock = 1
            widget.move(dx, 0)
            self._top.after(10, self._animate_shift_frame, frame - 1, widget,
                            dx)
        else:
            # but: stacktop??

            # Shift the widget to the stack.
            del self._rtextwidgets[0]
            self._stackwidgets.append(widget)
            self._animating_lock = 0

            # Display the available productions.
            self._draw_stack_top(widget)
            self._highlight_productions()

    def _animate_reduce(self):
        # What widgets are we shifting?
        numwidgets = len(self._parser.stack()[-1])  # number of children
        widgets = self._stackwidgets[-numwidgets:]

        # How far are we moving?
        if isinstance(widgets[0], TreeSegmentWidget):
            ydist = 15 + widgets[0].label().height()
        else:
            ydist = 15 + widgets[0].height()

        # Start animating.
        dt = self._animate.get()
        dy = ydist * 2.0 / dt
        self._animate_reduce_frame(dt / 2, widgets, dy)

    def _animate_reduce_frame(self, frame, widgets, dy):
        if frame > 0:
            self._animating_lock = 1
            for widget in widgets:
                widget.move(0, dy)
            self._top.after(10, self._animate_reduce_frame, frame - 1, widgets,
                            dy)
        else:
            del self._stackwidgets[-len(widgets):]
            for widget in widgets:
                self._cframe.remove_widget(widget)
            tok = self._parser.stack()[-1]
            if not isinstance(tok, Tree): raise ValueError()
            label = TextWidget(self._canvas,
                               str(tok.label()),
                               color='#006060',
                               font=self._boldfont)
            widget = TreeSegmentWidget(self._canvas, label, widgets, width=2)
            (x1, y1, x2, y2) = self._stacklabel.bbox()
            y = y2 - y1 + 10
            if not self._stackwidgets: x = 5
            else: x = self._stackwidgets[-1].bbox()[2] + 10
            self._cframe.add_widget(widget, x, y)
            self._stackwidgets.append(widget)

            # Display the available productions.
            self._draw_stack_top(widget)
            self._highlight_productions()

            #             # Delete the old widgets..
            #             del self._stackwidgets[-len(widgets):]
            #             for widget in widgets:
            #                 self._cframe.destroy_widget(widget)
            #
            #             # Make a new one.
            #             tok = self._parser.stack()[-1]
            #             if isinstance(tok, Tree):
            #                 attribs = {'tree_color': '#4080a0', 'tree_width': 2,
            #                            'node_font': bold, 'node_color': '#006060',
            #                            'leaf_color': '#006060', 'leaf_font':self._font}
            #                 widget = tree_to_treesegment(self._canvas, tok.type(),
            #                                              **attribs)
            #                 widget.node()['color'] = '#000000'
            #             else:
            #                 widget = TextWidget(self._canvas, tok.type(),
            #                                     color='#000000', font=self._font)
            #             widget.bind_click(self._popup_reduce)
            #             (x1, y1, x2, y2) = self._stacklabel.bbox()
            #             y = y2-y1+10
            #             if not self._stackwidgets: x = 5
            #             else: x = self._stackwidgets[-1].bbox()[2] + 10
            #             self._cframe.add_widget(widget, x, y)
            #             self._stackwidgets.append(widget)

            #self._redraw()
            self._animating_lock = 0

    #########################################
    ##  Hovering.
    #########################################

    def _highlight_hover(self, event):
        # What production are we hovering over?
        index = self._prodlist.nearest(event.y)
        if self._hover == index: return

        # Clear any previous hover highlighting.
        self._clear_hover()

        # If the production corresponds to an available reduction,
        # highlight the stack.
        selection = [int(s) for s in self._prodlist.curselection()]
        if index in selection:
            rhslen = len(self._productions[index].rhs())
            for stackwidget in self._stackwidgets[-rhslen:]:
                if isinstance(stackwidget, TreeSegmentWidget):
                    stackwidget.label()['color'] = '#00a000'
                else:
                    stackwidget['color'] = '#00a000'

        # Remember what production we're hovering over.
        self._hover = index

    def _clear_hover(self, *event):
        # Clear any previous hover highlighting.
        if self._hover == -1: return
        self._hover = -1
        for stackwidget in self._stackwidgets:
            if isinstance(stackwidget, TreeSegmentWidget):
                stackwidget.label()['color'] = 'black'
            else:
                stackwidget['color'] = 'black'
Ejemplo n.º 33
0
class DataDisplay(Frame):
    def __init__(self, widget_options):
        super().__init__()
        self.widget_options = widget_options
        self.init_gui()

    def init_gui(self):
        self.columnconfigure(0, weight=3)
        self.columnconfigure(1, weight=2)
        self.columnconfigure(2, weight=2)

        self.rowconfigure(1, weight=1)

        self.names = Listbox(self, **self.widget_options)
        self.date_added = Listbox(self, **self.widget_options)
        self.expdate = Listbox(self, **self.widget_options)
        self.names.bind("<ButtonRelease-1>", self.select_fields)
        self.date_added.bind("<ButtonRelease-1>", self.select_fields)
        self.expdate.bind("<ButtonRelease-1>", self.select_fields)

        self.name_label = Label(self, text="Food Name", **self.widget_options)
        self.added_label = Label(self,
                                 text="Date Added",
                                 **self.widget_options)
        self.exp_label = Label(self,
                               text="Expiration Date",
                               **self.widget_options)

        self.name_label.grid(row=0, column=0, sticky=N + S + E + W)
        self.added_label.grid(row=0, column=1, sticky=N + S + E + W)
        self.exp_label.grid(row=0, column=2, sticky=N + S + E + W)
        self.names.grid(row=1, column=0, sticky=N + S + E + W)
        self.date_added.grid(row=1, column=1, sticky=N + S + E + W)
        self.expdate.grid(row=1, column=2, sticky=N + S + E + W)

    def delete(self, *args):
        self.names.delete(*args)
        self.date_added.delete(*args)
        self.expdate.delete(*args)

    def insert(self, where, item):
        self.names.insert(where, item[0])
        self.date_added.insert(where, item[1])
        self.expdate.insert(where, item[2])

    def get(self, *args):
        name_select = self.names.curselection()
        date_added_select = self.date_added.curselection()
        expdate_select = self.expdate.curselection()

        item = (self.names.get(*args), self.date_added.get(*args),
                self.expdate.get(*args))
        return "{} {} {}".format(*item)

    def select_fields(self, event=None):
        instance = event.widget
        sel_ind = instance.curselection()[0] if instance.curselection() else 0
        self.names.selection_clear(0, END)
        self.date_added.selection_clear(0, END)
        self.expdate.selection_clear(0, END)

        self.date_added.selection_set(sel_ind)
        self.expdate.selection_set(sel_ind)
        self.names.selection_set(sel_ind)
Ejemplo n.º 34
0
class FilePane:
    def __init__(self,
                 root,
                 items=list(),
                 on_selection=list(),
                 on_close=list()):
        self.items = items
        self.item_count = len(items)
        self.on_selection = on_selection
        self.on_close = on_close

        self.window = Toplevel()
        self.window.title('Files')
        self.window.transient(root)
        self.window.protocol("WM_DELETE_WINDOW", self.on_window_close)

        self.menubar = Menu(self.window)
        self.menubar.add_command(label='Previous', command=self.previous)
        self.menubar.add_command(label='Next', command=self.next)

        # Display the menu
        self.window.config(menu=self.menubar)

        self.scrollbar = Scrollbar(self.window, orient='vertical')
        self.listbox = Listbox(self.window,
                               yscrollcommand=self.scrollbar.set,
                               exportselection=False)
        self.set_items(items)
        self.scrollbar.config(command=self.listbox.yview)
        self.scrollbar.pack(side='right', fill='y')
        self.listbox.pack(side='left', fill='both', expand=1)

        self.listbox.bind('<<ListboxSelect>>', self.on_select)

    def on_window_close(self):
        for callback in self.on_close:
            callback()
        self.window.withdraw()

    def hide(self):
        self.window.withdraw()

    def show(self):
        self.window.deiconify()

    def selected_item(self):
        return self.items[self.listbox.curselection()[0]]

    def select_index(self, index):
        self.listbox.selection_clear(0, END)

        # From https://stackoverflow.com/a/25451279/11628429
        self.listbox.select_set(
            index)  #This only sets focus on the first item.
        self.listbox.event_generate("<<ListboxSelect>>")

    def set_items(self, items):
        self.items = items
        self.item_count = len(items)
        self.listbox.delete(0, END)

        for item in items:
            item = path.split(item)[1]
            self.listbox.insert(END, item)

        self.select_index(0)

    def previous(self):
        index = self.listbox.curselection()[0] - 1
        if index < 0:
            index = self.item_count - 1
        self.select_index(index)

    def next(self):
        index = self.listbox.curselection()[0] + 1
        if index >= self.item_count:
            index = 0
        self.select_index(index)

    def on_select(self, event):
        if self.on_selection:
            for callback in self.on_selection:
                callback(self.selected_item())
Ejemplo n.º 35
0
class ContactsPage(Frame):
    """
    Contacts Page:
        Contains the list of currently added contacts

    === Public Attributes ===
    master: The frame containing all information on this page
    controller: Reference to the Controller Class

    page_name: String containing a name for this page; used for setting the tabs
                in the containing notebook

    contacts_list: Dictionary of contacts, each contact is a Contact class instance,
                    each key is the name of the contact
    current_contact: Contains the contact that was selected the last time we clicked on show info.

    scroll_bar: Scroll bar that controls what is viewable in the contacts list;
                won't scroll if nothing is in the list, or everything is already
                shown.
    contacts_field: Area where contacts are shown; 10 at a time
    letters_field: Listbox that shows each letter of the alphabet to help the user find
                    contact they're looking for
    show_info: Button that updates the info_field with the information of the
                currently selected contact
    wheel_spin: WheelSpinner object for the Show Contact Button.
    delete: Button that deletes the selected contact
    info_field: Listbox that contains the information of the currently selected contact
    info_scroll: Scrollbar that controls what is viewable in the info_field; won't
                    scroll if nothing is in the list, or everything is already shown

    self.load: Button to load contacts
    self.save: Button to save contacts

    === Methods ===
    create: Initializes objects & places them on the page
    insert_contact: Adds a contact's name to the end of the contacts field
    show_contact_info: Shows the information of the selected contact in the info listbox
    delete_contact: Deletes the selected contact & reloads the contacts Listbox
    clear_fields: Clears both fields on the contacts page
    load_contacts: Loads contacts in from a file
    save_contacts: Saves contacts as a file
    yview: Adjusts the view of contacts_field & letters_field at the same time
    on_mouse_wheel: Adjusts the view of contacts_field and letters_field at the same time, for the
        mouse wheel
    """

    def __init__(self, master, controller, **kw):
        super().__init__(master, **kw)
        self.master = master
        self.controller = controller

        self.page_name = "View Contacts"

        # Initialize object names
        self.contacts_list = {}
        self.current_contact = None
        self.alphabetical_order = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
                                   'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

        self.scroll_bar = None
        self.contacts_field = None
        self.letters_field = None
        self.show_info = None
        self.wheel_spin = None
        self.delete = None
        self.info_field = None
        self.info_scroll = None

        self.bind("<<Finish Spinning Wheel>>", self.show_winning_info)
        self.bind("<Visibility>", self.__on_visibility)

        self.load = None
        self.save = None

        self.create()

    def create(self) -> None:
        self.info_scroll = Scrollbar(self, orient=VERTICAL)
        self.info_field = Listbox(
            self,
            yscrollcommand=self.info_scroll.set
        )

        self.delete = Button(self, text="Delete", command=lambda: self.delete_contact())
        self.delete.grid(row=2, column=3, columnspan=3, sticky=N + S + E + W)

        self.show_info = Button(self, text="Show Info", command=lambda: self.show_contact_info())
        self.show_info.grid(row=2, column=0, columnspan=3, sticky=N + S + E + W)

        wheel_spin_options = ['Name', 'Home Phone Numbers', 'Work Phone Numbers',
                              'Personal Phone Numbers', 'Emails', 'Home Addresses', 'Notes']
        self.wheel_spin = WheelSpinner(self, wheel_spin_options, width=50, height=200, radius=60)
        self.wheel_spin.grid(row=3, column=0, columnspan=5)

        self.scroll_bar = Scrollbar(self)
        self.contacts_field = Listbox(
            self,
            yscrollcommand=self.scroll_bar.set,
            selectmode=SINGLE,
            exportselection=0
        )
        self.letters_field = Listbox(
            self,
            width=2,
            selectmode=NONE,
            exportselection=0
        )

        self.letters_field.bind('<<ListboxSelect>>', self.scroll_to_letter)
        self.contacts_field.grid(row=1, column=0, columnspan=5, sticky=N + S + E + W)
        self.letters_field.grid(row=1, column=4, sticky=N + S + E + W)
        self.scroll_bar.grid(row=1, column=5, sticky=N + S + E + W)
        self.scroll_bar.config(command=self.yview)
        self.contacts_field.bind("<MouseWheel>", self.on_mouse_wheel)
        self.letters_field.bind("<MouseWheel>", self.on_letter_mouse_wheel)

        self.save = Button(
            self,
            text="Save Contacts",
            command=lambda: self.save_contacts()
        )
        self.save.grid(row=0, column=3, columnspan=4, sticky=N + S + E + W)

        self.load = Button(
            self,
            text="Load Contacts",
            command=lambda: self.load_contacts()
        )
        self.load.grid(row=0, column=0, columnspan=3, sticky=N + S + E + W)

        for i in range(3):
            self.grid_rowconfigure(i, weight=1)

        for i in range(4):
            self.grid_columnconfigure(i, weight=1)

    def scroll_to_letter(self, event):
        id = 0
        for contact in self.order_contact():
            if contact[0] == self.letters_field.get(self.letters_field.curselection()[0]):
                self.contacts_field.see(id)
                self.contacts_field.selection_clear(0, END)
                self.contacts_field.selection_set(id)
                self.letters_field.selection_clear(0, END)
                return
            id += 1
        self.letters_field.selection_clear(0, END)

    def on_mouse_wheel(self, event) -> str:
        self.contacts_field.yview("scroll", int(-event.delta / 80), "units")
        return "break"

    def on_letter_mouse_wheel(self, event) -> str:
        self.letters_field.yview("scroll", int(-event.delta / 80), "units")
        return "break"

    def yview(self, *args) -> None:
        self.contacts_field.yview(*args)
        self.letters_field.yview(*args)

    def delete_contact(self) -> None:
        name = self.contacts_field.get(self.contacts_field.curselection()[0])
        del self.contacts_list[name]
        self.clear_fields()
        for contact in sorted(self.contacts_list):
            self.insert_contact(contact)

    def clear_fields(self) -> None:
        for field in [self.contacts_field, self.info_field, self.letters_field]:
            field.delete(0, END)

    def refresh_fields(self) -> None:
        self.clear_fields()
        for contact in self.order_contact():
            self.contacts_field.insert(END, contact)

        for letter in self.alphabetical_order:
            self.letters_field.insert(END, letter.upper())

    def load_contacts(self) -> None:
        self.randomize_alphabetical_order()
        with open("project/contacts_pickle", 'rb') as infile:
            self.contacts_list = pickle.load(infile)
            self.refresh_fields()

    def save_contacts(self) -> None:
        with open("project/contacts_pickle", 'wb') as outfile:
            pickle.dump(self.contacts_list, outfile)

    def insert_contact(self, contact) -> None:
        self.contacts_field.insert(END, contact)

    def show_contact_info(self) -> None:
        """
        This method shows the spinning wheel if a contact is selected and if the wheel isn't already
            rotating
        It is called on the Show Contact Info button.
        :return: None
        """
        if len(self.contacts_field.curselection()) == 0 or self.wheel_spin.is_rotating:
            return

        name = self.contacts_field.get(self.contacts_field.curselection()[0])
        self.current_contact = self.contacts_list[name]
        self.wheel_spin.draw()

    def show_winning_info(self, event) -> None:
        """
        This method is called when the event <<Finish Spinning Wheel>> is invoked. It displays the
        current contact information that was selected by the spinning wheel.
        :return: None
        """
        self.randomize_alphabetical_order()
        self.refresh_fields()
        winner = self.wheel_spin.winner
        label = self.wheel_spin.display_label
        text0 = self.current_contact.name + "'s " + winner.lower() + ':\n'
        text1 = ''

        if winner == 'Name':
            text1 = self.current_contact.name
        elif winner == 'Home Phone Numbers':
            for elem in self.current_contact.phone_numbers["Home"]:
                text1 = text1 + elem + ", "
        elif winner == 'Work Phone Numbers':
            for elem in self.current_contact.phone_numbers["Work"]:
                text1 = text1 + elem + ', '
        elif winner == 'Personal Phone Numbers':
            for elem in self.current_contact.phone_numbers["Personal"]:
                text1 = text1 + elem + ', '
        elif winner == 'Emails':
            for elem in self.current_contact.email_addresses:
                text1 = text1 + elem + ', '
        elif winner == 'Home Addresses':
            for elem in self.current_contact.addresses:
                text1 = text1 + elem + ', '
        elif winner == 'Notes':
            for elem in self.current_contact.notes:
                text1 = text1 + elem + ', '

        label['text'] = text0 + text1

    def randomize_alphabetical_order(self):
        random.shuffle(self.alphabetical_order)

    def order_contact(self) -> list:
        """
        This function takes all the contacts and order them in the order stored in self.alphabetical
        order
        :return: The ordered list
        """
        i = 0
        order = self.alphabetical_order
        contacts = list(self.contacts_list)
        ordered_list = []

        # We loop until we have all the contact ordered.
        while i < len(self.contacts_list):
            current_next_contact = None
            for contact in contacts:
                if current_next_contact is None:
                    current_next_contact = contact
                    continue
                # If the first letter is higher in the order than the current next contact, we
                # change the contact.
                if order.index(contact[0].lower()) < order.index(current_next_contact[0].lower()):
                    current_next_contact = contact
                    continue

                # If the first character is the same, we loop through the other character to find
                # which on should be
                # added first.
                if order.index(contact[0].lower()) == order.index(current_next_contact[0].lower()):
                    for current_character in range(1, min(len(contact), len(current_next_contact))):
                        if order.index(contact[current_character].lower()) < \
                           order.index(current_next_contact[current_character].lower()):
                            current_next_contact = contact
                            break
                        if order.index(contact[current_character].lower()) > \
                           order.index(current_next_contact[current_character].lower()):
                            break
            # we append the contact to the list and remove it from the remaining contact to order.
            contacts.remove(current_next_contact)
            ordered_list.append(current_next_contact)
            i += 1
        return ordered_list

    def __on_visibility(self, event) -> None:
        """
        This function is called when the user click on the contact tab. It randomizes the
        alphabetical order
        :param event:
        :return: None
        """
        self.randomize_alphabetical_order()
        self.refresh_fields()