示例#1
0
文件: tk_ui.py 项目: imclab/Eelbrain
def ask_file(title, message, filetypes, directory, mult):
    dlg = Open(title=title, filetypes=filetypes, initialdir=directory,
               multiple=mult)
    out = dlg.show()
    return out
示例#2
0
def ask_file(title, message, filetypes, directory, mult):
    dlg = Open(title=title, filetypes=filetypes, initialdir=directory,
               multiple=mult)
    out = dlg.show()
    return out
示例#3
0
class TextEditor:  # mix with menu/toolbar Frame class
    startfiledir = '.'
    ftypes = [
        ('All files', '*'),  # for file open dialog
        ('Text files', '.txt'),  # customize in subclass
        ('Python files', '.py')
    ]  # or set in each instance

    colors = [
        {
            'fg': 'black',
            'bg': 'white'
        },  # color pick list
        {
            'fg': 'yellow',
            'bg': 'black'
        },  # first item is default
        {
            'fg': 'white',
            'bg': 'blue'
        },  # tailor me as desired
        {
            'fg': 'black',
            'bg': 'beige'
        },  # or do PickBg/Fg chooser
        {
            'fg': 'yellow',
            'bg': 'purple'
        },
        {
            'fg': 'black',
            'bg': 'brown'
        },
        {
            'fg': 'lightgreen',
            'bg': 'darkgreen'
        },
        {
            'fg': 'darkblue',
            'bg': 'orange'
        },
        {
            'fg': 'orange',
            'bg': 'darkblue'
        }
    ]

    fonts = [
        ('courier', 9 + FontScale, 'normal'),  # platform-neutral fonts
        ('courier', 12 + FontScale, 'normal'),  # (family, size, style)
        ('courier', 10 + FontScale, 'bold'),  # or popup a listbox
        ('courier', 10 + FontScale, 'italic'),  # make bigger on linux
        ('times', 10 + FontScale, 'normal'),  # use 'bold italic' for 2
        ('helvetica', 10 + FontScale, 'normal'),  # also 'underline', etc.
        ('ariel', 10 + FontScale, 'normal'),
        ('system', 10 + FontScale, 'normal'),
        ('courier', 20 + FontScale, 'normal')
    ]

    def __init__(self, loadFirst=''):
        if not isinstance(self, GuiMaker):
            raise TypeError, 'TextEditor needs a GuiMaker mixin'
        self.setFileName(None)
        self.lastfind = None
        self.openDialog = None
        self.saveDialog = None
        self.text.focus()  # else must click in text
        if loadFirst:
            self.onOpen(loadFirst)

    def start(self):  # run by GuiMaker.__init__
        self.menuBar = [  # configure menu/toolbar
            (
                'File',
                0,  # a GuiMaker menu def tree
                [
                    ('Open...', 0, self.onOpen),  # build in method for self
                    ('Save', 0, self.onSave),  # label, shortcut, callback
                    ('Save As...', 5, self.onSaveAs),
                    ('New', 0, self.onNew),
                    'separator',
                    ('Quit...', 0, self.onQuit)
                ]),
            ('Edit', 0, [('Undo', 0, self.onUndo),
                         ('Redo', 0, self.onRedo), 'separator',
                         ('Cut', 0, self.onCut), ('Copy', 1, self.onCopy),
                         ('Paste', 0, self.onPaste), 'separator',
                         ('Delete', 0, self.onDelete),
                         ('Select All', 0, self.onSelectAll)]),
            ('Search', 0, [('Goto...', 0, self.onGoto),
                           ('Find...', 0, self.onFind),
                           ('Refind', 0, self.onRefind),
                           ('Change...', 0, self.onChange)]),
            ('Tools', 0, [('Pick Font...', 6, self.onPickFont),
                          ('Font List', 0, self.onFontList), 'separator',
                          ('Pick Bg...', 3, self.onPickBg),
                          ('Pick Fg...', 0, self.onPickFg),
                          ('Color List', 0, self.onColorList), 'separator',
                          ('Info...', 0, self.onInfo),
                          ('Clone', 1, self.onClone),
                          ('Run Code', 0, self.onRunCode)])
        ]
        self.toolBar = [('Save', self.onSave, {
            'side': LEFT
        }), ('Cut', self.onCut, {
            'side': LEFT
        }), ('Copy', self.onCopy, {
            'side': LEFT
        }), ('Paste', self.onPaste, {
            'side': LEFT
        }), ('Find', self.onRefind, {
            'side': LEFT
        }), ('Help', self.help, {
            'side': RIGHT
        }), ('Quit', self.onQuit, {
            'side': RIGHT
        })]

    def makeWidgets(self):  # run by GuiMaker.__init__
        name = Label(self, bg='black',
                     fg='white')  # add below menu, above tool
        name.pack(side=TOP, fill=X)  # menu/toolbars are packed

        vbar = Scrollbar(self)
        hbar = Scrollbar(self, orient='horizontal')
        text = Text(self, padx=5, wrap='none')
        text.config(undo=1, autoseparators=1)  # 2.0, default is 0, 1

        vbar.pack(side=RIGHT, fill=Y)
        hbar.pack(side=BOTTOM, fill=X)  # pack text last
        text.pack(side=TOP, fill=BOTH, expand=YES)  # else sbars clipped

        text.config(yscrollcommand=vbar.set)  # call vbar.set on text move
        text.config(xscrollcommand=hbar.set)
        vbar.config(command=text.yview)  # call text.yview on scroll move
        hbar.config(command=text.xview)  # or hbar['command']=text.xview

        # 2.0: apply user configs or defaults
        startfont = configs.get('font', self.fonts[0])
        startbg = configs.get('bg', self.colors[0]['bg'])
        startfg = configs.get('fg', self.colors[0]['fg'])
        text.config(font=startfont, bg=startbg, fg=startfg)
        if 'height' in configs: text.config(height=configs['height'])
        if 'width' in configs: text.config(width=configs['width'])
        self.text = text
        self.filelabel = name

    ############################################################################
    # File menu commands
    ############################################################################

    def my_askopenfilename(self):  # objects remember last result dir/file
        if not self.openDialog:
            self.openDialog = Open(initialdir=self.startfiledir,
                                   filetypes=self.ftypes)
        return self.openDialog.show()

    def my_asksaveasfilename(self):  # objects remember last result dir/file
        if not self.saveDialog:
            self.saveDialog = SaveAs(initialdir=self.startfiledir,
                                     filetypes=self.ftypes)
        return self.saveDialog.show()

    def onOpen(self, loadFirst=''):
        doit = (
            not self.text_edit_modified() or  # 2.0
            askyesno('PyEdit', 'Text has changed: discard changes?'))
        if doit:
            file = loadFirst or self.my_askopenfilename()
            if file:
                try:
                    text = open(file, 'r').read()
                except:
                    showerror('PyEdit', 'Could not open file ' + file)
                else:
                    self.setAllText(text)
                    self.setFileName(file)
                    self.text.edit_reset()  # 2.0: clear undo/redo stks
                    self.text.edit_modified(0)  # 2.0: clear modified flag

    def onSave(self):
        self.onSaveAs(self.currfile)  # may be None

    def onSaveAs(self, forcefile=None):
        file = forcefile or self.my_asksaveasfilename()
        if file:
            text = self.getAllText()
            try:
                open(file, 'w').write(text)
            except:
                showerror('PyEdit', 'Could not write file ' + file)
            else:
                self.setFileName(file)  # may be newly created
                self.text.edit_modified(0)  # 2.0: clear modified flag
                # don't clear undo/redo stks
    def onNew(self):
        doit = (
            not self.text_edit_modified() or  # 2.0
            askyesno('PyEdit', 'Text has changed: discard changes?'))
        if doit:
            self.setFileName(None)
            self.clearAllText()
            self.text.edit_reset()  # 2.0: clear undo/redo stks
            self.text.edit_modified(0)  # 2.0: clear modified flag

    def onQuit(self):
        doit = (
            not self.text_edit_modified()  # 2.0
            or askyesno('PyEdit',
                        'Text has changed: quit and discard changes?'))
        if doit:
            self.quit()  # Frame.quit via GuiMaker

    def text_edit_modified(self):
        """
        2.0: self.text.edit_modified() broken in Python 2.4:
        do manually for now (seems to be bool result type bug)
        """
        return self.tk.call((self.text._w, 'edit') + ('modified', None))

    ############################################################################
    # Edit menu commands
    ############################################################################

    def onUndo(self):  # 2.0
        try:  # tk8.4 keeps undo/redo stacks
            self.text.edit_undo()  # exception if stacks empty
        except TclError:  # menu tear-offs for quick undo
            showinfo('PyEdit', 'Nothing to undo')

    def onRedo(self):  # 2.0: redo an undone
        try:
            self.text.edit_redo()
        except TclError:
            showinfo('PyEdit', 'Nothing to redo')

    def onCopy(self):  # get text selected by mouse,etc
        if not self.text.tag_ranges(SEL):  # save in cross-app clipboard
            showerror('PyEdit', 'No text selected')
        else:
            text = self.text.get(SEL_FIRST, SEL_LAST)
            self.clipboard_clear()
            self.clipboard_append(text)

    def onDelete(self):  # delete selected text, no save
        if not self.text.tag_ranges(SEL):
            showerror('PyEdit', 'No text selected')
        else:
            self.text.delete(SEL_FIRST, SEL_LAST)

    def onCut(self):
        if not self.text.tag_ranges(SEL):
            showerror('PyEdit', 'No text selected')
        else:
            self.onCopy()  # save and delete selected text
            self.onDelete()

    def onPaste(self):
        try:
            text = self.selection_get(selection='CLIPBOARD')
        except TclError:
            showerror('PyEdit', 'Nothing to paste')
            return
        self.text.insert(INSERT, text)  # add at current insert cursor
        self.text.tag_remove(SEL, '1.0', END)
        self.text.tag_add(SEL, INSERT + '-%dc' % len(text), INSERT)
        self.text.see(INSERT)  # select it, so it can be cut

    def onSelectAll(self):
        self.text.tag_add(SEL, '1.0', END + '-1c')  # select entire text
        self.text.mark_set(INSERT, '1.0')  # move insert point to top
        self.text.see(INSERT)  # scroll to top

    ############################################################################
    # Search menu commands
    ############################################################################

    def onGoto(self, forceline=None):
        line = forceline or askinteger('PyEdit', 'Enter line number')
        self.text.update()
        self.text.focus()
        if line is not None:
            maxindex = self.text.index(END + '-1c')
            maxline = int(maxindex.split('.')[0])
            if line > 0 and line <= maxline:
                self.text.mark_set(INSERT, '%d.0' % line)  # goto line
                self.text.tag_remove(SEL, '1.0', END)  # delete selects
                self.text.tag_add(SEL, INSERT, 'insert + 1l')  # select line
                self.text.see(INSERT)  # scroll to line
            else:
                showerror('PyEdit', 'Bad line number')

    def onFind(self, lastkey=None):
        key = lastkey or askstring('PyEdit', 'Enter search string')
        self.text.update()
        self.text.focus()
        self.lastfind = key
        if key:  # 2.0: nocase
            nocase = configs.get('caseinsens', 1)  # 2.0: config
            where = self.text.search(key, INSERT, END, nocase=nocase)
            if not where:  # don't wrap
                showerror('PyEdit', 'String not found')
            else:
                pastkey = where + '+%dc' % len(key)  # index past key
                self.text.tag_remove(SEL, '1.0', END)  # remove any sel
                self.text.tag_add(SEL, where, pastkey)  # select key
                self.text.mark_set(INSERT, pastkey)  # for next find
                self.text.see(where)  # scroll display

    def onRefind(self):
        self.onFind(self.lastfind)

    def onChange(self):
        new = Toplevel(self)
        Label(new, text='Find text:').grid(row=0, column=0)
        Label(new, text='Change to:').grid(row=1, column=0)
        self.change1 = Entry(new)
        self.change2 = Entry(new)
        self.change1.grid(row=0, column=1, sticky=EW)
        self.change2.grid(row=1, column=1, sticky=EW)
        Button(new, text='Find', command=self.onDoFind).grid(row=0,
                                                             column=2,
                                                             sticky=EW)
        Button(new, text='Apply', command=self.onDoChange).grid(row=1,
                                                                column=2,
                                                                sticky=EW)
        new.columnconfigure(1, weight=1)  # expandable entrys

    def onDoFind(self):
        self.onFind(self.change1.get())  # Find in change box

    def onDoChange(self):
        if self.text.tag_ranges(SEL):  # must find first
            self.text.delete(SEL_FIRST, SEL_LAST)  # Apply in change
            self.text.insert(INSERT, self.change2.get())  # deletes if empty
            self.text.see(INSERT)
            self.onFind(self.change1.get())  # goto next appear
            self.text.update()  # force refresh

    ############################################################################
    # Tools menu commands
    ############################################################################

    def onFontList(self):
        self.fonts.append(self.fonts[0])  # pick next font in list
        del self.fonts[0]  # resizes the text area
        self.text.config(font=self.fonts[0])

    def onColorList(self):
        self.colors.append(self.colors[0])  # pick next color in list
        del self.colors[0]  # move current to end
        self.text.config(fg=self.colors[0]['fg'], bg=self.colors[0]['bg'])

    def onPickFg(self):
        self.pickColor('fg')  # added on 10/02/00

    def onPickBg(self):  # select arbitrary color
        self.pickColor('bg')  # in standard color dialog

    def pickColor(self, part):  # this is too easy
        (triple, hexstr) = askcolor()
        if hexstr:
            self.text.config(**{part: hexstr})

    def onInfo(self):
        text = self.getAllText()  # added on 5/3/00 in 15 mins
        bytes = len(text)  # words uses a simple guess:
        lines = len(text.split('\n'))  # any separated by whitespace
        words = len(text.split())
        index = self.text.index(INSERT)
        where = tuple(index.split('.'))
        showinfo(
            'PyEdit Information',
            'Current location:\n\n' + 'line:\t%s\ncolumn:\t%s\n\n' % where +
            'File text statistics:\n\n' +
            'bytes:\t%d\nlines:\t%d\nwords:\t%d\n' % (bytes, lines, words))

    def onClone(self):
        new = Toplevel()  # a new edit window in same process
        myclass = self.__class__  # instance's (lowest) class object
        myclass(new)  # attach/run instance of my class

    def onRunCode(self, parallelmode=True):
        """
        run Python code being edited--not an ide, but handy;
        tries to run in file's dir, not cwd (may be PP3E root);
        inputs and adds command-line arguments for script files;
        code's stdin/out/err = editor's start window, if any:
        run with a console window to see code's print outputs;
        but parallelmode uses start to open a dos box for i/o;
        module search path will include '.' dir where started;
        in non-file mode, code's Tk root window is PyEdit win;
        """
        def askcmdargs():
            return askstring('PyEdit', 'Commandline arguments?') or ''

        from PP3E.launchmodes import System, Start, Fork
        filemode = False
        thefile = str(self.getFileName())
        if os.path.exists(thefile):
            filemode = askyesno('PyEdit', 'Run from file?')
        if not filemode:  # run text string
            cmdargs = askcmdargs()
            namespace = {'__name__': '__main__'}  # run as top-level
            sys.argv = [thefile] + cmdargs.split()  # could use threads
            exec self.getAllText() + '\n' in namespace  # exceptions ignored
        elif self.text_edit_modified():  # 2.0: changed test
            showerror('PyEdit', 'Text changed: save before run')
        else:
            cmdargs = askcmdargs()
            mycwd = os.getcwd()  # cwd may be root
            os.chdir(os.path.dirname(thefile) or mycwd)  # cd for filenames
            thecmd = thefile + ' ' + cmdargs
            if not parallelmode:  # run as file
                System(thecmd, thecmd)()  # block editor
            else:
                if sys.platform[:3] == 'win':  # spawn in parallel
                    Start(thecmd, thecmd)()  # or use os.spawnv
                else:
                    Fork(thecmd, thecmd)()  # spawn in parallel
            os.chdir(mycwd)

    def onPickFont(self):
        # 2.0 font spec dialog
        new = Toplevel(self)
        Label(new, text='Family:').grid(row=0, column=0)  # nonmodal dialog
        Label(new, text='Size:  ').grid(row=1, column=0)  # see pick list
        Label(new, text='Style: ').grid(row=2, column=0)  # for valid inputs
        self.font1 = Entry(new)
        self.font2 = Entry(new)
        self.font3 = Entry(new)
        self.font1.insert(0, 'courier')  # suggested vals
        self.font2.insert(0, '12')
        self.font3.insert(0, 'bold italic')
        self.font1.grid(row=0, column=1, sticky=EW)
        self.font2.grid(row=1, column=1, sticky=EW)
        self.font3.grid(row=2, column=1, sticky=EW)
        Button(new, text='Apply', command=self.onDoFont).grid(row=3,
                                                              columnspan=2)
        new.columnconfigure(1, weight=1)  # expandable entrys

    def onDoFont(self):
        try:
            font = (self.font1.get(), int(self.font2.get()), self.font3.get())
            self.text.config(font=font)
        except:
            showerror('PyEdit', 'Bad font specification')

    ############################################################################
    # Utilities, useful outside this class
    ############################################################################

    def isEmpty(self):
        return not self.getAllText()

    def getAllText(self):
        return self.text.get('1.0', END + '-1c')  # extract text as a string

    def setAllText(self, text):
        self.text.delete('1.0', END)  # store text string in widget
        self.text.insert(END, text)  # or '1.0'
        self.text.mark_set(INSERT, '1.0')  # move insert point to top
        self.text.see(INSERT)  # scroll to top, insert set

    def clearAllText(self):
        self.text.delete('1.0', END)  # clear text in widget

    def getFileName(self):
        return self.currfile

    def setFileName(self, name):  # also: onGoto(linenum)
        self.currfile = name  # for save
        self.filelabel.config(text=str(name))

    def setBg(self, color):
        self.text.config(bg=color)  # to set manually from code

    def setFg(self, color):
        self.text.config(fg=color)  # 'black', hexstring

    def setFont(self, font):
        self.text.config(font=font)  # ('family', size, 'style')

    def setHeight(self, lines):  # default = 24h x 80w
        self.text.config(height=lines)  # may also be from textCongif.py

    def setWidth(self, chars):
        self.text.config(width=chars)

    def clearModified(self):
        self.text.edit_modified(0)  # clear modified flag

    def isModified(self):
        return self.text_edit_modified()  # changed since last reset?

    def help(self):
        showinfo('About PyEdit', helptext % ((Version, ) * 2))
示例#4
0
文件: main.py 项目: TvrtkoM/imgs2pdf
 def add_image_file(self):
     open_dialog = Open(self, initialdir="~")
     fp = open_dialog.show()
     if fp:
         self._item_num += 1
         self.view.insert("", END, values=("{0}".format(self._item_num), fp))