From 07598d824cd6a4158f97cf190dff3a6815b49b5f Mon Sep 17 00:00:00 2001 From: Bruce Luckcuck Date: Sat, 16 Jan 2021 13:29:35 -0500 Subject: [PATCH] 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. --- src/main/cms/cms.c | 25 ++++++++++++++++++++++--- src/main/drivers/display.c | 15 ++++++++++++++- src/main/drivers/display.h | 16 +++++++++++++++- src/main/io/displayport_crsf.c | 2 +- src/main/io/displayport_frsky_osd.c | 2 +- src/main/io/displayport_hott.c | 2 +- src/main/io/displayport_max7456.c | 4 ++-- src/main/io/displayport_msp.c | 2 +- src/main/io/displayport_oled.c | 2 +- src/main/io/displayport_srxl.c | 2 +- src/test/unit/unittest_displayport.h | 2 +- 11 files changed, 60 insertions(+), 14 deletions(-) diff --git a/src/main/cms/cms.c b/src/main/cms/cms.c index e5d1977196..ae03db3024 100644 --- a/src/main/cms/cms.c +++ b/src/main/cms/cms.c @@ -51,9 +51,10 @@ #include "config/config.h" #include "config/feature.h" +#include "drivers/motor.h" +#include "drivers/osd_symbols.h" #include "drivers/system.h" #include "drivers/time.h" -#include "drivers/motor.h" #include "fc/rc_controls.h" #include "fc/runtime_config.h" @@ -671,10 +672,13 @@ static void cmsDrawMenu(displayPort_t *pDisplay, uint32_t currentTimeUs) return; } + const bool displayWasCleared = pDisplay->cleared; uint8_t i; const OSD_Entry *p; uint8_t top = smallScreen ? 1 : (pDisplay->rows - pageMaxRow)/2; + pDisplay->cleared = false; + // Polled (dynamic) value display denominator. bool drawPolled = false; @@ -687,12 +691,11 @@ static void cmsDrawMenu(displayPort_t *pDisplay, uint32_t currentTimeUs) uint32_t room = displayTxBytesFree(pDisplay); - if (pDisplay->cleared) { + if (displayWasCleared) { for (p = pageTop, i= 0; (p <= pageTop + pageMaxRow); p++, i++) { SET_PRINTLABEL(runtimeEntryFlags[i]); SET_PRINTVALUE(runtimeEntryFlags[i]); } - pDisplay->cleared = false; } else if (drawPolled) { for (p = pageTop, i = 0; (p <= pageTop + pageMaxRow); p++, i++) { 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) diff --git a/src/main/drivers/display.c b/src/main/drivers/display.c index 1ac9ca00d8..d2b624f352 100644 --- a/src/main/drivers/display.c +++ b/src/main/drivers/display.c @@ -200,7 +200,19 @@ bool displayGetCanvas(displayCanvas_t *canvas, const displayPort_t *instance) 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->clearScreen(instance); @@ -208,4 +220,5 @@ void displayInit(displayPort_t *instance, const displayPortVTable_t *vTable) instance->cleared = true; instance->grabCount = 0; instance->cursorRow = -1; + instance->deviceType = deviceType; } diff --git a/src/main/drivers/display.h b/src/main/drivers/display.h index 8990d1a052..985fc0ac7f 100644 --- a/src/main/drivers/display.h +++ b/src/main/drivers/display.h @@ -20,6 +20,16 @@ #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 { DISPLAYPORT_ATTR_NONE = 0, DISPLAYPORT_ATTR_INFO, @@ -69,6 +79,9 @@ typedef struct displayPort_s { // Displayport device capability bool useDeviceBlink; + + // The type of display device + displayPortDeviceType_e deviceType; } displayPort_t; typedef struct displayPortVTable_s { @@ -115,8 +128,9 @@ bool displayCheckReady(displayPort_t *instance, bool rescan); void displayBeginTransaction(displayPort_t *instance, displayTransactionOption_e opts); void displayCommitTransaction(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 displayLayerSelect(displayPort_t *instance, displayPortLayer_e layer); bool displayLayerCopy(displayPort_t *instance, displayPortLayer_e destLayer, displayPortLayer_e sourceLayer); void displaySetBackgroundType(displayPort_t *instance, displayPortBackground_e backgroundType); +bool displaySupportsOsdSymbols(displayPort_t *instance); diff --git a/src/main/io/displayport_crsf.c b/src/main/io/displayport_crsf.c index 4ac97c713a..f7641cdcd3 100644 --- a/src/main/io/displayport_crsf.c +++ b/src/main/io/displayport_crsf.c @@ -210,7 +210,7 @@ displayPort_t *displayPortCrsfInit() && (rxConfig()->serialrx_provider == SERIALRX_CRSF)) { crsfDisplayPortSetDimensions(CRSF_DISPLAY_PORT_ROWS_MAX, CRSF_DISPLAY_PORT_COLS_MAX); - displayInit(&crsfDisplayPort, &crsfDisplayPortVTable); + displayInit(&crsfDisplayPort, &crsfDisplayPortVTable, DISPLAYPORT_DEVICE_TYPE_CRSF); return &crsfDisplayPort; } else { return NULL; diff --git a/src/main/io/displayport_frsky_osd.c b/src/main/io/displayport_frsky_osd.c index 488077a4b5..0db8fa7198 100644 --- a/src/main/io/displayport_frsky_osd.c +++ b/src/main/io/displayport_frsky_osd.c @@ -494,7 +494,7 @@ static const displayPortVTable_t frskyOsdVTable = { displayPort_t *frskyOsdDisplayPortInit(const videoSystem_e videoSystem) { if (frskyOsdInit(videoSystem)) { - displayInit(&frskyOsdDisplayPort, &frskyOsdVTable); + displayInit(&frskyOsdDisplayPort, &frskyOsdVTable, DISPLAYPORT_DEVICE_TYPE_FRSKYOSD); redraw(&frskyOsdDisplayPort); return &frskyOsdDisplayPort; } diff --git a/src/main/io/displayport_hott.c b/src/main/io/displayport_hott.c index 7e23abf412..90b568962f 100644 --- a/src/main/io/displayport_hott.c +++ b/src/main/io/displayport_hott.c @@ -131,7 +131,7 @@ static const displayPortVTable_t hottVTable = { displayPort_t *displayPortHottInit() { hottDisplayPort.device = NULL; - displayInit(&hottDisplayPort, &hottVTable); + displayInit(&hottDisplayPort, &hottVTable, DISPLAYPORT_DEVICE_TYPE_HOTT); hottDisplayPort.useFullscreen = true; hottDisplayPort.rows = HOTT_TEXTMODE_DISPLAY_ROWS; hottDisplayPort.cols = HOTT_TEXTMODE_DISPLAY_COLUMNS; diff --git a/src/main/io/displayport_max7456.c b/src/main/io/displayport_max7456.c index 918603129d..c520610cda 100644 --- a/src/main/io/displayport_max7456.c +++ b/src/main/io/displayport_max7456.c @@ -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 // from it at this time. Delay full initialization to // checkReady() with 'rescan' enabled - displayInit(&max7456DisplayPort, &max7456VTable); + displayInit(&max7456DisplayPort, &max7456VTable, DISPLAYPORT_DEVICE_TYPE_MAX7456); *displayPort = &max7456DisplayPort; return false; @@ -239,7 +239,7 @@ bool max7456DisplayPortInit(const vcdProfile_t *vcdProfile, displayPort_t **disp break; case MAX7456_INIT_OK: // MAX7456 configured and detected - displayInit(&max7456DisplayPort, &max7456VTable); + displayInit(&max7456DisplayPort, &max7456VTable, DISPLAYPORT_DEVICE_TYPE_MAX7456); redraw(&max7456DisplayPort); *displayPort = &max7456DisplayPort; diff --git a/src/main/io/displayport_msp.c b/src/main/io/displayport_msp.c index 56e4b015d3..1de4f03e6d 100644 --- a/src/main/io/displayport_msp.c +++ b/src/main/io/displayport_msp.c @@ -172,7 +172,7 @@ static const displayPortVTable_t mspDisplayPortVTable = { displayPort_t *displayPortMspInit(void) { - displayInit(&mspDisplayPort, &mspDisplayPortVTable); + displayInit(&mspDisplayPort, &mspDisplayPortVTable, DISPLAYPORT_DEVICE_TYPE_MSP); if (displayPortProfileMsp()->useDeviceBlink) { mspDisplayPort.useDeviceBlink = true; diff --git a/src/main/io/displayport_oled.c b/src/main/io/displayport_oled.c index 352159861f..2422e06bf9 100644 --- a/src/main/io/displayport_oled.c +++ b/src/main/io/displayport_oled.c @@ -127,7 +127,7 @@ static const displayPortVTable_t oledVTable = { displayPort_t *displayPortOledInit(void *device) { oledDisplayPort.device = device; - displayInit(&oledDisplayPort, &oledVTable); + displayInit(&oledDisplayPort, &oledVTable, DISPLAYPORT_DEVICE_TYPE_OLED); oledDisplayPort.rows = SCREEN_CHARACTER_ROW_COUNT; oledDisplayPort.cols = SCREEN_CHARACTER_COLUMN_COUNT; return &oledDisplayPort; diff --git a/src/main/io/displayport_srxl.c b/src/main/io/displayport_srxl.c index 9422cd9f4d..7af3d61e6b 100644 --- a/src/main/io/displayport_srxl.c +++ b/src/main/io/displayport_srxl.c @@ -150,7 +150,7 @@ displayPort_t *displayPortSrxlInit() && ((rxConfig()->serialrx_provider == SERIALRX_SRXL) || (rxConfig()->serialrx_provider == SERIALRX_SRXL2))) { srxlDisplayPort.device = NULL; - displayInit(&srxlDisplayPort, &srxlVTable); + displayInit(&srxlDisplayPort, &srxlVTable, DISPLAYPORT_DEVICE_TYPE_SRXL); srxlDisplayPort.rows = SPEKTRUM_SRXL_TEXTGEN_BUFFER_ROWS; srxlDisplayPort.cols = SPEKTRUM_SRXL_TEXTGEN_BUFFER_COLS; return &srxlDisplayPort; diff --git a/src/test/unit/unittest_displayport.h b/src/test/unit/unittest_displayport.h index e31c4deda2..bd0137238a 100644 --- a/src/test/unit/unittest_displayport.h +++ b/src/test/unit/unittest_displayport.h @@ -124,7 +124,7 @@ static const displayPortVTable_t testDisplayPortVTable = { displayPort_t *displayPortTestInit(void) { - displayInit(&testDisplayPort, &testDisplayPortVTable); + displayInit(&testDisplayPort, &testDisplayPortVTable, DISPLAYPORT_DEVICE_TYPE_MAX7456); testDisplayPort.rows = UNITTEST_DISPLAYPORT_ROWS; testDisplayPort.cols = UNITTEST_DISPLAYPORT_COLS; return &testDisplayPort;