
// Copyright (C) 2016-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 3 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 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.


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

#include "VectorUI.h"
#include "MasterUI.h"
#include "Misc/FileMgrFuncs.h"
    using file::findLeafName;
    using file::setExtension;
    using file::isRegularFile;
#include "Misc/NumericFuncs.h"
    using func::bitClear;
    using func::bitTest;
    using func::bitSet;
#include "Misc/TextMsgBuffer.h"

    namespace { // Implementation details...
        TextMsgBuffer& textMsgBuffer = TextMsgBuffer::instance();
    }
#include <vector>
    #include <string>
    using std::vector;
    using std::to_string;

void VectorUI::cb_vectorwindow_i(ScaleTrackedWindow*, void*) {
  //
        Closevector->do_callback();
}
void VectorUI::cb_vectorwindow(ScaleTrackedWindow* o, void* v) {
  ((VectorUI*)(o->user_data()))->cb_vectorwindow_i(o,v);
}

void VectorUI::cb_setbasechan_i(WidgetSpinner* o, void*) {
  //
          BaseChan = o->value() - 1;
          updateAll(false);
}
void VectorUI::cb_setbasechan(WidgetSpinner* o, void* v) {
  ((VectorUI*)(o->parent()->user_data()))->cb_setbasechan_i(o,v);
}

void VectorUI::cb_options_i(Fl_Menu_Button* o, void*) {
  int res = o->value();
  switch (res)
  {
      case 0:
          loadVector("");
          break;
      case 1:
      {
          bool ok = true;
            int count;
            int size;
            string name;

            if (Xcc == 0)
            {
                alert(synth, "Nothing to save!");
                ok = false;
            }
            else
            {
                count = 0;
                if (Ycc > 0)
                    size = NUM_MIDI_CHANNELS * 4;
                else
                    size = NUM_MIDI_CHANNELS * 2;
                for (int i = 0; i < size; i += NUM_MIDI_CHANNELS)
                {
                    string partName = "";
                    if (textMsgBuffer.fetch(collect_readData(synth, 0, PART::instrumentName, BaseChan + i)) != DEFAULT_NAME)
                        count += NUM_MIDI_CHANNELS;
                }
                if (count != size)
                {
                    if (count == 0)
                        name = "No instruments set!";
                    else
                        name = "Only " + to_string(count/NUM_MIDI_CHANNELS) + " of " +  to_string(size/NUM_MIDI_CHANNELS) + " instruments set!";
                    alert(synth, name);
                    ok = false;
                }
            }

            if (ok)
                saveVector();
          break;
      }
      case 2:
          paramsui->Recent->position(vectorwindow->x() + vectorwindow->w() - paramsui->Recent->w(),vectorwindow->y()+20);
          paramsui->Show(TOPLEVEL::XML::Vector);
          break;
      case 3:
          send_data(TOPLEVEL::action::forceUpdate, VECTOR::control::erase, 0, TOPLEVEL::type::Integer, TOPLEVEL::section::vector, UNUSED, UNUSED, UNUSED, BaseChan);
          break;
      case 4:
          send_data(TOPLEVEL::action::forceUpdate, VECTOR::control::erase, 0, TOPLEVEL::type::Integer);
          break;
  }
}
void VectorUI::cb_options(Fl_Menu_Button* o, void* v) {
  ((VectorUI*)(o->parent()->user_data()))->cb_options_i(o,v);
}

void VectorUI::cb_XL_i(Fl_Button* o, void*) {
  //
            (void) o; // suppress warning
            synth->getGuiMaster()->partSwitch(BaseChan);
            bankui->Show();
}
void VectorUI::cb_XL(Fl_Button* o, void* v) {
  ((VectorUI*)(o->parent()->parent()->user_data()))->cb_XL_i(o,v);
}

void VectorUI::cb_XR_i(Fl_Button* o, void*) {
  //
            (void) o; // suppress warning
            synth->getGuiMaster()->partSwitch(BaseChan + NUM_MIDI_CHANNELS);
            bankui->Show();
}
void VectorUI::cb_XR(Fl_Button* o, void* v) {
  ((VectorUI*)(o->parent()->parent()->user_data()))->cb_XR_i(o,v);
}

void VectorUI::cb_Xfeat1_i(Fl_Choice* o, void*) {
  //
            if (o->value() == 0)
                bitClear(Xf, 0);
            else
                bitSet(Xf, 0);
            send_data(0, VECTOR::control::Xfeature0, o->value(), TOPLEVEL::type::Integer);
}
void VectorUI::cb_Xfeat1(Fl_Choice* o, void* v) {
  ((VectorUI*)(o->parent()->parent()->user_data()))->cb_Xfeat1_i(o,v);
}

void VectorUI::cb_Xfeat2_i(Fl_Choice* o, void*) {
  //
            bitClear(Xf, 1);
            bitClear(Xf, 4);
            if (o->value() >= 1)
            {
                bitSet(Xf, 1);
                if (o->value() == 2)
                    bitSet(Xf, 4);
            }
            send_data(0, VECTOR::control::Xfeature1, o->value(), TOPLEVEL::type::Integer);
}
void VectorUI::cb_Xfeat2(Fl_Choice* o, void* v) {
  ((VectorUI*)(o->parent()->parent()->user_data()))->cb_Xfeat2_i(o,v);
}

void VectorUI::cb_Xfeat3_i(Fl_Choice* o, void*) {
  //
            bitClear(Xf, 2);
            bitClear(Xf, 5);
            if (o->value() >= 1)
            {
                bitSet(Xf, 2);
                if (o->value() == 2)
                    bitSet(Xf, 5);
            }
            send_data(0, VECTOR::control::Xfeature2, o->value(), TOPLEVEL::type::Integer);
}
void VectorUI::cb_Xfeat3(Fl_Choice* o, void* v) {
  ((VectorUI*)(o->parent()->parent()->user_data()))->cb_Xfeat3_i(o,v);
}

void VectorUI::cb_Xfeat4_i(Fl_Choice* o, void*) {
  //
            bitClear(Xf, 3);
            bitClear(Xf, 6);
            if (o->value() >= 1)
            {
                bitSet(Xf, 3);
                if (o->value() == 2)
                    bitSet(Xf, 6);
            }
            send_data(0, VECTOR::control::Xfeature3, o->value(), TOPLEVEL::type::Integer);
}
void VectorUI::cb_Xfeat4(Fl_Choice* o, void* v) {
  ((VectorUI*)(o->parent()->parent()->user_data()))->cb_Xfeat4_i(o,v);
}

void VectorUI::cb_Xcontrol_i(WidgetSpinner* o, void*) {
  //
          int tmp = o->value();

          if (tmp == 0)
          {
              Xcc = 0;
              Xgroup->deactivate();
              Ycc = 0;
              Ycontrol->value(0);
              Ycontrol->deactivate();
              Ygroup->deactivate();
              send_data(TOPLEVEL::action::forceUpdate, VECTOR::control::erase, 0, TOPLEVEL::type::Integer, TOPLEVEL::section::vector, UNUSED, UNUSED, UNUSED, BaseChan);
              return;
          }

          if (tmp > 119)
          {
              o->value(0);
              Xcc = 0;
              Xgroup->deactivate();
              Ycc = 0;
              Ycontrol->value(0);
              Ycontrol->deactivate();
              Ygroup->deactivate();
              errorlabel("CC must be less than 120");
              return;

          }

          string name = textMsgBuffer.fetch(collect_readData(synth, tmp, MAIN::knownCCtest, TOPLEVEL::main));
          if (name != "")
          {
              errorlabel("CC " + to_string(tmp) +" in use for " + name);
              Xcc = 0;
              o->value(0);
              Xgroup->deactivate();
              Ycc = 0;
              Ycontrol->value(0);
              Ycontrol->deactivate();
              Ygroup->deactivate();
              return;
          }

          Ycontrol->activate();
          Xcc =  tmp;
          Xgroup->activate();
          send_data(TOPLEVEL::action::forceUpdate, VECTOR::control::Xcontroller, tmp, TOPLEVEL::type::Integer);
}
void VectorUI::cb_Xcontrol(WidgetSpinner* o, void* v) {
  ((VectorUI*)(o->parent()->user_data()))->cb_Xcontrol_i(o,v);
}

void VectorUI::cb_Closevector_i(Fl_Button*, void*) {
  //
              saveWin(synth, vectorwindow->w(), vectorwindow->h(), vectorwindow->x(), vectorwindow->y(), false, "Vector");
          vectorwindow->hide();
          setVisible(synth, false, "Vector");
          vectorSeen = false;
}
void VectorUI::cb_Closevector(Fl_Button* o, void* v) {
  ((VectorUI*)(o->parent()->user_data()))->cb_Closevector_i(o,v);
}

void VectorUI::cb_YU_i(Fl_Button* o, void*) {
  //
            (void) o; // suppress warning
            synth->getGuiMaster()->partSwitch(BaseChan + (NUM_MIDI_CHANNELS * 2));
            bankui->Show();
}
void VectorUI::cb_YU(Fl_Button* o, void* v) {
  ((VectorUI*)(o->parent()->parent()->user_data()))->cb_YU_i(o,v);
}

void VectorUI::cb_YD_i(Fl_Button* o, void*) {
  //
            (void) o; // suppress warning
            synth->getGuiMaster()->partSwitch(BaseChan + (NUM_MIDI_CHANNELS * 3));
            bankui->Show();
}
void VectorUI::cb_YD(Fl_Button* o, void* v) {
  ((VectorUI*)(o->parent()->parent()->user_data()))->cb_YD_i(o,v);
}

void VectorUI::cb_Yfeat1_i(Fl_Choice* o, void*) {
  //
            if (o->value() == 0)
                bitClear(Yf, 0);
            else
                bitSet(Yf, 0);
            send_data(0, VECTOR::control::Yfeature0, o->value(), TOPLEVEL::type::Integer);
}
void VectorUI::cb_Yfeat1(Fl_Choice* o, void* v) {
  ((VectorUI*)(o->parent()->parent()->user_data()))->cb_Yfeat1_i(o,v);
}

void VectorUI::cb_Yfeat2_i(Fl_Choice* o, void*) {
  //
            bitClear(Yf, 1);
            bitClear(Yf, 4);
            if (o->value() >= 1)
            {
                bitSet(Yf, 1);
                if (o->value() == 2)
                    bitSet(Yf, 4);
            }
            send_data(0, VECTOR::control::Yfeature1, o->value(), TOPLEVEL::type::Integer);
}
void VectorUI::cb_Yfeat2(Fl_Choice* o, void* v) {
  ((VectorUI*)(o->parent()->parent()->user_data()))->cb_Yfeat2_i(o,v);
}

void VectorUI::cb_Yfeat3_i(Fl_Choice* o, void*) {
  //
            bitClear(Yf, 2);
            bitClear(Yf, 5);
            if (o->value() >= 1)
            {
                bitSet(Yf, 2);
                if (o->value() == 2)
                    bitSet(Yf, 5);
            }
            send_data(0, VECTOR::control::Yfeature2, o->value(), TOPLEVEL::type::Integer);
}
void VectorUI::cb_Yfeat3(Fl_Choice* o, void* v) {
  ((VectorUI*)(o->parent()->parent()->user_data()))->cb_Yfeat3_i(o,v);
}

void VectorUI::cb_Yfeat4_i(Fl_Choice* o, void*) {
  //
            bitClear(Yf, 3);
            bitClear(Yf, 6);
            if (o->value() >= 1)
            {
                bitSet(Yf, 3);
                if (o->value() == 2)
                    bitSet(Yf, 6);
            }
            send_data(0, VECTOR::control::Yfeature3, o->value(), TOPLEVEL::type::Integer);
}
void VectorUI::cb_Yfeat4(Fl_Choice* o, void* v) {
  ((VectorUI*)(o->parent()->parent()->user_data()))->cb_Yfeat4_i(o,v);
}

void VectorUI::cb_Ycontrol_i(WidgetSpinner* o, void*) {
  //
          int tmp = o->value();

          if (tmp < 1)
          {
              Ycc = 0;
              Ygroup->deactivate();
              send_data(0, VECTOR::control::Ycontroller, 0xff, TOPLEVEL::type::Integer);
              return;
          }
          if (tmp > 119)
          {
                  Ygroup->deactivate();
                  errorlabel("CC must be less than 120");
                  Ycc = 0;
                  o->value(0);
                  return;

          }


          string name = textMsgBuffer.fetch(collect_readData(synth, tmp, MAIN::knownCCtest, TOPLEVEL::main));
          if (name != "")
          {
              errorlabel("CC " + to_string(tmp) +" in use for " + name);
              Ycc = 0;
              Ygroup->deactivate();
              o->value(0);
              return;
          }


          Ycc =  tmp;
          send_data(TOPLEVEL::action::forceUpdate, VECTOR::control::Ycontroller, tmp, TOPLEVEL::type::Integer);
}
void VectorUI::cb_Ycontrol(WidgetSpinner* o, void* v) {
  ((VectorUI*)(o->parent()->user_data()))->cb_Ycontrol_i(o,v);
}

void VectorUI::cb_Loaded_i(Fl_Button* o, void*) {
  //
          (void) o; // suppress warning
          string tmp = input_text(synth, "Vector name:", loadlabel[BaseChan]);
          if (tmp != loadlabel[BaseChan])
              send_data(TOPLEVEL::action::lowPrio | TOPLEVEL::action::forceUpdate, VECTOR::control::name, 0, TOPLEVEL::type::Integer, TOPLEVEL::section::vector, UNUSED, UNUSED, UNUSED, BaseChan, textMsgBuffer.push(tmp));
}
void VectorUI::cb_Loaded(Fl_Button* o, void* v) {
  ((VectorUI*)(o->parent()->user_data()))->cb_Loaded_i(o,v);
}

ScaleTrackedWindow* VectorUI::make_window() {
  { ScaleTrackedWindow* o = vectorwindow = new ScaleTrackedWindow(375, 295, "Yoshimi : Vectors");
    vectorwindow->box(FL_FLAT_BOX);
    vectorwindow->color(FL_BACKGROUND_COLOR);
    vectorwindow->selection_color(FL_BACKGROUND_COLOR);
    vectorwindow->labeltype(FL_NO_LABEL);
    vectorwindow->labelfont(13);
    vectorwindow->labelsize(12);
    vectorwindow->labelcolor(FL_FOREGROUND_COLOR);
    vectorwindow->callback((Fl_Callback*)cb_vectorwindow, (void*)(this));
    vectorwindow->align(Fl_Align(FL_ALIGN_CENTER));
    vectorwindow->when(FL_WHEN_RELEASE);
    { WidgetSpinner* o = setbasechan = new WidgetSpinner(121, 12, 38, 20, "Base Channel");
      setbasechan->tooltip("The channel number for this vector");
      setbasechan->box(FL_NO_BOX);
      setbasechan->color(FL_BACKGROUND_COLOR);
      setbasechan->selection_color(FL_BACKGROUND_COLOR);
      setbasechan->labeltype(FL_NORMAL_LABEL);
      setbasechan->labelfont(1);
      setbasechan->labelsize(12);
      setbasechan->labelcolor((Fl_Color)64);
      setbasechan->maximum(16);
      setbasechan->textsize(12);
      setbasechan->textcolor((Fl_Color)64);
      setbasechan->callback((Fl_Callback*)cb_setbasechan);
      setbasechan->align(Fl_Align(FL_ALIGN_LEFT));
      setbasechan->when(FL_WHEN_RELEASE);
      o->value(BaseChan + 1);
    } // WidgetSpinner* setbasechan
    { Fl_Menu_Button* o = options = new Fl_Menu_Button(275, 12, 74, 20, "&Options");
      options->labelsize(12);
      options->labelcolor((Fl_Color)64);
      options->textsize(12);
      options->textcolor((Fl_Color)64);
      options->callback((Fl_Callback*)cb_options);
      o->add("Load");o->add("Save");o->add("Recent");o->add("Clear Ch");o->add("Clear All");
      vector<string> const& history{synth->getHistory(TOPLEVEL::XML::Vector)};
      setRecent(not history.empty());
    } // Fl_Menu_Button* options
    { Xgroup = new Fl_Group(8, 42, 360, 104, "X");
      Xgroup->box(FL_PLASTIC_THIN_UP_BOX);
      Xgroup->color(FL_CYAN);
      Xgroup->labelfont(1);
      Xgroup->labelsize(16);
      Xgroup->labelcolor((Fl_Color)64);
      Xgroup->align(Fl_Align(FL_ALIGN_CENTER));
      Xgroup->deactivate();
      { AddBackL = new Fl_Box(21, 53, 53, 19);
        AddBackL->box(FL_FLAT_BOX);
        AddBackL->color(FL_LIGHT1);
      } // Fl_Box* AddBackL
      { SubBackL = new Fl_Box(74, 53, 53, 19);
        SubBackL->box(FL_FLAT_BOX);
        SubBackL->color(FL_LIGHT1);
      } // Fl_Box* SubBackL
      { PadBackL = new Fl_Box(127, 53, 53, 19);
        PadBackL->box(FL_FLAT_BOX);
        PadBackL->color(FL_LIGHT1);
      } // Fl_Box* PadBackL
      { XinstL = new Fl_Text_Display(20, 69, 160, 1);
        XinstL->box(FL_NO_BOX);
        XinstL->labelsize(12);
        XinstL->labelcolor((Fl_Color)64);
        XinstL->textsize(12);
        XinstL->textcolor((Fl_Color)64);
        XinstL->align(Fl_Align(97));
      } // Fl_Text_Display* XinstL
      { XL = new Fl_Button(20, 53, 160, 20);
        XL->tooltip("Part corresponding to joystick \'left\' position");
        XL->box(FL_ENGRAVED_FRAME);
        XL->color((Fl_Color)51);
        XL->labelsize(12);
        XL->callback((Fl_Callback*)cb_XL);
        XL->align(Fl_Align(FL_ALIGN_CLIP));
      } // Fl_Button* XL
      { AddBackR = new Fl_Box(21, 115, 53, 19);
        AddBackR->box(FL_FLAT_BOX);
        AddBackR->color(FL_LIGHT1);
      } // Fl_Box* AddBackR
      { SubBackR = new Fl_Box(74, 115, 53, 19);
        SubBackR->box(FL_FLAT_BOX);
        SubBackR->color(FL_LIGHT1);
      } // Fl_Box* SubBackR
      { PadBackR = new Fl_Box(127, 115, 53, 19);
        PadBackR->box(FL_FLAT_BOX);
        PadBackR->color(FL_LIGHT1);
      } // Fl_Box* PadBackR
      { XinstR = new Fl_Text_Display(20, 131, 160, 1);
        XinstR->box(FL_NO_BOX);
        XinstR->labelsize(12);
        XinstR->labelcolor((Fl_Color)64);
        XinstR->textsize(12);
        XinstR->textcolor((Fl_Color)64);
        XinstR->align(Fl_Align(97));
      } // Fl_Text_Display* XinstR
      { XR = new Fl_Button(20, 115, 160, 20);
        XR->tooltip("Part corresponding to joystick \'right\' position");
        XR->box(FL_ENGRAVED_FRAME);
        XR->color((Fl_Color)51);
        XR->labelsize(12);
        XR->labelcolor((Fl_Color)64);
        XR->callback((Fl_Callback*)cb_XR);
        XR->align(Fl_Align(FL_ALIGN_CLIP));
      } // Fl_Button* XR
      { Xfeat = new Fl_Text_Display(233, 101, 97, 14, "Features");
        Xfeat->box(FL_NO_BOX);
        Xfeat->labelfont(1);
        Xfeat->labelcolor((Fl_Color)64);
        Xfeat->textsize(12);
        Xfeat->textcolor((Fl_Color)64);
      } // Fl_Text_Display* Xfeat
      { Fl_Choice* o = Xfeat1 = new Fl_Choice(208, 53, 58, 20, "1");
        Xfeat1->down_box(FL_BORDER_BOX);
        Xfeat1->labelsize(12);
        Xfeat1->labelcolor((Fl_Color)64);
        Xfeat1->textsize(12);
        Xfeat1->textcolor((Fl_Color)64);
        Xfeat1->callback((Fl_Callback*)cb_Xfeat1);
        Xfeat1->align(Fl_Align(FL_ALIGN_RIGHT));
        o->add("off");o->add("vol");
      } // Fl_Choice* Xfeat1
      { Fl_Choice* o = Xfeat2 = new Fl_Choice(302, 53, 58, 20, "2");
        Xfeat2->down_box(FL_BORDER_BOX);
        Xfeat2->labelsize(12);
        Xfeat2->labelcolor((Fl_Color)64);
        Xfeat2->textsize(12);
        Xfeat2->textcolor((Fl_Color)64);
        Xfeat2->callback((Fl_Callback*)cb_Xfeat2);
        o->add("off");o->add("pan");o->add("panR");
      } // Fl_Choice* Xfeat2
      { Fl_Choice* o = Xfeat3 = new Fl_Choice(208, 115, 58, 20, "3");
        Xfeat3->down_box(FL_BORDER_BOX);
        Xfeat3->labelsize(12);
        Xfeat3->labelcolor((Fl_Color)64);
        Xfeat3->textsize(12);
        Xfeat3->textcolor((Fl_Color)64);
        Xfeat3->callback((Fl_Callback*)cb_Xfeat3);
        Xfeat3->align(Fl_Align(FL_ALIGN_RIGHT));
        o->add("off");o->add("filt");o->add("filtR");
      } // Fl_Choice* Xfeat3
      { Fl_Choice* o = Xfeat4 = new Fl_Choice(302, 115, 58, 20, "4");
        Xfeat4->down_box(FL_BORDER_BOX);
        Xfeat4->labelsize(12);
        Xfeat4->labelcolor((Fl_Color)64);
        Xfeat4->textsize(12);
        Xfeat4->textcolor((Fl_Color)64);
        Xfeat4->callback((Fl_Callback*)cb_Xfeat4);
        o->add("off");o->add("mod");o->add("modR");
      } // Fl_Choice* Xfeat4
      Xgroup->end();
    } // Fl_Group* Xgroup
    { WidgetSpinner* o = Xcontrol = new WidgetSpinner(110, 85, 50, 20, "Controller");
      Xcontrol->tooltip("The MIDI CC this axis reponds to");
      Xcontrol->box(FL_NO_BOX);
      Xcontrol->color(FL_BACKGROUND_COLOR);
      Xcontrol->selection_color(FL_BACKGROUND_COLOR);
      Xcontrol->labeltype(FL_NORMAL_LABEL);
      Xcontrol->labelfont(1);
      Xcontrol->labelsize(12);
      Xcontrol->labelcolor((Fl_Color)64);
      Xcontrol->minimum(0);
      Xcontrol->maximum(127);
      Xcontrol->value(0);
      Xcontrol->textsize(12);
      Xcontrol->textcolor((Fl_Color)64);
      Xcontrol->callback((Fl_Callback*)cb_Xcontrol);
      Xcontrol->align(Fl_Align(FL_ALIGN_LEFT));
      Xcontrol->when(FL_WHEN_RELEASE);
      //
        o->value(Xcc);
    } // WidgetSpinner* Xcontrol
    { Closevector = new Fl_Button(308, 264, 58, 22, "&Close");
      Closevector->color((Fl_Color)196);
      Closevector->labelfont(13);
      Closevector->labelsize(12);
      Closevector->labelcolor((Fl_Color)64);
      Closevector->callback((Fl_Callback*)cb_Closevector);
    } // Fl_Button* Closevector
    { Ygroup = new Fl_Group(8, 152, 360, 104, "Y");
      Ygroup->box(FL_PLASTIC_THIN_UP_BOX);
      Ygroup->color(FL_CYAN);
      Ygroup->labelfont(1);
      Ygroup->labelsize(16);
      Ygroup->labelcolor((Fl_Color)64);
      Ygroup->align(Fl_Align(FL_ALIGN_CENTER));
      Ygroup->deactivate();
      { AddBackU = new Fl_Box(21, 163, 53, 19);
        AddBackU->box(FL_FLAT_BOX);
        AddBackU->color(FL_LIGHT1);
      } // Fl_Box* AddBackU
      { SubBackU = new Fl_Box(74, 163, 53, 19);
        SubBackU->box(FL_FLAT_BOX);
        SubBackU->color(FL_LIGHT1);
      } // Fl_Box* SubBackU
      { PadBackU = new Fl_Box(127, 163, 53, 19);
        PadBackU->box(FL_FLAT_BOX);
        PadBackU->color(FL_LIGHT1);
      } // Fl_Box* PadBackU
      { YinstU = new Fl_Text_Display(20, 179, 160, 1);
        YinstU->box(FL_NO_BOX);
        YinstU->labelsize(12);
        YinstU->labelcolor((Fl_Color)64);
        YinstU->textsize(12);
        YinstU->textcolor((Fl_Color)64);
        YinstU->align(Fl_Align(97));
      } // Fl_Text_Display* YinstU
      { YU = new Fl_Button(20, 163, 160, 20);
        YU->tooltip("Part corresponding to joystick \'up\' position");
        YU->box(FL_ENGRAVED_FRAME);
        YU->color((Fl_Color)51);
        YU->labelsize(12);
        YU->labelcolor((Fl_Color)64);
        YU->callback((Fl_Callback*)cb_YU);
        YU->align(Fl_Align(FL_ALIGN_CLIP));
      } // Fl_Button* YU
      { AddBackD = new Fl_Box(21, 225, 53, 19);
        AddBackD->box(FL_FLAT_BOX);
        AddBackD->color(FL_LIGHT1);
      } // Fl_Box* AddBackD
      { SubBackD = new Fl_Box(74, 225, 53, 19);
        SubBackD->box(FL_FLAT_BOX);
        SubBackD->color(FL_LIGHT1);
      } // Fl_Box* SubBackD
      { PadBackD = new Fl_Box(127, 225, 53, 19);
        PadBackD->box(FL_FLAT_BOX);
        PadBackD->color(FL_LIGHT1);
      } // Fl_Box* PadBackD
      { YinstD = new Fl_Text_Display(20, 241, 160, 1);
        YinstD->box(FL_NO_BOX);
        YinstD->labelsize(12);
        YinstD->labelcolor((Fl_Color)64);
        YinstD->textsize(12);
        YinstD->textcolor((Fl_Color)64);
        YinstD->align(Fl_Align(97));
      } // Fl_Text_Display* YinstD
      { YD = new Fl_Button(20, 225, 160, 20);
        YD->tooltip("Part corresponding to joystick \'down\'position");
        YD->box(FL_ENGRAVED_FRAME);
        YD->color((Fl_Color)51);
        YD->labelsize(12);
        YD->labelcolor((Fl_Color)64);
        YD->callback((Fl_Callback*)cb_YD);
        YD->align(Fl_Align(FL_ALIGN_CLIP));
      } // Fl_Button* YD
      { Yfeat = new Fl_Text_Display(233, 211, 97, 14, "Features");
        Yfeat->box(FL_NO_BOX);
        Yfeat->labelfont(1);
        Yfeat->labelcolor((Fl_Color)64);
        Yfeat->textsize(12);
        Yfeat->textcolor((Fl_Color)64);
      } // Fl_Text_Display* Yfeat
      { Fl_Choice* o = Yfeat1 = new Fl_Choice(208, 163, 58, 20, "1");
        Yfeat1->down_box(FL_BORDER_BOX);
        Yfeat1->labelsize(12);
        Yfeat1->labelcolor((Fl_Color)64);
        Yfeat1->textsize(12);
        Yfeat1->textcolor((Fl_Color)64);
        Yfeat1->callback((Fl_Callback*)cb_Yfeat1);
        Yfeat1->align(Fl_Align(FL_ALIGN_RIGHT));
        o->add("off");o->add("vol");
      } // Fl_Choice* Yfeat1
      { Fl_Choice* o = Yfeat2 = new Fl_Choice(302, 163, 58, 20, "2");
        Yfeat2->down_box(FL_BORDER_BOX);
        Yfeat2->labelsize(12);
        Yfeat2->labelcolor((Fl_Color)64);
        Yfeat2->textsize(12);
        Yfeat2->textcolor((Fl_Color)64);
        Yfeat2->callback((Fl_Callback*)cb_Yfeat2);
        o->add("off");o->add("pan");o->add("panR");
      } // Fl_Choice* Yfeat2
      { Fl_Choice* o = Yfeat3 = new Fl_Choice(208, 225, 58, 20, "3");
        Yfeat3->down_box(FL_BORDER_BOX);
        Yfeat3->labelsize(12);
        Yfeat3->labelcolor((Fl_Color)64);
        Yfeat3->textsize(12);
        Yfeat3->textcolor((Fl_Color)64);
        Yfeat3->callback((Fl_Callback*)cb_Yfeat3);
        Yfeat3->align(Fl_Align(FL_ALIGN_RIGHT));
        o->add("off");o->add("filt");o->add("filtR");
      } // Fl_Choice* Yfeat3
      { Fl_Choice* o = Yfeat4 = new Fl_Choice(302, 225, 58, 20, "4");
        Yfeat4->down_box(FL_BORDER_BOX);
        Yfeat4->labelsize(12);
        Yfeat4->labelcolor((Fl_Color)64);
        Yfeat4->textsize(12);
        Yfeat4->textcolor((Fl_Color)64);
        Yfeat4->callback((Fl_Callback*)cb_Yfeat4);
        o->add("off");o->add("mod");o->add("modR");
      } // Fl_Choice* Yfeat4
      Ygroup->end();
    } // Fl_Group* Ygroup
    { WidgetSpinner* o = Ycontrol = new WidgetSpinner(110, 195, 50, 20, "Controller");
      Ycontrol->tooltip("The MIDI CC this axis reponds to");
      Ycontrol->box(FL_NO_BOX);
      Ycontrol->color(FL_BACKGROUND_COLOR);
      Ycontrol->selection_color(FL_BACKGROUND_COLOR);
      Ycontrol->labeltype(FL_NORMAL_LABEL);
      Ycontrol->labelfont(1);
      Ycontrol->labelsize(12);
      Ycontrol->labelcolor((Fl_Color)64);
      Ycontrol->minimum(0);
      Ycontrol->maximum(127);
      Ycontrol->value(0);
      Ycontrol->textsize(12);
      Ycontrol->textcolor((Fl_Color)64);
      Ycontrol->callback((Fl_Callback*)cb_Ycontrol);
      Ycontrol->align(Fl_Align(FL_ALIGN_LEFT));
      Ycontrol->when(FL_WHEN_RELEASE);
      Ycontrol->deactivate();
      o->value(Ycc);
    } // WidgetSpinner* Ycontrol
    { Loaded = new Fl_Button(45, 264, 198, 22, "No Name");
      Loaded->tooltip("Last saved or loaded vector file - click to change the name");
      Loaded->box(FL_DOWN_BOX);
      Loaded->color(FL_BACKGROUND2_COLOR);
      Loaded->labelfont(1);
      Loaded->labelsize(12);
      Loaded->labelcolor((Fl_Color)64);
      Loaded->callback((Fl_Callback*)cb_Loaded);
    } // Fl_Button* Loaded
    vectorwindow->resizable(vectorwindow);
    vecDW = o->w();vecDH = o->h();
    o->size_range(vecDW, vecDH, 0, 0, 0, 0, 1);
    vectorwindow->end();
  } // ScaleTrackedWindow* vectorwindow
  return vectorwindow;
}

void VectorUI::send_data(int action, int control, float value, int type, int part , int kit , int engine , int insert , int parameter , int miscmsg ) {
  //
          if (control != MAIN::control::partNumber && control != MAIN::loadNamedVector && control != MAIN::saveNamedVector && control != VECTOR::control::erase)
          {
              parameter = BaseChan;
          }
          type |= TOPLEVEL::type::Write;
          collect_writeData(synth, value, action, type, control, part, kit, engine, insert, parameter, UNUSED, miscmsg);
}

void VectorUI::returns_update(CommandBlock *getData) {
  //
      float value = getData->data.value;
      unsigned char control = getData->data.control;
      unsigned char parameter = getData->data.parameter;
      unsigned char miscmsg = getData->data.miscmsg;
      int value_int = lrint(value);
      string msg;

      switch (control)
      {
          case VECTOR::control::name:
              msg = textMsgBuffer.fetch(miscmsg);
              loadlabel[parameter] = msg;
              Loaded->copy_label(msg.c_str());
              break;

          case VECTOR::control::Xcontroller:
              if (value_int > 119)
              {
                  Xcc = 0;
                  Ycc = 0;
                  Xgroup->deactivate();
                  Xcontrol->value(0);
                  Ycontrol->value(0);
                  Ygroup->deactivate();
                  Ycontrol->deactivate();
                  errorlabel("CC must be less than 120");
              }
              else
              {
                  Xgroup->activate();
                  Xcontrol->value(value_int);
                  Ycontrol->activate();

                  if (synth->getGuiMaster()->partmax < NUM_MIDI_CHANNELS * 2)
                  {
                      synth->getGuiMaster()->maxparts->value(NUM_MIDI_CHANNELS * 2);
                      synth->getGuiMaster()->maxparts->do_callback();
                      synth->getGuiMaster()->Panelsmallgroups->show();
                  }
              }
              break;

          case VECTOR::control::Xfeature0:
              Xfeat1->value(value_int);
              break;
          case VECTOR::control::Xfeature1:
              Xfeat2->value(value_int);
              break;
          case VECTOR::control::Xfeature2:
              Xfeat3->value(value_int);
              break;
          case VECTOR::control::Xfeature3:
              Xfeat4->value(value_int);
              break;

          case VECTOR::control::Ycontroller:
              if (value_int > 119)
              {
                  Ygroup->deactivate();
                  Ycontrol->value(0);
                  Ycc = 0;
                  Ygroup->deactivate();
                  errorlabel("CC must be less than 120");
              }
              else
              {
                  Ygroup->activate();
                  Ycontrol->value(value_int);

                  if (synth->getGuiMaster()->partmax < NUM_MIDI_CHANNELS * 4)
                  {
                      synth->getGuiMaster()->maxparts->value(NUM_MIDI_CHANNELS * 4);
                      synth->getGuiMaster()->maxparts->do_callback();
                      synth->getGuiMaster()->Panelsmallgroups->hide();
                      synth->getGuiMaster()->Panelgroups->show();
                  }
              }
              break;

          case VECTOR::control::Yfeature0:
              Yfeat1->value(value_int);
              break;
          case VECTOR::control::Yfeature1:
              Yfeat2->value(value_int);
              break;
          case VECTOR::control::Yfeature2:
              Yfeat3->value(value_int);
              break;
          case VECTOR::control::Yfeature3:
              Yfeat4->value(value_int);
              break;

          case VECTOR::control::erase:
              if (parameter >= NUM_MIDI_PARTS)
              {
                  for (int i = NUM_MIDI_CHANNELS - 1; i >= 0; --i)
                      clearVector(i);
                  BaseChan = 0;
                  setbasechan->value(1);
              }
              else
                  clearVector(parameter);
              break;
      };
      vectorwindow->redraw();
}

void VectorUI::setRecent(bool active) {
  //
      Fl_Menu_Item *m = (Fl_Menu_Item*)options->find_item("Recent");
      if (active)
          m->activate();
      else
          m->deactivate();
}

VectorUI::VectorUI(SynthEngine *_synth, BankUI *_bankui, ParametersUI *_paramsui) {
  //
      synth = _synth;
      bankui = _bankui;
      paramsui = _paramsui;
      BaseChan = 0;
      Xcc = 0;
      Xf = 0;
      Ycc = 0;
      Yf = 0;
      make_window();
      vectorwindow->copy_label(textMsgBuffer.fetch(collect_readData(synth, textMsgBuffer.push("Vectors"), UNUSED, TOPLEVEL::windowTitle)).c_str());
      updateAll();
      vectorSeen = false;
      lastvectorW = 0;
}

VectorUI::~VectorUI() {
  //
          if (vectorSeen)
              saveWin(synth, vectorwindow->w(), vectorwindow->h(), vectorwindow->x(), vectorwindow->y(), true, "Vector");
          vectorwindow->hide();
          delete  vectorwindow;
}

void VectorUI::updateAll(bool everything ) {
  //
      if (everything)
      {
          BaseChan = 0;
          setbasechan->value(BaseChan + 1);
          for (int i = 0; i < NUM_MIDI_CHANNELS; ++i)
              loadlabel[i] = "No Name " + to_string(i + 1);

      }
      setInstrumentLabel(BaseChan);
      setInstrumentLabel(BaseChan + NUM_MIDI_CHANNELS);
      setInstrumentLabel(BaseChan + NUM_MIDI_CHANNELS * 2);
      setInstrumentLabel(BaseChan + NUM_MIDI_CHANNELS * 3);

      Loaded->copy_label(loadlabel[BaseChan].c_str());
      setbuttons();
      if (Xcontrol->value() > 0)
          Ycontrol->activate();
      else
          Ycontrol->deactivate();
}

void VectorUI::RefreshChans() {
  //
      for (int i = NUM_MIDI_CHANNELS; i > 0; --i)
      {
          BaseChan = i - 1;
          setInstrumentLabel(BaseChan);
          setInstrumentLabel(BaseChan + NUM_MIDI_CHANNELS);
          setInstrumentLabel(BaseChan + NUM_MIDI_CHANNELS * 2);
          setInstrumentLabel(BaseChan + NUM_MIDI_CHANNELS * 3);
          setbuttons();
      }
      Loaded->copy_label(loadlabel[0].c_str());
      setbasechan->value(1);
}

void VectorUI::setbuttons() {
  //
      Xcc = collect_readData(synth, 0, VECTOR::control::Xcontroller, TOPLEVEL::section::vector, UNUSED, UNUSED, UNUSED, BaseChan);
      if (Xcc == 0 || Xcc > 119)
      {
          Xcc = 0;
          Xf = 0;
          Xgroup->deactivate();
          Ycc = 0;
          Yf = 0;
          Ygroup->deactivate();
      }
      else
      {
          Xf = collect_readData(synth, 0, VECTOR::control::Xfeature0, TOPLEVEL::section::vector, UNUSED, UNUSED, UNUSED, BaseChan);
          Xgroup->activate();

          Ycc = collect_readData(synth, 0, VECTOR::control::Ycontroller, TOPLEVEL::section::vector, UNUSED, UNUSED, UNUSED, BaseChan);
          if (Ycc > 119)
          {
              Ycc = 0;
              Ygroup->deactivate();
          }
          else
          {
              Yf = collect_readData(synth, 0, VECTOR::control::Yfeature0, TOPLEVEL::section::vector, UNUSED, UNUSED, UNUSED, BaseChan);
              Ygroup->activate();
          }
      }

      Xcontrol->value(Xcc);
      if (bitTest(Xf,0))
          Xfeat1->value(1);
      else
          Xfeat1->value(0);

      if (bitTest(Xf,4))
          Xfeat2->value(2);
      else if (bitTest(Xf,1))
          Xfeat2->value(1);
      else
          Xfeat2->value(0);

      if (bitTest(Xf,5))
          Xfeat3->value(2);
      else if (bitTest(Xf,2))
          Xfeat3->value(1);
      else
          Xfeat3->value(0);

      if (bitTest(Xf,6))
          Xfeat4->value(2);
      else if (bitTest(Xf,3))
          Xfeat4->value(1);
      else
          Xfeat4->value(0);

      Ycontrol->value(Ycc);
      if (bitTest(Yf,0))
          Yfeat1->value(1);
      else
          Yfeat1->value(0);

      if (bitTest(Yf,4))
          Yfeat2->value(2);
      else if (bitTest(Yf,1))
          Yfeat2->value(1);
      else
          Yfeat2->value(0);

      if (bitTest(Yf,5))
          Yfeat3->value(2);
      else if (bitTest(Yf,2))
          Yfeat3->value(1);
      else
          Yfeat3->value(0);

      if (bitTest(Yf,6))
          Yfeat4->value(2);
      else if (bitTest(Yf,3))
          Yfeat4->value(1);
      else
          Yfeat4->value(0);
}

void VectorUI::Show(SynthEngine *synth) {
  //
      int fetchW, fetchH, fetchX, fetchY, fetchO;
      loadWin(synth, fetchW, fetchH, fetchX, fetchY, fetchO, "Vector");
      vectorwindow->show();
      if (fetchW < vecDW || fetchH < vecDH)
      {
          fetchW = vecDW;
          fetchH = vecDH;
      }
      checkSane(fetchX, fetchY, fetchW, fetchH, vecDW, vecDH, true);

      vectorwindow->resize(fetchX, fetchY, fetchW, fetchH);
      vectorSeen = true;
      lastvectorW = 0;
}

void VectorUI::vectorRtext() {
  //
      if (lastvectorW == vectorwindow->w())
          return;
      lastvectorW = vectorwindow->w();

      float dW = vectorwindow->w() / vecDW;
      float dH = vectorwindow->h() / vecDH;
      float dScale;
      if (dW < dH)
          dScale = dW;
      else
          dScale = dH;
      if (dScale < 0.2f)
          dScale = 0.2f;

      int size12 = int(dScale * 12);
      int size16 = int(dScale * 16);

      setbasechan->labelsize(size12);
      setbasechan->textsize(size12);
      options->labelsize(size12);
          options->textsize(size12);

      Xgroup->labelsize(size16);
      Xcontrol->labelsize(size12);
          Xcontrol->textsize(size12);
      XinstL->labelsize(size12);
      XinstR->labelsize(size12);
      Xfeat->labelsize(size12);
      Xfeat1->labelsize(size12);
           Xfeat1->textsize(size12);
      Xfeat2->labelsize(size12);
           Xfeat2->textsize(size12);
      Xfeat3->labelsize(size12);
           Xfeat3->textsize(size12);
      Xfeat4->labelsize(size12);
           Xfeat4->textsize(size12);

      Ygroup->labelsize(size16);
      Ycontrol->labelsize(size12);
          Ycontrol->textsize(size12);
      YinstU->labelsize(size12);
      YinstD->labelsize(size12);
      Yfeat->labelsize(size12);
      Yfeat1->labelsize(size12);
          Yfeat1->textsize(size12);
      Yfeat2->labelsize(size12);
          Yfeat2->textsize(size12);
      Yfeat3->labelsize(size12);
          Yfeat3->textsize(size12);
      Yfeat4->labelsize(size12);
          Yfeat4->textsize(size12);

      Loaded->labelsize(size12);
      Closevector->labelsize(size12);

      vectorwindow->redraw();
}

void VectorUI::setInstrumentLabel(int vecPart) {
  //
      if ((vecPart & 0xf) != BaseChan)
          return;
      int engines = findengines(vecPart);
      int addcol = setcolors(engines & 1);
      int subcol = setcolors(engines & 2);
      int padcol = setcolors(engines & 4);

      if (vecPart == BaseChan)
      {
          AddBackL->color(addcol);
          SubBackL->color(subcol);
          PadBackL->color(padcol);
          XinstL->copy_label(findnames(vecPart).c_str());
      }
      else if (vecPart == BaseChan + NUM_MIDI_CHANNELS)
      {
          AddBackR->color(addcol);
          SubBackR->color(subcol);
          PadBackR->color(padcol);
          XinstR->copy_label(findnames(vecPart).c_str());
      }
      else if (vecPart == BaseChan + NUM_MIDI_CHANNELS * 2)
      {
          AddBackU->color(addcol);
          SubBackU->color(subcol);
          PadBackU->color(padcol);
          YinstU->copy_label(findnames(vecPart).c_str());
      }
      else if (vecPart == BaseChan + NUM_MIDI_CHANNELS * 3)
      {
          AddBackD->color(addcol);
          SubBackD->color(subcol);
          PadBackD->color(padcol);
          YinstD->copy_label(findnames(vecPart).c_str());
      }
      vectorwindow->redraw();
      Loaded->copy_label(loadlabel[BaseChan].c_str());
}

void VectorUI::setLoadLabelRemote(int chan, string name) {
  //
      loadlabel[chan] = name;
      BaseChan = chan;
      setbasechan->value(BaseChan + 1);
      updateAll(false);
}

string VectorUI::findnames(int vecPart) {
  //
          return textMsgBuffer.fetch(collect_readData(synth, 0, PART::control::instrumentName, vecPart, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, TOPLEVEL::action::lowPrio));
          ;
}

unsigned int VectorUI::findengines(int vecPart) {
  //
          return collect_readData(synth, 0, PART::control::instrumentEngines, vecPart);
          ;
}

int VectorUI::setcolors(int engine) {
  //
      int col;
      switch(engine)
      {
          case 1:
              col = add_back;
              break;
          case 2:
              col = sub_back;
              break;
          case 4:
              col = pad_back;
              break;
          default:
              col = bank_back_used;
              break;
      }
      return col;
}

void VectorUI::loadVector(string fname) {
  //
      if (fname.empty())
      {
          fname = setfiler(synth,"", "", false, TOPLEVEL::XML::Vector);
          if (fname.empty())
              return;
      }

      string replyMsg = "";
      int count = 0;
      for (int i = BaseChan; i < (BaseChan + NUM_MIDI_PARTS); i += NUM_MIDI_CHANNELS)
      {
          if (collect_readData(synth, 0, MAIN::control::partsChanged, TOPLEVEL::section::main, i))
          {
              replyMsg = (replyMsg + " " + to_string(i + 1));
              ++ count;
          }
      }
      if (count)
      {
          if (count > 1)
              replyMsg = "Instruments in parts " + replyMsg + " have been edited";
          else
              replyMsg = "Instrument in part " + replyMsg + " has been edited";
          replyMsg += ". Overwrite?";
          if (synth->getGuiMaster()->query("", "Yes", "No", replyMsg) < 2)
              return;
      }

      send_data(TOPLEVEL::action::muteAndLoop | TOPLEVEL::action::forceUpdate, MAIN::loadNamedVector, 0, TOPLEVEL::type::Integer, TOPLEVEL::section::main, UNUSED, UNUSED, BaseChan, UNUSED, textMsgBuffer.push(fname));
}

void VectorUI::saveVector() {
  //
      string filename = setfiler(synth,"", "", true, TOPLEVEL::XML::Vector);
      if (filename.empty())
          return;
      int pos = loadlabel[BaseChan].find("No Name");
      if (pos >=0 && pos < 2)
          Loaded->copy_label(findLeafName(filename).c_str());
      send_data(TOPLEVEL::action::lowPrio, MAIN::saveNamedVector, 0, TOPLEVEL::type::Integer, TOPLEVEL::section::main, UNUSED, UNUSED, BaseChan, UNUSED, textMsgBuffer.push(filename));
}

void VectorUI::clearVector(int BaseC) {
  //
      int min = 0;
      int max = NUM_MIDI_CHANNELS;
      if (BaseC < NUM_MIDI_CHANNELS)
      {
          min = BaseC;
          max = BaseC + 1;
      }
      for (int i = min; i < max; ++i)
      {
          loadlabel[i] = "No Name " + to_string(i + 1);
          Loaded->copy_label(loadlabel[i].c_str());
       }
       if (BaseC >= NUM_MIDI_CHANNELS)
       {
           BaseChan = 0;
           setInstrumentLabel(0);
           setInstrumentLabel(NUM_MIDI_CHANNELS);
           setInstrumentLabel(NUM_MIDI_CHANNELS * 2);
           setInstrumentLabel(NUM_MIDI_CHANNELS * 3);
       }

       Xcc = 0;
       Xf = 0;
       Xgroup->deactivate();
       Xcontrol->value(0);
       Ycc = 0;
       Yf = 0;
       Ygroup->deactivate();
       Ycontrol->deactivate();
       Ycontrol->value(0);
}

void VectorUI::checkParts(int nval) {
  //
  for (int i = 0; i < NUM_MIDI_CHANNELS; ++i)
  {
      if (nval > NUM_MIDI_CHANNELS * 3)
          Ygroup->activate();
      else
          Ygroup->deactivate();

      if (nval > NUM_MIDI_CHANNELS)
          Xgroup->activate();
      else
          Xgroup->deactivate();
  }
}

void VectorUI::errorlabel(string msg) {
  //
              synth->getGuiMaster()->words->copy_label(msg.c_str());
              synth->getGuiMaster()->message->show();
              synth->getGuiMaster()->message->position(Fl::event_x_root() + 16, Fl::event_y_root());
}
