       reverse = gt_read(CI1);
     }
 
-    // handle encoder button press
-    DUINO_Encoder::Button b = encoder->get_button();
-    if(b == DUINO_Encoder::DoubleClicked)
-    {
-      // switch main selection
-      invert_current_selection();
-      main_selected++;
-      main_selected %= 6;
-      invert_current_selection();
-    }
-    else if(b == DUINO_Encoder::Clicked)
-    {
-      // switch local selection
-      switch(main_selected)
-      {
-        case 0: // save
-          if(!saved_)
-          {
-            save_params(0, params.bytes, 30);
-            display->fill_rect(123, 2, 3, 3, DUINO_SH1106::Black);
-            display->display(123, 125, 0, 0);
-          }
-          break;
-        case 1: // top
-          invert_current_selection();
-          top_selected++;
-          top_selected %= 5;
-          invert_current_selection();
-          break;
-        default: // stages
-          invert_current_selection();
-          stage_selected++;
-          stage_selected %= 8;
-          invert_current_selection();
-          break;
-      }
-    }
-
-    // handle encoder spin
-    int16_t v = encoder->get_value();
-    if(v)
-    {
-      switch(main_selected)
-      {
-        case 0: // save
-          break;
-        case 1: // top
-          switch(top_selected)
-          {
-            case 0: // count
-              params.vals.stage_count += v;
-              if(params.vals.stage_count < 1)
-              {
-                params.vals.stage_count = 1;
-              }
-              else if(params.vals.stage_count > 8)
-              {
-                params.vals.stage_count = 8;
-              }
-              seq_values.stage_count = params.vals.stage_count;
-              display->fill_rect(10, 12, 5, 7, DUINO_SH1106::White);
-              display->draw_char(10, 12, '0' + params.vals.stage_count, DUINO_SH1106::Black);
-              display->display(10, 14, 1, 2);
-              break;
-            case 1: // dir/add
-              if(v < 0)
-              {
-                params.vals.diradd_mode = 0;
-              }
-              else if(v > 0)
-              {
-                params.vals.diradd_mode = 1;
-              }
-              seq_values.diradd_mode = (bool)params.vals.diradd_mode;
-              display->fill_rect(22, 12, 5, 7, DUINO_SH1106::White);
-              display->draw_char(22, 12, params.vals.diradd_mode ? 'A' : 'D', DUINO_SH1106::Black);
-              display->display(22, 26, 1, 2);
-              break;
-            case 2: // slew
-              params.vals.slew_rate += v;
-              if(params.vals.slew_rate < 0)
-              {
-                params.vals.slew_rate = 0;
-              }
-              else if(params.vals.slew_rate > 16)
-              {
-                params.vals.slew_rate = 16;
-              }
-              seq_values.slew_hz = slew_hz(params.vals.slew_rate);
-              slew_filter->set_frequency(seq_values.slew_hz);
-              display->fill_rect(60, 13, 16, 5, DUINO_SH1106::White);
-              display_slew_rate(60, 13, params.vals.slew_rate, DUINO_SH1106::Black);
-              display->display(60, 75, 1, 2);
-              break;
-            case 3: // gate
-              params.vals.gate_time += v;
-              if(params.vals.gate_time < 0)
-              {
-                params.vals.gate_time = 0;
-              }
-              else if(params.vals.gate_time > 16)
-              {
-                params.vals.gate_time = 16;
-              }
-              seq_values.gate_ms = params.vals.gate_time * (uint16_t)(seq_values.clock_period / 8000);
-              display->fill_rect(85, 13, 16, 5, DUINO_SH1106::White);
-              display_gate_time(85, 13, params.vals.gate_time, DUINO_SH1106::Black);
-              display->display(85, 100, 1, 2);
-              break;
-            case 4: // clock
-              params.vals.clock_bpm += v;
-              if(params.vals.clock_bpm < 0)
-              {
-                params.vals.clock_bpm = 0;
-              }
-              else if(params.vals.clock_bpm > 99)
-              {
-                params.vals.clock_bpm = 99;
-              }
-              seq_values.clock_period = bpm_to_us(params.vals.clock_bpm);
-              seq_values.clock_ext = !(bool)params.vals.clock_bpm;
-              display->fill_rect(109, 12, 17, 7, DUINO_SH1106::White);
-              display_clock(109, 12, params.vals.clock_bpm, DUINO_SH1106::Black);
-              update_clock();
-              display->display(109, 125, 1, 2);
-              break;
-          }
-          break;
-        case 2: // pitch
-          params.vals.stage_pitch[stage_selected] += v;
-          if(params.vals.stage_pitch[stage_selected] < 0)
-          {
-            params.vals.stage_pitch[stage_selected] = 0;
-          }
-          else if(params.vals.stage_pitch[stage_selected] > 119)
-          {
-            params.vals.stage_pitch[stage_selected] = 119;
-          }
-          seq_values.stage_cv[stage_selected] = note_to_cv(params.vals.stage_pitch[stage_selected]);
-          display->fill_rect(16 * stage_selected, 32, 16, 15, DUINO_SH1106::White);
-          display_note(16 * stage_selected, 32, params.vals.stage_pitch[stage_selected], DUINO_SH1106::Black);
-          display->display(16 * stage_selected, 16 * stage_selected + 15, 4, 5);
-          break;
-        case 3: // steps
-          params.vals.stage_steps[stage_selected] += v;
-          if(params.vals.stage_steps[stage_selected] < 1)
-          {
-            params.vals.stage_steps[stage_selected] = 1;
-          }
-          else if(params.vals.stage_steps[stage_selected] > 8)
-          {
-            params.vals.stage_steps[stage_selected] = 8;
-          }
-          seq_values.stage_steps[stage_selected] = params.vals.stage_steps[stage_selected];
-          display->fill_rect(16 * stage_selected + 1, 49, 5, 7, DUINO_SH1106::White);
-          display->draw_char(16 * stage_selected + 1, 49, '0' + params.vals.stage_steps[stage_selected],
-              DUINO_SH1106::Black);
-          display->display(16 * stage_selected + 1, 16 * stage_selected + 5, 6, 7);
-          break;
-        case 4: // gate
-          params.vals.stage_gate[stage_selected] += v;
-          if(params.vals.stage_gate[stage_selected] < 0)
-          {
-            params.vals.stage_gate[stage_selected] = 0;
-          }
-          else if(params.vals.stage_gate[stage_selected] > 5)
-          {
-            params.vals.stage_gate[stage_selected] = 5;
-          }
-          seq_values.stage_gate[stage_selected] = (GateMode)params.vals.stage_gate[stage_selected];
-          display->fill_rect(16 * stage_selected + 8, 49, 7, 7, DUINO_SH1106::White);
-          display->draw_bitmap_7(16 * stage_selected + 8, 49, gate_mode_icons,
-              (GateMode)params.vals.stage_gate[stage_selected], DUINO_SH1106::Black);
-          display->display(16 * stage_selected + 8, 16 * stage_selected + 14, 6, 7);
-          break;
-        case 5: // slew
-          if(v < 0)
-          {
-            params.vals.stage_slew &= ~(1 << stage_selected);
-          }
-          else if(v > 0)
-          {
-            params.vals.stage_slew |= (1 << stage_selected);
-          }
-          seq_values.stage_slew[stage_selected] = (bool)((params.vals.stage_slew >> stage_selected) & 1);
-          display->fill_rect(16 * stage_selected + 1, 59, 14, 4, DUINO_SH1106::Black);
-          display->fill_rect(16 * stage_selected + 2 + 6 * (~(params.vals.stage_slew >> stage_selected) & 1), 60, 6, 2,
-              DUINO_SH1106::White);
-          display->display(16 * stage_selected + 1, 16 * stage_selected + 14, 7, 7);
-          break;
-      }
-
-      // mark save box
-      if(main_selected)
-      {
-        if(saved_)
-        {
-          saved_ = false;
-          display->fill_rect(123, 2, 3, 3, DUINO_SH1106::Black);
-          display->display(123, 125, 0, 0);
-        }
-      }
-    }
+    widget_loop();
 
     // display reverse/address
     if(seq_values.diradd_mode != last_diradd_mode

  {
    if(bpm == 0)
    {
      display->draw_text(x, y, "EXT", color);
    }
    else
    {
      display->draw_char(x, y, '0' + bpm / 10, color);
      display->draw_char(x + 6, y, '0' + bpm % 10, color);
      display->draw_char(x + 12, y, '0', color);
    }
  }

  void display_note(int16_t x, int16_t y, int8_t note, DUINO_SH1106::SH1106Color color)
  {
    // draw octave
    display->draw_char(x + 9, y + 7, '0' + note / 12, color);

    // draw note
    display->draw_char(x + 2, y + 4, semitone_lt[note % 12], color);
    
    // draw intonation symbol
    switch(semitone_in[note % 12])
    {
      case IF:
        display->draw_vline(x + 9, y + 1, 5, color);
        display->draw_pixel(x + 10, y + 3, color);
        display->draw_pixel(x + 10, y + 5, color);
        display->draw_vline(x + 11, y + 4, 2, color);
        break;
      case IS:
        display->draw_vline(x + 9, y + 1, 5, color);
        display->draw_pixel(x + 10, y + 2, color);
        display->draw_pixel(x + 10, y + 4, color);
        display->draw_vline(x + 11, y + 1, 5, color);
        break;
    }
  }

  void display_reverse_address(int16_t x, int16_t y)
  {
    display->fill_rect(x, y, 5, 7, DUINO_SH1106::Black);

    if(seq_values.diradd_mode)
    {
      display->draw_char(30, 12, '1' + stage, DUINO_SH1106::White);
    }
    else
    {
      display->draw_char(30, 12, 0x10 + (unsigned char)reverse, DUINO_SH1106::White);
    }
  }

  void invert_current_selection()
  {
    switch(main_selected)
    {
      case 0: // save
        display->fill_rect(121, 0, 7, 7, DUINO_SH1106::Inverse);
        display->display(121, 127, 0, 0);
        break;
      case 1: // top
        switch(top_selected)
        {
          case 0: // count
            display->fill_rect(9, 11, 7, 9, DUINO_SH1106::Inverse);
            display->display(9, 15, 1, 2);
            break;
          case 1: // dir/add
            display->fill_rect(21, 11, 7, 9, DUINO_SH1106::Inverse);
            display->display(21, 27, 1, 2);
            break;
          case 2: // slew
            display->fill_rect(58, 11, 20, 9, DUINO_SH1106::Inverse);
            display->display(58, 77, 1, 2);
            break;
          case 3: // gate
            display->fill_rect(83, 11, 20, 9, DUINO_SH1106::Inverse);
            display->display(83, 102, 1, 2);
            break;
          case 4: // clock
            display->fill_rect(108, 11, 19, 9, DUINO_SH1106::Inverse);
            display->display(108, 126, 1, 2);
            break;
        }
        break;
      case 2: // pitch
        display->fill_rect(16 * stage_selected, 32, 16, 15, DUINO_SH1106::Inverse);
        display->display(16 * stage_selected, 16 * stage_selected + 15, 4, 5);
        break;
      case 3: // steps
        display->fill_rect(16 * stage_selected, 48, 7, 9, DUINO_SH1106::Inverse);
        display->display(16 * stage_selected, 16 * stage_selected + 6, 6, 7);
        break;
      case 4: // gate
        display->fill_rect(16 * stage_selected + 7, 48, 9, 9, DUINO_SH1106::Inverse);
        display->display(16 * stage_selected + 7, 16 * stage_selected + 15, 6, 7);
        break;
      case 5: // slew
        display->fill_rect(16 * stage_selected, 58, 16, 6, DUINO_SH1106::Inverse);
        display->display(16 * stage_selected, 16 * stage_selected + 15, 7, 7);
        break;
    }
  }

  void display_gate(uint8_t stage, DUINO_SH1106::SH1106Color color)
  {
    display->fill_rect(16 * stage + 6, 26, 4, 4, color);
  }

  struct DU_SEQ_Parameter_Values {


void update_clock();

void save_click_callback();
void count_scroll_callback(int delta);
void diradd_scroll_callback(int delta);
void slew_scroll_callback(int delta);
void gate_scroll_callback(int delta);
void clock_scroll_callback(int delta);
void s_pitch_scroll_callback(uint8_t selected, int delta);
void s_steps_scroll_callback(uint8_t selected, int delta);
void s_gate_scroll_callback(uint8_t selected, int delta);
void s_slew_scroll_callback(uint8_t selected, int delta);
void s_pitch_click_callback();
void s_steps_click_callback();
void s_gate_click_callback();
void s_slew_click_callback();

class DU_SEQ_Function : public DUINO_Function {
 public:
  DU_SEQ_Function() : DUINO_Function(0b01111100) { }
  
  virtual void setup()
  {
    // build widget hierarchy
    container_outer_ = new DUINO_WidgetContainer<6>(DUINO_Widget::DoubleClick, 2);
    widget_save_ = new DUINO_DisplayWidget(121, 0, 7, 7);
    widget_save_->attach_click_callback(save_click_callback);
    container_outer_->attach_child(widget_save_, 0);
    container_top_ = new DUINO_WidgetContainer<5>(DUINO_Widget::Click);
    widget_count_ = new DUINO_DisplayWidget(9, 11, 7, 9);
    widget_count_->attach_scroll_callback(count_scroll_callback);
    container_top_->attach_child(widget_count_, 0);
    widget_diradd_ = new DUINO_DisplayWidget(21, 11, 7, 9);
    widget_diradd_->attach_scroll_callback(diradd_scroll_callback);
    container_top_->attach_child(widget_diradd_, 1);
    widget_slew_ = new DUINO_DisplayWidget(58, 11, 20, 9);
    widget_slew_->attach_scroll_callback(slew_scroll_callback);
    container_top_->attach_child(widget_slew_, 2);
    widget_gate_ = new DUINO_DisplayWidget(83, 11, 20, 9);
    widget_gate_->attach_scroll_callback(gate_scroll_callback);
    container_top_->attach_child(widget_gate_, 3);
    widget_clock_ = new DUINO_DisplayWidget(108, 11, 19, 9);
    widget_clock_->attach_scroll_callback(clock_scroll_callback);
    container_top_->attach_child(widget_clock_, 4);
    container_outer_->attach_child(container_top_, 1);
    widgets_pitch_ = new DUINO_MultiDisplayWidget<8>(0, 32, 16, 15, 16, false, DUINO_Widget::Click);
    widgets_pitch_->attach_scroll_callback_i(s_pitch_scroll_callback);
    widgets_pitch_->attach_click_callback(s_pitch_click_callback);
    container_outer_->attach_child(widgets_pitch_, 2);
    widgets_steps_ = new DUINO_MultiDisplayWidget<8>(0, 48, 7, 9, 16, false, DUINO_Widget::Click);
    widgets_steps_->attach_scroll_callback_i(s_steps_scroll_callback);
    widgets_steps_->attach_click_callback(s_steps_click_callback);
    container_outer_->attach_child(widgets_steps_, 3);
    widgets_gate_ = new DUINO_MultiDisplayWidget<8>(7, 48, 9, 9, 16, false, DUINO_Widget::Click);
    widgets_gate_->attach_scroll_callback_i(s_gate_scroll_callback);
    widgets_gate_->attach_click_callback(s_gate_click_callback);
    container_outer_->attach_child(widgets_gate_, 4);
    widgets_slew_ = new DUINO_MultiDisplayWidget<8>(0, 58, 16, 6, 16, false, DUINO_Widget::Click);
    widgets_slew_->attach_scroll_callback_i(s_slew_scroll_callback);
    widgets_slew_->attach_click_callback(s_slew_click_callback);
    container_outer_->attach_child(widgets_slew_, 5);

    last_gate = false;
    last_stage = 0;
    last_diradd_mode = false;
