[Nym3-commit] r150 - trunk/nym3/Client
jr at komite.net
jr at komite.net
Sun Jan 2 00:19:38 CET 2005
Author: jr
Date: 2005-01-02 00:19:37 +0100 (Sun, 02 Jan 2005)
New Revision: 150
Modified:
trunk/nym3/Client/testcurses.py
Log:
- added a pager mode to view messages (supports resize, lines break,
moves in the message, moves between message)
- changed the behaviour of the tagprefix : only lasts for one command
- display of the tag flags
Modified: trunk/nym3/Client/testcurses.py
===================================================================
--- trunk/nym3/Client/testcurses.py 2004-12-29 12:04:07 UTC (rev 149)
+++ trunk/nym3/Client/testcurses.py 2005-01-01 23:19:37 UTC (rev 150)
@@ -78,7 +78,7 @@
"""Display the requested synopsis"""
# TODO : this needs a PAGER view.
self.synlist[self.ctx.index]['read_status'] = 'read'
- pass
+ return self.synlist[self.ctx.index]['synopsis']
def mark_unread(self):
for i in self.ctx.get_targets():
@@ -97,7 +97,8 @@
return ret
def line(self, i):
- """Ugly print current entry as a line"""
+ """Ugly print current entry as a line
+ also returns the index where the tag flag can be inserted"""
# TODO: we need to draw this better.
# Allow the user to specify some kind of format
assert(i < len(self.synlist))
@@ -105,7 +106,9 @@
sfrom, sdate, subject = self.extract(syn, 'From', 'Date', 'Subject')
sfrom = self.format(sfrom, 10)
sdate = self.format(sdate, 20)
- subject = self.format(subject, 20)
+ #the returned line need not to be of fixed length or < than a value
+ #the line is cut when it is displayed
+ #subject = self.format(subject, 20)
if syn['read_status'] == 'unread': flags = 'N'
else: flags = " "
if syn['fetch_status'] == 'fetch': flags += 'F'
@@ -115,10 +118,11 @@
else: flags += ' '
numdigits = int(math.ceil(math.log10(len(self.synlist))))
+ format = "%" + `numdigits` + "d %s %s %s %s"
+ tup = (i + 1, flags, sdate,sfrom, subject)
+ return format % tup, numdigits + 1 + len(flags)
+
- return ("%" + `numdigits` + "d %s %s %s %s") % (i + 1, flags, sdate,
- sfrom, subject)
-
def extract(self, syn, *h):
"""Get most important header of a mail"""
#TODO: this is not RFC2822-compliant
@@ -156,15 +160,182 @@
deleteC.fromData(delete_list)
return str(getC) + str(deleteC)
+class Pager:
+ """ this class takes care of the display of a message in a pager.
+ It does the approptiate display in a provided window"""
+
+ def __init__(self, fscreen, breakcolor):
+ #self.set_win(win)
+ #self.set_msg(message)
+ #self.buffer = curses.newpad(2, self.maxcol)
+ self.color = breakcolor
+ self.win = None
+ self.fscreen = fscreen
+ self.table = None
+
+ def set_win(self, win):
+ if self.win != None:
+ del (self.win)
+ self.win = win
+ if win != None:
+ (self.maxline, self.maxcol) = win.getmaxyx()
+ self.buffer = curses.newpad(2, self.maxcol)
+ if self.table != None:
+ self.parse_message()
+
+ def set_msg(self, msg):
+ self.table = msg.split('\n')
+ self.table = [self.table[i].rstrip() for i in range(len(self.table))]
+ self.line = 0
+ if self.win != None:
+ self.fstchunk = 0
+ self.index = [[] for i in range(len(self.table))]
+ self.parse_message()
+
+ def parse_message(self):
+ for i in range(len(self.table)):
+ self.parse_line(i)
+ #in order to put in self.nextline and self.nextfstchunk the
+ #good values
+ self.display_from_start()
+
+ def parse_line(self, idx):
+ i = 0
+ buf = self.buffer
+ line_string = self.table[idx]
+
+ buf.move(0,0)
+ self.index[idx] = [0]
+ tab = self.index[idx]
+ n = len(line_string)
+ while i < n:
+ buf.addch(ord(line_string[i]))
+ (y, x) = buf.getyx()
+ if y == 0:
+ i = i + 1
+ continue
+ else:
+ if x == 0:
+ #the caracter i fits in the line
+ i = i + 1
+ tab.append(i)
+ #if we are unable to display anything new on a line
+ #we stop to avoid infinite loops
+ if tab[-1] == tab[-2]:
+ break
+ try:
+ buf.move(0,1)
+ except curses.error:
+ tab.append(i)
+ break
+ #at the end, if everything was displayable we add the length of the
+ #line
+ if len(tab) == 1 or (tab[-1] != tab[-2] and tab[-1] != n):
+ tab.append(n)
+
+ def previous_chunk(self, l, k):
+ if k == 0:
+ if l == 0:
+ return (l, k)
+ else:
+ return (l - 1, len (self.index[l - 1]) - 2)
+ else:
+ return (l, k -1)
+
+ def next_chunk(self, l, k):
+ if l == len(self.table):
+ return (l, 0)
+ else:
+ if k == len(self.index[l]) -2:
+ return (l + 1, 0)
+ else:
+ return (l, k + 1)
+
+ def display_from_start(self):
+ idx = self.index[self.line]
+ k = self.fstchunk
+ l = self.line
+ i = 0
+ while i < self.maxline:
+ self.win.move(i, 0)
+ if l == len(self.table):
+ pass
+ else:
+ if k != 0:
+ try:
+ self.win.addch(ord('+'), self.color)
+ except curses.error:
+ pass
+ src = self.table[l][idx[k]: idx[k + 1]]
+ if src != "":
+ try:
+ self.win.addstr(src)
+ except curses.error:
+ pass
+ (l, k) = self.next_chunk(l, k)
+ if l != len(self.table):
+ idx = self.index[l]
+ self.win.clrtoeol()
+ i = i + 1
+ self.nextline = l
+ self.nextfstchunk = k
+ self.fscreen.touchwin()
+
+ def get_start_from_end(self):
+ l = self.line
+ k = self.fstchunk
+ idx = self.index[l]
+ i = self.maxline - 1
+ #at the beginning of the loop i, (l, k) is the first chunk
+ #on line i + 1
+ while i >= 0:
+ if l == 0 and k == 0:
+ break
+ else:
+ (l, k) = self.previous_chunk(l, k)
+ idx = self.index[l]
+ if idx[k] == idx[k + 1]:
+ if i == self.maxline - 1:
+ break
+ else:
+ (l, k) = self.next_chunk(l, k)
+ break
+ i = i - 1
+ self.line = l
+ self.fstchunk = k
+
+ #def on_resize(self, new_win):
+# self.set_win(new_win)
+# self.parse_message()
+
+ def refresh(self):
+ self.win.refresh(0, 0, 1, 0, 1 + self.maxline, self.maxcol)
+
+ def on_page_down(self):
+ if self.win != None and self.nextline != len(self.table):
+ self.line = self.nextline
+ self.fstchunk = self.nextfstchunk
+ self.display_from_start()
+
+ def on_page_up(self):
+ if self.win != None and self.line != 0:
+ self.get_start_from_end()
+ self.display_from_start()
+
class Screen_ctx:
""" this class holds all the information relative to the content and the
way a screen is drawn"""
-
+
+ MODE_MENU = 0
+ MODE_PAGER = 1
+ MODE_HELP = 2
+
def __init__(self, screen, tab):
"""initialize the structure from a screen and a displayable list"""
self.NORMAL = curses.color_pair(0)
self.HIGHLIGHT = curses.color_pair(1)
self.STATUS = curses.color_pair(2)
+ self.BROKENLINE = curses.color_pair(3)
# the screen itself
self.screen = screen
#the table, in fact a class with a method size() and line(i), and
@@ -177,50 +348,93 @@
self.fstpos = 1 #index of the line on the screen where the first
#line of the table is displayed
self.listrange = max (0, self.maxline - 3)
+ self.pager = Pager(screen, self.BROKENLINE)
self.action = {
ord('q') : self.quit,
ord('t') : self.tag,
ord(';') : self.settagprefix,
curses.KEY_DOWN : self.on_K_down,
curses.KEY_UP : self.on_K_up,
- curses.KEY_RESIZE : self.on_resize
+ curses.KEY_RESIZE : self.on_resize,
+ ord('\n') : self.view,
+ ord(' ') : self.view
}
+
+ self.pager_action = {
+ ord('q') : self.pager_quit,
+ curses.KEY_DOWN : self.pager_on_K_down,
+ curses.KEY_UP : self.pager_on_K_up,
+ curses.KEY_RESIZE : self.pager_on_resize,
+ curses.KEY_NPAGE : self.pager_on_K_npage,
+ curses.KEY_PPAGE : self.pager_on_K_ppage
+ }
+ self.mode = Screen_ctx.MODE_MENU
+ self.nd = 0
+
shortcuts = tab.get_actions()
for i in shortcuts.keys():
self.action[i] = shortcuts[i]
- self.tagprefix = None
+ self.tagprefix = False
+ self.tagged = {}
+ self.bufferline= ""
self.draw_picture()
- self.tagged = {}
+
def message(self):
- return "q:Quitter"
+ rl, rc = self.screen.getmaxyx()
+ s = "%d lr: %d mc: %d ml: %d rc: %d rl: %d" % (self.nd, self.listrange,
+ self.maxcol, self.maxline, rc, rl)
+ return s
+ #return "q:Quitter"
def status(self):
return "NymClient"
- def buffer(self):
- return "%d %d %d %d %d" % (self.listrange, self.index, self.maxline,
- self.tab.size(), self.fstindex)
-
+ def buffer(self):
+ if self.bufferline == "":
+ rl, rc = self.screen.getmaxyx()
+ s = "lr: %d mc: %d ml: %d rc: %d rl: %d" % (self.listrange,
+ self.maxcol, self.maxline, rc, rl)
+ if self.pager.win != None:
+ s = s + (" pmc: %d pml: %d" % (self.pager.maxcol,
+ self.pager.maxline))
+ return s
+ else:
+ return self.bufferline
+
+ def draw_menu(self):
+ for i in range(0, self.listrange):
+ if self.fstindex + i < self.tab.size():
+ if (self.fstindex + i == self.index):
+ j = self.HIGHLIGHT
+ else:
+ j = self.NORMAL
+ self.draw_line(self.fstindex + i, self.fstpos + i, j)
+ else:
+ self.draw_empty_line(self.fstpos + i)
+
+
def draw_picture(self):
"""Displays the screen"""
+ self.nd = self.nd + 1
+ self.screen.touchwin()
if self.maxline > 2:
self.draw_string(self.message(), 0, self.STATUS)
if self.maxline == 1:
self.draw_string(self.status(), 0, self.STATUS)
else:
self.draw_string(self.buffer(), self.maxline - 1, self.NORMAL)
+ self.bufferline= ""
self.draw_string(self.status(), self.maxline - 2, self.STATUS)
- for i in range(0, self.listrange):
- if self.fstindex + i < self.tab.size():
- if (self.fstindex + i == self.index):
- j = self.HIGHLIGHT
- else:
- j = self.NORMAL
- self.draw_line(self.fstindex + i, self.fstpos + i, j)
- else:
- self.draw_empty_line(self.fstpos + i)
- self.screen.refresh()
+ if self.mode == Screen_ctx.MODE_MENU:
+ self.draw_menu()
+ elif self.mode == Screen_ctx.MODE_PAGER:
+ pass
+ elif self.mode == Screen_ctx.MODE_HELP:
+ pass
+ self.screen.refresh()
+ if self.mode == Screen_ctx.MODE_PAGER:
+ self.pager.refresh()
def draw_empty_line(self, i):
"""draws an empty line at line i of the screen"""
@@ -231,7 +445,12 @@
"""draws line idx of tab at the line at the position pos on the screen
with color color"""
self.screen.move(pos,0)
- src = self.tab.line(idx)
+ (src, tgidx) = self.tab.line(idx)
+ if self.tagged.has_key(idx):
+ tag = '*'
+ else:
+ tag = ' '
+ src = src[0: tgidx] + tag + src[tgidx:]
self.screen.addstr(src[0: self.maxcol], color)
self.screen.bkgdset(ord(' '), color)
self.screen.clrtoeol()
@@ -239,8 +458,17 @@
def draw_string(self, s, pos, color):
"""draws string s at the position pos with color color"""
+ #if displaying the last character of the last line
+ #the cursor is moved to a line not in the screen
+ #causing an error
+ limit = self.maxcol
+ #if pos == self.maxline - 1:
+ # limit = limit - 1
self.screen.move(pos,0)
- self.screen.addstr(s[0: self.maxcol], color)
+ try:
+ self.screen.addstr(s[0: limit], color)
+ except curses.error:
+ pass
self.screen.bkgdset(ord(' '),color)
self.screen.clrtoeol()
self.screen.bkgdset(ord(' '),self.NORMAL)
@@ -249,13 +477,25 @@
self.active = True
while(self.active):
c = self.screen.getch()
- if self.action.has_key(c):
- self.action[c]()
+ if self.mode == Screen_ctx.MODE_MENU:
+ t = self.tagprefix
+ if self.action.has_key(c):
+ self.action[c]()
+ if t:
+ self.tagprefix = False
+ elif self.mode == Screen_ctx.MODE_PAGER:
+ if self.pager_action.has_key(c):
+ self.pager_action[c]()
self.draw_picture()
def quit(self):
self.active = False
+ def view(self):
+ self.mode = Screen_ctx.MODE_PAGER
+ self.pager_give_win()
+ self.pager.set_msg(self.tab.view())
+
def on_K_down(self):
if self.index < self.tab.size() - 1:
self.index = self.index + 1
@@ -286,12 +526,52 @@
self.tagged[self.index] = True
def settagprefix(self):
- self.tagprefix = True
-
+ if not self.tagprefix:
+ self.tagprefix = True
+ self.bufferline = "tag-"
+
def get_targets(self):
if self.tagprefix and self.tagged: return self.tagged.keys()
else: return [self.index]
+
+ #action in pager mode
+ def pager_quit(self):
+ self.mode = Screen_ctx.MODE_MENU
+ self.pager.set_win(None)
+
+ def pager_on_K_down(self):
+ i = self.index
+ self.on_K_down()
+ if i == self.index:
+ self.pager_quit()
+ else:
+ self.pager.set_msg(self.tab.view())
+ def pager_on_K_up(self):
+ i = self.index
+ self.on_K_up()
+ if i == self.index:
+ self.pager_quit()
+ else:
+ self.pager.set_msg(self.tab.view())
+
+ def pager_on_resize(self):
+ self.on_resize()
+ self.pager_give_win()
+
+ def pager_on_K_npage(self):
+ self.pager.on_page_down()
+
+ def pager_on_K_ppage(self):
+ self.pager.on_page_up()
+
+ def pager_give_win(self):
+ if self.listrange != 0:
+ sub = curses.newpad(self.listrange, self.maxcol)
+ self.pager.set_win(sub)
+ else:
+ self.pager.set_win(None)
+
def func(stdscr):
curses.curs_set(0)
#define here our colors pair
@@ -299,6 +579,9 @@
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_CYAN)
#status bar
curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLUE)
+ #broken line indicator
+ curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLACK)
+ stdscr.scrollok(False)
ctx = Screen_ctx(stdscr, Synbox_tab())
ctx.execute()
More information about the Nym3-commit
mailing list