/* MicroDexed MicroDexed is a port of the Dexed sound engine (https://github.com/asb2m10/dexed) for the Teensy-3.5/3.6 with audio shield. Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android (c)2018,2019 H. Wirtz This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _UI_HPP_ #define _UI_HPP_ #include #include #include "Arduino.h" #define _LCDML_DISP_cols 16 #define _LCDML_DISP_rows 2 #define _LCDML_DISP_cfg_cursor 0x7E // cursor Symbol #define _LCDML_DISP_cfg_scrollbar 1 // enable a scrollbar /*********************************************************************** GLOBAL ***********************************************************************/ LiquidCrystal_I2C lcd(0x27, _LCDML_DISP_cols, _LCDML_DISP_rows); const uint8_t scroll_bar[5][8] = { {B10001, B10001, B10001, B10001, B10001, B10001, B10001, B10001}, // scrollbar top {B11111, B11111, B10001, B10001, B10001, B10001, B10001, B10001}, // scroll state 1 {B10001, B10001, B11111, B11111, B10001, B10001, B10001, B10001}, // scroll state 2 {B10001, B10001, B10001, B10001, B11111, B11111, B10001, B10001}, // scroll state 3 {B10001, B10001, B10001, B10001, B10001, B10001, B11111, B11111} // scrollbar bottom }; void lcdml_menu_display(void); void lcdml_menu_clear(void); void lcdml_menu_control(void); void UI_func_information(uint8_t param); void UI_func_screensaver(uint8_t param); void UI_func_test(uint8_t param); void UI_func_back(uint8_t param); void UI_func_goToRootMenu(uint8_t param); LCDMenuLib2_menu LCDML_0(255, 0, 0, NULL, NULL); // root menu element (do not change) LCDMenuLib2 LCDML(LCDML_0, _LCDML_DISP_rows, _LCDML_DISP_cols, lcdml_menu_display, lcdml_menu_clear, lcdml_menu_control); // LCDML_add(id, prev_layer, new_num, lang_char_array, callback_function) LCDML_add(0, LCDML_0, 1, "Information", UI_func_information); LCDML_add(1, LCDML_0, 2, "Test", UI_func_test); LCDML_add(2, LCDML_0, 3, "Screensaver", UI_func_screensaver); #define _LCDML_DISP_cnt 2 // create menu LCDML_createMenu(_LCDML_DISP_cnt); /*********************************************************************** CONTROL ***********************************************************************/ #define g_LCDML_CONTROL_button_long_press 800 // ms #define g_LCDML_CONTROL_button_short_press 120 // ms #define ENCODER_OPTIMIZE_INTERRUPTS //Only when using pin2/3 (or 20/21 on mega) #include Encoder ENCODER(ENC_R_PIN_B, ENC_R_PIN_A); long g_LCDML_CONTROL_button_press_time = 0; bool g_LCDML_CONTROL_button_prev = HIGH; void lcdml_menu_control(void) { // If something must init, put in in the setup condition if (LCDML.BT_setup()) { //pinMode(ENC_R_PIN_A, INPUT_PULLUP); //pinMode(ENC_R_PIN_B, INPUT_PULLUP); pinMode(BUT_R_PIN, INPUT_PULLUP); } //Volatile Variable long g_LCDML_CONTROL_Encoder_position = ENCODER.read(); bool button = digitalRead(BUT_R_PIN); if (g_LCDML_CONTROL_Encoder_position <= -3) { if (!button) { LCDML.BT_left(); g_LCDML_CONTROL_button_prev = LOW; g_LCDML_CONTROL_button_press_time = -1; } else { LCDML.BT_down(); } ENCODER.write(g_LCDML_CONTROL_Encoder_position + 4); } else if (g_LCDML_CONTROL_Encoder_position >= 3) { if (!button) { LCDML.BT_right(); g_LCDML_CONTROL_button_prev = LOW; g_LCDML_CONTROL_button_press_time = -1; } else { LCDML.BT_up(); } ENCODER.write(g_LCDML_CONTROL_Encoder_position - 4); } else { if (!button && g_LCDML_CONTROL_button_prev) //falling edge, button pressed { g_LCDML_CONTROL_button_prev = LOW; g_LCDML_CONTROL_button_press_time = millis(); } else if (button && !g_LCDML_CONTROL_button_prev) //rising edge, button not active { g_LCDML_CONTROL_button_prev = HIGH; if (g_LCDML_CONTROL_button_press_time < 0) { g_LCDML_CONTROL_button_press_time = millis(); //Reset for left right action } else if ((millis() - g_LCDML_CONTROL_button_press_time) >= g_LCDML_CONTROL_button_long_press) { LCDML.BT_quit(); } else if ((millis() - g_LCDML_CONTROL_button_press_time) >= g_LCDML_CONTROL_button_short_press) { LCDML.BT_enter(); } } } } /*********************************************************************** DISPLAY ***********************************************************************/ void lcdml_menu_clear(void) { lcd.clear(); lcd.setCursor(0, 0); } void lcdml_menu_display(void) { // update content // *************** if (LCDML.DISP_checkMenuUpdate()) { // clear menu // *************** LCDML.DISP_clear(); // declaration of some variables // *************** // content variable char content_text[_LCDML_DISP_cols]; // save the content text of every menu element // menu element object LCDMenuLib2_menu *tmp; // some limit values uint8_t i = LCDML.MENU_getScroll(); uint8_t maxi = _LCDML_DISP_rows + i; uint8_t n = 0; // check if this element has children if ((tmp = LCDML.MENU_getDisplayedObj()) != NULL) { // loop to display lines do { // check if a menu element has a condition and if the condition be true if (tmp->checkCondition()) { // check the type off a menu element if (tmp->checkType_menu() == true) { // display normal content LCDML_getContent(content_text, tmp->getID()); lcd.setCursor(1, n); lcd.print(content_text); } else { if (tmp->checkType_dynParam()) { tmp->callback(n); } } // increment some values i++; n++; } // try to go to the next sibling and check the number of displayed rows } while (((tmp = tmp->getSibling(1)) != NULL) && (i < maxi)); } } if (LCDML.DISP_checkMenuCursorUpdate()) { // init vars uint8_t n_max = (LCDML.MENU_getChilds() >= _LCDML_DISP_rows) ? _LCDML_DISP_rows : (LCDML.MENU_getChilds()); uint8_t scrollbar_min = 0; uint8_t scrollbar_max = LCDML.MENU_getChilds(); uint8_t scrollbar_cur_pos = LCDML.MENU_getCursorPosAbs(); uint8_t scroll_pos = ((1.*n_max * _LCDML_DISP_rows) / (scrollbar_max - 1) * scrollbar_cur_pos); // display rows for (uint8_t n = 0; n < n_max; n++) { //set cursor lcd.setCursor(0, n); //set cursor char if (n == LCDML.MENU_getCursorPos()) { lcd.write(_LCDML_DISP_cfg_cursor); } else { lcd.write(' '); } // delete or reset scrollbar if (_LCDML_DISP_cfg_scrollbar == 1) { if (scrollbar_max > n_max) { lcd.setCursor((_LCDML_DISP_cols - 1), n); lcd.write((uint8_t)0); } else { lcd.setCursor((_LCDML_DISP_cols - 1), n); lcd.print(' '); } } } // display scrollbar if (_LCDML_DISP_cfg_scrollbar == 1) { if (scrollbar_max > n_max) { //set scroll position if (scrollbar_cur_pos == scrollbar_min) { // min pos lcd.setCursor((_LCDML_DISP_cols - 1), 0); lcd.write((uint8_t)1); } else if (scrollbar_cur_pos == (scrollbar_max - 1)) { // max pos lcd.setCursor((_LCDML_DISP_cols - 1), (n_max - 1)); lcd.write((uint8_t)4); } else { // between lcd.setCursor((_LCDML_DISP_cols - 1), scroll_pos / n_max); lcd.write((uint8_t)(scroll_pos % n_max) + 1); } } } } } /*********************************************************************** MENU ***********************************************************************/ void UI_func_information(uint8_t param) { if (LCDML.FUNC_setup()) // ****** SETUP ********* { // setup function lcd.setCursor(0, 0); lcd.print(F("MicroDexed")); lcd.setCursor(0, 1); lcd.print(F("LCDMenuLib2")); } if (LCDML.FUNC_loop()) // ****** LOOP ********* { // loop function, can be run in a loop when LCDML_DISP_triggerMenu(xx) is set // the quit button works in every DISP function without any checks; it starts the loop_end function if (LCDML.BT_checkAny()) { // check if any button is pressed (enter, up, down, left, right) // LCDML_goToMenu stops a running menu function and goes to the menu LCDML.FUNC_goBackToMenu(); } } if (LCDML.FUNC_close()) // ****** STABLE END ********* { // you can here reset some global vars or do nothing } } void UI_func_screensaver(uint8_t param) { if (LCDML.FUNC_setup()) // ****** SETUP ********* { // update LCD content lcd.setCursor(0, 0); // set cursor lcd.print("screensaver"); // print change content lcd.setCursor(0, 1); // set cursor lcd.print("press any key"); LCDML.FUNC_setLoopInterval(100); // starts a trigger event for the loop function every 100 milliseconds } if (LCDML.FUNC_loop()) { if (LCDML.BT_checkAny()) // check if any button is pressed (enter, up, down, left, right) { LCDML.FUNC_goBackToMenu(); // leave this function } } if (LCDML.FUNC_close()) { // The screensaver go to the root menu LCDML.MENU_goRoot(); } } void UI_func_test(uint8_t param) { if (LCDML.FUNC_setup()) // ****** SETUP ********* { // update LCD content lcd.setCursor(0, 0); // set cursor lcd.print("TEST"); // print change content lcd.setCursor(0, 1); // set cursor lcd.print("TEST123"); LCDML.FUNC_setLoopInterval(100); // starts a trigger event for the loop function every 100 milliseconds } if (LCDML.FUNC_loop()) { if (LCDML.BT_checkAny()) // check if any button is pressed (enter, up, down, left, right) { LCDML.FUNC_goBackToMenu(); // leave this function } } if (LCDML.FUNC_close()) { // The screensaver go to the root menu LCDML.MENU_goRoot(); } } /*void UI_func_back(uint8_t param) { if (LCDML.FUNC_setup()) // ****** SETUP ********* { // end function and go an layer back LCDML.FUNC_goBackToMenu(1); // leave this function and go a layer back } }*/ void UI_func_goToRootMenu(uint8_t param) { if (LCDML.FUNC_setup()) // ****** SETUP ********* { // go to root and display menu LCDML.MENU_goRoot(); } } #endif