class GroupNameLabel(Label):
    """Label with group name"""
    def __init__(self, parent, group, **kw):
        self._group = group
        kw['text'] = str(group)
        #        kw.setdefault('anchor', 'w')
        kw.setdefault('font', tkFont.Font(size=20))
        Label.__init__(self, parent, **kw)
        self._init_menu()

    def _init_menu(self):
        self._menu = Menu(self, tearoff=0)
        self._menu.add_command(label="Copy LaTeX", command=self._copy_latex)

        # right button on Mac and other systems
        button = '2' if tools.IS_MAC else '3'
        self.bind("<Button-{}>".format(button), self._right_click)

    def _right_click(self, event):
        self._menu.post(event.x_root, event.y_root)

    def _copy_latex(self):
        pyperclip.setcb(self._group.str_latex())

    @property
    def group(self):
        return self._group

    @group.setter
    def group(self, group):
        self._group = group
        self['text'] = str(group)
Esempio n. 2
0
class GroupNameLabel(Label):
    """Label with group name"""

    def __init__(self, parent, group, **kw):
        self._group = group
        kw['text'] = str(group)
        #        kw.setdefault('anchor', 'w')
        kw.setdefault('font', tkFont.Font(size=20))
        Label.__init__(self, parent, **kw)
        self._init_menu()

    def _init_menu(self):
        self._menu = Menu(self, tearoff=0)
        self._menu.add_command(label="Copy LaTeX", command=self._copy_latex)

        # right button on Mac and other systems
        button = '2' if tools.IS_MAC else '3'
        self.bind("<Button-{}>".format(button), self._right_click)

    def _right_click(self, event):
        self._menu.post(event.x_root, event.y_root)

    def _copy_latex(self):
        pyperclip.setcb(self._group.str_latex())

    @property
    def group(self):
        return self._group

    @group.setter
    def group(self, group):
        self._group = group
        self['text'] = str(group)
Esempio n. 3
0
class Example(Frame):
  
    def __init__(self, parent):
        Frame.__init__(self, parent)   
         
        self.parent = parent
        
        self.initUI()
        
    def initUI(self):
      
        self.parent.title("Popup menu")
        self.menu = Menu(self.parent, tearoff=0)
        self.menu.add_command(label="Beep", command=self.bell())
        self.menu.add_command(label="Exit", command=self.onExit)

        self.parent.bind("<Button-3>", self.showMenu)
        self.pack()
        
        
    def showMenu(self, e):
        self.menu.post(e.x_root, e.y_root)
       

    def onExit(self):
        self.quit()
Esempio n. 4
0
class Example(Frame):
  
    def __init__(self, parent):
        Frame.__init__(self, parent)   
         
        self.parent = parent
        
        self.initUI()
        
    def initUI(self):
      
        self.parent.title("Popup menu")
        self.menu = Menu(self.parent, tearoff=0)
        self.menu.add_command(label="Beep", command=self.bell())
        self.menu.add_command(label="Exit", command=self.onExit)

        self.parent.bind("<Button-2>", self.showMenu)
        self.pack()
        
        
    def showMenu(self, e):
        self.menu.post(e.x_root, e.y_root)
       

    def onExit(self):
        self.quit()
Esempio n. 5
0
class Example(Frame):
  
    def __init__(self, parent):
        Frame.__init__(self, parent)   
         
        self.parent = parent
        
        self.initUI()
        
    def initUI(self):
      
        self.parent.title("Popup menu")
        self.menu = Menu(self.parent, tearoff=0)
        #A context menu is a regular Menu widget. 
        #The tearoff feature is turned off. 
        #Now it is not possible to separate the menu into a new toplevel window.
        self.menu.add_command(label="Beep", command=self.bell())
        self.menu.add_command(label="Exit", command=self.onExit)

        self.parent.bind("<Button-3>", self.showMenu)
        #We bind the <Button-3> event to the showMenu() method. 
        #The event is generated when we right click on the client area of the window.
        self.pack()
        
    #The showMenu() method shows the context menu. 
    #The popup menu is shown at the x and y coordinates of the mouse click.    
    def showMenu(self, e):
        self.menu.post(e.x_root, e.y_root)
       

    def onExit(self):
        self.quit()
Esempio n. 6
0
    def _handle_r_click(self, event):
        """
        Handle mouse right click as a callback function

        Handle mouse right click by displaying a context menu for this widget,
        allow the addition and removal of window pics

        :param event:       The event generated by the window manager, automatically provided
        """
        Debug.printe(event, Debug.Level.INFO)

        # Create the menu to display
        p_menu = Menu(self._parent)
        p_menu.add_command(label="Add Picture", command=lambda: self._add_new_wall_pic())
        p_menu.add_command(label="Delete Picture", command=lambda: self._remove_wall_pic())
        p_menu.add_command(label="Delete All", command=lambda: self.remove_all())
        p_menu.post(event.x_root, event.y_root)
class Window(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)

        self.parent = parent

        self.startUI()

    def startUI(self):

        self.menu = Menu(self.parent, tearoff=0)
        self.menu.add_command(label="Beep", command=self.bell)
        self.menu.add_command(label="exit", command=self.quit)

        self.parent.bind("<Button-3>", self.showMenu)
        self.pack()

    def showMenu(self, e):
        self.menu.post(e.x_root, e.y_root)

    def bell(self):
        print "beep"
Esempio n. 8
0
class Window(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)

        self.parent = parent

        self.startUI()

    def startUI(self):

        self.menu = Menu(self.parent, tearoff=0)
        self.menu.add_command(label="Beep", command=self.bell)
        self.menu.add_command(label="exit", command=self.quit)

        self.parent.bind("<Button-3>", self.showMenu)
        self.pack()

    def showMenu(self, e):
        self.menu.post(e.x_root, e.y_root)

    def bell(self):
        print "beep"
Esempio n. 9
0
class TreeNode:
    def __init__(self, canvas, parent, item, menuList=[]):
        self.canvas = canvas
        self.parent = parent
        self.item = item
        self.state = 'collapsed'
        self.selected = 0
        self.children = {}
        self.kidKeys = []
        self.x = self.y = None
        self.iconimages = {}  # cache of PhotoImage instances for icons
        self.menuList = menuList
        self.menuVar = IntVar()
        self.menuVar.set(0)
        self._popupMenu = None
        self.image_id = None
        if self.menuList:
            if self.menuList[-1] == 'Separator':
                self.menuList = self.menuList[:-1]
            self._popupMenu = Menu(self.canvas, tearoff=0)
            for i in range(len(self.menuList)):
                item = self.menuList[i]
                if item == 'Separator':
                    self._popupMenu.add_separator()
                else:
                    self._popupMenu.add_radiobutton(
                        label=item,
                        variable=self.menuVar,
                        value=i,
                        indicatoron=0,
                        command=self.popupMenuCommand)

    def destroy(self):
        for key in self.kidKeys:
            c = self.children[key]
            del self.children[key]
            c.destroy()
        self.parent = None

    def geticonimage(self, name):
        try:
            return self.iconimages[name]
        except KeyError:
            pass
        file, ext = os.path.splitext(name)
        ext = ext or ".gif"
        fullname = os.path.join(ICONDIR, file + ext)
        image = PhotoImage(master=self.canvas, file=fullname)
        self.iconimages[name] = image
        return image

    def select(self, event=None):
        if self.selected:
            return
        self.deselectall()
        self.selected = 1
        if self.parent != None:
            if self.parent.state == 'expanded':
                self.canvas.delete(self.image_id)
                self.drawicon()
                self.drawtext()
        self.item.OnSelect(event)

    def deselect(self, event=None):
        if not self.selected:
            return
        self.selected = 0
        if self.parent != None:
            if self.parent.state == 'expanded':
                self.canvas.delete(self.image_id)
                self.drawicon()
                self.drawtext()

    def deselectall(self):
        if self.parent:
            self.parent.deselectall()
        else:
            self.deselecttree()

    def deselecttree(self):
        if self.selected:
            self.deselect()
        for key in self.kidKeys:
            child = self.children[key]
            child.deselecttree()

    def flip(self, event=None):
        if self.state == 'expanded':
            self.collapse()
        else:
            self.expand()
        self.item.OnDoubleClick()
        return "break"

    def popupMenu(self, event=None):
        if self._popupMenu:
            self._popupMenu.post(event.widget.winfo_pointerx(),
                                 event.widget.winfo_pointery())
            return "break"

    def popupMenuCommand(self):
        command = self.menuList[self.menuVar.get()]
        self.item.MenuCommand(command)
        if self.parent and (command != 'Update Explorer'):
            # Update parent to try to keep explorer up to date
            self.parent.update()

    def expand(self, event=None):
        if not self.item.IsExpandable():
            return
        if self.state != 'expanded':
            self.state = 'expanded'
            self.update()
            self.view()

    def collapse(self, event=None):
        if self.state != 'collapsed':
            self.state = 'collapsed'
            self.update()

    def view(self):
        top = self.y - 2
        bottom = self.lastvisiblechild().y + 17
        height = bottom - top
        visible_top = self.canvas.canvasy(0)
        visible_height = self.canvas.winfo_height()
        visible_bottom = self.canvas.canvasy(visible_height)
        if visible_top <= top and bottom <= visible_bottom:
            return
        x0, y0, x1, y1 = self.canvas._getints(self.canvas['scrollregion'])
        if top >= visible_top and height <= visible_height:
            fraction = top + height - visible_height
        else:
            fraction = top
        fraction = float(fraction) / y1
        self.canvas.yview_moveto(fraction)

    def reveal(self):
        # Make sure all parent nodes are marked as expanded
        parent = self.parent
        while parent:
            if parent.state == 'collapsed':
                parent.state = 'expanded'
                parent = parent.parent
            else:
                break
        # Redraw tree accordingly
        self.update()
        # Bring this item into view
        self.view()

    def lastvisiblechild(self):
        if self.kidKeys and self.state == 'expanded':
            return self.children[self.kidKeys[-1]].lastvisiblechild()
        else:
            return self

    def update(self):
        if self.parent:
            self.parent.update()
        else:
            oldcursor = self.canvas['cursor']
            self.canvas['cursor'] = "watch"
            self.canvas.update()
            self.canvas.delete(Tkinter.ALL)  # XXX could be more subtle
            self.draw(7, 2)
            x0, y0, x1, y1 = self.canvas.bbox(Tkinter.ALL)
            self.canvas.configure(scrollregion=(0, 0, x1, y1))
            self.canvas['cursor'] = oldcursor

    def draw(self, x, y):
        # XXX This hard-codes too many geometry constants!
        self.x, self.y = x, y
        self.drawicon()
        self.drawtext()
        if self.state != 'expanded':
            return y + 17
        # draw children
        sublist = self.item._GetSubList()
        if not sublist:
            # IsExpandable() was mistaken; that's allowed
            return y + 17
        self.kidKeys = []
        for item in sublist:
            key = item.GetKey()
            if self.children.has_key(key):
                child = self.children[key]
            else:
                child = TreeNode(self.canvas, self, item, self.menuList)
            self.children[key] = child
            self.kidKeys.append(key)
        # Remove unused children
        for key in self.children.keys():
            if key not in self.kidKeys:
                del (self.children[key])
        cx = x + 20
        cy = y + 17
        cylast = 0
        for key in self.kidKeys:
            child = self.children[key]
            cylast = cy
            self.canvas.create_line(x + 9, cy + 7, cx, cy + 7, fill="gray50")
            cy = child.draw(cx, cy)
            if child.item.IsExpandable():
                if child.state == 'expanded':
                    iconname = "minusnode"
                    callback = child.collapse
                else:
                    iconname = "plusnode"
                    callback = child.expand
                image = self.geticonimage(iconname)
                id = self.canvas.create_image(x + 9, cylast + 7, image=image)
                # XXX This leaks bindings until canvas is deleted:
                self.canvas.tag_bind(id, "<1>", callback)
                self.canvas.tag_bind(id, "<Double-1>", lambda x: None)
        id = self.canvas.create_line(
            x + 9,
            y + 10,
            x + 9,
            cylast + 7,
            ##stipple="gray50",     # XXX Seems broken in Tk 8.0.x
            fill="gray50")
        self.canvas.tag_lower(id)  # XXX .lower(id) before Python 1.5.2
        return cy

    def drawicon(self):
        if self.selected:
            imagename = (self.item.GetSelectedIconName()
                         or self.item.GetIconName() or "openfolder")
        else:
            imagename = self.item.GetIconName() or "folder"
        image = self.geticonimage(imagename)
        id = self.canvas.create_image(self.x, self.y, anchor="nw", image=image)
        self.image_id = id
        self.canvas.tag_bind(id, "<1>", self.select)
        self.canvas.tag_bind(id, "<Double-1>", self.flip)
        self.canvas.tag_bind(id, "<3>", self.popupMenu)

    def drawtext(self, text=None):
        textx = self.x + 20 - 1
        texty = self.y - 1
        labeltext = self.item.GetLabelText()
        if labeltext:
            id = self.canvas.create_text(textx,
                                         texty,
                                         anchor="nw",
                                         text=labeltext)
            self.canvas.tag_bind(id, "<1>", self.select)
            self.canvas.tag_bind(id, "<Double-1>", self.flip)
            x0, y0, x1, y1 = self.canvas.bbox(id)
            textx = max(x1, 200) + 10
        if text == None:
            text = self.item.GetText() or "<no text>"
        try:
            self.entry
        except AttributeError:
            pass
        else:
            self.edit_finish()
        try:
            label = self.label
        except AttributeError:
            # padding carefully selected (on Windows) to match Entry widget:
            self.label = Label(self.canvas, text=text, bd=0, padx=2, pady=2)
        if self.selected:
            self.label.configure(fg="white", bg="darkblue")
        else:
            fg = self.item.GetTextFg()
            self.label.configure(fg=fg, bg="white")
        id = self.canvas.create_window(textx,
                                       texty,
                                       anchor="nw",
                                       window=self.label)
        self.label.bind("<1>", self.select_or_edit)
        self.label.bind("<Double-1>", self.flip)
        self.label.bind("<3>", self.popupMenu)
        # Update text if necessary
        if text != self.label['text']:
            self.label['text'] = text
        self.text_id = id

    def select_or_edit(self, event=None):
        if self.selected and self.item.IsEditable():
            text = self.item.GetTextForEdit()
            self.label['text'] = text
            self.drawtext(text)
            self.edit(event)
        else:
            self.select(event)

    def edit(self, event=None):
        self.entry = Entry(self.label, bd=0, highlightthickness=1, width=0)
        self.entry.insert(0, self.label['text'])
        self.entry.selection_range(0, Tkinter.END)
        self.entry.pack(ipadx=5)
        self.entry.focus_set()
        self.entry.bind("<Return>", self.edit_finish)
        self.entry.bind("<Escape>", self.edit_cancel)

    def edit_finish(self, event=None):
        try:
            entry = self.entry
            del self.entry
        except AttributeError:
            return
        text = entry.get()
        entry.destroy()
        if text and text != self.item.GetText():
            self.item.SetText(text)
        text = self.item.GetText()
        self.label['text'] = text
        self.drawtext()
        self.canvas.focus_set()

    def edit_cancel(self, event=None):
        self.drawtext()
        self.canvas.focus_set()

    def find(self, searchKey):
        # Search for a node who's key matches the given key
        # Is it this node
        if searchKey == self.item.GetKey():
            return self
        # Nope, check the children
        sublist = self.item._GetSubList()
        for item in sublist:
            key = item.GetKey()
            # Use existing child or create new TreeNode if none exists
            if self.children.has_key(key):
                child = self.children[key]
            else:
                child = TreeNode(self.canvas, self, item, self.menuList)
                # Update local list of children and keys
                self.children[key] = child
                self.kidKeys.append(key)
            # See if node is child (or one of child's descendants)
            retVal = child.find(searchKey)
            if retVal:
                return retVal
        # Not here
        return None
Esempio n. 10
0
File: qgui.py Progetto: jkpr/QTools2
class PmaConvert:
    def __init__(self, config):
        root = Tk()

        # Root Definition
        root.geometry('1100x700')
        root.title('PMA Convert')

        # Configuration and Variables
        self.file_selection = ''
        self.is_converting = False
        self.options = config['option_definitions']
        gui_config = config['gui_config']

        # UI
        ## Frames
        self.main_frame = Frame(root)
        self.position_main_frame(gui_config['screen_orientation'])

        ## Components
        self.log = Text(self.main_frame, bd=1, relief=SUNKEN, width=140,
                        height=23, state=DISABLED, spacing3=1, wrap=WORD)

        choose_text = ('1. Choose XLSForm (.xls or .xlsx) file(s) for '
                       'conversion.')
        self.choose_files_label = Label(self.main_frame, text=choose_text)
        # TODO: Get spacing to work.
        # self.choose_files_label.grid(row=3, column=3, padx=(50, 50))
        # self.choose_files_label.grid(row=3, column=3, pady=(50, 50))
        self.choose_files_label.pack()
        self.choose_files_button = Button(self.main_frame,
                                          text='Choose file...', fg='black',
                                          command=self.on_open)
        self.choose_files_button.pack()

        out_text = 'Choose location for output file(s).'
        self.output_location_label = Label(self.main_frame, text=out_text)
        self.output_location_button = Button(self.main_frame,
                                             text='Choose location...',
                                             fg='black')
        if gui_config['output_location_on'] is True:
            self.output_location_label.pack()
            self.output_location_button.pack()

        self.choose_options_label = Label(self.main_frame,
                                          text='2. Choose conversion options.')
        self.choose_options_label.pack()

        ### Create Options Checkboxes
        # Task: Dynamically generate: http://stackoverflow.com/questions/...
        # ...553784/can-you-use-a-string-to-instantiate-a-class-in-python
        self.preexisting = BooleanVar()
        pre_text = self.options['preexisting']['label']
        self.preexisting_opt = Checkbutton(self.main_frame, text=pre_text,
                                           variable=self.preexisting)
        self.preexisting_opt.pack()
        self.regular = BooleanVar()
        reg_text = self.options['regular']['label']
        self.regular_opt = Checkbutton(self.main_frame, text=reg_text,
                                       variable=self.regular)
        self.regular_opt.pack()
        self.novalidate = BooleanVar()
        noval_text = self.options['novalidate']['label']
        self.novalidate_opt = Checkbutton(self.main_frame, text=noval_text,
                                          variable=self.novalidate)
        self.novalidate_opt.pack()
        self.ignore_version = BooleanVar()
        ig_text = self.options['ignore_version']['label']
        self.ignore_version_opt = Checkbutton(self.main_frame, text=ig_text,
                                              variable=self.ignore_version)
        self.ignore_version_opt.pack()
        self.linking_warn = BooleanVar()
        link_text = self.options['linking_warn']['label']
        self.linking_warn_option = Checkbutton(self.main_frame, text=link_text,
                                               variable=self.linking_warn)
        self.linking_warn_option.pack()
        self.debug = BooleanVar()
        debug_text = self.options['debug']['label']
        self.debug_option = Checkbutton(self.main_frame, text=debug_text,
                                        variable=self.debug)
        self.debug_option.pack()
        self.extras = BooleanVar()
        extras_text = self.options['extras']['label']
        self.extras_option = Checkbutton(self.main_frame, text=extras_text,
                                         variable=self.extras)
        self.extras_option.pack()

        self.convert_label = Label(self.main_frame, text='3. Run conversion.')
        self.convert_label.pack()

        # Task: Add xscrollcommand and yscrollcommand.
        self.convert_button = Button(self.main_frame, text='Convert',
                                     fg='black', command=self.convert)
        self.convert_button.pack()
        self.log.pack(fill=X, expand=1)
        self.log_text('PMA Convert allows you to convert .xls or .xlsx form '
                      'definition files to files which are compatible with ODK '
                      'Collect.\n\nIf you need to copy and paste from this '
                      'log, highlight the text and press CTRL+C to copy. Then '
                      'press CTRL+V to paste.\n\n'
                      '====================================================\n\n'
                      'Awaiting file selection.')

        # Task: Fix menus. They're not working.
        self.context_menu = Menu(self.main_frame, tearoff=0)
        self.context_menu.add_command(label="Convert", command=self.convert)
        self.main_frame.bind("<Button-3>", self.popup)

        # - Note: Strangely this stopped anchoring to bottom suddenly, for some
        # reason. So it is temporarily disabled.
        self.status_bar = Label(self.main_frame,
                                text='Awaiting file selection.',
                                bd=1, relief=SUNKEN, anchor=W)
        if gui_config['status_bar_on'] is True:
            self.status_bar.pack(side=BOTTOM, fill=X)

        # Run
        root.mainloop()

    # Functions
    def popup(self, event):
        # Note: Currently doesn't work.
        self.context_menu.post(event.x_root, event.y_root)
        # display the popup menu
        try:
            self.context_menu.tk_popup(event.x_root, event.y_root, 0)
        finally:
            # make sure to release the grab (Tk 8.0a1 only)
            self.context_menu.grab_release()

    def position_main_frame(self, orientation):
        if orientation == 'center':
            x, y, a = .5, .5, 'c'
            return self.main_frame.place(relx=x, rely=y, anchor=a)
        elif orientation == 'top':
            return self.main_frame.pack()
        else:
            return self.main_frame.pack()

    def on_open(self):
        file_types = [
            ('XLS Files', '*.xls'),
            ('XLSX Files', '*.xlsx'),
            ('All files', '*')
        ]
        try:
            self.file_selection = tkFileDialog.askopenfilename(
                filetypes=file_types, title='Open one or more files.',
                message='Open one or more files', multiple=1
            )
        except:
            self.file_selection = tkFileDialog.askopenfilename(
                filetypes=file_types, title='Open one or more files.', multiple=1
            )
        if self.file_selection != '':
            self.set_status('Click on Convert to convert files.')
            log_output = 'Ready for conversion: \n'
            for file in self.file_selection:
                log_output += '* ' + str(file) + '\n'
            log_output = log_output[:-1] # Removes the last '\n'.
            self.log.configure(self.log_text(log_output))

    def set_status(self, new_status):
        self.status_bar.configure(text=new_status)

    def log_text(self, new_text):
        self.log.configure(state=NORMAL)
        self.log.insert(END, str(new_text) + '\n\n')
        self.log.configure(state=DISABLED)
        self.log.bind("<1>", lambda event: self.log.focus_set())

    def convert(self):
        if self.file_selection != '':
            f = self.file_selection

            kwargs = {
                SUFFIX: u'',
                PREEXISTING: self.preexisting.get(),
                PMA: not self.regular.get(),
                CHECK_VERSIONING: not self.ignore_version.get(),
                STRICT_LINKING: not self.linking_warn.get(),
                VALIDATE: not self.novalidate.get(),
                EXTRAS: self.extras.get(),
                DEBUG: self.debug.get()
            }

            buffer = StringIO.StringIO()
            if not kwargs[DEBUG]:
                sys.stdout = buffer
                sys.stderr = buffer
            else:
                self.log_text('--> DEBUG MODE: check console output')

            try:
                xlsform_convert(f, **kwargs)
            except ConvertError as e:
                print unicode(e)
            except OSError as e:
                # Should catch WindowsError, impossible to test on Mac
                traceback.print_exc()
                print e

            if not kwargs[DEBUG]:
                sys.stdout = sys.__stdout__
                sys.stderr = sys.__stderr__

            self.log_text(buffer.getvalue())
Esempio n. 11
0
class Text(mx.AllMixins, tk.Text):
    
    def __init__(self, parent, scrollbar=True, **kw):

        parent = mx.get_master(parent)
        self.parent = parent
        
        frame = Frame(parent)
        frame.pack(fill='both', expand=True)
        
        # text widget
        if "wrap" not in kw:
            kw["wrap"] = "word"
        tk.Text.__init__(self, frame, **kw)
        #self.pack(side='left', fill='both', expand=True)
        mx.AllMixins.__init__(self, parent)
        
        # scrollbar
        if scrollbar:
            scrb = Scrollbar(frame, orient='vertical', command=self.yview) 
            self.config(yscrollcommand=scrb.set)
            scrb.pack(side='right', fill='y')
        
        # pop-up menu
        self.popup = Menu(self, tearoff=0)
        self.popup.add_command(label='Cut', command=self._cut)
        self.popup.add_command(label='Copy', command=self._copy)
        self.popup.add_command(label='Paste', command=self._paste)
        self.popup.add_separator()
        self.popup.add_command(label='Select All', command=self._select_all)
        self.popup.add_command(label='Clear All', command=self._clear_all)
        self.bind('<Button-3>', self._show_popup)

        # only allow mouse scroll when mouse inside text
        self.bind("<Leave>", lambda event: self.winfo_toplevel().focus_set(), "+")
        self.bind("<Enter>", lambda event: self.focus_set(), "+")
        
    def apply_theme(self, theme='standard'):
        '''theme=['standard', 'typewriter', 'terminal']'''

        if theme == 'typewriter':
            '''takes all inserted text and inserts it one char every 100ms'''
            options = {"font": ('Times', 10, 'bold')}
            self.config(options)
            text = self.get('1.0', 'end')
            self.delete('1.0', 'end')
            self.char_index = 0
            self._typewriter([char for char in text])
            
        elif theme == 'terminal':
            '''blocky insert cursor'''
            options = {'bg': 'black', 'fg': 'white', 'font': ('Courier', 10)}
            self.config(options)
            self.cursor = '1.0'
            self.fg = self.cget('fg')
            self.bg = self.cget('bg')
            self.switch = self.fg
            self.config(insertwidth=0)
            self._blink_cursor()
            self._place_cursor()

        elif theme == 'matrix':
            '''blocky insert cursor'''
            options = {'bg': 'black', 'fg': 'green', 'font': ('Courier', 10)}
            self.config(options)
            self.cursor = '1.0'
            self.fg = self.cget('fg')
            self.bg = self.cget('bg')
            self.switch = self.fg
            self.config(insertwidth=0)
            self._blink_cursor()
            self._place_cursor()

    def highlight_pattern(self, pattern, tag, start="1.0", end="end",
                          regexp=False, nocase=True, exact=True, **kwargs):
        '''Apply the given tag to all text that matches the given pattern

        If 'regexp' is set to True, pattern will be treated as a regular
        expression.

        From: http://stackoverflow.com/questions/3781670/how-to-highlight-text-in-a-tkinter-text-widget
        '''

        if not pattern:
            return 0
        start = self.index(start)
        end = self.index(end)
        self.mark_set("matchStart", start)
        self.mark_set("matchEnd", start)
        self.mark_set("searchLimit", end)

        count = tk.IntVar()
        while True:
            index = self.search(pattern, "matchEnd", "searchLimit",
                                count=count, regexp=regexp, nocase=nocase,
                                exact=exact, **kwargs)
            if index: 
                self.mark_set("matchStart", index)
                self.mark_set("matchEnd", "%s+%sc" % (index, count.get()))
                self.tag_add(tag, "matchStart", "matchEnd")
            else:
                break
        return count.get()

    def clear_highlights(self, *tagnames):
        names = tagnames or self.tag_names()
        self.tag_delete(*names)

    def next_pattern(self, pattern, current,
                     regexp=False, nocase=True, exact=True, **kwargs):
        if not pattern:
            return None
        start = self.index(current)
        end = self.index("end")

        count = tk.IntVar()
        index = self.search(pattern, start, end,
                            count=count, regexp=regexp, nocase=nocase,
                            exact=exact, **kwargs)
        if index:
            return index, index+"+%sc"%count.get()
        else:
            return None

    def prev_pattern(self, pattern, current,
                     regexp=False, nocase=True, exact=True, **kwargs):
        if not pattern:
            return None
        start = self.index(current)
        end = self.index("1.0")

        count = tk.IntVar()
        index = self.search(pattern, start, end,
                            count=count, regexp=regexp, nocase=nocase,
                            exact=exact, backwards=True, **kwargs)
        if index:
            return index, index+"-%sc"%count.get()
        else:
            return None


    # MISC INTERNALS

    def _show_popup(self, event):
        '''right-click popup menu'''
        
        if self.parent.focus_get() != self:
            self.focus_set()
        
        try:
            self.popup.post(event.x_root, event.y_root)
        finally:
            self.popup.grab_release()
            
    def _cut(self):
        
        try:
            selection = self.get(*self.tag_ranges('sel'))
            self.clipboard_clear()
            self.clipboard_append(selection)
            self.delete(*self.tag_ranges('sel'))
        except TypeError:
            pass
    
    def _copy(self):
        
        try:
            selection = self.get(*self.tag_ranges('sel'))
            self.clipboard_clear()
            self.clipboard_append(selection)
        except TypeError:
            pass
        
    def _paste(self):
        
        self.insert('insert', self.selection_get(selection='CLIPBOARD'))
        
    def _select_all(self):
        '''selects all text'''
        
        self.tag_add('sel', '1.0', 'end-1c')
        
    def _clear_all(self):
        '''erases all text'''
        
        isok = askokcancel('Clear All', 'Erase all text?', parent=self,
                           default='ok')
        if isok:
            self.delete('1.0', 'end')

    def _typewriter(self, text): # theme: typewriter
        '''after the theme is applied, this method takes all the inserted text
        and types it out one character every 100ms'''

        self.insert('insert', text[self.char_index])
        self.char_index += 1

        if hasattr(self, "typer") and self.char_index == len(text):
            self.after_cancel(self.typer)
        else:
            self.typer = self.after(100, self._typewriter, text)

    def _place_cursor(self): # theme: terminal
        '''check the position of the cursor against the last known position
        every 15ms and update the cursorblock tag as needed'''

        current_index = self.index('insert')

        if self.cursor != current_index:
            self.cursor = current_index
            self.tag_delete('cursorblock')
            
            start = self.index('insert')
            end = self.index('insert+1c')
            
            if start[0] != end[0]:
                self.insert(start, ' ')
                end = self.index('insert')
                
            self.tag_add('cursorblock', start, end)
            self.mark_set('insert', self.cursor)

        self.after(15, self._place_cursor)

    def _blink_cursor(self): # theme: terminal
        '''alternate the background color of the cursorblock tagged text
        every 600 milliseconds'''
        
        if self.switch == self.fg:
            self.switch = self.bg
        else:
            self.switch = self.fg

        self.tag_config('cursorblock', background=self.switch)

        self.after(600, self._blink_cursor)
Esempio n. 12
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 = tkFont.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 = tkFont.Font(family='helvetica',
                                     weight='bold',
                                     size=self._size.get())
        self._font = tkFont.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.node()['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 1
        elif self.shift(): return 1
        else:
            if len(self._parser.parses()) > 0:
                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 1
        return 0

    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 tkMessageBox 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 = string.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].node().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.node),
                               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.node()['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.node()['color'] = 'black'
            else:
                stackwidget['color'] = 'black'
Esempio n. 13
0
class PopupMenuCreator:
    def __init__(self, atom3i):
        self.master = atom3i.parent
        self.atom3i = atom3i
        self.cb = atom3i.cb
        self.optionsDatabase = atom3i.optionsDatabase
        self.popupLogoPhotoimage = Embedded_Images().getPopupLogo()

        self.popupMenu = None
        self.event = None

    # --------------------------- Popup Utilities -------------------------------

    def initilizePopupMenu(self, event):
        """ Create a new popup menu """
        if (self.popupMenu):
            self.popupMenu.unpost()
        self.popupMenu = Menu(self.master, tearoff=0, bg="white")
        self.event = event

    def showPopupMenu(self):
        """ Display the popup menu """
        if (self.popupMenu):
            self.popupMenu.post(self.event.x_root, self.event.y_root)

    def swapMenu(self, menu):
        """ 
    This is a fix for a problem that no longer exists :p
    It essentially takes one menu and slaps another one in its place.
    """
        raise Exception, "No one uses this method! But if you see this, maybe not so..."
        self.popupMenu.unpost()
        self.popupMenu = menu
        self.showPopupMenu()

    def popupRemover(self):
        """ Goodbye popup! """
        if (self.popupMenu):
            self.popupMenu.unpost()
            self.popupMenu = None

    # ----------------------  Context Sensitive Menus --------------------------

    def NoCursorNoSelectPopup(self, event):
        """ Popup menu to show when no items under the mouse, and no items selected """

        self.initilizePopupMenu(event)

        addLogo(self)
        #.........................
        addSeperator(self)
        #.........................
        addModelAction(self)
        addSelectAll(self)
        addPaste(self)
        addUndo(self)
        addRedo(self)
        #.........................
        addSeperator(self)
        #.........................
        addFileMenu(self)
        addModelMenu(self)
        addTransformationMenu(self)
        addLayoutMenu(self)
        addExportMenu(self)
        #.........................
        addSeperator(self)
        #.........................
        addOpenLastModel(self)
        addOpenLastMetaModel(self)
        addSourcePath(self)
        #.........................
        addSeperator(self)
        #.........................
        addToggleSmoothMode(self)
        #.........................
        addSeperator(self)
        #.........................
        addExit(self)

        self.showPopupMenu()

    def NoCursorMultiSelectPopup(self, event):
        """ Popup menu to show when no items under the mouse, and multiple items selected """

        self.initilizePopupMenu(event)

        addLogo(self)
        #.........................
        addSeperator(self)
        #.........................
        addLayoutMenu(self)
        addResizeEntity(self)
        addNodeLabelDragToggle(self)
        #.........................
        addSeperator(self)
        #.........................
        addSelectAll(self)
        addDeselectAll(self)
        #.........................
        addSeperator(self)
        #.........................
        addCut(self)
        addCopy(self)
        addPaste(self)
        #.........................
        addSeperator(self)
        #.........................
        addUndo(self)
        addRedo(self)
        #.........................
        addSeperator(self)
        #.........................
        addClear(self)

        self.showPopupMenu()

    def EntityAtCursorMultiSelectPopup(self, event):
        """ 
    A graphical entity is under the mouse cursor, along with multiple
    selected items
    """

        self.initilizePopupMenu(event)

        addLogo(self)
        #.........................
        addSeperator(self)
        #.........................
        addLayoutMenu(self)
        addEditEntity(self)
        addDragOverlap(self)
        addDrawArrow(self)
        addResizeEntity(self)
        addNodeLabelDragToggle(self)
        #.........................
        addSeperator(self)
        #.........................
        addSelectAll(self)
        addDeselectAll(self)
        #.........................
        addSeperator(self)
        #.........................
        addCut(self)
        addCopy(self)
        addPaste(self)
        #.........................
        addSeperator(self)
        #.........................
        addCopyAttributes(self)
        addPasteAttributes(self)
        #.........................
        addSeperator(self)
        #.........................
        addUndo(self)
        addRedo(self)
        #.........................
        addSeperator(self)
        #.........................
        addClear(self)

        self.showPopupMenu()

    def EntityAtCursorNoSelectPopup(self, event):
        """ A graphical entity is under the mouse cursor, but no selected items """

        self.initilizePopupMenu(event)

        addLogo(self)
        #.........................
        addSeperator(self)
        #.........................
        addEditEntity(self)
        addDragOverlap(self)
        addDrawArrow(self)
        addResizeEntity(self)
        #.........................
        addSeperator(self)
        #.........................
        addSelectAll(self)
        addPaste(self)
        #.........................
        addSeperator(self)
        #.........................
        addCopyAttributes(self)
        addPasteAttributes(self)
        #.........................
        addSeperator(self)
        #.........................
        addUndo(self)
        addRedo(self)

        self.showPopupMenu()

    def LinkAtCursorMultiSelectPopup(self, event):
        """ 
    A graphical link/connection is under the mouse cursor, along with multiple
    selected items
    """

        self.initilizePopupMenu(event)

        addLogo(self)
        #.........................
        addSeperator(self)
        #.........................
        addLayoutMenu(self)
        addEditEntity(self)
        addDragOverlap(self)
        addArrowEditor(self)
        addResizeEntity(self)
        addNodeLabelDragToggle(self)
        #.........................
        addSeperator(self)
        #.........................
        addSmoothSelected(self)
        addToggleSmoothMode(self)
        #.........................
        addSeperator(self)
        #.........................
        addSelectAll(self)
        addDeselectAll(self)
        #.........................
        addSeperator(self)
        #.........................
        addCut(self)
        addCopy(self)
        addPaste(self)
        #.........................
        addSeperator(self)
        #.........................
        addCopyAttributes(self)
        addPasteAttributes(self)
        #.........................
        addSeperator(self)
        #.........................
        addUndo(self)
        addRedo(self)
        #.........................
        addSeperator(self)
        #.........................
        addClear(self)

        self.showPopupMenu()

    def LinkAtCursorNoSelectPopup(self, event):
        """ 
    A graphical link/connection is under the mouse cursor, but there are no
    selected items
    """

        self.initilizePopupMenu(event)

        addLogo(self)
        #.........................
        addSeperator(self)
        #.........................
        addEditEntity(self)
        addDragOverlap(self)
        addArrowEditor(self)
        #.........................
        addSeperator(self)
        #.........................
        addSelectAll(self)
        addToggleSmoothMode(self)
        addPaste(self)
        #.........................
        addSeperator(self)
        #.........................
        addCopyAttributes(self)
        addPasteAttributes(self)
        #.........................
        addSeperator(self)
        #.........................
        addUndo(self)
        addRedo(self)

        self.showPopupMenu()

    def ArrowEditorPopup(self, event):
        """ Menu for the arrow editor """
        self.initilizePopupMenu(event)

        addLogo(self)
        #.........................
        addSeperator(self)
        #.........................
        addEditEntity(self)
        addInsertPoint(self)
        addDeletePoint(self)
        addSmoothSelected(self)
        addNodeLabelMoveToggle(self)
        #.........................
        addSeperator(self)
        #.........................
        addArrowEditorExit(self)

        self.showPopupMenu()

    # ----------------------- Popup a specific submenu -------------------------

    def LayoutPopup(self, event):
        self.initilizePopupMenu(event)
        self.popupMenu = self.atom3i.layoutMenu
        self.showPopupMenu()

    def ExportPopup(self, event):
        self.initilizePopupMenu(event)
        self.popupMenu = self.atom3i.exportMenu
        self.showPopupMenu()

    def ModelPopup(self, event):
        self.initilizePopupMenu(event)
        self.popupMenu = self.atom3i.modelMenu
        self.showPopupMenu()

    def TransformationPopup(self, event):
        self.initilizePopupMenu(event)
        self.popupMenu = self.atom3i.transMenu
        self.showPopupMenu()

    def FilePopup(self, event):
        self.initilizePopupMenu(event)
        self.popupMenu = self.atom3i.filemenu
        self.showPopupMenu()

    def LastModelPopup(self, event):
        self.initilizePopupMenu(event)
        addOpenLastModelSubroutine(self, self.popupMenu)
        self.showPopupMenu()

    def LastMetaModelPopup(self, event):
        self.initilizePopupMenu(event)
        addOpenLastMetaModelSubroutine(self, self.popupMenu)
        self.showPopupMenu()

    def SourcePathPopup(self, event):
        self.initilizePopupMenu(event)
        addSourcePathSubroutine(self, self.popupMenu)
        self.showPopupMenu()

    # ------------------------ String List to PopupMenu ---------------------------------

    def listChoicePopup(self, title, stringList, unused=None):
        """ 
    Creates a popup menu with radiobuttons labeled from the stringList.
    Returns the index of the label that was chosen.
    NOTE: choosing outside the popup implicitly chooses index 0
    """

        # Remove any existing popups first
        self.popupRemover()

        self.popupMenu = Menu(self.master, tearoff=0)
        integerVar = IntVar()

        self.popupMenu.add_command(label=title, command=self.popupRemover)
        self.popupMenu.add_separator()

        i = 1
        for label in stringList:
            self.popupMenu.add_radiobutton(label=label,
                                           variable=integerVar,
                                           value=i,
                                           indicatoron=False)
            i += 1

        # This gets the last known co-ordinates of the mouse :D
        # NOTE: We get co-ordinates in terms of canvas space, convert back into
        # screenspace first before using them...
        x, y = self.atom3i.cb.getLastClickCoord()
        dc = self.atom3i.cb.getCanvas()
        x, y = [x - dc.canvasx(0), y - dc.canvasy(0)]

        # These offsets place the menu just where I like it...
        x = int(x) + 40  #+ 100
        y = int(y) + 40  #+ 20

        # Posts the menu, and blocks program execution here on win32 only
        self.popupMenu.post(x, y)

        # Blocks program execution (all platforms) & waits for integerVar to be updated
        # Not ideal: If we close the popup without selecting anything this will
        # wait forever and execution will never get anywhere beyond this point!!!
        # Moreover: AToM3 will not shutdown properly!
        #self.master.wait_variable( integerVar )

        # THEORY: This will work whether or not the post() blocks or not
        # Practice: Works great on WinXP with Python 2.3
        #           Linux?
        while (1):
            self.master.update()
            value = integerVar.get()

            # Hapiness, we got the value we wanted
            if (value > 0):
                return value

                # The user killed the popup! O_O
            elif (self.popupMenu == None):
                return 0

                # Unhapiness, the user avoided selecting anything
            elif (value == 0):
                self.popupMenu.unpost()
                self.popupMenu.post(x, y)
                self.master.update()

            time.sleep(0.4)

        return 0  # We won't get here, but just in case...

    def listChoicePopupAlternative(self, title, stringList, actionLabel):
        """ OBSOLETE --- Delete this """

        raise Exception, "No one uses this method! But if you see this, maybe not so..."
        """
Esempio n. 14
0
class SyntaxHighlightingText(ScrolledText2):

    # constructor
    def __init__(self, root, change_hook = None, highlighter = None, grammar=None):
        ScrolledText2.__init__(self,root,change_hook)
        # Non-wrapping, no border, undo turned on, max undo 50
        self.text = self # For the methods taken from IDLE
        self.root = root
        self.change_hook = change_hook
        self.characters = ascii_letters + digits + punctuation
        self.tabwidth = 8    # for IDLE use, must remain 8 until Tk is fixed
        self.indentwidth = 4
        self.indention = 0   # The current indention level
        self.set_tabwidth(self.indentwidth) # IDLE...
        self.previous_line = "0"

        # create a popup menu
        self.menu = Menu(root, tearoff=0)
        self.menu.add_command(label="Undo", command=self.edit_undo)
        self.menu.add_command(label="Redo", command=self.edit_redo)
        #self.menu.add_command(type="separator")
        self.menu.add_command(label="Cut", command=self.cut)
        self.menu.add_command(label="Copy", command=self.copy)
        self.menu.add_command(label="Paste", command=self.paste)

        self.bind('<KeyRelease>', self.key_release)      # For scanning input
        self.bind('<Return>',self.autoindent)   # Overides default binding
        #self.bind('<Tab>',self.autoindent) # increments self.indention
        #self.bind('<BackSpace>',self.autoindent) # decrements self.indention
        self.bind('<Button-3>', self.popup) # right mouse button opens popup
        self.bind('<Button-1>', self.recolorCurrentLine) # left mouse can reposition cursor, so recolor (e.g. bracket highlighting necessary)
        self.bind('<Control-Any-KeyPress>', self.ctrl)
        
        self.grammar = grammar
        
        self.setHighlighter(highlighter)

    def setHighlighter(self, highlighter):
        if highlighter == None:
            highlighter = Highlighter()
        self.highlighter = highlighter
        # sets up the tags
        for tag, settings in self.highlighter.tags.items():
            self.tag_config(tag, **settings)

    def popup(self, event):
        self.menu.post(event.x_root, event.y_root)

    def get_tabwidth(self):
        # From IDLE
        current = self['tabs'] or 5000
        return int(current)

    def set_tabwidth(self, newtabwidth):
        # From IDLE
        text = self
        if self.get_tabwidth() != newtabwidth:
            pixels = text.tk.call("font", "measure", text["font"],
                                  "-displayof", text.master,
                                  "n" * newtabwidth)
            text.configure(tabs=pixels)

    def remove_singleline_tags(self, start, end):
        for tag in self.highlighter.tags.keys():
            if tag[:2] != 'ml':
                self.tag_remove(tag, start, end)

    def get_selection_indices(self):
        # If a selection is defined in the text widget, return (start,
        # end) as Tkinter text indices, otherwise return (None, None)
        try:
            first = self.text.index("sel.first")
            last = self.text.index("sel.last")
            return first, last
        except TclError:
            return None

    # Select all the text in textbox
    def select_all(self):
        self.tag_add(SEL, "1.0", END)
        self.mark_set(INSERT, END)
        self.see(INSERT)
        self.focus_set()
        return 'break'

    def cut(self,event=0):
        self.clipboard_clear()
        Selection=self.get_selection_indices()
        if Selection is not None:
            SelectedText = self.get(Selection[0],Selection[1])
            self.delete(Selection[0],Selection[1])
            self.clipboard_append(SelectedText)
            self.onChange()

    def copy(self,event=0):
        self.clipboard_clear()
        Selection=self.get_selection_indices()
        if Selection is not None:
            SelectedText = self.get(Selection[0],Selection[1])
            self.clipboard_append(SelectedText)

    def paste(self,event=0):
        # This should call colorize for the pasted lines.
        SelectedText = self.root.selection_get(selection='CLIPBOARD')
        Selection=self.get_selection_indices()
        if Selection is not None:
            self.delete(Selection[0],Selection[1])
        self.insert(INSERT, SelectedText)
        self.onChange()
        return "break"

    def autoindent(self,event):
        if event.keysym == 'Return':
            self.edit_separator() # For undo/redo
            index = self.index(INSERT).split('.')
            #print index
            line = int(index[0])
            column = int(index[1])
            if self.get('%s.%d'%(line, column-1)) == ':':
                self.indention += 1
            #print '\n',
            #print '\t'*self.indention
            self.insert(INSERT,'\n')
            self.insert(INSERT,'\t'*self.indention)
            return 'break' # Overides standard bindings
        elif event.keysym == 'Tab':
            self.edit_separator()
            self.indention += 1
            #print self.indention
        elif event.keysym == 'BackSpace':
            self.edit_separator()
            index = self.index(INSERT).split('.')
            #print index
            line = int(index[0])
            column = int(index[1])
            if self.get('%s.%d'%(line, column-1)) == '\t':
                self.indention -= 1

    def recolorCurrentLine(self, *foo):
        pos = self.index(INSERT)
        cline = pos.split('.')[0]
        #print "recoloring %s, %s" % (cline, self.previous_line)
        if cline != self.previous_line: self.colorize(self.previous_line)
        self.colorize(cline)
        self.previous_line = cline

    def key_release(self, key):
        #print "pressed", key.keysym, dir(key)
        if key.char in ' :[(]),"\'':
            self.edit_separator() # For undo/redo
        # recolorize the current line and the previous line (if it's a different one)
        self.recolorCurrentLine()
        # if delete or backspace were pressed, check if a multiline comment has to be removed
        pos = self.index(INSERT)
        if key.keysym in ("BackSpace", "Delete"):
            #print "removal at %s" % pos
            ranges = self.tag_ranges('mlcom')
            i = 0
            while i < len(ranges):
                range = ranges[i:i+2]
                second_range = (self.index(str(range[0]) + " + 1 char"), self.index(str(range[1]) + " - 1 char"))
                #print pos, range, second_range
                if pos in range or pos in second_range:
                    self.tag_remove('mlcom', range[0], range[1])
                i += 2
        # notify of change if any. masks for the key.state variable
        # 0x0001     Shift.
        # 0x0002     Caps Lock.
        # 0x0004     Control.
        # 0x0008     Left-hand Alt.
        # 0x0010     Num Lock.
        # 0x0080     Right-hand Alt.
        # 0x0100     Mouse button 1.
        # 0x0200     Mouse button 2.
        # 0x0400     Mouse button 3. 
        if key.char != '' and not (key.state & 4) or key.keysym in ("BackSpace", "Delete"):
            self.onChange()
        else:
            pass
            #print key

    def onChange(self):
        if self.change_hook is not None:
            self.change_hook()

    def delete_current_line(self):
        selection = self.get_selection_indices()
        if selection is None:
            start  = int(self.index(INSERT).split('.')[0])
            end = start
        else:
            start = int(selection[0].split('.')[0])
            end = int(selection[1].split('.')[0])
        self.delete('%d.0' % start, '%d.end' % end)
        self.onChange()
#         return 'break'

    def ctrl(self, key):
        if key.keysym == 'c': return self.copy()
        elif key.keysym == 'x': return self.cut()
        elif key.keysym == 'v': return self.paste()
        elif key.keysym == 'a': return self.select_all()
        elif key.keysym == 'd': return self.delete_current_line() 
        #pass # apparently now implemented in the control itself
        # edit: yes, but with counterintuitive behavior

    def colorize(self, cline):
        cursorPos = self.index(INSERT)
        buffer = self.get('%s.%d' % (cline,0), '%s.end' % (cline))

        # remove non-multiline tags
        self.remove_singleline_tags('%s.%d'% (cline, 0), '%s.end'% (cline))

        in_quote = False
        quote_start = 0
        for i in range(len(buffer)):
            here = '%s.%d' % (cline, i)
            # strings
            if buffer[i] in ['"',"'"]: # Doesn't distinguish between single and double quotes...
                if in_quote:
                    self.tag_add('str', '%s.%d' % (cline, quote_start), '%s.%d' % (cline, i+1))
                    in_quote = False
                else:
                    quote_start = i
                    in_quote = True
            if not in_quote:
                # operators
                if False:
                    for op in self.highlighter.operators:
                        if buffer[i:i+len(op)] == op:
                            self.tag_add('op', "%s.%d" % (cline, i), "%s.%d" % (cline, i+len(op)))
                # comments
                if buffer[i:i+2] == "//":
                    self.tag_add('com', '%s.%d' % (cline, i), '%s.end' % (cline))
                # multiline comments
                elif buffer[i:i+2] == "/*":
                    if not here in self.tag_ranges('mlcom'):
                        end_pos = self.search("*/", here, forwards=True) # get the end of the comment
                        if not end_pos:
                            continue
                        if self.search("/*", here + " + 2 chars", stopindex=end_pos): # if there's a nested comment, ignore it (it might just be a nested /* with a */)
                            continue
                        #!!! make sure the area does not contain any "/*", because the "*/" is not the right one otherwise
                        #print "multiline comment from %s to %s" % (here, str(end_pos))
                        self.tag_add('mlcom', here, str(end_pos) + " + 2 chars")
                elif buffer[i:i+2] == "*/":
                    end_pos = self.index(here + " + 2 chars")
                    if not end_pos in self.tag_ranges('mlcom'):
                        start_pos = self.search("/*", here, backwards=True) # get the beginning of the comment
                        if not start_pos:
                            continue
                        if self.search("*/", here, stopindex=start_pos, backwards=True): # if there's a nested comment, ignore it (it might just be a nested */ without a /*)
                            continue
                        #print "multiline comment from %s to %s" % (start_pos, end_pos)
                        self.tag_add('mlcom', start_pos, end_pos)
                # bracket highlighting
                elif buffer[i] in self.highlighter.open_brackets and here == cursorPos:
                    idxBracketType = self.highlighter.open_brackets.index(buffer[i])
                    openb, closeb = self.highlighter.brackets[idxBracketType]
                    stack = 1
                    for j,c in enumerate(buffer[i+1:]):
                        if c == openb:
                            stack += 1
                        elif c == closeb:
                            stack -= 1
                            if stack == 0:
                                self.tag_add('bracket_hl', here, here + " + 1 char")
                                self.tag_add('bracket_hl', "%s.%d" % (cline, i+1+j), "%s.%d" % (cline, i+1+j+1))
                                break
                elif buffer[i] in self.highlighter.close_brackets and self.index(here + " + 1 char") == cursorPos:
                    idxBracketType = self.highlighter.close_brackets.index(buffer[i])
                    openb, closeb = self.highlighter.brackets[idxBracketType]
                    stack = 1
                    l = list(buffer[:i])
                    l.reverse()
                    for j,c in enumerate(l):
                        if c == closeb:
                            stack += 1
                        elif c == openb:
                            stack -= 1
                            if stack == 0:
                                self.tag_add('bracket_hl', here, here + " + 1 char")
                                self.tag_add('bracket_hl', "%s.%d" % (cline, i-1-j), "%s.%d" % (cline, i-1-j+1))
                                break
        # tokens
        start, end = 0, 0
        obj_flag = 0
        
        # variable and predicate highlighting
        for match in re.finditer('(\\?[a-zA-Z0-9]+|[\w]*[a-zA-Z]\\()', buffer):
            token = match.group(0)
            if self.grammar is not None and self.grammar.isvar(token):
                self.tag_add('var', '%s.%d' % (cline, match.start()), '%s.%d' % (cline, match.end()))
            elif token[-1] == '(':
                self.tag_add('pred', '%s.%d' % (cline, match.start()), '%s.%d' % (cline, match.end()-1))
        
        for token in buffer.split(' '):
            end = start + len(token)
            start_index = '%s.%d' % (cline, start)
            end_index = '%s.%d' % (cline, end)
            if obj_flag:
                self.tag_add('obj', start_index, end_index)
                obj_flag = 0
            # keywords
            if token.strip() in self.highlighter.keywords:
                self.tag_add('kw', start_index, end_index)
                if token.strip() in ['def','class']:
                    obj_flag = 1
            else:
                # numbers
                try:
                    float(token)
                except ValueError:
                    pass
                else:
                    self.tag_add('number', '%s.%d' % (cline, start), "%s.%d" % (cline, end))
            start += len(token)+1

    def insert(self, index, text, *args):
        line = int(self.index(index).split(".")[0])
        Text.insert(self, index, text, *args)
        for i in range(text.count("\n")):
            self.colorize(str(line+i))

    def disable(self, disable):
        Text.config(self, state=DISABLED if disable else NORMAL)
Esempio n. 15
0
class TreeNode:

    def __init__(self, canvas, parent, item, menuList = []):
        self.canvas = canvas
        self.parent = parent
        self.item = item
        self.state = 'collapsed'
        self.selected = 0
        self.children = {}
        self.kidKeys = []
        self.x = self.y = None
        self.iconimages = {} # cache of PhotoImage instances for icons
        self.menuList = menuList
        self.menuVar = IntVar()
        self.menuVar.set(0)
        self._popupMenu = None
        self.image_id = None
        if self.menuList:
            if self.menuList[-1] == 'Separator':
                self.menuList = self.menuList[:-1]
            self._popupMenu = Menu(self.canvas, tearoff = 0)
            for i in range(len(self.menuList)):
                item = self.menuList[i]
                if item == 'Separator':
                    self._popupMenu.add_separator()
                else:
                    self._popupMenu.add_radiobutton(
                        label = item,
                        variable = self.menuVar,
                        value = i,
                        indicatoron = 0,
                        command = self.popupMenuCommand)
                    
    def destroy(self):
        for key in self.kidKeys:
            c = self.children[key]
            del self.children[key]
            c.destroy()
        self.parent = None

    def geticonimage(self, name):
        try:
            return self.iconimages[name]
        except KeyError:
            pass
        file, ext = os.path.splitext(name)
        ext = ext or ".gif"
        fullname = os.path.join(ICONDIR, file + ext)
        image = PhotoImage(master=self.canvas, file=fullname)
        self.iconimages[name] = image
        return image

    def select(self, event=None):
        if self.selected:
            return
        self.deselectall()
        self.selected = 1
        if self.parent != None:
            if self.parent.state == 'expanded':
                self.canvas.delete(self.image_id)
                self.drawicon()
                self.drawtext()
        self.item.OnSelect(event)

    def deselect(self, event=None):
        if not self.selected:
            return
        self.selected = 0
        if self.parent != None:
            if self.parent.state == 'expanded':
                self.canvas.delete(self.image_id)
                self.drawicon()
                self.drawtext()

    def deselectall(self):
        if self.parent:
            self.parent.deselectall()
        else:
            self.deselecttree()

    def deselecttree(self):
        if self.selected:
            self.deselect()
        for key in self.kidKeys:
            child = self.children[key]
            child.deselecttree()

    def flip(self, event=None):
        if self.state == 'expanded':
            self.collapse()
        else:
            self.expand()
        self.item.OnDoubleClick()
        return "break"

    def popupMenu(self, event=None):
        if self._popupMenu:
            self._popupMenu.post(event.widget.winfo_pointerx(),
                                 event.widget.winfo_pointery())
            return "break"

    def popupMenuCommand(self):
        command = self.menuList[self.menuVar.get()]
        self.item.MenuCommand(command)
        if self.parent and (command != 'Update Explorer'):
            # Update parent to try to keep explorer up to date
            self.parent.update()

    def expand(self, event=None):
        if not self.item.IsExpandable():
            return
        if self.state != 'expanded':
            self.state = 'expanded'
            self.update()
            self.view()

    def collapse(self, event=None):
        if self.state != 'collapsed':
            self.state = 'collapsed'
            self.update()

    def view(self):
        top = self.y - 2
        bottom = self.lastvisiblechild().y + 17
        height = bottom - top
        visible_top = self.canvas.canvasy(0)
        visible_height = self.canvas.winfo_height()
        visible_bottom = self.canvas.canvasy(visible_height)
        if visible_top <= top and bottom <= visible_bottom:
            return
        x0, y0, x1, y1 = self.canvas._getints(self.canvas['scrollregion'])
        if top >= visible_top and height <= visible_height:
            fraction = top + height - visible_height
        else:
            fraction = top
        fraction = float(fraction) / y1
        self.canvas.yview_moveto(fraction)

    def reveal(self):
        # Make sure all parent nodes are marked as expanded
        parent = self.parent
        while parent:
            if parent.state == 'collapsed':
                parent.state = 'expanded'
                parent = parent.parent
            else:
                break
        # Redraw tree accordingly
        self.update()
        # Bring this item into view
        self.view()

    def lastvisiblechild(self):
        if self.kidKeys and self.state == 'expanded':
            return self.children[self.kidKeys[-1]].lastvisiblechild()
        else:
            return self

    def update(self):
        if self.parent:
            self.parent.update()
        else:
            oldcursor = self.canvas['cursor']
            self.canvas['cursor'] = "watch"
            self.canvas.update()
            self.canvas.delete(Tkinter.ALL)     # XXX could be more subtle
            self.draw(7, 2)
            x0, y0, x1, y1 = self.canvas.bbox(Tkinter.ALL)
            self.canvas.configure(scrollregion=(0, 0, x1, y1))
            self.canvas['cursor'] = oldcursor

    def draw(self, x, y):
        # XXX This hard-codes too many geometry constants!
        self.x, self.y = x, y
        self.drawicon()
        self.drawtext()
        if self.state != 'expanded':
            return y+17
        # draw children
        sublist = self.item._GetSubList()
        if not sublist:
            # IsExpandable() was mistaken; that's allowed
            return y+17
        self.kidKeys = []
        for item in sublist:
            key = item.GetKey()
            if self.children.has_key(key):
                child = self.children[key]
            else:
                child = TreeNode(self.canvas, self, item, self.menuList)
            self.children[key] = child
            self.kidKeys.append(key)
        # Remove unused children
        for key in self.children.keys():
            if key not in self.kidKeys:
                del(self.children[key])
        cx = x+20
        cy = y+17
        cylast = 0
        for key in self.kidKeys:
            child = self.children[key]
            cylast = cy
            self.canvas.create_line(x+9, cy+7, cx, cy+7, fill="gray50")
            cy = child.draw(cx, cy)
            if child.item.IsExpandable():
                if child.state == 'expanded':
                    iconname = "minusnode"
                    callback = child.collapse
                else:
                    iconname = "plusnode"
                    callback = child.expand
                image = self.geticonimage(iconname)
                id = self.canvas.create_image(x+9, cylast+7, image=image)
                # XXX This leaks bindings until canvas is deleted:
                self.canvas.tag_bind(id, "<1>", callback)
                self.canvas.tag_bind(id, "<Double-1>", lambda x: None)
        id = self.canvas.create_line(x+9, y+10, x+9, cylast+7,
            ##stipple="gray50",     # XXX Seems broken in Tk 8.0.x
            fill="gray50")
        self.canvas.tag_lower(id) # XXX .lower(id) before Python 1.5.2
        return cy

    def drawicon(self):
        if self.selected:
            imagename = (self.item.GetSelectedIconName() or
                         self.item.GetIconName() or
                         "openfolder")
        else:
            imagename = self.item.GetIconName() or "folder"
        image = self.geticonimage(imagename)
        id = self.canvas.create_image(self.x, self.y, anchor="nw", image=image)
        self.image_id = id
        self.canvas.tag_bind(id, "<1>", self.select)
        self.canvas.tag_bind(id, "<Double-1>", self.flip)
        self.canvas.tag_bind(id, "<3>", self.popupMenu)
        
    def drawtext(self, text=None):
        textx = self.x+20-1
        texty = self.y-1
        labeltext = self.item.GetLabelText()
        if labeltext:
            id = self.canvas.create_text(textx, texty, anchor="nw",
                                         text=labeltext)
            self.canvas.tag_bind(id, "<1>", self.select)
            self.canvas.tag_bind(id, "<Double-1>", self.flip)
            x0, y0, x1, y1 = self.canvas.bbox(id)
            textx = max(x1, 200) + 10
        if text==None:
            text = self.item.GetText() or "<no text>"
        try:
            self.entry
        except AttributeError:
            pass
        else:
            self.edit_finish()
        try:
            label = self.label
        except AttributeError:
            # padding carefully selected (on Windows) to match Entry widget:
            self.label = Label(self.canvas, text=text, bd=0, padx=2, pady=2)
        if self.selected:
            self.label.configure(fg="white", bg="darkblue")
        else:
            fg = self.item.GetTextFg()
            self.label.configure(fg=fg, bg="white")
        id = self.canvas.create_window(textx, texty,
                                       anchor="nw", window=self.label)
        self.label.bind("<1>", self.select_or_edit)
        self.label.bind("<Double-1>", self.flip)
        self.label.bind("<3>", self.popupMenu)
        # Update text if necessary
        if text != self.label['text']:
            self.label['text'] = text
        self.text_id = id

    def select_or_edit(self, event=None):
        if self.selected and self.item.IsEditable():
            text = self.item.GetTextForEdit()
            self.label['text'] = text
            self.drawtext(text)
            self.edit(event)
        else:
            self.select(event)

    def edit(self, event=None):
        self.entry = Entry(self.label, bd=0, highlightthickness=1, width=0)
        self.entry.insert(0, self.label['text'])
        self.entry.selection_range(0, Tkinter.END)
        self.entry.pack(ipadx=5)
        self.entry.focus_set()
        self.entry.bind("<Return>", self.edit_finish)
        self.entry.bind("<Escape>", self.edit_cancel)

    def edit_finish(self, event=None):
        try:
            entry = self.entry
            del self.entry
        except AttributeError:
            return
        text = entry.get()
        entry.destroy()
        if text and text != self.item.GetText():
            self.item.SetText(text)
        text = self.item.GetText()
        self.label['text'] = text
        self.drawtext()
        self.canvas.focus_set()

    def edit_cancel(self, event=None):
        self.drawtext()
        self.canvas.focus_set()

    def find(self, searchKey):
        # Search for a node who's key matches the given key
        # Is it this node
        if searchKey == self.item.GetKey():
            return self
        # Nope, check the children
        sublist = self.item._GetSubList()
        for item in sublist:
            key = item.GetKey()
            # Use existing child or create new TreeNode if none exists
            if self.children.has_key(key):
                child = self.children[key]
            else:
                child = TreeNode(self.canvas, self, item, self.menuList)
                # Update local list of children and keys
                self.children[key] = child
                self.kidKeys.append(key)
            # See if node is child (or one of child's descendants)
            retVal = child.find(searchKey)
            if retVal:
                return retVal
        # Not here
        return None
Esempio n. 16
0
class ListFrame(LabelFrame):
    """
    A Frame representing one of the search term lists
    (e.g. Hashtags, Excluded Users).

    Displays all the items in the list,
    and allows the user to add or remove items.
    Methods should not be called directly;
    instead they should be bound as event handlers.
    """
    def __init__(self, name, add_handler, remove_handler, master=None):
        """
        Creates a ListFrame with the given name as its title.

        add_handler and remove_handler are functions to be called
        when items are added or removed, and should relay the information
        back to the Searcher (or whatever object actually uses the list).
        """
        LabelFrame.__init__(self, master)
        self['text'] = name
        self.add_handler = add_handler
        self.remove_handler = remove_handler
        self.list = Listbox(self)
        self.list.grid(row=0, columnspan=2)
        # Tkinter does not automatically close the right-click menu for us,
        # so we must close it when the user clicks away from the menu.
        self.list.bind("<Button-1>", lambda event: self.context_menu.unpost())
        self.list.bind("<Button-3>", self.open_menu)
        self.context_menu = Menu(self, tearoff=0)
        self.context_menu.add_command(label="Remove", command=self.remove)
        self.input = Entry(self)
        self.input.bind("<Return>", lambda event: self.add())
        self.input.grid(row=1, columnspan=2)
        self.add_button = Button(self)
        self.add_button['text'] = "Add"
        self.add_button['command'] = self.add
        self.add_button.grid(row=2, column=0, sticky=W + E)
        self.remove_button = Button(self)
        self.remove_button['text'] = "Remove"
        self.remove_button['command'] = self.remove
        self.remove_button.grid(row=2, column=1, sticky=W + E)

    def add(self):
        """
        Add the item in the input line to the list.
        """
        self.list.insert(END, self.input.get())
        self.add_handler(self.input.get())
        self.input.delete(0, END)

    def remove(self):
        """
        Remove the active (highlighted) item from the list.
        """
        deleted = self.list.get(ACTIVE)
        self.list.delete(ACTIVE)
        self.remove_handler(deleted)

    def open_menu(self, event):
        """
        Opens a right-click menu for the selected item.
        Currently the menu only has an option for removing the item.
        """
        index = self.list.index("@" + str(event.x) + "," + str(event.y))
        if index < 0:
            return
        self.context_menu.post(event.x_root, event.y_root)
        self.list.activate(index)
        self.list.selection_clear(0, END)
        self.list.selection_set(ACTIVE)
Esempio n. 17
0
class SyntaxHighlightingText(ScrolledText2):

    # constructor
    def __init__(self, root, change_hook=None, highlighter=None, grammar=None):
        ScrolledText2.__init__(self, root, change_hook)
        # Non-wrapping, no border, undo turned on, max undo 50
        self.text = self  # For the methods taken from IDLE
        self.root = root
        self.change_hook = change_hook
        self.characters = ascii_letters + digits + punctuation
        self.tabwidth = 8  # for IDLE use, must remain 8 until Tk is fixed
        self.indentwidth = 4
        self.indention = 0  # The current indention level
        self.set_tabwidth(self.indentwidth)  # IDLE...
        self.previous_line = "0"

        # create a popup menu
        self.menu = Menu(root, tearoff=0)
        self.menu.add_command(label="Undo", command=self.edit_undo)
        self.menu.add_command(label="Redo", command=self.edit_redo)
        #self.menu.add_command(type="separator")
        self.menu.add_command(label="Cut", command=self.cut)
        self.menu.add_command(label="Copy", command=self.copy)
        self.menu.add_command(label="Paste", command=self.paste)

        self.bind('<KeyRelease>', self.key_release)  # For scanning input
        self.bind('<Return>', self.autoindent)  # Overides default binding
        #self.bind('<Tab>',self.autoindent) # increments self.indention
        #self.bind('<BackSpace>',self.autoindent) # decrements self.indention
        self.bind('<Button-3>', self.popup)  # right mouse button opens popup
        self.bind(
            '<Button-1>', self.recolorCurrentLine
        )  # left mouse can reposition cursor, so recolor (e.g. bracket highlighting necessary)
        self.bind('<Control-Any-KeyPress>', self.ctrl)

        self.grammar = grammar

        self.setHighlighter(highlighter)

    def setHighlighter(self, highlighter):
        if highlighter == None:
            highlighter = Highlighter()
        self.highlighter = highlighter
        # sets up the tags
        for tag, settings in self.highlighter.tags.items():
            self.tag_config(tag, **settings)

    def popup(self, event):
        self.menu.post(event.x_root, event.y_root)

    def get_tabwidth(self):
        # From IDLE
        current = self['tabs'] or 5000
        return int(current)

    def set_tabwidth(self, newtabwidth):
        # From IDLE
        text = self
        if self.get_tabwidth() != newtabwidth:
            pixels = text.tk.call("font", "measure", text["font"],
                                  "-displayof", text.master, "n" * newtabwidth)
            text.configure(tabs=pixels)

    def remove_singleline_tags(self, start, end):
        for tag in self.highlighter.tags.keys():
            if tag[:2] != 'ml':
                self.tag_remove(tag, start, end)

    def get_selection_indices(self):
        # If a selection is defined in the text widget, return (start,
        # end) as Tkinter text indices, otherwise return (None, None)
        try:
            first = self.text.index("sel.first")
            last = self.text.index("sel.last")
            return first, last
        except TclError:
            return None

    # Select all the text in textbox
    def select_all(self):
        self.tag_add(SEL, "1.0", END)
        self.mark_set(INSERT, END)
        self.see(INSERT)
        self.focus_set()
        return 'break'

    def cut(self, event=0):
        self.clipboard_clear()
        Selection = self.get_selection_indices()
        if Selection is not None:
            SelectedText = self.get(Selection[0], Selection[1])
            self.delete(Selection[0], Selection[1])
            self.clipboard_append(SelectedText)
            self.onChange()

    def copy(self, event=0):
        self.clipboard_clear()
        Selection = self.get_selection_indices()
        if Selection is not None:
            SelectedText = self.get(Selection[0], Selection[1])
            self.clipboard_append(SelectedText)

    def paste(self, event=0):
        # This should call colorize for the pasted lines.
        SelectedText = self.root.selection_get(selection='CLIPBOARD')
        Selection = self.get_selection_indices()
        if Selection is not None:
            self.delete(Selection[0], Selection[1])
        self.insert(INSERT, SelectedText)
        self.onChange()
        return "break"

    def autoindent(self, event):
        if event.keysym == 'Return':
            self.edit_separator()  # For undo/redo
            index = self.index(INSERT).split('.')
            #print index
            line = int(index[0])
            column = int(index[1])
            if self.get('%s.%d' % (line, column - 1)) == ':':
                self.indention += 1
            #print '\n',
            #print '\t'*self.indention
            self.insert(INSERT, '\n')
            self.insert(INSERT, '\t' * self.indention)
            return 'break'  # Overides standard bindings
        elif event.keysym == 'Tab':
            self.edit_separator()
            self.indention += 1
            #print self.indention
        elif event.keysym == 'BackSpace':
            self.edit_separator()
            index = self.index(INSERT).split('.')
            #print index
            line = int(index[0])
            column = int(index[1])
            if self.get('%s.%d' % (line, column - 1)) == '\t':
                self.indention -= 1

    def recolorCurrentLine(self, *foo):
        pos = self.index(INSERT)
        cline = pos.split('.')[0]
        #print "recoloring %s, %s" % (cline, self.previous_line)
        if cline != self.previous_line: self.colorize(self.previous_line)
        self.colorize(cline)
        self.previous_line = cline

    def key_release(self, key):
        #print "pressed", key.keysym, dir(key)
        if key.char in ' :[(]),"\'':
            self.edit_separator()  # For undo/redo
        # recolorize the current line and the previous line (if it's a different one)
        self.recolorCurrentLine()
        # if delete or backspace were pressed, check if a multiline comment has to be removed
        pos = self.index(INSERT)
        if key.keysym in ("BackSpace", "Delete"):
            #print "removal at %s" % pos
            ranges = self.tag_ranges('mlcom')
            i = 0
            while i < len(ranges):
                range = ranges[i:i + 2]
                second_range = (self.index(str(range[0]) + " + 1 char"),
                                self.index(str(range[1]) + " - 1 char"))
                #print pos, range, second_range
                if pos in range or pos in second_range:
                    self.tag_remove('mlcom', range[0], range[1])
                i += 2
        # notify of change if any. masks for the key.state variable
        # 0x0001     Shift.
        # 0x0002     Caps Lock.
        # 0x0004     Control.
        # 0x0008     Left-hand Alt.
        # 0x0010     Num Lock.
        # 0x0080     Right-hand Alt.
        # 0x0100     Mouse button 1.
        # 0x0200     Mouse button 2.
        # 0x0400     Mouse button 3.
        if key.char != '' and not (key.state & 4) or key.keysym in (
                "BackSpace", "Delete"):
            self.onChange()
        else:
            pass
            #print key

    def onChange(self):
        if self.change_hook is not None:
            self.change_hook()

    def delete_current_line(self):
        selection = self.get_selection_indices()
        if selection is None:
            start = int(self.index(INSERT).split('.')[0])
            end = start
        else:
            start = int(selection[0].split('.')[0])
            end = int(selection[1].split('.')[0])
        self.delete('%d.0' % start, '%d.end' % end)
        self.onChange()


#         return 'break'

    def ctrl(self, key):
        if key.keysym == 'c': return self.copy()
        elif key.keysym == 'x': return self.cut()
        elif key.keysym == 'v': return self.paste()
        elif key.keysym == 'a': return self.select_all()
        elif key.keysym == 'd': return self.delete_current_line()
        #pass # apparently now implemented in the control itself
        # edit: yes, but with counterintuitive behavior

    def colorize(self, cline):
        cursorPos = self.index(INSERT)
        buffer = self.get('%s.%d' % (cline, 0), '%s.end' % (cline))

        # remove non-multiline tags
        self.remove_singleline_tags('%s.%d' % (cline, 0), '%s.end' % (cline))

        in_quote = False
        quote_start = 0
        for i in range(len(buffer)):
            here = '%s.%d' % (cline, i)
            # strings
            if buffer[i] in [
                    '"', "'"
            ]:  # Doesn't distinguish between single and double quotes...
                if in_quote:
                    self.tag_add('str', '%s.%d' % (cline, quote_start),
                                 '%s.%d' % (cline, i + 1))
                    in_quote = False
                else:
                    quote_start = i
                    in_quote = True
            if not in_quote:
                # operators
                if False:
                    for op in self.highlighter.operators:
                        if buffer[i:i + len(op)] == op:
                            self.tag_add('op', "%s.%d" % (cline, i),
                                         "%s.%d" % (cline, i + len(op)))
                # comments
                if buffer[i:i + 2] == "//":
                    self.tag_add('com', '%s.%d' % (cline, i),
                                 '%s.end' % (cline))
                # multiline comments
                elif buffer[i:i + 2] == "/*":
                    if not here in self.tag_ranges('mlcom'):
                        end_pos = self.search(
                            "*/", here,
                            forwards=True)  # get the end of the comment
                        if not end_pos:
                            continue
                        if self.search(
                                "/*", here + " + 2 chars", stopindex=end_pos
                        ):  # if there's a nested comment, ignore it (it might just be a nested /* with a */)
                            continue
                        #!!! make sure the area does not contain any "/*", because the "*/" is not the right one otherwise
                        #print "multiline comment from %s to %s" % (here, str(end_pos))
                        self.tag_add('mlcom', here,
                                     str(end_pos) + " + 2 chars")
                elif buffer[i:i + 2] == "*/":
                    end_pos = self.index(here + " + 2 chars")
                    if not end_pos in self.tag_ranges('mlcom'):
                        start_pos = self.search(
                            "/*", here,
                            backwards=True)  # get the beginning of the comment
                        if not start_pos:
                            continue
                        if self.search(
                                "*/", here, stopindex=start_pos, backwards=True
                        ):  # if there's a nested comment, ignore it (it might just be a nested */ without a /*)
                            continue
                        #print "multiline comment from %s to %s" % (start_pos, end_pos)
                        self.tag_add('mlcom', start_pos, end_pos)
                # bracket highlighting
                elif buffer[
                        i] in self.highlighter.open_brackets and here == cursorPos:
                    idxBracketType = self.highlighter.open_brackets.index(
                        buffer[i])
                    openb, closeb = self.highlighter.brackets[idxBracketType]
                    stack = 1
                    for j, c in enumerate(buffer[i + 1:]):
                        if c == openb:
                            stack += 1
                        elif c == closeb:
                            stack -= 1
                            if stack == 0:
                                self.tag_add('bracket_hl', here,
                                             here + " + 1 char")
                                self.tag_add('bracket_hl',
                                             "%s.%d" % (cline, i + 1 + j),
                                             "%s.%d" % (cline, i + 1 + j + 1))
                                break
                elif buffer[
                        i] in self.highlighter.close_brackets and self.index(
                            here + " + 1 char") == cursorPos:
                    idxBracketType = self.highlighter.close_brackets.index(
                        buffer[i])
                    openb, closeb = self.highlighter.brackets[idxBracketType]
                    stack = 1
                    l = list(buffer[:i])
                    l.reverse()
                    for j, c in enumerate(l):
                        if c == closeb:
                            stack += 1
                        elif c == openb:
                            stack -= 1
                            if stack == 0:
                                self.tag_add('bracket_hl', here,
                                             here + " + 1 char")
                                self.tag_add('bracket_hl',
                                             "%s.%d" % (cline, i - 1 - j),
                                             "%s.%d" % (cline, i - 1 - j + 1))
                                break
        # tokens
        start, end = 0, 0
        obj_flag = 0

        # variable and predicate highlighting
        for match in re.finditer('(\\?[a-zA-Z0-9]+|[\w]*[a-zA-Z]\\()', buffer):
            token = match.group(0)
            if self.grammar is not None and self.grammar.isvar(token):
                self.tag_add('var', '%s.%d' % (cline, match.start()),
                             '%s.%d' % (cline, match.end()))
            elif token[-1] == '(':
                self.tag_add('pred', '%s.%d' % (cline, match.start()),
                             '%s.%d' % (cline, match.end() - 1))

        for token in buffer.split(' '):
            end = start + len(token)
            start_index = '%s.%d' % (cline, start)
            end_index = '%s.%d' % (cline, end)
            if obj_flag:
                self.tag_add('obj', start_index, end_index)
                obj_flag = 0
            # keywords
            if token.strip() in self.highlighter.keywords:
                self.tag_add('kw', start_index, end_index)
                if token.strip() in ['def', 'class']:
                    obj_flag = 1
            else:
                # numbers
                try:
                    float(token)
                except ValueError:
                    pass
                else:
                    self.tag_add('number', '%s.%d' % (cline, start),
                                 "%s.%d" % (cline, end))
            start += len(token) + 1

    def insert(self, index, text, *args):
        line = int(self.index(index).split(".")[0])
        Text.insert(self, index, text, *args)
        for i in range(text.count("\n")):
            self.colorize(str(line + i))

    def disable(self, disable):
        Text.config(self, state=DISABLED if disable else NORMAL)
Esempio n. 18
0
class Text(mx.AllMixins, tk.Text):
    def __init__(self, parent, scrollbar=True, **kw):

        parent = mx.get_master(parent)
        self.parent = parent

        frame = Frame(parent)
        frame.pack(fill='both', expand=True)

        # text widget
        if "wrap" not in kw:
            kw["wrap"] = "word"
        tk.Text.__init__(self, frame, **kw)
        #self.pack(side='left', fill='both', expand=True)
        mx.AllMixins.__init__(self, parent)

        # scrollbar
        if scrollbar:
            scrb = Scrollbar(frame, orient='vertical', command=self.yview)
            self.config(yscrollcommand=scrb.set)
            scrb.pack(side='right', fill='y')

        # pop-up menu
        self.popup = Menu(self, tearoff=0)
        self.popup.add_command(label='Cut', command=self._cut)
        self.popup.add_command(label='Copy', command=self._copy)
        self.popup.add_command(label='Paste', command=self._paste)
        self.popup.add_separator()
        self.popup.add_command(label='Select All', command=self._select_all)
        self.popup.add_command(label='Clear All', command=self._clear_all)
        self.bind('<Button-3>', self._show_popup)

        # only allow mouse scroll when mouse inside text
        self.bind("<Leave>", lambda event: self.winfo_toplevel().focus_set(),
                  "+")
        self.bind("<Enter>", lambda event: self.focus_set(), "+")

    def apply_theme(self, theme='standard'):
        '''theme=['standard', 'typewriter', 'terminal']'''

        if theme == 'typewriter':
            '''takes all inserted text and inserts it one char every 100ms'''
            options = {"font": ('Times', 10, 'bold')}
            self.config(options)
            text = self.get('1.0', 'end')
            self.delete('1.0', 'end')
            self.char_index = 0
            self._typewriter([char for char in text])

        elif theme == 'terminal':
            '''blocky insert cursor'''
            options = {'bg': 'black', 'fg': 'white', 'font': ('Courier', 10)}
            self.config(options)
            self.cursor = '1.0'
            self.fg = self.cget('fg')
            self.bg = self.cget('bg')
            self.switch = self.fg
            self.config(insertwidth=0)
            self._blink_cursor()
            self._place_cursor()

        elif theme == 'matrix':
            '''blocky insert cursor'''
            options = {'bg': 'black', 'fg': 'green', 'font': ('Courier', 10)}
            self.config(options)
            self.cursor = '1.0'
            self.fg = self.cget('fg')
            self.bg = self.cget('bg')
            self.switch = self.fg
            self.config(insertwidth=0)
            self._blink_cursor()
            self._place_cursor()

    def highlight_pattern(self,
                          pattern,
                          tag,
                          start="1.0",
                          end="end",
                          regexp=False,
                          nocase=True,
                          exact=True,
                          **kwargs):
        '''Apply the given tag to all text that matches the given pattern

        If 'regexp' is set to True, pattern will be treated as a regular
        expression.

        From: http://stackoverflow.com/questions/3781670/how-to-highlight-text-in-a-tkinter-text-widget
        '''

        if not pattern:
            return 0
        start = self.index(start)
        end = self.index(end)
        self.mark_set("matchStart", start)
        self.mark_set("matchEnd", start)
        self.mark_set("searchLimit", end)

        count = tk.IntVar()
        while True:
            index = self.search(pattern,
                                "matchEnd",
                                "searchLimit",
                                count=count,
                                regexp=regexp,
                                nocase=nocase,
                                exact=exact,
                                **kwargs)
            if index:
                self.mark_set("matchStart", index)
                self.mark_set("matchEnd", "%s+%sc" % (index, count.get()))
                self.tag_add(tag, "matchStart", "matchEnd")
            else:
                break
        return count.get()

    def clear_highlights(self, *tagnames):
        names = tagnames or self.tag_names()
        self.tag_delete(*names)

    def next_pattern(self,
                     pattern,
                     current,
                     regexp=False,
                     nocase=True,
                     exact=True,
                     **kwargs):
        if not pattern:
            return None
        start = self.index(current)
        end = self.index("end")

        count = tk.IntVar()
        index = self.search(pattern,
                            start,
                            end,
                            count=count,
                            regexp=regexp,
                            nocase=nocase,
                            exact=exact,
                            **kwargs)
        if index:
            return index, index + "+%sc" % count.get()
        else:
            return None

    def prev_pattern(self,
                     pattern,
                     current,
                     regexp=False,
                     nocase=True,
                     exact=True,
                     **kwargs):
        if not pattern:
            return None
        start = self.index(current)
        end = self.index("1.0")

        count = tk.IntVar()
        index = self.search(pattern,
                            start,
                            end,
                            count=count,
                            regexp=regexp,
                            nocase=nocase,
                            exact=exact,
                            backwards=True,
                            **kwargs)
        if index:
            return index, index + "-%sc" % count.get()
        else:
            return None

    # MISC INTERNALS

    def _show_popup(self, event):
        '''right-click popup menu'''

        if self.parent.focus_get() != self:
            self.focus_set()

        try:
            self.popup.post(event.x_root, event.y_root)
        finally:
            self.popup.grab_release()

    def _cut(self):

        try:
            selection = self.get(*self.tag_ranges('sel'))
            self.clipboard_clear()
            self.clipboard_append(selection)
            self.delete(*self.tag_ranges('sel'))
        except TypeError:
            pass

    def _copy(self):

        try:
            selection = self.get(*self.tag_ranges('sel'))
            self.clipboard_clear()
            self.clipboard_append(selection)
        except TypeError:
            pass

    def _paste(self):

        self.insert('insert', self.selection_get(selection='CLIPBOARD'))

    def _select_all(self):
        '''selects all text'''

        self.tag_add('sel', '1.0', 'end-1c')

    def _clear_all(self):
        '''erases all text'''

        isok = askokcancel('Clear All',
                           'Erase all text?',
                           parent=self,
                           default='ok')
        if isok:
            self.delete('1.0', 'end')

    def _typewriter(self, text):  # theme: typewriter
        '''after the theme is applied, this method takes all the inserted text
        and types it out one character every 100ms'''

        self.insert('insert', text[self.char_index])
        self.char_index += 1

        if hasattr(self, "typer") and self.char_index == len(text):
            self.after_cancel(self.typer)
        else:
            self.typer = self.after(100, self._typewriter, text)

    def _place_cursor(self):  # theme: terminal
        '''check the position of the cursor against the last known position
        every 15ms and update the cursorblock tag as needed'''

        current_index = self.index('insert')

        if self.cursor != current_index:
            self.cursor = current_index
            self.tag_delete('cursorblock')

            start = self.index('insert')
            end = self.index('insert+1c')

            if start[0] != end[0]:
                self.insert(start, ' ')
                end = self.index('insert')

            self.tag_add('cursorblock', start, end)
            self.mark_set('insert', self.cursor)

        self.after(15, self._place_cursor)

    def _blink_cursor(self):  # theme: terminal
        '''alternate the background color of the cursorblock tagged text
        every 600 milliseconds'''

        if self.switch == self.fg:
            self.switch = self.bg
        else:
            self.switch = self.fg

        self.tag_config('cursorblock', background=self.switch)

        self.after(600, self._blink_cursor)
Esempio n. 19
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 = tkFont.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 = tkFont.Font(family="helvetica", weight="bold", size=self._size.get())
        self._font = tkFont.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.node()["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 1
        elif self.shift():
            return 1
        else:
            if len(self._parser.parses()) > 0:
                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 1
        return 0

    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__).strip(), width=75, font="fixed")
        except:
            ShowText(self._top, "Help: Shift-Reduce Parser Application", (__doc__).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 tkMessageBox 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 = string.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].node().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.node), 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.node()["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.node()["color"] = "black"
            else:
                stackwidget["color"] = "black"
Esempio n. 20
0
class IntegerView(Label, object):
    """This is the frame for displaying Integer with ability to factorize it.
    """
    def __init__(self, parent, integer=Integer(), **kw):
        #kw['state'] = 'disabled'
        kw.setdefault('anchor', 'nw')
        kw.setdefault('relief', 'sunken')

        kw.setdefault('width', 10)
        kw.setdefault('justify', 'left')
        self._var = StringVar()
        Label.__init__(self, parent, textvariable=self._var, **kw)
        self._factorization_enabled = False
        self.integer = integer
        self.bind("<Configure>", self._update_width)

        self._init_menu()

    def _init_menu(self):
        self._menu = Menu(self, tearoff=0)
        self._menu.add_command(label="Copy", command=self._copy)
        self._menu.add_command(label="Copy LaTeX", command=self._copy_latex)

        # right button on Mac and other systems
        button = '2' if tools.IS_MAC else '3'
        self.bind("<Button-{}>".format(button), self._right_click)

    def _right_click(self, event):
        self._menu.post(event.x_root, event.y_root)

    def _copy(self):
        pyperclip.setcb(str(self._integer))

    def _copy_latex(self):
        if self._factorization_enabled:
            cb = self._integer.str_latex()
        else:
            cb = self._integer.str_normal()
        pyperclip.setcb(cb)

    def _update_width(self, event):
        self['wraplength'] = self.winfo_width() - 10

    def _update_integer(self):
        self._var.set(str(self._integer))

    @property
    def integer(self):
        return self._integer

    @integer.setter
    def integer(self, value):
        self._integer = MultiModeStringFormatter.mixin_to(value)
        if self._factorization_enabled:
            self._integer.str_mode = 'verbose'
        self._update_integer()

    def toggle_factorization(self, value):
        self._factorization_enabled = value
        self._integer.str_mode = 'verbose' if value else 'normal'
        self._update_integer()
Esempio n. 21
0
class PopupMenuCreator:
      
  def __init__(self, atom3i ):
    self.master = atom3i.parent
    self.atom3i = atom3i
    self.cb = atom3i.cb
    self.optionsDatabase = atom3i.optionsDatabase
    self.popupLogoPhotoimage = Embedded_Images().getPopupLogo()

    self.popupMenu = None
    self.event = None
    
    
  # --------------------------- Popup Utilities -------------------------------
    
  def initilizePopupMenu( self, event ):
    """ Create a new popup menu """
    if( self.popupMenu ):
        self.popupMenu.unpost()
    self.popupMenu = Menu(self.master , tearoff=0, bg = "white")
    self.event = event
    
  def showPopupMenu( self ):
    """ Display the popup menu """
    if( self.popupMenu ):
      self.popupMenu.post(self.event.x_root, self.event.y_root)
    
  def swapMenu(self, menu ):
    """ 
    This is a fix for a problem that no longer exists :p
    It essentially takes one menu and slaps another one in its place.
    """
    raise Exception, "No one uses this method! But if you see this, maybe not so..." 
    self.popupMenu.unpost()
    self.popupMenu = menu
    self.showPopupMenu()
    
  def popupRemover(self):
    """ Goodbye popup! """
    if( self.popupMenu ):
      self.popupMenu.unpost()
      self.popupMenu = None
      
  
  # ----------------------  Context Sensitive Menus --------------------------    
    
  def NoCursorNoSelectPopup( self,event ):
    """ Popup menu to show when no items under the mouse, and no items selected """

    self.initilizePopupMenu( event )
  
    addLogo( self )
    #.........................
    addSeperator( self )
    #.........................
    addModelAction( self )
    addSelectAll( self )  
    addPaste( self )
    addUndo( self )
    addRedo( self ) 
    #.........................
    addSeperator( self )
    #.........................
    addFileMenu( self )
    addModelMenu( self )
    addTransformationMenu( self )
    addLayoutMenu( self ) 
    addExportMenu( self )
    #.........................
    addSeperator( self )
    #.........................     
    addOpenLastModel( self )
    addOpenLastMetaModel(self)
    addSourcePath( self )
    #.........................
    addSeperator( self )
    #.........................    
    addToggleSmoothMode( self )    
    #.........................
    addSeperator( self )
    #.........................
    addExit( self )
    
    self.showPopupMenu()
    
  def NoCursorMultiSelectPopup(self,event):
    """ Popup menu to show when no items under the mouse, and multiple items selected """
    
    self.initilizePopupMenu( event )
    
    addLogo( self )
    #.........................
    addSeperator( self )
    #.........................
    addLayoutMenu( self )
    addResizeEntity( self )
    addNodeLabelDragToggle( self )
    #.........................
    addSeperator( self )
    #.........................
    addSelectAll( self )
    addDeselectAll( self )
    #.........................
    addSeperator( self )
    #.........................
    addCut( self )
    addCopy( self )
    addPaste( self )
    #.........................
    addSeperator( self )
    #.........................
    addUndo( self )
    addRedo( self ) 
    #.........................
    addSeperator( self )
    #.........................
    addClear( self )
        
    self.showPopupMenu()
    
  def EntityAtCursorMultiSelectPopup(self,event):
    """ 
    A graphical entity is under the mouse cursor, along with multiple
    selected items
    """
    
    self.initilizePopupMenu( event )
    
    addLogo( self )
    #.........................
    addSeperator( self )
    #.........................
    addLayoutMenu( self )
    addEditEntity( self )
    addDragOverlap( self )
    addDrawArrow( self )  
    addResizeEntity( self )  
    addNodeLabelDragToggle( self )
    #.........................
    addSeperator( self )
    #.........................
    addSelectAll( self )
    addDeselectAll( self )
    #.........................
    addSeperator( self )
    #.........................
    addCut( self )
    addCopy( self )
    addPaste( self )
    #.........................
    addSeperator( self )
    #.........................
    addCopyAttributes( self )
    addPasteAttributes( self )
    #.........................
    addSeperator( self )
    #.........................
    addUndo( self )
    addRedo( self ) 
    #.........................
    addSeperator( self )
    #.........................
    addClear( self )
   
    
    self.showPopupMenu()

  def EntityAtCursorNoSelectPopup(self,event):
    """ A graphical entity is under the mouse cursor, but no selected items """
    
    self.initilizePopupMenu( event )
    
    addLogo( self )
    #.........................
    addSeperator( self )
    #.........................
    addEditEntity( self )
    addDragOverlap( self )
    addDrawArrow( self )
    addResizeEntity( self ) 
    #.........................
    addSeperator( self )
    #.........................
    addSelectAll( self )
    addPaste( self )
    #.........................
    addSeperator( self )
    #.........................
    addCopyAttributes( self )
    addPasteAttributes( self )
    #.........................
    addSeperator( self )
    #.........................
    addUndo( self )
    addRedo( self ) 
    
    self.showPopupMenu()
        
    
  def LinkAtCursorMultiSelectPopup(self,event):
    """ 
    A graphical link/connection is under the mouse cursor, along with multiple
    selected items
    """
    
    self.initilizePopupMenu( event )
    
    addLogo( self )
    #.........................
    addSeperator( self )
    #.........................
    addLayoutMenu( self )
    addEditEntity( self )
    addDragOverlap( self )
    addArrowEditor( self )
    addResizeEntity( self ) 
    addNodeLabelDragToggle( self )
    #.........................
    addSeperator( self )
    #.........................
    addSmoothSelected( self )
    addToggleSmoothMode( self )
    #.........................
    addSeperator( self )
    #.........................
    addSelectAll( self )
    addDeselectAll( self ) 
    #.........................
    addSeperator( self )
    #.........................
    addCut( self )
    addCopy( self )
    addPaste( self )
    #.........................
    addSeperator( self )
    #.........................
    addCopyAttributes( self )
    addPasteAttributes( self )
    #.........................
    addSeperator( self )
    #.........................
    addUndo( self )
    addRedo( self ) 
    #.........................
    addSeperator( self )
    #.........................
    addClear( self )
    
    
    self.showPopupMenu()
    
  def LinkAtCursorNoSelectPopup(self,event):
    """ 
    A graphical link/connection is under the mouse cursor, but there are no
    selected items
    """
    
    self.initilizePopupMenu( event )
    
    addLogo( self )
    #.........................
    addSeperator( self )
    #.........................
    addEditEntity( self )
    addDragOverlap( self )
    addArrowEditor( self )
    #.........................
    addSeperator( self )
    #.........................
    addSelectAll( self )
    addToggleSmoothMode( self )
    addPaste( self )
    #.........................
    addSeperator( self )
    #.........................
    addCopyAttributes( self )
    addPasteAttributes( self )
    #.........................
    addSeperator( self )
    #.........................
    addUndo( self )
    addRedo( self ) 
    
    self.showPopupMenu()
    
  def ArrowEditorPopup(self,event):
    """ Menu for the arrow editor """
    self.initilizePopupMenu( event )
    
    addLogo( self )
    #.........................
    addSeperator( self )
    #.........................
    addEditEntity( self )    
    addInsertPoint( self )
    addDeletePoint( self )
    addSmoothSelected( self )
    addNodeLabelMoveToggle( self )
    #.........................
    addSeperator( self )
    #.........................
    addArrowEditorExit( self )
    
    self.showPopupMenu()
    
  # ----------------------- Popup a specific submenu -------------------------
    
  def LayoutPopup(self,event):
    self.initilizePopupMenu( event )
    self.popupMenu = self.atom3i.layoutMenu
    self.showPopupMenu()
    
  def ExportPopup(self,event):
    self.initilizePopupMenu( event )
    self.popupMenu = self.atom3i.exportMenu
    self.showPopupMenu()
    
  def ModelPopup(self,event):
    self.initilizePopupMenu( event )
    self.popupMenu = self.atom3i.modelMenu
    self.showPopupMenu()
        
  def TransformationPopup(self,event):
    self.initilizePopupMenu( event )
    self.popupMenu = self.atom3i.transMenu
    self.showPopupMenu()
    
  def FilePopup(self,event):
    self.initilizePopupMenu( event )
    self.popupMenu = self.atom3i.filemenu
    self.showPopupMenu()
    
  def LastModelPopup(self,event):
    self.initilizePopupMenu( event )
    addOpenLastModelSubroutine( self, self.popupMenu )
    self.showPopupMenu()
     
  def LastMetaModelPopup(self,event):
    self.initilizePopupMenu( event )
    addOpenLastMetaModelSubroutine( self, self.popupMenu )
    self.showPopupMenu()
    
  def SourcePathPopup(self,event):
    self.initilizePopupMenu( event )
    addSourcePathSubroutine( self, self.popupMenu )
    self.showPopupMenu()
         
    
  # ------------------------ String List to PopupMenu ---------------------------------    
    
  def listChoicePopup(self, title, stringList, unused = None ):
    """ 
    Creates a popup menu with radiobuttons labeled from the stringList.
    Returns the index of the label that was chosen.
    NOTE: choosing outside the popup implicitly chooses index 0
    """
        
    # Remove any existing popups first
    self.popupRemover()
    
    self.popupMenu = Menu(self.master , tearoff=0)
    integerVar = IntVar()
    
    self.popupMenu.add_command( label=title, command=self.popupRemover )
    self.popupMenu.add_separator() 
    
    i = 1
    for label in stringList:
      self.popupMenu.add_radiobutton( label=label, variable=integerVar,
                                      value=i,indicatoron=False )                                               
      i += 1
      
    # This gets the last known co-ordinates of the mouse :D
    # NOTE: We get co-ordinates in terms of canvas space, convert back into
    # screenspace first before using them...
    x,y = self.atom3i.cb.getLastClickCoord()
    dc = self.atom3i.cb.getCanvas()
    x,y = [x-dc.canvasx(0),y-dc.canvasy(0)]

    # These offsets place the menu just where I like it...
    x = int(x) +40 #+ 100
    y = int(y) +40 #+ 20
        
    # Posts the menu, and blocks program execution here on win32 only
    self.popupMenu.post( x,y  )
    
    # Blocks program execution (all platforms) & waits for integerVar to be updated
    # Not ideal: If we close the popup without selecting anything this will
    # wait forever and execution will never get anywhere beyond this point!!!
    # Moreover: AToM3 will not shutdown properly!
    #self.master.wait_variable( integerVar )
    
    # THEORY: This will work whether or not the post() blocks or not
    # Practice: Works great on WinXP with Python 2.3
    #           Linux?
    while( 1 ):
      self.master.update()
      value = integerVar.get() 
 
      # Hapiness, we got the value we wanted
      if( value > 0 ):  return value
      
      # The user killed the popup! O_O
      elif( self.popupMenu == None ):  return 0
      
      # Unhapiness, the user avoided selecting anything
      elif( value == 0 ): 
        self.popupMenu.unpost()
        self.popupMenu.post( x,y  )
        self.master.update()
      
      time.sleep( 0.4 )
      
    return 0 # We won't get here, but just in case...
  
  def listChoicePopupAlternative(self, title, stringList, actionLabel ):
      """ OBSOLETE --- Delete this """
      
      raise Exception, "No one uses this method! But if you see this, maybe not so..."
          
      """
      optionList = [OptionDialog.BOOL_BUTTON_ENTRY,actionLabel]
      
      options = dict()
      optionOrder = list()
      for i in range(0,len(stringList)):
          options[i] = [False,optionList,stringList[i],'']
          optionOrder.append(i)
          i+=1
          
      dialog = OptionDialog(self.master, title, options,optionOrder, grab = False,
                            position = self.atom3i.cb.getLastClickCoordInRootCoords() )
    
      if( dialog.isCanceled() ):
        return 0
      
      options = dialog.getOptionsDatabase()
      i = 1
      for option in optionOrder:
        if( options[option][0] ):
          return i
        i += 1 
      return 0
      """
          
      
      
Esempio n. 22
0
class ApexList(Listbox):
    def __init__(self, parent, apex=None, **kw):
        if apex is None:
            apex = []
        kw.setdefault('selectmode', 'extended')
        Listbox.__init__(self, parent, **kw)
        self.set_apex(apex)
        self.bind("<Return>",
            lambda event: self.expand_selected())

        self._init_menu()

        self._right_click = None


    def _init_menu(self):
        self._menu = Menu(self, tearoff=0)
        self._menu.add_command(label="Copy", command=self._copy_selected)
        self._menu.add_command(label="Copy LaTeX",
            command=self._copy_selected_latex)
        self._menu.add_command(label="Copy all", command=self._copy_all)
        self._menu.add_command(label="Copy all LaTeX",
            command=self._copy_all_latex)
        self._menu.add_command(label="Expand", command=self.expand_selected)

        # right button on Mac and other systems
        button = '2' if tools.IS_MAC else '3'
        self.bind("<Button-{}>".format(button), self._right_click)

    def _right_click(self, event):
        self._right_click = event.x, event.y
        clicked_index = self.nearest(event.y)
        if not self.selection_includes(clicked_index):
            self.selection_clear(0, 'end')
            self.selection_set(clicked_index)
        self._menu.post(event.x_root, event.y_root)

    def _copy_selected(self):
        pyperclip.setcb(", ".join(map(self.get, self.curselection())))

    def _copy_selected_latex(self):
        def elem_latex(index):
            e = self._apex[index]
            if e.mode == StringViewFormatter.NORMAL:
                return e.str_normal()
            return e.str_latex()

        pyperclip.setcb(", ".join(map(elem_latex, self.curselection())))

    def _copy_all(self):
        pyperclip.setcb(", ".join(map(str, self._apex)))

    def _copy_all_latex(self):
        def elem_latex(e):
            if e.mode == StringViewFormatter.NORMAL:
                return e.str_normal()
            return e.str_latex()

        pyperclip.setcb(", ".join(map(elem_latex, self._apex)))

    def curselection(self):
        """Return list of indices of currently selected items."""
        return [int(index) for index in Listbox.curselection(self)]

    def _update_text(self, index):
        self.delete(index)
        self.insert(index, self._apex[index])

    def reprint(self):
        """Updates list elements' text
        """
        for i in xrange(len(self._apex)):
            self._update_text(i)

    def expand(self, indices=None):
        """Sets elements with specified indices to show verbose view
        """
        prev_selection = self.curselection()
        for index in indices:
            self._apex[index].mode = StringViewFormatter.MIXED
            self._update_text(index)
        for index in prev_selection:
            self.selection_set(index)

    def expand_all(self):
        self.expand(range(len(self._apex)))

    def expand_selected(self):
        self.expand(self.curselection())

    def reset(self):
        """Resets every element back to plain integer view
        """
        for index in range(len(self._apex)):
            self._apex[index].mode = StringViewFormatter.NORMAL
            self._update_text(index)

    def set_apex(self, apex):
        """Sets apex shown in this list
        """

        def transform_number(number):
            if type(number) in (SpectraElement, Integer):
                return StringViewFormatter(number)
            return StringViewFormatter(Integer(number))

        self._apex = [transform_number(number) for number in apex]
        self._apex.sort(key=lambda e: e.object, reverse=True)
        self.delete(0, "END")
        self.insert(0, *self._apex)
Esempio n. 23
0
class IntegerView(Label):
    """This is the frame for displaying Integer with ability to factorize it.
    """

    def __init__(self, parent, integer=Integer(), **kw):
        #kw['state'] = 'disabled'
        kw.setdefault('anchor', 'nw')
        kw.setdefault('relief', 'sunken')

        kw.setdefault('width', 10)
        kw.setdefault('justify', 'left')
        self._var = StringVar()
        Label.__init__(self, parent, textvariable=self._var, **kw)
        self._integer_view = StringViewFormatter(integer)
        self._update_integer()
        self._factorization_enabled = False
        self.bind("<Configure>", self._update_width)

        self._init_menu()

    def _init_menu(self):
        self._menu = Menu(self, tearoff=0)
        self._menu.add_command(label="Copy", command=self._copy)
        self._menu.add_command(label="Copy LaTeX", command=self._copy_latex)

        # right button on Mac and other systems
        button = '2' if tools.IS_MAC else '3'
        self.bind("<Button-{}>".format(button), self._right_click)

    def _right_click(self, event):
        self._menu.post(event.x_root, event.y_root)

    def _copy(self):
        pyperclip.setcb(str(self._integer_view))

    def _copy_latex(self):
        if self._factorization_enabled:
            cb = self._integer_view.str_latex()
        else:
            cb = self._integer_view.str_normal()
        pyperclip.setcb(cb)


    def _update_width(self, event):
        self['wraplength'] = self.winfo_width() - 10

    def _update_integer(self):
        self._var.set(self._integer_view)

    @property
    def integer(self):
        return self._integer_view.object

    @integer.setter
    def integer(self, value):
        self._integer_view = StringViewFormatter(value)
        if self._factorization_enabled:
            self._integer_view.mode = StringViewFormatter.VERBOSE
        self._update_integer()

    def toggle_factorization(self, value):
        self._factorization_enabled = value
        if value:
            self._integer_view.mode = StringViewFormatter.VERBOSE
        else:
            self._integer_view.mode = StringViewFormatter.NORMAL
        self._update_integer()
Esempio n. 24
0
 def _handle_r_click(self, event):
     p_menu = Menu(self._parent)
     p_menu.add_command(label="Add Texture", command=lambda: self._add_new_texture())
     p_menu.add_command(label="Delete Texture", command=lambda: self._remove_texture())
     p_menu.add_command(label="Delete All", command=lambda: self.remove_all())
     p_menu.post(event.x_root, event.y_root)
Esempio n. 25
0
class ApexList(Listbox):
    def __init__(self, parent, apex=None, **kw):
        if apex is None:
            apex = []
        kw.setdefault('selectmode', 'extended')
        Listbox.__init__(self, parent, **kw)
        self.set_apex(apex)
        self.bind("<Return>", lambda event: self.expand_selected())

        self._init_menu()

        self._right_click = None

    def _init_menu(self):
        self._menu = Menu(self, tearoff=0)
        self._menu.add_command(label="Copy", command=self._copy_selected)
        self._menu.add_command(label="Copy LaTeX",
                               command=self._copy_selected_latex)
        self._menu.add_command(label="Expand", command=self.expand_selected)

        # right button on Mac and other systems
        button = '2' if tools.IS_MAC else '3'
        self.bind("<Button-{}>".format(button), self._right_click)

    def _right_click(self, event):
        self._right_click = event.x, event.y
        clicked_index = self.nearest(event.y)
        if not self.selection_includes(clicked_index):
            self.selection_clear(0, 'end')
            self.selection_set(clicked_index)
        self._menu.post(event.x_root, event.y_root)

    def _copy_selected(self):
        pyperclip.setcb(", ".join(map(self.get, self.curselection())))

    def _copy_selected_latex(self):
        def elem_latex(index):
            e = self._apex[index]
            if e.str_mode == 'normal':
                return e.str_normal()
            return e.str_latex()

        pyperclip.setcb(", ".join(map(elem_latex, self.curselection())))

    def curselection(self):
        """Return list of indices of currently selected items."""
        return [int(index) for index in Listbox.curselection(self)]

    def select_by_divisor(self, divisor=None):
        """Selects and entries divisible by 'divisor'."""
        self.selection_clear(0, 'end')
        if divisor:
            for index, number in enumerate(self._apex):
                if number % divisor == 0:
                    self.selection_set(index)

    def _update_text(self, index):
        self.delete(index)
        self.insert(index, self._apex[index])

    def reprint(self):
        """Updates list elements' text
        """
        for i in xrange(len(self._apex)):
            self._update_text(i)

    def expand(self, indices=None):
        """Sets elements with specified indices to show verbose view
        """
        prev_selection = self.curselection()
        for index in indices:
            self._apex[index].str_mode = 'mixed'
            self._update_text(index)
        for index in prev_selection:
            self.selection_set(index)

    def expand_all(self):
        self.expand(range(len(self._apex)))

    def expand_selected(self):
        self.expand(self.curselection())

    def reset(self):
        """Resets every element back to plain integer view
        """
        for index in range(len(self._apex)):
            self._apex[index].str_mode = 'normal'
            self._update_text(index)

    def set_apex(self, apex):
        """Sets apex shown in this list
        """
        def transform_number(number):
            if type(number) not in (SpectraElement, Integer):
                number = Integer(number)
            return MultiModeStringFormatter.mixin_to(number)

        self._apex = [transform_number(number) for number in apex]
        self._apex.sort(reverse=True)
        self.delete(0, "END")
        self.insert(0, *self._apex)
Esempio n. 26
0
class ListFrame(LabelFrame):
    """
    A Frame representing one of the search term lists
    (e.g. Hashtags, Excluded Users).

    Displays all the items in the list,
    and allows the user to add or remove items.
    Methods should not be called directly;
    instead they should be bound as event handlers.
    """

    def __init__(self, name, add_handler, remove_handler, master=None):
        """
        Creates a ListFrame with the given name as its title.

        add_handler and remove_handler are functions to be called
        when items are added or removed, and should relay the information
        back to the Searcher (or whatever object actually uses the list).
        """
        LabelFrame.__init__(self, master)
        self['text'] = name
        self.add_handler = add_handler
        self.remove_handler = remove_handler
        self.list = Listbox(self)
        self.list.grid(row=0, columnspan=2)
        # Tkinter does not automatically close the right-click menu for us,
        # so we must close it when the user clicks away from the menu.
        self.list.bind("<Button-1>", lambda event: self.context_menu.unpost())
        self.list.bind("<Button-3>", self.open_menu)
        self.context_menu = Menu(self, tearoff=0)
        self.context_menu.add_command(label="Remove", command=self.remove)
        self.input = Entry(self)
        self.input.bind("<Return>", lambda event: self.add())
        self.input.grid(row=1, columnspan=2)
        self.add_button = Button(self)
        self.add_button['text'] = "Add"
        self.add_button['command'] = self.add
        self.add_button.grid(row=2, column=0, sticky=W+E)
        self.remove_button = Button(self)
        self.remove_button['text'] = "Remove"
        self.remove_button['command'] = self.remove
        self.remove_button.grid(row=2, column=1, sticky=W+E)

    def add(self):
        """
        Add the item in the input line to the list.
        """
        self.list.insert(END, self.input.get())
        self.add_handler(self.input.get())
        self.input.delete(0, END)

    def remove(self):
        """
        Remove the active (highlighted) item from the list.
        """
        deleted = self.list.get(ACTIVE)
        self.list.delete(ACTIVE)
        self.remove_handler(deleted)

    def open_menu(self, event):
        """
        Opens a right-click menu for the selected item.
        Currently the menu only has an option for removing the item.
        """
        index = self.list.index("@" + str(event.x) + "," + str(event.y))
        if index < 0:
            return
        self.context_menu.post(event.x_root, event.y_root)
        self.list.activate(index)
        self.list.selection_clear(0, END)
        self.list.selection_set(ACTIVE)