Esempio n. 1
0
 def setlayout(self, layout):
     if self.viewer and getattr(self.viewer.graphlayout, 'key',
                                True) is not None:
         self.viewers_history.append(self.viewer)
         del self.forward_viewers_history[:]
     self.layout = layout
     self.viewer = GraphRenderer(self.screen, layout)
     self.searchpos = 0
     self.searchresults = []
     self.zoom_to_fit()
Esempio n. 2
0
 def setlayout(self, layout):
     if self.viewer and getattr(self.viewer.graphlayout, 'key', True) is not None:
         self.viewers_history.append(self.viewer)
         del self.forward_viewers_history[:]
     self.layout = layout
     self.viewer = GraphRenderer(self.screen, layout)
     self.searchpos = 0
     self.searchresults = []
     self.zoom_to_fit()
Esempio n. 3
0
class GraphDisplay(Display):
    if "droidsansmono" in pygame.font.get_fonts():
        STATUSBARFONT = pygame.font.match_font("droidsansmono")
    else:
        STATUSBARFONT = pygame.font.get_default_font()
    ANIM_STEP = 0.03
    KEY_REPEAT = (500, 30)
    STATUSBAR_ALPHA = 0.75
    STATUSBAR_FGCOLOR = (255, 255, 80)
    STATUSBAR_BGCOLOR = (128, 0, 0)
    STATUSBAR_OVERFLOWCOLOR = (255, 0, 0)
    HELP_ALPHA = 0.95
    HELP_FGCOLOR = (255, 255, 80)
    HELP_BGCOLOR = (0, 128, 0)
    INPUT_ALPHA = 0.75
    INPUT_FGCOLOR = (255, 255, 80)
    INPUT_BGCOLOR = (0, 0, 128)

    KEYS = {
        'meta -': ('zoom', 0.5),
        '-': ('zoom', 0.5),
        'meta plus': ('zoom', 2.0),
        'plus': ('zoom', 2.0),
        'meta 0': 'zoom_actual_size',
        '0': 'zoom_actual_size',
        'meta 1': 'zoom_to_fit',
        '1': 'zoom_to_fit',
        'meta f4': 'quit',
        'meta quit': 'quit',
        'quit': 'quit',
        'meta right': 'layout_forward',
        'meta left': 'layout_back',
        'backspace': 'layout_back',
        'f': 'search',
        '/': 'search',
        'n': 'find_next',
        'p': 'find_prev',
        'r': 'reload',
        'left': ('pan', (-1, 0)),
        'right': ('pan', (1, 0)),
        'up': ('pan', (0, -1)),
        'down': ('pan', (0, 1)),
        'shift left': ('fast_pan', (-1, 0)),
        'shift right': ('fast_pan', (1, 0)),
        'shift up': ('fast_pan', (0, -1)),
        'shift down': ('fast_pan', (0, 1)),
        'help': 'help',
        'space': 'hit',
        "w": "toggle_whitespace",
        "a": "toggle_ast",
    }

    HELP_MSG = """
    Key bindings:

        +, = or .       Zoom in
        -               Zoom out
        1               Zoom to fit
        0               Actual size

        Arrows          Scroll
        Shift+Arrows    Scroll faster

        Space           Follow word link

        Backspace       Go back in history
        Meta Left       Go back in history
        Meta Right      Go forward in history
        R               Reload the page
        W               Toggle whitespace nodes
        A               Toggle AST/Parsetree

        F or /          Search for text
        N               Find next occurrence
        P               Find previous occurrence

        F1, H or ?      This help message

        Q or Esc        Quit

    Mouse bindings:

        Click on objects to move around
        Drag with the left mouse button to scroll
        Drag with the right mouse button to zoom in/out
        Use scroll wheel do scroll up or down
    """.replace('\n    ', '\n').strip()  # poor man's dedent

    def __init__(self, layout):
        super(GraphDisplay, self).__init__()
        self.font = pygame.font.Font(self.STATUSBARFONT, 16)
        self.viewers_history = []
        self.forward_viewers_history = []
        self.highlight_word = None
        self.highlight_obj = None
        self.viewer = None
        self.method_cache = {}
        self.key_cache = {}
        self.ascii_key_cache = {}
        self.status_bar_height = 0
        self.searchstr = None
        self.searchpos = 0
        self.searchresults = []
        self.initialize_keys()
        self.setlayout(layout)

    def initialize_keys(self):
        pygame.key.set_repeat(*self.KEY_REPEAT)

        mask = 0

        for strnames, methodname in self.KEYS.iteritems():
            names = strnames.split()
            if not isinstance(methodname, basestring):
                methodname, args = methodname[0], methodname[1:]
            else:
                args = ()
            method = getattr(self, methodname, None)
            if method is None:
                print 'Can not implement key mapping %r, %s.%s does not exist' % (
                    strnames, self.__class__.__name__, methodname)
                continue

            mods = []
            basemod = 0
            keys = []
            for name in names:
                if name in METAKEYS:
                    val = METAKEYS[name]
                    if not isinstance(val, int):
                        mods.append(tuple([METAKEYS[k] for k in val]))
                    else:
                        basemod |= val
                else:
                    val = GET_KEY(name)
                    assert len(keys) == 0
                    if not isinstance(val, (int, basestring)):
                        keys.extend([GET_KEY(k) for k in val])
                    else:
                        keys.append(val)
            assert keys
            for key in keys:
                if isinstance(key, int):
                    for mod in permute_mods(basemod, mods):
                        self.key_cache[(key, mod)] = (method, args)
                        mask |= mod
                else:
                    for mod in permute_mods(basemod, mods):
                        char = key.lower()
                        mod = mod & ~KMOD_SHIFT
                        self.ascii_key_cache[(char, mod)] = (method, args)
                        mask |= mod

        self.key_mask = mask

    def help(self):
        """Show a help window and wait for a key or a mouse press."""
        margin_x = margin_y = 64
        padding_x = padding_y = 8
        fgcolor = self.HELP_FGCOLOR
        bgcolor = self.HELP_BGCOLOR
        helpmsg = self.HELP_MSG
        width = self.width - 2 * margin_x
        height = self.height - 2 * margin_y
        lines = rendertext(helpmsg, self.font, fgcolor, width - 2 * padding_x,
                           height - 2 * padding_y)
        block = pygame.Surface((width, height), SWSURFACE | SRCALPHA)
        block.fill(bgcolor)
        sx = padding_x
        sy = padding_y
        for img in lines:
            w, h = img.get_size()
            block.blit(img, (sx, sy))
            sy += h
        block.set_alpha(int(255 * self.HELP_ALPHA))
        self.screen.blit(block, (margin_x, margin_y))

        pygame.display.flip()
        while True:
            wait_for_events()
            e = EventQueue.pop(0)
            if e.type in (MOUSEBUTTONDOWN, KEYDOWN, QUIT):
                break
        if e.type == QUIT:
            EventQueue.insert(0, e)  # re-insert a QUIT
        self.must_redraw = True

    def input(self, prompt):
        """Ask the user to input something.

        Returns the string that the user entered, or None if the user pressed
        Esc.
        """
        def draw(text):
            margin_x = margin_y = 0
            padding_x = padding_y = 8
            fgcolor = self.INPUT_FGCOLOR
            bgcolor = self.INPUT_BGCOLOR
            width = self.width - 2 * margin_x
            lines = renderline(text, self.font, fgcolor, width - 2 * padding_x)
            height = totalheight(lines) + 2 * padding_y
            block = pygame.Surface((width, height), SWSURFACE | SRCALPHA)
            block.fill(bgcolor)
            sx = padding_x
            sy = padding_y
            for img in lines:
                w, h = img.get_size()
                block.blit(img, (sx, sy))
                sy += h
            block.set_alpha(int(255 * self.INPUT_ALPHA))
            # This can be slow.  It would be better to take a screenshot
            # and use it as the background.
            self.viewer.render()
            if self.statusbarinfo:
                self.drawstatusbar()
            self.screen.blit(block, (margin_x, margin_y))
            pygame.display.flip()

        draw(prompt)
        text = ""
        self.must_redraw = True
        while True:
            wait_for_events()
            old_text = text
            events = EventQueue[:]
            del EventQueue[:]
            for e in events:
                if e.type == QUIT:
                    EventQueue.insert(0, e)  # re-insert a QUIT
                    return None
                elif e.type == KEYDOWN:
                    if e.key == K_ESCAPE:
                        return None
                    elif e.key == K_RETURN:
                        return forcestr(text)  # return encoded unicode
                    elif e.key == K_BACKSPACE:
                        text = text[:-1]
                    elif e.unicode and ord(e.unicode) >= ord(' '):
                        text += e.unicode
            if text != old_text:
                draw(prompt + text)

    def hit(self):
        word = self.highlight_word
        if word is not None:
            if word in self.layout.links:
                self.setstatusbar('loading...')
                self.redraw_now()
                self.layout.request_followlink(word)

    def search(self):
        searchstr = self.input('Find: ')
        if not searchstr:
            return
        self.searchstr = searchstr
        self.searchpos = -1
        self.searchresults = list(self.viewer.findall(self.searchstr))
        self.find_next()

    def find_next(self):
        if not self.searchstr:
            return
        if self.searchpos + 1 >= len(self.searchresults):
            self.setstatusbar('Not found: %s' % self.searchstr)
            return
        self.searchpos += 1
        self.highlight_found_item()

    def find_prev(self):
        if not self.searchstr:
            return
        if self.searchpos - 1 < 0:
            self.setstatusbar('Not found: %s' % self.searchstr)
            return
        self.searchpos -= 1
        self.highlight_found_item()

    def highlight_found_item(self):
        item = self.searchresults[self.searchpos]
        self.sethighlight(obj=item)
        msg = 'Found %%s containing %s (%d/%d)' % (self.searchstr.replace(
            '%', '%%'), self.searchpos + 1, len(self.searchresults))
        if isinstance(item, Node):
            self.setstatusbar(msg % 'node')
            self.look_at_node(item, keep_highlight=True)
        elif isinstance(item, Edge):
            self.setstatusbar(msg % 'edge')
            self.look_at_edge(item, keep_highlight=True)
        else:
            # should never happen
            self.setstatusbar(msg % item)

    def setlayout(self, layout):
        if self.viewer and getattr(self.viewer.graphlayout, 'key',
                                   True) is not None:
            self.viewers_history.append(self.viewer)
            del self.forward_viewers_history[:]
        self.layout = layout
        self.viewer = GraphRenderer(self.screen, layout)
        self.searchpos = 0
        self.searchresults = []
        self.zoom_to_fit()

    def zoom_actual_size(self):
        self.viewer.shiftscale(float(self.viewer.SCALEMAX) / self.viewer.scale)
        self.updated_viewer()

    def calculate_zoom_to_fit(self):
        return min(
            float(self.width) / self.viewer.width,
            float(self.height) / self.viewer.height,
            float(self.viewer.SCALEMAX) / self.viewer.scale)

    def zoom_to_fit(self):
        """
        center and scale to view the whole graph
        """

        f = self.calculate_zoom_to_fit()
        self.viewer.shiftscale(f)
        self.updated_viewer()

    def zoom(self, scale):
        self.viewer.shiftscale(max(scale, self.calculate_zoom_to_fit()))
        self.updated_viewer()

    def reoffset(self):
        self.viewer.reoffset(self.width, self.height)

    def pan(self, (x, y)):
        self.viewer.shiftoffset(x * (self.width // 8), y * (self.height // 8))
        self.updated_viewer()
Esempio n. 4
0
class GraphDisplay(Display):
    STATUSBARFONT = FIXEDFONT
    ANIM_STEP = 0.03
    KEY_REPEAT = (500, 30)
    STATUSBAR_ALPHA = 0.75
    STATUSBAR_FGCOLOR = (255, 255, 80)
    STATUSBAR_BGCOLOR = (128, 0, 0)
    STATUSBAR_OVERFLOWCOLOR = (255, 0, 0)
    HELP_ALPHA = 0.95
    HELP_FGCOLOR = (255, 255, 80)
    HELP_BGCOLOR = (0, 128, 0)
    INPUT_ALPHA = 0.75
    INPUT_FGCOLOR = (255, 255, 80)
    INPUT_BGCOLOR = (0, 0, 128)

    KEYS = {
        'meta -' : ('zoom', 0.5),
             '-' : ('zoom', 0.5),
        'meta plus' : ('zoom', 2.0),
             'plus' : ('zoom', 2.0),
        'meta 0' : 'zoom_actual_size',
             '0' : 'zoom_actual_size',
        'meta 1' : 'zoom_to_fit',
             '1' : 'zoom_to_fit',
        'meta f4' : 'quit',
        'meta quit' : 'quit',
             'quit' : 'quit',
        'meta right' : 'layout_forward',
        'meta left': 'layout_back',
        'backspace' : 'layout_back',
        'f': 'search',
        '/': 'search',
        'n': 'find_next',
        'p': 'find_prev',
        'r': 'reload',
        'left' : ('pan', (-1, 0)),
        'right' : ('pan', (1, 0)),
        'up' : ('pan', (0, -1)),
        'down' : ('pan', (0, 1)),
        'shift left' : ('fast_pan', (-1, 0)),
        'shift right' : ('fast_pan', (1, 0)),
        'shift up' : ('fast_pan', (0, -1)),
        'shift down' : ('fast_pan', (0, 1)),
        'help': 'help',
        'space': 'hit',
    }

    HELP_MSG = """
    Key bindings:

        +, = or .       Zoom in
        -               Zoom out
        1               Zoom to fit
        0               Actual size

        Arrows          Scroll
        Shift+Arrows    Scroll faster

        Space           Follow word link

        Backspace       Go back in history
        Meta Left       Go back in history
        Meta Right      Go forward in history
        R               Reload the page

        F or /          Search for text
        N               Find next occurrence
        P               Find previous occurrence

        F1, H or ?      This help message

        Q or Esc        Quit

    Mouse bindings:

        Click on objects to move around
        Drag with the left mouse button to zoom in/out
        Drag with the right mouse button to scroll
    """.replace('\n    ', '\n').strip()  # poor man's dedent


    def __init__(self, layout):
        super(GraphDisplay, self).__init__()
        self.font = pygame.font.Font(self.STATUSBARFONT, 16)
        self.viewers_history = []
        self.forward_viewers_history = []
        self.highlight_word = None
        self.highlight_obj = None
        self.viewer = None
        self.method_cache = {}
        self.key_cache = {}
        self.ascii_key_cache = {}
        self.status_bar_height = 0
        self.searchstr = None
        self.searchpos = 0
        self.searchresults = []
        self.initialize_keys()
        self.setlayout(layout)

    def initialize_keys(self):
        pygame.key.set_repeat(*self.KEY_REPEAT)
        
        mask = 0

        for strnames, methodname in self.KEYS.iteritems():
            names = strnames.split()
            if not isinstance(methodname, basestring):
                methodname, args = methodname[0], methodname[1:]
            else:
                args = ()
            method = getattr(self, methodname, None)
            if method is None:
                print 'Can not implement key mapping %r, %s.%s does not exist' % (
                        strnames, self.__class__.__name__, methodname)
                continue

            mods = []
            basemod = 0
            keys = []
            for name in names:
                if name in METAKEYS:
                    val = METAKEYS[name]
                    if not isinstance(val, int):
                        mods.append(tuple([METAKEYS[k] for k in val]))
                    else:
                        basemod |= val
                else:
                    val = GET_KEY(name)
                    assert len(keys) == 0
                    if not isinstance(val, (int, basestring)):
                        keys.extend([GET_KEY(k) for k in val])
                    else:
                        keys.append(val)
            assert keys
            for key in keys:
                if isinstance(key, int):
                    for mod in permute_mods(basemod, mods):
                        self.key_cache[(key, mod)] = (method, args)
                        mask |= mod
                else:
                    for mod in permute_mods(basemod, mods):
                        char = key.lower()
                        mod = mod & ~KMOD_SHIFT
                        self.ascii_key_cache[(char, mod)] = (method, args)
                        mask |= mod
            
        self.key_mask = mask

    def help(self):
        """Show a help window and wait for a key or a mouse press."""
        margin_x = margin_y = 64
        padding_x = padding_y = 8
        fgcolor = self.HELP_FGCOLOR
        bgcolor = self.HELP_BGCOLOR
        helpmsg = self.HELP_MSG
        width = self.width - 2*margin_x
        height = self.height - 2*margin_y
        lines = rendertext(helpmsg, self.font, fgcolor, width - 2*padding_x,
                           height - 2*padding_y)
        block = pygame.Surface((width, height), SWSURFACE | SRCALPHA)
        block.fill(bgcolor)
        sx = padding_x
        sy = padding_y
        for img in lines:
            w, h = img.get_size()
            block.blit(img, (sx, sy))
            sy += h
        block.set_alpha(int(255 * self.HELP_ALPHA))
        self.screen.blit(block, (margin_x, margin_y))

        pygame.display.flip()
        while True:
            wait_for_events()
            e = EventQueue.pop(0)
            if e.type in (MOUSEBUTTONDOWN, KEYDOWN, QUIT):
                break
        if e.type == QUIT:
            EventQueue.insert(0, e)   # re-insert a QUIT
        self.must_redraw = True

    def input(self, prompt):
        """Ask the user to input something.

        Returns the string that the user entered, or None if the user pressed
        Esc.
        """

        def draw(text):
            margin_x = margin_y = 0
            padding_x = padding_y = 8
            fgcolor = self.INPUT_FGCOLOR
            bgcolor = self.INPUT_BGCOLOR
            width = self.width - 2*margin_x
            lines = renderline(text, self.font, fgcolor, width - 2*padding_x)
            height = totalheight(lines) + 2 * padding_y
            block = pygame.Surface((width, height), SWSURFACE | SRCALPHA)
            block.fill(bgcolor)
            sx = padding_x
            sy = padding_y
            for img in lines:
                w, h = img.get_size()
                block.blit(img, (sx, sy))
                sy += h
            block.set_alpha(int(255 * self.INPUT_ALPHA))
            # This can be slow.  It would be better to take a screenshot
            # and use it as the background.
            self.viewer.render()
            if self.statusbarinfo:
                self.drawstatusbar()
            self.screen.blit(block, (margin_x, margin_y))
            pygame.display.flip()

        draw(prompt)
        text = ""
        self.must_redraw = True
        while True:
            wait_for_events()
            old_text = text
            events = EventQueue[:]
            del EventQueue[:]
            for e in events:
                if e.type == QUIT:
                    EventQueue.insert(0, e)   # re-insert a QUIT
                    return None
                elif e.type == KEYDOWN:
                    if e.key == K_ESCAPE:
                        return None
                    elif e.key == K_RETURN:
                        return text.encode('latin-1')   # XXX do better
                    elif e.key == K_BACKSPACE:
                        text = text[:-1]
                    elif e.unicode and ord(e.unicode) >= ord(' '):
                        text += e.unicode
            if text != old_text:
                draw(prompt + text)

    def hit(self):
        word = self.highlight_word
        if word is not None:
            if word in self.layout.links:
                self.setstatusbar('loading...')
                self.redraw_now()
                self.layout.request_followlink(word)


    def search(self):
        searchstr = self.input('Find: ')
        if not searchstr:
            return
        self.searchstr = searchstr
        self.searchpos = -1
        self.searchresults = list(self.viewer.findall(self.searchstr))
        self.find_next()

    def find_next(self):
        if not self.searchstr:
            return
        if self.searchpos + 1 >= len(self.searchresults):
            self.setstatusbar('Not found: %s' % self.searchstr)
            return
        self.searchpos += 1
        self.highlight_found_item()

    def find_prev(self):
        if not self.searchstr:
            return
        if self.searchpos - 1 < 0:
            self.setstatusbar('Not found: %s' % self.searchstr)
            return
        self.searchpos -= 1
        self.highlight_found_item()

    def highlight_found_item(self):
        item = self.searchresults[self.searchpos]
        self.sethighlight(obj=item)
        msg = 'Found %%s containing %s (%d/%d)' % (
                        self.searchstr.replace('%', '%%'),
                        self.searchpos+1, len(self.searchresults))
        if isinstance(item, Node):
            self.setstatusbar(msg % 'node')
            self.look_at_node(item, keep_highlight=True)
        elif isinstance(item, Edge):
            self.setstatusbar(msg % 'edge')
            self.look_at_edge(item, keep_highlight=True)
        else:
            # should never happen
            self.setstatusbar(msg % item)

    def setlayout(self, layout):
        if self.viewer and getattr(self.viewer.graphlayout, 'key', True) is not None:
            self.viewers_history.append(self.viewer)
            del self.forward_viewers_history[:]
        self.layout = layout
        self.viewer = GraphRenderer(self.screen, layout)
        self.searchpos = 0
        self.searchresults = []
        self.zoom_to_fit()

    def zoom_actual_size(self):
        self.viewer.shiftscale(float(self.viewer.SCALEMAX) / self.viewer.scale)
        self.updated_viewer()

    def calculate_zoom_to_fit(self):
        return min(float(self.width) / self.viewer.width,
                float(self.height) / self.viewer.height,
                float(self.viewer.SCALEMAX) / self.viewer.scale)
    
    def zoom_to_fit(self):
        """
        center and scale to view the whole graph
        """

        f = self.calculate_zoom_to_fit()
        self.viewer.shiftscale(f)
        self.updated_viewer()

    def zoom(self, scale):
        self.viewer.shiftscale(max(scale, self.calculate_zoom_to_fit()))
        self.updated_viewer()

    def reoffset(self):
        self.viewer.reoffset(self.width, self.height)
    
    def pan(self, (x, y)):
        self.viewer.shiftoffset(x * (self.width // 8), y * (self.height // 8))
        self.updated_viewer()