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

#include "MasterMiscUI.h"
// MasterUI.cc
// Original ZynAddSubFX author Nasca Octavian Paul
// Copyright (C) 2002-2005 Nasca Octavian Paul
// Copyright 2009-2011, Alan Calvert
// Copyright 2014-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.

// This file is a derivative of the ZynAddSubFX original.


#include "MasterUI.h"
#include "UI/WidgetMWSlider.h"
#include <FL/fl_draw.H>
#include "Misc/NumericFuncs.h"
    using func::asDecibel;
#include "Misc/FormatFuncs.h"
    using func::asString;

VUMeter::VUMeter(int x,int y, int w, int h, const char *label):Fl_Box(x,y,w,h,label) {
  npart=-1;
}

void VUMeter::init(int part_, SynthEngine *_synth) {
  // the "part_" parameters sets the part (if it is >=0), else it sets the master
      synth = _synth;
      label(NULL);
      npart = part_;
      oldpeakl = 0;
      oldpeakr = 0;
      oldrmsdbl = 0.0;
      oldrmsdbr = 0.0;
      maxdbl = NO_DB;
      maxdbr = NO_DB;
      clipped = 0;
      plgroup = &synth->getGuiMaster()->panelgroup;
      for (int i = 0; i < NUM_MIDI_PARTS; i++)
      {
          panelpart.oldpeak[i] = 0;
          panelpart.oldpeakR[i] = 0;
          panelpart.clip[i] = false;
          panelpart.clipR[i] = false;
      }
}

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

void VUMeter::draw_master() {
  //
              int ox = x();
              int oy = y();
              int lx = w();
              int ly = h();
              float dbl = asDecibel(fetchData(0, MAIN::control::readMainLRpeak, TOPLEVEL::section::main, 0));
              float dbr = asDecibel(fetchData(0, MAIN::control::readMainLRpeak, TOPLEVEL::section::main, 1));
              float rmsdbl = asDecibel(fetchData(0, MAIN::control::readMainLRrms, TOPLEVEL::section::main, 0));
              float rmsdbr = asDecibel(fetchData(0, MAIN::control::readMainLRrms, TOPLEVEL::section::main, 1));
  
              clipped = clipped | (dbl > 0) | ((dbr > 0) << 1);
              if (dbl > 0.5f)
                  dbl = 0.5f;
              if (dbr > 0.5f)
                  dbr = 0.5f;
  
              if (dbl > maxdbl)
                  maxdbl = dbl;
              if (dbr > maxdbr)
                  maxdbr = dbr;
  
              dbl = (MIN_DB - dbl) / MIN_DB;
              if (dbl < 0.0)
                  dbl = 0.0;
              else if (dbl > 1.0)
                  dbl = 1.0;
              dbr = (MIN_DB - dbr) / MIN_DB;
              if (dbr < 0.0)
                  dbr = 0.0;
              else if (dbr > 1.0)
                  dbr = 1.0;
  #          define VULENX (lx-35)
  #          define VULENY (ly/2-3)
              dbl *= VULENX;
              dbr *= VULENX;
              oldpeakl = (int)dbl;
              oldpeakr = (int)dbr;
  
              // compute RMS - start
              rmsdbl = ((MIN_DB - rmsdbl) / MIN_DB);
              if (rmsdbl < 0.0)
                  rmsdbl = 0.0;
              else if (rmsdbl >  1.0)
                  rmsdbl =  1.0;
              rmsdbr = ((MIN_DB - rmsdbr) / MIN_DB);
              if (rmsdbr < 0.0)
                  rmsdbr = 0.0;
              else if (rmsdbr >1.0)
                  rmsdbr = 1.0;
              int irmsdbl = rmsdbl * VULENX;
              int irmsdbr = rmsdbr * VULENX;
              // compute RMS - end
  
              // draw db level
              fl_rectf(ox, oy, oldpeakl, VULENY, 0, 200, 255);
              fl_rectf(ox, oy + ly / 2, oldpeakr, VULENY, 0, 200, 255);
  
              // fill with black
              fl_rectf(ox + oldpeakl, oy, VULENX - oldpeakl, VULENY, 0, 0, 0);
              fl_rectf(ox + oldpeakr, oy + ly / 2, VULENX - oldpeakr, VULENY, 0, 0, 0);
  
              // draw scale
              float tmp = VULENX * 1.0 / MIN_DB;
              for (int i = 1; i < 1 - MIN_DB; ++i)
              {
                  int tx = VULENX + (int)(tmp * i);
                  fl_rectf(ox + tx, oy, 1, VULENY + ly / 2, 0, 160, 200);
                  if (i % 5 == 0)
                      fl_rectf(ox + tx, oy, 1, VULENY + ly / 2, 0, 230, 240);
                  if (i % 10 == 0)
                      fl_rectf(ox + tx - 1, oy, 2, VULENY + ly / 2, 0, 225, 255);
              }
  
              // mellow yellow rms indicator
              if (irmsdbl)
                  fl_rectf(ox + irmsdbl - 1, oy, 3, VULENY, 255, 255, 0);
              if (irmsdbr)
                  fl_rectf(ox + irmsdbr - 1, oy + ly / 2, 3, VULENY, 255, 255, 0);
  
              // see red if clipped
              if (clipped & 1)
                  fl_rectf(ox + VULENX + 2, oy, lx - VULENX - 3, ly / 2 - 3, 250, 10, 10);
              else
                  fl_rectf(ox + VULENX + 2, oy, lx - VULENX - 3, ly / 2 - 3, 0, 0, 10);
  
              if (clipped & 2)
                  fl_rectf(ox + VULENX + 2, oy + ly / 2, lx - VULENX - 3, (ly - 2) / 2 - 2, 250, 10, 10);
              else
                  fl_rectf(ox + VULENX + 2, oy + ly / 2, lx - VULENX - 3, (ly - 2) / 2 - 2, 0, 0, 10);
  
              // show maxdB
              static char tmpstr[8];
              const char *dbtag = "dB";
  
              if ((maxdbl > NO_DB))
              {
                  fl_font(FL_HELVETICA | FL_BOLD, 9);
                  fl_color(255, 255, 255);
                  snprintf(tmpstr, 7, "%+3.f%s", maxdbl + 0.5f, dbtag);
                  fl_draw(tmpstr, ox + VULENX + 1, oy + 1,
                      lx - VULENX - 4, VULENY - 2, FL_ALIGN_RIGHT, NULL, 0);
              }
  
              if ((maxdbr > NO_DB))
              {
                  fl_font(FL_HELVETICA | FL_BOLD, 9);
                  fl_color(255, 255, 255);
                  snprintf(tmpstr, 7, "%+3.f%s", maxdbr + 0.5f, dbtag);
                  fl_draw(tmpstr, ox + VULENX + 1, oy + ly / 2 + 1,
                      lx - VULENX - 4, VULENY, FL_ALIGN_RIGHT, NULL, 0);
              }
}

void VUMeter::draw_part() {
  //
      int ox = x()+2;
      int oy = y()+2;
      int lx = w()-4;
      int ly = h()-4;
      int mid = (w() / 2) - 2;
      int actualpart = npart + *plgroup;
      float Vpeak = fetchData(0, MAIN::control::readPartPeak, TOPLEVEL::section::main, actualpart);
      if (Vpeak < 0) // its inactive
      {
          fl_rectf(ox, oy, lx, ly, 140, 140, 140);
      }
      else
      {
  
          if (Vpeak > 1.0f)
          {
              panelpart.clip[actualpart] = true;
              if (Vpeak > 1.5f)
                  Vpeak = 1.0f;
          }
  
          // draw the vu lines
          float db = asDecibel(Vpeak);
          db = (MIN_DB - db) / MIN_DB;
          db = (db > 1.0) ? 1.0 : db;
          db = db * ly - 2;
          panelpart.oldpeak[actualpart] = int(db);
          fl_rectf(ox, oy,mid, ly, 0, 0, 0);
          fl_rectf(ox, oy + ly - panelpart.oldpeak[actualpart], mid, panelpart.oldpeak[actualpart], 0, 200, 255);
          if (panelpart.clip[actualpart])
              fl_rectf(ox, oy, mid, 4, 255, 0, 0);
  
          Vpeak = fetchData(0, MAIN::control::readPartPeak, TOPLEVEL::section::main, actualpart, 1);
          if (Vpeak > 1.0)
              panelpart.clipR[actualpart] = true;
          db = asDecibel(Vpeak);
          db = (MIN_DB - db) / MIN_DB;
          db = (db > 1.0) ? 1.0 : db;
          db = db * ly - 2;
          panelpart.oldpeakR[actualpart] = int(db);
          fl_rectf(ox + mid, oy,lx - mid, ly, 0, 0, 0);
          fl_rectf(ox + mid, oy + ly - panelpart.oldpeakR[actualpart], lx - mid, panelpart.oldpeakR[actualpart], 0, 200, 255);
          if (panelpart.clipR[actualpart])
              fl_rectf(ox + mid, oy, lx - mid, 4, 255, 0, 0);
  
          // draw the scales
          float tmp = ly * 1.0 / MIN_DB;
          for (int i = 1; i < 1 - MIN_DB; ++i)
          {
              int ty = ly + int(tmp * i);
              if (i % 5 == 0)
                  fl_rectf(ox, oy + ly - ty, lx, 1, 0, 160, 200);
              if (i % 10 == 0)
                  fl_rectf(ox, oy + ly - ty, lx, 1, 0, 230, 240);
          }
      }
      fl_rectf(x() + mid, oy, 4, ly, 127, 127, 127);
}

void VUMeter::draw() {
  //
      if (npart >= 0)
          draw_part();
      else
          draw_master();
}

void VUMeter::tickdraw(VUMeter *o) {
  o->redraw();
}

void VUMeter::tick(void *v) {
  //
      tickdraw((VUMeter *) v);
      Fl::add_timeout(0.033333333, tick, v); // 1.0 / 30.0 => 30 fps
}

int VUMeter::handle(int event) {
  //
      switch(event)
      {
          case FL_SHOW:
              tick(this);
              return 1;
          case FL_HIDE:
              Fl::remove_timeout(tick, this);
              return 1;
          case FL_PUSH:
              if (npart < 0)
              {
                  maxdbl = NO_DB;
                  maxdbr = NO_DB;
                  clipped = 0;
                 	MasterUI *masterUI = synth->getGuiMaster(false);
                 	if (masterUI)
                      masterUI->resetPartsClip();
              }
              return 1;
      }
      return 0;
}

void VUMeter::resetPart(bool clipOnly ) {
  //
      for (int i = 0; i < NUM_MIDI_PARTS; i++)
      {
          panelpart.clip[i] = false;
          panelpart.clipR[i] = false;
          if (!clipOnly)
          {
              panelpart.oldpeak[i] = 0;
              panelpart.oldpeakR[i] = 0;
          }
      }
}

SysEffSend::SysEffSend(int x,int y, int w, int h, const char *label):WidgetPDial(x,y,w,h,label) {
  neff1=0; neff2=0;
}

void SysEffSend::init(int neff1_, int neff2_, SynthEngine *_synth) {
  //
          synth = _synth;
          neff1 = neff1_;
          neff2 = neff2_;
          minimum(0);
          maximum(127);
          step(1);
          labelfont(0);
          labelsize(11);
          align(FL_ALIGN_TOP);
          value(synth->Psysefxsend[neff1][neff2]);
          copy_label((asString(neff1 + 1) + "->" + asString(neff2 + 1)).c_str());
}

SysEffSend::~SysEffSend() {
  hide();
}

int SysEffSend::handle(int event) {
  //
      if (event == FL_PUSH || event == FL_DRAG || event == FL_MOUSEWHEEL)
          collect_data(synth, value(), 0, (TOPLEVEL::type::Write | TOPLEVEL::type::Integer), neff2, TOPLEVEL::section::systemEffects, UNUSED, neff1, TOPLEVEL::insert::systemEffectSend);
      return WidgetPDial::handle(event);
}

void Panellistitem::cb__i(Fl_Button*, void*) {
  //
                      for (int i = 0; i < NUM_MIDI_PARTS; i += NUM_MIDI_CHANNELS)
                      {
                        partVUMeter->panelpart.clip[npart + i] = false;
                        partVUMeter->panelpart.clipR[npart + i] = false;
                      };
}
void Panellistitem::cb_(Fl_Button* o, void* v) {
  ((Panellistitem*)(o->parent()->parent()->parent()->user_data()))->cb__i(o,v);
}

void Panellistitem::cb_partEdit_i(Fl_Button*, void*) {
  //
              int newpart = npart | synth->getGuiMaster()->panelgroup;
              synth->getGuiMaster()->activePart = npart + *plgroup;
              if (Fl::event() == FL_RELEASE && Fl::event_button() == FL_RIGHT_MOUSE)
                  synth->getGuiMaster()->partui->Showedit();

              if ((int)bankui->cbwig->value() != (newpart + 1))
              {
                  bankui->cbwig->value(newpart + 1);
                  bankui->cbwig->do_callback();
              };
}
void Panellistitem::cb_partEdit(Fl_Button* o, void* v) {
  ((Panellistitem*)(o->parent()->parent()->user_data()))->cb_partEdit_i(o,v);
}

void Panellistitem::cb_buttontop_i(Fl_Button*, void*) {
  //
    synth->getGuiMaster()->activePart = npart + *plgroup;
    bankui->cbwig->value(npart + 1 + *plgroup);
    bankui->cbwig->do_callback();
    bankui->Show();
}
void Panellistitem::cb_buttontop(Fl_Button* o, void* v) {
  ((Panellistitem*)(o->parent()->parent()->user_data()))->cb_buttontop_i(o,v);
}

void Panellistitem::cb_partvolume_i(mwheel_slider* o, void*) {
  //
    int realvalue;
    if (Fl::event_button() == 3)
    {
        realvalue = 96;
        o->value(realvalue);
        o->redraw();
    }
    else
        realvalue = o->value();
    synth->getGuiMaster()->partVol->value(realvalue);
    send_data(0, PART::control::volume, realvalue, TOPLEVEL::type::Integer);
}
void Panellistitem::cb_partvolume(mwheel_slider* o, void* v) {
  ((Panellistitem*)(o->parent()->parent()->user_data()))->cb_partvolume_i(o,v);
}

void Panellistitem::cb_partpanning_i(WidgetPDial* o, void*) {
  //
    int realvalue =  o->value();
    if (Fl::event_button() == 3)
       realvalue = 64;

    synth->getGuiMaster()->partPan->value(realvalue);
    send_data(0, PART::control::panning, realvalue, TOPLEVEL::type::Integer);
}
void Panellistitem::cb_partpanning(WidgetPDial* o, void* v) {
  ((Panellistitem*)(o->parent()->parent()->user_data()))->cb_partpanning_i(o,v);
}

void Panellistitem::cb_partrcv_i(Fl_Choice* o, void*) {
  //
      int tmp = o->value() & 0xf;
      o->textcolor(FL_BLACK);

      send_data(TOPLEVEL::action::forceUpdate, PART::control::midiChannel, tmp, TOPLEVEL::type::Integer);
}
void Panellistitem::cb_partrcv(Fl_Choice* o, void* v) {
  ((Panellistitem*)(o->parent()->parent()->user_data()))->cb_partrcv_i(o,v);
}

void Panellistitem::cb_audiosend_i(Fl_Choice* o, void*) {
  //
    send_data(TOPLEVEL::action::muteAndLoop, PART::control::audioDestination, o->value() + 1, TOPLEVEL::type::Integer);
}
void Panellistitem::cb_audiosend(Fl_Choice* o, void* v) {
  ((Panellistitem*)(o->parent()->parent()->user_data()))->cb_audiosend_i(o,v);
}

void Panellistitem::cb_partenabled_i(Fl_Check_Button2* o, void*) {
  //
        if (_SYS_::F2B(o->value()))
            synth->getGuiMaster()->activePart = npart + *plgroup;
        else
            synth->getGuiMaster()->activePart = UNUSED;
    send_data(TOPLEVEL::action::forceUpdate, PART::control::enable, o->value(), TOPLEVEL::type::Integer);
}
void Panellistitem::cb_partenabled(Fl_Check_Button2* o, void* v) {
  ((Panellistitem*)(o->parent()->user_data()))->cb_partenabled_i(o,v);
}

Fl_Group* Panellistitem::make_window() {
  { panellistitem = new Fl_Group(0, 0, 65, 270);
    panellistitem->box(FL_FLAT_BOX);
    panellistitem->color(FL_BACKGROUND_COLOR);
    panellistitem->selection_color(FL_BACKGROUND_COLOR);
    panellistitem->labeltype(FL_NO_LABEL);
    panellistitem->labelfont(0);
    panellistitem->labelsize(14);
    panellistitem->labelcolor(FL_FOREGROUND_COLOR);
    panellistitem->user_data((void*)(this));
    panellistitem->align(Fl_Align(FL_ALIGN_TOP));
    panellistitem->when(FL_WHEN_RELEASE);
    { Fl_Group* o = panellistitemgroup = new Fl_Group(0, -5, 65, 279);
      panellistitemgroup->box(FL_PLASTIC_THIN_UP_BOX);
      { Fl_Group* o = new Fl_Group(30, 64, 26, 112);
        o->box(FL_ENGRAVED_FRAME);
        { partVUMeter = new VUMeter(30, 65, 26, 110, "V U");
          partVUMeter->box(FL_FLAT_BOX);
          partVUMeter->color(FL_FOREGROUND_COLOR);
          partVUMeter->selection_color((Fl_Color)75);
          partVUMeter->labeltype(FL_NORMAL_LABEL);
          partVUMeter->labelfont(0);
          partVUMeter->labelsize(14);
          partVUMeter->labelcolor((Fl_Color)55);
          partVUMeter->align(Fl_Align(FL_ALIGN_WRAP));
          partVUMeter->when(FL_WHEN_RELEASE);
          partVUMeter->init(npart, synth);
        } // VUMeter* partVUMeter
        { Fl_Button* o = new Fl_Button(30, 64, 26, 111);
          o->tooltip("Click here to clear overload warning.");
          o->box(FL_NO_BOX);
          o->callback((Fl_Callback*)cb_);
        } // Fl_Button* o
        o->end();
      } // Fl_Group* o
      { partEdit = new Fl_Button(12, 248, 40, 20, "Edit");
        partEdit->tooltip("Left mouse button: Part select\nRight mouse button: Instrument edit");
        partEdit->box(FL_PLASTIC_UP_BOX);
        partEdit->labelfont(9);
        partEdit->labelsize(10);
        partEdit->callback((Fl_Callback*)cb_partEdit);
      } // Fl_Button* partEdit
      { partadd = new Fl_Box(5, 20, 17, 40);
        partadd->box(FL_FLAT_BOX);
      } // Fl_Box* partadd
      { partsub = new Fl_Box(22, 20, 18, 40);
        partsub->box(FL_FLAT_BOX);
      } // Fl_Box* partsub
      { partpad = new Fl_Box(40, 20, 17, 40);
        partpad->box(FL_FLAT_BOX);
      } // Fl_Box* partpad
      { partname = new Fl_Button(4, 20, 55, 40, "  ");
        partname->box(FL_THIN_DOWN_FRAME);
        partname->labelsize(10);
        partname->align(Fl_Align(192|FL_ALIGN_INSIDE));
      } // Fl_Button* partname
      { buttontop = new Fl_Button(4, 20, 55, 40, "  ");
        buttontop->box(FL_THIN_DOWN_FRAME);
        buttontop->labeltype(FL_NO_LABEL);
        buttontop->labelfont(9);
        buttontop->labelsize(10);
        buttontop->callback((Fl_Callback*)cb_buttontop);
        buttontop->align(Fl_Align(192|FL_ALIGN_INSIDE));
      } // Fl_Button* buttontop
      { mwheel_slider* o = partvolume = new mwheel_slider(9, 65, 20, 110);
        partvolume->type(4);
        partvolume->box(FL_THIN_DOWN_BOX);
        partvolume->color(FL_BACKGROUND_COLOR);
        partvolume->selection_color(FL_BACKGROUND_COLOR);
        partvolume->labeltype(FL_NORMAL_LABEL);
        partvolume->labelfont(0);
        partvolume->labelsize(14);
        partvolume->labelcolor(FL_FOREGROUND_COLOR);
        partvolume->minimum(127);
        partvolume->maximum(0);
        partvolume->step(1);
        partvolume->callback((Fl_Callback*)cb_partvolume);
        partvolume->align(Fl_Align(FL_ALIGN_BOTTOM));
        partvolume->when(FL_WHEN_CHANGED);
        o->value(synth->part[npart + *plgroup]->Pvolume);
        o->setValueType(VC_PartVolume); o->useCustomTip(true);
      } // mwheel_slider* partvolume
      { WidgetPDial* o = partpanning = new WidgetPDial(17, 180, 30, 30);
        partpanning->box(FL_OVAL_BOX);
        partpanning->color(FL_BACKGROUND_COLOR);
        partpanning->selection_color(FL_INACTIVE_COLOR);
        partpanning->labeltype(FL_NORMAL_LABEL);
        partpanning->labelfont(0);
        partpanning->labelsize(14);
        partpanning->labelcolor(FL_FOREGROUND_COLOR);
        partpanning->maximum(127);
        partpanning->step(1);
        partpanning->callback((Fl_Callback*)cb_partpanning);
        partpanning->align(Fl_Align(FL_ALIGN_BOTTOM));
        partpanning->when(FL_WHEN_CHANGED);
        o->value(synth->part[npart + *plgroup]->Ppanning);
        o->setValueType(VC_PanningStd);
      } // WidgetPDial* partpanning
      { Fl_Choice* o = partrcv = new Fl_Choice(8, 210, 50, 15);
        partrcv->tooltip("receive from MIDI channel");
        partrcv->down_box(FL_BORDER_BOX);
        partrcv->labelsize(10);
        partrcv->textfont(9);
        partrcv->textsize(10);
        partrcv->callback((Fl_Callback*)cb_partrcv);
        partrcv->align(Fl_Align(FL_ALIGN_TOP_LEFT));
        for (int i = 0; i < NUM_MIDI_CHANNELS; i++)
            {
                if (i == 9)
                    o->add("Dr10");
                else
                    o->add(string("Ch" + asString(i + 1)).c_str());
            }
        o->value(synth->part[npart + *plgroup]->Prcvchn);
      } // Fl_Choice* partrcv
      { Fl_Choice* o = audiosend = new Fl_Choice(8, 229, 50, 15);
        audiosend->tooltip("Set Audio Destination");
        audiosend->box(FL_BORDER_BOX);
        audiosend->down_box(FL_BORDER_BOX);
        audiosend->labelsize(9);
        audiosend->textfont(9);
        audiosend->textsize(9);
        audiosend->callback((Fl_Callback*)cb_audiosend);
        o->add("Main");o->add("Part");o->add("Both");
        if (synth->part[npart + *plgroup]->Paudiodest == 2) o->value(1); else if (synth->part[npart + *plgroup]->Paudiodest == 3) o->value(2); else o->value(0);
      } // Fl_Choice* audiosend
      if (!synth->partonoffRead(npart + *plgroup)) o->deactivate();
      if (synth->getRuntime().audioEngine != jack_audio && synth->getLV2PluginType() != LV2PluginTypeMulti) audiosend->deactivate();
      panellistitemgroup->end();
    } // Fl_Group* panellistitemgroup
    { Fl_Check_Button2* o = partenabled = new Fl_Check_Button2(10, 0, 45, 20, "01");
      partenabled->box(FL_NO_BOX);
      partenabled->down_box(FL_DOWN_BOX);
      partenabled->color(FL_BACKGROUND_COLOR);
      partenabled->selection_color(FL_FOREGROUND_COLOR);
      partenabled->labeltype(FL_EMBOSSED_LABEL);
      partenabled->labelfont(0);
      partenabled->labelsize(15);
      partenabled->labelcolor(FL_FOREGROUND_COLOR);
      partenabled->callback((Fl_Callback*)cb_partenabled);
      partenabled->align(Fl_Align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE));
      partenabled->when(FL_WHEN_RELEASE);
      o->value(synth->partonoffRead(npart + *plgroup));
    } // Fl_Check_Button2* partenabled
    panellistitem->end();
  } // Fl_Group* panellistitem
  return panellistitem;
}

void Panellistitem::send_data(int action, int control, float value, int type, int parameter ) {
  //
          type |= TOPLEVEL::type::Write;
          collect_data(synth, value, action, type, control, npart + *plgroup, UNUSED, UNUSED, UNUSED, parameter);
}

Panellistitem::Panellistitem(int x,int y, int w, int h, const char *label):Fl_Group(x,y,w,h,label) {
  //
      npart = 0;
      bankui = NULL;
}

void Panellistitem::init(int npart_, BankUI *bankui_, SynthEngine *_synth) {
  //
      synth = _synth;
      npart=npart_;
      bankui = bankui_;
      plgroup = &synth->getGuiMaster()->panelgroup;
      make_window();
      panellistitem->show();
      end();
}

void Panellistitem::refresh() {
  //
  
      int setpart = npart | *plgroup; // assumes *plgroup always power of 2
  
      partenabled->value(synth->partonoffRead(setpart));
  
      setPartLabel(setpart);
  
      partvolume->value(synth->part[setpart]->Pvolume);
      partpanning->value(synth->part[setpart]->Ppanning);
      int tmpch = synth->part[setpart]->Prcvchn;
  
      if (tmpch < NUM_MIDI_CHANNELS)
      {
          partrcv->value(tmpch);
          int type = synth->getRuntime().channelSwitchType;
          if (type == MIDI::SoloType::Row || type == MIDI::SoloType::Loop  || type == MIDI::SoloType::TwoWay)
              partrcv->textcolor(FL_BLUE);
          else
              partrcv->textcolor(FL_BLACK);
      }
      else
          partrcv->textcolor(FL_WHITE);
  
      partname->copy_label(synth->part[setpart]->Pname.c_str());
      int tmp = synth->part[setpart]->Paudiodest - 1;
      if (tmp < 0 or tmp > 3)
          tmp = 0;
      audiosend->value(tmp);
      if ((int)bankui->cbwig->value() != (setpart + 1))
          panellistitemgroup->color(fl_rgb_color(160, 160, 160));
      else
          panellistitemgroup->color(fl_rgb_color(50,190,240));
      panellistitemgroup->redraw();
      string num = asString(setpart + 1);
      partenabled->copy_label(num.c_str());
  
      if (synth->partonoffRead(setpart))
          panellistitemgroup->activate();
      else
          panellistitemgroup->deactivate();
}

void Panellistitem::setPartLabel(int npart) {
  //
      partadd->damage(1);
      partsub->damage(1);
      partpad->damage(1);
      int engine = findengines(npart);
      if (engine & 1)
          partadd->color(ADD_COLOUR);
      else
          partadd->color(FL_BACKGROUND_COLOR);
      if (engine & 2)
          partsub->color(SUB_COLOUR);
      else
          partsub->color(FL_BACKGROUND_COLOR);
      if (engine & 4)
          partpad->color(PAD_COLOUR);
      else
          partpad->color(FL_BACKGROUND_COLOR);
      if (synth->part[npart | *plgroup]->PyoshiType)
          partname->labelcolor(YOSHI_COLOUR);
      else
          partname->labelcolor(0);
      partname->copy_label(synth->part[npart | *plgroup]->Pname.c_str());
}

unsigned int Panellistitem::findengines(int npart) {
  //
      unsigned int engine = 0;
  
      for (int i = 0; i < NUM_KIT_ITEMS; ++i)
      {
          if (synth->part[npart]->kit[i].Padenabled)
              engine |= 1;
          if (synth->part[npart]->kit[i].Psubenabled)
              engine |= 2;
          if (synth->part[npart]->kit[i].Ppadenabled)
              engine |= 4;
      }
      return engine;
}

Panellistitem::~Panellistitem() {
  panellistitem->hide();
}

void Panellistitem::itemRtext(float dScale) {
  //
      int size = int(10 * dScale);
      int size14 = int(14 * dScale);
  
      partEdit->labelsize(size);
      partname->labelsize(size);
      partvolume->labelsize(size14);
      partpanning->labelsize(size14);
      partrcv->labelsize(size);
         partrcv->textsize(size);
      audiosend->labelsize(size);
          audiosend->textsize(size);
      partenabled->labelsize(int(15 * dScale));
}
