1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-21 23:35:34 +03:00

Add up/down page indicator to CMS menu display

Often the user doesn't realize that there are more menu items then displayed and the only way to tell was to try and move the selection to the bottom to see if another page appears.

This PR adds page up/down indicators if there are more menu items than those visible on the current display.

Uses the OSD arrow symbols when possible (for OSD supporting devices), otherwise the `^` (carat) and `V` are used for text-only represenatations.

To determine if the device was capable of displaying symbols the `displayPort` structure has a new `deviceType` set when it is initialized. There have been other times when knowing the type of device would have been useful so that's now supported. Then this is abstracted by a new `displaySupportsOsdSymbols()` function. Devices that support OSD are assumed to support the OSD symbols as the OSD element drawing code always uses them. For devices that don't support OSD function we have to presume the sybols aren't available.
This commit is contained in:
Bruce Luckcuck 2021-01-16 13:29:35 -05:00
parent 35de1c8229
commit 07598d824c
11 changed files with 60 additions and 14 deletions

View file

@ -51,9 +51,10 @@
#include "config/config.h" #include "config/config.h"
#include "config/feature.h" #include "config/feature.h"
#include "drivers/motor.h"
#include "drivers/osd_symbols.h"
#include "drivers/system.h" #include "drivers/system.h"
#include "drivers/time.h" #include "drivers/time.h"
#include "drivers/motor.h"
#include "fc/rc_controls.h" #include "fc/rc_controls.h"
#include "fc/runtime_config.h" #include "fc/runtime_config.h"
@ -671,10 +672,13 @@ static void cmsDrawMenu(displayPort_t *pDisplay, uint32_t currentTimeUs)
return; return;
} }
const bool displayWasCleared = pDisplay->cleared;
uint8_t i; uint8_t i;
const OSD_Entry *p; const OSD_Entry *p;
uint8_t top = smallScreen ? 1 : (pDisplay->rows - pageMaxRow)/2; uint8_t top = smallScreen ? 1 : (pDisplay->rows - pageMaxRow)/2;
pDisplay->cleared = false;
// Polled (dynamic) value display denominator. // Polled (dynamic) value display denominator.
bool drawPolled = false; bool drawPolled = false;
@ -687,12 +691,11 @@ static void cmsDrawMenu(displayPort_t *pDisplay, uint32_t currentTimeUs)
uint32_t room = displayTxBytesFree(pDisplay); uint32_t room = displayTxBytesFree(pDisplay);
if (pDisplay->cleared) { if (displayWasCleared) {
for (p = pageTop, i= 0; (p <= pageTop + pageMaxRow); p++, i++) { for (p = pageTop, i= 0; (p <= pageTop + pageMaxRow); p++, i++) {
SET_PRINTLABEL(runtimeEntryFlags[i]); SET_PRINTLABEL(runtimeEntryFlags[i]);
SET_PRINTVALUE(runtimeEntryFlags[i]); SET_PRINTVALUE(runtimeEntryFlags[i]);
} }
pDisplay->cleared = false;
} else if (drawPolled) { } else if (drawPolled) {
for (p = pageTop, i = 0; (p <= pageTop + pageMaxRow); p++, i++) { for (p = pageTop, i = 0; (p <= pageTop + pageMaxRow); p++, i++) {
if (IS_DYNAMIC(p)) if (IS_DYNAMIC(p))
@ -761,6 +764,22 @@ static void cmsDrawMenu(displayPort_t *pDisplay, uint32_t currentTimeUs)
} }
} }
} }
// Draw the up/down page indicators if the display has space.
// Only draw the symbols when necessary after the screen has been cleared. Otherwise they're static.
// If the device supports OSD symbols then use the up/down arrows. Otherwise assume it's a
// simple text device and use the '^' (carat) and 'V' for arrow approximations.
if (displayWasCleared && leftMenuColumn > 0) { // make sure there's room to draw the symbol
if (currentCtx.page > 0) {
const uint8_t symbol = displaySupportsOsdSymbols(pDisplay) ? SYM_ARROW_NORTH : '^';
displayWriteChar(pDisplay, leftMenuColumn - 1, top, DISPLAYPORT_ATTR_NONE, symbol);
}
if (currentCtx.page < pageCount - 1) {
const uint8_t symbol = displaySupportsOsdSymbols(pDisplay) ? SYM_ARROW_SOUTH : 'V';
displayWriteChar(pDisplay, leftMenuColumn - 1, top + pageMaxRow, DISPLAYPORT_ATTR_NONE, symbol);
}
}
} }
const void *cmsMenuChange(displayPort_t *pDisplay, const void *ptr) const void *cmsMenuChange(displayPort_t *pDisplay, const void *ptr)

View file

@ -200,7 +200,19 @@ bool displayGetCanvas(displayCanvas_t *canvas, const displayPort_t *instance)
return false; return false;
} }
void displayInit(displayPort_t *instance, const displayPortVTable_t *vTable) bool displaySupportsOsdSymbols(displayPort_t *instance)
{
// Assume device types that support OSD display will support the OSD symbols (since the OSD logic will use them)
if ((instance->deviceType == DISPLAYPORT_DEVICE_TYPE_MAX7456)
|| (instance->deviceType == DISPLAYPORT_DEVICE_TYPE_MSP)
|| (instance->deviceType == DISPLAYPORT_DEVICE_TYPE_FRSKYOSD)) {
return true;
} else {
return false;
}
}
void displayInit(displayPort_t *instance, const displayPortVTable_t *vTable, displayPortDeviceType_e deviceType)
{ {
instance->vTable = vTable; instance->vTable = vTable;
instance->vTable->clearScreen(instance); instance->vTable->clearScreen(instance);
@ -208,4 +220,5 @@ void displayInit(displayPort_t *instance, const displayPortVTable_t *vTable)
instance->cleared = true; instance->cleared = true;
instance->grabCount = 0; instance->grabCount = 0;
instance->cursorRow = -1; instance->cursorRow = -1;
instance->deviceType = deviceType;
} }

View file

@ -20,6 +20,16 @@
#pragma once #pragma once
typedef enum {
DISPLAYPORT_DEVICE_TYPE_MAX7456 = 0,
DISPLAYPORT_DEVICE_TYPE_OLED,
DISPLAYPORT_DEVICE_TYPE_MSP,
DISPLAYPORT_DEVICE_TYPE_FRSKYOSD,
DISPLAYPORT_DEVICE_TYPE_CRSF,
DISPLAYPORT_DEVICE_TYPE_HOTT,
DISPLAYPORT_DEVICE_TYPE_SRXL,
} displayPortDeviceType_e;
typedef enum { typedef enum {
DISPLAYPORT_ATTR_NONE = 0, DISPLAYPORT_ATTR_NONE = 0,
DISPLAYPORT_ATTR_INFO, DISPLAYPORT_ATTR_INFO,
@ -69,6 +79,9 @@ typedef struct displayPort_s {
// Displayport device capability // Displayport device capability
bool useDeviceBlink; bool useDeviceBlink;
// The type of display device
displayPortDeviceType_e deviceType;
} displayPort_t; } displayPort_t;
typedef struct displayPortVTable_s { typedef struct displayPortVTable_s {
@ -115,8 +128,9 @@ bool displayCheckReady(displayPort_t *instance, bool rescan);
void displayBeginTransaction(displayPort_t *instance, displayTransactionOption_e opts); void displayBeginTransaction(displayPort_t *instance, displayTransactionOption_e opts);
void displayCommitTransaction(displayPort_t *instance); void displayCommitTransaction(displayPort_t *instance);
bool displayGetCanvas(struct displayCanvas_s *canvas, const displayPort_t *instance); bool displayGetCanvas(struct displayCanvas_s *canvas, const displayPort_t *instance);
void displayInit(displayPort_t *instance, const displayPortVTable_t *vTable); void displayInit(displayPort_t *instance, const displayPortVTable_t *vTable, displayPortDeviceType_e deviceType);
bool displayLayerSupported(displayPort_t *instance, displayPortLayer_e layer); bool displayLayerSupported(displayPort_t *instance, displayPortLayer_e layer);
bool displayLayerSelect(displayPort_t *instance, displayPortLayer_e layer); bool displayLayerSelect(displayPort_t *instance, displayPortLayer_e layer);
bool displayLayerCopy(displayPort_t *instance, displayPortLayer_e destLayer, displayPortLayer_e sourceLayer); bool displayLayerCopy(displayPort_t *instance, displayPortLayer_e destLayer, displayPortLayer_e sourceLayer);
void displaySetBackgroundType(displayPort_t *instance, displayPortBackground_e backgroundType); void displaySetBackgroundType(displayPort_t *instance, displayPortBackground_e backgroundType);
bool displaySupportsOsdSymbols(displayPort_t *instance);

View file

@ -210,7 +210,7 @@ displayPort_t *displayPortCrsfInit()
&& (rxConfig()->serialrx_provider == SERIALRX_CRSF)) { && (rxConfig()->serialrx_provider == SERIALRX_CRSF)) {
crsfDisplayPortSetDimensions(CRSF_DISPLAY_PORT_ROWS_MAX, CRSF_DISPLAY_PORT_COLS_MAX); crsfDisplayPortSetDimensions(CRSF_DISPLAY_PORT_ROWS_MAX, CRSF_DISPLAY_PORT_COLS_MAX);
displayInit(&crsfDisplayPort, &crsfDisplayPortVTable); displayInit(&crsfDisplayPort, &crsfDisplayPortVTable, DISPLAYPORT_DEVICE_TYPE_CRSF);
return &crsfDisplayPort; return &crsfDisplayPort;
} else { } else {
return NULL; return NULL;

View file

@ -494,7 +494,7 @@ static const displayPortVTable_t frskyOsdVTable = {
displayPort_t *frskyOsdDisplayPortInit(const videoSystem_e videoSystem) displayPort_t *frskyOsdDisplayPortInit(const videoSystem_e videoSystem)
{ {
if (frskyOsdInit(videoSystem)) { if (frskyOsdInit(videoSystem)) {
displayInit(&frskyOsdDisplayPort, &frskyOsdVTable); displayInit(&frskyOsdDisplayPort, &frskyOsdVTable, DISPLAYPORT_DEVICE_TYPE_FRSKYOSD);
redraw(&frskyOsdDisplayPort); redraw(&frskyOsdDisplayPort);
return &frskyOsdDisplayPort; return &frskyOsdDisplayPort;
} }

View file

@ -131,7 +131,7 @@ static const displayPortVTable_t hottVTable = {
displayPort_t *displayPortHottInit() displayPort_t *displayPortHottInit()
{ {
hottDisplayPort.device = NULL; hottDisplayPort.device = NULL;
displayInit(&hottDisplayPort, &hottVTable); displayInit(&hottDisplayPort, &hottVTable, DISPLAYPORT_DEVICE_TYPE_HOTT);
hottDisplayPort.useFullscreen = true; hottDisplayPort.useFullscreen = true;
hottDisplayPort.rows = HOTT_TEXTMODE_DISPLAY_ROWS; hottDisplayPort.rows = HOTT_TEXTMODE_DISPLAY_ROWS;
hottDisplayPort.cols = HOTT_TEXTMODE_DISPLAY_COLUMNS; hottDisplayPort.cols = HOTT_TEXTMODE_DISPLAY_COLUMNS;

View file

@ -231,7 +231,7 @@ bool max7456DisplayPortInit(const vcdProfile_t *vcdProfile, displayPort_t **disp
// MAX7456 IO pins are defined, but we could not get a reply // MAX7456 IO pins are defined, but we could not get a reply
// from it at this time. Delay full initialization to // from it at this time. Delay full initialization to
// checkReady() with 'rescan' enabled // checkReady() with 'rescan' enabled
displayInit(&max7456DisplayPort, &max7456VTable); displayInit(&max7456DisplayPort, &max7456VTable, DISPLAYPORT_DEVICE_TYPE_MAX7456);
*displayPort = &max7456DisplayPort; *displayPort = &max7456DisplayPort;
return false; return false;
@ -239,7 +239,7 @@ bool max7456DisplayPortInit(const vcdProfile_t *vcdProfile, displayPort_t **disp
break; break;
case MAX7456_INIT_OK: case MAX7456_INIT_OK:
// MAX7456 configured and detected // MAX7456 configured and detected
displayInit(&max7456DisplayPort, &max7456VTable); displayInit(&max7456DisplayPort, &max7456VTable, DISPLAYPORT_DEVICE_TYPE_MAX7456);
redraw(&max7456DisplayPort); redraw(&max7456DisplayPort);
*displayPort = &max7456DisplayPort; *displayPort = &max7456DisplayPort;

View file

@ -172,7 +172,7 @@ static const displayPortVTable_t mspDisplayPortVTable = {
displayPort_t *displayPortMspInit(void) displayPort_t *displayPortMspInit(void)
{ {
displayInit(&mspDisplayPort, &mspDisplayPortVTable); displayInit(&mspDisplayPort, &mspDisplayPortVTable, DISPLAYPORT_DEVICE_TYPE_MSP);
if (displayPortProfileMsp()->useDeviceBlink) { if (displayPortProfileMsp()->useDeviceBlink) {
mspDisplayPort.useDeviceBlink = true; mspDisplayPort.useDeviceBlink = true;

View file

@ -127,7 +127,7 @@ static const displayPortVTable_t oledVTable = {
displayPort_t *displayPortOledInit(void *device) displayPort_t *displayPortOledInit(void *device)
{ {
oledDisplayPort.device = device; oledDisplayPort.device = device;
displayInit(&oledDisplayPort, &oledVTable); displayInit(&oledDisplayPort, &oledVTable, DISPLAYPORT_DEVICE_TYPE_OLED);
oledDisplayPort.rows = SCREEN_CHARACTER_ROW_COUNT; oledDisplayPort.rows = SCREEN_CHARACTER_ROW_COUNT;
oledDisplayPort.cols = SCREEN_CHARACTER_COLUMN_COUNT; oledDisplayPort.cols = SCREEN_CHARACTER_COLUMN_COUNT;
return &oledDisplayPort; return &oledDisplayPort;

View file

@ -150,7 +150,7 @@ displayPort_t *displayPortSrxlInit()
&& ((rxConfig()->serialrx_provider == SERIALRX_SRXL) || (rxConfig()->serialrx_provider == SERIALRX_SRXL2))) { && ((rxConfig()->serialrx_provider == SERIALRX_SRXL) || (rxConfig()->serialrx_provider == SERIALRX_SRXL2))) {
srxlDisplayPort.device = NULL; srxlDisplayPort.device = NULL;
displayInit(&srxlDisplayPort, &srxlVTable); displayInit(&srxlDisplayPort, &srxlVTable, DISPLAYPORT_DEVICE_TYPE_SRXL);
srxlDisplayPort.rows = SPEKTRUM_SRXL_TEXTGEN_BUFFER_ROWS; srxlDisplayPort.rows = SPEKTRUM_SRXL_TEXTGEN_BUFFER_ROWS;
srxlDisplayPort.cols = SPEKTRUM_SRXL_TEXTGEN_BUFFER_COLS; srxlDisplayPort.cols = SPEKTRUM_SRXL_TEXTGEN_BUFFER_COLS;
return &srxlDisplayPort; return &srxlDisplayPort;

View file

@ -124,7 +124,7 @@ static const displayPortVTable_t testDisplayPortVTable = {
displayPort_t *displayPortTestInit(void) displayPort_t *displayPortTestInit(void)
{ {
displayInit(&testDisplayPort, &testDisplayPortVTable); displayInit(&testDisplayPort, &testDisplayPortVTable, DISPLAYPORT_DEVICE_TYPE_MAX7456);
testDisplayPort.rows = UNITTEST_DISPLAYPORT_ROWS; testDisplayPort.rows = UNITTEST_DISPLAYPORT_ROWS;
testDisplayPort.cols = UNITTEST_DISPLAYPORT_COLS; testDisplayPort.cols = UNITTEST_DISPLAYPORT_COLS;
return &testDisplayPort; return &testDisplayPort;