1 /*
2 * menu.cc
3 * DIN Is Noise is copyright (c) 2006-2021 Jagannathan Sampath
4 * DIN Is Noise is released under GNU Public License 2.0
5 * For more information, please visit https://dinisnoise.org/
6 */
7 
8 #include "main.h"
9 #include "menu.h"
10 #include "ui_list.h"
11 #include "viewwin.h"
12 #include "din.h"
13 #include "keyboard_keyboard.h"
14 #include "mondrian.h"
15 #include "binaural_drones.h"
16 #include "tcl_interp.h"
17 #include "console.h"
18 #include "recorder.h"
19 #include "oscilloscope.h"
20 #include "ball.h"
21 #include "mesh.h"
22 #include "noiser.h"
23 #include "log.h"
24 #include "fft.h"
25 #include "file-utils.h"
26 #include "drawrrow.h"
27 #include "autorotator.h"
28 #include "autoflip.h"
29 #include "defvelaccel.h"
30 
31 #include <string>
32 #include <fstream>
33 
34 using namespace std;
35 
36 extern int mousex, mousey;
37 extern beat2value octave_shift;
38 
39 extern std::string INSTRUMENT;
40 extern const char* INSTRUMENTS[];
41 extern int CURRENT_INSTRUMENT, LAST_INSTRUMENT, NUM_INSTRUMENTS;
42 
43 extern float VOICE_VOLUME;
44 extern int NUM_OCTAVES;
45 extern void setup_plugin_labels ();
46 extern oscilloscope scope;
47 extern const float PI_BY_180;
48 extern char BUFFER [];
49 extern int wheely;
50 extern int line_height;
51 extern const char *ol_fixed_lbls [];
52 extern plugin_browser plugin__browser;
53 
54 #define SECONDS " seconds"
55 #define DEGREES " degrees"
56 
menu()57 menu::menu () :
58   diram (modulator::AM), dirfm (modulator::FM),
59 	bm_zoom_in(16), pb_zoom_in (16), bm_zoom_out(16), mb_zoom_out (16),
60 	abm_left (12), abm_right(12), abm_up(12), abm_down(12),
61 	abe_left (12), abe_right(12), abe_up(12), abe_down(12),
62 	abl_left (12, arrow_button::left), abl_right (12, arrow_button::right),
63 	gater_style_lis (ol_gater_style, "gr", " Style = "),
64 	am_style_lis (ol_am_style, "am", " AM style = "),
65 	fm_style_lis (ol_fm_style, "fm", " FM style = "),
66 	s_phrase_position (256, 16),
67 	td_tap_display (36),
68 	gc_top(0),
69 	gc_bottom(1)
70 	{
71   num_tabs = 0;
72 	am_depth = fm_depth = 0;
73 	dam_depth = dfm_depth = dam_bpm = dfm_bpm = 0;
74 
75 	cnl.id = 0;
76 	cnl.name = "Left Note";
77 	cnl.orient = mouse_slider_listener::X;
78 
79 	cnr.id = 1;
80 	cnr.name = "Right Note";
81 	cnr.orient = mouse_slider_listener::X;
82 
83 	arl.name = "Range Left";
84 	arl.orient = mouse_slider_listener::X;
85 
86 	arr.name = "Range Right";
87 	arr.orient = mouse_slider_listener::X;
88 
89 	arb.name = "Range Left & Right";
90 	arb.orient = mouse_slider_listener::Y;
91 
92 	rhl.name = "Range Height";
93 	rhl.orient = mouse_slider_listener::Y;
94 
95 	s_phrase_position.sizer.visible = 1;
96 
97 }
98 
setup_items()99 void menu::setup_items () {
100 
101 	b_close.visible = 0;
102 
103 	button* inst_ed [] = {
104     &b_keyboard_keyboard, // instruments
105 		&b_microtonal_keyboard,
106     &b_mondrian,
107 		&b_binaural_drones,
108 		&b_microtonal_keyboard_waveform, // editors
109 		&b_drone_waveform,
110 		&b_drone_modulation,
111 		&b_voice_modulation,
112 		&b_gater,
113 		&b_keyboard_keyboard_waveform,
114 		&b_attack,
115 		&b_decay,
116 		&b_midi_velocity,
117 		&b_delays,
118 		&b_octave_shift,
119 		&b_compressor,
120 		&b_morse_code,
121     &b_mondrian_waveform,
122     &b_mondrian_attack,
123     &b_mondrian_decay,
124 		&b_binaural_drones_waveform,
125 		&b_range_modulation,
126 		&b_range_width_height,
127 		&b_range_pitch_vol,
128 		&b_point_modulation,
129 		&b_noise_interpolator,
130 		&b_drone_pend,
131 	};
132 
133 	// all other menu items
134   widget* mi [] = {
135     &b_exit_din,
136 		&l_octave_shift,
137 		&ab_octave_down,
138 		&ab_octave_up,
139 		&sp_octave_shift_bpm,
140     &sp_gater_bpm,
141     &sp_voice_volume,
142     &cb_show_anchors,
143     &sp_change_drone_handle_size,
144     &sp_change_drone_trail_length,
145     &sp_am_depth,
146     &sp_fm_depth,
147     &sp_am_bpm,
148     &sp_fm_bpm,
149     &cb_instrument,
150     &cb_editors,
151     &cb_mkb_drone_params,
152     &cb_file,
153     &ol_gater_style,
154     &l_gater,
155     &ol_am_style,
156     &ol_fm_style,
157     &cb_mkb_drone_tools,
158     &ol_add_wand,
159     &b_move_drones,
160     &b_delete_drones,
161     &b_select_all_drones,
162     &b_invert_drone_selection,
163     &b_record_phrase,
164     &b_clear_phrases,
165     &l_phrase_position,
166     &s_phrase_position,
167     &ol_set_range,
168     &b_default_to_selected,
169 		&b_default_to_all,
170 		&b_selected_to_all,
171     &b_key_to_pitch_at_cursor,
172     &cb_scope,
173     &sp_scope_height,
174     &sp_scope_samples,
175     &l_tap_bpm,
176     &td_tap_display,
177     &l_tap_bpm_value,
178     &cb_am,
179     &cb_fm,
180     &cb_gater,
181     &cb_octave_shift,
182     &cb_auto_reset,
183     &cb_ed_tools,
184     &abe_left,
185     &abe_right,
186     &abe_up,
187     &abe_down,
188     &b_close,
189     &cb_snapx,
190     &cb_snapy,
191     &cb_snapboth,
192     &cb_snapnone,
193     &l_snap,
194     &pb_zoom_in,
195     &mb_zoom_out,
196     &b_insert_vertex,
197     &b_delete_vertex,
198     &b_fold_tangents,
199     &b_unfold_tangents,
200 		&ol_mirror,
201     &ol_vertices_carry_tangents,
202     &ol_mirror_tangents,
203     &cb_selection_only,
204     &b_undo,
205     &b_redo,
206     &b_copy,
207     &b_paste,
208     &b_draw_replacement_curve,
209     &l_library,
210     &abl_left,
211     &abl_right,
212     &lf_curve_name,
213     &b_add_curve,
214     &b_replace_curve,
215     &b_delete_curve,
216     &l_capture,
217     &b_start_capture,
218     &b_assign_capture,
219     &cb_label_vertices,
220     &cb_show_waveform_samples,
221     &sp_waveform_hz,
222     &b_pick_curve,
223     &sp_curve_limit,
224     &sp_waveform_periods,
225     &ol_curve_style,
226     &sp_curve_rpm,
227     &b_stop_rotating,
228     &cb_draw_curve,
229 		&cb_record,
230 		&b_clear_record,
231 		&lf_file,
232 		&b_save,
233 		&b_select_attractees,
234 		&b_select_attractors,
235 		&b_orbit_selected_drones,
236 		&cb_show_vel,
237 		&cb_show_accel,
238 		&sp_change_drone_vel,
239 		&sp_change_drone_accel,
240     &cb_show_gravity,
241     &balloon,
242     &sp_rotate_drone_vel,
243     &sp_drones_per_min,
244     &b_launch_drones,
245     &b_stop_launching_drones,
246     &ol_create_this,
247     &sp_mesh_rows,
248     &sp_mesh_cols,
249     &b_track_drones,
250     &b_select_tracked_drones,
251     &sp_bounces,
252     &sp_rebound,
253     &b_add_balls,
254     &b_move_selected_balls,
255     &b_delete_selected_targets,
256     &b_delete_all_targets,
257     &b_select_all_targets,
258     &b_invert_selected_targets,
259     &b_select_targets_in_box,
260     &b_split_horizontal,
261     &b_split_vertical,
262     &b_delete_box,
263     &sp_mondrian_min_voices,
264     &sp_mondrian_change_attack_time,
265     &sp_mondrian_change_decay_time,
266     &sp_mondrian_change_speed,
267     &b_freeze_balls,
268     &b_thaw_balls,
269 		&abm_left,
270 		&abm_right,
271 		&abm_up,
272 		&abm_down,
273 		&bm_zoom_in,
274 		&bm_zoom_out,
275 		&b_turn_off_ui,
276 		&b_set_targets,
277 		&b_clear_targets,
278 		&sp_drone_lifetime,
279 		&sp_orbit_insertion_time,
280 		&b_clear_modulations,
281 		&b_modulate_balls_up,
282 		&b_modulate_balls_down,
283 		&cb_binaural_drones_tools,
284 		&lf_master_volume,
285 		&sp_bd_separation,
286 		&b_create_binaurals_on_notes,
287 		&b_create_binaurals_from_pitch,
288 	 	&lf_bd_start_pitch,
289 		&sp_bd_pairs,
290 		&lf_bd_spacing,
291 		&cb_close_octave,
292 		&lf_vol_fade_time,
293 		&sp_mondrian_change_dir,
294 		&sp_mondrian_change_trail_size,
295 		&sp_mondrian_change_note_poly_points,
296 		&sp_mondrian_change_note_poly_radius,
297 		&b_auto_change_direction_clockwise,
298 		&b_stop_auto_changing_direction,
299 		&b_auto_change_direction_anti_clockwise,
300 		&b_flip_direction,
301 		&b_make_random_color,
302 		&ol_justification,
303 		&cb_resize_separation,
304 		&ol_key_note,
305 		&b_add_remove_slits,
306 		&b_select_wreckers,
307 		&b_select_healers,
308 		&b_switch_ball_type,
309 		&b_toggle_wreckers,
310 		&b_toggle_healers,
311 		&b_toggle_bouncers,
312 		&sp_mondrian_change_slit_size,
313 		&b_remove_slits_on_edge,
314 		&b_toggle_slit_anim,
315 		&cb_mondrian_auto_adjust_voices,
316 		&sp_mondrian_change_vol,
317 		&cb_draw_boxes,
318 		&cb_fill_boxes,
319 		&cb_draw_notes,
320 		&cb_label_notes,
321 		&ol_ball_types,
322 		&ol_split_types_h,
323 		&ol_split_types_v,
324 		&sp_mondrian_num_boxes,
325 		&b_make_note_grid,
326 		&b_make_nxn_grid,
327 		&b_delete_all_boxes,
328 		&cb_mkb_voice,
329 		&cb_mkb_misc,
330 		&b_select_launchers,
331 		&seloncre,
332 		&b_freeze_drones,
333 		&b_thaw_drones,
334 		&sp_dam_depth,
335 		&sp_dfm_depth,
336 		&sp_dam_bpm,
337 		&sp_dfm_bpm,
338 		&b_scale_drones,
339 		&b_rotate_drones,
340 		&ol_selection_targets,
341 		&sp_mondrian_change_slit_anim_time,
342 		&cb_mark_segments,
343 		&cb_auto_split_box,
344 		&cb_auto_delete_box,
345 		&sp_auto_split_time,
346 		&sp_auto_delete_time,
347 		&ol_auto_pick_box_split,
348 		&ol_auto_split_at,
349 		&ol_auto_split_orient,
350 		&ol_auto_pick_box_delete,
351 		&sp_min_split_size,
352 		&cb_speed,
353 		&cb_turn,
354 		&cb_teleport,
355 		&sp_turn_every,
356 		&sp_turn_min,
357 		&sp_turn_max,
358 		&sp_speed_every,
359 		&sp_speed_min,
360 		&sp_speed_max,
361 		&sp_max_speed,
362 		&sp_tel_every,
363 		&sp_tel_radius,
364 		&cb_draw_ball_position,
365 		&cb_draw_ball_heading,
366 		&cb_draw_ball_trails,
367 		&l_draw_ball,
368 		&cb_turn_sync,
369 		&cb_speed_sync,
370 		&sp_clone_every,
371 		&sp_max_clones,
372 		&sp_clone_offset,
373 		&sp_max_balls,
374 		&cb_clone,
375 		&cb_clone_can_clone,
376 		&ol_browse_balls,
377 		&cb_mon_tools,
378 		&cb_mon_parameters,
379 		&cb_mon_ballops,
380 		&cb_mon_boxops,
381 		&cb_mon_misc,
382 		&cb_transform,
383 		&sp_transform_every,
384 		&ol_bouncer,
385 		&ol_healer,
386 		&ol_wrecker,
387 		&cb_label_hz_vol,
388 		&il_binaural_drones,
389 		&cb_binaural_drones_edit,
390 		&bbd_select_all,
391 		&bbd_select_none,
392 		&bbd_invert_select,
393 		&bbd_delete,
394 		&bbd_sync,
395 		&lf_pitch_fade_time,
396 		&lf_modulation_amount,
397 		&bd_modulate_up,
398 		&bd_modulate_down,
399 		&bbd_modulate,
400 		&bbd_select2,
401 		&ol_select_what,
402 		&ol_select_rule,
403 		&bdf_value,
404 		&lf_l,
405 		&lf_r,
406 		&lf_sep,
407 		&lf_vol,
408 		&ol_just,
409 		&bbd_flip,
410 		&b_adjust_board_height,
411 		&b_adjust_range_left,
412 		&b_adjust_range_right,
413 		&b_adjust_range_both,
414 		&sp_snap_left,
415 		&sp_snap_right,
416 		&ol_bounce_style,
417 		&cb_mod_ran,
418 		&sp_range,
419 		&sp_ran_mod_width,
420 		&sp_ran_mod_width_bpm,
421 		&cb_mark_ran,
422 		&l_ran_mod,
423 		&b_rm_pause_resume,
424 		&b_rm_start_all,
425 		&b_rm_stop_all,
426 		&b_rm_toggle,
427 		&b_get_cur_ran,
428 		&ol_snap_style,
429 		&sp_ran_mod_height,
430 		&sp_ran_mod_height_bpm,
431 		&cb_mkb_ranges,
432 		&l_adjust_range,
433 		&l_adjust_height,
434 		&b_adjust_range_height,
435 		&dronearrow.shoulder.position,
436 		&dronearrow.shoulder.width,
437 		&l_drone_arrow,
438 		&sp_default_width,
439 		&sp_default_height,
440 		&b_change_note_left,
441 		&b_change_note_right,
442 		&ol_change_note_style,
443 		&ol_set_unset_toggle,
444 		&b_set,
445 		&b_unset,
446 		&b_toggle,
447 		&sp_browse_drone,
448 		&ol_drone_order,
449 		&l_drone_order,
450 		&ol_mesh_point,
451 		&f_mesh_xy,
452 		&cb_sync_rows_cols,
453 		&sp_mesh_dur,
454 		&b_flip_rows_cols,
455 		&cb_overlay,
456 		&dp_numdrones,
457 		&dp_bpm1,
458 		&dp_orient,
459 		&b_swap_curves,
460 		&cb_pitch_dis,
461 		&cb_vol_dis,
462 		&sp_lev_sz,
463 		&ol_change_note,
464 		&b_change_note_both,
465 		&sp_drone_master_vol,
466 		&l_use_drone_pend,
467 		&sp_drones_per_pend,
468 		&l_apply_to,
469 		&cb_am_bpm,
470 		&cb_fm_bpm,
471 		&b_set_to_mesh_rows,
472 		&b_set_to_mesh_cols,
473 		&ol_drone_is,
474 		&b_ball_trig,
475 		&ol_fixed,
476 		&cb_draw_mesh,
477 		&lf_conn_steps,
478 		&s_red_min,
479 		&s_green_min,
480 		&s_blue_min,
481 		&s_red_max,
482 		&s_green_max,
483 		&s_blue_max,
484 		&cb_conn_wrap,
485 		&separators.main,
486 		&separators.dp0,
487 		&cb_modulation,
488 		&cb_motion,
489 		&cb_visual,
490 		&b_connect,
491 		&b_disconnect,
492 		&ol_color,
493 		&separators.dp1,
494 		&b_abort_octave_shift,
495 		&sp_stiff,
496 		&b_arrow_reset,
497     &b_mute,
498     &b_unmute,
499     &gabt,
500     &sp_drone_vol,
501     &drone2noise,
502     &noise2drone,
503     &b_set_xform_center,
504     &autorotate.title,
505     &autorotate.whichl,
506     &autorotate.start,
507     &autorotate.stop,
508     &autorotate.toggle,
509     &autorotate.clockwise,
510     &autorotate.anticlockwise,
511     &autorotate.rpm,
512     &cb_defaults,
513     &sp_wand_dist,
514     &ol_drones_are,
515     &riset,
516     &fallt,
517     &lifetime,
518     &mortalize,
519     &reincarnate,
520     &immortalize,
521     &diram.vert,
522     &diram.hor,
523     &diram.vel,
524     &diram.accel,
525     &dirfm.vert,
526     &dirfm.hor,
527     &dirfm.vel,
528     &dirfm.accel,
529     &diram.lbl,
530     &dirfm.lbl,
531     &cb_chuck,
532     &chuck,
533     &chspeed,
534     &chflip,
535     &chtog,
536     &chlen,
537     &chapt,
538     &chtrail,
539     &handlesize,
540     &sva.lbl,
541     &sva.whats,
542     &sva.neg,
543     &sva.zero,
544     &sva.vert,
545     &sva.hor,
546     &sva.vel,
547     &sva.accel,
548     &autorotate.autoflip.lbl,
549     &autorotate.autoflip.angle,
550     &autorotate.autoflip.set,
551     &autorotate.autoflip.unset,
552     &autorotate.autoflip.toggle,
553     &dva.whichl,\
554     &dva.ldir,\
555     &dva.odir,\
556     &dva.neg,\
557     &dva.randomize,\
558     &dva.mag,\
559     &dva.clockwise,\
560     &dva.anticlockwise,\
561     &choutline,
562     &chautoresettrails,
563     &anchored,
564     &trailsize,
565     &dronearrow.neck,
566     &dronearrow.cap,
567     &dronearrow.decap,
568     &autorotate.deg,
569     &autorotate.tps,
570     &autorotate.mov,
571     &autorotate.smooth,
572     &autorotate.tick,
573     &dronearrowdefaults.lbl,
574     &dronearrowdefaults.neck,
575     &dronearrowdefaults.shoulder.position,
576     &dronearrowdefaults.shoulder.width,
577     &dronearrowdefaults.cap,
578     &dronearrowdefaults.arrow,
579     &trackcon,
580     &dva.autorotate.cb,
581     &dva.autorotate.mov,
582     &dva.autorotate.dir,
583     &dva.autorotate.rpm,
584     &dva.autorotate.dps,
585     &dva.autorotate.tps,
586     &dva.autoflip.cb,
587     &dva.autoflip.deg,
588     &velgt0,
589     &accelgt0,
590     &dva.sync,
591     // next item here
592 	};
593 
594 	int ii = 0;
595 	for (int i = 0; i < NUM_INSTRUMENTS; ++i) {
596 		button* ei = inst_ed[i];
597 		ei->id = i;
598 #ifndef __WIDGET_MOVE__
599 		ei->set_listener (&insl);
600 #endif
601 		items[ii++] = ei;
602 	}
603 	for (int i = NUM_INSTRUMENTS; i < n_inst_ed; ++i) {
604 		button* ei = inst_ed[i];
605 		ei->id = i + 1; // as 0 is instrument
606 #ifndef __WIDGET_MOVE__
607 		ei->set_listener (&edl);
608 #endif
609 		items[ii++] = ei;
610 	}
611 
612   for (int i = n_inst_ed, j = 0; i < nitems; ++i) items[ii++] = mi[j++];
613 
614   dlog << "+++ Items list setup +++ " << endl;
615 
616 #ifndef __WIDGET_MOVE__
617 	{
618 		button* btns [] = {&b_set_to_mesh_rows, &b_set_to_mesh_cols, &b_set, &b_unset, &b_toggle};
619 		click_listener* cl [] = {&stmrl, &stmcl, &sutl, &sutl, &sutl};
620 		checkbutton* cbtns [] = {&cb_am_bpm, &cb_fm_bpm};
621 		state_listener* sl [] = {&abl, &fbl};
622 		for (int i = 0; i < 5; ++i) btns[i]->set_listener (cl[i]);
623 		for (int i = 0; i < 2; ++i) cbtns[i]->set_listener (sl[i]);
624 
625 	}
626 #endif
627 
628   // tabs
629   num_tabs = 0;
630   last_tab = next_tab = cur_tab = 0;
631 	next_tab_instr = 0;
632   checkbutton* cb_tabs [] = {
633 		&cb_file,
634 		&cb_instrument,
635 		&cb_editors,
636 		&cb_mkb_voice,
637 		&cb_mkb_drone_tools,
638 		&cb_mkb_drone_params,
639 		&cb_mkb_ranges,
640 		&cb_mkb_misc,
641 		&cb_ed_tools,
642 		&cb_mon_tools,
643 		&cb_mon_parameters,
644 		&cb_mon_ballops,
645 		&cb_mon_boxops,
646 		&cb_mon_misc,
647 		&cb_binaural_drones_tools,
648 		&cb_binaural_drones_edit,
649 	};
650 
651   static const char* const cb_tab_lbls [] = {
652 		"File",
653 		"Instrument",
654 		"Editors",
655 		"Voice",
656 		"Drone Tools",
657 		"Drone Params",
658 		"Ranges",
659 		"Misc",
660 		"Tools",
661 		"Tools",
662 		"Params",
663 		"Ball Ops",
664 		"Box Ops",
665 		"Misc",
666 		"Create",
667 		"Edit"
668 	};
669 
670   for (int i = 0; i < 16; ++i) {
671     checkbutton* ci = cb_tabs[i];
672     ci->set_text (cb_tab_lbls[i]);
673     ci->set_listener (this);
674   }
675 
676   widget* wfile [] = {
677 		&b_exit_din,
678 		&cb_record,
679 		&b_clear_record,
680 		&b_save,
681 		&lf_file,
682 		&b_turn_off_ui,
683     &cb_scope,
684     &sp_scope_height,
685     &sp_scope_samples
686   };
687 
688 #ifndef __WIDGET_MOVE__
689 	cb_record.set_listener (&recl);
690 	b_clear_record.set_listener (&recl);
691 	b_save.set_listener (&recl);
692 	b_exit_din.set_listener (&miscl);
693 	b_turn_off_ui.set_listener (&miscl);
694 	lf_file.fld.typing_lsnr = &recl;
695 #endif
696 
697 	lf_file.fld.set_text ("din.wav");
698 	lf_file.lbl.set_text ("File on Desktop?");
699 
700   widget* winst [] = {
701     &b_microtonal_keyboard,
702     &b_keyboard_keyboard,
703     &b_mondrian,
704 		&b_binaural_drones
705   };
706 
707   widget* weds [] = {
708     &b_microtonal_keyboard_waveform,
709     &b_drone_waveform,
710     &b_drone_modulation,
711     &b_voice_modulation,
712 		&b_range_modulation,
713 		&b_range_width_height,
714 		&b_range_pitch_vol,
715     &b_gater,
716     &b_keyboard_keyboard_waveform,
717     &b_attack,
718     &b_decay,
719     &b_midi_velocity,
720     &b_mondrian_waveform,
721     &b_mondrian_attack,
722     &b_mondrian_decay,
723 		&b_binaural_drones_waveform,
724     &b_delays,
725     &b_octave_shift,
726     &b_compressor,
727     &b_morse_code,
728 		&b_point_modulation,
729 		&b_noise_interpolator,
730 		&b_drone_pend,
731   };
732 
733 	widget* wvoice [] = {
734 		&sp_voice_volume,
735 		&b_record_phrase,
736 		&b_clear_phrases,
737 		&s_phrase_position,
738 		&l_phrase_position,
739 		&sp_am_depth,
740 		&sp_fm_depth,
741 		&sp_am_bpm,
742 		&sp_fm_bpm,
743 		&ol_am_style,
744 		&ol_fm_style,
745 	};
746 
747 #ifndef __WIDGET_MOVE__
748   for (int i = 1; i < 3; ++i) static_cast<button*>(wvoice[i])->set_listener (&pcl); // phrase commands listener
749 #endif
750 
751 	widget* wdrone_tools [] = {
752 		&ol_add_wand,
753 		&b_delete_drones,
754 		&b_select_all_drones,
755 		&b_invert_drone_selection,
756 		&b_orbit_selected_drones,
757 		&b_select_attractees,
758 		&b_select_attractors,
759 		&b_launch_drones,
760 		&b_stop_launching_drones,
761 		&b_track_drones,
762 		&b_select_tracked_drones,
763 		&b_set_targets,
764 		&b_clear_targets,
765 		&b_select_launchers,
766 		&b_freeze_drones,
767 		&b_thaw_drones,
768 		&b_flip_rows_cols,
769 		&ol_create_this,
770 		&sp_mesh_rows,
771 		&sp_mesh_cols,
772 		&sp_browse_drone,
773 		&ol_drone_order,
774 		&l_drone_order,
775 		&cb_sync_rows_cols,
776 		&sp_mesh_dur,
777 		&dp_numdrones,
778 		&dp_bpm1,
779 		&dp_orient,
780 		&l_use_drone_pend,
781 		&cb_am_bpm,
782 		&cb_fm_bpm,
783 		&sp_drones_per_pend,
784 		&l_apply_to,
785 		&b_set_to_mesh_rows,
786 		&b_set_to_mesh_cols,
787 		&b_move_drones,
788 		&b_scale_drones,
789 		&b_rotate_drones,
790 		&b_connect,
791 		&b_disconnect,
792 		&lf_conn_steps,
793 		&cb_conn_wrap,
794     &b_mute,
795     &b_unmute,
796     &gabt,
797     &drone2noise,
798     &noise2drone,
799     &b_set_xform_center,
800     &mortalize,
801     &reincarnate,
802     &immortalize,
803     &chuck,
804     &trackcon,
805     &balloon,
806     &b_set,\
807     &b_unset,\
808     &b_toggle,\
809     &ol_set_unset_toggle,\
810 	};
811 
812   LISTEN(ol_add_wand,&awdl)
813   LISTEN(ol_add_wand.option,&dcl)
814   LISTEN(ol_drones_are, &darl)
815 
816 #ifndef __WIDGET_MOVE__
817 	LISTEN(b_scale_drones,&bsdl)
818 	LISTEN(b_rotate_drones,&brdl)
819 	LISTEN(b_move_drones,&bmdl)
820 	LISTEN(balloon,&dugl)
821   LISTEN(b_mute,&mul)
822   LISTEN(b_unmute,&umul)
823   LISTEN(drone2noise,&d2nl)
824   LISTEN(noise2drone,&n2dl)
825   LISTEN(seloncre,&dcl);
826   LISTEN(cb_conn_wrap, &wrapl)
827   LISTEN(b_connect, &bconl)
828   LISTEN(b_disconnect, &bdconl)
829   LISTEN(b_set_xform_center, &xcl);
830   LISTEN(mortalize,&morl)
831   LISTEN(immortalize,&immorl)
832   LISTEN(reincarnate,&reinl)
833   LISTEN(chuck, &chl)
834   LISTEN(chflip,&flpl)
835   LISTEN(chtog,&ctogl)
836   LISTEN(chautoresettrails,&aurl)
837 #endif
838 
839 	sp_stiff.set ("Connection stiffness", 0.001f, 0.0f, 1.0f, &stiffl);
840   gabt.set (0.1f, 0, MILLION, &gabtl);
841   gabt.set_text ("In", SECONDS);
842 	sp_drones_per_pend.set ("Drones Per Pendulum", 1, 2, MILLION, &dppl, 0);
843 	l_use_drone_pend.set_text ("Drone Pendulum's parameters?");
844 	l_apply_to.set_text ("Apply to");
845 
846   DECL_DRONE_PARAMS
847 
848   ol_drone_is.set_listener (this);
849   diram.setup ("Set AM direction to: ");
850   dirfm.setup ("Set FM direction to: ");
851   riset.set ("Rise time", 0.1f, 0, MILLION, &rl, 0);
852   fallt.set ("Fall time", 0.1f, 0, MILLION, &fl, 0);
853   sp_wand_dist.set ("Wand distance", 1, 0, MILLION, &wandl);
854 
855   autorotate.setup ();
856 
857   sva.setup ();
858   dva.setup ();
859 
860   anchored.set_listener (&ancl);
861 
862   chspeed.set ("Speed", 1.0f, &spdl); chspeed.limits = 0;
863   chlen.set ("Length", 1.0f, &lenl);
864   chapt.set ("Angle per turn", 0.1f, &apfl); chapt.limits = 0;
865   chtrail.set ("Trail length", 10000, &chtll);
866 
867   handlesize.set ("Handle size", 1, 0, MILLION, &handl);
868   trailsize.set ("Trail size", 1, 0, MILLION, &trll);
869   lifetime.set ("Lifetime", 0.1f, 0, MILLION, &lifel, 0);
870 
871 #ifndef __WIDGET_MOVE__
872 	for (int i = 1; i < 17; ++i) dynamic_cast<button*>(wdrone_tools[i])->set_listener (&dcl);
873 	for (int i = 0, j = DRONE_PARAMS_N - 1; i < 4; ++i) dynamic_cast<checkbutton*>(wdrone_params[j--])->set_listener (&dcl);
874 #endif
875 
876   static const char* txt [] = {"AM Depth", "FM Depth", "AM BPM", "FM BPM"};
877 	spinner<float>* spn [] = {&sp_am_depth, &sp_fm_depth, &sp_am_bpm, &sp_fm_bpm};
878   change_listener<field>* vlis [] = {&amdl, &fmdl, &ambpml, &fmbpml};
879 	spinner<float>* dspn [] = {&sp_dam_depth, &sp_dfm_depth, &sp_dam_bpm, &sp_dfm_bpm};
880 	change_listener<field>* dlis [] = {&damdl, &dfmdl, &dambpml, &dfmbpml};
881 
882 	for (int i = 0; i < 4; ++i) {
883     const char* txti = txt[i];
884 		spinner<float>* dspni = dspn[i];
885     dspni->set (txti, 1.0f, dlis[i]);
886 		dspni->orient = mouse_slider_listener::Y;
887 		spinner<float>* spni = spn[i];
888 		spni->set_text (txti);
889 		spni->set_listener (vlis[i]);
890 		spni->orient = mouse_slider_listener::Y;
891 	}
892 
893 	for (int i = 1; i < 4; ++i) spn[i]->set_delta (1.0f);
894 	sp_am_depth.set_delta (din0.am_delta.depth);
895 	sp_am_bpm.set_limits (0, MILLION);
896 	sp_fm_bpm.set_limits (0, MILLION);
897 
898 	widget* wranges [] = {
899 		&b_selected_to_all,
900 		&b_default_to_selected,
901 		&b_default_to_all,
902 		&b_adjust_range_left,
903 		&b_adjust_range_right,
904 		&b_adjust_range_both,
905 		&b_adjust_range_height,
906 		&b_adjust_board_height,
907 		&b_rm_start_all,
908 		&b_rm_stop_all,
909 		&b_rm_toggle,
910 		&b_rm_pause_resume,
911 		&b_get_cur_ran,
912 		&cb_mod_ran,
913 		&cb_mark_ran,
914 		&sp_ran_mod_width,
915 		&sp_ran_mod_width_bpm,
916 		&sp_ran_mod_height,
917 		&sp_ran_mod_height_bpm,
918 		&sp_range,
919 		&l_ran_mod,
920 		&l_adjust_height,
921 		&l_adjust_range,
922 		&ol_set_range,
923 		&sp_default_width,
924 		&sp_default_height,
925 		&b_change_note_left,
926 		&b_change_note_right,
927 		&ol_change_note_style,
928 		&ol_change_note,
929 		&b_change_note_both,
930 		&ol_fixed,
931     &sp_snap_left,
932     &sp_snap_right,
933     &ol_snap_style,
934 	};
935 
936 #ifndef __WIDGET_MOVE__
937 	for (int i = 0; i < 3; ++i) static_cast<button*>(wranges[i])->set_listener (&sral);
938 	for (int i = 3; i < 6; ++i) static_cast<button*>(wranges[i])->set_listener (&rwl);
939 	b_adjust_range_height.set_listener (&rhl);
940 	b_adjust_board_height.set_listener (&bhl);
941 	for (int i = 8; i < 13; ++i) static_cast<button*>(wranges[i])->set_listener (&rml);
942 	cb_mod_ran.set_listener (&rml);
943 	cb_mark_ran.set_listener (&rml);
944 	b_change_note_left.set_listener (&cnl);
945 	b_change_note_right.set_listener (&cnr);
946 	b_change_note_both.set_listener (&cnb);
947 #endif
948 
949   ol_change_note.set_listener (&cnol);
950   ol_change_note_style.set_listener (&cnsl);
951 
952 	widget* wmisc [] = {
953 		&l_octave_shift,
954 		&ab_octave_down,
955 		&ab_octave_up,
956 		&sp_octave_shift_bpm,
957 		&l_gater,
958 		&sp_gater_bpm,
959 		&ol_gater_style,
960 		&b_key_to_pitch_at_cursor,
961 		&l_tap_bpm,
962 		&td_tap_display,
963 		&l_tap_bpm_value,
964 		&cb_am,
965 		&cb_fm,
966 		&cb_gater,
967 		&cb_octave_shift,
968 		&cb_auto_reset,
969 		&cb_pitch_dis,
970 		&cb_vol_dis,
971 		&sp_lev_sz,
972 		&b_abort_octave_shift,
973 	};
974 
975 #ifndef __WIDGET_MOVE__
976 	LISTEN(b_abort_octave_shift, &aosl)
977 	cb_draw_mesh.set_listener (&dml);
978 	cb_pitch_dis.set_listener (&pvdl);
979 	cb_vol_dis.set_listener (&pvdl);
980 #endif
981 
982   sp_lev_sz.set ("Level size", 1, 1, MILLION, &pvdl);
983 
984   widget* wetools [] = { // curve editors tools
985     &abe_left,
986     &abe_right,
987     &abe_up,
988     &abe_down,
989     &pb_zoom_in,
990     &mb_zoom_out,
991 		&l_snap,
992     &cb_snapx,
993     &cb_snapy,
994     &cb_snapboth,
995     &cb_snapnone,
996     &b_pick_curve,
997     &b_insert_vertex,
998     &b_delete_vertex,
999 		&b_draw_replacement_curve,
1000 		&b_undo,
1001 		&b_redo,
1002 		&b_copy,
1003 		&b_paste,
1004 		&b_swap_curves,
1005 		&b_fold_tangents,
1006 		&b_unfold_tangents,
1007 		&ol_mirror,
1008 		&cb_selection_only,
1009 		&ol_vertices_carry_tangents,
1010 		&ol_mirror_tangents,
1011 		&lf_curve_name,
1012 		&sp_curve_limit,
1013 		&ol_curve_style,
1014     &l_library,
1015     &abl_left,
1016     &abl_right,
1017 		&b_add_curve,
1018 		&b_replace_curve,
1019 		&b_delete_curve,
1020     &l_capture,
1021     &b_start_capture,
1022     &b_assign_capture,
1023     &cb_draw_curve,
1024 		&cb_label_vertices,
1025 		&cb_mark_segments,
1026     &cb_show_waveform_samples,
1027 		&sp_waveform_hz,
1028     &sp_waveform_periods,
1029     &sp_curve_rpm,
1030     &b_stop_rotating,
1031 		&cb_overlay,
1032 		&b_swap_curves
1033   };
1034 
1035   widget* wmon [] = { // mondrian tools
1036     &b_add_balls,
1037     &b_move_selected_balls,
1038     &b_delete_selected_targets,
1039     &b_delete_all_targets,
1040     &b_select_all_targets,
1041     &b_invert_selected_targets,
1042     &b_split_horizontal,
1043     &b_split_vertical,
1044     &b_delete_box,
1045     &b_select_targets_in_box,
1046     &b_freeze_balls,
1047     &b_thaw_balls,
1048 		&b_clear_modulations,
1049 		&b_modulate_balls_up,
1050 		&b_modulate_balls_down,
1051 		&b_auto_change_direction_clockwise,
1052 		&b_auto_change_direction_anti_clockwise,
1053 		&b_stop_auto_changing_direction,
1054 		&b_flip_direction,
1055 		&b_make_random_color,
1056 		&b_add_remove_slits,
1057 		&b_select_wreckers,
1058 		&b_select_healers,
1059 		&b_switch_ball_type,
1060 		&b_toggle_wreckers,
1061 		&b_toggle_healers,
1062 		&b_toggle_bouncers,
1063 		&b_remove_slits_on_edge,
1064 		&b_toggle_slit_anim,
1065 		&b_make_note_grid,
1066 		&b_make_nxn_grid,
1067 		&b_delete_all_boxes,
1068 		&b_ball_trig,
1069 		&ol_ball_types,
1070 		&ol_split_types_h,
1071 		&ol_split_types_v,
1072 		&sp_mondrian_num_boxes,
1073 		&ol_selection_targets,
1074   };
1075 
1076 
1077   arrow_button* mnav[] = {&abm_left, &abm_down, &abm_right, &abm_up};
1078   int mdirs [] = {arrow_button::left, arrow_button::down, arrow_button::right, arrow_button::up};
1079   for (int i = 0; i < 4; ++i) {
1080     arrow_button* ab = mnav[i];
1081     ab->set_dir (mdirs[i]);
1082   }
1083 
1084   widget* wmon_pars [] = { // mondrian parameters
1085     &l_octave_shift,
1086     &ab_octave_down,
1087     &ab_octave_up,
1088     &sp_octave_shift_bpm,
1089 		&b_abort_octave_shift,
1090     &sp_mondrian_min_voices,
1091     &sp_mondrian_change_attack_time,
1092     &sp_mondrian_change_decay_time,
1093     &sp_mondrian_change_speed,
1094 		&sp_mondrian_change_dir,
1095 		&sp_mondrian_change_trail_size,
1096 		&sp_mondrian_change_note_poly_points,
1097 		&sp_mondrian_change_note_poly_radius,
1098 		&sp_mondrian_change_slit_size,
1099 		&sp_mondrian_change_slit_anim_time,
1100 		&cb_mondrian_auto_adjust_voices,
1101 		&sp_mondrian_change_vol
1102   };
1103 
1104 	widget* wmon_misc [] = { // mondrian misc
1105 		&l_draw_ball,
1106 		&abm_left,
1107 		&abm_right,
1108 		&abm_up,
1109 		&abm_down,
1110 		&bm_zoom_in,
1111 		&bm_zoom_out,
1112 		&cb_draw_boxes,
1113 		&cb_fill_boxes,
1114 		&cb_draw_notes,
1115 		&cb_label_notes,
1116 		&cb_label_hz_vol,
1117 		&cb_draw_ball_position,
1118 		&cb_draw_ball_heading,
1119 		&cb_draw_ball_trails
1120 	};
1121 
1122 	widget* wmon_boxops [] = {
1123 		&cb_auto_split_box,
1124 		&cb_auto_delete_box,
1125 		&sp_auto_split_time,
1126 		&sp_auto_delete_time,
1127 		&ol_auto_pick_box_split,
1128 		&ol_auto_split_at,
1129 		&ol_auto_split_orient,
1130 		&ol_auto_pick_box_delete,
1131 		&sp_min_split_size
1132 	};
1133 
1134 	widget* wmon_ballops [] = {
1135 		&cb_turn, &cb_speed, &cb_teleport, &cb_clone, &sp_turn_every, &sp_turn_min, &sp_turn_max,
1136 		&sp_speed_every, &sp_speed_min, &sp_speed_max, &sp_max_speed, &sp_tel_every, &sp_tel_radius,
1137 		&cb_turn_sync, &cb_speed_sync, &sp_clone_every, &sp_max_clones, &sp_clone_offset, &sp_max_balls,
1138 		&cb_clone_can_clone, &ol_browse_balls,
1139 		&cb_transform, &sp_transform_every, &ol_bouncer, &ol_healer, &ol_wrecker,
1140 	};
1141 
1142 	spinner<float>* bospn [] = {&sp_turn_every, &sp_speed_every, &sp_tel_every, &sp_clone_every, &sp_transform_every};
1143 	float bodta [] = {0.01f, 0.01f, 1.0f, 1.0f, 1.0f};
1144 	for (int i = 0; i < ball_op::NUM_OPS; ++i) {
1145 		spinner<float>* spni = bospn[i];
1146 		spni->set_text ("Every", SECONDS);
1147     spni->set (bodta[i], 0.0f, MILLION, &bolis);
1148 	}
1149 	sp_turn_min.set_text ("Clockwise Max", DEGREES);
1150   sp_turn_min.set (1, 0, MILLION, &bolis);
1151 	sp_turn_max.set_text ("Anti-clockwise Max", DEGREES);
1152   sp_turn_max.set (1, 0, MILLION, &bolis);
1153   sp_speed_min.set ("Brake", 0.1f, 0, MILLION, &bolis);
1154   sp_speed_max.set ("Accelerate", 0.1f, 0, MILLION, &bolis);
1155   sp_max_speed.set ("Max speed", 1, 0, MILLION, &bolis);
1156 	sp_tel_radius.set ("Max distance", 1, 0, MILLION, &bolis);
1157 	sp_clone_offset.set ("Offset", 1.0f, 0, MILLION, &bolis);
1158 	sp_max_clones.set ("Max clones", 1, 1, MILLION, &bolis);
1159 	sp_max_balls.set ("Max balls", 1, 0, MILLION,&bolis);
1160 
1161 #ifndef __WIDGET_MOVE__
1162 	checkbutton* bocbn [] = {&cb_turn, &cb_speed, &cb_teleport, &cb_clone, &cb_transform};
1163 	for (int i = 0; i < ball_op::NUM_OPS; ++i) bocbn[i]->set_listener (&bolis);
1164 	for (int i = 1; i < 7; ++i) static_cast<button*>(wmon_misc[i])->set_listener (&monl);
1165 	for (int i = 7; i < 15; ++i) static_cast<checkbutton*>(wmon_misc[i])->set_listener (&monl);
1166   for (int i = 0; i < 33; ++i) static_cast<button*>(wmon[i])->set_listener (&monl);
1167   for (int i = 0; i < 6; ++i) static_cast<button*>(wetools[i])->set_listener (&pzl);
1168   for (int i = 7; i < 11; ++i) static_cast<checkbutton*>(wetools[i])->set_listener (&snl);
1169 
1170   button* crvops [] = {
1171     &b_pick_curve,
1172     &b_insert_vertex,
1173     &b_delete_vertex,
1174     &b_draw_replacement_curve,
1175     &b_fold_tangents,
1176     &b_unfold_tangents,
1177     &ol_mirror.option,
1178     &b_copy,
1179     &b_paste,
1180     &b_swap_curves,
1181     &b_undo,
1182     &b_redo,
1183     &abl_left,
1184     &abl_right,
1185     &b_add_curve,
1186     &b_replace_curve,
1187     &b_delete_curve,
1188     &b_start_capture,
1189     &b_assign_capture,
1190   };
1191 
1192   for (int i = 0; i < 19; ++i) crvops[i]->set_listener (&col);
1193 
1194 #endif
1195 
1196 	options_list* oll [] = {&ol_ball_types, &ol_split_types_h, &ol_split_types_v, &ol_selection_targets,
1197 													&ol_auto_pick_box_split, &ol_auto_split_at, &ol_auto_split_orient, &ol_auto_pick_box_delete};
1198 	for (int i = 0; i < 8; ++i) {
1199 		options_list* oli = oll[i];
1200 		oli->set_listener (&monl);
1201 	}
1202 	ol_split_types_h.set_text (mondrian_listener::split_types[monl.hsplit]);
1203 	ol_split_types_v.set_text (mondrian_listener::split_types[monl.vsplit]);
1204 	ol_selection_targets.set_text (mondrian_listener::selection_targets[mondrian0.sel_tar]);
1205   ol_browse_balls.set_listener (&bolis);
1206 
1207   b_undo.click_repeat = b_redo.click_repeat = 1;
1208   abl_left.click_repeat = abl_right.click_repeat = 1;
1209 
1210   ol_mirror.set_listener (this);
1211   lf_curve_name.set_listener (&col);
1212 #ifndef __WIDGET_MOVE__
1213 	cb_label_vertices.set_listener (&col);
1214 	cb_mark_segments.set_listener (&col);
1215 	cb_overlay.set_listener (&col);
1216 	cb_draw_curve.set_listener (&col);
1217 #endif
1218 
1219 	widget* wbd [] = { // binaural drones
1220 		&b_create_binaurals_on_notes,
1221 		&b_create_binaurals_from_pitch,
1222 		&sp_bd_separation,
1223 		&sp_bd_pairs,
1224 		&lf_bd_start_pitch,
1225 		&lf_bd_spacing,
1226 		&ol_justification,
1227 		&ol_key_note,
1228 		&cb_resize_separation,
1229 		&cb_close_octave,
1230 	};
1231 
1232 	widget* wbde [] = {
1233 		&bbd_select_all,
1234 		&bbd_select_none,
1235 		&bbd_invert_select,
1236 		&bbd_delete,
1237 		&bbd_sync,
1238 		&bbd_select2,
1239 		&bd_modulate_up,
1240 		&bd_modulate_down,
1241 		&bbd_modulate,
1242 		&bbd_flip,
1243 		&il_binaural_drones,
1244 		&lf_vol_fade_time,
1245 		&lf_master_volume,
1246 		&lf_pitch_fade_time,
1247 		&lf_modulation_amount,
1248 		&ol_select_what,
1249 		&ol_select_rule,
1250 		&bdf_value,
1251 		&lf_l,
1252 		&lf_r,
1253 		&lf_sep,
1254 		&lf_vol,
1255 		&ol_just
1256 	};
1257 
1258 	il_binaural_drones.sel_lis = &bdl;
1259 	lf_sep.fld.set_text (0.0f);
1260 	ol_just.set_text (binaural_drones_listener::justs[binaural_drone::CENTER]);
1261 	ol_just.set_listener (&bdl);
1262 
1263 	bd_modulate_up.set_size (24);
1264 	bd_modulate_down.set_size (24);
1265 	bd_modulate_down.set_dir (arrow_button::left);
1266 
1267 #ifndef __WIDGET_MOVE__
1268 	for (int i = 0; i < 10; ++i) static_cast<button*>(wbde[i])->set_listener (&bdl);
1269 	for (int i = 0; i < 2; ++i) static_cast<button*>(wbd[i])->set_listener (&bdl); // binaural drones commands
1270 	cb_close_octave.set_listener (&bdl);
1271 	cb_resize_separation.set_listener (&bdl);
1272 #endif
1273 
1274   ol_select_what.set_listener (&bdl);
1275   ol_select_rule.set_listener (&bdl);
1276 	ol_justification.set_listener (&bdl);
1277 	ol_key_note.set_listener (&bdl);
1278 
1279 	label_field* lfb [] = {
1280     &lf_bd_start_pitch, &lf_bd_spacing, &lf_master_volume, &lf_vol_fade_time,
1281     &lf_pitch_fade_time, &lf_modulation_amount, &lf_l, &lf_r, &lf_sep, &lf_vol
1282   };
1283 	string lfbs [] = {
1284     "Start Pitch (Hz)", "Spacing (Hz)", "Master volume (%)", "Volume fade time (secs)",
1285     "Pitch fade time (secs)", "Amount", "L (Hz)", "R (Hz)", "Separation (Hz)", "Volume (%)"
1286   };
1287 	for (int i = 0; i < 10; ++i) {
1288 		label_field* li = lfb[i];
1289 		li->set_label (lfbs[i]);
1290 		li->set_listener (&bdl);
1291 	}
1292 
1293 	sp_bd_separation.set ("Separation (Hz)", 1.0f, 0.0f, MILLION, 0, 0);
1294 	sp_bd_separation.set_value (1.0f);
1295 	sp_bd_separation.orient = mouse_slider_listener::NONE;
1296 
1297 	sp_bd_pairs.set ("Number of Pairs", 1, 1, MILLION, 0, 0);
1298 	sp_bd_pairs.set_value (1);
1299 	sp_bd_pairs.orient = mouse_slider_listener::NONE;
1300 
1301 
1302   for (int i = 0; i < 23; ++i) {
1303 		editors.push_back (weds[i]);
1304 		//weds[i]->set_moveable(1);
1305 	}
1306 
1307   widget** wmap [] = {
1308 		wfile,
1309 		winst,
1310 		weds,
1311 		wvoice,
1312 		wdrone_tools,
1313 		wdrone_params,
1314 		wranges,
1315 		wmisc,
1316 		wetools,
1317 		wmon,
1318 		wmon_pars,
1319 		wmon_ballops,
1320 		wmon_boxops,
1321 		wmon_misc,
1322 		wbd,
1323 		wbde
1324 	};
1325   int numw [] = {
1326 		9,
1327 		4,
1328 		23,
1329 		11,
1330 		58,
1331 		DRONE_PARAMS_N,
1332 		35,
1333 		20,
1334 		47,
1335 		38,
1336 		17,
1337 		26,
1338 		9,
1339 		15,
1340 		10,
1341 		23
1342 	};
1343 
1344 	lf_conn_steps.set_label ("Steps");
1345 	LISTEN(lf_conn_steps, &stepsl)
1346 	lf_conn_steps.fld.typing_lsnr = &stepsl;
1347 	lf_conn_steps.fld.expr = 0;
1348 
1349 	DECL_COLOR_SLIDERS
1350 	color clrs [] = {color(1.0f, 0.0f, 0.0f), color(0.0f, 1.0f, 0.0f), color(0.0f, 0.0f, 1.0f),
1351 										color(1.0f, 0.0f, 0.0f), color(0.0f, 1.0f, 0.0f), color(0.0f, 0.0f, 1.0f)};
1352 
1353 	float svals [] = {0.1, 0.1, 0.1, 1, 1, 1};
1354 	for (int i = 0; i < COLOR_SLIDERS_M; ++i) {
1355 		slider<float>& si = dynamic_cast<slider<float>&>(*slrs [i]);
1356 		si.set_width_height (128, si.extents.height);
1357 		color& ci = clrs [i];
1358 		si.set_color (ci.r, ci.g, ci.b);
1359 		si.set_limits (0.0f, 1.0f);
1360 #ifndef __WIDGET_MOVE__
1361 		si.set_listener (&cscl, &cssl);
1362 #endif
1363 		si.set_val (svals[i]);
1364 	}
1365 
1366 	colorer.schemes[0]=&gc_top;
1367 	colorer.schemes[1]=&gc_bottom;
1368 	colorer.schemes[2]=&gc_blend;
1369 	colorer.schemes[3]=&gc_rand;
1370 	colorer.i = colorer_t::RANDOM;
1371 
1372 	LISTEN(ol_color,&ocoll)
1373   LISTEN(ol_fixed,&fxl)
1374   LISTEN(ol_snap_style,&sdl);
1375 
1376 	separator* seps [] = {&separators.main, &separators.dp0, &separators.dp1};
1377 	const char* sepsn [] = {"main", "dp0", "dp1"};
1378 	for (int i = 0; i < 3; ++i) {
1379 		separator& si = *seps[i];
1380 		si.set_name (sepsn[i]);
1381 	}
1382 
1383   for (int i = 0; i < 16; ++i) {
1384     int n = numw[i];
1385     widget** wmi = wmap[i];
1386     vector<widget*>& vw = tab_members[cb_tabs[i]];
1387     for (int m = 0; m < n; ++m) {
1388 			vw.push_back (wmi[m]);
1389 #ifdef __WIDGET_MOVE__
1390 			wmi[m]->set_moveable(1); // to move item
1391 #endif
1392 		}
1393     vw.push_back (&separators.main);
1394   }
1395 
1396 	sp_voice_volume.set ("Volume", 0.001f, -MILLION, MILLION, &vvl);
1397 	sp_drone_master_vol.set ("Master volume", 0.001f, -MILLION, MILLION, &dmvol);
1398   sp_drone_vol.set ("Volume", 0.01f, -MILLION, MILLION, &dvol);
1399   sp_drone_vol.set_value (0.0f);
1400 
1401   l_octave_shift.set_text ("Octave Shift");
1402   ab_octave_down.set_dir (arrow_button::left);
1403   ab_octave_up.set_dir (arrow_button::right);
1404 
1405 #ifndef __WIDGET_MOVE__
1406   ab_octave_down.set_listener (&osl);
1407   ab_octave_up.set_listener (&osl);
1408 #endif
1409 	int arrow_size = 24;
1410   ab_octave_up.set_size (arrow_size);
1411   ab_octave_down.set_size (arrow_size);
1412 	sp_octave_shift_bpm.set ("BPM", 1, 0.0f, MILLION, &osl);
1413 
1414 	sp_gater_bpm.set ("BPM", 1, 0, MILLION, &gbl);
1415   ol_gater_style.set_text (" style = ");
1416   ol_gater_style.set_listener (&gater_style_lis);
1417 
1418 	l_gater.set_text ("Gater");
1419 	l_gater.add_child (&sp_gater_bpm);
1420 	l_gater.add_child (&ol_gater_style);
1421 
1422 #ifdef __WIDGET_MOVE__
1423 
1424 	int wek [] = {7, 13, 2, 3, 6, 3, 3, 3, 2};
1425 	for (int i = 0, j = 4, k = 0; i < 9; ++i) {
1426 		k = wek[i];
1427 		makehier (&wetools[j], k);
1428 		j += k;
1429 	}
1430 
1431 	widget* osn [] = {&l_octave_shift, &ab_octave_down, &ab_octave_up, &b_abort_octave_shift, &sp_octave_shift_bpm, 0};
1432   makefam (osn, 5);
1433 
1434 	widget* brs [] = {&ol_set_range, &b_default_to_selected, &b_default_to_all, &b_selected_to_all, 0};
1435 	makehier (brs);
1436 
1437 	widget* aht [] = {&l_adjust_height, &b_adjust_range_height, &b_adjust_board_height, 0};
1438 	makehier (aht);
1439 
1440 	widget* arb [] = {&l_adjust_range, &b_adjust_range_left, &b_adjust_range_right, &b_adjust_range_both, 0};
1441 	makehier (arb);
1442 
1443 	widget* brm [] = {&l_ran_mod, &b_rm_pause_resume, &b_rm_start_all, &b_rm_stop_all, &b_rm_toggle, 0};
1444 	makehier (brm);
1445 
1446 	widget* brc [] = {&ol_change_note, &b_change_note_left, &b_change_note_right, &b_change_note_both, &ol_change_note_style, 0};
1447 	makehier (brc);
1448 
1449 	widget* wmmv [] = {&cb_modulation, &cb_visual, &cb_motion, &cb_chuck, &cb_defaults, 0};
1450 	makehier (wmmv);
1451 
1452 	widget* dpw0 [] = {&cb_show_vel, &cb_show_accel, &cb_show_gravity, &cb_show_anchors, 0};
1453 	makehier (dpw0);
1454 
1455 	widget* dpw3 [] = {&sp_dam_depth, &sp_dfm_depth, &sp_dam_bpm,  &sp_dfm_bpm, 0};
1456 	makehier (dpw3);
1457 
1458 	widget* dpw4 [] = {&sp_drones_per_min, &sp_drone_lifetime, &sp_orbit_insertion_time, 0};
1459 	makehier (dpw4);
1460 
1461 	widget* dpw5 [] = {&sp_change_drone_trail_length, &sp_change_drone_handle_size, 0};
1462 	makehier (dpw5);
1463 
1464 	widget* dpw6 [] = {&ol_set_unset_toggle, &b_toggle, &b_set, &b_unset, 0};
1465 	makehier (dpw6);
1466 
1467 	widget* rmw [] = {&cb_mod_ran, &ol_fixed, &sp_ran_mod_width, &sp_ran_mod_width_bpm, &sp_ran_mod_height, &sp_ran_mod_height_bpm, 0};
1468 	makehier (rmw);
1469 
1470 	widget* dpw [] = {&ol_create_this,&dp_orient,&dp_numdrones,&dp_bpm1, 0};
1471 	makehier (dpw);
1472 
1473 	widget *rcw [] = {&ol_create_this, &sp_mesh_rows, &sp_mesh_cols, &cb_sync_rows_cols, &b_flip_rows_cols, 0};
1474 	makehier (rcw, 5);
1475 	widget* dow [] = {&l_drone_order, &ol_drone_order, &ol_mesh_point, &f_mesh_xy, 0};
1476 	makehier (dow, 4);
1477 	widget* mshw [] = {&sp_mesh_rows, &sp_mesh_dur, &l_use_drone_pend, 0,};
1478 	makehier (mshw, 3);
1479   sp_mesh_rows.add_child (&l_drone_order);
1480 	widget* dpp [] = {&sp_drones_per_pend, &b_set_to_mesh_rows, &b_set_to_mesh_cols, 0};
1481 	makehier (dpp);
1482 	widget* apt [] = {&l_apply_to, &cb_am_bpm, &cb_fm_bpm, 0};
1483 	makehier (apt);
1484 	widget* udp [] = {&l_use_drone_pend, &sp_drones_per_pend, &l_apply_to, 0};
1485 	makehier (udp);
1486 	widget* wsp [] = {&sp_snap_left, &sp_snap_right, &ol_snap_style, 0};
1487 	makehier (wsp);
1488 	widget* wda [] = {&l_drone_arrow, &b_arrow_reset, &dronearrow.neck, &dronearrow.shoulder.width, &dronearrow.shoulder.position, &dronearrow.cap, &dronearrow.decap, 0};
1489 	makehier (wda);
1490   widget* wda2 [] = {
1491     &dronearrowdefaults.lbl,
1492     &dronearrowdefaults.arrow,
1493     &dronearrowdefaults.neck,
1494     &dronearrowdefaults.shoulder.width,
1495     &dronearrowdefaults.shoulder.position,
1496     &dronearrowdefaults.cap,
1497     0,
1498   };
1499   makehier (wda2);
1500 	widget* wbo [] = {&sp_bounces, &sp_rebound, &ol_bounce_style, 0};
1501 	makehier (wbo);
1502 	widget* wconn [] = {&b_disconnect, &b_connect, &lf_conn_steps, &cb_conn_wrap, &trackcon, 0};
1503 	makehier (wconn);
1504 	widget* wsl [] = {&s_red_min, &s_red_max, &s_green_min, &s_green_max, &s_blue_min, &s_blue_max, &ol_color, 0};
1505 	makehier (wsl);
1506 
1507   {
1508     widget* w [] = {
1509       &b_select_all_drones,
1510       &b_invert_drone_selection,
1511       &b_select_attractees,
1512       &b_select_attractors,
1513       &b_select_launchers,
1514       &b_select_tracked_drones,
1515       &sp_browse_drone, 0,
1516     };
1517     makehier (w);
1518   }
1519 
1520   {
1521     widget* w[] = {
1522       &ol_add_wand,
1523       &b_delete_drones,
1524       &b_move_drones,
1525       &b_scale_drones,
1526       &b_rotate_drones,
1527       &b_set_xform_center,
1528       &b_freeze_drones,
1529       &b_thaw_drones, 0,
1530     };
1531     makehier (w);
1532   }
1533 
1534   {
1535     widget* w[] = {
1536       &b_mute,
1537       &b_unmute,
1538       &drone2noise,
1539       &noise2drone,
1540       &gabt, 0,
1541     };
1542     makehier (w);
1543   }
1544 
1545   {
1546     widget* w[] = {
1547       &b_launch_drones,
1548       &b_stop_launching_drones,
1549       &b_orbit_selected_drones,
1550       &b_track_drones,
1551       &b_set_targets,
1552       &b_clear_targets, 0,
1553     };
1554     makehier (w);
1555   }
1556 
1557   {
1558     widget* w[] = {&riset, &fallt, &lifetime, 0};
1559     makehier (w);
1560   }
1561 
1562   {
1563     widget* w[] = {&mortalize, &reincarnate, &immortalize, 0};
1564     makehier (w);
1565   }
1566 
1567   {
1568     widget* w[] = {&chflip, &chtog, &chspeed, &chlen, &chtrail, &chapt, &choutline, &chautoresettrails, 0};
1569     makehier (w);
1570   }
1571 
1572   /*
1573   {
1574     widget* w[] = {
1575     };
1576   }
1577   */
1578 
1579 #endif
1580 
1581 	sp_range.set ("Range", 1, &ranl);
1582 	sp_range.draw_more = sp_range.variance.ui = 0;
1583 
1584 	const char* rms [] = {"Width", "BPM", "Height", "BPM"};
1585 	spinner<float>* srm [] = {&sp_ran_mod_width, &sp_ran_mod_width_bpm, &sp_ran_mod_height, &sp_ran_mod_height_bpm};
1586 	int srl [] = {-MILLION, 0, -MILLION, 0};
1587 	int sro[] = {mouse_slider_listener::X, mouse_slider_listener::X, mouse_slider_listener::Y, mouse_slider_listener::Y};
1588 	change_listener<field>* rlis[] = {&rmwl, &rmwbl, &rmhl, &rmhbl};
1589 	for (int i = 0; i < 4; ++i) {
1590 		spinner<float>* sp = srm[i];
1591 		sp->set (rms[i], 1.0f, srl[i], MILLION, rlis[i]);
1592 		sp->orient = sro[i];
1593 	}
1594 
1595 	const char* rde [] = {"Default width", "Default height"};
1596 	spinner<int>* sde [] = {&sp_default_width, &sp_default_height};
1597 	int msd [] = {mouse_slider_listener::X, mouse_slider_listener::Y};
1598 	for (int i = 0; i < 2; ++i) {
1599 		spinner<int>& si = *sde[i];
1600 		si.set (rde[i], 1, 0, MILLION, &rdel);
1601 		si.orient = msd[i];
1602 		si.draw_more = si.variance.ui = 0;
1603 	}
1604 
1605   // drones
1606   //
1607 	sp_change_drone_trail_length.set ("Trail length", 1, &dtl);
1608 	sp_change_drone_trail_length.set_value (0);
1609 
1610 	sp_change_drone_handle_size.set ("Handle size", 1, &dhsl);
1611 	sp_change_drone_handle_size.set_value (0);
1612 
1613 	sp_change_drone_vel.set ("Velocity", 0.1f, -MILLION, +MILLION, &dvl);
1614 	sp_change_drone_accel.set ("Acceleration", 0.01f, -MILLION, +MILLION, &dal);
1615 
1616   sp_rotate_drone_vel.set ("Rotate velocity", 1.0f, &rdvl);
1617   sp_rotate_drone_vel.orient = mouse_slider_listener::X;
1618 
1619   sp_drones_per_min.set ("Drones per minute", 1.0f, &dpml);
1620 	sp_drone_lifetime.set ("Lifetime", 0.01f, &dlf);
1621 
1622 	sp_orbit_insertion_time.set ("Orbit insert time", 0.01f, &oil);
1623 
1624 	sp_browse_drone.set ("Browse drone", 1, &brwdl);
1625 	sp_browse_drone.draw_more = sp_browse_drone.variance.ui = 0;
1626 
1627 	ol_create_this.set_listener (this);
1628 
1629 	dp_orient.set_listener (this);
1630 	dp_numdrones.set ("Number of Drones", 1, 2, MILLION, this);
1631 	dp_bpm1.set ("BPM", 1.0f, 0, MILLION, this);
1632 
1633   spinner<int>* msh [] = {&sp_mesh_rows, &sp_mesh_cols};
1634   static const char* const mlb [] = {"Rows", "Columns"};
1635   for (int i = 0; i < 2; ++i) {
1636     spinner<int>* sp = msh[i];
1637 		sp->set (mlb[i], 1, 2, MILLION, this, 0);
1638 		sp->set_value (2);
1639 		sp->orient = mouse_slider_listener::NONE;
1640 		sp->draw_more = sp->variance.ui = 0;
1641   }
1642 
1643 	cb_sync_rows_cols.set_text ("Sync");
1644 
1645 	l_drone_order.set_text ("Create drones");
1646 	ol_drone_order.set_listener (this);
1647 	ol_mesh_point.set_listener (this);
1648 
1649 	f_mesh_xy.set_text ("0 0");
1650 	f_mesh_xy.change_lsnr = this;
1651 
1652   sp_mesh_dur.set (0.1f, 0, MILLION, this);
1653   sp_mesh_dur.set_value (1.0f);
1654   sp_mesh_dur.set_text ("In", SECONDS);
1655 
1656 	ol_set_unset_toggle.set_text (" Position affects velocity");
1657 	ol_set_unset_toggle.set_listener (this);
1658 
1659   ol_am_style.set_listener (&am_style_lis); // voice am
1660   ol_fm_style.set_listener (&fm_style_lis); // voice fm
1661 
1662   l_phrase_position.set_text ("Phrase position ");
1663   s_phrase_position.set_limits (0.0f, 1.0f);
1664 
1665 #ifndef __WIDGET_MOVE__
1666   ol_create_this.option.set_listener (&dcl);
1667   cb_sync_rows_cols.set_listener (&dcl);
1668   s_phrase_position.set_listener (this);
1669   b_key_to_pitch_at_cursor.set_listener (&miscl);
1670 #endif
1671 
1672 	const char* lrs [] = {"Adjust Height?", "Adjust?", "Modulation?", "Change Note"};
1673 	label* lrm [] = {&l_adjust_height, &l_adjust_range, &l_ran_mod, &ol_change_note.option};
1674 	for (int i = 0; i < 4; ++i) lrm[i]->set_text (lrs[i]);
1675 
1676 	ol_set_range.set_listener (&sral);
1677 
1678 	const char* snp [] = {"Snap left", "Snap right"};
1679 	spinner<float>* snsp [] = {&sp_snap_left, &sp_snap_right};
1680   float snv [] = {din0.dinfo.snap.left, din0.dinfo.snap.right};
1681 	for (int i = 0; i < 2; ++i) {
1682 		spinner<float>* si = snsp[i];
1683 		si->set (snp[i], 0.01f, &sdl);
1684 		si->draw_more = 0;
1685 		si->variance.ui = 0;
1686     si->set_value (snv[i]);
1687     si->orient = mouse_slider_listener::X;
1688 	}
1689 
1690 	l_drone_arrow.set_text ("Drone Arrow");
1691   dronearrowdefaults.lbl.set_text ("Drone Arrow");
1692 	spinner<float>* das [] = {&dronearrow.shoulder.position, &dronearrow.neck, &dronearrow.shoulder.width};
1693   spinner2<float>* das2 [] = {&dronearrowdefaults.shoulder.position, &dronearrowdefaults.neck, &dronearrowdefaults.shoulder.width};
1694 	const char* dasl [] = {"Shoulder Position", "Neck", "Shoulder Width"};
1695   float vals [] = {drone::arrowt::U, drone::arrowt::K, drone::arrowt::V};
1696 	for (int i = 0; i < 3; ++i) {
1697 		spinner<float>& si = *das[i];
1698     spinner2<float>& si2 = *das2[i];
1699 		si.set (dasl[i], 0.1f, -MILLION, MILLION, &arrowl);
1700     si2.set (dasl[i], 0.1f, -MILLION, MILLION, &defarrowl, 0);
1701     si2.set_value (vals[i]);
1702     si2.orient = mouse_slider_listener::NONE;
1703 	}
1704   for (int i = 0; i < 2; ++i) {
1705     spinner<float>& si = *das[i];
1706     spinner2<float>& si2 = *das2[i];
1707     si.updowndecinc ();
1708     si2.updowndecinc ();
1709   }
1710   dronearrowdefaults.cap.set_listener (&defarrowl);
1711   dronearrowdefaults.arrow.calc ();
1712 
1713   cb_scope.set_text ("Show oscilloscope");
1714   cb_scope.set_listener (&scol);
1715 	sp_scope_height.set ("Height", 1, 0, MILLION, &scol);
1716 	sp_scope_samples.set ("Samples", 1, 1, MAX_SAMPLES, &scol);
1717 	sp_scope_samples.orient = mouse_slider_listener::X;
1718 
1719   l_tap_bpm.set_text ("Tap BPM");
1720   checkbutton* cb_tars [] = {&cb_am, &cb_fm, &cb_gater, &cb_octave_shift, &cb_auto_reset};
1721   static const char* const cb_text [] = {"AM", "FM", "Gater", "Octave Shift", "Auto reset"};
1722 
1723   cb_auto_reset.turn_on ();
1724   for (int i = 0; i < 5; ++i) {
1725     checkbutton* cbi = cb_tars[i];
1726 		cbi->set (cb_text[i], &tbl);
1727 		l_tap_bpm.add_child (cbi);
1728   }
1729   td_tap_display.set_listener (&tbl);
1730 
1731 	l_tap_bpm.add_child (&td_tap_display);
1732 	l_tap_bpm.add_child (&l_tap_bpm_value);
1733 
1734   const char* bpmstr [] = {"os", "fm", "am", "gr"};
1735   spinner<float>* bpmspn [] = {&sp_octave_shift_bpm, &sp_fm_bpm, &sp_am_bpm, &sp_gater_bpm};
1736   for (int i = 0; i < 4; ++i) bpm_map[bpmstr[i]] = bpmspn[i];
1737 
1738   // editor tools
1739   arrow_button* enav[] = {&abe_left, &abe_down, &abe_right, &abe_up};
1740   int edirs [] = {arrow_button::left, arrow_button::down, arrow_button::right, arrow_button::up};
1741   for (int i = 0; i < 4; ++i) {
1742     arrow_button* ab = enav[i];
1743     ab->set_dir (edirs[i]);
1744   }
1745 
1746   l_snap.set_text ("Snap?");
1747   checkbutton* cb_snaps [] = {&cb_snapx, &cb_snapy, &cb_snapboth, &cb_snapnone};
1748   const char* cb_snap_str [] = {"X", "Y", "Both", "None"};
1749   for (int i = 0; i < 4; ++i) {
1750     checkbutton* cbi = cb_snaps[i];
1751     cbi->set_text (cb_snap_str[i]);
1752   }
1753 
1754   l_library.set_text ("Library");
1755   lf_curve_name.set_label ("Curve name");
1756 	lf_curve_name.fld.expr = 0;
1757   l_capture.set_text ("Mouse capture");
1758 
1759   ol_vertices_carry_tangents.set_listener (this);
1760   ol_mirror_tangents.set_listener (this);
1761   ol_curve_style.set_listener (this);
1762 
1763 	sp_curve_rpm.set ("RPM", 1.0f, 0.0f, MILLION, &col);
1764 	sp_curve_rpm.set_value (0.0f);
1765 
1766 #ifndef __WIDGET_MOVE__
1767   b_stop_rotating.set_listener (&col);
1768   cb_show_waveform_samples.set_listener (&col);
1769 #endif
1770 
1771 	sp_waveform_hz.set ("Hz", 1.0f, 0.01f, MILLION, &col);
1772 	sp_waveform_hz.orient = mouse_slider_listener::NONE;
1773 
1774 	sp_waveform_periods.set ("Cycles", 1, 1, MILLION, &col);
1775 	sp_waveform_periods.orient = mouse_slider_listener::NONE;
1776 
1777 	sp_curve_limit.set ("Curve roughness", 0.001f, 0.001f, MILLION, &col);
1778 
1779 	// button labels
1780 	const char* labels [] = {
1781     "Menu",
1782     "Microtonal Keyboard",
1783     "Keyboard Keyboard",
1784     "Mondrian",
1785 		"Binaural Drones",
1786     "Waveform",
1787     "Drone Waveform",
1788     "Drone Modulation",
1789     "Voice Modulation",
1790     "Gater",
1791     "Waveform",
1792     "Attack",
1793     "Decay",
1794     "MIDI Velocity",
1795     "Delays",
1796     "Octave Shift",
1797     "Compressor",
1798     "Morse Code",
1799     "Exit DIN Is Noise",
1800     "Show anchors",
1801     "Move",
1802     "Delete",
1803     "Select all",
1804     "Invert selected",
1805     "Record a phrase",
1806     "Clear phrase",
1807     "Default to Selected",
1808     "Default to all",
1809 		"Selected to all",
1810     "Set key to pitch at cursor",
1811     "Insert vertex",
1812     "Delete vertex",
1813     "Fold tangents",
1814     "Unfold tangents",
1815     "Undo",
1816     "Redo",
1817     "Copy",
1818     "Paste",
1819     "Draw & replace curve",
1820     "Add",
1821     "Replace",
1822     "Delete",
1823     "Start",
1824     "Assign",
1825     "Label vertices",
1826     "(Selection only)",
1827     "Show waveform",
1828     "Pick curve",
1829     "Stop",
1830     "Draw curve only",
1831 		"Clear",
1832 		"Record",
1833 		"Select attractees",
1834 		"Select attractors",
1835 		"Orbit",
1836 		"Show velocity",
1837 		"Show acceleration",
1838     "Show Gravity",
1839     "Balloon",
1840     "Launch",
1841     "Stop launch",
1842     "Track",
1843     "Select tracked",
1844     "Waveform",
1845     "Attack",
1846     "Decay",
1847     "Add ",
1848     "Move balls",
1849     "Delete selected balls",
1850     "Delete all balls",
1851     "Select all balls",
1852     "Invert ball selection",
1853     "Select balls in box",
1854     "Split box horizontally",
1855     "Split box vertically",
1856     "Delete box",
1857     "Freeze balls",
1858     "Thaw balls",
1859 		"Turn Off UI",
1860 		"Set targets",
1861 		"Clear targets",
1862 		"Clear modulations",
1863 		"Modulate balls up",
1864 		"Modulate balls down",
1865 		"Create binaural drones on the notes of the scale",
1866 		"Create binaural drones using parameters above",
1867 		"Waveform",
1868 		"Close octave",
1869 		"Auto-change ball direction clockwise",
1870 		"Auto-change ball direction anti-clockwise",
1871 		"Stop auto-changing ball direction",
1872 		"Flip ball direction",
1873 		"Randomize box color",
1874 		"Resize separation",
1875 		"Add / Remove slits",
1876 		"Toggle wreckers",
1877 		"Toggle healers",
1878 		"Toggle bouncers",
1879 		"Healers <> Wreckers",
1880 		"Select wreckers",
1881 		"Select healers",
1882 		"Remove slits on edge",
1883 		"Toggle slit animation",
1884 		"Auto adjust voices",
1885 		"Draw boxes",
1886 		"Fill boxes",
1887 		"Draw notes",
1888 		"Label notes",
1889 		"Position",
1890 		"Make note grid",
1891 		"Make N x N grid",
1892 		"Delete all boxes",
1893 		"Select launchers",
1894 		"Select on Creation",
1895 		"Freeze",
1896 		"Thaw",
1897 		"Mark segments",
1898 		"Auto split box",
1899 		"Auto delete box",
1900 		"Speed",
1901 		"Turn",
1902 		"Teleport",
1903 		"Heading",
1904 		"Trails",
1905 		"Draw ball:",
1906 		"Sync",
1907 		"Sync",
1908 		"Clone",
1909 		"Clone can clone too",
1910 		"Transform",
1911 		"Label pitch and volume",
1912 		"All",
1913 		"None",
1914 		"Invert",
1915 		"Delete",
1916 		"Sync",
1917 		"Modulate",
1918 		"Select",
1919 		"Flip",
1920 		"All",
1921 		"Left",
1922 		"Right",
1923 		"Both",
1924 		"Modulate",
1925 		"Mark",
1926 		"Pause/Resume",
1927 		"Start",
1928 		"Stop",
1929 		"Toggle",
1930 		"Get",
1931 		"Range modulation",
1932 		"Selected",
1933 		"Left",
1934 		"Right",
1935 		"Set",
1936 		"Unset",
1937 		"Toggle",
1938 		"Range Width & Height",
1939 		"Flip",
1940 		"Overlay Instrument/Editor",
1941 		"Range Pitch & Volume",
1942 		"Swap",
1943 		"Overlay pitch distribution",
1944 		"Overlay volume distributon",
1945 		"Point Modulation",
1946 		"Both",
1947 		"AM BPM",
1948 		"FM BPM",
1949 		"Set to Rows",
1950 		"Set to Columns",
1951 		"Noise Interpolator",
1952 		"Ball triggers note <> Ball triggers noise",
1953 		"Scale",
1954 		"Rotate",
1955 		"Draw mesh outline",
1956 		"Modulation",
1957 		"Motion",
1958 		"Visual",
1959 		"Connect",
1960 		"Disconnect",
1961 		"Wrap",
1962 		"Drone Pendulum",
1963 		"Abort",
1964 		"Close",
1965 		"Reset",
1966     "Mute",
1967     "Unmute",
1968     "Drone > Noise",
1969     "Noise > Drone",
1970     "Find center",
1971     "Defaults",
1972     "Mortalize",
1973     "Reincarnate",
1974     "Immortalize",
1975     "Chuck",
1976     "Chuck",
1977     "Flip",
1978     "Toggle",
1979     "Draw chuck outline",
1980     "Auto reset trails",
1981     "Cap",
1982     "Decap",
1983     "Cap",
1984     "Track",
1985     "Auto rotate",
1986     "Auto flip",
1987     "-ve",
1988     "Randomize",
1989     "0",
1990     "0",
1991     "Sync",
1992     // next label
1993   };
1994 
1995   button* buttons [] = {
1996     &b_menu,
1997     &b_microtonal_keyboard,
1998     &b_keyboard_keyboard,
1999     &b_mondrian,
2000 		&b_binaural_drones,
2001     &b_microtonal_keyboard_waveform,
2002     &b_drone_waveform,
2003     &b_drone_modulation,
2004     &b_voice_modulation,
2005     &b_gater,
2006     &b_keyboard_keyboard_waveform,
2007     &b_attack,
2008     &b_decay,
2009     &b_midi_velocity,
2010     &b_delays,
2011     &b_octave_shift,
2012     &b_compressor,
2013     &b_morse_code,
2014     &b_exit_din,
2015     &cb_show_anchors,
2016     &b_move_drones,
2017     &b_delete_drones,
2018     &b_select_all_drones,
2019     &b_invert_drone_selection,
2020     &b_record_phrase,
2021     &b_clear_phrases,
2022 		&b_default_to_selected,
2023 		&b_default_to_all,
2024     &b_selected_to_all,
2025     &b_key_to_pitch_at_cursor,
2026     &b_insert_vertex,
2027     &b_delete_vertex,
2028     &b_fold_tangents,
2029     &b_unfold_tangents,
2030     &b_undo,
2031     &b_redo,
2032     &b_copy,
2033     &b_paste,
2034     &b_draw_replacement_curve,
2035     &b_add_curve,
2036     &b_replace_curve,
2037     &b_delete_curve,
2038     &b_start_capture,
2039     &b_assign_capture,
2040     &cb_label_vertices,
2041     &cb_selection_only,
2042     &cb_show_waveform_samples,
2043     &b_pick_curve,
2044     &b_stop_rotating,
2045     &cb_draw_curve,
2046 		&b_clear_record,
2047 		&cb_record,
2048 		&b_select_attractees,
2049 		&b_select_attractors,
2050 		&b_orbit_selected_drones,
2051 		&cb_show_vel,
2052 		&cb_show_accel,
2053     &cb_show_gravity,
2054     &balloon,
2055     &b_launch_drones,
2056     &b_stop_launching_drones,
2057     &b_track_drones,
2058     &b_select_tracked_drones,
2059     &b_mondrian_waveform,
2060     &b_mondrian_attack,
2061     &b_mondrian_decay,
2062     &b_add_balls,
2063     &b_move_selected_balls,
2064     &b_delete_selected_targets,
2065     &b_delete_all_targets,
2066     &b_select_all_targets,
2067     &b_invert_selected_targets,
2068     &b_select_targets_in_box,
2069     &b_split_horizontal,
2070     &b_split_vertical,
2071     &b_delete_box,
2072     &b_freeze_balls,
2073     &b_thaw_balls,
2074 		&b_turn_off_ui,
2075 		&b_set_targets,
2076 		&b_clear_targets,
2077 		&b_clear_modulations,
2078 		&b_modulate_balls_up,
2079 		&b_modulate_balls_down,
2080 		&b_create_binaurals_on_notes,
2081 		&b_create_binaurals_from_pitch,
2082 		&b_binaural_drones_waveform,
2083 		&cb_close_octave,
2084 		&b_auto_change_direction_clockwise,
2085 		&b_auto_change_direction_anti_clockwise,
2086 		&b_stop_auto_changing_direction,
2087 		&b_flip_direction,
2088 		&b_make_random_color,
2089 		&cb_resize_separation,
2090 		&b_add_remove_slits,
2091 		&b_toggle_wreckers,
2092 		&b_toggle_healers,
2093 		&b_toggle_bouncers,
2094 		&b_switch_ball_type,
2095 		&b_select_wreckers,
2096 		&b_select_healers,
2097 		&b_remove_slits_on_edge,
2098 		&b_toggle_slit_anim,
2099 		&cb_mondrian_auto_adjust_voices,
2100 		&cb_draw_boxes,
2101 		&cb_fill_boxes,
2102 		&cb_draw_notes,
2103 		&cb_label_notes,
2104 		&cb_draw_ball_position,
2105 		&b_make_note_grid,
2106 		&b_make_nxn_grid,
2107 		&b_delete_all_boxes,
2108 		&b_select_launchers,
2109 		&seloncre,
2110 		&b_freeze_drones,
2111 		&b_thaw_drones,
2112 		&cb_mark_segments,
2113 		&cb_auto_split_box,
2114 		&cb_auto_delete_box,
2115 		&cb_speed,
2116 		&cb_turn,
2117 		&cb_teleport,
2118 		&cb_draw_ball_heading,
2119 		&cb_draw_ball_trails,
2120 		&l_draw_ball,
2121 		&cb_turn_sync,
2122 		&cb_speed_sync,
2123 		&cb_clone,
2124 		&cb_clone_can_clone,
2125 		&cb_transform,
2126 		&cb_label_hz_vol,
2127 		&bbd_select_all,
2128 		&bbd_select_none,
2129 		&bbd_invert_select,
2130 		&bbd_delete,
2131 		&bbd_sync,
2132 		&bbd_modulate,
2133 		&bbd_select2,
2134 		&bbd_flip,
2135 		&b_adjust_board_height,
2136 		&b_adjust_range_left,
2137 		&b_adjust_range_right,
2138 		&b_adjust_range_both,
2139 		&cb_mod_ran,
2140 		&cb_mark_ran,
2141 		&b_rm_pause_resume,
2142 		&b_rm_start_all,
2143 		&b_rm_stop_all,
2144 		&b_rm_toggle,
2145 		&b_get_cur_ran,
2146 		&b_range_modulation,
2147 		&b_adjust_range_height,
2148 		&b_change_note_left,
2149 		&b_change_note_right,
2150 		&b_set,
2151 		&b_unset,
2152 		&b_toggle,
2153 		&b_range_width_height,
2154 		&b_flip_rows_cols,
2155 		&cb_overlay,
2156 		&b_range_pitch_vol,
2157 		&b_swap_curves,
2158 		&cb_pitch_dis,
2159 		&cb_vol_dis,
2160 		&b_point_modulation,
2161 		&b_change_note_both,
2162 		&cb_am_bpm,
2163 		&cb_fm_bpm,
2164 		&b_set_to_mesh_rows,
2165 		&b_set_to_mesh_cols,
2166 		&b_noise_interpolator,
2167 		&b_ball_trig,
2168 		&b_scale_drones,
2169 		&b_rotate_drones,
2170 		&cb_draw_mesh,
2171 		&cb_modulation,
2172 		&cb_motion,
2173 		&cb_visual,
2174 		&b_connect,
2175 		&b_disconnect,
2176 		&cb_conn_wrap,
2177 		&b_drone_pend,
2178 		&b_abort_octave_shift,
2179 		&b_close,
2180 		&b_arrow_reset,
2181     &b_mute,
2182     &b_unmute,
2183     &drone2noise,
2184     &noise2drone,
2185     &b_set_xform_center,
2186     &cb_defaults,
2187     &mortalize,
2188     &reincarnate,
2189     &immortalize,
2190     &cb_chuck,
2191     &chuck,
2192     &chflip,
2193     &chtog,
2194     &choutline,
2195     &chautoresettrails,
2196     &dronearrow.cap,
2197     &dronearrow.decap,
2198     &dronearrowdefaults.cap,
2199     &trackcon,
2200     &dva.autorotate.cb,
2201     &dva.autoflip.cb,
2202     &dva.neg,
2203     &dva.randomize,
2204     &velgt0,
2205     &accelgt0,
2206     &dva.sync,
2207     // next button
2208   };
2209 
2210   for (int i = 0; i < 211; ++i) {
2211     button* bi = buttons[i];
2212     bi->set_text (labels[i]);
2213   }
2214 
2215   dlog << "+++ Labeled buttons +++" << endl;
2216 
2217 	LISTEN(cb_modulation,&cmod)
2218 	LISTEN(cb_motion,&cmot)
2219 	LISTEN(cb_visual,&cvis)
2220   LISTEN(cb_defaults,&cdef)
2221   LISTEN(cb_chuck,&cch)
2222   LISTEN(dronearrow.cap,&arrowl)
2223   LISTEN(dronearrow.decap,&arrowl)
2224 
2225 
2226 #ifndef __WIDGET_MOVE__
2227   LISTEN (b_arrow_reset,&awl)
2228 #endif
2229 
2230 	ol_select_what.set_text ("L");
2231 	ol_select_rule.set_text (" >= ");
2232 	bdf_value.change_lsnr = &bdl;
2233 	bdf_value.set_text (bdl.val[binaural_drones_listener::GREATER_THAN_EQUAL]);
2234 
2235 	sp_bounces.set ("Bounces", 1, 0, MILLION, &bol);
2236 	ol_bounce_style.set_listener (this);
2237 
2238 	sp_rebound.set ("Speed %", 1, 0, MILLION, &rebl);
2239 
2240   sp_mondrian_min_voices.set ("Min Voices", 1, 1, MILLION, &monl);
2241 	sp_mondrian_min_voices.draw_more = 0;
2242 	sp_mondrian_min_voices.variance.ui = 0;
2243 
2244 	cb_mondrian_auto_adjust_voices.set_listener (&monl);
2245 
2246   sp_mondrian_change_attack_time.set ("Ball attack time", 0.01f, &batl);
2247   sp_mondrian_change_decay_time.set ("Ball decay time", 0.01f, &bdtl);
2248 
2249   sp_mondrian_change_speed.set_text ("Ball speed");
2250   sp_mondrian_change_speed.set_listener (&bsl);
2251 	sp_mondrian_change_speed.set_listener (&monl, 1);
2252 
2253 	sp_mondrian_change_dir.set ("Ball direction", 1, &brl);
2254   sp_mondrian_change_dir.orient = mouse_slider_listener::X;
2255 	sp_mondrian_change_dir.draw_more = 0;
2256 	sp_mondrian_change_dir.variance.ui = 0;
2257 
2258 	sp_mondrian_change_trail_size.set ("Ball trail length", 1, &tll);
2259 	sp_mondrian_change_note_poly_points.set ("Note polygon points", 1, 2, MILLION, &nppl);
2260 	sp_mondrian_change_note_poly_radius.set ("Note polygon radius", 1, 0, MILLION, &nprl);
2261 
2262 	sp_mondrian_change_slit_size.set ("Slit size", 1.0f, &ssl);
2263 
2264 	sp_mondrian_change_slit_anim_time.set ("Slit open/close time", 0.01f, &satl);
2265   sp_mondrian_change_slit_anim_time.set_value (0.0f);
2266 
2267 	sp_mondrian_change_vol.set ("Ball volume", 0.01f, -MILLION, MILLION, &bvl);
2268 	sp_mondrian_change_vol.set_value (0);
2269 
2270   sp_mondrian_num_boxes.set ("N", 1, 0, MILLION, &monl);
2271 	sp_mondrian_num_boxes.draw_more = 0;
2272 	sp_mondrian_num_boxes.variance.ui = 0;
2273 
2274 	sp_auto_split_time.set ("", 0.1f, 0.01f, MILLION, &monl);
2275   sp_auto_split_time.set_text ("Every", SECONDS);
2276 
2277 	sp_auto_delete_time.set ("", 0.1f, 0.01f, MILLION, &monl);
2278   sp_auto_delete_time.set_text ("Every", SECONDS);
2279 
2280 	sp_min_split_size.set ("Min split size", 1, 2, MILLION, &monl);
2281 
2282 #ifndef __WIDGET_MOVE__
2283 	cb_auto_split_box.set_listener (&monl);
2284 	cb_auto_delete_box.set_listener (&monl);
2285 #endif
2286 
2287 	options_list* olt [] = {&ol_bouncer, &ol_wrecker, &ol_healer};
2288 	for (int i = 0; i < 3; ++i) olt[i]->set_listener (&bolis);
2289 
2290 	button* pb[] = {&sp_mondrian_change_dir.inc, &sp_mondrian_change_dir.dec};
2291 	set_repeat (pb, 2, 0.005);
2292 
2293 	recl.typing (lf_file.fld);
2294 
2295   {
2296 
2297     nullt* sp [] = {
2298       &sp_change_drone_handle_size,
2299       &sp_change_drone_trail_length,
2300       &autorotate.rpm,
2301       &autorotate.deg,
2302       &autorotate.tps,
2303       &sp_mondrian_change_vol,
2304       &sp_mondrian_change_attack_time,
2305       &sp_mondrian_change_decay_time,
2306       &sp_mondrian_change_speed,
2307       &sp_mondrian_change_slit_size,
2308       &sp_mondrian_change_slit_anim_time,
2309       &sp_mondrian_change_note_poly_radius,
2310       &sp_change_drone_vel,
2311       &sp_change_drone_accel,
2312       &sp_dam_depth,
2313       &sp_dfm_depth,
2314       &sp_dam_bpm,
2315       &sp_dfm_bpm,
2316       &sp_drone_vol,
2317       &dronearrow.shoulder.position,
2318       &dronearrow.shoulder.width,
2319       &sp_rotate_drone_vel,
2320       &sp_drones_per_min,
2321       &sp_drone_lifetime,
2322       &sp_orbit_insertion_time,
2323       &sp_mondrian_change_attack_time,
2324       &sp_mondrian_change_decay_time,
2325       &sp_mondrian_change_speed,
2326       &sp_mondrian_change_dir,
2327       &sp_mondrian_change_trail_size,
2328       &sp_mondrian_change_vol,
2329       &sp_mondrian_change_slit_size,
2330       &sp_mondrian_change_slit_anim_time,
2331       &chspeed,
2332       &chlen,
2333       &chtrail,
2334       &autorotate.autoflip.angle,
2335       &dronearrow.neck,
2336       &dronearrow.shoulder.width,
2337       &dronearrow.shoulder.position,
2338       0
2339     };
2340 
2341     int i = 0;
2342     while (sp[i] != 0) sp[i++]->null = 1;
2343 
2344   }
2345 
2346 
2347 
2348 }
2349 
update()2350 void menu::update () {
2351 	position_menu_items ();
2352   position_tabs ();
2353 }
2354 
position_menu_items()2355 void menu::position_menu_items () {
2356 	static const int lines = 4;
2357 	int targety = view.ymax - lines * line_height;
2358 	int dy = targety - cb_file.extents.bottom;
2359   for (int p = 0; p < nitems; ++p) items[p]->move (0, dy, 0);
2360 }
2361 
loadspinners()2362 void menu::loadspinners () {
2363   file_in fi ("spinners");
2364   ifstream& f = fi ();
2365   f >> handlesize >> trailsize >> dva.mag >> lifetime >> dronearrowdefaults.neck >> dronearrowdefaults.shoulder.width >> dronearrowdefaults.shoulder.position;
2366   f >> dva.autorotate.rpm >> dva.autorotate.dps >> dva.autorotate.tps >> dva.autoflip.deg >> gabt >> din0.dinfo.gravity.mod.depth >> din0.dinfo.gravity.mod.bpm;
2367   f >> riset >> fallt;
2368   f >> sp_bounces >> sp_rebound;
2369 }
2370 
savespinners()2371 void menu::savespinners () {
2372 	file_out fo ("spinners");
2373 	ofstream& f = fo ();
2374   f << handlesize << trailsize << dva.mag << lifetime << dronearrowdefaults.neck << dronearrowdefaults.shoulder.width << dronearrowdefaults.shoulder.position;
2375   f << dva.autorotate.rpm << dva.autorotate.dps << dva.autorotate.tps << dva.autoflip.deg << gabt << din0.dinfo.gravity.mod.depth << din0.dinfo.gravity.mod.bpm;
2376   f << riset << fallt << endl;
2377   f << sp_bounces << sp_rebound;
2378 }
2379 
2380 
setup()2381 void menu::setup () {
2382   dlog << "*** setting up menu ***" << endl;
2383   show = screen_mousex = screen_mousey = 0;
2384   setup_items ();
2385   widget_load ("d_menu", items, nitems);
2386   loadspinners ();
2387 	b_menu.set_listener (&mbl);
2388   dlog << "+++ menu setup complete +++" << endl;
2389 }
2390 
set_pos(int x,int y)2391 void menu::set_pos (int x, int y) {
2392   b_menu.set_pos (x, y);
2393 }
2394 
draw()2395 void menu::draw () {
2396 
2397   b_menu.draw ();
2398 
2399   if (show) {
2400 
2401     // draw bg
2402     glEnable (GL_BLEND);
2403     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2404       glColor4f (0.0f, 0.0f, 0.0f, opacity);
2405       glRecti (bg_extents.left, bg_extents.bottom, bg_extents.right, bg_extents.top);
2406     glDisable (GL_BLEND);
2407 
2408 		glPolygonMode (GL_FRONT, GL_LINE);
2409 		glColor3f (0.5f, 0.5f, 0.5f);
2410 		glRecti (bg_extents.left, bg_extents.bottom, bg_extents.right, bg_extents.top);
2411 		glPolygonMode (GL_FRONT, GL_FILL);
2412 
2413     // draw items
2414     for (int i = 0; i < num_tabs; ++i) tabs[i]->draw ();
2415     if (cur_tab) {
2416       vector<widget*>& ti = tab_members [cur_tab];
2417       for (int i = 0, j = ti.size (); i < j; ++i) ti[i]->draw ();
2418       if (cur_tab == &cb_mkb_voice && din0.phrasor0.state == phrasor::playing) s_phrase_position.set_val (din0.phrasor0.amount);
2419     }
2420   }
2421 }
2422 
setup_tabs(ui * scr)2423 void menu::setup_tabs (ui* scr) {
2424 	checkbutton* com [] = {&cb_file, &cb_instrument, &cb_editors};
2425   checkbutton* mkb [] = {&cb_mkb_voice, &cb_mkb_drone_tools, &cb_mkb_drone_params, &cb_mkb_ranges, &cb_mkb_misc};
2426   checkbutton* eds [] = {&cb_ed_tools};
2427   checkbutton* mon [] = {&cb_mon_tools, &cb_mon_parameters, &cb_mon_ballops, &cb_mon_boxops, &cb_mon_misc};
2428 	checkbutton* bd [] = {&cb_binaural_drones_tools, &cb_binaural_drones_edit};
2429   int clear_existing_tabs = 1;
2430 	setup_tabs (com, 3, clear_existing_tabs);
2431   if (scr == &din0) { // microtonal keyboard
2432     setup_tabs (mkb, 5);
2433   } else if (scr == &keybd2) { // keyboard-keyboard
2434   } else if (scr == &mondrian0) { // mondrian
2435     setup_tabs (mon, 5);
2436   } else if (scr == &binaural_drones0) { // binaural drones
2437 		setup_tabs (bd, 2);
2438 	} else { // is an editor
2439     setup_tabs (com, 3, clear_existing_tabs);
2440     setup_tabs (eds, 1);
2441 		next_tab = &cb_ed_tools;
2442 		next_tab_instr = get_current_instrument ();
2443   }
2444   position_tabs ();
2445 }
2446 
setup_tabs(checkbutton ** tlist,int n,int clear)2447 void menu::setup_tabs (checkbutton** tlist, int n, int clear) {
2448   if (clear) tabs.clear ();
2449   for (int i = 0; i < n; ++i) tabs.push_back (tlist[i]);
2450   num_tabs = tabs.size ();
2451 }
2452 
position_tabs()2453 void menu::position_tabs () {
2454 
2455   if (num_tabs) {
2456 
2457     int x = cb_file.posx, y = cb_file.posy, spacing = 20;
2458     int i = 1, j = 0;
2459     for (; i < num_tabs;) {
2460       x = x + get_char_width (tabs[j]->text) + spacing;
2461       tabs[i]->set_pos (x, y);
2462 			++i;
2463 			j = i - 1;
2464     }
2465 
2466 		int ss = x + get_char_width (tabs[j]->text) - cb_file.posx;
2467     separators.main.set_extents (ss);
2468 		separators.dp0.set_extents (ss);
2469 		separators.dp1.set_extents (ss);
2470     calc_bg ();
2471 
2472     checkbutton* lt = tabs[num_tabs - 1];
2473     menu_mousex = lt->extents.right + 1;
2474     menu_mousey = view.ymax - lt->posy;
2475 
2476   }
2477 }
2478 
remove_from_tab(checkbutton * cb,widget * w)2479 void menu::remove_from_tab (checkbutton* cb, widget* w) {
2480   vector<widget*>& tw = tab_members [cb];
2481   vector<widget*>::iterator end = tw.end (), i = find (tw.begin(), end, w);
2482   if (i != end) tw.erase (i);
2483 }
2484 
add_to_tab(checkbutton * cb,widget * w)2485 void menu::add_to_tab (checkbutton* cb, widget* w) {
2486   vector<widget*>& tw = tab_members[cb];
2487 	vector<widget*>::iterator end = tw.end (), i = find (tw.begin(), end, w);
2488   if (i == end) tw.push_back (w);
2489 }
2490 
set_drone_params_items(int s,int e)2491 void menu::set_drone_params_items (int s, int e) {
2492   vector<widget*>& tw = tab_members[&cb_mkb_drone_params];
2493 	tw.clear ();
2494 	tw.push_back (&separators.main);
2495 	DECL_DRONE_PARAMS
2496 	for (int i = 0; i < 9; ++i) {
2497 		add_to_tab (&cb_mkb_drone_params, wdrone_params[i]);
2498 	}
2499 	for (int i = s; i < e; ++i) {
2500 		add_to_tab (&cb_mkb_drone_params, wdrone_params[i]);
2501 	}
2502 	calc_bg ();
2503 }
2504 
handle_input()2505 int menu::handle_input () {
2506 
2507   if (b_menu.handle_input ()) return 1;
2508 
2509   if (show) {
2510 
2511     if (wheel && !widget::HOVER) move_items (0, wheel * wheely);
2512 
2513     // find current tab
2514     for (int i = 0; i < num_tabs; ++i) tabs[i]->handle_input ();
2515 
2516     if (cur_tab) { // handle tab's items
2517       vector<widget*>& tm = tab_members [cur_tab];
2518       for (int i = 0, j = tm.size (); i < j; ++i) if (tm[i]->handle_input ()) return 1;
2519     }
2520 
2521 
2522   }
2523 
2524   return 0;
2525 
2526 }
2527 
init_modulation()2528 void menu::init_modulation () {
2529   spinner<float>* spn [] = {&sp_am_depth, &sp_fm_depth, &sp_am_bpm, &sp_fm_bpm}; // for voice
2530 	float vals [] = {din0.am_depth, din0.fm_depth, din0.am.bpm, din0.fm.bpm};
2531 	spinner<float>* dspn [] = {&sp_dam_depth, &sp_dfm_depth, &sp_dam_bpm, &sp_dfm_bpm}; // for drones
2532 	float* d_prev_vals [] = {&dam_depth, &dfm_depth, &dam_bpm, &dfm_bpm};
2533 	for (int i = 0; i < 4; ++i) {
2534 		spinner<float>* dspni = dspn[i];
2535 		dspni->limits = 0;
2536 		dspni->set_value (0);
2537 		*d_prev_vals[i] = 0;
2538 		spinner<float>* spni = spn[i];
2539 		spni->set_value (vals[i]);
2540 	}
2541 	am_depth = din0.am_depth;
2542 	fm_depth = din0.fm_depth;
2543 }
2544 
toggle(int mouse_warp)2545 void menu::toggle (int mouse_warp) {
2546 
2547   static int removedpluginbrowser;
2548 
2549   show = !show;
2550   if (show) {
2551 
2552     b_menu.set_text ("Close menu");
2553 
2554     if (b_close.visible) b_close.call_listener ();
2555 
2556     if (uis.current->inst) {
2557       if (uis.current == &din0) {
2558         uis.remove (&mkb_selector);
2559         if (din0.dinfo.gravity.visible) uis.remove (&din0.dinfo.gravity);
2560       }
2561       else if (uis.current == &mondrian0)
2562         uis.remove (&mon_selector);
2563     } else {
2564       uis.remove (&CRVED->capturer);
2565       uis.remove (&CRVED->pomo);
2566       removedpluginbrowser = uis.remove (&uis.plugin__browser);
2567       if (CRVED->fft_enabled) uis.remove (&fft0);
2568     }
2569 
2570     style_listener* sl [] = {&gater_style_lis, &am_style_lis, &fm_style_lis};
2571     for (int i = 0; i < 3; ++i) sl[i]->get_style ();
2572 
2573     screen_mousex = mousex;
2574     screen_mousey = mousey;
2575 		::warp_mouse (menu_mousex, menu_mousey);
2576 
2577 		if (next_tab && (next_tab_instr == get_current_instrument())) {
2578 			changed (*next_tab);
2579 			cur_tab = next_tab;
2580 			next_tab = 0;
2581 			next_tab_instr = 0;
2582 		}
2583 
2584   } else {
2585     b_menu.set_text ("Menu");
2586     menu_mousex = mousex;
2587     menu_mousey = mousey;
2588     if (uis.current->inst) {
2589       if (uis.current == &din0 ) {
2590         if (din0.dinfo.gravity.visible) uis.add (&din0, &din0.dinfo.gravity);
2591         if (!din0.adding && !b_close.visible) uis.add (&din0, &mkb_selector);
2592       }
2593       else if (uis.current == &mondrian0)
2594         uis.widgets_of [&mondrian0].push_back (&mon_selector);
2595     } else {
2596       uis.widgets_of[CRVED].push_back (&CRVED->capturer);
2597       uis.widgets_of[CRVED].push_back (&CRVED->pomo);
2598       if (removedpluginbrowser) uis.widgets_of[CRVED].push_back (&uis.plugin__browser);
2599       if (CRVED->fft_enabled) uis.widgets_of[CRVED].push_back (&fft0);
2600 		}
2601 		if (mouse_warp) warp_mouse (screen_mousex, screen_mousey);
2602   }
2603 
2604 	uis.update_bottom_line ();
2605 
2606 }
2607 
set_ball_ops(ball * b)2608 void menu::set_ball_ops (ball* b) {
2609 
2610 	ball_op* ops [ball_op::NUM_OPS] = {&b->op_turn, &b->op_speed, &b->op_teleport, &b->op_clone, &b->op_transform};
2611 	checkbutton* cbn [ball_op::NUM_OPS] = {&cb_turn, &cb_speed, &cb_teleport, &cb_clone, &cb_transform};
2612 	for (int i = 0; i < ball_op::NUM_OPS; ++i) cbn[i]->set_state (ops[i]->alarm.active, 0);
2613 
2614 	turn& trn = b->op_turn;
2615 	sp_turn_min.set_value (-trn.rd.min);
2616 	sp_turn_max.set_value (trn.rd.max);
2617 
2618 	speed& spd = b->op_speed;
2619 	sp_speed_min.set_value (-spd.rd.min);
2620 	sp_speed_max.set_value (spd.rd.max);
2621 	sp_max_speed.set_value (spd.max);
2622 
2623 	teleport& tel = b->op_teleport;
2624 	sp_tel_radius.set_value (tel.radius);
2625 
2626 	Clone& clo = b->op_clone;
2627 	sp_clone_offset.set_value (clo.offset);
2628 	sp_max_clones.set_value (clo.max);
2629 	sp_max_balls.set_value (Clone::max_balls);
2630 	cb_clone_can_clone.set_state (clo.clone_can_clone);
2631 
2632 	Transform& tf = b->op_transform;
2633 
2634 	ball_op* bpa [] = {&trn, &spd, &tel, &clo, &tf};
2635 	spinner<float>* spa [] = {&sp_turn_every, &sp_speed_every, &sp_tel_every, &sp_clone_every, &sp_transform_every};
2636 	for (int i = 0; i < ball_op::NUM_OPS; ++i) spa[i]->set_value (bpa[i]->alarm.triggert);
2637 
2638 }
2639 
clear_ball_ops()2640 void menu::clear_ball_ops () {
2641 	checkbutton* cbn [ball_op::NUM_OPS] = {&cb_turn, &cb_speed, &cb_teleport, &cb_clone, &cb_transform};
2642 	for (int i = 0; i < ball_op::NUM_OPS; ++i) cbn[i]->set_state (0, 0);
2643 }
2644 
CLICKED_BUTTON(menu,b_menu_lis)2645 CLICKED_BUTTON(menu, b_menu_lis) {
2646 	cons << YELLOW << "You can use right click to open / close the menu and mouse wheel to scroll" << eol;
2647 	TOGGLEMENU
2648 }
2649 
CLICKED_BUTTON(menu,b_inst_lis)2650 CLICKED_BUTTON(menu, b_inst_lis) {
2651 	int i = b.id;
2652 	scope.save_current_instrument ();
2653 	CURRENT_INSTRUMENT = i;
2654 	INSTRUMENT = INSTRUMENTS[i];
2655 	load_instrument ();
2656 }
2657 
CLICKED_BUTTON(menu,b_ed_lis)2658 CLICKED_BUTTON(menu, b_ed_lis) {
2659 	int i = b.id;
2660 	ui* ed = uis.uis[i];
2661 	uis.load_editor (ed);
2662 	setup_plugin_labels ();
2663 	if (curve_picker.visible) curve_picker.hide();
2664 }
2665 
clicked(button & b)2666 void misc_listener::clicked (button& b) {
2667 	if (&b == MENUP.b_exit_din)
2668 		try_quit ();
2669 	else if (&b == MENUP.b_turn_off_ui) {
2670 		turn_off_ui ();
2671 		return;
2672 	} else
2673 		din0.set_key_to_pitch_at_cursor ();
2674   TOGGLEMENU
2675 }
2676 
move_items(int dx,int dy)2677 void menu::move_items (int dx, int dy) {
2678 	for (int i = 0; i < nitems; ++i) {
2679 		widget* wi = items[i];
2680 		wi->move (dx, dy, 0);
2681 	}
2682 	calc_bg ();
2683 }
2684 
changed(checkbutton & tb)2685 void menu::changed (checkbutton& tb) { // current tab has changed
2686 
2687   cur_tab = &tb;
2688   tb.turn_on (DONT_CALL_LISTENER); // must be always on
2689 
2690   if (cur_tab == last_tab) return;
2691 
2692   if (last_tab) last_tab->turn_off (DONT_CALL_LISTENER);
2693 
2694   last_tab = cur_tab;
2695 
2696 	calc_bg ();
2697 
2698 	opacity = 0.9f;
2699 	if (&tb == &cb_mon_ballops || &tb == &cb_mon_boxops || &tb == &cb_mon_misc) opacity = 0.5f;
2700 
2701 	// save last tab to reload when loading new instrument
2702 	extern checkbutton* LAST_TABS [];
2703 	checkbutton* com [] = {&cb_file, &cb_instrument, &cb_editors, &cb_ed_tools}; // ignore these tabs
2704 	for (int i = 0; i < 4; ++i) if (com[i] == cur_tab) return;
2705 	LAST_TABS [CURRENT_INSTRUMENT] = cur_tab;
2706 
2707 }
2708 
VALUE_CHANGED(menu,sp_stiff_lis)2709 VALUE_CHANGED(menu,sp_stiff_lis) {
2710 	drone::STIFFNESS = f;
2711 	clamp (0.0f, drone::STIFFNESS, 1.0f);
2712 	cons << "Connection stiffness = " << drone::STIFFNESS << eol;
2713 }
2714 
VALUE_CHANGED(menu,gabt_lis)2715 VALUE_CHANGED(menu,gabt_lis) {
2716   drone::gabt = f;
2717   din0.gab.setgabt ();
2718   cons << YELLOW << "Mute/unmute and Drone <> Noise time = " << drone::gabt << SECONDS << eol;
2719 }
2720 
VALUE_CHANGED(menu,sp_dam_depth_lis)2721 VALUE_CHANGED(menu,sp_dam_depth_lis) {
2722 	din0.change_drone_depth (modulator::AM, MENU.sp_dam_depth);
2723 }
2724 
VALUE_CHANGED(menu,sp_dfm_depth_lis)2725 VALUE_CHANGED(menu,sp_dfm_depth_lis) {
2726 	din0.change_drone_depth (modulator::FM, MENU.sp_dfm_depth);
2727 }
2728 
VALUE_CHANGED(menu,sp_dam_bpm_lis)2729 VALUE_CHANGED(menu,sp_dam_bpm_lis) {
2730 	din0.change_drone_bpm (modulator::AM, MENU.sp_dam_bpm);
2731 }
2732 
VALUE_CHANGED(menu,sp_dfm_bpm_lis)2733 VALUE_CHANGED(menu,sp_dfm_bpm_lis) {
2734 	din0.change_drone_bpm (modulator::FM, MENU.sp_dfm_bpm);
2735 }
2736 
VALUE_CHANGED(menu,sp_am_depth_lis)2737 VALUE_CHANGED(menu,sp_am_depth_lis) {
2738 	din0.change_depth (din::AM, MENU.sp_am_depth());
2739 }
2740 
VALUE_CHANGED(menu,sp_fm_depth_lis)2741 VALUE_CHANGED(menu,sp_fm_depth_lis) {
2742 	din0.change_depth (din::FM, MENU.sp_fm_depth());
2743 }
2744 
VALUE_CHANGED(menu,sp_am_bpm_lis)2745 VALUE_CHANGED(menu,sp_am_bpm_lis) {
2746 	float v = f;
2747 	v = din0.am.set_bpm (v);
2748 	cons << YELLOW << "Voice AM bpm = " << v << eol;
2749 }
2750 
VALUE_CHANGED(menu,sp_fm_bpm_lis)2751 VALUE_CHANGED(menu,sp_fm_bpm_lis) {
2752 	float v = f;
2753 	v = din0.fm.set_bpm (v);
2754 	cons << YELLOW << "Voice FM bpm = " << v << eol;
2755 }
2756 
VALUE_CHANGED(menu,sp_browse_drone_lis)2757 VALUE_CHANGED(menu,sp_browse_drone_lis) {
2758 	din0.browsed_drone = f;
2759 	din0.browse_drone (0);
2760 }
2761 
2762 
VALUE_CHANGED(menu,sp_bounces_lis)2763 VALUE_CHANGED (menu,sp_bounces_lis) {
2764 	din0.dinfo.bounce.n = f;
2765   cons << GREEN << "Max bounces = " << din0.dinfo.bounce.n << eol;
2766 }
2767 
VALUE_CHANGED(menu,sp_rebound_lis)2768 VALUE_CHANGED(menu,sp_rebound_lis) {
2769 	din0.dinfo.bounce.speed = f;
2770   cons << GREEN << "Max speed% = " << din0.dinfo.bounce.speed << eol;
2771 }
2772 
changed(field & f)2773 void menu::changed (field& f) {
2774 
2775   if (&f == &sp_mesh_rows.f_value) {
2776     din0.dinfo.rows = f;
2777 		if (cb_sync_rows_cols.state) {
2778 			din0.dinfo.cols = din0.dinfo.mesh_vars.dpp = din0.dinfo.rows;
2779 			sp_mesh_cols.set_value (din0.dinfo.cols);
2780 			sp_drones_per_pend.set_value (din0.dinfo.mesh_vars.dpp);
2781 		}
2782     mkb_selector.set_mesh (din0.meshh.create, din0.dinfo.rows, din0.dinfo.cols);
2783 		picked (ol_mesh_point.option, 0);
2784   } else if (&f == &sp_mesh_cols.f_value) {
2785     din0.dinfo.cols = f;
2786 		if (cb_sync_rows_cols.state) {
2787 			din0.dinfo.rows = din0.dinfo.mesh_vars.dpp = din0.dinfo.cols;
2788 			sp_mesh_rows.set_value (din0.dinfo.rows);
2789 			sp_drones_per_pend.set_value (din0.dinfo.mesh_vars.dpp);
2790 		}
2791     mkb_selector.set_mesh (din0.meshh.create, din0.dinfo.rows, din0.dinfo.cols);
2792 		picked (ol_mesh_point.option, 0);
2793   } else if (&f == &sp_mesh_dur.f_value) {
2794 		float t = f;
2795 		din0.dinfo.mesh_vars.duration = t;
2796 		cons << "Make mesh in " << t << SECONDS << eol;
2797 	} else if (&f == &f_mesh_xy) {
2798 		int r, c;
2799 		tokenizer z (f.text);
2800 		z >> r >> c;
2801 		if (clamp (0, r, din0.dinfo.rows-1) || clamp (0, c, din0.dinfo.cols-1) ) {
2802 			sprintf (BUFFER, "%d %d", r, c);
2803 			f_mesh_xy.set_text(BUFFER);
2804 		}
2805 		proximity_orderer::ROW = r;
2806 		proximity_orderer::COL = c;
2807 	} else if (&f == &dp_numdrones.f_value) {
2808 		din0.dinfo.drone_pend.n = int(f);
2809 		cons << YELLOW << "Number of Drones = " << din0.dinfo.drone_pend.n << eol;
2810 	} else if (&f == &dp_bpm1.f_value) {
2811 		din0.dinfo.drone_pend.bpm = float(f);
2812 		cons << YELLOW << "Drone Pendulum BPM = " << din0.dinfo.drone_pend.bpm << eol;
2813 	}
2814 }
2815 
changed(slider<float> & s)2816 void menu::changed (slider<float>& s) {
2817   din0.phrasor0.set_cur (s());
2818 }
2819 
picked(label & lbl,int dir)2820 void menu::picked (label& lbl, int dir) {
2821   const static char* vct [] = {" Vertices desert tangents", " Vertices carry tangents"};
2822   const static char* mit [] = {" Tangents are not mirrored", " Tangents are mirrored"};
2823 	const static char* bbs [] = {" Drones bounce ahead", " Drones bounce back", " Drones bounce ahead or back"};
2824 	const static char *sut [] = {" Snap drones to notes", " Position affects velocity"};
2825 	const static char *ofl [] = {" in ascending rows", " in descending rows"," in ascending columns", " in descending columns", " randomly", " nearest to", " farthest from" };
2826 	const static char *wpt [] = {"bottom left", "bottom right", "top left", "top right", "center", "random point", "custom point"};
2827 	const static char *cwt [] = {" Create Drone Mesh", " Create Drone Pendulum"};
2828 	const static char *ort [] = {" Orientation = Horizontal", " Orientation = Vertical"};
2829 	const static char *mir [] = {" Horizontal Flip", " Vertical Flip", " Horizontal Flip (Local)", " Vertical Flip (Local)" };
2830 	const static char *dris [] = {" Drone is Drone", " Drone is Noise", " Drone is Drone or Noise"};
2831 
2832 	static const int npt = 7, npt_1 = npt-1;
2833 	static widget* mshw [] = {
2834 		&sp_mesh_rows,
2835 		&sp_mesh_cols,
2836 		&cb_sync_rows_cols,
2837 		&l_drone_order,
2838 		&sp_mesh_dur,
2839 		&b_flip_rows_cols,
2840 		&ol_drone_order,
2841 		&l_use_drone_pend,
2842 		&sp_drones_per_pend,
2843 		&l_apply_to,
2844 		&cb_am_bpm,
2845 		&cb_fm_bpm,
2846 		&b_set_to_mesh_rows,
2847 		&b_set_to_mesh_cols,
2848 		&ol_mesh_point,
2849 		&f_mesh_xy,
2850 	};
2851 	static widget* dpw [] = {
2852 		&dp_orient,
2853 		&dp_numdrones,
2854 		&dp_bpm1,
2855 	};
2856 
2857   if (&lbl == &ol_vertices_carry_tangents.option) {
2858     CRVED->carry_tangents = !CRVED->carry_tangents;
2859     lbl.set_text (vct[CRVED->carry_tangents]);
2860   } else if (&lbl == &ol_mirror_tangents.option) {
2861     CRVED->mirror_tangents = !CRVED->mirror_tangents;
2862     lbl.set_text (mit[CRVED->mirror_tangents]);
2863   } else if (&lbl == &ol_curve_style.option) {
2864     CRVED->toggle_curve_style ();
2865   } else if (&lbl == &ol_bounce_style.option) {
2866 		din0.dinfo.bounce.style += dir;
2867 		wrap<int> (din_info::bouncet::AHEAD, din0.dinfo.bounce.style, din_info::bouncet::RANDOM);
2868 		lbl.set_text (bbs[din0.dinfo.bounce.style]);
2869 	} else if (&lbl == &ol_set_unset_toggle.option) {
2870 		din0.dinfo.set_unset_toggle = !din0.dinfo.set_unset_toggle;
2871 		lbl.set_text (sut[din0.dinfo.set_unset_toggle]);
2872 		b_toggle.set_pos (lbl.extents.right + 20, b_toggle.posy);
2873 		b_set.set_pos (b_toggle.extents.right + 10, b_toggle.posy);
2874 		b_unset.set_pos (b_set.extents.right + 10, b_toggle.posy);
2875 	} else if (&lbl == &ol_drone_order.option) {
2876 		din0.dinfo.mesh_vars.order += dir;
2877 		wrap (0, din0.dinfo.mesh_vars.order, LAST_ORDERER);
2878 		lbl.set_text (ofl[din0.dinfo.mesh_vars.order]);
2879 		if (din0.dinfo.mesh_vars.order > 4) {
2880 			add_to_tab (&cb_mkb_drone_tools, &ol_mesh_point);
2881 			add_to_tab (&cb_mkb_drone_tools, &f_mesh_xy);
2882 			ol_mesh_point.set_pos (lbl.extents.right + 10, lbl.extents.bottom);
2883 			f_mesh_xy.set_pos (ol_mesh_point.option.extents.right + 10, f_mesh_xy.extents.bottom);
2884 		} else {
2885 			remove_from_tab (&cb_mkb_drone_tools, &ol_mesh_point);
2886 			remove_from_tab (&cb_mkb_drone_tools, &f_mesh_xy);
2887 		}
2888 	} else if (&lbl == &ol_mesh_point.option) {
2889 		din0.dinfo.mesh_vars.point += dir;
2890 		wrap (0, din0.dinfo.mesh_vars.point, npt_1);
2891 		sprintf (BUFFER, " %s @ ", wpt[din0.dinfo.mesh_vars.point]);
2892 		lbl.set_text (BUFFER);
2893 		int cols_1 = din0.dinfo.cols - 1;
2894 		int rows_1 = din0.dinfo.rows - 1;
2895 		rnd<int> rdr (0, rows_1), rdc (0, cols_1);
2896 		int ROW [] = {0, 0, rows_1, rows_1, din0.dinfo.rows / 2, rdr(), proximity_orderer::ROW};
2897 		int COL [] = {0, cols_1, 0, cols_1, din0.dinfo.cols / 2, rdc(), proximity_orderer::COL};
2898 		proximity_orderer::ROW = ROW [din0.dinfo.mesh_vars.point];
2899 		proximity_orderer::COL = COL [din0.dinfo.mesh_vars.point];
2900 		sprintf (BUFFER, "%d %d", proximity_orderer::ROW, proximity_orderer::COL);
2901 		f_mesh_xy.set_text (BUFFER);
2902 		f_mesh_xy.set_pos (lbl.extents.right + 10, f_mesh_xy.extents.bottom);
2903 	} else if (&lbl == &ol_create_this.option) {
2904 		din0.dinfo.create_this += dir;
2905 		wrap (0, din0.dinfo.create_this, 1);
2906 		int cw = din0.dinfo.create_this;
2907 		lbl.set_text (cwt[cw]);
2908 		if (cw) { // drone pendulum
2909 			for (int i = 0; i < 16; ++i) remove_from_tab (&cb_mkb_drone_tools, mshw[i]);
2910 			for (int i = 0; i < 3; ++i) add_to_tab (&cb_mkb_drone_tools, dpw[i]);
2911 		} else { // mesh
2912 			for (int i = 0; i < 3; ++i) remove_from_tab (&cb_mkb_drone_tools, dpw[i]);
2913 			int j = 14; if (din0.dinfo.mesh_vars.order > 4) j = 16;
2914 			for (int i = 0; i < j; ++i) add_to_tab (&cb_mkb_drone_tools, mshw[i]);
2915 		}
2916 		calc_bg ();
2917 	} else if (&lbl == &dp_orient.option) {
2918 		din0.dinfo.drone_pend.orient += dir;
2919 		wrap (0, din0.dinfo.drone_pend.orient, 1);
2920 		int o = din0.dinfo.drone_pend.orient;
2921 		lbl.set_text (ort[o]);
2922 	} else if (&lbl == &ol_mirror.option) {
2923 		CRVED->axis += dir;
2924 		wrap<int> (curve_editor::MIRROR_X, CRVED->axis, curve_editor::MIRROR_BBY);
2925 		lbl.set_text (mir[CRVED->axis]);
2926 		cb_selection_only.set_pos (lbl.extents.right + 5, lbl.extents.bottom);
2927 		calc_bg ();
2928 	} else if (&lbl == &ol_drone_is.option) {
2929     drone::IS += dir;
2930     wrap<int> (drone::DRONE, drone::IS, drone::DRONE_OR_NOISE);
2931 		const char* di = dris [drone::IS];
2932 		lbl.set_text (di);
2933 	}
2934 }
2935 
calc_bg()2936 void menu::calc_bg () {
2937   if (cur_tab && num_tabs) {
2938     vector<widget*>& v = tab_members [cur_tab];
2939     if (v.size () == 0) return;
2940     widget* w0 = v[0];
2941 		bg_extents.left = cb_file.extents.left;
2942 		bg_extents.right = bg_extents.left;
2943     bg_extents.bottom = w0->extents.bottom;
2944     bg_extents.top = tabs[0]->extents.top;
2945     for (int i = 0, j = v.size (); i < j; ++i) {
2946       widget* wi = v[i];
2947 			if (wi->extents.left < bg_extents.left) bg_extents.left = wi->extents.left;
2948 			if (wi->extents.right > bg_extents.right) bg_extents.right = wi->extents.right;
2949       if (wi->extents.bottom < bg_extents.bottom) bg_extents.bottom = wi->extents.bottom;
2950       if (wi->extents.top > bg_extents.top) bg_extents.top = wi->extents.top;
2951     }
2952 		static const int GUTTER = 5;
2953 		bg_extents.resize (GUTTER, GUTTER);
2954   }
2955 
2956 }
2957 
show_editors(ui * inst)2958 void menu::show_editors (ui* inst) {
2959   int starts [] = {8, 0, 12, 15};
2960   int ends [] = {12, 8, 15, 16};
2961 	int starti = starts[CURRENT_INSTRUMENT], endi = ends[CURRENT_INSTRUMENT];
2962   vector<widget*>& tw = tab_members [&cb_editors];
2963   for (int i = starti; i < endi; ++i) {
2964     widget* ei = editors[i];
2965     tw.push_back (ei);
2966   }
2967 }
2968 
hide_editors()2969 void menu::hide_editors () {
2970   vector<widget*>& tw = tab_members [&cb_editors];
2971   for (int i = 0; i < 16; ++i) {
2972     widget* ei = editors[i];
2973     vector<widget*>::iterator itr = find (tw.begin(), tw.end(), ei);
2974     if (itr != tw.end()) tw.erase (itr);
2975   }
2976 }
2977 
update_bpm(const string & name,float value)2978 void menu::update_bpm (const string& name, float value) {
2979   spinner<float>* psp = bpm_map [name];
2980   if (psp) psp->set_value (value);
2981 }
2982 
mark_tap_target()2983 void menu::mark_tap_target () {
2984   interpreter ("set taptarget");
2985   tokenizer tz (interpreter.result);
2986   while (1) {
2987     string target; tz >> target;
2988     if (target == "") break;
2989     if (target == "gr") cb_gater.turn_on (DONT_CALL_LISTENER);
2990     else if (target == "am") cb_am.turn_on (DONT_CALL_LISTENER);
2991     else if (target == "fm") cb_fm.turn_on (DONT_CALL_LISTENER);
2992     else if (target == "os") cb_octave_shift.turn_on (DONT_CALL_LISTENER);
2993   }
2994 }
2995 
~menu()2996 menu::~menu () {
2997 	dlog << "--- destroying menu ---" << endl;
2998   widget_save ("d_menu", items, nitems);
2999   savespinners ();
3000 	dlog << "--- destroyed menu ---" << endl;
3001 }
3002 
clicked(button & b)3003 void octave_shift_listener::clicked (button& b) {
3004   if (&b == MENUP.ab_octave_up || &b == &uis.ab_octave_up) modulate_up (); else modulate_down ();
3005 }
3006 
changed(field & f)3007 void octave_shift_listener::changed (field& f) {
3008 	float v = f;
3009   v = octave_shift.set_bpm (v);
3010 	static const string los = "Octave shift BPM = ";
3011 	cons << YELLOW << los << v << eol;
3012 }
3013 
changed(field & f)3014 void voice_volume_listener::changed (field& f) {
3015 	VOICE_VOLUME = f;
3016 	static const string vv ("Volume = ");
3017 	cons << YELLOW << vv << VOICE_VOLUME << eol;
3018 }
3019 
changed(field & f)3020 void drone_master_volume_listener::changed (field& f) {
3021 	float dmv = f;
3022 	din0.setdronemastervolume (dmv);
3023 }
3024 
changed(field & f)3025 void gater_bpm_listener::changed (field& f) {
3026 	float v = f;
3027   v = din0.gatr.set_bpm (v);
3028 	static const string gt = "Gater BPM = ";
3029 	cons << YELLOW << gt << v << eol;
3030 }
3031 
changed(field & f)3032 void drone_handle_size_listener::changed (field& f) {
3033   din0.change_drone_handle_size (MENU.sp_change_drone_handle_size);
3034 }
3035 
changed(field & f)3036 void drone_trail_length_listener::changed (field& f) {
3037   din0.change_drone_trail_points (MENU.sp_change_drone_trail_length);
3038 }
3039 
changed(field & f)3040 void change_drone_vel_listener::changed (field& f) {
3041   din0.change_drone_vel (MENU.sp_change_drone_vel);
3042 }
3043 
changed(field & f)3044 void change_drone_accel_listener::changed (field& f) {
3045 	din0.change_drone_accel (MENU.sp_change_drone_accel);
3046 }
3047 
changed(field & f)3048 void rotate_drone_vel_listener::changed (field& f) {
3049 	din0.rotate_drone_vel (MENU.sp_rotate_drone_vel);
3050 }
3051 
changed(field & f)3052 void drones_per_min_listener::changed (field& f) {
3053 	din0.change_drones_per_min (MENU.sp_drones_per_min);
3054 }
3055 
changed(field & f)3056 void drone_lifetime_listener::changed (field& f) {
3057 	din0.change_drone_lifetime (MENU.sp_drone_lifetime);
3058 }
3059 
changed(field & f)3060 void orbit_insertion_time_listener::changed (field& f) {
3061 	din0.change_orbit_insertion_time (MENU.sp_orbit_insertion_time);
3062 }
3063 
set_style(const string & style)3064 void style_listener::set_style (const string& style) {
3065   for (int i = 0; i < num_styles; ++i) {
3066     if (styles[i] == style) {
3067       id = i;
3068       string command ("set-style " + what + " " + style);
3069       interpreter (command);
3070       oplist.set_text (prefix + style);
3071     }
3072   }
3073 }
3074 
get_style()3075 void style_listener::get_style () {
3076   string command ("get-style " + what);
3077   interpreter (command);
3078   oplist.set_text (prefix + interpreter.result);
3079 }
3080 
next_style(int dir)3081 void style_listener::next_style (int dir) {
3082   id += dir;
3083   if (id < 0) id = last_style; else if (id >= num_styles) id = 0;
3084   set_style (styles[id]);
3085 }
3086 
picked(label & lbl,int dir)3087 void style_listener::picked (label& lbl, int dir) {
3088   next_style (dir);
3089 }
3090 
changed(checkbutton & cb)3091 void drone_commands_listener::changed (checkbutton& cb) {
3092   int state = cb.state;
3093 	if (&cb == MENUP.cb_show_vel) din0.dinfo.vel = state; else
3094 	if (&cb == MENUP.cb_show_accel) din0.dinfo.accel = state; else
3095   if (&cb == MENUP.cb_show_gravity) {if (state) din0.dinfo.gravity.show (); else din0.dinfo.gravity.hide ();} else
3096 	if (&cb == MENUP.cb_show_anchors) din0.dinfo.anchor = state; else
3097 	if (&cb == MENUP.seloncre) din0.dinfo.seloncre = state;
3098 	else din0.dinfo.mesh_vars.sync = cb.state;
3099 }
3100 
clicked(button & b)3101 void phrase_commands_listener::clicked (button& b) {
3102 	TOGGLEMENU
3103   if (&b == MENUP.b_record_phrase) din0.do_phrase_recording ();
3104   else if (&b == MENUP.b_clear_phrases) din0.clear_all_phrases ();
3105 }
3106 
read_mod()3107 void range_data::read_mod () {
3108 	int& a = din0.ranges[din0.dinfo.sel_range].mod.active;
3109 	mod = a;
3110 	a = 0;
3111 }
3112 
write_mod()3113 void range_data::write_mod () {
3114 	din0.ranges[din0.dinfo.sel_range].mod.active = mod;
3115 }
3116 
clicked(button & b)3117 void range_height_listener::clicked (button& b) {
3118 	mouse_slider0.add (MENUP.rhl);
3119 	MENU.rhl.read_mod ();
3120 	activate_mouse_slider ();
3121 }
3122 
moused(int dh,double scl)3123 void range_height_listener::moused (int dh, double scl) {
3124 	din0.height_changed (din0.dinfo.sel_range, dh);
3125 }
3126 
after_slide()3127 void range_height_listener::after_slide () {
3128 	MENU.rhl.write_mod ();
3129 }
3130 
read_mod()3131 void board_height_listener::read_mod () {
3132 	int n = din0.num_ranges;
3133 	moda.resize (n);
3134 	for (int i = 0; i < n; ++i) {
3135 		int& a = din0.ranges[i].mod.active;
3136 		moda[i]=a;
3137 		a = 0;
3138 	}
3139 }
3140 
write_mod()3141 void board_height_listener::write_mod () {
3142 	int n = din0.num_ranges;
3143 	for (int i = 0; i < n; ++i) din0.ranges[i].mod.active = moda[i];
3144 }
3145 
moused(int dh,double scl)3146 void board_height_listener::moused (int dh, double scl) {
3147 	din0.height_changed (-1, dh);
3148 }
3149 
clicked(button & b)3150 void board_height_listener::clicked (button& b) {
3151 	MENU.bhl.name = "Board height";
3152 	MENU.bhl.orient = mouse_slider_listener::Y;
3153 	mouse_slider0.add (MENUP.bhl);
3154 	MENU.bhl.read_mod ();
3155 	activate_mouse_slider ();
3156 }
3157 
after_slide()3158 void board_height_listener::after_slide () {
3159 	MENU.bhl.write_mod ();
3160 }
3161 
clicked(button & b)3162 void set_range_listener::clicked (button& b) {
3163 	if (&b == MENUP.b_selected_to_all) {
3164     din0.selected_range_to_all (i);
3165   } else if (&b == MENUP.b_default_to_selected) {
3166     din0.default_range_to_selected (i);
3167   } else if (&b == MENUP.b_default_to_all) {
3168     din0.default_range_to_all (i);
3169   }
3170 }
3171 
picked(label & lbl,int dir)3172 void set_range_listener::picked (label& lbl, int dir) {
3173 	i = !i;
3174 	static const char* opts [] = {" Set Width?", " Set Height?"};
3175 	lbl.set_text (opts[i]);
3176 }
3177 
clicked(button & b)3178 void range_width_listener::clicked (button& b) {
3179 	if (&b == MENUP.b_adjust_range_left) {
3180 		MENU.arl.range = din0.dinfo.sel_range;
3181 		MENU.arl.read_mod ();
3182 		mouse_slider0.add (MENUP.arl);
3183 		activate_mouse_slider ();
3184 	} else if (&b == MENUP.b_adjust_range_right) {
3185 		MENU.arr.range = din0.dinfo.sel_range;
3186 		MENU.arr.read_mod ();
3187 		mouse_slider0.add (MENUP.arr);
3188 		activate_mouse_slider ();
3189 	} else {
3190 		MENU.arb.range = din0.dinfo.sel_range;
3191 		MENU.arb.read_mod ();
3192 		mouse_slider0.add (MENUP.arb);
3193 		activate_mouse_slider ();
3194 	}
3195   din0.adjustranges.set ();
3196 }
3197 
moused(int dir,double scl)3198 void adjust_range_left_listener::moused (int dir, double scl) {
3199 	if (din0.range_left_changed (range, dir, 1)) {
3200 		din0.refresh_drones (0, range);
3201 		din0.find_visible_ranges ();
3202 	}
3203 }
3204 
after_slide()3205 void adjust_range_left_listener::after_slide () {
3206 	MENU.arl.write_mod ();
3207   din0.adjustranges.unset ();
3208 }
3209 
moused(int dir,double scl)3210 void adjust_range_right_listener::moused (int dir, double scl) {
3211 	if (din0.range_right_changed (range, dir, 1)) {
3212 		din0.refresh_drones (range, din0.last_range);
3213 		din0.find_visible_ranges ();
3214 	}
3215 }
3216 
after_slide()3217 void adjust_range_right_listener::after_slide () {
3218 	MENU.arr.write_mod ();
3219   din0.adjustranges.unset ();
3220 }
3221 
moused(int dir,double scl)3222 void adjust_range_both_listener::moused (int dir, double scl) {
3223 	int rl = din0.range_left_changed (range, -dir, 1);
3224 	int rr = din0.range_right_changed (range, dir, 1);
3225 	if (rl || rr) {
3226 		din0.refresh_all_drones ();
3227 		din0.find_visible_ranges ();
3228 	}
3229 }
3230 
after_slide()3231 void adjust_range_both_listener::after_slide () {
3232 	MENU.arb.write_mod ();
3233   din0.adjustranges.unset ();
3234 }
3235 
VALUE_CHANGED(menu,sp_range_lis)3236 VALUE_CHANGED(menu, sp_range_lis) {
3237   din0.dinfo.sel_range = f;
3238   MENU.load_range_mod (din0.dinfo.sel_range);
3239 }
3240 
VALUE_CHANGED(menu,sp_ran_mod_width_lis)3241 VALUE_CHANGED(menu, sp_ran_mod_width_lis) {
3242   float v = f;
3243   din0.ranges[din0.dinfo.sel_range].mod.fm.depth = v;
3244   sprintf (BUFFER, "Range %d, Modulation Width = %0.3f", din0.dinfo.sel_range, v);
3245   cons << BUFFER << eol;
3246 }
3247 
VALUE_CHANGED(menu,sp_ran_mod_width_bpm_lis)3248 VALUE_CHANGED(menu, sp_ran_mod_width_bpm_lis) {
3249   float v = f;
3250   din0.ranges[din0.dinfo.sel_range].mod.fm.bv.set_bpm (v);
3251   sprintf (BUFFER, "Range %d, Modulation Width BPM = %0.3f", din0.dinfo.sel_range, v);
3252   cons << BUFFER << eol;
3253 }
3254 
VALUE_CHANGED(menu,sp_ran_mod_height_lis)3255 VALUE_CHANGED(menu, sp_ran_mod_height_lis) {
3256   float v = f;
3257   din0.ranges[din0.dinfo.sel_range].mod.am.depth = v;
3258   sprintf (BUFFER, "Range %d, Modulation Height = %0.3f", din0.dinfo.sel_range, v);
3259   cons << BUFFER << eol;
3260 }
3261 
VALUE_CHANGED(menu,sp_ran_mod_height_bpm_lis)3262 VALUE_CHANGED(menu, sp_ran_mod_height_bpm_lis) {
3263   float v = f;
3264   din0.ranges[din0.dinfo.sel_range].mod.am.bv.set_bpm (v);
3265   sprintf (BUFFER, "Range %d, Modulation Height BPM = %0.3f", din0.dinfo.sel_range, v);
3266   cons << BUFFER << eol;
3267 }
3268 
edited(curve_editor * ed,int i)3269 void range_mod_lis::edited (curve_editor* ed, int i) {
3270 	din0.update_range_mod_solvers (i, ed->mix);
3271 	curve_listener::edited (ed, i);
3272 }
3273 
load_range(int r)3274 void menu::load_range (int r) {
3275 	sp_range.set_value (r);
3276 	load_range_mod (r);
3277 }
3278 
load_range_mod(int r)3279 void menu::load_range_mod (int r) {
3280 	range& ri = din0.ranges [r];
3281 	cb_mod_ran.set_state (ri.mod.active, 0);
3282 	sp_ran_mod_width.set_value (ri.mod.fm.depth);
3283 	sp_ran_mod_width_bpm.set_value (ri.mod.fm.bv.bpm);
3284 	sp_ran_mod_height.set_value (ri.mod.am.depth);
3285 	sp_ran_mod_height_bpm.set_value (ri.mod.am.bv.bpm);
3286 	ol_fixed.set_text (ol_fixed_lbls [ri.fixed]);
3287 	print_range_info (ri);
3288 }
3289 
picked(label & l,int dir)3290 void snap_drones_listener::picked (label& l, int dir) {
3291 	din0.dinfo.snap.style += dir;
3292 	static const char* ss [] = {" Free", " Slide", " Lock", " Mirror"};
3293 	wrap<int> (din_info::snap_t::FREE, din0.dinfo.snap.style, din_info::snap_t::MIRROR);
3294 	l.set_text (ss[din0.dinfo.snap.style]);
3295 }
3296 
changed(field & f)3297 void snap_drones_listener::changed (field& f) {
3298   float v = f;
3299 	if (&f == MENUP.sp_snap_left.f_value) {
3300 		float dl = v - din0.dinfo.snap.left;
3301 		din0.dinfo.snap.left = v;
3302 		if (din0.dinfo.snap.style > din_info::snap_t::FREE) {
3303 			if (din0.dinfo.snap.style == din_info::snap_t::SLIDE) {
3304 				din0.dinfo.snap.right += dl;
3305 			}
3306 			else if (din0.dinfo.snap.style == din_info::snap_t::LOCK) {
3307 				din0.dinfo.snap.right = din0.dinfo.snap.left;
3308 			}
3309 			else {
3310 				din0.dinfo.snap.right = 1.0f - din0.dinfo.snap.left;
3311 			}
3312 			MENU.sp_snap_right.set_value (din0.dinfo.snap.right);
3313 		}
3314 	} else if (&f == MENUP.sp_snap_right.f_value) {
3315 		float dr = v - din0.dinfo.snap.right;
3316 		din0.dinfo.snap.right = v;
3317 		if (din0.dinfo.snap.style > din_info::snap_t::FREE) {
3318 			if (din0.dinfo.snap.style == din_info::snap_t::LOCK) {
3319 				din0.dinfo.snap.left = din0.dinfo.snap.right;
3320 			} else if (din0.dinfo.snap.style == din_info::snap_t::SLIDE) {
3321 				din0.dinfo.snap.left += dr;
3322 			} else {
3323 				din0.dinfo.snap.left = 1.0f - din0.dinfo.snap.right; // mirror
3324 			}
3325 			MENU.sp_snap_left.set_value (din0.dinfo.snap.left);
3326 		}
3327 	}
3328 
3329 	if (din0.dinfo.snap.left > din0.dinfo.snap.right || din0.dinfo.snap.left < 0.0f || din0.dinfo.snap.right > 1.0f)
3330     cons << RED;
3331   else
3332     cons << GREEN;
3333 	sprintf (BUFFER, "Snap left = %0.3f, Snap right = %0.3f", din0.dinfo.snap.left, din0.dinfo.snap.right);
3334 	cons << BUFFER << eol;
3335 }
3336 
changed(field & f)3337 void scope_listener::changed (field& f) {
3338   int n = f;
3339   if (&f == MENUP.sp_scope_height.f_value) {
3340     scope.set_height (n);
3341 		static const string ht = "Height = ";
3342 		cons << YELLOW << ht << n << eol;
3343   } else {
3344 		scope.set_num_samples (n);
3345 		static const string ns = "Samples = ";
3346 		cons << YELLOW << ns << n << eol;
3347   }
3348 }
3349 
changed(checkbutton & cb)3350 void scope_listener::changed (checkbutton& cb) {
3351 	scope.visible = cb.state;
3352 }
3353 
setup()3354 void scope_listener::setup () {
3355 	if (scope.visible) MENU.cb_scope.turn_on (0); else MENU.cb_scope.turn_off (0);
3356 	MENU.sp_scope_height.set_value (scope.height);
3357 	MENU.sp_scope_samples.set_value (scope.num_samples);
3358 }
3359 
changed(tap_display & td)3360 void tap_bpm_listener::changed (tap_display& td) {
3361   sprintf (BUFFER, "%.3f", td.bpm);
3362   MENU.l_tap_bpm_value.set_text (BUFFER);
3363   extern double TAP_BPM; TAP_BPM = td.bpm;
3364   Tcl_UpdateLinkedVar (interpreter.interp, "tapbpm");
3365 }
3366 
changed(checkbutton & cb)3367 void tap_bpm_listener::changed (checkbutton& cb) {
3368   checkbutton* cbs [] = {MENUP.cb_am, MENUP.cb_fm, MENUP.cb_gater, MENUP.cb_octave_shift};
3369   const char* targets [] = {"am", "fm", "gr", "os"};
3370   for (int i = 0; i < 4; ++i) {
3371     checkbutton* cbi = cbs[i];
3372     if (&cb == cbi) {
3373       if (cbi->state)
3374         sprintf (BUFFER, "add-tap-target %s", targets[i]);
3375       else
3376         sprintf (BUFFER, "remove-tap-target %s", targets[i]);
3377       interpreter (BUFFER);
3378       return;
3379     }
3380   }
3381   if (&cb == MENUP.cb_auto_reset) {
3382     if (MENU.cb_auto_reset.state) interpreter ("set resetbeat 1"); else interpreter ("set resetbeat 0");
3383   }
3384 }
3385 
clicked(button & b)3386 void pan_zoom_listener::clicked (button& b) {
3387   if (&b == MENUP.abe_left) {CRVED->do_panx (1); cons << YELLOW << "You can press a to move curves left" << eol;}
3388   else if (&b == MENUP.abe_right) {CRVED->do_panx (-1); cons << YELLOW << "You can press d to move curves right"<< eol;}
3389   else if (&b == MENUP.abe_up) {CRVED->do_pany (-1); cons << YELLOW << "You can press w to move curves up" << eol;}
3390   else if (&b == MENUP.abe_down) {CRVED->do_pany (+1); cons << YELLOW << "You can press s to move curves down" << eol;}
3391   else if (&b == MENUP.pb_zoom_in) {CRVED->do_zoom (-1); cons << YELLOW << "You can press e to zoom in" << eol;}
3392   else {CRVED->do_zoom (+1);cons << YELLOW << "You can press q to zoom out" << eol;}
3393 }
3394 
changed(checkbutton & cb)3395 void snap_listener::changed (checkbutton& cb) {
3396   checkbutton* snaps [] = {MENUP.cb_snapnone, MENUP.cb_snapx, MENUP.cb_snapy, MENUP.cb_snapboth};
3397   int ids [] = {basic_editor::SNAP_NONE, basic_editor::SNAP_X, basic_editor::SNAP_Y, basic_editor::SNAP_BOTH};
3398   const char* mesgs [] = {"You can press n to turn off snapping", "You can press x to snap X",
3399                     "You can press y to snap Y", "You can press b to snap both X and Y"};
3400   for (int i = 0; i < 4; ++i) snaps[i]->turn_off (DONT_CALL_LISTENER);
3401 	for (int i = 0; i < 4; ++i) {
3402     if (&cb == snaps[i]) {
3403       CRVED->set_snap (ids[i]);
3404       cons << YELLOW << mesgs[i] << eol;
3405 			break;
3406     }
3407   }
3408 }
3409 
set_snap(int what)3410 void menu::set_snap (int what) {
3411   checkbutton* snaps [] = {&cb_snapnone, &cb_snapx, &cb_snapy, &cb_snapboth};
3412   int ids [] = {basic_editor::SNAP_NONE, basic_editor::SNAP_X, basic_editor::SNAP_Y, basic_editor::SNAP_BOTH};
3413   for (int i = 0; i < 4; ++i) {
3414     checkbutton* si = snaps[i];
3415     if (what == ids[i])
3416 			si->turn_on (DONT_CALL_LISTENER);
3417 		else
3418     	si->turn_off (DONT_CALL_LISTENER);
3419   }
3420 }
3421 
set_vertices_carry_tangents(int i)3422 void menu::set_vertices_carry_tangents (int i) {
3423   const static char* vct [] = {" Vertices desert tangents", " Vertices carry tangents"};
3424   ol_vertices_carry_tangents.option.set_text (vct[i]);
3425 }
3426 
set_mirror_tangents(int i)3427 void menu::set_mirror_tangents (int i) {
3428   const static char* mit [] = {" Tangents are not mirrored", " Tangents are mirrored"};
3429   ol_mirror_tangents.option.set_text (mit[i]);
3430 }
3431 
set_repeat(button ** B,int n,double dt)3432 void menu::set_repeat (button** B, int n, double dt) {
3433   for (int i = 0; i < n; ++i) {
3434     button* bi = B[i];
3435     bi->click_repeat = 1;
3436     bi->first_repeat_time = bi->subsequent_repeat_time = dt;
3437   }
3438 }
3439 
set_pan_repeat(double dt)3440 void menu::set_pan_repeat (double dt) {
3441   button* ab [] = {&abe_left, &abe_right, &abe_up, &abe_down, &abm_left, &abm_right, &abm_up, &abm_down};
3442   set_repeat (ab, 8, dt);
3443 }
3444 
set_zoom_repeat(double dt)3445 void menu::set_zoom_repeat (double dt) {
3446   button* zb [] = {&pb_zoom_in, &mb_zoom_out, &bm_zoom_in, &bm_zoom_out};
3447   set_repeat (zb, 4, dt);
3448 }
3449 
clicked(button & b)3450 void menu::curve_ops_listener::clicked (button& b) {
3451   int toggle = 1;
3452   if (&b == MENUP.b_undo) {
3453     cons << YELLOW << "You can press z to undo!" << eol;
3454     CRVED->do_undo ();
3455     toggle = 0;
3456   } else
3457   if (&b == MENUP.b_redo) {
3458     cons << YELLOW << "You can press LSHIFT + z to redo!" << eol;
3459     CRVED->do_redo ();
3460     toggle = 0;
3461   } else
3462   if (&b == MENUP.abl_left) {
3463 		cons << YELLOW << "You can press 9 to load previous curve from library" << eol;
3464     CRVED->do_load_curve (-1);
3465     toggle = 0;
3466   } else
3467   if (&b == MENUP.abl_right) {
3468 		cons << YELLOW << "You can press 0 to load next curve from library" << eol;
3469     CRVED->do_load_curve (+1);
3470     toggle = 0;
3471   }
3472   if (&b == MENUP.b_insert_vertex) {
3473     CRVED->insert_using_menu ();
3474   } else if (&b == MENUP.b_delete_vertex) {
3475     CRVED->remove_using_menu ();
3476   } else if (&b == MENUP.b_fold_tangents) {
3477     CRVED->fold_tangents_using_menu ();
3478   } else if (&b == MENUP.b_unfold_tangents) {
3479     CRVED->unfold_tangents_using_menu ();
3480 	} else if (&b == MENUP.ol_mirror.option) {
3481     CRVED->mirror_using_menu ();
3482   } else if (&b == MENUP.b_copy) {
3483     CRVED->copy_using_menu ();
3484   } else if (&b == MENUP.b_paste) {
3485     CRVED->paste_using_menu ();
3486   } else if (&b == MENUP.b_swap_curves) {
3487 		CRVED->swap ();
3488 	} else if (&b == MENUP.b_pick_curve) {
3489     CRVED->do_pick_curve ();
3490   }
3491   // to library
3492   else if (&b == MENUP.b_add_curve) {
3493     CRVED->add_curve ();
3494   } else if (&b == MENUP.b_replace_curve) {
3495     CRVED->replace_curve ();
3496   } else if (&b == MENUP.b_delete_curve) {
3497     CRVED->delete_curve ();
3498   } else if (&b == MENUP.b_draw_replacement_curve) {
3499     CRVED->draw_replacement_curve_using_menu ();
3500   } else if (&b == MENUP.b_start_capture) {
3501     CRVED->start_mouse_capture_from_menu ();
3502   } else if (&b == MENUP.b_assign_capture) {
3503     CRVED->assign_mouse_capture_from_menu ();
3504   } else if (&b == MENUP.b_stop_rotating) {
3505     MENU.sp_curve_rpm.set_value (0);
3506     CRVED->set_rpm (0);
3507   }
3508 	if (toggle) TOGGLEMENU
3509 }
3510 
changed(checkbutton & cb)3511 void menu::curve_ops_listener::changed (checkbutton& cb) {
3512 	int tog = 0;
3513 	if (&cb == MENUP.cb_mark_segments) {
3514 		CRVED->mark_segments = cb.state;
3515 	} else if (&cb == MENUP.cb_label_vertices) {
3516     CRVED->label_vertices = cb.state;
3517   } else if (&cb == MENUP.cb_show_waveform_samples) {
3518     CRVED->toggle_waveform_samples_display ();
3519   } else if (&cb == MENUP.cb_draw_curve) {
3520     CRVED->draw_curve_only = cb.state;
3521   } else {
3522 		CRVED->overlay = cb.state;
3523 		string n (get_current_instrument()->name);
3524 		if (cb.state)
3525 			cons << GREEN << "Overlaid the " << n << eol;
3526 		else
3527 			cons << RED << "Removed " << n << " from overlay." << eol;
3528 		tog = 1;
3529 	}
3530 	if (tog) TOGGLEMENU
3531 }
3532 
changed(field & f)3533 void menu::curve_ops_listener::changed (field& f) {
3534   if (&f == MENUP.sp_waveform_hz.f_value) {
3535     CRVED->set_hz (f);
3536   } else if (&f == MENUP.sp_waveform_periods.f_value) {
3537     CRVED->set_periods (f);
3538   } else if (&f == MENUP.sp_curve_rpm.f_value) {
3539     CRVED->set_rpm (f);
3540   } else if (&f == MENUP.sp_curve_limit.f_value) {
3541     CRVED->set_limit (f);
3542   } else {
3543 		if (f.text == "") f.set_text ("nameless");
3544     CRVED->set_picked_curve_name (f.text);
3545   }
3546 }
3547 
3548 
typing(field & f)3549 void recording_listener::typing (field& f) {
3550 	string fname (recorder0.folder + f.text);
3551 	string cmd ("file exists " + fname);
3552 	interpreter (cmd); int result; stringstream ss; ss << interpreter.result; ss >> result;
3553 	if (result) MENU.b_save.set_text ("Overwrite"); else MENU.b_save.set_text ("Save");
3554 	recorder0.fname = f.text;
3555 }
3556 
changed(checkbutton & cb)3557 void recording_listener::changed (checkbutton& cb) {
3558 	int state = cb.state;
3559 	if (state == 0) { // show recording save section of file menu
3560 		MENU.changed (MENU.cb_file);
3561 		if (MENU.show == 0) TOGGLEMENU
3562 	} else { // close file menu
3563 		if (MENU.show == 1) TOGGLEMENU
3564 	}
3565 	dont_call_listener (uis.cb_record, state);
3566 	dont_call_listener (MENU.cb_record, state);
3567 }
3568 
handle_split(int & var,int dir,float t)3569 void mondrian_listener::handle_split (int& var, int dir, float t) {
3570 	switch (var) {
3571 		case 0: // into 2 boxes
3572 			mondrian0.split_rect (dir, t);
3573 			break;
3574 		case 1: // into notes
3575 			mondrian0.multi_split_rect (dir);
3576 			break;
3577 		case 2: // into n x n grid
3578 			mondrian0.multi_split_rect (mondrian0.num_boxes, dir);
3579 	}
3580 }
3581 
clicked(button & b)3582 void mondrian_listener::clicked (button& b) {
3583 	int toggle = 1;
3584   if (&b == MENUP.b_split_horizontal) handle_split (hsplit, split::HORIZONTAL, mondrian0.win.mousey);
3585   else if (&b == MENUP.b_split_vertical) handle_split (vsplit, split::VERTICAL, mondrian0.win.mousex);
3586 	else if (&b == MENUP.b_add_balls) mondrian0.do_add_balls (mondrian0.added_ball_type);
3587 	else if (&b == MENUP.b_add_remove_slits) mondrian0.start_slitting ();
3588 	else if (&b == MENUP.b_modulate_balls_up) {if (!mondrian0.modulate_balls (+1)) cons << RED << "Please select some balls!" << eol;}
3589 	else if (&b == MENUP.b_modulate_balls_down) {if (!mondrian0.modulate_balls (-1)) cons << RED << "Please select some balls!" << eol;}
3590 	else if (&b == MENUP.b_select_all_targets) {mondrian0.select_all_targets ();toggle=0;}
3591 	else if (&b == MENUP.b_invert_selected_targets) {mondrian0.invert_selected_targets ();toggle=0;}
3592 	else if (&b == MENUP.b_select_targets_in_box) {mondrian0.select_box_targets ();toggle=0;}
3593   else if (&b == MENUP.b_delete_box) mondrian0.delete_current_rect ();
3594 	else if (&b == MENUP.b_delete_all_boxes) mondrian0.delete_all_rects = 1;
3595 	else if (&b == MENUP.b_freeze_balls) mondrian0.freeze_balls (mondrian0.get_balls());
3596 	else if (&b == MENUP.b_thaw_balls) mondrian0.thaw_balls (mondrian0.get_balls());
3597 	else if (&b == MENUP.b_delete_all_targets) mondrian0.delete_all_targets ();
3598 	else if (&b == MENUP.b_delete_selected_targets) mondrian0.delete_selected_targets ();
3599   else if (&b == MENUP.b_move_selected_balls) mondrian0.do_move_balls ();
3600 	else if (&b == MENUP.b_toggle_wreckers) mondrian0.toggle_balls_type (ball::WRECKER);
3601 	else if (&b == MENUP.b_toggle_healers) mondrian0.toggle_balls_type (ball::HEALER);
3602 	else if (&b == MENUP.b_toggle_bouncers) mondrian0.toggle_balls_type (ball::BOUNCER);
3603 	else if (&b == MENUP.b_switch_ball_type) mondrian0.switch_balls_type ();
3604 	else if (&b == MENUP.b_select_wreckers) mondrian0.select_type (ball::WRECKER);
3605 	else if (&b == MENUP.b_select_healers) mondrian0.select_type (ball::HEALER);
3606 	else if (&b == MENUP.b_remove_slits_on_edge) mondrian0.remove_slits_on_current_edge ();
3607 	else if (&b == MENUP.b_toggle_slit_anim) mondrian0.toggle_slit_anim ();
3608 	else if (&b == MENUP.b_clear_modulations) mondrian0.clear_modulations (mondrian0.get_balls());
3609 	else if (&b == MENUP.b_auto_change_direction_clockwise) {mondrian0.set_auto_rotate (-1);}
3610 	else if (&b == MENUP.b_auto_change_direction_anti_clockwise) {mondrian0.set_auto_rotate (1);}
3611 	else if (&b == MENUP.b_stop_auto_changing_direction) {mondrian0.set_auto_rotate (0);}
3612 	else if (&b == MENUP.b_flip_direction) {mondrian0.flip_velocity();}
3613 	else if (&b == MENUP.b_make_random_color) mondrian0.randomise_box_color();
3614 	else if (&b == MENUP.b_make_note_grid) mondrian0.make_note_grid ();
3615 	else if (&b == MENUP.b_make_nxn_grid) mondrian0.make_nxn_grid ();
3616 	else if (&b == MENUP.b_ball_trig) mondrian0.toggle_triggered_sound ();
3617 	else if (&b == MENUP.abm_left) {mondrian0.do_panx (1); toggle=0;}
3618 	else if (&b == MENUP.abm_right) {mondrian0.do_panx (-1); toggle=0;}
3619 	else if (&b == MENUP.abm_up) {mondrian0.do_pany (+1);toggle=0;}
3620 	else if (&b == MENUP.abm_down) {mondrian0.do_pany (-1); toggle=0;}
3621 	else if (&b == MENUP.bm_zoom_in) {mondrian0.do_zoom(-1); toggle=0;}
3622 	else if (&b == MENUP.bm_zoom_out) {mondrian0.do_zoom(+1); toggle=0;}
3623   if (toggle) TOGGLEMENU
3624 }
3625 
changed(checkbutton & cb)3626 void mondrian_listener::changed (checkbutton& cb) {
3627 	if (&cb == MENUP.cb_auto_split_box) {
3628 		mondrian0.auto_split_rect.active = cb.state;
3629 	} else if (&cb == MENUP.cb_auto_delete_box) {
3630 		mondrian0.auto_del_rect.active = cb.state;
3631 	} else if (&cb == MENUP.cb_draw_boxes) {
3632 		mondrian0.draw__boxes = cb.state;
3633 	} else if (&cb == MENUP.cb_fill_boxes) {
3634 		mondrian0.fill_boxes = cb.state;
3635 	} else if (&cb == MENUP.cb_draw_notes) {
3636 		mondrian0.draw__notes = cb.state;
3637 	} else if (&cb == MENUP.cb_label_notes) {
3638 		mondrian0.label_notes = cb.state;
3639 	} else if (&cb == MENUP.cb_label_hz_vol) {
3640 		mondrian0.label_hz_vol = cb.state;
3641 	} else if (&cb == MENUP.cb_draw_ball_position) {
3642 		mondrian0.draw_ball.position = cb.state;
3643 	} else if (&cb == MENUP.cb_draw_ball_heading) {
3644 		mondrian0.draw_ball.heading = cb.state;
3645 	} else if (&cb == MENUP.cb_draw_ball_trails) {
3646 		mondrian0.draw_ball.trails = cb.state;
3647 	} else if (&cb == MENUP.cb_mondrian_auto_adjust_voices) {
3648 		mondrian0.auto_adjust_voices = cb.state;
3649 	}
3650 }
3651 
changed(field & f)3652 void ball_speed_listener::changed (field& f) {
3653 	mondrian0.change_speed (MENU.sp_mondrian_change_speed, MENU.sp_mondrian_change_speed.dir_delta ());
3654 }
3655 
changed(field & f)3656 void ball_direction_listener::changed (field& f) {
3657 	mondrian0.rotate_velocity (MENU.sp_mondrian_change_dir.dir);
3658 }
3659 
changed(field & f)3660 void ball_volume_listener::changed (field& f) {
3661 	mondrian0.change_ball_vol_mult (MENU.sp_mondrian_change_vol);
3662 }
3663 
changed(field & f)3664 void trail_length_listener:: changed (field& f) {
3665 	mondrian0.change_trail_size (MENU.sp_mondrian_change_trail_size);
3666 }
3667 
changed(field & f)3668 void ball_attack_time_listener:: changed (field& f) {
3669 	mondrian0.change_attack_time_kb (MENU.sp_mondrian_change_attack_time);
3670 }
3671 
changed(field & f)3672 void ball_decay_time_listener:: changed (field& f) {
3673 	mondrian0.change_decay_time_kb (MENU.sp_mondrian_change_decay_time);
3674 }
3675 
changed(field & f)3676 void slit_size_listener:: changed (field& f) {
3677 	mondrian0.change_slit_size (MENU.sp_mondrian_change_slit_size);
3678 }
3679 
changed(field & f)3680 void slit_anim_time_listener:: changed (field& f) {
3681 	mondrian0.change_slit_anim_time (MENU.sp_mondrian_change_slit_anim_time);
3682 }
3683 
changed(field & f)3684 void note_poly_radius_listener::changed (field& f) {
3685 	mondrian0.set_note_poly_radius (float(f));
3686 }
3687 
changed(field & f)3688 void note_poly_points_listener::changed (field& f) {
3689 	mondrian0.set_note_poly_points (int(f));
3690 }
3691 
changed(field & f)3692 void mondrian_listener::changed (field& f) {
3693 	/*if (&f == MENUP.sp_mondrian_change_dir.f_delta) {
3694 		mondrian0.delta_rotate_velocity = float (MENU.sp_mondrian_change_dir.f_delta);
3695 		button* pb[] = {MENUP.sp_mondrian_change_dir.inc, MENUP.sp_mondrian_change_dir.dec};
3696 		MENU.set_repeat (pb, 2, 0.005 * mondrian0.delta_rotate_velocity);
3697 	}
3698 	else */
3699 	if (&f == MENUP.sp_mondrian_change_speed.f_delta) mondrian0.delta_speed = f;
3700 	else if (&f == MENUP.sp_mondrian_min_voices.f_value) {
3701 		mondrian0.min_voices = f;
3702 		uis.update_bottom_line ();
3703 		cons << YELLOW << "Min voices = " << mondrian0.min_voices << eol;
3704 	} else if (&f == MENUP.sp_mondrian_num_boxes.f_value) {
3705 		mondrian0.num_boxes = f;
3706 		cons << YELLOW << "Number of boxes = " << mondrian0.num_boxes << eol;
3707 	} else if (&f == MENUP.sp_auto_split_time.f_value) {
3708 		mondrian0.auto_split_rect.triggert = f;
3709 		cons << YELLOW << "Split box every = " << mondrian0.auto_split_rect.triggert << " secs" << eol;
3710 	} else if (&f == MENUP.sp_auto_delete_time.f_value) {
3711 		mondrian0.auto_del_rect.triggert = f;
3712 		cons << YELLOW << "Delete box every = " << mondrian0.auto_del_rect.triggert << " secs" << eol;
3713 	} else {
3714 		mondrian::min_split_size = f;
3715 		cons << YELLOW << "Min split size = " << mondrian::min_split_size << eol;
3716 	}
3717 }
3718 
handle_auto_pick_box(options_list & ol,int dir,int & v)3719 void mondrian_listener::handle_auto_pick_box (options_list& ol, int dir, int& v) {
3720 	v += dir;
3721 	wrap<int> (rect::EARLIEST, v, rect::BALLED);
3722 	ol.set_text (pick_box_types[v]);
3723 }
3724 
picked(label & lbl,int dir)3725 void mondrian_listener::picked (label& lbl, int dir) {
3726 	if (&lbl == MENUP.ol_auto_pick_box_split.option) {
3727 		handle_auto_pick_box (MENU.ol_auto_pick_box_split, dir, mondrian0.split_leaf);
3728 	} else if (&lbl == MENUP.ol_auto_pick_box_delete.option) {
3729 		handle_auto_pick_box (MENU.ol_auto_pick_box_delete, dir, mondrian0.delete_leaf);
3730 	} else if (&lbl == MENUP.ol_auto_split_at.option) {
3731 		mondrian0.auto_split_at += dir;
3732 		if (mondrian0.auto_split_at < split::NOTES) mondrian0.auto_split_at = split::ANYWHERE;
3733 		else if (mondrian0.auto_split_at > split::ANYWHERE) mondrian0.auto_split_at = split::NOTES;
3734 		MENU.ol_auto_split_at.set_text (auto_split_at_types [mondrian0.auto_split_at]);
3735 	} else if (&lbl == MENUP.ol_auto_split_orient.option) {
3736 		mondrian0.auto_split_orient += dir;
3737 		if (mondrian0.auto_split_orient < split::HORIZONTAL) mondrian0.auto_split_orient = split::BOTH;
3738 		else if (mondrian0.auto_split_orient > split::BOTH) mondrian0.auto_split_orient = split::HORIZONTAL;
3739 		MENU.ol_auto_split_orient.set_text (auto_split_orient_types [mondrian0.auto_split_orient]);
3740 	} else if (&lbl == MENUP.ol_ball_types.option) {
3741 		mondrian0.added_ball_type += dir;
3742 		if (mondrian0.added_ball_type < ball::BOUNCER)
3743 			mondrian0.added_ball_type = ball::HEALER;
3744 		else if (mondrian0.added_ball_type > ball::HEALER)
3745 			mondrian0.added_ball_type = ball::BOUNCER;
3746 		MENU.ol_ball_types.set_text (ball::types_str[mondrian0.added_ball_type]);
3747 	} else if (&lbl == MENUP.ol_split_types_h.option) {
3748 		hsplit += dir;
3749 		check_split_type (MENU.ol_split_types_h, hsplit);
3750 	} else if (&lbl == MENUP.ol_split_types_v.option) {
3751 		vsplit += dir;
3752 		check_split_type (MENU.ol_split_types_v, vsplit);
3753 	} else if (&lbl == MENUP.ol_selection_targets.option) {
3754     mondrian0.clear_selected_targets ();
3755 		mondrian0.sel_tar = !mondrian0.sel_tar;
3756 		MENU.ol_selection_targets.set_text (selection_targets[mondrian0.sel_tar]);
3757 		static const char* bb [] = {"Select all balls", "Select balls in box", "Invert selected balls", "Delete all balls", "Delete selected balls"};
3758 		static const char* bs [] = {"Select all slits", "Select slits in box", "Invert selected slits", "Remove all slits", "Remove selected slits"};
3759 		const char** pb [] = {bs, bb};
3760 		button* bt [] = {
3761 			MENUP.b_select_all_targets, MENUP.b_select_targets_in_box,
3762 			MENUP.b_invert_selected_targets, MENUP.b_delete_all_targets,
3763 			MENUP.b_delete_selected_targets
3764 		};
3765 		const char** cb = pb[mondrian0.sel_tar];
3766 		for (int i = 0; i < 5; ++i) bt[i]->set_text (cb[i]);
3767 	}
3768 }
3769 
check_split_type(options_list & ol,int & o)3770 void mondrian_listener::check_split_type (options_list& ol, int& o) {
3771 	if (o < 0) o = MAX_SPLIT_TYPES; else if (o > MAX_SPLIT_TYPES) o = 0;
3772 	ol.set_text (split_types[o]);
3773 }
3774 
3775 
binaural_drones_listener()3776 binaural_drones_listener::binaural_drones_listener () : select_rule (GREATER_THAN_EQUAL), select_what (0) {
3777 	val[EQUAL] = "0";
3778 	val[GREATER_THAN_EQUAL] = val[LESSER_THAN_EQUAL]= "100";
3779 	val[ID] = "1 2 1";
3780 	val[RANGE] = "100 200";
3781 	just = binaural_drone::CENTER;
3782 }
3783 
changed(field & f)3784 void binaural_drones_listener::changed (field& f) {
3785 	float v = float(f);
3786 	if (&f == MENUP.lf_bd_start_pitch.fld) {
3787 		binaural_drones0.starting_pitch = v;
3788 	} else if (&f == MENUP.lf_master_volume.fld) {
3789 		float ov = binaural_drones0.master_volume * 100.0f;
3790 		float mv = v / 100.0f;
3791 		binaural_drones0.master_volume = mv;
3792 		stringstream cmd;
3793 		cmd << "set-all-binaurals-volume " << mv;
3794 		interpreter (cmd.str());
3795 		sprintf (BUFFER, "Master Volume from %0.2f%% to %0.2f%% : please wait or ESC to abort", ov, v);
3796 		cons << YELLOW << BUFFER << eol;
3797 	} else if (&f == MENUP.lf_vol_fade_time.fld) {
3798 		binaural_drones0.vol_fader.set_duration (v);
3799 	} else if (&f == MENUP.lf_pitch_fade_time.fld) {
3800 		binaural_drones0.pitch_fader.set_duration (v);
3801 	} else if (&f == MENUP.lf_modulation_amount.fld) {
3802 		if (v < 1.0f) {
3803 			v = 1.0f;
3804 			MENU.lf_modulation_amount.fld.set_text (v);
3805 		}
3806 		binaural_drones0.modulation_amount = v;
3807 	} else if (&f == MENUP.lf_bd_spacing.fld) {
3808 		binaural_drones0.spacing = v;
3809 	} else if (&f == MENUP.bdf_value) {
3810 		val[select_rule] = MENU.bdf_value.text;
3811 		MENU.bdl.clicked (MENU.bbd_select2);
3812 	} else if (&f == MENUP.lf_vol.fld) {
3813 		float vp = v / 100.0f;
3814 		sprintf (BUFFER, "set-selected-binaurals-volume %f", vp);
3815 		interpreter (BUFFER);
3816 	} else if (&f == MENUP.lf_l.fld) {
3817 		set_hz (binaural_drone::LEFT, v);
3818 	} else if (&f == MENUP.lf_r.fld) {
3819 		set_hz (binaural_drone::RIGHT, v);
3820 	} else if (&f == MENUP.lf_sep.fld) {
3821 		int j = 0;
3822 		for (int i = 0; i < MENU.il_binaural_drones.n; ++i) {
3823 			if (MENU.il_binaural_drones.items[i].sel) {
3824 				binaural_drone* bi = binaural_drones0.binaural_drones[i];
3825 				bi->set_sep (v);
3826 				++j;
3827 			}
3828 		}
3829 		if (j)
3830 			binaural_drones0.pitch_fader.start ("Separation Hz set");
3831 		else
3832 			cons << RED << "Please select some binaural drone pairs" << eol;
3833 	}
3834 }
3835 
set_hz(int w,float v)3836 void binaural_drones_listener::set_hz (int w, float v) {
3837 
3838 	int n = MENU.il_binaural_drones.num_selected ();
3839 	if (n == 0) {
3840 		cons << RED << "Please select some binaural drone pairs" << eol;
3841 		return;
3842 	}
3843 
3844 	if (n == 1) {
3845 		int i = MENU.il_binaural_drones.get_first ();
3846 		binaural_drone* bi = binaural_drones0.binaural_drones[i];
3847 		bi->set_hz (w, v); // v is absolute
3848 		binaural_drones0.pitch_fader.start ("Hz set");
3849 	} else {
3850 		for (int i = 0; i < MENU.il_binaural_drones.n; ++i) {
3851 			if (MENU.il_binaural_drones.items[i].sel) {
3852 				binaural_drone* bi = binaural_drones0.binaural_drones[i];
3853 				float ohz [] = {bi->l_hz, bi->r_hz};
3854 				bi->set_hz (w, ohz[w] + v); // v is relative
3855 			}
3856 		}
3857 		binaural_drones0.pitch_fader.start ("Hz change");
3858 	}
3859 }
3860 
picked(label & lbl,int dir)3861 void binaural_drones_listener::picked (label& lbl, int dir) {
3862 	if (&lbl == MENUP.ol_justification.option) {
3863 		int j = binaural_drones0.change_justification (dir);
3864 		MENU.ol_justification.set_text (justs[j]);
3865 	} else if (&lbl == MENUP.ol_key_note.option) {
3866 		int k = binaural_drones0.change_key_note (dir);
3867 		const string kn [] = {"start pitch", "from scale"};
3868 		MENU.ol_key_note.set_text (" Key note is " + kn[k]);
3869 	} else if (&lbl == MENUP.ol_select_what.option) {
3870 		select_what += dir;
3871 		wrap<int> (binaural_drone::LEFT, select_what, binaural_drone::VOLUME);
3872 		const string sc [] = {"L ", "R ", "Separation ", "Volume "};
3873 		MENU.ol_select_what.set_text (sc[select_what]);
3874 		MENU.ol_select_rule.set_pos (MENU.ol_select_what.extents.right, MENU.ol_select_rule.posy);
3875 		MENU.bdf_value.set_pos (MENU.ol_select_rule.extents.right, MENU.bdf_value.posy);
3876 	} else if (&lbl == MENUP.ol_select_rule.option) {
3877 		select_rule += dir;
3878 		wrap<int> (EQUAL, select_rule, ID);
3879 		const string sr [] = {" = ", " >= ", " <= ", " <> ", " id "};
3880 		MENU.ol_select_rule.set_text (sr[select_rule]);
3881 		MENU.bdf_value.set_text (val[select_rule]);
3882 		MENU.bdf_value.set_pos (MENU.ol_select_rule.extents.right, MENU.bdf_value.posy);
3883 	} else if (&lbl == MENUP.ol_just.option) {
3884 		just += dir;
3885 		wrap<int> (binaural_drone::LEFT, just, binaural_drone::CENTER);
3886 		MENU.ol_just.set_text (justs[just]);
3887 		for (int i = 0; i < MENU.il_binaural_drones.n; ++i) {
3888 			if (MENU.il_binaural_drones.items[i].sel) {
3889 				binaural_drone* bi = binaural_drones0.binaural_drones[i];
3890 				bi->set_just (just);
3891 			}
3892 		}
3893 	}
3894 }
3895 
selected(item_list & il,int s)3896 void binaural_drones_listener::selected (item_list& il, int s) {
3897 	int ns = il.num_selected ();
3898 	if (ns == 1) {
3899 		binaural_drone* bs = binaural_drones0.binaural_drones[il.get_first()];
3900 		bs->sel = 1;
3901 		sprintf (BUFFER, "%0.3f", bs->vol*100.0);
3902 		MENU.lf_vol.set_text (BUFFER);
3903 		sprintf (BUFFER, "%0.3f", bs->l_hz);
3904 		MENU.lf_l.set_text (BUFFER);
3905 		sprintf (BUFFER, "%0.3f", bs->r_hz);
3906 		MENU.lf_r.set_text (BUFFER);
3907 		sprintf (BUFFER, "%0.3f", bs->sep);
3908 		MENU.lf_sep.set_text (BUFFER);
3909 		MENU.lf_l.set_label ("L (Hz) ");
3910 		MENU.lf_r.set_label ("R (Hz) ");
3911 		just = bs->just;
3912 		MENU.ol_just.set_text (justs[just]);
3913 	} else {
3914 		if (ns) {
3915 			MENU.lf_l.set_label ("dL (Hz) ");
3916 			MENU.lf_r.set_label ("dR (Hz) ");
3917 		}
3918 		MENU.lf_vol.fld.set_text (0.0f);
3919 		MENU.lf_l.fld.set_text (0.0f);
3920 		MENU.lf_r.fld.set_text (0.0f);
3921 		MENU.lf_sep.fld.set_text (0.0f);
3922 		just = binaural_drone::CENTER;
3923 		MENU.ol_just.set_text (justs[just]);
3924 		for (int i = 0, n = il.n; i < n; ++i) {
3925 			binaural_drone* bi = binaural_drones0.binaural_drones[i];
3926 			bi->sel = il.items[i].sel;
3927 		}
3928 	}
3929 	cons << GREEN << "Selected " << ns << " binaural drone pairs" << eol;
3930 }
3931 
changed(checkbutton & cb)3932 void binaural_drones_listener::changed (checkbutton& cb) {
3933 	binaural_drones0.close_octave = MENU.cb_close_octave.state;
3934 }
3935 
update_binaurals_list()3936 void menu::update_binaurals_list () {
3937 	il_binaural_drones.set_pos (cb_file.extents.left, bbd_select_all.extents.bottom);
3938 	calc_bg ();
3939 }
3940 
ball_ops_listener()3941 ball_ops_listener::ball_ops_listener () {
3942 	op_id = 0;
3943 }
3944 
picked(label & lbl,int dir)3945 void ball_ops_listener::picked (label& lbl, int dir) {
3946 	if (&lbl == MENUP.ol_browse_balls.option) {
3947 		mondrian0.browse_ball (dir);
3948 		return;
3949 	} else {
3950 		label* olt [] = {MENUP.ol_bouncer.option, MENUP.ol_wrecker.option, MENUP.ol_healer.option};
3951 		for (int i = 0; i < 3; ++i) {
3952 			if (&lbl == olt[i]) {
3953 				int& t = Transform::rules [i];
3954 				t += dir;
3955 				if (t < ball::BOUNCER) t = ball::INVALID;
3956 				else if (t > ball::INVALID) t = ball::BOUNCER;
3957 				sprintf (BUFFER, "%s becomes %s", ball::types_str[i], ball::types_str[t]);
3958 				olt[i]->set_text (BUFFER);
3959 				return;
3960 			}
3961 		}
3962 	}
3963 }
3964 
clicked(button & b)3965 void ball_ops_listener::clicked (button& b) {
3966 }
3967 
changed(checkbutton & cb)3968 void ball_ops_listener::changed (checkbutton& cb) {
3969 	ball* b = mondrian0.get_one_selected_ball ();
3970 	if (b) {
3971 		ball_op* ops [] = {&b->op_turn, &b->op_speed, &b->op_teleport, &b->op_clone, &b->op_transform};
3972 		checkbutton* cbn [] = {MENUP.cb_turn, MENUP.cb_speed, MENUP.cb_teleport, MENUP.cb_clone, MENUP.cb_transform};
3973 		for (int i = 0; i < ball_op::NUM_OPS; ++i) {
3974 			if (&cb == cbn[i]) {
3975 				ball_op* opi = ops[i];
3976 				// if (cb.state) opi->alarm.start (); else opi->alarm.stop ();
3977 				if (cb.state) opi->start (b); else opi->alarm.stop ();
3978 
3979 				break;
3980 			}
3981 		}
3982 
3983 		/*if (cb.state && (&cb == MENUP.cb_speed)) {
3984 			MENU.sp_max_speed.set_value (b->V);
3985 			b->op_speed.max = b->V;
3986 		}*/
3987 
3988 		b->op_clone.clone_can_clone = MENU.cb_clone_can_clone.state;
3989 
3990 	} else {
3991 		cons << RED << "Please select a ball!" << eol;
3992 	}
3993 }
3994 
changed(field & f)3995 void ball_ops_listener::changed (field& f) {
3996 	if (&f == MENUP.sp_max_balls.f_value) {
3997 		int i = f;
3998 		Clone::max_balls = i;
3999 		cons << YELLOW << "Max balls = " << Clone::max_balls << eol;
4000 	} else {
4001 		ball* b = mondrian0.get_one_selected_ball ();
4002 		if (b) {
4003 			if (&f == MENUP.sp_turn_every.f_value) {
4004 				float t = f;
4005 				b->op_turn.alarm.triggert = t;
4006 				sprintf (BUFFER, "Turn every %0.3f seconds", t);
4007 				cons << YELLOW << BUFFER << eol;
4008 			} else
4009 			if (&f == MENUP.sp_turn_min.f_value) {
4010 				float minn = f, maxx;
4011 				if (MENU.cb_turn_sync.state) {
4012 					maxx = minn;
4013 					MENU.sp_turn_max.set_value (maxx);
4014 				} else maxx = b->op_turn.rd.max;
4015 				b->op_turn.rd.set (-minn, maxx);
4016 				sprintf (BUFFER, "Turn Clockwise upto %0.3f degrees | Anti-clockwise upto %0.3f degrees", minn, maxx);
4017 				cons << YELLOW << BUFFER << eol;
4018 			} else
4019 			if (&f == MENUP.sp_turn_max.f_value) {
4020 				float minn, maxx = f;
4021 				if (MENU.cb_turn_sync.state) {
4022 					MENU.sp_turn_min.set_value (maxx);
4023 					minn = -maxx;
4024 				} else minn = b->op_turn.rd.min;
4025 				b->op_turn.rd.set (minn, maxx);
4026 				sprintf (BUFFER, "Turn Clockwise upto %0.3f degrees | Anti-clockwise upto %0.3f degrees", -minn, maxx);
4027 				cons << YELLOW << BUFFER << eol;
4028 			} else
4029 			if (&f == MENUP.sp_speed_min.f_value) {
4030 				float minn = f, maxx;
4031 				if (MENU.cb_speed_sync.state) {
4032 					maxx = minn;
4033 					MENU.sp_speed_max.set_value (maxx);
4034 				} else maxx = b->op_speed.rd.max;
4035 				b->op_speed.rd.set (-minn, maxx);
4036 				sprintf (BUFFER, "Accelerate = %0.3f | Brake = %0.3f", maxx, minn);
4037 				cons << YELLOW << BUFFER << eol;
4038 			} else
4039 			if (&f == MENUP.sp_speed_max.f_value) {
4040 				float minn, maxx = f;
4041 				if (MENU.cb_speed_sync.state) {
4042 					MENU.sp_speed_min.set_value (maxx);
4043 					minn = -maxx;
4044 				} else minn = b->op_speed.rd.min;
4045 				b->op_speed.rd.set (minn, maxx);
4046 				sprintf (BUFFER, "Accelerate = %0.3f | Brake = %0.3f", maxx, -minn);
4047 				cons << YELLOW << BUFFER << eol;
4048 			} else
4049 			if (&f == MENUP.sp_speed_every.f_value) {
4050 				float m = f;
4051 				b->op_speed.alarm.triggert = m;
4052 				sprintf (BUFFER, "Speed every %0.3f seconds", m);
4053 				cons << YELLOW << BUFFER << eol;
4054 			} else
4055 			if (&f == MENUP.sp_max_speed.f_value) {
4056 				float m = f;
4057 				b->op_speed.max = m;
4058 				sprintf (BUFFER, "Max speed = %0.3f", m);
4059 				cons << YELLOW << BUFFER << eol;
4060 			} else
4061 			if (&f == MENUP.sp_tel_every.f_value) {
4062 				float s = f;
4063 				b->op_teleport.alarm.triggert = s;
4064 				sprintf (BUFFER, "Teleport every %0.3f seconds", s);
4065 				cons << YELLOW << BUFFER << eol;
4066 			} else
4067 			if (&f == MENUP.sp_tel_radius.f_value) {
4068 				float r = f;
4069 				b->op_teleport.radius = r;
4070 				sprintf (BUFFER, "Max Teleport distance = %0.3f", r);
4071 				cons << YELLOW << BUFFER << eol;
4072 			} else
4073 			if (&f == MENUP.sp_clone_every.f_value) {
4074 				float m = f;
4075 				b->op_clone.alarm.triggert = m;
4076 				sprintf (BUFFER, "Clone every %0.3f seconds", m);
4077 				cons << YELLOW << BUFFER << eol;
4078 			} else
4079 			if (&f == MENUP.sp_max_clones.f_value) {
4080 				int i = f;
4081 				b->op_clone.n = b->op_clone.max = i;
4082 				cons << "Max clones = " << i << eol;
4083 			} else
4084 			if (&f == MENUP.sp_clone_offset.f_value) {
4085 				float m = f;
4086 				b->op_clone.offset = m;
4087 				cons << YELLOW << "Clone offset = " << m << eol;
4088 			} else
4089 			if (&f == MENUP.sp_transform_every.f_value) {
4090 				float m = f;
4091 				b->op_transform.alarm.triggert = m;
4092 				sprintf (BUFFER, "Transform every %0.3f seconds", m);
4093 				cons << YELLOW << BUFFER << eol;
4094 			}
4095 		} else {
4096 			cons << RED << "Please select a ball! " << eol;
4097 		}
4098 	}
4099 }
4100 
changed(field & f)4101 void arrowlis::changed (field& f) {
4102   if (&f == MENUP.dronearrow.shoulder.position.f_value) {
4103     din0.change_drone_arrow (MENU.dronearrow.shoulder.position, 0);
4104   } else if (&f == MENUP.dronearrow.shoulder.width.f_value) {
4105     din0.change_drone_arrow (MENU.dronearrow.shoulder.width, 1);
4106 	} else {
4107 		din0.change_drone_arrow (MENU.dronearrow.neck, 2);
4108   }
4109 }
4110 
changed(field & f)4111 void defarrowlis::changed (field& f) {
4112   drone::arrowt::U = MENU.dronearrowdefaults.shoulder.position.value;
4113   drone::arrowt::V = MENU.dronearrowdefaults.shoulder.width.value;
4114   drone::arrowt::K = MENU.dronearrowdefaults.neck.value;
4115   cons << GREEN <<
4116     "Drone arrow defaults: Neck = " << drone::arrowt::K <<
4117     ", Shoulder pos = " << drone::arrowt::U <<
4118     ", Shoulder width = " << drone::arrowt::V << eol;
4119   MENU.dronearrowdefaults.arrow.calc ();
4120 }
4121 
changed(checkbutton & cb)4122 void defarrowlis::changed (checkbutton& cb) {
4123   MENU.dronearrowdefaults.arrow.calc ();
4124 }
4125 
calc()4126 void drawrrow::calc () {
4127   int cap = MENU.dronearrowdefaults.cap.state;
4128   int n = 12;
4129   make_arrow (pts, 0, cap, n, x, y, ux, uy, vx, vy,
4130     MENU.dronearrowdefaults.shoulder.position.value,
4131     MENU.dronearrowdefaults.shoulder.width.value,
4132     MENU.dronearrowdefaults.neck.value);
4133   npts = n / 2;
4134 }
4135 
reset()4136 void drone::arrowt::reset () {
4137   u = MENU.dronearrowdefaults.shoulder.position ();
4138   v = MENU.dronearrowdefaults.shoulder.width ();
4139   t = MENU.dronearrowdefaults.neck ();
4140   cap = MENU.dronearrowdefaults.cap.state;
4141 }
4142 
clicked(button & b)4143 void arrowlis::clicked (button& b) {
4144   if (&b == MENUP.dronearrow.cap)
4145     din0.capdronearrows (1);
4146   else
4147     din0.capdronearrows (0);
4148   TOGGLEMENU
4149 }
4150 
4151 
4152 
changed(field & f)4153 void range_defaults_lis::changed (field& f) {
4154 	if (&f == MENUP.sp_default_width.f_value) {
4155 		extern int WIDTH;
4156 		WIDTH = f;
4157 		cons << "Default Range Width = " << WIDTH << eol;
4158 	} else {
4159 		extern int HEIGHT;
4160 		HEIGHT = f;
4161 		cons << "Default Range Height = " << HEIGHT << eol;
4162 	}
4163 }
4164 
moused(int dx,double scl)4165 void change_note_listener::moused (int dx, double scl) {
4166   int dir = sign (dx);
4167 	din0.change_range_note (id, dir * scl * delta0);
4168 }
4169 
clicked(button & b)4170 void change_note_listener::clicked (button& b) {
4171 	if (&b == MENUP.b_change_note_left) {
4172 		mouse_slider0.add (MENUP.cnl);
4173 	} else {
4174 		mouse_slider0.add (MENUP.cnr);
4175 	}
4176 	activate_mouse_slider (0, 0);
4177 }
4178 
clicked(button & b)4179 void change_note_both_listener::clicked (button& b) {
4180 	mouse_slider0.add (MENUP.cnl);
4181 	mouse_slider0.add (MENUP.cnr);
4182 	activate_mouse_slider (0, 0);
4183 }
4184 
picked(label & lbl,int dir)4185 void change_note_options_listener::picked (label& lbl, int dir) {
4186 	if (&lbl == MENUP.ol_change_note.option) {
4187 		static const string chg (" Change "), nte ("Note > ");
4188 		din0.dinfo.change_note = !din0.dinfo.change_note;
4189 		if (din0.dinfo.change_note)
4190 			MENU.add_to_tab (MENUP.cb_mkb_ranges, MENUP.ol_change_note_style);
4191 		else
4192 			MENU.remove_from_tab (MENUP.cb_mkb_ranges, MENUP.ol_change_note_style);
4193 		string cn (din_info::cnno[din0.dinfo.change_note]);
4194 		lbl.set_text (chg+cn);
4195 		print_range_info (din0.ranges[din0.dinfo.sel_range]);
4196 	} else {
4197 		din0.dinfo.change_note_style = !din0.dinfo.change_note_style;
4198 		set (lbl, din0.dinfo.change_note_style);
4199 	}
4200 }
4201 
set(label & lbl,int v)4202 void change_note_options_listener::set (label& lbl, int v) {
4203 	lbl.set_text (din_info::cnn_opts[v]);
4204 	extern scale_info all_notes;
4205 	scale_info* ptr_si [] = {&din0.scaleinfo, &all_notes};
4206 	din0.ptr_scaleinfo = ptr_si[v];
4207 }
4208 
changed(checkbutton & cb)4209 void menu::pitch_vol_dis_pix_lis::changed (checkbutton& cb) {
4210 	if (&cb == MENUP.cb_pitch_dis) {
4211 		din0.dinfo.dist.pitch = cb.state;
4212 	} else {
4213 		din0.dinfo.dist.vol = cb.state;
4214 	}
4215 }
4216 
changed(field & f)4217 void menu::pitch_vol_dis_pix_lis::changed (field& f) {
4218 	din0.dinfo.dist.pix = f;
4219 	cons << "Pixels per level = " << din0.dinfo.dist.pix << eol;
4220 }
4221 
prep_drone_xform(mouse_slider_listener * L,int shift=0,int scalestyle=mouse_slider::scalet::CHANGING)4222 void prep_drone_xform (mouse_slider_listener* L, int shift = 0, int scalestyle = mouse_slider::scalet::CHANGING) {
4223 	din0.freeze_orbiters ();
4224 	mouse_slider0.add (L);
4225 	activate_mouse_slider (shift, scalestyle);
4226 }
4227 
CLICKED_BUTTON(menu,b_move_drones_lis)4228 CLICKED_BUTTON (menu, b_move_drones_lis) {
4229   din0.start_moving_drones ();
4230 	TOGGLEMENU
4231 }
4232 
CLICKED_BUTTON(menu,b_set_xform_center_lis)4233 CLICKED_BUTTON (menu, b_set_xform_center_lis) {
4234   din0.calc_drones_centroid ();
4235   TOGGLEMENU
4236 }
4237 
CLICKED_BUTTON(menu,b_move_drones_under_gravity_lis)4238 CLICKED_BUTTON (menu, b_move_drones_under_gravity_lis) {
4239 	din0.set_drones_under_gravity ();
4240 	TOGGLEMENU
4241 }
4242 
CLICKED_BUTTON(menu,b_scale_drones_lis)4243 CLICKED_BUTTON (menu,b_scale_drones_lis) {
4244 	MENU.ms_sdl.name = "Scale";
4245 	if (din0.prep_scale_drones ()) {
4246     int shift = -2; // for 0.01f scaling, assuming base = 10 on mouse slider
4247     prep_drone_xform (MENUP.ms_sdl, shift, mouse_slider::scalet::CHANGING);
4248   } else cons << RED_PSD << eol;
4249 }
4250 
AFTER_SLIDE(menu,ms_scale_drones_lis)4251 AFTER_SLIDE (menu,ms_scale_drones_lis) {
4252 	din0.thaw_orbiters ();
4253 }
4254 
MOUSED(menu,ms_scale_drones_lis)4255 MOUSED (menu,ms_scale_drones_lis) {
4256 	din0.scale_drones (dir * scl);
4257 	din0.scale_drones ();
4258 }
4259 
CLICKED_BUTTON(menu,b_rotate_drones_lis)4260 CLICKED_BUTTON (menu,b_rotate_drones_lis) {
4261 	MENU.ms_rdl.name = "Rotate";
4262 	if (din0.prep_rotate_drones ()) prep_drone_xform (MENUP.ms_rdl); else cons << RED << "Please select some drones!" << eol;
4263 }
4264 
AFTER_SLIDE(menu,ms_rotate_drones_lis)4265 AFTER_SLIDE (menu,ms_rotate_drones_lis) {
4266 	din0.thaw_orbiters ();
4267 }
4268 
MOUSED(menu,ms_rotate_drones_lis)4269 MOUSED (menu,ms_rotate_drones_lis) {
4270 	din0.angle += (dir * scl * PI_BY_180);
4271 	din0.rotate_drones ();
4272 }
4273 
CLICKED_BUTTON(menu,set_to_mesh_rows_lis)4274 CLICKED_BUTTON (menu,set_to_mesh_rows_lis) {
4275 	MENU.sp_drones_per_pend.set_value (din0.dinfo.rows);
4276 	MENU.dppl.changed (MENU.sp_drones_per_pend.f_value);
4277 }
4278 
CLICKED_BUTTON(menu,set_to_mesh_cols_lis)4279 CLICKED_BUTTON (menu,set_to_mesh_cols_lis) {
4280 	MENU.sp_drones_per_pend.set_value (din0.dinfo.cols);
4281 	MENU.dppl.changed (MENU.sp_drones_per_pend.f_value);
4282 }
4283 
CLICKED_CHECKBUTTON(menu,cb_am_bpm_lis)4284 CLICKED_CHECKBUTTON (menu,cb_am_bpm_lis) {
4285 	din0.dinfo.mesh_vars.apply_to.am = cb.state;
4286 	din0.dinfo.mesh_vars.apply_to.calc_active ();
4287 }
4288 
CLICKED_CHECKBUTTON(menu,cb_fm_bpm_lis)4289 CLICKED_CHECKBUTTON (menu,cb_fm_bpm_lis) {
4290 	din0.dinfo.mesh_vars.apply_to.fm = cb.state;
4291 	din0.dinfo.mesh_vars.apply_to.calc_active ();
4292 }
4293 
CLICKED_BUTTON(menu,b_set_unset_toggle_lis)4294 CLICKED_BUTTON(menu,b_set_unset_toggle_lis) {
4295 	if (&b == MENUP.b_toggle) {
4296 		if (din0.dinfo.set_unset_toggle) din0.pos_afx_vel (-1); else din0.snap_drones (-1);
4297 	} else if (&b == MENUP.b_set) {
4298 		if (din0.dinfo.set_unset_toggle) din0.pos_afx_vel (1); else din0.snap_drones (1);
4299 	} else {
4300 		if (din0.dinfo.set_unset_toggle) din0.pos_afx_vel (0); else din0.snap_drones (0);
4301 	}
4302   TOGGLEMENU
4303 }
4304 
VALUE_CHANGED(menu,drones_per_pend_lis)4305 VALUE_CHANGED (menu,drones_per_pend_lis) {
4306 	din0.dinfo.mesh_vars.dpp = int (f);
4307 	cons << "Drones per pendulum = " << din0.dinfo.mesh_vars.dpp << eol;
4308 }
4309 
PICKED_OPTION(menu,ol_fixed_lis)4310 PICKED_OPTION (menu, ol_fixed_lis) {
4311 	range& rs = din0.ranges [din0.dinfo.sel_range];
4312 	rs.fixed += dir;
4313 	wrap<int> (range::LEFT, rs.fixed, range::RIGHT);
4314 	MENU.ol_fixed.set_text (ol_fixed_lbls[rs.fixed]);
4315 }
4316 
CLICKED_CHECKBUTTON(menu,cb_draw_mesh_lis)4317 CLICKED_CHECKBUTTON (menu,cb_draw_mesh_lis) {
4318 	din0.meshh.draw = cb.state;
4319 	TOGGLEMENU
4320 }
4321 
VALUE_CHANGED(menu,lf_conn_steps_lis)4322 VALUE_CHANGED (menu,lf_conn_steps_lis) {
4323 	din0.calc_stepz (f.text);
4324 	cons << YELLOW << "Click connect to connect drones" << eol;
4325 }
4326 
typing(field & f)4327 void menu::lf_conn_steps_lis::typing (field& f) {
4328 	static const int d = 12;
4329 	MENU.cb_conn_wrap.set_pos (f.extents.right + d, MENU.cb_conn_wrap.posy);
4330   MENU.trackcon.set_pos (MENU.cb_conn_wrap.extents.right + d, MENU.trackcon.posy);
4331 }
4332 
CLICKED_CHECKBUTTON(menu,cb_conn_wrap_lis)4333 CLICKED_CHECKBUTTON (menu, cb_conn_wrap_lis) {
4334 	cons << YELLOW << "Click connect to connect drones" << eol;
4335 }
4336 
CLICKED_BUTTON(menu,b_connect_lis)4337 CLICKED_BUTTON (menu, b_connect_lis) {
4338 	if (din0.connect_drones ()) TOGGLEMENU
4339 }
4340 
CLICKED_BUTTON(menu,b_disconnect_lis)4341 CLICKED_BUTTON (menu, b_disconnect_lis) {
4342 	if (din0.disconnect_drones ()) TOGGLEMENU
4343 }
4344 
update_data()4345 void get_color::update_data () {
4346 	data.clr[0] = color (MENU.s_red_min(), MENU.s_green_min(), MENU.s_blue_min());
4347 	data.clr[1] = color (MENU.s_red_max(), MENU.s_green_max(), MENU.s_blue_max());
4348 }
4349 
SLIDER_CHANGED(menu,sc_color_lis)4350 SLIDER_CHANGED(menu,sc_color_lis) {
4351 	get_color::update_data ();
4352 	din0.color_selected_drones ();
4353 	MENU.b_close.set_pos (mousex, MENU.b_close.posy);
4354 }
4355 
START_SLIDE(menu,ss_color_lis,slider<float>)4356 START_SLIDE(menu, ss_color_lis, slider<float>) {
4357 	if (MENU.b_close.visible == 0) {
4358 		DECL_COLOR_SLIDERS
4359 		button& b_close = detach_from_menu (slrs, COLOR_SLIDERS_N, MENU.s_red_max.posx, MENU.s_red_max.posy);
4360 		LISTEN (b_close, MENUP.cscll)
4361 	}
4362 }
4363 
CLICKED_BUTTON(menu,sc_close_lis)4364 CLICKED_BUTTON(menu, sc_close_lis) {
4365 	DECL_COLOR_SLIDERS
4366 	attach_to_menu (slrs, COLOR_SLIDERS_N);
4367 }
4368 
PICKED_OPTION(menu,ol_color_lis)4369 PICKED_OPTION(menu,ol_color_lis) {
4370 	colorer_t& colorer = MENU.colorer;
4371 	colorer += dir;
4372 	l.set_text (colorer_t::s_schemes[colorer.i]);
4373 	din0.color_selected_drones ();
4374 }
4375 
CLICKED_CHECKBUTTON(menu,cb_modulation_lis)4376 CLICKED_CHECKBUTTON (menu,cb_modulation_lis) {
4377   MENU.cb_visual.set_state (0,0);
4378 	MENU.cb_motion.set_state (0,0);
4379   MENU.cb_chuck.set_state (0,0);
4380   MENU.cb_defaults.set_state (0,0);
4381 	cb.set_state (1, 0);
4382 	MENU.set_drone_params_items (9, 23);
4383 }
4384 
CLICKED_CHECKBUTTON(menu,cb_motion_lis)4385 CLICKED_CHECKBUTTON (menu,cb_motion_lis) {
4386   MENU.cb_modulation.set_state (0,0);
4387   MENU.cb_visual.set_state (0,0);
4388   MENU.cb_chuck.set_state (0,0);
4389   MENU.cb_defaults.set_state (0,0);
4390 	cb.set_state (1, 0);
4391 	MENU.set_drone_params_items (23, 57);
4392 }
4393 
CLICKED_CHECKBUTTON(menu,cb_defaults_lis)4394 CLICKED_CHECKBUTTON (menu,cb_defaults_lis) {
4395   MENU.cb_modulation.set_state (0,0);
4396   MENU.cb_visual.set_state (0,0);
4397 	MENU.cb_motion.set_state (0,0);
4398   MENU.cb_chuck.set_state (0,0);
4399   cb.set_state (1, 0);
4400   MENU.set_drone_params_items (57, 93);
4401 }
4402 
CLICKED_CHECKBUTTON(menu,cb_chuck_lis)4403 CLICKED_CHECKBUTTON (menu,cb_chuck_lis) {
4404   MENU.cb_modulation.set_state (0,0);
4405   MENU.cb_visual.set_state (0,0);
4406 	MENU.cb_motion.set_state (0,0);
4407   MENU.cb_defaults.set_state (0,0);
4408 	cb.set_state (1, 0);
4409 	MENU.set_drone_params_items (93, 101);
4410 }
4411 
CLICKED_CHECKBUTTON(menu,cb_visual_lis)4412 CLICKED_CHECKBUTTON (menu,cb_visual_lis) {
4413   MENU.cb_modulation.set_state (0,0);
4414 	MENU.cb_motion.set_state (0,0);
4415   MENU.cb_chuck.set_state (0,0);
4416   MENU.cb_defaults.set_state (0,0);
4417 	cb.set_state (1, 0);
4418 	MENU.set_drone_params_items (101, DRONE_PARAMS_N);
4419 }
4420 
CLICKED_BUTTON(menu,b_abort_octave_shift_lis)4421 CLICKED_BUTTON (menu, b_abort_octave_shift_lis) {
4422 	abort_octave_shift (get_current_instrument());
4423 }
4424 
CLICKED_BUTTON(menu,b_arrow_reset_lis)4425 CLICKED_BUTTON (menu, b_arrow_reset_lis) {
4426 	din0.reset_drone_arrows ();
4427 }
4428 
handle_voice_tab_items(const char * viv)4429 void menu::handle_voice_tab_items (const char* viv) {
4430 
4431 	cb_mkb_voice.set_text (viv);
4432 
4433 	widget* wvoice [] = {
4434 		&sp_am_depth,
4435 		&sp_fm_depth,
4436 		&sp_am_bpm,
4437 		&sp_fm_bpm,
4438 		&ol_am_style,
4439 		&ol_fm_style,
4440 	};
4441 
4442 	if (din0.dinfo.voice_is_voice) {
4443 		for (int i = 0; i < 6; ++i) add_to_tab (&cb_mkb_voice, wvoice[i]);
4444 	} else {
4445 		for (int i = 0; i < 6; ++i) remove_from_tab (&cb_mkb_voice, wvoice[i]);
4446 	}
4447 
4448 	calc_bg ();
4449 
4450 }
4451 
print_range_info(range & ri)4452 void print_range_info (range& ri) {
4453 	note& L = ri.notes[0];
4454 	note& R = ri.notes[1];
4455 	sprintf (BUFFER, "Note > %s | Left = %s @ %0.3f Hz, Right = %s @ %0.3f Hz | Range %d", din_info::cnno[din0.dinfo.change_note], L.name.c_str(), L.hz, R.name.c_str(), R.hz, din0.dinfo.sel_range);
4456 	cons << CYAN << BUFFER << eol;
4457 }
4458 
detach_from_menu(widget ** wa,int n,int posx,int posy)4459 button& detach_from_menu (widget** wa, int n, int posx, int posy) {
4460 
4461 	button& close = MENU.b_close;
4462 	close.set_pos (posx, posy - line_height);
4463 	close.show ();
4464 
4465 	if (MENU.show) MENU.toggle (0);
4466 
4467 	vector<widget*>& vw = uis.widgets_of [uis.current];
4468 	vw.insert (vw.begin(), &close);
4469 
4470 	if (n == 1)
4471 		vw.insert (vw.begin(), wa[0]);
4472 	else
4473 		for (int i = 0; i < n; ++i) vw.insert (vw.begin(), wa[i]);
4474 
4475 	warp_mouse (MENU.menu_mousex, MENU.menu_mousey);
4476 
4477 	return close;
4478 
4479 }
4480 
attach_to_menu(widget ** wa,int n)4481 void attach_to_menu (widget** wa, int n) {
4482 	MENU.b_close.hide ();
4483 	uis.remove (MENUP.b_close);
4484 	if (n == 1) uis.remove (wa[0]); else for (int i = 0; i < n; ++i) uis.remove (wa[i]);
4485 	if (uis.current == &din0) uis.add (&din0, &mkb_selector); //uis.widgets_of [&din0].push_back (&mkb_selector);
4486 }
4487 
CLICKED_BUTTON(menu,b_mute_lis)4488 CLICKED_BUTTON (menu, b_mute_lis) {
4489   din0.gab.set (&din0, 0.0f, "muting drones");
4490   TOGGLEMENU
4491 }
4492 
CLICKED_BUTTON(menu,b_unmute_lis)4493 CLICKED_BUTTON (menu, b_unmute_lis) {
4494   din0.gab.set (&din0, 1.0f, "unmuting drones");
4495   TOGGLEMENU
4496 }
4497 
VALUE_CHANGED(menu,sp_drone_vol_lis)4498 VALUE_CHANGED (menu, sp_drone_vol_lis) {
4499   din0.setdronevol (MENU.sp_drone_vol);
4500 }
4501 
CLICKED_BUTTON(menu,drone2noiselis)4502 CLICKED_BUTTON (menu, drone2noiselis) {
4503   din0.drone2noise ();
4504   TOGGLEMENU
4505 }
4506 
CLICKED_BUTTON(menu,noise2dronelis)4507 CLICKED_BUTTON (menu, noise2dronelis) {
4508   din0.noise2drone ();
4509   TOGGLEMENU
4510 }
4511 
setup()4512 void menu::setvelaccel::setup () {
4513   lbl.set_text ("Set");
4514   whats.option.set_text (" Velocity");
4515   whats.set_listener (this);
4516   button* b[] = {&zero, &vert, &hor, &vel, &accel};
4517   const char* l[] = {"Vertical", "Horizontal", "Velocity", "Acceleration", "Zero"};
4518   for (int i = 0; i < 5; ++i) {
4519     button& bi = *b[i];
4520     bi.id = i;
4521     bi.set_listener (this);
4522     bi.set_text (l[i]);
4523   }
4524   neg.set_text ("-ve");
4525 #ifdef __WIDGET_MOVE__
4526   widget* w[] = {&lbl, &whats, &neg, &zero, &vert, &hor, &vel, &accel};
4527   makehier (w, 8);
4528   for (int i = 0; i < 8; ++i) w[i]->set_moveable(1);
4529 #endif
4530 }
4531 
clicked(button & b)4532 void menu::setvelaccel::clicked (button& b) {
4533   din0.setvelaccel (what, b.id, neg.state);
4534   TOGGLEMENU
4535 }
4536 
picked(label & l,int dir)4537 void menu::setvelaccel::picked (label& l, int dir) {
4538   static const char* lbl [] = {" Velocity", " Acceleration", " Both"};
4539   what += dir;
4540   wrap<int> (menu::autorott::VELOCITY, what, menu::autorott::BOTH);
4541   l.set_text (lbl[what]);
4542 }
4543 
setup()4544 void menu::autorott::setup () {
4545 
4546   title.set_text ("Auto rotate");
4547   which = VELOCITY;
4548   whichl.option.set_text (" Velocity");
4549   whichl.set_listener (this);
4550   mov.set_text ("Movement?");
4551   button* b[] = {&start, &stop, &toggle, &clockwise, &anticlockwise, &autoflip.set, &autoflip.unset, &autoflip.toggle, &smooth, &tick};
4552   const char* l [] = {"Start", "Stop", "Toggle", "Clockwise", "Anti-clockwise", "Set", "Unset", "Toggle", "Smooth", "Ticked"};
4553   click_listener* clk [] = {&startl, &stopl, &togl, &clkl, &aclkl, &autoflip.setl, &autoflip.unsetl, &autoflip.togl, this, this};
4554   for (int i = 0; i < 10; ++i) {
4555     button& bi = *b[i];
4556     bi.set_text (l[i]);
4557     bi.set_listener (clk[i]);
4558   }
4559 
4560   autoflip.lbl.set_text ("Auto flip");
4561   rpm.set ("RPM", 1.0f, 0.0f, MILLIONF, &rpml);
4562   deg.set ("Degrees per Second", 1.0f, -MILLIONF, MILLIONF, &degl);
4563   tps.set ("Ticks per Second", 1.0f, -MILLIONF, MILLIONF, &tpsl);
4564   autoflip.angle.set (1.0f, 0.0f, MILLIONF, &autoflip.angl);
4565   autoflip.angle.set_text ("Every", DEGREES);
4566 
4567 #ifdef __WIDGET_MOVE__
4568   widget* w[] = {
4569     &title, &whichl, &rpm, &start, &stop, &toggle, &clockwise, &anticlockwise,
4570     &autoflip.lbl, &autoflip.set, &autoflip.unset, &autoflip.toggle, &autoflip.angle,
4571     0
4572   };
4573   makehier (w);
4574 #endif
4575 }
4576 
clicked(button & b)4577 void menu::autorott::clicked (button& b) {
4578   if (&b == &smooth) {
4579     mov.id = autorotator::SMOOTH;
4580     din0.setautorotparam (MENU.autorotate.which, autorott::MOVEMENT);
4581   } else {
4582     mov.id = autorotator::TICK;
4583     din0.setautorotparam (MENU.autorotate.which, autorott::MOVEMENT);
4584   }
4585   TOGGLEMENU
4586 }
4587 
picked(label & lbl,int dir)4588 void menu::autorott::picked (label& lbl, int dir) {
4589   static const char* strs [] = {" Velocity", " Acceleration", " Both"};
4590   which += dir;
4591   wrap<int> (menu::autorott::VELOCITY, which, menu::autorott::BOTH);
4592   lbl.set_text (strs[which]);
4593 }
4594 
checksync(float v,anglet & t,spinner<float> & sp)4595 void menu::defvelaccelui::checksync (float v, anglet& t, spinner<float>& sp) {
4596   if (sync.state) {
4597     t = v;
4598     sp.set_value (v);
4599   }
4600 }
4601 
setup()4602 void menu::defvelaccelui::setup () {
4603 
4604   whichl.set_listener (this);
4605 
4606   spinner2<float>* sp [] = {
4607     &mag,
4608     &autorotate.rpm,
4609     &autorotate.dps,
4610     &autorotate.tps,
4611     &autoflip.deg,
4612   };
4613 
4614   const char* nam [] = {
4615     "Magnitude",
4616     "RPM",
4617     "Degrees Per Second",
4618     "Ticks Per Second",
4619     "Every"
4620   };
4621 
4622   change_listener<field>* chgl [] = {
4623     &magl,
4624     &rpml,
4625     &dpsl,
4626     &tpsl,
4627     &degl
4628   };
4629 
4630   int nsp = 5;
4631   for (int i = 0; i < nsp; ++i) {
4632     spinner2<float>& spi = *sp[i];
4633     spi.set (nam[i], 1.0f, 0.0f, MILLIONF, chgl[i]);
4634     spi.lis[2] = &varl;
4635     spi.variance.cb.id = i;
4636     spi.variance.fld.id = i;
4637     spi.variance.cb.set_listener (&chkl);
4638   }
4639 
4640   clockwise.set (1.0f, 0.0f, MILLIONF, &clockl);
4641   anticlockwise.set (1.0f, 0.0f, MILLIONF, &aclockl);
4642   clockwise.set_text ("Clockwise", DEGREES);
4643   anticlockwise.set_text ("Anti-clockwise", DEGREES);
4644   autoflip.deg.set_text ("Every", DEGREES);
4645 
4646   ldir.set_text ("Direction");
4647   odir.set_listener (&dirl);
4648 
4649   checkbutton* cb [] = {
4650     &neg,
4651     &randomize,
4652     &autorotate.cb,
4653     &autoflip.cb
4654   };
4655 
4656   for (int i = 0, j = nsp; i < 4; ++i, ++j) {
4657     checkbutton& cbi = *cb[i];
4658     cbi.id = j;
4659     cbi.set_listener (&chkl);
4660   }
4661 
4662   autorotate.setup ();
4663 
4664 #ifdef __WIDGET_MOVE__
4665   autoflip.setup ();
4666   widget* w[] = {
4667     &whichl,
4668     &mag,
4669     &ldir, &neg, &odir,
4670     &randomize, &clockwise, &anticlockwise, &sync,
4671     0
4672   };
4673   makehier (w);
4674 #endif
4675 
4676 }
4677 
load()4678 void menu::defvelaccelui::load () {
4679 
4680   defvelaccel* dval [] = {&drone::v0, &drone::a0};
4681   cur = dval [which];
4682   whichl.set_text (cur->name);
4683 
4684   neg.set_state (cur->neg, 0);
4685   static const char* s [] = {" Horizontal", " Vertical", " Mouse"};
4686   odir.set_text (s[cur->dir]);
4687   MENU.dva.idir = cur->dir;
4688 
4689   randomize.set_state (cur->rndrot, 0);
4690   clockwise.set_value (cur->clock.deg);
4691   anticlockwise.set_value (cur->anticlock.deg);
4692   sync.set_state (cur->sync, 0);
4693 
4694   spinner2<float>* sp [] = {
4695     &MENU.dva.mag,
4696     &MENU.dva.autorotate.rpm,
4697     &MENU.dva.autorotate.dps,
4698     &MENU.dva.autorotate.tps,
4699     &MENU.dva.autoflip.deg,
4700   };
4701 
4702   valt* vt [] = {
4703     &cur->mag,
4704     &cur->autos.rot.rpm,
4705     &cur->autos.rot.dps,
4706     &cur->autos.rot.tps,
4707     &cur->autos.flip.deg,
4708   };
4709 
4710   for (int i = 0; i < 5; ++i) {
4711     spinner2<float>& spi = *sp[i];
4712     valt& vti = *vt[i];
4713     spi.set_value (vti.val);
4714     spi.variance.rd = vti.rd;
4715     spi.variance.setfld ();
4716     spi.variance.cb.set_state (vti.rndrd, 0);
4717   }
4718 
4719   autorotate.load ();
4720   autoflip.cb.set_state (cur->autos.flip.yes);
4721 
4722 
4723 }
4724 
picked(label & lbl,int p)4725 void menu::defvelaccelui::picked (label& lbl, int p) {
4726   which = !which;
4727   load ();
4728 }
4729 
VALUE_CHANGED(menu::defvelaccelui,varlis)4730 VALUE_CHANGED (menu::defvelaccelui, varlis) {
4731   spinner2<float>* sp [] = {
4732     &MENU.dva.mag,
4733     &MENU.dva.autorotate.rpm,
4734     &MENU.dva.autorotate.dps,
4735     &MENU.dva.autorotate.tps,
4736     &MENU.dva.autoflip.deg,
4737   };
4738 
4739   defvelaccel& dva = *MENU.dva.cur;
4740   valt* vt [] = {
4741     &dva.mag,
4742     &dva.autos.rot.rpm,
4743     &dva.autos.rot.dps,
4744     &dva.autos.rot.tps,
4745     &dva.autos.flip.deg,
4746   };
4747 
4748   int id = f.id;
4749   vt[id]->rd = sp[id]->variance.rd;
4750 }
4751 
VALUE_CHANGED(menu::defvelaccelui,maglis)4752 VALUE_CHANGED (menu::defvelaccelui, maglis) {
4753   float v = float (f);
4754   MENU.dva.cur->mag.val = v;
4755   cons << "Default Drone " << MENU.dva.cur->name << " = " << v << eol;
4756 }
4757 
getdva()4758 defvelaccel& getdva () {
4759   defvelaccel* dval [] = {&drone::v0, &drone::a0};
4760   return *dval [MENU.dva.which];
4761 }
4762 
VALUE_CHANGED(menu::defvelaccelui,rpmlis)4763 VALUE_CHANGED (menu::defvelaccelui, rpmlis) {
4764   float v = f;
4765   defvelaccel& dva = getdva ();
4766   dva.autos.rot.rpm = v;
4767   cons << dva.name << " Auto rotate RPM = " << v << eol;
4768 }
4769 
VALUE_CHANGED(menu::defvelaccelui,dpslis)4770 VALUE_CHANGED (menu::defvelaccelui, dpslis) {
4771   float v = f;
4772   defvelaccel& dva = getdva ();
4773   dva.autos.rot.dps = v;
4774   cons << dva.name << " Degrees per Second = " << v << eol;
4775 }
VALUE_CHANGED(menu::defvelaccelui,tpslis)4776 VALUE_CHANGED (menu::defvelaccelui, tpslis) {
4777   float v = f;
4778   defvelaccel& dva = getdva ();
4779   dva.autos.rot.tps = v;
4780   cons << dva.name << " Ticks per Second = " << v << eol;
4781 }
4782 
VALUE_CHANGED(menu::defvelaccelui,deglis)4783 VALUE_CHANGED (menu::defvelaccelui, deglis) {
4784   float v = f;
4785   defvelaccel& dva = getdva ();
4786   dva.autos.flip.deg = v;
4787   cons << dva.name << " Auto flip every " << v << DEGREES << eol;
4788 }
4789 
VALUE_CHANGED(menu::defvelaccelui,clocklis)4790 VALUE_CHANGED (menu::defvelaccelui, clocklis) {
4791   float v = float (f);
4792   MENU.dva.cur->clock = v;
4793   MENU.dva.checksync (v, MENU.dva.cur->anticlock, MENU.dva.anticlockwise);
4794   MENU.dva.cur->setrotrd ();
4795   cons << "Default Drone Random" << MENU.dva.cur->name << " Clockwise Rotation = " << v << DEGREES << eol;
4796 }
4797 
VALUE_CHANGED(menu::defvelaccelui,anticlocklis)4798 VALUE_CHANGED (menu::defvelaccelui, anticlocklis) {
4799   float v = float(f);
4800   MENU.dva.cur->anticlock = v;
4801   MENU.dva.checksync (v, MENU.dva.cur->clock, MENU.dva.clockwise);
4802   MENU.dva.cur->setrotrd ();
4803   cons << "Default Drone Random" << MENU.dva.cur->name << " Anti-clockwise Rotation = " << v << DEGREES << eol;
4804 }
4805 
PICKED_OPTION(menu::defvelaccelui,dirlis)4806 PICKED_OPTION (menu::defvelaccelui, dirlis) {
4807   int& idir = MENU.dva.idir;
4808   idir += dir;
4809   wrap<int> (menu::defvelaccelui::HORIZONTAL, idir, menu::defvelaccelui::MOUSE);
4810   MENU.dva.cur->dir = idir;
4811   static const char* s [] = {" Horizontal", " Vertical", " Mouse"};
4812   MENU.dva.odir.set_text (s[idir]);
4813 }
4814 
get(float & g,float & ux,float & uy,defvelaccel & dva)4815 void get (float& g, float& ux, float& uy, defvelaccel& dva) {
4816   g = dva.mag ();
4817   point<int> mous (din0.delta_mousex, din0.delta_mousey);
4818   if (mous.x == 0 && mous.y == 0) {
4819     ux = 0;
4820     uy = 1;
4821   } else {
4822     unit_vector<float> (ux, uy, mous.x, -mous.y);
4823   }
4824   float dirxa [] = {1, 0, ux};
4825   float dirya [] = {0, 1, uy};
4826   float nega [] = {1, -1};
4827   float neg = nega [dva.neg];
4828   ux = neg * dirxa [dva.dir];
4829   uy = neg * dirya [dva.dir];
4830   if (dva.rndrot) rotate_vector (ux, uy, dva.rotrd());
4831 }
4832 
gethandlesize()4833 int gethandlesize () { return MENU.handlesize();}
gettrailsize()4834 int gettrailsize () {return MENU.trailsize();}
4835 
CLICKED_CHECKBUTTON(menu::defvelaccelui,chklis)4836 CLICKED_CHECKBUTTON (menu::defvelaccelui, chklis) {
4837   defvelaccel& dva = *MENU.dva.cur;
4838   int* val [] = {
4839     &dva.mag.rndrd,
4840     &dva.autos.rot.rpm.rndrd,
4841     &dva.autos.rot.dps.rndrd,
4842     &dva.autos.rot.tps.rndrd,
4843     &dva.autos.flip.deg.rndrd,
4844     &dva.neg,
4845     &dva.rndrot,
4846     &dva.autos.rot.yes,
4847     &dva.autos.flip.yes,
4848   };
4849   *val[cb.id] = cb.state;
4850 }
4851 
CLICKED_BUTTON(menu::autorott,startlis)4852 CLICKED_BUTTON (menu::autorott, startlis) {
4853   din0.setautorot (MENU.autorotate.which, 1);
4854 }
4855 
CLICKED_BUTTON(menu::autorott,stoplis)4856 CLICKED_BUTTON (menu::autorott, stoplis) {
4857   din0.setautorot (MENU.autorotate.which, 0);
4858 }
4859 
CLICKED_BUTTON(menu::autorott,togglis)4860 CLICKED_BUTTON (menu::autorott, togglis) {
4861   din0.setautorot (MENU.autorotate.which, 0, 1);
4862 }
4863 
CLICKED_BUTTON(menu::autorott,clockwiselis)4864 CLICKED_BUTTON (menu::autorott, clockwiselis) {
4865   din0.setautorotdir (MENU.autorotate.which, -1);
4866 }
4867 
CLICKED_BUTTON(menu::autorott,anticlockwiselis)4868 CLICKED_BUTTON (menu::autorott, anticlockwiselis) {
4869   din0.setautorotdir (MENU.autorotate.which, 1);
4870 }
4871 
VALUE_CHANGED(menu::autorott,rpmlis)4872 VALUE_CHANGED (menu::autorott, rpmlis) {
4873   din0.setautorotparam (MENU.autorotate.which, menu::autorott::RPM);
4874 }
4875 
VALUE_CHANGED(menu::autorott,deglis)4876 VALUE_CHANGED (menu::autorott, deglis) {
4877   din0.setautorotparam (MENU.autorotate.which, menu::autorott::DEG);
4878 }
4879 
VALUE_CHANGED(menu::autorott,tpslis)4880 VALUE_CHANGED (menu::autorott, tpslis) {
4881   din0.setautorotparam (MENU.autorotate.which, menu::autorott::TPS);
4882 }
4883 
CLICKED_BUTTON(menu::autorott::autoflipt,setlis)4884 CLICKED_BUTTON (menu::autorott::autoflipt, setlis) {
4885   din0.setautoflip (MENU.autorotate.which, 1);
4886 }
4887 
CLICKED_BUTTON(menu::autorott::autoflipt,unsetlis)4888 CLICKED_BUTTON (menu::autorott::autoflipt, unsetlis) {
4889   din0.setautoflip (MENU.autorotate.which, 0);
4890 }
4891 
CLICKED_BUTTON(menu::autorott::autoflipt,toglis)4892 CLICKED_BUTTON (menu::autorott::autoflipt, toglis) {
4893   din0.setautoflip (MENU.autorotate.which, 0, 1);
4894 }
4895 
VALUE_CHANGED(menu::autorott::autoflipt,anglis)4896 VALUE_CHANGED (menu::autorott::autoflipt, anglis) {
4897   din0.setautoflipangle (MENU.autorotate.which);
4898 }
4899 
PICKED_OPTION(menu,ol_add_wand_lis)4900 PICKED_OPTION (menu, ol_add_wand_lis) {
4901   static const char* aws [] = {" Add", " Wand"};
4902   din0.dinfo.wand = !din0.dinfo.wand;
4903   MENU.ol_add_wand.set_text (aws[din0.dinfo.wand]);
4904 }
4905 
PICKED_OPTION(menu,ol_drones_are_lis)4906 PICKED_OPTION (menu, ol_drones_are_lis) {
4907   static const char* das [] = {"are immortal", "are mortal", "reincarnate"};
4908   drone::ARE += dir;
4909   wrap<int> (drone::IMMORTAL, drone::ARE, drone::REINCARNATE);
4910   sprintf (BUFFER, " Drones %s", das[drone::ARE]);
4911   MENU.ol_drones_are.set_text (BUFFER);
4912 }
4913 
VALUE_CHANGED(menu,sp_wand_dist_lis)4914 VALUE_CHANGED (menu,sp_wand_dist_lis) {
4915   int d = f;
4916   drone::wand.set (d);
4917   cons << YELLOW << "Wand distance = " << d << eol;
4918 }
4919 
VALUE_CHANGED(menu,risel)4920 VALUE_CHANGED (menu,risel) {
4921   din0.dinfo.drone_rise_time = f;
4922   cons << "Drone rise time = " << din0.dinfo.drone_rise_time << eol;
4923 }
4924 
VALUE_CHANGED(menu,falll)4925 VALUE_CHANGED (menu,falll) {
4926   din0.dinfo.drone_fall_time = f;
4927   cons << "Drone fall time = " << din0.dinfo.drone_fall_time << eol;
4928 }
4929 
VALUE_CHANGED(menu,lifetimel)4930 VALUE_CHANGED(menu,lifetimel) {
4931   drone::LIFETIME = f;
4932   cons << "Drone life time = " << drone::LIFETIME << SECONDS << eol;
4933 }
4934 
VALUE_CHANGED(menu,speedl)4935 VALUE_CHANGED(menu,speedl) {
4936   din0.changechuckspeed (MENU.chspeed);
4937 }
4938 
VALUE_CHANGED(menu,lengthl)4939 VALUE_CHANGED(menu,lengthl) {
4940   din0.changechucklength (MENU.chlen);
4941 }
4942 
VALUE_CHANGED(menu,traill)4943 VALUE_CHANGED(menu,traill) {
4944   din0.change_drone_trail_points (MENU.chtrail);
4945 }
4946 
VALUE_CHANGED(menu,handlesizel)4947 VALUE_CHANGED(menu,handlesizel) {
4948   drone::HANDLESIZE = MENU.handlesize.f_value;
4949   cons << GREEN << "Default drone handle size = " << drone::HANDLESIZE << eol;
4950 }
4951 
VALUE_CHANGED(menu,trailsizel)4952 VALUE_CHANGED(menu,trailsizel) {
4953   TRAILSIZE = MENU.trailsize.f_value;
4954   cons << GREEN << "Default Drone/Ball trail size = " << TRAILSIZE << eol;
4955 }
4956 
VALUE_CHANGED(menu,angleperframel)4957 VALUE_CHANGED(menu,angleperframel) {
4958   drone::chuckt::apt += MENU.chapt();
4959   RESETALLCHUCKTRAILS
4960   cons << YELLOW << "Angle per turn = " << drone::chuckt::apt.deg << DEGREES << eol;
4961 }
4962 
CLICKED_BUTTON(menu,mortalizel)4963 CLICKED_BUTTON(menu,mortalizel) {
4964   din0.mortalize_drones ();
4965   TOGGLEMENU
4966 }
4967 
CLICKED_BUTTON(menu,reincarnatel)4968 CLICKED_BUTTON(menu,reincarnatel) {
4969   #define REINCARNATE 1
4970   din0.mortalize_drones (REINCARNATE);
4971   TOGGLEMENU
4972 }
4973 
CLICKED_BUTTON(menu,immortalizel)4974 CLICKED_BUTTON(menu,immortalizel) {
4975   din0.immortalize_drones ();
4976   TOGGLEMENU
4977 }
4978 
CLICKED_BUTTON(menu,chuckl)4979 CLICKED_BUTTON(menu,chuckl) {
4980   din0.chuck ();
4981   TOGGLEMENU
4982 }
4983 
CLICKED_BUTTON(menu,chflipl)4984 CLICKED_BUTTON(menu,chflipl) {
4985   din0.flipchuckspeed ();
4986   TOGGLEMENU
4987 }
4988 
CLICKED_BUTTON(menu,chtogl)4989 CLICKED_BUTTON(menu,chtogl) {
4990   din0.togchuckspeed ();
4991   TOGGLEMENU
4992 }
4993 
CLICKED_CHECKBUTTON(menu,autoresettrailslis)4994 CLICKED_CHECKBUTTON(menu,autoresettrailslis) {
4995   drone::chuckt::autoresettrails = cb.state;
4996   RESETALLCHUCKTRAILS
4997 }
4998 
PICKED_OPTION(menu,anchoredl)4999 PICKED_OPTION(menu,anchoredl) {
5000   drone::anchored = !drone::anchored;
5001   static const char* lbl [] = {" Drone is launched", " Drone is anchored"};
5002   MENU.anchored.set_text (lbl[drone::anchored]);
5003 }
5004 
clicked(button & cb)5005 void menu::moddirs::clicked (button& cb) {
5006   DECL_BUTTONS
5007   for (int i = 0; i < 4; ++i) {
5008     if (&cb == b[i]) {
5009       din0.setmoddir (what, i);
5010       break;
5011     }
5012   }
5013   TOGGLEMENU
5014 }
5015 
setup(const string & l)5016 void menu::moddirs::setup (const string& l) {
5017   DECL_BUTTONS
5018   lbl.set_text (l);
5019   const char* lbl [] = {"Vertical", "Horizontal", "Velocity", "Acceleration"};
5020   for (int i = 0; i < 4; ++i) b[i]->set_text (lbl[i]);
5021 #ifdef __WIDGET_MOVE__
5022   makehier ((widget**) b, 4);
5023 #endif
5024 }
5025 
setup()5026 void menu::defvelaccelui::autorotatet::setup () {
5027   dir.set_listener (&dirl);
5028   mov.set_listener (&movl);
5029 #ifdef __WIDGET_MOVE__
5030   widget* w[] = {
5031     &cb,
5032     &dir,
5033     &mov,
5034     &rpm,
5035     &dps,
5036     &tps,
5037     0
5038   };
5039   makehier (w);
5040 #endif
5041 }
5042 
load()5043 void menu::defvelaccelui::autorotatet::load () {
5044   defvelaccel& dva = getdva ();
5045   defvelaccel::autost::rott& rot = dva.autos.rot;
5046   cb.set_state (rot.yes, 0);
5047   dir.set_text (diropts[rot.dir]);
5048   mov.set_text (movopts[rot.mov]);
5049 }
5050 
5051 #ifdef __WIDGET_MOVE__
setup()5052 void menu::defvelaccelui::autoflipt::setup () {
5053   widget* w[] = {
5054     &cb,
5055     &deg,
5056     0
5057   };
5058   makehier (w);
5059 }
5060 #endif
5061 
PICKED_OPTION(menu::defvelaccelui::autorotatet,dirlis)5062 PICKED_OPTION (menu::defvelaccelui::autorotatet, dirlis) {
5063   defvelaccel& dva = getdva ();
5064   dva.autos.rot.dir += dir;
5065   wrap<int> (autorotator::CLOCKWISE, dva.autos.rot.dir, autorotator::RANDOM);
5066   static const char* opts [] = {" Clockwise", " Anti clockwise", " Clockwise or Anti-clockwise"};
5067   l.set_text (opts[dva.autos.rot.dir]);
5068 }
5069 
PICKED_OPTION(menu::defvelaccelui::autorotatet,movlis)5070 PICKED_OPTION (menu::defvelaccelui::autorotatet, movlis) {
5071   defvelaccel& dva = getdva ();
5072   dva.autos.rot.mov += dir;
5073   wrap<int> (autorotator::TICK, dva.autos.rot.mov, autorotator::RANDOM);
5074   static const char* opts [] = {" Ticked", " Smooth", " Smooth or Ticked"};
5075   l.set_text (opts[dva.autos.rot.mov]);
5076 }
5077 
CLICKED_CHECKBUTTON(menu::defvelaccelui::autorotatet,chklis)5078 CLICKED_CHECKBUTTON (menu::defvelaccelui::autorotatet, chklis) {
5079   defvelaccel& dva = getdva ();
5080   dva.autos.rot.yes = cb.state;
5081 }
5082 
CLICKED_CHECKBUTTON(menu::defvelaccelui::autoflipt,chklis)5083 CLICKED_CHECKBUTTON (menu::defvelaccelui::autoflipt, chklis) {
5084   defvelaccel& dva = getdva ();
5085   dva.autos.flip.yes = cb.state;
5086 }
5087 
bouncet()5088 drone::bouncet::bouncet () {
5089   n = 0;
5090   max = MENU.sp_bounces ();
5091 }
5092