mirror of
https://github.com/meshtastic/firmware.git
synced 2026-02-02 15:11:48 +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>
188 lines
7.9 KiB
C++
188 lines
7.9 KiB
C++
#ifdef MESHTASTIC_INCLUDE_INKHUD
|
|
|
|
/*
|
|
|
|
Base class for InkHUD applets
|
|
Must be overriden
|
|
|
|
An applet is one "program" which may show info on the display.
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "configuration.h"
|
|
|
|
#include <GFX.h> // GFXRoot drawing lib
|
|
|
|
#include "mesh/MeshTypes.h"
|
|
|
|
#include "./AppletFont.h"
|
|
#include "./Applets/System/Notification/Notification.h" // The notification object, not the applet
|
|
#include "./InkHUD.h"
|
|
#include "./Persistence.h"
|
|
#include "./Tile.h"
|
|
#include "graphics/niche/Drivers/EInk/EInk.h"
|
|
|
|
namespace NicheGraphics::InkHUD
|
|
{
|
|
|
|
using NicheGraphics::Drivers::EInk;
|
|
using std::to_string;
|
|
|
|
class Applet : public GFX
|
|
{
|
|
public:
|
|
// Which edge Applet::printAt will place on the Y parameter
|
|
enum VerticalAlignment : uint8_t {
|
|
TOP,
|
|
MIDDLE,
|
|
BOTTOM,
|
|
};
|
|
|
|
// Which edge Applet::printAt will place on the X parameter
|
|
enum HorizontalAlignment : uint8_t {
|
|
LEFT,
|
|
RIGHT,
|
|
CENTER,
|
|
};
|
|
|
|
// An easy-to-understand interpretation of SNR and RSSI
|
|
// Calculate with Applet::getSignalStrength
|
|
enum SignalStrength : int8_t {
|
|
SIGNAL_UNKNOWN = -1,
|
|
SIGNAL_NONE,
|
|
SIGNAL_BAD,
|
|
SIGNAL_FAIR,
|
|
SIGNAL_GOOD,
|
|
};
|
|
|
|
Applet();
|
|
|
|
void setTile(Tile *t); // Should only be called via Tile::setApplet
|
|
Tile *getTile(); // Tile with which this applet is linked
|
|
|
|
// Rendering
|
|
|
|
void render(bool full); // Draw the applet
|
|
bool wantsToRender(); // Check whether applet wants to render
|
|
bool wantsToAutoshow(); // Check whether applet wants to become foreground
|
|
Drivers::EInk::UpdateTypes wantsUpdateType(); // Check which display update type the applet would prefer
|
|
bool wantsFullRender(); // Check whether applet wants to render over its previous render
|
|
void updateDimensions(); // Get current size from tile
|
|
void resetDrawingSpace(); // Makes sure every render starts with same parameters
|
|
|
|
// State of the applet
|
|
|
|
void activate(); // Begin running
|
|
void deactivate(); // Stop running
|
|
void bringToForeground(); // Show
|
|
void sendToBackground(); // Hide
|
|
bool isActive();
|
|
bool isForeground();
|
|
|
|
// Event handlers
|
|
|
|
virtual void onRender(bool full) = 0; // For drawing the applet
|
|
virtual void onActivate() {}
|
|
virtual void onDeactivate() {}
|
|
virtual void onForeground() {}
|
|
virtual void onBackground() {}
|
|
virtual void onShutdown() {}
|
|
virtual void onButtonShortPress() {}
|
|
virtual void onButtonLongPress() {}
|
|
virtual void onExitShort() {}
|
|
virtual void onExitLong() {}
|
|
virtual void onNavUp() {}
|
|
virtual void onNavDown() {}
|
|
virtual void onNavLeft() {}
|
|
virtual void onNavRight() {}
|
|
virtual void onFreeText(char c) {}
|
|
virtual void onFreeTextDone() {}
|
|
virtual void onFreeTextCancel() {}
|
|
|
|
virtual bool approveNotification(Notification &n); // Allow an applet to veto a notification
|
|
|
|
static uint16_t getHeaderHeight(); // How tall the "standard" applet header is
|
|
|
|
static AppletFont fontSmall, fontMedium, fontLarge; // The general purpose fonts, used by all applets
|
|
|
|
const char *name = nullptr; // Shown in applet selection menu. Also used as an identifier by InkHUD::getSystemApplet
|
|
|
|
protected:
|
|
void drawPixel(int16_t x, int16_t y, uint16_t color) override; // Place a single pixel. All drawing output passes through here
|
|
|
|
void requestUpdate(EInk::UpdateTypes type = EInk::UpdateTypes::UNSPECIFIED,
|
|
bool full = true); // Ask WindowManager to schedule a display update
|
|
void requestAutoshow(); // Ask for applet to be moved to foreground
|
|
|
|
uint16_t X(float f); // Map applet width, mapped from 0 to 1.0
|
|
uint16_t Y(float f); // Map applet height, mapped from 0 to 1.0
|
|
void setCrop(int16_t left, int16_t top, uint16_t width, uint16_t height); // Ignore pixels drawn outside a certain region
|
|
void resetCrop(); // Removes setCrop()
|
|
|
|
// Text
|
|
|
|
void setFont(AppletFont f);
|
|
AppletFont getFont();
|
|
uint16_t getTextWidth(std::string text);
|
|
uint16_t getTextWidth(const char *text);
|
|
uint32_t getWrappedTextHeight(int16_t left, uint16_t width, std::string text); // Result of printWrapped
|
|
void printAt(int16_t x, int16_t y, const char *text, HorizontalAlignment ha = LEFT, VerticalAlignment va = TOP);
|
|
void printAt(int16_t x, int16_t y, std::string text, HorizontalAlignment ha = LEFT, VerticalAlignment va = TOP);
|
|
void printThick(int16_t xCenter, int16_t yCenter, std::string text, uint8_t thicknessX, uint8_t thicknessY); // Faux bold
|
|
void printWrapped(int16_t left, int16_t top, uint16_t width, std::string text); // Per-word line wrapping
|
|
|
|
void hatchRegion(int16_t x, int16_t y, uint16_t w, uint16_t h, uint8_t spacing, Color color); // Fill with sparse lines
|
|
void drawHeader(std::string text); // Draw the standard applet header
|
|
|
|
// Meshtastic Logo
|
|
|
|
static constexpr float LOGO_ASPECT_RATIO = 1.9; // Width:Height for drawing the Meshtastic logo
|
|
uint16_t getLogoWidth(uint16_t limitWidth, uint16_t limitHeight); // Size Meshtastic logo to fit within region
|
|
uint16_t getLogoHeight(uint16_t limitWidth, uint16_t limitHeight); // Size Meshtastic logo to fit within region
|
|
void drawLogo(int16_t centerX, int16_t centerY, uint16_t width, uint16_t height,
|
|
Color color = BLACK); // Draw the Meshtastic logo
|
|
|
|
std::string hexifyNodeNum(NodeNum num); // Style as !0123abdc
|
|
SignalStrength getSignalStrength(float snr, float rssi); // Interpret SNR and RSSI, as an easy to understand value
|
|
std::string getTimeString(uint32_t epochSeconds); // Human readable
|
|
std::string getTimeString(); // Current time, human readable
|
|
uint16_t getActiveNodeCount(); // Duration determined by user, in onscreen menu
|
|
std::string localizeDistance(uint32_t meters); // Human readable distance, imperial or metric
|
|
std::string parse(std::string text); // Handle text which might contain special chars
|
|
std::string parseShortName(meshtastic_NodeInfoLite *node); // Get the shortname, or a substitute if has unprintable chars
|
|
bool isPrintable(std::string); // Check for characters which the font can't print
|
|
|
|
// Convenient references
|
|
|
|
InkHUD *inkhud = nullptr;
|
|
Persistence::Settings *settings = nullptr;
|
|
Persistence::LatestMessage *latestMessage = nullptr;
|
|
|
|
private:
|
|
Tile *assignedTile = nullptr; // Rendered pixels are fed into a Tile object, which translates them, then passes to WM
|
|
bool active = false; // Has the user enabled this applet (at run-time)?
|
|
bool foreground = false; // Is the applet currently drawn on a tile?
|
|
|
|
bool wantRender = false; // In some situations, checked by WindowManager when updating, to skip unneeded redrawing.
|
|
bool wantAutoshow = false; // Does the applet have new data it would like to display in foreground?
|
|
NicheGraphics::Drivers::EInk::UpdateTypes wantUpdateType =
|
|
NicheGraphics::Drivers::EInk::UpdateTypes::UNSPECIFIED; // Which update method we'd prefer when redrawing the display
|
|
bool wantFullRender = true; // Render with a fresh canvas
|
|
|
|
using GFX::setFont; // Make sure derived classes use AppletFont instead of AdafruitGFX fonts directly
|
|
using GFX::setRotation; // Block setRotation calls. Rotation is handled globally by WindowManager.
|
|
|
|
AppletFont currentFont; // As passed to setFont
|
|
|
|
// As set by setCrop
|
|
int16_t cropLeft = 0;
|
|
int16_t cropTop = 0;
|
|
uint16_t cropWidth = 0;
|
|
uint16_t cropHeight = 0;
|
|
};
|
|
|
|
}; // namespace NicheGraphics::InkHUD
|
|
|
|
#endif |