Best Python code snippet using pyatom_python
dialogrenderer.py
Source:dialogrenderer.py  
1import random2import re3from typing import Tuple, Callable4import pygame5import pypeg26from pygame.surface import Surface7from pypeg2 import contiguous, attr, parse, word, maybe_some8from engine.graphics.fontmanager import FontManager9from engine.graphics.frame import Frame10from engine.graphics.textures import Textures11from engine.timer import Timer12from engine.tween.easing import Easing13from engine.tween.tween import Tween14from engine.tween.tweensubject import TweenSubject15class Text(pypeg2.List):16    pass17class BoldText(pypeg2.List):18    grammar = "<b>", attr("text", Text), "</b>"19class UnderlineText(pypeg2.List):20    grammar = "<u>", attr("text", Text), "</u>"21class ShakingText(pypeg2.List):22    grammar = "<shaking>", attr("text", Text), "</shaking>"23class StrikeText(pypeg2.List):24    grammar = "<strike>", attr("text", Text), "</strike>"25class ItalicText(pypeg2.List):26    grammar = "<i>", attr("text", Text), "</i>"27class WavingText(pypeg2.List):28    grammar = "<waving>", attr("text", Text), "</waving>"29class SmallText(pypeg2.List):30    grammar = "<small>", attr("text", Text), "</small>"31class BigText(pypeg2.List):32    grammar = "<big>", attr("text", Text), "</big>"33class SlowText(pypeg2.List):34    grammar = "<slow>", attr("text", Text), "</slow>"35class FastText(pypeg2.List):36    grammar = "<fast>", attr("text", Text), "</fast>"37class ColoredText(pypeg2.List):38    grammar = "<color ", pypeg2.Symbol, ">", attr("text", Text), "</color>"39# Ugh not this again40Text.grammar = attr("text", contiguous(maybe_some([SlowText, FastText, SmallText, BigText, ColoredText, WavingText, StrikeText, ShakingText, ItalicText, BoldText, UnderlineText,41                                                   re.compile(r"[^<>]")])))42class CharacterChunk:43    def __init__(self):44        self.char = ""45        self.surface = None46        self.state = {}47        self.yOffset = 0  # used to compensate the big and small text size48        self.animationXOffset = TweenSubject(0)  # used to animate letters49        self.animationYOffset = TweenSubject(0)50class DialogRenderer:51    # TODO Add choices here52    # TODO In order : more rich text rendering53    # TODO Add sound54    STATE_PARSING = 055    STATE_BUILDING = 156    STATE_READY = 257    LINE_HEIGHT = 4058    DEFAULT_TEXT_COLOR = (0, 0, 0, 0)59    FONT = "Dialog"60    Y_OFFSET = -461    CARET_TIMER_DURATION = 10062    SHAKING_TIMER_DURATION = 2063    WAVING_TIMER_DURATION = 60064    LETTER_DURATION = 20  # TODO Make this a user choice65    WAVING_X_AMPLITUDE = 366    WAVING_Y_AMPLITUDE = 867    WAVING_OFFSET = 15  # ms offset between each letter68    def __init__(self, window : Surface, frame : Frame, text : str, endCallback : Callable):69        self.__boundaries = frame.rect70        self.__text = text71        self.__endCb = endCallback72        self.__window = window73        self.__caretTexture = Textures.getTexture("gui.caret")74        self.__caretStep = 0  # the current step in the caret texture75        self.__caretTimer = Timer("caret", DialogRenderer.CARET_TIMER_DURATION, self.caretTimerCb)76        self.__shakingTimer = Timer("shaking", DialogRenderer.SHAKING_TIMER_DURATION, self.shakingTimerCb)77        self.__regularFont = FontManager.getFont(DialogRenderer.FONT + "Regular")78        self.__smallFont = FontManager.getFont(DialogRenderer.FONT + "Small")79        self.__bigFont = FontManager.getFont(DialogRenderer.FONT + "Big")80        self.__font = self.__regularFont81        self.__linesMax = int((self.__boundaries[3] - Frame.PADDING * 2) / (self.__font.size("H")[1]))82        self.__frame = frame83        self.__parserState = DialogRenderer.STATE_PARSING84        self.__states = {}85        self.__lines = [[]]86        self.__linesCharactersIndex = [0]87        self.__currentPageOffset = 088        self.__currentlyDrawingLine = 089        self.__alive = True90        self.__shakingChunks = []91        self.__wavingChunksTweens = []92        # Rich text parser variables93        self.__lastWhitespacePosOnTheLine = 094        self.__currentPosOnTheLine = 095        self.__xOffset = 096    def buildLines(self, tree):97        for text in tree.text:98            textType = type(text)99            if textType == str:100                if text == " ":101                    self.__lastWhitespacePosOnTheLine = self.__currentPosOnTheLine102                self.setFontProperties(self.__states)103                chunk = CharacterChunk()104                chunk.char = text105                chunk.surface = self.__font.render(text, True, DialogRenderer.DEFAULT_TEXT_COLOR)  # TODO Right color106                chunk.state = {**self.__states}107                if self.stateEnabled(chunk.state, "Small"):108                    chunk.yOffset = 10109                elif self.stateEnabled(chunk.state, "Big"):110                    chunk.yOffset = -5111                if text == "\n":112                    self.__lines.append([])113                    self.__linesCharactersIndex.append(0)114                elif text == "\t":115                    for x in range(0, (self.__linesMax - len(self.__lines) % self.__linesMax) + 1):116                        self.__lines.append([])117                        self.__linesCharactersIndex.append(0)118                elif self.__xOffset + chunk.surface.get_width() >= self.__boundaries[2] - Frame.PADDING * 2:119                    # Rewind until the previous whitespace to put the previous120                    # word on the newly created line121                    newLine = self.__lines[-1][self.__lastWhitespacePosOnTheLine+1:self.__currentPosOnTheLine+1]122                    self.__lines[-1] = self.__lines[-1][:self.__lastWhitespacePosOnTheLine+1]123                    # Ignore empty new lines (overflowing whitespace)124                    if len(newLine) > 0:125                        # If the first char of the line is a whitespace126                        # remove its chunk127                        firstChar = newLine[0].char128                        if firstChar == " ":129                            newLine = newLine[1:]130                    # Append new line and reset131                    self.__xOffset = sum(x.surface.get_width() for x in newLine)132                    self.__lines.append(newLine)133                    self.__linesCharactersIndex.append(0)134                    self.__currentPosOnTheLine = len(newLine)135                if text != "\n" and text != "\t":136                    self.__lines[-1].append(chunk)137                    self.__xOffset += chunk.surface.get_width()138                    if self.stateEnabled(chunk.state, "Shaking"):139                        self.__shakingChunks.append(chunk)140                    elif self.stateEnabled(chunk.state, "Waving"):141                        chunk.animationXOffset.value = -DialogRenderer.WAVING_X_AMPLITUDE142                        chunk.animationYOffset.value = -DialogRenderer.WAVING_Y_AMPLITUDE143                        xtween = Tween(None, chunk.animationXOffset, DialogRenderer.WAVING_X_AMPLITUDE,144                                       DialogRenderer.WAVING_TIMER_DURATION, Easing.easingInOutSine, None)145                        xtween.runningSince = xtween.duration / 2  # fast forward half the time to offset X and Y animations146                        ytween = Tween(None, chunk.animationYOffset, DialogRenderer.WAVING_Y_AMPLITUDE,147                                       DialogRenderer.WAVING_TIMER_DURATION, Easing.easingInOutSine, None)148                        xtween.runningSince += DialogRenderer.WAVING_OFFSET * self.__currentPosOnTheLine149                        ytween.runningSince += DialogRenderer.WAVING_OFFSET * self.__currentPosOnTheLine150                        self.__wavingChunksTweens.append(xtween)151                        self.__wavingChunksTweens.append(ytween)152                self.__currentPosOnTheLine += 1153            else:154                typeStr = textType.__name__[:-4]155                self.__states[typeStr] = True156                self.buildLines(text.text)157                self.__states[typeStr] = False158    def shakingTimerCb(self, tag):159        for chunk in self.__shakingChunks:160            chunk.animationXOffset.value = random.randint(-1, 1)161            chunk.animationYOffset.value = random.randint(-1, 1)162        self.__shakingTimer.restart()163    def setFontProperties(self, state):164        if self.stateEnabled(state, "Big"):165            self.__font = self.__bigFont166        elif self.stateEnabled(state, "Small"):167            self.__font = self.__smallFont168        else:169            self.__font = self.__regularFont170        self.__font.set_italic(self.stateEnabled(state, "Italic"))171        self.__font.set_underline(self.stateEnabled(state, "Underline"))172        self.__font.set_bold(self.stateEnabled(state, "Bold"))173    def stateEnabled(self, state, name):174        return name in state and state[name]175    def caretTimerCb(self, tag):176        self.__caretStep = (self.__caretStep + 1) % 4177        self.__caretTimer.restart()178    def update(self, dt, events):179        if not self.__alive:180            return181        self.__caretTimer.update(dt)182        self.__shakingTimer.update(dt)183        for tween in self.__wavingChunksTweens:184            tween.update(dt)185            if not tween.alive:186                tween.reverse()187        # Keys188        if self.__parserState == DialogRenderer.STATE_PARSING:189            self.__tree = parse(self.__text, Text)190            self.__parserState = DialogRenderer.STATE_BUILDING191        elif self.__parserState == DialogRenderer.STATE_BUILDING:192            self.buildLines(self.__tree)193            self.__characterTimer = Timer(None, DialogRenderer.LETTER_DURATION, self.characterTimerCb)194            self.__parserState = DialogRenderer.STATE_READY195        elif self.__parserState == DialogRenderer.STATE_READY:196            self.__characterTimer.update(dt)197            for event in events:198                if event.type == pygame.KEYDOWN:199                    if (event.key == pygame.K_RETURN):200                        if self.hasReachedEndOfPage():201                            self.__currentPageOffset += self.__linesMax202                            self.__currentlyDrawingLine = self.__currentPageOffset203                            if self.__currentPageOffset > len(self.__lines):204                                self.__alive = False205                                self.__endCb(0)206                        else:207                            # TODO Disallow this if we're drawing slow text208                            for line in range(self.__currentlyDrawingLine, self.__currentPageOffset + self.__linesMax):209                                if line >= len(self.__lines):210                                    break211                                self.__linesCharactersIndex[line] = len(self.__lines[line])212    def hasReachedEndOfPage(self):213        return (self.__currentlyDrawingLine == self.__currentPageOffset + self.__linesMax) or (not self.__characterTimer.alive)214    def characterTimerCb(self, tag):215        if self.__currentlyDrawingLine == self.__currentPageOffset + self.__linesMax:216            # Wait for user to press action to continue drawing lines217            self.__characterTimer.restart()218            return219        if self.__linesCharactersIndex[self.__currentlyDrawingLine] + 1 > len(self.__lines[self.__currentlyDrawingLine]):220            self.__currentlyDrawingLine += 1221        try:222            self.__linesCharactersIndex[self.__currentlyDrawingLine] += 1223        except IndexError:224            # Reached the end of the text225            return226        self.__characterTimer.restart()227    def draw(self):228        if not self.__alive:229            return230        # Draw frame231        self.__frame.draw()232        if self.__parserState != DialogRenderer.STATE_READY:233            return234        # Draw text235        xOffset = 0236        yOffset = 0237        lastXOffset = 0238        lastYOffset = 0239        lineIndex = self.__currentPageOffset240        for line in self.__lines[self.__currentPageOffset:self.__currentPageOffset + self.__linesMax]:241            if len(line) == 0:242                continue243            for chunk in line[:self.__linesCharactersIndex[lineIndex]]:244                cx = self.__boundaries[0] + Frame.PADDING + xOffset + chunk.animationXOffset.value245                cy = self.__boundaries[1] + Frame.PADDING + yOffset + DialogRenderer.Y_OFFSET + chunk.yOffset + chunk.animationYOffset.value246                self.__window.blit(chunk.surface, (cx, cy))247                if self.stateEnabled(chunk.state, "Strike"):248                    pygame.draw.rect(self.__window, DialogRenderer.DEFAULT_TEXT_COLOR, (cx - 4, cy + 2 + chunk.surface.get_height() / 2, chunk.surface.get_width() + 4, 2))  # TODO Put right text color here249                xOffset += chunk.surface.get_width()250                lastXOffset = xOffset if chunk.char != " " else lastXOffset251            lastYOffset = yOffset252            yOffset += DialogRenderer.LINE_HEIGHT253            xOffset = 0254            lineIndex += 1255        # Draw the caret256        if self.hasReachedEndOfPage():...dialogrenderer_old.py
Source:dialogrenderer_old.py  
1import random2import re3from typing import Tuple, Callable4import pygame5import pypeg26from pygame.surface import Surface7from pypeg2 import contiguous, attr, parse, word, maybe_some8from engine.graphics.fontmanager import FontManager9from engine.graphics.frame import Frame10from engine.graphics.textures import Textures11from engine.timer import Timer12from engine.tween.easing import Easing13from engine.tween.tween import Tween14from engine.tween.tweensubject import TweenSubject15class Text(pypeg2.List):16    pass17class BoldText(pypeg2.List):18    grammar = "<b>", attr("text", Text), "</b>"19class UnderlineText(pypeg2.List):20    grammar = "<u>", attr("text", Text), "</u>"21class ShakingText(pypeg2.List):22    grammar = "<shaking>", attr("text", Text), "</shaking>"23class StrikeText(pypeg2.List):24    grammar = "<strike>", attr("text", Text), "</strike>"25class ItalicText(pypeg2.List):26    grammar = "<i>", attr("text", Text), "</i>"27class WavingText(pypeg2.List):28    grammar = "<waving>", attr("text", Text), "</waving>"29class SmallText(pypeg2.List):30    grammar = "<small>", attr("text", Text), "</small>"31class BigText(pypeg2.List):32    grammar = "<big>", attr("text", Text), "</big>"33class SlowText(pypeg2.List):34    grammar = "<slow>", attr("text", Text), "</slow>"35class FastText(pypeg2.List):36    grammar = "<fast>", attr("text", Text), "</fast>"37class ColoredText(pypeg2.List):38    grammar = "<color ", pypeg2.Symbol, ">", attr("text", Text), "</color>"39# Ugh not this again40Text.grammar = attr("text", contiguous(maybe_some([SlowText, FastText, SmallText, BigText, ColoredText, WavingText, StrikeText, ShakingText, ItalicText, BoldText, UnderlineText,41                                                   re.compile(r"[^<>]")])))42class TextChunk:43    def __init__(self):44        self.text = ""45        self.surface = None46        self.state = {}47        self.yOffset = 0  # used to compensate the big and small text size48        self.animationXOffset = TweenSubject(0)  # used to animate letters49        self.animationYOffset = TweenSubject(0)50class DialogRenderer:51    # TODO Add choices here52    # TODO In order : more rich text rendering, "scrolling", letter by letter rendering53    # TODO Add sound54    STATE_PARSING = 055    STATE_CHUNKING = 156    STATE_WRAPPING = 257    STATE_READY = 358    LINE_HEIGHT = 4059    DEFAULT_TEXT_COLOR = (0, 0, 0, 0)60    FONT = "Dialog"61    Y_OFFSET = -462    CARET_TIMER_DURATION = 10063    SHAKING_TIMER_DURATION = 2064    WAVING_TIMER_DURATION = 60065    WAVING_X_AMPLITUDE = 366    WAVING_Y_AMPLITUDE = 867    WAVING_OFFSET = 15  # ms offset between each letter68    def __init__(self, window : Surface, frame : Frame, text : str, endCallback : Callable):69        self.__boundaries = frame.rect70        self.__text = text71        self.__endCb = endCallback72        self.__window = window73        self.__caretTexture = Textures.getTexture("gui.caret")74        self.__caretStep = 0  # the current step in the caret texture75        self.__caretTimer = Timer("caret", DialogRenderer.CARET_TIMER_DURATION, self.caretTimerCb)76        self.__shakingTimer = Timer("shaking", DialogRenderer.SHAKING_TIMER_DURATION, self.shakingTimerCb)77        self.__regularFont = FontManager.getFont(DialogRenderer.FONT + "Regular")78        self.__smallFont = FontManager.getFont(DialogRenderer.FONT + "Small")79        self.__bigFont = FontManager.getFont(DialogRenderer.FONT + "Big")80        self.__font = self.__regularFont81        self.__linesMax = int((self.__boundaries[3] - Frame.PADDING * 2) / (self.__font.size("H")[1]))82        self.__frame = frame83        self.__state = DialogRenderer.STATE_PARSING84        self.__states = {}85        self.__stateChanged = True86        self.__textChunks = []  # list of TextChunk instances87        self.__wrappedTextChunks = [[]]88        self.__currentLine = 089        self.__alive = True90        self.__shakingChunks = []91        self.__wavingChunksTweens = []92    def shakingTimerCb(self, tag):93        for chunk in self.__shakingChunks:94            chunk.animationXOffset.value = random.randint(-1, 1)95            chunk.animationYOffset.value = random.randint(-1, 1)96        self.__shakingTimer.restart()97    def setFontProperties(self, state):98        if self.stateEnabled(state, "Big"):99            self.__font = self.__bigFont100        elif self.stateEnabled(state, "Small"):101            self.__font = self.__smallFont102        else:103            self.__font = self.__regularFont104        self.__font.set_italic(self.stateEnabled(state, "Italic"))105        self.__font.set_underline(self.stateEnabled(state, "Underline"))106        self.__font.set_bold(self.stateEnabled(state, "Bold"))107    def createNewChunk(self, chunk, text):108        newChunk = TextChunk()109        newChunk.text = text110        newChunk.state = chunk.state111        newChunk.yOffset = chunk.yOffset112        newChunk.animationXOffset = TweenSubject(chunk.animationXOffset.value)113        newChunk.animationYOffset = TweenSubject(chunk.animationYOffset.value)114        newChunk.surface = self.__font.render(newChunk.text, True, DialogRenderer.DEFAULT_TEXT_COLOR)115        return newChunk116    def createNewChunks(self, chunk, text):117        if self.stateEnabled(chunk.state, "Shaking"):118            list = []119            for letter in text:120                newChunk = self.createNewChunk(chunk, letter)121                self.__shakingChunks.append(newChunk)122                list.append(newChunk)123            return list124        elif self.stateEnabled(chunk.state, "Waving"):125            list = []126            letterIndex = 0127            for letter in text:128                newChunk = self.createNewChunk(chunk, letter)129                newChunk.animationXOffset.value = -DialogRenderer.WAVING_X_AMPLITUDE130                newChunk.animationYOffset.value = -DialogRenderer.WAVING_Y_AMPLITUDE131                xtween = Tween(None, newChunk.animationXOffset, DialogRenderer.WAVING_X_AMPLITUDE, DialogRenderer.WAVING_TIMER_DURATION, Easing.easingInOutSine, None)132                xtween.runningSince = xtween.duration/2  # fast forward half the time to offset X and Y animations133                ytween = Tween(None, newChunk.animationYOffset, DialogRenderer.WAVING_Y_AMPLITUDE, DialogRenderer.WAVING_TIMER_DURATION, Easing.easingInOutSine, None)134                xtween.runningSince += DialogRenderer.WAVING_OFFSET * letterIndex135                ytween.runningSince += DialogRenderer.WAVING_OFFSET * letterIndex136                self.__wavingChunksTweens.append(xtween)137                self.__wavingChunksTweens.append(ytween)138                list.append(newChunk)139                letterIndex += 1140            return list141        else:142            return [self.createNewChunk(chunk, text)]143    def wordWrap(self):144        xOffset = 0145        for chunk in self.__textChunks:146            self.setFontProperties(chunk.state)147            text = ""148            words = chunk.text.split(" ")149            for word in words:150                word = word + " "151                wordLength = self.__font.size(word)[0]152                isCarriageReturn = word[0:1] == "\n"153                isPageBreak = word[0:1] == "\t"154                if (wordLength + xOffset <= self.__boundaries[2] - Frame.PADDING * 2) and not (isCarriageReturn or isPageBreak):155                    text += word156                    xOffset += wordLength157                else:158                    if not (isCarriageReturn or isPageBreak):159                        text = text[:-1]160                        if text != "":161                            newChunk = self.createNewChunks(chunk, text)162                            self.__wrappedTextChunks[-1].extend(newChunk)163                    if not isPageBreak:164                        self.__wrappedTextChunks.append([])165                    else:166                        for x in range(0, (self.__linesMax - len(self.__wrappedTextChunks) % self.__linesMax) + 1):167                            self.__wrappedTextChunks.append([])168                    if not (isCarriageReturn or isPageBreak):169                        text = word170                        xOffset = wordLength171                    else:172                        text = ""173                        xOffset = 0174            text = text[:-1]175            if text != "":176                newChunk = self.createNewChunks(chunk, text)177                self.__wrappedTextChunks[-1].extend(newChunk)178    def stateEnabled(self, state, name):179        return name in state and state[name]180    def buildChunks(self, thing):181        for text in thing.text:182            textType = type(text)183            if textType == str:184                if self.__stateChanged:185                    chunk = TextChunk()186                    chunk.state = {**self.__states}187                    if self.stateEnabled(chunk.state, "Small"):188                        chunk.yOffset = 10189                    elif self.stateEnabled(chunk.state, "Big"):190                        chunk.yOffset = -5191                    self.__textChunks.append(chunk)192                    self.__stateChanged = False193                self.__textChunks[-1].text += text194            else:195                typeStr = textType.__name__[:-4]196                self.__stateChanged = True197                self.__states[typeStr] = True198                self.buildChunks(text.text)199                self.__stateChanged = True200                self.__states[typeStr] = False201    def caretTimerCb(self, tag):202        self.__caretStep = (self.__caretStep + 1) % 4203        self.__caretTimer.restart()204    def update(self, dt, events):205        if not self.__alive:206            return207        self.__caretTimer.update(dt)208        self.__shakingTimer.update(dt)209        for tween in self.__wavingChunksTweens:210            tween.update(dt)211            if not tween.alive:212                tween.reverse()213        # Keys214        if self.__state == DialogRenderer.STATE_PARSING:215            self.__tree = parse(self.__text, Text)216            self.__state = DialogRenderer.STATE_CHUNKING217        elif self.__state == DialogRenderer.STATE_CHUNKING:218            self.buildChunks(self.__tree)219            self.__state = DialogRenderer.STATE_WRAPPING220        elif self.__state == DialogRenderer.STATE_WRAPPING:221            self.wordWrap()222            self.__state = DialogRenderer.STATE_READY223        elif self.__state == DialogRenderer.STATE_READY:224            for event in events:225                if event.type == pygame.KEYDOWN:226                    if event.key == pygame.K_RETURN:227                        self.__currentLine += self.__linesMax228                        if self.__currentLine > len(self.__wrappedTextChunks):229                            self.__alive = False230                            self.__endCb(0)231    def draw(self):232        if not self.__alive:233            return234        # Draw frame235        self.__frame.draw()236        if self.__state != DialogRenderer.STATE_READY:237            return238        # Draw text239        yOffset = 0240        xOffset = 0241        lastYOffset = 0242        lastXOffset = 0243        for line in self.__wrappedTextChunks[self.__currentLine:self.__currentLine+self.__linesMax]:244            for chunk in line:245                cx = self.__boundaries[0] + Frame.PADDING + xOffset + chunk.animationXOffset.value246                cy = self.__boundaries[1] + Frame.PADDING + yOffset + DialogRenderer.Y_OFFSET + chunk.yOffset + chunk.animationYOffset.value247                self.__window.blit(chunk.surface, (cx, cy))248                if self.stateEnabled(chunk.state, "Strike"):249                    pygame.draw.rect(self.__window, DialogRenderer.DEFAULT_TEXT_COLOR, (cx - 4, cy + 2 + chunk.surface.get_height()/2, chunk.surface.get_width() + 4, 2))  # TODO Put right text color here250                xOffset += chunk.surface.get_width()251            lastYOffset = yOffset252            lastXOffset = lastXOffset if xOffset == 0 else xOffset253            yOffset += DialogRenderer.LINE_HEIGHT254            xOffset = 0255        # Draw the caret...widget.py
Source:widget.py  
1import pygame2def btn_pos(offs, row, col, size):3    x = 15 + col * (size[0] + 12)4    y = offs + 5 + row * (size[1] + 5)5    return (x, y)6class Text (object):7    font = None8    def __init__(self, label):9        if self.font is None:10            # can only do this once pygame.font.init() has been called11            self.__class__.font = pygame.font.SysFont('notomono', 20)12        self.color = (0, 0, 0)13        self.label = label14    def _redraw(self):15        self.text = self.font.render(self.label, True, self.color)16    def set_color(self, color):17        self.color = color18        self._redraw()19    def set_text(self, label):20        self.label = label21        self._redraw()22class Label (Text):23    def __init__(self, label, pos, size=None):24        super().__init__(label)25        self.ena = True26        self.size = size27        self.set_text(label)28        self.rect = pygame.Rect(pos, self.size)29    def _redraw(self):30        text = self.font.render(self.label, True, self.color if self.ena else (100, 100, 100))31        if self.size is None:32            self.size = text.get_size()33        self.lbl = pygame.Surface(self.size)34        self.lbl.fill((200, 200, 200))35        dx = max(0, (self.lbl.get_width() - text.get_width()) // 2)36        dy = max(0, (self.lbl.get_height() - text.get_height()) // 2)37        self.lbl.blit(text, (dx, dy))38    def draw(self, surface):39        return surface.blit(self.lbl, self.rect)40    def press(self, pos):41        return False42    def depress(self, pos):43        return False44    def track(self, pos):45        return False46    def enable(self, ena=True):47        if self.ena != ena:48            self.ena = ena49            self._redraw()50class PushButton (Text):51    StateEnabled = 052    StateArmed = 153    StateDisabled = 254    def __init__(self, label, on_click, pos, size=None):55        super().__init__(label)56        self.on_click = on_click57        self.state = self.StateEnabled58        self.size = size59        self._redraw()60        self.rect = pygame.Rect(pos, self.size)61    def _redraw(self):62        color= [(0, 0, 0), (255, 255, 255), (100, 100, 100)][self.state]63        text = self.font.render(self.label, True, color)64        if self.size is None:65            self.size = text.get_size()66            self.size = (self.size[0] + 4, self.size[1] + 4)67        size = self.size68        self.btn = pygame.Surface(size)69        self.btn.fill((200, 200, 200))70        dx = (self.btn.get_width() - text.get_width()) // 271        dy = (self.btn.get_height() - text.get_height()) // 272        if self.state != self.StateDisabled:73            ghost = self.font.render(self.label, True, (255 - color[0], 255 - color[1], 255 - color[2]))74            self.btn.blit(ghost, (dx+1, dy+1))75            self.btn.blit(text, (dx-1, dy-1))76        else:77            self.btn.blit(text, (dx, dy))78        if self.state == self.StateEnabled:79            pygame.draw.lines(self.btn, (50, 50, 50), False, [(size[0]-1, 1), (size[0]-1, size[1]-1), (1, size[1] - 1)], 3)80            pygame.draw.lines(self.btn, (255, 255, 255), False, [(size[0]-1, 1), (1, 1), (1, size[1] - 1)], 3)81        if self.state == self.StateArmed:82            pygame.draw.lines(self.btn, (50, 50, 50), False, [(size[0]-1, 1), (1, 1), (1, size[1] - 1)], 3)83            pygame.draw.lines(self.btn, (255, 255, 255), False, [(size[0]-1, 1), (size[0]-1, size[1]-1), (1, size[1] - 1)], 3)84    def draw(self, surface):85        return surface.blit(self.btn, self.rect)86    def press(self, pos):87        if self.state == self.StateEnabled and self.rect.collidepoint(pos):88            self.state = self.StateArmed89            self._redraw()90            return True91        return False92    def depress(self, pos):93        if self.state == self.StateArmed:94            self.state = self.StateEnabled95            self._redraw()96            if self.on_click and self.rect.collidepoint(pos):97                self.on_click(self)98            return True99        return False100    def track(self, pos):101        return False102    def enable(self, ena=True):103        self.state = self.StateEnabled if ena else self.StateDisabled104        self._redraw()105class Combobox (Label):106    StateDefault = 0107    StateArmed = 1108    StateArmedPost = 2109    def __init__(self, current, values, on_update, pos, size):110        self.index = values.index(current)111        self.values = values112        self.armed_state = self.StateDefault113        self.on_update = on_update114        super().__init__(f">{current}<", pos, size)115        self.armed_rect = pygame.Rect(self.rect.topleft,  (self.rect.width, self.font.get_linesize() * len(values)))116    def is_armed(self):117        return self.ena and self.armed_state == self.StateArmed118    def _redraw_armed(self):119        self.sel = pygame.Surface(self.armed_rect.size)120        self.sel.fill((200, 200, 200))121        h = self.font.get_linesize()122        w = self.armed_rect.width123        for i, v in enumerate(self.values):124            rect = pygame.Rect((0, i * h), (w, h))125            if i == self.armed_index:126                self.sel.fill((100, 100, 100), rect)127                text = self.font.render(f">{v}<", True, (255, 255, 255))128            else:129                text = self.font.render(v, True, (0, 0, 0))130            dx = max(0, (w - text.get_width()) // 2)131            dy = max(0, (h - text.get_height()) // 2)132            self.sel.blit(text, (dx, dy + i * h))133    def draw(self, surface):134        if self.is_armed():135            return surface.blit(self.sel, self.armed_rect)136        surface.blit(self.lbl, self.rect)137        if self.armed_state == self.StateArmedPost:138            self.armed_state = self.StateDefault139            return self.armed_rect140        return self.rect141    def armed_cancel(self):142        if self.armed_state == self.StateArmed:143            self.armed_state = self.StateArmedPost144            self.set_text(f">{self.values[self.index]}<")145    def press(self, pos):146        if self.ena and self.armed_state == self.StateDefault and self.rect.collidepoint(pos):147            self.armed_state = self.StateArmed148            self.armed_index = self.index149            self._redraw_armed()150            return True151        return False152    def depress(self, pos):153        if self.is_armed():154            if self.armed_rect.collidepoint(pos):155                self.index = self.armed_index156                if self.on_update:157                    self.on_update(self)158            self.armed_cancel()159            return True160        return False161    def track(self, pos):162        if self.is_armed():163            if self.armed_rect.collidepoint(pos):164                self.armed_index = min(len(self.values) - 1, (pos[1] - self.armed_rect.top) // self.font.get_linesize())165                self._redraw_armed()166            else:167                self.armed_cancel()168            return True169        return False170class Setting (object):171    def __init__(self, label, on_update, current, settings, pos, btn_offs, btn_size):172        self.btns = []173        self.btns.append(PushButton(f"{label} +", lambda b: self.setting_next(), btn_pos(btn_offs, pos[0]+0, pos[1], btn_size), btn_size))174        self.btns.append(PushButton(f"{label} -", lambda b: self.setting_prev(), btn_pos(btn_offs, pos[0]+2, pos[1], btn_size), btn_size))175        self.lbl = Label(current, btn_pos(btn_offs, pos[0]+1, pos[1], btn_size), btn_size)176        self.settings = settings177        self.index = self.settings.index(current)178        self.idx = self.index179        self.on_update = on_update180        self.update(False)181    def update(self, notify=True):182        self.btns[0].enable(self.index < (len(self.settings) - 1))183        self.btns[1].enable(self.index > 0)184        self.lbl.set_text(self.settings[self.index])185        if notify and self.on_update:186            self.on_update(self)187    def setting_next(self):188        self.index = min(self.index + 1, len(self.settings) - 1)189        self.update()190    def setting_prev(self):191        self.index = max(self.index - 1, 0)192        self.update()193    def setting_reset(self):194        self.index = self.idx195        self.update()196    def draw(self, surface):197        for btn in self.btns:198            btn.draw(surface)199        self.lbl.draw(surface)200        return self.rect()201    def press(self, pos):202        u = False203        for btn in self.btns:204            u |= btn.press(pos)205        return u206    def depress(self, pos):207        u = False208        for btn in self.btns:209            u |= btn.depress(pos)210        return u211    def track(self, pos):212        u = False213        for btn in self.btns:214            u |= btn.track(pos)215        return u216    def enable(self, ena=True):217        for btn in self.btns:218            btn.enable(ena)219        self.lbl.enable(ena)220    def rect(self):...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
