// simple project using Arduino UNO and 128x64 OLED Display to display a menu
// created by upir, 2022
// youtube channel: https://www.youtube.com/upir_upir

// YOUTUBE VIDEO: https://youtu.be/HVHVkKt-ldc
// YOUTUBE VIDEO u8g2 version: https://youtu.be/K5e0lFRvZ2E

// links from the video:
// Flipper Zero menu - https://docs.flipperzero.one/basics/control#M5BZO
// WOKWI start project progress bar - https://wokwi.com/projects/300867986768527882
// image2cpp - https://javl.github.io/image2cpp/
// 128x64 SSD1306 OLED Display: https://s.click.aliexpress.com/e/_DCKdvnh
// Transparent OLED display: https://s.click.aliexpress.com/e/_Dns6eLz
// Arduino UNO: https://s.click.aliexpress.com/e/_AXDw1h
// Arduino UNO MINI: https://store.arduino.cc/products/uno-mini-le
// Big OLED Display: https://s.click.aliexpress.com/e/_ADL0T9
// Arduino breadboard prototyping shield: https://s.click.aliexpress.com/e/_ApbCwx
// u8g fonts (fonts available for u8g library): https://nodemcu-build.com/u8g-fonts.php
// u8g documentation: https://github.com/olikraus/u8glib/wiki/userreference
// Photopea (online Photoshop-like tool): https://www.photopea.com/
// image2cpp (convert images into C code): https://javl.github.io/image2cpp/
// Push buttons - https://s.click.aliexpress.com/e/_DmXS8B9
// LCD displays: https://s.click.aliexpress.com/e/_DBgR45P
// u8g2 documentation: https://github.com/olikraus/u8g2/wiki/u8gvsu8g2
// Image Magick: https://imagemagick.org/index.php
// LCD Image converter: https://lcd-image-converter.riuson.com/en/about/


// Related videos:
// Arduino Parking Sensor - https://youtu.be/sEWw087KOj0
// Turbo pressure gauge with Arduino and OLED display - https://youtu.be/JXmw1xOlBdk
// Arduino Car Cluster with OLED Display - https://youtu.be/El5SJelwV_0
// Knob over OLED Display - https://youtu.be/SmbcNx7tbX8
// Arduino + OLED = 3D ? - https://youtu.be/kBAcaA7NAlA
// Arduino OLED Gauge - https://youtu.be/xI6dXTA02UQ
// Smaller & Faster Arduino - https://youtu.be/4GfPQoIRqW8



#include "U8g2lib.h"

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0); // [full framebuffer, size = 1024 bytes]




const unsigned char FLAPPY[] PROGMEM =   {
  0x80,0x0f,0x00,0x70,0x12,0x00,0x08,0x21,0x00,0x04,0x51,0x00,0x02,0x51,0x00,
 0x3e,0x42,0x00,0x41,0xfc,0x00,0x41,0x03,0x01,0x3e,0xfd,0x00,0x04,0x42,0x00,
 0x18,0x3c,0x00,0xe0,0x03,0x00}; 


const unsigned char PONG[] PROGMEM =   {
  0x00,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x1a,0x00,0x00,0x1a,0x00,0x00,
 0x02,0x40,0x00,0x02,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x40,0x00,
 0x00,0x40,0x00,0x00,0x00,0x00}; 

const unsigned char CAMERA[] PROGMEM =   {
0x00,0x00,0x00,0xc0,0x07,0x00,0x40,0x04,0x00,0xff,0xff,0x01,0x01,0x00,0x01,
 0xc1,0x67,0x01,0x41,0x64,0x01,0x41,0x04,0x01,0x41,0x04,0x01,0xc1,0x07,0x01,
 0x01,0x00,0x01,0xff,0xff,0x01}; 


const unsigned char YOUTUBE[] PROGMEM =   {
0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0xf0,0x00,0x00,0xf0,0x03,0x00,
 0xf0,0x0f,0x00,0xf0,0x03,0x00,0xf0,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00}; 


const unsigned char WIFI[] PROGMEM =   {
0x00,0x00,0x00,0xf0,0x0f,0x00,0x08,0x10,0x00,0xe4,0x27,0x00,0x12,0x48,0x00,
 0xc9,0x93,0x00,0x24,0x24,0x00,0x90,0x09,0x00,0x80,0x01,0x00,0x80,0x01,0x00,
 0x80,0x01,0x00,0x00,0x00,0x00}; 

const unsigned char* bitmap_icons[5] = {
  FLAPPY,
  PONG,
  CAMERA,
  YOUTUBE,
  WIFI
};


const int NUM_ITEMS = 5; // number of items in the list and also the number of screenshots and screenshots with QR codes (other screens)
const int MAX_ITEM_LENGTH = 20; // maximum characters for the item name

char menu_items [NUM_ITEMS] [MAX_ITEM_LENGTH] = {  // array with item names
  { "FLAPPY" }, 
  { "PONG" }, 
  { "CAMERA" }, 
  { "YOUTUBE" }, 
  { "WI-FI" }
 };


#define BUTTON_UP_PIN 12 // pin for UP button 
#define BUTTON_SELECT_PIN 8 // pin for SELECT button
#define BUTTON_DOWN_PIN 4 // pin for DOWN button

#define DEMO_PIN 13 // pin for demo mode, use switch or wire to enable or disable demo mode, see more details below


int button_up_clicked = 0; // only perform action when button is clicked, and wait until another press
int button_select_clicked = 0; // same as above
int button_down_clicked = 0; // same as above

int item_selected = 0; // which item in the menu is selected

int item_sel_previous; // previous item - used in the menu screen to draw the item before the selected one
int item_sel_next; // next item - used in the menu screen to draw next item after the selected one

int current_screen = 0;   // 0 = menu, 1 = screenshot, 2 = qr

int demo_mode = 0; // when demo mode is set to 1, it automatically goes over all the screens, 0 = control menu with buttons
int demo_mode_state = 0; // demo mode state = which screen and menu item to display
int demo_mode_delay = 0; // demo mode delay = used to slow down the screen switching


void setup() {
  u8g2.setColorIndex(1);  // set the color to white
  u8g2.begin();
  u8g2.setBitmapMode(1);
  u8g2.setFont(u8g2_font_7x13B_tf);
  // define pins for buttons
  // INPUT_PULLUP means the button is HIGH when not pressed, and LOW when pressed
  // since it´s connected between some pin and GND
  pinMode(BUTTON_UP_PIN, INPUT_PULLUP); // up button
  pinMode(BUTTON_SELECT_PIN, INPUT_PULLUP); // select button
  pinMode(BUTTON_DOWN_PIN, INPUT_PULLUP); // down button

  pinMode(DEMO_PIN, INPUT_PULLUP);
  
}


void loop() {

  // when pin 13 is LOW (DEMO_PIN), enable demo mode
  // this could be done either by using a switch
  // or simply by connecting the wire between pin 13 and GND 
  // (those pins are next to each other)
  if (digitalRead(DEMO_PIN) == LOW) {
    demo_mode = 1; // enable demo mode  
  }
  else  {
    demo_mode = 0; // disable demo mode
  }
    

  if (demo_mode == 1) { // when demo mode is active, automatically switch between all the screens and menu items
    demo_mode_delay++; // increase demo mode delay
    if (demo_mode_delay > 15) { // after some time, switch to another screen - change this value to make it slower/faster
      demo_mode_delay = 0;
      demo_mode_state++; // increase counter
      if (demo_mode_state >= NUM_ITEMS*3) {demo_mode_state=0;} // jump back to the first screen
    }
  
    if (demo_mode_state % 3 == 0) {current_screen = 0; item_selected = demo_mode_state/3; } // menu screen
    else if (demo_mode_state % 3 == 1) {current_screen = 1; item_selected = demo_mode_state/3;} // screenshots screen
    else if (demo_mode_state % 3 == 2) {current_screen = 2; item_selected = demo_mode_state/3;} // qr codes screen

  } // end demo mode section


  if (current_screen == 0) { // MENU SCREEN

      // up and down buttons only work for the menu screen
      if ((digitalRead(BUTTON_UP_PIN) == LOW) && (button_up_clicked == 0)) { // up button clicked - jump to previous menu item
        item_selected = item_selected - 1; // select previous item
        button_up_clicked = 1; // set button to clicked to only perform the action once
        if (item_selected < 0) { // if first item was selected, jump to last item
          item_selected = NUM_ITEMS-1;
        }
      }
      else if ((digitalRead(BUTTON_DOWN_PIN) == LOW) && (button_down_clicked == 0)) { // down button clicked - jump to next menu item
        item_selected = item_selected + 1; // select next item
        button_down_clicked = 1; // set button to clicked to only perform the action once
        if (item_selected >= NUM_ITEMS) { // last item was selected, jump to first menu item
          item_selected = 0;
          }
      } 

      if ((digitalRead(BUTTON_UP_PIN) == HIGH) && (button_up_clicked == 1)) { // unclick 
        button_up_clicked = 0;
      }
      if ((digitalRead(BUTTON_DOWN_PIN) == HIGH) && (button_down_clicked == 1)) { // unclick
        button_down_clicked = 0;
      }

  }


  if ((digitalRead(BUTTON_SELECT_PIN) == LOW) && (button_select_clicked == 0)) { // select button clicked, jump between screens
     button_select_clicked = 1; // set button to clicked to only perform the action once
     if (current_screen == 0) {current_screen = 1;} // menu items screen --> screenshots screen
     else if (current_screen == 1) {current_screen = 2;} // screenshots screen --> qr codes screen
     else {current_screen = 0;} // qr codes screen --> menu items screen
  }
  if ((digitalRead(BUTTON_SELECT_PIN) == HIGH) && (button_select_clicked == 1)) { // unclick 
    button_select_clicked = 0;
  }

  // set correct values for the previous and next items
  item_sel_previous = item_selected - 1;
  if (item_sel_previous < 0) {item_sel_previous = NUM_ITEMS - 1;} // previous item would be below first = make it the last
  item_sel_next = item_selected + 1;  
  if (item_sel_next >= NUM_ITEMS) {item_sel_next = 0;} // next item would be after last = make it the first


  u8g2.clearBuffer(); // required for page drawing mode for u8g2 library

    if (current_screen == 0) { // MENU SCREEN

      // selected item background
      u8g2.drawRFrame(1, 22, 126, 20,7);

      // draw previous item as icon + label
      u8g2.setFont(u8g2_font_7x13_tf);
      u8g2.drawStr(25, 17, menu_items[item_sel_previous]); 
      u8g2.drawXBMP( 4, 3, 17, 12, bitmap_icons[item_sel_previous]);          

      // draw selected item as icon + label in bold font
      u8g2.setFont(u8g2_font_7x13B_tf);  
      u8g2.drawStr(25, 38, menu_items[item_selected]);   
      u8g2.drawXBMP( 4, 25, 17, 12, bitmap_icons[item_selected]);     

      // draw next item as icon + label
      u8g2.setFont(u8g2_font_7x13_tf);   
      u8g2.drawStr(25, 59, menu_items[item_sel_next]);   
      u8g2.drawXBMP( 4, 47, 17, 12, bitmap_icons[item_sel_next]);  

      // draw scrollbar background
      //u8g2.drawBitmapP(128-8, 0, 8/8, 64, bitmap_scrollbar_background);

      // draw scrollbar handle
      //u8g2.drawBox(125, 64/NUM_ITEMS * item_selected, 3, 64/NUM_ITEMS); 
           

    } 
    else if (current_screen == 1) { // SCREENSHOTS SCREEN
        //u8g2.drawBitmapP( 0, 0, 128/8, 64, bitmap_screenshots[item_selected]); // draw screenshot
    }
    else if (current_screen == 2) { // QR SCREEN
        //u8g2.drawBitmapP( 0, 0, 128/8, 64, bitmap_qr_codes[item_selected]); // draw qr code screenshot
    }   

  u8g2.sendBuffer(); // send buffer from RAM to display controller

}