def append_wobbly_star_shape(group: displayio.Group, color): # Make a wobbly star. The returned function wobbles its points a little. wobbly_star_points = [ (8, 50), (33, 0), (58, 50), (0, 20), (66, 20), ] star_center_x = 170 - 25 star_center_y = 120 - 33 wobbly_star_polygon = vectorio.Polygon(points=wobbly_star_points) wobbly_star_shape = vectorio.VectorShape(shape=wobbly_star_polygon, pixel_shader=monochrome(color), x=star_center_x, y=star_center_y) group.append(wobbly_star_shape) def make_star_wobble(): tremble = 4 shake = 3 trembling_points = [(random.randrange(x - tremble, x + tremble), random.randrange(y - tremble, y + tremble)) for x, y in wobbly_star_points] wobbly_star_polygon.points = trembling_points wobbly_star_shape.x = random.randrange(star_center_x - shake, star_center_x + shake) wobbly_star_shape.y = random.randrange(star_center_y - shake, star_center_y + shake) return make_star_wobble
def show_image(path): with open(path, 'rb') as f: bitmap = OnDiskBitmap(f) pixel_shader = ColorConverter() sprite = TileGrid(bitmap, pixel_shader=pixel_shader) group = Group() group.append(sprite) board.DISPLAY.show(group) board.DISPLAY.wait_for_frame()
def build( widget: Label, *, size: float | int, align: align, fit_to: bool | str, ) -> tuple[Group, SizeHint]: assert isinstance(size, int), ( "for now, text size on circuitpython must be an " + f"int, found object of type {type(size).__name__} with value size={size}" ) is_state = isinstance(widget._text, str) LabelType: Type[LabelBase] = BitmapLabel if is_state else GlyphLabel kwargs = {"save_text": False} if is_state else {} # print( # widget, # widget.text, # ) native_label: LabelBase = LabelType( font=FONT, text=fit_to if isinstance(fit_to, str) else widget.text, scale=size, **kwargs, ) native = Group() native.append(native_label) widget._impl_cache_ = (size, align) margin = widget._margin_ # w, h = ( # native_label.bounding_box[2], # native_label.bounding_box[3], # ) # print( # widget, # w / len(widget.text), # (w, h), # ), return ( native, ( int(1.15 * native_label.bounding_box[2] * size) + margin * 2, int(1.15 * native_label.bounding_box[3] * size) + margin * 2, ), )
def append_randart_shape(group: displayio.Group, color): # Make a random polygon to sit on the left side of the screen. # We'll update its points every now and then with the returned function. random_polygon = vectorio.Polygon(points=[(random.randrange(0, 100), random.randrange(0, 240)) for _ in range(40)]) random_shape = vectorio.VectorShape( shape=random_polygon, pixel_shader=monochrome(color), ) group.append(random_shape) def new_randart(): random_polygon.points = [(random.randrange(0, 100), random.randrange(0, 240)) for _ in range(40)] return new_randart
def append_vectorio_shape(group: displayio.Group, color): # Making fonts with vector points is a pain but the memory benefits are pretty nice. # Also you can rotate points for spinny text if you want! v_polygon = vectorio.Polygon(points=[ (0, 0), (10, 0), (18, 24), (26, 0), (36, 0), (22, 34), (10, 34), ]) v_shape = vectorio.VectorShape(shape=v_polygon, pixel_shader=monochrome(color), x=160, y=16) group.append(v_shape)
def showChoice(self, ch_idx, game_no=None, round_no=None, rounds_tot=None, won_sf=None, drew_sf=None, lost_sf=None): """Show player's choice on NeoPixels or display. The display also has game and round info and win/draw summary. This removes all the graphical objects and re-adds them which causes visible flickering during an update - this could be improved by only replacing / updating what needs changing. """ if self.disp is None: self.pix.fill(BLACK) self.pix[self.choiceToPixIdx(ch_idx)] = CHOICE_COL[ch_idx] return self.emptyGroup(self.disp_group) # Would be slightly better to create this Group once and re-use it round_choice_group = Group(max_size=3) if round_no is not None: title_dob = Label(self.font, text="Game {:d} Round {:d}/{:d}".format( game_no, round_no, rounds_tot), scale=2, color=TITLE_TXT_COL_FG) title_dob.x = round( (self.width - len(title_dob.text) * 2 * self.font_width) // 2) title_dob.y = round(self.font_height // 2) round_choice_group.append(title_dob) if won_sf is not None: gamesum_dob = Label(self.font, text="Won {:d} Drew {:d} Lost {:d}".format( won_sf, drew_sf, lost_sf), scale=2, color=TITLE_TXT_COL_FG) gamesum_dob.x = round( (self.width - len(gamesum_dob.text) * 2 * self.font_width) // 2) gamesum_dob.y = round(self.height - 2 * self.font_height // 2) round_choice_group.append(gamesum_dob) s_group = Group(scale=3, max_size=1) s_group.x = 32 s_group.y = (self.height - 3 * self.sprite_size) // 2 s_group.append(self.sprites[ch_idx]) round_choice_group.append(s_group) self.showGroup(round_choice_group)
def append_circle_shape(group: displayio.Group, color): # Make a circle that will revolve around the star while changing size min_circle_radius = 5 max_circle_radius = 20 circle_axis = 170, 120 circle_revolution_radius = 60 circle = vectorio.Circle(radius=max_circle_radius) circle_shape = vectorio.VectorShape(shape=circle, pixel_shader=monochrome(color), x=circle_axis[0], y=circle_axis[1]) group.append(circle_shape) radians_in_circle = 2 * math.pi def revolve_circle(): seconds_per_revolution = 8 revolution_ratio = (time.monotonic() % seconds_per_revolution) / seconds_per_revolution revolution_radians = revolution_ratio * radians_in_circle s = math.sin(revolution_radians) c = math.cos(revolution_radians) x = s * circle_revolution_radius + circle_axis[0] y = c * circle_revolution_radius + circle_axis[1] circle_shape.x = round(x) circle_shape.y = round(y) def resize_circle(): seconds_per_size_cycle = 13 size_ratio = abs( int(time.monotonic() % (2 * seconds_per_size_cycle) / seconds_per_size_cycle) - time.monotonic() % seconds_per_size_cycle / seconds_per_size_cycle) new_radius = min_circle_radius + size_ratio * (max_circle_radius - min_circle_radius) circle.radius = int(new_radius) return revolve_circle, resize_circle
def showChoice(self, ch_idx, game_no=None, round_no=None, rounds_tot=None, won_sf=None, drew_sf=None, lost_sf=None): """TODO DOC""" if self.disp is None: self.pix.fill(BLACK) self.pix[self.choiceToPixIdx(ch_idx)] = CHOICE_COL[ch_idx] return self.emptyGroup(self.disp_group) ### Would be slightly better to create this Group once and re-use it round_choice_group = Group(max_size=3) if round_no is not None: title_dob = Label(self.font, text="Game {:d} Round {:d}/{:d}".format( game_no, round_no, rounds_tot), scale=2, color=TITLE_TXT_COL_FG) title_dob.x = round( (self.width - len(title_dob.text) * 2 * self.font_width) // 2) title_dob.y = round(self.font_height // 2) round_choice_group.append(title_dob) if won_sf is not None: gamesum_dob = Label(self.font, text="Won {:d} Drew {:d} Lost {:d}".format( won_sf, drew_sf, lost_sf), scale=2, color=TITLE_TXT_COL_FG) gamesum_dob.x = round( (self.width - len(gamesum_dob.text) * 2 * self.font_width) // 2) gamesum_dob.y = round(self.height - 2 * self.font_height // 2) round_choice_group.append(gamesum_dob) s_group = Group(scale=3, max_size=1) s_group.x = 32 s_group.y = (self.height - 3 * self.sprite_size) // 2 s_group.append(self.sprites[ch_idx]) round_choice_group.append(s_group) self.showGroup(round_choice_group)
def build( widget: Button, *, radius: int, size: float | int, fit_to_text: bool, ) -> tuple[Native, tuple[int, int]]: """ Creates the native element for the std tg-gui widget based on the _fixed_style_attrs_. Those _fixed_style_attrs_ are passed as kwargs to this function. :param widget: the tg-gui widget instance to build the native for :param **style_attrs: the fixed style attributes that are set at build time :return: a tuple of the native widget and suggested size """ native = Group() label = Label(font=FONT, x=0, y=0, text=widget.text, scale=size) native.append(label) _, _, w, h = label.bounding_box w *= size h = int(1.15 * h * size) r = ( min(radius, w // 2 - 1, h // 2 - 1) if isinstance(radius, int) else min(w // 2, h // 2) - 1 ) padding = round(1.25 * r) widget._impl_cache_ = dict(radius=radius, label_width=w) return ( native, ( w + padding + widget._margin_ * 2, int(h * 1.2) + widget._margin_ * 2, ), )
def introductionScreen(self): # pylint: disable=too-many-locals,too-many-branches,too-many-statements """Introduction screen.""" if self.disp is not None: self.emptyGroup(self.disp_group) intro_group = Group(max_size=7) welcometo_dob = Label(self.font, text="Welcome To", scale=3, color=IWELCOME_COL_FG) welcometo_dob.x = (self.width - 10 * 3 * self.font_width) // 2 # Y pos on screen looks lower than I would expect welcometo_dob.y = 3 * self.font_height // 2 intro_group.append(welcometo_dob) extra_space = 8 spacing = 3 * self.sprite_size + extra_space y_adj = (-6, -2, -2) for idx, sprite in enumerate(self.sprites): s_group = Group(scale=3, max_size=1) s_group.x = -96 s_group.y = round((self.height - 1.5 * self.sprite_size) / 2 + (idx - 1) * spacing) + y_adj[idx] s_group.append(sprite) intro_group.append(s_group) arena_dob = Label(self.font, text="Arena", scale=3, color=IWELCOME_COL_FG) arena_dob.x = (self.width - 5 * 3 * self.font_width) // 2 arena_dob.y = self.height - 3 * self.font_height // 2 intro_group.append(arena_dob) self.showGroup(intro_group) # The color modification here is fragile as it only works # if the text colour is blue, i.e. data is in lsb only self.sample.play("welcome-to") while self.sample.playing(): if self.disp is not None and intro_group[0].color < WELCOME_COL_FG: intro_group[0].color += 0x10 time.sleep(0.120) onscreen_x_pos = 96 # Move each sprite onto the screen while saying its name with wav file anims = (("rock", 10, 1, 0.050), ("paper", 11, 2, 0.050), ("scissors", 7, 3, 0.050)) for idx, (audio_name, x_shift, grp_idx, delay_s) in enumerate(anims): if self.disp is None: self.showChoice(idx) # Use for NeoPixels self.sample.play(audio_name) # Audio needs to be long enough to finish movement while self.sample.playing(): if self.disp is not None: if intro_group[grp_idx].x < onscreen_x_pos: intro_group[grp_idx].x += x_shift time.sleep(delay_s) # Set NeoPixels back to black if self.disp is None: self.pix.fill(BLACK) self.sample.play("arena") while self.sample.playing(): if self.disp is not None and intro_group[4].color < WELCOME_COL_FG: intro_group[4].color += 0x10 time.sleep(0.060) # Button Guide for those with a display if self.disp is not None: left_dob = Label(self.font, text="< Select ", scale=2, color=INFO_COL_FG, background_color=INFO_COL_BG) left_width = len(left_dob.text) * 2 * self.font_width left_dob.x = -left_width left_dob.y = self.button_y_pos intro_group.append(left_dob) right_dob = Label(self.font, text=" Transmit >", scale=2, color=INFO_COL_FG, background_color=INFO_COL_BG) right_width = len(right_dob.text) * 2 * self.font_width right_dob.x = self.width right_dob.y = self.button_y_pos intro_group.append(right_dob) # Move left button text onto screen, then right steps = 20 for x_pos in [ left_dob.x + round(left_width * x / steps) for x in range(1, steps + 1) ]: left_dob.x = x_pos time.sleep(0.06) for x_pos in [ right_dob.x - round(right_width * x / steps) for x in range(1, steps + 1) ]: right_dob.x = x_pos time.sleep(0.06) time.sleep(8) # leave on screen for further 8 seconds
class EventTheme(BaseTheme): """ A Theme for an event countdown date. The theme supports days, hours, and minutes labels at the provided positions on the provided axis, but can easily be extended in the future. Raises: ValueError: Provide either an x or a y axis for the text labels. """ placeholder = "--" formatter = "{:>2}" label_positions = {"days": 0, "hours": 1, "mins": 2} def __init__(self, *args, pos, x_axis=None, y_axis=None, **kwargs): """ Given a series of positions for the time labels and an axis (either an x or a y), create a new theme representing an event countdown. Args: pos (tuple): A tuple of (int, int, int) representing positions for the days, hours, and minutes labels. x_axis (int, optional): The x axis on which to place labels. Either the x_axis or y_axis is optional, but not both. Defaults to None. y_axis (int, optional): The y axis on which to place labels. Either the x_axis or y_axis is optional, but not both. Defaults to None. """ super().__init__(*args, **kwargs) self._create_labels(x_axis, y_axis, *pos) def _create_labels(self, x_axis, y_axis, days_pos, hours_pos, mins_pos): if not (x_axis or y_axis) or (x_axis and y_axis): raise ValueError( "Must provide either an x or y axis for text labels, not both." ) self.display = Group(max_size=3) x_positions = [x_axis] * 3 if x_axis else [days_pos, hours_pos, mins_pos] y_positions = [y_axis] * 3 if y_axis else [days_pos, hours_pos, mins_pos] for x, y in zip(x_positions, y_positions): label = PlaceholderLabel( x, y, placeholder=self.placeholder, font=self.font, color=self.color ) self.display.append(label) def _update_label(self, label, new_value): pos = self.label_positions[label] old_value = self.display[pos].text if new_value != old_value: self.display[pos].text = new_value def update_time(self, days, hours, mins): """ Update the time displayed. Args: days (int): Days hours (int): Hours mins (int): Minutes """ self._update_label("days", self.formatter.format(days)) self._update_label("hours", self.formatter.format(hours)) self._update_label("mins", self.formatter.format(mins)) @property def days(self): return self.display[self.label_positions["days"]].text @property def hours(self): return self.display[self.label_positions["hours"]].text @property def mins(self): return self.display[self.label_positions["mins"]].text
row_spacing = FONT_HEIGHT + 2 rows_group = Group(max_size=rows) ### I have foreground and background colours I can use here ### 1234567890123456789012345678901234567890 ### aa:bb:cc:dd:ee:ff -101 12345678901234567 for idx in range(rows): row_label = Label( font=terminalio.FONT, text="", max_glyphs=40, ### maximum that will fit 240/6 color=0xc0c000) row_label.y = row_y row_y += row_spacing rows_group.append(row_label) summary_label = Label( font=terminalio.FONT, text="", max_glyphs=40, ### maximum that will fit 240/6 color=0x00c0c0) summary_label.y = 220 screen_group = Group(max_size=2) screen_group.append(rows_group) screen_group.append(summary_label) display.show(screen_group) ### was screen_group
text="----.-", scale=FONT_SCALE, color=0x00c0c0) voltage_value_dob.y = 30 voltage_units_dob = Label(font=terminalio.FONT, text="mV", scale=FONT_SCALE, color=0x00c0c0) voltage_units_dob.y = voltage_value_dob.y voltage_units_dob.x = len(voltage_value_dob.text) * FONT_WIDTH * FONT_SCALE ### 9 elements, 4 added immediately, 4 later, 1 spare for on-screen text screen_group = Group(max_size=4 + 4 + 1) if magnetometer is not None: screen_group.append(magnet_value_dob) screen_group.append(magnet_units_dob) screen_group.append(voltage_value_dob) screen_group.append(voltage_units_dob) ### Initialise some displayio objects and append them ### The following four variables are set by these two functions ### voltage_barneg_dob, voltage_sep_dob, voltage_barpos_dob ### magnet_circ_dob voltage_bar_set(0) if magnetometer is not None: magnet_circ_set(0) ### Start-up splash screen display.show(screen_group)
""" CircuitPython simple sensor data display demo using LC709203 battery monitor and TFT display """ import time import board import terminalio from displayio import Group from adafruit_display_text import bitmap_label from adafruit_lc709203f import LC709203F text_area = bitmap_label.Label(terminalio.FONT, scale=2) text_area.anchor_point = (0.5, 0.5) text_area.anchored_position = (board.DISPLAY.width // 2, board.DISPLAY.height // 2) main_group = Group() main_group.append(text_area) print("LC709203F test") print("Make sure LiPoly battery is plugged into the board!") sensor = LC709203F(board.I2C()) print("IC version:", hex(sensor.ic_version)) board.DISPLAY.show(main_group) while True: text_area.text = "Battery:\n{:.1f} Volts \n{}%".format(sensor.cell_voltage, sensor.cell_percent) time.sleep(1)
def showGameResultScreen(self, pla, sco, rounds_tot=None): # pylint: disable=unused-argument,too-many-locals,too-many-statements """Display a high score table with a visual bubble sort slow enough to see the algorithm at work.""" self.fadeUpDown("down") self.emptyGroup(self.disp_group) # Score list group + background + question mark for sorting gs_group = Group(max_size=4) # Pale grey large GAME SCORES background bg_scale = 6 sbg_dob1 = Label(self.font, text="GAME", scale=bg_scale, color=GS_COL) sbg_dob1.x = (self.width - 4 * bg_scale * self.font_width) // 2 sbg_dob1.y = self.height // 4 sbg_dob2 = Label(self.font, text="SCORES", scale=bg_scale, color=GS_COL) sbg_dob2.x = (self.width - 6 * bg_scale * self.font_width) // 2 sbg_dob2.y = self.height // 4 * 3 gs_group.append(sbg_dob1) gs_group.append(sbg_dob2) self.showGroup(gs_group) self.fadeUpDown("up") # Calculate maximum length player name # and see if scores happen to already be in order max_len = 0 prev_score = sco[0] descending = True for idx, (name, _) in enumerate(pla): max_len = max(max_len, len(name)) if sco[idx] > prev_score: descending = False prev_score = sco[idx] fmt = "{:" + str(max_len) + "s} {:2d}" x_pos = (self.width - (max_len + 3) * 2 * self.font_width) // 2 scale = 2 spacing = 4 if len(pla) <= 6 else 0 top_y_pos = round((self.height - len(pla) * scale * self.font_height - (len(pla) - 1) * spacing) / 2 + scale * self.font_height / 2) scores_group = Group(max_size=len(pla)) gs_group.append(scores_group) for idx, (name, _) in enumerate(pla): op_dob = Label( self.font, text=fmt.format(name, sco[idx]), scale=2, color=(PLAYER_NAME_COL_FG if idx == 0 else OPP_NAME_COL_FG)) op_dob.x = x_pos op_dob.y = top_y_pos + idx * (scale * self.font_height + spacing) scores_group.append(op_dob) time.sleep(0.2) # Sort the entries if needed sort_scores = list(sco) # Make an independent local copy if not descending: empty_group = Group() # minor hack to aid swaps in scores_group step = 3 qm_dob = Label(self.font, text="?", scale=2, color=QM_SORT_FG) qm_dob.x = round(x_pos - 1.5 * scale * self.font_width) gs_group.append(qm_dob) while True: swaps = 0 for idx in range(0, len(sort_scores) - 1): above_score = sort_scores[idx] above_y = scores_group[idx].y below_y = scores_group[idx + 1].y qm_dob.y = (above_y + below_y) // 2 if above_score < sort_scores[idx + 1]: qm_dob.text = "<" qm_dob.color = QM_SORTING_FG swaps += 1 # make list of steps range_y = below_y - above_y offsets = list(range(step, range_y + 1, step)) # Ensure this goes to the exact final position if offsets[-1] != range_y: offsets.append(range_y) for offset in offsets: scores_group[idx].y = above_y + offset scores_group[idx + 1].y = below_y - offset time.sleep(0.050) # swap the scores around sort_scores[idx] = sort_scores[idx + 1] sort_scores[idx + 1] = above_score # swap the graphical objects around using empty_group # to avoid ValueError: Layer already in a group old_above_dob = scores_group[idx] old_below_dob = scores_group[idx + 1] scores_group[idx + 1] = empty_group scores_group[idx] = old_below_dob scores_group[idx + 1] = old_above_dob qm_dob.text = "?" qm_dob.color = QM_SORT_FG time.sleep(0.2) else: time.sleep(0.6) if swaps == 0: break # Sort complete if no values were swapped gs_group.remove(qm_dob)
def showPlayerVPlayerScreen(self, me_name, op_name, my_ch_idx, op_ch_idx, result, summary, win, draw, void): # pylint: disable=too-many-locals,too-many-branches,too-many-statements """Display a win, draw, lose or error message.""" self.fadeUpDown("down") self.emptyGroup(self.disp_group) if void: error_tot = 3 error_group = Group(max_size=error_tot + 1) # Opponent's name helps pinpoint the error op_dob = Label(self.font, text=op_name, scale=2, color=OPP_NAME_COL_FG) op_dob.x = 40 op_dob.y = self.font_height error_group.append(op_dob) self.showGroup(error_group) self.fadeUpDown("up", duration=0.4) if result is not None: self.sample.play(result) font_scale = 2 # Attempting to put the three pieces of "Error!" text on screen # synchronised with the sound sample repeating the word for idx in range(error_tot): error_dob = Label(self.font, text="Error!", scale=font_scale, color=ERROR_COL_FG) error_dob.x = 40 error_dob.y = 60 + idx * 60 error_group.append(error_dob) time.sleep(0.5) # Small attempt to synchronise audio with text font_scale += 1 else: # Would be slightly better to create this Group once and re-use it pvp_group = Group(max_size=3) # Add player's name and sprite just off left side of screen # and opponent's just off right player_detail = [[ me_name, self.sprites[my_ch_idx], -16 - 3 * self.sprite_size, PLAYER_NAME_COL_FG, PLAYER_NAME_COL_BG ], [ op_name, self.opp_sprites[op_ch_idx], 16 + self.width, OPP_NAME_COL_FG, OPP_NAME_COL_BG ]] idx_lr = [0, 1] # index for left and right sprite if win: player_detail.reverse() # this player is winner so put last idx_lr.reverse() # Add some whitespace around winner's name player_detail[1][0] = " " + player_detail[1][0] + " " for (name, sprite, start_x, fg, bg) in player_detail: s_group = Group(scale=2, max_size=2) # Audio is choppy at scale=3 s_group.x = start_x s_group.y = (self.height - 2 * (self.sprite_size + self.font_height)) // 2 s_group.append(sprite) p_name_dob = Label( self.font, text=name, scale=1, # This is scaled by the group color=fg, background_color=bg) # Centre text below sprite - values are * Group scale p_name_dob.x = (self.sprite_size - len(name) * self.font_width) // 2 p_name_dob.y = self.sprite_size + 4 s_group.append(p_name_dob) pvp_group.append(s_group) if draw: sum_text = "Draw" elif win: sum_text = "You win" else: sum_text = "You lose" # Text starts invisible (BLACK) and color is later changed summary_dob = Label(self.font, text=sum_text, scale=3, color=BLACK) summary_dob.x = round( (self.width - 3 * self.font_width * len(sum_text)) / 2) summary_dob.y = round(self.height - (3 * self.font_height / 2)) pvp_group.append(summary_dob) self.showGroup(pvp_group) self.fadeUpDown("up", duration=0.4) # Start audio half way through animations if draw: # Move sprites onto the screen leaving them at either side for idx in range(16): pvp_group[idx_lr[0]].x += 6 pvp_group[idx_lr[1]].x -= 6 if idx == 8 and result is not None: self.sample.play(result) time.sleep(0.2) else: # Move sprites together, winning sprite overlaps and covers loser for idx in range(16): pvp_group[idx_lr[0]].x += 10 pvp_group[idx_lr[1]].x -= 10 if idx == 8 and result is not None: self.sample.play(result) time.sleep(0.2) self.sample.wait() # Wait for first sample to finish if summary is not None: self.sample.play(summary) # Flash colours for win, fad up to blue for rest if not draw and win: colours = [YELLOW_COL, ORANGE_COL, RED_COL] * 5 else: colours = [DRAWLOSE_COL * sc // 15 for sc in range(1, 15 + 1)] for col in colours: summary_dob.color = col time.sleep(0.120) self.sample.wait() # Ensure second sample has completed
if cam.width > width: continue if cam.height > height: continue try: bitmap = Bitmap(cam.width, cam.height, 65535) break except MemoryError: continue print(width, height, cam.width, cam.height) if bitmap is None: raise SystemExit("Could not allocate a bitmap") g = Group(scale=1, x=(width - cam.width) // 2, y=(height - cam.height) // 2) tg = TileGrid( bitmap, pixel_shader=ColorConverter(input_colorspace=Colorspace.RGB565_SWAPPED)) g.append(tg) display.show(g) t0 = time.monotonic_ns() display.auto_refresh = False while True: cam.capture(bitmap) bitmap.dirty() display.refresh(minimum_frames_per_second=0) t1 = time.monotonic_ns() print("fps", 1e9 / (t1 - t0)) t0 = t1
### Create the simple arrow cursors left_col = 20 right_col = display.width // 2 + left_col for x_pos in (left_col, right_col): y_pos = top_y_pos rps_dob_idx.append(len(screen_group)) for label_text in choices: rps_dob = Label(terminalio.FONT, text=label_text, scale=2, color=DEFAULT_TXT_COL_FG, background_color=DEFAULT_TXT_COL_BG) rps_dob.x = x_pos rps_dob.y = y_pos y_pos += 60 screen_group.append(rps_dob) cursor_dob = Label(terminalio.FONT, text=">", scale=3, color=CURSOR_COL_FG) cursor_dob.x = left_col - 20 setCursor(my_choice_idx, "mine") cursor_dob.y = top_y_pos screen_group.append(cursor_dob) ### Initially set to a space to not show it opp_cursor_dob = Label(terminalio.FONT, text=" ", scale=3, color=OPP_CURSOR_COL_FG, background_color=DEFAULT_TXT_COL_BG) opp_cursor_dob.x = right_col - 20 setCursor(my_choice_idx, "your")
def _update_display(self): self._update_display_strings() banner = label.Label(FONT, text=BANNER_STRING, color=COLOR) state = label.Label(FONT, text=self.state_str, color=COLOR) detector_result = label.Label(FONT, text=self.detection_result_str, color=COLOR) duration = label.Label(FONT, text=self.duration_str, color=COLOR) min_pressure_label = label.Label(FONT, text=self.min_press_str, color=COLOR) high_pressure_label = label.Label(FONT, text=self.high_press_str, color=COLOR) pressure_label = label.Label(FONT, text=self.press_str, color=COLOR) banner.x = 0 banner.y = 0 + Y_OFFSET state.x = 10 state.y = 10 + Y_OFFSET detector_result.x = 10 detector_result.y = 20 + Y_OFFSET duration.x = 10 duration.y = 30 + Y_OFFSET min_pressure_label.x = 0 min_pressure_label.y = BOTTOM_ROW - 10 pressure_label.x = DISPLAY_WIDTH - pressure_label.bounding_box[2] pressure_label.y = BOTTOM_ROW high_pressure_label.x = 0 high_pressure_label.y = BOTTOM_ROW splash = Group() splash.append(banner) splash.append(state) splash.append(detector_result) splash.append(duration) splash.append(min_pressure_label) splash.append(high_pressure_label) splash.append(pressure_label) self.display.show(splash)