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 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 blankScreen(disp, pix): # pylint: disable=unused-argument """A blank screen used to hide any serial console output.""" if disp is None: return disp.show(Group(max_size=1))
def playerListScreen(self): if self.disp is None: return self.emptyGroup(self.disp_group) # The two multiplier allows for rssi as separate label playerlist_group = Group(max_size=self.max_players * 2) self.showGroup(playerlist_group)
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 _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_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)
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, ), )
voltage_value_dob = Label(font=terminalio.FONT, 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
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
# SPDX-License-Identifier: MIT """ 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)
### Inputs _button_a = digitalio.DigitalInOut(board.BUTTON_A) _button_a.switch_to_input(pull=digitalio.Pull.UP) _button_b = digitalio.DigitalInOut(board.BUTTON_B) _button_b.switch_to_input(pull=digitalio.Pull.UP) button_left = lambda: not _button_a.value button_right = lambda: not _button_b.value ### The 6x14 terminalio classic font FONT_WIDTH, FONT_HEIGHT = terminalio.FONT.get_bounding_box() rows = 10 row_y = 30 row_spacing = FONT_HEIGHT + 2 rows_group = Group() ### I have foreground and background colours I can use here ### 1234567890123456789012345678901234567890 ### aa:bb:cc:dd:ee:ff -101 12345678901234567 for _ in range(rows): row_label = Label(font=terminalio.FONT, text="", color=0xc0c000) row_label.y = row_y row_y += row_spacing rows_group.append(row_label) summary_label = Label(font=terminalio.FONT, text="", color=0x00c0c0) summary_label.y = 220
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)
cam.size = size 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
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
def on_container_build(_, widget: Widget): assert widget._native_ is None widget._native_ = group = Group() group.hidden = False
def __init__( self, font: Union[BuiltinFont, BDF, PCF], x: int = 0, y: int = 0, text: str = "", color: int = 0xFFFFFF, background_color: int = None, line_spacing: float = 1.25, background_tight: bool = False, padding_top: int = 0, padding_bottom: int = 0, padding_left: int = 0, padding_right: int = 0, anchor_point: Tuple[float, float] = None, anchored_position: Tuple[int, int] = None, scale: int = 1, base_alignment: bool = False, tab_replacement: Tuple[int, str] = (4, " "), label_direction: str = "LTR", **kwargs, # pylint: disable=unused-argument ) -> None: # pylint: disable=too-many-arguments, too-many-locals super().__init__(x=x, y=y, scale=1) self._font = font self._text = text self._palette = Palette(2) self._color = 0xFFFFFF self._background_color = None self._line_spacing = line_spacing self._background_tight = background_tight self._padding_top = padding_top self._padding_bottom = padding_bottom self._padding_left = padding_left self._padding_right = padding_right self._anchor_point = anchor_point self._anchored_position = anchored_position self._base_alignment = base_alignment self._label_direction = label_direction self._tab_replacement = tab_replacement self._tab_text = self._tab_replacement[1] * self._tab_replacement[0] if "max_glyphs" in kwargs: print( "Please update your code: 'max_glyphs' is not needed anymore.") self._ascent, self._descent = self._get_ascent_descent() self._bounding_box = None self.color = color self.background_color = background_color # local group will hold background and text # the self group scale should always remain at 1, the self._local_group will # be used to set the scale of the label self._local_group = Group(scale=scale) self.append(self._local_group) self._baseline = -1.0 if self._base_alignment: self._y_offset = 0 else: self._y_offset = self._ascent // 2
elif who == "opp": sg_idx = rps_dob_idx[1] + c_idx else: raise ValueError("who is mine or opp") # An even number will leave colours on original values for _ in range(5 * 2): tmp_col = screen_group[sg_idx].color screen_group[sg_idx].color = screen_group[sg_idx].background_color screen_group[sg_idx].background_color = tmp_col time.sleep(0.5) # The 6x14 terminalio classic font FONT_WIDTH, FONT_HEIGHT = terminalio.FONT.get_bounding_box() screen_group = Group() # The position of the two players RPS Label objects inside screen_group rps_dob_idx = [] # 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,
elif who == "opp": sg_idx = rps_dob_idx[1] + c_idx else: raise ValueError("who is mine or opp") ### An even number will leave colours on original values for _ in range(5 * 2): tmp_col = screen_group[sg_idx].color screen_group[sg_idx].color = screen_group[sg_idx].background_color screen_group[sg_idx].background_color = tmp_col time.sleep(0.5) ### The 6x14 terminalio classic font FONT_WIDTH, FONT_HEIGHT = terminalio.FONT.get_bounding_box() screen_group = Group(max_size=len(choices) * 2 + 1 + 1) ### The position of the two players RPS Label objects inside screen_group rps_dob_idx = [] ### 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,
### Inputs _button_a = digitalio.DigitalInOut(board.BUTTON_A) _button_a.switch_to_input(pull=digitalio.Pull.UP) _button_b = digitalio.DigitalInOut(board.BUTTON_B) _button_b.switch_to_input(pull=digitalio.Pull.UP) button_left = lambda: not _button_a.value button_right = lambda: not _button_b.value ### The 6x14 terminalio classic font FONT_WIDTH, FONT_HEIGHT = terminalio.FONT.get_bounding_box() rows = 10 row_y = 30 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)
board.TOUCH_YD, board.TOUCH_YU, calibration=((5200, 59000), (5800, 57000)), size=(screen_width, screen_height)) elif display.rotation == 90: ts = Touchscreen(board.TOUCH_YU, board.TOUCH_YD, board.TOUCH_XL, board.TOUCH_XR, calibration=((5200, 59000), (5800, 57000)), size=(240, 320)) elif display.rotation == 180: ts = Touchscreen(board.TOUCH_XR, board.TOUCH_XL, board.TOUCH_YU, board.TOUCH_YD, calibration=((5200, 59000), (5800, 57000)), size=(320, 240)) elif display.rotation == 270: ts = Touchscreen(board.TOUCH_YD, board.TOUCH_YU, board.TOUCH_XR, board.TOUCH_XL, calibration=((5200, 59000), (5800, 57000)), size=(240, 320)) splash = Group(max_size=10)
class TouchKeys: '''Touch keyboard for pyportal usage.''' # Settings BUTTON_WIDTH, BUTTON_HEIGHT = 48, 40 BUTTON_COLOR, BUTTON_TEXT_COLOR = LIGHT_GRAY, BLACK BUTTON_MARGIN, PADDING = 0, 0 MAX_CHARS = 300 LEFT_START, TOP_START = 1, 114 CAPITALIZED = True Coords = namedtuple("Point", "x y") buttons = [] alpha_keys_caps = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'DEL', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', 'CAPS', 'SYM', ' ', 'RETURN', '???' ] alpha_keys_lower = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'DEL', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 'CAPS', 'SYM', ' ', 'RETURN', '???' ] symbol_keys = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '`', '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '=', '_', '+', '{', '}', '[', ']', ';', "'", ':', '"', '<', '>', '?', ',', '.', '/', '\\', '|', 'ABC', 'RETURN', '???' ] key_sets = [alpha_keys_caps, alpha_keys_lower, symbol_keys] # draw rectangle to hold the text stuff. text_area = Rect(0, 2, screen_width - 0, 108, fill=DARK_GRAY, outline=PINK_ISH) # create label area for text to show in. text_box = Label(font2, text="", color=LIGHT_GRAY, max_glyphs=MAX_CHARS, x=10, y=16) # define all the groups for the OSK for each key set: main_group = Group(max_size=(len(alpha_keys_caps) + 4)) main_group.append(text_area) main_group.append(text_box) def __init__(self): '''load the parts and display the keyboard and text entry box''' print('Loading keyboard') self.load_buttons(self.key_sets[0]) def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): splash.pop() def edit_text(self): pass # Some button functions def button_grid(self, row, col): return self.Coords( self.BUTTON_MARGIN * (row + self.PADDING) + self.BUTTON_WIDTH * row + self.LEFT_START, self.BUTTON_MARGIN * (col + self.PADDING) + self.BUTTON_HEIGHT * col + self.TOP_START) def add_button(self, row, col, label, width=1, color=LIGHT_GRAY, text_color=BLACK): pos = self.button_grid(row, col) new_button = Button(x=pos.x, y=pos.y, width=self.BUTTON_WIDTH * width + self.BUTTON_MARGIN * (width - 1), height=self.BUTTON_HEIGHT, label=label, label_font=font, label_color=text_color, fill_color=color, style=Button.SHADOWRECT) self.buttons.append(new_button) return new_button def find_button(self, label): result = None for _, btn in enumerate(self.buttons): if btn.label == label: result = btn return result def load_buttons(self, key_set): x, y = 0, 0 btn_width = 1 for char in key_set: if y == 4: btn_width = 2 if x > 0: x += 1 self.add_button(x, y, char, width=btn_width) x += 1 if x == 10: x = 0 y += 1 for btn in self.buttons: self.main_group.append(btn.group) def switch_alpha_symbol(self, input_char): # print('SWITCH TO ALPHA or SYMBOL KEY SET!') if input_char == 'ABC': if self.CAPITALIZED: cap = 0 elif not self.CAPITALIZED: cap = 1 # print(f'Cap setting: {cap}') for b, btn in enumerate(self.buttons): btn.label = self.key_sets[cap][b] elif input_char == 'SYM': for b, btn in enumerate(self.buttons): btn.label = self.key_sets[2][b] time.sleep(0.75) def delete_text_char(self): # print('THIS NEEDS TO DELETE SOMETHING') if len(self.text_box.text) > 0: self.text_box.text = self.text_box.text[:-1] def switch_capitalization(self): if self.CAPITALIZED: # print('Switch to Lower Case set') for b, btn in enumerate(self.buttons): # print(self.key_sets[0][b]) btn.label = self.key_sets[1][b] elif not self.CAPITALIZED: # print('Switch to Upper Case Set') for b, btn in enumerate(self.buttons): # print(self.key_sets[1][b]) btn.label = self.key_sets[0][b] self.CAPITALIZED = not self.CAPITALIZED time.sleep(0.75) def update_text(self, text_from_buttons): self.text_box.text += text_from_buttons def show(self, target_group): '''Get the keyboard to show on the display :crosses fingers:''' # print('SHOW ME THE KEYBOARD!') target_group.append(self.main_group) text_input = '' touched = False while True: touch = ts.touch_point if touch: # print(touch) for btn in self.buttons: if btn.contains(touch) and touched == False: touched = True input_char = btn.label # print(input_char) if input_char == 'DEL': # remove the last char added. text_input = text_input[:-1] self.delete_text_char() # print(text_input) elif input_char == 'CAPS': self.switch_capitalization() elif input_char == 'SYM' or input_char == 'ABC': self.switch_alpha_symbol(input_char) elif input_char == 'RETURN': # return the typed shit to the outside world! return text_input elif input_char == '???': print('Uhh.....') else: self.update_text(input_char) text_input += input_char # print(text_input) elif touched and not btn.contains(touch): # print('buttons released') touched = False time.sleep(0.05)