Subversion Repositories DIN Is Noise

Rev

Rev 2310 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
* eval.cc
* DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/


#include "state_button.h"
#include "capturer.h"
#include "binaural_drones.h"
#include "console.h"
#include "din.h"
#include "ui_list.h"
#include "fractaliser.h"
#include "keyboard_keyboard.h"
#include "main.h"
#include "mondrian.h"
#include "oscilloscope.h"
#include "recorder.h"
#include "tcl_interp.h"
#include "authors_note.h"

state_button* capturer_t::add () {
#ifdef __EVALUATION__
  if (ncaps == 1) {
    cons << RED << "Can add more mouse captures in the Licensed Version of DIN Is Noise" << eol;
    return 0;
  }
#endif
  state_button* sb = new state_button;
  sb->set_pos (sbx, sby);
  sbx += state_button::SIZE2;
  title.add_child (sb);
  caps.push_back (sb);
  ++ncaps;
  return sb;
}

i_binaural_drones::i_binaural_drones () :
  wav ("binaural-drones-waveform.crv"),
  waved ("binaural-drones-waveform.ed"),
  fdrcrv ("fader.crv"),
  hlp ("binaural-drones.hlp")
{

#ifdef __EVALUATION__
    name = "binaural-drones [Evaluation Version]";
#else
    name = "binaural-drones";
#endif
  wavlis.sb = this;
  waved.add (&wav, &wavlis);
  extern curve_library wav_lib;
  waved.attach_library (&wav_lib);
  prev_mousex = prev_mousey = 0;
  vol_fader.sol (&fdrcrv);
  pitch_fader.sol (&fdrcrv);
  abort = 0;
  inst = 1;
}


din::din (cmdlist& cl) :
wave ("microtonal-keyboard-waveform.crv"),
waved ("microtonal-keyboard-waveform.ed"),
wavlis (wave_listener::MICROTONAL_KEYBOARD),
win (0, 0, view.xmax, view.ymax),
drone_wave ("drone.crv"),
droneed ("drone.ed"),
dronelis (wave_listener::DRONE),
fm ("fm", "fm.crv"),
am ("am", "am.crv"),
moded ("modulation.ed"),
swing ("swing.crv"),
accent ("accent.crv"),
gatr ("gr", "gater.crv"),
gated ("gater.ed"),
gatlib ("gater-patterns.lib"),
helptext ("din.hlp")
{

#ifdef __EVALUATION__
    name = "microtonal-keyboard [Evaluation Version]";
#else
    name = "microtonal-keyboard";
#endif

    prev_mousex = prev_mousey = delta_mousex = delta_mousey = 0;
    win_mousex = win_mousey = prev_win_mousex = prev_win_mousey = 0;
    tonex = toney = 0;

    current_range = 0;

    adding = 0;

    wanding = 0;

    moving_drones = 0;

    rising = falling = 0;

    n_dvap = 0;
    dvap = 0;
    dcol = 0;

    dap = 0;
    n_dap = 0;

    num_drones = 0;

    create_drone_pend = 0;

    static const int cap = 1024;
    selected_drones.reserve (cap);

    scaleinfo.scl = this;

    fdr_gater_prev_amount = 0;

    rvec.reserve (cap);
    svec.reserve (cap);
    xforming = NONE;

    num_selected_drones = num_browsed_drones = 0;

    ptr_scaleinfo = &all_notes;

    nstepz = 0;
    con_pts = 0;
    con_clr = 0;
    con_size = 0;
    totcon = 0;
    _2totcon = 0;
    ec = 0;

    inst = 1;

    dinfo.cen.lis = this;

}

void din::chuck () {
  if (num_selected_drones > 1) {
#ifdef __EVALUATION__
    if (num_selected_drones > 3) {
      cons << RED << "Chuck with more than 3 drones possible in the Licensed Version of DIN Is Noise" << eol;
      return;
    }
#endif
    int yes = 1;
    drone* sun = selected_drones[0];
    sun->chuck.set (yes, 0);
    drone* planet = 0;
    for (int i = 1; i < num_selected_drones; ++i) {
      sun->trail.set (0);
      planet = selected_drones[i];
      planet->chuck.set (yes, sun);
      sun->chuck.sat = planet;
      planet->chuck.sat = 0;
      planet->chuck.calc (planet);
      sun = planet;
    }
    planet->trail.set (10000);
    cons << GREEN << "Chucked " << num_selected_drones << " drones" << eol;
  } else {
    cons << RED_A2D << eol;
  }
}

void din::create_drone_pendulum () {

#ifdef __EVALUATION__
  cons << RED << "Can create drone pendulums only in the Licensed Version of DIN Is Noise" << eol;
  return;
#endif

  int o = dinfo.drone_pend.orient;
  int no = !o;
  double along[] = {rgn.width, rgn.height};
  int num_drones = dinfo.drone_pend.n;

  CLEAR_SELECTED_DRONES

  double xl [] = {double(rgn.left), double(rgn.midx)};
  double yl [] = {double((rgn.bottom + rgn.top) / 2.0), double(rgn.bottom)};
  double x = xl [o], y = yl [o];
  double* xy [] = {&x, &y};
  double& xyo = *xy[o];
  double depths [] = {double(rgn.top - rgn.midy), double(rgn.right - rgn.midx)};
  double depth = depths[o];

  int nd1 = num_drones - 1;
  double spacing = along[o] * 1.0 / nd1;
  double _1bylast = 1.0 / nd1;
  double a = 0.0f, da = _1bylast;
  float obpm = 0.0f;
  for (int i = 0; i < num_drones; ++i) {
    get_color::data.p = i * _1bylast;
    drone* pd = add_drone (x, y);
    drone& d = *pd;
    if (!dinfo.seloncre) {
      d.sel = 1;
      selected_drones.push_back (pd);
    }
    d.mod.active = 1;
    mod_params* mods [] = {&d.mod.am, &d.mod.fm};
    mod_params& mod = *mods[o];
    mod.depth = warp_depth (a) * depth;
    obpm = warp_bpm (a) * dinfo.drone_pend.bpm;
    mod.bv.set_bpm (obpm);
    mods[no]->bv.set_bpm (obpm);
    a += da;
    xyo += spacing;
  }

  if (!dinfo.seloncre) print_selected_drones ();

  drone_pendulum_group* grp = new drone_pendulum_group (o, depth, selected_drones, num_selected_drones);
  drone_pendulums.push_back (grp);

  uis.dpeu.bpm.set_value (dinfo.drone_pend.bpm);
  uis.dpeu.depth.set_value (depth);

  cons << GREEN << "Created a drone pendulum of " << num_drones << " drones." << eol;

}

void din::create_drone_mesh () {
  mkb_selector.mesh = 0;
#ifdef __EVALUATION__
  if (mkb_selector.rowcol > 4) {
    cons << RED << "Can only create a 2 x 2 drone mesh with the Evaluation Version oF DIN Is Noise" << eol;
    return;
  }
#endif
  mkb_selector.orderer = mkb_selector.orderers [dinfo.mesh_vars.order];
  mkb_selector.order_order ();
  amd.triggert = dinfo.mesh_vars.duration * 1.0f / mkb_selector.rowcol;
  amd.i = 0;
  amd.j = mkb_selector.cols;

  CLEAR_SELECTED_DRONES
  amd.start ();

}

void din::change_range_note (int i, int d) {
#ifdef __EVALUATION__
  cons << RED << "Change Left/Right Note/Octave is available in the Licensed Version of DIN Is Noise" << eol;
  return;
#endif
  int cn = dinfo.change_note;
  scale_info& si = *ptr_scaleinfo;

  range& sr = ranges [dinfo.sel_range];
  if (cn)
    sr.change_note (i, d, si);
  else
    sr.change_octave (i, d, si);

  int ri, rj;
  ri = rj = dinfo.sel_range;
  if (i) {
    int srr = dinfo.sel_range + 1;
    if (srr < num_ranges) {
      range& rsrr = ranges [srr];
      if (cn)
        rsrr.change_note (0, d, si);
      else
        rsrr.change_octave (0, d, si);
      ri = dinfo.sel_range; rj = srr;
    }
  } else {
    int srl = dinfo.sel_range - 1;
    if (srl > -1) {
      range& rsrl = ranges [srl];
      if (cn)
        rsrl.change_note (1, d, si);
      else
        rsrl.change_octave (1, d, si);
      ri = srl; rj = dinfo.sel_range;
    }
  }

  if (ri == rj)
    refresh_drones (ri);
  else
    refresh_drones (ri, rj);

  note& L = sr.notes[0];
  note& R = sr.notes[1];
  sprintf (BUFFER, "Left Note = %s @ %0.3f Hz, Right Note = %s @ %0.3f Hz, Hz/pixel = %0.3f", L.name.c_str(), L.hz, R.name.c_str(), R.hz, sr.hz_per_pix ());
  cons << YELLOW << BUFFER << eol;

}

int din::connect_drones () {

  if (num_selected_drones < 2) {
    cons << RED_A2D << eol;
    return 0;
  }

#ifdef __EVALUATION__
  #define MAX_CONN 4
  if (num_selected_drones > MAX_CONN) {
    cons << RED << "Can only connect upto " << MAX_CONN << " drones in the Evaluation Version of DIN Is Noise" << eol;
    return 0;
  }
#endif

  if (nstepz == 0) {
    cons << RED << "Bad Steps value, please check Menu > Drone Tools > Steps" << eol;
    return 0;
  }

  for (int s = 0; s < nstepz; ++s) {
    int ds = stepz[s];
    for (int i = 0, j = 0; i < num_selected_drones; ++i) {
      j = i + ds;
      if (MENU.cb_conn_wrap.state) j %= num_selected_drones;
      if (j < num_selected_drones) {
        drone* pdi = selected_drones[i];
        drone& di = *pdi;
        drone* pdj = selected_drones[j];
        drone& dj = *pdj;
        if (can_connect (pdi, pdj)) {
          double m = magnitude (pdi->cx, pdi->cy, pdj->cx, pdj->cy);
          di.connections.push_back (pdj);
          dj.connections.push_back (pdi);
          di.mags.push_back (m);
          dj.mags.push_back (m);
          ++di.nconn;
          ++dj.nconn;
          totcon += 2;
        }
      }
    }
  }

  _2totcon = 2 * totcon;
  alloc_conns ();

  if (MENU.trackcon.state) {
    int last = num_selected_drones - 1;
    drone* pld = selected_drones [last];
    drone *pdi = 0, *pdj = 0;
    for (int i = 0, j = 1; i < last; ++i, ++j) {
      pdi = selected_drones [i];
      pdj = selected_drones [j];
      push_back (trackers, pdi);
      pdi->tracking = drone::POINT;
      pdi->tracked_drone = pdj;
    }
    pld->tracking = drone::USE;
    pld->tracked_drone = pdi;
    push_back (trackers, pld);
  }

  return 1;

}

int plugin::apply (multi_curve& crv) {

#ifdef __EVALUATION__
  cons << RED << "Can apply plugins only in the Licensed Version of DIN Is Noise" << eol;
  return 0;
#endif

  int n = points.size ();
  if (n == 0) return 0;

  crv.clear (0);

  for (int i = 0; i < n; ++i) {
    point<float>& p = points[i];
    crv.add_vertex (p.x, p.y);
    crv.add_left_tangent (p.x, p.y);
    crv.add_right_tangent (p.x, p.y);
  }

  if (shapeform)
    crv.set_shapeform (1);
  else
    crv.evaluate ();

  CRVED->set_curve_style (&crv);

  return 1;

}

int fractaliser::apply (multi_curve& crv) { // needed bcos of tangents
#ifdef __EVALUATION__
  cons << RED << "Can apply plugins only in the Licensed Version of DIN Is Noise" << eol;
  return 0;
#endif
  render ();
  int npts = points.size ();
  if (npts == 0) return 0;
  crv.clear (0);
  // if (change_curve_name) crv.set_name (ss.str());

  typedef std::list< point<float> >::iterator points_list_iterator;
  points_list_iterator lti = left_tangents.begin (), rti = right_tangents.begin ();
  for (int i = 0; i < npts; ++i) {
    point<float>& p = points[i];
    point<float>& lt = *lti++;
    point<float>& rt = *rti++;
    crv.add_vertex (p.x, p.y);
    crv.add_left_tangent (lt.x, lt.y);
    crv.add_right_tangent (rt.x, rt.y);
  }
  crv.set_shapeform (shapeform);
  crv.evaluate ();
  return 1;
}

keyboard_keyboard::keyboard_keyboard () :
  wave ("keyboard-keyboard-waveform.crv"),
  waved ("keyboard-keyboard-waveform.ed"),
  wavlis (wave_listener::KEYBOARD_KEYBOARD),
  attackcrv ("attack.crv"), decaycrv ("decay.crv"),
  attacked ("attack.ed"), decayed ("decay.ed"),
  helptext ("keyboard-keyboard.hlp"), velcrv ("velocity.crv"),
  veled ("velocity.ed"), vellib ("velocity.lib")
{

#ifdef __EVALUATION__
    name = "keyboard-keyboard [Evaluation Version]";
#else
    name = "keyboard-keyboard";
#endif
  last_mousex = last_mousey = -1;
  num_triggered_notes = 0;
  scaleinfo.scl = this;
  show_nearby_notes = 0;

  fname = "keyboard-keyboard.settings";
  ifstream file ((user_data_dir + fname).c_str (), ios::in);
  if (!file) {
    dlog << "!!! couldnt load: " << fname << endl;
  } else {
    string ignore;
    file >> ignore >> show_nearby_notes;
    file >> ignore >> ATTACK_TIME;
    file >> ignore >> DECAY_TIME;
    file >> ignore >> NOTE_VOLUME;
    file >> ignore >> PITCH_BEND;
    file >> ignore >> trig_what;
    PITCH_BEND_PER_PIXEL = 0.01f * PITCH_BEND;
  }

  inst = 1;

}


extern const char* INSTRUMENTS [];
extern const char* INSTRUMENTS_SHORT [];
extern const int NUM_INSTRUMENTS, LAST_INSTRUMENT;
extern int CURRENT_INSTRUMENT;
extern string INSTRUMENT;
extern instrument* INSTRUMENT_PTR [];
extern checkbutton* LAST_TABS [];
extern oscilloscope scope;

void load_instrument (instrument* inst) {

  if (inst == 0) inst = get_current_instrument ();

  MENU.b_microtonal_keyboard.turn_off (DONT_CALL_LISTENER);
  MENU.b_keyboard_keyboard.turn_off (DONT_CALL_LISTENER);
  MENU.b_mondrian.turn_off (DONT_CALL_LISTENER);
  MENU.b_binaural_drones.turn_off (DONT_CALL_LISTENER);

  if (inst == &keybd2) {
    MENU.b_keyboard_keyboard.turn_on ();
    MENU.next_tab = MENUP.cb_instrument;
    CURRENT_INSTRUMENT = 0;
  } else if (inst == &din0) {
    CURRENT_INSTRUMENT = 1;
    MENU.b_microtonal_keyboard.turn_on ();
    checkbutton* pcb = LAST_TABS [CURRENT_INSTRUMENT];
    if (pcb) {
      MENU.next_tab = pcb;
    } else {
      if (din0.num_selected_drones)
        MENU.next_tab = MENUP.cb_mkb_drone_params;
      else
        MENU.next_tab = MENUP.cb_mkb_voice;
    }
  } else if (inst == &mondrian0) {
    CURRENT_INSTRUMENT = 2;
    MENU.b_mondrian.turn_on ();
    MENU.cb_instrument.turn_on ();
    checkbutton* pcb = LAST_TABS [CURRENT_INSTRUMENT];
    if (pcb) MENU.next_tab = pcb; else MENU.next_tab = MENUP.cb_mon_tools;
  } else /*if (inst == &binaural_drones0)*/ {
    CURRENT_INSTRUMENT = 3;
    MENU.b_binaural_drones.turn_on ();
    MENU.cb_instrument.turn_on ();
    checkbutton* pcb = LAST_TABS [CURRENT_INSTRUMENT];
    if (pcb) MENU.next_tab = pcb; else MENU.next_tab = MENUP.cb_binaural_drones_tools;
  }

  scope.load_current_instrument ();
  MENU.scol.setup ();

  MENU.next_tab_instr = inst;
  uis.set_current (inst);

  MENU.hide_editors ();
  MENU.show_editors (inst);

#ifdef __EVALUATION__
  if (dynamic_cast<ui*>(inst) != &anote)
#endif

  MENU.setup_tabs (inst);

  setup_plugin_labels ();
  cons ("setup-editors");
  uis.update_bottom_line ();

}

extern string VERSION_NUMBER;
extern string APP_NAME;

void make_app_name () {
  #ifdef __EVALUATION__
    APP_NAME = "DIN Is Noise " + VERSION_NUMBER + " | EVALUATION VERSION";
  #elif defined __LICENSED__
    APP_NAME = "DIN Is Noise " + VERSION_NUMBER + " | LICENSED VERSION";
  #endif
}

void range_mod_lis::clicked (button& b) {
  if (&b == MENUP.b_rm_start_all) {
#ifdef __EVALUATION__
    cons << RED << "Range modulation available only on the Licensed Version of DIN Is Noise" << eol;
    return;
#endif
    din0.set_ran_mod (1);
  } else if (&b == MENUP.b_rm_stop_all) {
    din0.set_ran_mod (0);
  } else if (&b == MENUP.b_rm_toggle) {
#ifdef __EVALUATION__
    cons << RED << "Range modulation available only on the Licensed Version of DIN Is Noise" << eol;
    return;
#endif
    din0.toggle_ran_mod ();
  } else if (&b == MENUP.b_rm_pause_resume) {
#ifdef __EVALUATION__
    cons << RED << "Range modulation available only on the Licensed Version of DIN Is Noise" << eol;
    return;
#endif
    din0.pause_resume_ran_mod ();
  } else {
    din0.dinfo.sel_range = din0.current_range;
    MENU.load_range (din0.dinfo.sel_range);
  }
}

void range_mod_lis::changed (checkbutton& cb) {

  if (&cb == MENUP.cb_mod_ran) {
#ifdef __EVALUATION__
    cons << RED << "Range modulation available only on the Licensed Version of DIN Is Noise" << eol;
    cb.set_state (!cb.state, 0);
    return;
#endif
    modulator& srm = din0.ranges[din0.dinfo.sel_range].mod;
    int& a = srm.active;
    if (a) a *= cb.state; else a = cb.state;
  } else
    din0.dinfo.mark_sel_range = cb.state;
}

void recording_listener::clicked (button& b) {
  if (&b == MENUP.b_clear_record) {
    recorder0.clear ();
    uis.cb_record.set_text ("Record");
    MENU.cb_record.set_text ("Record");
    if (MENU.show) MENU.toggle ();
  } else {
#ifdef __EVALUATION__
    cons << RED << "Can save recordings only in the Licensed Version of DIN Is Noise" << eol;
    return;
#endif
    recorder0.start_saving ();
  }
}


void binaural_drones_listener::clicked (button& b) {

  if (&b == MENUP.bbd_select_all) {
    MENU.il_binaural_drones.select (1); // 1 == all
  } else if (&b == MENUP.bbd_select_none) {
    MENU.il_binaural_drones.select (0); // 0 == none
    //MENU.il_binaural_drones.last = 0;
  } else if (&b == MENUP.bbd_invert_select) {
    MENU.il_binaural_drones.invert_select ();
    //if (MENU.il_binaural_drones.num_selected() == 0) MENU.il_binaural_drones.last = 0;
  } else if (&b == MENUP.bbd_select2) {
    if (select_rule == ID) {
      tokenizer tv (MENU.bdf_value.text);
      int s, e, i; tv >> s >> e >> i;
      --s; --e;  // bcos starts at 1 on ui :(
      clamp (0, s, MENU.il_binaural_drones.n);
      clamp (0, e, MENU.il_binaural_drones.n);
      clamp (1, i, MENU.il_binaural_drones.n);
      sprintf (BUFFER, "wrap-get-nums %d %d %d", s, e, i);
    } else {
      const char* get [] = {"left", "right", "separation", "volume"};
      const char* op [] = {"==", ">=", "<=", "<>"};
      sprintf (BUFFER, "filter-binaurals %s %s %s", get[select_what], op[select_rule], MENU.bdf_value.text.c_str());
    }
    interpreter (BUFFER);
    tokenizer tz (interpreter.result);
    if (!MENU.il_binaural_drones.select_these (tz)) cons << RED << "No matching binaural drone pairs found!" << eol;
  }

  if (binaural_drones0.busy ()) {
    cons << RED << "Still executing your command, please wait or ESC to abort" << YELLOW << eol;
    return;
  }

  binaural_drones0.separation = MENU.sp_bd_separation.value;
  binaural_drones0.master_volume = (float) MENU.lf_master_volume.fld / 100.0f;
  binaural_drones0.pairs = MENU.sp_bd_pairs.value;
  binaural_drones0.close_octave = MENU.cb_close_octave.state;
  binaural_drones0.resize_separation = MENU.cb_resize_separation.state;

  const char* selerr = "Please select some binaural drone pairs";
  if (&b == MENUP.b_create_binaurals_on_notes) {

#ifdef __EVALUATION__
  cons << RED << "Available only in the Licensed Version of DIN Is Noise" << eol;
  return;
#endif

    cons << YELLOW << "Creating binaural drones [fading in], please wait" << eol;
    float tonic;
    if (binaural_drones0.keynote == i_binaural_drones::START_PITCH)
      tonic = binaural_drones0.starting_pitch;
    else
      tonic = get_tonic (&binaural_drones0);
    string intervals;
    vector<string>& notes = binaural_drones0.scaleinfo.notes;
    int j = notes.size (); if (binaural_drones0.close_octave == 0) --j;
    for (int i = 0; i < j; ++i) intervals = intervals + notes[i] + " ";
    stringstream cmd;
    cmd << "create-binaurals-on-notes " << tonic << ' ' << binaural_drones0.separation << " {" << intervals << "}" << ' ' << binaural_drones0.resize_separation;
    interpreter (cmd.str());
    MENU.changed (MENU.cb_binaural_drones_edit);
  } else if (&b == MENUP.b_create_binaurals_from_pitch) {

#ifdef __EVALUATION__
  if (binaural_drones0.num_binaural_drones || binaural_drones0.pairs > 1) {
    cons << RED << "Can create > 1 binaural drone pair in the Licensed Version of DIN Is Noise" << eol;
    return;
  }
#endif

    cons << YELLOW << "Creating binaural drones [fading in], please wait" << eol;
    string start_pitch = MENU.lf_bd_start_pitch.fld.text;
    string spacing = MENU.lf_bd_spacing.fld.text;
    sprintf (BUFFER, "create-binaurals-from-pitch %f %f %d %f", binaural_drones0.starting_pitch, binaural_drones0.separation, binaural_drones0.pairs, binaural_drones0.spacing);
    interpreter (BUFFER);
    MENU.changed (MENU.cb_binaural_drones_edit);
  } else if (&b == MENUP.bbd_sync) {
    if (MENU.il_binaural_drones.num_selected ()) {
      cons << YELLOW << "Syncing (fade-out + sync + fade-in) : please wait or ESC to abort" << eol;
      interpreter ("sync-selected-binaurals");
    } else {
      cons << RED << selerr << eol;
    }
  } else if (&b == MENUP.bbd_delete) {
    if (MENU.il_binaural_drones.num_selected ()) {
      cons << YELLOW << "Deleting (after fade-out) : please wait or ESC to abort" << eol;
      interpreter ("delete-selected-binaurals");
    } else {
      cons << RED << selerr << eol;
    }
  } else if (&b == MENUP.bd_modulate_up) {
    if (MENU.il_binaural_drones.num_selected ()) {
      cons << YELLOW << "Modulating up: please wait or ESC to abort" << eol;
      sprintf (BUFFER, "modulate-selected-binaurals %f", binaural_drones0.modulation_amount);
      interpreter (BUFFER);
    } else {
      cons << RED << selerr << eol;
    }
  } else if (&b == MENUP.bd_modulate_down) {
    if (MENU.il_binaural_drones.num_selected ()) {
      cons << YELLOW << "Modulating down: please wait or ESC to abort" << eol;
      sprintf (BUFFER, "modulate-selected-binaurals %f", 1.0f / binaural_drones0.modulation_amount);
      interpreter (BUFFER);
    } else {
      cons << RED << selerr << eol;
    }
  } else if (&b == MENUP.bbd_flip) {
    if (MENU.il_binaural_drones.num_selected ()) {
      for (int i = 0; i < MENU.il_binaural_drones.n; ++i) {
        if (MENU.il_binaural_drones.items[i].sel) {
          binaural_drone* bi = binaural_drones0.binaural_drones[i];
          float r_hz = bi->l_hz, l_hz = bi->r_hz;
          bi->set_hz (binaural_drone::LEFT, l_hz);
          bi->set_hz (binaural_drone::RIGHT, r_hz);
        }
      }
      binaural_drones0.pitch_fader.start ("Pitch flip");
      cons << YELLOW << "Flipping Hz: please wait or ESC to abort" << eol;
      interpreter ("flip-selected-binaurals");
    } else {
      cons << RED << selerr << eol;
    }
  }
}


void mondrian::load_settings  (ifstream& file) {

  std::string ignore;

#ifdef __EVALUATION__
    name = "Mondrian [Evaluation Version]";
#else
    name = "Mondrian";
#endif

  float l, b, r,  t;
  file >> ignore >> l >> b >> r >> t;
  win.set (l, b, r, t);

  file >> ignore >> win_chunk.x >> win_chunk.y;
  file >> ignore >> obj_chunk.x >> obj_chunk.y;

  win_per_obj (win_chunk.x / obj_chunk.x, win_chunk.y / obj_chunk.y);
  obj_per_win (obj_chunk.x / win_chunk.x , obj_chunk.y / win_chunk.y);

  file >> ignore >> win_resolution;

  /*float dummy1 = 0, dummy2 = 0;
  win2obj (win_resolution, dummy1, obj_resolution, dummy2);*/


  file >> ignore >> label_hz_vol;
  file >> ignore >> min_voices;
  file >> ignore >> auto_del_rect.active;
  file >> ignore >> auto_del_rect.triggert;
  file >> ignore >> auto_split_rect.active;
  file >> ignore >> auto_split_rect.triggert;
  file >> ignore >> auto_split_orient;
  file >> ignore >> auto_split_at;
  file >> ignore >> split_leaf;
  file >> ignore >> delete_leaf;
  file >> ignore >> mondrian::min_split_size;
  file >> ignore >> draw__boxes;
  file >> ignore >> draw_ball.position;
  file >> ignore >> draw_ball.heading;
  file >> ignore >> draw__notes;
  file >> ignore >> label_notes;
  file >> ignore >> fill_boxes;
  file >> ignore >> num_boxes;
  file >> ignore >> added_ball_type;
  file >> ignore >> cursor;
  file >> ignore >> auto_adjust_voices;
  file >> ignore >> slit::HALF_SIZE;
  file >> ignore >> MENU.cb_turn_sync.state;
  file >> ignore >> MENU.cb_speed_sync.state;
  file >> ignore >> MENU.texture.state;
  MENU.cb_turn_sync.set_state (MENU.cb_turn_sync.state);
  MENU.cb_speed_sync.set_state (MENU.cb_speed_sync.state);
  MENU.texture.set_state (MENU.texture.state);

}


extern float MIN_TIME;
extern int can_wheel ();
extern int IPS;

int mondrian::handle_input () {

  if (moving_balls) move_balls (win.mousex - win.mousex_prev, win.mousey - win.mousey_prev);
  if (editing_slit) slit_lip.edit (); else
  if (editing_edge) set_edge (hit, edge, win.mousex, win.mousey);

  if (lmb) {
    if (lmb_clicked == 0) {
      if (stop_moving_balls ());
      else if (stop_editing_slit ());
      else if (stop_editing_edge ());
      else if (try_slitting ());
      else {
        finding f; find (root, win.mousex, win.mousey, f);
        hit = f.found;
        if (hit) { // box hit
          box<float>& bf = hit->extents;
          edge = bf.get_edge_hit (win.mousex, win.mousey, gutter2);
          if (edge != edge::NONE) { // edge hit
            // slit hit?
            slit_lip.slitt = 0;
            float* curs [rect::nedges] = {&win.mousex, &win.mousey, &win.mousex, &win.mousey};
            slit_lip.cur = curs[edge];
            if (get_slit_lip (slit_lip, hit, edge, *slit_lip.cur)) { // slit hit!
              float* prevs [rect::nedges] = {&win.mousex_prev, &win.mousey_prev, &win.mousex_prev, &win.mousey_prev};
              slit_lip.prev = prevs[edge];
              toggle_flag (editing_slit, "Just move mouse to edit slit. ESC to stop."); // edit this slit
            } else toggle_flag (editing_edge, "Just move mouse to move edge. ESC or click to stop."); // edit this edge
            mon_selector.abort ();
          }
        }
      }
    }

    if (adding_balls) { // user is adding balls
      if (started_making_ball == 0) {
        started_making_ball = 1;
        new_ball = new ball (added_ball_type);
        new_ball->set_velocity (1.0f, 1.0f);
        mon_selector.abort ();
      } else {
        float dx, dy;
        win.diff_mouse (dx, dy);
        if (dx == 0 && dy == 0); else new_ball->set_velocity (dx, dy);
        new_ball->x = win.mousex;
        new_ball->y = win.mousey;
      }
    }    

    lmb_clicked = 1;

  } else {
    lmb_clicked = 0;
    if (new_ball) {
      new_ball->frozen = 0;
      finding f; find (root, new_ball->x, new_ball->y, f);
#ifdef __EVALUATION__
      if (num_balls) {
        cons << RED << "Can create more balls in the Licensed Version of DIN Is Noise" << eol;
        f.found = 0;
      }
#endif
      if (f.found) {
        new_ball->R = f.found;
        f.found->balls.push_back (new_ball);
        balls.push_back (new_ball);
        browse.clear ();
        clear_selected<ball> (selected_balls, num_selected_balls);
        new_ball->select = 1;
        selected_balls.push_back (new_ball);
        ++num_selected_balls;
        ++num_balls;
        after_selection ();
      } else
        delete new_ball;

      started_making_ball = 0;
      new_ball = 0;
    }
  }

  static const double reptf = 1./7, repts = 1./48.;
  double repts1 = 1./IPS;

  // octave shift
  if (keypressed (SDLK_z)) {if (!modulate_balls (-1)) modulate_down ();}
  else if (keypressed (SDLK_x)) {if (!modulate_balls (1)) modulate_up ();}

  // split box
  if (keypressed (SDLK_r)) { // vertically
    if (recting ()) ; else {
      if (SHIFT)
        multi_split_rect (split::VERTICAL); // vertically at notes
      else if (CTRL)
        multi_split_rect (num_boxes, split::VERTICAL); // vertically make num_boxes
      else
        split_rect (split::VERTICAL, win.mousex); // into 2 new boxes
    }
  }
  else if (keypressed (SDLK_f)) { // horizontally
    if (recting ()) ; else {
      if (SHIFT)
        multi_split_rect (split::HORIZONTAL); // horizontally at notes
      else if (CTRL)
        multi_split_rect (num_boxes, split::HORIZONTAL); // horizontally make num_boxes
      else
        split_rect (split::HORIZONTAL, win.mousey); // into 2 new boxes
    }
  }
  else if (keypressed (SDLK_t)) {
    if (recting ()) ; else {
      if (SHIFT || CTRL)
        make_nxn_grid (); // make grid of num_boxes x num_boxes
      else
        make_note_grid (); // make note grid
    }
  }

  if (keypressed(SDLK_RETURN)) toggle_triggered_sound ();

  // change ball speed
  static const float delta_speed = 0.25;
  if (keypressedd (SDLK_LEFTBRACKET)) change_speed (MENU.sp_mondrian_change_speed, -delta_speed);
  else if (keypressedd (SDLK_RIGHTBRACKET)) change_speed (MENU.sp_mondrian_change_speed, delta_speed);

  // change ball attack & decay time
  if (keypressedd (SDLK_SEMICOLON, reptf, repts)) {
    if (SHIFT) {
      delta_attack_time -= MIN_TIME;
      if (delta_attack_time < MIN_TIME) delta_attack_time = MIN_TIME;
      sprintf (BUFFER, "delta attack time = %0.3f secs", delta_attack_time);
      cons << BUFFER << eol;
    } else
      --MENU.sp_mondrian_change_attack_time;
  }
  else if (keypressedd (SDLK_QUOTE, reptf, repts)) {
    if (SHIFT) {
      delta_attack_time += MIN_TIME;
      sprintf (BUFFER, "delta attack time = %0.3f secs", delta_attack_time);
      cons << BUFFER << eol;
    } else
      ++MENU.sp_mondrian_change_attack_time;
  }
  else if (keypressedd (SDLK_COMMA, reptf, repts)) {
     if (SHIFT) {
       delta_decay_time -= MIN_TIME;
       if (delta_decay_time < MIN_TIME) delta_decay_time = MIN_TIME;
       sprintf (BUFFER, "delta decay time = %0.3f secs", delta_decay_time);
       cons << BUFFER << eol;
     } else
       --MENU.sp_mondrian_change_decay_time;
  }
  else if (keypressedd (SDLK_PERIOD, reptf, repts)) {
      if (SHIFT) {
        delta_decay_time += MIN_TIME;
        sprintf (BUFFER, "delta decay time = %0.3f secs", delta_decay_time);
        cons << BUFFER << eol;
      } else
        ++MENU.sp_mondrian_change_decay_time;
  }

  // change ball course
  if (keypressedd (SDLK_o, reptf, repts1)) {
    if (CTRL)
      toggle_auto_rotate (1); // always change anti-clockwise
    else  if (SHIFT) {
      change_ball_dtheta (-1);
    }
    else
      rotate_velocity (+1);
  } else if (keypressedd (SDLK_p, reptf, repts1)) {
    if (CTRL)
      toggle_auto_rotate (-1); // always change clockwise
    else if (SHIFT) {
      change_ball_dtheta (+1);
    }
    else
      rotate_velocity (-1); // rotate velocity vector clockwise
  }

  // ball / slit selection
  if (keypressed (SDLK_l)) {
    select_all_targets ();
  } else if (keypressed (SDLK_i)) {
    if (SHIFT)
      MENU.cb_label_hz_vol.toggle (); // label pitch/volume of triggered notes
    else
      invert_selected_targets ();
  } else if (keypressed (SDLK_k)) { // box
    select_box_targets ();
  } else if (keypressed (SDLK_n)) {
    clear_selected_targets ();
  }

  // ball browsing
  if (keypressedd (SDLK_LEFT)) browse_ball (-1); // MENU.bolis.picked (MENU.ol_browse_balls.option, -1);
  else if (keypressedd (SDLK_RIGHT)) browse_ball (+1); // MENU.bolis.picked (MENU.ol_browse_balls.option, +1);
 
  // freeze/thaw balls
  if (keypressed (SDLK_SPACE)) {
    list<ball*>& balls = get_balls ();
    if (SHIFT) freeze_balls (balls);
    else if (CTRL) thaw_balls (balls);
    else freeze_thaw_balls (balls);
  }
 
  if (keypressed (SDLK_j)) flip_velocity (); // flip ball velocity ie flips ball direction
 
  if (keypressedd (SDLK_KP_PLUS, reptf, repts)) ++MENU.sp_mondrian_change_slit_size;
  else if (keypressedd (SDLK_KP_MINUS, reptf, repts)) --MENU.sp_mondrian_change_slit_size;

  if (keypressedd (SDLK_MINUS, reptf, repts)) --MENU.sp_mondrian_change_trail_size;
  else if (keypressedd (SDLK_EQUALS, reptf, repts)) ++MENU.sp_mondrian_change_trail_size;

  if (keypressed (SDLK_b)) {
    if (SHIFT) do_add_balls (ball::WRECKER);
    else if (CTRL) do_add_balls (ball::HEALER);
    else do_add_balls (); // add bouncers
  }

  if (keypressed (SDLK_m)) do_move_balls (); // move balls
  if (keypressed (SDLK_c)) delete_selected_targets ();

  if (keypressedd (SDLK_y)) change_min_voices (-1);
  else if (keypressedd (SDLK_u)) change_min_voices (+1);
 
  if (keypressed (SDLK_F9)) remove_slits_on_current_edge ();
  else if (keypressed (SDLK_F10)) remove_slits_on_current_box ();
  else if (keypressed (SDLK_F11)) remove_slits_on_boxes_with_balls ();
  else if (keypressed (SDLK_F12)) remove_all_slits ();

  if (keypressed (SDLK_F3)) toggle_balls_type (ball::WRECKER);
  else if (keypressed (SDLK_F4)) toggle_balls_type (ball::HEALER);
  else if (keypressed (SDLK_F5)) toggle_balls_type (ball::BOUNCER);
  else if (keypressed (SDLK_F6)) switch_balls_type ();
  else if (keypressed (SDLK_F7)) select_type (ball::WRECKER);
  else if (keypressed (SDLK_F8)) select_type (ball::HEALER);

  if (keypressed (SDLK_v)) {
    if (recting()) ; else {
      if (SHIFT) delete_all_rects = !delete_all_rects;
      else
        delete_current_rect ();
    }
  }

  if (keypressed (SDLK_g)) {
    MENU.monl.picked (MENU.ol_selection_targets.option, +1);
    if (sel_tar == SELECT_BALLS)
      cons << GREEN << "Selection target: balls" << eol;
    else
      cons << GREEN << "Selection target: slits" << eol;
  }

  if (keypressed (SDLK_h)) toggle_slit_anim ();

  if (!mouse_slider0.active) {
    if (keypressedd (SDLK_9)) {
        if (SHIFT) --MENU.sp_mondrian_change_note_poly_radius; else --MENU.sp_mondrian_change_note_poly_points;
    } else if (keypressedd (SDLK_0)) {
      if (SHIFT) ++MENU.sp_mondrian_change_note_poly_radius; else ++MENU.sp_mondrian_change_note_poly_points;
    }
  }

  if (keypressed (SDLK_SLASH)) {if (!mouse_slider0.active) start_slitting ();}
  else if (keypressedd (SDLK_INSERT)) ++MENU.sp_mondrian_change_slit_anim_time;
  else if (keypressedd (SDLK_DELETE)) --MENU.sp_mondrian_change_slit_anim_time;

  if (keypressed (SDLK_F1)) _help ();

  // movement
  if (can_wheel ()) do_zoom (-wheel * zoom);
  double pan_rept = window::PAN_REPEAT, zoom_rept = window::ZOOM_REPEAT;
  if  (keypressedd (SDLK_a, pan_rept, pan_rept)) do_panx (-pan);
  else if (keypressedd (SDLK_d, pan_rept, pan_rept)) do_panx (+pan);
  else if (keypressedd (SDLK_w, pan_rept, pan_rept)) do_pany (+pan);
  else if (keypressedd (SDLK_s, pan_rept, pan_rept)) do_pany (-pan);

  if (!mouse_slider0.active) {
    if (keypressedd (SDLK_q, zoom_rept, zoom_rept)) do_zoom (+zoom); // zoom out
    else if (keypressedd (SDLK_e, zoom_rept, zoom_rept)) do_zoom (-zoom);  // zoom in
  }

  return 1;
}

void mondrian::clone_ball (ball* b) {
#ifdef __EVALUATION__
      if (num_balls) cons << RED << "Can clone balls in the Licensed Version of DIN Is Noise" << eol;
      return;
#endif
  ball* cb = new ball;
  b->clone_this (cb);
  locate_ball (cb);
  balls.push_back (cb);
  ++num_balls;
}


state_button* point_modulator::add (hit_t& h) {
#ifdef __EVALUATION__
  if (nlst == 1) {
    cons << RED << "Can add more point modulators in the Licensed Version of DIN Is Noise" << eol;
    return 0;
  }
#endif
  on_lst (_desel);
  state_button* sb = new state_button;
  sb->set_pos (sbx, sby);
  sbx += state_button::SIZE2;
  title.add_child (sb);
  const float bpm = 5.0f;
  mod_dat md (h, sb, bpm);
  lst.push_back (md);
  ++nlst;
  sb->set_listener (this);
  sb->set_state (1);

  set_title ();
  return sb;
}


int ui_list::handle_input () {

  // handle quit
  //
  #ifdef __MACOSX_CORE__
  if (keydown (SDLK_LMETA) && keypressed (SDLK_q)) { // command key + q  on mac os x
    quit = IMMEDIATE;
    return 1;
  }
  #else
  if (ALT && keypressed (SDLK_F4)) { // alt + f4 on windows & linux
    quit = IMMEDIATE;
    return 1;
  }
  #endif
 
  // handle widgets
  //

  basic_editor::hide_cursor = mouse_slider0.active;
  //basic_editor::hide_cursor = 0;
 
  if (widget::focus) { // handle input of widget with focus
    widget::focus->handle_input ();
    return 1;
  } else {
    vector<widget*> widgets = widgets_of [current];
    for (vector<widget*>::size_type i = 0, j = widgets.size (); i < j; ++i) {
      widget* wi = widgets[i];
      if (wi->visible && wi->enabled) {
        wi->handle_input ();
        if (widget::focus) return 1;
      }
    }
  }

  // toggle menu
  //
  #ifdef __EVALUATION__
    if (current != &anote) { // no menu on author's note
  #endif
    if (rmb) {
      if (!rmb_clicked) {
        rmb_clicked = 1;
        if (escape_from_things ());
        else main_menu.toggle ();
      }
    } else rmb_clicked = 0;
  #ifdef __EVALUATION__
  }
  #endif

  // handle current screen
  current->handle_input ();

  if (keypressed (SDLK_BACKQUOTE)) { // flip to last screen
    if (prev && !mouse_slider0.active) {
      if (prev->ed) load_editor (prev);
      else if (prev->inst) load_instrument (dynamic_cast<instrument*>(prev));
      else set_current (prev); // settings screen for now
    }
  }

  if (mouse_slider0.active == 0) {
    if (keypressed (SDLK_1)) { // switch instrument
      if (current->inst) goto_next_instrument (); // else back to current instrument
      load_instrument ();
    } else { // load editors attached to keys 2 - 8
      for (int i = 0; i < MAX_EDITORS; ++i) {
        if (keypressed (key[i])) {
          ui* edi = ed[i];
          if (edi) load_editor (edi);
        }
      }
    }
  }
 
  /*if (keypressed(SDLK_RETURN)) {
    if (alt_down ()) { // clear recording
      main_menu.recl.clicked (main_menu.b_clear_record);
    } else if (CTRL) { // start recording
      if (cb_record.state == 0) cb_record.turn_on (); else cb_record.turn_off ();
    }
  }*/


  if (keypressed (SDLK_F2)) {
    if (UI_OFF) turn_on_ui (); else turn_off_ui ();
  }

  if (keypressed (SDLK_PAUSE)) {
    scope.visible = !scope.visible;
    main_menu.cb_scope.set_state (scope.visible, 0);
  }

  if (keypressed (SDLK_MENU)) main_menu.mbl.clicked (main_menu.b_menu);

  if (keypressed (SDLK_ESCAPE)) {
    if (UI_OFF) turn_on_ui ();
    else if ( escape_from_things() ) ;
    else { // ask to press esc again to really quit
      esc:
      if (esct == -1) {
        cons << console::red << "Press ESC again to quit" << eol;
        esct = ui_clk();
      } else {
        double dt = ui_clk() - esct;
        if (dt > 1.0) { // 1 sec timeout
          esct = -1; // cancel
          goto esc;
        } else if (quit != SOON) try_quit ();
      }
    }
  }

  return 1;

}

extern ui* SCREENS [];
void ui_list::setup () {

  // all screens
  int nscreens = 41;
  uis.resize (nscreens);
  uis[0] = 0;
  ui** si = SCREENS;
  for (int i = 1; i < nscreens; ++i, ++si) uis[i] = *si;

  // bottom line
  int dirs [] = {arrow_button::left, arrow_button::right, arrow_button::up, arrow_button::down};
  arrow_button* scrl [] = {&ab_scroll_left, &ab_scroll_right, &ab_scroll_up, &ab_scroll_down};
  for (int i = 0; i < 4; ++i) {
    arrow_button* si = scrl[i];
    si->set_dir (dirs[i]);
    si->set_size (12);
    si->set_listener (&sal);
    si->click_repeat = 1;
    si->first_repeat_time = 0.005;
    si->subsequent_repeat_time = 0.015;
  }

  cb_voice.set_listener (&vlis);
  cb_voice.colorize (0);

  cb_gater.set_listener (&glis);
  cb_gater.colorize (0);

  cb_delay.set_listener (&dlis);
  cb_delay.colorize (0);

  cb_compress.set_listener (&clis);

  b_settings.set_listener (&slis);

  cb_record.set_listener (&main_menu.recl);

  sp_voices.set ("Voices", 1, 1, MILLION, &vov, 0);
  sp_attack_time.set ("Attack time", 0.1f, 0.0f, MILLION, &atv, 0);
  sp_decay_time.set ("Decay time", 0.1f, 0.0f, MILLION, &dkv, 0);
  sp_pitch_bend.set ("Hz/Pixel", 0.01f, 0.0f, MILLION, &pbl, 0);
  sp_octave_shift_bpm.set ("BPM", 1, 0.0f, MILLION, &osl, 0);

  cb_show_nearby_notes.set_listener (&pbl);
  cb_show_nearby_notes.turn_off ();

  // waveform display
  //
  l_waveform_display.set_text ("Waveform");

  ab_prev_wav.set_dir (arrow_button::left);
  ab_prev_wav.set_listener (&wdl);
  ab_next_wav.set_dir (arrow_button::right);
  ab_next_wav.set_listener (&wdl);

  ab_prev_wav.click_repeat = ab_next_wav.click_repeat = 1;
  ab_prev_wav.first_repeat_time = ab_next_wav.first_repeat_time = 0.33;
  ab_prev_wav.subsequent_repeat_time = ab_next_wav.subsequent_repeat_time = 1/20.;

  cd_waveform_display.set_size (96, 96);
  cd_waveform_display.crv = &keybd2.wave; // keyboard-keyboard's waveform
  cd_waveform_display.setbbox (keybd2.wave.shapeform);

  // octave shift
  l_octave_shift.set_text ("Octave Shift");
  ab_octave_down.set_dir (arrow_button::left);
  ab_octave_down.set_listener (&osl);
  ab_octave_up.set_dir (arrow_button::right);
  ab_octave_up.set_listener (&osl);
  int arrow_size = 24;
  ab_octave_up.set_size (arrow_size);
  ab_octave_down.set_size (arrow_size);
  b_abort_octave_shift.set_text ("Abort");
  b_abort_octave_shift.set_listener (&main_menu.aosl);

  // keys trigger? notes or noise
  ol_trig_what.set_listener (&twl);

  DEFINE_PARAMETERS
  widget_load ("d_parameters", pw, npars);
  for (int i = 1; i < npars; ++i) {
    d_parameters.add_child (pw[i]);
    //pw[i]->set_moveable(1);
  }

  d_parameters.set_name ("Parameters");
  d_parameters.set_moveable (1);

  ab_parameters.set_listener (&pal);

  cb_voice.set_state (din0.dinfo.voice);
  cb_gater.set_state (din0.dinfo.gater);
  cb_delay.set_state (din0.dinfo.delay);
  cb_compress.set_state (din0.dinfo.compress);

  cb_show_pitch_volume_board.set_listener (&spvl);
  cb_show_pitch_volume_drones.set_listener (&spvl);

#ifdef __EVALUATION__
  anote.setup ();
#endif

  plugin__browser.setup ();
  settings_scr.setup ();
  main_menu.setup ();

}

void nagscr () {
  #ifdef __EVALUATION__
    cons.clear ();
    uis.set_current (&anote); // nag screen :(
  #elif defined __LICENSED__
    load_instrument (); // open with last used instrument
  #endif
}

void drone_commands_listener::startwanding () {
  int* flags [] = {&din0.adding, &din0.wanding};
  static const char* mesg [] = {
    "Click to add drones, ESC or Right Click to stop",
    "Just move mouse to add drones, ESC or Right Click to stop"
  };

  din0.adding = din0.wanding = 0;
  *flags[din0.dinfo.wand] = 1;

#ifdef __EVALUATION__
  if (din0.wanding) {
    din0.wanding = 0;
    cons << RED << "Wand only available in the Licensed Version of DIN Is Noise" << eol;
    return;
  }
#endif

  cons << GREEN << mesg[din0.dinfo.wand] << eol;

}

void drone_commands_listener::clicked (button& b) {
  int toggle = 1;
  if (&b == MENUP.ol_add_wand.option) startwanding (); else
  if (&b == MENUP.b_delete_drones) din0.delete_selected_drones (); else
  if (&b == MENUP.b_select_all_drones) {toggle = 0; din0.select_all_drones ();} else
  if (&b == MENUP.b_launch_drones) din0.make_launchers (); else
  if (&b == MENUP.b_orbit_selected_drones) din0.orbit_selected_drones (); else
  if (&b == MENUP.b_freeze_drones) din0.freeze_drones (); else
  if (&b == MENUP.b_thaw_drones) din0.thaw_drones (); else
  if (&b == MENUP.b_select_launchers) {toggle = 0; din0.select_launchers (); } else
  if (&b == MENUP.b_set_targets) din0.set_targets (); else
  if (&b == MENUP.b_select_attractors) {toggle = 0; din0.select_attractors (); } else
  if (&b == MENUP.b_select_attractees) {toggle = 0; din0.select_attractees (); } else
  if (&b == MENUP.b_stop_launching_drones) din0.destroy_launchers (); else
  if (&b == MENUP.b_invert_drone_selection) {toggle = 0; din0.invert_selected_drones();} else
  if (&b == MENUP.b_track_drones) din0.make_trackers (); else
  if (&b == MENUP.b_select_tracked_drones) {toggle = 0; din0.select_tracked_drones (); } else
  if (&b == MENUP.ol_create_this.option) din0.toggle_create_this (); else
  if (&b == MENUP.b_clear_targets) din0.clear_targets(); else
  if (&b == MENUP.b_flip_rows_cols) {
    int r = MENU.sp_mesh_rows.value, c = MENU.sp_mesh_cols.value;
    MENU.sp_mesh_rows.set_value (c);
    MENU.sp_mesh_cols.set_value (r);
    din0.dinfo.rows = c;
    din0.dinfo.cols = r;
    mkb_selector.set_mesh (din0.meshh.create, din0.dinfo.rows, din0.dinfo.cols);
    MENU.picked (MENU.ol_mesh_point.option, 0);
    toggle = 0;
  }

  if (toggle) MENU.toggle ();
}


VALUE_CHANGED(menu,genslis) {
  int& gens = din0.dinfo.gens;
  gens = MENU.gens.value;
#ifdef __EVALUATION__
  if (gens > 1) {
    cons << RED << "Generations > 1 only in the licensed version of DIN Is Noise" << eol;
    gens = 1;
    MENU.gens.set_value (1);
    return;
  }
#endif
  cons << GREEN << "Default Generations = " << gens << eol;
}