touch: P4 always-external antenna, slim landscape composer, Glass tiles switch
- T-Display P4 (CAP_ANTENNA_SELECT): Radio settings "Always use the external antenna (MMCX)". Boot selects the external socket only with this opt-in, which asks first with a damage warning. Own NVS key ant_ext (never the reserved cfg byte p4_antenna), left out of the settings backup. Turning it off goes back to the on-board antenna at once. The control panel gets an Antenna tile (filled + "MMCX" on external); a tap asks for the external socket through the same warning, hold opens Radio settings. - Large screens in landscape (P4 landscape, Tanmatsu, CrowPanel 5.0/10.1): the empty composer text box is one line tall and grows from there; the row stays as tall as its buttons and a shorter box sits centred on them. P4 portrait two-row layout unchanged. - Settings > Theme > Background: "Glass tiles" (default on). Off draws Home widgets, cards, the control panel and its tiles solid. Pending + Apply. - 11 new strings translated in all 14 languages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5833e00d25
commit
f71a42ef0e
20 files changed
+479
-67
No files matched your search
@@ -1998,3 +1998,14 @@ newer keyboard по-нова клавиатура
|
||||
older keyboard по-стара клавиатура
|
||||
older keyboard (set manually) по-стара клавиатура (ръчно)
|
||||
keyboard not detected yet клавиатурата още не е разпозната
|
||||
Always use the external antenna (MMCX) Винаги външната антена (MMCX)
|
||||
Starts on the external socket at every boot. Only for an antenna that stays connected. Стартира на външния конектор при всяко включване. Само за антена, която остава свързана.
|
||||
Only pick External with an antenna fitted to the external socket. After a reboot it starts on the on-board antenna, unless the switch below is on. Избирайте Външна само с антена на външния конектор. След рестарт започва на вградената антена, освен ако превключвателят по-долу е включен.
|
||||
Always use the external antenna?\n\nThe radio will start on the external (MMCX) socket at every boot. Transmitting without an antenna attached can damage the radio.\n\nOnly turn this on if your external antenna stays connected. Винаги да се ползва външната антена?\n\nРадиото ще стартира на външния конектор (MMCX) при всяко включване. Предаване без свързана антена може да повреди радиото.\n\nВключете това само ако външната антена остава свързана.
|
||||
Turn on Включи
|
||||
On-board antenna selected Избрана е вградената антена
|
||||
External antenna at every boot Външна антена при всяко включване
|
||||
Antenna Антена
|
||||
On-board Вградена
|
||||
Glass tiles Стъклени плочки
|
||||
Widgets, cards and panel tiles let the background show through. Off: solid tiles. Джаджите, картите и плочките в панела пропускат фона. Изключено: плътни плочки.
|
||||
@@ -2014,3 +2014,14 @@ newer keyboard novější klávesnice
|
||||
older keyboard starší klávesnice
|
||||
older keyboard (set manually) starší klávesnice (nastaveno ručně)
|
||||
keyboard not detected yet klávesnice zatím nerozpoznána
|
||||
Always use the external antenna (MMCX) Vždy používat externí anténu (MMCX)
|
||||
Starts on the external socket at every boot. Only for an antenna that stays connected. Při každém spuštění začne na externím konektoru. Jen pro anténu, která zůstává připojená.
|
||||
Only pick External with an antenna fitted to the external socket. After a reboot it starts on the on-board antenna, unless the switch below is on. Externí vyberte jen s anténou na externím konektoru. Po restartu začne na vestavěné anténě, pokud není zapnutý přepínač níže.
|
||||
Always use the external antenna?\n\nThe radio will start on the external (MMCX) socket at every boot. Transmitting without an antenna attached can damage the radio.\n\nOnly turn this on if your external antenna stays connected. Vždy používat externí anténu?\n\nRádio začne při každém spuštění na externím konektoru (MMCX). Vysílání bez připojené antény může rádio poškodit.\n\nZapněte to jen tehdy, když externí anténa zůstává připojená.
|
||||
Turn on Zapnout
|
||||
On-board antenna selected Vybrána vestavěná anténa
|
||||
External antenna at every boot Externí anténa při každém startu
|
||||
Antenna Anténa
|
||||
On-board Vestavěná
|
||||
Glass tiles Skleněné dlaždice
|
||||
Widgets, cards and panel tiles let the background show through. Off: solid tiles. Widgety, karty a dlaždice panelu nechají prosvítat pozadí. Vypnuto: plné dlaždice.
|
||||
@@ -1995,3 +1995,14 @@ newer keyboard neuere Tastatur
|
||||
older keyboard ältere Tastatur
|
||||
older keyboard (set manually) ältere Tastatur (manuell gesetzt)
|
||||
keyboard not detected yet Tastatur noch nicht erkannt
|
||||
Always use the external antenna (MMCX) Immer die externe Antenne nutzen (MMCX)
|
||||
Starts on the external socket at every boot. Only for an antenna that stays connected. Startet bei jedem Booten an der externen Buchse. Nur für eine Antenne, die dauerhaft angeschlossen bleibt.
|
||||
Only pick External with an antenna fitted to the external socket. After a reboot it starts on the on-board antenna, unless the switch below is on. Extern nur wählen, wenn eine Antenne an der externen Buchse steckt. Nach einem Neustart läuft es über die interne Antenne, außer der Schalter unten ist an.
|
||||
Always use the external antenna?\n\nThe radio will start on the external (MMCX) socket at every boot. Transmitting without an antenna attached can damage the radio.\n\nOnly turn this on if your external antenna stays connected. Immer die externe Antenne nutzen?\n\nDas Funkmodul startet bei jedem Booten an der externen Buchse (MMCX). Senden ohne angeschlossene Antenne kann das Funkmodul beschädigen.\n\nNur einschalten, wenn deine externe Antenne angeschlossen bleibt.
|
||||
Turn on Einschalten
|
||||
On-board antenna selected Interne Antenne gewählt
|
||||
External antenna at every boot Externe Antenne bei jedem Start
|
||||
Antenna Antenne
|
||||
On-board Intern
|
||||
Glass tiles Glas-Kacheln
|
||||
Widgets, cards and panel tiles let the background show through. Off: solid tiles. Widgets, Karten und Kacheln im Kontrollfeld lassen den Hintergrund durchscheinen. Aus: deckende Kacheln.
|
||||
@@ -1998,3 +1998,14 @@ newer keyboard νεότερο πληκτρολόγιο
|
||||
older keyboard παλαιότερο πληκτρολόγιο
|
||||
older keyboard (set manually) παλαιότερο πληκτρολόγιο (χειροκίνητα)
|
||||
keyboard not detected yet το πληκτρολόγιο δεν έχει εντοπιστεί ακόμα
|
||||
Always use the external antenna (MMCX) Πάντα η εξωτερική κεραία (MMCX)
|
||||
Starts on the external socket at every boot. Only for an antenna that stays connected. Ξεκινά στην εξωτερική υποδοχή σε κάθε εκκίνηση. Μόνο για κεραία που μένει συνδεδεμένη.
|
||||
Only pick External with an antenna fitted to the external socket. After a reboot it starts on the on-board antenna, unless the switch below is on. Επιλέξτε Εξωτερική μόνο με κεραία στην εξωτερική υποδοχή. Μετά από επανεκκίνηση ξεκινά στην ενσωματωμένη κεραία, εκτός αν ο διακόπτης παρακάτω είναι ενεργός.
|
||||
Always use the external antenna?\n\nThe radio will start on the external (MMCX) socket at every boot. Transmitting without an antenna attached can damage the radio.\n\nOnly turn this on if your external antenna stays connected. Πάντα η εξωτερική κεραία;\n\nΟ πομποδέκτης θα ξεκινά στην εξωτερική υποδοχή (MMCX) σε κάθε εκκίνηση. Η εκπομπή χωρίς συνδεδεμένη κεραία μπορεί να καταστρέψει τον πομποδέκτη.\n\nΕνεργοποιήστε το μόνο αν η εξωτερική κεραία μένει συνδεδεμένη.
|
||||
Turn on Ενεργοποίηση
|
||||
On-board antenna selected Επιλέχθηκε η ενσωματωμένη κεραία
|
||||
External antenna at every boot Εξωτερική κεραία σε κάθε εκκίνηση
|
||||
Antenna Κεραία
|
||||
On-board Ενσωμ.
|
||||
Glass tiles Γυάλινα πλακίδια
|
||||
Widgets, cards and panel tiles let the background show through. Off: solid tiles. Τα widget, οι κάρτες και τα πλακίδια του πίνακα αφήνουν να φαίνεται το φόντο. Ανενεργό: συμπαγή πλακίδια.
|
||||
@@ -1998,3 +1998,14 @@ newer keyboard teclado nuevo
|
||||
older keyboard teclado antiguo
|
||||
older keyboard (set manually) teclado antiguo (ajustado a mano)
|
||||
keyboard not detected yet teclado aún no detectado
|
||||
Always use the external antenna (MMCX) Usar siempre la antena externa (MMCX)
|
||||
Starts on the external socket at every boot. Only for an antenna that stays connected. Arranca en el conector externo en cada inicio. Solo para una antena que queda conectada.
|
||||
Only pick External with an antenna fitted to the external socket. After a reboot it starts on the on-board antenna, unless the switch below is on. Elige Externa solo con una antena puesta en el conector externo. Tras reiniciar arranca en la antena integrada, salvo que el interruptor de abajo esté activado.
|
||||
Always use the external antenna?\n\nThe radio will start on the external (MMCX) socket at every boot. Transmitting without an antenna attached can damage the radio.\n\nOnly turn this on if your external antenna stays connected. ¿Usar siempre la antena externa?\n\nLa radio arrancará en el conector externo (MMCX) en cada inicio. Transmitir sin una antena conectada puede dañar la radio.\n\nActívalo solo si tu antena externa queda conectada.
|
||||
Turn on Activar
|
||||
On-board antenna selected Antena integrada seleccionada
|
||||
External antenna at every boot Antena externa en cada inicio
|
||||
Antenna Antena
|
||||
On-board Integrada
|
||||
Glass tiles Mosaicos de cristal
|
||||
Widgets, cards and panel tiles let the background show through. Off: solid tiles. Los widgets, tarjetas y mosaicos del panel dejan ver el fondo. Apagado: mosaicos sólidos.
|
||||
@@ -1997,3 +1997,14 @@ newer keyboard clavier récent
|
||||
older keyboard ancien clavier
|
||||
older keyboard (set manually) ancien clavier (réglé manuellement)
|
||||
keyboard not detected yet clavier pas encore détecté
|
||||
Always use the external antenna (MMCX) Toujours utiliser l'antenne externe (MMCX)
|
||||
Starts on the external socket at every boot. Only for an antenna that stays connected. Démarre sur la prise externe à chaque démarrage. Seulement pour une antenne qui reste branchée.
|
||||
Only pick External with an antenna fitted to the external socket. After a reboot it starts on the on-board antenna, unless the switch below is on. Ne choisissez Externe qu'avec une antenne branchée sur la prise externe. Après un redémarrage, c'est l'antenne embarquée, sauf si l'interrupteur ci-dessous est activé.
|
||||
Always use the external antenna?\n\nThe radio will start on the external (MMCX) socket at every boot. Transmitting without an antenna attached can damage the radio.\n\nOnly turn this on if your external antenna stays connected. Toujours utiliser l'antenne externe ?\n\nLa radio démarrera sur la prise externe (MMCX) à chaque démarrage. Émettre sans antenne branchée peut endommager la radio.\n\nN'activez ceci que si votre antenne externe reste branchée.
|
||||
Turn on Activer
|
||||
On-board antenna selected Antenne embarquée sélectionnée
|
||||
External antenna at every boot Antenne externe à chaque démarrage
|
||||
Antenna Antenne
|
||||
On-board Interne
|
||||
Glass tiles Tuiles en verre
|
||||
Widgets, cards and panel tiles let the background show through. Off: solid tiles. Les widgets, cartes et tuiles du panneau laissent voir le fond. Désactivé : tuiles opaques.
|
||||
@@ -2008,3 +2008,14 @@ newer keyboard újabb billentyűzet
|
||||
older keyboard régebbi billentyűzet
|
||||
older keyboard (set manually) régebbi billentyűzet (kézzel beállítva)
|
||||
keyboard not detected yet a billentyűzet még nincs felismerve
|
||||
Always use the external antenna (MMCX) Mindig a külső antenna (MMCX)
|
||||
Starts on the external socket at every boot. Only for an antenna that stays connected. Minden indításkor a külső csatlakozón indul. Csak tartósan csatlakoztatott antennához.
|
||||
Only pick External with an antenna fitted to the external socket. After a reboot it starts on the on-board antenna, unless the switch below is on. Külsőt csak akkor válassz, ha antenna van a külső csatlakozón. Újraindítás után a beépített antennán indul, kivéve ha az alábbi kapcsoló be van kapcsolva.
|
||||
Always use the external antenna?\n\nThe radio will start on the external (MMCX) socket at every boot. Transmitting without an antenna attached can damage the radio.\n\nOnly turn this on if your external antenna stays connected. Mindig a külső antennát használod?\n\nA rádió minden indításkor a külső (MMCX) csatlakozón indul. Antenna nélküli adás károsíthatja a rádiót.\n\nCsak akkor kapcsold be, ha a külső antenna csatlakoztatva marad.
|
||||
Turn on Bekapcsol
|
||||
On-board antenna selected Beépített antenna kiválasztva
|
||||
External antenna at every boot Külső antenna minden indításkor
|
||||
Antenna Antenna
|
||||
On-board Beépített
|
||||
Glass tiles Üveg csempék
|
||||
Widgets, cards and panel tiles let the background show through. Off: solid tiles. A widgetek, kártyák és a panel csempéi átengedik a hátteret. Ki: tömör csempék.
|
||||
@@ -1997,3 +1997,14 @@ newer keyboard tastiera nuova
|
||||
older keyboard tastiera vecchia
|
||||
older keyboard (set manually) tastiera vecchia (impostata a mano)
|
||||
keyboard not detected yet tastiera non ancora rilevata
|
||||
Always use the external antenna (MMCX) Usa sempre l'antenna esterna (MMCX)
|
||||
Starts on the external socket at every boot. Only for an antenna that stays connected. Si avvia sul connettore esterno a ogni accensione. Solo per un'antenna che resta collegata.
|
||||
Only pick External with an antenna fitted to the external socket. After a reboot it starts on the on-board antenna, unless the switch below is on. Scegli Esterna solo con un'antenna montata sul connettore esterno. Dopo un riavvio parte sull'antenna integrata, a meno che l'interruttore qui sotto sia attivo.
|
||||
Always use the external antenna?\n\nThe radio will start on the external (MMCX) socket at every boot. Transmitting without an antenna attached can damage the radio.\n\nOnly turn this on if your external antenna stays connected. Usare sempre l'antenna esterna?\n\nLa radio partirà sul connettore esterno (MMCX) a ogni accensione. Trasmettere senza un'antenna collegata può danneggiare la radio.\n\nAttivalo solo se la tua antenna esterna resta collegata.
|
||||
Turn on Attiva
|
||||
On-board antenna selected Antenna integrata selezionata
|
||||
External antenna at every boot Antenna esterna a ogni avvio
|
||||
Antenna Antenna
|
||||
On-board Integrata
|
||||
Glass tiles Riquadri in vetro
|
||||
Widgets, cards and panel tiles let the background show through. Off: solid tiles. Widget, schede e riquadri del pannello lasciano vedere lo sfondo. Spento: riquadri pieni.
|
||||
@@ -1995,3 +1995,14 @@ newer keyboard nieuwer toetsenbord
|
||||
older keyboard ouder toetsenbord
|
||||
older keyboard (set manually) ouder toetsenbord (handmatig ingesteld)
|
||||
keyboard not detected yet toetsenbord nog niet herkend
|
||||
Always use the external antenna (MMCX) Altijd de externe antenne gebruiken (MMCX)
|
||||
Starts on the external socket at every boot. Only for an antenna that stays connected. Start bij elke opstart op de externe aansluiting. Alleen voor een antenne die aangesloten blijft.
|
||||
Only pick External with an antenna fitted to the external socket. After a reboot it starts on the on-board antenna, unless the switch below is on. Kies Extern alleen met een antenne op de externe aansluiting. Na een herstart begint hij op de ingebouwde antenne, tenzij de schakelaar hieronder aan staat.
|
||||
Always use the external antenna?\n\nThe radio will start on the external (MMCX) socket at every boot. Transmitting without an antenna attached can damage the radio.\n\nOnly turn this on if your external antenna stays connected. Altijd de externe antenne gebruiken?\n\nDe radio start bij elke opstart op de externe (MMCX) aansluiting. Zenden zonder aangesloten antenne kan de radio beschadigen.\n\nZet dit alleen aan als je externe antenne aangesloten blijft.
|
||||
Turn on Aanzetten
|
||||
On-board antenna selected Ingebouwde antenne geselecteerd
|
||||
External antenna at every boot Externe antenne bij elke opstart
|
||||
Antenna Antenne
|
||||
On-board Intern
|
||||
Glass tiles Glazen tegels
|
||||
Widgets, cards and panel tiles let the background show through. Off: solid tiles. Widgets, kaarten en tegels in het bedieningspaneel laten de achtergrond doorschijnen. Uit: effen tegels.
|
||||
@@ -1997,3 +1997,14 @@ newer keyboard teclado novo
|
||||
older keyboard teclado antigo
|
||||
older keyboard (set manually) teclado antigo (definido manualmente)
|
||||
keyboard not detected yet teclado ainda não detectado
|
||||
Always use the external antenna (MMCX) Sempre usar a antena externa (MMCX)
|
||||
Starts on the external socket at every boot. Only for an antenna that stays connected. Inicia no conector externo a cada boot. Só para uma antena que fica conectada.
|
||||
Only pick External with an antenna fitted to the external socket. After a reboot it starts on the on-board antenna, unless the switch below is on. Escolha Externa só com uma antena no conector externo. Depois de reiniciar, começa na antena embutida, a menos que a chave abaixo esteja ligada.
|
||||
Always use the external antenna?\n\nThe radio will start on the external (MMCX) socket at every boot. Transmitting without an antenna attached can damage the radio.\n\nOnly turn this on if your external antenna stays connected. Sempre usar a antena externa?\n\nO rádio vai iniciar no conector externo (MMCX) a cada boot. Transmitir sem uma antena conectada pode danificar o rádio.\n\nSó ligue isto se a sua antena externa ficar conectada.
|
||||
Turn on Ligar
|
||||
On-board antenna selected Antena embutida selecionada
|
||||
External antenna at every boot Antena externa a cada boot
|
||||
Antenna Antena
|
||||
On-board Embutida
|
||||
Glass tiles Blocos de vidro
|
||||
Widgets, cards and panel tiles let the background show through. Off: solid tiles. Widgets, cartões e blocos do painel deixam o fundo aparecer. Desligado: blocos sólidos.
|
||||
@@ -1999,3 +1999,14 @@ newer keyboard tastatură nouă
|
||||
older keyboard tastatură veche
|
||||
older keyboard (set manually) tastatură veche (setată manual)
|
||||
keyboard not detected yet tastatura nu a fost detectată încă
|
||||
Always use the external antenna (MMCX) Folosește mereu antena externă (MMCX)
|
||||
Starts on the external socket at every boot. Only for an antenna that stays connected. Pornește pe conectorul extern la fiecare pornire. Doar pentru o antenă care rămâne conectată.
|
||||
Only pick External with an antenna fitted to the external socket. After a reboot it starts on the on-board antenna, unless the switch below is on. Alege Externă doar cu o antenă montată pe conectorul extern. După o repornire pornește pe antena integrată, dacă comutatorul de mai jos nu este activ.
|
||||
Always use the external antenna?\n\nThe radio will start on the external (MMCX) socket at every boot. Transmitting without an antenna attached can damage the radio.\n\nOnly turn this on if your external antenna stays connected. Folosești mereu antena externă?\n\nRadioul va porni pe conectorul extern (MMCX) la fiecare pornire. Transmisia fără antenă conectată poate defecta radioul.\n\nActivează doar dacă antena externă rămâne conectată.
|
||||
Turn on Activează
|
||||
On-board antenna selected Antenă integrată selectată
|
||||
External antenna at every boot Antenă externă la fiecare pornire
|
||||
Antenna Antenă
|
||||
On-board Integrată
|
||||
Glass tiles Plăci de sticlă
|
||||
Widgets, cards and panel tiles let the background show through. Off: solid tiles. Widgeturile, cardurile și plăcile din panou lasă fundalul să se vadă. Oprit: plăci opace.
|
||||
@@ -1998,3 +1998,14 @@ newer keyboard новая клавиатура
|
||||
older keyboard старая клавиатура
|
||||
older keyboard (set manually) старая клавиатура (задано вручную)
|
||||
keyboard not detected yet клавиатура ещё не определена
|
||||
Always use the external antenna (MMCX) Всегда внешняя антенна (MMCX)
|
||||
Starts on the external socket at every boot. Only for an antenna that stays connected. При каждом запуске работает через внешний разъём. Только для антенны, которая остаётся подключённой.
|
||||
Only pick External with an antenna fitted to the external socket. After a reboot it starts on the on-board antenna, unless the switch below is on. Выбирайте Внешнюю только с антенной на внешнем разъёме. После перезагрузки включается встроенная антенна, если переключатель ниже не включён.
|
||||
Always use the external antenna?\n\nThe radio will start on the external (MMCX) socket at every boot. Transmitting without an antenna attached can damage the radio.\n\nOnly turn this on if your external antenna stays connected. Всегда использовать внешнюю антенну?\n\nРадио будет запускаться на внешнем разъёме (MMCX) при каждом включении. Передача без подключённой антенны может повредить радио.\n\nВключайте, только если внешняя антенна остаётся подключённой.
|
||||
Turn on Включить
|
||||
On-board antenna selected Выбрана встроенная антенна
|
||||
External antenna at every boot Внешняя антенна при каждом запуске
|
||||
Antenna Антенна
|
||||
On-board Встроен.
|
||||
Glass tiles Стеклянные плитки
|
||||
Widgets, cards and panel tiles let the background show through. Off: solid tiles. Виджеты, карточки и плитки панели пропускают фон. Выкл.: сплошные плитки.
|
||||
@@ -1998,3 +1998,14 @@ newer keyboard новија тастатура
|
||||
older keyboard старија тастатура
|
||||
older keyboard (set manually) старија тастатура (ручно подешено)
|
||||
keyboard not detected yet тастатура још није препозната
|
||||
Always use the external antenna (MMCX) Увек спољна антена (MMCX)
|
||||
Starts on the external socket at every boot. Only for an antenna that stays connected. При сваком покретању ради преко спољног прикључка. Само за антену која остаје прикључена.
|
||||
Only pick External with an antenna fitted to the external socket. After a reboot it starts on the on-board antenna, unless the switch below is on. Изаберите Спољну само са антеном на спољном прикључку. После поновног покретања креће на уграђеној антени, осим ако је прекидач испод укључен.
|
||||
Always use the external antenna?\n\nThe radio will start on the external (MMCX) socket at every boot. Transmitting without an antenna attached can damage the radio.\n\nOnly turn this on if your external antenna stays connected. Увек користити спољну антену?\n\nРадио ће се покретати на спољном прикључку (MMCX) при сваком укључивању. Слање без прикључене антене може оштетити радио.\n\nУкључите ово само ако спољна антена остаје прикључена.
|
||||
Turn on Укључи
|
||||
On-board antenna selected Изабрана уграђена антена
|
||||
External antenna at every boot Спољна антена при сваком покретању
|
||||
Antenna Антена
|
||||
On-board Уграђена
|
||||
Glass tiles Стаклене плочице
|
||||
Widgets, cards and panel tiles let the background show through. Off: solid tiles. Виџети, картице и плочице панела пропуштају позадину. Искључено: пуне плочице.
|
||||
@@ -1998,3 +1998,14 @@ newer keyboard новіша клавіатура
|
||||
older keyboard старіша клавіатура
|
||||
older keyboard (set manually) старіша клавіатура (задано вручну)
|
||||
keyboard not detected yet клавіатуру ще не визначено
|
||||
Always use the external antenna (MMCX) Завжди зовнішня антена (MMCX)
|
||||
Starts on the external socket at every boot. Only for an antenna that stays connected. Під час кожного запуску працює через зовнішній роз'єм. Лише для антени, що лишається підключеною.
|
||||
Only pick External with an antenna fitted to the external socket. After a reboot it starts on the on-board antenna, unless the switch below is on. Обирайте Зовнішню лише з антеною на зовнішньому роз'ємі. Після перезапуску вмикається вбудована антена, якщо перемикач нижче не ввімкнено.
|
||||
Always use the external antenna?\n\nThe radio will start on the external (MMCX) socket at every boot. Transmitting without an antenna attached can damage the radio.\n\nOnly turn this on if your external antenna stays connected. Завжди використовувати зовнішню антену?\n\nРадіо запускатиметься на зовнішньому роз'ємі (MMCX) під час кожного ввімкнення. Передавання без підключеної антени може пошкодити радіо.\n\nВмикайте, лише якщо зовнішня антена лишається підключеною.
|
||||
Turn on Увімкнути
|
||||
On-board antenna selected Вибрано вбудовану антену
|
||||
External antenna at every boot Зовнішня антена під час кожного запуску
|
||||
Antenna Антена
|
||||
On-board Вбудов.
|
||||
Glass tiles Скляні плитки
|
||||
Widgets, cards and panel tiles let the background show through. Off: solid tiles. Віджети, картки й плитки панелі пропускають тло. Вимк.: суцільні плитки.
|
||||
@@ -529,6 +529,13 @@ static const uint16_t SIG_POLL_MAX_MINS = 1440;
|
||||
// safety property only holds if a power cycle cannot restore "external", which means the
|
||||
// choice must never reach flash. p4_antenna stays as a reserved trailing byte: dropping it
|
||||
// would rewind TOUCH_CFG_VER on devices already carrying a v41 blob, for no gain.
|
||||
//
|
||||
// The one exception is an explicit opt-in: "Always use the external antenna (MMCX)" in Radio
|
||||
// settings, behind a damage warning, for owners whose external antenna stays fitted. It lives
|
||||
// in its OWN key ("ant_ext", default 0), never in p4_antenna: an old v41 blob may still carry a
|
||||
// stale 1 there from when the choice was persisted, and that must not turn external on silently.
|
||||
// It is left out of the settings backup on purpose, so restoring a backup onto a unit with no
|
||||
// antenna fitted cannot switch it to the empty socket either.
|
||||
|
||||
// --- Per-chat history cap -----------------------------------------------------
|
||||
// A single busy channel could previously fill the entire shared message ring, which both
|
||||
@@ -2478,6 +2485,10 @@ uint8_t touchPrefsGetColorStyle() {
|
||||
void touchPrefsSetColorStyle(uint8_t style) { if (!s_begun) touchPrefsBegin(); prefsPutUChar("col_style", style > TOUCH_LOOK_PASTEL ? TOUCH_LOOK_REGULAR : style); }
|
||||
bool touchPrefsGetRainbow() { if (!s_begun) touchPrefsBegin(); return s_prefs.getUChar("col_rb", 0) != 0; }
|
||||
void touchPrefsSetRainbow(bool on) { if (!s_begun) touchPrefsBegin(); prefsPutUChar("col_rb", on ? 1 : 0); }
|
||||
bool touchPrefsGetGlassTiles() { if (!s_begun) touchPrefsBegin(); return s_prefs.getUChar("glass", 1) != 0; }
|
||||
void touchPrefsSetGlassTiles(bool on) { if (!s_begun) touchPrefsBegin(); prefsPutUChar("glass", on ? 1 : 0); }
|
||||
bool touchPrefsGetAntExtAlways() { if (!s_begun) touchPrefsBegin(); return s_prefs.getUChar("ant_ext", 0) == 1; }
|
||||
void touchPrefsSetAntExtAlways(bool on) { if (!s_begun) touchPrefsBegin(); prefsPutUChar("ant_ext", on ? 1 : 0); }
|
||||
static void prefsPutUInt(const char* key, uint32_t v); // the re-open dance, below with its siblings
|
||||
bool touchPrefsGetGpsSaver() { if (!s_begun) touchPrefsBegin(); return s_prefs.getUChar("gps_save", 0) != 0; }
|
||||
void touchPrefsSetGpsSaver(bool on) { if (!s_begun) touchPrefsBegin(); prefsPutUChar("gps_save", on ? 1 : 0); }
|
||||
@@ -2886,6 +2897,7 @@ static int backupKeys(BkKey* out, int cap) {
|
||||
"ent_send", "clk_12h", "nav_mbk", "tb_rev", "tb_edgesc", "lock_off", "glance_lck",
|
||||
"glance_en", "msg_led", "dnd_en", "dnd_ss", "dnd_es", "kbd_bl",
|
||||
"chat_icons", "col_more", "col_style", "col_rb", "bg_kind", "gps_save", "gps_every",
|
||||
"glass", // NOT "ant_ext": a restore must never point a unit at an empty antenna socket
|
||||
};
|
||||
for (const char* k : k_u8) add(k, 'c');
|
||||
add("map_cap", 's');
|
||||
|
||||
@@ -707,6 +707,10 @@ uint8_t touchPrefsGetColorStyle();
|
||||
void touchPrefsSetColorStyle(uint8_t style);
|
||||
bool touchPrefsGetRainbow();
|
||||
void touchPrefsSetRainbow(bool on);
|
||||
// Settings > Theme > Glass tiles: Home widgets, cards and control panel tiles are frosted
|
||||
// glass over the background (default ON, today's look); off = opaque panel-colour fills.
|
||||
bool touchPrefsGetGlassTiles();
|
||||
void touchPrefsSetGlassTiles(bool on);
|
||||
// Settings > Theme > Background: what is behind every screen. A plain colour is kept dark
|
||||
// (by night) or light (by day) enough for the text; 0xFFFFFFFF follows the accent.
|
||||
enum : uint8_t { TOUCH_BG_AURORA = 0, TOUCH_BG_AURORA_MOVING = 1, TOUCH_BG_COLOR = 2, TOUCH_BG_IMAGE = 3,
|
||||
@@ -783,8 +787,13 @@ bool touchPrefsGetSigProbeEnabled();
|
||||
bool touchPrefsSetSigProbeEnabled(bool on);
|
||||
uint16_t touchPrefsGetSigPollMins();
|
||||
|
||||
/* NB: there is deliberately no touchPrefsGet/SetP4Antenna(). The T-Display P4 antenna choice is
|
||||
* session-only so that every boot comes up on the on-board antenna — see the note in the .cpp. */
|
||||
/* Boards with a switchable LoRa antenna (CAP_ANTENNA_SELECT, the T-Display P4): "Always use the
|
||||
* external antenna". OFF by default, and then every boot comes up on the on-board antenna and the
|
||||
* Radio settings antenna choice stays session-only (see the note in the .cpp). ON is an explicit,
|
||||
* confirmed opt-in that makes boot select the external (MMCX) socket. Its own NVS key, NOT the
|
||||
* reserved cfg byte p4_antenna, and NOT in the settings backup. */
|
||||
bool touchPrefsGetAntExtAlways();
|
||||
void touchPrefsSetAntExtAlways(bool on);
|
||||
bool touchPrefsSetSigPollMins(uint16_t mins);
|
||||
|
||||
/** Settings backup: the screen and app preferences (display, sounds, keyboard,
|
||||
|
||||
+288
-63
@@ -828,6 +828,7 @@ static bool s_look_rainbow = false;
|
||||
static bool s_aur_on = false; // the aurora is behind every screen (bgTheme / auroraBoot, at boot)
|
||||
static uint8_t s_bg_kind = 0xFF; // Settings > Theme > Background (TOUCH_BG_*); 0xFF: the plain theme
|
||||
static bool s_glass_on = false; // cards on pages are glass (styleGlass)
|
||||
static bool s_glass_tiles = true; // Settings > Theme > Glass tiles (off: solid tiles and panel), at boot
|
||||
static inline bool bgActive() { return s_bg_kind != 0xFF; }
|
||||
// A picture behind every screen (the lock screen's JPEG decode and file picker), and the
|
||||
// moving aurora. No picture on the 2 MB Heltec V4: a full-screen one is a big share of
|
||||
@@ -2684,7 +2685,23 @@ static inline lv_coord_t chatComposerTopRowH() {
|
||||
static inline lv_coord_t chatComposerChromeH() {
|
||||
return 4 + chatComposerTopRowH();
|
||||
}
|
||||
// Slim composer: on the large screens in landscape (T-Display P4 landscape, Tanmatsu,
|
||||
// CrowPanel 5.0 / 10.1) the empty text box is ONE text line tall and grows a line at a
|
||||
// time from there, instead of starting as the fixed 60-px box (three lines of Normal text,
|
||||
// the dead space zomgugoff asked about). The row stays tall enough for its buttons; a
|
||||
// text box shorter than them sits centred on them (chatComposerSlimRowH and friends,
|
||||
// defined with the button sizes below). The P4's portrait two-row layout is unchanged.
|
||||
static inline bool chatComposerSlim() {
|
||||
#if CAP_LARGE_SCREEN
|
||||
return lv_disp_get_hor_res(nullptr) > lv_disp_get_ver_res(nullptr) && !chatComposerTwoRow();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
static lv_coord_t chatComposerOneLineTaH();
|
||||
static lv_coord_t chatComposerSlimRowH(lv_coord_t ta_h);
|
||||
static inline lv_coord_t chatComposerBaseH() {
|
||||
if (chatComposerSlim()) return chatComposerSlimRowH(chatComposerOneLineTaH());
|
||||
if (chatComposerTwoRow()) return CHAT_COMP_H + chatComposerTopRowH();
|
||||
#if defined(TLORA_PAGER)
|
||||
// Preserve the 34-px Small composer, then add enough chrome around the live
|
||||
@@ -2702,6 +2719,7 @@ static inline lv_coord_t chatComposerBaseH() {
|
||||
// composer automatically reclaims space from the message list. Reset to
|
||||
// CHAT_COMP_H on each chat-panel (re)build; updated by chatComposerAutoGrow().
|
||||
static lv_coord_t s_comp_h = CHAT_COMP_H;
|
||||
static lv_coord_t s_comp_ta_h = CHAT_COMP_H - 4; // ...and its text box's (the slim layout sets them apart)
|
||||
#if defined(HELTEC_V4_EXPANSION_IO_PIN) && !defined(HELTEC_LORA_V4_R8)
|
||||
constexpr int CHAT_KB_H = 160; // larger original-V4 touch targets
|
||||
#else
|
||||
@@ -2809,6 +2827,43 @@ static inline lv_coord_t chatComposerLeftInset() {
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
// The slim composer's numbers (see chatComposerSlim). One text line in the box: the
|
||||
// font's line plus the box's 3-px vertical pads, the label's 4-px top pad, the border
|
||||
// and a little slack (an exact fit made the text bob a pixel per keystroke), which is
|
||||
// the 30-px box the small boards use at Normal size.
|
||||
static lv_coord_t chatComposerOneLineTaH() {
|
||||
return lv_font_get_line_height(&g_font_14) + 14;
|
||||
}
|
||||
#if CAP_ROUND_CORNERS
|
||||
// P4: the buttons centre on the text box but never come closer than kMinLift to the
|
||||
// bottom edge (the corner arcs); the text box follows the buttons while it is shorter.
|
||||
static constexpr lv_coord_t CHAT_COMP_MIN_LIFT_P4 = SB_TOP_PAD - 2;
|
||||
static inline lv_coord_t chatComposerP4Lift(lv_coord_t ta_h) {
|
||||
const lv_coord_t lift = (ta_h - CHAT_COMP_BTN_P4) / 2;
|
||||
return lift < CHAT_COMP_MIN_LIFT_P4 ? CHAT_COMP_MIN_LIFT_P4 : lift;
|
||||
}
|
||||
static inline lv_coord_t chatComposerP4TaOff(lv_coord_t ta_h) {
|
||||
if (!chatComposerSlim()) return 0;
|
||||
const lv_coord_t off = chatComposerP4Lift(ta_h) + (CHAT_COMP_BTN_P4 - ta_h) / 2;
|
||||
return off > 0 ? off : 0;
|
||||
}
|
||||
#endif
|
||||
// The tallest button on the slim composer's row (QR / emoji chips, Send).
|
||||
static inline lv_coord_t chatComposerSlimBand() {
|
||||
const lv_coord_t c = chatComposerChipSz(), s = chatComposerSendSz();
|
||||
return c > s ? c : s;
|
||||
}
|
||||
// Row height for a text box ta_h tall, slim layout.
|
||||
static lv_coord_t chatComposerSlimRowH(lv_coord_t ta_h) {
|
||||
#if CAP_ROUND_CORNERS
|
||||
const lv_coord_t top_ta = chatComposerP4TaOff(ta_h) + ta_h;
|
||||
const lv_coord_t top_btn = chatComposerP4Lift(ta_h) + CHAT_COMP_BTN_P4;
|
||||
return (top_ta > top_btn ? top_ta : top_btn) + chatComposerChromeH();
|
||||
#else
|
||||
const lv_coord_t band = chatComposerSlimBand();
|
||||
return (ta_h > band ? ta_h : band) + chatComposerChromeH();
|
||||
#endif
|
||||
}
|
||||
static inline lv_coord_t chatComposerTaW(bool channel_mode) {
|
||||
const lv_coord_t chip = chatComposerChipSz();
|
||||
// Two-row: the chips are on the row above, so the text box only shares its row with Send.
|
||||
@@ -9354,6 +9409,10 @@ constexpr int KB_MIRROR_STRIP_H = 52;
|
||||
|
||||
// Keyboard rotation helpers (defined here so showKb/hideKb/kbMirrorBind can use them).
|
||||
// Layout adjusts keyboard + mirror + rotate arrows for the current rotation.
|
||||
#if CAP_LARGE_SCREEN && !CAP_ROUND_CORNERS
|
||||
static void chatComposerAutoGrow(LvChatPanel* p); // the rotation re-runs it (kbApplyLayoutForRotation)
|
||||
static void chatComposerAlignSlim(LvChatPanel* p); // defined after chatComposerAutoGrow
|
||||
#endif
|
||||
#if CAP_ROUND_CORNERS
|
||||
static void chatComposerApplyRows(LvChatPanel* p); // defined after chatComposerAutoGrow
|
||||
static void chatComposerPlaceButtons(LvChatPanel* p); // ditto
|
||||
@@ -9398,6 +9457,15 @@ static void kbApplyLayoutForRotation(uint8_t rot) {
|
||||
lv_obj_set_width(s_kb_panel->composer_ta, chatComposerTaW(s_kb_panel->channel_mode));
|
||||
#if CAP_ROUND_CORNERS
|
||||
chatComposerApplyRows(s_kb_panel); // one row <-> two rows as the orientation flips
|
||||
#elif CAP_LARGE_SCREEN
|
||||
// Slim (landscape) <-> classic (portrait) on a rotatable large panel (CrowPanel 5.0):
|
||||
// re-run the auto-grow on the new width so heights, Y and the centring follow. The
|
||||
// width was just set, so lay out first (it reads the box's content width).
|
||||
if (s_kb_panel->composer_row) {
|
||||
lv_obj_update_layout(s_kb_panel->composer_row);
|
||||
s_comp_h = -1;
|
||||
chatComposerAutoGrow(s_kb_panel);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// Rotation arrows. Default: just above the keyboard's top edge. In the
|
||||
@@ -9871,19 +9939,28 @@ static void chatComposerAutoGrow(LvChatPanel* p) {
|
||||
int lines = (int)((sz.y + lh - 1) / lh); // ceil to whole lines
|
||||
if (lines < 1) lines = 1;
|
||||
if (lines > CHAT_COMP_MAX_LINES) lines = CHAT_COMP_MAX_LINES;
|
||||
const lv_coord_t want = chatComposerBaseH() + (lv_coord_t)(lines - 1) * lh;
|
||||
if (want == s_comp_h) return; // height unchanged → nothing to relayout
|
||||
// Text box: one line (slim) or the board's base box, plus a line per extra wrapped line.
|
||||
// Row: the box plus chrome, or (slim) at least as tall as the buttons beside it.
|
||||
const bool slim = chatComposerSlim();
|
||||
const lv_coord_t base_ta = slim ? chatComposerOneLineTaH() : chatComposerBaseH() - chatComposerChromeH();
|
||||
const lv_coord_t ta_h = base_ta + (lv_coord_t)(lines - 1) * lh;
|
||||
const lv_coord_t want = slim ? chatComposerSlimRowH(ta_h) : ta_h + chatComposerChromeH();
|
||||
if (want == s_comp_h && ta_h == s_comp_ta_h) return; // unchanged → nothing to relayout
|
||||
// Read before the bottom inset changes below: if the newest message was in
|
||||
// view, keep it in view. Growing the inset alone left the scroll where it was,
|
||||
// so the taller composer covered the last messages (#617; an @-mention wraps
|
||||
// the text at once, which is where it showed).
|
||||
const bool stick_bottom = p->detail_open && !chatVirtAwayFromBottom(p);
|
||||
s_comp_h = want;
|
||||
s_comp_ta_h = ta_h;
|
||||
// Keyboard shown (V4) lifts the composer above the keys; otherwise (T-Deck, or
|
||||
// V4 with the keyboard down) it sits at the screen bottom.
|
||||
const bool kb = g_lv.keyboard && !lv_obj_has_flag(g_lv.keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_set_height(p->composer_row, s_comp_h);
|
||||
lv_obj_set_height(p->composer_ta, s_comp_h - chatComposerChromeH());
|
||||
lv_obj_set_height(p->composer_ta, s_comp_ta_h);
|
||||
// A pill at one line, the radius fixed at that size (see makeChatDetail, #617); set
|
||||
// here too because a rotation can switch between the slim and the classic box.
|
||||
lv_obj_set_style_radius(p->composer_ta, base_ta / 2, LV_PART_MAIN);
|
||||
lv_obj_set_y(p->composer_row, kb ? chatCompYKb() : chatCompYOpen());
|
||||
lv_obj_set_height(p->msgs, kb ? chatMsgHKb() : chatMsgHOpen());
|
||||
// Grow the bottom inset with the composer so the newest bubble keeps clearing it.
|
||||
@@ -9891,6 +9968,8 @@ static void chatComposerAutoGrow(LvChatPanel* p) {
|
||||
if (stick_bottom) chatVirtQueueScroll(p, LV_COORD_MAX);
|
||||
#if CAP_ROUND_CORNERS
|
||||
chatComposerPlaceButtons(p); // keep the buttons centred on the grown text box
|
||||
#elif CAP_LARGE_SCREEN
|
||||
chatComposerAlignSlim(p); // a box shorter than the buttons sits centred on them
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -9898,6 +9977,32 @@ static void composerAutoGrowCb(lv_event_t* e) {
|
||||
chatComposerAutoGrow(static_cast<LvChatPanel*>(lv_event_get_user_data(e)));
|
||||
}
|
||||
|
||||
#if CAP_LARGE_SCREEN && !CAP_ROUND_CORNERS
|
||||
// Slim composer on the square-cornered large screens (Tanmatsu, CrowPanels): every control
|
||||
// keeps its bottom alignment and x, and is lifted to sit centred in the band of the tallest
|
||||
// button, so a one-line text box and the smaller Send button line up with the big chips.
|
||||
// A text box taller than that band rests on the bottom as before. Classic layout (portrait
|
||||
// CrowPanel 5.0): everything back on the bottom edge. lv_obj_set_y keeps each align.
|
||||
static void chatComposerAlignSlim(LvChatPanel* p) {
|
||||
if (!p || !p->composer_ta) return;
|
||||
const bool slim = chatComposerSlim();
|
||||
const lv_coord_t band = chatComposerSlimBand();
|
||||
auto lift = [&](lv_obj_t* o, lv_coord_t h) {
|
||||
if (!o) return;
|
||||
const lv_coord_t off = (slim && h < band) ? (band - h) / 2 : 0;
|
||||
lv_obj_set_y(o, -off);
|
||||
};
|
||||
lift(p->composer_ta, s_comp_ta_h);
|
||||
lift(p->qr_btn, chatComposerChipSz());
|
||||
lift(p->emoji_btn, chatComposerChipSz());
|
||||
#if defined(HAS_CROWPANEL_50)
|
||||
lift(p->send_btn, chatComposerSendSz());
|
||||
#else
|
||||
lift(p->send_btn, 30); // a 30-px circle in a send_sz-wide slot (makeChatDetail)
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CAP_ROUND_CORNERS
|
||||
// Position the composer's controls for the current orientation (see chatComposerTwoRow):
|
||||
// portrait: [ QR emoji ] landscape: [ QR text ... emoji send ]
|
||||
@@ -9912,10 +10017,8 @@ static void chatComposerPlaceButtons(LvChatPanel* p) {
|
||||
const lv_coord_t b = CHAT_COMP_BTN_P4;
|
||||
const lv_coord_t gap = 6;
|
||||
const lv_coord_t right = chatComposerSendInset();
|
||||
const lv_coord_t ta_h = s_comp_h - chatComposerChromeH();
|
||||
const lv_coord_t kMinLift = SB_TOP_PAD - 2;
|
||||
lv_coord_t lift = (ta_h - b) / 2;
|
||||
if (lift < kMinLift) lift = kMinLift;
|
||||
const lv_coord_t ta_h = s_comp_ta_h;
|
||||
const lv_coord_t lift = chatComposerP4Lift(ta_h); // at least CHAT_COMP_MIN_LIFT_P4
|
||||
if (chatComposerTwoRow()) {
|
||||
lv_obj_align(p->emoji_btn, LV_ALIGN_TOP_RIGHT, -right, 0);
|
||||
lv_obj_align(p->qr_btn, LV_ALIGN_TOP_RIGHT, -(right + b + gap), 0);
|
||||
@@ -9923,7 +10026,8 @@ static void chatComposerPlaceButtons(LvChatPanel* p) {
|
||||
} else {
|
||||
const lv_coord_t left = chatComposerLeftInset();
|
||||
lv_obj_align(p->qr_btn, LV_ALIGN_BOTTOM_LEFT, left, -lift);
|
||||
lv_obj_align(p->composer_ta, LV_ALIGN_BOTTOM_LEFT, left + b + gap, 0);
|
||||
// Slim (landscape): a box shorter than the buttons rides up to sit centred on them.
|
||||
lv_obj_align(p->composer_ta, LV_ALIGN_BOTTOM_LEFT, left + b + gap, -chatComposerP4TaOff(ta_h));
|
||||
lv_obj_align(p->emoji_btn, LV_ALIGN_BOTTOM_RIGHT, -(right + b + gap), -lift);
|
||||
}
|
||||
lv_obj_align(p->send_btn, LV_ALIGN_BOTTOM_RIGHT, -right, -lift);
|
||||
@@ -15225,40 +15329,61 @@ static void radioScopeDirectToggleCb(lv_event_t* e) {
|
||||
touchPrefsSetScopeDirect(on);
|
||||
the_mesh.setScopeDirectFloods(on);
|
||||
}
|
||||
#if defined(HAS_TDISPLAY_P4)
|
||||
// T-Display P4 LoRa antenna select. Applies live (no reboot) but is deliberately SESSION-ONLY:
|
||||
// every boot re-forces the on-board antenna (see the boot-apply in begin() and the park in
|
||||
// Xl9535::powerOnSequence). Transmitting into an external connector with no antenna fitted is
|
||||
// what kills a PA, so the safe state has to be the one you get for free after a power cycle,
|
||||
// and picking the external antenna has to be a fresh, explicit decision each time.
|
||||
static lv_obj_t* s_p4_ant_dd = nullptr; // showConfirm takes a bare callback, so stash the widget
|
||||
static uint8_t s_p4_ant_pending = Xl9535::ANT_INTERNAL;
|
||||
#if CAP_ANTENNA_SELECT
|
||||
// Switchable LoRa antenna (CAP_ANTENNA_SELECT). Board glue, the one place that names the
|
||||
// hardware: the T-Display P4's SKY13453 on XL9535 IO1 (HIGH = on-board, LOW = external socket;
|
||||
// see Xl9535.h). Modes: 0 on-board, 1 external, 2 the legacy per-transmit toggle (diagnostic).
|
||||
enum : uint8_t { ANT_SEL_INTERNAL = 0, ANT_SEL_EXTERNAL = 1, ANT_SEL_AUTO = 2 };
|
||||
static uint8_t antSelMode() { return xl9535.antennaMode(); }
|
||||
static void antSelSet(uint8_t m) { xl9535.setAntennaMode(m); } // takes effect on the next transmit
|
||||
|
||||
static void radioP4AntennaConfirmApply() {
|
||||
xl9535.setAntennaMode(s_p4_ant_pending); // takes effect on the very next transmit
|
||||
if (s_p4_ant_dd) lv_dropdown_set_selected(s_p4_ant_dd, s_p4_ant_pending);
|
||||
if (g_lv.task) {
|
||||
g_lv.task->showAlert(s_p4_ant_pending == Xl9535::ANT_EXTERNAL ? TR("External antenna selected")
|
||||
: TR("Per-transmit switching on"), 1200);
|
||||
}
|
||||
// The Radio settings choice applies live and on its own is SESSION-ONLY: every boot re-forces the
|
||||
// on-board antenna (the boot-apply in begin() and the park in Xl9535::powerOnSequence), unless the
|
||||
// owner turned on "Always use the external antenna", an explicit opt-in behind a damage warning.
|
||||
// Transmitting into an external connector with no antenna fitted is what kills a PA, so the safe
|
||||
// state has to be the one you get for free after a power cycle for everyone who did not opt in.
|
||||
static lv_obj_t* s_ant_dd = nullptr; // showConfirm takes a bare callback, so stash the widgets
|
||||
static lv_obj_t* s_ant_always_sw = nullptr;
|
||||
static uint8_t s_ant_pending = ANT_SEL_INTERNAL;
|
||||
// Forget a stashed widget when its page goes: a freed pointer could come back as some
|
||||
// other object, and lv_obj_is_valid would then say yes.
|
||||
static void antSelWidgetDeleteCb(lv_event_t* e) {
|
||||
if (lv_event_get_code(e) != LV_EVENT_DELETE) return;
|
||||
lv_obj_t* o = lv_event_get_target(e);
|
||||
if (o == s_ant_dd) s_ant_dd = nullptr;
|
||||
if (o == s_ant_always_sw) s_ant_always_sw = nullptr;
|
||||
}
|
||||
|
||||
static void radioP4AntennaSelectCb(lv_event_t* e) {
|
||||
if (lv_event_get_code(e) != LV_EVENT_VALUE_CHANGED) return;
|
||||
lv_obj_t* dd = lv_event_get_target(e);
|
||||
const uint8_t m = (uint8_t)lv_dropdown_get_selected(dd);
|
||||
if (m == Xl9535::ANT_INTERNAL) { xl9535.setAntennaMode(m); return; } // always safe, no prompt
|
||||
// Show the live antenna wherever it is on screen: the Radio settings dropdown, the panel tile.
|
||||
static void antSelShowLive() {
|
||||
if (s_ant_dd) lv_dropdown_set_selected(s_ant_dd, antSelMode());
|
||||
if (s_cc_root) openControlCenter(); // rebuild so the antenna tile flips
|
||||
}
|
||||
|
||||
// External moves BOTH directions onto the external socket, so it needs an antenna actually fitted
|
||||
// there — that is the one real hardware risk and it gets the damage warning. Auto (the legacy
|
||||
// per-TX toggle) transmits on the on-board antenna and only listens on the external socket, so it
|
||||
// is not a PA hazard, just permanently lopsided; it gets an accurate performance warning instead
|
||||
// of a scary one. Revert the widget FIRST and only re-select from the confirm handler: showConfirm
|
||||
// has no cancel callback, so a dismissed dialog must leave UI and hardware where they were.
|
||||
s_p4_ant_dd = dd;
|
||||
s_p4_ant_pending = m;
|
||||
lv_dropdown_set_selected(dd, xl9535.antennaMode());
|
||||
showConfirm(m == Xl9535::ANT_EXTERNAL
|
||||
static void antSelConfirmApply() {
|
||||
antSelSet(s_ant_pending);
|
||||
if (g_lv.task) {
|
||||
g_lv.task->showAlert(s_ant_pending == ANT_SEL_EXTERNAL ? TR("External antenna selected")
|
||||
: s_ant_pending == ANT_SEL_AUTO ? TR("Per-transmit switching on")
|
||||
: TR("On-board antenna selected"), 1200);
|
||||
}
|
||||
antSelShowLive();
|
||||
}
|
||||
|
||||
// Ask for an antenna. On-board is always safe and applies at once. External moves BOTH
|
||||
// directions onto the external socket, so it needs an antenna actually fitted there: that is
|
||||
// the one real hardware risk and it gets the damage warning, except for an owner who already
|
||||
// accepted it by turning on "Always use the external antenna". Auto (the legacy per-TX toggle)
|
||||
// transmits on the on-board antenna and only listens on the external socket, so it is not a PA
|
||||
// hazard, just permanently lopsided; it gets an accurate performance warning instead.
|
||||
static void antSelRequest(uint8_t m) {
|
||||
s_ant_pending = (m > ANT_SEL_AUTO) ? ANT_SEL_INTERNAL : m;
|
||||
if (s_ant_pending == ANT_SEL_INTERNAL ||
|
||||
(s_ant_pending == ANT_SEL_EXTERNAL && touchPrefsGetAntExtAlways())) {
|
||||
antSelConfirmApply();
|
||||
return;
|
||||
}
|
||||
showConfirm(s_ant_pending == ANT_SEL_EXTERNAL
|
||||
? TR("Switch to the external antenna?\n\nMake sure an antenna is actually connected "
|
||||
"to the external antenna socket first. Transmitting with nothing attached can "
|
||||
"damage the radio.\n\nResets to the on-board antenna on every reboot.")
|
||||
@@ -15266,7 +15391,55 @@ static void radioP4AntennaSelectCb(lv_event_t* e) {
|
||||
"only. It transmits on the on-board antenna and listens on the external one, "
|
||||
"so your outbound signal will be much weaker than your inbound.\n\nResets to "
|
||||
"the on-board antenna on every reboot."),
|
||||
TR("Switch"), radioP4AntennaConfirmApply);
|
||||
TR("Switch"), antSelConfirmApply);
|
||||
}
|
||||
|
||||
static void radioAntennaSelectCb(lv_event_t* e) {
|
||||
if (lv_event_get_code(e) != LV_EVENT_VALUE_CHANGED) return;
|
||||
lv_obj_t* dd = lv_event_get_target(e);
|
||||
const uint8_t m = (uint8_t)lv_dropdown_get_selected(dd);
|
||||
// Revert the widget FIRST and only re-select once applied: showConfirm has no cancel
|
||||
// callback, so a dismissed dialog must leave UI and hardware where they were.
|
||||
s_ant_dd = dd;
|
||||
lv_dropdown_set_selected(dd, antSelMode());
|
||||
antSelRequest(m);
|
||||
}
|
||||
|
||||
// "Always use the external antenna (MMCX)": boot selects the external socket. Persisted in its
|
||||
// own key (touchPrefsGetAntExtAlways). Turning it ON asks first, with the damage warning, and the
|
||||
// switch only flips from the confirm handler; turning it OFF also goes back to the on-board
|
||||
// antenna at once, since the usual reason is that the external antenna came off.
|
||||
static void antAlwaysConfirmApply() {
|
||||
touchPrefsSetAntExtAlways(true);
|
||||
const bool saved = touchPrefsGetAntExtAlways(); // read back: a failed write must not look on
|
||||
if (s_ant_always_sw) {
|
||||
if (saved) lv_obj_add_state(s_ant_always_sw, LV_STATE_CHECKED);
|
||||
else lv_obj_clear_state(s_ant_always_sw, LV_STATE_CHECKED);
|
||||
}
|
||||
if (!saved) {
|
||||
if (g_lv.task) g_lv.task->showAlert(TR("Save failed"), 1500);
|
||||
return;
|
||||
}
|
||||
s_ant_pending = ANT_SEL_EXTERNAL;
|
||||
antSelSet(ANT_SEL_EXTERNAL);
|
||||
if (g_lv.task) g_lv.task->showAlert(TR("External antenna at every boot"), 1500);
|
||||
antSelShowLive();
|
||||
}
|
||||
static void radioAntAlwaysToggleCb(lv_event_t* e) {
|
||||
if (lv_event_get_code(e) != LV_EVENT_VALUE_CHANGED) return;
|
||||
lv_obj_t* sw = lv_event_get_target(e);
|
||||
s_ant_always_sw = sw;
|
||||
if (!lv_obj_has_state(sw, LV_STATE_CHECKED)) {
|
||||
touchPrefsSetAntExtAlways(false);
|
||||
s_ant_pending = ANT_SEL_INTERNAL;
|
||||
antSelConfirmApply(); // "On-board antenna selected"
|
||||
return;
|
||||
}
|
||||
lv_obj_clear_state(sw, LV_STATE_CHECKED); // stays off unless the confirm turns it on
|
||||
showConfirm(TR("Always use the external antenna?\n\nThe radio will start on the external (MMCX) "
|
||||
"socket at every boot. Transmitting without an antenna attached can damage the "
|
||||
"radio.\n\nOnly turn this on if your external antenna stays connected."),
|
||||
TR("Turn on"), antAlwaysConfirmApply);
|
||||
}
|
||||
#endif
|
||||
#if defined(HELTEC_LORA_V4_TFT)
|
||||
@@ -15482,15 +15655,20 @@ static void buildRadioSettings() {
|
||||
// The receiver and the sending side.
|
||||
{
|
||||
lv_obj_t* c = setCard("Signal");
|
||||
#if defined(HAS_TDISPLAY_P4)
|
||||
// The SKY13453 on XL9535 IO1 (HIGH = on-board, LOW = external socket; see Xl9535.h).
|
||||
// On-board is re-forced at every boot; External sits behind a confirmation, because
|
||||
// keying the PA into an empty socket is how one gets destroyed. "Auto" keeps the old
|
||||
// per-transmit toggle for comparison only (sends on-board, listens external).
|
||||
setDropdownRow(c, "LoRa antenna (P4)",
|
||||
"Always starts on the on-board antenna after a reboot. Only pick External with an antenna fitted to the external socket.",
|
||||
#if CAP_ANTENNA_SELECT
|
||||
// The switchable antenna (see antSelMode). On-board is re-forced at every boot unless the
|
||||
// switch below is on; External sits behind a confirmation, because keying the PA into an
|
||||
// empty socket is how one gets destroyed. "Auto" keeps the old per-transmit toggle for
|
||||
// comparison only (sends on-board, listens external).
|
||||
s_ant_dd = setDropdownRow(c, "LoRa antenna (P4)",
|
||||
"Only pick External with an antenna fitted to the external socket. After a reboot it starts on the on-board antenna, unless the switch below is on.",
|
||||
TR("Internal (on-board)\nExternal (MMCX)\nAuto (legacy, per transmit)"),
|
||||
xl9535.antennaMode(), radioP4AntennaSelectCb); // live state, not a stored pref
|
||||
antSelMode(), radioAntennaSelectCb); // live state, not a stored pref
|
||||
s_ant_always_sw = setSwitchRow(c, "Always use the external antenna (MMCX)",
|
||||
"Starts on the external socket at every boot. Only for an antenna that stays connected.",
|
||||
touchPrefsGetAntExtAlways(), radioAntAlwaysToggleCb);
|
||||
lv_obj_add_event_cb(s_ant_dd, antSelWidgetDeleteCb, LV_EVENT_DELETE, nullptr);
|
||||
lv_obj_add_event_cb(s_ant_always_sw, antSelWidgetDeleteCb, LV_EVENT_DELETE, nullptr);
|
||||
#endif
|
||||
#if defined(HELTEC_LORA_V4_TFT)
|
||||
// Heltec V4.3 only: the FEM's ~17 dB receive amplifier, separate from the SX1262's own
|
||||
@@ -39532,6 +39710,7 @@ static void makeChatDetail(LvChatPanel& p) {
|
||||
// types (chatComposerAutoGrow). Reset here so a previous chat's grown height
|
||||
// doesn't leak into this one's initial layout math below.
|
||||
s_comp_h = chatComposerBaseH();
|
||||
s_comp_ta_h = chatComposerSlim() ? chatComposerOneLineTaH() : s_comp_h - chatComposerChromeH();
|
||||
|
||||
// ---- Message area (scrollable container of speech-bubble children) ----
|
||||
// Each message gets its own lv_obj bubble inside p.msgs so we can style
|
||||
@@ -39783,7 +39962,7 @@ static void makeChatDetail(LvChatPanel& p) {
|
||||
p.composer_ta = lv_textarea_create(p.composer_row);
|
||||
// M9 conversations: QR | message input | emoji | # | Send. Other boards
|
||||
// have QR | message input | emoji | Send.
|
||||
lv_obj_set_size(p.composer_ta, comp_ta_w, composer_h - chatComposerChromeH());
|
||||
lv_obj_set_size(p.composer_ta, comp_ta_w, s_comp_ta_h);
|
||||
// Bottom-aligned so the box grows UPWARD as the message wraps to more lines.
|
||||
lv_obj_align(p.composer_ta, LV_ALIGN_BOTTOM_LEFT, comp_ta_x, 0);
|
||||
styleCard(p.composer_ta);
|
||||
@@ -39791,7 +39970,7 @@ static void makeChatDetail(LvChatPanel& p) {
|
||||
// A pill at one line. The radius is fixed at that size, not LV_RADIUS_CIRCLE:
|
||||
// as the box grows, a circle radius would grow with it, and at four lines the
|
||||
// curve cut through the start and end of the first and last lines (#617).
|
||||
lv_obj_set_style_radius(p.composer_ta, (composer_h - chatComposerChromeH()) / 2, LV_PART_MAIN);
|
||||
lv_obj_set_style_radius(p.composer_ta, s_comp_ta_h / 2, LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_hor(p.composer_ta, SC(12), LV_PART_MAIN);
|
||||
// Keep a few px of vertical slack in the textarea CONTENT so it never sits at
|
||||
// exactly one line-height (that made the internal scroll oscillate ±1px per
|
||||
@@ -39891,6 +40070,8 @@ static void makeChatDetail(LvChatPanel& p) {
|
||||
lv_obj_center(sl);
|
||||
#if CAP_ROUND_CORNERS
|
||||
chatComposerApplyRows(&p);
|
||||
#elif CAP_LARGE_SCREEN
|
||||
chatComposerAlignSlim(&p); // centre the one-line box and Send on the chips (slim layout)
|
||||
#endif
|
||||
|
||||
// No floating HOME button — exit is the Back chevron in the (double-height) status
|
||||
@@ -48594,6 +48775,9 @@ static int rgbDist(uint32_t a, uint32_t b) {
|
||||
static void bgTheme() {
|
||||
s_bg_kind = 0xFF;
|
||||
s_aur_on = s_glass_on = false;
|
||||
// Glass tiles off: the background stays, but every card, Home widget and control panel
|
||||
// tile is the solid panel colour, as before the aurora (ljh08ralith liked that look).
|
||||
s_glass_tiles = touchPrefsGetGlassTiles();
|
||||
#if !defined(HAS_TDECK_PRO)
|
||||
if (s_theme_high_contrast) return;
|
||||
s_bg_kind = touchPrefsGetBackground();
|
||||
@@ -48610,10 +48794,10 @@ static void bgTheme() {
|
||||
if (s_bg_kind == TOUCH_BG_COLOR) {
|
||||
const uint32_t c = touchPrefsGetBackgroundColor();
|
||||
COLOR_BG = bgSafeColor(c == 0xFFFFFFFFu ? COLOR_GLOW : c, s_theme_day);
|
||||
s_glass_on = rgbDist(COLOR_BG, COLOR_PANEL) > 24; // glass only where it stands apart from the cards
|
||||
s_glass_on = s_glass_tiles && rgbDist(COLOR_BG, COLOR_PANEL) > 24; // glass only where it stands apart from the cards
|
||||
return;
|
||||
}
|
||||
s_glass_on = true;
|
||||
s_glass_on = s_glass_tiles;
|
||||
if ((COLOR_BG & 0xF8FCF8u) == 0) COLOR_BG = 0x000400u;
|
||||
s_aur_key = lv_color_hex(COLOR_BG).full;
|
||||
#endif
|
||||
@@ -52677,6 +52861,17 @@ static void ccDndCb(lv_event_t* e) {
|
||||
openControlCenter(); // rebuild so the chip's icon + highlight flip
|
||||
}
|
||||
|
||||
#if CAP_ANTENNA_SELECT
|
||||
// The antenna chip: shows the live antenna (filled = external, "MMCX" or "On-board" under the icon). A tap
|
||||
// on external goes back to the on-board antenna at once; a tap on the on-board one asks for
|
||||
// the external socket through antSelRequest, so the damage warning shows here too (unless
|
||||
// "Always use the external antenna" is on). Holding it opens Radio settings.
|
||||
static void ccAntennaCb(lv_event_t* e) {
|
||||
if (lv_event_get_code(e) != LV_EVENT_CLICKED) return;
|
||||
antSelRequest(antSelMode() == ANT_SEL_EXTERNAL ? ANT_SEL_INTERNAL : ANT_SEL_EXTERNAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
// The battery saver's chip: boards with a battery, and whose panel was laid out for a
|
||||
// tenth chip (the Tanmatsu, T-Display P4 and M9 grids are fixed; those keep it in
|
||||
// Settings > Battery).
|
||||
@@ -52831,8 +53026,11 @@ static void ccToggle(lv_obj_t* parent, const char* sym, const char* label,
|
||||
lv_obj_set_style_bg_opa(b, active ? LV_OPA_COVER : LV_OPA_TRANSP, LV_PART_MAIN);
|
||||
icon_col = active ? COLOR_BG : COLOR_TEXT;
|
||||
} else {
|
||||
lv_obj_set_style_bg_color(b, lv_color_hex(hue), LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(b, active ? LV_OPA_COVER : s_look_tint, LV_PART_MAIN);
|
||||
// Off: the hue at the look's tint, see-through over the panel; with Glass tiles off
|
||||
// the same colour mixed in solid.
|
||||
const bool solid_off = !active && !s_glass_tiles;
|
||||
lv_obj_set_style_bg_color(b, lv_color_hex(solid_off ? rgbMix(COLOR_PANEL, hue, s_look_tint) : hue), LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(b, (active || solid_off) ? LV_OPA_COVER : s_look_tint, LV_PART_MAIN);
|
||||
icon_col = active ? (accentLuma(hue) > 150 ? 0x00201Cu : 0xFFFFFFu) : hue;
|
||||
if (lookNeon()) { // the launcher's lit neon edge
|
||||
lv_obj_set_style_border_color(b, lv_color_hex(hue), LV_PART_MAIN);
|
||||
@@ -53187,7 +53385,8 @@ static void openControlCenter() {
|
||||
// Frosted-glass panel: translucent fill so the (dimmed) screen behind shows through.
|
||||
// Only the panel BACKGROUND is see-through — the clock/sliders/chips drawn on top stay
|
||||
// fully opaque, so nothing becomes hard to read. ~85% keeps it clearly a solid surface.
|
||||
lv_obj_set_style_bg_opa(card, 218, LV_PART_MAIN);
|
||||
// Glass tiles off (Settings > Theme): a solid panel instead.
|
||||
lv_obj_set_style_bg_opa(card, s_glass_tiles ? 218 : LV_OPA_COVER, LV_PART_MAIN);
|
||||
lv_obj_set_style_radius(card, 12, LV_PART_MAIN);
|
||||
// Subtle light hairline (instead of the near-black border) reads more like a glass edge.
|
||||
lv_obj_set_style_border_color(card, lv_color_hex(themeRole(0x3A3D42, COLOR_BORDER)), LV_PART_MAIN);
|
||||
@@ -53522,6 +53721,9 @@ static void openControlCenter() {
|
||||
chip_count++;
|
||||
#endif
|
||||
chip_count++; // Do Not Disturb (all boards)
|
||||
#if CAP_ANTENNA_SELECT
|
||||
chip_count++; // Antenna
|
||||
#endif
|
||||
#if CC_HAS_SAVER
|
||||
chip_count++; // Battery saver
|
||||
#endif
|
||||
@@ -53594,6 +53796,13 @@ static void openControlCenter() {
|
||||
ccToggle(row, UI_ICON_MOON, TR("DND"), dnd_on, ccDndCb, tw, th,
|
||||
CAT_SOUND, nullptr, CC_NAV_DND);
|
||||
}
|
||||
#if CAP_ANTENNA_SELECT
|
||||
{
|
||||
const bool ext = antSelMode() == ANT_SEL_EXTERNAL;
|
||||
ccToggle(row, UI_ICON_ANTENNA, TR("Antenna"), ext, ccAntennaCb, tw, th,
|
||||
CAT_RADIO, ext ? "MMCX" : TR("On-board"));
|
||||
}
|
||||
#endif
|
||||
#if CC_HAS_SAVER
|
||||
ccToggle(row, UI_ICON_BATTERY, TR("Saver"), touchSleep::enabled(), ccSaverCb, tw, th,
|
||||
CAT_BATTERY, nullptr, CC_NAV_SAVER);
|
||||
@@ -64280,6 +64489,7 @@ static const uint32_t kThemeColors[] = {
|
||||
struct ThemeChoice {
|
||||
uint8_t mode; uint32_t accent; bool more; uint8_t style; bool rainbow;
|
||||
uint8_t bg_kind; uint32_t bg_col; char bg_img[TOUCH_LOCK_WALLPAPER_MAXLEN]; // Background
|
||||
bool glass; // Glass tiles
|
||||
};
|
||||
static ThemeChoice s_theme_saved = {}, s_theme_pend = {};
|
||||
static constexpr int kThemeColorN = (int)(sizeof(kThemeColors) / sizeof(kThemeColors[0]));
|
||||
@@ -64300,7 +64510,7 @@ struct ThemePageUi {
|
||||
lv_obj_t* swatch[kThemeColorN]; lv_obj_t* custom; lv_obj_t* custom_dot; lv_obj_t* accent_note;
|
||||
lv_obj_t* more_sw; lv_obj_t* style[3]; lv_obj_t* style_dot[3][3]; lv_obj_t* rainbow_sw; lv_obj_t* colour_note;
|
||||
lv_obj_t* bg[5]; lv_obj_t* bg_sw[5]; lv_obj_t* bg_col_btn; lv_obj_t* bg_col_dot;
|
||||
lv_obj_t* bg_img_btn; lv_obj_t* bg_img_lbl; lv_obj_t* bg_note;
|
||||
lv_obj_t* bg_img_btn; lv_obj_t* bg_img_lbl; lv_obj_t* bg_note; lv_obj_t* glass_sw;
|
||||
lv_obj_t* icons[2]; lv_obj_t* icons_av[2];
|
||||
lv_obj_t* apply; lv_obj_t* apply_lbl; // Apply and restart, on the preview box
|
||||
lv_obj_t* mini; // the bar that keeps it in reach once the box scrolls away
|
||||
@@ -64556,7 +64766,7 @@ static bool themePendingDiffers() {
|
||||
const ThemeChoice& b = s_theme_saved;
|
||||
return a.mode != b.mode || a.accent != b.accent || a.more != b.more ||
|
||||
a.style != b.style || a.rainbow != b.rainbow || a.bg_kind != b.bg_kind ||
|
||||
a.bg_col != b.bg_col || strcmp(a.bg_img, b.bg_img) != 0;
|
||||
a.bg_col != b.bg_col || strcmp(a.bg_img, b.bg_img) != 0 || a.glass != b.glass;
|
||||
}
|
||||
// MORE COLORS! as the pending choice has it: Taste the rainbow brings it along, and
|
||||
// high contrast keeps its own fixed colours.
|
||||
@@ -64966,6 +65176,8 @@ static void themePageRepaint() {
|
||||
base = base ? base + 1 : (strncmp(s_theme_pend.bg_img, "sd:", 3) ? s_theme_pend.bg_img : s_theme_pend.bg_img + 3);
|
||||
lv_label_set_text(s_tp.bg_img_lbl, base && base[0] ? base : TR("Choose an image"));
|
||||
}
|
||||
// Glass tiles: nothing to see through in high contrast or on the plain theme.
|
||||
themeSwitchSet(s_tp.glass_sw, s_theme_pend.glass, !hc && s_theme_pend.bg_kind != TOUCH_BG_NONE);
|
||||
if (s_tp.bg_note) {
|
||||
if (hc) lv_obj_clear_flag(s_tp.bg_note, LV_OBJ_FLAG_HIDDEN);
|
||||
else lv_obj_add_flag(s_tp.bg_note, LV_OBJ_FLAG_HIDDEN);
|
||||
@@ -65070,6 +65282,11 @@ static void themeBgColorCb(lv_event_t* e) {
|
||||
s_picker_for_bg = true;
|
||||
openAccentPicker();
|
||||
}
|
||||
static void themeGlassCb(lv_event_t* e) {
|
||||
if (lv_event_get_code(e) != LV_EVENT_VALUE_CHANGED) return;
|
||||
s_theme_pend.glass = lv_obj_has_state(lv_event_get_target(e), LV_STATE_CHECKED);
|
||||
themePageRepaint();
|
||||
}
|
||||
static void themeBgImageCb(lv_event_t* e) {
|
||||
if (lv_event_get_code(e) == LV_EVENT_CLICKED && !themeModeIsHc(s_theme_pend.mode)) themeBgPickImage();
|
||||
}
|
||||
@@ -65108,6 +65325,7 @@ static void themeApplyCb(lv_event_t* e) {
|
||||
touchPrefsSetBackground(s_theme_pend.bg_kind);
|
||||
touchPrefsSetBackgroundColor(s_theme_pend.bg_col);
|
||||
touchPrefsSetBackgroundImage(s_theme_pend.bg_img);
|
||||
touchPrefsSetGlassTiles(s_theme_pend.glass);
|
||||
#endif
|
||||
s_theme_saved = s_theme_pend;
|
||||
lv_obj_add_flag(lv_event_get_target(e), LV_OBJ_FLAG_HIDDEN); // one tap; the restart follows
|
||||
@@ -65306,6 +65524,7 @@ static void buildThemeSettings() {
|
||||
s_theme_saved.bg_kind = touchPrefsGetBackground();
|
||||
s_theme_saved.bg_col = touchPrefsGetBackgroundColor();
|
||||
touchPrefsGetBackgroundImage(s_theme_saved.bg_img, sizeof s_theme_saved.bg_img);
|
||||
s_theme_saved.glass = touchPrefsGetGlassTiles();
|
||||
s_theme_pend = s_theme_saved;
|
||||
const lv_coord_t sw = lv_disp_get_hor_res(nullptr);
|
||||
const lv_coord_t card_w = sw - 22; // as createSettingsModal's cards
|
||||
@@ -65558,6 +65777,11 @@ static void buildThemeSettings() {
|
||||
lv_obj_set_style_text_color(ic, lv_color_hex(COLOR_SUB), LV_PART_MAIN);
|
||||
lv_obj_move_to_index(ic, 0);
|
||||
#endif
|
||||
// Glass tiles (default on): Home widgets, cards and the control panel's tiles let the
|
||||
// background through. Off draws them in the solid panel colour, the pre-aurora look.
|
||||
s_tp.glass_sw = themeSwitchRow(c, cw, "Glass tiles",
|
||||
"Widgets, cards and panel tiles let the background show through. Off: solid tiles.",
|
||||
s_theme_pend.glass, themeGlassCb);
|
||||
s_tp.bg_note = themeNote(c, cw, "High contrast keeps its own fixed colours.");
|
||||
}
|
||||
#endif // !HAS_TDECK_PRO
|
||||
@@ -73685,15 +73909,16 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
|
||||
// the plain V4; ON on the V4-R8 since prefs v49). No-op on a V4.2 board (femLnaControllable() == false).
|
||||
if (board.femLnaControllable()) board.setFemLnaEnable(touchPrefsGetFemLna());
|
||||
#endif
|
||||
#if defined(HAS_TDISPLAY_P4)
|
||||
// T-Display P4 antenna select: force the on-board antenna (RF1 / IO1 HIGH) on EVERY boot,
|
||||
// deliberately ignoring whatever was chosen last session. The external socket may have
|
||||
// nothing screwed onto it, and transmitting into an open connector is what damages the PA —
|
||||
#if CAP_ANTENNA_SELECT
|
||||
// Switchable antenna (T-Display P4): force the on-board antenna (RF1 / IO1 HIGH) on EVERY
|
||||
// boot, deliberately ignoring whatever was chosen last session. The external socket may have
|
||||
// nothing screwed onto it, and transmitting into an open connector is what damages the PA,
|
||||
// so the state you get for free after any power cycle, crash or OTA has to be the safe one.
|
||||
// LilyGo's own driver preloads the same level for the same reason. Choosing external is a
|
||||
// per-session confirmed action; this re-asserts powerOnSequence()'s park in case anything
|
||||
// LilyGo's own driver preloads the same level for the same reason. The one exception is the
|
||||
// owner's confirmed "Always use the external antenna (MMCX)" opt-in (its own NVS key, never
|
||||
// the reserved cfg byte). This also re-asserts powerOnSequence()'s park in case anything
|
||||
// touched IO1 in between.
|
||||
xl9535.setAntennaMode(Xl9535::ANT_INTERNAL);
|
||||
antSelSet(touchPrefsGetAntExtAlways() ? ANT_SEL_EXTERNAL : ANT_SEL_INTERNAL);
|
||||
#endif
|
||||
|
||||
// Buffered LoRa receive (experimental, default OFF): apply the saved opt-in.
|
||||
|
||||
@@ -352,6 +352,16 @@
|
||||
#define CAP_GPS_BAUD_AUTO 0
|
||||
#endif
|
||||
|
||||
// A switchable LoRa antenna: an on-board antenna plus an external socket, picked at
|
||||
// run time (T-Display P4: SKY13453 on XL9535 IO1). Gates the Radio settings antenna
|
||||
// rows, the "Always use the external antenna" boot option and the control panel
|
||||
// antenna tile. The board glue lives in UITask.cpp (antSelMode/antSelSet).
|
||||
#if defined(HAS_TDISPLAY_P4)
|
||||
#define CAP_ANTENNA_SELECT 1
|
||||
#else
|
||||
#define CAP_ANTENNA_SELECT 0
|
||||
#endif
|
||||
|
||||
// ---- Capabilities aliased to existing device-neutral macros -----------------
|
||||
// (behaviour-identical; lets new code use CAP_* while old sites migrate lazily)
|
||||
#if defined(HAS_TDECK_TRACKBALL)
|
||||
|
||||
@@ -107,7 +107,8 @@ void Xl9535::powerOnSequence() {
|
||||
// Antenna select: park on the on-board antenna (RF1) before the radio exists, so the first
|
||||
// transmit after any boot cannot key the PA into a possibly-empty external socket. LilyGo's own
|
||||
// XL9535 init preloads this same level as its safe state. Choosing the external antenna is a
|
||||
// deliberate, confirmed, session-only action from Settings -> Radio.
|
||||
// deliberate, confirmed action from Settings -> Radio: session-only, unless the owner turned on
|
||||
// "Always use the external antenna", which UITask::begin applies later in boot.
|
||||
write(IO_RF_SWITCH, INTERNAL_LEVEL);
|
||||
write(IO_TOUCH_RST, true); // release touch (HI8561 driver probes it)
|
||||
// NB: SCREEN_RST is intentionally NOT touched here — RM69A10Display::begin() sequences it with
|
||||
|
||||
@@ -80,7 +80,8 @@ public:
|
||||
|
||||
enum AntMode : uint8_t {
|
||||
ANT_INTERNAL = 0, // RF1, on-board antenna — always attached, the safe default, forced every boot
|
||||
ANT_EXTERNAL = 1, // RF2, external socket — needs an antenna fitted; session-only, never persisted
|
||||
ANT_EXTERNAL = 1, // RF2, external socket — needs an antenna fitted; session-only unless the owner
|
||||
// turned on "Always use the external antenna" (own NVS key ant_ext, UITask boot-apply)
|
||||
ANT_AUTO = 2, // legacy per-TX toggle: transmits internal, receives external. Diagnostic only.
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user