class SogalText(NodePath): ''' A text label, contains many TextLines ''' def __init__(self, parent = None, pos = (0,0,0), text = u'', wordwrap = None, maxRows = None, spacing = 0, lineSpacing = 0, minLineHeight = 0.5, font = None, fg = (1,1,1,1), scale = 0.07, shadow = None, shadowOffset = (0.04, 0.04), textScale = None, ): ''' Constructor :param parent: parent NodePath :param text: text :param font: font of the text :param wordwrap: set the width when wraping the word (note that ) :param maxRows: max row of the text :param spacing: spacing of words :param lineSpacing: spacing of lines :param minLineHeight: height of a line when it is empty :param fg: foreground color :param scale: scale of the text :param shadow: shadow color of the text :param shadowOffset: shadow offset of the text ''' self.destroyed = False self.__parent = parent or aspect2d self.__lerpLock = Lock() self.__font = font self.__currentLerpInterval = None self.wordwrap = wordwrap self.lines = [] self.spacing = spacing self.lineSpacing = lineSpacing self.minLineHeight = minLineHeight self.maxRows = maxRows self.recordedText = [] #recorder text sections used in backup NodePath.__init__(self,'') self.setScale(scale) self.setPos(pos) self.currentHeight = 0 self.reparentTo(self.__parent) # @UndefinedVariable self.textMaker = TextNode('textMaker') if font: self.setFont(font, specNode = None) if fg: self.setFg(fg, specNode = None) if shadow: self.setShadow(shadow, shadowOffset, specNode = None) if textScale: self.setTexScale(textScale,specNode = None) self.textMaker.setAlign(TextNode.ALeft) if shadow: pass if text: self.appendText(text) def destroy(self): if self.__currentLerpInterval: self.__currentLerpInterval.pause() self.clear() if not self.destroyed: self.destroyed = True self.textMaker = None self.recordedText = None self.removeNode() def clear(self): if self.__currentLerpInterval: self.__currentLerpInterval.pause() self.currentHeight = 0 for tl in self.lines: tl.removeNode() self.lines = [] self.recordedText = [] def setFg(self, fg, specNode = None): node = specNode or self.textMaker node.setTextColor(fg[0], fg[1], fg[2], fg[3]) def setFont(self,font, specNode = None): node = specNode or self.textMaker node.setFont(font) def setShadow(self, shadow, offset = (0.04, 0.04), specNode = None): node = specNode or self.textMaker if shadow[3] != 0: node.setShadowColor(shadow[0], shadow[1], shadow[2], shadow[3]) node.setShadow(offset) else: node.clearShadow() def setTextScale(self, scale , specNode = None): node = specNode or self.textMaker node.setTextScale(scale) def setMaxRows(self,maxrows): self.maxRows = maxrows def setWordwrap(self,wordwrap): self.wordwrap = wordwrap def setMinLineHeight(self,minLineHeight): self.minLineHeight = minLineHeight def appendText(self, text,speed = 0, fadein = 0, fadeinType = 0, newLine = False, custom = False, font = None, textScale = 1, fg = (1,1,1,1), shadow = None, shadowOffset = (0.04, 0.04), **kwargs): textprops = dict(text = text,newLine = newLine, custom = custom, font = font, textScale = textScale, fg = fg, shadow = shadow, shadowOffset = shadowOffset, **kwargs) self.recordedText.append(textprops) self.appendStoredText(textprops, speed, fadein, fadeinType) def appendStoredText(self,textprops, speed = 0, fadein = 0, fadeinType = 0): #append a text stored with appendText() or by loading self.recordedText text = textprops['text'] newLine = textprops['newLine'] custom = textprops['custom'] if custom: textMaker = TextNode('temptextmaker', self.textMaker) font = textprops['font'] if font: textMaker.setFont(font) textScale = textprops['textScale'] if textScale: textMaker.setTextScale(textScale) fg = textprops['fg'] if fg: self.setFg(fg, textMaker) shadow = textprops['shadow'] shadowOffset = textprops['shadowOffset'] if shadow: self.setShadow(shadow, shadowOffset, textMaker) #prepared to add more props here else: textMaker = self.textMaker if newLine or not self.lines: self.startLine() if not speed: for word in text: self.appendWord(word, tm = textMaker, fadein = fadein, fadeinType = fadeinType) #TYPER EFFECT else: self.__TextLerpInit() self.__currentLerpInterval = LerpFunc(self._appendTextLerpFunc,extraArgs = [text,textMaker,fadein,fadeinType], duration = len(text)/float(speed)) self.__currentLerpInterval.start() def __TextLerpInit(self): if self.__currentLerpInterval: self.__currentLerpInterval.finish() self.__lerpLock.acquire() self.__lastTextLerpValue = 0 self.__lerpLock.release() def _appendTextLerpFunc(self, lerp, text, tm, fadein, fadeinType): '''The function interval method for typer effect''' self.__lerpLock.acquire() tlen = len(text) start = int(math.floor(self.__lastTextLerpValue * tlen)) end = int(math.floor(lerp * tlen)) if end > start: appendingText = text[start:end] for word in appendingText: self.appendWord(word, tm, fadein = fadein, fadeinType = fadeinType) self.__lastTextLerpValue = lerp self.__lerpLock.release() def isWaiting(self): if self.__currentLerpInterval: return self.__currentLerpInterval.isPlaying() return False def quickFinish(self): if self.__currentLerpInterval: return self.__currentLerpInterval.finish() for l in self.lines: l.quickFinish() def appendWord(self,word,tm = None, fadein = 0, fadeinType = 0): if word == '\n': self.startLine() return textMaker = tm or self.textMaker if not self.lines: self.startLine() active_line = self.lines[-1] unicodeText = isinstance(word, types.UnicodeType) if unicodeText: textMaker.setWtext(word) else: textMaker.setText(word) width = textMaker.getWidth() height = textMaker.getHeight() node = textMaker.generate() textpath = NodePath('text_path') textpath.attachNewNode(node) if self.wordwrap: if active_line.getTotalWidth() + width > self.wordwrap: self.startLine() active_line = self.lines[-1] active_line.append(textpath, width, height,self.spacing, fadein = fadein, fadeinType = fadeinType) active_line.setPos(0,0,-(self.currentHeight + active_line.getLineHeight()) ) def startLine(self): if self.lines: self.currentHeight += self.lines[-1].getLineHeight() + self.lineSpacing line = TextLine(parent = self, height = self.minLineHeight) line.setPos(0,0,-self.currentHeight) self.lines.append(line) def removeNode(self, *args, **kwargs): return NodePath.removeNode(self, *args, **kwargs) def getCurrentText(self): return self.recordedText def getCopiedText(self): return copy.deepcopy(self.recordedText) def loadRecordedText(self,recorded): for section in recorded: self.appendStoredText(section) self.recordedText = copy.copy(recorded) def getNewText(self): if self.recordedText: return self.recordedText[0]['text'] return '' def getEndPos(self): if self.lines: return (self.lines[-1].getEndPos()[0],0 , -(self.currentHeight + self.lines[-1].getLineHeight())) else: return (0,0,0) def hasContent(self): "get if this text label empty" return bool(self.lines)
class Timer: def __init__(self, style): """ Timer class with fun pictures @param style: 0 = SUN, 1 = MOON, 2 = GUN @type style: int """ self.style = style VirtualFileSystem.getGlobalPtr().mount(Filename("mf/timer.mf"), ".", VirtualFileSystem.MFReadOnly) self.egg = loader.loadModel("timer.egg") self.img = None self.interval = None self.types[style](self) def create_sun(self): """ Creates the sun timer """ # load image self.img = OnscreenImage(image=self.egg.find('**/sun'), pos=(1.15, 0, 0.75), color=(255, 255, 0, 1), scale=0.25) # interval self.interval = LerpFunc(self.run_interval, fromData=1, toData=0, duration=TIME) self.interval.start() return def create_moon(self): """ Creates the moon timer """ # load image self.img = OnscreenImage(image=self.egg.find('**/moon-quarter'), pos=(0, 0, 0), color=(1, 1, 1, 1), scale=0.25) # interval self.interval = LerpFunc(self.run_interval, fromData=1, toData=0, duration=TIME) self.interval.start() return def create_gun(self): """ Creates the gun timer """ # load image self.img = OnscreenImage(image=self.egg.find('**/gun-0'), pos=(1.05, 0, 0.75), scale=0.25) # interval self.interval = LerpFunc(self.run_interval, fromData=1, toData=0, duration=TIME) self.interval.start() return def run_interval(self, c): if self.style == SUN: self.img.setColor((1, c, 0, 1)) self.img.setPos(1.15-(c/4), 0, 0.75+(math.sin(math.pi*c)/10)) elif self.style == MOON: self.img.setColor((1, c, c, 1)) self.img.setPos(0.9+(c/4), 0, 0.75+(math.sin(math.pi*c)/10)) elif self.style == GUN: self.img.setHpr(0, 0, 360*(1-c)-60) if c % (1 / 6) < 0.05: if c % (1 / 6) > 0.025: self.img.setColor((1, 40*(c % (1 / 6)), 40*(c % (1 / 6)), 1)) else: self.img.setImage(self.egg.find('**/gun-{}'.format(6 - (round(c / (1 / 6)))))) self.img.setColor((1, 1-40*(c % (1 / 6)), 1-40*(c % (1 / 6)), 1)) else: self.img.setColor((1, 1, 1, 1)) def annihilate(self): self.interval.finish() self.img.destroy() loader.unloadModel(self.egg) VirtualFileSystem.getGlobalPtr().unmount("mf/timer.mf") del self types = { SUN: create_sun, MOON: create_moon, GUN: create_gun }