marmots/scripting.py
2020-06-27 11:21:39 -04:00

815 lines
28 KiB
Python

from engine import *
from basetoken import *
from tpers import *
from util import *
from contextlib import contextmanager
def RegStmt(clsStmt):
SyntLine.rgclsStmt.append(clsStmt)
return clsStmt
def RegRtype(clsRtype):
Rtype.rgclsRtype.append(clsRtype)
return clsRtype
# rtype -- runtime type
# method: RglitFromSt(st) -- parse the string and return a list of potentially matching literals
# method: RgsyntFromSt(scope, st) -- parse the string and return a list of synts whose rtypes match this
# method: StForSobj(sobj) -- a user-visible description of the sobj
# method: FMember(sobj) -- returns true if sobj is a member of this type
# method: FOverlap(rtype) -- returns true if there is some overlap between this type and rtype
class Rtype(TPrs):
rgclsRtype = []
@classmethod
def RtypeMax(cls):
return cls()
def RglitFromSt(self, st):
return []
def RgsyntFromSt(self, syntBlock, st):
for lit in self.RglitFromSt(st):
yield SyntLit(None, lit, self)
while syntBlock != None:
if isinstance(syntBlock, SyntBlock):
for synt in self.RgsyntFromSyntBlock(syntBlock, st):
yield synt
syntBlock = syntBlock.syntParent
# helper for RgsyntFromSt
def RgsyntFromSyntBlock(self, syntBlock, st):
# yield all vars in scope
for syntLine in syntBlock.rgsynt:
if SyntVar.FVarOfType(syntLine.rgsynt[0], self):
yield SyntVarRef(None, syntLine.rgsynt[0])
def StForSobj(self, sobj):
return str(sobj)
def FMember(self, sobj):
return isinstance(sobj, self.pythontype)
def FOverlap(self, rtype):
return isinstance(rtype, self.__class__)
@RegRtype
class RtypeBool(Rtype):
pythontype = bool
def RglitFromSt(self, st):
if "true".startswith(st.lower()):
yield True
if "false".startswith(st.lower()):
yield False
@RegRtype
class RtypeNum(Rtype):
pythontype = float
def RglitFromSt(self, st):
try:
yield float(st)
except:
pass
@RegRtype
class RtypeString(Rtype):
pythontype = str
def RglitFromSt(self, st):
if st.startswith('"') or st.startswith("'"):
yield st[1:]
class RtypeAny(Rtype):
def RgsyntFromSt(self, syntBlock, st):
for clsRtype in self.rgclsRtype:
rtype = clsRtype.RtypeMax()
for synt in rtype.RgsyntFromSt(syntBlock, st):
yield synt
def FMember(self, sobj):
return True
def FOverlap(self, rtype):
return True
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)
# synt -- a piece of syntax
# method: Project() -- projects it
#
class Synt(Typeable):
desc = None
def InitPersistent(self, syntParent):
self.syntParent = syntParent
self.rgsynt = []
self.Populate()
@classmethod
def SyntDefault(cls, syntParent):
return cls(syntParent)
def ProjectTypeinForChild(self, pwParent, syntChild, st):
def OnSelect(synt, psel):
self.Replace(syntChild, synt)
syntChild.SetStTypein(None)
if syntChild.GetStTypein() != None:
pwParent = PwDropdown(pwParent)
PwTypein(pwParent, st, syntChild)
if syntChild.GetStTypein() != None:
for synt in self.RgsyntForChild(syntChild, syntChild.GetStTypein()):
PwButton(pwParent, synt.StForTypein(), synt, OnSelect)
def RgsyntForChild(self, syntChild, st):
return []
def Replace(self, syntOld, syntNew):
self.rgsynt[self.Isynt(syntOld)] = syntNew
syntNew.syntParent = self
def Isynt(self, syntChild):
if isinstance(syntChild, int):
return syntChild
return self.rgsynt.index(syntChild)
def Rtype(self):
return None
def RtypeTopForChild(self, syntChild):
return None
def Eval(self, ectx):
pass
def Populate(self):
pass
def Project(self, pcur):
pass
# desc - list of desces
# desce:
# string: "foo" -- literal uneditable text
# list: ["foo"] -- text to edit the current synt
# tuple: (clsSynt, type) -- child description
# clsSynt: class of child synt
# type: number - same as another child expression with that number
# None - no rtype specified / possible
# tuple (number, rtypeTop) - number == same as another child expression with that number, rtypeTop = required type
class SyntDesc(Synt):
@classmethod
def StForTypein(cls):
for desce in cls.desc:
if isinstance(desce, list) and len(desce) == 1:
return desce[0]
@staticmethod
def DefProp(isynt):
def get(self):
return self.rgsynt[isynt]
def set(self, syntNew):
self.Replace(isynt, syntNew)
def delete(self):
self.Replace(isynt, None)
return property(get, set, delete)
def Populate(self):
for desce in self.desc:
if isinstance(desce, tuple):
synt = desce[0].SyntDefault(self)
self.rgsynt.append(synt)
# for synt in self.rgsynt:
# synt.Populate()
def SyntProperty(self, isynt):
def get():
return self.rgsynt[isynt]
def set(syntNew):
self.Replace(isynt, syntNew)
def delete():
self.Replace(isynt, None)
return property(get, set, delete)
def RtypeTopForChild(self, syntChild):
isyntChild = self.Isynt(syntChild)
isyntDesce = 0
for desce in self.desc:
if isinstance(desce, tuple):
if isyntDesce == isyntChild:
if isinstance(desce[1], tuple):
return desce[1][0]
return None
isyntDesce += 1
return None
def Project(self, pcur):
"adds more horizontal pws to a horizontal pw"
isynt = 0
for desce in self.desc:
if isinstance(desce, str):
PwStatic(pcur.PwHoriz(self), desce)
elif isinstance(desce, list):
# selection for the synt itself
self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, desce[0])
elif isinstance(desce, tuple):
# embedded syntax
self.rgsynt[isynt].Project(pcur)
isynt += 1
class SyntName(Synt):
def Project(self, pcur):
PwTypein(pcur.PwHoriz(self), self.GetStTypein(), self)
class SyntExpr(Synt):
def Project(self, pcur):
self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, " ")
class SyntLine(Synt):
rgclsStmt = []
def Populate(self):
self.rgsynt.append(SyntBlank(self))
def SetStmt(self, syntStmt):
self.Replace(self.rgsynt[0], syntStmt)
def Project(self, pcur):
pwKey = PwKeyHandler(pcur.pwVert, self.HandleKey)
with pcur.ProjectHoriz(pwKey, self):
self.rgsynt[0].Project(pcur)
def RgsyntForChild(self, syntChild, st):
for clsStmt in self.rgclsStmt:
if clsStmt.StForTypein().lower().startswith(st.lower()):
yield clsStmt(None)
def HandleKey(self, pwKey, pov, psel, key):
if ansi.FEnter(key):
self.syntParent.InsertLineAfter(self, None)
psel.Inc(pwKey.PwParent())
return True
return False
class SyntBlock(Synt):
def Project(self, pcur):
with pcur.Indent(2 if pcur.pwHoriz != None else 0):
pcur.EndLine()
if pcur.pwVert == None:
pcur.pwVert = PwBlock(None, self, pcur.dxindent)
def OnInsertNewLine(syntAfter, psel):
self.InsertLineAfter(syntAfter, None)
psel.Inc(pcur.pwVert)
PwButtonHidden(pcur.pwVert, "[insert new line]", None, OnInsertNewLine, pcur.dxindent)
for syntLine in self.rgsynt:
syntLine.Project(pcur)
def InsertLineAfter(self, syntAfter, syntStmt):
syntLine = SyntLine(self)
if syntStmt != None:
syntLine.SetStmt(syntStmt)
if syntAfter == None:
self.rgsynt.insert(0, syntLine)
else:
self.rgsynt.insert(self.rgsynt.index(syntAfter) + 1, syntLine)
return syntLine
class SyntLit(Synt):
def InitPersistent(self, syntParent, value, rtype):
Synt.InitPersistent(self, syntParent)
self.value = value
self.rtype = rtype
def Rtype(self):
return rtype
@RegStmt
class SyntBlank(SyntDesc):
desc = [[" "]]
@RegStmt
class SyntVar(SyntDesc):
desc = [["Define"], " ", (SyntName, None), " to be ", (SyntExpr, 1)]
name = SyntDesc.DefProp(0)
expr = SyntDesc.DefProp(1)
@classmethod
def FVarOfType(cls, synt, rtype):
return isinstance(synt, cls) and synt.expr != None and rtype.FOverlap(expr.Rtype())
class SyntVarRef(Synt):
def __init__(self, syntParent, syntVar = None):
Synt.__init__(self, syntParent)
self.syntVar = syntVar
def Rtype(self):
return self.syntVar.Rtype()
@RegStmt
class SyntIf(SyntDesc):
desc = [["If"], " ", (SyntExpr, (1, RtypeBool)), ", then:", (SyntBlock, None), "or else:", (SyntBlock, None)]
expr = SyntDesc.DefProp(0)
blockIfTrue = SyntDesc.DefProp(1)
blockIfFalse = SyntDesc.DefProp(2)
# 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 Fail(TPrs):
def InitPersistent(self, stFailure):
self.stFailure == stFailure
# projection cursor
class Pcur(object):
@staticmethod
def PwProjected(synt):
pcur = Pcur()
synt.Project(pcur)
return pcur.pwVert
def __init__(self):
self.pwVert = None
self.pwHoriz = None
self.dxindent = 0
@contextmanager
def Indent(self, dxindent = 2):
self.dxindent += dxindent
yield
self.dxindent -= dxindent
@contextmanager
def ProjectHoriz(self, pwParent, synt):
self.ProjectHorizI(pwParent, synt)
yield
self.EndLine()
def PwHoriz(self, synt):
if self.pwHoriz == None:
self.ProjectHorizI(self.pwVert, synt)
return self.pwHoriz
def EndLine(self):
self.pwHoriz = None
def ProjectHorizI(self, pwParent, synt):
self.pwHoriz = PwList(pwParent, synt, self.dxindent)
# 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 PrintTree(self, dxindent = 0):
print (" " * dxindent) + self.StDebug()
for pwChild in self.RgpwChild():
pwChild.PrintTree(dxindent + 2)
def StDebug(self):
return self.__class__.__name__
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 PwContainOne(Pw):
def AddChild(self, pw):
self.pwChild = pw
def RgpwChild(self):
return [self.pwChild]
def FContainer(self):
return True
class PwExpand(PwContainOne):
def DxDyNew(self, w, dxStart, mpksel):
dxdy = self.pwChild.DxDyNew(w, dxStart, mpksel)
if dxdy[0] == 0 and dxdy[1] > 0:
return dxdy
return (0, dxdy[0] + 1)
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
if not fOverlay:
ascr.PutSt(" " * w, x, y, self.pwChild.ColFg(), self.pwChild.ColBg(mpksel.Get(self.pwChild)))
self.pwChild.Draw(ascr, x, y, w, dxStart, mpksel, fOverlay)
class PwStatic(Pw):
def __init__(self, pwParent, stText):
Pw.__init__(self, pwParent)
self.stText = stText
def StDebug(self):
return Pw.StDebug(self) + " '" + self.StTextDisplay(Ksel.NAV) + "'"
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(), psel)
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 Pcur.PwProjected(self.block)
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(Pcur.PwProjected(self.block).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 = SyntBlock(None)
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")