Help adapting code to lose delay - multiple neopixel

Hello,

Im currently trying to adapt some tail lights using neopixel rings and strips.

The first part of my idea is to have two 12 led rings on dim red as tail lights, when a button is pressed there are two smaller 7 led rings which illuminate at 100% brightness and the outer rings also change to 100% brightness.

The second part is an led strip which will be used for an indicator. when a button is pressed the strip will fill one led after another until the strip is full and then all leds go off at once, a slight pause and then repeat until the button is de-pressed. Similar to new audi sweeping indicators.

I have the above working.

The issue i have i assume is because of the delay used in the code, basically once the indicator button is pressed nothing else responds until the sweep of the indicator is complete.
For example i switch the indicator on and try press the brake light and only when the sweep is complete does the brake light illuminate and again if the brake light button is depressed whilst the indicator is sweeping the light remain on until the indicator completes the sweep.

Can anyone assist me with changing my code? I've been googling frantically and found numerous sites with examples of this process working using Millis but cant work out how to edit my code to use that format.

Thanks in advanced.

// tail and brake
#include <Adafruit_NeoPixel.h>
#define PIN            9
#define NUMPIXELS      38
const int buttonPin = 6;
int buttonState = 0;
// indicator
#define PIN1            10
#define NUMPIXELS1      24
const int buttonPin1 = 7;
int buttonState1 = 0;

Adafruit_NeoPixel pixels1 = Adafruit_NeoPixel(NUMPIXELS1, PIN1, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip1 = Adafruit_NeoPixel(NUMPIXELS1, PIN1, NEO_GRB + NEO_KHZ800);

// tail light
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

int delayval = 0;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  pixels.begin();
  pinMode(buttonPin1, INPUT_PULLUP);
  pixels1.begin();
  strip1.begin();
}
  void colorWipe(uint32_t c, uint8_t wait) {
    for (uint16_t i = 0; i < strip1.numPixels(); i++) {
      strip1.setPixelColor(i, c);
      strip1.show();
      delay(wait);
    }
  }

void loop() {

  buttonState = digitalRead(buttonPin);
  buttonState1 = digitalRead(buttonPin1);
  tailLights();
  indicatorSweep();
}
void tailLights() {
// brake lights
  if (buttonState == LOW) {
    for (int i = 0; i < NUMPIXELS; i++) {
      pixels.setPixelColor(i, pixels.Color(255, 0, 0)); // all led rings max brightness red colour - Brakes applied 
      pixels.show(); 
      delay(delayval);
    }
  }
  else 
// tail lights
  {
    for (int i = 0; i < 12; i++) {
      pixels.setPixelColor(i, pixels.Color(30, 0, 0)); // first large led ring of 12 leds dim red colour
      pixels.show(); 
      delay(delayval); 
    }
    for (int i = 12; i < 19; i++) {
      pixels.setPixelColor(i, pixels.Color(0, 0, 0)); //first small ring of 7 leds off
      pixels.show(); 
      delay(delayval); 
    }

    for (int i = 19; i < 31; i++) {
      pixels.setPixelColor(i, pixels.Color(30, 0, 0)); // second large ring of 12 leds dim red colour
      pixels.show(); 
      delay(delayval);  
    }
    for (int i = 31; i < 38; i++) {
      pixels.setPixelColor(i, pixels.Color(0, 0, 0)); // second small ring of 7 leds off
      pixels.show(); 
      delay(delayval); 
    }
  }
}

void indicatorSweep() {
// indicator
  if (buttonState1 == LOW) { // fills the led strip one by one untill full amber then all off 
    colorWipe(strip1.Color(255, 60, 0), 20); 

    colorWipe(strip1.Color(0, 0, 0), 0); 
    delay(300);
    strip1.show();

  }

}

This code implements the Adafruit examples in state machine mode:-

// StrandTest from AdaFruit implemented as a state machine
// pattern change by push button
// By Mike Cook Jan 2016

#define PINforControl   7 // pin connected to the small NeoPixels strip
#define NUMPIXELS1      6 // number of LEDs on second strip

#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS1, PINforControl, NEO_GRB + NEO_KHZ800);

unsigned long patternInterval = 20 ; // time between steps in the pattern
unsigned long lastUpdate = 0 ; // for millis() when last update occoured
unsigned long intervals [] = { 20, 20, 50, 100 } ; // speed for each pattern
const byte button = 2; // pin to connect button switch to between pin and ground

void setup() {
  strip.begin(); // This initializes the NeoPixel library.
  wipe(); // wipes the LED buffers
  pinMode(button, INPUT_PULLUP); // change pattern button
}

void loop() {
  static int pattern = 0, lastReading;
  int reading = digitalRead(button);
  if(lastReading == HIGH && reading == LOW){
    pattern++ ; // change pattern number
    if(pattern > 3) pattern = 0; // wrap round if too big
    patternInterval = intervals[pattern]; // set speed for this pattern
    wipe(); // clear out the buffer 
    delay(50); // debounce delay
  }
  lastReading = reading; // save for next time

if(millis() - lastUpdate > patternInterval) updatePattern(pattern);
}

void  updatePattern(int pat){ // call the pattern currently being created
  switch(pat) {
    case 0:
        rainbow(); 
        break;
    case 1: 
        rainbowCycle();
        break;
    case 2:
        theaterChaseRainbow(); 
        break;
    case 3:
         colorWipe(strip.Color(255, 0, 0)); // red
         break;     
  }  
}

void rainbow() { // modified from Adafruit example to make it a state machine
  static uint16_t j=0;
    for(int i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
     j++;
  if(j >= 256) j=0;
  lastUpdate = millis(); // time for next change to the display
  
}
void rainbowCycle() { // modified from Adafruit example to make it a state machine
  static uint16_t j=0;
    for(int i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
  j++;
  if(j >= 256*5) j=0;
  lastUpdate = millis(); // time for next change to the display
}

void theaterChaseRainbow() { // modified from Adafruit example to make it a state machine
  static int j=0, q = 0;
  static boolean on = true;
  // for (int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
  //  for (int q=0; q < 3; q++) {
     if(on){
            for (int i=0; i < strip.numPixels(); i=i+3) {
                strip.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
             }
     }
      else {
           for (int i=0; i < strip.numPixels(); i=i+3) {
               strip.setPixelColor(i+q, 0);        //turn every third pixel off
                 }
      }
     on = !on; // toggel pixelse on or off for next time
      strip.show(); // display
      q++; // update the q variable
      if(q >=3 ){ // if it overflows reset it and update the J variable
        q=0;
        j++;
        if(j >= 256) j = 0;
      }
  lastUpdate = millis(); // time for next change to the display    
}

void colorWipe(uint32_t c) { // modified from Adafruit example to make it a state machine
  static int i =0;
    strip.setPixelColor(i, c);
    strip.show();
  i++;
  if(i >= strip.numPixels()){
    i = 0;
    wipe(); // blank out strip
  }
  lastUpdate = millis(); // time for next change to the display
}


void wipe(){ // clear all LEDs
     for(int i=0;i<strip.numPixels();i++){
       strip.setPixelColor(i, strip.Color(0,0,0)); 
       }
}

uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

Compare the colorWipe function here with the one you have. You will notice there is no for loop or delay.

When called my colorWipe function does the equivalent of one step of the for loop and then returns. It does this by having what was the index variable i, being a static int variable i. The static int means that every time the function is called it uses the value for i that was set the last time it was called. Then the colour of the ith LED is changed and i is incremented.

Then an if statement is used to see if all the LEDs have been changed, if they have then all the LEDs are wiped, that is set to black. Finally in the function the time the function should be called again is set. This is the equivalent of the delay in the your colour.Wipe function.

Finally look at the start of the loop function where variables are checked to see if it is time to run the next step in the animation. You need to do that as well.

Note that this code runs one animation at a time but if the animations use a different set of LEDs then you can run them simultaneously.