diff options
author | ConfuSomu | 2021-03-28 13:24:59 -0400 |
---|---|---|
committer | ConfuSomu | 2021-03-28 13:24:59 -0400 |
commit | cadb04d9a3a4236437f5081724b763db04b3f7fd (patch) | |
tree | 319a83f5cc7029407c9d7801565aa8df57abfd66 | |
parent | f5b82cacfb2712837a97999837e90e23e33e3ea5 (diff) | |
download | pico-watch-cadb04d9a3a4236437f5081724b763db04b3f7fd.tar pico-watch-cadb04d9a3a4236437f5081724b763db04b3f7fd.tar.gz pico-watch-cadb04d9a3a4236437f5081724b763db04b3f7fd.zip |
Implement API method for choosing between strings
This allows creating a menu with more ease.
-rw-r--r-- | api.cpp | 76 | ||||
-rw-r--r-- | api.hpp | 11 | ||||
-rw-r--r-- | oled/ss_oled.c | 27 |
3 files changed, 102 insertions, 12 deletions
@@ -15,6 +15,7 @@ void Api::init() { } void Api::init_display() { + sleep_ms(500); // Wait for the OLED to settle oledInit(&m_oled, OLED_128x64, 0x3d, 0, 0, 1, SDA_PIN, SCL_PIN, RESET_PIN, 1000000L); oledFill(&m_oled, 0,1); oledSetContrast(&m_oled, OLED_DEFAULT_CONTRAST); @@ -185,6 +186,81 @@ int Api::gui_popup_intchoice(std::string title, std::string body, int min_num, i return current_num; } +void Api::gui_popup_strchoice_footer(const char selection[]) { + std::string buf{selection}; + buf.insert(0, "Select: "); + + if (buf.size() > 36) // 2 lines of 18 chars + buf.resize(36); + + // Choose most adapted font size + int font; + int chars_per_line; + if (buf.size() > 26) { + font = FONT_6x8; + chars_per_line = 18; + } else { + font = FONT_8x8; + chars_per_line = 13; + } + + // Make selection text fit by adding '\n' at a regular interval + // TODO: Make this a private function + int since_nl = 0; // Characters since newline + for (std::string::size_type i = 0; i < buf.size(); ++i) { + if (buf[i] == '\n') + since_nl = 0; + else if (since_nl++ == chars_per_line) { + buf.insert(i, 1, '\n'); + since_nl = 0; // Probably unneeded + } + } + + oledRectangle(&m_oled, 9,47, 119,63, 1, 1); // Footer background, FIXME pixel bleeding + oledWriteString(&m_oled, 0,10,6, buf.c_str(), font, 1, 0); + m_writebb_needed = true; display_write_backbuffer(); +} + +int Api::gui_popup_strchoice(std::string title, std::string body, const char *choices[27], int choices_size, int min_index, int max_index, int default_index){ + m_button_last_pressed = BUTTON_NONE; + m_send_button_press_to_app = false; + if (max_index == -1) + max_index = choices_size-1; + + int current_index = default_index; + + title.insert(0, "Choose|"); // TODO: Could be made nicer with a custom char instead of pipe char + gui_popup_generic(title, body, 13, 39); // 39: 3 lines of body text, to leave space for selection string + gui_popup_strchoice_footer(choices[current_index]); + + do { + m_button_last_pressed = BUTTON_NONE; + sleep_ms(50); // TODO: use _wfi() + switch (m_button_last_pressed) { + case BUTTON_UP: + current_index += 1; + if (current_index > max_index) + current_index = max_index; + break; + case BUTTON_DOWN: + current_index -= 1; + if (current_index < min_index) + current_index = min_index; + break; + case BUTTON_MODE: + current_index = default_index; + break; + } + if (m_button_last_pressed) + gui_popup_strchoice_footer(choices[current_index]); + } while (m_button_last_pressed != BUTTON_SELECT); + + // Give back control to running app + oledFill(&m_oled, 0, 1); + m_send_button_press_to_app = true; + return current_index; +} + bool Api::gui_footer_text(std::string text, int offset_x, int offset_row, bool invert, bool no_bg) { // Max chars per line for FONT_8x8 is 16 chars // Max chars per line for FONT_6x8 is 21 chars @@ -21,6 +21,7 @@ class Api { // When char* directly passed as parameter: The memory is possibly fragmented as long strings (>215) push the allocation downwards, into lower (higher address) in the heap. title is at 0x20041f90 and body at 0x200045e8, for length of 215 chars. void gui_popup_generic(std::string &title, std::string &body, int max_title_length = 13, int max_body_length = 78); void gui_popup_intchoice_footer(int current_num, int min_num, int max_num); + void gui_popup_strchoice_footer(const char selection[]); public: bool m_send_button_press_to_app = true; enum perf_modes { @@ -64,6 +65,16 @@ class Api { // \param step Value to increment/decrement from when user changes number. This cannot result in an out-of-bounds as the number is clipped to the min/max when this happens. This maybe undesirable behaviour. // \note Strings longer than 13 and 39 respectively will be truncated. int gui_popup_intchoice(std::string title, std::string body, int min_num = 0, int max_num = 10, int default_num = 5, int step = 1); + // Display a popup over the current view and wait for user to choose (with left and right) a string (char array). The default choice is default_index and the user can reset back to it with mode/cancel button. After confirming with select, the choice's index is returned. + // This is a blocking function and should be used only in the app's render method. + // \param title Popup's title. The title is prefixed with "Choice|", so the `title` argument cannot exceed 6 characters. + // \param body String containing the popup's body. The zone has a size of 13×3 characters, so body should not be longer than 39 characters. Newline allows going to the next line and the text is automatically wrapped. Under the body is displayed the current choosen number with the min and max in parenthesis. + // \param choices List of const char arrays to choose from, each string cannot be longer than 27 chars because of "Select: " text. Font size between 6×8 and 8×8 is choosen automatically. Set the second dimension size of your array of choices to max 27. For example, define: `const char *choices[27] = {…}` than call this function by passing directly `choices`. + // \param choices_size Size of choices array, used for avoiding selection of element that are out of the array's bounds. This is only used for determining max_index when max_index is unset. **Following parameters can be left at their default value:** + // \param min_index Smallest element index that can be choosen. This allows reusing the same choice list for muliple prompts and allows programmatically changing the choices available to the user. + // \param max_index Biggest element index that can be choosen. This defaults to the size of the list (set by `choices_size`) if left at -1. + // \param default_index Default string displayed. + int gui_popup_strchoice(std::string title, std::string body, const char *choices[27], int choices_size, int min_index = 0, int max_index = -1, int default_index = 0); // Display text at the bottom of the screen. // The font size is automatically choosen based on the text lenght. // \param text Text to display. Text longer than 21 will be truncated. diff --git a/oled/ss_oled.c b/oled/ss_oled.c index ff40451..c29171f 100644 --- a/oled/ss_oled.c +++ b/oled/ss_oled.c @@ -1740,20 +1740,23 @@ unsigned char c, *s, ucTemp[40]; if (iScroll < 6) // if characters are visible { c = szMsg[i] - 32; - // we can't directly use the pointer to FLASH memory, so copy to a local buffer - ucTemp[0] = 0; - memcpy(&ucTemp[1], &ucSmallFont[(int)c*5], 5); - if (bInvert) InvertBytes(ucTemp, 6); - iLen = 6 - iFontSkip; - if (pOLED->iCursorX + iLen > pOLED->oled_x) // clip right edge - iLen = pOLED->oled_x - pOLED->iCursorX; - oledWriteDataBlock(pOLED, &ucTemp[iFontSkip], iLen, bRender); // write character pattern - // oledCachedWrite(ucTemp, 6); - pOLED->iCursorX += iLen; + if (szMsg[i] != '\n') { // Do not draw the new line char + // we can't directly use the pointer to FLASH memory, so copy to a local buffer + ucTemp[0] = 0; + memcpy(&ucTemp[1], &ucSmallFont[(int)c*5], 5); + if (bInvert) InvertBytes(ucTemp, 6); + iLen = 6 - iFontSkip; + if (pOLED->iCursorX + iLen > pOLED->oled_x) // clip right edge + iLen = pOLED->oled_x - pOLED->iCursorX; + oledWriteDataBlock(pOLED, &ucTemp[iFontSkip], iLen, bRender); // write character pattern + // oledCachedWrite(ucTemp, 6); + pOLED->iCursorX += iLen; + } iFontSkip = 0; - if (pOLED->iCursorX >= pOLED->oled_x-5 && pOLED->oled_wrap) // word wrap enabled? + + if ((pOLED->iCursorX >= pOLED->oled_x-5 && pOLED->oled_wrap) || szMsg[i] == '\n') // word wrap enabled? or newline char { - pOLED->iCursorX = 0; // start at the beginning of the next line + pOLED->iCursorX = x; // start at the beginning of the next line pOLED->iCursorY++; oledSetPosition(pOLED, pOLED->iCursorX, pOLED->iCursorY, bRender); } |