     }
   }
 
+  void widget_trigger_mode_scroll_callback(int delta)
+  {
+    trigger_mode = delta > 0;
+    display_trigger_mode();
+  }
+
+  void widget_key_scroll_callback(int delta)
+  {
+    key += delta;
+    key %= 12;
+    if(key < 0)
+    {
+      key += 12;
+    }
+    display_key();
+    triggered = true;
+  }
+
+  void widget_scale_scroll_callback(int delta)
+  {
+    scale_id += delta;
+    if(scale_id < -1)
+    {
+      scale_id = -1;
+    }
+    else if(scale_id >= N_SCALES)
+    {
+      scale_id = N_SCALES - 1;
+    }
+    scale = get_scale_by_id(scale_id);
+    display_scale();
+    triggered = true;
+  }
+
+  void widgets_notes_click_callback(uint8_t selected)
+  {
+    scale ^= (1 << selected);
+    scale_id = get_id_from_scale(scale);
+    display_scale();
+    triggered = true;
+  }
+
  private:
   float note_cv(int octave, uint8_t key, uint8_t note)
   {
     return (float)octave + (float)key / 12.0 + (float)note / 12.0;
   }
 
-  void get_note_indicator_coordinates(uint8_t note, uint16_t * x, uint16_t * y)
-  {
-    switch(note)
-    {
-      case 0: // C
-        *x = 6;
-        *y = 54;
-        break;
-      case 1: // Db
-        *x = 15;
-        *y = 29;
-        break;
-      case 2: // D
-        *x = 24;
-        *y = 54;
-        break;
-      case 3: // Eb
-        *x = 33;
-        *y = 29;
-        break;
-      case 4: // E
-        *x = 42;
-        *y = 54;
-        break;
-      case 5: // F
-        *x = 60;
-        *y = 54;
-        break;
-      case 6: // Gb
-        *x = 69;
-        *y = 29;
-        break;
-      case 7: // G
-        *x = 78;
-        *y = 54;
-        break;
-      case 8: // Ab
-        *x = 87;
-        *y = 29;
-        break;
-      case 9: // A
-        *x = 96;
-        *y = 54;
-        break;
-      case 10: // Bb
-        *x = 105;
-        *y = 29;
-        break;
-      case 11: // B
-        *x = 114;
-        *y = 54;
-        break;
-    }
-  }
-
-  void invert_current_selection()
-  {
-    if(main_selected)
-    {
-      int16_t x, y;
-      get_note_indicator_coordinates(note_selected, &x, &y);
-      Display.draw_pixel(x, y, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 2, y, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 4, y, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 6, y, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x, y + 2, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x, y + 4, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x, y + 6, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 2, y + 6, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 4, y + 6, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 6, y + 6, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 6, y + 2, DUINO_SH1106::Inverse);
-      Display.draw_pixel(x + 6, y + 4, DUINO_SH1106::Inverse);
-      if(y == 29)
-      {
-        Display.display(x, x + 6, 3, 4);
-      }
-      else
-      {
-        Display.display(x, x + 6, 6, 7);
-      }
-    }
-    else
-    {
-      switch(top_selected)
-      {
-        case 0: // trigger mode
-          Display.fill_rect(76, 0, 9, 9, DUINO_SH1106::Inverse);
-          Display.display(76, 84, 0, 1);
-          break;
-        case 1: // key
-          Display.fill_rect(90, 0, 13, 9, DUINO_SH1106::Inverse);
-          Display.display(90, 102, 0, 1);
-          break;
-        case 2: // scale
-          Display.fill_rect(108, 0, 19, 9, DUINO_SH1106::Inverse);
-          Display.display(108, 126, 0, 1);
-          break;
-      }
-    }
+  void draw_left_key(int16_t x, int16_t y)
+  {
+    Display.draw_vline(x, y, 52, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y, 9, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y + 51, 15, DUINO_SH1106::White);
+    Display.draw_vline(x + 10, y, 29, DUINO_SH1106::White);
+    Display.draw_hline(x + 11, y + 28, 5, DUINO_SH1106::White);
+    Display.draw_vline(x + 16, y + 28, 24, DUINO_SH1106::White);
+  }
+
+  void draw_center_key(int16_t x, int16_t y)
+  {
+    Display.draw_vline(x, y + 28, 24, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y + 28, 5, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y + 51, 15, DUINO_SH1106::White);
+    Display.draw_vline(x + 6, y, 29, DUINO_SH1106::White);
+    Display.draw_hline(x + 7, y, 3, DUINO_SH1106::White);
+    Display.draw_vline(x + 10, y, 29, DUINO_SH1106::White);
+    Display.draw_hline(x + 11, y + 28, 5, DUINO_SH1106::White);
+    Display.draw_vline(x + 16, y + 28, 24, DUINO_SH1106::White);
+  }
+
+  void draw_right_key(int16_t x, int16_t y)
+  {
+    Display.draw_vline(x, y + 28, 24, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y + 28, 5, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y + 51, 15, DUINO_SH1106::White);
+    Display.draw_vline(x + 6, y, 29, DUINO_SH1106::White);
+    Display.draw_hline(x + 7, y, 9, DUINO_SH1106::White);
+    Display.draw_vline(x + 16, y, 52, DUINO_SH1106::White);
+  }
+
+  void draw_black_key(int16_t x, int16_t y)
+  {
+    Display.draw_vline(x, y, 27, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y, 9, DUINO_SH1106::White);
+    Display.draw_hline(x + 1, y + 26, 9, DUINO_SH1106::White);
+    Display.draw_vline(x + 10, y, 27, DUINO_SH1106::White);
   }
 
   void display_trigger_mode()
   {
-    bool selected = !main_selected && top_selected == 0;
-    Display.fill_rect(77, 1, 7, 7, selected ? DUINO_SH1106::White : DUINO_SH1106::Black);
-
-    Display.draw_bitmap_7(77, 1, icons, trigger_mode, selected ? DUINO_SH1106::Black : DUINO_SH1106::White);
-
-    Display.display(77, 83, 0, 0);
+    Display.fill_rect(widget_trigger_mode_->x() + 1, widget_trigger_mode_->y() + 1, 7, 7,
+        widget_trigger_mode_->inverted() ? DUINO_SH1106::White : DUINO_SH1106::Black);
+    Display.draw_bitmap_7(widget_trigger_mode_->x() + 1, widget_trigger_mode_->y() + 1, icons, trigger_mode,
+        widget_trigger_mode_->inverted() ? DUINO_SH1106::Black : DUINO_SH1106::White);
+    widget_trigger_mode_->display();
   }
 
   void display_key()
   {
-    bool selected = !main_selected && top_selected == 1;
-    Display.fill_rect(91, 1, 11, 7, selected ? DUINO_SH1106::White : DUINO_SH1106::Black);
+    Display.fill_rect(widget_key_->x() + 1, widget_key_->y() + 1, 11, 7,
+        widget_key_->inverted() ? DUINO_SH1106::White : DUINO_SH1106::Black);
 
     bool sharp = false;
     unsigned char letter;

  uint16_t scale;
  uint8_t output_note;
  int output_octave;
  bool main_selected;
  uint8_t top_selected;  // 0 - trigger mode, 1 - key, 2 - scale
  int8_t note_selected;
  uint8_t current_displayed_note;
};


  {
    if(!trigger_mode || triggered)
    {
      if(scale == 0)
      {
        cv_out(CO1, 0.0);
        output_octave = 0;
        output_note = 0;
      }
      else
      {
        // read input
        float input = cv_read(CI1);

        // find a lower bound
        int below_octave = (int)input - 1;
        uint8_t below_note = 0;
        while(!(scale & (1 << below_note)))
        {
          below_note++;
        }

        // find closest lower and upper values
        int above_octave = below_octave, octave = below_octave;
        uint8_t above_note = below_note, note = below_note;
        while(note_cv(above_octave, key, above_note) < input)
        {
          note++;
          if(note > 11)
          {
            note = 0;
            octave++;
          }

          if(scale & (1 << note))
          {
            below_octave = above_octave;
            below_note = above_note;
            above_octave = octave;
            above_note = note;
          }
        }

        // output the nearer of the two values
        float below = note_cv(below_octave, key, below_note);
        float above = note_cv(above_octave, key, above_note);
        if(input - below < above - input)
        {
          cv_out(CO1, below);
          octave = below_octave;
          note = below_note;
        }
        else
        {
          cv_out(CO1, above);
          octave = above_octave;
          note = above_note;
        }

        // send trigger and update display note if note has changed
        if(octave != output_octave || note != output_note)
        {
          gt_out(GT1, true, true);
          output_octave = octave;
          output_note = note;
        }
      }
      
      // reset trigger
      triggered = false;
    }

    widget_loop();

    // display current note
    if(output_note != current_displayed_note)
