Initial revision
This commit is contained in:
parent
df79a1ee19
commit
c636014c43
|
@ -0,0 +1,213 @@
|
|||
# module calendar
|
||||
|
||||
##############################
|
||||
# Calendar support functions #
|
||||
##############################
|
||||
|
||||
# This is based on UNIX ctime() et al. (also Standard C and POSIX)
|
||||
# Subtle but crucial differences:
|
||||
# - the order of the elements of a 'struct tm' differs, to ease sorting
|
||||
# - months numbers are 1-12, not 0-11; month arrays have a dummy element 0
|
||||
# - Monday is the first day of the week (numbered 0)
|
||||
|
||||
# These are really parameters of the 'time' module:
|
||||
epoch = 1970 # Time began on January 1 of this year (00:00:00 UCT)
|
||||
day_0 = 3 # The epoch begins on a Thursday (Monday = 0)
|
||||
|
||||
# Return 1 for leap years, 0 for non-leap years
|
||||
def isleap(year):
|
||||
return year % 4 = 0 and (year % 100 <> 0 or year % 400 = 0)
|
||||
|
||||
# Constants for months referenced later
|
||||
January = 1
|
||||
February = 2
|
||||
|
||||
# Number of days per month (except for February in leap years)
|
||||
mdays = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
|
||||
|
||||
# Exception raised for bad input (with string parameter for details)
|
||||
error = 'calendar error'
|
||||
|
||||
# Turn seconds since epoch into calendar time
|
||||
def gmtime(secs):
|
||||
if secs < 0: raise error, 'negative input to gmtime()'
|
||||
mins, secs = divmod(secs, 60)
|
||||
hours, mins = divmod(mins, 60)
|
||||
days, hours = divmod(hours, 24)
|
||||
wday = (days + day_0) % 7
|
||||
year = epoch
|
||||
# XXX Most of the following loop can be replaced by one division
|
||||
while 1:
|
||||
yd = 365 + isleap(year)
|
||||
if days < yd: break
|
||||
days = days - yd
|
||||
year = year + 1
|
||||
yday = days
|
||||
month = January
|
||||
while 1:
|
||||
md = mdays[month] + (month = February and isleap(year))
|
||||
if days < md: break
|
||||
days = days - md
|
||||
month = month + 1
|
||||
return year, month, days + 1, hours, mins, secs, yday, wday
|
||||
# XXX Week number also?
|
||||
|
||||
# Return number of leap years in range [y1, y2)
|
||||
# Assume y1 <= y2 and no funny (non-leap century) years
|
||||
def leapdays(y1, y2):
|
||||
return (y2+3)/4 - (y1+3)/4
|
||||
|
||||
# Inverse of gmtime():
|
||||
# Turn UCT calendar time (less yday, wday) into seconds since epoch
|
||||
def mktime(year, month, day, hours, mins, secs):
|
||||
days = day - 1
|
||||
for m in range(January, month): days = days + mdays[m]
|
||||
if isleap(year) and month > February: days = days+1
|
||||
days = days + (year-epoch)*365 + leapdays(epoch, year)
|
||||
return ((days*24 + hours)*60 + mins)*60 + secs
|
||||
|
||||
# Full and abbreviated names of weekdays
|
||||
day_name = ('Monday', 'Tuesday', 'Wednesday', 'Thursday')
|
||||
day_name = day_name + ('Friday', 'Saturday', 'Sunday')
|
||||
day_abbr = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun')
|
||||
|
||||
# Full and abbreviated of months (1-based arrays!!!)
|
||||
month_name = ('', 'January', 'February', 'March', 'April')
|
||||
month_name = month_name + ('May', 'June', 'July', 'August')
|
||||
month_name = month_name + ('September', 'October', 'November', 'December')
|
||||
month_abbr = (' ', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun')
|
||||
month_abbr = month_abbr + ('Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
|
||||
|
||||
# Zero-fill string to two positions (helper for asctime())
|
||||
def dd(s):
|
||||
while len(s) < 2: s = '0' + s
|
||||
return s
|
||||
|
||||
# Blank-fill string to two positions (helper for asctime())
|
||||
def zd(s):
|
||||
while len(s) < 2: s = ' ' + s
|
||||
return s
|
||||
|
||||
# Turn calendar time as returned by gmtime() into a string
|
||||
# (the yday parameter is for compatibility with gmtime())
|
||||
def asctime(year, month, day, hours, mins, secs, yday, wday):
|
||||
s = day_abbr[wday] + ' ' + month_abbr[month] + ' ' + zd(`day`)
|
||||
s = s + ' ' + dd(`hours`) + ':' + dd(`mins`) + ':' + dd(`secs`)
|
||||
return s + ' ' + `year`
|
||||
|
||||
# Localization: Minutes West from Greenwich
|
||||
# timezone = -2*60 # Middle-European time with DST on
|
||||
timezone = 5*60 # EST (sigh -- THINK time() doesn't return UCT)
|
||||
|
||||
# Local time ignores DST issues for now -- adjust 'timezone' to fake it
|
||||
def localtime(secs):
|
||||
return gmtime(secs - timezone*60)
|
||||
|
||||
# UNIX-style ctime (except it doesn't append '\n'!)
|
||||
def ctime(secs):
|
||||
return asctime(localtime(secs))
|
||||
|
||||
######################
|
||||
# Non-UNIX additions #
|
||||
######################
|
||||
|
||||
# Calendar printing etc.
|
||||
|
||||
# Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12), day (1-31)
|
||||
def weekday(year, month, day):
|
||||
secs = mktime(year, month, day, 0, 0, 0)
|
||||
days = secs / (24*60*60)
|
||||
return (days + day_0) % 7
|
||||
|
||||
# Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for year, month
|
||||
def monthrange(year, month):
|
||||
day1 = weekday(year, month, 1)
|
||||
ndays = mdays[month] + (month = February and isleap(year))
|
||||
return day1, ndays
|
||||
|
||||
# Return a matrix representing a month's calendar
|
||||
# Each row represents a week; days outside this month are zero
|
||||
def _monthcalendar(year, month):
|
||||
day1, ndays = monthrange(year, month)
|
||||
rows = []
|
||||
r7 = range(7)
|
||||
day = 1 - day1
|
||||
while day <= ndays:
|
||||
row = [0, 0, 0, 0, 0, 0, 0]
|
||||
for i in r7:
|
||||
if 1 <= day <= ndays: row[i] = day
|
||||
day = day + 1
|
||||
rows.append(row)
|
||||
return rows
|
||||
|
||||
# Caching interface to _monthcalendar
|
||||
mc_cache = {}
|
||||
def monthcalendar(year, month):
|
||||
key = `year` + month_abbr[month]
|
||||
try:
|
||||
return mc_cache[key]
|
||||
except RuntimeError:
|
||||
mc_cache[key] = ret = _monthcalendar(year, month)
|
||||
return ret
|
||||
|
||||
# Center a string in a field
|
||||
def center(str, width):
|
||||
n = width - len(str)
|
||||
if n < 0: return str
|
||||
return ' '*(n/2) + str + ' '*(n-n/2)
|
||||
|
||||
# XXX The following code knows that print separates items with space!
|
||||
|
||||
# Print a single week (no newline)
|
||||
def prweek(week, width):
|
||||
for day in week:
|
||||
if day = 0: print ' '*width,
|
||||
else:
|
||||
if width > 2: print ' '*(width-3),
|
||||
if day < 10: print '',
|
||||
print day,
|
||||
|
||||
# Return a header for a week
|
||||
def weekheader(width):
|
||||
str = ''
|
||||
for i in range(7):
|
||||
if str: str = str + ' '
|
||||
str = str + day_abbr[i%7][:width]
|
||||
return str
|
||||
|
||||
# Print a month's calendar
|
||||
def prmonth(year, month):
|
||||
print weekheader(3)
|
||||
for week in monthcalendar(year, month):
|
||||
prweek(week, 3)
|
||||
print
|
||||
|
||||
# Spacing between month columns
|
||||
spacing = ' '
|
||||
|
||||
# 3-column formatting for year calendars
|
||||
def format3c(a, b, c):
|
||||
print center(a, 20), spacing, center(b, 20), spacing, center(c, 20)
|
||||
|
||||
# Print a year's calendar
|
||||
def prcal(year):
|
||||
header = weekheader(2)
|
||||
format3c('', `year`, '')
|
||||
for q in range(January, January+12, 3):
|
||||
print
|
||||
format3c(month_name[q], month_name[q+1], month_name[q+2])
|
||||
format3c(header, header, header)
|
||||
data = []
|
||||
height = 0
|
||||
for month in range(q, q+3):
|
||||
cal = monthcalendar(year, month)
|
||||
if len(cal) > height: height = len(cal)
|
||||
data.append(cal)
|
||||
for i in range(height):
|
||||
for cal in data:
|
||||
if i >= len(cal):
|
||||
print ' '*20,
|
||||
else:
|
||||
prweek(cal[i], 2)
|
||||
print spacing,
|
||||
print
|
|
@ -0,0 +1,61 @@
|
|||
# Module 'cmp'
|
||||
|
||||
# Efficiently compare files, boolean outcome only (equal / not equal).
|
||||
|
||||
# Tricks (used in this order):
|
||||
# - Files with identical type, size & mtime are assumed to be clones
|
||||
# - Files with different type or size cannot be identical
|
||||
# - We keep a cache of outcomes of earlier comparisons
|
||||
# - We don't fork a process to run 'cmp' but read the files ourselves
|
||||
|
||||
import posix
|
||||
|
||||
cache = {}
|
||||
|
||||
def cmp(f1, f2): # Compare two files, use the cache if possible.
|
||||
# Return 1 for identical files, 0 for different.
|
||||
# Raise exceptions if either file could not be statted, read, etc.
|
||||
s1, s2 = sig(posix.stat(f1)), sig(posix.stat(f2))
|
||||
if s1[0] <> 8 or s2[0] <> 8:
|
||||
# Either is a not a plain file -- always report as different
|
||||
return 0
|
||||
if s1 = s2:
|
||||
# type, size & mtime match -- report same
|
||||
return 1
|
||||
if s1[:2] <> s2[:2]: # Types or sizes differ, don't bother
|
||||
# types or sizes differ -- report different
|
||||
return 0
|
||||
# same type and size -- look in the cache
|
||||
key = f1 + ' ' + f2
|
||||
try:
|
||||
cs1, cs2, outcome = cache[key]
|
||||
# cache hit
|
||||
if s1 = cs1 and s2 = cs2:
|
||||
# cached signatures match
|
||||
return outcome
|
||||
# stale cached signature(s)
|
||||
except RuntimeError:
|
||||
# cache miss
|
||||
pass
|
||||
# really compare
|
||||
outcome = do_cmp(f1, f2)
|
||||
cache[key] = s1, s2, outcome
|
||||
return outcome
|
||||
|
||||
def sig(st): # Return signature (i.e., type, size, mtime) from raw stat data
|
||||
# 0-5: st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid
|
||||
# 6-9: st_size, st_atime, st_mtime, st_ctime
|
||||
type = st[0] / 4096
|
||||
size = st[6]
|
||||
mtime = st[8]
|
||||
return type, size, mtime
|
||||
|
||||
def do_cmp(f1, f2): # Compare two files, really
|
||||
bufsize = 8096 # Could be tuned
|
||||
fp1 = open(f1, 'r')
|
||||
fp2 = open(f2, 'r')
|
||||
while 1:
|
||||
b1 = fp1.read(bufsize)
|
||||
b2 = fp2.read(bufsize)
|
||||
if b1 <> b2: return 0
|
||||
if not b1: return 1
|
|
@ -0,0 +1,74 @@
|
|||
# Module 'cmpcache'
|
||||
#
|
||||
# Efficiently compare files, boolean outcome only (equal / not equal).
|
||||
#
|
||||
# Tricks (used in this order):
|
||||
# - Use the statcache module to avoid statting files more than once
|
||||
# - Files with identical type, size & mtime are assumed to be clones
|
||||
# - Files with different type or size cannot be identical
|
||||
# - We keep a cache of outcomes of earlier comparisons
|
||||
# - We don't fork a process to run 'cmp' but read the files ourselves
|
||||
#
|
||||
# XXX There is a dependency on constants in <sys/stat.h> here.
|
||||
|
||||
import posix
|
||||
import statcache
|
||||
|
||||
|
||||
# The cache.
|
||||
#
|
||||
cache = {}
|
||||
|
||||
|
||||
# Compare two files, use the cache if possible.
|
||||
# May raise posix.error if a stat or open of either fails.
|
||||
#
|
||||
def cmp(f1, f2):
|
||||
# Return 1 for identical files, 0 for different.
|
||||
# Raise exceptions if either file could not be statted, read, etc.
|
||||
s1, s2 = sig(statcache.stat(f1)), sig(statcache.stat(f2))
|
||||
if s1[0] <> 8 or s2[0] <> 8: # XXX 8 is S_IFREG in <sys/stat.h>
|
||||
# Either is a not a plain file -- always report as different
|
||||
return 0
|
||||
if s1 = s2:
|
||||
# type, size & mtime match -- report same
|
||||
return 1
|
||||
if s1[:2] <> s2[:2]: # Types or sizes differ, don't bother
|
||||
# types or sizes differ -- report different
|
||||
return 0
|
||||
# same type and size -- look in the cache
|
||||
key = f1 + ' ' + f2
|
||||
if cache.has_key(key):
|
||||
cs1, cs2, outcome = cache[key]
|
||||
# cache hit
|
||||
if s1 = cs1 and s2 = cs2:
|
||||
# cached signatures match
|
||||
return outcome
|
||||
# stale cached signature(s)
|
||||
# really compare
|
||||
outcome = do_cmp(f1, f2)
|
||||
cache[key] = s1, s2, outcome
|
||||
return outcome
|
||||
|
||||
# Return signature (i.e., type, size, mtime) from raw stat data.
|
||||
#
|
||||
def sig(st):
|
||||
# 0-5: st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid
|
||||
# 6-9: st_size, st_atime, st_mtime, st_ctime
|
||||
type = st[0] / 4096 # XXX dependent on S_IFMT in <sys/stat.h>
|
||||
size = st[6]
|
||||
mtime = st[8]
|
||||
return type, size, mtime
|
||||
|
||||
# Compare two files, really.
|
||||
#
|
||||
def do_cmp(f1, f2):
|
||||
#print ' cmp', f1, f2 # XXX remove when debugged
|
||||
bufsize = 8096 # Could be tuned
|
||||
fp1 = open(f1, 'r')
|
||||
fp2 = open(f2, 'r')
|
||||
while 1:
|
||||
b1 = fp1.read(bufsize)
|
||||
b2 = fp2.read(bufsize)
|
||||
if b1 <> b2: return 0
|
||||
if not b1: return 1
|
|
@ -0,0 +1,73 @@
|
|||
# Module 'commands'
|
||||
#
|
||||
# Various tools for executing commands and looking at their output and status.
|
||||
|
||||
import rand
|
||||
import posix
|
||||
import path
|
||||
|
||||
|
||||
# Get 'ls -l' status for an object into a string
|
||||
#
|
||||
def getstatus(file):
|
||||
return getoutput('ls -ld' + mkarg(file))
|
||||
|
||||
|
||||
# Get the output from a shell command into a string.
|
||||
# The exit status is ignored; a trailing newline is stripped.
|
||||
# Assume the command will work with ' >tempfile 2>&1' appended.
|
||||
# XXX This should use posix.popen() instead, should it exist.
|
||||
#
|
||||
def getoutput(cmd):
|
||||
return getstatusoutput(cmd)[1]
|
||||
|
||||
|
||||
# Ditto but preserving the exit status.
|
||||
# Returns a pair (sts, output)
|
||||
#
|
||||
def getstatusoutput(cmd):
|
||||
tmp = '/usr/tmp/wdiff' + `rand.rand()`
|
||||
sts = -1
|
||||
try:
|
||||
sts = posix.system(cmd + ' >' + tmp + ' 2>&1')
|
||||
text = readfile(tmp)
|
||||
finally:
|
||||
altsts = posix.system('rm -f ' + tmp)
|
||||
if text[-1:] = '\n': text = text[:-1]
|
||||
return sts, text
|
||||
|
||||
|
||||
# Return a string containing a file's contents.
|
||||
#
|
||||
def readfile(fn):
|
||||
fp = open(fn, 'r')
|
||||
a = ''
|
||||
n = 8096
|
||||
while 1:
|
||||
b = fp.read(n)
|
||||
if not b: break
|
||||
a = a + b
|
||||
return a
|
||||
|
||||
|
||||
# Make command argument from directory and pathname (prefix space, add quotes).
|
||||
#
|
||||
def mk2arg(head, x):
|
||||
return mkarg(path.cat(head, x))
|
||||
|
||||
|
||||
# Make a shell command argument from a string.
|
||||
# Two strategies: enclose in single quotes if it contains none;
|
||||
# otherwis, enclose in double quotes and prefix quotable characters
|
||||
# with backslash.
|
||||
#
|
||||
def mkarg(x):
|
||||
if '\'' not in x:
|
||||
return ' \'' + x + '\''
|
||||
s = ' "'
|
||||
for c in x:
|
||||
if c in '\\$"':
|
||||
s = s + '\\'
|
||||
s = s + c
|
||||
s = s + '"'
|
||||
return s
|
|
@ -0,0 +1,36 @@
|
|||
# Module 'dircache'
|
||||
#
|
||||
# Return a sorted list of the files in a POSIX directory, using a cache
|
||||
# to avoid reading the directory more often than necessary.
|
||||
# Also contains a subroutine to append slashes to directories.
|
||||
|
||||
import posix
|
||||
import path
|
||||
|
||||
cache = {}
|
||||
|
||||
def listdir(path): # List directory contents, using cache
|
||||
try:
|
||||
cached_mtime, list = cache[path]
|
||||
del cache[path]
|
||||
except RuntimeError:
|
||||
cached_mtime, list = -1, []
|
||||
try:
|
||||
mtime = posix.stat(path)[8]
|
||||
except posix.error:
|
||||
return []
|
||||
if mtime <> cached_mtime:
|
||||
try:
|
||||
list = posix.listdir(path)
|
||||
except posix.error:
|
||||
return []
|
||||
list.sort()
|
||||
cache[path] = mtime, list
|
||||
return list
|
||||
|
||||
opendir = listdir # XXX backward compatibility
|
||||
|
||||
def annotate(head, list): # Add '/' suffixes to directories
|
||||
for i in range(len(list)):
|
||||
if path.isdir(path.cat(head, list[i])):
|
||||
list[i] = list[i] + '/'
|
|
@ -0,0 +1,215 @@
|
|||
# Module 'dirmp'
|
||||
#
|
||||
# Defines a class to build directory diff tools on.
|
||||
|
||||
import posix
|
||||
|
||||
import path
|
||||
|
||||
import dircache
|
||||
import cmpcache
|
||||
import statcache
|
||||
|
||||
|
||||
# File type constants from <sys/stat.h>.
|
||||
#
|
||||
S_IFDIR = 4
|
||||
S_IFREG = 8
|
||||
|
||||
# Extract the file type from a stat buffer.
|
||||
#
|
||||
def S_IFMT(st): return st[0] / 4096
|
||||
|
||||
|
||||
# Directory comparison class.
|
||||
#
|
||||
class dircmp():
|
||||
#
|
||||
def new(dd, (a, b)): # Initialize
|
||||
dd.a = a
|
||||
dd.b = b
|
||||
# Properties that caller may change before callingdd. run():
|
||||
dd.hide = ['.', '..'] # Names never to be shown
|
||||
dd.ignore = ['RCS', 'tags'] # Names ignored in comparison
|
||||
#
|
||||
return dd
|
||||
#
|
||||
def run(dd): # Compare everything except common subdirectories
|
||||
dd.a_list = filter(dircache.listdir(dd.a), dd.hide)
|
||||
dd.b_list = filter(dircache.listdir(dd.b), dd.hide)
|
||||
dd.a_list.sort()
|
||||
dd.b_list.sort()
|
||||
dd.phase1()
|
||||
dd.phase2()
|
||||
dd.phase3()
|
||||
#
|
||||
def phase1(dd): # Compute common names
|
||||
dd.a_only = []
|
||||
dd.common = []
|
||||
for x in dd.a_list:
|
||||
if x in dd.b_list:
|
||||
dd.common.append(x)
|
||||
else:
|
||||
dd.a_only.append(x)
|
||||
#
|
||||
dd.b_only = []
|
||||
for x in dd.b_list:
|
||||
if x not in dd.common:
|
||||
dd.b_only.append(x)
|
||||
#
|
||||
def phase2(dd): # Distinguish files, directories, funnies
|
||||
dd.common_dirs = []
|
||||
dd.common_files = []
|
||||
dd.common_funny = []
|
||||
#
|
||||
for x in dd.common:
|
||||
a_path = path.cat(dd.a, x)
|
||||
b_path = path.cat(dd.b, x)
|
||||
#
|
||||
ok = 1
|
||||
try:
|
||||
a_stat = statcache.stat(a_path)
|
||||
except posix.error, why:
|
||||
# print 'Can\'t stat', a_path, ':', why[1]
|
||||
ok = 0
|
||||
try:
|
||||
b_stat = statcache.stat(b_path)
|
||||
except posix.error, why:
|
||||
# print 'Can\'t stat', b_path, ':', why[1]
|
||||
ok = 0
|
||||
#
|
||||
if ok:
|
||||
a_type = S_IFMT(a_stat)
|
||||
b_type = S_IFMT(b_stat)
|
||||
if a_type <> b_type:
|
||||
dd.common_funny.append(x)
|
||||
elif a_type = S_IFDIR:
|
||||
dd.common_dirs.append(x)
|
||||
elif a_type = S_IFREG:
|
||||
dd.common_files.append(x)
|
||||
else:
|
||||
dd.common_funny.append(x)
|
||||
else:
|
||||
dd.common_funny.append(x)
|
||||
#
|
||||
def phase3(dd): # Find out differences between common files
|
||||
xx = cmpfiles(dd.a, dd.b, dd.common_files)
|
||||
dd.same_files, dd.diff_files, dd.funny_files = xx
|
||||
#
|
||||
def phase4(dd): # Find out differences between common subdirectories
|
||||
# A new dircmp object is created for each common subdirectory,
|
||||
# these are stored in a dictionary indexed by filename.
|
||||
# The hide and ignore properties are inherited from the parent
|
||||
dd.subdirs = {}
|
||||
for x in dd.common_dirs:
|
||||
a_x = path.cat(dd.a, x)
|
||||
b_x = path.cat(dd.b, x)
|
||||
dd.subdirs[x] = newdd = dircmp().new(a_x, b_x)
|
||||
newdd.hide = dd.hide
|
||||
newdd.ignore = dd.ignore
|
||||
newdd.run()
|
||||
#
|
||||
def phase4_closure(dd): # Recursively call phase4() on subdirectories
|
||||
dd.phase4()
|
||||
for x in dd.subdirs.keys():
|
||||
dd.subdirs[x].phase4_closure()
|
||||
#
|
||||
def report(dd): # Print a report on the differences between a and b
|
||||
# Assume that phases 1 to 3 have been executed
|
||||
# Output format is purposely lousy
|
||||
print 'diff', dd.a, dd.b
|
||||
if dd.a_only:
|
||||
print 'Only in', dd.a, ':', dd.a_only
|
||||
if dd.b_only:
|
||||
print 'Only in', dd.b, ':', dd.b_only
|
||||
if dd.same_files:
|
||||
print 'Identical files :', dd.same_files
|
||||
if dd.diff_files:
|
||||
print 'Differing files :', dd.diff_files
|
||||
if dd.funny_files:
|
||||
print 'Trouble with common files :', dd.funny_files
|
||||
if dd.common_dirs:
|
||||
print 'Common subdirectories :', dd.common_dirs
|
||||
if dd.common_funny:
|
||||
print 'Common funny cases :', dd.common_funny
|
||||
#
|
||||
def report_closure(dd): # Print reports on dd and on subdirs
|
||||
# If phase 4 hasn't been done, no subdir reports are printed
|
||||
dd.report()
|
||||
try:
|
||||
x = dd.subdirs
|
||||
except NameError:
|
||||
return # No subdirectories computed
|
||||
for x in dd.subdirs.keys():
|
||||
print
|
||||
dd.subdirs[x].report_closure()
|
||||
#
|
||||
def report_phase4_closure(dd): # Report and do phase 4 recursively
|
||||
dd.report()
|
||||
dd.phase4()
|
||||
for x in dd.subdirs.keys():
|
||||
print
|
||||
dd.subdirs[x].report_phase4_closure()
|
||||
|
||||
|
||||
# Compare common files in two directories.
|
||||
# Return:
|
||||
# - files that compare equal
|
||||
# - files that compare different
|
||||
# - funny cases (can't stat etc.)
|
||||
#
|
||||
def cmpfiles(a, b, common):
|
||||
res = ([], [], [])
|
||||
for x in common:
|
||||
res[cmp(path.cat(a, x), path.cat(b, x))].append(x)
|
||||
return res
|
||||
|
||||
|
||||
# Compare two files.
|
||||
# Return:
|
||||
# 0 for equal
|
||||
# 1 for different
|
||||
# 2 for funny cases (can't stat, etc.)
|
||||
#
|
||||
def cmp(a, b):
|
||||
try:
|
||||
if cmpcache.cmp(a, b): return 0
|
||||
return 1
|
||||
except posix.error:
|
||||
return 2
|
||||
|
||||
|
||||
# Remove a list item.
|
||||
# NB: This modifies the list argument.
|
||||
#
|
||||
def remove(list, item):
|
||||
for i in range(len(list)):
|
||||
if list[i] = item:
|
||||
del list[i]
|
||||
break
|
||||
|
||||
|
||||
# Return a copy with items that occur in skip removed.
|
||||
#
|
||||
def filter(list, skip):
|
||||
result = []
|
||||
for item in list:
|
||||
if item not in skip: result.append(item)
|
||||
return result
|
||||
|
||||
|
||||
# Demonstration and testing.
|
||||
#
|
||||
def demo():
|
||||
import sys
|
||||
import getopt
|
||||
options, args = getopt.getopt(sys.argv[1:], 'r')
|
||||
if len(args) <> 2: raise getopt.error, 'need exactly two args'
|
||||
dd = dircmp().new(args[0], args[1])
|
||||
dd.run()
|
||||
if ('-r', '') in options:
|
||||
dd.report_phase4_closure()
|
||||
else:
|
||||
dd.report()
|
||||
|
||||
# demo()
|
|
@ -0,0 +1,63 @@
|
|||
# Module 'dump'
|
||||
#
|
||||
# Print python code that reconstructs a variable.
|
||||
# This only works in certain cases.
|
||||
#
|
||||
# It works fine for:
|
||||
# - ints and floats (except NaNs and other weird things)
|
||||
# - strings
|
||||
# - compounds and lists, provided it works for all their elements
|
||||
# - imported modules, provided their name is the module name
|
||||
#
|
||||
# It works for top-level dictionaries but not for dictionaries
|
||||
# contained in other objects (could be made to work with some hassle
|
||||
# though).
|
||||
#
|
||||
# It does not work for functions (all sorts), classes, class objects,
|
||||
# windows, files etc.
|
||||
#
|
||||
# Finally, objects referenced by more than one name or contained in more
|
||||
# than one other object lose their sharing property (this is bad for
|
||||
# strings used as exception identifiers, for instance).
|
||||
|
||||
# Dump a whole symbol table
|
||||
#
|
||||
def dumpsymtab(dict):
|
||||
for key in dict.keys():
|
||||
dumpvar(key, dict[key])
|
||||
|
||||
# Dump a single variable
|
||||
#
|
||||
def dumpvar(name, x):
|
||||
import sys
|
||||
t = type(x)
|
||||
if t = type({}):
|
||||
print name, '= {}'
|
||||
for key in x.keys():
|
||||
item = x[key]
|
||||
if not printable(item):
|
||||
print '#',
|
||||
print name, '[', `key`, '] =', `item`
|
||||
elif t in (type(''), type(0), type(0.0), type([]), type(())):
|
||||
if not printable(x):
|
||||
print '#',
|
||||
print name, '=', `x`
|
||||
elif t = type(sys):
|
||||
print 'import', name, '#', x
|
||||
else:
|
||||
print '#', name, '=', x
|
||||
|
||||
# check if a value is printable in a way that can be read back with input()
|
||||
#
|
||||
def printable(x):
|
||||
t = type(x)
|
||||
if t in (type(''), type(0), type(0.0)):
|
||||
return 1
|
||||
if t in (type([]), type(())):
|
||||
for item in x:
|
||||
if not printable(item):
|
||||
return 0
|
||||
return 1
|
||||
if x = {}:
|
||||
return 1
|
||||
return 0
|
|
@ -0,0 +1,47 @@
|
|||
# module getopt -- Standard command line processing.
|
||||
|
||||
# Function getopt.getopt() has a different interface but provides the
|
||||
# same functionality as the Unix getopt() function.
|
||||
|
||||
# It has two arguments: the first should be argv[1:] (it doesn't want
|
||||
# the script name), the second the string of option letters as passed
|
||||
# to Unix getopt() (i.e., a string of allowable option letters, with
|
||||
# options requiring an argument followed by a colon).
|
||||
|
||||
# It raises the exception getopt.error with a string argument if it
|
||||
# detects an error.
|
||||
|
||||
# It returns two items:
|
||||
# (1) a list of pairs (option, option_argument) giving the options in
|
||||
# the order in which they were specified. (I'd use a dictionary
|
||||
# but applications may depend on option order or multiple
|
||||
# occurrences.) Boolean options have '' as option_argument.
|
||||
# (2) the list of remaining arguments (may be empty).
|
||||
|
||||
error = 'getopt error'
|
||||
|
||||
def getopt(args, options):
|
||||
list = []
|
||||
while args and args[0][0] = '-' and args[0] <> '-':
|
||||
if args[0] = '--':
|
||||
args = args[1:]
|
||||
break
|
||||
optstring, args = args[0][1:], args[1:]
|
||||
while optstring <> '':
|
||||
opt, optstring = optstring[0], optstring[1:]
|
||||
if classify(opt, options): # May raise exception as well
|
||||
if optstring = '':
|
||||
if not args:
|
||||
raise error, 'option -' + opt + ' requires argument'
|
||||
optstring, args = args[0], args[1:]
|
||||
optarg, optstring = optstring, ''
|
||||
else:
|
||||
optarg = ''
|
||||
list.append('-' + opt, optarg)
|
||||
return list, args
|
||||
|
||||
def classify(opt, options): # Helper to check type of option
|
||||
for i in range(len(options)):
|
||||
if opt = options[i] <> ':':
|
||||
return options[i+1:i+2] = ':'
|
||||
raise error, 'option -' + opt + ' not recognized'
|
|
@ -0,0 +1,423 @@
|
|||
#/**************************************************************************
|
||||
# * *
|
||||
# * Copyright (C) 1984, Silicon Graphics, Inc. *
|
||||
# * *
|
||||
# * These coded instructions, statements, and computer programs contain *
|
||||
# * unpublished proprietary information of Silicon Graphics, Inc., and *
|
||||
# * are protected by Federal copyright law. They may not be disclosed *
|
||||
# * to third parties or copied or duplicated in any form, in whole or *
|
||||
# * in part, without the prior written consent of Silicon Graphics, Inc. *
|
||||
# * *
|
||||
# **************************************************************************/
|
||||
#/* file with device definitions (see /usr/include/device.h) */
|
||||
|
||||
NULLDEV = 0
|
||||
BUTOFFSET = 1
|
||||
VALOFFSET = 256
|
||||
TIMOFFSET = 515
|
||||
XKBDOFFSET = 143
|
||||
INOFFSET = 1024
|
||||
OUTOFFSET = 1033
|
||||
BUTCOUNT = 190
|
||||
VALCOUNT = 27
|
||||
TIMCOUNT = 4
|
||||
XKBDCOUNT = 28
|
||||
INCOUNT = 8
|
||||
OUTCOUNT = 8
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
BUT0 = 1
|
||||
BUT1 = 2
|
||||
BUT2 = 3
|
||||
BUT3 = 4
|
||||
BUT4 = 5
|
||||
BUT5 = 6
|
||||
BUT6 = 7
|
||||
BUT7 = 8
|
||||
BUT8 = 9
|
||||
BUT9 = 10
|
||||
BUT10 = 11
|
||||
BUT11 = 12
|
||||
BUT12 = 13
|
||||
BUT13 = 14
|
||||
BUT14 = 15
|
||||
BUT15 = 16
|
||||
BUT16 = 17
|
||||
BUT17 = 18
|
||||
BUT18 = 19
|
||||
BUT19 = 20
|
||||
BUT20 = 21
|
||||
BUT21 = 22
|
||||
BUT22 = 23
|
||||
BUT23 = 24
|
||||
BUT24 = 25
|
||||
BUT25 = 26
|
||||
BUT26 = 27
|
||||
BUT27 = 28
|
||||
BUT28 = 29
|
||||
BUT29 = 30
|
||||
BUT30 = 31
|
||||
BUT31 = 32
|
||||
BUT32 = 33
|
||||
BUT33 = 34
|
||||
BUT34 = 35
|
||||
BUT35 = 36
|
||||
BUT36 = 37
|
||||
BUT37 = 38
|
||||
BUT38 = 39
|
||||
BUT39 = 40
|
||||
BUT40 = 41
|
||||
BUT41 = 42
|
||||
BUT42 = 43
|
||||
BUT43 = 44
|
||||
BUT44 = 45
|
||||
BUT45 = 46
|
||||
BUT46 = 47
|
||||
BUT47 = 48
|
||||
BUT48 = 49
|
||||
BUT49 = 50
|
||||
BUT50 = 51
|
||||
BUT51 = 52
|
||||
BUT52 = 53
|
||||
BUT53 = 54
|
||||
BUT54 = 55
|
||||
BUT55 = 56
|
||||
BUT56 = 57
|
||||
BUT57 = 58
|
||||
BUT58 = 59
|
||||
BUT59 = 60
|
||||
BUT60 = 61
|
||||
BUT61 = 62
|
||||
BUT62 = 63
|
||||
BUT63 = 64
|
||||
BUT64 = 65
|
||||
BUT65 = 66
|
||||
BUT66 = 67
|
||||
BUT67 = 68
|
||||
BUT68 = 69
|
||||
BUT69 = 70
|
||||
BUT70 = 71
|
||||
BUT71 = 72
|
||||
BUT72 = 73
|
||||
BUT73 = 74
|
||||
BUT74 = 75
|
||||
BUT75 = 76
|
||||
BUT76 = 77
|
||||
BUT77 = 78
|
||||
BUT78 = 79
|
||||
BUT79 = 80
|
||||
BUT80 = 81
|
||||
BUT81 = 82
|
||||
BUT82 = 83
|
||||
MAXKBDBUT = 83
|
||||
BUT100 = 101
|
||||
BUT101 = 102
|
||||
BUT102 = 103
|
||||
BUT110 = 111
|
||||
BUT111 = 112
|
||||
BUT112 = 113
|
||||
BUT113 = 114
|
||||
BUT114 = 115
|
||||
BUT115 = 116
|
||||
BUT116 = 117
|
||||
BUT117 = 118
|
||||
BUT118 = 119
|
||||
BUT119 = 120
|
||||
BUT120 = 121
|
||||
BUT121 = 122
|
||||
BUT122 = 123
|
||||
BUT123 = 124
|
||||
BUT124 = 125
|
||||
BUT125 = 126
|
||||
BUT126 = 127
|
||||
BUT127 = 128
|
||||
BUT128 = 129
|
||||
BUT129 = 130
|
||||
BUT130 = 131
|
||||
BUT131 = 132
|
||||
BUT132 = 133
|
||||
BUT133 = 134
|
||||
BUT134 = 135
|
||||
BUT135 = 136
|
||||
BUT136 = 137
|
||||
BUT137 = 138
|
||||
BUT138 = 139
|
||||
BUT139 = 140
|
||||
BUT140 = 141
|
||||
BUT141 = 142
|
||||
BUT142 = 143
|
||||
BUT143 = 144
|
||||
BUT144 = 145
|
||||
BUT145 = 146
|
||||
BUT146 = 147
|
||||
BUT147 = 148
|
||||
BUT148 = 149
|
||||
BUT149 = 150
|
||||
BUT150 = 151
|
||||
BUT151 = 152
|
||||
BUT152 = 153
|
||||
BUT153 = 154
|
||||
BUT154 = 155
|
||||
BUT155 = 156
|
||||
BUT156 = 157
|
||||
BUT157 = 158
|
||||
BUT158 = 159
|
||||
BUT159 = 160
|
||||
BUT160 = 161
|
||||
BUT161 = 162
|
||||
BUT162 = 163
|
||||
BUT163 = 164
|
||||
BUT164 = 165
|
||||
BUT165 = 166
|
||||
BUT166 = 167
|
||||
BUT167 = 168
|
||||
BUT168 = 169
|
||||
BUT181 = 182
|
||||
BUT182 = 183
|
||||
BUT183 = 184
|
||||
BUT184 = 185
|
||||
BUT185 = 186
|
||||
BUT186 = 187
|
||||
BUT187 = 188
|
||||
BUT188 = 189
|
||||
BUT189 = 190
|
||||
MOUSE1 = 101
|
||||
MOUSE2 = 102
|
||||
MOUSE3 = 103
|
||||
LEFTMOUSE = 103
|
||||
MIDDLEMOUSE = 102
|
||||
RIGHTMOUSE = 101
|
||||
LPENBUT = 104
|
||||
BPAD0 = 105
|
||||
BPAD1 = 106
|
||||
BPAD2 = 107
|
||||
BPAD3 = 108
|
||||
LPENVALID = 109
|
||||
SWBASE = 111
|
||||
SW0 = 111
|
||||
SW1 = 112
|
||||
SW2 = 113
|
||||
SW3 = 114
|
||||
SW4 = 115
|
||||
SW5 = 116
|
||||
SW6 = 117
|
||||
SW7 = 118
|
||||
SW8 = 119
|
||||
SW9 = 120
|
||||
SW10 = 121
|
||||
SW11 = 122
|
||||
SW12 = 123
|
||||
SW13 = 124
|
||||
SW14 = 125
|
||||
SW15 = 126
|
||||
SW16 = 127
|
||||
SW17 = 128
|
||||
SW18 = 129
|
||||
SW19 = 130
|
||||
SW20 = 131
|
||||
SW21 = 132
|
||||
SW22 = 133
|
||||
SW23 = 134
|
||||
SW24 = 135
|
||||
SW25 = 136
|
||||
SW26 = 137
|
||||
SW27 = 138
|
||||
SW28 = 139
|
||||
SW29 = 140
|
||||
SW30 = 141
|
||||
SW31 = 142
|
||||
SBBASE = 182
|
||||
SBPICK = 182
|
||||
SBBUT1 = 183
|
||||
SBBUT2 = 184
|
||||
SBBUT3 = 185
|
||||
SBBUT4 = 186
|
||||
SBBUT5 = 187
|
||||
SBBUT6 = 188
|
||||
SBBUT7 = 189
|
||||
SBBUT8 = 190
|
||||
AKEY = 11
|
||||
BKEY = 36
|
||||
CKEY = 28
|
||||
DKEY = 18
|
||||
EKEY = 17
|
||||
FKEY = 19
|
||||
GKEY = 26
|
||||
HKEY = 27
|
||||
IKEY = 40
|
||||
JKEY = 34
|
||||
KKEY = 35
|
||||
LKEY = 42
|
||||
MKEY = 44
|
||||
NKEY = 37
|
||||
OKEY = 41
|
||||
PKEY = 48
|
||||
QKEY = 10
|
||||
RKEY = 24
|
||||
SKEY = 12
|
||||
TKEY = 25
|
||||
UKEY = 33
|
||||
VKEY = 29
|
||||
WKEY = 16
|
||||
XKEY = 21
|
||||
YKEY = 32
|
||||
ZKEY = 20
|
||||
ZEROKEY = 46
|
||||
ONEKEY = 8
|
||||
TWOKEY = 14
|
||||
THREEKEY = 15
|
||||
FOURKEY = 22
|
||||
FIVEKEY = 23
|
||||
SIXKEY = 30
|
||||
SEVENKEY = 31
|
||||
EIGHTKEY = 38
|
||||
NINEKEY = 39
|
||||
BREAKKEY = 1
|
||||
SETUPKEY = 2
|
||||
CTRLKEY = 3
|
||||
LEFTCTRLKEY = CTRLKEY
|
||||
CAPSLOCKKEY = 4
|
||||
RIGHTSHIFTKEY = 5
|
||||
LEFTSHIFTKEY = 6
|
||||
NOSCRLKEY = 13
|
||||
ESCKEY = 7
|
||||
TABKEY = 9
|
||||
RETKEY = 51
|
||||
SPACEKEY = 83
|
||||
LINEFEEDKEY = 60
|
||||
BACKSPACEKEY = 61
|
||||
DELKEY = 62
|
||||
SEMICOLONKEY = 43
|
||||
PERIODKEY = 52
|
||||
COMMAKEY = 45
|
||||
QUOTEKEY = 50
|
||||
ACCENTGRAVEKEY = 55
|
||||
MINUSKEY = 47
|
||||
VIRGULEKEY = 53
|
||||
BACKSLASHKEY = 57
|
||||
EQUALKEY = 54
|
||||
LEFTBRACKETKEY = 49
|
||||
RIGHTBRACKETKEY = 56
|
||||
LEFTARROWKEY = 73
|
||||
DOWNARROWKEY = 74
|
||||
RIGHTARROWKEY = 80
|
||||
UPARROWKEY = 81
|
||||
PAD0 = 59
|
||||
PAD1 = 58
|
||||
PAD2 = 64
|
||||
PAD3 = 65
|
||||
PAD4 = 63
|
||||
PAD5 = 69
|
||||
PAD6 = 70
|
||||
PAD7 = 67
|
||||
PAD8 = 68
|
||||
PAD9 = 75
|
||||
PADPF1 = 72
|
||||
PADPF2 = 71
|
||||
PADPF3 = 79
|
||||
PADPF4 = 78
|
||||
PADPERIOD = 66
|
||||
PADMINUS = 76
|
||||
PADCOMMA = 77
|
||||
PADENTER = 82
|
||||
LEFTALTKEY = 143
|
||||
RIGHTALTKEY = 144
|
||||
RIGHTCTRLKEY = 145
|
||||
F1KEY = 146
|
||||
F2KEY = 147
|
||||
F3KEY = 148
|
||||
F4KEY = 149
|
||||
F5KEY = 150
|
||||
F6KEY = 151
|
||||
F7KEY = 152
|
||||
F8KEY = 153
|
||||
F9KEY = 154
|
||||
F10KEY = 155
|
||||
F11KEY = 156
|
||||
F12KEY = 157
|
||||
PRINTSCREENKEY = 158
|
||||
SCROLLLOCKKEY = 159
|
||||
PAUSEKEY = 160
|
||||
INSERTKEY = 161
|
||||
HOMEKEY = 162
|
||||
PAGEUPKEY = 163
|
||||
ENDKEY = 164
|
||||
PAGEDOWNKEY = 165
|
||||
NUMLOCKKEY = 166
|
||||
PADVIRGULEKEY = 167
|
||||
PADASTERKEY = 168
|
||||
PADPLUSKEY = 169
|
||||
SGIRESERVED = 256
|
||||
DIAL0 = 257
|
||||
DIAL1 = 258
|
||||
DIAL2 = 259
|
||||
DIAL3 = 260
|
||||
DIAL4 = 261
|
||||
DIAL5 = 262
|
||||
DIAL6 = 263
|
||||
DIAL7 = 264
|
||||
DIAL8 = 265
|
||||
MOUSEX = 266
|
||||
MOUSEY = 267
|
||||
LPENX = 268
|
||||
LPENY = 269
|
||||
BPADX = 270
|
||||
BPADY = 271
|
||||
CURSORX = 272
|
||||
CURSORY = 273
|
||||
GHOSTX = 274
|
||||
GHOSTY = 275
|
||||
SBTX = 276
|
||||
SBTY = 277
|
||||
SBTZ = 278
|
||||
SBRX = 279
|
||||
SBRY = 280
|
||||
SBRZ = 281
|
||||
SBPERIOD = 282
|
||||
TIMER0 = 515
|
||||
TIMER1 = 516
|
||||
TIMER2 = 517
|
||||
TIMER3 = 518
|
||||
KEYBD = 513
|
||||
RAWKEYBD = 514
|
||||
VALMARK = 523
|
||||
GERROR = 524
|
||||
REDRAW = 528
|
||||
WMSEND = 529
|
||||
WMREPLY = 530
|
||||
WMGFCLOSE = 531
|
||||
WMTXCLOSE = 532
|
||||
MODECHANGE = 533
|
||||
INPUTCHANGE = 534
|
||||
QFULL = 535
|
||||
PIECECHANGE = 536
|
||||
WINCLOSE = 537
|
||||
QREADERROR = 538
|
||||
WINFREEZE = 539
|
||||
WINTHAW = 540
|
||||
REDRAWICONIC = 541
|
||||
WINQUIT = 542
|
||||
DEPTHCHANGE = 543
|
||||
KEYBDFNAMES = 544
|
||||
KEYBDFSTRINGS = 545
|
||||
WINSHUT = 546
|
||||
INPUT0 = 1024
|
||||
INPUT1 = 1025
|
||||
INPUT2 = 1026
|
||||
INPUT3 = 1027
|
||||
INPUT4 = 1028
|
||||
INPUT5 = 1029
|
||||
INPUT6 = 1030
|
||||
INPUT7 = 1032
|
||||
OUTPUT0 = 1033
|
||||
OUTPUT1 = 1034
|
||||
OUTPUT2 = 1035
|
||||
OUTPUT3 = 1036
|
||||
OUTPUT4 = 1037
|
||||
OUTPUT5 = 1038
|
||||
OUTPUT6 = 1039
|
||||
OUTPUT7 = 1040
|
||||
MAXSGIDEVICE = 20000
|
||||
MENUBUTTON = RIGHTMOUSE
|
|
@ -0,0 +1,365 @@
|
|||
# Constants defined in <gl.h>
|
||||
|
||||
#**************************************************************************
|
||||
#* *
|
||||
#* Copyright (C) 1984, Silicon Graphics, Inc. *
|
||||
#* *
|
||||
#* These coded instructions, statements, and computer programs contain *
|
||||
#* unpublished proprietary information of Silicon Graphics, Inc., and *
|
||||
#* are protected by Federal copyright law. They may not be disclosed *
|
||||
#* to third parties or copied or duplicated in any form, in whole or *
|
||||
#* in part, without the prior written consent of Silicon Graphics, Inc. *
|
||||
#* *
|
||||
#**************************************************************************
|
||||
|
||||
# Graphics Libary constants
|
||||
|
||||
# Booleans
|
||||
TRUE = 1
|
||||
FALSE = 0
|
||||
|
||||
# maximum X and Y screen coordinates
|
||||
XMAXSCREEN = 1279
|
||||
YMAXSCREEN = 1023
|
||||
XMAXMEDIUM = 1023 # max for medium res monitor
|
||||
YMAXMEDIUM = 767
|
||||
XMAX170 = 645 # max for RS-170
|
||||
YMAX170 = 484
|
||||
XMAXPAL = 779 # max for PAL
|
||||
YMAXPAL = 574
|
||||
|
||||
# various hardware/software limits
|
||||
ATTRIBSTACKDEPTH = 10
|
||||
VPSTACKDEPTH = 8
|
||||
MATRIXSTACKDEPTH = 32
|
||||
NAMESTACKDEPTH = 1025
|
||||
STARTTAG = -2
|
||||
ENDTAG = -3
|
||||
CPOSX_INVALID = -(2*XMAXSCREEN)
|
||||
|
||||
# names for colors in color map loaded by greset
|
||||
BLACK = 0
|
||||
RED = 1
|
||||
GREEN = 2
|
||||
YELLOW = 3
|
||||
BLUE = 4
|
||||
MAGENTA = 5
|
||||
CYAN = 6
|
||||
WHITE = 7
|
||||
|
||||
# popup colors
|
||||
PUP_CLEAR = 0
|
||||
PUP_COLOR = 1
|
||||
PUP_BLACK = 2
|
||||
PUP_WHITE = 3
|
||||
|
||||
# defines for drawmode
|
||||
NORMALDRAW = 0
|
||||
PUPDRAW = 1
|
||||
OVERDRAW = 2
|
||||
UNDERDRAW = 3
|
||||
CURSORDRAW = 4
|
||||
|
||||
# defines for defpattern
|
||||
PATTERN_16 = 16
|
||||
PATTERN_32 = 32
|
||||
PATTERN_64 = 64
|
||||
|
||||
PATTERN_16_SIZE = 16
|
||||
PATTERN_32_SIZE = 64
|
||||
PATTERN_64_SIZE = 256
|
||||
|
||||
# defines for readsource
|
||||
SRC_AUTO = 0
|
||||
SRC_FRONT = 1
|
||||
SRC_BACK = 2
|
||||
SRC_ZBUFFER = 3
|
||||
SRC_PUP = 4
|
||||
SRC_OVER = 5
|
||||
SRC_UNDER = 6
|
||||
SRC_FRAMEGRABBER = 7
|
||||
|
||||
# defines for blendfunction
|
||||
BF_ZERO = 0
|
||||
BF_ONE = 1
|
||||
BF_DC = 2
|
||||
BF_SC = 2
|
||||
BF_MDC = 3
|
||||
BF_MSC = 3
|
||||
BF_SA = 4
|
||||
BF_MSA = 5
|
||||
BF_DA = 6
|
||||
BF_MDA = 7
|
||||
|
||||
# defines for zfunction
|
||||
ZF_NEVER = 0
|
||||
ZF_LESS = 1
|
||||
ZF_EQUAL = 2
|
||||
ZF_LEQUAL = 3
|
||||
ZF_GREATER = 4
|
||||
ZF_NOTEQUAL = 5
|
||||
ZF_GEQUAL = 6
|
||||
ZF_ALWAYS = 7
|
||||
|
||||
# defines for zsource
|
||||
ZSRC_DEPTH = 0
|
||||
ZSRC_COLOR = 1
|
||||
|
||||
# defines for pntsmooth
|
||||
SMP_OFF = 0
|
||||
SMP_ON = 1
|
||||
|
||||
# defines for linesmooth
|
||||
SML_OFF = 0
|
||||
SML_ON = 1
|
||||
|
||||
# defines for setpup
|
||||
PUP_NONE = 0
|
||||
PUP_GREY = 1
|
||||
|
||||
# defines for glcompat
|
||||
GLC_OLDPOLYGON = 0
|
||||
GLC_ZRANGEMAP = 1
|
||||
|
||||
# defines for curstype
|
||||
C16X1 = 0
|
||||
C16X2 = 1
|
||||
C32X1 = 2
|
||||
C32X2 = 3
|
||||
CCROSS = 4
|
||||
|
||||
# defines for shademodel
|
||||
FLAT = 0
|
||||
GOURAUD = 1
|
||||
|
||||
# defines for logicop
|
||||
### LO_ZERO = 0x0
|
||||
### LO_AND = 0x1
|
||||
### LO_ANDR = 0x2
|
||||
### LO_SRC = 0x3
|
||||
### LO_ANDI = 0x4
|
||||
### LO_DST = 0x5
|
||||
### LO_XOR = 0x6
|
||||
### LO_OR = 0x7
|
||||
### LO_NOR = 0x8
|
||||
### LO_XNOR = 0x9
|
||||
### LO_NDST = 0xa
|
||||
### LO_ORR = 0xb
|
||||
### LO_NSRC = 0xc
|
||||
### LO_ORI = 0xd
|
||||
### LO_NAND = 0xe
|
||||
### LO_ONE = 0xf
|
||||
|
||||
|
||||
#
|
||||
# START defines for getgdesc
|
||||
#
|
||||
|
||||
GD_XPMAX = 0
|
||||
GD_YPMAX = 1
|
||||
GD_XMMAX = 2
|
||||
GD_YMMAX = 3
|
||||
GD_ZMIN = 4
|
||||
GD_ZMAX = 5
|
||||
GD_BITS_NORM_SNG_RED = 6
|
||||
GD_BITS_NORM_SNG_GREEN = 7
|
||||
GD_BITS_NORM_SNG_BLUE = 8
|
||||
GD_BITS_NORM_DBL_RED = 9
|
||||
GD_BITS_NORM_DBL_GREEN = 10
|
||||
GD_BITS_NORM_DBL_BLUE = 11
|
||||
GD_BITS_NORM_SNG_CMODE = 12
|
||||
GD_BITS_NORM_DBL_CMODE = 13
|
||||
GD_BITS_NORM_SNG_MMAP = 14
|
||||
GD_BITS_NORM_DBL_MMAP = 15
|
||||
GD_BITS_NORM_ZBUFFER = 16
|
||||
GD_BITS_OVER_SNG_CMODE = 17
|
||||
GD_BITS_UNDR_SNG_CMODE = 18
|
||||
GD_BITS_PUP_SNG_CMODE = 19
|
||||
GD_BITS_NORM_SNG_ALPHA = 21
|
||||
GD_BITS_NORM_DBL_ALPHA = 22
|
||||
GD_BITS_CURSOR = 23
|
||||
GD_OVERUNDER_SHARED = 24
|
||||
GD_BLEND = 25
|
||||
GD_CIFRACT = 26
|
||||
GD_CROSSHAIR_CINDEX = 27
|
||||
GD_DITHER = 28
|
||||
GD_LINESMOOTH_CMODE = 30
|
||||
GD_LINESMOOTH_RGB = 31
|
||||
GD_LOGICOP = 33
|
||||
GD_NSCRNS = 35
|
||||
GD_NURBS_ORDER = 36
|
||||
GD_NBLINKS = 37
|
||||
GD_NVERTEX_POLY = 39
|
||||
GD_PATSIZE_64 = 40
|
||||
GD_PNTSMOOTH_CMODE = 41
|
||||
GD_PNTSMOOTH_RGB = 42
|
||||
GD_PUP_TO_OVERUNDER = 43
|
||||
GD_READSOURCE = 44
|
||||
GD_READSOURCE_ZBUFFER = 48
|
||||
GD_STEREO = 50
|
||||
GD_SUBPIXEL_LINE = 51
|
||||
GD_SUBPIXEL_PNT = 52
|
||||
GD_SUBPIXEL_POLY = 53
|
||||
GD_TRIMCURVE_ORDER = 54
|
||||
GD_WSYS = 55
|
||||
GD_ZDRAW_GEOM = 57
|
||||
GD_ZDRAW_PIXELS = 58
|
||||
GD_SCRNTYPE = 61
|
||||
GD_TEXTPORT = 62
|
||||
GD_NMMAPS = 63
|
||||
GD_FRAMEGRABBER = 64
|
||||
GD_TIMERHZ = 66
|
||||
GD_DBBOX = 67
|
||||
GD_AFUNCTION = 68
|
||||
GD_ALPHA_OVERUNDER = 69
|
||||
GD_BITS_ACBUF = 70
|
||||
GD_BITS_ACBUF_HW = 71
|
||||
GD_BITS_STENCIL = 72
|
||||
GD_CLIPPLANES = 73
|
||||
GD_FOGVERTEX = 74
|
||||
GD_LIGHTING_TWOSIDE = 76
|
||||
GD_POLYMODE = 77
|
||||
GD_POLYSMOOTH = 78
|
||||
GD_SCRBOX = 79
|
||||
GD_TEXTURE = 80
|
||||
|
||||
# return value for inquiries when there is no limit
|
||||
GD_NOLIMIT = 2
|
||||
|
||||
# return values for GD_WSYS
|
||||
GD_WSYS_NONE = 0
|
||||
GD_WSYS_4S = 1
|
||||
|
||||
# return values for GD_SCRNTYPE
|
||||
GD_SCRNTYPE_WM = 0
|
||||
GD_SCRNTYPE_NOWM = 1
|
||||
|
||||
#
|
||||
# END defines for getgdesc
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# START NURBS interface definitions
|
||||
#
|
||||
|
||||
# NURBS Rendering Properties
|
||||
N_PIXEL_TOLERANCE = 1
|
||||
N_CULLING = 2
|
||||
N_DISPLAY = 3
|
||||
N_ERRORCHECKING = 4
|
||||
N_SUBDIVISIONS = 5
|
||||
N_S_STEPS = 6
|
||||
N_T_STEPS = 7
|
||||
N_TILES = 8
|
||||
|
||||
N_SHADED = 1.0
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# FLAGS FOR NURBS SURFACES AND CURVES
|
||||
#
|
||||
# Bit: 9876 5432 1 0
|
||||
# |tttt|nnnn|f|r| : r - 1 bit = 1 if rational coordinate exists
|
||||
# : f - 1 bit = 1 if rational coordinate is before rest
|
||||
# : = 0 if rational coordinate is after rest
|
||||
# : nnnn - 4 bits for number of coordinates
|
||||
# : tttt - 4 bits for type of data (color, position, etc.)
|
||||
#
|
||||
# NURBS data type
|
||||
# N_T_ST 0 parametric space data
|
||||
# N_T_XYZ 1 model space data
|
||||
#
|
||||
# rational or non-rational data and position in memory
|
||||
# N_NONRATIONAL 0 non-rational data
|
||||
# N_RATAFTER 1 rational data with rat coord after rest
|
||||
# N_RATBEFORE 3 rational data with rat coord before rest
|
||||
#
|
||||
# N_MKFLAG(a,b,c) ((a<<6) | (b<<2) | c)
|
||||
#
|
||||
# ---------------------------------------------------------------------------
|
||||
#
|
||||
N_ST = 0x8 # N_MKFLAG( N_T_ST, 2, N_NONRATIONAL )
|
||||
N_STW = 0xd # N_MKFLAG( N_T_ST, 3, N_RATAFTER )
|
||||
N_WST = 0xf # N_MKFLAG( N_T_ST, 3, N_RATBEFORE )
|
||||
N_XYZ = 0x4c # N_MKFLAG( N_T_XYZ, 3, N_NONRATIONAL )
|
||||
N_XYZW = 0x51 # N_MKFLAG( N_T_XYZ, 4, N_RATAFTER )
|
||||
N_WXYZ = 0x53 # N_MKFLAG( N_T_XYZ, 4, N_RATBEFORE )
|
||||
|
||||
#
|
||||
# END NURBS interface definitions
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# START lighting model defines
|
||||
#
|
||||
|
||||
LMNULL = 0.0
|
||||
|
||||
# MATRIX modes
|
||||
MSINGLE = 0
|
||||
MPROJECTION = 1
|
||||
MVIEWING = 2
|
||||
|
||||
# LIGHT constants
|
||||
MAXLIGHTS = 8
|
||||
MAXRESTRICTIONS = 4
|
||||
|
||||
# MATERIAL properties
|
||||
DEFMATERIAL = 0
|
||||
EMISSION = 1
|
||||
AMBIENT = 2
|
||||
DIFFUSE = 3
|
||||
SPECULAR = 4
|
||||
SHININESS = 5
|
||||
COLORINDEXES = 6
|
||||
ALPHA = 7
|
||||
|
||||
# LIGHT properties
|
||||
DEFLIGHT = 100
|
||||
LCOLOR = 101
|
||||
POSITION = 102
|
||||
|
||||
# LIGHTINGMODEL properties
|
||||
DEFLMODEL = 200
|
||||
LOCALVIEWER = 201
|
||||
ATTENUATION = 202
|
||||
|
||||
# TARGET constants
|
||||
MATERIAL = 1000
|
||||
LIGHT0 = 1100
|
||||
LIGHT1 = 1101
|
||||
LIGHT2 = 1102
|
||||
LIGHT3 = 1103
|
||||
LIGHT4 = 1104
|
||||
LIGHT5 = 1105
|
||||
LIGHT6 = 1106
|
||||
LIGHT7 = 1107
|
||||
LMODEL = 1200
|
||||
|
||||
# lmcolor modes
|
||||
LMC_COLOR = 0
|
||||
LMC_EMISSION = 1
|
||||
LMC_AMBIENT = 2
|
||||
LMC_DIFFUSE = 3
|
||||
LMC_SPECULAR = 4
|
||||
LMC_AD = 5
|
||||
LMC_NULL = 6
|
||||
|
||||
#
|
||||
# END lighting model defines
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# START distributed graphics library defines
|
||||
#
|
||||
|
||||
DGLSINK = 0 # sink connection
|
||||
DGLLOCAL = 1 # local connection
|
||||
DGLTSOCKET = 2 # tcp socket connection
|
||||
DGL4DDN = 3 # 4DDN (DECnet)
|
||||
|
||||
#
|
||||
# END distributed graphics library defines
|
||||
#
|
|
@ -0,0 +1,106 @@
|
|||
import audio
|
||||
|
||||
RATE = 8192
|
||||
|
||||
# Initialize the audio stuff
|
||||
audio.setrate(3)
|
||||
audio.setoutgain(100) # for speaker
|
||||
|
||||
play = audio.write
|
||||
|
||||
def samp(n):
|
||||
savegain = audio.getoutgain()
|
||||
try:
|
||||
audio.setoutgain(0)
|
||||
x = raw_input('Hit Enter to sample ' + `n` + ' seconds: ')
|
||||
return audio.read(n*RATE)
|
||||
finally:
|
||||
audio.setoutgain(savegain)
|
||||
|
||||
def echo(s, delay, gain):
|
||||
return s[:delay] + audio.add(s[delay:], audio.amplify(s, gain, gain))
|
||||
|
||||
def save(s, file):
|
||||
f = open(file, 'w')
|
||||
f.write(s)
|
||||
|
||||
def load(file):
|
||||
return loadfp(open(file, 'r'))
|
||||
|
||||
def loadfp(fp):
|
||||
s = ''
|
||||
while 1:
|
||||
buf = fp.read(16*1024)
|
||||
if not buf: break
|
||||
s = s + buf
|
||||
return s
|
||||
|
||||
def unbias(s):
|
||||
if not s: return s
|
||||
a = audio.chr2num(s)
|
||||
sum = 0
|
||||
for i in a: sum = sum + i
|
||||
bias = (sum + len(a)/2) / len(a)
|
||||
print 'Bias value:', bias
|
||||
if bias:
|
||||
for i in range(len(a)):
|
||||
a[i] = a[i] - bias
|
||||
s = audio.num2chr(a)
|
||||
return s
|
||||
|
||||
# Stretch by a/b.
|
||||
# Think of this as converting the sampling rate from a samples/sec
|
||||
# to b samples/sec. Or, if the input is a bytes long, the output
|
||||
# will be b bytes long.
|
||||
#
|
||||
def stretch(s, a, b):
|
||||
y = audio.chr2num(s)
|
||||
m = len(y)
|
||||
out = []
|
||||
n = m * b / a
|
||||
# i, j will walk through y and out (step 1)
|
||||
# ib, ja are i*b, j*a and are kept as close together as possible
|
||||
i, ib = 0, 0
|
||||
j, ja = 0, 0
|
||||
for j in range(n):
|
||||
ja = ja+a
|
||||
while ib < ja:
|
||||
i = i+1
|
||||
ib = ib+b
|
||||
if i >= m:
|
||||
break
|
||||
if ib = ja:
|
||||
out.append(y[i])
|
||||
else:
|
||||
out.append((y[i]*(ja-(ib-b)) + y[i-1]*(ib-ja)) / b)
|
||||
return audio.num2chr(out)
|
||||
|
||||
def sinus(freq): # return a 1-second sine wave
|
||||
from math import sin, pi
|
||||
factor = 2.0*pi*float(freq)/float(RATE)
|
||||
list = range(RATE)
|
||||
for i in list:
|
||||
list[i] = int(sin(float(i) * factor) * 127.0)
|
||||
return audio.num2chr(list)
|
||||
|
||||
def softclip(s):
|
||||
if '\177' not in s and '\200' not in s:
|
||||
return s
|
||||
num = audio.chr2num(s)
|
||||
extremes = (-128, 127)
|
||||
for i in range(1, len(num)-1):
|
||||
if num[i] in extremes:
|
||||
num[i] = (num[i-1] + num[i+1]) / 2
|
||||
return audio.num2chr(num)
|
||||
|
||||
def demo():
|
||||
gday = load('gday')[1000:6000]
|
||||
save(gday, 'gday0')
|
||||
gg = [gday]
|
||||
for i in range(1, 10):
|
||||
for g in gg: play(g)
|
||||
g = stretch(gday, 10, 10-i)
|
||||
save(g, 'gday' + `i`)
|
||||
gg.append(g)
|
||||
while 1:
|
||||
for g in gg: play(g)
|
|
@ -0,0 +1,281 @@
|
|||
# Module 'panel'
|
||||
#
|
||||
# Support for the Panel library.
|
||||
# Uses built-in module 'pnl'.
|
||||
# Applciations should use 'panel.function' instead of 'pnl.function';
|
||||
# most 'pnl' functions are transparently exported by 'panel',
|
||||
# but dopanel() is overridden and you have to use this version
|
||||
# if you want to use callbacks.
|
||||
|
||||
|
||||
import pnl
|
||||
|
||||
|
||||
debug = 0
|
||||
|
||||
|
||||
# Test if an object is a list.
|
||||
#
|
||||
def is_list(x):
|
||||
return type(x) = type([])
|
||||
|
||||
|
||||
# Reverse a list.
|
||||
#
|
||||
def reverse(list):
|
||||
res = []
|
||||
for item in list:
|
||||
res.insert(0, item)
|
||||
return res
|
||||
|
||||
|
||||
# Get an attribute of a list, which may itself be another list.
|
||||
# Don't use 'prop' for name.
|
||||
#
|
||||
def getattrlist(list, name):
|
||||
for item in list:
|
||||
if item and is_list(item) and item[0] = name:
|
||||
return item[1:]
|
||||
return []
|
||||
|
||||
|
||||
# Get a property of a list, which may itself be another list.
|
||||
#
|
||||
def getproplist(list, name):
|
||||
for item in list:
|
||||
if item and is_list(item) and item[0] = 'prop':
|
||||
if len(item) > 1 and item[1] = name:
|
||||
return item[2:]
|
||||
return []
|
||||
|
||||
|
||||
# Test if an actuator description contains the property 'end-of-group'
|
||||
#
|
||||
def is_endgroup(list):
|
||||
x = getproplist(list, 'end-of-group')
|
||||
return (x and x[0] = '#t')
|
||||
|
||||
|
||||
# Neatly display an actuator definition given as S-expression
|
||||
# the prefix string is printed before each line.
|
||||
#
|
||||
def show_actuator(prefix, a):
|
||||
for item in a:
|
||||
if not is_list(item):
|
||||
print prefix, item
|
||||
elif item and item[0] = 'al':
|
||||
print prefix, 'Subactuator list:'
|
||||
for a in item[1:]:
|
||||
show_actuator(prefix + ' ', a)
|
||||
elif len(item) = 2:
|
||||
print prefix, item[0], '=>', item[1]
|
||||
elif len(item) = 3 and item[0] = 'prop':
|
||||
print prefix, 'Prop', item[1], '=>',
|
||||
print item[2]
|
||||
else:
|
||||
print prefix, '?', item
|
||||
|
||||
|
||||
# Neatly display a panel.
|
||||
#
|
||||
def show_panel(prefix, p):
|
||||
for item in p:
|
||||
if not is_list(item):
|
||||
print prefix, item
|
||||
elif item and item[0] = 'al':
|
||||
print prefix, 'Actuator list:'
|
||||
for a in item[1:]:
|
||||
show_actuator(prefix + ' ', a)
|
||||
elif len(item) = 2:
|
||||
print prefix, item[0], '=>', item[1]
|
||||
elif len(item) = 3 and item[0] = 'prop':
|
||||
print prefix, 'Prop', item[1], '=>',
|
||||
print item[2]
|
||||
else:
|
||||
print prefix, '?', item
|
||||
|
||||
|
||||
# Exception raised by build_actuator or build_panel.
|
||||
#
|
||||
panel_error = 'panel error'
|
||||
|
||||
|
||||
# Dummy callback used to initialize the callbacks.
|
||||
#
|
||||
def dummy_callback(arg):
|
||||
pass
|
||||
|
||||
|
||||
# Assign attributes to members of the target.
|
||||
# Attribute names in exclist are ignored.
|
||||
# The member name is the attribute name prefixed with the prefix.
|
||||
#
|
||||
def assign_members(target, attrlist, exclist, prefix):
|
||||
for item in attrlist:
|
||||
if is_list(item) and len(item) = 2 and item[0] not in exclist:
|
||||
name, value = item[0], item[1]
|
||||
ok = 1
|
||||
if value[0] in '-0123456789':
|
||||
value = eval(value)
|
||||
elif value[0] = '"':
|
||||
value = value[1:-1]
|
||||
elif value = 'move-then-resize':
|
||||
# Strange default set by Panel Editor...
|
||||
ok = 0
|
||||
else:
|
||||
print 'unknown value', value, 'for', name
|
||||
ok = 0
|
||||
if ok:
|
||||
lhs = 'target.' + prefix + name
|
||||
stmt = lhs + '=' + `value`
|
||||
if debug: print 'exec', stmt
|
||||
try:
|
||||
exec(stmt + '\n')
|
||||
except KeyboardInterrupt: # Don't catch this!
|
||||
raise KeyboardInterrupt
|
||||
except:
|
||||
print 'assign failed:', stmt
|
||||
|
||||
|
||||
# Build a real actuator from an actuator descriptior.
|
||||
# Return a pair (actuator, name).
|
||||
#
|
||||
def build_actuator(descr):
|
||||
namelist = getattrlist(descr, 'name')
|
||||
if namelist:
|
||||
# Assume it is a string
|
||||
actuatorname = namelist[0][1:-1]
|
||||
else:
|
||||
actuatorname = ''
|
||||
type = descr[0]
|
||||
if type[:4] = 'pnl_': type = type[4:]
|
||||
act = pnl.mkact(type)
|
||||
act.downfunc = act.activefunc = act.upfunc = dummy_callback
|
||||
#
|
||||
assign_members(act, descr[1:], ('al', 'data', 'name'), '')
|
||||
#
|
||||
# Treat actuator-specific data
|
||||
#
|
||||
datalist = getattrlist(descr, 'data')
|
||||
prefix = ''
|
||||
if type[-4:] = 'puck':
|
||||
prefix = 'puck_'
|
||||
elif type = 'mouse':
|
||||
prefix = 'mouse_'
|
||||
assign_members(act, datalist, (), prefix)
|
||||
#
|
||||
return act, actuatorname
|
||||
|
||||
|
||||
# Build all sub-actuators and add them to the super-actuator.
|
||||
# The super-actuator must already have been added to the panel.
|
||||
# Sub-actuators with defined names are added as members to the panel
|
||||
# so they can be referenced as p.name.
|
||||
#
|
||||
# Note: I have no idea how panel.endgroup() works when applied
|
||||
# to a sub-actuator.
|
||||
#
|
||||
def build_subactuators(panel, super_act, al):
|
||||
#
|
||||
# This is nearly the same loop as below in build_panel(),
|
||||
# except a call is made to addsubact() instead of addact().
|
||||
#
|
||||
for a in al:
|
||||
act, name = build_actuator(a)
|
||||
act.addsubact(super_act)
|
||||
if name:
|
||||
stmt = 'panel.' + name + ' = act'
|
||||
if debug: print 'exec', stmt
|
||||
exec(stmt + '\n')
|
||||
if is_endgroup(a):
|
||||
panel.endgroup()
|
||||
sub_al = getattrlist(a, 'al')
|
||||
if sub_al:
|
||||
build_subactuators(panel, act, sub_al)
|
||||
#
|
||||
# Fix the actuator to which whe just added subactuators.
|
||||
# This can't hurt (I hope) and is needed for the scroll actuator.
|
||||
#
|
||||
super_act.fixact()
|
||||
|
||||
|
||||
# Build a real panel from a panel definition.
|
||||
# Return a panel object p, where for each named actuator a, p.name is a
|
||||
# reference to a.
|
||||
#
|
||||
def build_panel(descr):
|
||||
#
|
||||
# Sanity check
|
||||
#
|
||||
if (not descr) or descr[0] <> 'panel':
|
||||
raise panel_error, 'panel description must start with "panel"'
|
||||
#
|
||||
if debug: show_panel('', descr)
|
||||
#
|
||||
# Create an empty panel
|
||||
#
|
||||
panel = pnl.mkpanel()
|
||||
#
|
||||
# Assign panel attributes
|
||||
#
|
||||
assign_members(panel, descr[1:], ('al'), '')
|
||||
#
|
||||
# Look for actuator list
|
||||
#
|
||||
al = getattrlist(descr, 'al')
|
||||
#
|
||||
# The order in which actuators are created is important
|
||||
# because of the endgroup() operator.
|
||||
# Unfortunately the Panel Editor outputs the actuator list
|
||||
# in reverse order, so we reverse it here.
|
||||
#
|
||||
al = reverse(al)
|
||||
#
|
||||
for a in al:
|
||||
act, name = build_actuator(a)
|
||||
act.addact(panel)
|
||||
if name:
|
||||
stmt = 'panel.' + name + ' = act'
|
||||
exec(stmt + '\n')
|
||||
if is_endgroup(a):
|
||||
panel.endgroup()
|
||||
sub_al = getattrlist(a, 'al')
|
||||
if sub_al:
|
||||
build_subactuators(panel, act, sub_al)
|
||||
#
|
||||
return panel
|
||||
|
||||
|
||||
# Wrapper around pnl.dopanel() which calls call-back functions.
|
||||
#
|
||||
def my_dopanel():
|
||||
# Extract only the first 4 elements to allow for future expansion
|
||||
a, down, active, up = pnl.dopanel()[:4]
|
||||
if down:
|
||||
down.downfunc(down)
|
||||
if active:
|
||||
active.activefunc(active)
|
||||
if up:
|
||||
up.upfunc(up)
|
||||
return a
|
||||
|
||||
|
||||
# Create one or more panels from a description file (S-expressions)
|
||||
# generated by the Panel Editor.
|
||||
#
|
||||
def defpanellist(file):
|
||||
import parser
|
||||
descrlist = parser.parse_file(open(file, 'r'))
|
||||
panellist = []
|
||||
for descr in descrlist:
|
||||
panellist.append(build_panel(descr))
|
||||
return panellist
|
||||
|
||||
|
||||
# Import everything from built-in method pnl, so the user can always
|
||||
# use panel.foo() instead of pnl.foo().
|
||||
# This gives *no* performance penalty once this module is imported.
|
||||
#
|
||||
from pnl import * # for export
|
||||
|
||||
dopanel = my_dopanel # override pnl.dopanel
|
|
@ -0,0 +1,128 @@
|
|||
# Module 'parser'
|
||||
#
|
||||
# Parse S-expressions output by the Panel Editor
|
||||
# (which is written in Scheme so it can't help writing S-expressions).
|
||||
#
|
||||
# See notes at end of file.
|
||||
|
||||
|
||||
whitespace = ' \t\n'
|
||||
operators = '()\''
|
||||
separators = operators + whitespace + ';' + '"'
|
||||
|
||||
|
||||
# Tokenize a string.
|
||||
# Return a list of tokens (strings).
|
||||
#
|
||||
def tokenize_string(s):
|
||||
tokens = []
|
||||
while s:
|
||||
c = s[:1]
|
||||
if c in whitespace:
|
||||
s = s[1:]
|
||||
elif c = ';':
|
||||
s = ''
|
||||
elif c = '"':
|
||||
n = len(s)
|
||||
i = 1
|
||||
while i < n:
|
||||
c = s[i]
|
||||
i = i+1
|
||||
if c = '"': break
|
||||
if c = '\\': i = i+1
|
||||
tokens.append(s[:i])
|
||||
s = s[i:]
|
||||
elif c in operators:
|
||||
tokens.append(c)
|
||||
s = s[1:]
|
||||
else:
|
||||
n = len(s)
|
||||
i = 1
|
||||
while i < n:
|
||||
if s[i] in separators: break
|
||||
i = i+1
|
||||
tokens.append(s[:i])
|
||||
s = s[i:]
|
||||
return tokens
|
||||
|
||||
|
||||
# Tokenize a whole file (given as file object, not as file name).
|
||||
# Return a list of tokens (strings).
|
||||
#
|
||||
def tokenize_file(fp):
|
||||
tokens = []
|
||||
while 1:
|
||||
line = fp.readline()
|
||||
if not line: break
|
||||
tokens = tokens + tokenize_string(line)
|
||||
return tokens
|
||||
|
||||
|
||||
# Exception raised by parse_exr.
|
||||
#
|
||||
syntax_error = 'syntax error'
|
||||
|
||||
|
||||
# Parse an S-expression.
|
||||
# Input is a list of tokens as returned by tokenize_*().
|
||||
# Return a pair (expr, tokens)
|
||||
# where expr is a list representing the s-expression,
|
||||
# and tokens contains the remaining tokens.
|
||||
# May raise syntax_error.
|
||||
#
|
||||
def parse_expr(tokens):
|
||||
if (not tokens) or tokens[0] <> '(':
|
||||
raise syntax_error, 'expected "("'
|
||||
tokens = tokens[1:]
|
||||
expr = []
|
||||
while 1:
|
||||
if not tokens:
|
||||
raise syntax_error, 'missing ")"'
|
||||
if tokens[0] = ')':
|
||||
return expr, tokens[1:]
|
||||
elif tokens[0] = '(':
|
||||
subexpr, tokens = parse_expr(tokens)
|
||||
expr.append(subexpr)
|
||||
else:
|
||||
expr.append(tokens[0])
|
||||
tokens = tokens[1:]
|
||||
|
||||
|
||||
# Parse a file (given as file object, not as file name).
|
||||
# Return a list of parsed S-expressions found at the top level.
|
||||
#
|
||||
def parse_file(fp):
|
||||
tokens = tokenize_file(fp)
|
||||
exprlist = []
|
||||
while tokens:
|
||||
expr, tokens = parse_expr(tokens)
|
||||
exprlist.append(expr)
|
||||
return exprlist
|
||||
|
||||
|
||||
# EXAMPLE:
|
||||
#
|
||||
# The input
|
||||
# '(hip (hop hur-ray))'
|
||||
#
|
||||
# passed to tokenize_string() returns the token list
|
||||
# ['(', 'hip', '(', 'hop', 'hur-ray', ')', ')']
|
||||
#
|
||||
# When this is passed to parse_expr() it returns the expression
|
||||
# ['hip', ['hop', 'hur-ray']]
|
||||
# plus an empty token list (because there are no tokens left.
|
||||
#
|
||||
# When a file containing the example is passed to parse_file() it returns
|
||||
# a list whose only element is the output of parse_expr() above:
|
||||
# [['hip', ['hop', 'hur-ray']]]
|
||||
|
||||
|
||||
# TOKENIZING:
|
||||
#
|
||||
# Comments start with semicolon (;) and continue till the end of the line.
|
||||
#
|
||||
# Tokens are separated by whitespace, except the following characters
|
||||
# always form a separate token (outside strings):
|
||||
# ( ) '
|
||||
# Strings are enclosed in double quotes (") and backslash (\) is used
|
||||
# as escape character in strings.
|
|
@ -0,0 +1,63 @@
|
|||
# Module 'dump'
|
||||
#
|
||||
# Print python code that reconstructs a variable.
|
||||
# This only works in certain cases.
|
||||
#
|
||||
# It works fine for:
|
||||
# - ints and floats (except NaNs and other weird things)
|
||||
# - strings
|
||||
# - compounds and lists, provided it works for all their elements
|
||||
# - imported modules, provided their name is the module name
|
||||
#
|
||||
# It works for top-level dictionaries but not for dictionaries
|
||||
# contained in other objects (could be made to work with some hassle
|
||||
# though).
|
||||
#
|
||||
# It does not work for functions (all sorts), classes, class objects,
|
||||
# windows, files etc.
|
||||
#
|
||||
# Finally, objects referenced by more than one name or contained in more
|
||||
# than one other object lose their sharing property (this is bad for
|
||||
# strings used as exception identifiers, for instance).
|
||||
|
||||
# Dump a whole symbol table
|
||||
#
|
||||
def dumpsymtab(dict):
|
||||
for key in dict.keys():
|
||||
dumpvar(key, dict[key])
|
||||
|
||||
# Dump a single variable
|
||||
#
|
||||
def dumpvar(name, x):
|
||||
import sys
|
||||
t = type(x)
|
||||
if t = type({}):
|
||||
print name, '= {}'
|
||||
for key in x.keys():
|
||||
item = x[key]
|
||||
if not printable(item):
|
||||
print '#',
|
||||
print name, '[', `key`, '] =', `item`
|
||||
elif t in (type(''), type(0), type(0.0), type([]), type(())):
|
||||
if not printable(x):
|
||||
print '#',
|
||||
print name, '=', `x`
|
||||
elif t = type(sys):
|
||||
print 'import', name, '#', x
|
||||
else:
|
||||
print '#', name, '=', x
|
||||
|
||||
# check if a value is printable in a way that can be read back with input()
|
||||
#
|
||||
def printable(x):
|
||||
t = type(x)
|
||||
if t in (type(''), type(0), type(0.0)):
|
||||
return 1
|
||||
if t in (type([]), type(())):
|
||||
for item in x:
|
||||
if not printable(item):
|
||||
return 0
|
||||
return 1
|
||||
if x = {}:
|
||||
return 1
|
||||
return 0
|
|
@ -0,0 +1,12 @@
|
|||
# Module 'rand'
|
||||
|
||||
import whrandom
|
||||
|
||||
def srand(seed):
|
||||
whrandom.seed(seed%256, seed/256%256, seed/65536%256)
|
||||
|
||||
def rand():
|
||||
return int(whrandom.random() * 32768.0) % 32768
|
||||
|
||||
def choice(seq):
|
||||
return seq[rand() % len(seq)]
|
|
@ -0,0 +1,9 @@
|
|||
# Module 'util' -- some useful functions that dont fit elsewhere
|
||||
|
||||
# Remove an item from a list at most once
|
||||
#
|
||||
def remove(item, list):
|
||||
for i in range(len(list)):
|
||||
if list[i] = item:
|
||||
del list[i]
|
||||
break
|
|
@ -0,0 +1,14 @@
|
|||
# Module 'anywin'
|
||||
# Open a file or directory in a window
|
||||
|
||||
import dirwin
|
||||
import filewin
|
||||
import path
|
||||
|
||||
def open(name):
|
||||
print 'opening', name, '...'
|
||||
if path.isdir(name):
|
||||
w = dirwin.open(name)
|
||||
else:
|
||||
w = filewin.open(name)
|
||||
return w
|
|
@ -0,0 +1,28 @@
|
|||
# Module 'dirwin'
|
||||
|
||||
# Directory windows, a subclass of listwin
|
||||
|
||||
import gwin
|
||||
import listwin
|
||||
import anywin
|
||||
import path
|
||||
import dircache
|
||||
|
||||
def action(w, string, i, detail):
|
||||
(h, v), clicks, button, mask = detail
|
||||
if clicks = 2:
|
||||
name = path.cat(w.name, string)
|
||||
try:
|
||||
w = anywin.open(name)
|
||||
except posix.error, why:
|
||||
stdwin.message('Can\'t open ' + name + ': ' + why[1])
|
||||
|
||||
def open(name):
|
||||
name = path.cat(name, '')
|
||||
list = dircache.opendir(name)[:]
|
||||
list.sort()
|
||||
dircache.annotate(name, list)
|
||||
w = listwin.open(name, list)
|
||||
w.name = name
|
||||
w.action = action
|
||||
return w
|
|
@ -0,0 +1,31 @@
|
|||
# Module 'filewin'
|
||||
# File windows, a subclass of textwin (which is a subclass of gwin)
|
||||
|
||||
import stdwin
|
||||
import textwin
|
||||
import path
|
||||
|
||||
builtin_open = open
|
||||
|
||||
def readfile(fn): # Return a string containing the file's contents
|
||||
fp = builtin_open(fn, 'r')
|
||||
a = ''
|
||||
n = 8096
|
||||
while 1:
|
||||
b = fp.read(n)
|
||||
if not b: break
|
||||
a = a + b
|
||||
return a
|
||||
|
||||
|
||||
# FILE WINDOW
|
||||
|
||||
def open_readonly(fn): # Open a file window
|
||||
w = textwin.open_readonly(fn, readfile(fn))
|
||||
w.fn = fn
|
||||
return w
|
||||
|
||||
def open(fn): # Open a file window
|
||||
w = textwin.open(fn, readfile(fn))
|
||||
w.fn = fn
|
||||
return w
|
|
@ -0,0 +1,118 @@
|
|||
# Module 'gwin'
|
||||
# Generic stdwin windows
|
||||
|
||||
# This is used as a base class from which to derive other window types.
|
||||
# The mainloop() function here is an event dispatcher for all window types.
|
||||
|
||||
import stdwin
|
||||
import stdwinsupport
|
||||
|
||||
S = stdwinsupport # Shorthand
|
||||
|
||||
windows = [] # List of open windows
|
||||
|
||||
|
||||
# Open a window
|
||||
|
||||
def open(title): # Open a generic window
|
||||
w = stdwin.open(title)
|
||||
stdwin.setdefwinsize(0, 0)
|
||||
# Set default event handlers
|
||||
w.draw = nop
|
||||
w.char = nop
|
||||
w.mdown = nop
|
||||
w.mmove = nop
|
||||
w.mup = nop
|
||||
w.m2down = m2down
|
||||
w.m2up = m2up
|
||||
w.size = nop
|
||||
w.move = nop
|
||||
w.activate = w.deactivate = nop
|
||||
w.timer = nop
|
||||
# default command handlers
|
||||
w.close = close
|
||||
w.tab = tab
|
||||
w.enter = enter
|
||||
w.backspace = backspace
|
||||
w.arrow = arrow
|
||||
w.kleft = w.kup = w.kright = w.kdown = nop
|
||||
windows.append(w)
|
||||
return w
|
||||
|
||||
|
||||
# Generic event dispatching
|
||||
|
||||
def mainloop(): # Handle events until no windows left
|
||||
while windows:
|
||||
treatevent(stdwin.getevent())
|
||||
|
||||
def treatevent(e): # Handle a stdwin event
|
||||
type, w, detail = e
|
||||
if type = S.we_draw:
|
||||
w.draw(w, detail)
|
||||
elif type = S.we_menu:
|
||||
m, item = detail
|
||||
m.action[item](w, m, item)
|
||||
elif type = S.we_command:
|
||||
treatcommand(w, detail)
|
||||
elif type = S.we_char:
|
||||
w.char(w, detail)
|
||||
elif type = S.we_mouse_down:
|
||||
if detail[1] > 1: w.m2down(w, detail)
|
||||
else: w.mdown(w, detail)
|
||||
elif type = S.we_mouse_move:
|
||||
w.mmove(w, detail)
|
||||
elif type = S.we_mouse_up:
|
||||
if detail[1] > 1: w.m2up(w, detail)
|
||||
else: w.mup(w, detail)
|
||||
elif type = S.we_size:
|
||||
w.size(w, w.getwinsize())
|
||||
elif type = S.we_activate:
|
||||
w.activate(w)
|
||||
elif type = S.we_deactivate:
|
||||
w.deactivate(w)
|
||||
elif type = S.we_move:
|
||||
w.move(w)
|
||||
elif type = S.we_timer:
|
||||
w.timer(w)
|
||||
|
||||
def treatcommand(w, type): # Handle a we_command event
|
||||
if type = S.wc_close:
|
||||
w.close(w)
|
||||
elif type = S.wc_return:
|
||||
w.enter(w)
|
||||
elif type = S.wc_tab:
|
||||
w.tab(w)
|
||||
elif type = S.wc_backspace:
|
||||
w.backspace(w)
|
||||
elif type in (S.wc_left, S.wc_up, S.wc_right, S.wc_down):
|
||||
w.arrow(w, type)
|
||||
|
||||
|
||||
# Methods
|
||||
|
||||
def close(w): # Close method
|
||||
for i in range(len(windows)):
|
||||
if windows[i] is w:
|
||||
del windows[i]
|
||||
break
|
||||
|
||||
def arrow(w, detail): # Arrow key method
|
||||
if detail = S.wc_left:
|
||||
w.kleft(w)
|
||||
elif detail = S.wc_up:
|
||||
w.kup(w)
|
||||
elif detail = S.wc_right:
|
||||
w.kright(w)
|
||||
elif detail = S.wc_down:
|
||||
w.kdown(w)
|
||||
|
||||
|
||||
# Trivial methods
|
||||
|
||||
def tab(w): w.char(w, '\t')
|
||||
def enter(w): w.char(w, '\n') # 'return' is a Python reserved word
|
||||
def backspace(w): w.char(w, '\b')
|
||||
def m2down(w, detail): w.mdown(w, detail)
|
||||
def m2up(w, detail): w.mup(w, detail)
|
||||
def nop(args): pass
|
|
@ -0,0 +1,47 @@
|
|||
# Module 'listwin'
|
||||
# List windows, a subclass of gwin
|
||||
|
||||
import gwin
|
||||
import stdwin
|
||||
|
||||
def maxlinewidth(a): # Compute maximum textwidth of lines in a sequence
|
||||
max = 0
|
||||
for line in a:
|
||||
width = stdwin.textwidth(line)
|
||||
if width > max: max = width
|
||||
return max
|
||||
|
||||
def action(w, string, i, detail): # Default item selection method
|
||||
pass
|
||||
|
||||
def mup(w, detail): # Mouse up method
|
||||
(h, v), clicks, button, mask = detail
|
||||
i = divmod(v, w.lineheight)[0]
|
||||
if 0 <= i < len(w.data):
|
||||
w.action(w, w.data[i], i, detail)
|
||||
|
||||
def draw(w, ((left, top), (right, bottom))): # Text window draw method
|
||||
data = w.data
|
||||
d = w.begindrawing()
|
||||
lh = w.lineheight
|
||||
itop = top/lh
|
||||
ibot = (bottom-1)/lh + 1
|
||||
if itop < 0: itop = 0
|
||||
if ibot > len(data): ibot = len(data)
|
||||
for i in range(itop, ibot): d.text((0, i*lh), data[i])
|
||||
|
||||
def open(title, data): # Display a list of texts in a window
|
||||
lineheight = stdwin.lineheight()
|
||||
h, v = maxlinewidth(data), len(data)*lineheight
|
||||
h0, v0 = h + stdwin.textwidth(' '), v + lineheight
|
||||
if h0 > stdwin.textwidth(' ')*80: h0 = 0
|
||||
if v0 > stdwin.lineheight()*24: v0 = 0
|
||||
stdwin.setdefwinsize(h0, v0)
|
||||
w = gwin.open(title)
|
||||
w.setdocsize(h, v)
|
||||
w.lineheight = lineheight
|
||||
w.data = data
|
||||
w.draw = draw
|
||||
w.action = action
|
||||
w.mup = mup
|
||||
return w
|
|
@ -0,0 +1,87 @@
|
|||
# Module 'rect'.
|
||||
#
|
||||
# Operations on rectangles.
|
||||
# There is some normalization: all results return the object 'empty'
|
||||
# if their result would contain no points.
|
||||
|
||||
|
||||
# Exception.
|
||||
#
|
||||
error = 'rect.error'
|
||||
|
||||
|
||||
# The empty rectangle.
|
||||
#
|
||||
empty = (0, 0), (0, 0)
|
||||
|
||||
|
||||
# Check if a rectangle is empty.
|
||||
#
|
||||
def is_empty((left, top), (right, bottom)):
|
||||
return left >= right or top >= bottom
|
||||
|
||||
|
||||
# Compute the intersection or two or more rectangles.
|
||||
# This works with a list or tuple argument.
|
||||
#
|
||||
def intersect(list):
|
||||
if not list: raise error, 'intersect called with empty list'
|
||||
if is_empty(list[0]): return empty
|
||||
(left, top), (right, bottom) = list[0]
|
||||
for rect in list[1:]:
|
||||
if not is_empty(rect):
|
||||
(l, t), (r, b) = rect
|
||||
if left < l: left = l
|
||||
if top < t: top = t
|
||||
if right > r: right = r
|
||||
if bottom > b: bottom = b
|
||||
if is_empty((left, top), (right, bottom)):
|
||||
return empty
|
||||
return (left, top), (right, bottom)
|
||||
|
||||
|
||||
# Compute the smallest rectangle containing all given rectangles.
|
||||
# This works with a list or tuple argument.
|
||||
#
|
||||
def union(list):
|
||||
(left, top), (right, bottom) = empty
|
||||
for (l, t), (r, b) in list[1:]:
|
||||
if not is_empty((l, t), (r, b)):
|
||||
if l < left: left = l
|
||||
if t < top: top = t
|
||||
if r > right: right = r
|
||||
if b > bottom: bottom = b
|
||||
res = (left, top), (right, bottom)
|
||||
if is_empty(res):
|
||||
return empty
|
||||
return res
|
||||
|
||||
|
||||
# Check if a point is in a rectangle.
|
||||
#
|
||||
def pointinrect((h, v), ((left, top), (right, bottom))):
|
||||
return left <= h < right and top <= v < bottom
|
||||
|
||||
|
||||
# Return a rectangle that is dh, dv inside another
|
||||
#
|
||||
def inset(((left, top), (right, bottom)), (dh, dv)):
|
||||
left = left + dh
|
||||
top = top + dv
|
||||
right = right - dh
|
||||
bottom = bottom - dv
|
||||
r = (left, top), (right, bottom)
|
||||
if is_empty(r):
|
||||
return empty
|
||||
else:
|
||||
return r
|
||||
|
||||
|
||||
# Conversions between rectangles and 'geometry tuples',
|
||||
# given as origin (h, v) and dimensions (width, height).
|
||||
#
|
||||
def rect2geom((left, top), (right, bottom)):
|
||||
return (left, top), (right-left, bottom-top)
|
||||
|
||||
def geom2rect((h, v), (width, height)):
|
||||
return (h, v), (h+width, v+height)
|
|
@ -0,0 +1,36 @@
|
|||
# Module 'stdwinevents' -- Constants for stdwin event types
|
||||
#
|
||||
# Suggested usage:
|
||||
# from stdwinevents import *
|
||||
|
||||
# The function stdwin.getevent() returns a tuple containing:
|
||||
# (type, window, detail)
|
||||
# where detail may be <no value> or a value depending on type, see below:
|
||||
|
||||
# Values for type:
|
||||
|
||||
WE_NULL = 0 # not reported -- means 'no event' internally
|
||||
WE_ACTIVATE = 1 # detail is <no object>
|
||||
WE_CHAR = 2 # detail is the character
|
||||
WE_COMMAND = 3 # detail is one of the WC_* constants below
|
||||
WE_MOUSE_DOWN = 4 # detail is ((h, v), clicks, button, mask)
|
||||
WE_MOUSE_MOVE = 5 # ditto
|
||||
WE_MOUSE_UP = 6 # ditto
|
||||
WE_MENU = 7 # detail is (menu, item)
|
||||
WE_SIZE = 8 # detail is (width, height) [???]
|
||||
WE_MOVE = 9 # not reported -- reserved for future use
|
||||
WE_DRAW = 10 # detail is ((left, top), (right, bottom))
|
||||
WE_TIMER = 11 # detail is <no object>
|
||||
WE_DEACTIVATE = 12 # detail is <no object>
|
||||
|
||||
# Values for detail when type is WE_COMMAND:
|
||||
|
||||
WC_CLOSE = 1 # user hit close box
|
||||
WC_LEFT = 2 # left arrow key
|
||||
WC_RIGHT = 3 # right arrow key
|
||||
WC_UP = 4 # up arrow key
|
||||
WC_DOWN = 5 # down arrow key
|
||||
WC_CANCEL = 6 # not reported -- turned into KeyboardInterrupt
|
||||
WC_BACKSPACE = 7 # backspace key
|
||||
WC_TAB = 8 # tab key
|
||||
WC_RETURN = 9 # return or enter key
|
|
@ -0,0 +1,237 @@
|
|||
# Module 'tablewin'
|
||||
|
||||
# Display a table, with per-item actions:
|
||||
|
||||
# A1 | A2 | A3 | .... | AN
|
||||
# B1 | B2 | B3 | .... | BN
|
||||
# C1 | C2 | C3 | .... | CN
|
||||
# .. | .. | .. | .... | ..
|
||||
# Z1 | Z2 | Z3 | .... | ZN
|
||||
|
||||
# Not all columns need to have the same length.
|
||||
# The data structure is a list of columns;
|
||||
# each column is a list of items.
|
||||
# Each item is a pair of a string and an action procedure.
|
||||
# The first item may be a column title.
|
||||
|
||||
import stdwin
|
||||
import gwin
|
||||
|
||||
def open(title, data): # Public function to open a table window
|
||||
#
|
||||
# Set geometry parameters (one day, these may be changeable)
|
||||
#
|
||||
margin = stdwin.textwidth(' ')
|
||||
lineheight = stdwin.lineheight()
|
||||
#
|
||||
# Geometry calculations
|
||||
#
|
||||
colstarts = [0]
|
||||
totwidth = 0
|
||||
maxrows = 0
|
||||
for coldata in data:
|
||||
# Height calculations
|
||||
rows = len(coldata)
|
||||
if rows > maxrows: maxrows = rows
|
||||
# Width calculations
|
||||
width = colwidth(coldata) + margin
|
||||
totwidth = totwidth + width
|
||||
colstarts.append(totwidth)
|
||||
#
|
||||
# Calculate document and window height
|
||||
#
|
||||
docwidth, docheight = totwidth, maxrows*lineheight
|
||||
winwidth, winheight = docwidth, docheight
|
||||
if winwidth > stdwin.textwidth('n')*100: winwidth = 0
|
||||
if winheight > stdwin.lineheight()*30: winheight = 0
|
||||
#
|
||||
# Create the window
|
||||
#
|
||||
stdwin.setdefwinsize(winwidth, winheight)
|
||||
w = gwin.open(title)
|
||||
#
|
||||
# Set properties and override methods
|
||||
#
|
||||
w.data = data
|
||||
w.margin = margin
|
||||
w.lineheight = lineheight
|
||||
w.colstarts = colstarts
|
||||
w.totwidth = totwidth
|
||||
w.maxrows = maxrows
|
||||
w.selection = (-1, -1)
|
||||
w.lastselection = (-1, -1)
|
||||
w.selshown = 0
|
||||
w.setdocsize(docwidth, docheight)
|
||||
w.draw = draw
|
||||
w.mup = mup
|
||||
w.arrow = arrow
|
||||
#
|
||||
# Return
|
||||
#
|
||||
return w
|
||||
|
||||
def update(w, data): # Change the data
|
||||
#
|
||||
# Hide selection
|
||||
#
|
||||
hidesel(w, w.begindrawing())
|
||||
#
|
||||
# Get old geometry parameters
|
||||
#
|
||||
margin = w.margin
|
||||
lineheight = w.lineheight
|
||||
#
|
||||
# Geometry calculations
|
||||
#
|
||||
colstarts = [0]
|
||||
totwidth = 0
|
||||
maxrows = 0
|
||||
for coldata in data:
|
||||
# Height calculations
|
||||
rows = len(coldata)
|
||||
if rows > maxrows: maxrows = rows
|
||||
# Width calculations
|
||||
width = colwidth(coldata) + margin
|
||||
totwidth = totwidth + width
|
||||
colstarts.append(totwidth)
|
||||
#
|
||||
# Calculate document and window height
|
||||
#
|
||||
docwidth, docheight = totwidth, maxrows*lineheight
|
||||
#
|
||||
# Set changed properties and change window size
|
||||
#
|
||||
w.data = data
|
||||
w.colstarts = colstarts
|
||||
w.totwidth = totwidth
|
||||
w.maxrows = maxrows
|
||||
w.change((0, 0), (10000, 10000))
|
||||
w.setdocsize(docwidth, docheight)
|
||||
w.change((0, 0), (docwidth, docheight))
|
||||
#
|
||||
# Show selection, or forget it if out of range
|
||||
#
|
||||
showsel(w, w.begindrawing())
|
||||
if not w.selshown: w.selection = (-1, -1)
|
||||
|
||||
def colwidth(coldata): # Subroutine to calculate column width
|
||||
maxwidth = 0
|
||||
for string, action in coldata:
|
||||
width = stdwin.textwidth(string)
|
||||
if width > maxwidth: maxwidth = width
|
||||
return maxwidth
|
||||
|
||||
def draw(w, ((left, top), (right, bottom))): # Draw method
|
||||
ileft = whichcol(w, left)
|
||||
iright = whichcol(w, right-1) + 1
|
||||
if iright > len(w.data): iright = len(w.data)
|
||||
itop = divmod(top, w.lineheight)[0]
|
||||
if itop < 0: itop = 0
|
||||
ibottom, remainder = divmod(bottom, w.lineheight)
|
||||
if remainder: ibottom = ibottom + 1
|
||||
d = w.begindrawing()
|
||||
if ileft <= w.selection[0] < iright:
|
||||
if itop <= w.selection[1] < ibottom:
|
||||
hidesel(w, d)
|
||||
d.erase((left, top), (right, bottom))
|
||||
for i in range(ileft, iright):
|
||||
col = w.data[i]
|
||||
jbottom = len(col)
|
||||
if ibottom < jbottom: jbottom = ibottom
|
||||
h = w.colstarts[i]
|
||||
v = itop * w.lineheight
|
||||
for j in range(itop, jbottom):
|
||||
string, action = col[j]
|
||||
d.text((h, v), string)
|
||||
v = v + w.lineheight
|
||||
showsel(w, d)
|
||||
|
||||
def mup(w, detail): # Mouse up method
|
||||
(h, v), nclicks, button, mask = detail
|
||||
icol = whichcol(w, h)
|
||||
if 0 <= icol < len(w.data):
|
||||
irow = divmod(v, w.lineheight)[0]
|
||||
col = w.data[icol]
|
||||
if 0 <= irow < len(col):
|
||||
string, action = col[irow]
|
||||
action(w, string, (icol, irow), detail)
|
||||
|
||||
def whichcol(w, h): # Return column number (may be >= len(w.data))
|
||||
for icol in range(0, len(w.data)):
|
||||
if h < w.colstarts[icol+1]:
|
||||
return icol
|
||||
return len(w.data)
|
||||
|
||||
def arrow(w, type):
|
||||
import stdwinsupport
|
||||
S = stdwinsupport
|
||||
if type = S.wc_left:
|
||||
incr = -1, 0
|
||||
elif type = S.wc_up:
|
||||
incr = 0, -1
|
||||
elif type = S.wc_right:
|
||||
incr = 1, 0
|
||||
elif type = S.wc_down:
|
||||
incr = 0, 1
|
||||
else:
|
||||
return
|
||||
icol, irow = w.lastselection
|
||||
icol = icol + incr[0]
|
||||
if icol < 0: icol = len(w.data)-1
|
||||
if icol >= len(w.data): icol = 0
|
||||
if 0 <= icol < len(w.data):
|
||||
irow = irow + incr[1]
|
||||
if irow < 0: irow = len(w.data[icol]) - 1
|
||||
if irow >= len(w.data[icol]): irow = 0
|
||||
else:
|
||||
irow = 0
|
||||
if 0 <= icol < len(w.data) and 0 <= irow < len(w.data[icol]):
|
||||
w.lastselection = icol, irow
|
||||
string, action = w.data[icol][irow]
|
||||
detail = (0, 0), 1, 1, 1
|
||||
action(w, string, (icol, irow), detail)
|
||||
|
||||
|
||||
# Selection management
|
||||
# TO DO: allow multiple selected entries
|
||||
|
||||
def select(w, selection): # Public function to set the item selection
|
||||
d = w.begindrawing()
|
||||
hidesel(w, d)
|
||||
w.selection = selection
|
||||
showsel(w, d)
|
||||
if w.selshown: lastselection = selection
|
||||
|
||||
def hidesel(w, d): # Hide the selection, if shown
|
||||
if w.selshown: invertsel(w, d)
|
||||
|
||||
def showsel(w, d): # Show the selection, if hidden
|
||||
if not w.selshown: invertsel(w, d)
|
||||
|
||||
def invertsel(w, d): # Invert the selection, if valid
|
||||
icol, irow = w.selection
|
||||
if 0 <= icol < len(w.data) and 0 <= irow < len(w.data[icol]):
|
||||
left = w.colstarts[icol]
|
||||
right = w.colstarts[icol+1]
|
||||
top = irow * w.lineheight
|
||||
bottom = (irow+1) * w.lineheight
|
||||
d.invert((left, top), (right, bottom))
|
||||
w.selshown = (not w.selshown)
|
||||
|
||||
|
||||
# Demonstration
|
||||
|
||||
def demo_action(w, string, (icol, irow), detail): # Action function for demo
|
||||
select(w, (irow, icol))
|
||||
|
||||
def demo(): # Demonstration
|
||||
da = demo_action # shorthand
|
||||
col0 = [('a1', da), ('bbb1', da), ('c1', da)]
|
||||
col1 = [('a2', da), ('bbb2', da)]
|
||||
col2 = [('a3', da), ('b3', da), ('c3', da), ('d4', da), ('d5', da)]
|
||||
col3 = []
|
||||
for i in range(1, 31): col3.append('xxx' + `i`, da)
|
||||
data = [col0, col1, col2, col3]
|
||||
w = open('tablewin.demo', data)
|
||||
gwin.mainloop()
|
||||
return w
|
|
@ -0,0 +1,119 @@
|
|||
# Module 'textwin'
|
||||
|
||||
# Text windows, a subclass of gwin
|
||||
|
||||
import stdwin
|
||||
import stdwinsupport
|
||||
import gwin
|
||||
|
||||
S = stdwinsupport # Shorthand
|
||||
|
||||
|
||||
def fixsize(w):
|
||||
docwidth, docheight = w.text.getrect()[1]
|
||||
winheight = w.getwinsize()[1]
|
||||
if winheight > docheight: docheight = winheight
|
||||
w.setdocsize(0, docheight)
|
||||
fixeditmenu(w)
|
||||
|
||||
def cut(w, m, id):
|
||||
s = w.text.getfocustext()
|
||||
if s:
|
||||
stdwin.setcutbuffer(s)
|
||||
w.text.replace('')
|
||||
fixsize(w)
|
||||
|
||||
def copy(w, m, id):
|
||||
s = w.text.getfocustext()
|
||||
if s:
|
||||
stdwin.setcutbuffer(s)
|
||||
fixeditmenu(w)
|
||||
|
||||
def paste(w, m, id):
|
||||
w.text.replace(stdwin.getcutbuffer())
|
||||
fixsize(w)
|
||||
|
||||
def addeditmenu(w):
|
||||
m = w.editmenu = w.menucreate('Edit')
|
||||
m.action = []
|
||||
m.additem('Cut', 'X')
|
||||
m.action.append(cut)
|
||||
m.additem('Copy', 'C')
|
||||
m.action.append(copy)
|
||||
m.additem('Paste', 'V')
|
||||
m.action.append(paste)
|
||||
|
||||
def fixeditmenu(w):
|
||||
m = w.editmenu
|
||||
f = w.text.getfocus()
|
||||
can_copy = (f[0] < f[1])
|
||||
m.enable(1, can_copy)
|
||||
if not w.readonly:
|
||||
m.enable(0, can_copy)
|
||||
m.enable(2, (stdwin.getcutbuffer() <> ''))
|
||||
|
||||
def draw(w, area): # Draw method
|
||||
w.text.draw(area)
|
||||
|
||||
def size(w, newsize): # Size method
|
||||
w.text.move((0, 0), newsize)
|
||||
fixsize(w)
|
||||
|
||||
def close(w): # Close method
|
||||
del w.text # Break circular ref
|
||||
gwin.close(w)
|
||||
|
||||
def char(w, c): # Char method
|
||||
w.text.replace(c)
|
||||
fixsize(w)
|
||||
|
||||
def backspace(w): # Backspace method
|
||||
void = w.text.event(S.we_command, w, S.wc_backspace)
|
||||
fixsize(w)
|
||||
|
||||
def arrow(w, detail): # Arrow method
|
||||
w.text.arrow(detail)
|
||||
fixeditmenu(w)
|
||||
|
||||
def mdown(w, detail): # Mouse down method
|
||||
void = w.text.event(S.we_mouse_down, w, detail)
|
||||
fixeditmenu(w)
|
||||
|
||||
def mmove(w, detail): # Mouse move method
|
||||
void = w.text.event(S.we_mouse_move, w, detail)
|
||||
|
||||
def mup(w, detail): # Mouse up method
|
||||
void = w.text.event(S.we_mouse_up, w, detail)
|
||||
fixeditmenu(w)
|
||||
|
||||
def activate(w): # Activate method
|
||||
fixeditmenu(w)
|
||||
|
||||
def open(title, str): # Display a string in a window
|
||||
w = gwin.open(title)
|
||||
w.readonly = 0
|
||||
w.text = w.textcreate((0, 0), w.getwinsize())
|
||||
w.text.replace(str)
|
||||
w.text.setfocus(0, 0)
|
||||
addeditmenu(w)
|
||||
fixsize(w)
|
||||
w.draw = draw
|
||||
w.size = size
|
||||
w.close = close
|
||||
w.mdown = mdown
|
||||
w.mmove = mmove
|
||||
w.mup = mup
|
||||
w.char = char
|
||||
w.backspace = backspace
|
||||
w.arrow = arrow
|
||||
w.activate = activate
|
||||
return w
|
||||
|
||||
def open_readonly(title, str): # Same with char input disabled
|
||||
w = open(title, str)
|
||||
w.readonly = 1
|
||||
w.char = w.backspace = gwin.nop
|
||||
# Disable Cut and Paste menu item; leave Copy alone
|
||||
w.editmenu.enable(0, 0)
|
||||
w.editmenu.enable(2, 0)
|
||||
return w
|
|
@ -0,0 +1,423 @@
|
|||
#/**************************************************************************
|
||||
# * *
|
||||
# * Copyright (C) 1984, Silicon Graphics, Inc. *
|
||||
# * *
|
||||
# * These coded instructions, statements, and computer programs contain *
|
||||
# * unpublished proprietary information of Silicon Graphics, Inc., and *
|
||||
# * are protected by Federal copyright law. They may not be disclosed *
|
||||
# * to third parties or copied or duplicated in any form, in whole or *
|
||||
# * in part, without the prior written consent of Silicon Graphics, Inc. *
|
||||
# * *
|
||||
# **************************************************************************/
|
||||
#/* file with device definitions (see /usr/include/device.h) */
|
||||
|
||||
NULLDEV = 0
|
||||
BUTOFFSET = 1
|
||||
VALOFFSET = 256
|
||||
TIMOFFSET = 515
|
||||
XKBDOFFSET = 143
|
||||
INOFFSET = 1024
|
||||
OUTOFFSET = 1033
|
||||
BUTCOUNT = 190
|
||||
VALCOUNT = 27
|
||||
TIMCOUNT = 4
|
||||
XKBDCOUNT = 28
|
||||
INCOUNT = 8
|
||||
OUTCOUNT = 8
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
BUT0 = 1
|
||||
BUT1 = 2
|
||||
BUT2 = 3
|
||||
BUT3 = 4
|
||||
BUT4 = 5
|
||||
BUT5 = 6
|
||||
BUT6 = 7
|
||||
BUT7 = 8
|
||||
BUT8 = 9
|
||||
BUT9 = 10
|
||||
BUT10 = 11
|
||||
BUT11 = 12
|
||||
BUT12 = 13
|
||||
BUT13 = 14
|
||||
BUT14 = 15
|
||||
BUT15 = 16
|
||||
BUT16 = 17
|
||||
BUT17 = 18
|
||||
BUT18 = 19
|
||||
BUT19 = 20
|
||||
BUT20 = 21
|
||||
BUT21 = 22
|
||||
BUT22 = 23
|
||||
BUT23 = 24
|
||||
BUT24 = 25
|
||||
BUT25 = 26
|
||||
BUT26 = 27
|
||||
BUT27 = 28
|
||||
BUT28 = 29
|
||||
BUT29 = 30
|
||||
BUT30 = 31
|
||||
BUT31 = 32
|
||||
BUT32 = 33
|
||||
BUT33 = 34
|
||||
BUT34 = 35
|
||||
BUT35 = 36
|
||||
BUT36 = 37
|
||||
BUT37 = 38
|
||||
BUT38 = 39
|
||||
BUT39 = 40
|
||||
BUT40 = 41
|
||||
BUT41 = 42
|
||||
BUT42 = 43
|
||||
BUT43 = 44
|
||||
BUT44 = 45
|
||||
BUT45 = 46
|
||||
BUT46 = 47
|
||||
BUT47 = 48
|
||||
BUT48 = 49
|
||||
BUT49 = 50
|
||||
BUT50 = 51
|
||||
BUT51 = 52
|
||||
BUT52 = 53
|
||||
BUT53 = 54
|
||||
BUT54 = 55
|
||||
BUT55 = 56
|
||||
BUT56 = 57
|
||||
BUT57 = 58
|
||||
BUT58 = 59
|
||||
BUT59 = 60
|
||||
BUT60 = 61
|
||||
BUT61 = 62
|
||||
BUT62 = 63
|
||||
BUT63 = 64
|
||||
BUT64 = 65
|
||||
BUT65 = 66
|
||||
BUT66 = 67
|
||||
BUT67 = 68
|
||||
BUT68 = 69
|
||||
BUT69 = 70
|
||||
BUT70 = 71
|
||||
BUT71 = 72
|
||||
BUT72 = 73
|
||||
BUT73 = 74
|
||||
BUT74 = 75
|
||||
BUT75 = 76
|
||||
BUT76 = 77
|
||||
BUT77 = 78
|
||||
BUT78 = 79
|
||||
BUT79 = 80
|
||||
BUT80 = 81
|
||||
BUT81 = 82
|
||||
BUT82 = 83
|
||||
MAXKBDBUT = 83
|
||||
BUT100 = 101
|
||||
BUT101 = 102
|
||||
BUT102 = 103
|
||||
BUT110 = 111
|
||||
BUT111 = 112
|
||||
BUT112 = 113
|
||||
BUT113 = 114
|
||||
BUT114 = 115
|
||||
BUT115 = 116
|
||||
BUT116 = 117
|
||||
BUT117 = 118
|
||||
BUT118 = 119
|
||||
BUT119 = 120
|
||||
BUT120 = 121
|
||||
BUT121 = 122
|
||||
BUT122 = 123
|
||||
BUT123 = 124
|
||||
BUT124 = 125
|
||||
BUT125 = 126
|
||||
BUT126 = 127
|
||||
BUT127 = 128
|
||||
BUT128 = 129
|
||||
BUT129 = 130
|
||||
BUT130 = 131
|
||||
BUT131 = 132
|
||||
BUT132 = 133
|
||||
BUT133 = 134
|
||||
BUT134 = 135
|
||||
BUT135 = 136
|
||||
BUT136 = 137
|
||||
BUT137 = 138
|
||||
BUT138 = 139
|
||||
BUT139 = 140
|
||||
BUT140 = 141
|
||||
BUT141 = 142
|
||||
BUT142 = 143
|
||||
BUT143 = 144
|
||||
BUT144 = 145
|
||||
BUT145 = 146
|
||||
BUT146 = 147
|
||||
BUT147 = 148
|
||||
BUT148 = 149
|
||||
BUT149 = 150
|
||||
BUT150 = 151
|
||||
BUT151 = 152
|
||||
BUT152 = 153
|
||||
BUT153 = 154
|
||||
BUT154 = 155
|
||||
BUT155 = 156
|
||||
BUT156 = 157
|
||||
BUT157 = 158
|
||||
BUT158 = 159
|
||||
BUT159 = 160
|
||||
BUT160 = 161
|
||||
BUT161 = 162
|
||||
BUT162 = 163
|
||||
BUT163 = 164
|
||||
BUT164 = 165
|
||||
BUT165 = 166
|
||||
BUT166 = 167
|
||||
BUT167 = 168
|
||||
BUT168 = 169
|
||||
BUT181 = 182
|
||||
BUT182 = 183
|
||||
BUT183 = 184
|
||||
BUT184 = 185
|
||||
BUT185 = 186
|
||||
BUT186 = 187
|
||||
BUT187 = 188
|
||||
BUT188 = 189
|
||||
BUT189 = 190
|
||||
MOUSE1 = 101
|
||||
MOUSE2 = 102
|
||||
MOUSE3 = 103
|
||||
LEFTMOUSE = 103
|
||||
MIDDLEMOUSE = 102
|
||||
RIGHTMOUSE = 101
|
||||
LPENBUT = 104
|
||||
BPAD0 = 105
|
||||
BPAD1 = 106
|
||||
BPAD2 = 107
|
||||
BPAD3 = 108
|
||||
LPENVALID = 109
|
||||
SWBASE = 111
|
||||
SW0 = 111
|
||||
SW1 = 112
|
||||
SW2 = 113
|
||||
SW3 = 114
|
||||
SW4 = 115
|
||||
SW5 = 116
|
||||
SW6 = 117
|
||||
SW7 = 118
|
||||
SW8 = 119
|
||||
SW9 = 120
|
||||
SW10 = 121
|
||||
SW11 = 122
|
||||
SW12 = 123
|
||||
SW13 = 124
|
||||
SW14 = 125
|
||||
SW15 = 126
|
||||
SW16 = 127
|
||||
SW17 = 128
|
||||
SW18 = 129
|
||||
SW19 = 130
|
||||
SW20 = 131
|
||||
SW21 = 132
|
||||
SW22 = 133
|
||||
SW23 = 134
|
||||
SW24 = 135
|
||||
SW25 = 136
|
||||
SW26 = 137
|
||||
SW27 = 138
|
||||
SW28 = 139
|
||||
SW29 = 140
|
||||
SW30 = 141
|
||||
SW31 = 142
|
||||
SBBASE = 182
|
||||
SBPICK = 182
|
||||
SBBUT1 = 183
|
||||
SBBUT2 = 184
|
||||
SBBUT3 = 185
|
||||
SBBUT4 = 186
|
||||
SBBUT5 = 187
|
||||
SBBUT6 = 188
|
||||
SBBUT7 = 189
|
||||
SBBUT8 = 190
|
||||
AKEY = 11
|
||||
BKEY = 36
|
||||
CKEY = 28
|
||||
DKEY = 18
|
||||
EKEY = 17
|
||||
FKEY = 19
|
||||
GKEY = 26
|
||||
HKEY = 27
|
||||
IKEY = 40
|
||||
JKEY = 34
|
||||
KKEY = 35
|
||||
LKEY = 42
|
||||
MKEY = 44
|
||||
NKEY = 37
|
||||
OKEY = 41
|
||||
PKEY = 48
|
||||
QKEY = 10
|
||||
RKEY = 24
|
||||
SKEY = 12
|
||||
TKEY = 25
|
||||
UKEY = 33
|
||||
VKEY = 29
|
||||
WKEY = 16
|
||||
XKEY = 21
|
||||
YKEY = 32
|
||||
ZKEY = 20
|
||||
ZEROKEY = 46
|
||||
ONEKEY = 8
|
||||
TWOKEY = 14
|
||||
THREEKEY = 15
|
||||
FOURKEY = 22
|
||||
FIVEKEY = 23
|
||||
SIXKEY = 30
|
||||
SEVENKEY = 31
|
||||
EIGHTKEY = 38
|
||||
NINEKEY = 39
|
||||
BREAKKEY = 1
|
||||
SETUPKEY = 2
|
||||
CTRLKEY = 3
|
||||
LEFTCTRLKEY = CTRLKEY
|
||||
CAPSLOCKKEY = 4
|
||||
RIGHTSHIFTKEY = 5
|
||||
LEFTSHIFTKEY = 6
|
||||
NOSCRLKEY = 13
|
||||
ESCKEY = 7
|
||||
TABKEY = 9
|
||||
RETKEY = 51
|
||||
SPACEKEY = 83
|
||||
LINEFEEDKEY = 60
|
||||
BACKSPACEKEY = 61
|
||||
DELKEY = 62
|
||||
SEMICOLONKEY = 43
|
||||
PERIODKEY = 52
|
||||
COMMAKEY = 45
|
||||
QUOTEKEY = 50
|
||||
ACCENTGRAVEKEY = 55
|
||||
MINUSKEY = 47
|
||||
VIRGULEKEY = 53
|
||||
BACKSLASHKEY = 57
|
||||
EQUALKEY = 54
|
||||
LEFTBRACKETKEY = 49
|
||||
RIGHTBRACKETKEY = 56
|
||||
LEFTARROWKEY = 73
|
||||
DOWNARROWKEY = 74
|
||||
RIGHTARROWKEY = 80
|
||||
UPARROWKEY = 81
|
||||
PAD0 = 59
|
||||
PAD1 = 58
|
||||
PAD2 = 64
|
||||
PAD3 = 65
|
||||
PAD4 = 63
|
||||
PAD5 = 69
|
||||
PAD6 = 70
|
||||
PAD7 = 67
|
||||
PAD8 = 68
|
||||
PAD9 = 75
|
||||
PADPF1 = 72
|
||||
PADPF2 = 71
|
||||
PADPF3 = 79
|
||||
PADPF4 = 78
|
||||
PADPERIOD = 66
|
||||
PADMINUS = 76
|
||||
PADCOMMA = 77
|
||||
PADENTER = 82
|
||||
LEFTALTKEY = 143
|
||||
RIGHTALTKEY = 144
|
||||
RIGHTCTRLKEY = 145
|
||||
F1KEY = 146
|
||||
F2KEY = 147
|
||||
F3KEY = 148
|
||||
F4KEY = 149
|
||||
F5KEY = 150
|
||||
F6KEY = 151
|
||||
F7KEY = 152
|
||||
F8KEY = 153
|
||||
F9KEY = 154
|
||||
F10KEY = 155
|
||||
F11KEY = 156
|
||||
F12KEY = 157
|
||||
PRINTSCREENKEY = 158
|
||||
SCROLLLOCKKEY = 159
|
||||
PAUSEKEY = 160
|
||||
INSERTKEY = 161
|
||||
HOMEKEY = 162
|
||||
PAGEUPKEY = 163
|
||||
ENDKEY = 164
|
||||
PAGEDOWNKEY = 165
|
||||
NUMLOCKKEY = 166
|
||||
PADVIRGULEKEY = 167
|
||||
PADASTERKEY = 168
|
||||
PADPLUSKEY = 169
|
||||
SGIRESERVED = 256
|
||||
DIAL0 = 257
|
||||
DIAL1 = 258
|
||||
DIAL2 = 259
|
||||
DIAL3 = 260
|
||||
DIAL4 = 261
|
||||
DIAL5 = 262
|
||||
DIAL6 = 263
|
||||
DIAL7 = 264
|
||||
DIAL8 = 265
|
||||
MOUSEX = 266
|
||||
MOUSEY = 267
|
||||
LPENX = 268
|
||||
LPENY = 269
|
||||
BPADX = 270
|
||||
BPADY = 271
|
||||
CURSORX = 272
|
||||
CURSORY = 273
|
||||
GHOSTX = 274
|
||||
GHOSTY = 275
|
||||
SBTX = 276
|
||||
SBTY = 277
|
||||
SBTZ = 278
|
||||
SBRX = 279
|
||||
SBRY = 280
|
||||
SBRZ = 281
|
||||
SBPERIOD = 282
|
||||
TIMER0 = 515
|
||||
TIMER1 = 516
|
||||
TIMER2 = 517
|
||||
TIMER3 = 518
|
||||
KEYBD = 513
|
||||
RAWKEYBD = 514
|
||||
VALMARK = 523
|
||||
GERROR = 524
|
||||
REDRAW = 528
|
||||
WMSEND = 529
|
||||
WMREPLY = 530
|
||||
WMGFCLOSE = 531
|
||||
WMTXCLOSE = 532
|
||||
MODECHANGE = 533
|
||||
INPUTCHANGE = 534
|
||||
QFULL = 535
|
||||
PIECECHANGE = 536
|
||||
WINCLOSE = 537
|
||||
QREADERROR = 538
|
||||
WINFREEZE = 539
|
||||
WINTHAW = 540
|
||||
REDRAWICONIC = 541
|
||||
WINQUIT = 542
|
||||
DEPTHCHANGE = 543
|
||||
KEYBDFNAMES = 544
|
||||
KEYBDFSTRINGS = 545
|
||||
WINSHUT = 546
|
||||
INPUT0 = 1024
|
||||
INPUT1 = 1025
|
||||
INPUT2 = 1026
|
||||
INPUT3 = 1027
|
||||
INPUT4 = 1028
|
||||
INPUT5 = 1029
|
||||
INPUT6 = 1030
|
||||
INPUT7 = 1032
|
||||
OUTPUT0 = 1033
|
||||
OUTPUT1 = 1034
|
||||
OUTPUT2 = 1035
|
||||
OUTPUT3 = 1036
|
||||
OUTPUT4 = 1037
|
||||
OUTPUT5 = 1038
|
||||
OUTPUT6 = 1039
|
||||
OUTPUT7 = 1040
|
||||
MAXSGIDEVICE = 20000
|
||||
MENUBUTTON = RIGHTMOUSE
|
|
@ -0,0 +1,365 @@
|
|||
# Constants defined in <gl.h>
|
||||
|
||||
#**************************************************************************
|
||||
#* *
|
||||
#* Copyright (C) 1984, Silicon Graphics, Inc. *
|
||||
#* *
|
||||
#* These coded instructions, statements, and computer programs contain *
|
||||
#* unpublished proprietary information of Silicon Graphics, Inc., and *
|
||||
#* are protected by Federal copyright law. They may not be disclosed *
|
||||
#* to third parties or copied or duplicated in any form, in whole or *
|
||||
#* in part, without the prior written consent of Silicon Graphics, Inc. *
|
||||
#* *
|
||||
#**************************************************************************
|
||||
|
||||
# Graphics Libary constants
|
||||
|
||||
# Booleans
|
||||
TRUE = 1
|
||||
FALSE = 0
|
||||
|
||||
# maximum X and Y screen coordinates
|
||||
XMAXSCREEN = 1279
|
||||
YMAXSCREEN = 1023
|
||||
XMAXMEDIUM = 1023 # max for medium res monitor
|
||||
YMAXMEDIUM = 767
|
||||
XMAX170 = 645 # max for RS-170
|
||||
YMAX170 = 484
|
||||
XMAXPAL = 779 # max for PAL
|
||||
YMAXPAL = 574
|
||||
|
||||
# various hardware/software limits
|
||||
ATTRIBSTACKDEPTH = 10
|
||||
VPSTACKDEPTH = 8
|
||||
MATRIXSTACKDEPTH = 32
|
||||
NAMESTACKDEPTH = 1025
|
||||
STARTTAG = -2
|
||||
ENDTAG = -3
|
||||
CPOSX_INVALID = -(2*XMAXSCREEN)
|
||||
|
||||
# names for colors in color map loaded by greset
|
||||
BLACK = 0
|
||||
RED = 1
|
||||
GREEN = 2
|
||||
YELLOW = 3
|
||||
BLUE = 4
|
||||
MAGENTA = 5
|
||||
CYAN = 6
|
||||
WHITE = 7
|
||||
|
||||
# popup colors
|
||||
PUP_CLEAR = 0
|
||||
PUP_COLOR = 1
|
||||
PUP_BLACK = 2
|
||||
PUP_WHITE = 3
|
||||
|
||||
# defines for drawmode
|
||||
NORMALDRAW = 0
|
||||
PUPDRAW = 1
|
||||
OVERDRAW = 2
|
||||
UNDERDRAW = 3
|
||||
CURSORDRAW = 4
|
||||
|
||||
# defines for defpattern
|
||||
PATTERN_16 = 16
|
||||
PATTERN_32 = 32
|
||||
PATTERN_64 = 64
|
||||
|
||||
PATTERN_16_SIZE = 16
|
||||
PATTERN_32_SIZE = 64
|
||||
PATTERN_64_SIZE = 256
|
||||
|
||||
# defines for readsource
|
||||
SRC_AUTO = 0
|
||||
SRC_FRONT = 1
|
||||
SRC_BACK = 2
|
||||
SRC_ZBUFFER = 3
|
||||
SRC_PUP = 4
|
||||
SRC_OVER = 5
|
||||
SRC_UNDER = 6
|
||||
SRC_FRAMEGRABBER = 7
|
||||
|
||||
# defines for blendfunction
|
||||
BF_ZERO = 0
|
||||
BF_ONE = 1
|
||||
BF_DC = 2
|
||||
BF_SC = 2
|
||||
BF_MDC = 3
|
||||
BF_MSC = 3
|
||||
BF_SA = 4
|
||||
BF_MSA = 5
|
||||
BF_DA = 6
|
||||
BF_MDA = 7
|
||||
|
||||
# defines for zfunction
|
||||
ZF_NEVER = 0
|
||||
ZF_LESS = 1
|
||||
ZF_EQUAL = 2
|
||||
ZF_LEQUAL = 3
|
||||
ZF_GREATER = 4
|
||||
ZF_NOTEQUAL = 5
|
||||
ZF_GEQUAL = 6
|
||||
ZF_ALWAYS = 7
|
||||
|
||||
# defines for zsource
|
||||
ZSRC_DEPTH = 0
|
||||
ZSRC_COLOR = 1
|
||||
|
||||
# defines for pntsmooth
|
||||
SMP_OFF = 0
|
||||
SMP_ON = 1
|
||||
|
||||
# defines for linesmooth
|
||||
SML_OFF = 0
|
||||
SML_ON = 1
|
||||
|
||||
# defines for setpup
|
||||
PUP_NONE = 0
|
||||
PUP_GREY = 1
|
||||
|
||||
# defines for glcompat
|
||||
GLC_OLDPOLYGON = 0
|
||||
GLC_ZRANGEMAP = 1
|
||||
|
||||
# defines for curstype
|
||||
C16X1 = 0
|
||||
C16X2 = 1
|
||||
C32X1 = 2
|
||||
C32X2 = 3
|
||||
CCROSS = 4
|
||||
|
||||
# defines for shademodel
|
||||
FLAT = 0
|
||||
GOURAUD = 1
|
||||
|
||||
# defines for logicop
|
||||
### LO_ZERO = 0x0
|
||||
### LO_AND = 0x1
|
||||
### LO_ANDR = 0x2
|
||||
### LO_SRC = 0x3
|
||||
### LO_ANDI = 0x4
|
||||
### LO_DST = 0x5
|
||||
### LO_XOR = 0x6
|
||||
### LO_OR = 0x7
|
||||
### LO_NOR = 0x8
|
||||
### LO_XNOR = 0x9
|
||||
### LO_NDST = 0xa
|
||||
### LO_ORR = 0xb
|
||||
### LO_NSRC = 0xc
|
||||
### LO_ORI = 0xd
|
||||
### LO_NAND = 0xe
|
||||
### LO_ONE = 0xf
|
||||
|
||||
|
||||
#
|
||||
# START defines for getgdesc
|
||||
#
|
||||
|
||||
GD_XPMAX = 0
|
||||
GD_YPMAX = 1
|
||||
GD_XMMAX = 2
|
||||
GD_YMMAX = 3
|
||||
GD_ZMIN = 4
|
||||
GD_ZMAX = 5
|
||||
GD_BITS_NORM_SNG_RED = 6
|
||||
GD_BITS_NORM_SNG_GREEN = 7
|
||||
GD_BITS_NORM_SNG_BLUE = 8
|
||||
GD_BITS_NORM_DBL_RED = 9
|
||||
GD_BITS_NORM_DBL_GREEN = 10
|
||||
GD_BITS_NORM_DBL_BLUE = 11
|
||||
GD_BITS_NORM_SNG_CMODE = 12
|
||||
GD_BITS_NORM_DBL_CMODE = 13
|
||||
GD_BITS_NORM_SNG_MMAP = 14
|
||||
GD_BITS_NORM_DBL_MMAP = 15
|
||||
GD_BITS_NORM_ZBUFFER = 16
|
||||
GD_BITS_OVER_SNG_CMODE = 17
|
||||
GD_BITS_UNDR_SNG_CMODE = 18
|
||||
GD_BITS_PUP_SNG_CMODE = 19
|
||||
GD_BITS_NORM_SNG_ALPHA = 21
|
||||
GD_BITS_NORM_DBL_ALPHA = 22
|
||||
GD_BITS_CURSOR = 23
|
||||
GD_OVERUNDER_SHARED = 24
|
||||
GD_BLEND = 25
|
||||
GD_CIFRACT = 26
|
||||
GD_CROSSHAIR_CINDEX = 27
|
||||
GD_DITHER = 28
|
||||
GD_LINESMOOTH_CMODE = 30
|
||||
GD_LINESMOOTH_RGB = 31
|
||||
GD_LOGICOP = 33
|
||||
GD_NSCRNS = 35
|
||||
GD_NURBS_ORDER = 36
|
||||
GD_NBLINKS = 37
|
||||
GD_NVERTEX_POLY = 39
|
||||
GD_PATSIZE_64 = 40
|
||||
GD_PNTSMOOTH_CMODE = 41
|
||||
GD_PNTSMOOTH_RGB = 42
|
||||
GD_PUP_TO_OVERUNDER = 43
|
||||
GD_READSOURCE = 44
|
||||
GD_READSOURCE_ZBUFFER = 48
|
||||
GD_STEREO = 50
|
||||
GD_SUBPIXEL_LINE = 51
|
||||
GD_SUBPIXEL_PNT = 52
|
||||
GD_SUBPIXEL_POLY = 53
|
||||
GD_TRIMCURVE_ORDER = 54
|
||||
GD_WSYS = 55
|
||||
GD_ZDRAW_GEOM = 57
|
||||
GD_ZDRAW_PIXELS = 58
|
||||
GD_SCRNTYPE = 61
|
||||
GD_TEXTPORT = 62
|
||||
GD_NMMAPS = 63
|
||||
GD_FRAMEGRABBER = 64
|
||||
GD_TIMERHZ = 66
|
||||
GD_DBBOX = 67
|
||||
GD_AFUNCTION = 68
|
||||
GD_ALPHA_OVERUNDER = 69
|
||||
GD_BITS_ACBUF = 70
|
||||
GD_BITS_ACBUF_HW = 71
|
||||
GD_BITS_STENCIL = 72
|
||||
GD_CLIPPLANES = 73
|
||||
GD_FOGVERTEX = 74
|
||||
GD_LIGHTING_TWOSIDE = 76
|
||||
GD_POLYMODE = 77
|
||||
GD_POLYSMOOTH = 78
|
||||
GD_SCRBOX = 79
|
||||
GD_TEXTURE = 80
|
||||
|
||||
# return value for inquiries when there is no limit
|
||||
GD_NOLIMIT = 2
|
||||
|
||||
# return values for GD_WSYS
|
||||
GD_WSYS_NONE = 0
|
||||
GD_WSYS_4S = 1
|
||||
|
||||
# return values for GD_SCRNTYPE
|
||||
GD_SCRNTYPE_WM = 0
|
||||
GD_SCRNTYPE_NOWM = 1
|
||||
|
||||
#
|
||||
# END defines for getgdesc
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# START NURBS interface definitions
|
||||
#
|
||||
|
||||
# NURBS Rendering Properties
|
||||
N_PIXEL_TOLERANCE = 1
|
||||
N_CULLING = 2
|
||||
N_DISPLAY = 3
|
||||
N_ERRORCHECKING = 4
|
||||
N_SUBDIVISIONS = 5
|
||||
N_S_STEPS = 6
|
||||
N_T_STEPS = 7
|
||||
N_TILES = 8
|
||||
|
||||
N_SHADED = 1.0
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# FLAGS FOR NURBS SURFACES AND CURVES
|
||||
#
|
||||
# Bit: 9876 5432 1 0
|
||||
# |tttt|nnnn|f|r| : r - 1 bit = 1 if rational coordinate exists
|
||||
# : f - 1 bit = 1 if rational coordinate is before rest
|
||||
# : = 0 if rational coordinate is after rest
|
||||
# : nnnn - 4 bits for number of coordinates
|
||||
# : tttt - 4 bits for type of data (color, position, etc.)
|
||||
#
|
||||
# NURBS data type
|
||||
# N_T_ST 0 parametric space data
|
||||
# N_T_XYZ 1 model space data
|
||||
#
|
||||
# rational or non-rational data and position in memory
|
||||
# N_NONRATIONAL 0 non-rational data
|
||||
# N_RATAFTER 1 rational data with rat coord after rest
|
||||
# N_RATBEFORE 3 rational data with rat coord before rest
|
||||
#
|
||||
# N_MKFLAG(a,b,c) ((a<<6) | (b<<2) | c)
|
||||
#
|
||||
# ---------------------------------------------------------------------------
|
||||
#
|
||||
N_ST = 0x8 # N_MKFLAG( N_T_ST, 2, N_NONRATIONAL )
|
||||
N_STW = 0xd # N_MKFLAG( N_T_ST, 3, N_RATAFTER )
|
||||
N_WST = 0xf # N_MKFLAG( N_T_ST, 3, N_RATBEFORE )
|
||||
N_XYZ = 0x4c # N_MKFLAG( N_T_XYZ, 3, N_NONRATIONAL )
|
||||
N_XYZW = 0x51 # N_MKFLAG( N_T_XYZ, 4, N_RATAFTER )
|
||||
N_WXYZ = 0x53 # N_MKFLAG( N_T_XYZ, 4, N_RATBEFORE )
|
||||
|
||||
#
|
||||
# END NURBS interface definitions
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# START lighting model defines
|
||||
#
|
||||
|
||||
LMNULL = 0.0
|
||||
|
||||
# MATRIX modes
|
||||
MSINGLE = 0
|
||||
MPROJECTION = 1
|
||||
MVIEWING = 2
|
||||
|
||||
# LIGHT constants
|
||||
MAXLIGHTS = 8
|
||||
MAXRESTRICTIONS = 4
|
||||
|
||||
# MATERIAL properties
|
||||
DEFMATERIAL = 0
|
||||
EMISSION = 1
|
||||
AMBIENT = 2
|
||||
DIFFUSE = 3
|
||||
SPECULAR = 4
|
||||
SHININESS = 5
|
||||
COLORINDEXES = 6
|
||||
ALPHA = 7
|
||||
|
||||
# LIGHT properties
|
||||
DEFLIGHT = 100
|
||||
LCOLOR = 101
|
||||
POSITION = 102
|
||||
|
||||
# LIGHTINGMODEL properties
|
||||
DEFLMODEL = 200
|
||||
LOCALVIEWER = 201
|
||||
ATTENUATION = 202
|
||||
|
||||
# TARGET constants
|
||||
MATERIAL = 1000
|
||||
LIGHT0 = 1100
|
||||
LIGHT1 = 1101
|
||||
LIGHT2 = 1102
|
||||
LIGHT3 = 1103
|
||||
LIGHT4 = 1104
|
||||
LIGHT5 = 1105
|
||||
LIGHT6 = 1106
|
||||
LIGHT7 = 1107
|
||||
LMODEL = 1200
|
||||
|
||||
# lmcolor modes
|
||||
LMC_COLOR = 0
|
||||
LMC_EMISSION = 1
|
||||
LMC_AMBIENT = 2
|
||||
LMC_DIFFUSE = 3
|
||||
LMC_SPECULAR = 4
|
||||
LMC_AD = 5
|
||||
LMC_NULL = 6
|
||||
|
||||
#
|
||||
# END lighting model defines
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# START distributed graphics library defines
|
||||
#
|
||||
|
||||
DGLSINK = 0 # sink connection
|
||||
DGLLOCAL = 1 # local connection
|
||||
DGLTSOCKET = 2 # tcp socket connection
|
||||
DGL4DDN = 3 # 4DDN (DECnet)
|
||||
|
||||
#
|
||||
# END distributed graphics library defines
|
||||
#
|
|
@ -0,0 +1,281 @@
|
|||
# Module 'panel'
|
||||
#
|
||||
# Support for the Panel library.
|
||||
# Uses built-in module 'pnl'.
|
||||
# Applciations should use 'panel.function' instead of 'pnl.function';
|
||||
# most 'pnl' functions are transparently exported by 'panel',
|
||||
# but dopanel() is overridden and you have to use this version
|
||||
# if you want to use callbacks.
|
||||
|
||||
|
||||
import pnl
|
||||
|
||||
|
||||
debug = 0
|
||||
|
||||
|
||||
# Test if an object is a list.
|
||||
#
|
||||
def is_list(x):
|
||||
return type(x) = type([])
|
||||
|
||||
|
||||
# Reverse a list.
|
||||
#
|
||||
def reverse(list):
|
||||
res = []
|
||||
for item in list:
|
||||
res.insert(0, item)
|
||||
return res
|
||||
|
||||
|
||||
# Get an attribute of a list, which may itself be another list.
|
||||
# Don't use 'prop' for name.
|
||||
#
|
||||
def getattrlist(list, name):
|
||||
for item in list:
|
||||
if item and is_list(item) and item[0] = name:
|
||||
return item[1:]
|
||||
return []
|
||||
|
||||
|
||||
# Get a property of a list, which may itself be another list.
|
||||
#
|
||||
def getproplist(list, name):
|
||||
for item in list:
|
||||
if item and is_list(item) and item[0] = 'prop':
|
||||
if len(item) > 1 and item[1] = name:
|
||||
return item[2:]
|
||||
return []
|
||||
|
||||
|
||||
# Test if an actuator description contains the property 'end-of-group'
|
||||
#
|
||||
def is_endgroup(list):
|
||||
x = getproplist(list, 'end-of-group')
|
||||
return (x and x[0] = '#t')
|
||||
|
||||
|
||||
# Neatly display an actuator definition given as S-expression
|
||||
# the prefix string is printed before each line.
|
||||
#
|
||||
def show_actuator(prefix, a):
|
||||
for item in a:
|
||||
if not is_list(item):
|
||||
print prefix, item
|
||||
elif item and item[0] = 'al':
|
||||
print prefix, 'Subactuator list:'
|
||||
for a in item[1:]:
|
||||
show_actuator(prefix + ' ', a)
|
||||
elif len(item) = 2:
|
||||
print prefix, item[0], '=>', item[1]
|
||||
elif len(item) = 3 and item[0] = 'prop':
|
||||
print prefix, 'Prop', item[1], '=>',
|
||||
print item[2]
|
||||
else:
|
||||
print prefix, '?', item
|
||||
|
||||
|
||||
# Neatly display a panel.
|
||||
#
|
||||
def show_panel(prefix, p):
|
||||
for item in p:
|
||||
if not is_list(item):
|
||||
print prefix, item
|
||||
elif item and item[0] = 'al':
|
||||
print prefix, 'Actuator list:'
|
||||
for a in item[1:]:
|
||||
show_actuator(prefix + ' ', a)
|
||||
elif len(item) = 2:
|
||||
print prefix, item[0], '=>', item[1]
|
||||
elif len(item) = 3 and item[0] = 'prop':
|
||||
print prefix, 'Prop', item[1], '=>',
|
||||
print item[2]
|
||||
else:
|
||||
print prefix, '?', item
|
||||
|
||||
|
||||
# Exception raised by build_actuator or build_panel.
|
||||
#
|
||||
panel_error = 'panel error'
|
||||
|
||||
|
||||
# Dummy callback used to initialize the callbacks.
|
||||
#
|
||||
def dummy_callback(arg):
|
||||
pass
|
||||
|
||||
|
||||
# Assign attributes to members of the target.
|
||||
# Attribute names in exclist are ignored.
|
||||
# The member name is the attribute name prefixed with the prefix.
|
||||
#
|
||||
def assign_members(target, attrlist, exclist, prefix):
|
||||
for item in attrlist:
|
||||
if is_list(item) and len(item) = 2 and item[0] not in exclist:
|
||||
name, value = item[0], item[1]
|
||||
ok = 1
|
||||
if value[0] in '-0123456789':
|
||||
value = eval(value)
|
||||
elif value[0] = '"':
|
||||
value = value[1:-1]
|
||||
elif value = 'move-then-resize':
|
||||
# Strange default set by Panel Editor...
|
||||
ok = 0
|
||||
else:
|
||||
print 'unknown value', value, 'for', name
|
||||
ok = 0
|
||||
if ok:
|
||||
lhs = 'target.' + prefix + name
|
||||
stmt = lhs + '=' + `value`
|
||||
if debug: print 'exec', stmt
|
||||
try:
|
||||
exec(stmt + '\n')
|
||||
except KeyboardInterrupt: # Don't catch this!
|
||||
raise KeyboardInterrupt
|
||||
except:
|
||||
print 'assign failed:', stmt
|
||||
|
||||
|
||||
# Build a real actuator from an actuator descriptior.
|
||||
# Return a pair (actuator, name).
|
||||
#
|
||||
def build_actuator(descr):
|
||||
namelist = getattrlist(descr, 'name')
|
||||
if namelist:
|
||||
# Assume it is a string
|
||||
actuatorname = namelist[0][1:-1]
|
||||
else:
|
||||
actuatorname = ''
|
||||
type = descr[0]
|
||||
if type[:4] = 'pnl_': type = type[4:]
|
||||
act = pnl.mkact(type)
|
||||
act.downfunc = act.activefunc = act.upfunc = dummy_callback
|
||||
#
|
||||
assign_members(act, descr[1:], ('al', 'data', 'name'), '')
|
||||
#
|
||||
# Treat actuator-specific data
|
||||
#
|
||||
datalist = getattrlist(descr, 'data')
|
||||
prefix = ''
|
||||
if type[-4:] = 'puck':
|
||||
prefix = 'puck_'
|
||||
elif type = 'mouse':
|
||||
prefix = 'mouse_'
|
||||
assign_members(act, datalist, (), prefix)
|
||||
#
|
||||
return act, actuatorname
|
||||
|
||||
|
||||
# Build all sub-actuators and add them to the super-actuator.
|
||||
# The super-actuator must already have been added to the panel.
|
||||
# Sub-actuators with defined names are added as members to the panel
|
||||
# so they can be referenced as p.name.
|
||||
#
|
||||
# Note: I have no idea how panel.endgroup() works when applied
|
||||
# to a sub-actuator.
|
||||
#
|
||||
def build_subactuators(panel, super_act, al):
|
||||
#
|
||||
# This is nearly the same loop as below in build_panel(),
|
||||
# except a call is made to addsubact() instead of addact().
|
||||
#
|
||||
for a in al:
|
||||
act, name = build_actuator(a)
|
||||
act.addsubact(super_act)
|
||||
if name:
|
||||
stmt = 'panel.' + name + ' = act'
|
||||
if debug: print 'exec', stmt
|
||||
exec(stmt + '\n')
|
||||
if is_endgroup(a):
|
||||
panel.endgroup()
|
||||
sub_al = getattrlist(a, 'al')
|
||||
if sub_al:
|
||||
build_subactuators(panel, act, sub_al)
|
||||
#
|
||||
# Fix the actuator to which whe just added subactuators.
|
||||
# This can't hurt (I hope) and is needed for the scroll actuator.
|
||||
#
|
||||
super_act.fixact()
|
||||
|
||||
|
||||
# Build a real panel from a panel definition.
|
||||
# Return a panel object p, where for each named actuator a, p.name is a
|
||||
# reference to a.
|
||||
#
|
||||
def build_panel(descr):
|
||||
#
|
||||
# Sanity check
|
||||
#
|
||||
if (not descr) or descr[0] <> 'panel':
|
||||
raise panel_error, 'panel description must start with "panel"'
|
||||
#
|
||||
if debug: show_panel('', descr)
|
||||
#
|
||||
# Create an empty panel
|
||||
#
|
||||
panel = pnl.mkpanel()
|
||||
#
|
||||
# Assign panel attributes
|
||||
#
|
||||
assign_members(panel, descr[1:], ('al'), '')
|
||||
#
|
||||
# Look for actuator list
|
||||
#
|
||||
al = getattrlist(descr, 'al')
|
||||
#
|
||||
# The order in which actuators are created is important
|
||||
# because of the endgroup() operator.
|
||||
# Unfortunately the Panel Editor outputs the actuator list
|
||||
# in reverse order, so we reverse it here.
|
||||
#
|
||||
al = reverse(al)
|
||||
#
|
||||
for a in al:
|
||||
act, name = build_actuator(a)
|
||||
act.addact(panel)
|
||||
if name:
|
||||
stmt = 'panel.' + name + ' = act'
|
||||
exec(stmt + '\n')
|
||||
if is_endgroup(a):
|
||||
panel.endgroup()
|
||||
sub_al = getattrlist(a, 'al')
|
||||
if sub_al:
|
||||
build_subactuators(panel, act, sub_al)
|
||||
#
|
||||
return panel
|
||||
|
||||
|
||||
# Wrapper around pnl.dopanel() which calls call-back functions.
|
||||
#
|
||||
def my_dopanel():
|
||||
# Extract only the first 4 elements to allow for future expansion
|
||||
a, down, active, up = pnl.dopanel()[:4]
|
||||
if down:
|
||||
down.downfunc(down)
|
||||
if active:
|
||||
active.activefunc(active)
|
||||
if up:
|
||||
up.upfunc(up)
|
||||
return a
|
||||
|
||||
|
||||
# Create one or more panels from a description file (S-expressions)
|
||||
# generated by the Panel Editor.
|
||||
#
|
||||
def defpanellist(file):
|
||||
import parser
|
||||
descrlist = parser.parse_file(open(file, 'r'))
|
||||
panellist = []
|
||||
for descr in descrlist:
|
||||
panellist.append(build_panel(descr))
|
||||
return panellist
|
||||
|
||||
|
||||
# Import everything from built-in method pnl, so the user can always
|
||||
# use panel.foo() instead of pnl.foo().
|
||||
# This gives *no* performance penalty once this module is imported.
|
||||
#
|
||||
from pnl import * # for export
|
||||
|
||||
dopanel = my_dopanel # override pnl.dopanel
|
|
@ -0,0 +1,128 @@
|
|||
# Module 'parser'
|
||||
#
|
||||
# Parse S-expressions output by the Panel Editor
|
||||
# (which is written in Scheme so it can't help writing S-expressions).
|
||||
#
|
||||
# See notes at end of file.
|
||||
|
||||
|
||||
whitespace = ' \t\n'
|
||||
operators = '()\''
|
||||
separators = operators + whitespace + ';' + '"'
|
||||
|
||||
|
||||
# Tokenize a string.
|
||||
# Return a list of tokens (strings).
|
||||
#
|
||||
def tokenize_string(s):
|
||||
tokens = []
|
||||
while s:
|
||||
c = s[:1]
|
||||
if c in whitespace:
|
||||
s = s[1:]
|
||||
elif c = ';':
|
||||
s = ''
|
||||
elif c = '"':
|
||||
n = len(s)
|
||||
i = 1
|
||||
while i < n:
|
||||
c = s[i]
|
||||
i = i+1
|
||||
if c = '"': break
|
||||
if c = '\\': i = i+1
|
||||
tokens.append(s[:i])
|
||||
s = s[i:]
|
||||
elif c in operators:
|
||||
tokens.append(c)
|
||||
s = s[1:]
|
||||
else:
|
||||
n = len(s)
|
||||
i = 1
|
||||
while i < n:
|
||||
if s[i] in separators: break
|
||||
i = i+1
|
||||
tokens.append(s[:i])
|
||||
s = s[i:]
|
||||
return tokens
|
||||
|
||||
|
||||
# Tokenize a whole file (given as file object, not as file name).
|
||||
# Return a list of tokens (strings).
|
||||
#
|
||||
def tokenize_file(fp):
|
||||
tokens = []
|
||||
while 1:
|
||||
line = fp.readline()
|
||||
if not line: break
|
||||
tokens = tokens + tokenize_string(line)
|
||||
return tokens
|
||||
|
||||
|
||||
# Exception raised by parse_exr.
|
||||
#
|
||||
syntax_error = 'syntax error'
|
||||
|
||||
|
||||
# Parse an S-expression.
|
||||
# Input is a list of tokens as returned by tokenize_*().
|
||||
# Return a pair (expr, tokens)
|
||||
# where expr is a list representing the s-expression,
|
||||
# and tokens contains the remaining tokens.
|
||||
# May raise syntax_error.
|
||||
#
|
||||
def parse_expr(tokens):
|
||||
if (not tokens) or tokens[0] <> '(':
|
||||
raise syntax_error, 'expected "("'
|
||||
tokens = tokens[1:]
|
||||
expr = []
|
||||
while 1:
|
||||
if not tokens:
|
||||
raise syntax_error, 'missing ")"'
|
||||
if tokens[0] = ')':
|
||||
return expr, tokens[1:]
|
||||
elif tokens[0] = '(':
|
||||
subexpr, tokens = parse_expr(tokens)
|
||||
expr.append(subexpr)
|
||||
else:
|
||||
expr.append(tokens[0])
|
||||
tokens = tokens[1:]
|
||||
|
||||
|
||||
# Parse a file (given as file object, not as file name).
|
||||
# Return a list of parsed S-expressions found at the top level.
|
||||
#
|
||||
def parse_file(fp):
|
||||
tokens = tokenize_file(fp)
|
||||
exprlist = []
|
||||
while tokens:
|
||||
expr, tokens = parse_expr(tokens)
|
||||
exprlist.append(expr)
|
||||
return exprlist
|
||||
|
||||
|
||||
# EXAMPLE:
|
||||
#
|
||||
# The input
|
||||
# '(hip (hop hur-ray))'
|
||||
#
|
||||
# passed to tokenize_string() returns the token list
|
||||
# ['(', 'hip', '(', 'hop', 'hur-ray', ')', ')']
|
||||
#
|
||||
# When this is passed to parse_expr() it returns the expression
|
||||
# ['hip', ['hop', 'hur-ray']]
|
||||
# plus an empty token list (because there are no tokens left.
|
||||
#
|
||||
# When a file containing the example is passed to parse_file() it returns
|
||||
# a list whose only element is the output of parse_expr() above:
|
||||
# [['hip', ['hop', 'hur-ray']]]
|
||||
|
||||
|
||||
# TOKENIZING:
|
||||
#
|
||||
# Comments start with semicolon (;) and continue till the end of the line.
|
||||
#
|
||||
# Tokens are separated by whitespace, except the following characters
|
||||
# always form a separate token (outside strings):
|
||||
# ( ) '
|
||||
# Strings are enclosed in double quotes (") and backslash (\) is used
|
||||
# as escape character in strings.
|
|
@ -0,0 +1,55 @@
|
|||
# module 'poly' -- Polynomials
|
||||
|
||||
# A polynomial is represented by a list of coefficients, e.g.,
|
||||
# [1, 10, 5] represents 1*x**0 + 10*x**1 + 5*x**2 (or 1 + 10x + 5x**2).
|
||||
# There is no way to suppress internal zeros; trailing zeros are
|
||||
# taken out by normalize().
|
||||
|
||||
def normalize(p): # Strip unnecessary zero coefficients
|
||||
n = len(p)
|
||||
while p:
|
||||
if p[n-1]: return p[:n]
|
||||
n = n-1
|
||||
return []
|
||||
|
||||
def plus(a, b):
|
||||
if len(a) < len(b): a, b = b, a # make sure a is the longest
|
||||
res = a[:] # make a copy
|
||||
for i in range(len(b)):
|
||||
res[i] = res[i] + b[i]
|
||||
return normalize(res)
|
||||
|
||||
def minus(a, b):
|
||||
if len(a) < len(b): a, b = b, a # make sure a is the longest
|
||||
res = a[:] # make a copy
|
||||
for i in range(len(b)):
|
||||
res[i] = res[i] - b[i]
|
||||
return normalize(res)
|
||||
|
||||
def one(power, coeff): # Representation of coeff * x**power
|
||||
res = []
|
||||
for i in range(power): res.append(0)
|
||||
return res + [coeff]
|
||||
|
||||
def times(a, b):
|
||||
res = []
|
||||
for i in range(len(a)):
|
||||
for j in range(len(b)):
|
||||
res = plus(res, one(i+j, a[i]*b[j]))
|
||||
return res
|
||||
|
||||
def power(a, n): # Raise polynomial a to the positive integral power n
|
||||
if n = 0: return [1]
|
||||
if n = 1: return a
|
||||
if n/2*2 = n:
|
||||
b = power(a, n/2)
|
||||
return times(b, b)
|
||||
return times(power(a, n-1), a)
|
||||
|
||||
def der(a): # First derivative
|
||||
res = a[1:]
|
||||
for i in range(len(res)):
|
||||
res[i] = res[i] * (i+1)
|
||||
return res
|
||||
|
||||
# Computing a primitive function would require rational arithmetic...
|
|
@ -0,0 +1,124 @@
|
|||
# Module 'path' -- common operations on POSIX pathnames
|
||||
|
||||
import posix
|
||||
|
||||
|
||||
# Intelligent pathname concatenation.
|
||||
# Inserts a '/' unless the first part is empty or already ends in '/'.
|
||||
# Ignores the first part altogether if the second part is absolute
|
||||
# (begins with '/').
|
||||
#
|
||||
def cat(a, b):
|
||||
if b[:1] = '/': return b
|
||||
if a = '' or a[-1:] = '/': return a + b
|
||||
return a + '/' + b
|
||||
|
||||
|
||||
# Split a path in head (empty or ending in '/') and tail (no '/').
|
||||
# The tail will be empty if the path ends in '/'.
|
||||
#
|
||||
def split(p):
|
||||
head, tail = '', ''
|
||||
for c in p:
|
||||
tail = tail + c
|
||||
if c = '/':
|
||||
head, tail = head + tail, ''
|
||||
return head, tail
|
||||
|
||||
|
||||
# Return the tail (basename) part of a path.
|
||||
#
|
||||
def basename(p):
|
||||
return split(p)[1]
|
||||
|
||||
|
||||
# Return the longest prefix of all list elements.
|
||||
#
|
||||
def commonprefix(m):
|
||||
if not m: return ''
|
||||
prefix = m[0]
|
||||
for item in m:
|
||||
for i in range(len(prefix)):
|
||||
if prefix[:i+1] <> item[:i+1]:
|
||||
prefix = prefix[:i]
|
||||
if i = 0: return ''
|
||||
break
|
||||
return prefix
|
||||
|
||||
|
||||
# Does a file/directory exist?
|
||||
#
|
||||
def exists(path):
|
||||
try:
|
||||
st = posix.stat(path)
|
||||
except posix.error:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
# Is a path a posix directory?
|
||||
#
|
||||
def isdir(path):
|
||||
try:
|
||||
st = posix.stat(path)
|
||||
except posix.error:
|
||||
return 0
|
||||
return st[0] / 4096 = 4 # S_IFDIR
|
||||
|
||||
|
||||
# Is a path a symbolic link?
|
||||
# This will always return false on systems where posix.lstat doesn't exist.
|
||||
#
|
||||
def islink(path):
|
||||
try:
|
||||
st = posix.lstat(path)
|
||||
except (posix.error, NameError):
|
||||
return 0
|
||||
return st[0] / 4096 = 10 # S_IFLNK
|
||||
|
||||
|
||||
_mounts = []
|
||||
|
||||
def _getmounts():
|
||||
import commands, string
|
||||
mounts = []
|
||||
data = commands.getoutput('/etc/mount')
|
||||
lines = string.splitfields(data, '\n')
|
||||
for line in lines:
|
||||
words = string.split(line)
|
||||
if len(words) >= 3 and words[1] = 'on':
|
||||
mounts.append(words[2])
|
||||
return mounts
|
||||
|
||||
|
||||
# Is a path a mount point?
|
||||
# This only works for normalized, absolute paths,
|
||||
# and only if the mount table as printed by /etc/mount is correct.
|
||||
# Sorry.
|
||||
#
|
||||
def ismount(path):
|
||||
if not _mounts:
|
||||
_mounts[:] = _getmounts()
|
||||
return path in _mounts
|
||||
|
||||
|
||||
# Directory tree walk.
|
||||
# For each directory under top (including top itself),
|
||||
# func(arg, dirname, filenames) is called, where dirname
|
||||
# is the name of the directory and filenames is the list of
|
||||
# files (and subdirectories etc.) in the directory.
|
||||
# func may modify the filenames list, to implement a filter,
|
||||
# or to impose a different order of visiting.
|
||||
#
|
||||
def walk(top, func, arg):
|
||||
try:
|
||||
names = posix.listdir(top)
|
||||
except posix.error:
|
||||
return
|
||||
func(arg, top, names)
|
||||
exceptions = ('.', '..')
|
||||
for name in names:
|
||||
if name not in exceptions:
|
||||
name = cat(top, name)
|
||||
if isdir(name):
|
||||
walk(name, func, arg)
|
|
@ -0,0 +1,12 @@
|
|||
# Module 'rand'
|
||||
|
||||
import whrandom
|
||||
|
||||
def srand(seed):
|
||||
whrandom.seed(seed%256, seed/256%256, seed/65536%256)
|
||||
|
||||
def rand():
|
||||
return int(whrandom.random() * 32768.0) % 32768
|
||||
|
||||
def choice(seq):
|
||||
return seq[rand() % len(seq)]
|
|
@ -0,0 +1,70 @@
|
|||
# Module 'shutil' -- utility functions usable in a shell-like program
|
||||
|
||||
import posix
|
||||
import path
|
||||
|
||||
MODEBITS = 010000 # Lower 12 mode bits
|
||||
# Change this to 01000 (9 mode bits) to avoid copying setuid etc.
|
||||
|
||||
# Copy data from src to dst
|
||||
#
|
||||
def copyfile(src, dst):
|
||||
fsrc = open(src, 'r')
|
||||
fdst = open(dst, 'w')
|
||||
while 1:
|
||||
buf = fsrc.read(16*1024)
|
||||
if not buf: break
|
||||
fdst.write(buf)
|
||||
|
||||
# Copy mode bits from src to dst
|
||||
#
|
||||
def copymode(src, dst):
|
||||
st = posix.stat(src)
|
||||
mode = divmod(st[0], MODEBITS)[1]
|
||||
posix.chmod(dst, mode)
|
||||
|
||||
# Copy all stat info (mode bits, atime and mtime) from src to dst
|
||||
#
|
||||
def copystat(src, dst):
|
||||
st = posix.stat(src)
|
||||
mode = divmod(st[0], MODEBITS)[1]
|
||||
posix.chmod(dst, mode)
|
||||
posix.utimes(dst, st[7:9])
|
||||
|
||||
# Copy data and mode bits ("cp src dst")
|
||||
#
|
||||
def copy(src, dst):
|
||||
copyfile(src, dst)
|
||||
copymode(src, dst)
|
||||
|
||||
# Copy data and all stat info ("cp -p src dst")
|
||||
#
|
||||
def copy2(src, dst):
|
||||
copyfile(src, dst)
|
||||
copystat(src, dst)
|
||||
|
||||
# Recursively copy a directory tree.
|
||||
# The destination must not already exist.
|
||||
#
|
||||
def copytree(src, dst):
|
||||
names = posix.listdir(src)
|
||||
posix.mkdir(dst, 0777)
|
||||
dot_dotdot = '.', '..'
|
||||
for name in names:
|
||||
if name not in dot_dotdot:
|
||||
srcname = path.cat(src, name)
|
||||
dstname = path.cat(dst, name)
|
||||
#print 'Copying', srcname, 'to', dstname
|
||||
try:
|
||||
#if path.islink(srcname):
|
||||
# linkto = posix.readlink(srcname)
|
||||
# posix.symlink(linkto, dstname)
|
||||
#elif path.isdir(srcname):
|
||||
if path.isdir(srcname):
|
||||
copytree(srcname, dstname)
|
||||
else:
|
||||
copy2(srcname, dstname)
|
||||
# XXX What about devices, sockets etc.?
|
||||
except posix.error, why:
|
||||
print 'Could not copy', srcname, 'to', dstname,
|
||||
print '(', why[1], ')'
|
|
@ -0,0 +1,90 @@
|
|||
# Module 'statcache'
|
||||
#
|
||||
# Maintain a cache of file stats.
|
||||
# There are functions to reset the cache or to selectively remove items.
|
||||
|
||||
import posix
|
||||
|
||||
|
||||
# The cache.
|
||||
# Keys are pathnames, values are `posix.stat' outcomes.
|
||||
#
|
||||
cache = {}
|
||||
|
||||
|
||||
# Stat a file, possibly out of the cache.
|
||||
#
|
||||
def stat(path):
|
||||
try:
|
||||
return cache[path]
|
||||
except RuntimeError:
|
||||
pass
|
||||
cache[path] = ret = posix.stat(path)
|
||||
return ret
|
||||
|
||||
|
||||
# Reset the cache completely.
|
||||
# Hack: to reset a global variable, we import this module.
|
||||
#
|
||||
def reset():
|
||||
import statcache
|
||||
# Check that we really imported the same module
|
||||
if cache is not statcache.cache:
|
||||
raise 'sorry, statcache identity crisis'
|
||||
statcache.cache = {}
|
||||
|
||||
|
||||
# Remove a given item from the cache, if it exists.
|
||||
#
|
||||
def forget(path):
|
||||
try:
|
||||
del cache[path]
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
|
||||
# Remove all pathnames with a given prefix.
|
||||
#
|
||||
def forget_prefix(prefix):
|
||||
n = len(prefix)
|
||||
for path in cache.keys():
|
||||
if path[:n] = prefix:
|
||||
del cache[path]
|
||||
|
||||
|
||||
# Forget about a directory and all entries in it, but not about
|
||||
# entries in subdirectories.
|
||||
#
|
||||
def forget_dir(prefix):
|
||||
if prefix[-1:] = '/' and prefix <> '/':
|
||||
prefix = prefix[:-1]
|
||||
forget(prefix)
|
||||
if prefix[-1:] <> '/':
|
||||
prefix = prefix + '/'
|
||||
n = len(prefix)
|
||||
for path in cache.keys():
|
||||
if path[:n] = prefix:
|
||||
rest = path[n:]
|
||||
if rest[-1:] = '/': rest = rest[:-1]
|
||||
if '/' not in rest:
|
||||
del cache[path]
|
||||
|
||||
|
||||
# Remove all pathnames except with a given prefix.
|
||||
# Normally used with prefix = '/' after a chdir().
|
||||
#
|
||||
def forget_except_prefix(prefix):
|
||||
n = len(prefix)
|
||||
for path in cache.keys():
|
||||
if path[:n] <> prefix:
|
||||
del cache[path]
|
||||
|
||||
|
||||
# Check for directory.
|
||||
#
|
||||
def isdir(path):
|
||||
try:
|
||||
# mode is st[0]; type is mode/4096; S_IFDIR is 4
|
||||
return stat(path)[0] / 4096 = 4
|
||||
except RuntimeError:
|
||||
return 0
|
|
@ -0,0 +1,14 @@
|
|||
# Module 'anywin'
|
||||
# Open a file or directory in a window
|
||||
|
||||
import dirwin
|
||||
import filewin
|
||||
import path
|
||||
|
||||
def open(name):
|
||||
print 'opening', name, '...'
|
||||
if path.isdir(name):
|
||||
w = dirwin.open(name)
|
||||
else:
|
||||
w = filewin.open(name)
|
||||
return w
|
|
@ -0,0 +1,28 @@
|
|||
# Module 'dirwin'
|
||||
|
||||
# Directory windows, a subclass of listwin
|
||||
|
||||
import gwin
|
||||
import listwin
|
||||
import anywin
|
||||
import path
|
||||
import dircache
|
||||
|
||||
def action(w, string, i, detail):
|
||||
(h, v), clicks, button, mask = detail
|
||||
if clicks = 2:
|
||||
name = path.cat(w.name, string)
|
||||
try:
|
||||
w = anywin.open(name)
|
||||
except posix.error, why:
|
||||
stdwin.message('Can\'t open ' + name + ': ' + why[1])
|
||||
|
||||
def open(name):
|
||||
name = path.cat(name, '')
|
||||
list = dircache.opendir(name)[:]
|
||||
list.sort()
|
||||
dircache.annotate(name, list)
|
||||
w = listwin.open(name, list)
|
||||
w.name = name
|
||||
w.action = action
|
||||
return w
|
|
@ -0,0 +1,31 @@
|
|||
# Module 'filewin'
|
||||
# File windows, a subclass of textwin (which is a subclass of gwin)
|
||||
|
||||
import stdwin
|
||||
import textwin
|
||||
import path
|
||||
|
||||
builtin_open = open
|
||||
|
||||
def readfile(fn): # Return a string containing the file's contents
|
||||
fp = builtin_open(fn, 'r')
|
||||
a = ''
|
||||
n = 8096
|
||||
while 1:
|
||||
b = fp.read(n)
|
||||
if not b: break
|
||||
a = a + b
|
||||
return a
|
||||
|
||||
|
||||
# FILE WINDOW
|
||||
|
||||
def open_readonly(fn): # Open a file window
|
||||
w = textwin.open_readonly(fn, readfile(fn))
|
||||
w.fn = fn
|
||||
return w
|
||||
|
||||
def open(fn): # Open a file window
|
||||
w = textwin.open(fn, readfile(fn))
|
||||
w.fn = fn
|
||||
return w
|
|
@ -0,0 +1,118 @@
|
|||
# Module 'gwin'
|
||||
# Generic stdwin windows
|
||||
|
||||
# This is used as a base class from which to derive other window types.
|
||||
# The mainloop() function here is an event dispatcher for all window types.
|
||||
|
||||
import stdwin
|
||||
import stdwinsupport
|
||||
|
||||
S = stdwinsupport # Shorthand
|
||||
|
||||
windows = [] # List of open windows
|
||||
|
||||
|
||||
# Open a window
|
||||
|
||||
def open(title): # Open a generic window
|
||||
w = stdwin.open(title)
|
||||
stdwin.setdefwinsize(0, 0)
|
||||
# Set default event handlers
|
||||
w.draw = nop
|
||||
w.char = nop
|
||||
w.mdown = nop
|
||||
w.mmove = nop
|
||||
w.mup = nop
|
||||
w.m2down = m2down
|
||||
w.m2up = m2up
|
||||
w.size = nop
|
||||
w.move = nop
|
||||
w.activate = w.deactivate = nop
|
||||
w.timer = nop
|
||||
# default command handlers
|
||||
w.close = close
|
||||
w.tab = tab
|
||||
w.enter = enter
|
||||
w.backspace = backspace
|
||||
w.arrow = arrow
|
||||
w.kleft = w.kup = w.kright = w.kdown = nop
|
||||
windows.append(w)
|
||||
return w
|
||||
|
||||
|
||||
# Generic event dispatching
|
||||
|
||||
def mainloop(): # Handle events until no windows left
|
||||
while windows:
|
||||
treatevent(stdwin.getevent())
|
||||
|
||||
def treatevent(e): # Handle a stdwin event
|
||||
type, w, detail = e
|
||||
if type = S.we_draw:
|
||||
w.draw(w, detail)
|
||||
elif type = S.we_menu:
|
||||
m, item = detail
|
||||
m.action[item](w, m, item)
|
||||
elif type = S.we_command:
|
||||
treatcommand(w, detail)
|
||||
elif type = S.we_char:
|
||||
w.char(w, detail)
|
||||
elif type = S.we_mouse_down:
|
||||
if detail[1] > 1: w.m2down(w, detail)
|
||||
else: w.mdown(w, detail)
|
||||
elif type = S.we_mouse_move:
|
||||
w.mmove(w, detail)
|
||||
elif type = S.we_mouse_up:
|
||||
if detail[1] > 1: w.m2up(w, detail)
|
||||
else: w.mup(w, detail)
|
||||
elif type = S.we_size:
|
||||
w.size(w, w.getwinsize())
|
||||
elif type = S.we_activate:
|
||||
w.activate(w)
|
||||
elif type = S.we_deactivate:
|
||||
w.deactivate(w)
|
||||
elif type = S.we_move:
|
||||
w.move(w)
|
||||
elif type = S.we_timer:
|
||||
w.timer(w)
|
||||
|
||||
def treatcommand(w, type): # Handle a we_command event
|
||||
if type = S.wc_close:
|
||||
w.close(w)
|
||||
elif type = S.wc_return:
|
||||
w.enter(w)
|
||||
elif type = S.wc_tab:
|
||||
w.tab(w)
|
||||
elif type = S.wc_backspace:
|
||||
w.backspace(w)
|
||||
elif type in (S.wc_left, S.wc_up, S.wc_right, S.wc_down):
|
||||
w.arrow(w, type)
|
||||
|
||||
|
||||
# Methods
|
||||
|
||||
def close(w): # Close method
|
||||
for i in range(len(windows)):
|
||||
if windows[i] is w:
|
||||
del windows[i]
|
||||
break
|
||||
|
||||
def arrow(w, detail): # Arrow key method
|
||||
if detail = S.wc_left:
|
||||
w.kleft(w)
|
||||
elif detail = S.wc_up:
|
||||
w.kup(w)
|
||||
elif detail = S.wc_right:
|
||||
w.kright(w)
|
||||
elif detail = S.wc_down:
|
||||
w.kdown(w)
|
||||
|
||||
|
||||
# Trivial methods
|
||||
|
||||
def tab(w): w.char(w, '\t')
|
||||
def enter(w): w.char(w, '\n') # 'return' is a Python reserved word
|
||||
def backspace(w): w.char(w, '\b')
|
||||
def m2down(w, detail): w.mdown(w, detail)
|
||||
def m2up(w, detail): w.mup(w, detail)
|
||||
def nop(args): pass
|
|
@ -0,0 +1,47 @@
|
|||
# Module 'listwin'
|
||||
# List windows, a subclass of gwin
|
||||
|
||||
import gwin
|
||||
import stdwin
|
||||
|
||||
def maxlinewidth(a): # Compute maximum textwidth of lines in a sequence
|
||||
max = 0
|
||||
for line in a:
|
||||
width = stdwin.textwidth(line)
|
||||
if width > max: max = width
|
||||
return max
|
||||
|
||||
def action(w, string, i, detail): # Default item selection method
|
||||
pass
|
||||
|
||||
def mup(w, detail): # Mouse up method
|
||||
(h, v), clicks, button, mask = detail
|
||||
i = divmod(v, w.lineheight)[0]
|
||||
if 0 <= i < len(w.data):
|
||||
w.action(w, w.data[i], i, detail)
|
||||
|
||||
def draw(w, ((left, top), (right, bottom))): # Text window draw method
|
||||
data = w.data
|
||||
d = w.begindrawing()
|
||||
lh = w.lineheight
|
||||
itop = top/lh
|
||||
ibot = (bottom-1)/lh + 1
|
||||
if itop < 0: itop = 0
|
||||
if ibot > len(data): ibot = len(data)
|
||||
for i in range(itop, ibot): d.text((0, i*lh), data[i])
|
||||
|
||||
def open(title, data): # Display a list of texts in a window
|
||||
lineheight = stdwin.lineheight()
|
||||
h, v = maxlinewidth(data), len(data)*lineheight
|
||||
h0, v0 = h + stdwin.textwidth(' '), v + lineheight
|
||||
if h0 > stdwin.textwidth(' ')*80: h0 = 0
|
||||
if v0 > stdwin.lineheight()*24: v0 = 0
|
||||
stdwin.setdefwinsize(h0, v0)
|
||||
w = gwin.open(title)
|
||||
w.setdocsize(h, v)
|
||||
w.lineheight = lineheight
|
||||
w.data = data
|
||||
w.draw = draw
|
||||
w.action = action
|
||||
w.mup = mup
|
||||
return w
|
|
@ -0,0 +1,87 @@
|
|||
# Module 'rect'.
|
||||
#
|
||||
# Operations on rectangles.
|
||||
# There is some normalization: all results return the object 'empty'
|
||||
# if their result would contain no points.
|
||||
|
||||
|
||||
# Exception.
|
||||
#
|
||||
error = 'rect.error'
|
||||
|
||||
|
||||
# The empty rectangle.
|
||||
#
|
||||
empty = (0, 0), (0, 0)
|
||||
|
||||
|
||||
# Check if a rectangle is empty.
|
||||
#
|
||||
def is_empty((left, top), (right, bottom)):
|
||||
return left >= right or top >= bottom
|
||||
|
||||
|
||||
# Compute the intersection or two or more rectangles.
|
||||
# This works with a list or tuple argument.
|
||||
#
|
||||
def intersect(list):
|
||||
if not list: raise error, 'intersect called with empty list'
|
||||
if is_empty(list[0]): return empty
|
||||
(left, top), (right, bottom) = list[0]
|
||||
for rect in list[1:]:
|
||||
if not is_empty(rect):
|
||||
(l, t), (r, b) = rect
|
||||
if left < l: left = l
|
||||
if top < t: top = t
|
||||
if right > r: right = r
|
||||
if bottom > b: bottom = b
|
||||
if is_empty((left, top), (right, bottom)):
|
||||
return empty
|
||||
return (left, top), (right, bottom)
|
||||
|
||||
|
||||
# Compute the smallest rectangle containing all given rectangles.
|
||||
# This works with a list or tuple argument.
|
||||
#
|
||||
def union(list):
|
||||
(left, top), (right, bottom) = empty
|
||||
for (l, t), (r, b) in list[1:]:
|
||||
if not is_empty((l, t), (r, b)):
|
||||
if l < left: left = l
|
||||
if t < top: top = t
|
||||
if r > right: right = r
|
||||
if b > bottom: bottom = b
|
||||
res = (left, top), (right, bottom)
|
||||
if is_empty(res):
|
||||
return empty
|
||||
return res
|
||||
|
||||
|
||||
# Check if a point is in a rectangle.
|
||||
#
|
||||
def pointinrect((h, v), ((left, top), (right, bottom))):
|
||||
return left <= h < right and top <= v < bottom
|
||||
|
||||
|
||||
# Return a rectangle that is dh, dv inside another
|
||||
#
|
||||
def inset(((left, top), (right, bottom)), (dh, dv)):
|
||||
left = left + dh
|
||||
top = top + dv
|
||||
right = right - dh
|
||||
bottom = bottom - dv
|
||||
r = (left, top), (right, bottom)
|
||||
if is_empty(r):
|
||||
return empty
|
||||
else:
|
||||
return r
|
||||
|
||||
|
||||
# Conversions between rectangles and 'geometry tuples',
|
||||
# given as origin (h, v) and dimensions (width, height).
|
||||
#
|
||||
def rect2geom((left, top), (right, bottom)):
|
||||
return (left, top), (right-left, bottom-top)
|
||||
|
||||
def geom2rect((h, v), (width, height)):
|
||||
return (h, v), (h+width, v+height)
|
|
@ -0,0 +1,36 @@
|
|||
# Module 'stdwinevents' -- Constants for stdwin event types
|
||||
#
|
||||
# Suggested usage:
|
||||
# from stdwinevents import *
|
||||
|
||||
# The function stdwin.getevent() returns a tuple containing:
|
||||
# (type, window, detail)
|
||||
# where detail may be <no value> or a value depending on type, see below:
|
||||
|
||||
# Values for type:
|
||||
|
||||
WE_NULL = 0 # not reported -- means 'no event' internally
|
||||
WE_ACTIVATE = 1 # detail is <no object>
|
||||
WE_CHAR = 2 # detail is the character
|
||||
WE_COMMAND = 3 # detail is one of the WC_* constants below
|
||||
WE_MOUSE_DOWN = 4 # detail is ((h, v), clicks, button, mask)
|
||||
WE_MOUSE_MOVE = 5 # ditto
|
||||
WE_MOUSE_UP = 6 # ditto
|
||||
WE_MENU = 7 # detail is (menu, item)
|
||||
WE_SIZE = 8 # detail is (width, height) [???]
|
||||
WE_MOVE = 9 # not reported -- reserved for future use
|
||||
WE_DRAW = 10 # detail is ((left, top), (right, bottom))
|
||||
WE_TIMER = 11 # detail is <no object>
|
||||
WE_DEACTIVATE = 12 # detail is <no object>
|
||||
|
||||
# Values for detail when type is WE_COMMAND:
|
||||
|
||||
WC_CLOSE = 1 # user hit close box
|
||||
WC_LEFT = 2 # left arrow key
|
||||
WC_RIGHT = 3 # right arrow key
|
||||
WC_UP = 4 # up arrow key
|
||||
WC_DOWN = 5 # down arrow key
|
||||
WC_CANCEL = 6 # not reported -- turned into KeyboardInterrupt
|
||||
WC_BACKSPACE = 7 # backspace key
|
||||
WC_TAB = 8 # tab key
|
||||
WC_RETURN = 9 # return or enter key
|
|
@ -0,0 +1,237 @@
|
|||
# Module 'tablewin'
|
||||
|
||||
# Display a table, with per-item actions:
|
||||
|
||||
# A1 | A2 | A3 | .... | AN
|
||||
# B1 | B2 | B3 | .... | BN
|
||||
# C1 | C2 | C3 | .... | CN
|
||||
# .. | .. | .. | .... | ..
|
||||
# Z1 | Z2 | Z3 | .... | ZN
|
||||
|
||||
# Not all columns need to have the same length.
|
||||
# The data structure is a list of columns;
|
||||
# each column is a list of items.
|
||||
# Each item is a pair of a string and an action procedure.
|
||||
# The first item may be a column title.
|
||||
|
||||
import stdwin
|
||||
import gwin
|
||||
|
||||
def open(title, data): # Public function to open a table window
|
||||
#
|
||||
# Set geometry parameters (one day, these may be changeable)
|
||||
#
|
||||
margin = stdwin.textwidth(' ')
|
||||
lineheight = stdwin.lineheight()
|
||||
#
|
||||
# Geometry calculations
|
||||
#
|
||||
colstarts = [0]
|
||||
totwidth = 0
|
||||
maxrows = 0
|
||||
for coldata in data:
|
||||
# Height calculations
|
||||
rows = len(coldata)
|
||||
if rows > maxrows: maxrows = rows
|
||||
# Width calculations
|
||||
width = colwidth(coldata) + margin
|
||||
totwidth = totwidth + width
|
||||
colstarts.append(totwidth)
|
||||
#
|
||||
# Calculate document and window height
|
||||
#
|
||||
docwidth, docheight = totwidth, maxrows*lineheight
|
||||
winwidth, winheight = docwidth, docheight
|
||||
if winwidth > stdwin.textwidth('n')*100: winwidth = 0
|
||||
if winheight > stdwin.lineheight()*30: winheight = 0
|
||||
#
|
||||
# Create the window
|
||||
#
|
||||
stdwin.setdefwinsize(winwidth, winheight)
|
||||
w = gwin.open(title)
|
||||
#
|
||||
# Set properties and override methods
|
||||
#
|
||||
w.data = data
|
||||
w.margin = margin
|
||||
w.lineheight = lineheight
|
||||
w.colstarts = colstarts
|
||||
w.totwidth = totwidth
|
||||
w.maxrows = maxrows
|
||||
w.selection = (-1, -1)
|
||||
w.lastselection = (-1, -1)
|
||||
w.selshown = 0
|
||||
w.setdocsize(docwidth, docheight)
|
||||
w.draw = draw
|
||||
w.mup = mup
|
||||
w.arrow = arrow
|
||||
#
|
||||
# Return
|
||||
#
|
||||
return w
|
||||
|
||||
def update(w, data): # Change the data
|
||||
#
|
||||
# Hide selection
|
||||
#
|
||||
hidesel(w, w.begindrawing())
|
||||
#
|
||||
# Get old geometry parameters
|
||||
#
|
||||
margin = w.margin
|
||||
lineheight = w.lineheight
|
||||
#
|
||||
# Geometry calculations
|
||||
#
|
||||
colstarts = [0]
|
||||
totwidth = 0
|
||||
maxrows = 0
|
||||
for coldata in data:
|
||||
# Height calculations
|
||||
rows = len(coldata)
|
||||
if rows > maxrows: maxrows = rows
|
||||
# Width calculations
|
||||
width = colwidth(coldata) + margin
|
||||
totwidth = totwidth + width
|
||||
colstarts.append(totwidth)
|
||||
#
|
||||
# Calculate document and window height
|
||||
#
|
||||
docwidth, docheight = totwidth, maxrows*lineheight
|
||||
#
|
||||
# Set changed properties and change window size
|
||||
#
|
||||
w.data = data
|
||||
w.colstarts = colstarts
|
||||
w.totwidth = totwidth
|
||||
w.maxrows = maxrows
|
||||
w.change((0, 0), (10000, 10000))
|
||||
w.setdocsize(docwidth, docheight)
|
||||
w.change((0, 0), (docwidth, docheight))
|
||||
#
|
||||
# Show selection, or forget it if out of range
|
||||
#
|
||||
showsel(w, w.begindrawing())
|
||||
if not w.selshown: w.selection = (-1, -1)
|
||||
|
||||
def colwidth(coldata): # Subroutine to calculate column width
|
||||
maxwidth = 0
|
||||
for string, action in coldata:
|
||||
width = stdwin.textwidth(string)
|
||||
if width > maxwidth: maxwidth = width
|
||||
return maxwidth
|
||||
|
||||
def draw(w, ((left, top), (right, bottom))): # Draw method
|
||||
ileft = whichcol(w, left)
|
||||
iright = whichcol(w, right-1) + 1
|
||||
if iright > len(w.data): iright = len(w.data)
|
||||
itop = divmod(top, w.lineheight)[0]
|
||||
if itop < 0: itop = 0
|
||||
ibottom, remainder = divmod(bottom, w.lineheight)
|
||||
if remainder: ibottom = ibottom + 1
|
||||
d = w.begindrawing()
|
||||
if ileft <= w.selection[0] < iright:
|
||||
if itop <= w.selection[1] < ibottom:
|
||||
hidesel(w, d)
|
||||
d.erase((left, top), (right, bottom))
|
||||
for i in range(ileft, iright):
|
||||
col = w.data[i]
|
||||
jbottom = len(col)
|
||||
if ibottom < jbottom: jbottom = ibottom
|
||||
h = w.colstarts[i]
|
||||
v = itop * w.lineheight
|
||||
for j in range(itop, jbottom):
|
||||
string, action = col[j]
|
||||
d.text((h, v), string)
|
||||
v = v + w.lineheight
|
||||
showsel(w, d)
|
||||
|
||||
def mup(w, detail): # Mouse up method
|
||||
(h, v), nclicks, button, mask = detail
|
||||
icol = whichcol(w, h)
|
||||
if 0 <= icol < len(w.data):
|
||||
irow = divmod(v, w.lineheight)[0]
|
||||
col = w.data[icol]
|
||||
if 0 <= irow < len(col):
|
||||
string, action = col[irow]
|
||||
action(w, string, (icol, irow), detail)
|
||||
|
||||
def whichcol(w, h): # Return column number (may be >= len(w.data))
|
||||
for icol in range(0, len(w.data)):
|
||||
if h < w.colstarts[icol+1]:
|
||||
return icol
|
||||
return len(w.data)
|
||||
|
||||
def arrow(w, type):
|
||||
import stdwinsupport
|
||||
S = stdwinsupport
|
||||
if type = S.wc_left:
|
||||
incr = -1, 0
|
||||
elif type = S.wc_up:
|
||||
incr = 0, -1
|
||||
elif type = S.wc_right:
|
||||
incr = 1, 0
|
||||
elif type = S.wc_down:
|
||||
incr = 0, 1
|
||||
else:
|
||||
return
|
||||
icol, irow = w.lastselection
|
||||
icol = icol + incr[0]
|
||||
if icol < 0: icol = len(w.data)-1
|
||||
if icol >= len(w.data): icol = 0
|
||||
if 0 <= icol < len(w.data):
|
||||
irow = irow + incr[1]
|
||||
if irow < 0: irow = len(w.data[icol]) - 1
|
||||
if irow >= len(w.data[icol]): irow = 0
|
||||
else:
|
||||
irow = 0
|
||||
if 0 <= icol < len(w.data) and 0 <= irow < len(w.data[icol]):
|
||||
w.lastselection = icol, irow
|
||||
string, action = w.data[icol][irow]
|
||||
detail = (0, 0), 1, 1, 1
|
||||
action(w, string, (icol, irow), detail)
|
||||
|
||||
|
||||
# Selection management
|
||||
# TO DO: allow multiple selected entries
|
||||
|
||||
def select(w, selection): # Public function to set the item selection
|
||||
d = w.begindrawing()
|
||||
hidesel(w, d)
|
||||
w.selection = selection
|
||||
showsel(w, d)
|
||||
if w.selshown: lastselection = selection
|
||||
|
||||
def hidesel(w, d): # Hide the selection, if shown
|
||||
if w.selshown: invertsel(w, d)
|
||||
|
||||
def showsel(w, d): # Show the selection, if hidden
|
||||
if not w.selshown: invertsel(w, d)
|
||||
|
||||
def invertsel(w, d): # Invert the selection, if valid
|
||||
icol, irow = w.selection
|
||||
if 0 <= icol < len(w.data) and 0 <= irow < len(w.data[icol]):
|
||||
left = w.colstarts[icol]
|
||||
right = w.colstarts[icol+1]
|
||||
top = irow * w.lineheight
|
||||
bottom = (irow+1) * w.lineheight
|
||||
d.invert((left, top), (right, bottom))
|
||||
w.selshown = (not w.selshown)
|
||||
|
||||
|
||||
# Demonstration
|
||||
|
||||
def demo_action(w, string, (icol, irow), detail): # Action function for demo
|
||||
select(w, (irow, icol))
|
||||
|
||||
def demo(): # Demonstration
|
||||
da = demo_action # shorthand
|
||||
col0 = [('a1', da), ('bbb1', da), ('c1', da)]
|
||||
col1 = [('a2', da), ('bbb2', da)]
|
||||
col2 = [('a3', da), ('b3', da), ('c3', da), ('d4', da), ('d5', da)]
|
||||
col3 = []
|
||||
for i in range(1, 31): col3.append('xxx' + `i`, da)
|
||||
data = [col0, col1, col2, col3]
|
||||
w = open('tablewin.demo', data)
|
||||
gwin.mainloop()
|
||||
return w
|
|
@ -0,0 +1,119 @@
|
|||
# Module 'textwin'
|
||||
|
||||
# Text windows, a subclass of gwin
|
||||
|
||||
import stdwin
|
||||
import stdwinsupport
|
||||
import gwin
|
||||
|
||||
S = stdwinsupport # Shorthand
|
||||
|
||||
|
||||
def fixsize(w):
|
||||
docwidth, docheight = w.text.getrect()[1]
|
||||
winheight = w.getwinsize()[1]
|
||||
if winheight > docheight: docheight = winheight
|
||||
w.setdocsize(0, docheight)
|
||||
fixeditmenu(w)
|
||||
|
||||
def cut(w, m, id):
|
||||
s = w.text.getfocustext()
|
||||
if s:
|
||||
stdwin.setcutbuffer(s)
|
||||
w.text.replace('')
|
||||
fixsize(w)
|
||||
|
||||
def copy(w, m, id):
|
||||
s = w.text.getfocustext()
|
||||
if s:
|
||||
stdwin.setcutbuffer(s)
|
||||
fixeditmenu(w)
|
||||
|
||||
def paste(w, m, id):
|
||||
w.text.replace(stdwin.getcutbuffer())
|
||||
fixsize(w)
|
||||
|
||||
def addeditmenu(w):
|
||||
m = w.editmenu = w.menucreate('Edit')
|
||||
m.action = []
|
||||
m.additem('Cut', 'X')
|
||||
m.action.append(cut)
|
||||
m.additem('Copy', 'C')
|
||||
m.action.append(copy)
|
||||
m.additem('Paste', 'V')
|
||||
m.action.append(paste)
|
||||
|
||||
def fixeditmenu(w):
|
||||
m = w.editmenu
|
||||
f = w.text.getfocus()
|
||||
can_copy = (f[0] < f[1])
|
||||
m.enable(1, can_copy)
|
||||
if not w.readonly:
|
||||
m.enable(0, can_copy)
|
||||
m.enable(2, (stdwin.getcutbuffer() <> ''))
|
||||
|
||||
def draw(w, area): # Draw method
|
||||
w.text.draw(area)
|
||||
|
||||
def size(w, newsize): # Size method
|
||||
w.text.move((0, 0), newsize)
|
||||
fixsize(w)
|
||||
|
||||
def close(w): # Close method
|
||||
del w.text # Break circular ref
|
||||
gwin.close(w)
|
||||
|
||||
def char(w, c): # Char method
|
||||
w.text.replace(c)
|
||||
fixsize(w)
|
||||
|
||||
def backspace(w): # Backspace method
|
||||
void = w.text.event(S.we_command, w, S.wc_backspace)
|
||||
fixsize(w)
|
||||
|
||||
def arrow(w, detail): # Arrow method
|
||||
w.text.arrow(detail)
|
||||
fixeditmenu(w)
|
||||
|
||||
def mdown(w, detail): # Mouse down method
|
||||
void = w.text.event(S.we_mouse_down, w, detail)
|
||||
fixeditmenu(w)
|
||||
|
||||
def mmove(w, detail): # Mouse move method
|
||||
void = w.text.event(S.we_mouse_move, w, detail)
|
||||
|
||||
def mup(w, detail): # Mouse up method
|
||||
void = w.text.event(S.we_mouse_up, w, detail)
|
||||
fixeditmenu(w)
|
||||
|
||||
def activate(w): # Activate method
|
||||
fixeditmenu(w)
|
||||
|
||||
def open(title, str): # Display a string in a window
|
||||
w = gwin.open(title)
|
||||
w.readonly = 0
|
||||
w.text = w.textcreate((0, 0), w.getwinsize())
|
||||
w.text.replace(str)
|
||||
w.text.setfocus(0, 0)
|
||||
addeditmenu(w)
|
||||
fixsize(w)
|
||||
w.draw = draw
|
||||
w.size = size
|
||||
w.close = close
|
||||
w.mdown = mdown
|
||||
w.mmove = mmove
|
||||
w.mup = mup
|
||||
w.char = char
|
||||
w.backspace = backspace
|
||||
w.arrow = arrow
|
||||
w.activate = activate
|
||||
return w
|
||||
|
||||
def open_readonly(title, str): # Same with char input disabled
|
||||
w = open(title, str)
|
||||
w.readonly = 1
|
||||
w.char = w.backspace = gwin.nop
|
||||
# Disable Cut and Paste menu item; leave Copy alone
|
||||
w.editmenu.enable(0, 0)
|
||||
w.editmenu.enable(2, 0)
|
||||
return w
|
|
@ -0,0 +1,129 @@
|
|||
# module 'string' -- A collection of string operations
|
||||
|
||||
# XXX Some of these operations are incredibly slow and should be built in
|
||||
|
||||
# Some strings for ctype-style character classification
|
||||
whitespace = ' \t\n'
|
||||
lowercase = 'abcdefghijklmnopqrstuvwxyz'
|
||||
uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
letters = lowercase + uppercase
|
||||
digits = '0123456789'
|
||||
hexdigits = digits + 'abcdef' + 'ABCDEF'
|
||||
octdigits = '01234567'
|
||||
|
||||
# Case conversion helpers
|
||||
_caseswap = {}
|
||||
for i in range(26):
|
||||
_caseswap[lowercase[i]] = uppercase[i]
|
||||
_caseswap[uppercase[i]] = lowercase[i]
|
||||
del i
|
||||
|
||||
# convert UPPER CASE letters to lower case
|
||||
def lower(s):
|
||||
res = ''
|
||||
for c in s:
|
||||
if 'A' <= c <= 'Z': c = _caseswap[c]
|
||||
res = res + c
|
||||
return res
|
||||
|
||||
# Convert lower case letters to UPPER CASE
|
||||
def upper(s):
|
||||
res = ''
|
||||
for c in s:
|
||||
if 'a' <= c <= 'z': c = _caseswap[c]
|
||||
res = res + c
|
||||
return res
|
||||
|
||||
# Swap lower case letters and UPPER CASE
|
||||
def swapcase(s):
|
||||
res = ''
|
||||
for c in s:
|
||||
if 'a' <= c <= 'z' or 'A' <= c <= 'Z': c = _caseswap[c]
|
||||
res = res + c
|
||||
return res
|
||||
|
||||
# Strip leading and trailing tabs and spaces
|
||||
def strip(s):
|
||||
i, j = 0, len(s)
|
||||
while i < j and s[i] in whitespace: i = i+1
|
||||
while i < j and s[j-1] in whitespace: j = j-1
|
||||
return s[i:j]
|
||||
|
||||
# Split a string into a list of space/tab-separated words
|
||||
# NB: split(s) is NOT the same as splitfields(s, ' ')!
|
||||
def split(s):
|
||||
res = []
|
||||
i, n = 0, len(s)
|
||||
while i < n:
|
||||
while i < n and s[i] in whitespace: i = i+1
|
||||
if i = n: break
|
||||
j = i
|
||||
while j < n and s[j] not in whitespace: j = j+1
|
||||
res.append(s[i:j])
|
||||
i = j
|
||||
return res
|
||||
|
||||
# Split a list into fields separated by a given string
|
||||
# NB: splitfields(s, ' ') is NOT the same as split(s)!
|
||||
def splitfields(s, sep):
|
||||
res = []
|
||||
ns = len(s)
|
||||
nsep = len(sep)
|
||||
i = j = 0
|
||||
while j+nsep <= ns:
|
||||
if s[j:j+nsep] = sep:
|
||||
res.append(s[i:j])
|
||||
i = j = j + nsep
|
||||
else:
|
||||
j = j + 1
|
||||
res.append(s[i:])
|
||||
return res
|
||||
|
||||
# Find substring
|
||||
index_error = 'substring not found in string.index'
|
||||
def index(s, sub):
|
||||
n = len(sub)
|
||||
for i in range(len(s) - n):
|
||||
if sub = s[i:i+n]: return i
|
||||
raise index_error, (s, sub)
|
||||
|
||||
# Convert string to integer
|
||||
atoi_error = 'non-numeric argument to string.atoi'
|
||||
def atoi(str):
|
||||
s = str
|
||||
if s[:1] in '+-': s = s[1:]
|
||||
if not s: raise atoi_error, str
|
||||
for c in s:
|
||||
if c not in digits: raise atoi_error, str
|
||||
return eval(str)
|
||||
|
||||
# Left-justify a string
|
||||
def ljust(s, width):
|
||||
n = len(s)
|
||||
if n >= width: return s
|
||||
return s + ' '*(width-n)
|
||||
|
||||
# Right-justify a string
|
||||
def rjust(s, width):
|
||||
n = len(s)
|
||||
if n >= width: return s
|
||||
return ' '*(width-n) + s
|
||||
|
||||
# Center a string
|
||||
def center(s, width):
|
||||
n = len(s)
|
||||
if n >= width: return s
|
||||
return ' '*((width-n)/2) + s + ' '*(width -(width-n)/2)
|
||||
|
||||
# Zero-fill a number, e.g., (12, 3) --> '012' and (-3, 3) --> '-03'
|
||||
# Decadent feature: the argument may be a string or a number
|
||||
# (Use of this is deprecated; it should be a string as with ljust c.s.)
|
||||
def zfill(x, width):
|
||||
if type(x) = type(''): s = x
|
||||
else: s = `x`
|
||||
n = len(s)
|
||||
if n >= width: return s
|
||||
sign = ''
|
||||
if s[0] = '-':
|
||||
sign, s = '-', s[1:]
|
||||
return sign + '0'*(width-n) + s
|
|
@ -0,0 +1,129 @@
|
|||
# module 'string' -- A collection of string operations
|
||||
|
||||
# XXX Some of these operations are incredibly slow and should be built in
|
||||
|
||||
# Some strings for ctype-style character classification
|
||||
whitespace = ' \t\n'
|
||||
lowercase = 'abcdefghijklmnopqrstuvwxyz'
|
||||
uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
letters = lowercase + uppercase
|
||||
digits = '0123456789'
|
||||
hexdigits = digits + 'abcdef' + 'ABCDEF'
|
||||
octdigits = '01234567'
|
||||
|
||||
# Case conversion helpers
|
||||
_caseswap = {}
|
||||
for i in range(26):
|
||||
_caseswap[lowercase[i]] = uppercase[i]
|
||||
_caseswap[uppercase[i]] = lowercase[i]
|
||||
del i
|
||||
|
||||
# convert UPPER CASE letters to lower case
|
||||
def lower(s):
|
||||
res = ''
|
||||
for c in s:
|
||||
if 'A' <= c <= 'Z': c = _caseswap[c]
|
||||
res = res + c
|
||||
return res
|
||||
|
||||
# Convert lower case letters to UPPER CASE
|
||||
def upper(s):
|
||||
res = ''
|
||||
for c in s:
|
||||
if 'a' <= c <= 'z': c = _caseswap[c]
|
||||
res = res + c
|
||||
return res
|
||||
|
||||
# Swap lower case letters and UPPER CASE
|
||||
def swapcase(s):
|
||||
res = ''
|
||||
for c in s:
|
||||
if 'a' <= c <= 'z' or 'A' <= c <= 'Z': c = _caseswap[c]
|
||||
res = res + c
|
||||
return res
|
||||
|
||||
# Strip leading and trailing tabs and spaces
|
||||
def strip(s):
|
||||
i, j = 0, len(s)
|
||||
while i < j and s[i] in whitespace: i = i+1
|
||||
while i < j and s[j-1] in whitespace: j = j-1
|
||||
return s[i:j]
|
||||
|
||||
# Split a string into a list of space/tab-separated words
|
||||
# NB: split(s) is NOT the same as splitfields(s, ' ')!
|
||||
def split(s):
|
||||
res = []
|
||||
i, n = 0, len(s)
|
||||
while i < n:
|
||||
while i < n and s[i] in whitespace: i = i+1
|
||||
if i = n: break
|
||||
j = i
|
||||
while j < n and s[j] not in whitespace: j = j+1
|
||||
res.append(s[i:j])
|
||||
i = j
|
||||
return res
|
||||
|
||||
# Split a list into fields separated by a given string
|
||||
# NB: splitfields(s, ' ') is NOT the same as split(s)!
|
||||
def splitfields(s, sep):
|
||||
res = []
|
||||
ns = len(s)
|
||||
nsep = len(sep)
|
||||
i = j = 0
|
||||
while j+nsep <= ns:
|
||||
if s[j:j+nsep] = sep:
|
||||
res.append(s[i:j])
|
||||
i = j = j + nsep
|
||||
else:
|
||||
j = j + 1
|
||||
res.append(s[i:])
|
||||
return res
|
||||
|
||||
# Find substring
|
||||
index_error = 'substring not found in string.index'
|
||||
def index(s, sub):
|
||||
n = len(sub)
|
||||
for i in range(len(s) - n):
|
||||
if sub = s[i:i+n]: return i
|
||||
raise index_error, (s, sub)
|
||||
|
||||
# Convert string to integer
|
||||
atoi_error = 'non-numeric argument to string.atoi'
|
||||
def atoi(str):
|
||||
s = str
|
||||
if s[:1] in '+-': s = s[1:]
|
||||
if not s: raise atoi_error, str
|
||||
for c in s:
|
||||
if c not in digits: raise atoi_error, str
|
||||
return eval(str)
|
||||
|
||||
# Left-justify a string
|
||||
def ljust(s, width):
|
||||
n = len(s)
|
||||
if n >= width: return s
|
||||
return s + ' '*(width-n)
|
||||
|
||||
# Right-justify a string
|
||||
def rjust(s, width):
|
||||
n = len(s)
|
||||
if n >= width: return s
|
||||
return ' '*(width-n) + s
|
||||
|
||||
# Center a string
|
||||
def center(s, width):
|
||||
n = len(s)
|
||||
if n >= width: return s
|
||||
return ' '*((width-n)/2) + s + ' '*(width -(width-n)/2)
|
||||
|
||||
# Zero-fill a number, e.g., (12, 3) --> '012' and (-3, 3) --> '-03'
|
||||
# Decadent feature: the argument may be a string or a number
|
||||
# (Use of this is deprecated; it should be a string as with ljust c.s.)
|
||||
def zfill(x, width):
|
||||
if type(x) = type(''): s = x
|
||||
else: s = `x`
|
||||
n = len(s)
|
||||
if n >= width: return s
|
||||
sign = ''
|
||||
if s[0] = '-':
|
||||
sign, s = '-', s[1:]
|
||||
return sign + '0'*(width-n) + s
|
|
@ -0,0 +1,9 @@
|
|||
# Module 'util' -- some useful functions that dont fit elsewhere
|
||||
|
||||
# Remove an item from a list at most once
|
||||
#
|
||||
def remove(item, list):
|
||||
for i in range(len(list)):
|
||||
if list[i] = item:
|
||||
del list[i]
|
||||
break
|
|
@ -0,0 +1,74 @@
|
|||
# WICHMANN-HILL RANDOM NUMBER GENERATOR
|
||||
#
|
||||
# Wichmann, B. A. & Hill, I. D. (1982)
|
||||
# Algorithm AS 183:
|
||||
# An efficient and portable pseudo-random number generator
|
||||
# Applied Statistics 31 (1982) 188-190
|
||||
#
|
||||
# see also:
|
||||
# Correction to Algorithm AS 183
|
||||
# Applied Statistics 33 (1984) 123
|
||||
#
|
||||
# McLeod, A. I. (1985)
|
||||
# A remark on Algorithm AS 183
|
||||
# Applied Statistics 34 (1985),198-200
|
||||
#
|
||||
#
|
||||
# USE:
|
||||
# whrandom.random() yields double precision random numbers
|
||||
# uniformly distributed between 0 and 1.
|
||||
#
|
||||
# whrandom.seed() must be called before whrandom.random()
|
||||
# to seed the generator
|
||||
|
||||
|
||||
# Translated by Guido van Rossum from C source provided by
|
||||
# Adrian Baddeley.
|
||||
|
||||
|
||||
# The seed
|
||||
#
|
||||
_seed = [0, 0, 0]
|
||||
|
||||
|
||||
# Set the seed
|
||||
#
|
||||
def seed(x, y, z):
|
||||
_seed[:] = [x, y, z]
|
||||
|
||||
|
||||
# Return the next random number in the range [0.0 .. 1.0)
|
||||
#
|
||||
def random():
|
||||
from math import floor # floor() function
|
||||
#
|
||||
[x, y, z] = _seed
|
||||
x = 171 * (x % 177) - 2 * (x/177)
|
||||
y = 172 * (y % 176) - 35 * (y/176)
|
||||
z = 170 * (z % 178) - 63 * (z/178)
|
||||
#
|
||||
if x < 0: x = x + 30269
|
||||
if y < 0: y = y + 30307
|
||||
if z < 0: z = z + 30323
|
||||
#
|
||||
_seed[:] = [x, y, z]
|
||||
#
|
||||
term = float(x)/30269.0 + float(y)/30307.0 + float(z)/30323.0
|
||||
rand = term - floor(term)
|
||||
#
|
||||
if rand >= 1.0: rand = 0.0 # floor() inaccuracy?
|
||||
#
|
||||
return rand
|
||||
|
||||
|
||||
# Initialize from the current time
|
||||
#
|
||||
def init():
|
||||
import time
|
||||
t = time.time()
|
||||
seed(t%256, t/256%256, t/65536%256)
|
||||
|
||||
|
||||
# Make sure the generator is preset to a nonzero value
|
||||
#
|
||||
init()
|
Loading…
Reference in New Issue