[Urwid] scrolling

James Mills prologic at shortcircuit.net.au
Wed Jun 28 05:25:13 EDT 2006


Hi,

How does one accomplish scrolling ?

See attached source.

On line 60, once this has been filled with as many rows
of the urwid.Text widget as can fit on the screen, I no longer
see any new ones.

Obviously what I'm after here is some kind of scroll-back-type
widget that only shows the newest x rows of text.

Thanks,

cheers
James

PS: If anyone wants to improve upon what I've done (it's only
an example), please send me patches. You'll need my PyMills
library (http://trac.shortcircuit.net.au/projects/pymills/)

svn co
svn://svn.shortcircuit.net.au/projects/pymills/branches/pymills-ng
pymills

-- 
--
-"Problems are Solved by Method"
-
- James Mills <prologic at shortcircuit.net.au>
- HomePage: http://shortcircuit.net.au/~prologic/
- Phone: +61732166379
- Mobile: +61404270962
- Skype: therealprologic
- MSN: prologic at shortcircuit.net.au
- ICQ: 98888663
- IRC: irc://shortcircuit.net.au#se

Please avoid sending me Word or PowerPoint attachments.
See http://www.gnu.org/philosophy/no-word-attachments.html
-------------- next part --------------
#!/usr/bin/env python

import re
import os
import sys
import urwid
import socket
from inspect import getargspec
from urwid.curses_display import Screen

from pymills.irc import *
from pymills.event import *
from pymills.misc import backMerge
from pymills.sockets import TCPClient

MAIN_TITLE = "PyMills IRC Client"

HELP_STRINGS = {
"main": "For help, type: /help"
}

class TestClient(TCPClient, IRC):

	def __init__(self, event):
		TCPClient.__init__(self)
		IRC.__init__(self)

	def ircRAW(self, data):
		self.write(data + "\r\n")
	
	@listener("read")
	def onREAD(self, line):
		TCPClient.onREAD(self, line)
		IRC.onREAD(self, line)
	
class MainWindow(Screen, Component):

	def __init__(self, event, client):
		Screen.__init__(self)
		Component.__init__(self)

		self.event = event
		self.client = client
		self.channel = None

		self.client.setNick(
				os.getenv("USER", "PyMills"))
		self.client.setIdent(
				os.getenv("USER", "PyMills"))

		self.cmdRegex = re.compile(
				"\/(?P<command>[a-z]+) ?"
				"(?P<args>.*)(?iu)")

		self.register_palette([
				("title", "white", "dark blue", "standout"),
				("line", "light gray", "black"),
				("help", "white", "dark blue")])

		self.lines = [urwid.Text("")]
		self.body = urwid.Filler(
				urwid.Pile(self.lines),
				valign="top")

		self.title = urwid.Text(MAIN_TITLE)
		self.header = urwid.AttrWrap(self.title, "title")

		self.help = urwid.AttrWrap(
				urwid.Text(
					HELP_STRINGS["main"]), "help")
		self.input = urwid.Edit(caption="%s> " % self.channel)
		self.footer = urwid.Pile([self.help, self.input])

		self.top = urwid.Frame(self.body, self.header,
				self.footer)

	def main(self):
		self.run_wrapper(self.run)

	def unknownCommand(self, command):
		self.lines.append(
				urwid.Text(
					"Unknown command: %s" % command))
	
	def syntaxError(self, command, args, expected):
		self.lines.append(
				urwid.Text(
					"Syntax error (%s): %s Expected: %s" % (
						command, args, expected)))

	def process(self, s):

		match = self.cmdRegex.match(s)
		if match is not None:

			command = match.groupdict()["command"]
			if not match.groupdict()["args"] == "":
				tokens = match.groupdict()["args"].split(" ")
			else:
				tokens = []

			fn = "cmd" + command.upper()
			if hasattr(self, fn):
				f = getattr(self, fn)
				if callable(f):

					args, vargs, kwargs, default = getargspec(f)
					args.remove("self")
					if len(args) == len(tokens):
						if len(args) == 0:
							f()
						else:
							f(*tokens)
					else:
						if len(tokens) > len(args):
							if vargs is None:
								if len(args) > 0:
									factor = len(tokens) - len(args) + 1
									f(*backMerge(tokens, factor))
								else:
									print "1"
									self.syntaxError(command,
											" ".join(tokens),
											" ".join(
												[x for x in args + [vargs]
													if x is not None]))
							else:
								f(*tokens)
						elif default is not None and \
								len(args) == (
										len(tokens) + len(default)):
							f(*(tokens + list(default)))
						else:
							self.syntaxError(command,
									" ".join(tokens),
									" ".join(
										[x for x in args + [vargs]
											if x is not None]))
			else:
				if self.channel is not None:
					self.client.ircPRIVMSG(channel, s)
				else:
					self.unknownCommand(command)

	@filter("numeric")
	def onNUMERIC(self, source, target, numeric, arg, message):

		if numeric == ERR_NICKNAMEINUSE:
			self.client.ircNICK(
					self.client.getNick() + "_")
		else:
			if arg is not None:
				self.lines.append(urwid.Text(
					"%s :%s" % (arg, message)))
			else:
				self.lines.append(urwid.Text(message))

		return True, None
	
	@filter("notice")
	def onNOTICE(self, source, target, message):
		self.lines.append(urwid.Text(
				"-%s- %s" % (source, message)))
		return True, None

	@filter("privmsg")
	def onPRIVMSG(self, source, target, message):
		self.lines.append(urwid.Text(
				"<%s> %s" % (source, message)))
		return True, None
	
	def cmdEXIT(self, message=""):
		self.cmdQUIT(message)
		self.done = True

	def cmdSERVER(self, host, port=6667):
		self.client.open(host, port)
		self.client.ircUSER(
				self.client.getIdent(),
				socket.gethostname(),
				host,
				"PyMills Example IRC Client")
		self.client.ircNICK(self.client.getNick())

	def cmdJOIN(self, channel):
		if self.channel is not None:
			self.cmdPART(channel, "Joining %s" % channel)

		self.client.ircJOIN(channel)
		self.channel = channel
	
	def cmdPART(self, channel=None, message="Leaving"):
		if channel is None:
			channel = self.channel
		if channel is not None:
			self.client.ircPART(channel, message)
			self.channel = None
		
	def cmdQUOTE(self, message):
		self.client.ircRAW(message)

	def cmdQUIT(self, message="Bye"):
		self.client.ircQUIT(message)

	def run(self):

		size = self.get_cols_rows()

		self.done = False
		while not self.done:

			self.update_screen(size)

			keys = self.get_input()

			for k in keys:

				if k == "window resize":
					size = self.get_cols_rows()
					continue
				elif k == "enter":
					self.process(self.input.get_edit_text())
					self.input.set_edit_text("")
					continue

				self.top.keypress(size, k)
				self.input.set_edit_text(
						self.input.get_edit_text() + k)

			if self.client.connected:
				self.client.process()
			self.event.flush()

	def update_screen(self, size):
		canvas = self.top.render(size, focus=True)
		self.draw_screen(size, canvas)
	
def main():
	event = EventManager()
	client = TestClient(event)
	MainWindow(event, client).main()

if __name__ == "__main__":
	main()


More information about the Urwid mailing list