示例#1
0
class PuzzleViewer(Frame):

    @classmethod
    def _format(cls, obj, indent=0):
        prefix = '  ' * indent
        if isinstance(obj, list):
            return textwrap.indent(
                '\n[' + ','.join(cls._format(e, indent + 1)
                                 for e in obj) + '\n]',
                prefix)
        elif isinstance(obj, dict):
            return textwrap.indent(
                '\n{' + (','.join(
                         '{}:{}'.format(cls._format(k, indent + 1),
                                        cls._format(v, indent + 1))
                         for k, v
                         in obj.items())) + '\n}',
                prefix)
        return textwrap.indent('\n' + str(obj), prefix)

    def __init__(self, master):
        super().__init__(master)
        self._text = Text(self, font=("Mono", 12))
        self.button = Button(self, text='repr',
                             command=self.toggle)
        self._raw_text = ''
        self._text.pack(fill='both', expand=1)
        self.button.pack()

    def update_text(self, obj):
        self._raw_text = obj
        self._text.delete('0.0', 'end')
        if self.button.cget('text') == 'repr':
            self._text.insert('end', pprint.pformat(obj))
        else:
            self._text.insert('end', self._format(obj))

    def toggle(self):
        if self.button.cget('text') == 'repr':
            self.button.config(text='str')
            self.update_text(self._raw_text)
        else:
            self.button.config(text='repr')
            self.update_text(self._raw_text)
示例#2
0
    def createTempMenu(self):

        level = self.menu_tree.getSelectionLevel(self.temp_menu_tree.tree[0])
        self.menu_tree.traverseDownToSelectionLevel(
            self.temp_menu_tree.tree[0])
        rowNumber = 0
        for child in level:

            settingValue = Label(self.menuFrame, text=child.value[0])
            settingValue.grid(row=rowNumber, column=1)
            settingKey = Button(
                self.menuFrame,
                text=child.name,
                command=lambda: self.changeMenuValue(child, settingValue))
            self.buttonColor = settingKey.cget('bg')
            settingKey.grid(row=rowNumber, column=0)
            self.nodeToButtonDict[child] = (settingKey, settingValue)
            if rowNumber == 0:
                self.currentSelectionButton = settingKey
                self.currentSelectionNode = child
            rowNumber += 1

        self.makeSelectedButtonColored(self.currentSelectionButton)
示例#3
0
class GetKeysDialog(Toplevel):

    # Dialog title for invalid key sequence
    keyerror_title = 'Key Sequence Error'

    def __init__(self,
                 parent,
                 title,
                 action,
                 current_key_sequences,
                 *,
                 _htest=False,
                 _utest=False):
        """
        parent - parent of this dialog
        title - string which is the title of the popup dialog
        action - string, the name of the virtual event these keys will be
                 mapped to
        current_key_sequences - list, a list of all key sequence lists
                 currently mapped to virtual events, for overlap checking
        _htest - bool, change box location when running htest
        _utest - bool, do not wait when running unittest
        """
        Toplevel.__init__(self, parent)
        self.withdraw()  # Hide while setting geometry.
        self.configure(borderwidth=5)
        self.resizable(height=False, width=False)
        self.title(title)
        self.transient(parent)
        self.grab_set()
        self.protocol("WM_DELETE_WINDOW", self.cancel)
        self.parent = parent
        self.action = action
        self.current_key_sequences = current_key_sequences
        self.result = ''
        self.key_string = StringVar(self)
        self.key_string.set('')
        # Set self.modifiers, self.modifier_label.
        self.set_modifiers_for_platform()
        self.modifier_vars = []
        for modifier in self.modifiers:
            variable = StringVar(self)
            variable.set('')
            self.modifier_vars.append(variable)
        self.advanced = False
        self.create_widgets()
        self.update_idletasks()
        self.geometry("+%d+%d" %
                      (parent.winfo_rootx() +
                       (parent.winfo_width() / 2 - self.winfo_reqwidth() / 2),
                       parent.winfo_rooty() +
                       ((parent.winfo_height() / 2 -
                         self.winfo_reqheight() / 2) if not _htest else 150))
                      )  # Center dialog over parent (or below htest box).
        if not _utest:
            self.deiconify()  # Geometry set, unhide.
            self.wait_window()

    def showerror(self, *args, **kwargs):
        # Make testing easier.  Replace in #30751.
        messagebox.showerror(*args, **kwargs)

    def create_widgets(self):
        self.frame = frame = Frame(self, borderwidth=2, relief='sunken')
        frame.pack(side='top', expand=True, fill='both')

        frame_buttons = Frame(self)
        frame_buttons.pack(side='bottom', fill='x')

        self.button_ok = Button(frame_buttons,
                                text='OK',
                                width=8,
                                command=self.ok)
        self.button_ok.grid(row=0, column=0, padx=5, pady=5)
        self.button_cancel = Button(frame_buttons,
                                    text='Cancel',
                                    width=8,
                                    command=self.cancel)
        self.button_cancel.grid(row=0, column=1, padx=5, pady=5)

        # Basic entry key sequence.
        self.frame_keyseq_basic = Frame(frame, name='keyseq_basic')
        self.frame_keyseq_basic.grid(row=0,
                                     column=0,
                                     sticky='nsew',
                                     padx=5,
                                     pady=5)
        basic_title = Label(self.frame_keyseq_basic,
                            text=f"New keys for '{self.action}' :")
        basic_title.pack(anchor='w')

        basic_keys = Label(self.frame_keyseq_basic,
                           justify='left',
                           textvariable=self.key_string,
                           relief='groove',
                           borderwidth=2)
        basic_keys.pack(ipadx=5, ipady=5, fill='x')

        # Basic entry controls.
        self.frame_controls_basic = Frame(frame)
        self.frame_controls_basic.grid(row=1, column=0, sticky='nsew', padx=5)

        # Basic entry modifiers.
        self.modifier_checkbuttons = {}
        column = 0
        for modifier, variable in zip(self.modifiers, self.modifier_vars):
            label = self.modifier_label.get(modifier, modifier)
            check = Checkbutton(self.frame_controls_basic,
                                command=self.build_key_string,
                                text=label,
                                variable=variable,
                                onvalue=modifier,
                                offvalue='')
            check.grid(row=0, column=column, padx=2, sticky='w')
            self.modifier_checkbuttons[modifier] = check
            column += 1

        # Basic entry help text.
        help_basic = Label(self.frame_controls_basic,
                           justify='left',
                           text="Select the desired modifier keys\n" +
                           "above, and the final key from the\n" +
                           "list on the right.\n\n" +
                           "Use upper case Symbols when using\n" +
                           "the Shift modifier.  (Letters will be\n" +
                           "converted automatically.)")
        help_basic.grid(row=1, column=0, columnspan=4, padx=2, sticky='w')

        # Basic entry key list.
        self.list_keys_final = Listbox(self.frame_controls_basic,
                                       width=15,
                                       height=10,
                                       selectmode='single')
        self.list_keys_final.insert('end', *AVAILABLE_KEYS)
        self.list_keys_final.bind('<ButtonRelease-1>', self.final_key_selected)
        self.list_keys_final.grid(row=0, column=4, rowspan=4, sticky='ns')
        scroll_keys_final = Scrollbar(self.frame_controls_basic,
                                      orient='vertical',
                                      command=self.list_keys_final.yview)
        self.list_keys_final.config(yscrollcommand=scroll_keys_final.set)
        scroll_keys_final.grid(row=0, column=5, rowspan=4, sticky='ns')
        self.button_clear = Button(self.frame_controls_basic,
                                   text='Clear Keys',
                                   command=self.clear_key_seq)
        self.button_clear.grid(row=2, column=0, columnspan=4)

        # Advanced entry key sequence.
        self.frame_keyseq_advanced = Frame(frame, name='keyseq_advanced')
        self.frame_keyseq_advanced.grid(row=0,
                                        column=0,
                                        sticky='nsew',
                                        padx=5,
                                        pady=5)
        advanced_title = Label(
            self.frame_keyseq_advanced,
            justify='left',
            text=f"Enter new binding(s) for '{self.action}' :\n" +
            "(These bindings will not be checked for validity!)")
        advanced_title.pack(anchor='w')
        self.advanced_keys = Entry(self.frame_keyseq_advanced,
                                   textvariable=self.key_string)
        self.advanced_keys.pack(fill='x')

        # Advanced entry help text.
        self.frame_help_advanced = Frame(frame)
        self.frame_help_advanced.grid(row=1, column=0, sticky='nsew', padx=5)
        help_advanced = Label(
            self.frame_help_advanced,
            justify='left',
            text="Key bindings are specified using Tkinter keysyms as\n" +
            "in these samples: <Control-f>, <Shift-F2>, <F12>,\n"
            "<Control-space>, <Meta-less>, <Control-Alt-Shift-X>.\n"
            "Upper case is used when the Shift modifier is present!\n\n" +
            "'Emacs style' multi-keystroke bindings are specified as\n" +
            "follows: <Control-x><Control-y>, where the first key\n" +
            "is the 'do-nothing' keybinding.\n\n" +
            "Multiple separate bindings for one action should be\n" +
            "separated by a space, eg., <Alt-v> <Meta-v>.")
        help_advanced.grid(row=0, column=0, sticky='nsew')

        # Switch between basic and advanced.
        self.button_level = Button(frame,
                                   command=self.toggle_level,
                                   text='<< Basic Key Binding Entry')
        self.button_level.grid(row=2, column=0, stick='ew', padx=5, pady=5)
        self.toggle_level()

    def set_modifiers_for_platform(self):
        """Determine list of names of key modifiers for this platform.

        The names are used to build Tk bindings -- it doesn't matter if the
        keyboard has these keys; it matters if Tk understands them.  The
        order is also important: key binding equality depends on it, so
        config-keys.def must use the same ordering.
        """
        if sys.platform == "darwin":
            self.modifiers = ['Shift', 'Control', 'Option', 'Command']
        else:
            self.modifiers = ['Control', 'Alt', 'Shift']
        self.modifier_label = {'Control': 'Ctrl'}  # Short name.

    def toggle_level(self):
        "Toggle between basic and advanced keys."
        if self.button_level.cget('text').startswith('Advanced'):
            self.clear_key_seq()
            self.button_level.config(text='<< Basic Key Binding Entry')
            self.frame_keyseq_advanced.lift()
            self.frame_help_advanced.lift()
            self.advanced_keys.focus_set()
            self.advanced = True
        else:
            self.clear_key_seq()
            self.button_level.config(text='Advanced Key Binding Entry >>')
            self.frame_keyseq_basic.lift()
            self.frame_controls_basic.lift()
            self.advanced = False

    def final_key_selected(self, event=None):
        "Handler for clicking on key in basic settings list."
        self.build_key_string()

    def build_key_string(self):
        "Create formatted string of modifiers plus the key."
        keylist = modifiers = self.get_modifiers()
        final_key = self.list_keys_final.get('anchor')
        if final_key:
            final_key = translate_key(final_key, modifiers)
            keylist.append(final_key)
        self.key_string.set(f"<{'-'.join(keylist)}>")

    def get_modifiers(self):
        "Return ordered list of modifiers that have been selected."
        mod_list = [variable.get() for variable in self.modifier_vars]
        return [mod for mod in mod_list if mod]

    def clear_key_seq(self):
        "Clear modifiers and keys selection."
        self.list_keys_final.select_clear(0, 'end')
        self.list_keys_final.yview('moveto', '0.0')
        for variable in self.modifier_vars:
            variable.set('')
        self.key_string.set('')

    def ok(self, event=None):
        keys = self.key_string.get().strip()
        if not keys:
            self.showerror(title=self.keyerror_title,
                           parent=self,
                           message="No key specified.")
            return
        if (self.advanced or self.keys_ok(keys)) and self.bind_ok(keys):
            self.result = keys
        self.grab_release()
        self.destroy()

    def cancel(self, event=None):
        self.result = ''
        self.grab_release()
        self.destroy()

    def keys_ok(self, keys):
        """Validity check on user's 'basic' keybinding selection.

        Doesn't check the string produced by the advanced dialog because
        'modifiers' isn't set.
        """
        final_key = self.list_keys_final.get('anchor')
        modifiers = self.get_modifiers()
        title = self.keyerror_title
        key_sequences = [
            key for keylist in self.current_key_sequences for key in keylist
        ]
        if not keys.endswith('>'):
            self.showerror(title, parent=self, message='Missing the final Key')
        elif (not modifiers and final_key not in FUNCTION_KEYS + MOVE_KEYS):
            self.showerror(title=title,
                           parent=self,
                           message='No modifier key(s) specified.')
        elif (modifiers == ['Shift']) \
                 and (final_key not in
                      FUNCTION_KEYS + MOVE_KEYS + ('Tab', 'Space')):
            msg = 'The shift modifier by itself may not be used with'\
                  ' this key symbol.'
            self.showerror(title=title, parent=self, message=msg)
        elif keys in key_sequences:
            msg = 'This key combination is already in use.'
            self.showerror(title=title, parent=self, message=msg)
        else:
            return True
        return False

    def bind_ok(self, keys):
        "Return True if Tcl accepts the new keys else show message."
        try:
            binding = self.bind(keys, lambda: None)
        except TclError as err:
            self.showerror(
                title=self.keyerror_title,
                parent=self,
                message=(f'The entered key sequence is not accepted.\n\n'
                         f'Error: {err}'))
            return False
        else:
            self.unbind(keys, binding)
            return True
示例#4
0
class Application(Frame):
    """The main Tk application, a simple dialog."""
    def __init__(self, master=None):
        super().__init__(master)
        self.badge = None
        self.grid()
        self.columnconfigure(0, minsize=200)
        self.columnconfigure(1, minsize=200)
        self.rowconfigure(0, minsize=300)
        self.rowconfigure(3, minsize=30)
        self.create_widgets()
        # self.output.insert("1.0", "This is a test\n")
        # self.sentto.insert("end", b"this is an error\n", "error")
        self.connect()
        self.after(SERIAL_POLL_INTERVAL, self.poll_serial)

    def create_widgets(self):
        """Sets up dialog elements."""
        da_row = 0
        "counter so I don't have to update every grid() call when I add/remove row"
        self.select = tix.FileSelectBox(self,
                                        browsecmd=self.on_file_selected,
                                        pattern="*.fs",
                                        directory="forth")
        # self.select["textVariable"] = self.forth_file
        self.select.grid(row=da_row, columnspan=2, sticky='nwes', pady=10)
        da_row += 1
        self.output_label = Label(self, text="Badge Output")
        self.output_label.grid(row=da_row,
                               column=1,
                               sticky='w',
                               padx=10,
                               pady=3)
        self.sentto_label = Label(self, text="Sent To Badge")
        self.sentto_label.grid(row=da_row,
                               column=0,
                               sticky='w',
                               padx=10,
                               pady=3)
        da_row += 1
        # height is in lines, width in characters
        self.output = Text(self, height=16, width=40)
        self.output.grid(row=da_row, column=1, padx=10)
        self.sentto = Text(self, height=16, width=40)
        self.sentto.tag_configure("error", background="red")
        self.sentto.grid(row=da_row, column=0, padx=10)
        da_row += 1
        self.connect_btn = Button(self,
                                  text="Connect",
                                  command=self.toggle_connect)
        self.connect_btn.grid(row=da_row, column=0, columnspan=2)
        da_row += 1
        self.exec_btn = Button(self, text="Execute", command=self.send_file)
        self.exec_btn.state(["disabled"])
        self.exec_btn.grid(row=da_row,
                           column=0,
                           sticky='w' + 'e',
                           padx=10,
                           pady=3)
        self.quit = Button(self, text="QUIT", command=self.master.destroy)
        self.quit.grid(row=da_row, column=1, sticky='w' + 'e', padx=10, pady=3)
        da_row += 1
        self.status_panel = Frame(self, relief="sunken", borderwidth=3)
        self.status_panel.grid(row=da_row, columnspan=2, sticky='nwse')
        self.connect_status = Label(self.status_panel, text="Not Connected")
        self.connect_status.grid(row=0, padx=10, pady=5, sticky="w")
        if self.badge is not None:
            self.connect_btn.state(["disabled"])
            self.connect_status.config(text="Connected: " +
                                       self.badge.os_device)

    def send_file(self, _retry=False):
        """Send the selected file to the badge."""
        if self.badge:
            try:
                # oddly, very first set LED seems to not set correct color
                self.badge.led(0, 0, 128)
                self.badge.led(0, 0, 128)
                with open(self.select.cget("value"), 'r') as forthin:
                    self.badge.forth_run(forthin.read())
                time.sleep(1)  # because forth_run() may be too fast
                self.badge.led(0, 128, 0)
            except IOError:
                if not _retry:
                    self.connect()
                    self.send_file(True)
                else:
                    raise

    def poll_serial(self):
        "Checks serial port for incoming bytes, reads and displays them."
        if self.badge is not None:
            bytes_in = self.badge.read_from()
            if bytes_in:
                self.output.insert("end", bytes_in + b'\n')
        self.after(SERIAL_POLL_INTERVAL, self.poll_serial)

    def toggle_connect(self):
        "If connected, disconnect, otherwise connect."
        if self.connect_btn.cget("text") == "Connect":
            self.connect()
        else:
            self.disconnect()

    def disconnect(self):
        "Disconnect from current badge."
        isinstance(self.badge, Badge)
        self.badge.close()
        self.badge = None
        self.connect_btn.config(text="Connect")
        self.connect_status.config(text="Not connected.")
        self.exec_btn.state(["disabled"])

    def connect(self):
        """Attempt to connect to a badge; toggle Connect button if successful."""
        try:
            self.badge = Badge(on_serial_write=self.on_bytes_sent,
                               min_write_dt=0.01)
            self.connect_status.config(text="Connected: " +
                                       self.badge.os_device)
            self.connect_btn.config(text="Disconnect")
            # enable "Execute" if file is selected
            self.on_file_selected(self.select.cget("value"))
        except BadgeSerialException:
            self.connect_status.config(text="Not connected")

    def on_file_selected(self, selected_file):
        """Respond to user selection of file by enabling the Execute button."""
        if Path(selected_file).is_file:
            self.exec_btn.state(["!disabled"])
        else:
            self.exec_btn.state(["disabled"])

    def on_bytes_sent(self, data, count):
        self.sentto.insert("end", data[:count])
        if count < len(data):
            self.sentto.insert("end", data[count:], "error")
        self.sentto.insert("end", "\n")
示例#5
0
class Application(Frame):
    """The main Tk application, a simple dialog."""
    def __init__(self, master=None):
        super().__init__(master)
        self.badge = None
        self.grid()
        self.columnconfigure(0, minsize=200)
        self.columnconfigure(1, minsize=200)
        self.rowconfigure(0, minsize=300)
        self.rowconfigure(3, minsize=30)
        self.create_widgets()
        self.connect()

    def create_widgets(self):
        """Sets up dialog elements."""
        self.select = tix.FileSelectBox(self, browsecmd=self.on_file_selected,
                                        pattern="*.fs", directory="forth")
        # self.select["textVariable"] = self.forth_file
        self.select.grid(row=0, columnspan=2, sticky='n'+'w'+'e')
        self.connect_btn = Button(self, text="Connect",
                                  command=self.toggle_connect)
        self.connect_btn.grid(row=1, column=0, columnspan=2)
        self.exec_btn = Button(self, text="Execute", command=self.send_file)
        self.exec_btn.state(["disabled"])
        self.exec_btn.grid(row=2, column=0, sticky='w' + 'e', padx=5, pady=3)
        self.quit = Button(self, text="QUIT", command=self.master.destroy)
        self.quit.grid(row=2, column=1, sticky='w' + 'e', padx=5, pady=3)
        self.status_panel = Frame(self, relief="groove", borderwidth=3)
        self.status_panel.grid(row=3, columnspan=2, sticky='nwse')
        self.connect_status = Label(self.status_panel, text="Not Connected")
        self.connect_status.grid(row=0, padx=5, pady=5, sticky="w")
        if self.badge is not None:
            self.connect_btn.state(["disabled"])
            self.connect_status.config(text="Connected: " + self.badge.os_device)

    def send_file(self, _retry=False):
        """Send the selected file to the badge."""
        if self.badge:
            try:
                # oddly, very first set LED seems to not set correct color
                self.badge.led(0, 0, 128)
                self.badge.led(0, 0, 128)
                with open(self.select.cget("value"), 'r') as forthin:
                    self.badge.forth_run(forthin.read())
                time.sleep(1)  # because forth_run() may be too fast
                self.badge.led(0, 128, 0)
            except IOError:
                if not _retry:
                    self.connect()
                    self.send_file(True)
                else:
                    raise

    def toggle_connect(self):
        "If connected, disconnect, otherwise connect."
        if self.connect_btn.cget("text") == "Connect":
            self.connect()
        else:
            self.disconnect()

    def disconnect(self):
        "Disconnect from current badge."
        isinstance(self.badge, Badge)
        self.badge.close()
        self.badge = None
        self.connect_btn.config(text="Connect")
        self.connect_status.config(text="Not connected.")
        self.exec_btn.state(["disabled"])

    def connect(self):
        """Attempt to connect to a badge; toggle Connect button if successful."""
        try:
            self.badge = Badge()
            self.connect_status.config(text="Connected: " + self.badge.os_device)
            self.connect_btn.config(text="Disconnect")
            # enable "Execute" if file is selected
            self.on_file_selected(self.select.cget("value"))
        except BadgeSerialException:
            self.connect_status.config(text="Not connected")

    def on_file_selected(self, selected_file):
        """Respond to user selection of file by enabling the Execute button."""
        if Path(selected_file).is_file:
            self.exec_btn.state(["!disabled"])
        else:
            self.exec_btn.state(["disabled"])
示例#6
0
class GetKeysDialog(Toplevel):

    # Dialog title for invalid key sequence
    keyerror_title = 'Key Sequence Error'

    def __init__(self, parent, title, action, current_key_sequences,
                 *, _htest=False, _utest=False):
        """
        parent - parent of this dialog
        title - string which is the title of the popup dialog
        action - string, the name of the virtual event these keys will be
                 mapped to
        current_key_sequences - list, a list of all key sequence lists
                 currently mapped to virtual events, for overlap checking
        _htest - bool, change box location when running htest
        _utest - bool, do not wait when running unittest
        """
        Toplevel.__init__(self, parent)
        self.withdraw()  # Hide while setting geometry.
        self.configure(borderwidth=5)
        self.resizable(height=False, width=False)
        self.title(title)
        self.transient(parent)
        self.grab_set()
        self.protocol("WM_DELETE_WINDOW", self.cancel)
        self.parent = parent
        self.action = action
        self.current_key_sequences = current_key_sequences
        self.result = ''
        self.key_string = StringVar(self)
        self.key_string.set('')
        # Set self.modifiers, self.modifier_label.
        self.set_modifiers_for_platform()
        self.modifier_vars = []
        for modifier in self.modifiers:
            variable = StringVar(self)
            variable.set('')
            self.modifier_vars.append(variable)
        self.advanced = False
        self.create_widgets()
        self.update_idletasks()
        self.geometry(
                "+%d+%d" % (
                    parent.winfo_rootx() +
                    (parent.winfo_width()/2 - self.winfo_reqwidth()/2),
                    parent.winfo_rooty() +
                    ((parent.winfo_height()/2 - self.winfo_reqheight()/2)
                    if not _htest else 150)
                ) )  # Center dialog over parent (or below htest box).
        if not _utest:
            self.deiconify()  # Geometry set, unhide.
            self.wait_window()

    def showerror(self, *args, **kwargs):
        # Make testing easier.  Replace in #30751.
        messagebox.showerror(*args, **kwargs)

    def create_widgets(self):
        self.frame = frame = Frame(self, borderwidth=2, relief='sunken')
        frame.pack(side='top', expand=True, fill='both')

        frame_buttons = Frame(self)
        frame_buttons.pack(side='bottom', fill='x')

        self.button_ok = Button(frame_buttons, text='OK',
                                width=8, command=self.ok)
        self.button_ok.grid(row=0, column=0, padx=5, pady=5)
        self.button_cancel = Button(frame_buttons, text='Cancel',
                                   width=8, command=self.cancel)
        self.button_cancel.grid(row=0, column=1, padx=5, pady=5)

        # Basic entry key sequence.
        self.frame_keyseq_basic = Frame(frame, name='keyseq_basic')
        self.frame_keyseq_basic.grid(row=0, column=0, sticky='nsew',
                                      padx=5, pady=5)
        basic_title = Label(self.frame_keyseq_basic,
                            text=f"New keys for '{self.action}' :")
        basic_title.pack(anchor='w')

        basic_keys = Label(self.frame_keyseq_basic, justify='left',
                           textvariable=self.key_string, relief='groove',
                           borderwidth=2)
        basic_keys.pack(ipadx=5, ipady=5, fill='x')

        # Basic entry controls.
        self.frame_controls_basic = Frame(frame)
        self.frame_controls_basic.grid(row=1, column=0, sticky='nsew', padx=5)

        # Basic entry modifiers.
        self.modifier_checkbuttons = {}
        column = 0
        for modifier, variable in zip(self.modifiers, self.modifier_vars):
            label = self.modifier_label.get(modifier, modifier)
            check = Checkbutton(self.frame_controls_basic,
                                command=self.build_key_string, text=label,
                                variable=variable, onvalue=modifier, offvalue='')
            check.grid(row=0, column=column, padx=2, sticky='w')
            self.modifier_checkbuttons[modifier] = check
            column += 1

        # Basic entry help text.
        help_basic = Label(self.frame_controls_basic, justify='left',
                           text="Select the desired modifier keys\n"+
                                "above, and the final key from the\n"+
                                "list on the right.\n\n" +
                                "Use upper case Symbols when using\n" +
                                "the Shift modifier.  (Letters will be\n" +
                                "converted automatically.)")
        help_basic.grid(row=1, column=0, columnspan=4, padx=2, sticky='w')

        # Basic entry key list.
        self.list_keys_final = Listbox(self.frame_controls_basic, width=15,
                                       height=10, selectmode='single')
        self.list_keys_final.insert('end', *AVAILABLE_KEYS)
        self.list_keys_final.bind('<ButtonRelease-1>', self.final_key_selected)
        self.list_keys_final.grid(row=0, column=4, rowspan=4, sticky='ns')
        scroll_keys_final = Scrollbar(self.frame_controls_basic,
                                      orient='vertical',
                                      command=self.list_keys_final.yview)
        self.list_keys_final.config(yscrollcommand=scroll_keys_final.set)
        scroll_keys_final.grid(row=0, column=5, rowspan=4, sticky='ns')
        self.button_clear = Button(self.frame_controls_basic,
                                   text='Clear Keys',
                                   command=self.clear_key_seq)
        self.button_clear.grid(row=2, column=0, columnspan=4)

        # Advanced entry key sequence.
        self.frame_keyseq_advanced = Frame(frame, name='keyseq_advanced')
        self.frame_keyseq_advanced.grid(row=0, column=0, sticky='nsew',
                                         padx=5, pady=5)
        advanced_title = Label(self.frame_keyseq_advanced, justify='left',
                               text=f"Enter new binding(s) for '{self.action}' :\n" +
                                     "(These bindings will not be checked for validity!)")
        advanced_title.pack(anchor='w')
        self.advanced_keys = Entry(self.frame_keyseq_advanced,
                                   textvariable=self.key_string)
        self.advanced_keys.pack(fill='x')

        # Advanced entry help text.
        self.frame_help_advanced = Frame(frame)
        self.frame_help_advanced.grid(row=1, column=0, sticky='nsew', padx=5)
        help_advanced = Label(self.frame_help_advanced, justify='left',
            text="Key bindings are specified using Tkinter keysyms as\n"+
                 "in these samples: <Control-f>, <Shift-F2>, <F12>,\n"
                 "<Control-space>, <Meta-less>, <Control-Alt-Shift-X>.\n"
                 "Upper case is used when the Shift modifier is present!\n\n" +
                 "'Emacs style' multi-keystroke bindings are specified as\n" +
                 "follows: <Control-x><Control-y>, where the first key\n" +
                 "is the 'do-nothing' keybinding.\n\n" +
                 "Multiple separate bindings for one action should be\n"+
                 "separated by a space, eg., <Alt-v> <Meta-v>." )
        help_advanced.grid(row=0, column=0, sticky='nsew')

        # Switch between basic and advanced.
        self.button_level = Button(frame, command=self.toggle_level,
                                  text='<< Basic Key Binding Entry')
        self.button_level.grid(row=2, column=0, stick='ew', padx=5, pady=5)
        self.toggle_level()

    def set_modifiers_for_platform(self):
        """Determine list of names of key modifiers for this platform.

        The names are used to build Tk bindings -- it doesn't matter if the
        keyboard has these keys; it matters if Tk understands them.  The
        order is also important: key binding equality depends on it, so
        config-keys.def must use the same ordering.
        """
        if sys.platform == "darwin":
            self.modifiers = ['Shift', 'Control', 'Option', 'Command']
        else:
            self.modifiers = ['Control', 'Alt', 'Shift']
        self.modifier_label = {'Control': 'Ctrl'}  # Short name.

    def toggle_level(self):
        "Toggle between basic and advanced keys."
        if  self.button_level.cget('text').startswith('Advanced'):
            self.clear_key_seq()
            self.button_level.config(text='<< Basic Key Binding Entry')
            self.frame_keyseq_advanced.lift()
            self.frame_help_advanced.lift()
            self.advanced_keys.focus_set()
            self.advanced = True
        else:
            self.clear_key_seq()
            self.button_level.config(text='Advanced Key Binding Entry >>')
            self.frame_keyseq_basic.lift()
            self.frame_controls_basic.lift()
            self.advanced = False

    def final_key_selected(self, event=None):
        "Handler for clicking on key in basic settings list."
        self.build_key_string()

    def build_key_string(self):
        "Create formatted string of modifiers plus the key."
        keylist = modifiers = self.get_modifiers()
        final_key = self.list_keys_final.get('anchor')
        if final_key:
            final_key = translate_key(final_key, modifiers)
            keylist.append(final_key)
        self.key_string.set(f"<{'-'.join(keylist)}>")

    def get_modifiers(self):
        "Return ordered list of modifiers that have been selected."
        mod_list = [variable.get() for variable in self.modifier_vars]
        return [mod for mod in mod_list if mod]

    def clear_key_seq(self):
        "Clear modifiers and keys selection."
        self.list_keys_final.select_clear(0, 'end')
        self.list_keys_final.yview('moveto', '0.0')
        for variable in self.modifier_vars:
            variable.set('')
        self.key_string.set('')

    def ok(self, event=None):
        keys = self.key_string.get().strip()
        if not keys:
            self.showerror(title=self.keyerror_title, parent=self,
                           message="No key specified.")
            return
        if (self.advanced or self.keys_ok(keys)) and self.bind_ok(keys):
            self.result = keys
        self.grab_release()
        self.destroy()

    def cancel(self, event=None):
        self.result = ''
        self.grab_release()
        self.destroy()

    def keys_ok(self, keys):
        """Validity check on user's 'basic' keybinding selection.

        Doesn't check the string produced by the advanced dialog because
        'modifiers' isn't set.
        """
        final_key = self.list_keys_final.get('anchor')
        modifiers = self.get_modifiers()
        title = self.keyerror_title
        key_sequences = [key for keylist in self.current_key_sequences
                             for key in keylist]
        if not keys.endswith('>'):
            self.showerror(title, parent=self,
                           message='Missing the final Key')
        elif (not modifiers
              and final_key not in FUNCTION_KEYS + MOVE_KEYS):
            self.showerror(title=title, parent=self,
                           message='No modifier key(s) specified.')
        elif (modifiers == ['Shift']) \
                 and (final_key not in
                      FUNCTION_KEYS + MOVE_KEYS + ('Tab', 'Space')):
            msg = 'The shift modifier by itself may not be used with'\
                  ' this key symbol.'
            self.showerror(title=title, parent=self, message=msg)
        elif keys in key_sequences:
            msg = 'This key combination is already in use.'
            self.showerror(title=title, parent=self, message=msg)
        else:
            return True
        return False

    def bind_ok(self, keys):
        "Return True if Tcl accepts the new keys else show message."
        try:
            binding = self.bind(keys, lambda: None)
        except TclError as err:
            self.showerror(
                    title=self.keyerror_title, parent=self,
                    message=(f'The entered key sequence is not accepted.\n\n'
                             f'Error: {err}'))
            return False
        else:
            self.unbind(keys, binding)
            return True
示例#7
0
class Application(Frame):
    """The main Tk application, a simple dialog."""
    def __init__(self, master=None):
        super().__init__(master)
        self.badge = None
        self.grid()
        self.columnconfigure(0, minsize=200)
        self.columnconfigure(1, minsize=200)
        self.rowconfigure(0, minsize=300)
        self.rowconfigure(3, minsize=30)
        self.create_widgets()
        self.connect()

    def create_widgets(self):
        """Sets up dialog elements."""
        self.select = tix.FileSelectBox(self,
                                        browsecmd=self.on_file_selected,
                                        pattern="*.fs",
                                        directory="forth")
        # self.select["textVariable"] = self.forth_file
        self.select.grid(row=0, columnspan=2, sticky='n' + 'w' + 'e')
        self.connect_btn = Button(self,
                                  text="Connect",
                                  command=self.toggle_connect)
        self.connect_btn.grid(row=1, column=0, columnspan=2)
        self.exec_btn = Button(self, text="Execute", command=self.send_file)
        self.exec_btn.state(["disabled"])
        self.exec_btn.grid(row=2, column=0, sticky='w' + 'e', padx=5, pady=3)
        self.quit = Button(self, text="QUIT", command=self.master.destroy)
        self.quit.grid(row=2, column=1, sticky='w' + 'e', padx=5, pady=3)
        self.status_panel = Frame(self, relief="groove", borderwidth=3)
        self.status_panel.grid(row=3, columnspan=2, sticky='nwse')
        self.connect_status = Label(self.status_panel, text="Not Connected")
        self.connect_status.grid(row=0, padx=5, pady=5, sticky="w")
        if self.badge is not None:
            self.connect_btn.state(["disabled"])
            self.connect_status.config(text="Connected: " +
                                       self.badge.os_device)

    def send_file(self, _retry=False):
        """Send the selected file to the badge."""
        if self.badge:
            try:
                # oddly, very first set LED seems to not set correct color
                self.badge.led(0, 0, 128)
                self.badge.led(0, 0, 128)
                with open(self.select.cget("value"), 'r') as forthin:
                    self.badge.forth_run(forthin.read())
                time.sleep(1)  # because forth_run() may be too fast
                self.badge.led(0, 128, 0)
            except IOError:
                if not _retry:
                    self.connect()
                    self.send_file(True)
                else:
                    raise

    def toggle_connect(self):
        "If connected, disconnect, otherwise connect."
        if self.connect_btn.cget("text") == "Connect":
            self.connect()
        else:
            self.disconnect()

    def disconnect(self):
        "Disconnect from current badge."
        isinstance(self.badge, Badge)
        self.badge.close()
        self.badge = None
        self.connect_btn.config(text="Connect")
        self.connect_status.config(text="Not connected.")
        self.exec_btn.state(["disabled"])

    def connect(self):
        """Attempt to connect to a badge; toggle Connect button if successful."""
        try:
            self.badge = Badge()
            self.connect_status.config(text="Connected: " +
                                       self.badge.os_device)
            self.connect_btn.config(text="Disconnect")
            # enable "Execute" if file is selected
            self.on_file_selected(self.select.cget("value"))
        except BadgeSerialException:
            self.connect_status.config(text="Not connected")

    def on_file_selected(self, selected_file):
        """Respond to user selection of file by enabling the Execute button."""
        if Path(selected_file).is_file:
            self.exec_btn.state(["!disabled"])
        else:
            self.exec_btn.state(["disabled"])
示例#8
0
class SetupWindow(Tk):
    """
    Little GUI for setting user's name, the partner's ip and that
    the PC is a server or not.
    """
    def __init__(self, *args, **kwargs):
        Tk.__init__(self, *args, **kwargs)

        try:  # Set icon
            self.iconbitmap('icon.ico')
        except Exception:
            pass

        self.wm_title('TinyChat')
        self.resizable(False, False)
        try:
            self.eval('tk::PlaceWindow %s center' %
                      self.winfo_pathname(self.winfo_id()))
        except TclError:
            pass

        self.name = 'anonymous'
        self.other_ip = socket.gethostbyname(socket.gethostname())
        self.is_server = True

        # Read last config from file
        if os.path.isfile('config.json'):
            with open('config.json', 'r') as file:
                config = json.load(file)
                self.name = config['name']
                self.other_ip = config['other_ip']
                self.is_server = config['is_server']

        self.name_label = Label(self, text='Name')
        self.other_ip_label = Label(self, text='IP')
        self.server_label = Label(self, text='Server')

        self.name_entry = Entry(self,
                                textvariable=StringVar(),
                                bd=1,
                                width=30,
                                bg='white',
                                fg='black')
        self.other_ip_entry = Entry(self,
                                    textvariable=StringVar(),
                                    bd=1,
                                    width=30,
                                    bg='white',
                                    fg='black')
        self.server_button = Button(self,
                                    text='Yes' if self.is_server else 'No',
                                    width=22,
                                    command=lambda: self.set_is_server())
        self.apply_button = Button(self,
                                   text='Start',
                                   width=7,
                                   command=self.apply)

        self.name_entry.config(textvariable=StringVar(self, self.name))
        self.other_ip_entry.config(textvariable=StringVar(self, self.other_ip))
        self.other_ip_entry.config(
            state='disabled' if self.is_server else 'normal')

        self.name_label.grid(padx=1, pady=2, row=0, column=0)
        self.name_entry.grid(padx=1, pady=2, row=0, column=1)
        self.other_ip_label.grid(padx=1, pady=2, row=1, column=0)
        self.other_ip_entry.grid(padx=1, pady=2, row=1, column=1)
        self.server_label.grid(padx=1, pady=2, row=2, column=0)
        self.server_button.grid(padx=1, pady=2, row=2, column=1)
        self.apply_button.grid(padx=1, pady=5, row=3, column=1)

        self.mainloop()

    def set_is_server(self):
        self.is_server = not self.is_server
        self.server_button.config(text='Yes' if self.is_server else 'No')
        self.other_ip_entry.config(
            state='disabled' if self.is_server else 'normal')

    def apply(self):
        global MY_NAME, OTHER_IP, IS_SERVER

        if self.name_entry.get() and self.other_ip_entry.get():
            MY_NAME = self.name_entry.get()
            OTHER_IP = self.other_ip_entry.get()
            IS_SERVER = self.server_button.cget('text') == 'Yes'

            config = {
                'name': MY_NAME,
                'other_ip': OTHER_IP,
                'is_server': IS_SERVER
            }
            with open('config.json', 'w+') as file:
                json.dump(config, file)

            self.destroy()