# data file for the Fltk User Interface Designer (fluid)
version 1.0308
header_name {.h}
code_name {.cc}
comment {MicrotonalUI.h} {not_in_source in_header
}

comment {Microtonal.cc} {in_source not_in_header
}

comment {Original ZynAddSubFX author Nasca Octavian Paul
Copyright (C) 2002-2005 Nasca Octavian Paul
Copyright 2009, Alan Calvert
Copyright 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 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.

} {selected in_source in_header
}

decl {\#include <FL/fl_ask.H>} {public local
}

decl {\#include "Misc/Microtonal.h"} {public local
}

decl {\#include "UI/MiscGui.h"
    \#include "EffUI.h"
    \#include "BankUI.h"
    \#include "ADnoteUI.h"
    \#include "SUBnoteUI.h"
    \#include "PADnoteUI.h"
    \#include "UI/WidgetMWSlider.h"
    \#include "UI/WidgetCheckButton.h"
    \#include "Interface/TextLists.h"
    \#include "Params/Controller.h"} {public local
}

decl {\#include "UI/WidgetSpinner.h"} {public local
}

decl {\#include "Misc/FileMgrFuncs.h"} {private local
}

decl {\#include "Misc/TextMsgBuffer.h"

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

class MicrotonalUI {} {
  Function {make_window()} {} {
    Fl_Window microtonaluiwindow {
      label Scales
      callback {scaleClose->do_callback();}
      xywh {460 128 410 485} type Double hide resizable
      code0 {scaleDW = o->w(); scaleDH = o->h();}
      code1 {o->size_range(scaleDW, scaleDH, 0, 0, 0, 0, 1);}
    } {
      Fl_Group {} {
        tooltip {Center where the note's freqs. are inverted
(not when keymapped)} xywh {248 2 157 48} box ENGRAVED_FRAME
      } {
        Fl_Text_Display invertlabel {
          label Invert
          xywh {273 7 5 24} box NO_BOX selection_color 64 labelfont 3 labelsize 12 labelcolor 226 align 136 textsize 11 textcolor 64
        }
        Fl_Text_Display keyslabel {
          label keys
          xywh {273 18 5 30} box NO_BOX labelfont 3 labelsize 12 labelcolor 226 align 136 textsize 11 textcolor 64
        }
        Fl_Check_Button invertKeys {
          callback {//
          send_data(TOPLEVEL::action::forceUpdate, SCALES::control::invertScale, o->value(), TOPLEVEL::type::Integer);}
          tooltip {Turn upside-down the note frequencies} xywh {256 16 19 19} down_box DOWN_BOX color 50 selection_color 64 labelfont 1 labelcolor 64 align 8
          code0 {o->value(microtonal->Pinvertupdown);}
          class Fl_Check_Button2
        }
        Fl_Text_Display centerlabel {
          label Center
          xywh {336 17 50 8} box NO_BOX labelfont 3 labelsize 11 labelcolor 226
        }
        Fl_Spinner centerinvertcounter {
          callback {//
          send_data(0, SCALES::control::invertedScaleCenter, o->value(), TOPLEVEL::type::Integer);}
          xywh {339 20 47 22} labelsize 11 labelcolor 64 align 1 minimum -0 maximum 127 value 0 textfont 1 textsize 12 textcolor 64
          code0 {o->value(microtonal->Pinvertupdowncenter);}
          code1 {if (microtonal->Pinvertupdown==0) o->deactivate();}
          code2 {o->step(1.0);}
          class WidgetSpinner
        }
      }
      Fl_Group {} {
        xywh {108 2 141 48} box ENGRAVED_FRAME
      } {
        Fl_Text_Display reflabel {
          label {Ref.}
          xywh {155 20 50 8} box NO_BOX labelfont 1 labelsize 12 labelcolor 64
        }
        Fl_Text_Display notelabel {
          label Note
          xywh {191 20 50 6} box NO_BOX labelfont 3 labelsize 11 labelcolor 226 textcolor 64
        }
        Fl_Spinner anotecounter {
          callback {//
          send_data(0, SCALES::control::refNote, o->value(), TOPLEVEL::type::Integer);}
          tooltip {Midi note range: 24 (C1) to 84 (C6)} xywh {192 23 44 20} labelsize 11 labelcolor 64 align 1 minimum 24 maximum 84 value 69 textfont 1 textsize 11 textcolor 64
          code0 {o->value(microtonal->PrefNote);}
          class WidgetSpinner
        }
        Fl_Value_Input afreqinput {
          label {Freq.}
          callback {//
          refFreq = o->value();
          afreqset->show();
          AsetBack->show();}
          tooltip {The frequency of the reference note -'return' to apply (default: A4=440.0)} xywh {114 20 55 20} labelsize 11 labelcolor 64 align 1 minimum 30 maximum 1100 value 440 textfont 1 textsize 10 textcolor 64
          code0 {o->step(0.001, 1);}
          code1 {refFreq = microtonal->PrefFreq;}
          code2 {o->value(refFreq);}
        }
        Fl_Button AsetBack {
          callback {//
          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);}
          xywh {171 22 14 17} box THIN_DOWN_BOX color 45 labelcolor 64 hide
        }
        Fl_Return_Button afreqset {
          callback {//
          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);}
          xywh {166 20 14 18} box NO_BOX labelcolor 64 hide
        }
      }
      Fl_Group microtonalgroup {
        xywh {3 49 402 485} box ENGRAVED_FRAME
        code0 {if (microtonal->Penabled==0) o->deactivate();}
      } {
        Fl_Input nameinput {
          label {Name:}
          callback {//
          send_data(TOPLEVEL::action::lowPrio | TOPLEVEL::action::forceUpdate, SCALES::control::name, 0, TOPLEVEL::type::Integer, UNUSED, textMsgBuffer.push(string(o->value())));}
          xywh {7 64 285 25} labelfont 1 labelsize 11 labelcolor 64 align 5 textcolor 64
          code0 {o->value(microtonal->Pname.c_str());}
        }
        Fl_Input commentinput {
          label {Description:}
          callback {//
          send_data(TOPLEVEL::action::lowPrio | TOPLEVEL::action::forceUpdate, SCALES::control::comment, 0, TOPLEVEL::type::Integer, UNUSED, textMsgBuffer.push(string(o->value())));}
          xywh {7 104 394 25} labelfont 1 labelsize 11 labelcolor 64 align 5 textcolor 64
          code0 {o->value(microtonal->Pcomment.c_str());}
        }
        Fl_Text_Display shiftlabel {
          label Shift
          xywh {318 65 50 8} box NO_BOX labelfont 3 labelsize 11 labelcolor 226
        }
        Fl_Spinner scaleShift {
          callback {//
          send_data(0, SCALES::control::scaleShift, o->value(), TOPLEVEL::type::Integer);}
          tooltip {Octave base offset} xywh {320 68 47 22} labelsize 11 labelcolor 64 align 1 minimum -63 maximum 64 value 0 textfont 1 textsize 12 textcolor 64
          code0 {o->value(microtonal->Pscaleshift-64);}
          code1 {o->step(1.0);}
          class WidgetSpinner
        }
        Fl_Group Tuning {
          label {Tunings:}
          xywh {7 144 190 300} box ENGRAVED_FRAME labelfont 1 labelsize 11 labelcolor 64 align 5
        } {
          Fl_Input tuningsinput {
            tooltip {You must retune if you change this.} xywh {10 147 182 250} type Multiline labelfont 1 labelsize 11 labelcolor 64 align 5 when 2 textcolor 64
            code0 {updateTuningsInput();}
          }
          Fl_Value_Output octavesizeoutput {
            label {Notes / oct.}
            callback {//
                o->value(microtonal->getoctavesize());}
            tooltip {Notes/Octave} xywh {17 415 45 20} labelsize 10 labelcolor 64 align 5 maximum 500 step 1 value 12 textfont 1 textcolor 64
            code0 {o->value(microtonal->getoctavesize());}
          }
          Fl_Button importscl {
            label {Import .scl file}
            callback {//
            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));
            ;}
            tooltip {Import Scala .scl file (tunnings)} xywh {85 401 100 18} box GTK_THIN_UP_BOX color 198 labelfont 1 labelsize 10 labelcolor 64
          }
          Fl_Button exportscl {
            label {Export .scl file}
            callback {//
                int value = microtonal->texttotunings(tuningsinput->value());
                if (value < 1)
                {
                    errors(value, true);
                    return;
                }
                string filename = setfiler(synth,"", "", true, TOPLEVEL::XML::ScalaTune);
                if (filename.empty())
                    return;
                send_data(TOPLEVEL::action::lowPrio, SCALES::control::exportScl, 0, TOPLEVEL::type::Integer, UNUSED, textMsgBuffer.push(filename));}
            tooltip {Export Scala .scl file (tunnings)} xywh {85 422 100 18} box GTK_THIN_UP_BOX color 198 labelfont 1 labelsize 10 labelcolor 64
          }
        }
        Fl_Group Keymap {
          label {Keyboard Map:} open
          xywh {196 144 205 300} box ENGRAVED_FRAME labelfont 1 labelsize 11 labelcolor 64
        } {
          Fl_Input mappinginput {
            tooltip {You must retune if you change this.} xywh {251 147 146 250} type Multiline labelfont 1 labelsize 11 labelcolor 64 align 5 when 2 textcolor 64
            code0 {updateMappingInput();}
          }
          Fl_Box first1 {
            label First
            xywh {197 204 50 8} labelfont 3 labelsize 11 labelcolor 226
          }
          Fl_Box first2 {
            label note
            xywh {198 214 50 8} labelfont 3 labelsize 11 labelcolor 226
          }
          Fl_Spinner firstnotecounter {
            callback {//
            int tmp = int (o->value());
            int max = middlenotecounter->value();
            if (tmp > max)
                    tmp = 0;
            else if (tmp < 0)
                tmp = max;
            o->value(tmp);
            send_data(0, SCALES::control::lowKey, tmp, TOPLEVEL::type::Integer);}
            tooltip {First MIDI note number} xywh {203 228 44 20} selection_color 64 labelsize 11 labelcolor 64 align 1 minimum -1 maximum 128 textfont 1 textsize 11 textcolor 64
            code0 {o->value(microtonal->Pfirstkey);}
            code1 {o->step(1.0);}
            class WidgetSpinner
          }
          Fl_Box middle1 {
            label Middle
            xywh {197 269 50 8} labelfont 3 labelsize 11 labelcolor 226
          }
          Fl_Box middle2 {
            label note
            xywh {198 279 50 8} labelfont 3 labelsize 11 labelcolor 226
          }
          Fl_Spinner middlenotecounter {
            callback {//
            int tmp = int(o->value());
            int min = firstnotecounter->value();
            int max = lastnotecounter->value();
            if (tmp < min)
                tmp = max;
            else if (tmp > max)
                tmp = min;
            o->value(tmp);

            send_data(0, SCALES::control::middleKey, o->value(), TOPLEVEL::type::Integer);}
            tooltip {Middle note (where scale degree 0 is mapped to)} xywh {203 293 44 20} labelsize 11 labelcolor 64 align 1 minimum -1 maximum 128 value 60 textfont 1 textsize 11 textcolor 64
            code0 {o->value(microtonal->Pmiddlenote);}
            class WidgetSpinner
          }
          Fl_Box last1 {
            label Last
            xywh {197 334 50 8} labelfont 3 labelsize 11 labelcolor 226
          }
          Fl_Box last2 {
            label note
            xywh {198 344 50 8} labelfont 3 labelsize 11 labelcolor 226
          }
          Fl_Spinner lastnotecounter {
            callback {//
            int tmp = int(o->value());
            int min = middlenotecounter->value();
            if (tmp < min)
                tmp = 127;
            else if (tmp > 127)
                tmp = min;
            o->value(tmp);

            send_data(0, SCALES::control::highKey, tmp, TOPLEVEL::type::Integer);}
            tooltip {Last MIDI note number} xywh {203 357 44 20} labelsize 11 labelcolor 64 align 1 minimum 0 maximum 128 value 127 textfont 1 textsize 11 textcolor 64
            code0 {o->value(microtonal->Plastkey);}
            class WidgetSpinner
          }
          Fl_Spinner mapsizecounter {
            label {Map Size}
            tooltip {The actual kemap size. This can be greater or smaller than the number of entries in the map} xywh {203 415 42 22} labelsize 11 labelcolor 64 align 1 minimum 0 maximum 127 value 0 textfont 1 textsize 11 textcolor 64
            code0 {o->value(microtonal->Pmapsize);}
            class WidgetSpinner
          }
          Fl_Button exportkbm {
            label {Export .kbm file}
            callback {//
            string filename = setfiler(synth,"", "", true, TOPLEVEL::XML::ScalaMap);
            if (filename.empty())
                return;
            retune();
            send_data(TOPLEVEL::action::lowPrio | TOPLEVEL::action::forceUpdate, SCALES::control::exportKbm, 0, TOPLEVEL::type::Integer, UNUSED, textMsgBuffer.push(filename));}
            tooltip {Export Scala .kbm file (keyboard mapping)} xywh {273 422 104 18} box GTK_THIN_UP_BOX color 198 labelfont 1 labelsize 10 labelcolor 64
          }
        }
        Fl_Check_Button mappingenabledbutton {
          label ON
          callback {//
          o->show();

          send_data(TOPLEVEL::action::forceUpdate, SCALES::control::enableKeyboardMap, o->value(), TOPLEVEL::type::Integer);}
          tooltip {Enable the Mapping (otherwise the mapping is linear)} xywh {212 166 20 21} down_box DOWN_BOX color 50 selection_color 64 labelfont 3 labelcolor 226 align 33
          code0 {o->value(microtonal->Pmappingenabled);}
          code1 {if (microtonal->Pmappingenabled==0) Keymap->deactivate();}
          class Fl_Check_Button2
        }
        Fl_Button retunebutton {
          label Retune
          callback {//
          retune();
          send_data(0, SCALES::control::tuning, 1, TOPLEVEL::type::Integer);
          send_data(0, SCALES::control::keyboardMap, 1, TOPLEVEL::type::Integer);
          ;}
          tooltip {Retune the synth according to the inputs from "Tunnings" and "Keyboard Mapping"} xywh {169 448 107 28} box PLASTIC_UP_BOX color 228 labeltype EMBOSSED_LABEL labelfont 1 labelcolor 64
        }
        Fl_Button clearbutton {
          label {Clear All}
          callback {//
          send_data(TOPLEVEL::action::forceUpdate, SCALES::control::clearAll, 0, TOPLEVEL::type::Integer);}
          tooltip {Return to default scale settings} xywh {25 448 107 28} box PLASTIC_UP_BOX color 89 labelfont 1 labelcolor 64
        }
        Fl_Button importkbm {
          label {Import .kbm file}
          callback {//
            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));
            ;}
          tooltip {Import Scala .kbm file (keyboard mapping)} xywh {273 401 104 18} box GTK_THIN_UP_BOX color 198 labelfont 1 labelsize 10 labelcolor 64
        }
      }
      Fl_Text_Display enablelabel {
        label Enable
        xywh {27 24 50 8} box NO_BOX labelfont 1 labelsize 12 labelcolor 64
      }
      Fl_Text_Display microtonallabel {
        label Microtonal
        xywh {40 40 50 8} box NO_BOX labelfont 1 labelsize 12 labelcolor 64
      }
      Fl_Check_Button enableMicrotonal {
        callback {//
        send_data(TOPLEVEL::action::forceUpdate, SCALES::control::enableMicrotonal, o->value(), TOPLEVEL::type::Integer);}
        xywh {4 13 21 22} down_box DOWN_BOX color 50 selection_color 64 labelfont 1 labelcolor 64 align 4
        code0 {o->value(microtonal->Penabled);}
        class Fl_Check_Button2
      }
      Fl_Button scaleClose {
        label Close
        callback {//
    saveWin(synth, microtonaluiwindow->w(), microtonaluiwindow->h(), microtonaluiwindow->x(), microtonaluiwindow->y(), false, "Scales");
    microtonaluiwindow->hide();
    lastscaleSeen = false;}
        xywh {315 448 67 28} box THIN_UP_BOX down_box THIN_DOWN_BOX color 196 labelcolor 64
      }
    }
  }
  Function {send_data(int action, int control, float value, int type, int par = UNUSED, int miscmsg = UNUSED)} {} {
    code {//
        type |= TOPLEVEL::type::Write;
        collect_writeData(synth, value, action, type, control, TOPLEVEL::section::scales, UNUSED, UNUSED, UNUSED, par, UNUSED, miscmsg);} {}
  }
  Function {fetchData(float value, int control, int part, int kititem = UNUSED, int engine = UNUSED, int insert = UNUSED, int parameter = UNUSED, int offset = UNUSED, int miscmsg = UNUSED, int request = UNUSED)} {return_type float
  } {
    code {//
        return collect_readData(synth, value, control, part, kititem, engine, insert, parameter, offset, miscmsg, request);} {}
  }
  Function {returns_update(CommandBlock *getData)} {} {
    code {//
    float value = getData->data.value;
    bool wasFromUs = ((getData->data.source & TOPLEVEL::action::noAction) == TOPLEVEL::action::fromGUI);
    unsigned char control = getData->data.control;
    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);
            mappingenabledbutton->value(false);
            Keymap->deactivate();
            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));
            if (value_int > 0)
            {
                tuningsinput->value(msg.c_str());
            }
            else if (wasFromUs)
                errors(value_int, true);
            break;
        case SCALES::control::keyboardMap:
        { // this only uses the mapped notes
            msg = (textMsgBuffer.fetch(miscmsg));
            mappinginput->value(msg.c_str());
        }
        break;
        case SCALES::control::keymapSize:
        { // the map size only
            mapsizecounter->value(value_int);
        }
        break;
        case SCALES::control::importKbm:
            if (value_int > 0)
            { // this sets ALL mapping entries
                mappingenabledbutton->value(true);
                checkInvert();
                Keymap->activate();
                msg = (textMsgBuffer.fetch(parameter));
                int mapsize = func::string2int(splitline(msg));
                mapsizecounter->value(mapsize);
                firstnotecounter->value(func::string2int(splitline(msg)));
                lastnotecounter->value(func::string2int(splitline(msg)));
                middlenotecounter->value(func::string2int(splitline(msg)));
                anotecounter->value(func::string2int(splitline(msg)));
                afreqinput->value(func::string2float(splitline(msg)));
                //octavesizeoutput->value(func::string2float(splitline(msg))); // temporarily disabled
                //int formalOctave = func::string2float(splitline(msg)); // temporarily disabled
                string map;
                for (int i = 0; i < mapsize; ++i)
                    map += (splitline(msg) + char(10));
                mappinginput->value(map.c_str());
            }
            else if (wasFromUs)
                errors(value_int, false);
            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();
            showScales();
            break;
}} {}
  }
  Function {updateTuningsInput()} {} {
    code {//
    char *tmpbuf = new char[100];
    tuningsinput->cut(0, tuningsinput->maximum_size());
    for (int i = 0; i < microtonal->getoctavesize(); ++i)
    {
        string line = "";
        microtonal->tuningtoline(i, line);
        if (!microtonal->octave[i].comment.empty())
        {
            line += " ! ";
            line += microtonal->octave[i].comment;
        }

        line += "\\n";
        snprintf(tmpbuf, 100, "%s", line.c_str());
        tuningsinput->insert(tmpbuf);
    }
    delete [] tmpbuf;} {}
  }
  Function {updateMappingInput()} {} {
    code {//
    char *tmpbuf = new char[100];
    mappinginput->cut(0, tuningsinput->maximum_size());
    for (int i = 0; i < microtonal->Pmapsize; ++i)
    {
        string line = "";
        if ((microtonal->Pmapping[i]) == -1)
            line = 'x';
        else
            line = to_string(microtonal->Pmapping[i]);
        if (!microtonal->PmapComment[i].empty())
        {
            line += " ! ";
            line += microtonal->PmapComment[i];
        }
        line += "\\n";
        snprintf(tmpbuf, 100, "%s", line.c_str());
        mappinginput->insert(tmpbuf);
    }
    delete [] tmpbuf;} {}
  }
  Function {splitline(string& page)} {return_type string
  } {
    code {//
        const char ch = 10;
        string line = "";
        do{
            size_t pos = page.find(ch);
            if (pos != string::npos)
            {
                line = page.substr(0, pos);
                page = page.substr(pos + 1, page.length());
            }
            else
            {
                line = page;
                page = "";
                func::trimEnds(line);
            }
        } while (line[0] == '!'); // don't want comment lines
        return line;} {}
  }
  Function {MicrotonalUI(Microtonal *microtonal_, SynthEngine *synth_)} {} {
    code {//
    synth = synth_;
    microtonal=microtonal_;
    lastscaleW = 0;
    lastscaleSeen = false;
    make_window();} {}
  }
  Function {~MicrotonalUI()} {} {
    code {//
    if (lastscaleSeen)
        saveWin(synth, microtonaluiwindow->w(), microtonaluiwindow->h(), microtonaluiwindow->x(), microtonaluiwindow->y(), true, "Scales");
    microtonaluiwindow->hide();
    delete tuningsinput;
    delete mappinginput;
    delete microtonaluiwindow;} {}
  }
  Function {showScales()} {} {
    code {//
    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();} {}
  }
  Function {scaleRtext()} {} {
    code {//
    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->labelsize(size11);
        centerinvertcounter->textsize(size12);

    reflabel->labelsize(size12);
    notelabel->labelsize(size11);
    anotecounter->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(size11);
        scaleShift->textsize(size12);

    Tuning->labelsize(size11);
    tuningsinput->textsize(size14);
    octavesizeoutput->textsize(size14);
    importscl->labelsize(size);
    exportscl->labelsize(size);
    Keymap->labelsize(size11);
    mappinginput->textsize(size14);

    first1->labelsize(size11);
    first2->labelsize(size11);
    firstnotecounter->labelsize(size11);
        firstnotecounter->textsize(size11);

    middle1->labelsize(size11);
    middle2->labelsize(size11);
    middlenotecounter->labelsize(size11);
        middlenotecounter->textsize(size11);

    last1->labelsize(size11);
    last2->labelsize(size11);
    lastnotecounter->labelsize(size11);
        lastnotecounter->textsize(size11);

    mapsizecounter->labelsize(size11);
        mapsizecounter->textsize(size11);
    importkbm->labelsize(size);
    exportkbm->labelsize(size);
    mappingenabledbutton->labelsize(size14);
    retunebutton->labelsize(size14);
    clearbutton->labelsize(size14);
    enablelabel->labelsize(size12);
    microtonallabel->labelsize(size12);
    enableMicrotonal->labelsize(size14);
    scaleClose->labelsize(size14);

    microtonaluiwindow->redraw();} {}
  }
  Function {retune()} {} {
    code {//
    int value = microtonal->texttotunings(tuningsinput->value());
    if (value < 1)
    {
        errors(value, true);
        return;
    }
    octavesizeoutput->do_callback();

    send_data(TOPLEVEL::action::lowPrio, SCALES::control::keymapSize, mapsizecounter->value(), TOPLEVEL::type::Integer);
    value = microtonal->texttomapping(mappinginput->value());
    if (value < 0)
    {
        errors(value, false);
        return;
    }
    anotecounter->do_callback();} {}
  }
  Function {checkInvert()} {} {
    code {//
    if (!invertKeys->value())
        centerinvertcounter->deactivate();
    else
        centerinvertcounter->activate();} {}
  }
  Function {errors(int value, bool type)} {} {
    code {//
    string message;
    if (type)
        message = "Tuning: ";
    else
        message = "Keymap: ";
    /*  TODO sort this!
     * no response to 'type' always Tuning"
            we always see this:
                "Must be numbers (like 232.59) or divisions (like 121/64)"
            Keymap should see this
                "Invalid characters"
    */
    // incoming negative values inverted for text list
    alert(synth, message + scale_errors[0 - value]);} {}
  }
  decl {Microtonal *microtonal;} {private local
  }
  decl {string winlabel;} {private local
  }
  decl {SynthEngine *synth;} {private local
  }
  decl {float refFreq;} {private local
  }
  decl {int scaleDW;} {private local
  }
  decl {int scaleDH;} {private local
  }
  decl {int lastscaleW;} {public local
  }
  decl {bool lastscaleSeen;} {private local
  }
}
