#!/usr/bin/env python """ item.py - Emano ItemWindow Class Author: Sean B. Palmer, inamidst.com Source: http://inamidst.com/emano/ """ import sys, curses import events, window class ItemWindow(window.Window): def __init__(self, editor): self.editor = editor self.mappings = { events.UP: self.moveUp, events.DOWN: self.moveDown, events.LEFT: self.moveLeft, events.RIGHT: self.moveRight, events.PAGE_UP: self.pageUp, events.PAGE_DOWN: self.pageDown, # events.CTRL_H: self.editor.menu.help, # Ctrl+H events.RETURN: self.select, events.CTRL_C: self.editor.menu.exit, # @@ temporary events.CTRL_W: self.close, events.BACKSPACE: self.backspace, events.DELETE: self.delete } self.startline = 0 self.pos = 0 self.items = [] self.filter = '' # self.reset() def reset(self): self.startline = 0 self.pos = 0 self.items = [] self.filter = '' self.editor.statwin.query('Filter: ') def position(self): y, x = self.editor.screen.getyx() z = y + self.startline return y, x, z def append(self, name, value, default=False): if not isinstance(name, basestring): self.editor.statwin.notice('Error: %r is not a string' % name) return # if not name.startswith(' * '): # was: '* ' # name = ' * ' + name if default is True: self.pos = len(self.items) self.items.append((name, value)) # # @@ might be better to use an incrementer for speed # # self.manifest.append(len(self.items) - 1) def getItems(self): for (name, value) in self.items: if (not self.filter) or (self.filter in name): yield (name, value) def length(self): i = 0 for item in self.getItems(): i += 1 return i def get(self, i): import itertools items = itertools.islice(self.getItems(), i, sys.maxint) try: return items.next() except StopIteration: raise Exception("Asking for: %s of %s" % (i, self.length())) def draw(self, force=False): py, px = self.editor.screen.getyx() if force or ((py > self.editor.maxy) and hasattr(self, 'hicache')): highlight = self.hicache else: highlight = py # if the line has moved, move the focus to it # if the line is off the screen, redraw # if the line has gone, go to the nearest screen line if self.length() < self.editor.maxy: self.startline = 0 import itertools start, finish = self.startline, self.startline + self.editor.maxy + 1 items = itertools.islice(self.getItems(), start, finish) items = list(items) if hasattr(self, 'highlight') and py > self.editor.maxy: for n, item in enumerate(items): if item == self.highlight: highlight = n highlight = min(len(items) - 1, highlight) highlight = max(0, highlight) # if there are no items if len(items) < (finish - self.startline): items += [('', None)] * (finish - self.startline - len(items)) for y, item in enumerate(items): try: line, value = item except: raise ValueError("%s" % item) if y == highlight: self.highlight = (line, value) if len(line) < self.editor.maxx: spaces = ' ' * ((self.editor.maxx - len(line)) + 1) else: spaces, line = '', line[:self.editor.maxx] if (y == highlight) and (py > self.editor.maxy): self.editor.screen.addstr(y, 0, line + spaces, curses.A_REVERSE) elif y == highlight: first, rest = (line + spaces)[:1], (line + spaces)[1:] self.editor.screen.addstr(y, 0, first) self.editor.screen.addstr(y, 1, rest, curses.A_REVERSE) else: self.editor.screen.addstr(y, 0, line + spaces) self.hicache = highlight self.editor.screen.refresh() if py > self.editor.maxy: self.editor.moveCursor(py, px) else: self.editor.moveCursor(highlight, px) def collectFilter(self): # @@ The persistence of line marking stuff in self.draw def updateFilter(text): self.filter = text self.draw() # @@ pass the return? # Change the listeners for (page) up/down in the CommandWindow import copy mappings = copy.copy(self.editor.statwin.mappings) def mk(callback): def collectAndCall(self=self, callback=callback, mappings=mappings): self.editor.statwin.mappings = mappings self.editor.statwin.collectInput() self.draw(force=True) # i.e. self.editor.listwin.draw() callback() return collectAndCall newmappings = { events.UP: self.moveUp, events.DOWN: self.moveDown, events.PAGE_UP: self.pageUp, events.PAGE_DOWN: self.pageDown, events.RETURN: self.select, events.CTRL_W: self.close } for (event, method) in newmappings.iteritems(): self.editor.statwin.mappings[event] = mk(method) self.editor.statwin.returnFocus = self self.editor.statwin.dialogue('Filter: ', updateFilter, stream=True) self.editor.statwin.input = self.filter # @@ move up/down? py, px = self.editor.screen.getyx() self.editor.moveCursor(self.editor.maxy + 1, px + len(self.filter)) self.draw() # to cover up that leading space def insertChar(self, char): self.collectFilter() self.editor.statwin.insertChar(char) def backspace(self): self.collectFilter() self.editor.statwin.deleteChar() def delete(self): self.collectFilter() self.editor.statwin.delChar() def moveLeft(self): self.collectFilter() self.editor.statwin.moveLeft() def moveRight(self): self.collectFilter() self.editor.statwin.moveRight() def pageUp(self): for i in xrange(24): # @@ for now self.moveUp() def pageDown(self): for i in xrange(24): # @@ for now self.moveDown() def moveUp(self): # @@ document this y, x, z = self.position() if y > 0: self.editor.moveCursor(y - 1, x) self.draw() elif self.startline > 0: self.startline -= 1 self.editor.moveCursor(y, x) self.draw() # @@ why? moving off top of screen? def moveDown(self): # @@ document this y, x, z = self.position() if z < (self.length() - 1) and y < self.editor.maxy: self.editor.moveCursor(y + 1, x) self.draw() elif z < (self.length() - 1) and y == self.editor.maxy: self.startline += 1 self.editor.moveCursor(y, x) self.draw() # @@ why? moving off bottom of screen? def select(self): y, x, z = self.position() func, args = self.get(z)[1] if args is None: args = tuple() self.reset() self.editor.setFocus(self.editor.mainwin) self.editor.mainwin.draw() func(*args) def close(self): self.reset() self.editor.setFocus(self.editor.mainwin) self.editor.mainwin.draw() self.editor.statwin.default() def event(self, e): # @@ Are these dependent on term setting? if self.mappings.has_key(e): self.mappings[e]() return True else: return False if __name__=="__main__": main()