Update NTK.
[nondaw.git] / sequencer / src / gui / ui.fl
blobbb0f5ea786a6103aef9f60e2bf355e768da8fe76
1 # data file for the Fltk User Interface Designer (fluid)
2 version 1.0300 
3 header_name {.H} 
4 code_name {.C}
5 comment {//
6 // Copyright (C) 2008 Jonathan Moore Liles
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 } {in_source in_header
23
25 decl {\#include <FL/Fl_Dial.H>} {public local
26
28 decl {\#include "FL/About_Dialog.H"} {private local
29
31 decl {class Fl_Scalepack;} {public local
32
34 decl {class Fl_Sometimes_Input;} {public local
35
37 decl {\#include "FL/Fl_Theme_Chooser.H"} {private local
38
40 decl {\#include "FL/Fl_Scalepack.H"} {private local
41
43 decl {\#include "FL/Fl_Sometimes_Input.H"} {private local
44
46 decl {\#include "FL/Fl_Menu_Settings.H"} {private local
47
49 decl {\#include <FL/Fl_Shared_Image.H>} {private local
50
52 decl {\#include "widgets.H"} {private local
53
55 decl {\#include "event_edit.H"} {private local
56
58 decl {\#include "../jack.H"} {private local
59
61 decl {\#include "../NSM.H"} {private local
62
64 decl {extern NSM_Client *nsm;} {private local
65
67 decl {extern UI *ui;} {private local
68
70 decl {class O_Canvas;} {private local
71
73 decl {class Triggers;} {public local
74
76 decl {class Instrument_Editor;} {private local
77
79 decl {Fl_Color canvas_background_color;} {public local
80
82 decl {extern Fl_Color velocity_colors[];} {private local
83
85 Function {update_transport( void * )} {open return_type void
86 } {
87   code {// transport_poll();
89 handle_midi_input();
91  ui->progress_group->do_callback();
93  ui->vmetro_widget->update();   
95  ui->triggers_widget->update();
97 Fl::repeat_timeout( TRANSPORT_POLL_INTERVAL, update_transport );
99 static int oldstate = -1;
101 if ( transport.rolling != oldstate )
104         ui->play_button->label( transport.rolling ? "@square" : "@>" );
105         oldstate = transport.rolling;
106         
107         if ( transport.rolling )
108         {
109                 ui->menu_new->deactivate();
110                 ui->menu_open->deactivate();
111         }
112         else
113         {
114                 ui->menu_new->activate();
115                 ui->menu_open->activate();
116         }
120 if ( nsm && nsm->is_active() )
122      if ( ui->menu_new->active() )
123      {
124             ui->menu_new->deactivate();
125             ui->menu_open->deactivate();
126             ui->menu_save_as->deactivate(); 
127      }
130 // JUST A TEST
131 if ( transport.rolling )
133         if ( ui->tabs->value() == ui->pattern_tab )
134                 ui->pattern_canvas_widget->redraw_playhead();
135         else
136         if ( ui->tabs->value() == ui->phrase_tab )
137                 ui->phrase_canvas_widget->redraw_playhead();
141 ui->transport_state->do_callback();} {}
144 class UI {open
145 } {
146   decl {Fl_Text_Buffer *sequence_notes_buffer;} {private local
147   }
148   decl {Fl_Text_Buffer *pattern_notes_buffer;} {private local
149   }
150   decl {Fl_Text_Buffer *phrase_notes_buffer} {private local
151   }
152   Function {UI()} {open
153   } {
154     code {fl_register_images();
156 canvas_background_color = FL_GREEN;
158 playback_mode_menu = NULL;
160 main_window = make_main_window();
161 seq_window = make_seq_window();
163 make_randomization_dialog();
165 // make_instrument_edit_dialog();
167 Fl::add_handler( shortcut_handler );
169 // use old focus behavior
170 Fl::visible_focus( 0 );
172 // try to fill the screen, but only when the screen is tiny and our window is huge.
174         int sx, sy, sw, sh;
176         Fl::screen_xywh( sx, sy, sw, sh );
178         if ( sw < main_window->w() || sh < main_window->h() )
179             main_window->resize( sx, sy, sw, sh );
182 Fl::add_timeout( TRANSPORT_POLL_INTERVAL, update_transport );
185 playlist->signal_new_song.connect( sigc::mem_fun( this, &UI::update_sequence_widgets ) );} {}
186   }
187   Function {~UI()} {open
188   } {
189     code {delete seq_window;
190 delete main_window;} {}
191   }
192   Function {run()} {open
193   } {
194     code {Fl::run();} {}
195   }
196   Function {load_settings()} {open return_type void
197   } {
198     code {char *path;
200 asprintf( &path, "%s/%s", config.user_config_dir, "view" );
202 ((Fl_Menu_Settings*)menu_bar)->load( menu_bar->find_item( "&View" ), path );
204 free( path );} {}
205   }
206   Function {save_settings()} {open return_type void
207   } {
208     code {char *path;
210 asprintf( &path, "%s/%s", config.user_config_dir, "view" );
212 ((Fl_Menu_Settings*)menu_bar)->dump( menu_bar->find_item( "&View" ), path );
214 free( path );} {}
215   }
216   Function {make_main_window()} {open
217   } {
218     Fl_Window main_window {
219       label {Non Sequencer}
220       callback {// Ignore escape
221 if ( Fl::event() == FL_SHORTCUT && Fl::event_key() == FL_Escape )
222         return;
223          
224 if ( maybe_save_song() )
225         quit();} open
226       xywh {798 131 865 805} type Double color 47 resizable
227       code0 {o->color( FL_BACKGROUND_COLOR );} xclass non size_range {700 509 0 0} visible
228     } {
229       Fl_Group {} {open
230         xywh {0 30 865 70} box FLAT_BOX
231       } {
232         Fl_Value_Input {} {
233           label BPM
234           callback {transport.set_beats_per_minute( o->value() );}
235           xywh {389 47 45 25} labelsize 9 align 1 when 8
236           code1 {transport.signal_tempo_change.connect( sigc::mem_fun( o, static_cast<int (Fl_Valuator::*)(double)>(&Fl_Valuator::value) ) );}
237           code2 {o->value( transport.beats_per_minute );}
238         }
239         Fl_Value_Input {} {
240           callback {transport.set_beats_per_bar( o->value() );}
241           xywh {444 47 26 25}
242           code0 {transport.signal_bpb_change.connect( sigc::mem_fun( o, static_cast<int (Fl_Valuator::*)(double)>(&Fl_Valuator::value) ) );}
243           code1 {o->value( transport.beats_per_bar );}
244         }
245         Fl_Box {} {
246           label {/}
247           xywh {469 47 19 25}
248         }
249         Fl_Value_Input {} {
250           callback {transport.set_beat_type( o->value() );}
251           xywh {489 47 24 25}
252           code0 {transport.signal_beat_change.connect( sigc::mem_fun( o, static_cast<int (Fl_Valuator::*)(double)>(&Fl_Valuator::value) ) );}
253           code1 {o->value( transport.beat_type );}
254         }
255         Fl_Pack vmetro_widget {
256           label Metronome
257           xywh {520 35 336 59} type HORIZONTAL box UP_BOX color 40 selection_color 48 labelsize 33 align 0 resizable
258           code0 {\#include "widgets.H"}
259           code1 {o->box( FL_FLAT_BOX );}
260           class Visual_Metronome
261         } {}
262         Fl_Pack transport_controls_group {open
263           xywh {4 32 156 42} type HORIZONTAL
264           code0 {o->spacing( 2 );}
265           class Fl_Scalepack
266         } {
267           Fl_Button play_button {
268             label {@>}
269             callback {transport.toggle();}
270             xywh {10 34 43 38} shortcut 0x20 labeltype ENGRAVED_LABEL
271           }
272           Fl_Button rec_button {
273             label {@circle}
274             callback {transport.recording = o->value();
277 if ( o->value() )
279         if ( config.record_mode == NEW )
280         {
281                 pattern *p = new pattern;
282                 p->length( -1 );
283                 
284                 pattern_c->grid( p );
285         }
286         
287         ((pattern*)pattern_c->grid())->record( 0 );
288         
289         o->labelcolor( FL_RED );
291 else
293         pattern::recording()->record_stop();
294         
295         o->labelcolor( FL_WHITE );
297             xywh {60 34 43 38} type Toggle shortcut 0x80072 selection_color 47 labeltype ENGRAVED_LABEL when 1
298           }
299           Fl_Button home_button {
300             label {@|<}
301             callback {transport.locate( 0 );}
302             xywh {110 34 43 38} shortcut 0xff50 labeltype ENGRAVED_LABEL
303           }
304         }
305         Fl_Choice record_mode_menu {
306           label {&Record Mode}
307           callback {if ( ! transport.recording )
308         config.record_mode = (record_mode_e)o->value();
309 else
310         o->value( config.record_mode );} open
311           xywh {170 47 100 25} box DOWN_BOX down_box BORDER_BOX color 37 labelsize 9 align 1
312         } {
313           MenuItem {} {
314             label Merge
315             xywh {15 15 40 25}
316           }
317           MenuItem {} {
318             label Overwrite
319             xywh {25 25 40 25}
320           }
321           MenuItem {} {
322             label Layer
323             xywh {35 35 40 25}
324           }
325           MenuItem {} {
326             label New
327             xywh {45 45 40 25}
328           }
329         }
330         Fl_Choice playback_mode_menu {
331           label {Playback &Mode} open
332           xywh {279 47 100 25} box DOWN_BOX down_box BORDER_BOX color 37 labelsize 9 align 1
333         } {
334           MenuItem {} {
335             label Pattern
336             callback {song.play_mode = PATTERN;}
337             xywh {5 5 40 25}
338           }
339           MenuItem {} {
340             label Sequence
341             callback {song.play_mode = SEQUENCE;}
342             xywh {15 15 40 25}
343           }
344           MenuItem {} {
345             label Trigger
346             callback {song.play_mode = TRIGGER;}
347             xywh {25 25 40 25}
348           }
349           MenuItem {} {
350             label Queue
351             callback {song.play_mode = QUEUE;}
352             xywh {0 0 40 24}
353           }
354         }
355       }
356       Fl_Tabs tabs {
357         callback {((Fl_Group*)o->value())->child( 0 )->take_focus();
359 ui->pan_indicators->show();
361 if ( o->value() == pattern_tab )
362         pattern_canvas_widget->handle_pan();
363 else if ( o->value() == phrase_tab )
364         phrase_canvas_widget->handle_pan();
365         
366 if ( o->value() != pattern_tab )
368         if ( o->value() != phrase_tab )
369                 ui->pan_indicators->hide();
370         edit_menu->deactivate();
372 else
374         edit_menu->activate();
377 menu_bar->redraw();} open
378         xywh {0 79 865 698} box BORDER_BOX color 47 labeltype SHADOW_LABEL labelsize 19 when 1 resizable
379         code0 {canvas_background_color = fl_rgb_color( 18, 18, 18 );}
380       } {
381         Fl_Group sequence_tab {
382           label Sequence open
383           xywh {0 102 865 674} box FLAT_BOX color 37 hide resizable
384           code0 {update_sequence_widgets();}
385         } {
386           Fl_Group {} {open
387             xywh {10 125 233 502} labelsize 12
388           } {
389             Fl_Browser playlist_browser {
390               label Playlist
391               xywh {10 125 233 435} type Hold box EMBOSSED_BOX color 39 selection_color 30 labelcolor 55 align 1 when 4 textsize 18 textcolor 95 resizable
392               code0 {static int widths[] = { 40, 30, 0 };}
393               code1 {o->column_widths( widths ); o->column_char( '\\t' );}
394               code2 {o->value( 1 );}
395             }
396             Fl_Button sequence_phrase_delete_button {
397               label Delete
398               callback {int val = playlist_browser->value();
400 if ( val > 1 )
402 //      playlist_browser->value( playlist_browser->value() + 1 );
404         playlist->remove( val - 2 );
406         update_sequence_widgets();
407         
408         if ( ! playlist_browser->value() )
409                 playlist_browser->value( playlist_browser->size() );
411               xywh {14 566 73 25} shortcut 0xffff color 88 labelcolor 23
412             }
413             Fl_Button sequence_phrase_up_button {
414               label Up
415               callback {if ( playlist_browser->value() > 2 )
417         playlist->move( playlist_browser->value() - 2, UP );
418         playlist_browser->value( playlist_browser->value() - 1 );
419         update_sequence_widgets();
421               xywh {97 566 65 25} shortcut 0xffbf
422             }
423             Fl_Button sequence_phrase_down_button {
424               label Down
425               callback {if ( playlist_browser->value() > 1 )
427         playlist->move( playlist_browser->value() - 2, DOWN );
428         playlist_browser->value( playlist_browser->value() + 1 );
429         update_sequence_widgets();
431               xywh {169 566 74 25} shortcut 0xffc0
432             }
433             Fl_Menu_Button sequence_phrase_choice {
434               label {Insert Phrase}
435               callback {playlist->insert( playlist_browser->value() - 1, o->value() + 1 );
437 update_sequence_widgets();
439 int val = playlist_browser->value();
441 if ( val )
442         playlist_browser->value( playlist_browser->value() + 1 );
443 else
444         playlist_browser->value( playlist_browser->size() );} open
445               xywh {11 597 232 30} color 63
446             } {}
447           }
448           Fl_Input sequence_name_field {
449             label {name:}
450             callback {playlist->name( o->value() );}
451             xywh {91 740 158 26} color 36 align 20 when 1 textcolor 32
452           }
453           Fl_Light_Button detach_button {
454             label Detach
455             callback {if ( o->value() )
457         Fl_Group *g = seq_detached_group;
458         seq_window->show();
459         g->add( sequence_tab );
460         sequence_tab->resize( g->x(), g->y(), g->w(), g->h() );
461         tabs->do_callback();
462         main_window->redraw();
464 else
466         seq_window->hide();
467         tabs->insert( (Fl_Widget&)*sequence_tab, 0 );
468         sequence_tab->resize( pattern_tab->x(), pattern_tab->y(), pattern_tab->w(), pattern_tab->h() );
469         tabs->do_callback();    
471             xywh {7 740 78 26}
472           }
473           Fl_Text_Editor sequence_notes_edit {
474             label {Notes:}
475             callback {playlist->notes( o->buffer()->text() );}
476             xywh {254 691 606 73} selection_color 48 labelsize 12 align 5 textcolor 94
477             code0 {o->buffer( sequence_notes_buffer = new Fl_Text_Buffer );}
478           }
479           Fl_Box triggers_widget {
480             label Patterns
481             xywh {253 125 607 549} color 48 align 1 resizable
482             code0 {o->color( FL_BACKGROUND_COLOR );}
483             class Triggers
484           }
485           Fl_Group progress_group {
486             callback {if ( ! o->visible_r() )
487         return;
489 phrase *p = phrase::phrase_by_number( playlist->playing() );
491 if ( p )
492         phrase_progress->value( p->index() / (double)p->length() );
493         
494 if ( playlist->length() )
495         sequence_progress->value( playlist->index() / (double)playlist->length() );} open
496             xywh {10 656 233 66}
497           } {
498             Fl_Slider phrase_progress {
499               label Phrase
500               xywh {10 656 233 24} type Horizontal labelsize 12 align 1
501             }
502             Fl_Slider sequence_progress {
503               label Sequence
504               callback {transport.locate( (tick_t)((double)playlist->length() * o->value()) );}
505               xywh {10 698 233 24} type Horizontal labelsize 12 align 1
506             }
507           }
508         }
509         Fl_Group phrase_tab {
510           label Phrase open
511           xywh {0 102 865 674} box FLAT_BOX color 47 hide
512           code0 {update_phrase_widgets();}
513         } {
514           Fl_Box phrase_canvas_widget {
515             label Phrase
516             xywh {1 103 863 587} box FLAT_BOX color 37 labelsize 100 align 16 resizable
517             code0 {o->set_canvas( phrase_c );}
518             code1 {phrase_c->signal_pan.connect( sigc::mem_fun( phrase_canvas_widget, &O_Canvas::handle_pan ) );}
519             class O_Canvas
520           }
521           Fl_Group {} {open
522             xywh {5 697 856 77} box FLAT_BOX color 47
523           } {
524             Fl_Input phrase_name_field {
525               label {name:}
526               callback {phrase_c->grid()->name( strdup( o->value() ) );
528 // if the name changed..
529 update_sequence_widgets();}
530               xywh {5 704 155 24} box ROUNDED_BOX color 49 labelfont 2 labelcolor 55 align 20 textcolor 32
531               code0 {o->up_box( FL_ROUNDED_BOX );}
532               class Fl_Sometimes_Input
533             }
534             Fl_Spinner phrase_number_spinner {
535               label {Phrase:}
536               callback {phrase *p = ((phrase *)phrase_c->grid())->by_number( o->value() );
538 if ( p )
539     phrase_c->grid( p );
541 o->maximum( phrase::phrases() );}
542               xywh {165 704 55 24} color 36 labelsize 9 align 1 when 1
543             }
544             Fl_Light_Button phrase_mute_button {
545               label Mute
546               xywh {5 740 93 23} color 37 hide
547             }
548             Fl_Light_Button phrase_solo_button {
549               label Solo
550               xywh {111 740 87 23} color 37 hide
551             }
552             Fl_Text_Editor phrase_notes_edit {
553               label {Notes:}
554               callback {phrase_c->grid()->notes( o->buffer()->text() );}
555               xywh {235 709 620 58} selection_color 48 labelsize 12 textcolor 94 resizable
556               code0 {o->buffer( phrase_notes_buffer = new Fl_Text_Buffer );}
557             }
558           }
559         }
560         Fl_Group pattern_tab {
561           label Pattern open
562           xywh {0 102 865 674} box FLAT_BOX color 47
563           code0 {update_pattern_widgets();}
564         } {
565           Fl_Box pattern_canvas_widget {
566             label Pattern selected
567             xywh {1 103 863 587} box FLAT_BOX color 37 labelsize 100 align 16 resizable
568             code0 {\#include "draw.H"}
569             code1 {o->set_canvas( pattern_c );}
570             code2 {\#include "input.H"}
571             code3 {pattern_c->signal_pan.connect( sigc::mem_fun( pattern_canvas_widget, &O_Canvas::handle_pan ) );}
572             class O_Canvas
573           }
574           Fl_Group {} {open
575             xywh {0 694 862 78} box FLAT_BOX color 47
576           } {
577             Fl_Input pattern_name_field {
578               label {name:}
579               callback {pattern_c->grid()->name( strdup( o->value() ) );}
580               xywh {5 704 155 24} box ROUNDED_BOX color 49 align 20 when 1 textfont 2 textcolor 55
581               code0 {o->up_box( FL_ROUNDED_BOX );}
582               class Fl_Sometimes_Input
583             }
584             Fl_Spinner pattern_number_spinner {
585               label {Pattern:}
586               callback {pattern *p = ((pattern *)pattern_c->grid())->by_number( o->value() );
588 if ( p )
589     pattern_c->grid( p );
591 o->maximum( pattern::patterns() );}
592               xywh {165 704 55 24} color 36 labelsize 9 align 1 when 1
593               code0 {o->maximum( 1 );}
594               code1 {// pattern::signal_create_destroy.connect( sigc::mem_fun( o, static_cast<void (Fl_Spinner::*)(double)>(&Fl_Spinner::maximum) ) );}
595             }
596             Fl_Light_Button pattern_mute_button {
597               label Mute
598               callback {Grid *g = pattern_c->grid();
600 g->mode( g->mode() == MUTE ? PLAY : MUTE );
602 o->value( g->mode() == MUTE );
604 pattern_solo_button->value( 0 );}
605               xywh {10 738 65 25} type Normal color 37
606             }
607             Fl_Light_Button pattern_solo_button {
608               label Solo
609               callback {Grid *g = pattern_c->grid();
611 g->mode( g->mode() == SOLO ? PLAY : SOLO );
613 o->value( g->mode() == SOLO );
615 pattern_mute_button->value( 0 );}
616               xywh {80 738 65 25} type Normal color 37
617             }
618             Fl_Text_Editor pattern_notes_edit {
619               label {Notes:}
620               callback {pattern_c->grid()->notes( o->buffer()->text() );}
621               xywh {230 713 227 48} selection_color 48 labelsize 12 textcolor 94 resizable
622               code0 {o->buffer( pattern_notes_buffer = new Fl_Text_Buffer );}
623             }
624             Fl_Group pattern_settings_group {open
625               xywh {458 694 400 78}
626             } {
627               Fl_Spinner pattern_channel_spinner {
628                 label Channel
629                 callback {((pattern *)pattern_c->grid())->channel( o->value() - 1 );}
630                 xywh {815 700 40 24} color 36 when 1
631                 code0 {\#include "../pattern.H"}
632                 code1 {o->maximum( 16 );}
633               }
634               Fl_Spinner pattern_port_spinner {
635                 label Port
636                 callback {((pattern *)pattern_c->grid())->port( o->value() - 1 );}
637                 xywh {815 734 40 24} color 36 when 1
638                 code0 {o->maximum( 16 );}
639               }
640               Fl_Output mapping_text {
641                 label Mapping
642                 xywh {464 734 145 24} align 20
643               }
644               Fl_Menu_Button mapping_menu {
645                 label {@>}
646                 callback {mapping_text->value( o->text() );
649 char picked[80];
650 mapping_menu->item_pathname(picked, sizeof(picked)-1 );
652 if ( 0 == strncmp( picked, "Instrument", strlen( "Instrument" ) ) )
654         ((pattern*)pattern_c->grid())->mapping.open( Mapping::INSTRUMENT, o->text() );
656         pattern_c->changed_mapping();
658         pattern_key_combo->deactivate();
660 else
661 if ( 0 == strncmp( picked, "Scale", strlen( "Scale" ) ) )
663         ((pattern*)pattern_c->grid())->mapping.open( Mapping::SCALE, o->text() );
665         pattern_c->changed_mapping();
667         pattern_key_combo->activate();
668 }} open
669                 xywh {609 734 30 24} labeltype NO_LABEL
670                 code0 {update_mapping_menu();}
671               } {
672                 Submenu mapping_scale_menu {
673                   label Scale open
674                   xywh {25 25 74 25}
675                 } {}
676                 Submenu mapping_instrument_menu {
677                   label Instrument open
678                   xywh {10 10 74 25}
679                 } {}
680               }
681               Fl_Choice pattern_key_combo {
682                 label {&Key}
683                 callback {((pattern*)pattern_c->grid())->mapping.key( o->value() );
685 pattern_c->changed_mapping();}
686                 xywh {674 734 75 24} down_box BORDER_BOX when 1
687               } {
688                 MenuItem {} {
689                   label C
690                   xywh {30 30 40 25}
691                 }
692                 MenuItem {} {
693                   label {C\#/Db}
694                   xywh {40 40 40 25}
695                 }
696                 MenuItem {} {
697                   label D
698                   xywh {50 50 40 25}
699                 }
700                 MenuItem {} {
701                   label {D\#/Eb}
702                   xywh {60 60 40 25}
703                 }
704                 MenuItem {} {
705                   label E
706                   xywh {70 70 40 25}
707                 }
708                 MenuItem {} {
709                   label F
710                   xywh {80 80 40 25}
711                 }
712                 MenuItem {} {
713                   label {F\#/Gb}
714                   xywh {90 90 40 25}
715                 }
716                 MenuItem {} {
717                   label G
718                   xywh {100 100 40 25}
719                 }
720                 MenuItem {} {
721                   label {G\#}
722                   xywh {110 110 40 25}
723                 }
724                 MenuItem {} {
725                   label A
726                   xywh {0 0 40 25}
727                 }
728                 MenuItem {} {
729                   label {A\#/Bb}
730                   xywh {10 10 40 25}
731                 }
732                 MenuItem {} {
733                   label B
734                   xywh {20 20 40 25}
735                 }
736               }
737               Fl_Choice pattern_note_combo {
738                 label {&Note 1/}
739                 callback {((pattern*)pattern_c->grid())->note( atoi( o->menu()[ o->value() ].text ));}
740                 xywh {704 700 45 24} down_box BORDER_BOX when 1
741               } {
742                 MenuItem {} {
743                   label 1
744                   xywh {0 0 40 25}
745                 }
746                 MenuItem {} {
747                   label 2
748                   xywh {10 10 40 25}
749                 }
750                 MenuItem {} {
751                   label 4
752                   xywh {20 20 40 25}
753                 }
754                 MenuItem {} {
755                   label 8
756                   xywh {30 30 40 25}
757                 }
758                 MenuItem {} {
759                   label 16
760                   xywh {40 40 40 25}
761                 }
762                 MenuItem {} {
763                   label 32
764                   xywh {50 50 40 25}
765                 }
766                 MenuItem {} {
767                   label 64
768                   xywh {60 60 40 25} divider
769                 }
770                 MenuItem {} {
771                   label 3
772                   xywh {60 60 40 25}
773                 }
774                 MenuItem {} {
775                   label 6
776                   xywh {70 70 40 25}
777                 }
778                 MenuItem {} {
779                   label 12
780                   xywh {80 80 40 25}
781                 }
782                 MenuItem {} {
783                   label 24
784                   xywh {90 90 40 25}
785                 }
786               }
787               Fl_Choice pattern_res_combo {
788                 label {&Resolution 1/}
789                 callback {pattern_c->grid()->resolution( atoi( o->menu()[ o->value() ].text ));}
790                 xywh {584 700 55 24} down_box BORDER_BOX when 1
791               } {
792                 MenuItem {} {
793                   label 4
794                   xywh {30 30 40 25}
795                 }
796                 MenuItem {} {
797                   label 8
798                   xywh {40 40 40 25}
799                 }
800                 MenuItem {} {
801                   label 16
802                   xywh {50 50 40 25}
803                 }
804                 MenuItem {} {
805                   label 32
806                   xywh {60 60 40 25}
807                 }
808                 MenuItem {} {
809                   label 64
810                   xywh {80 80 40 25}
811                 }
812                 MenuItem {} {
813                   label 128
814                   xywh {90 90 40 25} divider
815                 }
816                 MenuItem {} {
817                   label 3
818                   xywh {70 70 40 25}
819                 }
820                 MenuItem {} {
821                   label 6
822                   xywh {80 80 40 25}
823                 }
824                 MenuItem {} {
825                   label 12
826                   xywh {90 90 40 25}
827                 }
828                 MenuItem {} {
829                   label 24
830                   xywh {100 100 40 25}
831                 }
832               }
833             }
834           }
835         }
836       }
837       Fl_Group {} {open
838         xywh {0 776 865 31}
839       } {
840         Fl_Box status {
841           label status
842           xywh {1 776 782 31} box UP_BOX align 84
843           code0 {o->label( NULL );}
844         }
845         Fl_Box transport_state {
846           label state
847           callback {const char *s = "INVALID";
849 if ( transport.master )
850         s = "Master";
851 else if ( transport.valid )
852         s = "Slave";
854 if ( s != o->label() )
856         o->label( s );
857         if ( ! strcmp( s, "INVALID" ) )
858                 o->color( fl_darker( FL_RED ) );
859         else
860                 o->color( fl_darker( FL_GREEN ) );
862           xywh {783 776 82 31} box THIN_UP_BOX align 64
863         }
864       }
865       Fl_Group pan_indicators {open
866         xywh {370 692 120 20}
867       } {
868         Fl_Box scroll_up_box {
869           label {@2<}
870           xywh {400 694 30 18}
871         }
872         Fl_Box scroll_down_box {
873           label {@2>}
874           xywh {430 694 30 18}
875         }
876         Fl_Box scroll_left_box {
877           label {@<}
878           xywh {370 692 30 18} hide
879         }
880         Fl_Box scroll_right_box {
881           label {@>}
882           xywh {460 692 30 18} hide
883         }
884       }
885       Fl_Group {} {open
886         xywh {0 0 865 31}
887       } {
888         Fl_Menu_Bar menu_bar {open
889           xywh {0 0 865 30} color 47
890         } {
891           Submenu {} {
892             label {&File} open
893             xywh {0 0 100 20} color 37
894           } {
895             MenuItem menu_new {
896               label {&New}
897               callback {if ( maybe_save_song() )
899         init_song();
901         // Sync the GUI.
902         update_pattern_widgets();
903         update_sequence_widgets();
904         update_phrase_widgets();
905         
906         
907         gui_status( "New song." );
909               xywh {0 0 40 25}
910             }
911             MenuItem menu_open {
912               label {&Open}
913               callback {char *name = fl_file_chooser( "Open File", "Non Files (*.non)", NULL, 0 );
915 if ( name )
917         if ( ! load_song( name ) )
918                 fl_alert( "Could not load song!" );
919         else
920                 gui_status( "Song opened." );
921         
922         update_sequence_widgets();
923         update_pattern_widgets();
924         update_phrase_widgets();
926         playback_mode_menu->value( song.play_mode );
927         playback_mode_menu->redraw();
929               xywh {0 0 40 25} shortcut 0x4006f color 37
930             }
931             MenuItem menu_save {
932               label {&Save}
933               callback {save_dialog( song.filename );}
934               xywh {0 0 40 25} shortcut 0x40073 color 37 deactivate
935               code0 {song.signal_dirty.connect( sigc::mem_fun( o, &Fl_Menu_Item::activate ) );}
936               code1 {song.signal_clean.connect( sigc::mem_fun( o, &Fl_Menu_Item::deactivate ) );}
937             }
938             MenuItem menu_save_as {
939               label {Save &As}
940               callback {save_dialog( NULL );}
941               xywh {0 0 40 25}
942             }
943             MenuItem {} {
944               label {&Import}
945               callback {char *name = fl_file_chooser( "MIDI Import", "MIDI Files (*.mid)", NULL, 0 );
947 if ( ! name )
948         return;
950 smf f;
952 if ( ! f.open( name, smf::READ ) )
954         fl_message( "could not open file" );
955         return;
958 f.read_header();
960 switch ( f.format() )
962         case 0:
963                 if ( ! pattern::import( &f, 0 ) )
964                         fl_message( "Error importing MIDI" );
965                 break;
966         case 1: case 2:
967                 {
968                         char **sa = f.track_listing();
970                         if ( sa && *sa )
971                         {
972                                 List_Chooser tc( "Select tracks to import:", "Import" );
974                                 char *s;
975                                 for ( int i = 0; (s = sa[i]); ++i )
976                                 {
977                                         tc.add( s );
978                                         free( s );
979                                 }
981                                 free( sa );
983                                 tc.show();
985                                 while( tc.shown() )
986                                         Fl::wait();
988                                 int n = 0;
989                                 for ( int i = 1; i <= tc.browser->size(); ++i )
990                                 {
991                                         if ( tc.browser->selected( i ) )
992                                         {
993                                                 if ( pattern::import( &f , i - 1 ) )
994                                                         ++n;
995                                                 else
996                                                         WARNING( "error importing track %d", i - 1 );
997                                         }
999                                 }
1000                                 // fl_message( "%d patterns imported.", n );
1001                                 gui_status( "Imported %d tracks as patterns", n );
1002                         }
1004                         break;
1005                 }
1007               xywh {0 0 40 25}
1008               code0 {\#include "../smf.H"}
1009             }
1010             MenuItem {} {
1011               label {&Export}
1012               callback {// Fl_File_Chooser::custom_filter_label = "*.mid";
1014 Fl_File_Chooser *fc = new Fl_File_Chooser( ".", "MIDI Files (*.mid)", Fl_File_Chooser::CREATE, "MIDI Export" );
1016 fc->show();
1018 // wait for user to make a choice
1019 while( fc->shown() )
1020       Fl::wait();
1022 if ( ! fc->value() )
1023         return;
1025 if ( tabs->value() == pattern_tab )
1026         ((pattern*)pattern_c->grid())->save( fc->value() );}
1027               xywh {0 0 40 25}
1028               code0 {\#include <FL/Fl_File_Chooser.H>}
1029             }
1030             MenuItem {} {
1031               label {&Quit}
1032               callback {main_window->do_callback();}
1033               xywh {0 0 40 25} shortcut 0x40071 color 37
1034             }
1035           }
1036           Submenu edit_menu {
1037             label {&Edit} open
1038             xywh {0 0 74 25} color 37
1039           } {
1040             MenuItem {} {
1041               label {&Events}
1042               callback {event_editor( pattern_c->grid() );}
1043               xywh {0 0 40 25}
1044             }
1045             MenuItem {} {
1046               label {&Randomization Settings}
1047               callback {randomization_dialog->show();}
1048               xywh {0 0 40 25}
1049             }
1050           }
1051           Submenu {} {
1052             label {&View} open
1053             xywh {10 10 74 25} color 37
1054           } {
1055             MenuItem {} {
1056               label {&Metronome}
1057               callback {int val = o->menu()[ o->value() ].value();
1059 if ( val )
1060         vmetro_widget->show();
1061 else
1062         vmetro_widget->hide();}
1063               xywh {0 0 40 25} type Toggle value 1
1064             }
1065             MenuItem {} {
1066               label {&Compacted}
1067               callback {int val = o->menu()[ o->value() ].value();
1069 pattern_c->row_compact( val ? Canvas::ON : Canvas::OFF );
1071 pattern_canvas_widget->redraw();}
1072               xywh {10 10 40 25} type Toggle value 1
1073             }
1074             MenuItem {} {
1075               label {&Follow Playhead}
1076               callback {int val = o->menu()[ o->value() ].value();
1078 config.follow_playhead = val ? true : false;}
1079               xywh {10 10 40 25} type Toggle value 1
1080             }
1081             Submenu {} {
1082               label {Note Shape} open
1083               xywh {0 0 74 24}
1084             } {
1085               MenuItem {} {
1086                 label Box
1087                 callback {pattern::note_shape = BOX;
1088                pattern_canvas_widget->redraw();}
1089                 xywh {0 0 40 24} type Radio
1090               }
1091               MenuItem {} {
1092                 label Square
1093                 callback {pattern::note_shape = SQUARE;
1094                pattern_canvas_widget->redraw();}
1095                 xywh {0 0 40 24} type Radio value 1
1096               }
1097             }
1098             MenuItem {} {
1099               label {&Theme}
1100               callback {fl_theme_chooser();}
1101               xywh {0 0 40 24}
1102             }
1103           }
1104           Submenu {} {
1105             label {&Help} open
1106             xywh {100 0 74 25} color 37
1107           } {
1108             MenuItem {} {
1109               label {&Keys}
1110               callback {show_help_dialog( "KEYS" );}
1111               xywh {0 0 40 25}
1112             }
1113             MenuItem {} {
1114               label {&Manual}
1115               callback {show_help_dialog( "MANUAL" );}
1116               xywh {10 10 40 25} divider
1117             }
1118             MenuItem {} {
1119               label {&About}
1120               callback {About_Dialog ab( PIXMAP_PATH "/non-sequencer/icon-256x256.png" );
1122             ab.logo_box->label( VERSION );
1124         ab.title->label( "The Non Sequencer" );
1126         ab.copyright->label( "Copyright (C) 2007-2012 Jonathan Moore Liles" );
1127         ab.credits->label( "Non-Sequencer was written from scratch by\\nJonathan Moore Liles for his own use\\n(see the manual).\\n\\nNobody planned. Nobody helped.\\nYou can help now by donating time, money,\\nand/or replacing the rest of Linux Audio\\nwith fast, light, reliable alternatives.\\n" );
1129         ab.website_url->label( "http://non-sequencer.tuxfamily.org" );
1131 ab.run();}
1132               xywh {0 0 40 25} color 37
1133               code0 {\#include "../non.H"}
1134             }
1135           }
1136         }
1137         Fl_Button sm_indicator {
1138           label SM
1139           xywh {825 8 35 15} box ROUNDED_BOX down_box ROUNDED_BOX color 46 selection_color 93 labelfont 3 labelcolor 39 deactivate
1140         }
1141       }
1142     }
1143   }
1144   Function {make_seq_window()} {open
1145   } {
1146     Fl_Window seq_window {
1147       label {Non Sequencer - Sequence}
1148       callback {sequence_tab->activate();
1149 o->hide();
1150 detach_button->value( 0 );} open
1151       xywh {681 189 876 675} type Double hide resizable
1152     } {
1153       Fl_Group seq_detached_group {open
1154         xywh {0 0 876 675} resizable
1155       } {}
1156     }
1157   }
1158   Function {make_randomization_dialog()} {} {
1159     Fl_Window randomization_dialog {
1160       label {Randomization Settings} open
1161       xywh {656 39 340 95} type Double hide
1162       code0 {// feel->value( )}
1163       code1 {probability->value( song.random.probability );} non_modal
1164     } {
1165       Fl_Choice feel {
1166         label {Feel: 1/}
1167         callback {song.random.feel = atoi( o->menu()[ find_numeric_menu_item( o->menu(), o->value() ) ].text );} open
1168         xywh {67 55 50 24} down_box BORDER_BOX
1169       } {
1170         MenuItem {} {
1171           label 4
1172           xywh {10 10 40 25}
1173         }
1174         MenuItem {} {
1175           label 8
1176           xywh {0 0 40 25}
1177         }
1178         MenuItem {} {
1179           label 16
1180           xywh {10 10 40 25}
1181         }
1182       }
1183       Fl_Box {} {
1184         label {Randomization Settings}
1185         xywh {10 15 321 28} box ROUNDED_BOX color 94 labelsize 22 labelcolor 39
1186       }
1187       Fl_Counter probability {
1188         label Probability
1189         callback {song.random.probability = o->value();}
1190         xywh {216 53 112 26} type Simple align 4 when 4 minimum 0 maximum 1 step 0.01
1191       }
1192     }
1193   }
1194   Function {update_pattern_widgets()} {open
1195   } {
1196     code {if ( ! pattern_settings_group )
1197         return;
1198         
1199 pattern *g = (pattern *)pattern_c->grid();
1201 pattern_number_spinner->value( g->number() );
1202 pattern_name_field->value( g->name() );
1203 pattern_channel_spinner->value( 1 + g->channel() );
1204 pattern_port_spinner->value( 1 + g->port() );
1205 pattern_solo_button->value( g->mode() == SOLO );
1206 pattern_mute_button->value( g->mode() == MUTE );
1208 if ( g->mapping.key() == -1 )
1209         pattern_key_combo->deactivate();
1210 else
1212         pattern_key_combo->activate();
1213         pattern_key_combo->value( g->mapping.key() );
1216 mapping_text->value( g->mapping.name() );
1220 pattern_note_combo->value( find_numeric_menu_item( menu_pattern_note_combo, g->note() ));
1221 pattern_res_combo->value( find_numeric_menu_item( menu_pattern_res_combo, g->resolution() ));
1223 if ( g->notes() )
1224         pattern_notes_buffer->text( g->notes() );
1225 else
1226         pattern_notes_buffer->text( strdup( "" ) );} {}
1227   }
1228   Function {update_phrase_widgets()} {} {
1229     code {phrase *g = (phrase *)phrase_c->grid();
1231 if ( ! g )
1232         return;
1233         
1234 g->viewport.y = 0;
1235 g->viewport.h = pattern::patterns();
1236 phrase_c->resize_grid();
1237 phrase_c->changed_mapping();
1238 phrase_number_spinner->value( g->number() );
1239 phrase_name_field->value( g->name() );
1240 phrase_solo_button->value( g->mode() == SOLO );
1241 phrase_mute_button->value( g->mode() == MUTE );
1243 if ( g->notes() )
1244         phrase_notes_buffer->text( g->notes() );
1245 else
1246         phrase_notes_buffer->text( strdup( "" ) );} {}
1247   }
1248   Function {update_sequence_widgets()} {open
1249   } {
1250     code {if ( playlist->notes() )
1251         sequence_notes_buffer->text( playlist->notes() );
1252 else
1253         sequence_notes_buffer->text( strdup( "" ) );
1254         
1255 sequence_name_field->value( playlist->name() );
1257 sequence_phrase_choice->clear();
1259 for ( int i = 1; i <= phrase::phrases(); i++ )
1261         phrase *p = phrase::phrase_by_number( i );
1263         if ( p )
1264                 sequence_phrase_choice->add( p->name() );
1268 Fl_Browser *o = playlist_browser;
1270 int val = o->value();
1272 o->clear();
1274 char *s = playlist->dump();
1276 char *l = strtok( s, "\\n" );
1278 o->add( "@b@C2Bar\\t@b@C2\#\\t@b@C2Name" );
1280 if ( ! l )
1281         return;
1283 o->add( l );
1285 while ( ( l = strtok( NULL, "\\n" ) ) )
1287         o->add( l );
1290 o->value( val );
1292 free( s );
1295 if ( playback_mode_menu )
1296         playback_mode_menu->value( song.play_mode );} {}
1297   }
1298   Function {update_mapping_menu()} {open
1299   } {
1300     code {char **sa = Instrument::listing();
1302 if ( sa )
1305         for ( int i = 0; sa[i]; i++ )
1306         {
1307                 char pat[512];
1308                 snprintf( pat, 512, "Instrument/%s", sa[i] );
1309                 mapping_menu->add( pat, 0, 0, 0, 0 );
1310                 free( sa[i] );
1311         }
1312         free( sa );
1315 sa = Scale::listing();
1316 for ( int i = 0; sa[i]; i++ )
1318         char pat[512];
1319         snprintf( pat, 512, "Scale/%s", sa[i] );
1320         mapping_menu->add( pat, 0, 0, 0, 0 );
1321         free( sa[i] );
1323 free( sa );} {}
1324   }
1325   Function {update_canvas_widgets()} {return_type {static void}
1326   } {
1327     code {if ( pattern_c->grid() )
1328         ui->update_pattern_widgets();
1330 if ( phrase_c->grid() )
1331         ui->update_phrase_widgets();} {}
1332   }
1333   Function {find_numeric_menu_item( const Fl_Menu_Item *menu, int n )} {return_type {static int}
1334   } {
1335     code {for ( unsigned int i = 0; menu[i].text; i++ )
1337         if ( atoi( menu[i].text ) == n )
1338                 return i;
1341 return 0;} {}
1342   }
1343   Function {save_dialog( const char *name )} {open return_type void
1344   } {
1345     code {if ( ! name )
1348         Fl_File_Chooser *fc = new Fl_File_Chooser( ".", "Non Sequences (*.non)", Fl_File_Chooser::CREATE, "Save sequence" );
1350         fc->show();
1352         // wait for user to make a choice
1353         while( fc->shown() )
1354                  Fl::wait();
1356         if ( ! fc->value() )
1357                 return;
1358         
1359         name = fc->value();     
1362 if ( ! save_song( name ) )
1363         fl_alert( "Could not save song" );
1364 else
1365         gui_status( "Saved." );} {}
1366   }
1367   Function {show_help_dialog( const char *file )} {return_type void
1368   } {
1369     code {char pat[256];
1371 snprintf( pat, 256, "file://%s/non-sequencer/%s.html", DOCUMENT_PATH, file );
1373 open_url( pat );} {}
1374   }
1375   Function {maybe_save_song()} {open return_type bool
1376   } {
1377     code {if ( song.dirty() )
1379         int c = fl_choice( "Song has been modified since last save. What shall I do?", "&Cancel", "&Save", "&Discard" );
1381         switch ( c )
1382         {
1383                 case 0:
1384                         return false;
1385                 case 1:
1386                         /* SAVE */
1387                         save_dialog( song.filename );
1388                         break;
1389                 case 2:
1390                         break;
1391         }       
1394 return true;} {}
1395   }
1396   Function {switch_to_pattern( int n )} {return_type void
1397   } {
1398     code {pattern *p = pattern::pattern_by_number( n );
1400 if ( p )
1404         
1405         tabs->value( pattern_tab );
1406         
1407         pattern_canvas_widget->take_focus();
1408         
1409         pattern_c->grid( p );
1410         
1411 //      update_pattern_widgets();
1412 }} {}
1413   }
1414   Function {edit_instrument_row( Instrument *i, int n )} {open return_type void
1415   } {
1416     code {Instrument_Editor ie;
1418 ie.set( i, n );
1420 ie.run();} {}
1421   }
1424 Function {shortcut_handler( int e )} {return_type int
1425 } {
1426   code {if ( e != FL_SHORTCUT )
1427         return 0;
1430 // this is for mainwindow shortcuts only, ignore all other windows.
1431 if ( Fl::first_window() != ui->main_window )
1432         return 0;
1434 int processed = 0;
1436 // shortcuts that don't fit anywhere else (widgets that don't take shortcuts, etc.)
1438 \#define KEY(key) ((Fl::test_shortcut( (key) )))
1440         processed = 1;
1441         if KEY( FL_ALT + 's' )
1442         {
1443                 ui->tabs->value( ui->sequence_tab );
1444                 ui->tabs->do_callback();
1445         }
1446         else
1447         if KEY( FL_ALT + 'a' )
1448         {
1449                 ui->tabs->value( ui->phrase_tab );
1450                 ui->tabs->do_callback();
1451         }
1452         else
1453         if KEY( FL_ALT + 'p' )
1454         {
1455                 ui->tabs->value( ui->pattern_tab );
1456                 ui->tabs->do_callback();
1457         }
1458         else
1459         if KEY( FL_ALT + 'c' )
1460                 ui->pattern_channel_spinner->take_focus();
1461         else
1462         if KEY( FL_ALT + 'o' )
1463                 ui->pattern_port_spinner->take_focus();
1464         else
1465         if KEY( FL_ALT + 'i' )
1466                 ui->mapping_menu->take_focus();
1467         else
1468                 processed = 0;
1470 return processed;} {}
1473 class O_Canvas {open : {public Fl_Widget}
1474 } {
1475   decl {Canvas *_c;} {private local
1476   }
1477   decl {bool _border_drawn;} {private local
1478   }
1479   Function {O_Canvas( int X, int Y, int W, int H, const char*L=0) : Fl_Widget(X,Y,W,H,L)} {open
1480   } {
1481     code {_c = NULL;
1482 _border_drawn = false;
1483               box(FL_FLAT_BOX);} {}
1484   }
1485   Function {handle( int m )} {open return_type int
1486   } {
1487     code {// Accept focus if offered.
1488 if ( m == FL_FOCUS || m == FL_UNFOCUS )
1490         _border_drawn = false;
1491         redraw_playhead();
1492         return 1;
1495 // Hack in click-to-focus
1496 if ( m == FL_PUSH )
1497         if ( Fl::event_inside( this ) )
1498                 take_focus();
1501 if ( Fl_Widget::handle( m ) )
1502         return 1;
1504 // Ignore events unless we have the focus.
1505 if ( this != Fl::focus() )
1506         return 0;
1508 // MESSAGE( "got event %i for canvas %p", m, _c );
1510 int p = 0;
1512 if ( _c )
1513         {
1514                 p = canvas_input_callback( this, _c, m );
1515         }
1517 return p;} {}
1518   }
1519   Function {resize( int x, int y, int w, int h )} {open
1520   } {
1521     code {Fl_Widget::resize( x, y, w, h );
1523 if ( _c )
1525         DMESSAGE( "Resizing canvas." );
1526         _c->resize( x + 1, y + 1, w - 1, h - 1 );
1530 // Fl_Window::resize( x, y, w, h );} {}
1531   }
1532   Function {draw()} {open return_type void
1533   } {
1534     code {draw_border();
1536 //if ( ! takesevents() )
1537 //      return;
1539 if ( _c )
1542         if ( damage() & FL_DAMAGE_ALL ) printf( " damage_all" );
1543         if ( damage() & FL_DAMAGE_SCROLL ) printf( " damage_scroll" );
1544         if ( damage() & FL_DAMAGE_USER1 ) printf( " damage_user1" );
1545         if ( damage() & FL_DAMAGE_USER2 ) printf( " damage_user2" );
1546         if ( damage() & FL_DAMAGE_EXPOSE ) printf(  " damage_expose" );
1547         printf("\\n");
1549         
1550         if ( damage() & FL_DAMAGE_ALL )
1551         {
1552                 draw_box( FL_FLAT_BOX, x(), y(), w(), h(), canvas_background_color );
1553                 _border_drawn = false;
1554                 draw_border();
1555                 _c->redraw();
1556                 _c->draw_playhead();
1557         }
1558         else
1559         {
1560                 if ( damage() & FL_DAMAGE_SCROLL )
1561                 {
1562                 // optimized draw
1563                 _c->draw();
1564                 }
1565                 if ( damage() & FL_DAMAGE_USER1 )
1566                 {
1567                 // playhead
1568                 _c->draw_playhead();
1569                 }
1570         }
1572 else
1574         WARNING( "No canvas set for widget." );
1575 }} {}
1576   }
1577   Function {set_canvas( Canvas *c )} {open
1578   } {
1579     code {_c = c;
1581 _c->resize( x(), y(), w(), h() );
1583 _c->signal_draw.connect( sigc::mem_fun( this, &O_Canvas::redraw_notes ) );
1584 _c->signal_resize.connect( sigc::mem_fun( this, &O_Canvas::clear ) );
1586 _c->signal_settings_change.connect( sigc::ptr_fun( &UI::update_canvas_widgets ) );
1587 _c->signal_settings_change.connect( sigc::mem_fun( song, &song_settings::set_dirty ) );} {}
1588   }
1589   Function {click_to_focus()} {open return_type bool
1590   } {
1591     code {return true;} {}
1592   }
1593   Function {clear( void )} {open return_type void
1594   } {
1595     code {redraw();} {}
1596   }
1597   Function {redraw_notes( void )} {open return_type void
1598   } {
1599     code {damage( FL_DAMAGE_SCROLL );
1601 // this might be called from within draw(), in which case the above does nothing.} {}
1602   }
1603   Function {redraw_playhead( void )} {open return_type void
1604   } {
1605     code {if ( _c && _c->playhead_moved() )
1606     {
1607             damage( FL_DAMAGE_USER1 );
1608     }} {}
1609   }
1610   Function {draw_border()} {open return_type void
1611   } {
1612     code {if ( _border_drawn )
1613         return;
1615 if ( this != Fl::focus() )
1616         fl_color( FL_RED );
1617 else
1618         fl_color( FL_BLACK );
1619         
1620 fl_line_style( FL_DASH );
1621 fl_rect( x(), y(), w(), h() );
1622 fl_line_style( FL_SOLID );
1624 _border_drawn = true;} {}
1625   }
1626   Function {handle_pan( void )} {open return_type void
1627   } {
1628     code {int up, left, right, down;
1630 if ( ! ui )
1631    return;
1632 _c->can_scroll( &left, &right, &up, &down );
1634 if ( left == 0 )
1635         ui->scroll_left_box->hide();
1636 else
1637         ui->scroll_left_box->show();
1638         
1639 if ( up == 0 )
1640         ui->scroll_up_box->hide();
1641 else
1642         ui->scroll_up_box->show();
1643         
1644 if ( down == 0 )
1645         ui->scroll_down_box->hide();
1646 else
1647         ui->scroll_down_box->show();
1649 ui->scroll_right_box->hide();} {}
1650   }
1653 class Instrument_Editor {} {
1654   Function {Instrument_Editor()} {open return_type void
1655   } {
1656     code {make_window();} {}
1657   }
1658   decl {Instrument *_inst;} {private local
1659   }
1660   decl {int _note;} {private local
1661   }
1662   Function {make_window()} {open
1663   } {
1664     Fl_Window window {
1665       label {Instrument Editor}
1666       callback {done->do_callback();} open
1667       xywh {670 458 335 190} type Double hide
1668     } {
1669       Fl_Box {} {
1670         label {Instrument Row}
1671         xywh {8 15 321 28} box ROUNDED_BOX color 94 labelsize 22 labelcolor 39
1672       }
1673       Fl_Input name_field {
1674         label Name
1675         callback {_inst->note_name( _note, strdup( o->value() ) );}
1676         xywh {10 70 321 25} selection_color 48 align 1 when 1 textcolor 32
1677       }
1678       Fl_Value_Slider volume_slider {
1679         label {Volume %}
1680         callback {_inst->velocity( _note, o->value() );}
1681         xywh {10 112 321 27} type Horizontal align 1 maximum 100 step 1 textsize 14
1682       }
1683       Fl_Value_Output note_field {
1684         label {Note:}
1685         xywh {52 158 43 24}
1686       }
1687       Fl_Return_Button done {
1688         label Done
1689         callback {if ( _inst )
1690         _inst->save();
1691         
1692 window->hide();}
1693         xywh {255 157 76 25}
1694       }
1695     }
1696   }
1697   Function {set( Instrument *i, int n )} {open return_type void
1698   } {
1699     code {_inst = i;
1700 _note = n;
1702 volume_slider->value( i->velocity( n ) );
1703 name_field->value( i->note_name( n ) );
1704 note_field->value( n );} {}
1705   }
1706   Function {run()} {open return_type void
1707   } {
1708     code {window->show();
1710 while ( window->shown() )
1711         Fl::wait();} {}
1712   }
1715 class Trigger {open : {public Fl_Dial}
1716 } {
1717   Function {Trigger( int X, int Y, int W, int H, const char *L ) : Fl_Dial( X, Y, W, H, L )} {open
1718   } {
1719     code {} {}
1720   }
1721   Function {handle( int m )} {open return_type int
1722   } {
1723     code {int r = 0;
1725 switch ( m )
1727         case FL_PUSH:
1728         {
1729                 switch ( Fl::event_button() )
1730                 {
1731                         case 1:
1732                         {
1733                                 pattern *p = pattern::pattern_by_number( atoi( label() ) );
1734                 
1735                                 if ( p )
1736                                 {                                  
1737                                      if ( TRIGGER == song.play_mode )           
1738                                      {
1739                                         if ( p->playing() )
1740                                             p->stop();
1741                                         else
1742                                             p->trigger();
1743                                      }
1744                                      else
1745                                      {
1746                                         if ( p->mode() == PLAY )
1747                                             p->mode( MUTE );
1748                                         else
1749                                             p->mode( PLAY );
1750                                      }
1751                                 }
1752                                 
1753                                 break;
1754                         }
1755                         case 2:
1756                         {
1757                                 pattern *p = pattern::pattern_by_number( atoi( label() ) );
1758                                 
1759                                 if ( p )
1760                                 {
1761                                         if ( p->mode() != SOLO )
1762                                                 p->mode( SOLO );
1763                                         else
1764                                                 p->mode( PLAY );
1765                                 }
1766                                 
1767                                 break;
1768                         }
1769                         case 3:
1770                         {
1771                                 ui->switch_to_pattern( atoi( label() ) );
1772                         }
1773                                 break;
1774                 }
1775                 r = 1;
1776                 break;
1777         }
1778         case FL_RELEASE:
1779                 do_callback();
1780                 r = 1;
1781                 break;
1782         case FL_DRAG:
1783                 r = 1;
1784                 break;
1785         default:
1786                 r = Fl_Widget::handle( m );
1787                 break;
1791 return r;} {}
1792   }
1795 widget_class Triggers {open
1796   xywh {335 80 1278 1003} type Double hide resizable
1797   code0 {populate();}
1798   code1 {\#include <FL/Fl_Dial.H>}
1799   class Fl_Group
1800 } {
1801   Fl_Pack rows {open
1802     xywh {25 25 15 15}
1803   } {}
1804   Function {populate( void )} {open private return_type void
1805   } {
1806     code {_timer = 0;
1808 int bw = (w() / 16);
1809 int bh = h() / (128/ 16);
1811 begin();
1813 for ( int n = 0; n < 128 ; n += 16 )
1815         Fl_Pack *p = new Fl_Pack( 0, 0, 25, 25 );
1816         
1817         p->type( Fl_Pack::HORIZONTAL );
1818         
1819         for ( int i = 0; i < 16; i++ )
1820         {
1821                 
1822                 Trigger *b = new Trigger( 0, 0, bw, 50, "Num" );
1823                 
1824                 char pat[4];
1825                 
1826                 sprintf( pat, "%d", n + i + 1 );
1827                 
1828                 b->label( strdup( pat ) );
1829                 b->minimum( 0 );
1830                 b->maximum( 1 );
1831                 b->angles( 0, 360 );
1832                 b->type( FL_FILL_DIAL );
1833                 b->color2( FL_GRAY );
1834                 b->box( FL_ROUNDED_BOX );
1835 //              b->down_box( FL_ROUNDED_BOX );
1836                 b->selection_color( FL_GREEN );
1837                 b->color( FL_BLACK );
1838                 b->align( FL_ALIGN_CENTER );
1839                                 
1840                 p->add( b );
1841         }
1842                 
1843         p->end(); 
1844         
1845         p->resize( 0, 0, w(), bh );
1846         rows->add( p );
1850 end();
1852 rows->resize( x(), y(), w(), h() );
1854 redraw();} {}
1855   }
1856   Function {update( void )} {open return_type void
1857   } {
1858     code {++_timer;
1860     if ( !visible_r() )
1861         return;           
1863 if ( ! takesevents() )
1864         return;
1866         Fl_Color mode_color[3];
1868 //        mode_color[PLAY] = fl_color_average( FL_GRAY, FL_GREEN, 0.5 );
1869         mode_color[PLAY] = FL_DARK2;    
1870         mode_color[MUTE] = FL_LIGHT2;
1871         mode_color[SOLO] = fl_color_average( FL_GRAY, FL_RED, 0.5 );
1873 int i;
1874 for ( i = 0; i < MAX_PATTERN; i++ )
1878         Trigger *b = (Trigger*)(((Fl_Pack*)rows->child( i / 16 ))->child( i % 16 ));
1880         if ( i >= pattern::patterns() )
1881         {
1882                 b->color( FL_BLACK );
1883                 b->value( 0 );
1884                 continue;
1885         }
1886         
1887         pattern *p = pattern::pattern_by_number( i + 1 );
1888                         
1889         if ( p->playing() )
1890         {
1891                 b->color( FL_GRAY );
1892                 
1893                 b->selection_color( mode_color[ p->mode() ] );
1895                 if ( p->queue() >= 0 )
1896                 {
1897                       if ( _timer % 16 < 8 )
1898                       {
1899                             b->color( mode_color[ p->queue() ] );
1900                       }
1901                 }
1902                 
1903                 b->value( (double)p->index() / p->length() );
1904         }
1905         else
1906         {
1907                 b->value( 0 );
1908         }
1909                 
1910 }} {}
1911   }
1912   Function {resize( int X, int Y, int W, int H )} {open return_type void
1913   } {
1914     code {for ( int i = rows->children(); i--; )
1916         Fl_Pack *p = (Fl_Pack*) rows->child( i );
1917         
1918         for ( int j = p->children(); j--; )
1919         {
1920                 int bw = W / p->children();
1921                 p->child( j )->resize( 0, 0, bw, 25 );;
1922         }
1924         p->resize( 0, 0, W, H / rows->children() );
1925                         
1926         p->redraw();
1929 Fl_Group::resize( X, Y, W, H );} {}
1930   }
1931   decl {unsigned long _timer;} {private local
1932   }