More settings rework
This commit is contained in:
@@ -4,35 +4,8 @@
|
|||||||
#include "portmacro.h"
|
#include "portmacro.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
/**
|
/**
|
||||||
* A helper class for showing a full-screen scrolling message.
|
* A helper for showing a full-screen scrolling message.
|
||||||
*/
|
*/
|
||||||
class ScrollMessage {
|
|
||||||
TickType_t messageStart = 0;
|
|
||||||
int16_t lastOffset = -1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calcualte the width in pixels of the message string, in the large
|
|
||||||
* font and taking into account multi-byte chars.
|
|
||||||
*
|
|
||||||
* @param message The null-terminated message string.
|
|
||||||
*/
|
|
||||||
static uint16_t messageWidth(const char *message);
|
|
||||||
|
|
||||||
public:
|
|
||||||
ScrollMessage() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets this `ScrollMessage` instance to its initial state.
|
|
||||||
*/
|
|
||||||
void reset() {
|
|
||||||
messageStart = 0;
|
|
||||||
lastOffset = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether this `ScrollMessage` instance is in its initial state.
|
|
||||||
*/
|
|
||||||
bool isReset() const { return messageStart == 0; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw and update the scroll message if needed.
|
* Draw and update the scroll message if needed.
|
||||||
@@ -44,10 +17,8 @@ public:
|
|||||||
* @param message The null-terminated message string. This must be the
|
* @param message The null-terminated message string. This must be the
|
||||||
* same string as the previous call, unless this `ScrollMessage` instance
|
* same string as the previous call, unless this `ScrollMessage` instance
|
||||||
* is in its initial state or `reset()` has been called.
|
* is in its initial state or `reset()` has been called.
|
||||||
* @param currentTick The current tick as returned by `xTaskGetTickCount()`.
|
* @param currentTick The current tick as returned by `xTaskGetTickCount()` offset to 0 at start of scrolling.
|
||||||
* @return Whether the OLED framebuffer has been modified.
|
|
||||||
*/
|
*/
|
||||||
bool drawUpdate(const char *message, TickType_t currentTick);
|
void drawScrollingText(const char *message, TickType_t currentTickOffset);
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* SCROLL_MESSAGE_HPP_ */
|
#endif /* SCROLL_MESSAGE_HPP_ */
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "Translation.h"
|
#include "Translation.h"
|
||||||
|
|
||||||
|
|
||||||
#define PRESS_ACCEL_STEP (TICKS_100MS / 3)
|
#define PRESS_ACCEL_STEP (TICKS_100MS / 3)
|
||||||
#define PRESS_ACCEL_INTERVAL_MIN TICKS_100MS
|
#define PRESS_ACCEL_INTERVAL_MIN TICKS_100MS
|
||||||
#define PRESS_ACCEL_INTERVAL_MAX (TICKS_100MS * 3)
|
#define PRESS_ACCEL_INTERVAL_MAX (TICKS_100MS * 3)
|
||||||
@@ -40,5 +39,6 @@ typedef struct {
|
|||||||
void enterSettingsMenu();
|
void enterSettingsMenu();
|
||||||
bool warnUser(const char *warning, const ButtonState buttons);
|
bool warnUser(const char *warning, const ButtonState buttons);
|
||||||
extern const menuitem rootSettingsMenu[];
|
extern const menuitem rootSettingsMenu[];
|
||||||
|
extern const menuitem *subSettingsMenus[];
|
||||||
|
|
||||||
#endif /* GUI_HPP_ */
|
#endif /* GUI_HPP_ */
|
||||||
|
|||||||
@@ -28,19 +28,20 @@ static uint16_t str_display_len(const char *const str) {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ScrollMessage::messageWidth(const char *message) { return FONT_12_WIDTH * str_display_len(message); }
|
/**
|
||||||
|
* Calculate the width in pixels of the message string, in the large
|
||||||
|
* font and taking into account multi-byte chars.
|
||||||
|
*
|
||||||
|
* @param message The null-terminated message string.
|
||||||
|
*/
|
||||||
|
uint16_t messageWidth(const char *message) { return FONT_12_WIDTH * str_display_len(message); }
|
||||||
|
|
||||||
bool ScrollMessage::drawUpdate(const char *message, TickType_t currentTick) {
|
void drawScrollingText(const char *message, TickType_t currentTickOffset) {
|
||||||
bool lcdRefresh = false;
|
|
||||||
|
|
||||||
if (messageStart == 0) {
|
|
||||||
messageStart = currentTick;
|
|
||||||
lcdRefresh = true;
|
|
||||||
}
|
|
||||||
int16_t messageOffset;
|
int16_t messageOffset;
|
||||||
uint16_t msgWidth = messageWidth(message);
|
uint16_t msgWidth = messageWidth(message);
|
||||||
if (msgWidth > OLED_WIDTH) {
|
if (msgWidth > OLED_WIDTH) {
|
||||||
messageOffset = ((currentTick - messageStart) / (getSettingValue(SettingsOptions::DescriptionScrollSpeed) == 1 ? TICKS_100MS / 10 : (TICKS_100MS / 5)));
|
messageOffset = (currentTickOffset / (getSettingValue(SettingsOptions::DescriptionScrollSpeed) == 1 ? TICKS_100MS / 10 : (TICKS_100MS / 5)));
|
||||||
messageOffset %= msgWidth + OLED_WIDTH; // Roll around at the end
|
messageOffset %= msgWidth + OLED_WIDTH; // Roll around at the end
|
||||||
if (messageOffset < OLED_WIDTH) {
|
if (messageOffset < OLED_WIDTH) {
|
||||||
// Snap the message to the left edge.
|
// Snap the message to the left edge.
|
||||||
@@ -54,15 +55,7 @@ bool ScrollMessage::drawUpdate(const char *message, TickType_t currentTick) {
|
|||||||
messageOffset = (OLED_WIDTH - msgWidth) / 2 + msgWidth;
|
messageOffset = (OLED_WIDTH - msgWidth) / 2 + msgWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastOffset != messageOffset) {
|
|
||||||
OLED::clearScreen();
|
|
||||||
|
|
||||||
//^ Rolling offset based on time
|
//^ Rolling offset based on time
|
||||||
OLED::setCursor((OLED_WIDTH - messageOffset), 0);
|
OLED::setCursor((OLED_WIDTH - messageOffset), 0);
|
||||||
OLED::print(message, FontStyle::LARGE);
|
OLED::print(message, FontStyle::LARGE);
|
||||||
lastOffset = messageOffset;
|
|
||||||
lcdRefresh = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lcdRefresh;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -440,6 +440,12 @@ const menuitem advancedMenu[] = {
|
|||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
|
extern const menuitem *subSettingsMenus[] {
|
||||||
|
#if defined(POW_DC) || defined(POW_QC) || defined(POW_PD)
|
||||||
|
powerMenu,
|
||||||
|
#endif
|
||||||
|
solderingMenu, PowerSavingMenu, UIMenu, advancedMenu,
|
||||||
|
};
|
||||||
/* ^^^ !!!ENABLE CLANG-FORMAT back!!! ^^^ */
|
/* ^^^ !!!ENABLE CLANG-FORMAT back!!! ^^^ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -460,10 +466,9 @@ static void printShortDescription(SettingsItemIndex settingsItemIndex, uint16_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int userConfirmation(const char *message) {
|
static int userConfirmation(const char *message) {
|
||||||
ScrollMessage scrollMessage;
|
TickType_t tickStart = xTaskGetTickCount();
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
bool lcdRefresh = scrollMessage.drawUpdate(message, xTaskGetTickCount());
|
drawScrollingText(message, xTaskGetTickCount() - tickStart);
|
||||||
|
|
||||||
ButtonState buttons = getButtonState();
|
ButtonState buttons = getButtonState();
|
||||||
switch (buttons) {
|
switch (buttons) {
|
||||||
@@ -481,11 +486,9 @@ static int userConfirmation(const char *message) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lcdRefresh) {
|
|
||||||
OLED::refresh();
|
OLED::refresh();
|
||||||
osDelay(40);
|
osDelay(40);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ extern "C" {
|
|||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "TipThermoModel.h"
|
#include "TipThermoModel.h"
|
||||||
#include "Translation.h"
|
#include "Translation.h"
|
||||||
|
#include "bflb_platform.h"
|
||||||
#include "cmsis_os.h"
|
#include "cmsis_os.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "history.hpp"
|
#include "history.hpp"
|
||||||
@@ -63,7 +64,7 @@ void guiRenderLoop(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
MSG("Run GUI %d - %d\r\n", (int)currentOperatingMode, (int)buttons);
|
||||||
// Dispatch button state to gui mode
|
// Dispatch button state to gui mode
|
||||||
OperatingMode newMode = currentOperatingMode;
|
OperatingMode newMode = currentOperatingMode;
|
||||||
switch (currentOperatingMode) {
|
switch (currentOperatingMode) {
|
||||||
@@ -144,6 +145,7 @@ void guiRenderLoop(void) {
|
|||||||
OLED::useSecondaryFramebuffer(false);
|
OLED::useSecondaryFramebuffer(false);
|
||||||
context.transitionMode = TransitionAnimation::None; // Clear transition flag
|
context.transitionMode = TransitionAnimation::None; // Clear transition flag
|
||||||
}
|
}
|
||||||
|
MSG("Post GUI %d - %d\r\n", (int)currentOperatingMode, (int)buttons);
|
||||||
// Render done, draw it out
|
// Render done, draw it out
|
||||||
OLED::refresh();
|
OLED::refresh();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,119 @@
|
|||||||
#include "OperatingModes.h"
|
#include "OperatingModes.h"
|
||||||
|
#include "ScrollMessage.hpp"
|
||||||
|
|
||||||
OperatingMode handleSettingsButtons(const ButtonState buttons, guiContext *cxt) {
|
#define HELP_TEXT_TIMEOUT_TICKS (TICKS_SECOND * 3)
|
||||||
switch (buttons) {
|
/*
|
||||||
case BUTTON_NONE:
|
* The settings menu is the most complex bit of GUI code we have
|
||||||
// Do nothing
|
* The menu consists of a two tier menu
|
||||||
break;
|
* Main menu -> Categories
|
||||||
case BUTTON_BOTH:
|
* Secondary menu -> Settings
|
||||||
break;
|
*
|
||||||
|
* For each entry in the menu
|
||||||
|
*/
|
||||||
|
|
||||||
case BUTTON_B_LONG:
|
/**
|
||||||
return OperatingMode::DebugMenuReadout;
|
* Prints two small lines (or one line for CJK) of short description for
|
||||||
break;
|
* setting items and prepares cursor after it.
|
||||||
case BUTTON_F_LONG:
|
* @param settingsItemIndex Index of the setting item.
|
||||||
#ifdef PROFILE_SUPPORT
|
* @param cursorCharPosition Custom cursor char position to set after printing
|
||||||
if (!isTipDisconnected()) {
|
* description.
|
||||||
return OperatingMode::SolderingProfile;
|
*/
|
||||||
|
static void printShortDescription(SettingsItemIndex settingsItemIndex, uint16_t cursorCharPosition) {
|
||||||
|
// print short description (default single line, explicit double line)
|
||||||
|
uint8_t shortDescIndex = static_cast<uint8_t>(settingsItemIndex);
|
||||||
|
OLED::printWholeScreen(translatedString(Tr->SettingsShortNames[shortDescIndex]));
|
||||||
|
|
||||||
|
// prepare cursor for value
|
||||||
|
// make room for scroll indicator
|
||||||
|
OLED::setCursor(cursorCharPosition * FONT_12_WIDTH - 2, 0);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
return OperatingMode::TemperatureAdjust;
|
// Render a menu, based on the position given
|
||||||
#endif
|
// This will either draw the menu item, or the help text depending on how long its been since button press
|
||||||
break;
|
void render_menu(const menuitem *item, guiContext *cxt) {
|
||||||
case BUTTON_F_SHORT:
|
|
||||||
if (!isTipDisconnected()) {
|
// If recent interaction or not help text draw the entry
|
||||||
return OperatingMode::Soldering;
|
if ((xTaskGetTickCount() - lastButtonTime < HELP_TEXT_TIMEOUT_TICKS) || item->description == 0) {
|
||||||
|
|
||||||
|
if (item->shortDescriptionSize > 0) {
|
||||||
|
printShortDescription(item->shortDescriptionIndex, item->shortDescriptionSize);
|
||||||
}
|
}
|
||||||
break;
|
item->draw();
|
||||||
case BUTTON_B_SHORT:
|
} else {
|
||||||
return OperatingMode::SettingsMenu;
|
// Draw description
|
||||||
break;
|
const char *description = translatedString(Tr->SettingsDescriptions[item->description - 1]);
|
||||||
default:
|
drawScrollingText(description, xTaskGetTickCount() - lastButtonTime);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return OperatingMode::HomeScreen;
|
}
|
||||||
|
|
||||||
|
uint16_t getMenuLength(const menuitem *menu) {
|
||||||
|
// walk this menu to find the length
|
||||||
|
for (uint16_t pos = 0; pos < 64; pos++) {
|
||||||
|
if (menu[pos].draw == NULL) {
|
||||||
|
return pos + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0; // Cant find length, be safe
|
||||||
}
|
}
|
||||||
|
|
||||||
OperatingMode gui_SettingsMenu(const ButtonState buttons, guiContext *cxt) {
|
OperatingMode gui_SettingsMenu(const ButtonState buttons, guiContext *cxt) {
|
||||||
// Render out the current settings menu
|
// Render out the current settings menu
|
||||||
// State 1 -> Root menu
|
// State 1 -> Root menu
|
||||||
// State 2 -> Sub entry
|
// State 2 -> Sub entry
|
||||||
|
// Draw main entry if sub-entry is 0, otherwise draw sub-entry
|
||||||
|
|
||||||
uint16_t *mainEntry = &(cxt->scratch_state.state1);
|
uint16_t *mainEntry = &(cxt->scratch_state.state1);
|
||||||
uint16_t *subEntry = &(cxt->scratch_state.state2);
|
uint16_t *subEntry = &(cxt->scratch_state.state2);
|
||||||
|
uint16_t *currentMenuLength = &(cxt->scratch_state.state5);
|
||||||
|
|
||||||
return handleSettingsButtons(buttons, cxt);
|
const menuitem *currentMenu;
|
||||||
|
// Draw the currently on screen item
|
||||||
|
uint16_t currentScreen;
|
||||||
|
if (*subEntry == 0) {
|
||||||
|
// Drawing main menu
|
||||||
|
currentMenu = rootSettingsMenu;
|
||||||
|
currentScreen = *mainEntry;
|
||||||
|
} else {
|
||||||
|
// Drawing sub menu
|
||||||
|
currentMenu = subSettingsMenus[*mainEntry];
|
||||||
|
currentScreen = *subEntry;
|
||||||
|
}
|
||||||
|
render_menu(&(currentMenu[currentScreen]), cxt);
|
||||||
|
|
||||||
|
// Update the cached menu length if unknown
|
||||||
|
if (*currentMenuLength == 0) {
|
||||||
|
// We walk the current menu to find the length
|
||||||
|
*currentMenuLength = getMenuLength(currentMenu);
|
||||||
|
}
|
||||||
|
// Draw scroll
|
||||||
|
uint8_t indicatorHeight = OLED_HEIGHT / *currentMenuLength;
|
||||||
|
uint8_t position = (OLED_HEIGHT * currentScreen) / *currentMenuLength;
|
||||||
|
// Draw if not last item
|
||||||
|
if ((*currentMenuLength != currentScreen) || xTaskGetTickCount() % 1000 < 500) {
|
||||||
|
OLED::drawScrollIndicator(position, indicatorHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now handle user button input
|
||||||
|
|
||||||
|
switch (buttons) {
|
||||||
|
case BUTTON_NONE:
|
||||||
|
break;
|
||||||
|
case BUTTON_BOTH:
|
||||||
|
return OperatingMode::HomeScreen;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BUTTON_B_LONG:
|
||||||
|
break;
|
||||||
|
case BUTTON_F_LONG:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case BUTTON_F_SHORT:
|
||||||
|
break;
|
||||||
|
case BUTTON_B_SHORT:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Otherwise we stay put for next render iteration
|
||||||
|
return OperatingMode::SettingsMenu;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user