Rev 2300 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* ui.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 "ui_list.h"
#include "din.h"
#include "morse_code.h"
#include "console.h"
#include "curve_editor.h"
#include "tcl_interp.h"
#include "command.h"
#include "chrono.h"
#include "keyboard_keyboard.h"
#include "viewwin.h"
#include "authors_note.h"
#include "fft.h"
#include "main.h"
#include "curve_picker.h"
#include "capturer.h"
#include "fractaliser.h"
#include "warper.h"
#include "mondrian.h"
#include "binaural_drones.h"
#include "spiraler.h"
#include "circler.h"
#include "rose_milker.h"
#include "sine_mixer.h"
#include <fstream>
#include <string>
#include "container.h"
#define NO_NEED_TO 0
using namespace std;
extern string user_data_dir;
extern curve_editor waved, comed, octed, veled, drone_mod_ed, ran_mod_ed, ran_wh_ed, pitch_vol_ed, pomo_ed, delayed, drone_pend_ed;
extern font_editor fed;
extern int mousex, mousey, mouseyy;
extern string INSTRUMENT;
extern oscilloscope scope;
extern int line_height;
extern sine_mixer sinemixer;
extern const char* voice_is_lbls[];
extern const int NUM_INSTRUMENTS;
ui_list::ui_list () :
vlis (&cb_voice, &fdr_voice, &din0.dinfo.voice),
glis (&cb_gater, &fdr_gater, &din0.dinfo.gater),
dlis (&cb_delay, &fdr_delay, &din0.dinfo.delay)
{
current = 0;
prev = 0;
crved = 0;
esct = -1;
rmb_clicked = 0;
LISTEN (ol_voice_is, &vivl);
}
void ui_list::set_current (ui* u) {
if (current) {
current->leave ();
ui::over = prev = current;
}
current = u;
cons << YELLOW << "@ " << current->name << eol;
if (u->ed)
crved = dynamic_cast<curve_editor*>(u);
else
uis[0] = current;
current->enter ();
}
void ui_list::load_editor (ui* ed) {
main_menu.setup_tabs (ed);
set_current (ed);
}
void ui_list::bg () {
current->calc_win_mouse ();
for (vector<ui*>::size_type i = 1, j = uis.size(); i < j; ++i) uis[i]->bg (); // bg for instruments and editors
// fade fx for voice, gater & delay
eval_fade (fdr_voice, cb_voice);
flash_gater (); // flashes in sync with gater value
eval_fade (fdr_delay, cb_delay);
}
float ui_list::eval_fade (fader& fdr, checkbutton& cb) {
if (fdr.eval ()) cb.blend_on_off_color (fdr.alpha);
return fdr.amount;
}
void ui_list::flash_gater () {
static color clr [2] = {color (1, 0, 0), color (0, 1, 0)};
float dg = aout.gatr [aout.last_sample];
if (fdr_gater.eval ()) {
cb_gater.blend_on_off_color (fdr_gater.alpha);
color& c = const_cast<color&> (cb_gater.clr);
c *= dg;
} else {
int gi = din0.dinfo.gater;
cb_gater.set_color (dg * clr [gi].r, dg * clr [gi].g, dg * clr[gi].b);
}
}
int ui_list::is_widget_on_screen (widget* w, ui* scr) {
vector<widget*>& widgets = widgets_of [scr];
for (int i = 0, j = widgets.size (); i < j; ++i) if (w == widgets[i]) return 1;
return 0;
}
int ui_list::set_editor (const string& name, int screen) {
if (screen > 0) {
ui* ei = 0;
for (int i = 0, j = uis.size(); i < j; ++i) {
if (uis[i]->name == name) {
ei = uis[i];
break;
}
}
if (ei) {
ed [screen - 2] = ei;
return 1;
} else {
cmdlst.result = "bad editor name";
return 0;
}
} else {
cmdlst.result = "bad screen number (valid: 2 to 8)";
return 0;
}
}
void ui_list::draw () {
glClear (GL_COLOR_BUFFER_BIT);
// graphics drawing
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
current->draw ();
// ui drawing
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, view.xmax, 0, view.ymax, 0, 1);
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->draw ();
}
}
// all screens
ui* SCREENS [] = {
&keybd2,
&mondrian0,
&din0,
&binaural_drones0,
&din0.waved,
&din0.droneed,
&drone_mod_ed,
&din0.moded,
&din0.gated,
&keybd2.waved,
&keybd2.attacked,
&keybd2.decayed,
&keybd2.veled,
&delayed,
&octed,
&comed,
&mc.ed,
&mondrian0.waved,
&mondrian0.attacked,
&mondrian0.decayed,
&binaural_drones0.waved,
&ran_mod_ed,
&ran_wh_ed,
&pitch_vol_ed,
&pomo_ed,
&noiser::ed,
&drone_pend_ed,
&drone::modvt::ed,
&fed,
&fractaliser_.ed,
&warper_.ed,
&spiraler_.scr.sin_ed,
&spiraler_.scr.cos_ed,
&spiraler_.scr.rad_ed,
&rosemilker.scr.sin_ed,
&rosemilker.scr.cos_ed,
&circler_.scr.sin_ed,
&circler_.scr.cos_ed,
&circler_.scr.rad_ed,
&sinemixer.sin_ed,
&rosemilker.scr.rad_ed,
0
};
void ui_list::show_hide_widgets (int sh) {
for (ui** p = SCREENS; *p != 0; ++p) {
ui* u = *p;
vector<widget*>& vu = widgets_of [u];
int j = vu.size ();
if (j) {
if (sh)
for (int i = 0; i < j; ++i) vu[i]->show();
else
for (int i = 0; i < j; ++i) vu[i]->hide();
}
}
curve_picker.hide ();
}
void ui_list::add_widgets () {
widget* wall [] = {&cons, &main_menu, &b_settings}; // appears on all screens
for (ui** p = SCREENS; *p != 0; ++p) for (int i = 0; i < 3; ++i) widgets_of[*p].push_back (wall[i]);
// add selectors to microtonal keyboard and mondrian
mkb_selector.set_listener (&din0);
mon_selector.set_listener (&mondrian0);
// add fft display on waveform editors
ui* uwav [] = {&din0.waved, &keybd2.waved, &din0.droneed, &mondrian0.waved, &binaural_drones0.waved};
for (int i = 0; i < 5; ++i) widgets_of[uwav[i]].push_back (&fft0);
// add plugin browser to these editors
ui* ueds [] = {
&din0.waved,
&din0.moded,
&din0.droneed,
&drone_mod_ed,
&keybd2.waved,
&fractaliser_.ed,
&warper_.ed,
&mondrian0.waved,
&din0.gated,
&binaural_drones0.waved,
&ran_mod_ed,
&pitch_vol_ed,
&pomo_ed,
&drone_pend_ed,
&noiser::ed,
};
for (int i = 0; i < 15; ++i) widgets_of[ueds[i]].push_back (&plugin__browser);
// depth, bpm spinners to drone pendulum editor
widget* dpeuw [] = {&dpeu.depth, &dpeu.bpm};
widget_load ("d_dpeu", dpeuw, 2);
dpeu.depth.set ("Depth", 1.0f, -MILLION, MILLION, &dpeul, 0);
dpeu.bpm.set ("BPM", 1.0f, -MILLION, MILLION, &dpeul, 0);
widgets_of [&drone_pend_ed].push_back (&dpeu.depth);
widgets_of [&drone_pend_ed].push_back (&dpeu.bpm);
// add widgets for curve editors only
for (ui** p = SCREENS + NUM_INSTRUMENTS; *p != 0; ++p) {
ui* u = *p;
vector<widget*>& wu = widgets_of [u];
curve_editor* ce = dynamic_cast<curve_editor*>(u);
wu.insert (wu.begin(), &ce->capturer);
wu.insert (wu.begin(), &ce->pomo);
wu.push_back (&curve_picker);
ce->capturer.setup (ce);
ce->pomo.setup (ce);
}
// add scope to all instruments
extern instrument* INSTRUMENT_PTR[];
for (int i = 0; i < NUM_INSTRUMENTS; ++i) widgets_of[(ui *)INSTRUMENT_PTR[i]].push_back (&scope);
// no menu on author's note & settings screen
widgets_of[&anote].push_back(&cons);
widgets_of[&settings_scr].push_back (&cons);
widget* wdin [] = {
&ol_voice_is,
&cb_voice,
&cb_gater,
&cb_delay,
&cb_compress,
&ab_scroll_left,
&ab_scroll_right,
&ab_scroll_up,
&ab_scroll_down,
&cb_show_pitch_volume_board,
&cb_show_pitch_volume_drones,
&cb_record,
&mkb_selector,
};
for (int i = 0, j = 13; i < j; ++i) widgets_of [&din0].push_back (wdin[i]);
widget* wkeybd2 [] = {
&cb_delay,
&cb_compress,
&sp_attack_time,
&sp_decay_time,
&sp_voices,
&sp_pitch_bend,
&cb_show_nearby_notes,
&d_parameters,
&ab_parameters,
&l_waveform_display,
&ab_prev_wav,
&ab_next_wav,
&cd_waveform_display,
&l_octave_shift,
&ab_octave_down,
&ab_octave_up,
&sp_octave_shift_bpm,
&b_abort_octave_shift,
&cb_record,
&ol_trig_what
};
for (int i = 0, j = 20; i < j; ++i) widgets_of [&keybd2].push_back (wkeybd2[i]);
widget* wmondrian [] = {
&l_mondrian_voices,
&cb_delay,
&cb_compress,
&cb_record,
&mon_selector,
};
for (int i = 0, j = 5; i < j; ++i) widgets_of [&mondrian0].push_back (wmondrian[i]);
l_mondrian_voices.set_text ("Voices: ** / **");
widget* wsbd [] = {
&cb_delay,
&cb_compress,
&cb_record,
};
for (int i = 0, j = 3; i < j; ++i) widgets_of [&binaural_drones0].push_back (wsbd[i]);
}
void ui_list::update_widgets (int wnow, int hnow, int wprev, int hprev) {
main_menu.update ();
plugin__browser.update ();
cb_gater.set_text ("Beater");
cb_delay.set_text ("Delay");
cb_compress.set_text ("Compressor");
b_settings.set_text ("Settings");
cb_record.set_text ("Record");
l_mondrian_voices.update ();
int lh = line_height;
int y = update_bottom_line ();
y += lh;
arrow_button* scrl [] = {&ab_scroll_left, &ab_scroll_right, &ab_scroll_up, &ab_scroll_down};
int nscrls = 4;
int w = ab_scroll_left.extents.width;
int dw [] = {5, 7, 0, 0};
int x = (view.xmax - nscrls * w) / 2;
for (int i = 0; i < nscrls; ++i) {
arrow_button* ab = scrl[i];
ab->set_pos (x, y);
x = x + w + dw[i];
}
x += w;
cb_show_pitch_volume_board.set_pos (x, ab_scroll_down.extents.bottom - fnt.lift);
cb_show_pitch_volume_board.set_text ("i");
x += w;
cb_show_pitch_volume_drones.set_pos (x + 1, ab_scroll_down.extents.bottom - fnt.lift);
cb_show_pitch_volume_drones.set_text ("j");
d_parameters.set_text ("Parameters");
sp_attack_time.update ();
sp_decay_time.update ();
sp_voices.update ();
sp_pitch_bend.update ();
cb_show_nearby_notes.set_text ("Show nearby notes");
l_waveform_display.update ();
l_octave_shift.update ();
ab_octave_up.update ();
ab_octave_down.update ();
sp_octave_shift_bpm.update ();
settings_scr.update_widgets ();
}
void ui_list::dofft () {
if (!fft0.folded () && crved == current) fft0.go (crved->curveinfo[0].curve);
}
void fade_button_listener::after_fade (fader& f) {
cb->enabled = 1;
f.afl = 0;
}
void voice_listener::changed (checkbutton& cb) {
fade_button_listener::changed (cb);
MENU.next_tab = MENUP.cb_mkb_voice;
MENU.next_tab_instr = &din0;
}
fade_button_listener::fade_button_listener (checkbutton* _cb, fader* _f, int* _t) {cb = _cb; f = _f; target = _t; lsnr = 0;}
void fade_button_listener::changed (checkbutton& cb) {
if (f->on == 0) {
int on = cb.state;
*target = on;
if (on) f->set (0, 1); else f->set (1, 0);
cb.enabled = 0;
f->afl = this;
}
}
void compress__listener::changed (checkbutton& cb) {
din0.dinfo.compress = cb.state;
}
void settings__listener::clicked (button& b) {
uis.set_current (&uis.settings_scr);
}
void pitch_bend_listener::changed (field& f) {
PITCH_BEND_PER_PIXEL = uis.sp_pitch_bend.value;
PITCH_BEND = PITCH_BEND_PER_PIXEL * 100;
}
void pitch_bend_listener::changed (checkbutton& cb) {
keybd2.show_nearby_notes = cb.state;
}
void waveform_display_listener::clicked (button& b) {
CRVED = &keybd2.waved;
if (&b == &uis.ab_prev_wav) {
CRVED->win.calc ();
CRVED->load_curve (-1);
} else {
CRVED->win.calc ();
CRVED->load_curve (+1);
}
}
void parameters_listener::clicked (button& b) {
arrow_button& ab = dynamic_cast<arrow_button&> (b);
if (ab.dir == arrow_button::down) {
ab.set_dir (arrow_button::right);
uis.d_parameters.hide (widget::only_children);
} else {
uis.d_parameters.show ();
ab.set_dir (arrow_button::down);
}
ab.show ();
}
ui_list::~ui_list () {
dlog << "--- destroying uis ---" << endl;
DEFINE_PARAMETERS
widget_save ("d_parameters", pw, npars);
widget* dpeuw [] = {&dpeu.depth, &dpeu.bpm};
widget_save ("d_dpeu", dpeuw, 2);
dlog << "--- destroyed uis ---" << endl;
}
void ui::enter () {
/*if (prev_mousex == -1 && prev_mousey == -1) {
prev_mousex = view.midx;
prev_mousey = view.midy;
}*/
warp_mouse (prev_mousex, prev_mousey);
}
void ui::leave () {
if (MENU.b_close.visible) MENU.b_close.call_listener ();
if (NO_NEED_TO == hide_menu ()) {
prev_mousex = mousex;
prev_mousey = mousey;
}
if (!ed) scope.save_current_instrument ();
mouse_slider0.deactivate ();
}
extern const float MIN_TIME;
void attack_val::changed (field& F) {
float f = uis.sp_attack_time.value;
if (equals (f, 0.0f)) ATTACK_TIME = MIN_TIME; else ATTACK_TIME = f;
}
void decay_val::changed (field& F) {
float f = uis.sp_decay_time.value;
if (equals (f, 0.0f)) DECAY_TIME = MIN_TIME; else DECAY_TIME = f;
}
void voices_val::changed (field& F) {
int i = uis.sp_voices.value;
int j = i; if (i < 1) j = 1;
NOTE_VOLUME = 1.0f / j;
keybd2.calc_visual_params ();
}
void scroll_arrow_listener::clicked (button& b) {
if (&b == &uis.ab_scroll_left) {
din0.scroll (-din0.dinfo.scroll.dx, 0, 0);
} else if (&b == &uis.ab_scroll_right) {
din0.scroll (din0.dinfo.scroll.dx, 0, 0);
} else if (&b == &uis.ab_scroll_up) {
din0.scroll (0, -din0.dinfo.scroll.dy, 0);
} else {
din0.scroll (0, din0.dinfo.scroll.dy, 0);
}
}
void show_pitch_volume_listener::changed (checkbutton& cb) {
if (&cb == &uis.cb_show_pitch_volume_board)
din0.dinfo.show_pitch_volume.board = cb.state;
else
din0.dinfo.show_pitch_volume.drones = cb.state;
}
void fft::clicked (button& b) {
if (ab_fold.dir == arrow_button::down) {
ab_fold.set_dir (arrow_button::right);
l_title.hide (widget::only_children);
ab_fold.show ();
} else {
ab_fold.set_dir (arrow_button::down);
l_title.show ();
fft0.go (uis.crved->curveinfo[0].curve);
}
}
int fft::folded () {
return (ab_fold.dir == arrow_button::right);
}
void ui_list::handle_plugin (widget* which, int what) {
enum {INSTALL = 1, REMOVE = 0};
ui* ueds [] = {
&din0.waved,
&din0.moded,
&din0.droneed,
&keybd2.waved,
&fractaliser_.ed
};
int num_editors = 5;
if (what == INSTALL) {
for (int i = 0; i < num_editors; ++i) widgets_of[ueds[i]].push_back (which);
} else {
for (int i = 0; i < num_editors; ++i) {
vector<widget*>& widgets = widgets_of [ueds[i]];
vector<widget*>::iterator iter = find (widgets.begin (), widgets.end(), which);
if (iter != widgets.end()) widgets.erase (iter);
}
}
main_menu.toggle ();
}
int ui_list::update_bottom_line () {
widget** winst = 0;
widget* wdin[] = {&cb_voice, &cb_gater, &cb_delay, &cb_compress, &main_menu.b_menu, &b_settings, &cb_record};
widget* wmon[] = {&l_mondrian_voices, &cb_delay, &cb_compress, &main_menu.b_menu, &b_settings, &cb_record};
widget* wcom[] = {&cb_delay, &cb_compress, &main_menu.b_menu, &b_settings, &cb_record};
widget* wed [] = {&main_menu.b_menu, &b_settings};
instrument* inst = get_current_instrument ();
int n = 0;
if (inst == &din0) {
winst = wdin;
n = 7;
} else if (inst == &mondrian0) {
winst = wmon;
n = 6;
} else if (inst == &binaural_drones0 || inst == &keybd2) {
winst = wcom;
n = 5;
} else {
winst = wed;
n = 2;
}
int dx = 25, w = 0;
for (int i = 0; i < n; ++i) w += winst[i]->extents.width;
w += n * dx;
int x = (view.xmax - w) / 2, y = 2; //(int)(0.25f * get_line_height() + 0.5);
for (int i = 0; i < n; ++i) {
widget& b = *winst[i];
const box<int>& e = b.extents;
b.set_extents (x, y, x + e.width, y + e.height);
b.set_pos (x, y);
x = e.right + dx;
}
ol_voice_is.set_pos (cb_voice.posx - 3 * ol_voice_is.left.extents.width - 2, cb_voice.posy);
return y;
}
int ui_list::remove (widget* w) {
return erase (widgets_of [current], w);
}
void ui_list::add (ui* u, widget* w) { widgets_of [u].push_back (w); }
int ui_list::escape_from_things () {
int ret = 1;
if (UI_OFF) turn_on_ui ();
else if (mouse_slider0.deactivate ()) ;
else if (current->ed) ret = current->esc();
else if (mkb_selector()) mkb_selector.abort ();
else if (mon_selector()) mon_selector.abort ();
else if (esc_octave_shift (get_current_instrument()));
else if (main_menu.b_close.visible) main_menu.b_close.call_listener ();
else if (main_menu.show) main_menu.toggle ();
else if (current == &din0) {
if (din0.gab.n) din0.gab.abort ();
else if (din0.moving_drones) din0.toggle_moving_drones ();
else if (din0.adding) {
din0.adding = 0;
cons << RED << "Stopped adding drones!" << eol;
add (&din0, &mkb_selector);
}
else if (din0.stopwanding()) ;
else if (din0.meshh.create) din0.stop_creating_mesh ();
else if (din0.create_drone_pend) din0.stop_creating_drone_pendulum ();
else if (din0.finish_phrase_recording());
else if (din0.dinfo.gravity.stop_editing ());
else ret = 0;
}
else if (keybd2.turn_off_bend ());
else if (mondrian0.stop_doing_stuff ());
else if (binaural_drones0.aborted ());
else if (current == &settings_scr) settings_scr.clicked (settings_scr.b_go_back);
else ret = 0;
return ret;
}
int is_menu_visible () {
return uis.main_menu.show;
}
void abort_selectors () {
mon_selector.abort ();
mkb_selector.abort ();
}
PICKED_OPTION (ui_list,trig_what_lis) {
int& tw = keybd2.trig_what;
tw = !tw;
extern const char* keys_trig_what [];
set_label (l, keys_trig_what, tw);
}
PICKED_OPTION (ui_list, ol_voice_is_lis) {
din0.dinfo.voice_is_voice = !din0.dinfo.voice_is_voice;
const char* viv = voice_is_lbls [din0.dinfo.voice_is_voice];
extern ui_list uis;
uis.cb_voice.set_text (viv);
MENU.handle_voice_tab_items (viv);
}
VALUE_CHANGED (ui_list, dpeu_lis) {
din0.update_drone_pendulums ();
}
void oscilloscope::show () {
visible = MENU.cb_scope.state;
}