Example #1
0
    def __init__(self, *args: Any, **kwargs: Any) -> None:
        super().__init__(*args, **kwargs)

        # These can be bound in a parent widget. This doesn't use
        # enable_traversal() because we want more bindings than it
        # creates. Undocumented because plugins shouldn't need this.
        self.bindings: List[Tuple[str,
                                  Callable[['tkinter.Event[tkinter.Misc]'],
                                           utils.BreakOrNone]]] = [
                                               ('<Control-Prior>',
                                                functools.partial(
                                                    self._on_page_updown,
                                                    False, -1)),
                                               ('<Control-Next>',
                                                functools.partial(
                                                    self._on_page_updown,
                                                    False, +1)),
                                               ('<Control-Shift-Prior>',
                                                functools.partial(
                                                    self._on_page_updown, True,
                                                    -1)),
                                               ('<Control-Shift-Next>',
                                                functools.partial(
                                                    self._on_page_updown, True,
                                                    +1)),
                                           ]
        for number in range(1, 10):
            callback = functools.partial(self._on_alt_n, number)
            self.bindings.append(('<Alt-Key-%d>' % number, callback))

        self.bind('<<NotebookTabChanged>>', self._focus_selected_tab, add=True)
        self.bind('<Button-1>', self._on_click, add=True)
        utils.bind_mouse_wheel(self, self._on_wheel, add=True)
Example #2
0
    def __init__(self, parent, filetype, **kwargs):
        super().__init__(parent, **kwargs)
        self.set_filetype(filetype)

        # FIXME: lots of things have been turned into plugins, but
        # there's still wayyyy too much stuff in here...
        partial = functools.partial  # pep8 line length
        self.bind('<BackSpace>', partial(self._on_delete, False))
        self.bind('<Control-BackSpace>', partial(self._on_delete, True))
        self.bind('<Control-Delete>', partial(self._on_delete, True))
        self.bind('<Shift-Control-Delete>',
                  partial(self._on_delete, True, shifted=True))
        self.bind('<Shift-Control-BackSpace>',
                  partial(self._on_delete, True, shifted=True))
        self.bind('<Return>', (lambda event: self.cursor_has_moved()))
        self.bind('<parenright>', self._on_closing_brace, add=True)
        self.bind('<bracketright>', self._on_closing_brace, add=True)
        self.bind('<braceright>', self._on_closing_brace, add=True)
        self.bind('<Control-z>', self.undo)
        self.bind('<Control-y>', self.redo)
        self.bind('<Control-x>', self.cut)
        self.bind('<Control-c>', self.copy)
        self.bind('<Control-v>', self.paste)
        self.bind('<Control-a>', self.select_all)

        self.bind('<Control-plus>', lambda event: self.on_wheel('up'))
        self.bind('<Control-minus>', lambda event: self.on_wheel('down'))
        self.bind('<Control-0>', lambda event: self.on_wheel('reset'))
        utils.bind_mouse_wheel(self, self.on_wheel, prefixes='Control-')
Example #3
0
    def __init__(self, parent, filetype, **kwargs):
        super().__init__(parent, **kwargs)
        self.set_filetype(filetype)

        # FIXME: lots of things have been turned into plugins, but
        # there's still wayyyy too much stuff in here...
        partial = functools.partial  # pep8 line length
        self.bind('<BackSpace>', partial(self._on_delete, False))
        self.bind('<Control-BackSpace>', partial(self._on_delete, True))
        self.bind('<Control-Delete>', partial(self._on_delete, True))
        self.bind('<Shift-Control-Delete>',
                  partial(self._on_delete, True, shifted=True))
        self.bind('<Shift-Control-BackSpace>',
                  partial(self._on_delete, True, shifted=True))
        self.bind('<Return>', (lambda event: self.cursor_has_moved()))
        self.bind('<parenright>', self._on_closing_brace, add=True)
        self.bind('<bracketright>', self._on_closing_brace, add=True)
        self.bind('<braceright>', self._on_closing_brace, add=True)

        # most other things work by default, but these don't
        self.bind('<Control-v>', self._paste)
        self.bind('<Control-y>', self._redo)
        self.bind('<Control-a>', self._select_all)

        utils.bind_mouse_wheel(self, self._on_ctrl_wheel, prefixes='Control-')
Example #4
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # These can be bound in a parent widget. This doesn't use
        # enable_traversal() because we want more bindings than it
        # creates.
        # TODO: document these?
        partial = functools.partial  # pep-8 line length
        self.bindings = [
            ('<Control-Prior>', partial(self._on_page_updown, False, -1)),
            ('<Control-Next>', partial(self._on_page_updown, False, +1)),
            ('<Control-Shift-Prior>', partial(self._on_page_updown, True, -1)),
            ('<Control-Shift-Next>', partial(self._on_page_updown, True, +1)),
        ]
        for number in range(1, 10):
            callback = functools.partial(self._on_alt_n, number)
            self.bindings.append(('<Alt-Key-%d>' % number, callback))

        self.bind('<<NotebookTabChanged>>', self._focus_selected_tab, add=True)
        self.bind('<Button-1>', self._on_click, add=True)
        utils.bind_mouse_wheel(self, self._on_wheel, add=True)
Example #5
0
def _fill_menus_with_default_stuff() -> None:
    # Make sure to get the order of menus right:
    #   File, Edit, <everything else>, Help
    get_menu("Help")  # handled specially in get_menu
    get_menu("File")
    get_menu("Edit")

    def new_file() -> None:
        get_tab_manager().add_tab(tabs.FileTab(get_tab_manager()))

    def open_files() -> None:
        paths: Sequence[str] = filedialog.askopenfilenames(
            **filedialog_kwargs)  # type: ignore

        # tkinter returns '' if the user cancels, and i'm arfaid that python
        # devs might "fix" a future version to return None
        if not paths:
            return

        for path in map(pathlib.Path, paths):
            try:
                tab = tabs.FileTab.open_file(get_tab_manager(), path)
            except (UnicodeError, OSError) as e:
                log.exception("opening '%s' failed", path)
                utils.errordialog(
                    type(e).__name__, "Opening failed!",
                    traceback.format_exc())
                continue

            get_tab_manager().add_tab(tab)

    def save_file(save_as: bool) -> None:
        tab = get_tab_manager().select()
        assert isinstance(tab, tabs.FileTab)
        if save_as:
            tab.save_as()
        else:
            tab.save()

    def close_selected_tab() -> None:
        tab = get_tab_manager().select()
        assert tab is not None
        if tab.can_be_closed():
            get_tab_manager().close_tab(tab)

    get_menu("File").add_command(label="New File", command=new_file)
    get_menu("File").add_command(label="Open", command=open_files)
    get_menu("File").add_command(label="Save",
                                 command=functools.partial(save_file, False))
    get_menu("File").add_command(label="Save As",
                                 command=functools.partial(save_file, True))
    get_menu("File").add_separator()
    get_menu("File").add_command(label="Close", command=close_selected_tab)
    get_menu("File").add_command(label="Quit", command=quit)

    set_enabled_based_on_tab("File/Save",
                             (lambda tab: isinstance(tab, tabs.FileTab)))
    set_enabled_based_on_tab("File/Save As",
                             (lambda tab: isinstance(tab, tabs.FileTab)))
    set_enabled_based_on_tab("File/Close", (lambda tab: tab is not None))
    set_enabled_based_on_tab("File/Quit", (lambda tab: tab is None))

    def change_font_size(how: Literal['bigger', 'smaller', 'reset']) -> None:
        if how == 'reset':
            settings.reset('font_size')
            return

        size = settings.get('font_size', int)
        if how == 'bigger':
            size += 1
        else:
            size -= 1
            if size < 3:
                return

        settings.set('font_size', size)

    # trigger change_font_size() with mouse wheel from any text widget
    utils.bind_mouse_wheel(
        'Text',
        (lambda updn: change_font_size('bigger'
                                       if updn == 'up' else 'smaller')),
        prefixes='Control-',
        add=True)

    get_menu("View").add_command(label="Bigger Font",
                                 command=functools.partial(
                                     change_font_size, 'bigger'))
    get_menu("View").add_command(label="Smaller Font",
                                 command=functools.partial(
                                     change_font_size, 'smaller'))
    get_menu("View").add_command(label="Reset Font Size",
                                 command=functools.partial(
                                     change_font_size, 'reset'))
    set_enabled_based_on_tab("View/Bigger Font", (lambda tab: tab is not None))
    set_enabled_based_on_tab("View/Smaller Font",
                             (lambda tab: tab is not None))
    set_enabled_based_on_tab("View/Reset Font Size",
                             (lambda tab: tab is not None))

    get_menu("Settings").add_command(label="Porcupine Settings",
                                     command=settings.show_dialog)

    def add_link(menu_path: str, label: str, url: str) -> None:
        def callback() -> None:  # lambda doesn't work for this...
            webbrowser.open(url)  # ...because this returns non-None and mypy

        get_menu(menu_path).add_command(label=label, command=callback)

    # TODO: porcupine starring button
    add_link("Help", "Porcupine Wiki",
             "https://github.com/Akuli/porcupine/wiki")
    add_link("Help", "Report a problem or request a feature",
             "https://github.com/Akuli/porcupine/issues/new")
    add_link("Help/Python", "Free help chat",
             "http://webchat.freenode.net/?channels=%23%23learnpython")
    add_link("Help/Python", "My Python tutorial",
             "https://github.com/Akuli/python-tutorial/blob/master/README.md")
    add_link("Help/Python", "Official documentation",
             "https://docs.python.org/")
Example #6
0
 def __init__(self, manager):
     super().__init__(manager)
     self.bind('<Button-1>', self._on_click, add=True)
     utils.bind_mouse_wheel(self, self._on_wheel, add=True)