mirror of
https://github.com/meshtastic/firmware.git
synced 2026-02-01 06:32:01 +00:00
* Added keyboard option to menu. Shows a keyboard layout but does not type. * Keyboard types into text box and wraps. * send FreeText messages from the send submenu - renamed `KEYBOARD` action to `FREE_TEXT` and moved its menu location to the send submenu - opening the FreeText applet from the menu keeps the menu open and disabled the timeout - the FreeText applet writes to inkhud->freetext - the sending a canned message checks inkhud->freetext and if it isn't empty, sends and clears the inkhud->freetext * Text scrolls along with input * handle free text message completion as an event implements `handleFreeText` and `OnFreeText()` for system applets to interface with the FreeText Applet The FreeText Applet generates an `OnFreeText` event when completing a message which is handled by the first system applet with the `handleFreeText` flag set to true. The Menu Applet now handles this event. * call `onFreeText` whenever the FreeText Applet exits allows the menu to consistently restart its auto-close timeout * Add text cursor * Change UI to remove the header and make text box longer Keyboard displays captial letters for legibility Keyboard types captial letters with long press * center FreeText keys and draw symbolic buttons Move input field and keyboard drawing to their own functions: - `drawInputField()` - `drawKeyboard()` Store the keys in a 1-dimensional array Implement a matching array, `keyWidths`, to set key widths relative to the font size * Add character limit and counter * Fix softlock when hitting character limit * Move text box as its own menu page * rework FreeTextApplet into KeyboardApplet - The Keyboard Applet renders an on-screen keyboard at the lower portion of the screen. - Calling `inkhud->openKeyboard()` sends all the user applets to the background and resizes the first system applet with `handleFreeText` set to True to fit above the on-screen keyboard - `inkhud->closeKeyboard()` reverses this layout change * Fix input box rendering and add character limit to menu free text * remove FREE_TEXT menu page and use the FREE_TEXT menu action solely * force update when changing the free text message * reorganize KeyboardApplet - add comments after each row of `key[]` and `keyWidths[]` to preserve formatting - The selected key is now set using the key index directly - rowWidths are pre-calculated in the KeyboardApplet constructor - removed `drawKeyboard()` and implemented `drawKeyLabel()` * implement `Renderer::clearTile()` to clear the region below a tile * add parameter to forceUpdate() for re-rendering the full screen setting the `all` parameter to true in `inkhud->forceUpdate()` now causes the full screen buffer to clear an re-render. This is helpful for when sending applets to the background and the UI needs a clean canvas. System Applets can now set the `alwaysRender` flag true which causes it to re-render on every screen update. This is set to true in the Battery Icon Applet. * clean up tile clearing loops * implement dirty rendering to let applets draw over their previous render - `Applet::requestUpdate()` now has an optional flag to keep the old canvas - If honored, the renderer calls `render(true)` which runs `onDirtyRender()` instead of `onRender()` for said applet - The renderer will not call a dirty render if the full screen is getting re-rendered * simplify arithmetic in clearTile for better understanding * combine Applet::onRender() and Applet::onDirtyRender() into Applet::onRender(bool full) - add new `full` parameter to onRender() in every applet. This parameter can be ignored by most applets. - `Applet::requestUpdate()` has an optional flag that requests a full render by default * implement tile and partial rendering in KeyboardApplet * add comment for drawKeyLabel() * improve clarity of byte operations in clearTile() * remove typo and commented code * fix inaccurate comments * add null check to openKeyboard() and closeKeyboard() --------- Co-authored-by: zeropt <ferr0fluidmann@gmail.com> Co-authored-by: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com>
125 lines
5.0 KiB
C++
125 lines
5.0 KiB
C++
#ifdef MESHTASTIC_INCLUDE_INKHUD
|
|
|
|
#include "configuration.h"
|
|
|
|
#include "graphics/niche/Drivers/Backlight/LatchingBacklight.h"
|
|
#include "graphics/niche/InkHUD/InkHUD.h"
|
|
#include "graphics/niche/InkHUD/Persistence.h"
|
|
#include "graphics/niche/InkHUD/SystemApplet.h"
|
|
#include "graphics/niche/Utils/CannedMessageStore.h"
|
|
|
|
#include "./MenuItem.h"
|
|
#include "./MenuPage.h"
|
|
|
|
#include "Channels.h"
|
|
#include "concurrency/OSThread.h"
|
|
|
|
namespace NicheGraphics::InkHUD
|
|
{
|
|
|
|
class Applet;
|
|
|
|
class MenuApplet : public SystemApplet, public concurrency::OSThread
|
|
{
|
|
public:
|
|
MenuApplet();
|
|
void onForeground() override;
|
|
void onBackground() override;
|
|
void onButtonShortPress() override;
|
|
void onButtonLongPress() override;
|
|
void onExitShort() override;
|
|
void onNavUp() override;
|
|
void onNavDown() override;
|
|
void onNavLeft() override;
|
|
void onNavRight() override;
|
|
void onFreeText(char c) override;
|
|
void onFreeTextDone() override;
|
|
void onFreeTextCancel() override;
|
|
void onRender(bool full) override;
|
|
|
|
void show(Tile *t); // Open the menu, onto a user tile
|
|
void setStartPage(MenuPage page);
|
|
|
|
protected:
|
|
Drivers::LatchingBacklight *backlight = nullptr; // Convenient access to the backlight singleton
|
|
|
|
int32_t runOnce() override;
|
|
|
|
void execute(MenuItem item); // Perform the MenuAction associated with a MenuItem, if any
|
|
void showPage(MenuPage page); // Load and display a MenuPage
|
|
|
|
void populateSendPage(); // Dynamically create MenuItems including canned messages
|
|
void populateRecipientPage(); // Dynamically create a page of possible destinations for a canned message
|
|
void populateAppletPage(); // Dynamically create MenuItems for toggling loaded applets
|
|
void populateAutoshowPage(); // Dynamically create MenuItems for selecting which applets can autoshow
|
|
void populateRecentsPage(); // Create menu items: a choice of values for settings.recentlyActiveSeconds
|
|
|
|
void drawInputField(uint16_t left, uint16_t top, uint16_t width, uint16_t height,
|
|
std::string text); // Draw input field for free text
|
|
uint16_t getSystemInfoPanelHeight();
|
|
void drawSystemInfoPanel(int16_t left, int16_t top, uint16_t width,
|
|
uint16_t *height = nullptr); // Info panel at top of root menu
|
|
void sendText(NodeNum dest, ChannelIndex channel, const char *message); // Send a text message to mesh
|
|
void freeCannedMessageResources(); // Clear MenuApplet's canned message processing data
|
|
|
|
MenuPage startPageOverride = MenuPage::ROOT;
|
|
MenuPage currentPage = MenuPage::ROOT;
|
|
MenuPage previousPage = MenuPage::EXIT;
|
|
uint8_t cursor = 0; // Which menu item is currently highlighted
|
|
bool cursorShown = false; // Is *any* item highlighted? (Root menu: no initial selection)
|
|
bool freeTextMode = false;
|
|
uint16_t systemInfoPanelHeight = 0; // Need to know before we render
|
|
uint16_t menuTextLimit = 200;
|
|
|
|
std::vector<MenuItem> items; // MenuItems for the current page. Filled by ShowPage
|
|
std::vector<std::string> nodeConfigLabels; // Persistent labels for Node Config pages
|
|
uint8_t selectedChannelIndex = 0; // Currently selected LoRa channel (Node Config → Radio → Channel)
|
|
bool channelPositionEnabled = false;
|
|
bool gpsEnabled = false;
|
|
|
|
// Recents menu checkbox state (derived from settings.recentlyActiveSeconds)
|
|
static constexpr uint8_t RECENTS_COUNT = 6;
|
|
bool recentsSelected[RECENTS_COUNT] = {};
|
|
|
|
// Data for selecting and sending canned messages via the menu
|
|
// Placed into a sub-class for organization only
|
|
class CannedMessages
|
|
{
|
|
public:
|
|
// Share NicheGraphics component
|
|
// Handles loading, getting, setting
|
|
CannedMessageStore *store;
|
|
|
|
// One canned message
|
|
// Links the menu item to the true message text
|
|
struct MessageItem {
|
|
std::string label; // Shown in menu. Prefixed, and UTF-8 chars parsed
|
|
std::string rawText; // The message which will be sent, if this item is selected
|
|
} *selectedMessageItem;
|
|
|
|
// One possible destination for a canned message
|
|
// Links the menu item to the intended recipient
|
|
// May represent either broadcast or DM
|
|
struct RecipientItem {
|
|
std::string label; // Shown in menu
|
|
NodeNum dest = NODENUM_BROADCAST;
|
|
uint8_t channelIndex = 0;
|
|
} *selectedRecipientItem;
|
|
|
|
// These lists are generated when the menu page is populated
|
|
// Cleared onBackground (when MenuApplet closes)
|
|
std::vector<MessageItem> messageItems;
|
|
std::vector<RecipientItem> recipientItems;
|
|
|
|
MessageItem freeTextItem;
|
|
} cm;
|
|
|
|
Applet *borrowedTileOwner = nullptr; // Which applet we have temporarily replaced while displaying menu
|
|
|
|
bool invertedColors = false; // Helper to display current state of config.display.displaymode in InkHUD options
|
|
};
|
|
|
|
} // namespace NicheGraphics::InkHUD
|
|
|
|
#endif
|