// generated by Fast Light User Interface Designer (fluid) version 1.0405

#include "VirKeyboardUI.h"
// VirKeyboard.cc

// Original ZynAddSubFX author Nasca Octavian Paul
// Copyright (C) 2002-2005 Nasca Octavian Paul
// Copyright 2009-2010, Alan Calvert
// Copyright 2014-2024, Will Godfrey

// This file is part of yoshimi, which 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 2 of
// the License, or (at your option) any later version.

// yoshimi 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 (version 2 or
// later) for more details.

// You should have received a copy of the GNU General Public License along with
// yoshimi; if not, write to the Free Software Foundation, Inc., 51 Franklin
// Street, Fifth Floor, Boston, MA  02110-1301, USA.

// This file is a derivative of original ZynAddSubFX code


#include "Misc/TextMsgBuffer.h"

    namespace { // Implementation details...
        TextMsgBuffer& textMsgBuffer = TextMsgBuffer::instance();
    }
static const int keyspos[12]={0,-1,1,-2,2,3,-4,4,-5,5,-6,6};
static const int keysoct1qwerty[]={'q','2','w','3','e','r','5','t','6','y','7','u','i','9','o','0','p','[','=',']','\\',FL_Enter,0};
static const int keysoct2qwerty[]={'z','s','x','d','c','v','g','b','h','n','j','m',',','l','.',';','/',0};
static const int keysoct1dw[]={'\'','2',',','3','.','p','5','y','6','f','7','g','c','9','r','0','l','/',']','=','\\',FL_Enter,0};
static const int keysoct2dw[]={';','o','q','e','j','k','i','x','d','b','h','m','w','n','v','s','z',0};
static const int keysoct1qwertz[]={'q','2','w','3','e','r','5','t','6','z','7','u','i','9','o','0','p',252,'\'','+','\\',FL_Enter,0};
static const int keysoct2qwertz[]={'y','s','x','d','c','v','g','b','h','n','j','m',',','l','.',246,'-',0};
static const int keysoct1azerty[]={'a',233,'z','\"','e','r','(','t','-','y',232,'u','i',231,'o',224,'p',65106,'=','$',0};
static const int keysoct2azerty[]={'w','s','x','d','c','v','g','b','h','n','j',',',';','l',':','m','!',0};
static const int SIZE_WHITE = 14;
static const int SIZE_BLACK = 8;

VirKeys::VirKeys(int x,int y, int w, int h, const char *label):Fl_Box(x,y,w,h,label) {
}

void VirKeys::init(SynthEngine *_synth, float &scaledWhite, float &scaledBlack) {
  //
      synth = _synth;
      keyWhite = &scaledWhite;
      keyBlack = &scaledBlack;
      for (int i = 0; i < N_OCT * 12 + 1; ++i)
              pressed[i] = 0;
      pitchWh = 0;
      midich = 0;
      midivel = 100;
      midioct = 2;
      keyoct1 = 3;
      keyoct2 = 2;
      rndvelocity = 0;
}

void VirKeys::draw() {
  //
      int ox = x();
      int oy = y();
      int lx = w();
      int ly = h() - 1;
      int i;
      if (damage() != 1)
      {
          fl_color(WHITE_KEY_COLOUR);
          fl_rectf(ox, oy, lx, ly);

          fl_color(BLACK_KEY_COLOUR);
          fl_line(ox, oy, ox + lx, oy);
          fl_line(ox, oy + ly, ox + lx, oy + ly);
          for (i = 0; i < N_OCT * 7 + 1; ++i)
          {
              fl_line(ox + i * (*keyWhite), oy, ox + i * (*keyWhite), oy + ly);
              int ik = i % 7;
              if (ik == 1 || ik == 2 || ik == 4 || ik == 5 || ik == 6)
                  fl_rectf(ox + i * (*keyWhite) - (*keyBlack) / 2, oy,
                              (*keyBlack) + 1, ly * 3 / 5);
          }
      }

      for (i = 0; i < N_OCT * 12; ++i)
      {
          int noct = i / 12;
          int kv = keyspos[i % 12];
          if (kv >= 0)
          {   // white keys
              if (pressed[i] == 0)
                  fl_color(WHITE_KEY_COLOUR);
              else
                  fl_color(WHITE_KEY_PRESSED);
              fl_rectf(ox + (kv + 7 * noct) * (*keyWhite) + 3, oy + ly * 3 / 5 + 2,
                          (*keyWhite) - 4, ly * 2 / 5 - 3);
          }
          else
          {   // black keys
              kv = keyspos[(i + 1) % 12];
              if (pressed[i] == 0)
                  fl_color(BLACK_KEY_COLOUR);
              else
                  fl_color(BLACK_KEY_PRESSED);
              fl_rectf(ox + 1 + (kv + 7 * noct) * (*keyWhite) - (*keyBlack) / 2, oy + 2,
                          (*keyBlack) - 3, ly * 3 / 5 - 5);
          }
      }
}

void VirKeys::send_data(int action, int control, float value, int type, int kititem , int engine ) {
  //
          type |= TOPLEVEL::type::Write;
          collect_writeData(synth, value, action, type, control, TOPLEVEL::section::midiIn, kititem, engine);
}

int VirKeys::handle(int event) {
  //
      int i;
      int ly = h();
      int x_ = Fl::event_x() - x();
      int y_ = Fl::event_y() - y();
      if (Fl::event_alt())
      {
          auto key = Fl::event_key();
          if (key == 'c')
              return 0;
      }

      if (x_ < 0 && x_ > w() && y_ < 0 && y_>h())
          return 0;
      if (event == FL_PUSH || event == FL_DRAG || event == FL_RELEASE)
      {
          int kpos = -1;
          if (y_ > ly * 3 / 5)
          {   // white keys
              int pos = x_ / (*keyWhite);
              if (pos < 0)
                  return 1;
              for (i = 0; i < 12; ++i)
              {
                  if (pos % 7 == keyspos[i])
                  {
                      kpos = pos / 7 * 12 + i;
                      break;
                  }
              }
          }
          else
          {   // black keys
              int pos = (x_ + (*keyWhite) / 2) / (*keyWhite);
              if (pos < 0)
                  return 1;
              for (i = 1; i < 12; ++i)
              {
                  if (pos % 7 == -keyspos[i])
                  {
                      kpos = pos / 7 * 12 + i;
                      break;
                  }
              }
          }

          if (Fl::event_shift() == 0 && (event == FL_PUSH || event==FL_DRAG))
              presskey(kpos, 1, 1);

          if (event == FL_PUSH && Fl::event_shift() != 0)
          {
              if (pressed[kpos] == 0)
                  presskey(kpos, 0, 1);
              else
                  releasekey(kpos, 1);
          }
          if (event == FL_RELEASE && Fl::event_shift() == 0)
              relaseallkeys(1);
          take_focus();
      }

      const int *keysoct1 = keysoct1qwerty;
      const int *keysoct2 = keysoct2qwerty;

      if (synth->getRuntime().virKeybLayout == 1)
      {
          keysoct1 = keysoct1dw;
          keysoct2 = keysoct2dw;
      }
      else if (synth->getRuntime().virKeybLayout == 2)
      {
          keysoct1 = keysoct1qwertz;
          keysoct2 = keysoct2qwertz;
      }
      else if (synth->getRuntime().virKeybLayout == 3)
      {
          keysoct1 = keysoct1azerty;
          keysoct2 = keysoct2azerty;
      }

      if (event == FL_KEYDOWN || event == FL_KEYUP)
      {
          int key = Fl::event_key();
          int kpos = -1;
          for (i = 0; keysoct1[i] != 0; ++i)
              if (key == keysoct1[i])
                  kpos = i + 12 * keyoct1;
          for (i = 0; keysoct2[i] != 0; ++i)
              if (key == keysoct2[i])
                  kpos = i + 12 * keyoct2;

          if (kpos == -1)
              return 0;
          if (event == FL_KEYUP && Fl::event_key(key) == 0 && Fl::get_key(key) != 0)
              return 0;
          if (event == FL_KEYDOWN)
              presskey(kpos, 0, 2);
          else
              releasekey(kpos, 2);
      }
      return 1;
}

void VirKeys::presskey(int nk,int exclusive,int type) {
  // Exclusive means that multiple keys can be pressed at once
      // when the user uses the shift key
      if (nk >= N_OCT * 12)
          return;
      if (nk < 0 && exclusive == 0)
      {
          relaseallkeys(type);
          return;
      }
      if (nk < 0)
          return;
      if (pressed[nk] != 0)
          return; // the key is already pressed

      if (exclusive != 0)
          relaseallkeys(type);
      pressed[nk] = type;

      damage(1);
      float vel = midivel;
      if (rndvelocity != 0)
      {
          vel = midivel * (127.0 - rndvelocity) / 127.0 + synth->numRandom() * rndvelocity;
      }
      send_data(0, 0, vel, TOPLEVEL::type::Integer, midich, nk + midioct * 12);
}

void VirKeys::releasekey(int nk,int type) {
  //
      if (nk < 0 || nk >= N_OCT * 12)
          return;
      if (pressed[nk] == 0)
          return; // the key is not pressed
      if (type != 0 && pressed[nk] != type)
          return;
      pressed[nk] = 0;
      damage(1);
      send_data(0, 1, 0, TOPLEVEL::type::Integer, midich, nk + midioct * 12);
}

void VirKeys::relaseallkeys(int type) {
  //
      for (int i = 0; i < N_OCT * 12; ++i)
          releasekey(i, type);
}

void VirKeyboard::cb_virkeyboardwindow_i(ScaleTrackedWindow*, void*) {
  //
        virtClose->do_callback();
}
void VirKeyboard::cb_virkeyboardwindow(ScaleTrackedWindow* o, void* v) {
  ((VirKeyboard*)(o->user_data()))->cb_virkeyboardwindow_i(o,v);
}

void VirKeyboard::cb_key_i(Fl_Counter* o, void*) {
  //
          relaseallkeys();
          if (Fl::event_button() == 3)
               o->value(3);
          virkeys->keyoct1 = (int)o->value();
          virkeys->take_focus();
}
void VirKeyboard::cb_key(Fl_Counter* o, void* v) {
  ((VirKeyboard*)(o->parent()->user_data()))->cb_key_i(o,v);
}

void VirKeyboard::cb_maps_i(Fl_Counter* o, void*) {
  //
          relaseallkeys();
          if (Fl::event_button() == 3)
               o->value(2);
          virkeys->keyoct2=(int) o->value();
          virkeys->take_focus();
}
void VirKeyboard::cb_maps(Fl_Counter* o, void* v) {
  ((VirKeyboard*)(o->parent()->user_data()))->cb_maps_i(o,v);
}

void VirKeyboard::cb_velocity_i(mwheel_slider_rev* o, void*) {
  //
          if (Fl::event_button() == 3)
              o->value(100);
          virkeys->midivel=int(o->value());
          o->selection_color(setSlider(o->value(), 100));
          virkeys->take_focus();
}
void VirKeyboard::cb_velocity(mwheel_slider_rev* o, void* v) {
  ((VirKeyboard*)(o->parent()->user_data()))->cb_velocity_i(o,v);
}

void VirKeyboard::cb_octave_i(Fl_Counter* o, void*) {
  //
          relaseallkeys();
          if (Fl::event_button() == 3)
               o->value(2);
          virkeys->midioct=(int) o->value();
          virkeys->take_focus();
}
void VirKeyboard::cb_octave(Fl_Counter* o, void* v) {
  ((VirKeyboard*)(o->parent()->user_data()))->cb_octave_i(o,v);
}

void VirKeyboard::cb_virtClose_i(Fl_Button*, void*) {
  //
          relaseallkeys();
          virkeyboardwindow->hide();
          saveWin(synth, virkeyboardwindow->w(), virkeyboardwindow->h(), virkeyboardwindow->x(), virkeyboardwindow->y(), false, "Midi-virtualkeyboard");
          virtSeen = false;
      	lastvirtW = 0;
}
void VirKeyboard::cb_virtClose(Fl_Button* o, void* v) {
  ((VirKeyboard*)(o->parent()->user_data()))->cb_virtClose_i(o,v);
}

void VirKeyboard::cb_controlslider_i(mwheel_slider* o, void*) {
  //
          oldcontrol = 127 - o->value();
          int ctl = findcontroller(controller->value());
          if (Fl::event_button() == 3)
          {
              oldcontrol = int(collect_readData(synth, 0, ctl, TOPLEVEL::section::midiIn, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, TOPLEVEL::type::Default));
              o->value(127 - oldcontrol);
              o->damage();
          }
          virkeys->take_focus();
          send_data(TOPLEVEL::action::fromMIDI, 2, oldcontrol, TOPLEVEL::type::Integer, virkeys->midich, midictl);
}
void VirKeyboard::cb_controlslider(mwheel_slider* o, void* v) {
  ((VirKeyboard*)(o->parent()->user_data()))->cb_controlslider_i(o,v);
}

void VirKeyboard::cb_controller_i(Fl_Choice* o, void*) {
  //
          setpoint2midictl(o->value());
          if (midictl != MIDI::CC::null)
          {
              int ctl = findcontroller(o->value());
              if (ctl != UNUSED)
              {
                  int value = collect_readData(synth, 0, ctl, virkeys->midich);
                  controlslider->value(127 - value);
              }

          }
          virkeys->take_focus();
}
void VirKeyboard::cb_controller(Fl_Choice* o, void* v) {
  ((VirKeyboard*)(o->parent()->user_data()))->cb_controller_i(o,v);
}

void VirKeyboard::cb_random_i(WidgetPDial* o, void*) {
  //
          if (Fl::event_button() == 3)
               o->value(0);
          o->selection_color(setKnob(o->value(),0));
          virkeys->rndvelocity=(int) o->value();
}
void VirKeyboard::cb_random(WidgetPDial* o, void* v) {
  ((VirKeyboard*)(o->parent()->user_data()))->cb_random_i(o,v);
}

void VirKeyboard::cb_midichannel_i(WidgetSpinner* o, void*) {
  //
          relaseallkeys();
          if (Fl::event_button() == 3)
               o->value(1);
          virkeys->midich = lrint(o->value()) - 1;
          controller->do_callback();
          virkeys->take_focus();
}
void VirKeyboard::cb_midichannel(WidgetSpinner* o, void* v) {
  ((VirKeyboard*)(o->parent()->user_data()))->cb_midichannel_i(o,v);
}

void VirKeyboard::cb_pitchwheel_i(mwheel_slider* o, void*) {
  //
          int old = o->value();
          if (Fl::event_button() == 3)
          {
              old = 0;
              o->value(old);
              o->damage();
          }
          o->selection_color(setSlider(o->value(),0));
          virkeys->take_focus();
          send_data(0, MIDI::control::controller, -old, TOPLEVEL::type::Integer, virkeys->midich, MIDI::CC::pitchWheelAdjusted);
}
void VirKeyboard::cb_pitchwheel(mwheel_slider* o, void* v) {
  ((VirKeyboard*)(o->parent()->user_data()))->cb_pitchwheel_i(o,v);
}

ScaleTrackedWindow* VirKeyboard::make_window() {
  { ScaleTrackedWindow* o = virkeyboardwindow = new ScaleTrackedWindow(650, 130, "Yoshimi Virtual Keyboard");
    virkeyboardwindow->tooltip("+ Shift to hold or release keys");
    virkeyboardwindow->box(FL_FLAT_BOX);
    virkeyboardwindow->color(FL_BACKGROUND_COLOR);
    virkeyboardwindow->selection_color(FL_BACKGROUND_COLOR);
    virkeyboardwindow->labeltype(FL_NO_LABEL);
    virkeyboardwindow->labelfont(0);
    virkeyboardwindow->labelsize(14);
    virkeyboardwindow->labelcolor(FL_FOREGROUND_COLOR);
    virkeyboardwindow->callback((Fl_Callback*)cb_virkeyboardwindow, (void*)(this));
    virkeyboardwindow->align(Fl_Align(FL_ALIGN_TOP));
    virkeyboardwindow->when(FL_WHEN_RELEASE);
    { VirKeys* o = virkeys = new VirKeys(32, 10, 587, 80, "Keyboard");
      virkeys->box(FL_FLAT_BOX);
      virkeys->color(FL_BACKGROUND_COLOR);
      virkeys->selection_color(FL_BACKGROUND_COLOR);
      virkeys->labeltype(FL_NORMAL_LABEL);
      virkeys->labelfont(0);
      virkeys->labelsize(14);
      virkeys->labelcolor(FL_FOREGROUND_COLOR);
      virkeys->align(Fl_Align(FL_ALIGN_CENTER));
      virkeys->when(FL_WHEN_RELEASE);
      o->init(synth, scaledWhite, scaledBlack);
    } // VirKeys* virkeys
    { Fl_Counter* o = key = new Fl_Counter(365, 95, 45, 15, "Key   ");
      key->tooltip(". 2 3    5 6 7 ...\nq w e r  t y u ...");
      key->type(1);
      key->labelsize(10);
      key->minimum(0);
      key->maximum(5);
      key->step(1);
      key->textfont(1);
      key->textsize(10);
      key->callback((Fl_Callback*)cb_key);
      key->align(Fl_Align(FL_ALIGN_LEFT));
      key->when(FL_WHEN_RELEASE_ALWAYS);
      o->value(virkeys->keyoct1);
    } // Fl_Counter* key
    { oct1 = new Fl_Text_Display(407, 108, 30, 0, "Oct");
      oct1->labelsize(10);
      oct1->textsize(10);
    } // Fl_Text_Display* oct1
    { Fl_Counter* o = maps = new Fl_Counter(365, 110, 45, 15, "Maps  ");
      maps->tooltip(". s d   g h j ...\nz x c v b n m ...");
      maps->type(1);
      maps->labelsize(10);
      maps->minimum(0);
      maps->maximum(5);
      maps->step(1);
      maps->textfont(1);
      maps->textsize(10);
      maps->callback((Fl_Callback*)cb_maps);
      maps->align(Fl_Align(FL_ALIGN_LEFT));
      maps->when(FL_WHEN_RELEASE_ALWAYS);
      o->value(virkeys->keyoct2);
    } // Fl_Counter* maps
    { oct2 = new Fl_Text_Display(407, 122, 30, 0, "Oct");
      oct2->labelsize(10);
      oct2->textsize(10);
    } // Fl_Text_Display* oct2
    { mwheel_slider_rev* o = velocity = new mwheel_slider_rev(96, 106, 110, 16, "Velocity");
      velocity->tooltip("Velocity");
      velocity->type(5);
      velocity->box(FL_FLAT_BOX);
      velocity->color(FL_BACKGROUND_COLOR);
      velocity->selection_color(FL_BACKGROUND_COLOR);
      velocity->labeltype(FL_NORMAL_LABEL);
      velocity->labelfont(0);
      velocity->labelsize(10);
      velocity->labelcolor(FL_FOREGROUND_COLOR);
      velocity->minimum(1);
      velocity->maximum(127);
      velocity->step(1);
      velocity->callback((Fl_Callback*)cb_velocity);
      velocity->align(Fl_Align(FL_ALIGN_TOP));
      velocity->when(FL_WHEN_CHANGED);
      o->value(virkeys->midivel);
      o->selection_color(setSlider(o->value(), 100));
      o->setValueType(VC_plainValue);o->useCustomTip(true);
    } // mwheel_slider_rev* velocity
    { Fl_Counter* o = octave = new Fl_Counter(257, 106, 56, 18, "Octave");
      octave->tooltip("Midi Octave");
      octave->type(1);
      octave->labelsize(10);
      octave->minimum(0);
      octave->maximum(5);
      octave->step(1);
      octave->textfont(1);
      octave->textsize(10);
      octave->callback((Fl_Callback*)cb_octave);
      octave->align(Fl_Align(FL_ALIGN_TOP));
      octave->when(FL_WHEN_RELEASE_ALWAYS);
      o->value(virkeys->midioct);
    } // Fl_Counter* octave
    { virtClose = new Fl_Button(452, 101, 55, 20, "&Close");
      virtClose->box(FL_THIN_UP_BOX);
      virtClose->color((Fl_Color)196);
      virtClose->labelsize(12);
      virtClose->callback((Fl_Callback*)cb_virtClose);
    } // Fl_Button* virtClose
    { mwheel_slider* o = controlslider = new mwheel_slider(628, 10, 18, 112);
      controlslider->tooltip("Controller value");
      controlslider->type(2);
      controlslider->box(FL_ENGRAVED_BOX);
      controlslider->color((Fl_Color)230);
      controlslider->selection_color((Fl_Color)65);
      controlslider->labeltype(FL_NORMAL_LABEL);
      controlslider->labelfont(0);
      controlslider->labelsize(8);
      controlslider->labelcolor(FL_FOREGROUND_COLOR);
      controlslider->maximum(127);
      controlslider->step(1);
      controlslider->value(64);
      controlslider->callback((Fl_Callback*)cb_controlslider);
      controlslider->align(Fl_Align(FL_ALIGN_TOP_LEFT));
      controlslider->when(FL_WHEN_CHANGED);
      o->value(127 - oldcontrol);
      o->setValueType(VC_plainReverse); o->useCustomTip(true);
    } // mwheel_slider* controlslider
    { Fl_Choice* o = controller = new Fl_Choice(524, 105, 100, 15, "Controller");
      controller->down_box(FL_BORDER_BOX);
      controller->labelsize(10);
      controller->textfont(1);
      controller->textsize(10);
      controller->callback((Fl_Callback*)cb_controller);
      controller->align(Fl_Align(FL_ALIGN_TOP));
      controller->when(FL_WHEN_RELEASE_ALWAYS);
      o->add("01: Mod. Wheel");o->add("07: Volume");o->add("10: Panning");o->add("11: Expression");o->add("64: Sustain");o->add("65: Portamento");o->add("71: Filter Q");o->add("74: Filter Freq");o->add("75: Bandwidth");o->add("76: FM Gain");o->add("77: Res. c. freq");o->add("78: Res. bw.");
      midictl = MIDI::CC::filterCutoff;o->value(7);
    } // Fl_Choice* controller
    { WidgetPDial* o = random = new WidgetPDial(221, 106, 20, 21, "Vrnd");
      random->tooltip("Velocity Randomness");
      random->box(FL_ROUND_UP_BOX);
      random->color(FL_BACKGROUND_COLOR);
      random->selection_color(FL_INACTIVE_COLOR);
      random->labeltype(FL_NORMAL_LABEL);
      random->labelfont(0);
      random->labelsize(10);
      random->labelcolor(FL_FOREGROUND_COLOR);
      random->maximum(127);
      random->step(1);
      random->callback((Fl_Callback*)cb_random);
      random->align(Fl_Align(129));
      random->when(FL_WHEN_CHANGED);
      o->value(virkeys->rndvelocity);
      o->setValueType(VC_percent127);
      o->selection_color(setKnob(o->value(),0));
    } // WidgetPDial* random
    { WidgetSpinner* o = midichannel = new WidgetSpinner(45, 106, 36, 17, "MIDI Channel");
      midichannel->box(FL_NO_BOX);
      midichannel->color(FL_BACKGROUND_COLOR);
      midichannel->selection_color(FL_BACKGROUND_COLOR);
      midichannel->labeltype(FL_NORMAL_LABEL);
      midichannel->labelfont(0);
      midichannel->labelsize(10);
      midichannel->labelcolor(FL_FOREGROUND_COLOR);
      midichannel->maximum(16);
      midichannel->textsize(10);
      midichannel->callback((Fl_Callback*)cb_midichannel);
      midichannel->align(Fl_Align(FL_ALIGN_TOP));
      midichannel->when(FL_WHEN_RELEASE);
      o->value(virkeys->midich + 1);
    } // WidgetSpinner* midichannel
    { mwheel_slider* o = pitchwheel = new mwheel_slider(6, 10, 18, 112);
      pitchwheel->tooltip("Pitch Wheel");
      pitchwheel->box(FL_DOWN_BOX);
      pitchwheel->color((Fl_Color)65);
      pitchwheel->selection_color((Fl_Color)64);
      pitchwheel->labeltype(FL_NORMAL_LABEL);
      pitchwheel->labelfont(0);
      pitchwheel->labelsize(8);
      pitchwheel->labelcolor((Fl_Color)64);
      pitchwheel->minimum(-8192);
      pitchwheel->maximum(8191);
      pitchwheel->step(1);
      pitchwheel->callback((Fl_Callback*)cb_pitchwheel);
      pitchwheel->align(Fl_Align(FL_ALIGN_TOP));
      pitchwheel->when(FL_WHEN_CHANGED);
      o->value(virkeys->pitchWh);
      o->setValueType(VC_pitchWheel); o->useCustomTip(true);
      o->selection_color(setSlider(o->value(),0));
    } // mwheel_slider* pitchwheel
    virkeyboardwindow->resizable(virkeyboardwindow);
    virtDW = o->w(); virtDH = o->h();
    o->size_range(virtDW, virtDH, 0, 0, 0, 0, 1);
    virkeyboardwindow->end();
  } // ScaleTrackedWindow* virkeyboardwindow
  return virkeyboardwindow;
}

void VirKeyboard::setpoint2midictl(int setpoint) {
  //
          switch(setpoint)
          {
              case 0:
                  midictl = MIDI::CC::modulation;
                  break;
              case 1:
                  midictl = MIDI::CC::volume;
                  break;
              case 2:
                  midictl = MIDI::CC::panning;
                  break;
              case 3:
                  midictl = MIDI::CC::expression;
                  break;
              case 4:
                  midictl = MIDI::CC::sustain;
                  break;
              case 5:
                  midictl = MIDI::CC::portamento;
                  break;
              case 6:
                  midictl = MIDI::CC::filterQ;
                  break;
              case 7:
                  midictl = MIDI::CC::filterCutoff;
                  break;
              case 8:
                  midictl = MIDI::CC::bandwidth;
                  break;
              case 9:
                  midictl = MIDI::CC::fmamp;
                  break;
              case 10:
                  midictl = MIDI::CC::resonanceCenter;
                  break;
              case 11:
                  midictl = MIDI::CC::resonanceBandwidth;
                  break;
              default:
                  midictl = MIDI::CC::null;
                  break;
          }
}

int VirKeyboard::findcontroller(int setpoint) {
  //
              int ctl = UNUSED;
              switch(setpoint)
              {
                  case 0:
                      ctl = PART::control::midiModWheel;
                      break;
                  case 1:
                      ctl = PART::control::volume;
                      break;
                  case 2:
                      ctl = PART::control::panning;
                      break;
                  case 3:
                      ctl = PART::control::midiExpression;
                      break;
                  case 4:
                      ctl = PART::control::midiSustain;
                      break;
                  case 5:
                      ctl = PART::control::midiPortamento;
                      break;
                  case 6:
                      ctl = PART::control::midiFilterQ;
                      break;
                  case 7:
                      ctl = PART::control::midiFilterCutoff;
                      break;
                  case 8:
                      ctl = PART::control::midiBandwidth;
                      break;
                  case 9:
                      ctl = PART::control::midiFMamp;
                      break;
                  case 10:
                      ctl = PART::control::midiResonanceCenter;
                      break;
                  case 11:
                      ctl = PART::control::midiResonanceBandwidth;
                      break;
                  default:
                      break;
              }
              return ctl;
}

VirKeyboard::VirKeyboard(SynthEngine *_synth) {
  //
      synth = _synth;
      midictl = 75;
      oldcontrol = 64;
      make_window();
      virkeyboardwindow->copy_label(textMsgBuffer.fetch(collect_readData(synth, textMsgBuffer.push("Virtual Keyboard"), UNUSED, TOPLEVEL::windowTitle)).c_str());
      virtSeen = false;
      lastvirtW = 0;
}

VirKeyboard::~VirKeyboard() {
  //
      if (virtSeen)
          saveWin(synth, virkeyboardwindow->w(), virkeyboardwindow->h(), virkeyboardwindow->x(), virkeyboardwindow->y(), true, "Midi-virtualkeyboard");
      virkeyboardwindow->hide();
      delete virkeyboardwindow;
}

void VirKeyboard::send_data(int action, int control, float value, int type, int kititem , int engine ) {
  //
          type |= TOPLEVEL::type::Write;
          collect_writeData(synth, value, action, type, control, TOPLEVEL::section::midiIn, kititem, engine);
}

void VirKeyboard::ShowKbd() {
  //
      int fetchX, fetchY, fetchW, fetchH, fetchO;
      loadWin(synth, fetchW, fetchH, fetchX, fetchY, fetchO, "Midi-virtualkeyboard");
      if (fetchW < virtDW || fetchH < virtDH)
      {
          fetchW = virtDW;
          fetchH = virtDH;
      }
      checkSane(fetchX, fetchY, fetchW, fetchH, virtDW, virtDH);

      virkeyboardwindow->resize(fetchX, fetchY, fetchW, fetchH);
      virkeyboardwindow->show();
      virtSeen = true;
      lastvirtW = 0;
}

void VirKeyboard::Hide() {
  //
      virkeyboardwindow->hide();
}

void VirKeyboard::relaseallkeys() {
  virkeys->relaseallkeys(0);
}

void VirKeyboard::virtRtext() {
  //
      if (lastvirtW == virkeyboardwindow->w())
          return;
      lastvirtW = virkeyboardwindow->w();

      float dScale = virkeyboardwindow->w() / float(virtDW);

      scaledWhite = SIZE_WHITE * dScale;
      scaledBlack = SIZE_BLACK * dScale;
      int size = int(10 * dScale);
      int size12 = int(12 * dScale);

      key->labelsize(size);
          key->textsize(size);
      key->damage();
      oct1->labelsize(size);
      maps->labelsize(size);
          maps->textsize(size);
      oct2->labelsize(size);
      velocity->labelsize(size);
          velocity->textsize(size);
      octave->labelsize(size);
          octave->textsize(size);
      controller->labelsize(size);
          controller->textsize(size);
      random->labelsize(size);
      midichannel->labelsize(size);
          midichannel->textsize(size);
      virtClose->labelsize(size12);

      virkeyboardwindow->redraw();
}
