#==============================
# CFGRVRBT
# v1.0.0
# (c)2023-2025 Texas Instruments
#         Education Technology
#         All Rights Reserved
#
# Version by:
#    rlorentzen       (CFGRVRBT)
#    s.reid  a0837846 (SetDashEvo)
#
# PUT THIS IN ARCHIVE, then RUN it by
# 'import CFGRVRBT' on the Evo platform.
#==============================
# Draw text in screen lines 0-10.  11 possibly, 12 only on splash.
# 0=small font
# 1=medium font
# 2=large font
#----
# draw "soft" key buttons on bottom of screen based on soft-key
# selections desired.
# light blue rectangles with black text in small font.
#
import ti_graphics as gr
from ti_system import *
from sys import exit as _exit
from ti_hub import *

# ------------------------------
# static data initialization
# for this module
# ------------------------------
_screen_cap = False
_def_locale = 1  # default locale is english.  locales go from 0 to 6.
_locale = 1
_fonts = (gr.Font.SMALLD, gr.Font.MEDIUM, gr.Font.LARGE)
_indexAdjust = ((11, 11), (5, 5), (11, 4), (15, 6), (20, 5),
                (25, 5), (30, 5), (35, 5), (40, 5), (45, 6), (49, 0))
_cursor = ('\uf021', '\uf029')
_left_right = "\u25c0\u25b6"
# 0 = german
# 1 = english
# 2 = spanish
# 3 = french
# 4 = netherlands
# 5 = portuguese
# 6 = swedish
# ------------------------------
# Non-Localized Strings
# (splash screen)
# ------------------------------
_app_copyright = "© 2026 TEXAS INSTRUMENTS"
_app_version_value = ' 1.0.0.3'
_lcalpha=['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
_ucalpha=['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
_digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
# ------------------------------
# softkey menu package constants
# ------------------------------
_softbutton_width = 64
_softbutton_half = 32
_softbutton_text = 224
_softbutton_rect = 222
_softbutton_height = 18
_softbutton_rwid = 61
# ------------------------------
# Softkey menu button strings
#
# Localized strings displayed on softkey buttons
# ------------------------------
_search = (
    "SUCHEN",
    "SEARCH",
    "BUSCAR",
    "RÉTABLIR",
    "ZOEKEN",
    "PROCURAR",
    "SÖK")
_quit = ("STOPP", "QUIT", "SALIR", "QUIT", "STOP", "SAIR", "STOPPA")
_forget = (
    "VERGISS",
    "FORGET",
    "OLVIDAR",
    "OUBLIEZ",
    "VERGEET",
    "ESQUEÇA",
    "GLÖM")
_identify = ("IDENT", "IDENT", "IDENT", "IDENT", "IDENT", "IDENT", "IDENT")
_edit = (
    "BEARBEITEN",
    "EDIT",
    "EDITAR",
    "PARAM.",
    "BEWERKEN",
    "EDITAR",
    "REDIGERA")
_no = ("NEIN", "NO", "NO", "NON", "NEJ", "NÃO", "NEJ")
_yes = ("JA", "YES", "SÍ", "OUI", "JA", "SIM", "JA")
_esc = ("ESC", "ESC", "ESC", "ESC", "ESC", "ESC", "ESC")
_next = ("\u25b6", "\u25b6", "\u25b6", "\u25b6", "\u25b6", "\u25b6", "\u25b6")
_back = ("\u25c0", "\u25c0", "\u25c0", "\u25c0", "\u25c0", "\u25c0", "\u25c0")
_done = ("FERTIG", "DONE", "HECHO", "TERMINÉ", "GEREED", "EFETUADO", "KLAR")
# ------------------------------
# ==============================
# Application strings - localized
# ==============================
# Application version (splash screen)
# ------------------------------
_app_version = (
    "Version",
    "Version",
    "Versión",
    "Version",
    "Versie",
    "Versão",
    "Version")
# ------------------------------
# Application title (splash screen)
# ------------------------------
_app_title = (
    "APP FÜR TI-ROVER BT EINRICHTEN",
    "SETUP PROGRAM FOR TI-ROVER BT",
    "CONFIGURAR APP PARA EL ROBOT",
    "APP DE CONFIGURATION POUR ROBOT",
    "SETUP-APP VOOR TI-ROVER BT",
    "APP DE CONFIGURAÇÃO PARA ROBÔ",
    "SETUP APP FÖR TI-ROVER BT")
# ------------------------------
# Sketch Version: (splash screen)
# ------------------------------
_sketch_version = (
    "SKETCHVERSION : ",
    "SKETCH VERSION : ",
    "VERSIÓN DE SKETCH : ",
    "VERSION DE SKETCH : ",
    "SKETCH VERSIE : ",
    "VERSÃO DO SKETCH : ",
    "SKETCHVERSION : ")
# ------------------------------
# UpdateSketch Version: (splash screen)
# ------------------------------
_sketch_update=(
'[DE] TI BLUETOOTH ADAPTER NEEDS TO BE UPDATED.',
'TI BLUETOOTH® ADAPTER NEEDS TO BE UPDATED.',
'[ES] TI BLUETOOTH ADAPTER NEEDS TO BE UPDATED.',
'[FR] TI BLUETOOTH ADAPTER NEEDS TO BE UPDATED.',
'[NL] TI BLUETOOTH ADAPTER NEEDS TO BE UPDATED.',
'[PT] TI BLUETOOTH ADAPTER NEEDS TO BE UPDATED.',
'[SE] TI BLUETOOTH ADAPTER NEEDS TO BE UPDATED.')

_sketch_update2=(
'[DE] PLEASE VISIT EDUCATION.TI.COM/BLUETOOTH TO UPDATE THE ADAPTER',
'VISIT EDUCATION.TI.COM/BLUETOOTH.',
'[ES] PLEASE VISIT EDUCATION.TI.COM/BLUETOOTH TO UPDATE THE ADAPTER',
'[FR] PLEASE VISIT EDUCATION.TI.COM/BLUETOOTH TO UPDATE THE ADAPTER',
'[NL] PLEASE VISIT EDUCATION.TI.COM/BLUETOOTH TO UPDATE THE ADAPTER',
'[PT] PLEASE VISIT EDUCATION.TI.COM/BLUETOOTH TO UPDATE THE ADAPTER',
'[SE] PLEASE VISIT EDUCATION.TI.COM/BLUETOOTH TO UPDATE THE ADAPTER')
# ------------------------------
# Press ANY key (splash screen)
# ------------------------------
_press_any = (
    "DRÜCKEN SIE EINE BELIEBIGE TASTE",
    "PRESS ANY KEY",
    "PULSE CUALQUIER TECLA",
    "APPUYEZ SUR N'IMPORTE QUELLE TOUCHE",
    "DRUK OP EEN WILLEKEURIGE TOETS",
    "PRIMA QUALQUER TECLA",
    "TRYCK PÅ VALFRI KNAPP")
# ------------------------------
# Adapter detected (splash screen)
# ------------------------------
_detected = (
    "TI BLUETOOTH-ADAPTER ERKANNT",
    "TI BLUETOOTH® ADAPTER DETECTED",
    "SE HA DETECTADO UN TI BLUETOOTH",
    "ADAPTATEUR TI BLUETOOTH DÉTECTÉ",
    "TI BLUETOOTH-ADAPTER GEDETECTEERD",
    "ADAPTADOR TI BLUETOOTH DETETADO",
    "TI BLUETOOTH-ADAPTER UPPTÄCKT")
# ------------------------------
# Adapter not detected (splash screen)
# ------------------------------
_not_detected = (
    "TI BLUETOOTH-ADAPTER NICHT ERKANNT",
    "TI BLUETOOTH® NOT DETECTED",
    "NO SE HA DETECTADO EL TI BLUETOOTH",
    "ADAPTATEUR TI BLUETOOTH NON DÉTECTÉ",
    "TI BLUETOOTH-ADAPTER NIET GEDETECTEERD",
    "ADAPTADOR TI BLUETOOTH NÃO DETETADO",
    "TI BLUETOOTH-ADAPTER HITTADES INTE")
# ------------------------------
# Attach an adapter to continue (splash screen)
# ------------------------------
_attach_cont = (
    "SCHLIESSEN SIE DEN ADAPTER AN",
    "ATTACH ADAPTER TO CONTINUE",
    "CONECTE EL ADAPTADOR PARA CONTINUAR.",
    "CONNECTEZ L'ADAPTATEUR POUR CONTINUER.",
    "SLUIT DE ADAPTER AAN OM DOOR TE GAAN.",
    "CONETE O ADAPTADOR PARA CONTINUAR.",
    "ANSLUT ADAPTERN FÖR ATT FORTSÄTTA")
# ------------------------------
# Please Wait...
# ------------------------------
_please_wait = (
    "Bitte Warten…",
    "Please wait…",
    "Por Favor Espere…",
    "Veuillez Patienter…",
    "Even Geduld…",
    "Aguarde Por Favor…",
    "Vänta")
# ------------------------------
# Busy...
# ------------------------------
_busy = (
    "BESETZT…",
    "BUSY…",
    "OCUPADO…",
    "OCCUPÉ…",
    "BEZET…",
    "OCUPADO…",
    "UPPTAGEN…")

# ------------------------------
# Connecting/Reconnecting Robot screen title
# ------------------------------
_connecting = (
    "ROBOTER VERBINDET",
    "CONNECTING",
    "ROBOT CONECTANDO",
    "CONNEXION DU ROBOT",
    "ROBOT VERBINDING MAKEN",
    "LIGAÇÃO DO ROBÔ",
    "ROBOT ANSLUTER")
# ------------------------------
# "Named" Robot not found screen
# ------------------------------
_not_found = (
    "ROBOTER KANN NICHT GETFUNDEN WERDEN",
    "ROBOT CANNOT BE FOUND",
    "NO SE PUEDE ENCONTRAR EL ROBOT",
    "LE ROBOT EST INTROUVABLE",
    "ROBOT NIET GEVONDEN",
    "NÃO FOI POSSÍVEL ENCONTRAR O ROBÔ",
    "ROBOTEN KAN INTE HITTAS")
# ------------------------------
# "Named" Robot not available screen text, first block
# ------------------------------
_not_available2 = (
    "' IST NICHT AKTIVIERT ODER NICHT VERFÜGBAR.",
    "' IS NOT ON OR IS NOT AVAILABLE.",
    "' NO ESTÁ ACTIVADO O NO ESTÁ DISPONIBLE.",
    "' N'EST PAS ACTIVÉ OU N'EST PAS DISPONIBLE.",
    "' STAAT NIET AAN OF IS NIET BESCHIKBAAR.",
    "' NÃO ESTÁ LIGADO OU NÃO ESTÁ DISPONÍVEL.",
    "' ÄR INTE PÅ ELLER ÄR INTE TILLGÄNGLIGT.")
# ------------------------------
# "Named" Robot not available screen text, second block
# ------------------------------
_not_available3 = (
    "[SUCHEN] UM EINE VERBINDUNG ZU EINEM ROBOTER HERZUSTELLEN.",
    "USE [SEARCH] TO CONNECT TO A ROBOT.",
    "UTILICE [BUSCAR] PARA CONECTARSE A UN ROBOT.",
    "UTILISEZ [RÉTABLIR] POUR VOUS CONNECTER À UN ROBOT.",
    "GEBRUIK [ZOEKEN] OM VERBINDING TE MAKEN MET EEN ROBOT.",
    "UTILIZE [PROCURAR] PARA LIGAR A UM ROBOT.",
    "ANVÄND [SÖK] FÖR ATT ANSLUTA TILL EN ROBOT.")
# ------------------------------
# No Robots Found screen title.
# ------------------------------
_none_found = (
    "KEINE ROBOTER GEFUNDEN.",
    "NO ROBOTS FOUND",
    "NO SE HAN ENCONTRADO ROBOTS.",
    "AUCUN ROBOT TROUVÉ.",
    "GEEN ROBOTS GEVONDEN.",
    "NÃO FORAM ENCONTRADOS ROBÔS.",
    "INGA ROBOTAR HITTADES.")
# ------------------------------
# No Robots Found screen text
# ------------------------------
_turn_them_on = (
    "STELLEN SIE SICHER, DASS DIE ROBOTER EINGESCHALTET UND IN REICHWEITE SIND.",
    "MAKE SURE ROBOTS ARE TURNED ON AND IN RANGE.",
    "ASEGÚRESE DE QUE LOS ROBOTS ESTÁN ENCENDIDOS Y DENTRO DEL RANGO.",
    "ASSUREZ-VOUS QUE LES ROBOTS SONT SOUS TENSION ET À PORTÉE.",
    "ZORG ERVOOR DAT ROBOTS AAN STAAN EN BINNEN BEREIK ZIJN.",
    "CERTIFIQUE-SE DE QUE OS ROBÔS ESTÃO LIGADOS E DENTRO DO ALCANCE.",
    "SE TILL ATT ROBOTAR ÄR PÅSLAGNA OCH INOM RÄCKVIDD.")
# ------------------------------
# Searching For Robots screen title
# ------------------------------
_looking = (
    "SUCHEN SIE NACH ROBOTERN…",
    "SEARCH FOR ROBOTS…",
    "BUSCAR ROBOTS…",
    "RECHERCHER DES ROBOTS…",
    "ZOEK NAAR ROBOTS…",
    "PROCURE ROBÔS…",
    "SÖK EFTER ROBOTAR…")
# ------------------------------
# Select a Robot screen
# ------------------------------
_select_robot = (
    "ROBOTER AUSWÄHLEN",
    "SELECT ROBOT",
    "SELECCIONE ROBOT",
    "SÉLECTIONNER LE ROBOT",
    "SELECTEER ROBOT",
    "SELECIONE O ROBÔ",
    "VÄLJ ROBOT")
# ------------------------------
# Forget Robot screen title
# ------------------------------
_forget_this = (
    "VERGISS DIESEN ROBOTER",
    "FORGET THIS ROBOT",
    "OLVIDAR ESTE ROBOT",
    "OUBLIEZ CE ROBOT",
    "VERGEET DEZE ROBOT",
    "ESQUEÇA ESTE ROBÔ",
    "GLÖM DEN HÄR ROBOTEN")
# ------------------------------
# Forget Robot confirmation screen, text block 1
# ------------------------------
_forget1 = (
    "MÖCHTEN SIE DIESEN ROBOTER WIRKLICH VERGESSEN?",
    "ARE YOU SURE YOU WANT TO FORGET THIS ROBOT?",
    "¿ESTÁS SEGURO DE QUE QUIERES OLVIDAR ESTE ROBOT?",
    "VOULEZ-VOUS VRAIMENT OUBLIER CE ROBOT?",
    "WEET U ZEKER DAT U DEZE ROBOT WILT VERGETEN?",
    "TEM A CERTEZA DE QUE PRETENDE ESQUECER ESTE ROBOT?",
    "ÄR DU SÄKER PÅ ATT DU VILL GLÖMMA DEN HÄR ROBOTEN?")
# ------------------------------
# Forget Robot confirmation screen, text block 2
# ------------------------------
_forget2 = (
    "DER TI BLUETOOTH-ADAPTER WIRD NICHT MIT EINEM ROBOTER VERBUNDEN.",
    "TI BLUETOOTH ADAPTER WILL NOT BE CONNECTED TO ANY ROBOT.",
    "EL ADAPTADOR TI BLUETOOTH NO SE CONECTARÁ A NINGÚN ROBOT.",
    "L'ADAPTATEUR TI BLUETOOTH NE SERA CONNECTÉ À AUCUN ROBOT.",
    "DE TI BLUETOOTH-ADAPTER ZAL OP GEEN ENKELE ROBOT VERBONDEN ZIJN.",
    "O ADAPTADOR TI BLUETOOTH NÃO SERÁ CONETADO A NENHUM ROBÔ.",
    "TI BLUETOOTH-ADAPTERN ANSLUTS INTE TILL NÅGON ROBOT.")
# ------------------------------
# Help Screen title
# ------------------------------
_help = (
    "HILFE",
    "HELP",
    "AYUDA",
    "AIDE",
    "HULP",
    "AJUDA",
    "HJÄLP")
# ------------------------------
# Help Screen - text block 1
# ------------------------------
_help1 = (
    "DAS BEENDEN DER APP IST NICHT NOTWENDIG, UM EINEN ZUSÄTZLICHEN TI BLUETOOTH ADAPTER UND ROBOTER ZU AKTUALISIEREN.",
    "QUITTING THE APP IS NOT NECESSARY TO UPDATE AN ADDITIONAL TI BLUETOOTH ADAPTER AND ROBOT.",
    "NO ES NECESARIO SALIR DE LA APLICACIÓN PARA ACTUALIZAR UN ROBOT Y ADAPTADOR TI BLUETOOTH ADICIONALES.",
    "IL N'EST PAS NÉCESSAIRE DE QUITTER L'APPLICATION POUR METTRE À JOUR UN ADAPTATEUR TI BLUETOOTH ET UN ROBOT SUPPLÉMENTAIRES.",
    "HET AFSLUITEN VAN DE APP IS NIET NODIG OM EEN EXTRA TI BLUETOOTH-ADAPTER EN ROBOT BIJ TE WERKEN.",
    "NÃO É NECESSÁRIO SAIR DA APLICAÇÃO PARA ATUALIZAR UM ROBÔ E ADAPTADOR TI BLUETOOTH ADICIONAL.",
    "DET ÄR INTE NÖDVÄNDIGT ATT AVSLUTA APPEN FÖR ATT UPPDATERA YTTERLIGARE EN TI BLUETOOTH-ADAPTER OCH ROBOT.")
# ------------------------------
# Help Screen - text block 2
# ------------------------------
_help2 = (
    "TRENNEN SIE DEN AKTUELLEN ADAPTER, SCHLIESSEN SIE EINEN NEUEN ADAPTER AN, UND BEFOLGEN SIE DIE ANWEISUNGEN DER APP.",
    "DETACH THE CURRENT ADAPTER, ATTACH A NEW ADAPTER AND FOLLOW APP INSTRUCTIONS.",
    "DESCONECTE EL ADAPTADOR ACTUAL, CONECTE UN NUEVO ADAPTADOR Y SIGA LAS INSTRUCCIONES DE LA APLICACIÓN.",
    "DÉCONNECTEZ L'ADAPTATEUR ACTUEL, CONNECTEZ UN NOUVEL ADAPTATEUR ET SUIVEZ LES INSTRUCTIONS DE L'APPLICATION.",
    "KOPPEL DE HUIDIGE ADAPTER LOS, SLUIT EEN NIEUWE ADAPTER AAN EN VOLG DE INSTRUCTIES VAN DE APP.",
    "RETIRE O ADAPTADOR ATUAL, LIGUE UM NOVO ADAPTADOR E SIGA AS INSTRUÇÕES DA APLICAÇÃO.",
    "KOPPLA BORT DEN AKTUELLA ADAPTERN, ANSLUT EN NY ADAPTER OCH FÖLJ APPINSTRUKTIONERNA.")
# ------------------------------
# Current Robot Connection screen title
# ------------------------------
_current_conn = (
    "AKTUELLE VERBINDUNG",
    "CURRENT CONNECTION",
    "CONEXIÓN ACTUAL",
    "CONNEXION ACTUELLE",
    "HUIDIGE VERBINDING",
    "LIGAÇÃO ATUAL",
    "AKTUELL ANSLUTNING")
# ------------------------------
# 'current' robot
# ------------------------------
_current = (
    "(aktueller)",
    "(current)",
    "(actual)",
    "(actuel)",
    "(huidige)",
    "(atual)",
    "(aktuell)")

# ------------------------------
# Current Robot Connection Robot name label
# ------------------------------
_my_name = (
    "Name    :",
    "Name    :",
    "Nombre  :",
    "Nom     :",
    "Naam    :",
    "Nome    :",
    "Namn    :")
# ------------------------------
# Current Robot Connection Color label
# ------------------------------
_my_color = (
    "Farbe   :",
    "Color   :",
    "Color   :",
    "Couleur :",
    "Kleur   :",
    "Cor     :",
    "Färg    :")
# ------------------------------
# Current Robot Connection Battery label
# ------------------------------
_my_battery = (
    "Batterie:",
    "Battery :",
    "Bateria :",
    "Batterie:",
    "Batterij:",
    "Bateria :",
    "Batteri :")
# ------------------------------
# Current Robot Connection Battery State Good
# ------------------------------
_batt_ok = (
    "Gut",
    "Good",
    "Bien",
    "Bon",
    "Goed",
    "Bom",
    "Bra")
# ------------------------------
# Current Robot Connection Battery State Low
# ------------------------------
# if this message is shown, ALSO display the _low_warn string!
_batt_low = (
    "Niedrig",
    "Low",
    "Baja",
    "Faible",
    "Laag",
    "Baixo",
    "Låg")
# ------------------------------
# Current Robot Connection Battery State Low WARNING message
# ------------------------------
_low_warn = (
    "BATTERIE SCHWACH! LADEN SIE DIE BATTERIE DES ROBOTERS AUF, ODER WÄHLEN SIE MIT [SUCHEN] EINEN ANDEREN ROBOTER AUS.",
    "LOW BATTERY! PLEASE CHARGE THE ROBOT BATTERY OR USE [SEARCH] TO CHOOSE ANOTHER ROBOT.",
    "BATERÍA BAJA! CARGUE LA BATERÍA DEL ROBOT O UTILICE [BUSCAR] PARA ELEGIR OTRO ROBOT.",
    "BATTERIE FAIBLE! CHARGEZ LA BATTERIE DU ROBOT OU UTILISEZ [RÉTABLIR] POUR CHOISIR UN AUTRE ROBOT.",
    "BATTERIJ BIJNA LEEG! LAAD DE ROBOTBATTERIJ OP OF GEBRUIK [ZOEKEN] OM EEN ANDERE ROBOT TE KIEZEN.",
    "BATERIA FRACA! CARREGUE A BATERIA DO ROBOT OU UTILIZE [PROCURAR] PARA ESCOLHER OUTRO ROBOT.",
    "SVAGT BATTERI! LADDA ROBOTENS BATTERI ELLER ANVÄND [SÖK] FÖR ATT VÄLJA EN ANNAN ROBOT.")
# ------------------------------
# Quit Confirmation Screen messaging.
# ------------------------------
_sure = (
    "MÖCHTEN SIE DEN VORGANG WIRKLICH BEENDEN?",
    "ARE YOU SURE YOU WANT TO QUIT?",
    "¿ESTÁS SEGURO DE QUE DESEA SALIR?",
    "VOULEZ-VOUS VRAIMENT QUITTER?",
    "WEET U ZEKER DAT U WILT AFSLUITEN?",
    "TEM A CERTEZA DE QUE PRETENDE SAIR?",
    "ÄR DU SÄKER PÅ ATT DU VILL AVSLUTA?")
# ------------------------------
# Edit Robot Settings screen
# ------------------------------
_edit_robot_title = (
    "ROBOTEREINSTELLUNGEN",
    "EDIT ROBOT SETTINGS",
    "EDITAR AJUSTES DEL ROBOT",
    "PARAMÈTRES DU ROBOT",
    "ROBOTINSTELLINGEN BEWERKEN",
    "EDITAR DEFINIÇÕES DO ROBÔ",
    "REDIGERA ROBOTINSTÄLLNINGAR")
# ------------------------------
# Current Name (edit robot settings screen
# ------------------------------
_current_name = (
    "AKTUELLER NAME:",
    "CURRENT NAME  :",
    "NOMBRE ACTUAL :",
    "NOM ACTUEL    :",
    "HUIDIGE NAAM  :",
    "NOME ATUAL    :",
    "AKTUELLT NAMN :")
# ==============================
# color tuples used in this program
# ------------------------------
_gray = (236, 236, 236)  # gray
_ltgray = (230, 230, 230)  # light gray
_medgray = (164, 164, 164)  # medium gray
_darkgray = (96, 96, 96)     # gray for text - edit robot name
_white = (255, 255, 255)  # white background color
_yellow = (255, 240, 32)   # yellow robot personality
_green = (16, 160, 16)    # green robot personality, connection, detected
_orange = (255, 168, 16)   # orange robot personality
_blue = (64, 230, 250)   # blue robot personality
_red = (255, 64, 48)    # red robot personality, low battery, not detected
_purple = (224, 64, 255)   # purple robot personality
# light blue for softkey buttons and title bar backgrounds
_light_blue = (207, 228, 249)
# dark background for title bar - area to draw title
_background = (50, 64, 82)
_black = (0, 0, 0)        # black text
_the_colors = (_white, _yellow, _green, _orange, _blue, _red, _purple)
_pcolor = ("None", "Yellow", "Green", "Orange", "Blue", "Red", "Purple")
#
_alock = False
_alpha = False
_2nd = False
_indics = (' ', '\uf022', '\uf024', '\uf023')
_lock = ('\uf03a', '\u0020')
#  keys are our lists of valid keys for certain contexts
_main_keys = ('F1', 'F3', 'F4', 'F5')
_conn_keys = ('F1', 'F2', 'F3', 'F4', 'F5')
_pers_keys = ('left', 'right', 'up', 'enter', 'F1', 'F5')
_robot_keys = ('1', '2', '3', '4', '5', 'F1', 'F3', 'F5')
_F1_F5_keys = ('F1', 'F5')
_search_keys = ('F1', 'F3', 'F5')
_quit_keys = ('F1', 'F5', 'mode')
# platform keys for non-Alpha keyboard
_digitkeys = ('F1', 'F2', 'F3', 'F4', 'F5',
              '2nd', 'mode', 'del', 'left', 'up', 'right',
              'alpha', 'xvar', 'stat', 'down',
              'math', 'apps', 'prgm', 'vars', 'esc',
              '1/x', 'sin', 'cos', 'tan', 'power',
              'x^2', ',', '(', ')', '/',
              'log', '7', '8', '9', '*',
              'ln', '4', '5', '6', '-',
              '=', '1', '2', '3', '+',
              '0', '.', 'neg', 'enter')
# platform keys for LC alpha
_lcalphakeys = (
    'F1', 'F2', 'F3', 'F4', 'F5',
    '2nd', 'mode', 'del', 'left', 'up', 'right',
    'alpha', 'xvar', 'stat', 'down',
    'a', 'b', 'c', 'vars', 'esc',
    'd', 'e', 'f', 'g', 'h',
    'i', 'j', 'k', 'l', 'm',
    'n', 'o', 'p', 'q', 'r',
    's', 't', 'u', 'v', 'w',
    'x', 'y', 'z', ' ', '"',
    ' ', ':', '?', 'enter')
# platform keys for UC alpha
_ucalphakeys = ('F1', 'F2', 'F3', 'F4', 'F5',
                '2nd', 'mode', 'del', 'left', 'up', 'right',
                'alpha', 'xvar', 'stat', 'down',
                'A', 'B', 'C', 'vars', 'esc',
                'D', 'E', 'F', 'G', 'H',
                'I', 'J', 'K', 'L', 'M',
                'N', 'O', 'P', 'Q', 'R',
                'S', 'T', 'U', 'V', 'W',
                'X', 'Y', 'Z', ' ', '"',
                ' ', ':', '?', 'enter')
# ------------------------------
# Soft Menu Definitions
# ------------------------------
_forget_menu = ([0, _no], [4, _yes])
_search_again = [[0, _search], [4, _quit]]
_search_quit = [[0, _esc], [2, _search], [4, _quit]]
_quit_confirm = [[0, _no], [4, _yes]]
_search_forget = [[0, _search], [2, _forget], [4, _quit]]
_conn_menu = ([0, _edit], [1, _identify], [2, _forget], [3, _next], [4, _quit])
_conn_menu2 = ([0, _search], [1, _identify], [
               2, _help], [3, _back], [4, _quit])
_help_menu = ([0, _esc], [4, _quit])
_done_menu = ([0, _esc], [4, _done])
# ------------------------------
_menu = (_my_name, _my_color, _my_battery)
# ------------------------------
# RGBs to use to set front RGB on Dash when we change personality
# ------------------------------
_front_rgb = ('40 40 0', '0 20 0', '40 10 0', '0 20 20', '20 0 0', '20 0 10')
# ------------------------------
# ------------------------------
# dynamic globals to hold current discovery operation results
# ------------------------------
_bot_macs = []
_bot_colors = []
_bot_charges = []
_bot_names = []
_bot_count = 0
# ------------------------------
# offsets and positions for drawing and line adjustments
# ------------------------------
_left_column = 8    # leftmost column to start drawing text at
_menu_row = 63   # highest row to draw menu text at - text line 2
_last_row = 208  # bottom row to draw text at
_goffset = 12   # offset to apply to row when drawing graphic shapes instead of text
_per_line = 16   # pixels to adjust per "text" line drawn on screen.
_color_bar_w = 30   # how wide to draw a color bar
_color_bar_h = 9    # height of color bar
# ------------------------------


class _bta():
    _discoverDelay = 4.0
    _connectDelay = 8.0
    _min_version = '1.2.0.87'
    _min_timeout = 1.0
    _wait_time = 0.1

    @classmethod
    def _getString(cls, timeout):
        """
        Retrieve a string from the device with a timeout.
        Waits up to `timeout` seconds for a response from `get()`.
        Returns an empty string if the timeout expires.
        """
        timeout = timeout + cls._min_timeout
        count = cls._wait_time
        sleep(cls._wait_time)
        while True:
            msg = get()
            if msg is None:
                msg = ''
            if msg == -11.0:
                msg = '-11'
            if isinstance(msg, list):
                msg = ' '.join(str(x) for x in msg)
            if msg != '' or count >= timeout:
                return msg
            count += cls._wait_time
            sleep(cls._wait_time)

    @classmethod
    def _comm(cls, cmd, pre_t=0, post_t=0, excludeLists=True):
        send(cmd)
        msg = cls._getString(pre_t)
        # filter out extra HCI responses from Rover BT
        while excludeLists and isinstance(msg, list):
            msg = cls._getString(pre_t)
        sleep(post_t)
        return msg

    @classmethod
    def _read(cls, pre_t=0, post_t=0):
        msg = cls._getString(pre_t)
        sleep(post_t)
        return msg

    @classmethod
    def reset_bta(cls):
        msg = cls._comm("START", 0.1)
        if msg.find('OK') == -1:
            return False
        else:
            return True

    @classmethod
    def discover(cls):
        _i = 3
        bots = []
        while _i:
            _i -= 1
            msg1 = cls._comm('discover ww', 2.0)
            if msg1 == 'NONE':
                msg1 = ''
            if msg1 == '' or isinstance(msg1, (float, int)):
                msg1 = 'NONE'
            bots.extend(cls.splitDiscover(msg1))
        _seen = []
        unique = []
        for bot in bots:
            if len(bot):
                first = bot[0] if isinstance(bot, (list, tuple)) else bot
                if first not in _seen:
                    _seen.append(first)
                    unique.append(bot)
        return unique

    @classmethod
    def splitDiscover(cls, msg):
        d = []
        if msg.find('NONE') != 0:
            m = msg.split('\r\n')
            for i in range(len(m)):
                d.append(m[i].split())
        return d

    @classmethod
    def hci(cls, byte_stream):
        cmd = "H: {}".format(byte_stream)
        msg = cls._comm(cmd)
        return msg

    @classmethod
    def readSlot(cls, slot=0):
        cmd = "NVREAD {}".format(slot)
        msg = cls._comm(cmd)
        if msg == '':
            msg = 0
        if msg == 0:
            msg = '000000000000'
        return msg

    @classmethod
    def setFormat(cls, set):
        cmd = "FORMAT {}".format(set)  # STD, CE, HEX
        msg = cls._comm(cmd)
        return msg

    @classmethod
    def isti(cls):
        cmd = "ISTI"
        msg = cls._comm(cmd)
        return msg

    @classmethod
    def isBtaAttached(cls):
         if not _screen_cap:
            return cls.isti().find('TIBLEA') != -1
         else:
            return True

    @classmethod
    def readBtaVersion(cls):
        msg = cls._comm('version')
        if msg == '':
            return '0.0.0'
        return msg

    @classmethod
    def isBtaCurrent(cls):
        ver = cls.readBtaVersion()
        ver = ver.split()[0].split('.')
        minver = cls._min_version.split()[0].split('.')
        for i in range(0, 4):
            cur = int(ver[i])
            min = int(minver[i])
            if cur == min:
                continue
            return cur > min
        return True

    @classmethod
    def isBtaConfigured(cls):
        msg = cls.readSlot()
        return msg.find('000000000000') == -1 and len(msg) == 12

    @classmethod
    def clearBta(cls):
        cmd = "FORGET"
        msg = cls._comm(cmd, 0.05)
        return msg.find('OK') != -1

    @classmethod
    def isConnected(cls):
        cmd = "ISCONNECTED"
        msg = cls._comm(cmd, 0.05)
        return msg.find('OK') != -1

    @classmethod
    def bleRate(cls, rate=100):
        cmd = "BlERATE {}".format(rate)
        msg = cls._comm(cmd)
        return msg

    @classmethod
    def sensorGo(cls):
        cmd = "SENSOR GO"
        msg = cls._comm(cmd)
        return msg

    @classmethod
    def sensorStop(cls):
        cmd = "SENSOR STOP"
        msg = cls._comm(cmd)
        return msg

    @classmethod
    def readMove(cls):
        cmd = "READ MOVE"
        msg = cls._comm(cmd)
        return msg

    @classmethod
    def readBattery(cls):
        cmd = "READ BATTERY"
        msg = cls._comm(cmd, excludeLists=False)
        return msg

    @classmethod
    def disconnect(cls):
        cmd = "DISCONNECT 0"
        msg = cls._comm(cmd, 0.5)

    @classmethod
    def connect(cls, mac):
        cmd = "CONNECT {} 0".format(mac)
        msg = cls._comm(cmd, cls._connectDelay)
        return msg

    @classmethod
    def areSensorsEnabled(cls):
        """Return True iff both sensor channels are active."""
        r = cls._comm('read sensor', 0.05)
        return isinstance(r, list) and r[0] == 1 and r[1] == 1

    @classmethod
    def enableSensors(cls):
        """Start sensor notifications (returns True on success)."""
        return cls._comm('sensor go', 0.8, 0.3).find('OK') != -1

    @classmethod
    def identify(cls):
        """Send IDENT command; returns True if robot nods."""
        if cls.isBtaAttached() and cls.isConnected():
            return cls._comm('identify', 0.05, 0.3).find('OK') != -1
        return False

    @classmethod
    def readName(cls):
        """Read robot name; empty string on failure."""
        msg = cls._comm('read name', 0.05)
        if msg.find('FAIL') != -1 or msg.find('-11') != -1:
            return ''
        return msg

    @classmethod
    def setName(cls, new_name):
        """Set robot name; returns True on success."""
        return cls._comm('name ' + new_name, 0.1, 0.5).find('OK') != -1

    @classmethod
    def set_personality(cls, personality):
        """Set Dash personality (1-6) and update LED color."""
        if 1 <= personality <= 6:
            msg = cls._comm('color personality ' + str(personality), 0.1, 0.5)
            cls._comm('color ' + _front_rgb[personality - 1] + ' 0 front')
            return msg.find('OK') != -1
        return False

    @classmethod
    def read_personality(cls):
        """Read current Dash personality index (0 if none)."""
        msg = cls._comm('read color personality', 0.05)
        if msg == '':
            return 0
        if isinstance(msg, str):
            if 'FAIL' in msg:
                return 0
            return int(msg)
        return int(msg)

    @classmethod
    def save_mac(cls, mac):
        """Save 12‑digit MAC address to NV slot 0."""
        if len(mac) == 12:
            msg = cls._comm('nvsave ' + mac + ' 0', 0.05, 0.1)
            return isinstance(msg, str) and msg.find('OK') != -1
        return False

    @classmethod
    def set_quiet(cls):
        """Enable quiet mode on the Dash robot."""
        msg = cls._comm('quiet ', 0.1, 0.25)
        return isinstance(msg, str) and msg.find('OK') != -1

    @classmethod
    def set_volume(cls, level=1):
        """Set Dash volume level (default 1)."""
        msg = cls._comm('volume ' + str(level) + ' set', 0.05, 0.1)
        return isinstance(msg, str) and msg.find('OK') != -1


########################################
# Battery Level API
########################################


def battery_level():
  s = _bta.readBattery()
  batt = int(s.split()[2])
  return round(batt / 31 * 100)


# ------------------------------
# Get Locale for translation selection.
#
# returns the current locale, or default locale if method not
# available.
# ------------------------------


def get_locale():
    _v = _locale
    try:
        _v = locale()
    except BaseException:
        _v = _def_locale
    return _v

# ------------------------------
# clear_rect()
#
# utility routine to erase an area of the screen to white.
# ------------------------------


def clear_rect(x, y, w, h):
    gr.setColor(_white)
    gr.fillRect(x, y, w, h)
    gr.setColor(_black)
    return
# ==============================
# DRAW SOFT MENU keys package.
#
# This set of routines draws a menu structure using soft buttons
# across the bottom portion of the display.
# ==============================
# draw the softbutton background.
# ------------------------------

def __draw_rectangle(i, wid):
    gr.setColor(_light_blue)
    adj = 2
    if wid < _softbutton_rwid:
        adj = (_softbutton_rwid - wid) / 2 + 2
    gr.fillRect(i*_softbutton_width+adj,_softbutton_rect,wid,_softbutton_height)
    gr.setPixel(i*_softbutton_width+adj, _softbutton_rect, _white)
    gr.setPixel(i*_softbutton_width+adj+1, _softbutton_rect, _white)
    gr.setPixel(i*_softbutton_width+adj, _softbutton_rect+1, _white)
    gr.setPixel(i*_softbutton_width+adj+wid-1, _softbutton_rect, _white)
    gr.setPixel(i*_softbutton_width+adj+wid-1, _softbutton_rect+1, _white)
    gr.setPixel(i*_softbutton_width+adj+wid-2, _softbutton_rect, _white)
    gr.setColor(_black)
    return

# ------------------------------
# draw text centered on the button.
# ------------------------------


def __draw_center_button(n, bwid, swid, btext):
    wid = bwid
    if bwid < _softbutton_rwid:
        wid = _softbutton_rwid
    _offset = int(wid / 2 - swid / 2) + 2
    gr.drawString(btext, (n * _softbutton_width) + _offset, _softbutton_text)
    return

# ------------------------------
# given text and button rectangle, draw button n.
# ------------------------------


def __draw_softbutton(n, btext):
    w, h = gr.string_size(btext[_locale], _getfont(0))
    wid = w + 8
    if wid < _softbutton_rwid:
        wid = _softbutton_rwid
    if w < 30:
        wid -= 16
    __draw_rectangle(n, wid)
    __draw_center_button(n, wid, w, btext[_locale])
    return

# ------------------------------
# _draw_softmenu()
#
# Draws the menus across bottom of screen.
# ------------------------------


def _draw_softmenu(menu):
    clear_rect(0, _softbutton_rect, 320, _softbutton_height)
    gr.setFont(_getfont(0))
    n = len(menu)
    for i in range(0, n):
        __draw_softbutton(menu[i][0], menu[i][1])
    gr.setFont(_getfont(1))
    return

# ==============================
# please_wait()
#
# Displays busy(2), connecting(1),
# or looking(0), screens with
# the please wait message centered.
# ==============================


def please_wait(doConn):
    if doConn == 1:
        _draw_context_title(_connecting[_locale])
    elif doConn == 0:
        _draw_context_title(_looking[_locale])
    elif doConn == 2:
        _draw_context_title(_busy[_locale])
    _draw_centered_text(5, _please_wait[_locale])
    return

# ==============================
# setDashSplash()
#
# Draw Application Splash Screen,
# Tests for Adapter Presence.
# If adapter is unplugged during
# operation, come to this routine.
# ==============================


def setDashSplash():
    global _screen_cap
    attached = False
    wasattached = True
    gr.setColor(_black)
    gr.cls()
    _draw_centered_text(5, _app_title[_locale])
    _draw_centered_text(6, _app_version[_locale] + _app_version_value, 0)
    _draw_centered_text(12, _app_copyright, 0)
    choice = ''
    not_drawn = True
    blinky = 0
    current = False
    while choice != 'enter':
        attached = _bta.isBtaAttached()
        if attached != wasattached:
            wasattached = attached
            # erase text lines 8,9,10, and 11.
            clear_rect(0, _textrow(8), 319, _per_line * 4)
            not_drawn = True
        if attached and not_drawn:
            if _bta.isBtaCurrent():
                _draw_centered_text(11, _press_any[_locale], 0)
                gr.setColor(_green)
                current = True
            else:
                gr.setColor(_red)
                current = False
                _draw_centered_text(10, _sketch_update[_locale], 0)
                _draw_centered_text(11, _sketch_update2[_locale], 0)
            _draw_centered_text(8, _detected[_locale], 0)
            ver = _bta.readBtaVersion()
            _draw_centered_text(9, _sketch_version[_locale] + ver, 0)
            not_drawn = False
        elif not attached and not_drawn:
            _draw_centered_text(11, _press_any[_locale], 0)
            gr.setColor(_red)
            _draw_centered_text(8, _not_detected[_locale], 0)
            _draw_centered_text(9, _attach_cont[_locale], 0)
            not_drawn = False
        gr.setColor(_black)
        k = getKey(0)
        if k == 71:
            _screen_cap = not _screen_cap
            k = 0
        pick = ''
        if k != 0:
            pick = _mapKeyToString(k)
        if attached and current:
            if pick != '':
                choice = 'enter'
        if pick == 'esc':
            return False
        if pick == '':
            sleep(0.15)
            if attached and current:
                blinky += 1
                if blinky == 2:
                    clear_rect(0, _textrow(11), 319, _per_line)
                if blinky > 4:
                    blinky = 0
                    _draw_centered_text(11, _press_any[_locale], 0)
    return attached

# ------------------------------
# _reconnect()
#
# If robot is not currently connected, AND our adapter is configured,
# connect to the robot.
# ------------------------------


def _reconnect():
    m = 'NONE'  # not configured
    if not _bta.isConnected():
        if _bta.isBtaConfigured():
            please_wait(1)
            m = _bta.connect(_bta.readSlot())
            # MISS/OK/FAIL... deal with the result when we go back
    else:
        m = 'OK'  # robot is already connected.
    return m

# ------------------------------
# _disconnect()
#
# If robot is connected, disconnect from Dash.
# ------------------------------


def _disconnect():
    if _bta.isConnected():
        _bta.disconnect()
    return

# ------------------------------
# _doConnect(mac-addr)
#
# Does a wait screen while we connect to a robot...
# ------------------------------


def _doConnect(ma):
    rv = 2
    please_wait(1)
    if not _bta.isBtaAttached():
        return -1
    if _bta.isConnected():
        _bta.disconnect()
    msg = _bta.connect(ma)
    if msg.find('OK') != -1:
        _bta.save_mac(ma)
        rv = 1  # not connected
        if _bta.isConnected():
            # we are connected
            _bta.set_quiet()
            _bta.set_volume()
            rv = 0
    elif msg.find('MISS') != -1:
        # robot is missing!
        rv = 2
    return rv

# ------------------------------


def _mapIndex(k):
    if k <= 105:
        i = 0
        n = len(_indexAdjust)
        while i < n:
            if k >= _indexAdjust[i][0]:
                k -= _indexAdjust[i][1]
                i += 1
            else:
                return k
    return -1

# ------------------------------
# _mapKeyToString()
#
# Maps key scancode to a key
# string for use in script.
# ------------------------------


def _mapKeyToString(k):
    if k != 0:
        i = _mapIndex(k)
        if i >= 0:
            if _alpha == 0:
                return _digitkeys[i]
            elif _alpha == 1:
                return _lcalphakeys[i]
            else:
                return _ucalphakeys[i]
    return ''

# ------------------------------
# _drawIndic()
# ------------------------------


def _drawIndic(choice):
    global _alock, _alpha, _2nd
    gr.setFont(_getfont(1))
    _i = 0
    if choice == '':
        updateLock = True
        if _alock:
            _a = 0
            _alpha = 2
            _i = 3
        else:
            _a = 1
            _alpha = 0
            _i = 0
    else:
        updateLock = False
    if choice == '2nd':
        _2nd = not _2nd
        _i = 0
        if _2nd:
            _i = 1
        choice = ''
    elif choice == 'alpha':
        if _2nd:
            _2nd = False
            _alock = not _alock
            _i = 2
            if _alock:
                _a = 0
                _alpha = 1
            else:
                _a = 1
                _alpha = 0
                _i = 0
            updateLock = True
        else:
            _alpha += 1
            if _alpha > 2:
                if _alock:
                    _alpha = 1
                else:
                    _alpha = 0
                    _i = 0
            if _alpha:
                _i = _alpha + 1
        choice = ''
    if choice == '':
        gr.setColor(_light_blue)
        w = 14
        if updateLock:
            w += 14
        gr.fillRect(292, 32, w, 16)
        gr.setColor(_black)
        gr.drawString(_indics[_i], 292, 34)
        if updateLock:
            gr.drawString(_lock[_a], 306, 34)
    return choice

# ------------------------------
# _key_selection( valid-keys )
#
# Get key selection, only those keys in the valid_keys list passed
# in are accepted.
#
# valid_rects if present is a list of tuples of the form (x,y,x2,y2)
# that is used to determine if the mouse x,y point is inside the
# rectangle with upper left corner at x,y and bottom right corner at
# x2,y2.
# index 0 rectangle will return choice '1', index 1 is choice '2',
# etc.
# ------------------------------


def _key_selection(valid_keys, indic=False):
    global _screen_cap
    choice = ''
    count = 0
    while choice not in valid_keys:
        wait(0.05)
        k = getKey(0)
        if not indic:
            if k == 71:
                k = 0
                _screen_cap = not _screen_cap
        count += 1
        if k == 0 and count >= 20:
            count = 0
            # keep link active at least once per second.
            attached = _bta.isBtaAttached()
            if not attached:
                return 'none'
        else:
            choice = _mapKeyToString(k)
            if indic and choice in ('2nd', 'alpha'):
                choice = _drawIndic(choice)
    return choice

# ------------------------------
# _textrow(r)
#
# Compute pixel row for text draw given text row number from 0 to 11
# ------------------------------


def _textrow(r):
    return (r * _per_line) + 33

# ------------------------------
# _getfont(fs)
#
# Based on incoming parameter, return a font style to use.
# ------------------------------


def _getfont(fs):
    if fs >= 0 and fs <= 2:
        return _fonts[fs]
    return _fonts[1]

# ------------------------------
# _draw_centered_text(row,text,fs)
#
# Draws text on a given screen row, centered on that row, default
# is medium font, optional large (2) or smalld (0) fonts available.
# ------------------------------


def _draw_centered_text(row, txt, fs=1):
    f = _getfont(fs)
    _w, _h = gr.string_size(txt, f)
    _x = 160 - (_w / 2)
    if _x < _left_column:
        _x = _left_column
    _y = _textrow(row)
    gr.setFont(f)
    gr.drawString(txt, _x, _y)
    if fs != 1:
        gr.setFont(_getfont(1))
    return

# ------------------------------
# _draw_context_title(text)
#
# Draws the title bar of the screen
# in white text, on reverse light
# blue background, with the text
# having a darker background.
# ------------------------------


def _draw_context_title(title):
    gr.cls()
    gr.setPen(gr.Style.SMOOTH, 0)
    gr.setColor(_light_blue)
    gr.fillRect(0, 30, 320, 20)
    gr.setColor(_ltgray)
    gr.drawLine(0, 51, 319, 51)
    gr.setColor(_background)
    gr.drawLine(0, 50, 319, 50)
    gr.setFont(_getfont(0))
    w, h = gr.string_size(title, _getfont(0))
    gr.fillRect(6, 32, w + 12, 18)
    gr.setPixel(6, 32, _light_blue)
    gr.setPixel(6, 33, _light_blue)
    gr.setPixel(7, 32, _light_blue)
    gr.setPixel(w + 17, 32, _light_blue)
    gr.setPixel(w + 16, 32, _light_blue)
    gr.setPixel(w + 17, 33, _light_blue)
    gr.setColor(_white)
    gr.drawString(title, 12, 34)
    gr.setColor(_black)
    gr.setFont(_getfont(1))
    return

# ------------------------------
# _split_string()
#
# Splits incoming string on spaces.
# ------------------------------


def _split_string(t, f):
    w, h = gr.string_size(t, f)
    st1 = t
    st2 = None
    while w > 310:
        en = st1.rfind(' ')
        st2 = t[en:len(t)]
        st1 = t[0:en]
        w, h = gr.string_size(st1, f)
    return st1, st2

# ------------------------------
# draw_small_text()
#
# Draw text left oriented in small font, with line splitting
# if text being drawn would go past end of screen on right.
# ------------------------------


def _draw_small_text(c, r, t):
    f = _getfont(0)
    gr.setFont(f)
    st = t
    i = 0
    while st is not None:
        st, st2 = _split_string(st, f)
        gr.drawString(st, c, _textrow(r + i))
        st = st2
        i += 1
    gr.setFont(_getfont(1))
    return

# ------------------------------
# draw_text()
#
# Draw text in medium font.
# ------------------------------


def draw_text(c, r, t):
    gr.drawString(t, c, r)
    return

# ------------------------------
# _draw_menu(menu-struct-array)
#
# Draw a screen of information, starting at text line given, and
# continuing until the menu array has been fully drawn.
# ------------------------------


def _draw_menu(menu_array):
    for i in range(len(menu_array)):
        draw_text(_left_column, _textrow(i + 2), menu_array[i][_locale])
    return

# ------------------------------
# _forget_named_robot(name)
#
# Manage the FORGET <named> ROBOT screen in the UI flow layout.
# Returns after disconnecting and forgetting the current configured
# robot, or "esc" and do not forget.
# ------------------------------


def _forget_named_robot(name):
    _draw_context_title(_forget_this[_locale])
    _draw_softmenu(_forget_menu)
    _draw_small_text(_left_column, 2, _forget1[_locale])
    _draw_small_text(_left_column, 5, _forget2[_locale])
    p_choice = _key_selection(_F1_F5_keys)
    if p_choice == 'F5':
        if _bta.isConnected():
            _bta.disconnect()
        _bta.clearBta()
        p_choice = ''
    return p_choice

# ------------------------------
# _validNameKeys()
#
# Set list of keys we use for name entry
# ------------------------------


def _validNameKeys():
    ky = ['enter', 'del', 'down', 'up', 'none', 'esc', 'F1', 'F5']
    return ky + _lcalpha + _ucalpha

# ------------------------------
# _update_robot()
#
# used to edit color and name
# ------------------------------


def _update_robot(oldName, oldPers):
    # Draw UI header and current robot info
    _draw_context_title(_edit_robot_title[_locale])
    _draw_softmenu(_done_menu)
    gr.setColor(_darkgray)
    gr.setFont(_getfont(0))
    gr.drawString(_current_name[_locale] + " " + oldName, _left_column, _textrow(2))
    gr.setFont(_getfont(1))
    gr.setColor(_black)
    gr.drawString(_my_name[_locale], _left_column, _textrow(4))
    gr.drawString(_my_color[_locale], _left_column, _textrow(5))
    gr.setColor(_the_colors[oldPers])
    gr.fillRect(_left_column + 100, _textrow(5) + 2, _color_bar_w, _color_bar_h)
    gr.setColor(_black)

    # State machine: edit name or color
    mode='name'
    name=oldName
    pers=oldPers
    while True:
        if mode=='name':
            k,name=_update_robot_name(name)
        else:
            k,pers=_update_robot_color(pers)
        if k in ('enter','F5'):
            if name != oldName:
                _bta.setName(name)
            if pers != oldPers:
                _bta.set_personality(pers)
            break
        elif k in ('up','down'):
            mode='color' if mode=='name' else 'name'
        elif k in ('F1','none'):
            break

    return k,name,pers

# ------------------------------
# _update_robot_name(curr-name)
#
# Manage the EDIT ROBOT screen in the UI flow layout.
# Enter a new name beginning with an alpha character and having
# alphas or digits in the name afterward, up to 10 characters long.
# ------------------------------


def _update_robot_name(oldName):
    global _alpha, _alock
    _good_keys = ('enter', 'down', 'up', 'none', 'F1', 'F5')
    _name_keys = _validNameKeys()
    _isFull = 0
    _doUpdate = False
    _noDig = True
    _alpha = 2
    _alock = True
    _drawIndic('')
    n_choice = ''
    name = ''
    gr.drawString(_my_name[_locale] + " " + name + _cursor[_isFull], _left_column, _textrow(4))
    while not (n_choice in _good_keys):
        if n_choice == 'del':
            if len(name) > 1:
                name = name[:len(name) - 1]
            else:
                name = ''
            n_choice = ''
            _doUpdate = True
        elif n_choice == 'esc':
            name = ''
            n_choice = ''
            _isFull = 0
            _doUpdate = True
        if name == '' and _noDig == False:
            _noDig = True
            _name_keys = _validNameKeys()
        if len(name) < 10:
            _isFull = 0
            if n_choice in _name_keys:
                name += n_choice
                if len(name) == 10:
                    _isFull = 1
                _doUpdate = True
                if len(name) == 1 and _noDig:
                    # once we have an alphachar as first, add digits to valid
                    # keys
                    _name_keys += _digits
                    _noDig = False
        if _doUpdate:
            clear_rect(_left_column, _textrow(4), 200, _per_line)
            gr.drawString(_my_name[_locale] + " " + name + _cursor[_isFull], _left_column, _textrow(4))
            _doUpdate = False
        n_choice = _key_selection(_name_keys, True)
    _alpha = 0
    _alock = False
    _drawIndic('')
    clear_rect(_left_column, _textrow(4), 200, _per_line)
    gr.drawString(_my_name[_locale] + " " + name, _left_column, _textrow(4))
    rv = n_choice
    return rv, name

# ------------------------------
# _update_robot_color(current)
# ------------------------------


def _update_robot_color(current_personality):
    _pers = -1
    _current = current_personality
    rv = ''
    while rv == '':
        if _pers != _current:
            _pers = _current
            gr.setColor(_the_colors[_pers])
            gr.fillRect(_left_column+100, _textrow(5)+2, _color_bar_w, _color_bar_h)
            gr.setColor(_darkgray)
            gr.drawString(_left_right, _left_column+116+_color_bar_w, _textrow(5))
            gr.setColor(_black)
        p_choice = _key_selection(_pers_keys)
        if p_choice != '':
            if _bta.isBtaAttached():
                if p_choice == 'left':
                    _current -= 1
                    if _current < 1:
                        _current = 6
                elif p_choice == 'right':
                    _current += 1
                    if _current > 6:
                        _current = 1
                elif p_choice in ('F5', 'F1', 'enter', 'up', 'down'):
                    rv = p_choice
            else:
                rv = 'none'
    return rv, _current

# ------------------------------
# _namedRobotNotFound(robot-name)
#
# Manage the ROBOT NOT FOUND screen with a named robot.
# ------------------------------


def _namedRobotNotFound(robot_name):
    _draw_context_title(_not_found[_locale])
    _draw_small_text( _left_column, 3, "'"+robot_name+ _not_available2[_locale] )
    _draw_small_text(_left_column, 7, _not_available3[_locale])
    _draw_softmenu(_search_forget)
    n_choice = _key_selection(_search_keys)
    return n_choice

# ------------------------------
# _noRobotsFound()
#
# Manage the NO ROBOT FOUND screen with no robots
# ------------------------------


def _noRobotsFound():
    _draw_context_title(_none_found[_locale])
    _draw_small_text(_left_column, 2, _turn_them_on[_locale])
    _draw_softmenu(_search_again)
    n_choice = _key_selection(_F1_F5_keys)
    return n_choice

# ------------------------------
# _do_help()
#
# Display help screen.
# ------------------------------


def _do_help():
    _draw_context_title(_help[_locale])
    _draw_small_text(_left_column, 2, _help1[_locale])
    _draw_small_text(_left_column, 7, _help2[_locale])
    _draw_softmenu(_help_menu)
    n_choice = _key_selection(_F1_F5_keys)
    return n_choice

# ------------------------------
# _missingRobot()
#
# No (named) robots found...
# ------------------------------


def _missingRobot(in_name):
    if in_name != '':
        k = _namedRobotNotFound(in_name)
    else:
        k = _noRobotsFound()
    if k == 'F1':
        please_wait(0)
        k = 'loop'  # search again!
    elif k == 'F5':
        k = 'quit'
    return k

# ------------------------------
# _pickRobot()
#
# Pick a robot from list
# ------------------------------


def _pickRobot(in_name):
    _draw_context_title(_select_robot[_locale])
    y_off = _textrow(2)
    n = 1
    gr.setColor(_black)
    for i in range(_bot_count):
        robot_name = _bot_names[i]
        charge = _bot_charges[i]
        gr.drawString(str(n) + ':', _left_column - 2, y_off)
        gr.drawString(robot_name, _left_column + 80, y_off)
        # color for robot personality
        gr.setColor(_the_colors[_bot_colors[i]])
        gr.fillRect(_left_column + 18, y_off + 3, _color_bar_w, _color_bar_h)
        gr.setColor(_background)
        gr.drawRect(_left_column + 18, y_off + 2, _color_bar_w, _color_bar_h)
        # do we draw the low battery icon?
        if charge <= 20:
            gr.setColor(_red)
            gr.drawRect(_left_column + 56, y_off + 4, 12, 6)
            gr.fillRect(_left_column + 68, y_off + 5, 3, 5)
        # do we draw the connected icon?
        if robot_name == in_name:
            gr.setColor(_medgray)
            w, h = gr.string_size(robot_name)
            gr.drawString(_current[_locale], _left_column + 94 + w, y_off)
        gr.setColor(_black)
        y_off += _per_line
        n += 1
        # end for
    _draw_softmenu(_search_quit)
    k = 'loop'
    while k == 'loop':
        k = _key_selection(_robot_keys)
        if k == 'F3':
            k = ''  # exit and loop on outer loop!
        elif k >= '1' and k <= '5':
            if int(k) > _bot_count:
                k = 'loop'
        elif k == 'F1':
            if in_name != '':
                please_wait(1)
                r = _reconnect()
        elif k == 'F5':
            k = 'quit'
        elif k == 'none':
            pass
        else:
            k = 'loop'
    return k

# ------------------------------
# _scanning_for_robots(name)
#
# Scans for robots, building list of what is found.  Then, draws
# robot selection menu and waits for selection, or quit program
# ------------------------------


def _scanning_for_robots(in_name):
    global _bot_macs
    global _bot_colors
    global _bot_charges
    global _bot_names
    global _bot_count

    please_wait(0)
    if not _bta.isBtaAttached():
        return 'none'
    k = 'loop'
    while k == 'loop':
        _disconnect()
        the_bots = _bta.discover()
        number_of_bots = len(the_bots)
        _bot_macs = []
        _bot_colors = []
        _bot_charges = []
        _bot_names = []
        _bot_count = 0
        if number_of_bots > 0:
            for n in range(number_of_bots):
                if len(the_bots[n]) == 7:
                    _bot_macs += [the_bots[n][0]]
                    _bot_colors += [int(the_bots[n][2])]
                    _bot_charges += [int(the_bots[n][5], 16)]
                    _bot_names += [the_bots[n][6]]
                    _bot_count += 1
        if _bot_count == 0:
            k = _missingRobot(in_name)
        else:
            k = _pickRobot(in_name)
            if k == '':
                k = 'loop'  # outer loop!
    return k

# ------------------------------
# _current_connection(robot-name,personality,batt-level)
#
# Manages the current connection display screen and menu options
# ------------------------------


def _current_connection(name, pers, batt):
    m = 0
    drawn = False
    _draw_context_title(_current_conn[_locale])
    _draw_menu(_menu)
    gr.setColor(_black)
    gr.setFont(_getfont(1))
    gr.drawString(name, _left_column + 100, _textrow(2))
    _tx = _batt_ok[_locale]
    if batt <= 20:
        _tx = _batt_low[_locale]
        gr.setColor(_medgray)
        _draw_small_text(_left_column, 7, _low_warn[_locale])
        gr.setColor(_red)
    gr.drawString(_tx, _left_column + 100, _textrow(4))
    gr.setColor(_the_colors[pers])
    gr.fillRect(_left_column + 100, _textrow(3) + 2, _color_bar_w, _color_bar_h)
    gr.setColor(_black)
    k = ''
    while k == '':
        if not drawn:
            if m == 0:
                _draw_softmenu(_conn_menu)
            elif m == 1:
                _draw_softmenu(_conn_menu2)
            drawn = True

        k = _key_selection(_conn_keys)
        if k == 'F2':
            k = ''
            _bta.identify()
        if k == 'F4':
            k = ''
            if m == 0:
                m = 1
            else:
                m = 0
            drawn = False
    if k == 'F5':
        k = 'quit'
    return k, m

# ------------------------------
# confirmQuit()
#
# Confirm whether or not we really want to quit
# ------------------------------


def confirmQuit():
    _draw_context_title(_quit[_locale])
    _draw_small_text(_left_column, 2, _sure[_locale])
    _draw_softmenu(_quit_confirm)
    n_choice = _key_selection(_quit_keys)
    if n_choice == 'F5':
        return True
    return False

# ==============================
# Primary app UI entry point
# ==============================


def doSetDash():
    _not_completed = True
    pidx = 0
    rn = ''
    cn_name = ''
    k = ''
    while _not_completed:
        if _bta.isBtaConfigured():
            rn = _bta.readSlot(5)
            cn_name = rn
        cn = _bta.isConnected()
        if not cn:
            k = _scanning_for_robots(rn)
        else:
            cn_name = _bta.readName()
            if not _bta.areSensorsEnabled():
                _bta.enableSensors()
            pidx = _bta.read_personality()
            batt = battery_level()
            k, option = _current_connection(cn_name, pidx, batt)
            if option == 0:
                if k == 'F1':
                    k = ''
                    while k == '':
                        k, rn, px = _update_robot(cn_name, pidx)
                        if k != 'none':
                            please_wait(2)
                            if k == 'F5' or k == 'enter':
                                cn_name = rn
                                pidx = px
                                k = 'done'
                            elif k == 'F1':
                                _bta.set_personality(pidx)
                                _bta.setName(cn_name)
                                k = 'done'
                            else:
                                k = ''
                elif k == 'F3':
                    k = _forget_named_robot(cn_name)
                    if k == '':
                        cn_name = ''
                        rn = ''
                        cn = False
            elif option == 1:
                if k == 'F1':
                    k = _scanning_for_robots(cn_name)
                elif k == 'F3':
                    k = _do_help()
            if k == 'F5':
                k = 'quit'
        if k == 'quit':
            _not_completed = False
        elif k == 'F3':
            k = _forget_named_robot(cn_name)
            if k == '':
                cn_name = ''
                rn = ''
                cn = False
        elif k == 'none':
            return True
        elif k == '' or k == 'esc' or k == 'enter':
            pass
        # picked a robot...
        elif k >= '1' and k <= '5' and k <= str(_bot_count):
            sel = int(k) - 1
            k = 1
            while k != 0:
                please_wait(1)
                k = _doConnect(_bot_macs[sel])
                if k == 0:  # dash is connected to, verify connection
                    cn = _bta.isConnected()
                    if not cn:
                        cn = _bta.isConnected()
                    if not cn:
                        k = 1  # do a retry on the connection.
                elif k == 2:  # robot missing or not available
                    rn = _bot_names[sel]
                    cn_name = rn
                    k = _namedRobotNotFound(rn)
                    cn = False
                    if k != 'none':
                        k = 0
                    else:
                        return True
                elif k == -1:
                    return True
        if not _not_completed:
            # if we are exiting/quiting, ask for confirmation
            if confirmQuit() == False:
                _not_completed = True
    return False


# ==============================
# Run the script - main script loop.
# ==============================
_runscript = True
_locale = get_locale()
while _runscript:
    try:
        _runscript = setDashSplash()
        if _runscript:
            _runscript = doSetDash()
    except KeyboardInterrupt:
        if confirmQuit():
            _runscript = False
            gr.cls()
_exit()
# ==============================

