initial commit
This commit is contained in:
commit
5d61e939aa
13
ansi.py
Normal file
13
ansi.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
#@+leo-ver=4-thin
|
||||
#@+node:jpenner.20091215224421.2:@thin ansi.py
|
||||
import config
|
||||
if config.USE_CYTHON:
|
||||
from ansi_cython import *
|
||||
else:
|
||||
from ansi_python import *
|
||||
|
||||
#@+others
|
||||
#@-others
|
||||
#@nonl
|
||||
#@-node:jpenner.20091215224421.2:@thin ansi.py
|
||||
#@-leo
|
540
ansi_cython.pyx
Normal file
540
ansi_cython.pyx
Normal file
|
@ -0,0 +1,540 @@
|
|||
#@+leo-ver=4-thin
|
||||
#@+node:jpenner.20091212133112.2:@thin ansi_cython.pyx
|
||||
#@@language python
|
||||
import config
|
||||
|
||||
cdef extern from "stdio.h":
|
||||
int sprintf(char *, char *,...)
|
||||
|
||||
cdef extern from "stdlib.h":
|
||||
ctypedef unsigned long size_t
|
||||
void free(void *ptr)
|
||||
void *malloc(size_t size)
|
||||
void *calloc(size_t nelem, size_t elsize)
|
||||
void *realloc(void *ptr, size_t size)
|
||||
size_t strlen(char *s)
|
||||
char *strcpy(char *dest, char *src)
|
||||
|
||||
#@+others
|
||||
#@+node:jpenner.20091212133112.3:Codes
|
||||
esc = '%s['%chr(27)
|
||||
reset = '%s0m'%esc
|
||||
cls = '%s2j'%esc
|
||||
|
||||
BLACK = 0
|
||||
RED = 1
|
||||
GREEN = 2
|
||||
YELLOW = 3
|
||||
BLUE = 4
|
||||
MAGENTA = 5
|
||||
CYAN = 6
|
||||
WHITE = 7
|
||||
|
||||
FBRIGHT = 8
|
||||
FBLINK = 16
|
||||
|
||||
rgcolorBg = range(8)
|
||||
rgcolorFg = range(8)
|
||||
rgcolorFg.extend([col | FBRIGHT for col in range(8)])
|
||||
|
||||
K_BACKSPACE = chr(8)
|
||||
K_TAB = chr(9)
|
||||
K_RETURN = chr(10)
|
||||
K_DEL = chr(127)
|
||||
K_LEFT = 256
|
||||
K_RIGHT = 257
|
||||
K_UP = 258
|
||||
K_DOWN = 259
|
||||
K_HOME = 260
|
||||
K_END = 261
|
||||
K_PGUP = 262
|
||||
K_PGDN = 263
|
||||
|
||||
def StrKey(ch):
|
||||
if type(ch) == str:
|
||||
return ord(ch)
|
||||
return str(ch)
|
||||
|
||||
def Ctrl(ch):
|
||||
ch = ch.upper()
|
||||
assert ch != 'M' and ch != 'J' and ch != 'H'
|
||||
return chr(ord(ch - 'A' + 1))
|
||||
|
||||
def FEnter(key):
|
||||
return key == "\n" or key == "\r"
|
||||
#@nonl
|
||||
#@-node:jpenner.20091212133112.3:Codes
|
||||
#@+node:jpenner.20091212133112.4:Ach
|
||||
# ANSI Character - contains prop and character
|
||||
|
||||
cdef struct SAch:
|
||||
unsigned char ch
|
||||
char fgCol
|
||||
char bgCol
|
||||
|
||||
cdef union UAch:
|
||||
int ach
|
||||
SAch sach
|
||||
|
||||
cpdef MkAch(char *ch, char fgcol=WHITE, char bgcol=BLACK):
|
||||
cdef UAch uach
|
||||
uach.sach.ch = ch[0]
|
||||
uach.sach.fgCol = fgcol
|
||||
uach.sach.bgCol = bgcol
|
||||
return uach.ach
|
||||
|
||||
# the class must be named Ach for backwards compatibility, but the hungarian name is OAch
|
||||
class Ach(object):
|
||||
def __init__(self, int ach):
|
||||
cdef UAch uach
|
||||
uach.ach = ach
|
||||
self.ch = chr(uach.sach.ch)
|
||||
self.fgCol = uach.sach.fgCol
|
||||
self.bgCol = uach.sach.bgCol
|
||||
|
||||
def ToAch(self):
|
||||
return MkAch(self.ch, self.fgCol, self.bgCol)
|
||||
|
||||
cdef AchFromOach(oach):
|
||||
if oach == None:
|
||||
return achBlankI
|
||||
return MkAch(oach.ch, oach.fgCol, oach.bgCol)
|
||||
cdef OachFromAch(int ach):
|
||||
if ach == achBlankI:
|
||||
return None
|
||||
assert ach != achInvdI
|
||||
return Ach(ach)
|
||||
|
||||
def ChFromAch(int ach):
|
||||
cdef UAch uach
|
||||
uach.ach = ach
|
||||
return chr(uach.sach.ch)
|
||||
|
||||
achBlank = 0
|
||||
achInvd = -1
|
||||
|
||||
cdef enum:
|
||||
achBlankI = 0
|
||||
achInvdI = -1
|
||||
chesc = 27
|
||||
FBRIGHTI = 8
|
||||
FBLINKI = 16
|
||||
|
||||
cdef inline AstFromAch(int ach, int achPrev = achInvdI):
|
||||
cdef UAch uach, uachPrev
|
||||
uach.ach = ach
|
||||
uachPrev.ach = achPrev
|
||||
cdef char ast[60]
|
||||
cdef char sgr[4]
|
||||
cdef int csgr = 0
|
||||
|
||||
if (achPrev == achInvdI) or (uachPrev.sach.fgCol != uach.sach.fgCol):
|
||||
sgr[csgr] = (uach.sach.fgCol & 7) + 30
|
||||
csgr = csgr + 1
|
||||
fBright = uach.sach.fgCol & FBRIGHTI
|
||||
if (achPrev == achInvdI) or (fBright != uachPrev.sach.fgCol & FBRIGHTI):
|
||||
if fBright:
|
||||
sgr[csgr] = 1
|
||||
else:
|
||||
sgr[csgr] = 2
|
||||
csgr = csgr + 1
|
||||
fBlink = uach.sach.fgCol & FBLINKI
|
||||
if (achPrev == achInvdI) or (fBlink != uachPrev.sach.fgCol & FBLINKI):
|
||||
if fBlink:
|
||||
sgr[csgr] = 5
|
||||
else:
|
||||
sgr[csgr] = 25
|
||||
csgr = csgr + 1
|
||||
if (achPrev == achInvdI) or (uachPrev.sach.bgCol != uach.sach.bgCol):
|
||||
sgr[csgr] = uach.sach.bgCol + 40
|
||||
csgr = csgr + 1
|
||||
if csgr == 0:
|
||||
sprintf(ast, "%c", uach.sach.ch)
|
||||
elif csgr == 1:
|
||||
sprintf(ast, "%c[%dm%c", chesc, sgr[0], uach.sach.ch)
|
||||
elif csgr == 2:
|
||||
sprintf(ast, "%c[%d;%dm%c", chesc, sgr[0], sgr[1], uach.sach.ch)
|
||||
elif csgr == 3:
|
||||
sprintf(ast, "%c[%d;%d;%dm%c", chesc, sgr[0], sgr[1], sgr[2], uach.sach.ch)
|
||||
elif csgr == 4:
|
||||
sprintf(ast, "%c[%d;%d;%d;%dm%c", chesc, sgr[0], sgr[1], sgr[2], sgr[3], uach.sach.ch)
|
||||
else:
|
||||
assert csgr >= 0 and csgr <= 4, "more sgr possibilities, please handle"
|
||||
return ast
|
||||
|
||||
#@-node:jpenner.20091212133112.4:Ach
|
||||
#@+node:jpenner.20091212133112.5:HTML
|
||||
mpch_entity = [0, 9786, 9787, 9829, 9830, 9827, 9824, 8226, 9688, 9675, 9689, 9794, 9792, 9834, 9835, 9788, 9658, 9668, 8597, 8252,
|
||||
182, 167, 9644, 8616, 8593, 8595, 8594, 8592, 8735, 8596, 9650, 9660, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
|
||||
44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
|
||||
74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
|
||||
103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
|
||||
8962, 199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197, 201, 230, 198, 244, 246, 242, 251,
|
||||
249, 255, 214, 220, 162, 163, 165, 8359, 402, 225, 237, 243, 250, 241, 209, 170, 186, 191, 8976, 172, 189, 188, 161, 171,
|
||||
187, 9617, 9618, 9619, 9474, 9508, 9569, 9570, 9558, 9557, 9571, 9553, 9559, 9565, 9564, 9563, 9488, 9492, 9524, 9516,
|
||||
9500, 9472, 9532, 9566, 9567, 9562, 9556, 9577, 9574, 9568, 9552, 9580, 9575, 9576, 9572, 9573, 9561, 9560, 9554, 9555,
|
||||
9579, 9578, 9496, 9484, 9608, 9604, 9612, 9616, 9600, 945, 223, 915, 960, 931, 963, 181, 964, 934, 920, 937, 948, 8734,
|
||||
966, 949, 8745, 8801, 177, 8805, 8804, 8992, 8993, 247, 8776, 176, 8729, 183, 8730, 8319, 178, 9632, 160]
|
||||
|
||||
setch_unsafe = set([ord('&'), ord('<'), ord('>'), ord('"'), ord("'")])
|
||||
mpcol_hcol = ["#000000", "#AA0000", "#00AA00", "#AA5500", "#0000AA", "#AA00AA", "#00AAAA", "#AAAAAA",
|
||||
"#555555", "#FF5555", "#55FF55", "#FFFF55", "#5555FF", "#FF55FF", "#55FFFF", "#FFFFFF"]
|
||||
|
||||
cdef HstFromAch(int ach, int achPrev = achInvdI):
|
||||
cdef UAch uach, uachPrev
|
||||
uach.ach = ach
|
||||
uachPrev.ach = achPrev
|
||||
stStyle = None
|
||||
if achPrev == achInvdI or uachPrev.sach.fgCol != uach.sach.fgCol or uachPrev.sach.bgCol != uach.sach.bgCol:
|
||||
stStyle = "color:" + mpcol_hcol[uach.sach.fgCol & 15] + ";background-color:" + mpcol_hcol[uach.sach.bgCol & 15]
|
||||
rgst = []
|
||||
if stStyle != None and achPrev != achInvdI:
|
||||
rgst.append("</span>")
|
||||
if stStyle != None:
|
||||
rgst.append("<span style='" + stStyle + "'>")
|
||||
if ach == achBlank:
|
||||
rgst.append(' ')
|
||||
else:
|
||||
entity = mpch_entity[uach.sach.ch]
|
||||
if entity == uach.sach.ch and not uach.sach.ch in setch_unsafe:
|
||||
rgst.append(chr(uach.sach.ch))
|
||||
else:
|
||||
rgst.append("&#" + str(entity) + ";")
|
||||
return ''.join(rgst)
|
||||
|
||||
#@-node:jpenner.20091212133112.5:HTML
|
||||
#@+node:jpenner.20091212133112.6:Pos
|
||||
class Pos(object):
|
||||
def __init__(self, int w=config.W, int h=config.H, int x=1, int y=1):
|
||||
self.i = PosI(w, h, x, y)
|
||||
def X(self):
|
||||
cdef PosI posI = self.i
|
||||
return posI.X()
|
||||
def Y(self):
|
||||
cdef PosI posI = self.i
|
||||
return posI.Y()
|
||||
def Inc(self):
|
||||
cdef PosI posI = self.i
|
||||
posI.Inc()
|
||||
def Up(self):
|
||||
cdef PosI posI = self.i
|
||||
return posI.Up()
|
||||
def Down(self):
|
||||
cdef PosI posI = self.i
|
||||
return posI.Down()
|
||||
def Left(self):
|
||||
cdef PosI posI = self.i
|
||||
return posI.Left()
|
||||
def Right(self):
|
||||
cdef PosI posI = self.i
|
||||
return posI.Right()
|
||||
def __setstate__(self, state):
|
||||
self.i = PosI(state["w"], state["h"], state["xz"] + 1, state["yz"] + 1)
|
||||
def __getstate__(self):
|
||||
cdef PosI posI = self.i
|
||||
return {"w": posI.w, "h": posI.h, "xz": posI.xz, "yz": posI.yz}
|
||||
|
||||
cdef class PosI(object):
|
||||
cdef int w, h, xz, yz
|
||||
def __init__(self, int w=config.W, int h=config.H, int x=1, int y=1):
|
||||
self.w = w
|
||||
self.h = h
|
||||
self.xz = x - 1
|
||||
self.yz = y - 1
|
||||
|
||||
cdef inline X(self): return self.xz + 1
|
||||
cdef inline Y(self): return self.yz + 1
|
||||
|
||||
cdef inline Inc(self):
|
||||
if self.xz == self.w - 1:
|
||||
if self.yz < self.h:
|
||||
self.xz = 0
|
||||
self.yz = self.yz + 1
|
||||
else:
|
||||
self.xz = self.xz + 1
|
||||
|
||||
cdef inline Up(self):
|
||||
if self.yz > 0:
|
||||
self.yz = self.yz - 1
|
||||
return True
|
||||
cdef inline Down(self):
|
||||
if self.yz < self.h - 1:
|
||||
self.yz = self.yz + 1
|
||||
return True
|
||||
cdef inline Left(self):
|
||||
if self.xz > 0:
|
||||
self.xz = self.xz - 1
|
||||
return True
|
||||
cdef inline Right(self):
|
||||
if self.xz < self.w - 1:
|
||||
self.xz = self.xz + 1
|
||||
return True
|
||||
cdef ToPos(self):
|
||||
return Pos(self.w, self.h, self.X(), self.Y())
|
||||
#@nonl
|
||||
#@-node:jpenner.20091212133112.6:Pos
|
||||
#@+node:jpenner.20100105170222.1:Ascr
|
||||
|
||||
class Ascr(object):
|
||||
def __init__(self, int w=config.W, int h=config.H, int achFill = achBlankI):
|
||||
cdef AscrI ascrI = AscrI(w,h)
|
||||
self.i = ascrI
|
||||
if achFill != achBlankI:
|
||||
ascrI.Fill(achFill, w, h)
|
||||
|
||||
def __setstate__(self, state):
|
||||
cdef AscrI ascrI = AscrI(state["w"], state["h"])
|
||||
self.i = ascrI
|
||||
cdef int iach = 0
|
||||
for mpxz_oach in state["mpyzxz_ach"]:
|
||||
for oach in mpxz_oach:
|
||||
ascrI.rgach[iach] = AchFromOach(oach)
|
||||
iach = iach + 1
|
||||
|
||||
def __getstate__(self):
|
||||
cdef AscrI ascrI = self.i
|
||||
cdef int iach = 0
|
||||
mpyzxz_oach = []
|
||||
for yz in range(ascrI.h):
|
||||
mpxz_oach = []
|
||||
for xz in range(ascrI.w):
|
||||
mpxz_oach.append(OachFromAch(ascrI.rgach[iach]))
|
||||
iach = iach + 1
|
||||
mpyzxz_oach.append(mpxz_oach)
|
||||
return {"w":ascrI.w, "h":ascrI.h, "mpyzxz_ach": mpyzxz_oach}
|
||||
|
||||
def W(self):
|
||||
cdef AscrI ascrI = self.i
|
||||
return ascrI.w
|
||||
def H(self):
|
||||
cdef AscrI ascrI = self.i
|
||||
return ascrI.h
|
||||
def ZPos(self, int xz, int yz):
|
||||
cdef AscrI ascrI = self.i
|
||||
return ascrI.ZPos(xz, yz)
|
||||
|
||||
#@ @+others
|
||||
#@+node:jpenner.20100105170222.2:Put
|
||||
def PutAch(self, int ach, int x, int y):
|
||||
cdef AscrI ascrI = self.i
|
||||
ascrI.PutAch(ach, x, y)
|
||||
|
||||
def GetAch(self, int x, int y):
|
||||
cdef AscrI ascrI = self.i
|
||||
return ascrI.rgach[ascrI.IAch(x - 1, y - 1)]
|
||||
|
||||
def PutRgach(self, rgach, int x, int y):
|
||||
cdef AscrI ascrI = self.i
|
||||
ascrI.PutRgach(rgach, x, y)
|
||||
|
||||
def PutSt(self, char *st, int x, int y, int colFg = WHITE, int colBg=BLACK):
|
||||
cdef AscrI ascrI = self.i
|
||||
ascrI.PutSt(st, x, y, colFg, colBg)
|
||||
|
||||
def Fill(self, int ach, int wIn, int hIn, int x = 1, int y = 1):
|
||||
cdef AscrI ascrI = self.i
|
||||
ascrI.Fill(ach, wIn, hIn, x, y)
|
||||
|
||||
def PutAscr(self, ascr, int x=1, int y=1):
|
||||
cdef AscrI ascrI = self.i
|
||||
ascrI.PutAscr(ascr.i, x, y)
|
||||
#@nonl
|
||||
#@-node:jpenner.20100105170222.2:Put
|
||||
#@+node:jpenner.20100105170222.3:Diff
|
||||
def AstDiff(self, ascr):
|
||||
cdef AscrI ascrI = self.i
|
||||
return ascrI.AstDiff(ascr.i)
|
||||
|
||||
def Hst(self):
|
||||
cdef AscrI ascrI = self.i
|
||||
return ascrI.Hst()
|
||||
#@-node:jpenner.20100105170222.3:Diff
|
||||
#@+node:jpenner.20091212133112.10:Ast
|
||||
def Ast(self):
|
||||
return Ascr(self.W(), self.H(), achInvdI).AstDiff(self) #stupid implementation
|
||||
#@nonl
|
||||
#@-node:jpenner.20091212133112.10:Ast
|
||||
#@-others
|
||||
#@-node:jpenner.20100105170222.1:Ascr
|
||||
#@+node:jpenner.20091212133112.7:AscrI
|
||||
|
||||
# ANSI Screen
|
||||
cdef class AscrI(object):
|
||||
cdef int w, h
|
||||
cdef int *rgach
|
||||
def __cinit__(self, int w=config.W, int h=config.H, int achFill = achBlankI):
|
||||
self.rgach = <int*>calloc(w * h, sizeof(int))
|
||||
if achFill != achBlankI:
|
||||
for iach in range(w * h):
|
||||
self.rgach[iach] = achFill
|
||||
self.w = w
|
||||
self.h = h
|
||||
|
||||
def __dealloc__(self):
|
||||
free(self.rgach)
|
||||
|
||||
cdef Zpos(self, int xz, int yz):
|
||||
return Pos(self.w, self.h, xz + 1, yz + 1)
|
||||
|
||||
#@ @+others
|
||||
#@+node:jpenner.20091212133112.8:Put
|
||||
cdef inline IAch(self, int xz, int yz):
|
||||
return xz + (self.w * yz)
|
||||
|
||||
cdef PutAch(self, int ach, int x, int y):
|
||||
if not (x < 1 or y < 1 or x > self.w or y > self.h): #clip
|
||||
self.rgach[self.IAch(x - 1, y - 1)] = ach
|
||||
#self.mpyzxz_ach[y-1][x-1] = ach
|
||||
|
||||
cdef inline GetAch(self, int x, int y):
|
||||
return self.rgach[self.IAch(x - 1, y - 1)]
|
||||
|
||||
cdef PutRgach(self, rgach, int x, int y):
|
||||
cdef int xz = x - 1
|
||||
cdef int iach
|
||||
if xz < self.w:
|
||||
if xz < 0:
|
||||
rgach = rgach[min(-xz, len(rgach)):]
|
||||
xz = 0
|
||||
if xz + len(rgach) >= self.w:
|
||||
rgach = rgach[:self.w - xz]
|
||||
iach = self.IAch(xz, y - 1)
|
||||
for ach in rgach:
|
||||
if ach != achBlankI:
|
||||
self.rgach[iach] = ach
|
||||
iach = iach + 1
|
||||
#self.mpyzxz_ach[y-1][xz:xz + len(rgach)] = rgach
|
||||
|
||||
cdef PutSt(self, char *st, int x, int y, int colFg = WHITE, int colBg=BLACK):
|
||||
if y < 1 or y > self.h:
|
||||
return
|
||||
cdef int cch = len(st)
|
||||
cdef int ichStart = 0
|
||||
cdef int xz = x - 1
|
||||
if xz < 0:
|
||||
ichStart = (-xz)
|
||||
cch = cch - ichStart
|
||||
xz = 0
|
||||
cch = min(cch, self.w - xz)
|
||||
cdef UAch uach
|
||||
uach.sach.fgCol = colFg
|
||||
uach.sach.bgCol = colBg
|
||||
cdef int iach = self.IAch(xz, y - 1)
|
||||
for ich in range(ichStart, ichStart + cch):
|
||||
uach.sach.ch = st[ich]
|
||||
self.rgach[iach] = uach.ach
|
||||
iach = iach + 1
|
||||
|
||||
#self.PutRgach([MkAch(ch, colFg, colBg) for ch in st], x, y)
|
||||
|
||||
cdef Fill(self, int ach, int wIn, int hIn, int x = 1, int y = 1):
|
||||
if x > self.w or y > self.h or ach == achBlankI:
|
||||
return
|
||||
cdef int xz = max(x - 1, 0)
|
||||
cdef int yz = max(y - 1, 0)
|
||||
cdef int w = min(self.w - xz, wIn)
|
||||
cdef int h = min(self.h - yz, hIn)
|
||||
cdef int iach
|
||||
for yzT in range(yz, yz + h):
|
||||
iach = self.IAch(xz, yzT)
|
||||
for xzT in range(w):
|
||||
self.rgach[iach] = ach
|
||||
iach = iach + 1
|
||||
#self.mpyzxz_ach[yzT][xz:xz + w] = ach
|
||||
|
||||
cdef PutAscr(self, AscrI ascr, int x=1, int y=1):
|
||||
if x > self.w or y > self.h:
|
||||
return
|
||||
cdef int xz = max(x - 1, 0)
|
||||
cdef int yz = max(y - 1, 0)
|
||||
cdef int w = min(self.w - xz, ascr.w)
|
||||
cdef int h = min(self.h - yz, ascr.h)
|
||||
cdef int yzOther = 0
|
||||
cdef int iach, iachOther, ach
|
||||
for yzT in range(yz, yz + h):
|
||||
iach = self.IAch(xz, yzT)
|
||||
iachOther = ascr.IAch(0, yzOther)
|
||||
for xzT in range(w):
|
||||
ach = ascr.rgach[iachOther]
|
||||
if ach != achBlankI:
|
||||
self.rgach[iach] = ach
|
||||
iach = iach + 1
|
||||
iachOther = iachOther + 1
|
||||
yzOther = yzOther + 1
|
||||
#@-node:jpenner.20091212133112.8:Put
|
||||
#@+node:jpenner.20091212133112.9:AstDiff
|
||||
cdef AstDiff(self, AscrI ascr):
|
||||
assert self.w == ascr.w and self.h == ascr.h
|
||||
cdef int xz = 0
|
||||
cdef int yz = 0
|
||||
cdef int xzPred = -1
|
||||
cdef int achPrev = achInvdI
|
||||
cdef int achBeforeEOL = achInvdI
|
||||
cdef int achOld, achNew, achNewRaw
|
||||
cdef int achSpace = MkAch(' ')
|
||||
|
||||
rgast = []
|
||||
for iach in range(self.w * self.h):
|
||||
achOld = self.rgach[iach]
|
||||
achNewRaw = ascr.rgach[iach]
|
||||
if achNewRaw == achBlankI:
|
||||
achNew = achSpace
|
||||
else:
|
||||
achNew = achNewRaw
|
||||
if xz == self.w - 2:
|
||||
achBeforeEOL = achNew
|
||||
if achOld != achNewRaw:
|
||||
if xz == self.w - 1:
|
||||
# Linewrap avoidance algorithm:
|
||||
# when drawing the last character on a line, draw it in the space occupied by the character before.
|
||||
rgast.append("%s%d;%dH" % (esc, yz + 1, xz))
|
||||
rgast.append(AstFromAch(achNew, achInvdI))
|
||||
# then, move the cursor back onto the character we just drew, and perform an insert.
|
||||
rgast.append("%sD%s@" % (esc, esc))
|
||||
# finally, draw the character before the last character in the line.
|
||||
rgast.append(AstFromAch(achBeforeEOL, achNew))
|
||||
else:
|
||||
if xz != xzPred:
|
||||
xzPred = xz
|
||||
rgast.append("%s%d;%dH" % (esc, yz + 1, xz + 1))
|
||||
achPrev = achInvdI
|
||||
rgast.append(AstFromAch(achNew, achPrev))
|
||||
|
||||
achPrev = achNew
|
||||
xzPred = xzPred + 1
|
||||
xz = xz + 1
|
||||
if xz == self.w:
|
||||
xz = 0
|
||||
xzPred = -1
|
||||
yz = yz + 1
|
||||
return "".join(rgast)
|
||||
#@-node:jpenner.20091212133112.9:AstDiff
|
||||
#@+node:jpenner.20091212133112.11:Hst
|
||||
cdef Hst(self):
|
||||
rgst = ["<pre style='font-family:\"Courier New\", Courier, System, monospace'>"]
|
||||
cdef int achPrev = achInvdI
|
||||
cdef int xz = 0
|
||||
cdef int ach
|
||||
for iach in range(self.w * self.h):
|
||||
ach = self.rgach[iach]
|
||||
rgst.append(HstFromAch(ach, achPrev))
|
||||
achPrev = ach
|
||||
xz = xz + 1
|
||||
if xz == self.w:
|
||||
xz = 0
|
||||
rgst.append("<br>")
|
||||
|
||||
rgst.append("</span></pre>")
|
||||
return ''.join(rgst)
|
||||
#@-node:jpenner.20091212133112.11:Hst
|
||||
#@-others
|
||||
#@-node:jpenner.20091212133112.7:AscrI
|
||||
#@+node:jpenner.20091212133112.12:FKeyPrintable
|
||||
def FKeyPrintable(key):
|
||||
return type(key) == str and (ord(key) >= 32 and ord(key) <= 126)
|
||||
|
||||
#@-node:jpenner.20091212133112.12:FKeyPrintable
|
||||
#@-others
|
||||
#@nonl
|
||||
#@-node:jpenner.20091212133112.2:@thin ansi_cython.pyx
|
||||
#@-leo
|
294
ansi_python.py
Normal file
294
ansi_python.py
Normal file
|
@ -0,0 +1,294 @@
|
|||
#@+leo-ver=4-thin
|
||||
#@+node:jpenner.20090510085557.4:@thin ansi_python.py
|
||||
#@@language python
|
||||
import config
|
||||
import numpy
|
||||
|
||||
#@+others
|
||||
#@+node:jpenner.20091212133112.3:Codes
|
||||
esc = '%s['%chr(27)
|
||||
reset = '%s0m'%esc
|
||||
cls = '%s2j'%esc
|
||||
|
||||
BLACK = 0
|
||||
RED = 1
|
||||
GREEN = 2
|
||||
YELLOW = 3
|
||||
BLUE = 4
|
||||
MAGENTA = 5
|
||||
CYAN = 6
|
||||
WHITE = 7
|
||||
|
||||
FBRIGHT = 8
|
||||
FBLINK = 16
|
||||
|
||||
rgcolorBg = range(8)
|
||||
rgcolorFg = range(8)
|
||||
rgcolorFg.extend([col | FBRIGHT for col in range(8)])
|
||||
|
||||
K_BACKSPACE = chr(8)
|
||||
K_TAB = chr(9)
|
||||
K_RETURN = chr(10)
|
||||
K_DEL = chr(127)
|
||||
K_LEFT = 256
|
||||
K_RIGHT = 257
|
||||
K_UP = 258
|
||||
K_DOWN = 259
|
||||
K_HOME = 260
|
||||
K_END = 261
|
||||
K_PGUP = 262
|
||||
K_PGDN = 263
|
||||
|
||||
def StrKey(ch):
|
||||
if type(ch) == str:
|
||||
return ord(ch)
|
||||
return str(ch)
|
||||
|
||||
def Ctrl(ch):
|
||||
ch = ch.upper()
|
||||
assert ch != 'M' and ch != 'J' and ch != 'H'
|
||||
return chr(ord(ch - 'A' + 1))
|
||||
|
||||
def FEnter(key):
|
||||
return key == "\n" or key == "\r"
|
||||
#@nonl
|
||||
#@-node:jpenner.20091212133112.3:Codes
|
||||
#@+node:jpenner.20090510085557.6:Ach
|
||||
# ANSI Character - contains prop and character
|
||||
class Ach(object):
|
||||
def __init__(self, ch, fgcol=WHITE, bgcol=BLACK):
|
||||
self.ch = ch
|
||||
self.fgCol = fgcol
|
||||
self.bgCol = bgcol
|
||||
def __eq__(self, ach):
|
||||
return type(ach) is Ach and self.ch == ach.ch and self.fgCol == ach.fgCol and self.bgCol == ach.bgCol
|
||||
def __ne__(self, ach):
|
||||
return not (self == ach)
|
||||
|
||||
def MkAch(ch, fgcol=WHITE, bgcol=BLACK):
|
||||
return Ach(ch, fgcol, bgcol)
|
||||
|
||||
def ChFromAch(ach):
|
||||
return ach.ch
|
||||
|
||||
achBlank = Ach(' ')
|
||||
achInvd = Ach(chr(255), -1, -1)
|
||||
|
||||
def AstFromAch(ach, achPrev = None):
|
||||
ast = ach.ch
|
||||
rgsgr = []
|
||||
if (achPrev == None) or (achPrev.fgCol != ach.fgCol):
|
||||
rgsgr.append(str((ach.fgCol & 7) + 30))
|
||||
fBright = ach.fgCol & FBRIGHT
|
||||
if (achPrev == None) or (fBright != achPrev.fgCol & FBRIGHT):
|
||||
if fBright:
|
||||
rgsgr.append("1")
|
||||
else:
|
||||
rgsgr.append("2")
|
||||
fBlink = ach.fgCol & FBLINK
|
||||
if (achPrev == None) or (fBlink != achPrev.fgCol & FBLINK):
|
||||
if fBlink:
|
||||
rgsgr.append("5")
|
||||
else:
|
||||
rgsgr.append("25")
|
||||
if (achPrev == None) or (achPrev.bgCol != ach.bgCol):
|
||||
rgsgr.append(str(ach.bgCol + 40))
|
||||
if len(rgsgr) > 0:
|
||||
ast = esc + ";".join(rgsgr) + "m" + ast
|
||||
return ast
|
||||
|
||||
dtAch = numpy.dtype(object)
|
||||
|
||||
#@-node:jpenner.20090510085557.6:Ach
|
||||
#@+node:jpenner.20091016050502.2:HTML
|
||||
mpch_entity = [0, 9786, 9787, 9829, 9830, 9827, 9824, 8226, 9688, 9675, 9689, 9794, 9792, 9834, 9835, 9788, 9658, 9668, 8597, 8252,
|
||||
182, 167, 9644, 8616, 8593, 8595, 8594, 8592, 8735, 8596, 9650, 9660, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
|
||||
44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
|
||||
74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
|
||||
103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
|
||||
8962, 199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197, 201, 230, 198, 244, 246, 242, 251,
|
||||
249, 255, 214, 220, 162, 163, 165, 8359, 402, 225, 237, 243, 250, 241, 209, 170, 186, 191, 8976, 172, 189, 188, 161, 171,
|
||||
187, 9617, 9618, 9619, 9474, 9508, 9569, 9570, 9558, 9557, 9571, 9553, 9559, 9565, 9564, 9563, 9488, 9492, 9524, 9516,
|
||||
9500, 9472, 9532, 9566, 9567, 9562, 9556, 9577, 9574, 9568, 9552, 9580, 9575, 9576, 9572, 9573, 9561, 9560, 9554, 9555,
|
||||
9579, 9578, 9496, 9484, 9608, 9604, 9612, 9616, 9600, 945, 223, 915, 960, 931, 963, 181, 964, 934, 920, 937, 948, 8734,
|
||||
966, 949, 8745, 8801, 177, 8805, 8804, 8992, 8993, 247, 8776, 176, 8729, 183, 8730, 8319, 178, 9632, 160]
|
||||
|
||||
setch_unsafe = set(['&', '<', '>', '"', "'"])
|
||||
mpcol_hcol = ["#000000", "#AA0000", "#00AA00", "#AA5500", "#0000AA", "#AA00AA", "#00AAAA", "#AAAAAA",
|
||||
"#555555", "#FF5555", "#55FF55", "#FFFF55", "#5555FF", "#FF55FF", "#55FFFF", "#FFFFFF"]
|
||||
|
||||
def HstFromAch(ach, achPrev = None):
|
||||
stStyle = None
|
||||
if achPrev == None or achPrev.fgCol != ach.fgCol or achPrev.bgCol != ach.bgCol:
|
||||
stStyle = "color:" + mpcol_hcol[ach.fgCol & 15] + ";background-color:" + mpcol_hcol[ach.bgCol & 15]
|
||||
rgst = []
|
||||
if stStyle != None and achPrev != None:
|
||||
rgst.append("</span>")
|
||||
if stStyle != None:
|
||||
rgst.append("<span style='" + stStyle + "'>")
|
||||
ch = ord(ach.ch)
|
||||
entity = mpch_entity[ch]
|
||||
if entity == ch and not ach.ch in setch_unsafe:
|
||||
rgst.append(ach.ch)
|
||||
else:
|
||||
rgst.append("&#" + str(mpch_entity[ord(ach.ch)]) + ";")
|
||||
return ''.join(rgst)
|
||||
#@nonl
|
||||
#@-node:jpenner.20091016050502.2:HTML
|
||||
#@+node:jpenner.20090510085557.7:Pos
|
||||
class Pos(object):
|
||||
def __init__(self, w=config.W, h=config.H, x=1, y=1):
|
||||
self.w = w
|
||||
self.h = h
|
||||
self.xz = x - 1
|
||||
self.yz = y - 1
|
||||
|
||||
def X(self): return self.xz + 1
|
||||
def Y(self): return self.yz + 1
|
||||
|
||||
def Inc(self):
|
||||
if self.xz == self.w - 1:
|
||||
if self.yz < self.h:
|
||||
self.xz = 0
|
||||
self.yz = self.yz + 1
|
||||
else:
|
||||
self.xz = self.xz + 1
|
||||
|
||||
def Up(self):
|
||||
if self.yz > 0:
|
||||
self.yz = self.yz - 1
|
||||
def Down(self):
|
||||
if self.yz < self.h - 1:
|
||||
self.yz = self.yz + 1
|
||||
def Left(self):
|
||||
if self.xz > 0:
|
||||
self.xz = self.xz - 1
|
||||
def Right(self):
|
||||
if self.xz < self.w - 1:
|
||||
self.xz = self.xz + 1
|
||||
#@-node:jpenner.20090510085557.7:Pos
|
||||
#@+node:jpenner.20090510085557.8:Ascr
|
||||
# ANSI Screen
|
||||
class Ascr(object):
|
||||
def __init__(self, w=config.W, h=config.H, achFill = None):
|
||||
self.mpyzxz_ach = numpy.empty((h,w), dtAch)
|
||||
self.mpyzxz_ach[:] = achFill
|
||||
self.w = w
|
||||
self.h = h
|
||||
|
||||
def Zpos(self, xz, yz):
|
||||
return Pos(self.w, self.h, xz + 1, yz + 1)
|
||||
|
||||
def W(self): return self.w
|
||||
def H(self): return self.h
|
||||
|
||||
#@ @+others
|
||||
#@+node:jpenner.20090526105844.8:Put
|
||||
def PutAch(self, ach, x, y):
|
||||
if not (x < 1 or y < 1 or x > self.w or y > self.h): #clip
|
||||
self.mpyzxz_ach[y-1][x-1] = ach
|
||||
|
||||
def GetAch(self, x, y):
|
||||
return self.mpyzxz_ach[y-1][x-1]
|
||||
|
||||
def PutRgach(self, rgach, x, y):
|
||||
xz = x - 1
|
||||
if xz < self.w:
|
||||
if xz < 0:
|
||||
rgach = rgach[min(-xz, len(rgach)):]
|
||||
xz = 0
|
||||
if xz + len(rgach) >= self.w:
|
||||
rgach = rgach[:self.w - xz]
|
||||
self.mpyzxz_ach[y-1][xz:xz + len(rgach)] = rgach
|
||||
|
||||
def PutSt(self, st, x, y, colFg = WHITE, colBg=BLACK):
|
||||
self.PutRgach([MkAch(ch, colFg, colBg) for ch in st], x, y)
|
||||
|
||||
def Fill(self, ach, w, h, x = 1, y = 1):
|
||||
if x > self.w or y > self.h:
|
||||
return
|
||||
xz = max(x - 1, 0)
|
||||
yz = max(y - 1, 0)
|
||||
w = min(self.w - xz, w)
|
||||
h = min(self.h - yz, h)
|
||||
for yzT in range(yz, yz + h):
|
||||
self.mpyzxz_ach[yzT][xz:xz + w] = ach
|
||||
|
||||
def PutAscr(self, ascr, x=1, y=1):
|
||||
for irow, rgachRow in enumerate(ascr.mpyzxz_ach):
|
||||
iachPut = -1
|
||||
for iach, ach in enumerate(rgachRow):
|
||||
if iachPut < 0 and ach != None:
|
||||
iachPut = iach
|
||||
elif iachPut >= 0 and ach == None:
|
||||
self.PutRgach(rgachRow[iachPut:iach], x + iachPut, y + irow)
|
||||
iachPut = -1
|
||||
if iachPut >= 0:
|
||||
self.PutRgach(rgachRow[iachPut:], x + iachPut, y + irow)
|
||||
iachPut = -1
|
||||
#@-node:jpenner.20090526105844.8:Put
|
||||
#@+node:jpenner.20090527144214.3:Diff
|
||||
def AstDiff(self, ascr):
|
||||
assert self.w == ascr.w and self.h == ascr.h
|
||||
rgast = []
|
||||
achPrev = None
|
||||
yz = 0
|
||||
for rgachRowOld, rgachRowNew in zip(self.mpyzxz_ach, ascr.mpyzxz_ach):
|
||||
xz = 0
|
||||
xzPred = -1
|
||||
for achOld, achNew in zip(rgachRowOld, rgachRowNew):
|
||||
if xz == self.w - 2:
|
||||
achBeforeEOL = achNew
|
||||
if achOld != achNew:
|
||||
achNew = achNew or achBlank
|
||||
if xz == self.w - 1:
|
||||
# Linewrap avoidance algorithm:
|
||||
# when drawing the last character on a line, draw it in the space occupied by the character before.
|
||||
rgast.append("%s%d;%dH" % (esc, yz + 1, xz))
|
||||
rgast.append(AstFromAch(achNew, None))
|
||||
# then, move the cursor back onto the character we just drew, and perform an insert.
|
||||
rgast.append("%sD%s@" % (esc, esc))
|
||||
# finally, draw the character before the last character in the line.
|
||||
rgast.append(AstFromAch(achBeforeEOL or achBlank, achNew))
|
||||
else:
|
||||
if xz != xzPred:
|
||||
xzPred = xz
|
||||
rgast.append("%s%d;%dH" % (esc, yz + 1, xz + 1))
|
||||
achPrev = None
|
||||
rgast.append(AstFromAch(achNew, achPrev))
|
||||
achPrev = achNew
|
||||
xzPred = xzPred + 1
|
||||
xz = xz + 1
|
||||
yz = yz + 1
|
||||
return "".join(rgast)
|
||||
#@nonl
|
||||
#@-node:jpenner.20090527144214.3:Diff
|
||||
#@+node:jpenner.20090529173104.26:Ast
|
||||
def Ast(self):
|
||||
return Ascr(self.w, self.h, achInvd).AstDiff(self) #stupid implementation
|
||||
#@nonl
|
||||
#@-node:jpenner.20090529173104.26:Ast
|
||||
#@+node:jpenner.20091016050502.3:Hst
|
||||
def Hst(self):
|
||||
rgst = ["<pre>"]
|
||||
achPrev = None
|
||||
for rgachRow in self.mpyzxz_ach:
|
||||
for ach in rgachRow:
|
||||
rgst.append(HstFromAch(ach or achBlank, achPrev))
|
||||
achPrev = ach or achBlank
|
||||
rgst.append("<br>")
|
||||
rgst.append("</span></pre>")
|
||||
return ''.join(rgst)
|
||||
#@nonl
|
||||
#@-node:jpenner.20091016050502.3:Hst
|
||||
#@-others
|
||||
#@-node:jpenner.20090510085557.8:Ascr
|
||||
#@+node:jpenner.20090521203229.341:FKeyPrintable
|
||||
def FKeyPrintable(key):
|
||||
return type(key) == str and (ord(key) >= 32 and ord(key) <= 126)
|
||||
|
||||
#@-node:jpenner.20090521203229.341:FKeyPrintable
|
||||
#@-others
|
||||
#@nonl
|
||||
#@-node:jpenner.20090510085557.4:@thin ansi_python.py
|
||||
#@-leo
|
27
auth.py
Normal file
27
auth.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
#@+leo-ver=4-thin
|
||||
#@+node:jpenner.20090607135901.1:@thin auth.py
|
||||
import MySQLdb
|
||||
import hashlib
|
||||
import config
|
||||
|
||||
class NoopAuth(object):
|
||||
def FAuthorized(self, user, passwd):
|
||||
return True
|
||||
|
||||
class DrupalAuth(object):
|
||||
def FAuthorized(self, user, passwd):
|
||||
conn = MySQLdb.connect(host = config.drupaldb_host, user = config.drupaldb_user, passwd = config.drupaldb_password, db = config.drupaldb)
|
||||
try:
|
||||
cursor = conn.cursor()
|
||||
try:
|
||||
cursor.execute("SELECT name, pass FROM users WHERE name = %s AND pass = %s", (user, hashlib.md5(passwd).hexdigest()))
|
||||
return cursor.fetchone() != None
|
||||
finally:
|
||||
cursor.close()
|
||||
except Exception:
|
||||
return False
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
#@-node:jpenner.20090607135901.1:@thin auth.py
|
||||
#@-leo
|
826
basetoken.py
Normal file
826
basetoken.py
Normal file
|
@ -0,0 +1,826 @@
|
|||
from engine import *
|
||||
import config
|
||||
from zope.interface import implements, Interface
|
||||
import weakref
|
||||
from util import *
|
||||
|
||||
class Blinker(Token):
|
||||
def InitPersistent(self, owner, setter, rgVal = [True, False], interval = 500):
|
||||
Token.InitPersistent(self, owner)
|
||||
self.setter = setter
|
||||
self.rgVal = rgVal
|
||||
self.interval = interval
|
||||
def run(self):
|
||||
while True:
|
||||
for val in self.rgVal:
|
||||
self.setter(val)
|
||||
self.wait(self.interval)
|
||||
|
||||
class StaticGraphic(Token):
|
||||
def InitPersistent(self, owner, ascr, pos, *rgtag):
|
||||
Token.InitPersistent(self, owner)
|
||||
self.pos = pos
|
||||
self.tag("drawable", *rgtag)
|
||||
self.ascr = ascr
|
||||
def draw(self, ascr, client):
|
||||
ascr.PutAscr(self.ascr, self.pos[0], self.pos[1])
|
||||
|
||||
|
||||
class AnimatedGraphic(StaticGraphic):
|
||||
def InitPersistent(self, owner, rgascr, pos, interval, *rgtag):
|
||||
StaticGraphic.InitPersistent(self, owner, rgascr[0], pos, *rgtag)
|
||||
Blinker(self, self.setAscr, rgascr, interval)
|
||||
def setAscr(self, ascr):
|
||||
self.ascr = ascr
|
||||
|
||||
class Terminal(Token):
|
||||
def InitPersistent(self, owner, client, w = config.W, h = config.H):
|
||||
Token.InitPersistent(self, owner, "drawable", "background")
|
||||
self.client = client
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.w = w
|
||||
self.h = h
|
||||
self.fWrapHoriz = False
|
||||
self.fWrapVert = True
|
||||
self.stLine = None
|
||||
self.xLine = None
|
||||
self.yLine = None
|
||||
self.screen = []
|
||||
self.fBlink = False
|
||||
self.colBg = ansi.BLUE
|
||||
self.chEcho = None
|
||||
for y in range(h):
|
||||
self.screen.append("")
|
||||
Blinker(self, self.setBlink)
|
||||
|
||||
def setBlink(self, fBlink):
|
||||
self.fBlink = fBlink
|
||||
|
||||
def getKey(self):
|
||||
return self.client.evKey.receive(self)
|
||||
|
||||
def getPrintableKey(self):
|
||||
while True:
|
||||
key = self.getKey()
|
||||
if ansi.FKeyPrintable(key):
|
||||
return key
|
||||
|
||||
def deleteCh(self):
|
||||
stOld = self.screen[self.y]
|
||||
self.screen[self.y] = stOld[0:self.x] + stOld[self.x + 1:]
|
||||
|
||||
def printSt(self, st):
|
||||
stOld = self.screen[self.y]
|
||||
stNew = stOld[0:self.x] + st + stOld[self.x+len(st):]
|
||||
self.screen[self.y] = stNew
|
||||
self.moveTo(self.x + len(st), self.y)
|
||||
|
||||
def moveTo(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
while (self.x >= self.w):
|
||||
if (self.fWrapHoriz):
|
||||
self.y = self.y + 1
|
||||
self.x = self.x - self.w
|
||||
else:
|
||||
self.x = self.w - 1
|
||||
while (self.x < 0):
|
||||
self.y = self.y - 1
|
||||
self.x = self.x + self.w
|
||||
if (self.y < 0):
|
||||
self.y = 0
|
||||
while (self.fWrapVert and self.y >= self.h):
|
||||
self.screen = self.screen[1:]
|
||||
self.screen.append("")
|
||||
self.y = self.y - 1
|
||||
self.screen[self.y] = self.screen[self.y].ljust(self.x)
|
||||
|
||||
def type(self, st):
|
||||
self.client.beep()
|
||||
for iSt in range(len(st)):
|
||||
self.printSt(st[iSt:iSt + 1])
|
||||
self.wait(35)
|
||||
|
||||
def typeLn(self, st):
|
||||
self.type(st)
|
||||
self.newLine()
|
||||
|
||||
def centerLn(self, st):
|
||||
self.typeLn(st.rjust((self.w / 2) + (len(st) / 2)))
|
||||
|
||||
def getLine(self):
|
||||
self.xLine = self.x
|
||||
self.yLine = self.y
|
||||
self.stLine = ""
|
||||
|
||||
fWrapHorizStart = self.fWrapHoriz
|
||||
self.fWrapHoriz = False
|
||||
while True:
|
||||
key = self.getKey()
|
||||
fBeep = True
|
||||
if (key == ansi.K_BACKSPACE and self.x > self.xLine):
|
||||
self.stLine = self.stLine[:self.x - self.xLine - 1] + self.stLine[self.x - self.xLine:]
|
||||
self.moveTo(self.x - 1, self.y)
|
||||
elif (key == ansi.K_LEFT and self.x > self.xLine):
|
||||
self.moveTo(self.x - 1, self.y)
|
||||
elif (key == ansi.K_RIGHT):
|
||||
self.moveTo(self.x + 1, self.y)
|
||||
if (self.x - self.xLine) > len(self.stLine):
|
||||
self.stLine = self.stLine + " "
|
||||
elif (ansi.FKeyPrintable(key)):
|
||||
self.stLine = self.stLine[:self.x - self.xLine] + key + self.stLine[(self.x + 1) - self.xLine:]
|
||||
self.moveTo(self.x + 1, self.y)
|
||||
elif key == ansi.K_RETURN:
|
||||
break
|
||||
else:
|
||||
print "weird key", ansi.StrKey(key)
|
||||
fBeep = False
|
||||
if fBeep:
|
||||
self.client.beep()
|
||||
self.fWrapHoriz = fWrapHorizStart
|
||||
|
||||
x,y = self.x, self.y
|
||||
self.moveTo(self.xLine, self.yLine)
|
||||
self.printSt(self.StLineDisp())
|
||||
self.moveTo(x,y)
|
||||
|
||||
stLine = self.stLine.strip()
|
||||
self.stLine = None
|
||||
self.xLine = None
|
||||
self.yLine = None
|
||||
return stLine
|
||||
|
||||
def StLineDisp(self):
|
||||
return self.stLine if not self.chEcho else self.chEcho * len(self.stLine)
|
||||
def draw(self, ascr, client):
|
||||
if client == self.client:
|
||||
y = 1
|
||||
for line in self.screen:
|
||||
ascr.PutSt("{0:{1}}".format(line, self.w), 1, y, ansi.WHITE | ansi.FBRIGHT, self.colBg)
|
||||
y = y + 1
|
||||
if self.stLine:
|
||||
ascr.PutSt(self.StLineDisp(), self.xLine + 1, self.yLine + 1, ansi.WHITE | ansi.FBRIGHT, self.colBg)
|
||||
if (self.fBlink):
|
||||
ascr.PutAch(ansi.MkAch(" ", ansi.WHITE | ansi.FBRIGHT, ansi.WHITE), self.x + 1, self.y + 1)
|
||||
def spin(self, stSpin):
|
||||
self.moveTo(self.x - 1, self.y)
|
||||
self.printSt(stSpin)
|
||||
|
||||
def newSpinner(self):
|
||||
return Blinker(self.game, self.spin, ["/","-","\\", "|"], 100)
|
||||
|
||||
def newLine(self, count = 1, wait = 0):
|
||||
for i in range(count):
|
||||
self.moveTo(0, self.y + 1)
|
||||
self.beep()
|
||||
self.wait(wait)
|
||||
|
||||
def beep(self):
|
||||
self.client.beep()
|
||||
|
||||
def setColBg(self, colBg):
|
||||
self.colBg = colBg
|
||||
class AutoJoiner(Token):
|
||||
def InitPersistent(self, owner, *rgclsTok):
|
||||
Token.InitPersistent(self, owner)
|
||||
self.rgclsTok = rgclsTok
|
||||
|
||||
def InitTransient(self):
|
||||
Token.InitTransient(self)
|
||||
self.mpclient_rgtok = {}
|
||||
def run(self):
|
||||
def dgoobLeave(client):
|
||||
for tok in self.mpclient_rgtok[client]:
|
||||
print "killing ", tok
|
||||
tok.die()
|
||||
while True:
|
||||
with self.game.evLeave.oob(self, dgoobLeave):
|
||||
client = self.game.evJoin.receive(self)
|
||||
rgtok = []
|
||||
for clsTok in self.rgclsTok:
|
||||
if FIter(clsTok):
|
||||
tok = clsTok[0](self.game, client, *clsTok[1:])
|
||||
else:
|
||||
tok = clsTok(self.game, client)
|
||||
rgtok.append(tok)
|
||||
self.mpclient_rgtok[client] = rgtok
|
||||
|
||||
class AliveWithPlayers(Token):
|
||||
def InitPersistent(self, owner, *rgclsTok):
|
||||
Token.InitPersistent(self, owner)
|
||||
self.rgclsTok = rgclsTok
|
||||
|
||||
def InitTransient(self):
|
||||
Token.InitTransient(self)
|
||||
self.rgclient = []
|
||||
|
||||
def OnLeave(self, client):
|
||||
self.rgclient.remove(client)
|
||||
if len(self.rgclient) == 0:
|
||||
for tok in [x for x in self.rgtokOwn]:
|
||||
tok.die()
|
||||
|
||||
def run(self):
|
||||
with self.game.evLeave.oob(self, self.OnLeave):
|
||||
while True:
|
||||
self.rgclient.append(self.game.evJoin.receive(self))
|
||||
if len(self.rgclient) == 1:
|
||||
for clsTok in self.rgclsTok:
|
||||
if FIter(clsTok):
|
||||
tok = clsTok[0](self, clsTok[1:])
|
||||
else:
|
||||
tok = clsTok(self)
|
||||
|
||||
class AutoKiller(Token):
|
||||
def InitTransient(self):
|
||||
Token.InitTransient(self)
|
||||
self.rgclient = []
|
||||
def OnLeave(self, client):
|
||||
self.rgclient.remove(client)
|
||||
if len(self.rgclient) == 0:
|
||||
self.game.finish()
|
||||
def run(self):
|
||||
with self.game.evLeave.oob(self, self.OnLeave):
|
||||
while True:
|
||||
self.rgclient.append(self.game.evJoin.receive(self))
|
||||
|
||||
#selection oracle
|
||||
class Selor(TPrs):
|
||||
NONE = 0
|
||||
PRI = 1
|
||||
SEC = 2
|
||||
|
||||
def __init__(self, mi, selorParent, rgmiSec, fPri):
|
||||
self.selorParent = selorParent
|
||||
self.mi = mi
|
||||
self.rgmiSec = rgmiSec
|
||||
self.fPri = fPri
|
||||
|
||||
def MiParent(self):
|
||||
if self.selorParent != None:
|
||||
return self.selorParent.mi
|
||||
return None
|
||||
|
||||
def KSel(self):
|
||||
if self.fPri:
|
||||
return self.PRI
|
||||
elif self.mi in self.rgmiSec:
|
||||
return self.SEC
|
||||
else:
|
||||
return self.NONE
|
||||
|
||||
def SelorChild(self, miChild, fPri):
|
||||
return Selor(miChild, self, self.rgmiSec, self.fPri and fPri)
|
||||
|
||||
def SelorDeselect(self):
|
||||
return Selor(self.mi, self.selorParent, self.rgmiSec, False)
|
||||
class Mi(TPrs):
|
||||
def InitPersistent(self):
|
||||
self.miParent = None
|
||||
self.fNotice = False
|
||||
self.rgmiNotice = [self]
|
||||
def Height(self, w):
|
||||
return 1
|
||||
|
||||
def StName(self):
|
||||
return "Unnamed"
|
||||
|
||||
def StKey(self):
|
||||
return self.StName()
|
||||
def HandleKey(self, key):
|
||||
return False
|
||||
def FIgnoreParent(self):
|
||||
return False
|
||||
|
||||
def DrawWithParent(self, selorParent, ascr, x, y, w, fPri):
|
||||
self.Draw(ascr, x, y, w, selorParent.SelorChild(self, fPri))
|
||||
|
||||
def ColBgDefault(self):
|
||||
return ansi.BLUE
|
||||
def ColBgSelected(self, fPri):
|
||||
return ansi.YELLOW if fPri else ansi.CYAN
|
||||
def ColBgNotice(self):
|
||||
return ansi.CYAN
|
||||
|
||||
def ColBg(self, selor):
|
||||
if selor != None and selor.KSel() != Selor.NONE:
|
||||
if selor.KSel() == Selor.PRI:
|
||||
for mi in self.rgmiNotice:
|
||||
if mi != self and mi.fNotice:
|
||||
print "Notice cleared for ", mi.StName(), "by ", self.StName()
|
||||
mi.fNotice = False
|
||||
return self.ColBgSelected(True)
|
||||
else:
|
||||
return self.ColBgSelected(False)
|
||||
elif self.FNoticeFlagged():
|
||||
return self.ColBgNotice()
|
||||
elif not self.FIgnoreParent() and selor != None and selor.MiParent() != None:
|
||||
return selor.MiParent().ColBg(selor.selorParent.SelorDeselect())
|
||||
else:
|
||||
return self.ColBgDefault()
|
||||
|
||||
def ColFg(self):
|
||||
return ansi.WHITE | ansi.FBRIGHT
|
||||
def FlagNotice(self):
|
||||
self.fNotice = True
|
||||
|
||||
def ListenForNotice(self, mi):
|
||||
self.rgmiNotice.append(mi)
|
||||
|
||||
def FNoticeFlagged(self):
|
||||
for mi in self.rgmiNotice:
|
||||
if mi.fNotice:
|
||||
return True
|
||||
return False
|
||||
def FSelectable(self):
|
||||
return True
|
||||
class MiInvisible(Mi):
|
||||
def Height(self, w):
|
||||
return 0
|
||||
def Draw(self, *rgarg):
|
||||
pass
|
||||
def FSelectable(self):
|
||||
return False
|
||||
|
||||
miInvisible = MiInvisible()
|
||||
class MiStatic(Mi):
|
||||
def InitPersistent(self, stText):
|
||||
Mi.InitPersistent(self)
|
||||
self.stText = stText
|
||||
def StName(self):
|
||||
return self.stText
|
||||
def FSelectable(self):
|
||||
return False
|
||||
def Height(self, w):
|
||||
return len(RgstWrapped(self.StName(), w, 0))
|
||||
def Draw(self, ascr, x, y, w, selor):
|
||||
for st in RgstWrapped(self.StName(), w, 0):
|
||||
ascr.PutSt("{0:^{1}}".format(st, w), x, y, self.ColFg(), self.ColBg(selor))
|
||||
y = y + 1
|
||||
|
||||
class MiDgText(MiStatic):
|
||||
def InitPersistent(self, dgText):
|
||||
MiStatic.InitPersistent(self, None)
|
||||
self.dgText = dgText
|
||||
def StName(self):
|
||||
return self.dgText()
|
||||
class MiButton(MiStatic):
|
||||
def InitPersistent(self, stName, dgCmd, value = None):
|
||||
MiStatic.InitPersistent(self, stName)
|
||||
self.dgCmd = dgCmd
|
||||
self.value = value
|
||||
|
||||
def StName(self):
|
||||
if self.stText == None and self.value != None:
|
||||
return self.value.StName()
|
||||
return self.stText
|
||||
|
||||
def Exec(self):
|
||||
return self.dgCmd()
|
||||
|
||||
def FSelectable(self):
|
||||
return True
|
||||
def HandleKey(self, key):
|
||||
if ansi.FEnter(key) or key == ' ':
|
||||
return self.Exec()
|
||||
return False
|
||||
|
||||
def Value(self):
|
||||
return self.value
|
||||
|
||||
class MiToggle(MiButton):
|
||||
def InitPersistent(self, stName, fInitial = False):
|
||||
MiButton.InitPersistent(self, stName, None, fInitial)
|
||||
|
||||
def Exec(self):
|
||||
self.value = not self.value
|
||||
return True
|
||||
|
||||
def StName(self):
|
||||
stPre = "[X] " if self.value else "[ ] "
|
||||
return stPre + self.stText
|
||||
|
||||
def StKey(self):
|
||||
return self.stText
|
||||
class MiList(Mi):
|
||||
def InitPersistent(self, rgval, ival = 0):
|
||||
Mi.InitPersistent(self)
|
||||
self.rgval = rgval
|
||||
self.ival = ival
|
||||
|
||||
def Value(self):
|
||||
return self.rgval[self.ival]
|
||||
|
||||
def Inc(self):
|
||||
if self.ival < len(self.rgval) - 1:
|
||||
self.ival = self.ival + 1
|
||||
|
||||
def Dec(self):
|
||||
if self.ival > 0:
|
||||
self.ival = self.ival - 1
|
||||
|
||||
def HandleKey(self, key):
|
||||
if key == ansi.K_LEFT:
|
||||
self.Dec()
|
||||
elif key == ansi.K_RIGHT:
|
||||
self.Inc()
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
def Draw(self, ascr, x, y, w, selor):
|
||||
xText = w / 4
|
||||
xVal = w / 2
|
||||
ascr.PutSt(self.StName() + ":", xText, y, self.ColFg(), self.ColBg(selor))
|
||||
self.DrawValue(ascr, xVal, y, selor.SelorDeselect())
|
||||
class MiTypein(Mi):
|
||||
def InitPersistent(self, dgEnter, stName = "Typein", pctW = 100):
|
||||
Mi.InitPersistent(self)
|
||||
self.stedit = Stedit(dgEnter)
|
||||
self.stName = stName
|
||||
self.pctW = pctW
|
||||
assert pctW > 0 and pctW <= 100
|
||||
|
||||
def StName(self):
|
||||
return self.stName
|
||||
|
||||
def Value(self):
|
||||
return self.stedit.GetValue()
|
||||
|
||||
def SetValue(self, st):
|
||||
self.stedit.SetValue(st)
|
||||
def HandleKey(self, key):
|
||||
return self.stedit.HandleKey(key)
|
||||
|
||||
def ColBgDefault(self):
|
||||
return ansi.BLACK
|
||||
def ColBgSelected(self, fPri):
|
||||
return ansi.WHITE if fPri else ansi.BLUE
|
||||
def ColFg(self):
|
||||
return ansi.WHITE
|
||||
|
||||
def FIgnoreParent(self):
|
||||
return True
|
||||
def Height(self, wT):
|
||||
return len(RgstWrapped(self.GetStToWrap(), self.GetW(wT)))
|
||||
def GetW(self, wT):
|
||||
return int(wT * (self.pctW / 100.0))
|
||||
def GetStToWrap(self):
|
||||
return self.stedit.StForSize()
|
||||
def Draw(self, ascr, xT, y, wT, selor):
|
||||
w = self.GetW(wT)
|
||||
x = xT + ((wT - w) / 2)
|
||||
if selor.KSel() != Selor.NONE:
|
||||
stToWrap = self.GetStToWrap()
|
||||
else:
|
||||
stToWrap = self.stedit.GetValue()
|
||||
for snippet in RgSnippetWrapped(stToWrap, w):
|
||||
ascr.PutSt("{0:{1}}".format(snippet.st, w), x, y, self.ColFg(), self.ColBg(selor.SelorDeselect()))
|
||||
if selor.KSel() != Selor.NONE:
|
||||
self.stedit.DrawCursor(ascr, x, y, self.ColFg(), self.ColBg(selor), snippet)
|
||||
y = y + 1
|
||||
class MiTab(MiStatic):
|
||||
def InitPersistent(self, stText, mi):
|
||||
MiStatic.InitPersistent(self, stText)
|
||||
self.mi = mi
|
||||
self.ListenForNotice(mi)
|
||||
def Value(self):
|
||||
return self.mi
|
||||
def FSelectable(self):
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def MiTabbed(*rgstTab_mi):
|
||||
miTabRow = MiMenuHoriz([MiTab(*stTab_mi) for stTab_mi in rgstTab_mi])
|
||||
return MiMenu([miTabRow, MiTabBody(miTabRow)])
|
||||
class MiTabBody(Mi):
|
||||
def InitPersistent(self, miMenu):
|
||||
Mi.InitPersistent(self)
|
||||
self.miMenu = miMenu
|
||||
def Mi(self):
|
||||
return self.miMenu.Value()
|
||||
def HandleKey(self, key):
|
||||
return self.Mi().HandleKey(key)
|
||||
def Draw(self, ascr, x, y, w, selor):
|
||||
self.Mi().Draw(ascr, x, y, w, selor)
|
||||
def Height(self,w):
|
||||
return self.Mi().Height(w)
|
||||
class MiValue(Mi):
|
||||
def InitPersistent(self, mi):
|
||||
Mi.InitPersistent(self)
|
||||
self.mi = mi
|
||||
def StName(self):
|
||||
return self.mi.StName()
|
||||
def Value(self):
|
||||
return self.mi.Value()
|
||||
def Height(self,w):
|
||||
return self.mi.Height(w)
|
||||
def Draw(self, ascr, x, y, w, selor):
|
||||
self.mi.DrawValue(ascr, x, y, selor.SelorChild(self.mi, False))
|
||||
|
||||
class Selection(TPrs):
|
||||
def InitPersistent(self, rgo, o = None, io = 0):
|
||||
self.rgo = rgo
|
||||
self.o = o
|
||||
self.io = -1 if o == None else io
|
||||
self.Validate()
|
||||
|
||||
def Invalidate(self):
|
||||
self.o = None
|
||||
self.io = -1
|
||||
|
||||
def Validate(self):
|
||||
# aw hell, selection only handles inserts, not deletes :(
|
||||
if self.o == None or self.io < 0:
|
||||
self.Invalidate()
|
||||
elif len(self.rgo) <= self.io or self.rgo[self.io] != self.o:
|
||||
try:
|
||||
self.io = self.rgo.index(self.o)
|
||||
except Exception:
|
||||
self.Invalidate()
|
||||
if self.o == None and not self.FEmpty():
|
||||
self.io = IoInc(self.rgo, self.io, self.FSelectableI)
|
||||
self.o = self.rgo[self.io]
|
||||
|
||||
def GetSelected(self):
|
||||
self.Validate()
|
||||
return self.o
|
||||
|
||||
def SetSelected(self, o):
|
||||
self.o = o
|
||||
self.Validate()
|
||||
def ITopScroll(self, h, dgHeight):
|
||||
# requirements:
|
||||
# selection must be visible
|
||||
# if possible, selection should be centered
|
||||
if self.io < 0:
|
||||
return 0
|
||||
iotop = self.io
|
||||
iobot = self.io
|
||||
hCurr = dgHeight(self.o)
|
||||
yobot = hCurr
|
||||
fGrowUp = False
|
||||
while hCurr < h:
|
||||
fDoneUp = iotop == 0
|
||||
fDoneDown = iobot == len(self.rgo) - 1
|
||||
if (fGrowUp or fDoneDown) and not fDoneUp:
|
||||
ho = dgHeight(self.rgo[iotop - 1])
|
||||
if (yobot + ho >= h): # handle case where thing above selected thing is huge and pushes the selection off the screen
|
||||
break
|
||||
iotop = iotop - 1
|
||||
yobot = yobot + ho
|
||||
elif not fDoneDown:
|
||||
ho = dgHeight(self.rgo[iobot + 1])
|
||||
iobot = iobot + 1
|
||||
else:
|
||||
break
|
||||
hCurr = hCurr + ho
|
||||
fGrowUp = not fGrowUp
|
||||
return iotop
|
||||
|
||||
def Inc(self):
|
||||
return self.ChangeI(IoInc)
|
||||
|
||||
def Dec(self):
|
||||
return self.ChangeI(IoDec)
|
||||
|
||||
def FEmpty(self):
|
||||
for o in self.rgo:
|
||||
if self.FSelectableI(o):
|
||||
return False
|
||||
return True
|
||||
|
||||
def ChangeI(self, fnChange):
|
||||
self.Validate()
|
||||
if self.o != None:
|
||||
ioT = self.io
|
||||
self.io = fnChange(self.rgo, self.io, self.FSelectableI)
|
||||
self.o = self.rgo[self.io]
|
||||
return ioT != self.io
|
||||
|
||||
def FSelectableI(self, o):
|
||||
return o != None and o.FSelectable()
|
||||
|
||||
class MiMenuI(Mi):
|
||||
def InitPersistent(self, rgmi):
|
||||
Mi.InitPersistent(self)
|
||||
self.selMi = Selection(rgmi)
|
||||
self.mpstName_mi = {}
|
||||
for mi in rgmi:
|
||||
if mi != None:
|
||||
self.mpstName_mi[mi.StKey().lower()] = mi
|
||||
def Value(self, stKey = None):
|
||||
if stKey == None:
|
||||
return self.selMi.GetSelected().Value()
|
||||
return self.mpstName_mi[stKey.lower()].Value()
|
||||
def MiByName(self, stKey):
|
||||
return self.mpstName_mi[stKey.lower()]
|
||||
def HeightMi(self, mi, w):
|
||||
if mi == None:
|
||||
return 1
|
||||
return mi.Height(w)
|
||||
def ColBgSelected(self, fPri):
|
||||
return self.ColBgDefault()
|
||||
|
||||
class MiMenu(MiMenuI):
|
||||
def InitPersistent(self, rgmi, hMax = -1):
|
||||
MiMenuI.InitPersistent(self, rgmi)
|
||||
self.hMax = hMax
|
||||
def HandleKey(self, key):
|
||||
mi = self.selMi.GetSelected()
|
||||
if mi == None or not mi.HandleKey(key):
|
||||
if key == ansi.K_DOWN:
|
||||
return self.selMi.Inc()
|
||||
elif key == ansi.K_UP:
|
||||
return self.selMi.Dec()
|
||||
return False
|
||||
return True
|
||||
|
||||
def HMax(self, ascr, y):
|
||||
if self.hMax < 0:
|
||||
return (ascr.H() - y) + 1
|
||||
return self.hMax
|
||||
|
||||
def Height(self, w):
|
||||
return sum([self.HeightMi(mi,w) for mi in self.selMi.rgo])
|
||||
|
||||
def Draw(self, ascr, x, y, w, selor):
|
||||
ascr.Fill(ansi.MkAch(' ', self.ColFg(), self.ColBg(selor)), w, self.Height(w), x, y)
|
||||
miSelected = self.selMi.GetSelected()
|
||||
h = 0
|
||||
hMax = self.HMax(ascr, y)
|
||||
itop = self.selMi.ITopScroll(hMax, lambda mi: self.HeightMi(mi, w))
|
||||
for imi, mi in enumerate(self.selMi.rgo):
|
||||
if imi < itop:
|
||||
continue
|
||||
if mi != None:
|
||||
mi.DrawWithParent(selor, ascr, x, y + h, w, miSelected == mi)
|
||||
h = h + self.HeightMi(mi, w)
|
||||
if h >= hMax:
|
||||
break
|
||||
class MiMenuHoriz(MiMenuI):
|
||||
def InitPersistent(self, rgmi, rgsize = None):
|
||||
MiMenuI.InitPersistent(self, rgmi)
|
||||
if rgsize == None:
|
||||
rgsize = [1 for mi in rgmi]
|
||||
self.rgsize = rgsize
|
||||
self.sizeMax = float(sum(rgsize))
|
||||
|
||||
def Width(self, imi, w):
|
||||
return int((self.rgsize[imi] / self.sizeMax) * w)
|
||||
|
||||
def HandleKey(self, key):
|
||||
mi = self.selMi.GetSelected()
|
||||
if mi == None or not mi.HandleKey(key):
|
||||
if key == ansi.K_RIGHT:
|
||||
return self.selMi.Inc()
|
||||
elif key == ansi.K_LEFT:
|
||||
return self.selMi.Dec()
|
||||
return False
|
||||
return True
|
||||
|
||||
def Height(self, w):
|
||||
return max([self.HeightMi(mi, w) for mi in self.selMi.rgo])
|
||||
def Draw(self, ascr, x, y, w, selor):
|
||||
ascr.Fill(ansi.MkAch(' ', self.ColFg(), self.ColBg(selor)), w, self.Height(w), x, y)
|
||||
miSelected = self.selMi.GetSelected()
|
||||
for imi, mi in enumerate(self.selMi.rgo):
|
||||
wT = self.Width(imi, w)
|
||||
if mi != None:
|
||||
mi.DrawWithParent(selor, ascr, x, y, wT, miSelected == mi)
|
||||
x = x + wT
|
||||
|
||||
def DgProjectMiButton(dgExec):
|
||||
def DgProject(value):
|
||||
return MiButton(None, lambda: dgExec(value), value)
|
||||
return DgProject
|
||||
|
||||
class RgmiProjected(TPrs):
|
||||
def InitPersistent(self, rgvalue, dgProject):
|
||||
self.rgvalue = rgvalue
|
||||
self.dgProject = dgProject
|
||||
|
||||
def InitTransient(self):
|
||||
self.mpvalue_wrmi = weakref.WeakKeyDictionary()
|
||||
|
||||
def __getitem__(self, i):
|
||||
return self.MiFromValue(self.rgvalue[i])
|
||||
|
||||
def MiFromValue(self, value):
|
||||
if value in self.mpvalue_wrmi:
|
||||
mi = self.mpvalue_wrmi[value]()
|
||||
if mi != None:
|
||||
return mi
|
||||
mi = self.dgProject(value)
|
||||
mi._valueProjected = value
|
||||
self.mpvalue_wrmi[value] = weakref.ref(mi) # this probably gc's much more than is necessary ... :/
|
||||
return mi
|
||||
|
||||
def __len__(self):
|
||||
return len(self.rgvalue)
|
||||
|
||||
def index(self, mi):
|
||||
return self.rgvalue.index(mi._valueProjected)
|
||||
|
||||
|
||||
class OvStatic(TokenClient):
|
||||
TOP = 1
|
||||
MIDDLE = 2
|
||||
BOTTOM = 3
|
||||
FILL = 4
|
||||
|
||||
def InitPersistent(self, owner, client, miMenu, kplace, *rgtag):
|
||||
TokenClient.InitPersistent(self, owner, client, "drawable", "menu", *rgtag)
|
||||
self.miMenu = miMenu
|
||||
self.kplace = kplace
|
||||
self.mpst_miSel = {}
|
||||
def SetSelection(self, stSel, mi):
|
||||
self.mpst_miSel[stSel] = mi
|
||||
|
||||
def GetSelection(self, stSel):
|
||||
try:
|
||||
return self.mpst_miSel[stSel]
|
||||
except KeyError:
|
||||
return None
|
||||
def draw(self, ascr, client):
|
||||
self.drawI(ascr, client, False)
|
||||
|
||||
def drawI(self, ascr, client, fSelected):
|
||||
if client == self.client:
|
||||
selor = Selor(self.miMenu, None, self.mpst_miSel.values(), fSelected)
|
||||
if self.kplace & self.FILL:
|
||||
h = ascr.H()
|
||||
y = 1
|
||||
dh = h - self.miMenu.Height(ascr.W())
|
||||
if dh > 0:
|
||||
ascr.Fill(ansi.MkAch(' ', self.miMenu.ColFg(), self.miMenu.ColBg(selor)), ascr.W(), dh, 1, ascr.H() - dh + 1)
|
||||
else:
|
||||
h = self.miMenu.Height(ascr.W())
|
||||
if self.kplace == self.TOP:
|
||||
y = 1
|
||||
elif self.kplace == self.MIDDLE:
|
||||
y = (ascr.H() / 2) - (h / 2)
|
||||
else: # BOTTOM
|
||||
y = ascr.H() - h + 1
|
||||
self.miMenu.Draw(ascr, 1, y, ascr.W(), selor)
|
||||
|
||||
def Value(self, stName = None):
|
||||
return self.miMenu.Value(stName)
|
||||
class OvMenu(OvStatic):
|
||||
def run(self):
|
||||
while True:
|
||||
self.miMenu.HandleKey(self.client.evKey.receive(self))
|
||||
|
||||
def draw(self, ascr, client):
|
||||
self.drawI(ascr, client, True)
|
||||
class OvPopup(OvStatic):
|
||||
def InitPersistent(self, owner, client, miMenu):
|
||||
OvStatic.InitPersistent(self, owner, client, miMenu, self.MIDDLE, "drawable", "menu")
|
||||
self.evShow = Event(self.game)
|
||||
self.evDone = Event(self.game)
|
||||
self.fAwake = False
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
self.evShow.receive(self)
|
||||
self.fAwake = True
|
||||
while self.fAwake:
|
||||
key = self.client.evKey.receive(self)
|
||||
if not self.miMenu.HandleKey(key):
|
||||
if key == ansi.K_TAB or key == ansi.K_DEL or key == ' ' or ansi.FEnter(key):
|
||||
self.fAwake = False
|
||||
self.evDone.fire()
|
||||
|
||||
def draw(self, ascr, client):
|
||||
if self.fAwake:
|
||||
self.drawI(ascr, client, True)
|
||||
class MsgScroller(Token):
|
||||
def InitPersistent(self, owner, colFg=ansi.BLUE, colBg=ansi.BLACK, y=config.H):
|
||||
Token.InitPersistent(self, owner, "drawable", "msgscroller", "overlay")
|
||||
self.colFg = colFg
|
||||
self.colBg = colBg
|
||||
self.rgmsg = []
|
||||
self.msg = None
|
||||
self.evPost = Event(self.game)
|
||||
self.y = y
|
||||
|
||||
def postI(self, msg):
|
||||
self.rgmsg.append(msg)
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
self.postI(self.evPost.receive(self))
|
||||
with self.evPost.oob(self, self.postI):
|
||||
while len(self.rgmsg) > 0:
|
||||
self.msg = self.rgmsg[0]
|
||||
self.rgmsg = self.rgmsg[1:]
|
||||
self.x = config.W
|
||||
while self.x > -len(self.msg):
|
||||
self.x = self.x - 1
|
||||
self.wait(30)
|
||||
self.msg = None
|
||||
|
||||
def draw(self, ascr, client):
|
||||
if self.msg:
|
||||
ascr.PutSt(self.msg, self.x, self.y, self.colFg, self.colBg)
|
16
build_entity.py
Normal file
16
build_entity.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
#@+leo-ver=4-thin
|
||||
#@+node:jpenner.20091016050502.1:@thin build_entity.py
|
||||
import re
|
||||
|
||||
reEnt = re.compile(r"^.*&#(\d+);.*$");
|
||||
mpch_entity = [0]
|
||||
|
||||
with open("cp437_html.txt") as fp:
|
||||
for line in fp.readlines():
|
||||
ent = reEnt.match(line).group(1)
|
||||
mpch_entity.append(int(ent))
|
||||
|
||||
print "mpch_entity = ", mpch_entity
|
||||
#@nonl
|
||||
#@-node:jpenner.20091016050502.1:@thin build_entity.py
|
||||
#@-leo
|
23
config.py
Normal file
23
config.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Port to run the telnet server on.
|
||||
PORT_TELNET = 19999
|
||||
# Port to run the flash policy server on. Set to None to turn off.
|
||||
PORT_FLASHPOLICY = 20001
|
||||
# Hostname to bind servers on. Leave as "" for all.
|
||||
BIND_HOSTNAME = ""
|
||||
# width and height; default 80x25
|
||||
W = 80
|
||||
H = 25
|
||||
# directory to save ANSI pictures to. leave as "." for current directory. no trailing slash required. "" == /
|
||||
DIR_ANSI = "."
|
||||
# authorization. Options are "Noop" (make up a username, no password), "Drupal" (fetches from MySQL Drupal database)
|
||||
AUTH = "Noop"
|
||||
# if Drupal, configure these options:
|
||||
#drupaldb = "database"
|
||||
#drupaldb_user = "user"
|
||||
#drupaldb_password = "password"
|
||||
#drupaldb_host = "localhost"
|
||||
|
||||
# Port to run the command server on. Set to None to turn off. Only set this port for testing: it will allow anyone to take down the server!
|
||||
PORT_CMDSERVER = 20002
|
||||
# Flag whether we should build and use Cython modules to improve performance.
|
||||
USE_CYTHON = True
|
517
engine.py
Normal file
517
engine.py
Normal file
|
@ -0,0 +1,517 @@
|
|||
import stackless
|
||||
import random
|
||||
import logging
|
||||
import pickle
|
||||
import time
|
||||
import ansi
|
||||
import auth
|
||||
import config
|
||||
import telnet
|
||||
import traceback
|
||||
from twisted.internet import reactor
|
||||
from tpers import TPrs, TPLS, Version
|
||||
import tpers
|
||||
|
||||
class Event(TPrs):
|
||||
def InitPersistent(self, game):
|
||||
self.game = game
|
||||
|
||||
def InitTransient(self):
|
||||
self.rgtk = TPLS()
|
||||
self.stkValue = []
|
||||
|
||||
def oob(self, tok, dgoob):
|
||||
return Oob(self, tok, dgoob)
|
||||
|
||||
def receive(self, tok):
|
||||
chNotify = tok.chEv
|
||||
self.rgtk.append(tok)
|
||||
while True:
|
||||
ev, value = chNotify.receive()
|
||||
if ev == self:
|
||||
return value
|
||||
ev.rgtk.append(tok)
|
||||
if ev in tok.mpevDgoob and tok.mpevDgoob[ev](value):
|
||||
raise Event.OobBreakException()
|
||||
|
||||
def fire(self, value = None):
|
||||
self.stkValue.append(value)
|
||||
self.game.queueEv.append(self)
|
||||
self.game.ensureRun()
|
||||
|
||||
def fireI(self):
|
||||
rgtkOld = self.rgtk
|
||||
value = self.stkValue[0]
|
||||
self.stkValue = self.stkValue[1:]
|
||||
self.rgtk = TPLS()
|
||||
for tk in rgtkOld:
|
||||
if tk.fRunning:
|
||||
tk.chEv.send((self,value))
|
||||
stackless.run()
|
||||
|
||||
class Oob(object):
|
||||
def __init__(self, ev, tok, dgoob):
|
||||
self.ev = ev
|
||||
self.tok = tok
|
||||
self.dgoob = dgoob
|
||||
def __enter__(self):
|
||||
self.ev.rgtk.append(self.tok)
|
||||
self.tok.mpevDgoob[self.ev] = self.dgoob
|
||||
def __exit__(self, etype, eval, tb):
|
||||
if etype != TaskletExit:
|
||||
try:
|
||||
self.tok.mpevDgoob.pop(self.ev)
|
||||
self.ev.rgtk.remove(self.tok)
|
||||
if etype == OobBreakException:
|
||||
return True
|
||||
except Exception:
|
||||
print "exception exiting oob:"
|
||||
traceback.print_exc()
|
||||
print "oob:", etype, eval
|
||||
traceback.print_tb(tb)
|
||||
|
||||
class OobBreakException(Exception):
|
||||
pass
|
||||
|
||||
class Runner(TPrs):
|
||||
def InitPersistent(self):
|
||||
self.mpuser_cld = {}
|
||||
print "New Runner created"
|
||||
|
||||
def InitTransient(self):
|
||||
self.rgclient = []
|
||||
|
||||
def GetCld(self, user):
|
||||
cld = self.mpuser_cld.get(user)
|
||||
if cld == None:
|
||||
cld = Cld(user)
|
||||
self.mpuser_cld[user] = cld
|
||||
return cld
|
||||
|
||||
def RunGameI(self, client):
|
||||
client.runner = self
|
||||
self.rgclient.append(client)
|
||||
def OnDisconnect():
|
||||
self.rgclient.remove(client)
|
||||
client.addDgQuit(OnDisconnect)
|
||||
return self.RunGame(client)
|
||||
|
||||
def RunServer(self):
|
||||
for client in self.rgclient:
|
||||
client.quit(True)
|
||||
telnet.RunServer(self.RunGameI)
|
||||
def Run(clsRunner, fn):
|
||||
runner = tpers.Odb.Load(fn) or clsRunner()
|
||||
|
||||
def ExecCmd(stCmd):
|
||||
if stCmd == "save":
|
||||
tpers.Odb.Save(runner, fn)
|
||||
return "Saved to " + fn
|
||||
return "Unrecognized command: '" + stCmd + "'"
|
||||
telnet.RunCmdServer(ExecCmd)
|
||||
|
||||
runner.RunServer()
|
||||
|
||||
class Ownable(TPrs):
|
||||
def InitPersistent(self, owner = None):
|
||||
self.owner = owner
|
||||
self.rgtokOwn = TPLS()
|
||||
if owner != None:
|
||||
owner.rgtokOwn.append(self)
|
||||
def FPersist(self):
|
||||
if self.owner != None and not self.owner.FPersist():
|
||||
return False
|
||||
return TPrs.FPersist(self)
|
||||
def die(self):
|
||||
if self.owner != None:
|
||||
self.owner.rgtokOwn.remove(self)
|
||||
for tok in [x for x in self.rgtokOwn]:
|
||||
tok.die()
|
||||
self.DontPersist()
|
||||
|
||||
@Version(2)
|
||||
class Game(Ownable):
|
||||
def InitPersistent(self):
|
||||
Ownable.InitPersistent(self)
|
||||
self.fQuit = False
|
||||
self.running = False
|
||||
self.mptagTokenset = {}
|
||||
self.rgdgdie = []
|
||||
self.evJoin = Event(self)
|
||||
self.evLeave = Event(self)
|
||||
self.mpuser_cldg = {}
|
||||
self.CreateRgtok(self.GetRgclsTokPers(), True)
|
||||
|
||||
def InitTransient(self):
|
||||
self.MakeTransient("fScheduled", False)
|
||||
self.rgclient = []
|
||||
self.rgproc = [PTimer(), PEvent(), PDraw(*self.GetRgtagDraw())]
|
||||
for proc in self.rgproc:
|
||||
proc.setGame(self)
|
||||
# don't recreate tokens when game has died (shouldn't even be persisting)
|
||||
if not self.FDead():
|
||||
self.CreateRgtok(self.GetRgclsTokTrans(), False)
|
||||
else:
|
||||
print "Dead", self.__class__, "has persisted"
|
||||
|
||||
def FDead(self):
|
||||
try:
|
||||
rc = self.rc
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
def GetCldg(self, user):
|
||||
cldg = self.mpuser_cldg.get(user)
|
||||
if cldg == None:
|
||||
cldg = Cldg()
|
||||
self.mpuser_cldg[user] = cldg
|
||||
return cldg
|
||||
|
||||
def GetRgclsTokPers(self):
|
||||
return []
|
||||
|
||||
def GetRgclsTokTrans(self):
|
||||
return []
|
||||
|
||||
def GetRgtagDraw(self):
|
||||
return ["background", "solid", "overlay"]
|
||||
|
||||
def CreateRgtok(self, rgclsTok, fPersist):
|
||||
for clsTok in rgclsTok:
|
||||
if FIter(clsTok):
|
||||
tok = clsTok[0](self, *clsTok[1:])
|
||||
else:
|
||||
tok = clsTok(self)
|
||||
if not fPersist:
|
||||
tok.DontPersist()
|
||||
|
||||
def tagToken(self, token, tag):
|
||||
if not (tag in self.mptagTokenset):
|
||||
self.mptagTokenset[tag] = set([token])
|
||||
else:
|
||||
self.mptagTokenset[tag].add(token)
|
||||
|
||||
def untagToken(self, token, tag):
|
||||
if tag in self.mptagTokenset:
|
||||
self.mptagTokenset[tag].discard(token)
|
||||
|
||||
def rgtoken(self, tag, rgpriority = []):
|
||||
if not (tag in self.mptagTokenset):
|
||||
return []
|
||||
|
||||
rgtoken = []
|
||||
tokenSet = self.mptagTokenset[tag].copy()
|
||||
for priority in rgpriority:
|
||||
if (priority in self.mptagTokenset):
|
||||
ptokenSet = self.mptagTokenset[priority] & tokenSet
|
||||
for token in ptokenSet:
|
||||
rgtoken.append(token)
|
||||
tokenSet -= ptokenSet
|
||||
for token in tokenSet:
|
||||
rgtoken.append(token)
|
||||
|
||||
return rgtoken
|
||||
|
||||
def quit(self):
|
||||
self.running = False
|
||||
self.fQuit = True
|
||||
|
||||
def finish(self, rc = None):
|
||||
self.running = False
|
||||
self.rc = rc
|
||||
class QuitException(Exception):
|
||||
pass
|
||||
|
||||
class LoadException(Exception):
|
||||
pass
|
||||
|
||||
def die(self):
|
||||
for dgdie in self.rgdgdie:
|
||||
dgdie()
|
||||
Ownable.die(self)
|
||||
def runStep(self):
|
||||
try:
|
||||
if self.running:
|
||||
for proc in self.rgproc:
|
||||
proc.process()
|
||||
if not self.running:
|
||||
self.die()
|
||||
for client in self.rgclient:
|
||||
client.leaveGame(self.rc)
|
||||
for client in self.rgclient:
|
||||
client.postRunStep()
|
||||
finally:
|
||||
self.fScheduled = False
|
||||
return self.running
|
||||
def joinGame(self,client):
|
||||
self.rgclient.append(client)
|
||||
self.evJoin.fire(client)
|
||||
|
||||
def leaveGame(self, client):
|
||||
self.evLeave.fire(client)
|
||||
|
||||
def leaveGameI(self, client):
|
||||
self.rgclient.remove(client)
|
||||
def ensureRun(self):
|
||||
self.running = True
|
||||
if not self.fScheduled:
|
||||
self.fScheduled = True
|
||||
reactor.callLater(0, self.runStep)
|
||||
def UpgradeFrom(self, versionOld):
|
||||
if versionOld < 2:
|
||||
self.mpuser_cldg = {}
|
||||
|
||||
# Client data
|
||||
@Version(2)
|
||||
class Cld(TPrs):
|
||||
def InitPersistent(self, user):
|
||||
self.user = user
|
||||
def UpgradeFrom(self, versionOld):
|
||||
if versionOld < 2:
|
||||
del self.mpgame_cldg
|
||||
|
||||
#per-game client data
|
||||
class Cldg(TPrs):
|
||||
def FPersist(self):
|
||||
if len(self._persistent) == 0:
|
||||
return False
|
||||
return TPrs.FPersist(self)
|
||||
|
||||
class Client(TPrs):
|
||||
def InitTransient(self):
|
||||
self.chRun = stackless.channel()
|
||||
self.gameCurr = None
|
||||
self.chCont = None
|
||||
self.fRunning = False
|
||||
self.dgJoinGame = None
|
||||
self.rgdgQuit = []
|
||||
self.fQuit = False
|
||||
self.cld = None
|
||||
self.runner = None
|
||||
|
||||
def FPersist(self):
|
||||
return False
|
||||
def go(self, fnRun, protocol):
|
||||
self.protocol = protocol
|
||||
self.tskRun = stackless.tasklet(fnRun)
|
||||
self.tskRun(self)
|
||||
if self._runTskRun():
|
||||
self.gameCurr.ensureRun()
|
||||
def joinGame(self, game):
|
||||
assert not self.fRunning, "already running"
|
||||
chCont = stackless.channel()
|
||||
self.chRun.send((game, chCont))
|
||||
return chCont.receive()
|
||||
|
||||
def leaveGame(self, rc = None):
|
||||
self.fRunning = False
|
||||
self.gameCurr.leaveGame(self)
|
||||
self.rc = rc
|
||||
|
||||
def quit(self):
|
||||
self.leaveGame(None)
|
||||
self.fQuit = True
|
||||
def _runTskRun(self):
|
||||
"run self.tskRun after it has been scheduled, and await results"
|
||||
stackless.run()
|
||||
if not self.tskRun.scheduled:
|
||||
return False
|
||||
self.gameCurr, self.chCont = self.chRun.receive()
|
||||
self.gameCurr.joinGame(self)
|
||||
self.fRunning = True
|
||||
if self.dgJoinGame:
|
||||
self.dgJoinGame(self, self.gameCurr)
|
||||
return True
|
||||
|
||||
def postRunStep(self):
|
||||
if not self.fRunning:
|
||||
self.gameCurr.leaveGameI(self)
|
||||
if not self.fQuit:
|
||||
self.chCont.send(self.rc)
|
||||
self.fQuit = not self._runTskRun()
|
||||
if self.fQuit:
|
||||
for dgQuit in self.rgdgQuit:
|
||||
dgQuit()
|
||||
return self.fQuit
|
||||
def beep(self):
|
||||
pass
|
||||
def login(self, user, passwd):
|
||||
authr = getattr(auth, config.AUTH + "Auth")()
|
||||
if (authr.FAuthorized(user, passwd)):
|
||||
self.cld = self.runner.GetCld(user)
|
||||
return True
|
||||
return False
|
||||
def addDgQuit(self, dgquit):
|
||||
self.rgdgQuit.append(dgquit)
|
||||
|
||||
def removeDgQuit(self, dgquit):
|
||||
self.rgdgQuit.remove(dgquit)
|
||||
def Cldg(self, game = None):
|
||||
if game == None:
|
||||
game = self.gameCurr
|
||||
return game.GetCldg(self.cld.user)
|
||||
|
||||
class Processor(TPrs):
|
||||
def setGame(self, game):
|
||||
self.game = game
|
||||
|
||||
def process(self):
|
||||
pass
|
||||
|
||||
class PTimer(Processor):
|
||||
def msNow(self):
|
||||
return int(time.time() * 1000)
|
||||
def setGame(self, game):
|
||||
self.game = game
|
||||
self.fReset = False
|
||||
game.evTick = Event(game)
|
||||
game.ms = 0
|
||||
game.msDelta = 0
|
||||
self.dms = -self.msNow()
|
||||
|
||||
def __setstate__(self, dict):
|
||||
Processor.__setstate__(self, dict)
|
||||
self.fReset = True
|
||||
def process(self):
|
||||
if self.fReset:
|
||||
# keep game.ms constant
|
||||
self.dms = self.game.ms - self.msNow()
|
||||
self.fReset = False
|
||||
msNew = self.msNow() + self.dms
|
||||
self.game.msDelta = msNew - self.game.ms
|
||||
self.game.ms = msNew
|
||||
self.game.evTick.fire(self.game.msDelta)
|
||||
|
||||
class PEvent(Processor):
|
||||
def setGame(self, game):
|
||||
self.game = game
|
||||
game.queueEv = []
|
||||
game.rgdgdie.append(self.die)
|
||||
|
||||
def die(self):
|
||||
for ev in self.game.queueEv:
|
||||
for tk in ev.rgtk:
|
||||
tk.die()
|
||||
ev.stkValue = []
|
||||
self.game.queueEv = []
|
||||
|
||||
def process(self):
|
||||
while self.game.queueEv:
|
||||
self.game.queueEv[0].fireI()
|
||||
self.game.queueEv.pop(0)
|
||||
|
||||
class PDraw(Processor):
|
||||
def InitPersistent(self, *rgprio):
|
||||
self.rgprio = rgprio
|
||||
self.msDrawAgain = -1
|
||||
self.fTimerSet = False
|
||||
|
||||
def process(self):
|
||||
if self.game.ms >= self.msDrawAgain:
|
||||
for client in self.game.rgclient:
|
||||
ascr = ansi.Ascr()
|
||||
for tok in self.game.rgtoken("drawable", self.rgprio):
|
||||
try:
|
||||
tok.draw(ascr, client)
|
||||
except Exception:
|
||||
print "error drawing"
|
||||
traceback.print_exc()
|
||||
|
||||
client.protocol.Draw(ascr)
|
||||
self.msDrawAgain = self.game.ms + 120
|
||||
self.fTimerSet = False
|
||||
elif not self.fTimerSet:
|
||||
reactor.callLater((self.msDrawAgain - self.game.ms) / 1000.0, self.game.ensureRun)
|
||||
self.fTimerSet = True
|
||||
class Taggable(Ownable):
|
||||
def InitPersistent(self, owner, *rgtag):
|
||||
Ownable.InitPersistent(self, owner)
|
||||
game = owner
|
||||
while not isinstance(game, Game):
|
||||
game = game.owner
|
||||
self.game = game
|
||||
self.tags = set()
|
||||
self.tag(*rgtag)
|
||||
|
||||
def tag(self, *rgtag):
|
||||
self.tags |= set(rgtag)
|
||||
for tag in rgtag:
|
||||
self.game.tagToken(self, tag)
|
||||
|
||||
def untag(self, *rgtag):
|
||||
self.tags -= set(rgtag)
|
||||
for tag in rgtag:
|
||||
self.game.untagToken(self, tag)
|
||||
|
||||
def die(self):
|
||||
for tag in self.tags.copy():
|
||||
self.untag(tag)
|
||||
Ownable.die(self)
|
||||
|
||||
class Token(Taggable):
|
||||
def InitPersistent(self, owner, *rgtag):
|
||||
Taggable.InitPersistent(self, owner, *rgtag)
|
||||
self.msGamePreWait = 0
|
||||
self.ms = 0
|
||||
self.fRunning = True
|
||||
self.rgtokOwn = TPLS()
|
||||
|
||||
def InitTransient(self):
|
||||
Taggable.InitTransient(self)
|
||||
self.chEv = stackless.channel()
|
||||
self.tasklet = stackless.tasklet(self.runI)
|
||||
self.mpevDgoob = {}
|
||||
|
||||
self._fWriteToPersistent = True
|
||||
self.tasklet()
|
||||
def __enter__(self):
|
||||
return self
|
||||
def __exit__(self, etype, eval, traceback):
|
||||
self.die()
|
||||
def wait(self, msDelta):
|
||||
# have we waited once already this tick? If not, reset
|
||||
if (self.msGamePreWait != self.game.ms):
|
||||
self.ms = self.game.ms
|
||||
|
||||
msEnd = self.ms + msDelta
|
||||
|
||||
delay = (msEnd - self.game.ms) / 1000.0
|
||||
if delay > 0:
|
||||
reactor.callLater(delay, self.game.ensureRun)
|
||||
|
||||
while (self.game.ms < msEnd):
|
||||
self.game.evTick.receive(self)
|
||||
self.ms = msEnd
|
||||
|
||||
self.msGamePreWait = self.game.ms
|
||||
|
||||
|
||||
def die(self):
|
||||
self.tasklet.kill()
|
||||
self.fRunning = False
|
||||
Taggable.die(self)
|
||||
def run(self):
|
||||
pass
|
||||
|
||||
def runI(self):
|
||||
try:
|
||||
self.run()
|
||||
#except TaskletExit:
|
||||
# raise
|
||||
except Exception:
|
||||
print "token script crashed:"
|
||||
traceback.print_exc()
|
||||
def FIter(l):
|
||||
try:
|
||||
iter(l)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
class TokenClient(Token):
|
||||
def InitPersistent(self, owner, client, *rgtag):
|
||||
Token.InitPersistent(self, owner, *rgtag)
|
||||
self.client = client
|
||||
|
||||
def FPersist(self):
|
||||
return False
|
1
entity.py
Normal file
1
entity.py
Normal file
|
@ -0,0 +1 @@
|
|||
mpch_entity = [0, 9786, 9787, 9829, 9830, 9827, 9824, 8226, 9688, 9675, 9689, 9794, 9792, 9834, 9835, 9788, 9658, 9668, 8597, 8252, 182, 167, 9644, 8616, 8593, 8595, 8594, 8592, 8735, 8596, 9650, 9660, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 8962, 199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197, 201, 230, 198, 244, 246, 242, 251, 249, 255, 214, 220, 162, 163, 165, 8359, 402, 225, 237, 243, 250, 241, 209, 170, 186, 191, 8976, 172, 189, 188, 161, 171, 187, 9617, 9618, 9619, 9474, 9508, 9569, 9570, 9558, 9557, 9571, 9553, 9559, 9565, 9564, 9563, 9488, 9492, 9524, 9516, 9500, 9472, 9532, 9566, 9567, 9562, 9556, 9577, 9574, 9568, 9552, 9580, 9575, 9576, 9572, 9573, 9561, 9560, 9554, 9555, 9579, 9578, 9496, 9484, 9608, 9604, 9612, 9616, 9600, 945, 223, 915, 960, 931, 963, 181, 964, 934, 920, 937, 948, 8734, 966, 949, 8745, 8801, 177, 8805, 8804, 8992, 8993, 247, 8776, 176, 8729, 183, 8730, 8319, 178, 9632, 160]
|
71
haxor.py
Normal file
71
haxor.py
Normal file
|
@ -0,0 +1,71 @@
|
|||
#@+leo-ver=4-thin
|
||||
#@+node:jpenner.20090526212048.3:@thin haxor.py
|
||||
from engine import *
|
||||
from basetoken import *
|
||||
import telnet
|
||||
|
||||
#@<<IntroTerm>>
|
||||
#@+node:jpenner.20090526212048.6:<<IntroTerm>>
|
||||
class IntroTerm(Terminal):
|
||||
#@ @+others
|
||||
#@+node:jpenner.20090526212048.5:run
|
||||
def run(self):
|
||||
self.newLine(3, 300)
|
||||
self.type("Logon Please: ")
|
||||
name = self.getLine()
|
||||
self.newLine(2, 300)
|
||||
self.typeLn("Welcome, " + name)
|
||||
self.type("You have ")
|
||||
self.wait(200)
|
||||
self.typeLn("top security clearance.")
|
||||
self.type("You are looking ")
|
||||
self.wait(200)
|
||||
self.typeLn("good to-day.")
|
||||
while True:
|
||||
self.typeLn("Would you like to download")
|
||||
self.type("all secret files? [Y/N] ")
|
||||
if (self.getPrintableKey().upper() == "Y"):
|
||||
break
|
||||
self.printSt("No")
|
||||
self.newLine()
|
||||
self.typeLn("But thou must!")
|
||||
self.wait(500)
|
||||
self.printSt("Yessir!")
|
||||
self.newLine(2, 50)
|
||||
self.type("Downloading... ")
|
||||
spinner = self.newSpinner()
|
||||
self.wait(3000)
|
||||
spinner.die()
|
||||
blnkScrn = Blinker(self.game, self.setColBg, [ansi.RED, ansi.BLUE])
|
||||
self.newLine(2, 50)
|
||||
self.typeLn("EXPERT HAX0R DETECTED")
|
||||
self.typeLn("CODE RED CODE RED")
|
||||
self.newLine(2, 400)
|
||||
self.wait(500)
|
||||
self.typeLn("OH SHIIIIIIIIIIIIIIIIT!")
|
||||
self.wait(800)
|
||||
blnkScrn.die()
|
||||
self.setColBg(ansi.BLACK)
|
||||
self.newLine(2, 50)
|
||||
self.printSt("NO CARRIER")
|
||||
self.newLine()
|
||||
self.client.quit()
|
||||
#@-node:jpenner.20090526212048.5:run
|
||||
#@-others
|
||||
#@nonl
|
||||
#@-node:jpenner.20090526212048.6:<<IntroTerm>>
|
||||
#@nl
|
||||
|
||||
class Haxor(object):
|
||||
def __init__(self):
|
||||
self.game = GmSimple([AutoJoiner, IntroTerm])
|
||||
def RunGame(self, client):
|
||||
client.joinGame(self.game)
|
||||
def RunServer(self):
|
||||
telnet.RunServer(self.RunGame)
|
||||
|
||||
if __name__ == "__main__":
|
||||
Haxor().RunServer()
|
||||
#@nonl
|
||||
#@-node:jpenner.20090526212048.3:@thin haxor.py
|
||||
#@-leo
|
35
login.py
Normal file
35
login.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
#@+leo-ver=4-thin
|
||||
#@+node:jpenner.20090607135901.3:@thin login.py
|
||||
from basetoken import *
|
||||
import ansi
|
||||
|
||||
class LoginTerm(Terminal):
|
||||
def run(self):
|
||||
self.setColBg(ansi.BLUE)
|
||||
self.newLine(3, 300)
|
||||
self.type("Logon Please: ")
|
||||
user = self.getLine()
|
||||
self.newLine()
|
||||
self.type("Password: ")
|
||||
self.chEcho = "*"
|
||||
passwd = self.getLine()
|
||||
self.chEcho = None
|
||||
self.newLine(2, 300)
|
||||
if self.client.login(user, passwd):
|
||||
self.typeLn("Welcome to MarMOTS, " + user)
|
||||
self.typeLn("I see you have driven here in your Ferrari.")
|
||||
self.typeLn("Logging you in...")
|
||||
self.wait(250)
|
||||
self.game.finish(True)
|
||||
else:
|
||||
self.setColBg(ansi.RED)
|
||||
self.typeLn("I am sorry, " + user + ", but you appear to be insufficiently rhinoceros.")
|
||||
self.typeLn("Please report back after joining the Klik of the Month Klub.")
|
||||
self.newLine(2,300)
|
||||
self.setColBg(ansi.BLACK)
|
||||
self.printSt("NO CARRIER")
|
||||
self.wait(200)
|
||||
self.game.finish(False)
|
||||
#@nonl
|
||||
#@-node:jpenner.20090607135901.3:@thin login.py
|
||||
#@-leo
|
12
marmots_todo.txt
Normal file
12
marmots_todo.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
debugging output:
|
||||
- decorate classes which we expect not to be in the output, warn if we persist them
|
||||
-
|
||||
|
||||
TRef
|
||||
Load
|
||||
Unload (save and close reference)
|
||||
|
||||
-- we do not want to hold on to references
|
||||
-- actually in our case we don't want to save GameWBs at all, we want to persist boards lazily (except for metadata?)
|
||||
Cldg
|
||||
-- well, this sucks :P guid? attach to game?
|
3
runserver.bat
Normal file
3
runserver.bat
Normal file
|
@ -0,0 +1,3 @@
|
|||
setup.py build_ext --inplace -c mingw32
|
||||
whiteboard.py
|
||||
pause
|
33
savecycle.sh
Normal file
33
savecycle.sh
Normal file
|
@ -0,0 +1,33 @@
|
|||
#!/bin/bash
|
||||
|
||||
fnnew="whiteboard.marm.`date "+%F_%H-%M"`"
|
||||
|
||||
cd /home/jeremy/marmots
|
||||
|
||||
save ()
|
||||
{
|
||||
echo save | telnet localhost 20002 &> /dev/null
|
||||
sleep 5 # wait for save to complete
|
||||
}
|
||||
|
||||
backup ()
|
||||
{
|
||||
cp whiteboard.marm $fnnew
|
||||
gzip $fnnew
|
||||
}
|
||||
|
||||
if [ -e whiteboard.marm ]
|
||||
then
|
||||
cp whiteboard.marm whiteboard.marm.old
|
||||
save
|
||||
cmp whiteboard.marm whiteboard.marm.old &> /dev/null
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
backup
|
||||
fi
|
||||
rm whiteboard.marm.old
|
||||
else
|
||||
save
|
||||
backup
|
||||
fi
|
||||
|
711
scripting.py
Normal file
711
scripting.py
Normal file
|
@ -0,0 +1,711 @@
|
|||
from engine import *
|
||||
from basetoken import *
|
||||
from tpers import *
|
||||
from util import *
|
||||
|
||||
# scope -- a block? a scril? (scril lets you specifically avoid vars that are defined after a certain point) + game?
|
||||
# method: rgvar(stype) -- returns a list of variables in scope that match the current stype
|
||||
# var -- a variable
|
||||
# contains: stype, sargInitializer
|
||||
# a var IS A SCRIL
|
||||
# the scmd creates a new vari in the current ectx, and adds the scril to a map of things that refer to it
|
||||
# sproj -- an object that can project a sarg into an pw
|
||||
# stypes should be sprojectors and express a default projection as a class method (why?)
|
||||
# MiSarg -- an editor for sargs
|
||||
# MiSargNum, MiSargDrop
|
||||
# MiScriptLine -- projects a scriptline
|
||||
# sobj -- generic hungarian for any object that is usable in scripts
|
||||
# fail -- a FAILURE OBJECT; if it is used as a sarg when evaluating an scmd, a failure is logged and the scmd returns fail.
|
||||
|
||||
# execution:
|
||||
# ectx -- execution context
|
||||
# contains: mpvar_sobj
|
||||
# block
|
||||
# iscril (selection?)
|
||||
# ectxReturn
|
||||
# methods: call(block)
|
||||
|
||||
class Block(TPrs):
|
||||
def InitPersistent(self, scrilParent):
|
||||
self.rgscril = []
|
||||
self.scrilParent = scrilParent
|
||||
def InsertScrilAfter(self, scrilAfter, scmd = None):
|
||||
scrilNew = Scril(self, scmd)
|
||||
if scrilAfter == None:
|
||||
self.rgscril.insert(0, scrilNew)
|
||||
else:
|
||||
self.rgscril.insert(self.rgscril.index(scrilAfter) + 1, scrilNew)
|
||||
return scrilNew
|
||||
def Project(self, pwBlock, dxIndent = 0):
|
||||
if pwBlock == None:
|
||||
pwBlock = PwBlock(None, self, 0)
|
||||
PwButtonHidden(pwBlock, "[insert new line]", None, self.InsertScrilAfter, dxIndent)
|
||||
for scril in self.rgscril:
|
||||
scril.Project(pwBlock, dxIndent)
|
||||
return pwBlock
|
||||
|
||||
class Typeable(TPrs):
|
||||
def InitTransient(self):
|
||||
self.steditTypein = Stedit()
|
||||
def GetStTypein(self):
|
||||
st = self.steditTypein.GetValue()
|
||||
return None if st == "" else st
|
||||
def SetStTypein(self, stTypein):
|
||||
self.steditTypein.SetValue(stTypein or "")
|
||||
def HandleTypeinKey(self, key):
|
||||
return self.steditTypein.HandleKey(key)
|
||||
|
||||
# Sarg -- pointer to scripting object / argument to a command
|
||||
# this object type appears to exist solely so that MiSarg can edit something without digging through a list
|
||||
class Sarg(Typeable):
|
||||
def InitPersistent(self, stype, scril):
|
||||
self.stype = stype
|
||||
self.sobj = stype.SobjDefault(scril)
|
||||
|
||||
def FExpr(self):
|
||||
"Returns true if the sobj must be evaluated to get a result."
|
||||
return self.sobj.__class__ == Scril
|
||||
|
||||
def Eval(self, ectx):
|
||||
if self.FExpr():
|
||||
return self.sobj.Exec(ectx)
|
||||
else:
|
||||
return self.sobj
|
||||
|
||||
class Fail(TPrs):
|
||||
def InitPersistent(self, stFailure):
|
||||
self.stFailure == stFailure
|
||||
|
||||
# stype -- a description of a sobj (scripting object)
|
||||
# method: FMember(sobj) -- returns true if an object is in the set of things that this stype represents
|
||||
# method: FOverlaps(stype) -- returns true if there is some overlap between the two stypes
|
||||
# -- there is no subtype/supertype relation because stypes are used to help the user,
|
||||
# and I suspect being specific in this manner is too much of a burden to place on them.
|
||||
# methods: rgsarg(scope) -- returns a list of all legal objects that exist in the current scope
|
||||
# this includes functions which return things of this stype, and variables
|
||||
# literals are not included
|
||||
# project(cls, game, sarg) -- returns an MiSarg which displays and edits (default sproj for a sarg?)
|
||||
class Stype(object):
|
||||
"""A definition of a scripting object type. All methods are class methods; stypes are never instantiated."""
|
||||
def __init__(self):
|
||||
raise "do not instantiate stypes"
|
||||
@classmethod
|
||||
def FMember(cls, sobj):
|
||||
return isinstance(sobj, cls.pythontype)
|
||||
@classmethod
|
||||
def FOverlaps(cls, stype):
|
||||
return stype == self
|
||||
@classmethod
|
||||
def Rgsobj(cls, scope):
|
||||
return []
|
||||
@classmethod
|
||||
def Rgsobj_st(cls, scope):
|
||||
return [(sobj, str(sobj)) for sobj in cls.Rgsobj(scope)]
|
||||
@classmethod
|
||||
def OnSelect(cls, sarg, sobj):
|
||||
sarg.sobj = sobj
|
||||
@classmethod
|
||||
def Sproj(cls, sarg, pwBlock, pwScril):
|
||||
ProjectTypein(pwScril, sarg, str(sarg.sobj), cls.Rgsobj_st, cls.OnSelect)
|
||||
return False
|
||||
|
||||
def ProjectTypein(pwParent, typeable, st, dgRgsobj_st, dgOnSelect):
|
||||
def OnSelect(sobj):
|
||||
dgOnSelect(typeable, sobj)
|
||||
typeable.SetStTypein(None)
|
||||
if typeable.GetStTypein() != None:
|
||||
pwParent = PwDropdown(pwParent)
|
||||
PwTypein(pwParent, st, typeable)
|
||||
if typeable.GetStTypein() != None:
|
||||
for sobj, st in dgRgsobj_st(typeable):
|
||||
PwButton(pwParent, st, sobj, OnSelect)
|
||||
|
||||
class StypeBool(Stype):
|
||||
pythontype = bool
|
||||
@classmethod
|
||||
def SobjDefault(cls, scril):
|
||||
return False
|
||||
@classmethod
|
||||
def Rgsobj(cls, scope):
|
||||
return [True, False]
|
||||
|
||||
class StypeBlock(Stype):
|
||||
pythontype = Block
|
||||
@classmethod
|
||||
def SobjDefault(cls, scril):
|
||||
return Block(scril)
|
||||
@classmethod
|
||||
def Sproj(cls, sarg, pwBlock, pwScril):
|
||||
sarg.sobj.Project(pwBlock, pwScril.DxIndent() + 2)
|
||||
return True
|
||||
|
||||
# scmd -- a definition of a scripting command
|
||||
class Scmd(object):
|
||||
"""A definition of a scripting command. All methods are class methods; scmds are never instantiated."""
|
||||
def __init__(self):
|
||||
raise "do not instantiate scmds"
|
||||
|
||||
# used by RegScmd to build a list of all valid scmds for editing
|
||||
rgscmd = []
|
||||
|
||||
@classmethod
|
||||
def Rgscmd_st(cls, scril):
|
||||
return [(scmd, scmd.StName()) for scmd in cls.rgscmd]
|
||||
@classmethod
|
||||
def Desc(cls, *rgsarg):
|
||||
"""
|
||||
Returns a list of desces. A desce can be a constant string, representing nonselectable helper text,
|
||||
an sproj, a list containing an sproj and a reference to a passed-in sarg, which explicitly binds that
|
||||
sproj to that sarg, or a list containing a string, which stands for the selectable text which represents
|
||||
the scril itself.
|
||||
ie, [["Move"], " ", [SprojMovable, rgsarg[1]], " to ", [SprojPosition, rgsarg[0]]]
|
||||
If a bare sproj is given, bind it to the first unbound sarg (after processing all explicitly bound sargs).
|
||||
|
||||
This method must accept invalid sargs; it is the sproj's job to relay the invalidness to the user.
|
||||
"""
|
||||
return cls.desc
|
||||
|
||||
stName = None
|
||||
|
||||
@classmethod
|
||||
def StName(cls):
|
||||
"Returns the name that the user types in to select this scmd."
|
||||
if cls.stName != None:
|
||||
return cls.stName
|
||||
for desce in cls.Desc(Scril(None, cls).rgsarg):
|
||||
if type(desce) == list and type(desce[0]) == str:
|
||||
return desce[0]
|
||||
assert False, "no selectable self in desc"
|
||||
|
||||
@classmethod
|
||||
def Csarg(cls):
|
||||
"Returns the number of arguments that this command takes."
|
||||
return len(cls.rgstypeArg)
|
||||
@classmethod
|
||||
def StypeResult(cls):
|
||||
return cls.stypeResult
|
||||
@classmethod
|
||||
def RgstypeArg(cls):
|
||||
return cls.rgstypeArg
|
||||
|
||||
def RegScmd(stypeResult, *rgstypeArg):
|
||||
def RegI(cls):
|
||||
cls.stypeResult = stypeResult
|
||||
cls.rgstypeArg = rgstypeArg
|
||||
Scmd.rgscmd.append(cls)
|
||||
return cls
|
||||
return RegI
|
||||
|
||||
@RegScmd(None)
|
||||
class ScmdBlank(Scmd):
|
||||
stName = ""
|
||||
desc = [[" "]]
|
||||
@classmethod
|
||||
def Exec(cls, ectx):
|
||||
pass
|
||||
|
||||
@RegScmd(None)
|
||||
class ScmdHelloWorld(Scmd):
|
||||
"Hello, world!"
|
||||
desc = [["Hello World"], "!"]
|
||||
@classmethod
|
||||
def Exec(cls, ectx):
|
||||
print "Hello, world!"
|
||||
|
||||
@RegScmd(None, StypeBool, StypeBlock, StypeBlock)
|
||||
class ScmdIf(Scmd):
|
||||
desc = [["If"], " ", StypeBool.Sproj, ", then:", StypeBlock.Sproj, "or else:", StypeBlock.Sproj]
|
||||
@classmethod
|
||||
def Exec(cls, ectx, sargExpr, sargIfTrue, sargIfFalse):
|
||||
if sargExpr.Eval(ectx):
|
||||
print "true!"
|
||||
|
||||
# needs work
|
||||
#===========================================================================
|
||||
# @RegScmd(None, StypeSt, StypeObj)
|
||||
# class ScmdVar(Scmd):
|
||||
# desc = ["Define a new ", ["variable"], " called \"", StypeSt, "\", set to ", StypeObj, "."]
|
||||
# @classmethod
|
||||
# def Exec(cls, ectx, sargStName, sargInit):
|
||||
# ectx.mpvar_sobj[ectx.ScrilCurr()] = sargInit.Eval()
|
||||
#===========================================================================
|
||||
|
||||
class Scril(Typeable):
|
||||
"A line in a script."
|
||||
def InitPersistent(self, blockParent, scmd = None):
|
||||
self.scmd = scmd or ScmdBlank
|
||||
self.rgsarg = [Sarg(stypeArg, self) for stypeArg in self.scmd.RgstypeArg()]
|
||||
self.blockParent = blockParent
|
||||
|
||||
def SetScmd(self, scmd):
|
||||
if (scmd.Csarg() > self.scmd.Csarg()):
|
||||
self.rgsarg.extend([Sarg(stypeArg, self) for stypeArg in scmd.RgstypeArg()[self.scmd.Csarg():]])
|
||||
elif (scmd.Csarg() < self.scmd.Csarg()):
|
||||
self.rgsarg = self.rgsarg[:scmd.Csarg()]
|
||||
self.scmd = scmd
|
||||
|
||||
def Exec(self, ectx):
|
||||
return self.scmd.Exec(ectx, *self.rgsarg)
|
||||
|
||||
def HandleKey(self, pwKey, pov, psel, key):
|
||||
if ansi.FEnter(key):
|
||||
self.blockParent.InsertScrilAfter(self, ScmdBlank)
|
||||
return True
|
||||
return False
|
||||
def Project(self, pwBlock, dxindent):
|
||||
"adds horizontal pws to a vertical pw"
|
||||
pwScril = None
|
||||
|
||||
desc = self.scmd.Desc(*self.rgsarg)
|
||||
rgsargUnbound = list(self.rgsarg)
|
||||
#filter bound sargs
|
||||
for desce in desc:
|
||||
if isinstance(desce, list) and len(desce) > 1:
|
||||
rgsargUnbound.remove(desce[1])
|
||||
|
||||
fNewScril = True
|
||||
for desce in desc:
|
||||
if fNewScril:
|
||||
pwKey = PwKeyHandler(pwBlock, self.HandleKey)
|
||||
pwScril = PwList(pwKey, self, dxindent)
|
||||
fNewScril = False
|
||||
if isinstance(desce, str):
|
||||
PwStatic(pwScril, desce)
|
||||
elif isinstance(desce, list):
|
||||
if isinstance(desce[0], str):
|
||||
# selection for the scmd / scril
|
||||
ProjectTypein(pwScril, self, desce[0], Scmd.Rgscmd_st, Scril.SetScmd)
|
||||
else:
|
||||
# mapping to sarg
|
||||
fNewScril = self.ProjectSarg(pwBlock, pwScril, desce[0], desce[1])
|
||||
else:
|
||||
# sproj
|
||||
fNewScril = self.ProjectSarg(pwBlock, pwScril, desce, rgsargUnbound.pop(0))
|
||||
|
||||
def ProjectSarg(self, pwBlock, pwScril, sproj, sarg):
|
||||
return sproj(sarg, pwBlock, pwScril)
|
||||
|
||||
# pw - projected widget
|
||||
# Nothing ever depends on the object identity or permanence of a pw!
|
||||
# They are generated on demand, whenever we need to draw or process a
|
||||
# keypress.
|
||||
|
||||
class Pw(object):
|
||||
def __init__(self, pwParent):
|
||||
if pwParent != None:
|
||||
pwParent.AddChild(self)
|
||||
self.pwParent = pwParent
|
||||
def PwParent(self):
|
||||
return self.pwParent
|
||||
def Value(self):
|
||||
return None
|
||||
def FSelectable(self):
|
||||
return False
|
||||
def FContainer(self):
|
||||
return False
|
||||
def RgpwChild(self):
|
||||
return []
|
||||
def HandleKey(self, pov, psel, key):
|
||||
return False
|
||||
def PwFirstSelectable(self):
|
||||
if self.FSelectable():
|
||||
return self
|
||||
for pwChild in self.RgpwChild():
|
||||
pw = pwChild.PwFirstSelectable()
|
||||
if pw != None:
|
||||
return pw
|
||||
return None
|
||||
|
||||
class PwContainer(Pw):
|
||||
def __init__(self, pwParent):
|
||||
Pw.__init__(self, pwParent)
|
||||
self.rgpwContents = []
|
||||
def AddChild(self, pw):
|
||||
self.rgpwContents.append(pw)
|
||||
def RgpwChild(self):
|
||||
return self.rgpwContents
|
||||
def FContainer(self):
|
||||
return True
|
||||
|
||||
class PwStatic(Pw):
|
||||
def __init__(self, pwParent, stText):
|
||||
Pw.__init__(self, pwParent)
|
||||
self.stText = stText
|
||||
def DxDyNew(self, w, dxStart, mpksel):
|
||||
rgsnippet = self.Rgsnippet(w, dxStart, mpksel)
|
||||
if len(rgsnippet) == 1:
|
||||
return (dxStart + len(rgsnippet[0].st), 0)
|
||||
else:
|
||||
return (len(rgsnippet[-1].st), len(rgsnippet) - 1)
|
||||
def StTextDisplay(self, ksel):
|
||||
return self.stText
|
||||
def Rgsnippet(self, w, dxStart, mpksel):
|
||||
ksel = mpksel.Get(self)
|
||||
return list(RgSnippetWrapped(self.StTextDisplay(ksel), w, ksel == Ksel.NAV, dxStart))
|
||||
def ColBg(self, ksel):
|
||||
return ansi.BLACK
|
||||
def ColFg(self):
|
||||
return ansi.WHITE | ansi.FBRIGHT
|
||||
def RgSnippetXY(self, x, y, w, dxStart, mpksel):
|
||||
fFirst = True
|
||||
for snippet in self.Rgsnippet(w, dxStart, mpksel):
|
||||
xT = x + dxStart if fFirst else x
|
||||
yield (snippet, xT, y)
|
||||
y = y + 1
|
||||
fFirst = False
|
||||
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
|
||||
if not fOverlay:
|
||||
ksel = mpksel.Get(self)
|
||||
for (snippet, x, y) in self.RgSnippetXY(x, y, w, dxStart, mpksel):
|
||||
ascr.PutSt(snippet.st, x, y, self.ColFg(), self.ColBg(ksel))
|
||||
|
||||
class PwTypein(PwStatic):
|
||||
def __init__(self, pwParent, stSobj, typeable):
|
||||
if typeable.GetStTypein() == None:
|
||||
stDisplay = stSobj
|
||||
else:
|
||||
stDisplay = None
|
||||
PwStatic.__init__(self, pwParent, stDisplay)
|
||||
self.typeable = typeable
|
||||
def Value(self):
|
||||
return self.typeable
|
||||
def StTextDisplay(self, ksel):
|
||||
if self.stText == None:
|
||||
return self.typeable.steditTypein.StForSize(ksel == Ksel.NAV)
|
||||
return self.stText
|
||||
def FSelectable(self):
|
||||
return True
|
||||
def ColBg(self, ksel):
|
||||
if ksel == Ksel.NAV:
|
||||
return ansi.YELLOW
|
||||
elif ksel == Ksel.OTHERNAV:
|
||||
return ansi.MAGENTA
|
||||
return ansi.BLUE
|
||||
def HandleKey(self, pov, psel, key):
|
||||
return self.typeable.HandleTypeinKey(key)
|
||||
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
|
||||
if not fOverlay:
|
||||
ksel = mpksel.Get(self)
|
||||
fTextSelect = ksel == Ksel.NAV and self.typeable.GetStTypein() != None
|
||||
for (snippet, x, y) in self.RgSnippetXY(x, y, w, dxStart, mpksel):
|
||||
ascr.PutSt(snippet.st, x, y, self.ColFg(), self.ColBg(Ksel.NONE if fTextSelect else ksel))
|
||||
if fTextSelect:
|
||||
self.typeable.steditTypein.DrawCursor(ascr, x, y, self.ColFg(), self.ColBg(ksel), snippet)
|
||||
else:
|
||||
for pwChild in self.RgpwChild():
|
||||
pwChild.Draw(ascr, x, y, dxStart, mpksel, fOverlay)
|
||||
|
||||
class PwButton(PwStatic):
|
||||
def __init__(self, pwParent, stText, value, dgEnter):
|
||||
PwStatic.__init__(self, pwParent, stText)
|
||||
self.value = value
|
||||
self.dgEnter = dgEnter
|
||||
def Value(self):
|
||||
return self.value
|
||||
def FSelectable(self):
|
||||
return True
|
||||
def ColBg(self, ksel):
|
||||
if ksel == Ksel.NAV:
|
||||
return ansi.YELLOW
|
||||
elif ksel == Ksel.OTHERNAV:
|
||||
return ansi.MAGENTA
|
||||
return ansi.BLUE
|
||||
def ColFg(self):
|
||||
return ansi.BLUE | ansi.FBRIGHT
|
||||
def HandleKey(self, pov, psel, key):
|
||||
if key == ansi.K_RETURN:
|
||||
self.dgEnter(self.Value())
|
||||
return True
|
||||
return False
|
||||
|
||||
class PwButtonHidden(PwButton):
|
||||
def __init__(self, pwParent, stText, value, dgEnter, dxIndent):
|
||||
PwButton.__init__(self, pwParent, stText, value, dgEnter)
|
||||
self.dxIndent = dxIndent
|
||||
def DxDyNew(self, w, dxStart, mpksel):
|
||||
if mpksel.Get(self) == Ksel.NAV:
|
||||
return PwButton.DxDyNew(self, w - self.dxIndent, dxStart + self.dxIndent, mpksel)
|
||||
return (0, 0)
|
||||
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
|
||||
if mpksel.Get(self) == Ksel.NAV:
|
||||
PwButton.Draw(self, ascr, x + self.dxIndent, y, w - self.dxIndent, dxStart, mpksel, fOverlay)
|
||||
|
||||
class PwKeyHandler(PwContainer):
|
||||
def __init__(self, pwParent, dgHandleKey):
|
||||
PwContainer.__init__(self, pwParent)
|
||||
self.dgHandleKey = dgHandleKey
|
||||
def DxDyNew(self, w, dxStart, mpksel):
|
||||
return self.RgpwChild()[0].DxDyNew(w, dxStart, mpksel)
|
||||
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
|
||||
self.RgpwChild()[0].Draw(ascr, x, y, w, dxStart, mpksel, fOverlay)
|
||||
def HandleKey(self, pov, psel, key):
|
||||
self.dgHandleKey(self, pov, psel, key)
|
||||
|
||||
class PwBlock(PwContainer):
|
||||
def __init__(self, pwParent, block, dxIndent = 2):
|
||||
PwContainer.__init__(self, pwParent)
|
||||
self.block = block
|
||||
self.dxIndent = dxIndent
|
||||
def Value(self):
|
||||
return self.block
|
||||
def DxIndent(self):
|
||||
return self.dxIndent
|
||||
def DxDyNew(self, w, dxStart, mpksel):
|
||||
return (0, 1 + sum([pw.DxDyNew(w - self.DxIndent(), 0, mpksel)[1] + 1 for pw in self.rgpwContents]))
|
||||
def RgpwChildToDraw(self):
|
||||
return self.RgpwChild()
|
||||
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
|
||||
for pw in self.RgpwChildToDraw():
|
||||
pw.Draw(ascr, x + self.DxIndent(), y, w - self.DxIndent(), 0, mpksel, fOverlay)
|
||||
(dxNew, dyNew) = pw.DxDyNew(w - self.DxIndent(), 0, mpksel)
|
||||
if dxNew > 0 or dyNew > 0:
|
||||
y = y + dyNew + 1
|
||||
def HandleKey(self, pov, psel, key):
|
||||
if key == ansi.K_UP:
|
||||
return psel.Dec(self)
|
||||
elif key == ansi.K_DOWN:
|
||||
return psel.Inc(self)
|
||||
elif key == ansi.K_DEL:
|
||||
pass
|
||||
return False
|
||||
|
||||
class PwDropdown(PwBlock):
|
||||
def __init__(self, pwParent):
|
||||
PwBlock.__init__(self, pwParent, None, 0)
|
||||
def WidthMax(self, mpksel):
|
||||
w = -1
|
||||
for pw in self.RgpwChild():
|
||||
wPw = pw.DxDyNew(1000000, 0, mpksel)[0]
|
||||
if wPw > w:
|
||||
w = wPw
|
||||
return w
|
||||
def RgpwChildToDraw(self):
|
||||
return PwBlock.RgpwChild(self)[1:]
|
||||
def PwChildFirst(self):
|
||||
return PwBlock.RgpwChild(self)[0]
|
||||
def DxDyNew(self, w, dxStart, mpksel):
|
||||
return self.PwChildFirst().DxDyNew(w, dxStart, mpksel)
|
||||
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
|
||||
if not fOverlay:
|
||||
self.PwChildFirst().Draw(ascr, x, y, w, dxStart, mpksel, False)
|
||||
else:
|
||||
wMax = self.WidthMax(mpksel)
|
||||
w = w - dxStart
|
||||
x = x + dxStart
|
||||
if x + wMax > w and wMax < w:
|
||||
x = w - self.WidthMax(mpksel)
|
||||
PwBlock.Draw(self, ascr, x, y + 1, w, 0, mpksel, False)
|
||||
|
||||
class PwList(PwContainer):
|
||||
def __init__(self, pwParent, scril, dxIndent):
|
||||
PwContainer.__init__(self, pwParent)
|
||||
self.scril = scril
|
||||
self.dxIndent = dxIndent
|
||||
def Value(self):
|
||||
return self.scril
|
||||
def DxDyNew(self, w, dxStart, mpksel):
|
||||
dx = dxStart
|
||||
dy = 0
|
||||
for pw in self.rgpwContents:
|
||||
(dx, dyPw) = pw.DxDyNew(w, dx, mpksel)
|
||||
dy = dy + dyPw
|
||||
return (dx, dy)
|
||||
def DxIndent(self):
|
||||
return self.dxIndent
|
||||
def Draw(self, ascr, x, y, w, dx, mpksel, fOverlay):
|
||||
for pw in self.rgpwContents:
|
||||
pw.Draw(ascr, x + self.DxIndent(), y, w - self.DxIndent(), dx, mpksel, fOverlay)
|
||||
(dx, dy) = pw.DxDyNew(w, dx, mpksel)
|
||||
y = y + dy
|
||||
def HandleKey(self, pov, psel, key):
|
||||
if key == ansi.K_LEFT:
|
||||
return psel.Dec(self)
|
||||
elif key == ansi.K_RIGHT:
|
||||
return psel.Inc(self)
|
||||
return False
|
||||
|
||||
class Ksel(object):
|
||||
FOTHER = 0x2000
|
||||
NONE = FOTHER | 0x1000 # OR together all ksel flags and add 0x1000; largest possible ksel
|
||||
NAV = 0
|
||||
OTHERNAV = NAV | FOTHER
|
||||
|
||||
@staticmethod
|
||||
def KselBest(ksel1, ksel2):
|
||||
if ksel1 < ksel2:
|
||||
return ksel1
|
||||
return ksel2
|
||||
|
||||
class Psel(TPrs):
|
||||
def InitPersistent(self, pw, ksel):
|
||||
assert len(pw.RgpwChild()) == 0 #leaf
|
||||
self.rgo_ipw = self.Rgo_ipwFromPw(pw)
|
||||
self.ksel = ksel
|
||||
|
||||
def Rgo_ipwFromPw(self, pw):
|
||||
rgo_ipw = []
|
||||
if pw != None:
|
||||
while pw.PwParent() != None:
|
||||
rgo_ipw.insert(0, (pw.Value(), pw.PwParent().RgpwChild().index(pw)))
|
||||
pw = pw.PwParent()
|
||||
return rgo_ipw
|
||||
|
||||
def Validate(self, pwRoot):
|
||||
assert pwRoot.PwParent() == None #root
|
||||
io_ipw = 0
|
||||
pwSelected = pwRoot
|
||||
while len(pwSelected.RgpwChild()) > 0 and io_ipw < len(self.rgo_ipw):
|
||||
(o, ipw) = self.rgo_ipw[io_ipw]
|
||||
ipwNew = 0
|
||||
for pwChild in pwSelected.RgpwChild():
|
||||
if o != None and pwChild.Value() == o:
|
||||
break
|
||||
ipwNew = ipwNew + 1
|
||||
if ipwNew == len(pwSelected.RgpwChild()):
|
||||
ipwLim = ipw + 1 if ipw < len(pwSelected.RgpwChild()) else len(pwSelected.RgpwChild())
|
||||
ipwNew = IoDec(pwSelected.RgpwChild(), ipwLim, self.FPwValid)
|
||||
if ipwNew < 0:
|
||||
break
|
||||
pwSelected = pwSelected.RgpwChild()[ipwNew]
|
||||
io_ipw = io_ipw + 1
|
||||
|
||||
# we've made our best guess as to what the closest selectable thing is -- now make sure we point at SOMEthing selectable.
|
||||
if not pwSelected.FSelectable():
|
||||
pwT = pwSelected
|
||||
while pwT != None:
|
||||
pwSelected = pwT.PwFirstSelectable()
|
||||
if pwSelected != None:
|
||||
break
|
||||
pwT = pwT.PwParent()
|
||||
|
||||
self.rgo_ipw = self.Rgo_ipwFromPw(pwSelected)
|
||||
|
||||
def FPwValid(self, pw):
|
||||
if pw.FSelectable():
|
||||
return True
|
||||
for pwChild in pw.RgpwChild():
|
||||
if self.FPwValid(pwChild):
|
||||
return True
|
||||
return False
|
||||
|
||||
def Value(self, pwRoot):
|
||||
self.Validate(pwRoot)
|
||||
if len(self.rgo_ipw) > 0:
|
||||
return self.rgo_ipw[-1][0]
|
||||
return None
|
||||
|
||||
def PwSelected(self, pwRoot, clevel = None):
|
||||
self.Validate(pwRoot)
|
||||
return self.PwSelectedI(pwRoot, self.rgo_ipw[:clevel])
|
||||
|
||||
def PwSelectedI(self, pw, rgo_ipw):
|
||||
for (_, ipw) in rgo_ipw:
|
||||
pw = pw.RgpwChild()[ipw]
|
||||
return pw
|
||||
# contract: pwContainer is actually selected
|
||||
def Inc(self, pwContainer):
|
||||
return self.ChangeI(pwContainer, IoInc)
|
||||
def Dec(self, pwContainer):
|
||||
return self.ChangeI(pwContainer, IoDec)
|
||||
|
||||
def ChangeI(self, pwContainer, fnChange):
|
||||
clevelChild = 1
|
||||
pwRoot = pwContainer
|
||||
while pwRoot.PwParent() != None:
|
||||
clevelChild = clevelChild + 1
|
||||
pwRoot = pwRoot.PwParent()
|
||||
self.Validate(pwRoot)
|
||||
assert self.PwSelected(pwRoot, clevelChild).PwParent() == pwContainer
|
||||
|
||||
ipw = self.rgo_ipw[clevelChild - 1][1]
|
||||
rgpw = pwContainer.RgpwChild()
|
||||
ipwNew = fnChange(rgpw, ipw, self.FPwValid)
|
||||
self.rgo_ipw[clevelChild - 1] = (rgpw[ipwNew].Value(), ipwNew)
|
||||
self.Validate(pwRoot)
|
||||
return ipwNew != ipw
|
||||
|
||||
# projector overlay -- handles navigation, drawing the projection, etc
|
||||
class Pov(TokenClient):
|
||||
def InitPersistent(self, owner, client, block):
|
||||
TokenClient.InitPersistent(self, owner, client, "drawable", "overlay")
|
||||
self.block = block
|
||||
self.pselstate = self.game.rgtoken("pselstate")[0]
|
||||
|
||||
def PwProjected(self):
|
||||
return self.block.Project(None)
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
key = self.client.evKey.receive(self)
|
||||
psel = self.pselstate.PselByClient(self.client)
|
||||
pwSel = psel.PwSelected(self.PwProjected())
|
||||
while pwSel != None:
|
||||
if pwSel.HandleKey(self, psel, key):
|
||||
break
|
||||
pwSel = pwSel.PwParent()
|
||||
|
||||
def draw(self, ascr, client):
|
||||
if client == self.client:
|
||||
pw = self.PwProjected()
|
||||
mpksel = self.pselstate.GetMpksel(pw, client)
|
||||
pw.Draw(ascr, 1, 1, ascr.W(), 0, mpksel, False)
|
||||
pw.Draw(ascr, 1, 1, ascr.W(), 0, mpksel, True)
|
||||
|
||||
class PselState(Token):
|
||||
def InitPersistent(self, owner, block):
|
||||
Token.InitPersistent(self, owner, "pselstate")
|
||||
self.block = block
|
||||
def InitTransient(self):
|
||||
Token.InitTransient(self)
|
||||
self.mpclient_psel = {}
|
||||
def OnLeave(self, client):
|
||||
del self.mpclient_psel[client]
|
||||
def OnJoin(self, client):
|
||||
print "client joined,", client
|
||||
self.mpclient_psel[client] = Psel(self.block.Project(None).PwFirstSelectable(), Ksel.NAV)
|
||||
class Mpksel(object):
|
||||
def __init__(self, pwRoot, client, mpclient_psel):
|
||||
self.mppw_ksel = {}
|
||||
for clientT, psel in mpclient_psel.items():
|
||||
kselNew = Ksel.NAV
|
||||
if clientT != client:
|
||||
kselNew = kselNew | Ksel.FOTHER
|
||||
pw = psel.PwSelected(pwRoot)
|
||||
self.mppw_ksel[pw] = Ksel.KselBest(kselNew, self.Get(pw))
|
||||
|
||||
def Get(self, pw):
|
||||
return self.mppw_ksel.get(pw, Ksel.NONE)
|
||||
|
||||
def GetMpksel(self, pwRoot, client):
|
||||
return self.Mpksel(pwRoot, client, self.mpclient_psel)
|
||||
def PselByClient(self, client):
|
||||
return self.mpclient_psel[client]
|
||||
def run(self):
|
||||
print "pselstate running"
|
||||
with self.game.evLeave.oob(self, self.OnLeave):
|
||||
while True:
|
||||
self.OnJoin(self.game.evJoin.receive(self))
|
||||
|
||||
class GameScriptTest(Game):
|
||||
def InitPersistent(self):
|
||||
Game.InitPersistent(self)
|
||||
self.block = Block(None)
|
||||
self.block.InsertScrilAfter(None, ScmdHelloWorld)
|
||||
self.block.InsertScrilAfter(None, ScmdBlank)
|
||||
self.block.InsertScrilAfter(None, ScmdHelloWorld)
|
||||
self.block.InsertScrilAfter(None, ScmdIf)
|
||||
self.block.InsertScrilAfter(None, ScmdHelloWorld)
|
||||
|
||||
def GetRgclsTokTrans(self):
|
||||
return [[PselState, self.block], [AutoJoiner, [Pov, self.block]]]
|
||||
|
||||
class RunnerScriptTest(Runner):
|
||||
def InitPersistent(self):
|
||||
self.game = GameScriptTest()
|
||||
Runner.InitPersistent(self)
|
||||
|
||||
def RunGame(self, client):
|
||||
client.joinGame(self.game)
|
||||
|
||||
if __name__ == "__main__":
|
||||
Run(RunnerScriptTest, "script_test.marm")
|
12
setup.py
Normal file
12
setup.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
#@+leo-ver=4-thin
|
||||
#@+node:jpenner.20091212133112.13:@thin setup.py
|
||||
from distutils.core import setup
|
||||
from distutils.extension import Extension
|
||||
from Cython.Distutils import build_ext
|
||||
|
||||
setup(
|
||||
cmdclass = {'build_ext': build_ext},
|
||||
ext_modules = [Extension("ansi_cython", ["ansi_cython.pyx"])]
|
||||
)
|
||||
#@-node:jpenner.20091212133112.13:@thin setup.py
|
||||
#@-leo
|
233
telnet.py
Normal file
233
telnet.py
Normal file
|
@ -0,0 +1,233 @@
|
|||
#@+leo-ver=4-thin
|
||||
#@+node:jpenner.20090510085557.10:@thin telnet.py
|
||||
#@@language python
|
||||
from twisted.protocols import basic
|
||||
from twisted.conch import telnet
|
||||
from twisted.internet.protocol import Factory,ServerFactory
|
||||
from twisted.internet import protocol, reactor
|
||||
from zope.interface import implements
|
||||
from twisted.python import log
|
||||
import ansi
|
||||
import engine
|
||||
import sys
|
||||
import config
|
||||
|
||||
#@<<Server>>
|
||||
#@+node:jpenner.20090513213413.1:<<Server>>
|
||||
class AnsiTelnet(protocol.Protocol):
|
||||
implements(telnet.ITelnetProtocol)
|
||||
|
||||
rgoptRemote = [telnet.SGA, telnet.ECHO] #putty sez: 31 (NAWS), 32 (TERMINAL-SPEED), 24 (TERMINAL-TYPE), 39 (NEW-ENVIRON), 36 (ENVIRON), 3(SGA)
|
||||
# We might support NAWS at some point -- internally we will always deal in 80x25, but it might be helpful to have
|
||||
# window resizing work, and provide feedback if the window is too small.
|
||||
# I don't know what we'd do in response to TERMINAL-SPEED, since we're just going to blast out data as fast as possible anyway.
|
||||
# NEW-ENVIRON might be useful for sending usernames or cookies automatically from flashterm.
|
||||
# ENVIRON is an older version of NEW-ENVIRON.
|
||||
# TERMINAL-TYPE is client-to-server only, and the server only speaks ANSI. Again, maybe useful as a feedback mechanism.
|
||||
|
||||
rgoptLocal = [telnet.SGA] #putty sez: 1 (ECHO), 3 (SGA)
|
||||
|
||||
def __init__(self, client):
|
||||
print "created"
|
||||
self.ast = None
|
||||
self.client = client
|
||||
self.evKey = None
|
||||
self.evArrow = None
|
||||
self.Refresh()
|
||||
|
||||
def connectionMade(self):
|
||||
print "connection made"
|
||||
rgdefr = []
|
||||
def AddCb(defr):
|
||||
"""
|
||||
rgdefr.append(defr)
|
||||
def cbWaitForHello(result):
|
||||
print "cb: ", result, len(rgdefr)
|
||||
rgdefr.remove(defr)
|
||||
if len(rgdefr) == 0:
|
||||
self.Hello()
|
||||
defr.addCallback(cbWaitForHello)
|
||||
defr.addErrback(cbWaitForHello)
|
||||
"""
|
||||
pass
|
||||
|
||||
for opt in self.rgoptRemote:
|
||||
AddCb(self.transport.will(opt))
|
||||
for opt in self.rgoptLocal:
|
||||
AddCb(self.transport.do(opt))
|
||||
print "end: ", len(rgdefr)
|
||||
self.Hello()
|
||||
|
||||
#@ <<Options>>
|
||||
#@+node:jpenner.20090514181656.118:<<Options>>
|
||||
def enableLocal(self, option):
|
||||
print "enableLocal", ord(option)
|
||||
return option in self.rgoptLocal
|
||||
def enableRemote(self, option):
|
||||
print "enableRemote", ord(option)
|
||||
return option in self.rgoptRemote
|
||||
|
||||
def disableLocal(self, option):
|
||||
print "disableLocal", option
|
||||
pass
|
||||
def disableRemote(self, option):
|
||||
print "disableRemote", option
|
||||
pass
|
||||
#@nonl
|
||||
#@-node:jpenner.20090514181656.118:<<Options>>
|
||||
#@nl
|
||||
|
||||
def dataReceived(self, data):
|
||||
if self.ast != None:
|
||||
data = self.ast + data
|
||||
ich = 0
|
||||
ichSplit = 0
|
||||
fAnsi = False
|
||||
fEsc = False
|
||||
for ch in data:
|
||||
if fAnsi:
|
||||
if not (ch == ";" or ch.isdigit()):
|
||||
fAnsi = False
|
||||
if ch.isalpha():
|
||||
stRgarg = data[ichSplit + 2:ich]
|
||||
if len(stRgarg) == 0:
|
||||
rgarg = []
|
||||
else:
|
||||
rgarg = [int(stArg) for stArg in stRgarg.split(";")]
|
||||
self.RcvAnsi(ch, rgarg)
|
||||
ichSplit = ich + 1
|
||||
elif ch == ansi.esc[0]:
|
||||
fEsc = True
|
||||
elif fEsc:
|
||||
fEsc = False
|
||||
if ch == ansi.esc[1]:
|
||||
fAnsi = True
|
||||
if ichSplit < ich - 1:
|
||||
self.RcvText(data[ichSplit:ich - 1])
|
||||
ichSplit = ich - 1
|
||||
ich = ich + 1
|
||||
if fEsc or fAnsi:
|
||||
self.ast = data[ichSplit:ich]
|
||||
else:
|
||||
self.ast = None
|
||||
if ichSplit < ich:
|
||||
self.RcvText(data[ichSplit:ich])
|
||||
|
||||
#@ @+others
|
||||
#@+node:jpenner.20090526105844.6:Hello
|
||||
def Hello(self):
|
||||
print "negotiated!"
|
||||
self.transport.write(ansi.esc + "2J") #cls
|
||||
self.transport.write(ansi.esc + "=25l") #hide the cursor
|
||||
self.client.dgJoinGame = self.CreateEvents
|
||||
self.client.addDgQuit(self.transport.loseConnection)
|
||||
self.client.go(self.factory.fnRun, self)
|
||||
#@nonl
|
||||
#@-node:jpenner.20090526105844.6:Hello
|
||||
#@+node:jpenner.20090526212048.1:Keys
|
||||
def RcvText(self, text):
|
||||
if self.client.evKey:
|
||||
for ch in text:
|
||||
self.client.evKey.fire(ch)
|
||||
|
||||
mpcode_key = {"A": ansi.K_UP, "B": ansi.K_DOWN, "C": ansi.K_RIGHT, "D": ansi.K_LEFT,
|
||||
"K": ansi.K_END, "H": ansi.K_HOME, "V": ansi.K_PGUP, "U": ansi.K_PGDN }
|
||||
|
||||
def RcvAnsi(self, code, rgarg):
|
||||
if self.client.evKey:
|
||||
if code in self.mpcode_key:
|
||||
self.client.evKey.fire(self.mpcode_key[code])
|
||||
else:
|
||||
print "unrecognized code", code, rgarg
|
||||
|
||||
def CreateEvents(self, client, game):
|
||||
client.evKey = engine.Event(game)
|
||||
#@nonl
|
||||
#@-node:jpenner.20090526212048.1:Keys
|
||||
#@+node:jpenner.20090527144214.1:Draw
|
||||
def Draw(self, ascr):
|
||||
self.transport.write(self.ascr.AstDiff(ascr))
|
||||
self.transport.write(ansi.esc + "H") #cursor stays in top-left corner? ascr should contain a cursor pos?
|
||||
self.ascr = ascr
|
||||
|
||||
def Refresh(self):
|
||||
self.ascr = ansi.Ascr(config.W, config.H, ansi.achInvd)
|
||||
#@nonl
|
||||
#@-node:jpenner.20090527144214.1:Draw
|
||||
#@+node:jpenner.20090529173104.4:connectionLost
|
||||
def connectionLost(self, reason):
|
||||
print "lost connection"
|
||||
self.client.removeDgQuit(self.transport.loseConnection)
|
||||
self.client.quit()
|
||||
#@nonl
|
||||
#@-node:jpenner.20090529173104.4:connectionLost
|
||||
#@-others
|
||||
#@nonl
|
||||
#@-node:jpenner.20090513213413.1:<<Server>>
|
||||
#@nl
|
||||
#@<<factory>>
|
||||
#@+node:jpenner.20090515161650.1:<<factory>>
|
||||
class AnsiFactory(ServerFactory):
|
||||
def __init__(self, fnRun):
|
||||
self.fnRun = fnRun
|
||||
def buildProtocol(self, addr):
|
||||
p = telnet.TelnetTransport(AnsiTelnet, engine.Client())
|
||||
p.factory = self
|
||||
print "built protocol for ", addr
|
||||
return p
|
||||
#@-node:jpenner.20090515161650.1:<<factory>>
|
||||
#@nl
|
||||
|
||||
#@<<Flash Policy>>
|
||||
#@+node:jpenner.20090518103251.118:<<Flash Policy>>
|
||||
class FlashPolicy(basic.LineReceiver):
|
||||
delimiter = '\0'
|
||||
|
||||
def lineReceived(self,line):
|
||||
if line == "<policy-file-request/>":
|
||||
self.sendLine("<?xml version=\"1.0\"?><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"" + str(config.PORT_TELNET) + "\" /></cross-domain-policy>")
|
||||
#@-node:jpenner.20090518103251.118:<<Flash Policy>>
|
||||
#@nl
|
||||
#@<<Command server>>
|
||||
#@+node:jpenner.20090914034457.2:<<Command server>>
|
||||
class CmdProtocol(basic.LineReceiver):
|
||||
def connectionMade(self):
|
||||
if self.transport.getHost().host != "127.0.0.1":
|
||||
self.transport.write("Sorry, you must connect from localhost")
|
||||
self.transport.loseConnection()
|
||||
|
||||
def lineReceived(self, line):
|
||||
self.transport.write(self.factory.fnCmd(line) + self.delimiter)
|
||||
|
||||
class CmdFactory(ServerFactory):
|
||||
def __init__(self, fnCmd):
|
||||
self.fnCmd = fnCmd
|
||||
def buildProtocol(self, addr):
|
||||
p = CmdProtocol()
|
||||
p.factory = self
|
||||
print "built cmd protocol for ", addr
|
||||
return p
|
||||
#@-node:jpenner.20090914034457.2:<<Command server>>
|
||||
#@nl
|
||||
|
||||
#@<<runner>>
|
||||
#@+node:jpenner.20090513213413.2:<<runner>>
|
||||
def RunServer(fnRun):
|
||||
log.startLogging(sys.stdout)
|
||||
|
||||
factoryPolicy = Factory()
|
||||
factoryPolicy.protocol = FlashPolicy
|
||||
|
||||
reactor.listenTCP(config.PORT_TELNET, AnsiFactory(fnRun), 50, config.BIND_HOSTNAME)
|
||||
if config.PORT_FLASHPOLICY:
|
||||
reactor.listenTCP(config.PORT_FLASHPOLICY, factoryPolicy, 50, config.BIND_HOSTNAME)
|
||||
reactor.run()
|
||||
|
||||
def RunCmdServer(fnCmd):
|
||||
if config.PORT_CMDSERVER:
|
||||
reactor.listenTCP(config.PORT_CMDSERVER, CmdFactory(fnCmd), 50, "localhost")
|
||||
#@nonl
|
||||
#@-node:jpenner.20090513213413.2:<<runner>>
|
||||
#@nl
|
||||
#@-node:jpenner.20090510085557.10:@thin telnet.py
|
||||
#@-leo
|
8
testsig.py
Normal file
8
testsig.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
import signal
|
||||
|
||||
def handler(signum, frame):
|
||||
print "signal:", signum, frame
|
||||
|
||||
signal.signal(signal.SIGINT, handler)
|
||||
|
||||
input()
|
268
tpers.py
Normal file
268
tpers.py
Normal file
|
@ -0,0 +1,268 @@
|
|||
import cPickle
|
||||
import pdb
|
||||
import traceback
|
||||
|
||||
def Decorator(dg):
|
||||
def DecoratorNew(*rgarg, **mparg):
|
||||
def CallDecorator(o):
|
||||
return dg(o, *rgarg, **mparg) or o
|
||||
return CallDecorator
|
||||
return DecoratorNew
|
||||
|
||||
@Decorator
|
||||
def Version(cls, vr):
|
||||
cls._version = vr
|
||||
|
||||
def RenameFrom(stName, namespace):
|
||||
def SetOldName(cls):
|
||||
namespace[stName] = cls
|
||||
return cls
|
||||
return SetOldName
|
||||
|
||||
class TransientSetter(object):
|
||||
def __init__(self, obj):
|
||||
self.obj = obj
|
||||
try:
|
||||
self._fWriteOld = obj._fWriteToPersistent
|
||||
except Exception:
|
||||
self._fWriteOld = True
|
||||
def __enter__(self):
|
||||
self.obj._fWriteToPersistent = False
|
||||
return self.obj
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.obj._fWriteToPersistent = self._fWriteOld
|
||||
|
||||
@Version(1)
|
||||
class TPrs(object):
|
||||
def __init__(self, *rgarg, **mparg):
|
||||
self._persistent = TPM()
|
||||
self._fWriteToPersistent = True
|
||||
self._versionCurr = self._version
|
||||
self._fPersistent = True
|
||||
self.InitPersistent(*rgarg, **mparg)
|
||||
with self.SetTransiently():
|
||||
self.InitTransient()
|
||||
|
||||
def InitPersistent(self, *rgarg, **mparg):
|
||||
pass
|
||||
|
||||
def InitTransient(self):
|
||||
pass
|
||||
|
||||
def SetTransiently(self):
|
||||
return TransientSetter(self)
|
||||
|
||||
def MakeTransient(self, key, value):
|
||||
try:
|
||||
del self._persistent[key]
|
||||
except Exception:
|
||||
pass
|
||||
with self.SetTransiently():
|
||||
setattr(self, key, value)
|
||||
|
||||
def FPersist(self):
|
||||
return self._fPersistent
|
||||
|
||||
def DontPersist(self):
|
||||
self._fPersistent = False
|
||||
|
||||
def UpgradeFrom(self, versionOld):
|
||||
pass
|
||||
|
||||
def __getattr__(self, key):
|
||||
stPersistent = "no persistent yet"
|
||||
if key != "_persistent":
|
||||
try:
|
||||
return self._persistent[key]
|
||||
except Exception:
|
||||
stPersistent = str(self._persistent)
|
||||
raise AttributeError("Attribute '" + key + "' not found in object with type '" + type(self).__name__ + "':" + stPersistent + " __dict__:" + str(self.__dict__))
|
||||
|
||||
__obj_setattr = object.__setattr__
|
||||
__obj_delattr = object.__delattr__
|
||||
def __setattr__(self, key, value):
|
||||
try:
|
||||
if self._fWriteToPersistent or key in self._persistent:
|
||||
self._persistent[key] = value
|
||||
try:
|
||||
self.__obj_delattr(key)
|
||||
except AttributeError:
|
||||
pass
|
||||
return
|
||||
except Exception: pass
|
||||
self.__obj_setattr(key, value)
|
||||
|
||||
def __delattr__(self, key):
|
||||
try:
|
||||
del self._persistent[key]
|
||||
return
|
||||
except Exception: pass
|
||||
self.__obj_delattr(key)
|
||||
|
||||
def __reduce__(self):
|
||||
if self.FPersist():
|
||||
return (NewObjWithClass, (type(self),), self._persistent)
|
||||
else:
|
||||
return (NewObjWithClass, (None,))
|
||||
|
||||
def __setstate__(self, state):
|
||||
self._persistent = state
|
||||
self._fWriteToPersistent = True
|
||||
if self._versionCurr != self._version:
|
||||
Odb.rgtprsToUpgrade.append(self)
|
||||
with self.SetTransiently():
|
||||
self.InitTransient()
|
||||
def _Upgrade(self):
|
||||
self.UpgradeFrom(self._versionCurr)
|
||||
self._versionCurr = self._version
|
||||
|
||||
class Odb(object):
|
||||
@staticmethod
|
||||
def Save(tprs, fn):
|
||||
with open(fn, "w") as fl:
|
||||
cPickle.dump(tprs, fl)
|
||||
|
||||
@classmethod
|
||||
def Load(cls, fn):
|
||||
cls.rgtprsToUpgrade = []
|
||||
try:
|
||||
with open(fn, "r") as fl:
|
||||
tprs = cPickle.load(fl)
|
||||
except Exception as e:
|
||||
print "error unpickling:", e
|
||||
traceback.print_exc()
|
||||
return None
|
||||
if len(cls.rgtprsToUpgrade) > 0:
|
||||
for tprsToUpgrade in cls.rgtprsToUpgrade:
|
||||
tprsToUpgrade._Upgrade()
|
||||
fnUpgraded = fn + ".upgraded"
|
||||
Odb.Save(tprs, fnUpgraded)
|
||||
tprs = Odb.Load(fnUpgraded)
|
||||
cls.rgtprsToUpgrade = None
|
||||
return tprs
|
||||
|
||||
clsList = list
|
||||
clsDict = dict
|
||||
clsSet = set
|
||||
clsTuple = tuple
|
||||
|
||||
def MkTransparent(value):
|
||||
if type(value) == list:
|
||||
return TPL(value)
|
||||
elif type(value) == dict:
|
||||
return TPM(value)
|
||||
elif type(value) == set:
|
||||
return TPS(value)
|
||||
elif type(value) == tuple:
|
||||
return TPT(value)
|
||||
else:
|
||||
return value
|
||||
|
||||
def RgTransparent(rg):
|
||||
if rg == None: return []
|
||||
return [MkTransparent(x) for x in rg]
|
||||
|
||||
def MpTransparent(mp):
|
||||
if isinstance(mp, TPM): return mp
|
||||
mpNew = {}
|
||||
if mp != None:
|
||||
for k,v in mp.iteritems():
|
||||
mpNew[k] = MkTransparent(v)
|
||||
return mpNew
|
||||
|
||||
def FPersist(obj):
|
||||
return (not isinstance(obj, TPrs)) or obj.FPersist()
|
||||
|
||||
def MkPersistable(obj):
|
||||
if FPersist(obj):
|
||||
return obj
|
||||
return None
|
||||
|
||||
def NewObjWithClass(cls):
|
||||
if cls == None:
|
||||
return None
|
||||
return cls.__new__(cls)
|
||||
|
||||
class TPL(clsList):
|
||||
__pl_setitem = clsList.__setitem__
|
||||
__pl_setslice = clsList.__setslice__
|
||||
__pl_iadd = clsList.__iadd__
|
||||
__pl_append = clsList.append
|
||||
__pl_insert = clsList.insert
|
||||
__pl_extend = clsList.extend
|
||||
|
||||
def __init__(self, rg = None):
|
||||
clsList.__init__(self, RgTransparent(rg))
|
||||
|
||||
def __setitem__(self, i, item):
|
||||
return self.__pl_setitem(i, MkTransparent(item))
|
||||
|
||||
def __setslice__(self, i, j, other):
|
||||
return self.__pl_setslice(i, j, RgTransparent(other))
|
||||
|
||||
def __iadd__(self, other):
|
||||
return self.__pl_iadd(RgTransparent(other))
|
||||
|
||||
def append(self, item):
|
||||
return self.__pl_append(MkTransparent(item))
|
||||
|
||||
def insert(self, i, item):
|
||||
return self.__pl_insert(i, MkTransparent(item))
|
||||
|
||||
def extend(self, other):
|
||||
return self.__pl_extend(RgTransparent(other))
|
||||
|
||||
def __reduce__(self):
|
||||
return (MkTransparent, ([MkPersistable(x) for x in self],))
|
||||
|
||||
# Strip weak references rather than replacing them with None
|
||||
class TPLS(TPL):
|
||||
def __reduce__(self):
|
||||
return (MkTransparent, ([x for x in self if FPersist(x)],))
|
||||
|
||||
class TPM(clsDict):
|
||||
__pm_setitem = clsDict.__setitem__
|
||||
__pm_update = clsDict.update
|
||||
|
||||
def __init__(self, *rgarg, **kwarg):
|
||||
clsDict.__init__(self, MpTransparent(dict(*rgarg, **kwarg)))
|
||||
|
||||
def __setitem__(self, k, v):
|
||||
return self.__pm_setitem(k, MkTransparent(v))
|
||||
|
||||
def update(self, other, **kwargs):
|
||||
return self.__pm_update(MpTransparent(other), **MpTransparent(kwargs))
|
||||
|
||||
def __reduce__(self):
|
||||
mp = {}
|
||||
for k, v in self.iteritems():
|
||||
if FPersist(k):
|
||||
mp[k] = MkPersistable(v)
|
||||
return (MkTransparent, (mp,))
|
||||
|
||||
class TPS(clsSet):
|
||||
__ps_update = clsSet.update
|
||||
__ps_ior = clsSet.__ior__
|
||||
__ps_add = clsSet.add
|
||||
|
||||
def __init__(self, rg = None):
|
||||
clsSet.__init__(self, RgTransparent(rg))
|
||||
|
||||
def update(self, *rgother):
|
||||
return self.__ps_update(*RgTransparent(rgother))
|
||||
|
||||
def __ior__(self, other):
|
||||
return self.__ps_ior(MkTransparent(other))
|
||||
|
||||
def add(self, elem):
|
||||
return self.__ps_add(MkTransparent(elem))
|
||||
|
||||
def __reduce__(self):
|
||||
return (MkTransparent, (set([x for x in self if FPersist(x)]),))
|
||||
|
||||
class TPT(clsTuple):
|
||||
def __new__(cls, tup = None):
|
||||
return clsTuple.__new__(cls, RgTransparent(tup))
|
||||
|
||||
def __reduce__(self):
|
||||
return (MkTransparent, (tuple([MkPersistable(x) for x in self]),))
|
103
tpers_old.py
Normal file
103
tpers_old.py
Normal file
|
@ -0,0 +1,103 @@
|
|||
#@+leo-ver=4-thin
|
||||
#@+node:jpenner.20090714203921.6:@thin tpers_old.py
|
||||
import ZODB
|
||||
import persistent
|
||||
|
||||
#@+others
|
||||
#@+node:jpenner.20090714203921.7:def MkTransparent
|
||||
def MkTransparent(value):
|
||||
if type(value) == list:
|
||||
return TPL(value)
|
||||
elif type(value) == dict:
|
||||
return TPM(value)
|
||||
elif type(value) == set:
|
||||
return TPS(value)
|
||||
elif type(value) == tuple:
|
||||
return TPT(value)
|
||||
else:
|
||||
return value
|
||||
#@-node:jpenner.20090714203921.7:def MkTransparent
|
||||
#@+node:jpenner.20090714203921.10:def RgTransparent
|
||||
def RgTransparent(rg):
|
||||
if rg == None: return []
|
||||
return [MkTransparent(x) for x in rg]
|
||||
#@-node:jpenner.20090714203921.10:def RgTransparent
|
||||
#@+node:jpenner.20090714203921.11:def MpTransparent
|
||||
def MpTransparent(mp):
|
||||
if isinstance(mp, TPM): return mp
|
||||
mpNew = {}
|
||||
if mp != None:
|
||||
for k,v in mp.iteritems():
|
||||
mpNew[k] = MkTransparent(v)
|
||||
return mpNew
|
||||
#@-node:jpenner.20090714203921.11:def MpTransparent
|
||||
#@+node:jpenner.20090714203921.8:class TPrs
|
||||
class TPrs(persistent.Persistent):
|
||||
__prs_setattr = persistent.Persistent.__setattr__
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
self.__prs_setattr(name, MkTransparent(value))
|
||||
#@-node:jpenner.20090714203921.8:class TPrs
|
||||
#@+node:jpenner.20090714203921.9:class TPL
|
||||
class TPL(clsList):
|
||||
__pl_setitem = clsList.__setitem__
|
||||
__pl_setslice = clsList.__setslice__
|
||||
__pl_iadd = clsList.__iadd__
|
||||
__pl_append = clsList.append
|
||||
__pl_insert = clsList.insert
|
||||
__pl_extend = clsList.extend
|
||||
|
||||
def __init__(self, rg = None):
|
||||
clsList.__init__(self, RgTransparent(rg))
|
||||
|
||||
def __setitem__(self, i, item):
|
||||
return self.__pl_setitem(i, MkTransparent(item))
|
||||
|
||||
def __setslice__(self, i, j, other):
|
||||
return self.__pl_setslice(i, j, RgTransparent(other))
|
||||
|
||||
def __iadd__(self, other):
|
||||
return self.__pl_iadd(RgTransparent(other))
|
||||
|
||||
def append(self, item):
|
||||
return self.__pl_append(MkTransparent(item))
|
||||
|
||||
def insert(self, i, item):
|
||||
return self.__pl_insert(i, MkTransparent(item))
|
||||
|
||||
def extend(self, other):
|
||||
return self.__pl_extend(RgTransparent(other))
|
||||
|
||||
def __reduce__(self):
|
||||
return (MkTransparent, ([MkPersistable(x) for x in self],))
|
||||
|
||||
# Strip weak references rather than replacing them with None
|
||||
class TPLS(TPL):
|
||||
def __reduce__(self):
|
||||
return (MkTransparent, ([x for x in self if FPersist(x)],))
|
||||
#@-node:jpenner.20090714203921.9:class TPL
|
||||
#@+node:jpenner.20090714203921.12:class TPM
|
||||
class TPM(clsDict):
|
||||
__pm_setitem = clsDict.__setitem__
|
||||
__pm_update = clsDict.update
|
||||
|
||||
def __init__(self, *rgarg, **kwarg):
|
||||
clsDict.__init__(self, MpTransparent(dict(*rgarg, **kwarg)))
|
||||
|
||||
def __setitem__(self, k, v):
|
||||
return self.__pm_setitem(k, MkTransparent(v))
|
||||
|
||||
def update(self, other, **kwargs):
|
||||
return self.__pm_update(MpTransparent(other), **MpTransparent(kwargs))
|
||||
|
||||
def __reduce__(self):
|
||||
mp = {}
|
||||
for k, v in self.iteritems():
|
||||
if FPersist(k):
|
||||
mp[k] = MkPersistable(v)
|
||||
return (MkTransparent, (mp,))
|
||||
|
||||
#@-node:jpenner.20090714203921.12:class TPM
|
||||
#@-others
|
||||
#@-node:jpenner.20090714203921.6:@thin tpers_old.py
|
||||
#@-leo
|
127
util.py
Normal file
127
util.py
Normal file
|
@ -0,0 +1,127 @@
|
|||
from tpers import TPrs
|
||||
import ansi
|
||||
# probably reinventing the wheel :/
|
||||
class Rgseq(TPrs):
|
||||
def InitPersistent(self, *rgseq):
|
||||
self.rgseq = rgseq
|
||||
def __len__(self):
|
||||
return sum([len(seq) for seq in self.rgseq])
|
||||
|
||||
def __getitem__(self, i):
|
||||
c = 0
|
||||
for seq in self.rgseq:
|
||||
cSeq = len(seq)
|
||||
if i < c + cSeq:
|
||||
return seq[i - c]
|
||||
c = c + cSeq
|
||||
raise IndexError
|
||||
|
||||
def index(self, o):
|
||||
c = 0
|
||||
for seq in self.rgseq:
|
||||
try:
|
||||
iSeq = seq.index(o)
|
||||
return iSeq + c
|
||||
except ValueError:
|
||||
c = c + len(seq)
|
||||
raise ValueError
|
||||
|
||||
class Snippet(object):
|
||||
def __init__(self, st, ichStart, ichLim):
|
||||
self.st = st
|
||||
self.ichStart = ichStart
|
||||
self.ichLim = ichLim
|
||||
|
||||
def RgstWrapped(st, w, fForEditing = False, dxStart = 0):
|
||||
return [snippet.st for snippet in RgSnippetWrapped(st, w, fForEditing, dxStart)]
|
||||
|
||||
def RgSnippetWrapped(st, w, fForEditing = False, xStart = 0):
|
||||
ichWrap = -1
|
||||
ichStart = 0
|
||||
for ich, ch in enumerate(st):
|
||||
if not fForEditing and ch == ' ':
|
||||
ichWrap = ich
|
||||
if ich == ichStart + w - xStart:
|
||||
ichStartNew = ichWrap + 1
|
||||
if ichWrap < 0:
|
||||
ichWrap = ich
|
||||
ichStartNew = ich
|
||||
elif fForEditing: # don't swallow spaces
|
||||
ichWrap = ichStartNew
|
||||
yield Snippet(st[ichStart:ichWrap], ichStart, ichStartNew)
|
||||
ichStart = ichStartNew
|
||||
ichWrap = -1
|
||||
xStart = 0
|
||||
if fForEditing and ch == ' ':
|
||||
ichWrap = ich
|
||||
|
||||
if ichStart < len(st) or ichStart == 0:
|
||||
yield Snippet(st[ichStart:], ichStart, len(st))
|
||||
|
||||
# selection helpers
|
||||
def IoInc(rgo, io, fnSelectable, fRebound = True):
|
||||
io = io + 1
|
||||
while io < len(rgo) and not fnSelectable(rgo[io]):
|
||||
io = io + 1
|
||||
if io >= len(rgo) or not fnSelectable(rgo[io]):
|
||||
if fRebound:
|
||||
return IoDec(rgo, io, fnSelectable, False)
|
||||
return -1
|
||||
return io
|
||||
|
||||
def IoDec(rgo, io, fnSelectable, fRebound = True):
|
||||
io = io - 1
|
||||
while io > 0 and not fnSelectable(rgo[io]):
|
||||
io = io - 1
|
||||
if io < 0 or not fnSelectable(rgo[io]):
|
||||
if fRebound:
|
||||
return IoInc(rgo, io, fnSelectable, False)
|
||||
return -1
|
||||
return io
|
||||
|
||||
class Stedit(TPrs):
|
||||
def InitPersistent(self, dgEnter = None, stInitial = ""):
|
||||
self.dgEnter = dgEnter
|
||||
self.SetValue(stInitial)
|
||||
def SetValue(self, st):
|
||||
self.st = st
|
||||
self.ich = len(st)
|
||||
def GetValue(self):
|
||||
return self.st
|
||||
def StForSize(self, fSel = True):
|
||||
if fSel and self.ich == len(self.st):
|
||||
return self.st + "_"
|
||||
return self.st
|
||||
|
||||
def HandleKey(self, key):
|
||||
if key == ansi.K_LEFT and self.ich > 0:
|
||||
self.ich = self.ich - 1
|
||||
elif key == ansi.K_RIGHT and self.ich < len(self.st):
|
||||
self.ich = self.ich + 1
|
||||
elif key == ansi.K_BACKSPACE and self.ich > 0:
|
||||
self.st = self.st[:self.ich - 1] + self.st[self.ich:]
|
||||
self.ich = self.ich - 1
|
||||
elif key == ansi.K_DEL and self.ich < len(self.st):
|
||||
self.st = self.st[:self.ich] + self.st[self.ich + 1:]
|
||||
elif key == ansi.K_HOME:
|
||||
self.ich = 0
|
||||
elif key == ansi.K_END:
|
||||
self.ich = len(self.st)
|
||||
elif ansi.FKeyPrintable(key):
|
||||
self.st = self.st[:self.ich] + key + self.st[self.ich:]
|
||||
self.ich = self.ich + 1
|
||||
elif ansi.FEnter(key) and self.dgEnter != None:
|
||||
if not self.dgEnter(self.st):
|
||||
self.st = ""
|
||||
self.ich = 0
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
def DrawCursor(self, ascr, x, y, colFg, colBg, snippet):
|
||||
if self.ich >= snippet.ichStart and (snippet.ichLim < 0 or self.ich < snippet.ichLim):
|
||||
if self.ich == len(self.st):
|
||||
ch = ' '
|
||||
else:
|
||||
ch = self.st[self.ich]
|
||||
ascr.PutAch(ansi.MkAch(ch, colFg, colBg), x + self.ich - snippet.ichStart, y)
|
678
whiteboard.py
Normal file
678
whiteboard.py
Normal file
|
@ -0,0 +1,678 @@
|
|||
#@+leo-ver=4-thin
|
||||
#@+node:jpenner.20090528201601.6:@thin whiteboard.py
|
||||
from engine import *
|
||||
from basetoken import *
|
||||
from tpers import *
|
||||
from datetime import *
|
||||
from util import *
|
||||
import telnet
|
||||
import time
|
||||
import login
|
||||
import weakref
|
||||
|
||||
#@<<Whiteboard>>
|
||||
#@+node:jpenner.20090528201601.9:<<Whiteboard>>
|
||||
class Layer(TPrs):
|
||||
def InitPersistent(self, ascr, stName):
|
||||
self.ascr = ascr
|
||||
self.stName = stName
|
||||
|
||||
def StName(self):
|
||||
return self.stName
|
||||
|
||||
def SetName(self, st):
|
||||
self.stName = st
|
||||
|
||||
def Draw(self, ascr):
|
||||
ascr.PutAscr(self.ascr)
|
||||
def FSelectable(self):
|
||||
return True
|
||||
|
||||
@Version(3)
|
||||
class Board(Ownable):
|
||||
def InitPersistent(self, owner, stName, user, rglayer=None, dtLastModified=None):
|
||||
Ownable.InitPersistent(self, owner)
|
||||
if rglayer == None:
|
||||
rglayer = [Layer(ansi.Ascr(self.W(), self.H()), "Layer 1")]
|
||||
self.rglayer = rglayer
|
||||
self.stName = stName
|
||||
self.user = user
|
||||
self.chat = Chat()
|
||||
if dtLastModified == None:
|
||||
self.SetTimestamp()
|
||||
else:
|
||||
self.dtLastModified = dtLastModified
|
||||
|
||||
def StName(self):
|
||||
return self.owner.StNameBoard(self)
|
||||
def StLastModified(self):
|
||||
return self.dtLastModified.strftime("%b %d, %Y at %I:%M%p")
|
||||
|
||||
def LayerByName(self, stName):
|
||||
for layer in self.rglayer:
|
||||
if layer.StName().lower() == stName.lower():
|
||||
return layer
|
||||
return None
|
||||
|
||||
def NewLayer(self, stName):
|
||||
if len(self.rglayer) < 8:
|
||||
layerNew = Layer(ansi.Ascr(self.W(), self.H()), stName)
|
||||
self.rglayer.append(layerNew)
|
||||
return layerNew
|
||||
|
||||
def MoveLayer(self, layer, fUp):
|
||||
ilayer = self.rglayer.index(layer)
|
||||
if fUp and ilayer > 0:
|
||||
ilayer = ilayer - 1
|
||||
elif not fUp and ilayer < len(self.rglayer) - 1:
|
||||
ilayer = ilayer + 1
|
||||
self.rglayer.remove(layer)
|
||||
self.rglayer.insert(ilayer, layer)
|
||||
|
||||
def W(self): return config.W
|
||||
def H(self): return config.H
|
||||
|
||||
def Touch(self):
|
||||
self.SetTimestamp()
|
||||
self.owner.BoardTouched(self)
|
||||
|
||||
def SetTimestamp(self):
|
||||
self.dtLastModified = datetime.now()
|
||||
|
||||
def draw(self, ascr):
|
||||
for layer in reversed(self.rglayer):
|
||||
layer.Draw(ascr)
|
||||
#@ @+others
|
||||
#@+node:jpenner.20090602154503.5:Save
|
||||
def Save(self):
|
||||
fn = config.DIR_ANSI + "/" + "_".join([str(x) for x in time.localtime()])
|
||||
ascr = ansi.Ascr(self.W(), self.H())
|
||||
self.draw(ascr)
|
||||
with open(fn + ".html", "w") as fl:
|
||||
fl.write("<html><body bgcolor='#000000'><center>")
|
||||
fl.write(ascr.Hst())
|
||||
fl.write("</center></body></html>")
|
||||
with open(fn + ".ans", "w") as fl:
|
||||
fl.write(ascr.Ast())
|
||||
#@nonl
|
||||
#@-node:jpenner.20090602154503.5:Save
|
||||
#@-others
|
||||
def UpgradeFrom(self, versionOld):
|
||||
if versionOld < 2:
|
||||
gameWB = [gameWB for gameWB in self.owner.rggameWB if gameWB.rgtoken("whiteboard")[0].board == self][0]
|
||||
self.stName = gameWB.stName
|
||||
self.user = gameWB.user
|
||||
if versionOld < 3:
|
||||
self.chat = Chat()
|
||||
|
||||
@Version(5)
|
||||
class Whiteboard(Token):
|
||||
def InitPersistent(self, game, board):
|
||||
Token.InitPersistent(self, game, "whiteboard")
|
||||
self.board = board
|
||||
|
||||
def UpgradeFrom(self, versionOld):
|
||||
if versionOld < 3:
|
||||
dt = None
|
||||
else:
|
||||
dt = self.dtLastModified
|
||||
del self.dtLastModified
|
||||
if versionOld < 4:
|
||||
rglayer = [Layer(self.ascr, "Layer 1")]
|
||||
del self.ascr
|
||||
self.untag("drawable")
|
||||
self.untag("solid")
|
||||
else:
|
||||
rglayer = self.rglayer
|
||||
del self.rglayer
|
||||
if versionOld < 5:
|
||||
self.board = Board(self.game.gameLobby, self.game.stName, self.game.user, rglayer, dt)
|
||||
#@-node:jpenner.20090528201601.9:<<Whiteboard>>
|
||||
#@nl
|
||||
#@<<Chat>>
|
||||
#@+node:jpenner.20090918200439.1:<<Chat>>
|
||||
class Chl(object):
|
||||
def __init__(self, client, st):
|
||||
self.user = client.cld.user
|
||||
self.st = st.rstrip()
|
||||
|
||||
class ChlMsg(Chl):
|
||||
def StUser(self):
|
||||
return "<" + self.user + ">"
|
||||
def Col(self):
|
||||
return ansi.WHITE
|
||||
|
||||
class ChlAct(Chl):
|
||||
def StUser(self):
|
||||
return "* " + self.user
|
||||
def Col(self):
|
||||
return ansi.MAGENTA
|
||||
|
||||
class ChlSys(Chl):
|
||||
def StUser(self):
|
||||
return self.user
|
||||
def Col(self):
|
||||
return ansi.BLUE
|
||||
|
||||
class Chat(TPrs):
|
||||
def InitTransient(self):
|
||||
TPrs.InitTransient(self)
|
||||
self.cchl = 100
|
||||
self.DetachFromGame()
|
||||
|
||||
def InitPersistent(self):
|
||||
TPrs.InitPersistent(self)
|
||||
self.rgchl = []
|
||||
|
||||
def AttachToGame(self, game):
|
||||
self.game = game
|
||||
self.evChat = Event(game)
|
||||
|
||||
def DetachFromGame(self):
|
||||
self.game = None
|
||||
self.evChat = None
|
||||
|
||||
def Add(self, chl):
|
||||
if len(chl.st) > 0:
|
||||
self.rgchl.insert(0, chl)
|
||||
if len(self.rgchl) > self.cchl:
|
||||
self.rgchl = self.rgchl[:self.cchl]
|
||||
self.evChat.fire(chl)
|
||||
|
||||
def CChl(self):
|
||||
return len(self.rgchl)
|
||||
def CUsers(self):
|
||||
return len(self.game.rgclient)
|
||||
def DrawMsg(self, ascr, x, y, w, h, colBg=ansi.BLACK, ichl=0):
|
||||
yDraw = y + h - 1
|
||||
for chl in self.rgchl[ichl:]:
|
||||
stUser = chl.StUser()
|
||||
colFg = chl.Col()
|
||||
wMsg = w - len(stUser) - 1
|
||||
rgstMsg = RgstWrapped(chl.st, wMsg)
|
||||
|
||||
rgstMsg.reverse()
|
||||
for istMsg, stMsg in enumerate(rgstMsg):
|
||||
if istMsg == len(rgstMsg) - 1:
|
||||
st = "{0} {1:{2}}".format(stUser, stMsg, wMsg)
|
||||
else:
|
||||
st = "{0:{1}} {2:{3}}".format("", len(stUser), stMsg, wMsg)
|
||||
ascr.PutSt(st, x, yDraw, colFg, colBg)
|
||||
yDraw = yDraw - 1
|
||||
if yDraw == y - 1:
|
||||
return
|
||||
while yDraw >= y:
|
||||
ascr.PutSt("{0:{1}}".format("", w), x, yDraw, ansi.WHITE, colBg)
|
||||
yDraw = yDraw - 1
|
||||
|
||||
def DrawUsers(self, ascr, x, y, w, h, colBg=ansi.BLACK, iuser=0):
|
||||
yDraw = y
|
||||
for client in sorted(self.game.rgclient, lambda c1, c2: cmp(c1.Cldg().iclient, c2.Cldg().iclient))[iuser:]:
|
||||
ascr.PutSt("{0:{1}}".format(str(client.Cldg().iclient) + ") " + client.cld.user, w), x, yDraw, ansi.WHITE, colBg)
|
||||
yDraw = yDraw + 1
|
||||
if yDraw == y + h:
|
||||
break
|
||||
while yDraw < y + h:
|
||||
ascr.PutSt("{0:{1}}".format("", w), x, yDraw, ansi.WHITE, colBg)
|
||||
yDraw = yDraw + 1
|
||||
#@-node:jpenner.20090918200439.1:<<Chat>>
|
||||
#@nl
|
||||
#@<<Cursor>>
|
||||
#@+node:jpenner.20090528201601.10:<<Cursor>>
|
||||
class Cursor(TokenClient):
|
||||
def InitPersistent(self, game, client):
|
||||
TokenClient.InitPersistent(self, game, client, "drawable", "cursor")
|
||||
self.fBlink = False
|
||||
self.cDontBlink = 0
|
||||
self.whiteboard = self.game.rgtoken("whiteboard")[0].board
|
||||
self.pos = ansi.Pos(self.whiteboard.W(), self.whiteboard.H())
|
||||
miFg = MiColour("Foreground", ansi.rgcolorFg, ansi.WHITE)
|
||||
miBg = MiColour("Background", ansi.rgcolorBg, ansi.BLACK)
|
||||
miChars = MiChars([[49, 50, 51, 52, 53, 54, 55, 56, 57, 48], #digits
|
||||
[176, 177, 178, 219, 223, 220, 221, 222, 254, 249], #blocks
|
||||
[218, 191, 192, 217, 196, 179, 195, 180, 193, 194], #single lines
|
||||
[201, 187, 200, 188, 205, 186, 204, 185, 202, 203], #double lines
|
||||
[213, 184, 212, 190, 205, 179, 198, 181, 207, 209], #sing vert, doub horiz
|
||||
[214, 183, 211, 189, 196, 186, 199, 182, 208, 210], #doub vert, sing horiz
|
||||
[197, 206, 216, 215, 173, 168, 169, 170, 174, 175], #crosses
|
||||
#[ 1, 2, 3, 4, 5, 6, 14, 15, 19, 20], #smiles
|
||||
[224, 225, 226, 227, 228, 229, 230, 231, 232, 233], #greek
|
||||
[234, 235, 236, 237, 238, 239, 240, 241, 242, 243], #crap
|
||||
[244, 245, 246, 247, 248, 249, 251, 252, 253, 167], #more crap
|
||||
[155, 156, 157, 158, 159, 171, 172, 166, 32, 32], #$
|
||||
[142, 132, 131, 143, 134, 133, 160, 145, 146, 32], #a
|
||||
[128, 135, 137, 136, 138, 144, 130, 164, 165, 32], #c, e, n
|
||||
[139, 140, 141, 161, 153, 148, 147, 149, 162, 32], #i, o
|
||||
[154, 129, 150, 151, 163, 32, 32, 32, 32, 32], #u
|
||||
], miFg, miBg)
|
||||
miQuit = MiButton("Back to Menu", self.client.leaveGame)
|
||||
self.cf = MiMenu([None, miFg, miBg, None, miChars, None, MiButton("Save", self.Save), None, miQuit, None])
|
||||
self.miChat = MiMenu([None, MiChat(client, 13, self.whiteboard.chat), MiTypein(self.SendMsg), None, miQuit, None])
|
||||
self.rgmiLayer = RgmiProjected(self.whiteboard.rglayer, DgProjectMiButton(self.SelectLayer))
|
||||
self.miLayers = MiMenu(Rgseq([None], self.rgmiLayer, [None, MiButton("New Layer", self.NewLayer), MiButton("Move up", self.LayerUp), MiButton("Move down", self.LayerDown),
|
||||
None, MiToggle("Show One"), None, MiStatic("Rename selected layer:"), MiTypein(self.RenameLayer, "LayerName", 80), None, miQuit, None]))
|
||||
self.ovPopup = OvPopup(self, self.client, MiTab.MiTabbed(["Drawing", self.cf], ["Layers", self.miLayers], ["Chat", self.miChat]))
|
||||
miStatus = MiMenuHoriz([MiStatic("Hit <Tab> for menu"), MiValue(miChars)])
|
||||
miStatus.ListenForNotice(self.miChat)
|
||||
self.ovStatus = OvStatic(self, self.client, miStatus, OvStatic.BOTTOM)
|
||||
|
||||
self.SelectLayer(self.whiteboard.rglayer[0])
|
||||
WhiteboardDraw(self, client)
|
||||
def Save(self):
|
||||
self.whiteboard.Save()
|
||||
msgscroller = self.game.rgtoken("msgscroller")[0]
|
||||
msgscroller.evPost.fire("Saved picture")
|
||||
|
||||
def SelectLayer(self, layer):
|
||||
self.ovPopup.SetSelection("layer", self.rgmiLayer.MiFromValue(layer))
|
||||
miRename = self.miLayers.MiByName("LayerName").SetValue(layer.StName())
|
||||
return True
|
||||
|
||||
def GetLayer(self):
|
||||
return self.ovPopup.GetSelection("layer").Value()
|
||||
|
||||
def NewLayer(self):
|
||||
ilayer = 1
|
||||
stLayer = None
|
||||
while stLayer == None:
|
||||
stLayer = "Layer " + str(ilayer)
|
||||
if self.whiteboard.LayerByName(stLayer) != None:
|
||||
stLayer = None
|
||||
ilayer = ilayer + 1
|
||||
layerNew = self.whiteboard.NewLayer(stLayer)
|
||||
if layerNew != None:
|
||||
self.SelectLayer(layerNew)
|
||||
return True
|
||||
|
||||
def LayerUp(self):
|
||||
self.whiteboard.MoveLayer(self.GetLayer(), True)
|
||||
return True
|
||||
|
||||
def LayerDown(self):
|
||||
self.whiteboard.MoveLayer(self.GetLayer(), False)
|
||||
return True
|
||||
|
||||
def RenameLayer(self, st):
|
||||
if st != "":
|
||||
self.GetLayer().SetName(st)
|
||||
return True
|
||||
|
||||
def blinkCursor(self, fBlink):
|
||||
self.fBlink = fBlink
|
||||
if not fBlink and self.cDontBlink > 0:
|
||||
self.cDontBlink = self.cDontBlink - 1
|
||||
|
||||
def SendMsg(self, st):
|
||||
if st.lower().startswith("/me ") and len(st.rstrip()) > 3:
|
||||
self.whiteboard.chat.Add(ChlAct(self.client, st[4:]))
|
||||
else:
|
||||
self.whiteboard.chat.Add(ChlMsg(self.client, st))
|
||||
|
||||
def OnChat(self, chl):
|
||||
if type(chl) != ChlSys:
|
||||
self.miChat.FlagNotice()
|
||||
|
||||
def run(self):
|
||||
with self.whiteboard.chat.evChat.oob(self, self.OnChat):
|
||||
while True:
|
||||
key = self.client.evKey.receive(self)
|
||||
fDontBlink = True
|
||||
if key == ansi.K_LEFT:
|
||||
self.pos.Left()
|
||||
elif key == ansi.K_RIGHT:
|
||||
self.pos.Right()
|
||||
elif key == ansi.K_UP:
|
||||
self.pos.Up()
|
||||
elif key == ansi.K_DOWN:
|
||||
self.pos.Down()
|
||||
elif key == ansi.K_BACKSPACE:
|
||||
self.pos.Left()
|
||||
self.PutWb(ansi.achBlank)
|
||||
elif key == ansi.K_DEL:
|
||||
self.PutWb(ansi.achBlank)
|
||||
self.pos.Right()
|
||||
elif key == ansi.K_TAB:
|
||||
fDontBlink = False
|
||||
self.ovPopup.evShow.fire()
|
||||
self.ovPopup.evDone.receive(self)
|
||||
elif key == ansi.K_HOME:
|
||||
self.Skip(self.pos.Left)
|
||||
elif key == ansi.K_END:
|
||||
self.Skip(self.pos.Right)
|
||||
elif key == ansi.K_PGUP:
|
||||
self.Skip(self.pos.Up)
|
||||
elif key == ansi.K_PGDN:
|
||||
self.Skip(self.pos.Down)
|
||||
elif ansi.FKeyPrintable(key):
|
||||
if key.isdigit():
|
||||
self.PutWb(chr(self.cf.Value("Characters")[IchFromCh(key)]))
|
||||
else:
|
||||
self.PutWb(key)
|
||||
self.pos.Right()
|
||||
else:
|
||||
print "weird key:", ansi.StrKey(key)
|
||||
fDontBlink = False
|
||||
|
||||
if fDontBlink:
|
||||
self.cDontBlink = 2 if self.fBlink else 1
|
||||
|
||||
if self.pos.Y() < self.whiteboard.H() / 2:
|
||||
self.ovStatus.kplace = OvStatic.BOTTOM
|
||||
else:
|
||||
self.ovStatus.kplace = OvStatic.TOP
|
||||
|
||||
def PutWb(self, ch):
|
||||
self.Put(ch, self.GetLayer().ascr)
|
||||
self.whiteboard.Touch()
|
||||
|
||||
def Put(self, ch, ascr):
|
||||
if type(ch) == str:
|
||||
ach = ansi.MkAch(ch, self.cf.Value("Foreground"), self.cf.Value("Background"))
|
||||
else:
|
||||
ach = ch
|
||||
ascr.PutAch(ach, self.pos.X(), self.pos.Y())
|
||||
|
||||
def GetAch(self):
|
||||
return self.GetLayer().ascr.GetAch(self.pos.X(), self.pos.Y())
|
||||
|
||||
def Skip(self, dgMove):
|
||||
self.SkipI(dgMove, self.GetAch())
|
||||
|
||||
def SkipI(self, dgMove, ach):
|
||||
fStop = False
|
||||
while not fStop:
|
||||
fStop = not dgMove() or self.GetAch() != ach
|
||||
|
||||
def draw(self, ascr, client):
|
||||
if self.fBlink or self.cDontBlink > 0:
|
||||
if client == self.client:
|
||||
chCursor = chr(176)
|
||||
ach = ascr.GetAch(self.pos.X(), self.pos.Y())
|
||||
if ach != None and ansi.ChFromAch(ach) == chCursor:
|
||||
chCursor = chr(177)
|
||||
self.Put(chCursor, ascr)
|
||||
elif self.fBlink:
|
||||
self.Put(str(self.client.Cldg().iclient)[0], ascr)
|
||||
|
||||
class WhiteboardDraw(TokenClient):
|
||||
def InitPersistent(self, owner, client):
|
||||
TokenClient.InitPersistent(self, owner, client, "drawable", "solid")
|
||||
|
||||
def draw(self, ascr, client):
|
||||
if client == self.client:
|
||||
if self.owner.miLayers.Value("Show One"):
|
||||
self.owner.GetLayer().Draw(ascr)
|
||||
else:
|
||||
self.owner.whiteboard.draw(ascr)
|
||||
|
||||
class CursorBlinker(Token):
|
||||
def InitPersistent(self, owner):
|
||||
Token.InitPersistent(self, owner)
|
||||
Blinker(self, self.BlinkAllCursors)
|
||||
|
||||
def BlinkAllCursors(self, fBlink):
|
||||
for tok in self.game.rgtoken("cursor"):
|
||||
tok.blinkCursor(fBlink)
|
||||
#@-node:jpenner.20090528201601.10:<<Cursor>>
|
||||
#@nl
|
||||
#@<<Overlay>>
|
||||
#@+node:jpenner.20090614150414.1:<<Overlay>>
|
||||
#@+others
|
||||
#@+node:jpenner.20090529173104.19:MiColour
|
||||
class MiColour(MiList):
|
||||
def InitPersistent(self, stName, rgcolor, col):
|
||||
self.rgcolor = rgcolor
|
||||
MiList.InitPersistent(self, rgcolor, rgcolor.index(col))
|
||||
self.stName = stName
|
||||
|
||||
def StName(self):
|
||||
return self.stName
|
||||
|
||||
def DrawValue(self, ascr, x, y, selor):
|
||||
for icol in range(len(self.rgcolor)):
|
||||
col = self.rgcolor[icol]
|
||||
ascr.PutAch(ansi.MkAch(chr(219) if icol != self.ival else chr(254), col, ansi.BLACK if col != ansi.BLACK else ansi.WHITE), x + icol, y)
|
||||
#@-node:jpenner.20090529173104.19:MiColour
|
||||
#@+node:jpenner.20090529173104.20:MiChars
|
||||
class MiChars(MiList):
|
||||
def InitPersistent(self, rgchar, miFg, miBg):
|
||||
MiList.InitPersistent(self, rgchar)
|
||||
self.miFg = miFg
|
||||
self.miBg = miBg
|
||||
def StName(self):
|
||||
return "Characters"
|
||||
def DrawValue(self, ascr, x, y, selor):
|
||||
for ich, ch in enumerate(self.Value()):
|
||||
ascr.PutSt(ChFromIch(ich) + ":", x, y, self.ColFg(), self.ColBg(selor))
|
||||
ascr.PutAch(ansi.MkAch(chr(ch), self.miFg.Value(), self.miBg.Value()), x + 2, y)
|
||||
x = x + 4
|
||||
|
||||
def ChFromIch(ich):
|
||||
if ich == 9:
|
||||
return '0'
|
||||
return str(ich + 1)
|
||||
|
||||
def IchFromCh(ch):
|
||||
if ch == '0':
|
||||
return 9
|
||||
return int(ch) - 1
|
||||
#@nonl
|
||||
#@-node:jpenner.20090529173104.20:MiChars
|
||||
#@+node:jpenner.20090926091308.1:MiChat
|
||||
class MiChat(Mi):
|
||||
KWNDMSG = 0
|
||||
KWNDUSERS = 1
|
||||
def InitPersistent(self, client, height, chat):
|
||||
Mi.InitPersistent(self)
|
||||
self.client = client
|
||||
self.chat = chat
|
||||
self.height = height
|
||||
assert height > 2
|
||||
self.kwnd = self.KWNDMSG
|
||||
self.imsg = 0
|
||||
self.iuser = 0
|
||||
|
||||
def StName(self):
|
||||
return "Chat"
|
||||
|
||||
def HandleKey(self, key):
|
||||
if self.kwnd == self.KWNDUSERS:
|
||||
if key == ansi.K_LEFT:
|
||||
self.kwnd = self.KWNDMSG
|
||||
elif (key == 'a' or key == 'A') and self.iuser > 0:
|
||||
self.iuser = self.iuser - 1
|
||||
elif (key == 'z' or key == 'Z') and self.iuser < self.chat.CUsers() - 1:
|
||||
self.iuser = self.iuser + 1
|
||||
else:
|
||||
return False
|
||||
else: #KWNDMSG
|
||||
if key == ansi.K_RIGHT:
|
||||
self.kwnd = self.KWNDUSERS
|
||||
elif (key == 'a' or key == 'A') and self.imsg < self.chat.CChl() - 1:
|
||||
self.imsg = self.imsg + 1
|
||||
elif (key == 'z' or key == 'Z') and self.imsg > 0:
|
||||
self.imsg = self.imsg - 1
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
def Height(self, w):
|
||||
return self.height
|
||||
|
||||
def ColBgDefault(self):
|
||||
return ansi.BLACK
|
||||
def ColBgSelected(self, fPri):
|
||||
return ansi.BLACK
|
||||
def ColFg(self):
|
||||
return ansi.WHITE
|
||||
|
||||
def FIgnoreParent(self):
|
||||
return True
|
||||
|
||||
def Draw(self, ascr, x, y, w, selor):
|
||||
wChat = (w / 4) * 3
|
||||
wUser = (w / 4) - 1
|
||||
self.chat.DrawMsg(ascr, x, y, wChat, self.height - 1, self.ColBg(selor), self.imsg)
|
||||
for yT in range(y, y + self.height - 1):
|
||||
ascr.PutAch(ansi.MkAch(chr(179)), x + wChat, yT)
|
||||
ascr.PutSt("{0:{1}<{2}}{3}{0:{1}<{4}}".format("", chr(196), wChat, chr(193), wUser), x, y + self.height - 1)
|
||||
self.chat.DrawUsers(ascr, x + wChat + 1, y, wUser, self.height - 1, self.ColBg(selor), self.iuser)
|
||||
if selor.KSel() == Selor.PRI:
|
||||
if self.kwnd == self.KWNDMSG:
|
||||
xBar = x + wChat - 1
|
||||
pct = 1 - (self.imsg / float(self.chat.CChl()))
|
||||
else: # KWNDUSERS
|
||||
xBar = x + w - 1
|
||||
pct = self.iuser / float(self.chat.CUsers())
|
||||
yBar = int(y + (pct * (self.height - 4)))
|
||||
ascr.PutAch(ansi.MkAch("A", ansi.RED, ansi.WHITE), xBar, yBar)
|
||||
ascr.PutAch(ansi.MkAch(chr(186), ansi.RED, ansi.WHITE), xBar, yBar + 1)
|
||||
ascr.PutAch(ansi.MkAch("Z", ansi.RED, ansi.WHITE), xBar, yBar + 2)
|
||||
#@-node:jpenner.20090926091308.1:MiChat
|
||||
#@-others
|
||||
#@nonl
|
||||
#@-node:jpenner.20090614150414.1:<<Overlay>>
|
||||
#@nl
|
||||
#@<<Joiner>>
|
||||
#@+node:jpenner.20090529173104.3:<<Joiner>>
|
||||
class Joiner(Token):
|
||||
def InitPersistent(self, owner):
|
||||
Token.InitPersistent(self, owner)
|
||||
self.msgScroller = self.game.rgtoken("msgscroller")[0]
|
||||
self.board = self.game.rgtoken("whiteboard")[0].board
|
||||
|
||||
def OnJoin(self, client):
|
||||
with client.Cldg().SetTransiently() as cldg:
|
||||
cldg.iclient = -1
|
||||
iclient = 1
|
||||
rgiclient = [clientT.Cldg().iclient for clientT in self.game.rgclient]
|
||||
while iclient in rgiclient:
|
||||
iclient = iclient + 1
|
||||
cldg.iclient = iclient
|
||||
self.msgScroller.evPost.fire(client.cld.user + "(#" + str(cldg.iclient) + ") has joined! :)")
|
||||
self.board.chat.Add(ChlSys(client, "has joined"))
|
||||
|
||||
def OnLeave(self, client):
|
||||
self.msgScroller.evPost.fire(client.cld.user + " has left! :(")
|
||||
self.board.chat.Add(ChlSys(client, "has left"))
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
with self.game.evJoin.oob(self, self.OnJoin):
|
||||
self.OnLeave(self.game.evLeave.receive(self))
|
||||
#@-node:jpenner.20090529173104.3:<<Joiner>>
|
||||
#@nl
|
||||
|
||||
#@+others
|
||||
#@+node:jpenner.20091003162445.1:Lobby
|
||||
|
||||
class Lobby(TokenClient):
|
||||
def InitPersistent(self, owner, client):
|
||||
TokenClient.InitPersistent(self, owner, client)
|
||||
self.miDrawings = MiMenu(RgmiProjected(self.game.rgboard, DgProjectMiButton(self.Goto)))
|
||||
self.miCmds = MiMenu([None, None, MiTypein(self.New, "DrawingName"), MiButton("New Drawing", self.NewBtn),
|
||||
None, None, None, None, None, None, None, None, MiStatic("Last modified:"), MiDgText(self.StLastModified)])
|
||||
OvMenu(self, client, MiMenuHoriz([self.miDrawings, self.miCmds], [65, 35]), OvMenu.FILL)
|
||||
|
||||
def New(self, stName):
|
||||
if stName != "":
|
||||
self.game.NewBoard(stName, self.client.cld.user)
|
||||
|
||||
def NewBtn(self):
|
||||
self.New(self.miCmds.Value("DrawingName"))
|
||||
|
||||
def StLastModified(self):
|
||||
return self.miDrawings.Value().StLastModified()
|
||||
|
||||
def Goto(self, board):
|
||||
self.client.leaveGame(board)
|
||||
#@-node:jpenner.20091003162445.1:Lobby
|
||||
#@+node:jpenner.20090529173104.25:Runner
|
||||
class RunnerWB(Runner):
|
||||
def InitPersistent(self):
|
||||
self.gameLobby = GameLobby()
|
||||
Runner.InitPersistent(self)
|
||||
|
||||
def RunGame(self, client):
|
||||
if (client.joinGame(GameLogin())):
|
||||
while True:
|
||||
board = client.joinGame(self.gameLobby)
|
||||
client.joinGame(self.gameLobby.GameFromBoard(board))
|
||||
|
||||
class GameLogin(Game):
|
||||
def GetRgclsTokTrans(self):
|
||||
return [[AutoJoiner, login.LoginTerm]]
|
||||
|
||||
@Version(5)
|
||||
class GameLobby(Game):
|
||||
def InitPersistent(self):
|
||||
self.rgboard = []
|
||||
Game.InitPersistent(self)
|
||||
|
||||
def InitTransient(self):
|
||||
Game.InitTransient(self)
|
||||
self.mpboard_gameWB = {}
|
||||
|
||||
def GetRgclsTokTrans(self):
|
||||
return [[AutoJoiner, Lobby]]
|
||||
|
||||
def GameFromBoard(self, board):
|
||||
if not (board in self.mpboard_gameWB):
|
||||
gameWB = GameWB(self, board)
|
||||
def KillBoard():
|
||||
del self.mpboard_gameWB[board]
|
||||
gameWB.rgdgdie.append(KillBoard)
|
||||
self.mpboard_gameWB[board] = gameWB
|
||||
return gameWB
|
||||
return self.mpboard_gameWB[board]
|
||||
|
||||
def NewBoard(self, stName, user):
|
||||
self.rgboard.insert(0, Board(self, stName, user))
|
||||
|
||||
def StNameBoard(self, board):
|
||||
cclient = 0
|
||||
if board in self.mpboard_gameWB:
|
||||
cclient = len(self.mpboard_gameWB[board].rgclient)
|
||||
return board.stName + " (by " + board.user + ") [" + str(cclient) + "]"
|
||||
|
||||
def BoardTouched(self, board):
|
||||
#haaaack
|
||||
if board != self.rgboard[0]:
|
||||
self.rgboard.remove(board)
|
||||
self.rgboard.insert(0, board)
|
||||
self.ensureRun() # redraw
|
||||
|
||||
def UpgradeFrom(self, versionOld):
|
||||
if versionOld < 3:
|
||||
for gameWB in self.rggameWB:
|
||||
gameWB.gameLobby = self
|
||||
if versionOld < 4:
|
||||
self.rgboard = [game.rgtoken("whiteboard")[0].board for game in self.rggameWB]
|
||||
for gameWB in self.rggameWB:
|
||||
gameWB.finish()
|
||||
if versionOld < 5:
|
||||
del self.rggameWB
|
||||
|
||||
class GameWB(Game):
|
||||
def InitPersistent(self, gameLobby, board):
|
||||
self.gameLobby = gameLobby
|
||||
self.board = board
|
||||
Game.InitPersistent(self)
|
||||
|
||||
def InitTransient(self):
|
||||
Game.InitTransient(self)
|
||||
if not self.FDead():
|
||||
self.board.chat.AttachToGame(self)
|
||||
self.rgdgdie.append(self.board.chat.DetachFromGame)
|
||||
|
||||
def GetRgclsTokPers(self):
|
||||
return [[Whiteboard, self.board]]
|
||||
|
||||
def GetRgclsTokTrans(self):
|
||||
return [MsgScroller, Joiner, [AutoJoiner, Cursor], [AliveWithPlayers, CursorBlinker], AutoKiller]
|
||||
|
||||
def GetRgtagDraw(self):
|
||||
return ["background", "solid", "cursor", "menu", "msgscroller"]
|
||||
|
||||
if __name__ == "__main__":
|
||||
Run(RunnerWB, "whiteboard.marm")
|
Loading…
Reference in a new issue