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

#include "MicrotonalUI.h"
// Microtonal.cc
// Original ZynAddSubFX author Nasca Octavian Paul
// Copyright (C) 2002-2005 Nasca Octavian Paul
// Copyright 2009, Alan Calvert
// Copyright 2016-2021, 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 the ZynAddSubFX original.


#include "Misc/FileMgrFuncs.h"
#include "Misc/TextMsgBuffer.h"

    namespace { // Implementation details...
        TextMsgBuffer& textMsgBuffer = TextMsgBuffer::instance();
    }

void MicrotonalUI::cb_microtonaluiwindow_i(Fl_Double_Window*, void*) {
  scaleClose->do_callback();
}
void MicrotonalUI::cb_microtonaluiwindow(Fl_Double_Window* o, void* v) {
  ((MicrotonalUI*)(o->user_data()))->cb_microtonaluiwindow_i(o,v);
}

void MicrotonalUI::cb_invertKeys_i(Fl_Check_Button2* o, void*) {
  //
          send_data(TOPLEVEL::action::forceUpdate, SCALES::control::invertScale, o->value(), TOPLEVEL::type::Integer);
}
void MicrotonalUI::cb_invertKeys(Fl_Check_Button2* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->user_data()))->cb_invertKeys_i(o,v);
}

void MicrotonalUI::cb_centerinvertcounter_i(WidgetSpinner* o, void*) {
  //
          send_data(0, SCALES::control::invertedScaleCenter, o->value(), TOPLEVEL::type::Integer);
}
void MicrotonalUI::cb_centerinvertcounter(WidgetSpinner* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->user_data()))->cb_centerinvertcounter_i(o,v);
}

void MicrotonalUI::cb_anotecounter_i(WidgetSpinner* o, void*) {
  //
          send_data(0, SCALES::control::refNote, o->value(), TOPLEVEL::type::Integer);
}
void MicrotonalUI::cb_anotecounter(WidgetSpinner* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->user_data()))->cb_anotecounter_i(o,v);
}

void MicrotonalUI::cb_afreqinput_i(Fl_Value_Input* o, void*) {
  //
          refFreq = o->value();
          afreqset->show();
          AsetBack->show();
}
void MicrotonalUI::cb_afreqinput(Fl_Value_Input* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->user_data()))->cb_afreqinput_i(o,v);
}

void MicrotonalUI::cb_AsetBack_i(Fl_Button* o, void*) {
  //
          if (refFreq < A_MIN)
          {
              refFreq = A_MIN;
              afreqinput->value(refFreq);
          }
          else if (refFreq > A_MAX)
          {
              refFreq = A_MAX;
              afreqinput->value(refFreq);
          }

          afreqset->hide();
          o->hide();

          send_data(0, SCALES::control::refFrequency, refFreq, 0);
}
void MicrotonalUI::cb_AsetBack(Fl_Button* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->user_data()))->cb_AsetBack_i(o,v);
}

void MicrotonalUI::cb_afreqset_i(Fl_Return_Button* o, void*) {
  //
          if (refFreq < A_MIN)
          {
              refFreq = A_MIN;
              afreqinput->value(refFreq);
          }
          else if (refFreq > A_MAX)
          {
              refFreq = A_MAX;
              afreqinput->value(refFreq);
          }
          AsetBack->hide();
          o->hide();

          send_data(0, SCALES::control::refFrequency, refFreq, 0);
}
void MicrotonalUI::cb_afreqset(Fl_Return_Button* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->user_data()))->cb_afreqset_i(o,v);
}

void MicrotonalUI::cb_nameinput_i(Fl_Input* o, void*) {
  //
          send_data(TOPLEVEL::action::lowPrio | TOPLEVEL::action::forceUpdate, SCALES::control::name, 0, TOPLEVEL::type::Integer, UNUSED, textMsgBuffer.push(string(o->value())));
}
void MicrotonalUI::cb_nameinput(Fl_Input* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->user_data()))->cb_nameinput_i(o,v);
}

void MicrotonalUI::cb_commentinput_i(Fl_Input* o, void*) {
  //
          send_data(TOPLEVEL::action::lowPrio | TOPLEVEL::action::forceUpdate, SCALES::control::comment, 0, TOPLEVEL::type::Integer, UNUSED, textMsgBuffer.push(string(o->value())));
}
void MicrotonalUI::cb_commentinput(Fl_Input* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->user_data()))->cb_commentinput_i(o,v);
}

void MicrotonalUI::cb_scaleShift_i(WidgetSpinner* o, void*) {
  //
          send_data(0, SCALES::control::scaleShift, o->value(), TOPLEVEL::type::Integer);
}
void MicrotonalUI::cb_scaleShift(WidgetSpinner* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->user_data()))->cb_scaleShift_i(o,v);
}

void MicrotonalUI::cb_octavesizeoutput_i(Fl_Value_Output* o, void*) {
  //
                o->value(microtonal->getoctavesize());
}
void MicrotonalUI::cb_octavesizeoutput(Fl_Value_Output* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->parent()->user_data()))->cb_octavesizeoutput_i(o,v);
}

void MicrotonalUI::cb_importscl_i(Fl_Button*, void*) {
  //
            string filename = setfiler(synth,"", "", false, TOPLEVEL::XML::ScalaTune);
            if (filename.empty())
                return;
            send_data(TOPLEVEL::action::lowPrio | TOPLEVEL::action::forceUpdate, SCALES::control::importScl, 0, TOPLEVEL::type::Integer, UNUSED, textMsgBuffer.push(filename));
}
void MicrotonalUI::cb_importscl(Fl_Button* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->parent()->user_data()))->cb_importscl_i(o,v);
}

void MicrotonalUI::cb_firstnotecounter_i(WidgetSpinner* o, void*) {
  //
            int tmp = int (o->value());
            int max = middlenotecounter->value() - 1;
            if (tmp > max)
            {
                if (oldFirst == max)
                tmp = 0;
                else
                    tmp = max;
                o->value(tmp);
            }
            oldFirst = tmp;

            send_data(0, SCALES::control::lowKey, tmp, TOPLEVEL::type::Integer);
}
void MicrotonalUI::cb_firstnotecounter(WidgetSpinner* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->parent()->user_data()))->cb_firstnotecounter_i(o,v);
}

void MicrotonalUI::cb_middlenotecounter_i(WidgetSpinner* o, void*) {
  //
            int tmp = int(o->value());
            int min = firstnotecounter->value() + 1;
            int max = lastnotecounter->value() - 1;
            if (tmp < min)
            {
                if (oldMid == min)
                    tmp = max;
                else
                    tmp = min;
                o->value(tmp);
            }
            else if (tmp > max)
            {
                if (oldMid == max)
                    tmp = min;
                else
                    tmp = max;
                o->value(tmp);
            }
            oldMid = tmp;

            send_data(0, SCALES::control::middleKey, o->value(), TOPLEVEL::type::Integer);
}
void MicrotonalUI::cb_middlenotecounter(WidgetSpinner* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->parent()->user_data()))->cb_middlenotecounter_i(o,v);
}

void MicrotonalUI::cb_lastnotecounter_i(WidgetSpinner* o, void*) {
  //
            int tmp = int(o->value());
            int min = middlenotecounter->value() + 1;
            if (tmp < min)
            {
                if (oldLast == min)
                    tmp = 127;
                else
                    tmp = min;
                o->value(tmp);
            }
            oldLast = tmp;

            send_data(0, SCALES::control::highKey, tmp, TOPLEVEL::type::Integer);
}
void MicrotonalUI::cb_lastnotecounter(WidgetSpinner* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->parent()->user_data()))->cb_lastnotecounter_i(o,v);
}

void MicrotonalUI::cb_mapsizeoutput_i(Fl_Value_Output* o, void*) {
  o->value(microtonal->Pmapsize);
}
void MicrotonalUI::cb_mapsizeoutput(Fl_Value_Output* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->parent()->user_data()))->cb_mapsizeoutput_i(o,v);
}

void MicrotonalUI::cb_importkbm_i(Fl_Button*, void*) {
  //
            string filename = setfiler(synth,"", "", false, TOPLEVEL::XML::ScalaMap);
            if (filename.empty())
                return;

            send_data(TOPLEVEL::action::lowPrio | TOPLEVEL::action::forceUpdate, SCALES::control::importKbm, 0, TOPLEVEL::type::Integer, UNUSED, textMsgBuffer.push(filename));
}
void MicrotonalUI::cb_importkbm(Fl_Button* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->parent()->user_data()))->cb_importkbm_i(o,v);
}

void MicrotonalUI::cb_mappingenabledbutton_i(Fl_Check_Button2* o, void*) {
  //
          o->show();

          send_data(TOPLEVEL::action::forceUpdate, SCALES::control::enableKeyboardMap, o->value(), TOPLEVEL::type::Integer);
}
void MicrotonalUI::cb_mappingenabledbutton(Fl_Check_Button2* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->user_data()))->cb_mappingenabledbutton_i(o,v);
}

void MicrotonalUI::cb_applybutton_i(Fl_Button*, void*) {
  apply();
          send_data(0, SCALES::control::tuning, 1, TOPLEVEL::type::Integer);
          send_data(0, SCALES::control::keyboardMap, 1, TOPLEVEL::type::Integer);
          send_data(0, SCALES::control::retune, 1, TOPLEVEL::type::Integer);
}
void MicrotonalUI::cb_applybutton(Fl_Button* o, void* v) {
  ((MicrotonalUI*)(o->parent()->parent()->user_data()))->cb_applybutton_i(o,v);
}

void MicrotonalUI::cb_enableMicrotonal_i(Fl_Check_Button2* o, void*) {
  //
        send_data(TOPLEVEL::action::forceUpdate, SCALES::control::enableMicrotonal, o->value(), TOPLEVEL::type::Integer);
}
void MicrotonalUI::cb_enableMicrotonal(Fl_Check_Button2* o, void* v) {
  ((MicrotonalUI*)(o->parent()->user_data()))->cb_enableMicrotonal_i(o,v);
}

void MicrotonalUI::cb_scaleClose_i(Fl_Button*, void*) {
  //
    saveWin(synth, microtonaluiwindow->w(), microtonaluiwindow->h(), microtonaluiwindow->x(), microtonaluiwindow->y(), false, "Scales");
    microtonaluiwindow->hide();
    lastscaleSeen = false;
}
void MicrotonalUI::cb_scaleClose(Fl_Button* o, void* v) {
  ((MicrotonalUI*)(o->parent()->user_data()))->cb_scaleClose_i(o,v);
}

Fl_Double_Window* MicrotonalUI::make_window() {
  { Fl_Double_Window* o = microtonaluiwindow = new Fl_Double_Window(410, 485, "Scales");
    microtonaluiwindow->callback((Fl_Callback*)cb_microtonaluiwindow, (void*)(this));
    { Fl_Box* o = new Fl_Box(254, 14, 22, 22);
      o->box(FL_UP_BOX);
      o->color((Fl_Color)237);
    } // Fl_Box* o
    { Fl_Group* o = new Fl_Group(248, 2, 156, 48);
      o->tooltip("Center where the note\'s freqs. are inverted\n(not when keymapped)");
      o->box(FL_ENGRAVED_FRAME);
      { invertlabel = new Fl_Text_Display(273, 7, 5, 24, "Invert");
        invertlabel->box(FL_NO_BOX);
        invertlabel->labelfont(1);
        invertlabel->labelsize(12);
        invertlabel->textsize(11);
        invertlabel->align(Fl_Align(136));
      } // Fl_Text_Display* invertlabel
      { keyslabel = new Fl_Text_Display(273, 18, 5, 30, "keys");
        keyslabel->box(FL_NO_BOX);
        keyslabel->labelfont(1);
        keyslabel->labelsize(12);
        keyslabel->textsize(11);
        keyslabel->align(Fl_Align(136));
      } // Fl_Text_Display* keyslabel
      { Fl_Check_Button2* o = invertKeys = new Fl_Check_Button2(256, 16, 19, 19);
        invertKeys->tooltip("Turn upside-down the note frequencies");
        invertKeys->box(FL_NO_BOX);
        invertKeys->down_box(FL_DOWN_BOX);
        invertKeys->color(FL_LIGHT1);
        invertKeys->selection_color(FL_FOREGROUND_COLOR);
        invertKeys->labeltype(FL_NORMAL_LABEL);
        invertKeys->labelfont(1);
        invertKeys->labelsize(14);
        invertKeys->labelcolor(FL_FOREGROUND_COLOR);
        invertKeys->callback((Fl_Callback*)cb_invertKeys);
        invertKeys->align(Fl_Align(FL_ALIGN_RIGHT));
        invertKeys->when(FL_WHEN_RELEASE);
        o->value(microtonal->Pinvertupdown);
      } // Fl_Check_Button2* invertKeys
      { Fl_Box* o = new Fl_Box(335, 17, 56, 27);
        o->box(FL_THIN_UP_BOX);
        o->color((Fl_Color)237);
      } // Fl_Box* o
      { centerlabel = new Fl_Text_Display(336, 17, 50, 8, "Center");
        centerlabel->box(FL_NO_BOX);
        centerlabel->labelsize(11);
      } // Fl_Text_Display* centerlabel
      { WidgetSpinner* o = centerinvertcounter = new WidgetSpinner(339, 20, 47, 20);
        centerinvertcounter->box(FL_NO_BOX);
        centerinvertcounter->color(FL_BACKGROUND_COLOR);
        centerinvertcounter->selection_color(FL_BACKGROUND_COLOR);
        centerinvertcounter->labeltype(FL_NORMAL_LABEL);
        centerinvertcounter->labelfont(0);
        centerinvertcounter->labelsize(11);
        centerinvertcounter->labelcolor(FL_FOREGROUND_COLOR);
        centerinvertcounter->minimum(0);
        centerinvertcounter->maximum(127);
        centerinvertcounter->value(0);
        centerinvertcounter->textfont(1);
        centerinvertcounter->textsize(12);
        centerinvertcounter->callback((Fl_Callback*)cb_centerinvertcounter);
        centerinvertcounter->align(Fl_Align(129));
        centerinvertcounter->when(FL_WHEN_RELEASE);
        o->value(microtonal->Pinvertupdowncenter);
        if (microtonal->Pinvertupdown==0) o->deactivate();
      } // WidgetSpinner* centerinvertcounter
      o->end();
    } // Fl_Group* o
    { Fl_Group* o = new Fl_Group(108, 2, 141, 48);
      o->box(FL_ENGRAVED_FRAME);
      { reflabel = new Fl_Text_Display(155, 20, 50, 8, "Ref.");
        reflabel->box(FL_NO_BOX);
        reflabel->labelfont(1);
        reflabel->labelsize(12);
      } // Fl_Text_Display* reflabel
      { Fl_Box* o = new Fl_Box(188, 19, 54, 25);
        o->box(FL_THIN_UP_BOX);
        o->color((Fl_Color)237);
      } // Fl_Box* o
      { notelabel = new Fl_Text_Display(191, 18, 50, 8, "Note");
        notelabel->box(FL_NO_BOX);
        notelabel->labelsize(11);
      } // Fl_Text_Display* notelabel
      { WidgetSpinner* o = anotecounter = new WidgetSpinner(192, 23, 45, 17);
        anotecounter->tooltip("Midi note range: 24 (C1) to 84 (C6)");
        anotecounter->box(FL_FLAT_BOX);
        anotecounter->color(FL_BACKGROUND_COLOR);
        anotecounter->selection_color(FL_BACKGROUND_COLOR);
        anotecounter->labeltype(FL_NORMAL_LABEL);
        anotecounter->labelfont(0);
        anotecounter->labelsize(11);
        anotecounter->labelcolor(FL_FOREGROUND_COLOR);
        anotecounter->minimum(24);
        anotecounter->maximum(84);
        anotecounter->value(69);
        anotecounter->textfont(1);
        anotecounter->textsize(11);
        anotecounter->callback((Fl_Callback*)cb_anotecounter);
        anotecounter->align(Fl_Align(FL_ALIGN_TOP));
        anotecounter->when(FL_WHEN_RELEASE);
        o->value(microtonal->PrefNote);
      } // WidgetSpinner* anotecounter
      { Fl_Value_Input* o = afreqinput = new Fl_Value_Input(114, 20, 55, 20, "Freq.");
        afreqinput->tooltip("The frequency of the reference note (default: A4=440.0)");
        afreqinput->labelsize(11);
        afreqinput->minimum(30);
        afreqinput->maximum(1100);
        afreqinput->value(440);
        afreqinput->textfont(1);
        afreqinput->textsize(10);
        afreqinput->callback((Fl_Callback*)cb_afreqinput);
        afreqinput->align(Fl_Align(FL_ALIGN_TOP));
        o->step(0.001, 1);
        refFreq = microtonal->PrefFreq;
        o->value(refFreq);
      } // Fl_Value_Input* afreqinput
      { AsetBack = new Fl_Button(171, 22, 14, 17);
        AsetBack->box(FL_THIN_DOWN_BOX);
        AsetBack->color(FL_DARK2);
        AsetBack->callback((Fl_Callback*)cb_AsetBack);
        AsetBack->hide();
      } // Fl_Button* AsetBack
      { afreqset = new Fl_Return_Button(166, 20, 14, 18);
        afreqset->box(FL_NO_BOX);
        afreqset->callback((Fl_Callback*)cb_afreqset);
        afreqset->hide();
      } // Fl_Return_Button* afreqset
      o->end();
    } // Fl_Group* o
    { Fl_Box* o = new Fl_Box(210, 165, 22, 22);
      o->box(FL_UP_BOX);
      o->color((Fl_Color)237);
    } // Fl_Box* o
    { Fl_Group* o = microtonalgroup = new Fl_Group(3, 49, 402, 432);
      microtonalgroup->box(FL_ENGRAVED_FRAME);
      { Fl_Input* o = nameinput = new Fl_Input(10, 64, 285, 25, "Name:");
        nameinput->labelfont(1);
        nameinput->labelsize(11);
        nameinput->callback((Fl_Callback*)cb_nameinput);
        nameinput->align(Fl_Align(FL_ALIGN_TOP_LEFT));
        o->value(microtonal->Pname.c_str());
      } // Fl_Input* nameinput
      { Fl_Input* o = commentinput = new Fl_Input(10, 104, 391, 25, "Description:");
        commentinput->labelfont(1);
        commentinput->labelsize(11);
        commentinput->callback((Fl_Callback*)cb_commentinput);
        commentinput->align(Fl_Align(FL_ALIGN_TOP_LEFT));
        o->value(microtonal->Pcomment.c_str());
      } // Fl_Input* commentinput
      { Fl_Box* o = new Fl_Box(315, 65, 56, 27);
        o->box(FL_THIN_UP_BOX);
        o->color((Fl_Color)237);
      } // Fl_Box* o
      { shiftlabel = new Fl_Text_Display(318, 65, 50, 8, "Shift");
        shiftlabel->box(FL_NO_BOX);
        shiftlabel->labelsize(11);
      } // Fl_Text_Display* shiftlabel
      { WidgetSpinner* o = scaleShift = new WidgetSpinner(320, 68, 47, 20);
        scaleShift->tooltip("Octave base offset");
        scaleShift->box(FL_NO_BOX);
        scaleShift->color(FL_BACKGROUND_COLOR);
        scaleShift->selection_color(FL_BACKGROUND_COLOR);
        scaleShift->labeltype(FL_NORMAL_LABEL);
        scaleShift->labelfont(0);
        scaleShift->labelsize(10);
        scaleShift->labelcolor(FL_FOREGROUND_COLOR);
        scaleShift->minimum(-63);
        scaleShift->maximum(64);
        scaleShift->value(0);
        scaleShift->textfont(1);
        scaleShift->textsize(12);
        scaleShift->callback((Fl_Callback*)cb_scaleShift);
        scaleShift->align(Fl_Align(FL_ALIGN_TOP));
        scaleShift->when(FL_WHEN_RELEASE);
        o->value(microtonal->Pscaleshift-64);
      } // WidgetSpinner* scaleShift
      { Tuning = new Fl_Group(7, 144, 190, 300, "Tunings:");
        Tuning->box(FL_ENGRAVED_FRAME);
        Tuning->labelfont(1);
        Tuning->labelsize(11);
        Tuning->align(Fl_Align(FL_ALIGN_TOP_LEFT));
        { tuningsinput = new Fl_Input(10, 147, 182, 258);
          tuningsinput->tooltip("You must retune if you change this.");
          tuningsinput->type(4);
          tuningsinput->labelfont(1);
          tuningsinput->labelsize(11);
          tuningsinput->align(Fl_Align(FL_ALIGN_TOP_LEFT));
          tuningsinput->when(FL_WHEN_NEVER);
          updateTuningsInput();
        } // Fl_Input* tuningsinput
        { Fl_Value_Output* o = octavesizeoutput = new Fl_Value_Output(17, 417, 45, 20, "Notes / oct.");
          octavesizeoutput->tooltip("Notes/Octave");
          octavesizeoutput->labelsize(10);
          octavesizeoutput->maximum(500);
          octavesizeoutput->step(1);
          octavesizeoutput->value(12);
          octavesizeoutput->textfont(1);
          octavesizeoutput->callback((Fl_Callback*)cb_octavesizeoutput);
          octavesizeoutput->align(Fl_Align(FL_ALIGN_TOP_LEFT));
          o->value(microtonal->getoctavesize());
        } // Fl_Value_Output* octavesizeoutput
        { importscl = new Fl_Button(85, 417, 100, 20, "Import .scl file");
          importscl->tooltip("Inport Scala .scl file (tunnings)");
          importscl->box(FL_THIN_UP_BOX);
          importscl->labelfont(1);
          importscl->labelsize(10);
          importscl->callback((Fl_Callback*)cb_importscl);
        } // Fl_Button* importscl
        Tuning->end();
      } // Fl_Group* Tuning
      { Keymap = new Fl_Group(195, 144, 206, 300, "Keyboard Map:");
        Keymap->box(FL_ENGRAVED_FRAME);
        Keymap->labelfont(1);
        Keymap->labelsize(11);
        { mappinginput = new Fl_Input(251, 147, 146, 258);
          mappinginput->tooltip("You must retune if you change this.");
          mappinginput->type(4);
          mappinginput->labelfont(1);
          mappinginput->labelsize(11);
          mappinginput->align(Fl_Align(FL_ALIGN_TOP_LEFT));
          mappinginput->when(FL_WHEN_NEVER);
          updateMappingInput();
        } // Fl_Input* mappinginput
        { Fl_Box* o = new Fl_Box(199, 225, 50, 25);
          o->box(FL_THIN_UP_BOX);
          o->color((Fl_Color)237);
        } // Fl_Box* o
        { first1 = new Fl_Text_Display(197, 214, 50, 8, "First");
          first1->box(FL_NO_BOX);
          first1->labelsize(11);
        } // Fl_Text_Display* first1
        { first2 = new Fl_Text_Display(198, 224, 50, 8, "note");
          first2->box(FL_NO_BOX);
          first2->labelsize(11);
        } // Fl_Text_Display* first2
        { WidgetSpinner* o = firstnotecounter = new WidgetSpinner(203, 228, 42, 18);
          firstnotecounter->tooltip("First MIDI note number");
          firstnotecounter->box(FL_NO_BOX);
          firstnotecounter->color(FL_BACKGROUND_COLOR);
          firstnotecounter->selection_color(FL_BACKGROUND_COLOR);
          firstnotecounter->labeltype(FL_NORMAL_LABEL);
          firstnotecounter->labelfont(0);
          firstnotecounter->labelsize(11);
          firstnotecounter->labelcolor(FL_FOREGROUND_COLOR);
          firstnotecounter->minimum(0);
          firstnotecounter->maximum(125);
          firstnotecounter->textfont(1);
          firstnotecounter->textsize(11);
          firstnotecounter->callback((Fl_Callback*)cb_firstnotecounter);
          firstnotecounter->align(Fl_Align(FL_ALIGN_TOP));
          firstnotecounter->when(FL_WHEN_RELEASE);
          oldFirst = microtonal->Pfirstkey;
          o->value(oldFirst);
        } // WidgetSpinner* firstnotecounter
        { Fl_Box* o = new Fl_Box(199, 290, 50, 25);
          o->box(FL_THIN_UP_BOX);
          o->color((Fl_Color)237);
        } // Fl_Box* o
        { middle1 = new Fl_Text_Display(197, 279, 50, 8, "Middle");
          middle1->box(FL_NO_BOX);
          middle1->labelsize(11);
        } // Fl_Text_Display* middle1
        { middle2 = new Fl_Text_Display(198, 289, 50, 8, "note");
          middle2->box(FL_NO_BOX);
          middle2->labelsize(11);
        } // Fl_Text_Display* middle2
        { WidgetSpinner* o = middlenotecounter = new WidgetSpinner(203, 293, 42, 18);
          middlenotecounter->tooltip("Middle note (where scale degree 0 is mapped to)");
          middlenotecounter->box(FL_NO_BOX);
          middlenotecounter->color(FL_BACKGROUND_COLOR);
          middlenotecounter->selection_color(FL_BACKGROUND_COLOR);
          middlenotecounter->labeltype(FL_NORMAL_LABEL);
          middlenotecounter->labelfont(0);
          middlenotecounter->labelsize(11);
          middlenotecounter->labelcolor(FL_FOREGROUND_COLOR);
          middlenotecounter->maximum(126);
          middlenotecounter->value(60);
          middlenotecounter->textfont(1);
          middlenotecounter->textsize(11);
          middlenotecounter->callback((Fl_Callback*)cb_middlenotecounter);
          middlenotecounter->align(Fl_Align(FL_ALIGN_TOP));
          middlenotecounter->when(FL_WHEN_RELEASE);
          oldMid = microtonal->Pmiddlenote;
          o->value(oldMid);
        } // WidgetSpinner* middlenotecounter
        { Fl_Box* o = new Fl_Box(199, 354, 50, 25);
          o->box(FL_THIN_UP_BOX);
          o->color((Fl_Color)237);
        } // Fl_Box* o
        { last1 = new Fl_Text_Display(197, 344, 50, 8, "Last");
          last1->box(FL_NO_BOX);
          last1->labelsize(11);
        } // Fl_Text_Display* last1
        { last2 = new Fl_Text_Display(198, 354, 50, 8, "note");
          last2->box(FL_NO_BOX);
          last2->labelsize(11);
        } // Fl_Text_Display* last2
        { WidgetSpinner* o = lastnotecounter = new WidgetSpinner(203, 357, 42, 18);
          lastnotecounter->tooltip("Last MIDI note number");
          lastnotecounter->box(FL_NO_BOX);
          lastnotecounter->color(FL_BACKGROUND_COLOR);
          lastnotecounter->selection_color(FL_BACKGROUND_COLOR);
          lastnotecounter->labeltype(FL_NORMAL_LABEL);
          lastnotecounter->labelfont(0);
          lastnotecounter->labelsize(11);
          lastnotecounter->labelcolor(FL_FOREGROUND_COLOR);
          lastnotecounter->minimum(2);
          lastnotecounter->maximum(127);
          lastnotecounter->value(127);
          lastnotecounter->textfont(1);
          lastnotecounter->textsize(11);
          lastnotecounter->callback((Fl_Callback*)cb_lastnotecounter);
          lastnotecounter->align(Fl_Align(FL_ALIGN_TOP));
          lastnotecounter->when(FL_WHEN_RELEASE);
          oldLast = microtonal->Plastkey;
          o->value(oldLast);
        } // WidgetSpinner* lastnotecounter
        { Fl_Value_Output* o = mapsizeoutput = new Fl_Value_Output(202, 417, 44, 20, "Map Size");
          mapsizeoutput->labelsize(10);
          mapsizeoutput->maximum(500);
          mapsizeoutput->step(1);
          mapsizeoutput->value(12);
          mapsizeoutput->textfont(1);
          mapsizeoutput->callback((Fl_Callback*)cb_mapsizeoutput);
          mapsizeoutput->align(Fl_Align(FL_ALIGN_TOP_LEFT));
          o->value(microtonal->Pmapsize);
        } // Fl_Value_Output* mapsizeoutput
        { importkbm = new Fl_Button(285, 417, 104, 20, "Import .kbm file");
          importkbm->tooltip("Inport Scala .kbm file (keyboard mapping)");
          importkbm->box(FL_THIN_UP_BOX);
          importkbm->labelfont(1);
          importkbm->labelsize(10);
          importkbm->callback((Fl_Callback*)cb_importkbm);
        } // Fl_Button* importkbm
        Keymap->end();
      } // Fl_Group* Keymap
      { Fl_Check_Button2* o = mappingenabledbutton = new Fl_Check_Button2(212, 166, 20, 21, "ON");
        mappingenabledbutton->tooltip("Enable the Mapping (otherwise the mapping is linear)");
        mappingenabledbutton->box(FL_NO_BOX);
        mappingenabledbutton->down_box(FL_DOWN_BOX);
        mappingenabledbutton->color(FL_LIGHT1);
        mappingenabledbutton->selection_color(FL_FOREGROUND_COLOR);
        mappingenabledbutton->labeltype(FL_NORMAL_LABEL);
        mappingenabledbutton->labelfont(0);
        mappingenabledbutton->labelsize(14);
        mappingenabledbutton->labelcolor(FL_FOREGROUND_COLOR);
        mappingenabledbutton->callback((Fl_Callback*)cb_mappingenabledbutton);
        mappingenabledbutton->align(Fl_Align(33));
        mappingenabledbutton->when(FL_WHEN_RELEASE);
        o->value(microtonal->Pmappingenabled);
        if (microtonal->Pmappingenabled==0) Keymap->deactivate();
      } // Fl_Check_Button2* mappingenabledbutton
      { applybutton = new Fl_Button(152, 447, 107, 28, "Retune");
        applybutton->tooltip("Retune the synth according to the inputs from \"Tunnings\" and \"Keyboard Map\
ping\"");
        applybutton->box(FL_THIN_UP_BOX);
        applybutton->labeltype(FL_EMBOSSED_LABEL);
        applybutton->labelfont(1);
        applybutton->callback((Fl_Callback*)cb_applybutton);
      } // Fl_Button* applybutton
      if (microtonal->Penabled==0) o->deactivate();
      microtonalgroup->end();
    } // Fl_Group* microtonalgroup
    { enablelabel = new Fl_Text_Display(27, 24, 50, 8, "Enable");
      enablelabel->box(FL_NO_BOX);
      enablelabel->labelfont(1);
      enablelabel->labelsize(12);
    } // Fl_Text_Display* enablelabel
    { microtonallabel = new Fl_Text_Display(40, 40, 50, 8, "Microtonal");
      microtonallabel->box(FL_NO_BOX);
      microtonallabel->labelfont(1);
      microtonallabel->labelsize(12);
    } // Fl_Text_Display* microtonallabel
    { Fl_Box* o = new Fl_Box(2, 13, 22, 22);
      o->box(FL_UP_BOX);
      o->color((Fl_Color)237);
    } // Fl_Box* o
    { Fl_Check_Button2* o = enableMicrotonal = new Fl_Check_Button2(4, 13, 21, 22);
      enableMicrotonal->box(FL_NO_BOX);
      enableMicrotonal->down_box(FL_DOWN_BOX);
      enableMicrotonal->color(FL_LIGHT1);
      enableMicrotonal->selection_color(FL_FOREGROUND_COLOR);
      enableMicrotonal->labeltype(FL_NORMAL_LABEL);
      enableMicrotonal->labelfont(1);
      enableMicrotonal->labelsize(14);
      enableMicrotonal->labelcolor(FL_FOREGROUND_COLOR);
      enableMicrotonal->callback((Fl_Callback*)cb_enableMicrotonal);
      enableMicrotonal->align(Fl_Align(FL_ALIGN_LEFT));
      enableMicrotonal->when(FL_WHEN_RELEASE);
      o->value(microtonal->Penabled);
    } // Fl_Check_Button2* enableMicrotonal
    { scaleClose = new Fl_Button(315, 447, 67, 28, "Close");
      scaleClose->box(FL_THIN_UP_BOX);
      scaleClose->down_box(FL_THIN_DOWN_BOX);
      scaleClose->callback((Fl_Callback*)cb_scaleClose);
    } // Fl_Button* scaleClose
    scaleDW = o->w(); scaleDH = o->h();
    o->size_range(scaleDW, scaleDH, 0, 0, 0, 0, 1);
    microtonaluiwindow->end();
    microtonaluiwindow->resizable(microtonaluiwindow);
  } // Fl_Double_Window* microtonaluiwindow
  return microtonaluiwindow;
}

void MicrotonalUI::send_data(int action, int control, float value, int type, int par , int miscmsg ) {
  //
          type |= TOPLEVEL::type::Write;
          collect_data(synth, value, action, type, control, TOPLEVEL::section::scales, UNUSED, UNUSED, UNUSED, par, UNUSED, miscmsg);
}

float MicrotonalUI::fetchData(float value, int control, int part, int kititem , int engine , int insert , int parameter , int offset , int miscmsg , int request ) {
  //
          return collect_readData(synth, value, control, part, kititem, engine, insert, parameter, offset, miscmsg, request);
}

void MicrotonalUI::returns_update(CommandBlock *getData) {
  //
      float value = getData->data.value;
      bool wasFromUs = ((getData->data.source & TOPLEVEL::action::noAction) == TOPLEVEL::action::fromGUI);
      unsigned char control = getData->data.control;
      unsigned char kititem = getData->data.kit;
      unsigned char engine = getData->data.engine;
      unsigned char insert = getData->data.insert;
      unsigned char parameter = getData->data.parameter;
  
      unsigned char miscmsg = getData->data.miscmsg;
      int value_int = lrint(value);
      bool value_bool = _SYS_::F2B(value);
      string msg;
  
      switch (control)
      {
          case SCALES::control::refFrequency:
              afreqinput->value(value);
              break;
          case SCALES::control::refNote:
              anotecounter->value(value_int);
              break;
          case SCALES::control::invertScale:
              invertKeys->value(value_bool);
              checkInvert();
              break;
          case SCALES::control::invertedScaleCenter:
              centerinvertcounter->value(value_int);
              break;
          case SCALES::control::scaleShift:
              scaleShift->value(value_int);
              break;
  
          case SCALES::control::enableMicrotonal:
              enableMicrotonal->value(value_bool);
              checkInvert();
              if (value_bool)
                  microtonalgroup->activate();
              else
                  microtonalgroup->deactivate();
              break;
  
          case SCALES::control::enableKeyboardMap:
              mappingenabledbutton->value(value_bool);
              checkInvert();
              if (value_bool)
                  Keymap->activate();
              else
                  Keymap->deactivate();
              break;
          case SCALES::control::lowKey:
              firstnotecounter->value(value_int);
              break;
          case SCALES::control::middleKey:
              middlenotecounter->value(value_int);
              break;
          case SCALES::control::highKey:
              lastnotecounter->value(value_int);
              break;
  
          case SCALES::control::tuning:
          case SCALES::control::importScl:
              msg = (textMsgBuffer.fetch(miscmsg)); // must always fetch it
              if (value_int > 0)
              {
                  tuningsinput->value(msg.c_str());
                  octavesizeoutput->value(value_int);
              }
              else if (wasFromUs)
                  errors(value_int, true);
              break;
          case SCALES::control::keyboardMap:
          case SCALES::control::importKbm:
              msg = (textMsgBuffer.fetch(miscmsg)); // must always fetch it
              if (value_int > 0)
              {
                  mappinginput->value(msg.c_str());
                  mapsizeoutput->value(value_int);
                  if (control == SCALES::control::importKbm)
                  {
                      anotecounter->value(kititem);
                      firstnotecounter->value(engine);
                      middlenotecounter->value(insert);
                      lastnotecounter->value(parameter);
                      afreqinput->value(fetchData(0, SCALES::control::refFrequency, TOPLEVEL::section::scales));
                  }
              }
              else if (wasFromUs)
                  errors(value_int, true);
              break;
  
          case SCALES::control::name:
              nameinput->value(textMsgBuffer.fetch(miscmsg).c_str());
              break;
          case SCALES::control::comment:
              commentinput->value(textMsgBuffer.fetch(miscmsg).c_str());
              break;
  
          case SCALES::control::clearAll:
              microtonaluiwindow->hide();
              make_window();
              break;
  }
}

void MicrotonalUI::updateTuningsInput() {
  //
      char *tmpbuf = new char[100];
      tuningsinput->cut(0, tuningsinput->maximum_size());
      for (int i = 0; i < microtonal->getoctavesize(); ++i)
      {
          if (i != 0)
              tuningsinput->insert("\n");
          microtonal->tuningtoline(i, tmpbuf, 100);
          tuningsinput->insert(tmpbuf);
      }
      delete [] tmpbuf;
}

void MicrotonalUI::updateMappingInput() {
  //
      char *tmpbuf = new char[100];
      mappinginput->cut(0, tuningsinput->maximum_size());
      for (int i = 0; i < microtonal->Pmapsize; ++i)
      {
          if (i != 0)
              mappinginput->insert("\n");
          if ((microtonal->Pmapping[i]) == -1)
              snprintf(tmpbuf, 100, "x");
          else
              snprintf(tmpbuf, 100, "%d", microtonal->Pmapping[i]);
          mappinginput->insert(tmpbuf);
      }
      delete [] tmpbuf;
}

MicrotonalUI::MicrotonalUI(Microtonal *microtonal_, SynthEngine *synth_) {
  //
      synth = synth_;
      microtonal=microtonal_;
      lastscaleW = 0;
      lastscaleSeen = false;
      make_window();
}

MicrotonalUI::~MicrotonalUI() {
  //
      if (lastscaleSeen)
          saveWin(synth, microtonaluiwindow->w(), microtonaluiwindow->h(), microtonaluiwindow->x(), microtonaluiwindow->y(), true, "Scales");
      microtonaluiwindow->hide();
      delete tuningsinput;
      delete mappinginput;
      delete microtonaluiwindow;
}

void MicrotonalUI::showScales() {
  //
      int fetchX, fetchY, fetchW, fetchH, fetchO;
  
      loadWin(synth, fetchW, fetchH, fetchX, fetchY, fetchO, "Scales");
      if (fetchW < scaleDW || fetchH < scaleDH)
      {
          fetchW = scaleDW;
          fetchH = scaleDH;
      }
      checkSane(fetchX, fetchY, fetchW, fetchH, scaleDW, scaleDH);
  
      microtonaluiwindow->resize(fetchX, fetchY, fetchW, fetchH);
      lastscaleW = 0;
      lastscaleSeen = true;
      microtonaluiwindow->show();
}

void MicrotonalUI::scaleRtext() {
  //
      if (lastscaleW == microtonaluiwindow->w())
          return;
      lastscaleW = microtonaluiwindow->w();
  
      float dScale = microtonaluiwindow->w() / float(scaleDW);
  
      int size = int(10 * dScale);
      int size11 = int(11 * dScale);
      int size12 = int(12 * dScale);
      int size14 = int(14 * dScale);
  
      invertlabel->labelsize(size12);
      keyslabel->labelsize(size12);
      invertKeys->labelsize(size14);
      centerlabel->labelsize(size11);
      centerinvertcounter->textsize(size12);
      reflabel->labelsize(size12);
      notelabel->labelsize(size11);
      anotecounter->textsize(size11);
      afreqinput->labelsize(size11);
          afreqinput->textsize(size);
      AsetBack->labelsize(size14);
      afreqset->labelsize(size14);
      nameinput->labelsize(size11);
          nameinput->textsize(size14);
      commentinput->labelsize(size11);
          commentinput->textsize(size14);
      shiftlabel->labelsize(size11);
      scaleShift->labelsize(size);
          scaleShift->textsize(size12);
      Tuning->labelsize(size11);
      tuningsinput->textsize(size14);
      octavesizeoutput->textsize(size14);
      importscl->labelsize(size);
      Keymap->labelsize(size11);
      mappinginput->textsize(size14);
      first1->labelsize(size11);
      first2->labelsize(size11);
          firstnotecounter->textsize(size11);
      middle1->labelsize(size11);
      middle2->labelsize(size11);
          middlenotecounter->textsize(size11);
      last1->labelsize(size11);
      last2->labelsize(size11);
          lastnotecounter->textsize(size11);
      mapsizeoutput->textsize(size14);
      importkbm->labelsize(size);
      mappingenabledbutton->labelsize(size14);
      applybutton->labelsize(size14);
      enablelabel->labelsize(size12);
      microtonallabel->labelsize(size12);
      enableMicrotonal->labelsize(size14);
      scaleClose->labelsize(size14);
  
      microtonaluiwindow->redraw();
}

void MicrotonalUI::apply() {
  //
      int value = microtonal->texttotunings(tuningsinput->value());
      if (value < 1)
      {
          errors(value, true);
          return;
      }
      octavesizeoutput->do_callback();
  
      value = microtonal->texttomapping(mappinginput->value());
      if (value < 1)
      {
          errors(value, false);
          return;
      }
      synth->setAllPartMaps();
      mapsizeoutput->do_callback();
      anotecounter->do_callback();
}

void MicrotonalUI::checkInvert() {
  //
      if ((enableMicrotonal->value() && mappingenabledbutton->value()) || !invertKeys->value())
          centerinvertcounter->deactivate();
      else
          centerinvertcounter->activate();
}

void MicrotonalUI::errors(int value, bool type) {
  //
      string message;
      if (type)
          message = "Tuning: ";
      else
          message = "Keymap: ";
      switch (value)
      {
          case 0:
              message += "Nothing entered";
              break;
          case -1:
              message += "Value is too small";
              break;
          case -2:
              if (type)
                  message += "Must be numbers (like 232.59)\n or divisions (like 121/64)";
              else
                  message += "Invalid characters";
              break;
          case -3:
              message += "File not found";
              break;
          case -4:
              message += "Empty file";
              break;
          case -5:
              message += "Short or corrupted file";
              break;
          case -6:
              if (type)
                  message += "Invalid octave size";
              else
                  message += "Invalid keymap size";
              break;
          case -7:
              message += "Invalid note number";
              break;
          case -8:
              message += "Value out of range";
              break;
      }
      alert(synth, message);
}
