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

#include "MidiLearnUI.h"
// MidiLearnUI.cc
// Copyright (C) 2016-2022, 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.


#include <FL/fl_ask.H>
    #include "Misc/Config.h"
    #include "Misc/SynthEngine.h"
#include "MasterUI.h"
#include "Misc/SynthEngine.h"
#include <vector>
    #include <string>
    using std::vector;
    using std::to_string;
#include "Misc/FileMgrFuncs.h"
    using file::findLeafName;
#include "Misc/FormatFuncs.h"
    using func::asHexString;
#include "Misc/TextMsgBuffer.h"

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

void MidiLearnKitItem::cb_CCcounter_i(WidgetSpinner*, void*) {
  send_data(0, MIDILEARN::control::CCorChannel);
}
void MidiLearnKitItem::cb_CCcounter(WidgetSpinner* o, void* v) {
  ((MidiLearnKitItem*)(o->parent()->parent()->user_data()))->cb_CCcounter_i(o,v);
}

void MidiLearnKitItem::cb__i(Fl_Button*, void*) {
  // does nothing - hides spinner arrows;
}
void MidiLearnKitItem::cb_(Fl_Button* o, void* v) {
  ((MidiLearnKitItem*)(o->parent()->parent()->user_data()))->cb__i(o,v);
}

void MidiLearnKitItem::cb_sevenbit_i(Fl_Light_Button*, void*) {
  send_data(0, MIDILEARN::control::sevenBit);
}
void MidiLearnKitItem::cb_sevenbit(Fl_Light_Button* o, void* v) {
  ((MidiLearnKitItem*)(o->parent()->parent()->user_data()))->cb_sevenbit_i(o,v);
}

void MidiLearnKitItem::cb_channelchoice_i(Fl_Choice*, void*) {
  send_data(0, 48);
}
void MidiLearnKitItem::cb_channelchoice(Fl_Choice* o, void* v) {
  ((MidiLearnKitItem*)(o->parent()->parent()->user_data()))->cb_channelchoice_i(o,v);
}

Fl_Menu_Item MidiLearnKitItem::menu_channelchoice[] = {
 {"1", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"2", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"3", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"4", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"5", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"6", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"7", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"8", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"9", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"10", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"11", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"12", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"13", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"14", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"15", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"16", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {"All", 0,  0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0},
 {0,0,0,0,0,0,0,0,0}
};
Fl_Menu_Item* MidiLearnKitItem::chan1 = MidiLearnKitItem::menu_channelchoice + 0;
Fl_Menu_Item* MidiLearnKitItem::chan2 = MidiLearnKitItem::menu_channelchoice + 1;
Fl_Menu_Item* MidiLearnKitItem::chan3 = MidiLearnKitItem::menu_channelchoice + 2;
Fl_Menu_Item* MidiLearnKitItem::chan4 = MidiLearnKitItem::menu_channelchoice + 3;
Fl_Menu_Item* MidiLearnKitItem::chan5 = MidiLearnKitItem::menu_channelchoice + 4;
Fl_Menu_Item* MidiLearnKitItem::chan6 = MidiLearnKitItem::menu_channelchoice + 5;
Fl_Menu_Item* MidiLearnKitItem::chan7 = MidiLearnKitItem::menu_channelchoice + 6;
Fl_Menu_Item* MidiLearnKitItem::chan8 = MidiLearnKitItem::menu_channelchoice + 7;
Fl_Menu_Item* MidiLearnKitItem::chan9 = MidiLearnKitItem::menu_channelchoice + 8;
Fl_Menu_Item* MidiLearnKitItem::chan10 = MidiLearnKitItem::menu_channelchoice + 9;
Fl_Menu_Item* MidiLearnKitItem::chan11 = MidiLearnKitItem::menu_channelchoice + 10;
Fl_Menu_Item* MidiLearnKitItem::chan12 = MidiLearnKitItem::menu_channelchoice + 11;
Fl_Menu_Item* MidiLearnKitItem::chan13 = MidiLearnKitItem::menu_channelchoice + 12;
Fl_Menu_Item* MidiLearnKitItem::chan14 = MidiLearnKitItem::menu_channelchoice + 13;
Fl_Menu_Item* MidiLearnKitItem::chan15 = MidiLearnKitItem::menu_channelchoice + 14;
Fl_Menu_Item* MidiLearnKitItem::chan16 = MidiLearnKitItem::menu_channelchoice + 15;
Fl_Menu_Item* MidiLearnKitItem::chanAll = MidiLearnKitItem::menu_channelchoice + 16;

void MidiLearnKitItem::cb_compresscheck_i(Fl_Check_Button2*, void*) {
  //
          send_data(0, MIDILEARN::control::limit);
}
void MidiLearnKitItem::cb_compresscheck(Fl_Check_Button2* o, void* v) {
  ((MidiLearnKitItem*)(o->parent()->parent()->user_data()))->cb_compresscheck_i(o,v);
}

void MidiLearnKitItem::cb_blockcheck_i(Fl_Check_Button2*, void*) {
  //
          send_data(0, MIDILEARN::control::block);
}
void MidiLearnKitItem::cb_blockcheck(Fl_Check_Button2* o, void* v) {
  ((MidiLearnKitItem*)(o->parent()->parent()->user_data()))->cb_blockcheck_i(o,v);
}

void MidiLearnKitItem::cb_activity_i(Fl_Light_Button* o, void*) {
  //
          if (o->value() != 0)
              o->value(0);
          else
              o->value(1);
}
void MidiLearnKitItem::cb_activity(Fl_Light_Button* o, void* v) {
  ((MidiLearnKitItem*)(o->parent()->parent()->user_data()))->cb_activity_i(o,v);
}

void MidiLearnKitItem::cb_minval_i(WidgetSpinner*, void*) {
  send_data(0, MIDILEARN::control::minimum);
}
void MidiLearnKitItem::cb_minval(WidgetSpinner* o, void* v) {
  ((MidiLearnKitItem*)(o->parent()->parent()->user_data()))->cb_minval_i(o,v);
}

void MidiLearnKitItem::cb_1_i(Fl_Button*, void*) {
  // does nothing - hides spinner arrows;
}
void MidiLearnKitItem::cb_1(Fl_Button* o, void* v) {
  ((MidiLearnKitItem*)(o->parent()->parent()->user_data()))->cb_1_i(o,v);
}

void MidiLearnKitItem::cb_maxval_i(WidgetSpinner*, void*) {
  //
          send_data(0, MIDILEARN::control::maximum);
}
void MidiLearnKitItem::cb_maxval(WidgetSpinner* o, void* v) {
  ((MidiLearnKitItem*)(o->parent()->parent()->user_data()))->cb_maxval_i(o,v);
}

void MidiLearnKitItem::cb_2_i(Fl_Button*, void*) {
  // does nothing - hides spinner arrows;
}
void MidiLearnKitItem::cb_2(Fl_Button* o, void* v) {
  ((MidiLearnKitItem*)(o->parent()->parent()->user_data()))->cb_2_i(o,v);
}

void MidiLearnKitItem::cb_commandName_i(Fl_Button*, void*) {
  //
          send_data(0, MIDILEARN::control::deleteLine);
}
void MidiLearnKitItem::cb_commandName(Fl_Button* o, void* v) {
  ((MidiLearnKitItem*)(o->parent()->parent()->user_data()))->cb_commandName_i(o,v);
}

void MidiLearnKitItem::cb_mutecheck_i(Fl_Check_Button2* o, void*) {
  //
        if (o->value())
            midilearnkititemgroup->deactivate();
        else
            midilearnkititemgroup->activate();
        send_data(0, MIDILEARN::control::mute);
}
void MidiLearnKitItem::cb_mutecheck(Fl_Check_Button2* o, void* v) {
  ((MidiLearnKitItem*)(o->parent()->user_data()))->cb_mutecheck_i(o,v);
}

Fl_Group* MidiLearnKitItem::make_window() {
  { midilearnkititem = new Fl_Group(0, 0, 825, 20);
    midilearnkititem->box(FL_FLAT_BOX);
    midilearnkititem->color(FL_BACKGROUND_COLOR);
    midilearnkititem->selection_color(FL_BACKGROUND_COLOR);
    midilearnkititem->labeltype(FL_NO_LABEL);
    midilearnkititem->labelfont(0);
    midilearnkititem->labelsize(14);
    midilearnkititem->labelcolor(FL_FOREGROUND_COLOR);
    midilearnkititem->user_data((void*)(this));
    midilearnkititem->align(Fl_Align(FL_ALIGN_TOP));
    midilearnkititem->when(FL_WHEN_RELEASE);
    { midilearnkititemgroup = new Fl_Group(56, -4, 745, 23);
      midilearnkititemgroup->box(FL_FLAT_BOX);
      { CCcounter = new WidgetSpinner(80, 0, 43, 15);
        CCcounter->tooltip("Continuous Controller to recognise");
        CCcounter->box(FL_NO_BOX);
        CCcounter->color(FL_BACKGROUND_COLOR);
        CCcounter->selection_color(FL_BACKGROUND_COLOR);
        CCcounter->labeltype(FL_NORMAL_LABEL);
        CCcounter->labelfont(0);
        CCcounter->labelsize(12);
        CCcounter->labelcolor(FL_FOREGROUND_COLOR);
        CCcounter->minimum(0);
        CCcounter->maximum(129);
        CCcounter->value(14);
        CCcounter->textsize(12);
        CCcounter->callback((Fl_Callback*)cb_CCcounter);
        CCcounter->align(Fl_Align(FL_ALIGN_LEFT));
        CCcounter->when(FL_WHEN_RELEASE);
      } // WidgetSpinner* CCcounter
      { Fl_Button* o = new Fl_Button(114, 0, 15, 16);
        o->box(FL_FLAT_BOX);
        o->down_box(FL_FLAT_BOX);
        o->callback((Fl_Callback*)cb_);
      } // Fl_Button* o
      { nrpn = new Fl_Button(76, 0, 49, 15, "8888 h");
        nrpn->tooltip("NRPN value");
        nrpn->box(FL_THIN_DOWN_BOX);
        nrpn->down_box(FL_THIN_DOWN_BOX);
        nrpn->color((Fl_Color)247);
        nrpn->selection_color(FL_BACKGROUND2_COLOR);
        nrpn->labelsize(12);
        nrpn->hide();
      } // Fl_Button* nrpn
      { sevenbit = new Fl_Light_Button(59, 0, 13, 15);
        sevenbit->tooltip("Set for 7bit NRPN");
        sevenbit->box(FL_NO_BOX);
        sevenbit->color((Fl_Color)28);
        sevenbit->selection_color((Fl_Color)1);
        sevenbit->callback((Fl_Callback*)cb_sevenbit);
        sevenbit->hide();
      } // Fl_Light_Button* sevenbit
      { channelchoice = new Fl_Choice(137, 0, 39, 15);
        channelchoice->tooltip("Incoming channel");
        channelchoice->down_box(FL_BORDER_BOX);
        channelchoice->selection_color(FL_BACKGROUND_COLOR);
        channelchoice->labelsize(12);
        channelchoice->textsize(12);
        channelchoice->callback((Fl_Callback*)cb_channelchoice);
        channelchoice->menu(menu_channelchoice);
      } // Fl_Choice* channelchoice
      { compresscheck = new Fl_Check_Button2(324, 0, 15, 15);
        compresscheck->tooltip("Limit or compress incoming value");
        compresscheck->box(FL_NO_BOX);
        compresscheck->down_box(FL_DOWN_BOX);
        compresscheck->color(FL_BACKGROUND_COLOR);
        compresscheck->selection_color(FL_FOREGROUND_COLOR);
        compresscheck->labeltype(FL_NORMAL_LABEL);
        compresscheck->labelfont(1);
        compresscheck->labelsize(14);
        compresscheck->labelcolor(FL_FOREGROUND_COLOR);
        compresscheck->callback((Fl_Callback*)cb_compresscheck);
        compresscheck->align(Fl_Align(FL_ALIGN_LEFT));
        compresscheck->when(FL_WHEN_RELEASE);
      } // Fl_Check_Button2* compresscheck
      { blockcheck = new Fl_Check_Button2(360, 0, 20, 15);
        blockcheck->tooltip("Stop any later lines (or system controls) responding to this CC/Channel pair");
        blockcheck->box(FL_NO_BOX);
        blockcheck->down_box(FL_DOWN_BOX);
        blockcheck->color(FL_BACKGROUND_COLOR);
        blockcheck->selection_color(FL_FOREGROUND_COLOR);
        blockcheck->labeltype(FL_NORMAL_LABEL);
        blockcheck->labelfont(1);
        blockcheck->labelsize(14);
        blockcheck->labelcolor(FL_FOREGROUND_COLOR);
        blockcheck->callback((Fl_Callback*)cb_blockcheck);
        blockcheck->align(Fl_Align(FL_ALIGN_LEFT));
        blockcheck->when(FL_WHEN_RELEASE);
      } // Fl_Check_Button2* blockcheck
      { activity = new Fl_Light_Button(180, 0, 13, 15);
        activity->box(FL_NO_BOX);
        activity->color(FL_SELECTION_COLOR);
        activity->selection_color((Fl_Color)2);
        activity->callback((Fl_Callback*)cb_activity);
      } // Fl_Light_Button* activity
      { minval = new WidgetSpinner(197, 0, 52, 15);
        minval->tooltip("Minimum % to pass on");
        minval->type(1);
        minval->box(FL_NO_BOX);
        minval->color(FL_BACKGROUND_COLOR);
        minval->selection_color(FL_BACKGROUND_COLOR);
        minval->labeltype(FL_NORMAL_LABEL);
        minval->labelfont(0);
        minval->labelsize(12);
        minval->labelcolor(FL_FOREGROUND_COLOR);
        minval->minimum(0);
        minval->step(0.5);
        minval->value(0);
        minval->textsize(12);
        minval->callback((Fl_Callback*)cb_minval);
        minval->align(Fl_Align(FL_ALIGN_LEFT));
        minval->when(FL_WHEN_RELEASE);
      } // WidgetSpinner* minval
      { Fl_Button* o = new Fl_Button(240, 0, 15, 16);
        o->box(FL_FLAT_BOX);
        o->down_box(FL_FLAT_BOX);
        o->callback((Fl_Callback*)cb_1);
      } // Fl_Button* o
      { maxval = new WidgetSpinner(261, 0, 52, 15);
        maxval->tooltip("Maximim % to pass on");
        maxval->type(1);
        maxval->box(FL_NO_BOX);
        maxval->color(FL_BACKGROUND_COLOR);
        maxval->selection_color(FL_BACKGROUND_COLOR);
        maxval->labeltype(FL_NORMAL_LABEL);
        maxval->labelfont(0);
        maxval->labelsize(12);
        maxval->labelcolor(FL_FOREGROUND_COLOR);
        maxval->minimum(0);
        maxval->step(0.5);
        maxval->value(100);
        maxval->textsize(12);
        maxval->callback((Fl_Callback*)cb_maxval);
        maxval->align(Fl_Align(FL_ALIGN_LEFT));
        maxval->when(FL_WHEN_RELEASE);
      } // WidgetSpinner* maxval
      { Fl_Button* o = new Fl_Button(303, 0, 15, 16);
        o->box(FL_FLAT_BOX);
        o->down_box(FL_FLAT_BOX);
        o->callback((Fl_Callback*)cb_2);
      } // Fl_Button* o
      { commandName = new Fl_Button(395, 0, 400, 15, "text");
        commandName->tooltip("To delete, hold CTRL and click here.");
        commandName->box(FL_THIN_DOWN_BOX);
        commandName->color((Fl_Color)247);
        commandName->selection_color((Fl_Color)247);
        commandName->labelfont(1);
        commandName->labelsize(10);
        commandName->callback((Fl_Callback*)cb_commandName);
        commandName->align(Fl_Align(FL_ALIGN_CLIP));
      } // Fl_Button* commandName
      midilearnkititemgroup->end();
    } // Fl_Group* midilearnkititemgroup
    { Fl_Check_Button2* o = mutecheck = new Fl_Check_Button2(39, 0, 21, 15);
      mutecheck->tooltip("Completely ignore this line");
      mutecheck->box(FL_NO_BOX);
      mutecheck->down_box(FL_DOWN_BOX);
      mutecheck->color(FL_BACKGROUND_COLOR);
      mutecheck->selection_color(FL_FOREGROUND_COLOR);
      mutecheck->labeltype(FL_NORMAL_LABEL);
      mutecheck->labelfont(1);
      mutecheck->labelsize(14);
      mutecheck->labelcolor(FL_FOREGROUND_COLOR);
      mutecheck->callback((Fl_Callback*)cb_mutecheck);
      mutecheck->align(Fl_Align(FL_ALIGN_LEFT));
      mutecheck->when(FL_WHEN_RELEASE);
      o->copy_label(to_string(n + 1).c_str());
    } // Fl_Check_Button2* mutecheck
    midilearnkititem->end();
  } // Fl_Group* midilearnkititem
  return midilearnkititem;
}

void MidiLearnKitItem::send_data(int action, int control) {
  //
      bool doit = true;
      int type = 0;
      int CC = UNUSED;
      int chan = UNUSED;
      int min = UNUSED;
      int max = UNUSED;
      switch (control)
      {
          case MIDILEARN::control::block:
              if (blockcheck->value() != 0)
                  type = 1;
              break;
          case MIDILEARN::control::limit:
              if (compresscheck->value() != 0)
                  type = 2;
              break;
          case MIDILEARN::control::mute:
              if (mutecheck->value() != 0)
                  type = 4;
              break;
          case MIDILEARN::control::sevenBit:
              if (sevenbit->value() != 0)
                 type = 16;
              break;
          case MIDILEARN::control::minimum:
              min = lrint(minval->value() * 2.0f);
              break;
          case MIDILEARN::control::maximum:
              max = lrint(maxval->value() * 2.0f);
              break;
          case MIDILEARN::control::deleteLine:
              doit = (Fl::event_state(FL_CTRL) != 0);
              if (doit)
                  doit = (choice(synth, "", "Yes", "No", "Remove line " + to_string( n + 1) + " " + commandName->label() + "?") > 1);
              break;
          case MIDILEARN::control::CCorChannel:
              CC = lrint(CCcounter->value());
              break;
          case 48:
              chan = lrint(channelchoice->value());
              control = MIDILEARN::control::CCorChannel;
              break;
      }
      if (doit)
          collect_data(synth, n, action, type, control, TOPLEVEL::section::midiLearn, CC, chan, min, max, UNUSED, 0);
}

MidiLearnKitItem::MidiLearnKitItem(int x,int y, int w, int h, const char *label):Fl_Group(x,y,w,h,label) {
  n=0;
}

MidiLearnKitItem::~MidiLearnKitItem() {
  //
      midilearnkititem->hide();
      delete(midilearnkititem);
}

void MidiLearnKitItem::init(SynthEngine *synth_, int n_) {
  //
      synth = synth_;
      n = n_;
      make_window();
      show();
      end();
}

void MidiLearnKitItem::kitRscale(float dScale) {
  //
      int size11 = int(11 * dScale);
      int size12 = int(12 * dScale);
      int size14 = int(14 * dScale);
  
      chan1->labelsize(size11);
      chan2->labelsize(size11);
      chan3->labelsize(size11);
      chan4->labelsize(size11);
      chan5->labelsize(size11);
      chan6->labelsize(size11);
      chan7->labelsize(size11);
      chan8->labelsize(size11);
      chan9->labelsize(size11);
      chan10->labelsize(size11);
      chan11->labelsize(size11);
      chan12->labelsize(size11);
      chan13->labelsize(size11);
      chan14->labelsize(size11);
      chan15->labelsize(size11);
      chan16->labelsize(size11);
      chanAll->labelsize(size11);
  
      CCcounter->labelsize(size12);
          CCcounter->textsize(size12);
      nrpn->labelsize(size12);
      sevenbit->labelsize(size14);
      channelchoice->labelsize(size12);
          channelchoice->textsize(size12);
      compresscheck->labelsize(size14);
      blockcheck->labelsize(size14);
      activity->labelsize(size14);
      minval->labelsize(size12);
          minval->textsize(size12);
      maxval->labelsize(size12);
          maxval->textsize(size12);
      mutecheck->labelsize(size12);
      commandName->labelsize(int(10 * dScale));
  
       midilearnkititem->redraw();
}

void MidiLearnUI::cb_midilearnwindow_i(Fl_Double_Window*, void*) {
  close->do_callback();
}
void MidiLearnUI::cb_midilearnwindow(Fl_Double_Window* o, void* v) {
  ((MidiLearnUI*)(o->user_data()))->cb_midilearnwindow_i(o,v);
}

void MidiLearnUI::cb_close_i(Fl_Button*, void*) {
  //
    saveWin(synth, midilearnwindow->w(), midilearnwindow->h(), midilearnwindow->x(), midilearnwindow->y(), false, "Midi-learn");
    midilearnwindow->hide();
    learnSeen = false;
}
void MidiLearnUI::cb_close(Fl_Button* o, void* v) {
  ((MidiLearnUI*)(o->parent()->user_data()))->cb_close_i(o,v);
}

void MidiLearnUI::cb_load_i(Fl_Button*, void*) {
  //
        string filename = setfiler(synth,"", "", false, TOPLEVEL::XML::MLearn);
        if (filename.empty())
            return;
        loadMidi(filename);
}
void MidiLearnUI::cb_load(Fl_Button* o, void* v) {
  ((MidiLearnUI*)(o->parent()->user_data()))->cb_load_i(o,v);
}

void MidiLearnUI::cb_save_i(Fl_Button*, void*) {
  //
        string filename = setfiler(synth,"", "", true, TOPLEVEL::XML::MLearn);
        if (filename.empty())
            return;
        send_data(0, MIDILEARN::control::saveList, 0, 0, 0, 0, 0, 0, textMsgBuffer.push((string) filename));
        recent->activate();
        setWindowTitle(findLeafName(filename));
}
void MidiLearnUI::cb_save(Fl_Button* o, void* v) {
  ((MidiLearnUI*)(o->parent()->user_data()))->cb_save_i(o,v);
}

void MidiLearnUI::cb_clear_i(Fl_Button* o, void*) {
  //
        if (choice(synth, "", "Yes", "No", "Remove all entries") < 2)
            return;

        send_data(0, MIDILEARN::control::clearAll,0,0);
        o->deactivate();
        setWindowTitle();
}
void MidiLearnUI::cb_clear(Fl_Button* o, void* v) {
  ((MidiLearnUI*)(o->parent()->user_data()))->cb_clear_i(o,v);
}

void MidiLearnUI::cb_recent_i(Fl_Button*, void*) {
  //
        synth->getGuiMaster()->paramsui->Recent->position(midilearnwindow->x() + recent->x() - 80, midilearnwindow->y() + recent->y() - 187);
        synth->getGuiMaster()->paramsui->Show(TOPLEVEL::XML::MLearn);
}
void MidiLearnUI::cb_recent(Fl_Button* o, void* v) {
  ((MidiLearnUI*)(o->parent()->user_data()))->cb_recent_i(o,v);
}

Fl_Double_Window* MidiLearnUI::make_window() {
  { Fl_Double_Window* o = midilearnwindow = new Fl_Double_Window(820, 285, "Midi Learn");
    midilearnwindow->tooltip("Editor for all learned controllers.\nCTRL-right click on any knob/slider/butt\
on to learn.\nNote: Adding/deleting entries or changing CC/Chan will renumber \
the lines.");
    midilearnwindow->callback((Fl_Callback*)cb_midilearnwindow, (void*)(this));
    { kitlist = new Fl_Scroll(0, 15, 818, 245);
      kitlist->tooltip("Editor for all learned controllers.\nCTRL-Right click on any knob/slider/butt\
on to learn.\nNote: Adding/deleting entries or changing CC/Chan will renumber \
the lines.");
      kitlist->type(2);
      kitlist->box(FL_DOWN_FRAME);
      kitlist->end();
    } // Fl_Scroll* kitlist
    { none = new Fl_Box(290, 131, 206, 44, "No Entries");
      none->labelsize(32);
    } // Fl_Box* none
    { mutebox = new Fl_Box(18, 0, 41, 15, "Mute");
      mutebox->labelfont(1);
      mutebox->labelsize(11);
      mutebox->align(Fl_Align(FL_ALIGN_BOTTOM|FL_ALIGN_INSIDE));
    } // Fl_Box* mutebox
    { ccbox = new Fl_Box(80, 0, 40, 15, "CC");
      ccbox->labelfont(1);
      ccbox->labelsize(11);
      ccbox->align(Fl_Align(FL_ALIGN_BOTTOM|FL_ALIGN_INSIDE));
    } // Fl_Box* ccbox
    { chanbox = new Fl_Box(139, 0, 40, 15, "Chan");
      chanbox->labelfont(1);
      chanbox->labelsize(11);
      chanbox->align(Fl_Align(FL_ALIGN_BOTTOM|FL_ALIGN_INSIDE));
    } // Fl_Box* chanbox
    { blockbox = new Fl_Box(355, 0, 50, 15, "Block");
      blockbox->labelfont(1);
      blockbox->labelsize(11);
      blockbox->align(Fl_Align(FL_ALIGN_BOTTOM|FL_ALIGN_INSIDE));
    } // Fl_Box* blockbox
    { limitbox = new Fl_Box(310, 0, 48, 15, "Limit");
      limitbox->labelfont(1);
      limitbox->labelsize(11);
      limitbox->align(Fl_Align(FL_ALIGN_BOTTOM|FL_ALIGN_INSIDE));
    } // Fl_Box* limitbox
    { controlbox = new Fl_Box(530, 0, 130, 15, "Control Function");
      controlbox->labelfont(1);
      controlbox->labelsize(11);
      controlbox->align(Fl_Align(FL_ALIGN_BOTTOM|FL_ALIGN_INSIDE));
    } // Fl_Box* controlbox
    { minbox = new Fl_Box(200, 0, 40, 15, "Min %");
      minbox->labelfont(1);
      minbox->labelsize(11);
      minbox->align(Fl_Align(FL_ALIGN_BOTTOM|FL_ALIGN_INSIDE));
    } // Fl_Box* minbox
    { maxbox = new Fl_Box(263, 0, 40, 15, "Max %");
      maxbox->labelfont(1);
      maxbox->labelsize(11);
      maxbox->align(Fl_Align(FL_ALIGN_BOTTOM|FL_ALIGN_INSIDE));
    } // Fl_Box* maxbox
    { close = new Fl_Button(730, 262, 63, 20, "Close");
      close->box(FL_THIN_UP_BOX);
      close->callback((Fl_Callback*)cb_close);
    } // Fl_Button* close
    { load = new Fl_Button(30, 264, 70, 18, "Load");
      load->tooltip("Load complete learned list");
      load->down_box(FL_DOWN_BOX);
      load->labelfont(1);
      load->labelsize(12);
      load->callback((Fl_Callback*)cb_load);
    } // Fl_Button* load
    { save = new Fl_Button(130, 264, 70, 18, "Save");
      save->tooltip("Save complete learned list");
      save->down_box(FL_DOWN_BOX);
      save->labelfont(1);
      save->labelsize(12);
      save->callback((Fl_Callback*)cb_save);
      save->deactivate();
    } // Fl_Button* save
    { clear = new Fl_Button(330, 264, 70, 18, "Clear");
      clear->tooltip("Remove all entries");
      clear->down_box(FL_DOWN_BOX);
      clear->labelfont(1);
      clear->labelsize(12);
      clear->callback((Fl_Callback*)cb_clear);
      clear->deactivate();
    } // Fl_Button* clear
    { Fl_Button* o = recent = new Fl_Button(230, 264, 70, 18, "Recent");
      recent->tooltip("Load from recently seen list");
      recent->down_box(FL_DOWN_BOX);
      recent->labelfont(1);
      recent->labelsize(12);
      recent->callback((Fl_Callback*)cb_recent);
      vector<string> &listType = *synth->getHistory(TOPLEVEL::XML::MLearn);
      if (listType.size() == 0) o->deactivate(); else o->activate();
    } // Fl_Button* recent
    send_data(TOPLEVEL::action::lowPrio, MIDILEARN::control::sendRefreshRequest, 0, 3);
    learnDW = o->w(); learnDH = o->h();
    o->size_range(learnDW, learnDH, 0, 0, 0, 0, 1);
    midilearnwindow->end();
    midilearnwindow->resizable(midilearnwindow);
  } // Fl_Double_Window* midilearnwindow
  return midilearnwindow;
}

void MidiLearnUI::showLearn() {
  //
      int fetchW, fetchH, fetchX, fetchY, fetchO;
      loadWin(synth, fetchW, fetchH, fetchX, fetchY, fetchO, "Midi-learn");
      if (fetchW < learnDW || fetchH < learnDH)
      {
          fetchW = learnDW;
          fetchH = learnDH;
      }
      checkSane(fetchX, fetchY, fetchW, fetchH, learnDW, learnDH);
  
      midilearnwindow->resize(fetchX, fetchY, fetchW, fetchH);
      midilearnwindow->show();
      learnW = 0;
      learnSeen = true;
}

void MidiLearnUI::send_data(int action, int control, float value, int type, int kititem , int engine , int insert , int parameter , int miscmsg ) {
  //
      collect_data(synth, value, action, type, control, TOPLEVEL::section::midiLearn, kititem, engine, insert, parameter, UNUSED, miscmsg);
}

void MidiLearnUI::returns_update(CommandBlock *getData) {
  //
      int value = lrint(getData->data.value);
      unsigned char type = getData->data.type;
      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;
      string hex;
      int nrpnTot;
      unsigned int IDold;
      unsigned int IDnew;
      switch(control)
      {
          case MIDILEARN::control::block:
              break;
          case MIDILEARN::control::ignoreMove:
              if (type != UNUSED) // edit line in place
              {
                  midilearnkititem[value]->blockcheck->value((type & 1) != 0);
                  midilearnkititem[value]->compresscheck->value((type & 2) != 0);
                  midilearnkititem[value]->mutecheck->value((type & 4) != 0);
                  midilearnkititem[value]->sevenbit->value((type & 16) != 0);
                  if (type & 4) // it's muted
                      midilearnkititem[value]->midilearnkititemgroup->deactivate();
                  else
                      midilearnkititem[value]->midilearnkititemgroup->activate();
              }
              if (kititem != UNUSED)
                  midilearnkititem[value]->CCcounter->value(kititem);
              if (engine != UNUSED)
                  midilearnkititem[value]->channelchoice->value(engine);
              if (insert != UNUSED)
                  midilearnkititem[value]->minval->value(insert / 2.0f);
              if (parameter != UNUSED)
                  midilearnkititem[value]->maxval->value(parameter / 2.0f);
              break;
          case MIDILEARN::control::nrpnDetected: // set NRPN fixed value in place
              nrpnTot = (int(engine) << 8) + (int(kititem));
              /* These were stored 8 bit values so must be joined then
               * split as two 7 bit values to give NRPN msb and lsb
               */
              hex = (asHexString(nrpnTot >> 7)) + " " + (asHexString(nrpnTot & 0x7f));
              midilearnkititem[value]->stat |= 0x10;
              midilearnkititem[value]->nrpn->copy_label(hex.c_str());
              midilearnkititem[value]->CCcounter->hide();
              midilearnkititem[value]->nrpn->show();
              midilearnkititem[value]->sevenbit->show();
              break;
          case MIDILEARN::control::CCorChannel:
              addLine(getData);
              break;
          case MIDILEARN::control::findSize: // not using this yet
              break;
          case MIDILEARN::control::sendLearnMessage:
              synth->getGuiMaster()->setmessage(UNUSED, false, textMsgBuffer.fetch(miscmsg), "Close", "Cancel");
              break;
          case MIDILEARN::control::sendRefreshRequest:
              //midilearnwindow->show();
              showLearn();
              break;
          case MIDILEARN::control::reportActivity: // flash LED
              IDold = kititem | (engine << 8);
              for (int i = 0; i < MIDI_LEARN_BLOCK; ++ i)
              {
                  if (midilearnkititem[i] != NULL && midilearnkititem[i]->mutecheck->value() == 0)
                  {
                      unsigned char newchan = midilearnkititem[i]->channelchoice->value();
                      if (newchan == NUM_MIDI_CHANNELS) // all of them
                          newchan = engine; // force it to match
                      IDnew = (unsigned int)midilearnkititem[i]->CCcounter->value() | (newchan << 8);
                      if (IDold == IDnew && (type & 0x10) == (midilearnkititem[i]->stat & 0x10))
                      {
                          midilearnkititem[i]->activity->do_callback();
                          if (midilearnkititem[i]->blockcheck->value() != 0)
                              IDold = 0xffffff; // block following lines
                      }
                  }
              }
              break;
          case MIDILEARN::control::clearAll:
              clearAll(value == 0);
              break;
          case MIDILEARN::control::cancelLearn:
              synth->getGuiMaster()->setmessage(UNUSED, false, "Learn cancelled", "Close");
              break;
      }
}

void MidiLearnUI::addLine(CommandBlock *getData) {
  //
      int lineNo = ((int)getData->data.value);
      int status = getData->data.type;
      string name = textMsgBuffer.fetch(getData->data.miscmsg);
      none->hide();
      clear->activate();
      save->activate();
      midilearnkititem[lineNo] = new MidiLearnKitItem(0, 0,818,20,"");
      midilearnkititem[lineNo]->init(synth, lineNo);
      kitlist->add(midilearnkititem[lineNo]);
  
      midilearnkititem[lineNo]->position(2, 21 + lineNo*20);
      midilearnkititem[lineNo]->stat = (status & 0x10);
      midilearnkititem[lineNo]->mutecheck->value(status & 4);
      midilearnkititem[lineNo]->CCcounter->value(getData->data.kit);
      midilearnkititem[lineNo]->channelchoice->value(getData->data.engine);
      midilearnkititem[lineNo]->minval->value(getData->data.insert / 2.0f);
      midilearnkititem[lineNo]->maxval->value(getData->data.parameter / 2.0f);
      midilearnkititem[lineNo]->compresscheck->value(status & 2);
      midilearnkititem[lineNo]->blockcheck->value(status & 1);
      midilearnkititem[lineNo]->commandName->copy_label(name.c_str());
      if (status & 4)
          midilearnkititem[lineNo]->midilearnkititemgroup->deactivate();
      learnW = 0;
      midilearnwindow->redraw();
}

MidiLearnUI::MidiLearnUI(SynthEngine *_synth) {
  //
      synth = _synth;
      for (int i = 0; i < MIDI_LEARN_BLOCK; ++i)
          midilearnkititem[i] = NULL;
      make_window();
      setWindowTitle();
      learnW = 0;
      learnSeen = false;
}

MidiLearnUI::~MidiLearnUI() {
  //
      if (learnSeen)
          saveWin(synth, midilearnwindow->w(), midilearnwindow->h(), midilearnwindow->x(), midilearnwindow->y(), true, "Midi-learn");
      midilearnwindow->hide();
      delete midilearnwindow;
}

void MidiLearnUI::clearAll(bool empty) {
  //
      kitlist->clear();
      for (int i = 0; i < MIDI_LEARN_BLOCK; ++i)
          midilearnkititem[i] = NULL;
      if (empty)
      {
          none->show();
          clear->deactivate();
          save->deactivate();
      }
      kitlist->redraw();
      kitlist->show();
}

void MidiLearnUI::loadMidi(string file) {
  //
      send_data(TOPLEVEL::action::forceUpdate, MIDILEARN::control::loadList, 0, 0, 0, 0, 0, 0, textMsgBuffer.push((string) file));
      recent->activate();
      setWindowTitle(findLeafName(file));
}

void MidiLearnUI::setWindowTitle(string name ) {
  //
      if (name > "")
          name = " - " + name;
      midilearnwindow->copy_label(synth->makeUniqueName("MIDI Learn" + name).c_str());
}

void MidiLearnUI::learnRtext() {
  //
      if (learnW == midilearnwindow->w())
          return;
      learnW = midilearnwindow->w();
  
      float dScale = midilearnwindow->w() / float(learnDW);
  
      int size11 = int(11 * dScale);
      int size12 = int(12 * dScale);
  
      close->labelsize(size12);
      load->labelsize(size12);
      save->labelsize(size12);
      clear->labelsize(size12);
      recent->labelsize(size12);
  
      mutebox->labelsize(size11);
      ccbox->labelsize(size11);
      chanbox->labelsize(size11);
      blockbox->labelsize(size11);
      limitbox->labelsize(size11);
      controlbox->labelsize(size11);
      minbox->labelsize(size11);
      maxbox->labelsize(size11);
  
      none->labelsize(int(32 * dScale));
      for (int i = 0; i < MIDI_LEARN_BLOCK; ++i)
      {
          if (midilearnkititem[i] == NULL)
              continue;
          midilearnkititem[i]->kitRscale(dScale);
          midilearnkititem[i]->resize(2 * dScale, (21 + i * 20) * dScale, 818 * dScale, 20 * dScale);
      }
      midilearnwindow->redraw();
}
