def __init__(self, batch, groups, on_click, on_enter, on_motion, on_search): # create document self.document = FormattedDocument(' ') self.document.set_style( 0, 1, dict(font_name=FONT_NAME, font_size=FONT_SIZE, color=FONT_COLOR)) # calculate font height and margin font = self.document.get_font(0) self.font_height = font.ascent - font.descent self.margin = self.font_height * TEXT_INPUT_MARGIN # create text input self.input = IncrementalTextLayout(self.document, 100, self.font_height, batch=batch, group=groups[1]) self.input.x = 100 self.input.y = 100 # creating a caret and push it to window handlers self.caret = Caret(self.input, FONT_COLOR[:3], on_click, on_enter, on_motion, on_search) self.clear_text() # create background rectangle self.rect = Rectangle(0, 0, 100, self.font_height + 2 * self.margin, color=TEXT_INPUT_COLOR, batch=batch, group=groups[0])
def on_activate(self): super().on_activate() if not self.document: self.document = FormattedDocument(text=self.license_text) self.document.set_style( 0, len(self.document.text), { 'font_name': 'Arial', 'font_size': get_bottom_bar_height(self.screen_resolution) // 5, 'bold': False, 'italic': False, 'color': (*WHITE_RGB, self.opacity), 'align': 'center' }) if not self.license_layout: self.license_layout = IncrementalTextLayout( document=self.document, width=self.viewport.x2 - self.viewport.x1, height=self.viewport.y2 - self.viewport.y1, multiline=True, batch=BATCHES['ui_batch'], group=GROUPS['button_text']) self.license_layout.x, self.license_layout.y = self.viewport.x1, self.viewport.y1
class TextInput: """Text input field""" def __init__(self, batch, groups, on_click, on_enter, on_motion, on_search): # create document self.document = FormattedDocument(' ') self.document.set_style( 0, 1, dict(font_name=FONT_NAME, font_size=FONT_SIZE, color=FONT_COLOR)) # calculate font height and margin font = self.document.get_font(0) self.font_height = font.ascent - font.descent self.margin = self.font_height * TEXT_INPUT_MARGIN # create text input self.input = IncrementalTextLayout(self.document, 100, self.font_height, batch=batch, group=groups[1]) self.input.x = 100 self.input.y = 100 # creating a caret and push it to window handlers self.caret = Caret(self.input, FONT_COLOR[:3], on_click, on_enter, on_motion, on_search) self.clear_text() # create background rectangle self.rect = Rectangle(0, 0, 100, self.font_height + 2 * self.margin, color=TEXT_INPUT_COLOR, batch=batch, group=groups[0]) def resize(self, x, y, w): """Resize the text input with given coordinates and width""" self.rect.x = x self.rect.y = y self.rect.width = w self.input.x = x + self.margin self.input.y = y + self.margin self.input.width = w - 2 * self.margin def get_text(self): """Return currently displayed text""" return self.document.text def set_text(self, text): """Set the text to display""" self.document.text = text def clear_text(self): """Clear displayed text""" self.document.text = ''
def _create_text(self): assert self.window is not None self.text_batch = Batch() self.text_document = FormattedDocument() layout = TextLayout(self.text_document, self.window.width, self.window.height, multiline=True, wrap_lines=True, batch=self.text_batch) layout.content_valign = 'bottom'
def init_bar(self, weapons): try: if self.ammolayout._document: self.ammolayout.delete() for tri in self.tris: tri.remove() except AttributeError: pass ammotext = '\t'.join(str(w.ammo) for key, w in weapons.iteritems() if key != 'w0') self.ammos = ammotext.split('\t') self.ammodoc = FormattedDocument(ammotext) self.ammodoc.set_style(0, len(ammotext), dict(color=[255]*4, tab_stops=[120*(i+1) for i in range(6)], font_size=24, align='center', wrap=False)) self.ammolayout = IncrementalTextLayout(self.ammodoc, width=600, height=50, batch=self.batch, multiline=True) self.ammolayout.x = (1280 / 2) * self.scale.x self.ammolayout.y = 20 * self.scale.y self.ammolayout.anchor_x = 'center' self.ammolayout.anchor_y = 'bottom' w = self.ammolayout.content_width colorlist = [weaponcolors[key] for key in weapons if key != 'w0'] self.tris = [Triangle(640*self.scale.x-w/2-52+120*i, 35*self.scale.y, 50, 50, col, self.batch, 0, 0) for i, col in enumerate(colorlist)]
def __init__(self, pos, width, height, window, batch, line_space=None, font_size=24, hcolor=(25, 25, 25), scl=unity): super(KeysFrame, self).__init__() self.scale = scl self.pos = vec2(*pos) * scl self.target_pos = pos self.window = window self.line_space = (line_space + font_size) * self.scale.x self.font_size = font_size * self.scale.x self.width = width * self.scale.x self.height = height * self.scale.y self.hcolor = hcolor self.doc = Doc('\n') self.layout = Layout(self.doc, width=self.width, height=self.height, multiline=True, batch=batch) self.doc.set_paragraph_style(0, 0, dict(indent=None, line_spacing=self.line_space, font_size=self.font_size)) self.layout.anchor_x = 'left' self.layout.anchor_y = 'top' self.layout.x = self.pos[0] self.layout.y = self.pos[1] self.even = 0 self.active_i = [] self.curr_line = None self.active_line = None @self.window.event def on_mouse_scroll(x, y, scroll_x, scroll_y): self.layout.view_y = scroll_y * self.layout.content_height self.handler = on_mouse_scroll
def __init__(self, width: int, height: int = 0, multiline: bool = False, dpi: object = None, batch: Batch = None, group: Group = None, wrap_lines: bool = True, x: int = 0, y: int = 0, underlined: bool = True, caret_color: tuple = (0, 0, 0), numbers_only: bool = False, font_name=None, font_size=None, font_color=(255, 255, 255, 2555), max_chars=0) -> None: self.document = FormattedDocument() self.layout = IncrementalTextLayout(self.document, width, height, multiline, dpi, batch, group, wrap_lines) self.numbers_only = numbers_only self.style['color'] = font_color self.max_chars = max_chars if font_name: self.style['font_name'] = font_name if font_size: self.style['font_size'] = font_size self.reset_style() if not height: # If the dev didn't specify a height, make the height equal to the height of the font font = pyglet.font.load( font_name or self.document.get_style('font'), font_size or self.document.get_style('font_size')) self.height = font.ascent - font.descent self._hover_cursor = self.get_window().CURSOR_TEXT super().__init__(self.layout, color=caret_color) # TODO: Allow the dev to specify how x and y are treated self.x = x - self.width // 2 self.y = y - self.height // 2 if underlined: self.underline = Rectangle( x=self.x, y=self.y, width=self.width, height=1, )
def __init__(self, caption: str, position: Vector2 = Vector2.zero, size: Vector2 = Vector2.one, document_style=None, font_name: str = 'DisposableDroid BB', font_size: int = 20, color: (int, int, int, int) = ColorHelper.WHITE, hover_color: (int, int, int, int) = ColorHelper.TRANSPARENT): super().__init__(position, size) document_style = {} if document_style is None else document_style document_style.update(dict(font_name=font_name, font_size=font_size)) self._caption = caption self._document = FormattedDocument(caption) self.update_document_style(document_style) self._text_layout = TextLayout(self._document, width=size.x, height=size.y, batch=self.batch, group=OrderedGroup(self.group.order + 1.1), wrap_lines=True, multiline=True) self._text_layout.content_valign = 'center' self.position = position self.color = color self._set_background_color(hover_color) self._set_background_color(self._background_color)
def __init__(self, a, b, batch, scale): super(ScoreBoard, self).__init__() self.ascore, self.aname = a self.bscore, self.bname = b self.adoc = FormattedDocument('\t'.join((self.aname, str(self.ascore)))) self.bdoc = FormattedDocument('\t'.join((str(self.bscore), self.bname))) scsize = 100 nmsize = 32 self.scale = scale self.alayout = ScrollableTextLayout(self.adoc, width=400, height=300, batch=batch, multiline=True) w = 400 - len(str(self.ascore)) * scsize * 72 / 96 self.adoc.set_style(0, len(self.adoc.text), dict(wrap=False, color=[255]*4, align='left', tab_stops=[w])) self.adoc.set_style(0, len(self.aname), dict(font_size=nmsize)) a = len(self.aname)+1 self.adoc.set_style(a, a + len(str(self.ascore)), dict(font_size=scsize, baseline=-scsize / 4)) self.alayout.x = (1280 / 2) * self.scale.x self.alayout.y = (720 / 2) * self.scale.y + 50 self.alayout.anchor_x = 'right' self.alayout.anchor_y = 'center' self.blayout = ScrollableTextLayout(self.bdoc, width=400, height=300, batch=batch, multiline=True) w = 400 - len(str(self.bname)) * nmsize * 72 / 96 self.bdoc.set_style(0, len(self.bdoc.text), dict(wrap=False, color=[255]*4, align='right', tab_stops=[w])) self.bdoc.set_style(0, len(str(self.bscore)), dict(font_size=scsize, baseline=-scsize / 4)) a = len(str(self.bscore))+1 self.bdoc.set_style(a, a + len(self.bname), dict(font_size=nmsize)) self.blayout.x = 1280 / 2 self.blayout.y = 720 / 2 + 50 self.blayout.anchor_x = 'left' self.blayout.anchor_y = 'center'
class Editor(Layer): def __init__(self): super(Editor, self).__init__() self.doc = FormattedDocument('<b>testing</b> testing testing') self.doc.set_style(0, 1000, {'font_name': 'ProggySquareTT'}) self.itlo = IncrementalTextLayout(self.doc, 1024, 750, multiline=True, batch=self.batch) self.itlo.x = 0 self.itlo.y = 750 caret = Caret(self.itlo) caret.visible = True caret.color = (100, 255, 0) director.window.push_handlers(caret) def draw(self): pyglet.gl.glClearColor(1, 1, 1, 1) self.batch.draw()
def __init__(self, text, textlst, pos, window, batch, line_space=None, font_size=24, hcolor=(25, 25, 25), scl=unity): super(PopMenu, self).__init__() self.scale = scl self.pos = vec2(*pos) * scl self.target_pos = pos self.window = window self.line_space = (line_space + font_size) * self.scale.x self.font_size = font_size * self.scale.x self.hcolor = hcolor #initial text self.idoc = pyglet.text.document.UnformattedDocument(text, ) self.idoc.set_style(0, len(text), dict(font_size=self.font_size, color=[255]*4)) self.ilayout = pyglet.text.layout.TextLayout(self.idoc, batch=batch, group=CustomGroup(-1)) self.ilayout.anchor_x, self.ilayout.anchor_y = ('left', 'center') self.ilayout.x, self.ilayout.y = self.pos #other text in popmenu, is inserted later self.doc = Doc('\n') self.doc.set_paragraph_style(0, 0, dict(indent=None, line_spacing=self.line_space, font_size=self.font_size)) self.lwidth = max(len(txt) * self.font_size*72./96 for txt in textlst) tempf = self.idoc.get_font(0) self.lheight = tempf.size+tempf.ascent-tempf.descent self.textlst = textlst self.layout = Layout(self.doc, width=self.lwidth, height=self.lheight*len(textlst)+1, multiline=True, batch=batch) self.layout.anchor_x, self.layout.anchor_y = 'left', 'top' self.layout.x = self.pos[0]-self.lwidth/2+self.ilayout.content_width/2 self.layout.y = self.pos[1] self.even = 0 self.active_i = [] self.curr_line = None self.active_line = None self.active = False self.hlighted = False @self.window.event def on_mouse_scroll(x, y, scroll_x, scroll_y): self.layout.view_y = scroll_y * self.layout.content_height self.handler = on_mouse_scroll
def __init__(self, padding=0): super(MessageQueue, self).__init__() self.font = gui.config.get('control_panel', 'MSG_QUEUE_FONT') self.titleLabelText = gui.config.get('control_panel_strings', 'MSG_QUEUE_TITLE') bgColorStr = gui.config.get('control_panel', 'MSG_QUEUE_BG_COLOR') self.bgColor = list(map(int, tuple(bgColorStr.split(',')))) self.titleLabel = None self.textLayout = None self.dt = 0 self.halfSecs = 0 self.bgRect = None self.border = None self.padding = padding self.currentPos = 0 self.numMsgs = 0 self.doc = FormattedDocument() self.msgs = list()
class UIText(UIBase): def __init__(self, caption: str, position: Vector2 = Vector2.zero, size: Vector2 = Vector2.one, document_style=None, font_name: str = 'DisposableDroid BB', font_size: int = 20, color: (int, int, int, int) = ColorHelper.WHITE, hover_color: (int, int, int, int) = ColorHelper.TRANSPARENT): super().__init__(position, size) document_style = {} if document_style is None else document_style document_style.update(dict(font_name=font_name, font_size=font_size)) self._caption = caption self._document = FormattedDocument(caption) self.update_document_style(document_style) self._text_layout = TextLayout(self._document, width=size.x, height=size.y, batch=self.batch, group=OrderedGroup(self.group.order + 1.1), wrap_lines=True, multiline=True) self._text_layout.content_valign = 'center' self.position = position self.color = color self._set_background_color(hover_color) self._set_background_color(self._background_color) def set_text(self, text: str): self.my_label.text = text self.size.y = self.my_label.content_height self.my_label.height = self.my_label.content_height @property def caption(self) -> str: return self._caption @caption.setter def caption(self, value: str): self._caption = value self._document.text = value @UIBase.batch.setter def batch(self, value: Batch): UIBase.batch.fset(self, value) self._text_layout.batch = value @UIBase.group.setter def group(self, value: OrderedGroup): UIBase.group.fset(self, value) self._update_text_layout_groups(value) @UIBase.position.setter def position(self, value: Vector2): UIBase.position.fset(self, value) self._text_layout.x = value.x self._text_layout.y = value.y @UIBase.size.setter def size(self, value: Vector2): UIBase.size.fset(self, value) self._text_layout.width = value.x self._text_layout.height = value.y @UIBase.color.setter def color(self, value: (int, int, int, int)): UIBase.color.fset(self, value[:3]) self._background_color = value self.opacity = value[3] def _set_background_color(self, color: (int, int, int, int)): UIBase.color.fset(self, color[:3]) self.opacity = color[3] def update_document_style(self, style: dict): if style is not None: self._document.set_style(0, len(self._caption), style) def _update_text_layout_groups(self, group: OrderedGroup): self._text_layout.begin_update() self._text_layout._init_groups(OrderedGroup(group.order + 1)) self._text_layout.end_update() def update_logic(self, **kwargs): super().update_logic()
class MessageQueue(Widget): MSG_DELETE_FREQ = 0.5 # in seconds def __init__(self, padding=0): super(MessageQueue, self).__init__() self.font = gui.config.get('control_panel', 'MSG_QUEUE_FONT') self.titleLabelText = gui.config.get('control_panel_strings', 'MSG_QUEUE_TITLE') bgColorStr = gui.config.get('control_panel', 'MSG_QUEUE_BG_COLOR') self.bgColor = list(map(int, tuple(bgColorStr.split(',')))) self.titleLabel = None self.textLayout = None self.dt = 0 self.halfSecs = 0 self.bgRect = None self.border = None self.padding = padding self.currentPos = 0 self.numMsgs = 0 self.doc = FormattedDocument() self.msgs = list() def reset(self): self.doc.text = "" self.msgs = list() def delete(self): if self.textLayout is not None: self.textLayout.delete() if self.titleLabel is not None: self.titleLabel.delete() self.titleLabel = None if self.bgRect is not None: self.bgRect.delete() self.bgRect = None if self.border is not None: self.border.delete() self.border = None def size(self, frame): super(MessageQueue, self).size(frame) self.width = frame.width or 200 self.height = 200 if self.textLayout is None: self.textLayout = TextLayout(self.doc, width=self.width, batch=self.parentFrame.batch, group=fgGroup, multiline=True) self.parentFrame.setNeedsLayout() else: self.textLayout.width = self.width if self.titleLabel is None: self.titleLabel = Label(self.titleLabelText, x=self.x + 10, y=self.y + 10, batch=self.parentFrame.batch, group=fgGroup, color=(0, 0, 0, 255), font_name=self.font, font_size=14) else: self.titleLabel.x = self.x + 10 self.titleLabel.y = self.y + 10 def layout(self, x, y): super(MessageQueue, self).layout(x, y) self.textLayout.x = self.x + self.padding self.textLayout.y = self.y - self.padding self.textLayout.width = self.width self.textLayout.height = self.height self.titleLabel.x = self.x + 10 self.titleLabel.y = self.y + 10 self.createBackground() def createBackground(self): if self.bgRect is not None: self.bgRect.delete() self.bgRect = None if self.border is not None: self.border.delete() self.border = None self.bgRect = createRect(self.x, self.y, self.width, self.height, self.bgColor, self.parentFrame.batch, mgGroup) self.border = createRect(self.x, self.y + self.height, self.width, 2, (0, 0, 0, 255), self.parentFrame.batch, highlightGroup) def deleteMsg(self, item): self.msgs.remove(item) self.doc.delete_text(item.index, item.index + len(item)) for msg in self.msgs: if msg.num > item.num: msg.num -= 1 msg.index -= len(item) def addMessage(self, message): if len(self.msgs) and message == self.msgs[0].string: return message += '\n' item = Message(message, self.halfSecs) self.doc.set_style(0, len(self.doc.text), { 'font_name': self.font, 'bold': False }) for msg in self.msgs: msg.num += 1 msg.index += len(item) self.msgs.insert(0, item) self.doc.insert_text(0, message, { 'font_name': self.font, 'bold': True }) if self.textLayout is not None: while (self.textLayout.content_height >= self.height - self.titleLabel.content_height + 14): item = self.msgs[len(self.msgs) - 1] self.deleteMsg(item) def update(self, dt): self.dt += dt if self.dt >= self.MSG_DELETE_FREQ: # expired messages are collected on 0.5 sec freq self.halfSecs += 1 self.dt %= self.MSG_DELETE_FREQ toRemove = [] for item in self.msgs: if item.isExpired(self.halfSecs): toRemove.append(item) if len(toRemove): for item in toRemove: self.deleteMsg(item)
class WeaponBar(object): """docstring for WeaponBar""" def __init__(self, batch, scale): super(WeaponBar, self).__init__() self.batch = batch self.weapons = {} self.ammos = [] self.tris = [] self.scale = scale def __len__(self): return len(self.weapons) def init_bar(self, weapons): try: if self.ammolayout._document: self.ammolayout.delete() for tri in self.tris: tri.remove() except AttributeError: pass ammotext = '\t'.join(str(w.ammo) for key, w in weapons.iteritems() if key != 'w0') self.ammos = ammotext.split('\t') self.ammodoc = FormattedDocument(ammotext) self.ammodoc.set_style(0, len(ammotext), dict(color=[255]*4, tab_stops=[120*(i+1) for i in range(6)], font_size=24, align='center', wrap=False)) self.ammolayout = IncrementalTextLayout(self.ammodoc, width=600, height=50, batch=self.batch, multiline=True) self.ammolayout.x = (1280 / 2) * self.scale.x self.ammolayout.y = 20 * self.scale.y self.ammolayout.anchor_x = 'center' self.ammolayout.anchor_y = 'bottom' w = self.ammolayout.content_width colorlist = [weaponcolors[key] for key in weapons if key != 'w0'] self.tris = [Triangle(640*self.scale.x-w/2-52+120*i, 35*self.scale.y, 50, 50, col, self.batch, 0, 0) for i, col in enumerate(colorlist)] def update(self, weapons): if len(weapons) != len(self.weapons): self.init_bar(weapons) self.weapons = weapons.copy() else: ammotext = '\t'.join(str(w.ammo) for key, w in weapons.iteritems() if key != 'w0') ammos = ammotext.split('\t') self.ammolayout.begin_update() for i, a in enumerate(ammos): if a != self.ammos[i]: ln = sum(len(self.ammos[j]) for j in range(i)) + i self.ammodoc.delete_text(ln, ln + len(self.ammos[i])) self.ammodoc.insert_text(ln, a) self.ammolayout.end_update() self.ammos = ammos def remove(self): try: self.weapons = {} self.ammolayout.delete() for tri in self.tris: tri.remove() except AttributeError: pass
def __init__(self, batch, window): super(Hud, self).__init__() self.text_ = 'This is the warmup phase' self.hp_t = '-1' self.armor_t = '-1' self.text_active = 5 self.killmsg_active = False self.chat_active = False self.batch = batch self.scale = vec2(window.width / 1280., window.height / 720.) self.hp = Label(self.hp_t, font_name=font, font_size=36, bold=True, x=80, y=10, anchor_x='center', anchor_y='bottom', batch=self.batch) self.armor = Label(self.armor_t, font_name=font, font_size=36, x=240, y=10, anchor_x='center', anchor_y='bottom', bold=True, batch=self.batch) self.text = Label(self.text_, font_name=font, font_size=36, x=640, y=360, anchor_x='center', anchor_y='center', batch=self.batch) self.weapon = Label('melee', font_name=font, font_size=32, x=1160, y=80, anchor_x='center', anchor_y='bottom', color=(0, 255, 255, 255), batch=self.batch) self.ammo = Label('1', font_name=font, font_size=36, x=1160, y=10, anchor_x='center', anchor_y='bottom', bold=True, batch=self.batch) self.time = Label('0:00', font_name=font, font_size=36, x=640, y=680, anchor_x='center', anchor_y='center', bold=True, batch=self.batch) self.chatdoc = FormattedDocument('\n' * 11) #self.chatlog = document .FormattedDocument('\n') self.chat = ScrollableTextLayout(self.chatdoc, width=500, height=208, multiline=True, batch=self.batch) self.chat.x = 130 self.chat.y = 130 self.chat.content_valign = 'bottom' self.killdoc = FormattedDocument('\n') self.killmsg = ScrollableTextLayout(self.killdoc, width=300, height=104, multiline=True, batch=self.batch) self.killmsg.x = 20 self.killmsg.y = 600 self.scoredoc = FormattedDocument('0 : 0') self.score = ScrollableTextLayout(self.scoredoc, width=150, height=104, multiline=True, batch=self.batch) self.score.x = 1270 self.score.y = 650 self.score.anchor_x = 'right' self.score.anchor_y = 'center' self.normal_hpcol = (255, 255, 255, 255) self.low_hpcol = (255, 128, 0, 255) self.high_hpcol = (0, 204, 255, 255) self.bname = '_' self.aname = '_' self.gametime = 70 self.weaponcolors = {proto.melee: (0, 255, 255, 255), proto.explBlaster: (255, 255, 0, 255)} self.killmsg_count = 0 self.scoreboard = None self.weaponbar = WeaponBar(self.batch, self.scale) self.do_scale()
class PopMenu(object): """docstring for PopMenu""" def __init__(self, text, textlst, pos, window, batch, line_space=None, font_size=24, hcolor=(25, 25, 25), scl=unity): super(PopMenu, self).__init__() self.scale = scl self.pos = vec2(*pos) * scl self.target_pos = pos self.window = window self.line_space = (line_space + font_size) * self.scale.x self.font_size = font_size * self.scale.x self.hcolor = hcolor #initial text self.idoc = pyglet.text.document.UnformattedDocument(text, ) self.idoc.set_style(0, len(text), dict(font_size=self.font_size, color=[255]*4)) self.ilayout = pyglet.text.layout.TextLayout(self.idoc, batch=batch, group=CustomGroup(-1)) self.ilayout.anchor_x, self.ilayout.anchor_y = ('left', 'center') self.ilayout.x, self.ilayout.y = self.pos #other text in popmenu, is inserted later self.doc = Doc('\n') self.doc.set_paragraph_style(0, 0, dict(indent=None, line_spacing=self.line_space, font_size=self.font_size)) self.lwidth = max(len(txt) * self.font_size*72./96 for txt in textlst) tempf = self.idoc.get_font(0) self.lheight = tempf.size+tempf.ascent-tempf.descent self.textlst = textlst self.layout = Layout(self.doc, width=self.lwidth, height=self.lheight*len(textlst)+1, multiline=True, batch=batch) self.layout.anchor_x, self.layout.anchor_y = 'left', 'top' self.layout.x = self.pos[0]-self.lwidth/2+self.ilayout.content_width/2 self.layout.y = self.pos[1] self.even = 0 self.active_i = [] self.curr_line = None self.active_line = None self.active = False self.hlighted = False @self.window.event def on_mouse_scroll(x, y, scroll_x, scroll_y): self.layout.view_y = scroll_y * self.layout.content_height self.handler = on_mouse_scroll def remove_handler(self): self.window.remove_handler('on_mouse_scroll', self.handler) def insert(self, text): self.even += 1 iseven = self.even % 2 text += ' ' * 60 self.doc.insert_text(len(self.doc.text), text + '\n', dict(font_size=self.font_size, color=[255] * 4, background_color=[50 * iseven] * 3 + [255])) ln = len(self.doc.text) - 3 self.doc.set_paragraph_style(ln, ln, dict(indent=None, wrap=False, line_spacing=self.line_space)) def over_button(self, x, y): self.mpos = (x, y) if not self.active: return (0 < x - self.pos.x < self.ilayout.content_width and 0 < y - self.pos.y + self.ilayout.content_height / 2 < self.ilayout.content_height) else: return (0 < x - self.layout.x < self.layout.width and 0 < self.layout.y - y < self.layout.height) def highlight(self): if not self.active: if not self.hlighted: self.idoc.set_style(0, len(self.idoc.text), dict(background_color=[25]*3+[255])) self.hlighted = True else: y = self.layout.y - self.mpos[1] - self.layout.view_y lines = self.doc.text.split('\n') num = int(float(y) / self.line_space - 0.18) try: if not self.active_line: ind = self.doc.text.find(lines[num]) if (ind, num) not in self.active_i: self.curr_line = (ind, num) self.restore() self.doc.set_paragraph_style(ind, ind, dict( background_color= self.hcolor + (255,))) self.active_i.append((ind, num)) except (IndexError, ValueError): self.restore() def restore(self): if not self.active: if self.hlighted: self.idoc.set_style(0, len(self.idoc.text), dict(background_color=[0]*3+[255])) self.hlighted = False if len(self.active_i) > 0: for a in self.active_i: ind, num = a if not a == self.active_line: self.doc.set_paragraph_style(ind, ind, dict( background_color= [50 * (num % 2)] * 3 + [255])) self.active_i = [] if (ind, num) == self.curr_line: self.curr_line = None def activate(self): if not self.active: self.active = True self.layout.begin_update() for txt in self.textlst: self.insert(txt) self.layout.end_update() return False else: if self.curr_line[0] != 0: lines = self.doc.text.split('\n') self.idoc.text = lines[self.curr_line[1]].strip() npos = self.pos[0]-self.lwidth/2 + self.ilayout.content_width/2 self.layout.x = npos self.active = False self.doc.delete_text(1, len(self.doc.text)) self.even = 0 return self.idoc.text def deactivate(self): self.active = False self.doc.delete_text(1, len(self.doc.text)) self.even = 0
class EventLoopFixture(InteractiveFixture): question = '\n\n(P)ass/(F)ail/(S)kip/(Q)uit?' key_pass = key.P key_fail = key.F key_skip = key.S key_quit = key.Q clear_color = 1, 1, 1, 1 base_options = { 'width': 300, 'height': 300, } def __init__(self, request, peng): super(EventLoopFixture, self).__init__(request) self._request = request self.window = None self.text_batch = None self.text_document = None self.answer = None self.peng = peng request.addfinalizer(self.tear_down) def tear_down(self): if self.window: self.window.close() self.window = None def create_window(self, **kwargs): combined_kwargs = {} combined_kwargs.update(self.base_options) combined_kwargs.update(kwargs) #self.window = Window(**combined_kwargs) self.window = self.peng.createWindow(**combined_kwargs) self.window.push_handlers(self) return self.window def create_menu(self, menu="menu"): m = TestMenu(self, menu, self.peng.window, self.peng) self.window.addMenu(m) self.window.changeMenu(menu) return m def get_document(self): if self.text_document is None: self._create_text() return self.text_document def _create_text(self): assert self.window is not None self.text_batch = Batch() self.text_document = FormattedDocument() layout = TextLayout(self.text_document, self.window.width, self.window.height, multiline=True, wrap_lines=True, batch=self.text_batch) layout.content_valign = 'bottom' def add_text(self, text): self.get_document() self.text_document.insert_text(len(self.text_document.text), text) self.window._legacy_invalid = True def ask_question(self, description=None, screenshot=True): """Ask a question inside the test window. By default takes a screenshot and validates that too.""" if self.window is None: self.create_window() self.add_text('\n\n') if description: self.add_text(description) self.add_text(self.question) self.answer = None caught_exception = None try: if self.interactive: self.run_event_loop() self.handle_answer() else: self.run_event_loop(0.1) except Exception as ex: import traceback traceback.print_exc() caught_exception = ex finally: if screenshot: try: screenshot_name = self._take_screenshot(self.window) if caught_exception is None and not self.interactive: self._check_screenshot(screenshot_name) except: if not caught_exception: raise if caught_exception: raise caught_exception def handle_answer(self): if self.answer is None: raise Exception('Did not receive valid input in question window') elif self.answer == self.key_fail: # TODO: Ask input pytest.fail('Tester marked test failed') elif self.answer == self.key_skip: pytest.skip('Tester marked test skipped') elif self.answer == self.key_quit: pytest.exit('Tester requested to quit') def ask_question_no_window(self, description=None): """Ask a question to verify the current test result. Uses the console or an external gui as no window is available.""" super(EventLoopFixture, self).ask_question(description) def run_event_loop(self, duration=None): if duration: clock.schedule_once(self.interrupt_event_loop, duration) pyglet.app.run() def interrupt_event_loop(self, *args, **kwargs): pyglet.app.exit() @staticmethod def schedule_once(callback, dt=.1): clock.schedule_once(callback, dt) def on_draw(self): self.clear() self.draw_text() def clear(self): gl.glClearColor(*self.clear_color) self.window.clear() def draw_text(self): if self.text_batch is not None: self.text_batch.draw() def on_key_press(self, symbol, modifiers): if symbol in (self.key_pass, self.key_fail, self.key_skip, self.key_quit): self.answer = symbol self.interrupt_event_loop() # Prevent handling of Escape to close the window return True
class KeysFrame(object): """docstring for KeysFrame""" def __init__(self, pos, width, height, window, batch, line_space=None, font_size=24, hcolor=(25, 25, 25), scl=unity): super(KeysFrame, self).__init__() self.scale = scl self.pos = vec2(*pos) * scl self.target_pos = pos self.window = window self.line_space = (line_space + font_size) * self.scale.x self.font_size = font_size * self.scale.x self.width = width * self.scale.x self.height = height * self.scale.y self.hcolor = hcolor self.doc = Doc('\n') self.layout = Layout(self.doc, width=self.width, height=self.height, multiline=True, batch=batch) self.doc.set_paragraph_style(0, 0, dict(indent=None, line_spacing=self.line_space, font_size=self.font_size)) self.layout.anchor_x = 'left' self.layout.anchor_y = 'top' self.layout.x = self.pos[0] self.layout.y = self.pos[1] self.even = 0 self.active_i = [] self.curr_line = None self.active_line = None @self.window.event def on_mouse_scroll(x, y, scroll_x, scroll_y): self.layout.view_y = scroll_y * self.layout.content_height self.handler = on_mouse_scroll def remove_handler(self): self.window.remove_handler('on_mouse_scroll', self.handler) def insert(self, action, key): self.even += 1 iseven = self.even % 2 action = dict(weaponsdict.items() + inputdict.items())[action] text = action + '\t' + key #i have no clue how to calculate the width properly length = pyglet.text.Label(key, font_size=self.font_size) length = length.content_width stop = self.width - length text += ' ' * 6 self.doc.insert_text(len(self.doc.text), text + '\n', dict(font_size=self.font_size, color=[255] * 4, background_color=[50 * iseven] * 3 + [255])) ln = len(self.doc.text) - 3 self.doc.set_paragraph_style(ln, ln, dict(tab_stops=[stop], indent=None, line_spacing=self.line_space, wrap=False)) def in_box(self, mpos): x, y = mpos self.mpos = mpos return (0 < x - self.layout.x < self.layout.width and 0 < self.layout.y - y < self.layout.height) def over_button(self, x, y): self.mpos = (x, y) return (0 < x - self.layout.x < self.layout.width and 0 < self.layout.y - y < self.layout.height) def highlight(self): y = self.layout.y - self.mpos[1] - self.layout.view_y lines = self.doc.text.split('\n') num = int(float(y) / self.line_space - 0.18) try: if not self.active_line: action, key = lines[num].split('\t') ind = self.doc.text.find(action) + 1 if (ind, num) not in self.active_i: self.curr_line = (ind, num) self.restore() self.doc.set_paragraph_style(ind, ind, dict( background_color= self.hcolor + (255,))) self.active_i.append((ind, num)) except (IndexError, ValueError): self.restore() def restore(self): if len(self.active_i) > 0: for a in self.active_i: ind, num = a if not a == self.active_line: self.doc.set_paragraph_style(ind, ind, dict( background_color= [50 * (num % 2)] * 3 + [255])) self.active_i = [] if (ind, num) == self.curr_line: self.curr_line = None def activate(self): if not self.curr_line: return self.active_line = self.curr_line ind, num = self.active_line self.doc.set_paragraph_style(ind, ind, dict(background_color= (255, 128, 0) + (255,))) def deactivate(self): self.active_line = None self.restore() def get_action(self): ind, num = self.active_line action, key = self.doc.text.split('\n')[num].split('\t') self.layout.delete() return action def update(self): pass
class MessageQueue(Widget): MSG_DELETE_FREQ = 0.5 # in seconds def __init__(self, padding=0): super(MessageQueue, self).__init__() self.font = gui.config.get('control_panel', 'MSG_QUEUE_FONT') self.titleLabelText = gui.config.get('control_panel_strings', 'MSG_QUEUE_TITLE') bgColorStr = gui.config.get('control_panel', 'MSG_QUEUE_BG_COLOR') self.bgColor = list(map(int, tuple(bgColorStr.split(',')))) self.titleLabel = None self.textLayout = None self.dt = 0 self.halfSecs = 0 self.bgRect = None self.border = None self.padding = padding self.currentPos = 0 self.numMsgs = 0 self.doc = FormattedDocument() self.msgs = list() def reset(self): self.doc.text = "" self.msgs = list() def delete(self): if self.textLayout is not None: self.textLayout.delete() if self.titleLabel is not None: self.titleLabel.delete() self.titleLabel = None if self.bgRect is not None: self.bgRect.delete() self.bgRect = None if self.border is not None: self.border.delete() self.border = None def size(self, frame): super(MessageQueue, self).size(frame) self.width = frame.width or 200 self.height = 200 if self.textLayout is None: self.textLayout = TextLayout(self.doc, width=self.width, batch=self.parentFrame.batch, group=fgGroup, multiline=True) self.parentFrame.setNeedsLayout() else: self.textLayout.width = self.width if self.titleLabel is None: self.titleLabel = Label(self.titleLabelText, x=self.x + 10, y=self.y + 10, batch=self.parentFrame.batch, group=fgGroup, color=(0, 0, 0, 255), font_name=self.font, font_size=14) else: self.titleLabel.x = self.x + 10 self.titleLabel.y = self.y + 10 def layout(self, x, y): super(MessageQueue, self).layout(x, y) self.textLayout.x = self.x + self.padding self.textLayout.y = self.y - self.padding self.textLayout.width = self.width self.textLayout.height = self.height self.titleLabel.x = self.x + 10 self.titleLabel.y = self.y + 10 self.createBackground() def createBackground(self): if self.bgRect is not None: self.bgRect.delete() self.bgRect = None if self.border is not None: self.border.delete() self.border = None self.bgRect = createRect(self.x, self.y, self.width, self.height, self.bgColor, self.parentFrame.batch, mgGroup) self.border = createRect(self.x, self.y + self.height, self.width, 2, (0, 0, 0, 255), self.parentFrame.batch, highlightGroup) def deleteMsg(self, item): self.msgs.remove(item) self.doc.delete_text(item.index, item.index + len(item)) for msg in self.msgs: if msg.num > item.num: msg.num -= 1 msg.index -= len(item) def addMessage(self, message): if len(self.msgs) and message == self.msgs[0].string: return message += '\n' item = Message(message, self.halfSecs) self.doc.set_style(0, len(self.doc.text), {'font_name': self.font, 'bold': False}) for msg in self.msgs: msg.num += 1 msg.index += len(item) self.msgs.insert(0, item) self.doc.insert_text(0, message, {'font_name': self.font, 'bold': True}) if self.textLayout is not None: while (self.textLayout.content_height >= self.height - self.titleLabel.content_height + 14): item = self.msgs[len(self.msgs) - 1] self.deleteMsg(item) def update(self, dt): self.dt += dt if self.dt >= self.MSG_DELETE_FREQ: # expired messages are collected on 0.5 sec freq self.halfSecs += 1 self.dt %= self.MSG_DELETE_FREQ toRemove = [] for item in self.msgs: if item.isExpired(self.halfSecs): toRemove.append(item) if len(toRemove): for item in toRemove: self.deleteMsg(item)
class TextBox(Focusable, Caret, Hoverable): underline: Rectangle = None _on_enter: Callable = None ignore_enter: bool = False style: dict = {} def __init__(self, width: int, height: int = 0, multiline: bool = False, dpi: object = None, batch: Batch = None, group: Group = None, wrap_lines: bool = True, x: int = 0, y: int = 0, underlined: bool = True, caret_color: tuple = (0, 0, 0), numbers_only: bool = False, font_name=None, font_size=None, font_color=(255, 255, 255, 2555), max_chars=0) -> None: self.document = FormattedDocument() self.layout = IncrementalTextLayout(self.document, width, height, multiline, dpi, batch, group, wrap_lines) self.numbers_only = numbers_only self.style['color'] = font_color self.max_chars = max_chars if font_name: self.style['font_name'] = font_name if font_size: self.style['font_size'] = font_size self.reset_style() if not height: # If the dev didn't specify a height, make the height equal to the height of the font font = pyglet.font.load( font_name or self.document.get_style('font'), font_size or self.document.get_style('font_size')) self.height = font.ascent - font.descent self._hover_cursor = self.get_window().CURSOR_TEXT super().__init__(self.layout, color=caret_color) # TODO: Allow the dev to specify how x and y are treated self.x = x - self.width // 2 self.y = y - self.height // 2 if underlined: self.underline = Rectangle( x=self.x, y=self.y, width=self.width, height=1, ) def reset_style(self): self.document.set_style(0, len(self.document.text), self.style) @property def x(self): return self.layout.x @x.setter def x(self, value): if self.underline: self.underline.x = value self.layout.x = value @property def y(self): return self.layout.y @y.setter def y(self, value): print(value) if self.underline: self.underline.y = value self.layout.y = value @property def width(self): return self.layout.width @width.setter def width(self, value): if self.underline: self.underline.width = value self.layout.width = value @property def height(self): return self.layout.height @height.setter def height(self, value): print(value) self.layout.height = value def draw(self): if self.focused: self.on_activate() else: self.on_deactivate() self.layout.draw() if self.underline: self.underline.draw() def on_text(self, text: str): # Only type inside when the user is focused on the textbox # print(text) if not self.focused: return if ord(text) == 13: if self.ignore_enter: # Enter self.ignore_enter = False return else: return self.on_enter() # if self.max_chars and len(self.value) >= self.max_chars: # return # if self.numbers_only and not text.isnumeric(): # return res = super().on_text(text) print('res', res, 'text', text) self.reset_style() return res def _on_enter_base(self) -> None: """ The event handler that will be called by default if none are defined """ pass @property def value(self): return self.document.text @value.setter def value(self, val): self.document.text = val self.reset_style() @property def on_enter(self): if self._on_enter: return self._on_enter return self._on_enter_base @on_enter.setter def on_enter(self, func): def new_on_enter(): if self.focused: func() self._on_enter = new_on_enter
class Hud(object): """docstring for Hud""" def __init__(self, batch, window): super(Hud, self).__init__() self.text_ = 'This is the warmup phase' self.hp_t = '-1' self.armor_t = '-1' self.text_active = 5 self.killmsg_active = False self.chat_active = False self.batch = batch self.scale = vec2(window.width / 1280., window.height / 720.) self.hp = Label(self.hp_t, font_name=font, font_size=36, bold=True, x=80, y=10, anchor_x='center', anchor_y='bottom', batch=self.batch) self.armor = Label(self.armor_t, font_name=font, font_size=36, x=240, y=10, anchor_x='center', anchor_y='bottom', bold=True, batch=self.batch) self.text = Label(self.text_, font_name=font, font_size=36, x=640, y=360, anchor_x='center', anchor_y='center', batch=self.batch) self.weapon = Label('melee', font_name=font, font_size=32, x=1160, y=80, anchor_x='center', anchor_y='bottom', color=(0, 255, 255, 255), batch=self.batch) self.ammo = Label('1', font_name=font, font_size=36, x=1160, y=10, anchor_x='center', anchor_y='bottom', bold=True, batch=self.batch) self.time = Label('0:00', font_name=font, font_size=36, x=640, y=680, anchor_x='center', anchor_y='center', bold=True, batch=self.batch) self.chatdoc = FormattedDocument('\n' * 11) #self.chatlog = document .FormattedDocument('\n') self.chat = ScrollableTextLayout(self.chatdoc, width=500, height=208, multiline=True, batch=self.batch) self.chat.x = 130 self.chat.y = 130 self.chat.content_valign = 'bottom' self.killdoc = FormattedDocument('\n') self.killmsg = ScrollableTextLayout(self.killdoc, width=300, height=104, multiline=True, batch=self.batch) self.killmsg.x = 20 self.killmsg.y = 600 self.scoredoc = FormattedDocument('0 : 0') self.score = ScrollableTextLayout(self.scoredoc, width=150, height=104, multiline=True, batch=self.batch) self.score.x = 1270 self.score.y = 650 self.score.anchor_x = 'right' self.score.anchor_y = 'center' self.normal_hpcol = (255, 255, 255, 255) self.low_hpcol = (255, 128, 0, 255) self.high_hpcol = (0, 204, 255, 255) self.bname = '_' self.aname = '_' self.gametime = 70 self.weaponcolors = {proto.melee: (0, 255, 255, 255), proto.explBlaster: (255, 255, 0, 255)} self.killmsg_count = 0 self.scoreboard = None self.weaponbar = WeaponBar(self.batch, self.scale) self.do_scale() def do_scale(self): for item in (self.armor, self.hp, self.text, self.chat, self.killmsg, self.time, self.ammo, self.weapon, self.score): item.x *= self.scale.x item.y *= self.scale.y def init_player(self, players): if len(players) == 0: self.set_score(0, 0) else: self.bname = players.values()[0].name self.set_score(0, 0) self.init_pers_hud() def init_pers_hud(self): if self.hp._vertex_lists: self.weaponbar.batch = self.batch self.weapon.batch = self.batch self.ammo.batch = self.batch self.hp.batch = self.batch self.armor.begin_update() self.armor.batch = self.batch self.armor.end_update() def init_spec(self): self.weaponbar.remove() self.weapon.delete() self.ammo.delete() self.hp.delete() self.armor.delete() def draw(self): self.active_batch.draw() def update(self, dt): if self.text_active: self.text_active -= dt if self.text_active <= 0: self.text_active = False self.text.delete() if self.killmsg_active: self.killmsg_active -= dt if self.killmsg_active <= 0: self.killmsg_count -= 1 start = self.killdoc.get_paragraph_start(1) end = self.killdoc.get_paragraph_end(1) self.killdoc.delete_text(start, end) if self.killmsg_count > 0: self.killmsg_active = 4 else: self.killmsg_active = False self.killmsg.delete() if self.chat_active: self.chat_active -= dt if self.chat_active <= 0: self.chat_active = False self.chat.delete() self.time.text = self.calc_time(self.gametime) def update_prop(self, armor=False, hp=False, text=False, weapon=False, ammo=False, time=False, name=False, msg=False, chat=None): if armor: if armor != self.armor.text: self.armor.text = armor if int(armor) <= 20: self.armor.color = self.low_hpcol elif int(armor) > 100: self.armor.color = self.high_hpcol else: self.armor.color = self.normal_hpcol if hp: if hp != self.hp.text: self.hp.text = hp if int(hp) <= 20: self.hp.color = self.low_hpcol elif int(hp) > 100: self.hp.color = self.high_hpcol else: self.hp.color = self.normal_hpcol if text: if not self.text_active: self.text.begin_update() self.text.text = text self.text_active = 3 self.text.batch = self.batch self.text.end_update() else: self.text.text = text self.text_active = 3 if weapon: if weapon != self.weapon.text: self.weapon.text = weapon wkey = [key for key, val in allstrings.iteritems() if val == weapon][0] self.weapon.color = weaponcolors[wkey] + [255] if ammo: ammo, weapons = ammo if ammo != self.ammo.text: self.ammo.text = ammo self.weaponbar.update(weapons) if isinstance(time, float): self.gametime = time if name: a, name = name if a: self.aname = name else: self.bname = name #self.score.text = '0:0 ' + self.bname if chat: name, color, msg = chat self.chat.begin_update() #self.chat.text = chat self.chatdoc.insert_text(len(self.chatdoc.text), name, dict(color=list(color) + [255], bold=True)) self.chatdoc.insert_text(len(self.chatdoc.text), '\t' + msg + '\n', dict(color=[255] * 4, bold=False)) start = self.chatdoc.get_paragraph_start(0) end = self.chatdoc.get_paragraph_end(0) self.chatdoc.delete_text(start, end) """self.chatlog.insert_text(len(self.chatlog.text), name, dict(color=list(color) + [255], bold=True)) self.chatlog.insert_text(len(self.chatlog.text), '\t' + msg + '\n', dict(color=[255] * 4, bold=False))""" self.chat.batch = self.batch self.chat.view_y = -self.chat.content_height self.chat.end_update() self.chat_active = 4 def set_score(self, a, b, msg=False, scoreboard=False): self.score.begin_update() self.scoredoc.delete_text(0, len(self.scoredoc.text)) self.scoredoc.insert_text(0, ''.join((str(a), ' ', self.aname, '\n', str(b), ' ', self.bname)), dict(color=[255] * 4)) apos = self.scoredoc.get_paragraph_start(1) bpos = self.scoredoc.get_paragraph_start(len(self.scoredoc.text) - 1) self.scoredoc.set_style(apos, apos+len(str(a)), dict(font_size=24, baseline=-6)) self.scoredoc.set_style(bpos, bpos+len(str(b)), dict(font_size=24, baseline=-6)) self.score.end_update() self.score.width = self.score.content_width + 40 if msg: w, killer, killed = msg if w == 11: w = 4 if w == 12: w = 5 wcol = weaponcolors['w' + str(w-1)] self.killmsg.begin_update() self.killdoc.insert_text(len(self.killdoc.text), killer, dict(color=[255] * 4)) self.killdoc.insert_text(len(self.killdoc.text), ' fragged', dict(color=wcol + [255])) self.killdoc.insert_text(len(self.killdoc.text), ' '.join(('', killed, '\n')), dict(color=[255] * 4)) self.killmsg.batch = self.batch if not self.killmsg_active: self.killmsg_active = 4 self.killmsg_count += 1 self.killmsg.end_update() if scoreboard: if not self.scoreboard: self.scoreboard = ScoreBoard((a, self.aname), (b, self.bname), self.batch, self.scale) else: if not self.scoreboard is None: self.scoreboard.delete() self.scoreboard = None def calc_time(self, gametime): mins = '{:01.0f}'.format(gametime // 60) secs = '{:02.0f}'.format(gametime % 60) return ''.join((mins, ':', secs))
class LicensePageV2(UIObject, ABC): def __init__(self, logger, parent_viewport): super().__init__(logger, parent_viewport) self.license_text = '' self.document = None self.license_layout = None @final def on_activate(self): super().on_activate() if not self.document: self.document = FormattedDocument(text=self.license_text) self.document.set_style( 0, len(self.document.text), { 'font_name': 'Arial', 'font_size': get_bottom_bar_height(self.screen_resolution) // 5, 'bold': False, 'italic': False, 'color': (*WHITE_RGB, self.opacity), 'align': 'center' }) if not self.license_layout: self.license_layout = IncrementalTextLayout( document=self.document, width=self.viewport.x2 - self.viewport.x1, height=self.viewport.y2 - self.viewport.y1, multiline=True, batch=BATCHES['ui_batch'], group=GROUPS['button_text']) self.license_layout.x, self.license_layout.y = self.viewport.x1, self.viewport.y1 @final @window_size_has_changed def on_window_resize(self, width, height): super().on_window_resize(width, height) self.viewport.x1, self.viewport.x2 = self.parent_viewport.x1, self.parent_viewport.x2 self.viewport.y1 = self.parent_viewport.y1 + get_bottom_bar_height( self.screen_resolution) self.viewport.y2 = self.parent_viewport.y2 if self.is_activated: self.license_layout.x, self.license_layout.y = self.viewport.x1, self.viewport.y1 self.license_layout.width = self.viewport.x2 - self.viewport.x1 self.license_layout.height = self.viewport.y2 - self.viewport.y1 self.document.set_style(0, len(self.document.text), { 'font_size': get_bottom_bar_height(self.screen_resolution) // 5 }) @final @is_active @cursor_is_inside_the_text_box def on_mouse_scroll(self, x, y, scroll_x, scroll_y): self.license_layout.view_y += scroll_y * self.document.get_style( 'font_size') @final def on_update_opacity(self, new_opacity): super().on_update_opacity(new_opacity) if self.opacity <= 0: self.license_layout.delete() self.license_layout = None elif self.document: self.document.set_style(0, len(self.document.text), {'color': (*WHITE_RGB, self.opacity)})