# data file for the Fltk User Interface Designer (fluid)
version 1.0300 
header_name {.H} 
code_name {.C}
comment {//
// Copyright (C) 2008 Jonathan Moore Liles
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
} {in_source in_header
} 

decl {\#include <FL/Fl_Dial.H>} {public local
} 

decl {\#include <About_Dialog.H>} {private local
} 

decl {class Fl_Scalepack;} {public local
} 

decl {class Fl_Sometimes_Input;} {public local
} 

decl {\#include <Fl_Flowpack.H>} {public global
} 

decl {\#include <FL/Fl_Overlay_Window.H>} {public local
} 

decl {\#include <FL/Fl_Theme_Chooser.H>} {private local
} 

decl {\#include <FL/Fl_Progress.H>} {public global
} 

decl {\#include <Fl_Scalepack.H>} {private local
} 

decl {\#include <Fl_Sometimes_Input.H>} {private local
} 

decl {\#include <Fl_Menu_Settings.H>} {private local
} 

decl {\#include <FL/Fl_Shared_Image.H>} {private local
} 

decl {\#include <math.h>} {private local
} 

decl {\#include "event_edit.H"} {private local
} 

decl {\#include "../jack.H"} {private local
} 

decl {\#include "../NSM.H"} {private local
} 

decl {extern NSM_Client *nsm;} {private local
} 

decl {\#include "../transport.H"} {private local
} 

decl {extern UI *ui;} {private local
} 

decl {class O_Canvas;} {private local
} 

decl {class Triggers;} {public local
} 

decl {class Instrument_Editor;} {private local
} 

decl {Fl_Color canvas_background_color;} {public local
} 

decl {Fl_Color velocity_colors[128];} {public local
} 

Function {init_colors()} {open private C return_type {static void}
} {
  code {unsigned int i;
    /* velocity colors */

    Fl_Color lo = fl_color_average( FL_CYAN, FL_BLACK, 0.10 );
    Fl_Color hi = fl_color_average( FL_CYAN, FL_WHITE, 0.80 );

    for ( i = 128; i--; )
    {
        velocity_colors[i] = fl_color_average( hi, lo, 1.0 * ((float)i / 128) );
    }} {}
} 

widget_class Visual_Metronome {open
  xywh {978 1028 100 100} type Double visible
} {
  Fl_Slider progress {
    private xywh {139 115 1149 23} type Horizontal box FLAT_BOX color 7 selection_color 54
    code0 {o->resize( x(), (y() + h()) - (h() / 3), w(), h() / 3 );}
    code1 {o->slider_size( 0.25 );}
    code2 {o->slider( FL_FLAT_BOX  );}
  }
  Function {draw(void)} {open protected return_type void
  } {
    code {if ( damage() & ~FL_DAMAGE_CHILD )
{
	if ( ! _bpb )
		return;

int bw = w() / _bpb;

int b = _bpb;

if ( b )
{

for ( int i = 0; i < b; ++i )
{
		if ( i == _beat )
		fl_color( velocity_colors[ i * 127 / _bpb ] );
	else
		fl_color( FL_GRAY );
		
	int X = x() + ( i * bw );
	int Y = y();
	int W = bw;
	int H = h() - 14;
	
	fl_rectf(X,Y,W,H);
	fl_color( fl_darker( fl_color() ) );
	fl_rect( X,Y,W,H);
		
	char pat[4];
		
	snprintf( pat, sizeof(pat), "%d", i + 1 );
	fl_font( FL_HELVETICA_BOLD, 24 );
	fl_draw( pat, X,Y,W,H, FL_ALIGN_CENTER );
	
}
}
}
progress->resize( x(), y() + h() - 14, w(), 14 );

if ( damage() & FL_DAMAGE_CHILD )
	update_child( *progress );
else
	draw_child( *progress );

// _flip = ! _flip;} {}
  }
  decl {int _bpb} {private local
  }
  decl {int _tpb} {private local
  }
  decl {int _beat} {private local
  }
  decl {bool _flip} {private local
  }
  decl {int _tick} {private local
  }
  Function {bpb( int b )} {open private return_type void
  } {
    code {if ( b != _bpb )
{
	_bpb = b;
	redraw();
}} {}
  }
  Function {tpb( int ticks )} {open private return_type void
  } {
    code {_tpb = ticks;

progress->minimum( 0 );
progress->maximum( ticks );} {}
  }
  Function {beat( int b )} {open private return_type void
  } {
    code {if ( b == _beat || b >= _bpb )
	return;

_flip = ! _flip;

_beat = b;
redraw();} {}
  }
  Function {tick( int tick )} {open private return_type void
  } {
    code {if ( tick == _tick )
	return;
	
if ( _beat < 0 )
	return;

if ( _flip )
{
	progress->value( _tpb - tick );
}
else
{
	progress->value( tick );
}

_tick = tick;} {}
  }
  Function {update( void )} {open return_type void
  } {
    code {if ( transport.beats_per_bar ) {
bpb( transport.beats_per_bar );
tpb( transport.ticks_per_beat );
beat( transport.beat - 1 );
tick( transport.tick - 1 );}} {}
  }
  code {_bpb = 0;
_tpb = 0;
_beat = 0;
_tick = 0;
_flip = 0;} {}
} 

class Overlay_Callback_Window {: {public Fl_Overlay_Window}
} {
  decl {void (*_draw_overlay_callback)(void*);} {private local
  }
  decl {void *_draw_overlay_userdata;} {private local
  }
  Function {Overlay_Callback_Window(int X, int Y, int W, int H, const char *L=0) : Fl_Overlay_Window(X,Y,W,H,L)} {open
  } {
    code {_draw_overlay_callback = 0;
_draw_overlay_userdata = 0;} {}
  }
  Function {Overlay_Callback_Window(int W, int H, const char *L=0) : Fl_Overlay_Window(W,H,L)} {open
  } {
    code {_draw_overlay_callback = 0;
_draw_overlay_userdata = 0;} {}
  }
  Function {draw_overlay()} {open return_type {virtual void}
  } {
    code {if ( _draw_overlay_callback )
  _draw_overlay_callback( _draw_overlay_userdata );} {}
  }
  Function {draw_overlay_callback( void(*cb)(void*), void *v)} {open return_type void
  } {
    code {_draw_overlay_callback = cb;
_draw_overlay_userdata = v;} {}
  }
} 

Function {update_transport( void * )} {open return_type void
} {
  code {// transport_poll();

handle_midi_input();

 ui->progress_group->do_callback();

 ui->vmetro_widget->update();	

 ui->triggers_widget->update();

Fl::repeat_timeout( TRANSPORT_POLL_INTERVAL, update_transport );

static int oldstate = -1;

if ( transport.rolling != oldstate )
{

	ui->play_button->label( transport.rolling ? "@square" : "@>" );
	oldstate = transport.rolling;
	
	if ( transport.rolling )
	{
		ui->menu_new->deactivate();
		ui->menu_open->deactivate();
	}
	else
	{
		ui->menu_new->activate();
		ui->menu_open->activate();
	}

}

if ( nsm && nsm->is_active() )
{
     if ( ui->menu_new->active() )
     {
            ui->menu_new->deactivate();
            ui->menu_open->deactivate();
            ui->menu_save_as->deactivate(); 
     }
}

// JUST A TEST
if ( transport.rolling )
{
	if ( ui->tabs->value() == ui->pattern_tab )
		ui->pattern_canvas_widget->redraw_playhead();
	else
	if ( ui->tabs->value() == ui->phrase_tab )
		ui->phrase_canvas_widget->redraw_playhead();

}

ui->transport_state->do_callback();} {}
} 

class UI {open
} {
  decl {Fl_Text_Buffer *sequence_notes_buffer;} {private local
  }
  decl {Fl_Text_Buffer *pattern_notes_buffer;} {private local
  }
  decl {Fl_Text_Buffer *phrase_notes_buffer} {private local
  }
  Function {UI()} {open
  } {
    code {fl_register_images();

canvas_background_color = FL_GREEN;

playback_mode_menu = NULL;

main_window = make_main_window();
seq_window = make_seq_window();

init_colors();

// make_instrument_edit_dialog();

// use old focus behavior
Fl::visible_focus( 0 );

// try to fill the screen, but only when the screen is tiny and our window is huge.
{
        int sx, sy, sw, sh;

        Fl::screen_xywh( sx, sy, sw, sh );

        if ( sw < main_window->w() || sh < main_window->h() )
            main_window->resize( sx, sy, sw, sh );
}

Fl::add_timeout( TRANSPORT_POLL_INTERVAL, update_transport );


playlist->signal_new_song.connect( sigc::mem_fun( this, &UI::update_sequence_widgets ) );
pattern_canvas_widget->signal_settings_change.connect( sigc::mem_fun( this, &UI::update_pattern_widgets ) );
phrase_canvas_widget->signal_settings_change.connect( sigc::mem_fun( this, &UI::update_phrase_widgets ) );} {}
  }
  Function {~UI()} {open
  } {
    code {delete seq_window;
delete main_window;} {}
  }
  Function {run()} {open
  } {
    code {Fl::run();} {}
  }
  Function {load_settings()} {open return_type void
  } {
    code {char *path;

asprintf( &path, "%s/%s", config.user_config_dir, "view" );

((Fl_Menu_Settings*)menu_bar)->load( menu_bar->find_item( "&View" ), path );

free( path );} {}
  }
  Function {save_settings()} {open return_type void
  } {
    code {char *path;

asprintf( &path, "%s/%s", config.user_config_dir, "view" );

((Fl_Menu_Settings*)menu_bar)->dump( menu_bar->find_item( "&View" ), path );

free( path );} {}
  }
  Function {draw_overlay( void *v )} {open protected return_type {static void}
  } {
    code {((UI*)v)->draw_overlay();} {}
  }
  Function {draw_overlay()} {open protected return_type void
  } {
    code {Canvas *c = current_canvas();
if ( c )
   c->draw_overlay();} {}
  }
  Function {make_main_window()} {open
  } {
    Fl_Window main_window {
      label {Non Sequencer}
      callback {// Ignore escape
if ( Fl::event() == FL_SHORTCUT && Fl::event_key() == FL_Escape )
	return;
	 
if ( maybe_save_song() )
	quit();} open
      xywh {213 323 865 805} type Double color 47 resizable
      code0 {o->color( FL_BACKGROUND_COLOR );}
      code1 {o->draw_overlay_callback( &UI::draw_overlay, this );}
      code2 {o->xclass( APP_NAME );}
      class Overlay_Callback_Window size_range {700 509 0 0} visible
    } {
      Fl_Group {} {open
        xywh {0 25 865 70} box FLAT_BOX
      } {
        Fl_Group {} {open
          xywh {552 26 312 69}
          code0 {o->resizable(0);}
        } {
          Fl_Value_Input {} {
            label BPM
            callback {transport.set_beats_per_minute( o->value() );}
            xywh {825 39 35 19} labelsize 9 align 1 when 8 textsize 10
            code1 {transport.signal_tempo_change.connect( sigc::mem_fun( o, static_cast<int (Fl_Valuator::*)(double)>(&Fl_Valuator::value) ) );}
            code2 {o->value( transport.beats_per_minute );}
          }
          Fl_Group {} {
            label {Time Sig.} open
            xywh {756 38 64 21} labelsize 9
          } {
            Fl_Value_Input {} {
              callback {transport.set_beats_per_bar( o->value() );}
              xywh {756 39 24 19} textsize 10
              code0 {transport.signal_bpb_change.connect( sigc::mem_fun( o, static_cast<int (Fl_Valuator::*)(double)>(&Fl_Valuator::value) ) );}
              code1 {o->value( transport.beats_per_bar );}
            }
            Fl_Box {} {
              label {/}
              xywh {780 38 14 21}
            }
            Fl_Value_Input {} {
              callback {transport.set_beat_type( o->value() );}
              xywh {795 39 24 19} textsize 10
              code0 {transport.signal_beat_change.connect( sigc::mem_fun( o, static_cast<int (Fl_Valuator::*)(double)>(&Fl_Valuator::value) ) );}
              code1 {o->value( transport.beat_type );}
            }
          }
          Fl_Choice record_mode_menu {
            label {Record Mode}
            callback {if ( ! transport.recording )
	config.record_mode = (record_mode_e)o->value();
else
	o->value( config.record_mode );}
            xywh {555 39 105 19} box DOWN_BOX down_box BORDER_BOX color 37 labelsize 9 align 1 textsize 9
          } {
            MenuItem {} {
              label Merge
              xywh {15 15 40 25} labelfont 3 labelsize 10
            }
            MenuItem {} {
              label Overwrite
              xywh {25 25 40 25} labelfont 3 labelsize 10
            }
            MenuItem {} {
              label Layer
              xywh {35 35 40 25} labelfont 3 labelsize 10
            }
            MenuItem {} {
              label New
              xywh {45 45 40 25} labelfont 3 labelsize 10
            }
          }
          Fl_Choice playback_mode_menu {
            label {Playback &Mode}
            xywh {665 39 85 19} box DOWN_BOX down_box BORDER_BOX color 37 labelsize 9 align 1
          } {
            MenuItem {} {
              label Pattern
              callback {song.play_mode = PATTERN;}
              xywh {5 5 40 25} labelfont 3 labelsize 10
            }
            MenuItem {} {
              label Sequence
              callback {song.play_mode = SEQUENCE;}
              xywh {15 15 40 25} labelfont 3 labelsize 10
            }
            MenuItem {} {
              label Trigger
              callback {song.play_mode = TRIGGER;}
              xywh {25 25 40 25} labelfont 3 labelsize 10
            }
            MenuItem {} {
              label Queue
              callback {song.play_mode = QUEUE;}
              xywh {0 0 40 24} labelfont 3 labelsize 10
            }
          }
          Fl_Pack {} {open
            xywh {555 60 305 30} type HORIZONTAL
            class Fl_Scalepack
          } {
            Fl_Button {} {
              label Sequence
              callback {tabs->value( sequence_tab );


edit_menu->deactivate();
menu_bar->redraw();}
              xywh {565 70 68 15} type Radio shortcut 0x80031 selection_color 69
            }
            Fl_Button {} {
              label Phrase
              callback {tabs->value( phrase_tab );

edit_menu->activate();
menu_bar->redraw();}
              xywh {575 80 68 5} type Radio shortcut 0x80032 selection_color 69
            }
            Fl_Button {} {
              label Pattern
              callback {tabs->value( pattern_tab );

edit_menu->activate();
menu_bar->redraw();}
              xywh {585 90 68 0} type Radio shortcut 0x80033 value 1 selection_color 69
            }
          }
        }
        Fl_Pack vmetro_widget {
          label Metronome
          xywh {160 27 390 61} type HORIZONTAL box UP_BOX color 40 selection_color 48 labelsize 33 align 0 resizable
          code0 {o->box( FL_FLAT_BOX );}
          class Visual_Metronome
        } {}
        Fl_Pack transport_controls_group {open
          xywh {4 27 151 60} type HORIZONTAL
          code0 {o->spacing( 2 );}
          class Fl_Scalepack
        } {
          Fl_Button play_button {
            label {@>}
            callback {transport.toggle();}
            xywh {10 29 43 38} shortcut 0x20 labeltype ENGRAVED_LABEL
          }
          Fl_Button rec_button {
            label {@circle}
            callback {transport.recording = o->value();


if ( o->value() )
{
	if ( config.record_mode == NEW )
	{
		pattern *p = new pattern;
		p->length( -1 );
		
		pattern_canvas_widget->grid( p );
	}
	
	((pattern*)pattern_canvas_widget->grid())->record( 0 );
	
	o->labelcolor( FL_RED );
}
else
{
	pattern::recording()->record_stop();
	
	o->labelcolor( FL_WHITE );
}}
            xywh {60 29 43 38} type Toggle shortcut 0x80072 selection_color 47 labeltype ENGRAVED_LABEL when 1
          }
          Fl_Button home_button {
            label {@|<}
            callback {transport.locate( 0 );}
            xywh {110 29 43 38} shortcut 0xff50 labeltype ENGRAVED_LABEL
          }
        }
      }
      Fl_Tabs tabs {
        callback {((Fl_Group*)o->value())->child( 0 )->take_focus();} open
        xywh {-1 91 868 694} box FLAT_BOX color 47 labeltype SHADOW_LABEL labelsize 19 when 1 resizable
        code0 {canvas_background_color = fl_rgb_color( 18, 18, 18 );}
      } {
        Fl_Group sequence_tab {open
          xywh {0 91 865 692} box FLAT_BOX color 37 labeltype NO_LABEL labelsize 12 hide resizable
          code0 {update_sequence_widgets();}
        } {
          Fl_Group {} {open
            xywh {5 118 240 502} labelsize 12
          } {
            Fl_Browser playlist_browser {
              label Playlist
              xywh {5 155 240 398} type Hold box EMBOSSED_BOX color 39 selection_color 30 labelsize 12 labelcolor 55 align 1 when 4 textsize 18 textcolor 95 resizable
              code0 {static int widths[] = { 40, 30, 0 };}
              code1 {o->column_widths( widths ); o->column_char( '\\t' );}
              code2 {o->value( 1 );}
            }
            Fl_Button sequence_phrase_delete_button {
              label Delete
              callback {int val = playlist_browser->value();

if ( val > 1 )
{
//	playlist_browser->value( playlist_browser->value() + 1 );

	playlist->remove( val - 2 );

	update_sequence_widgets();
	
	if ( ! playlist_browser->value() )
		playlist_browser->value( playlist_browser->size() );
}}
              xywh {6 559 64 25} shortcut 0xffff color 88 labelcolor 23
            }
            Fl_Button sequence_phrase_up_button {
              label Up
              callback {if ( playlist_browser->value() > 2 )
{
	playlist->move( playlist_browser->value() - 2, UP );
	playlist_browser->value( playlist_browser->value() - 1 );
	update_sequence_widgets();
}}
              xywh {135 559 45 25} shortcut 0xffbf
            }
            Fl_Button sequence_phrase_down_button {
              label Down
              callback {if ( playlist_browser->value() > 1 )
{
	playlist->move( playlist_browser->value() - 2, DOWN );
	playlist_browser->value( playlist_browser->value() + 1 );
	update_sequence_widgets();
}}
              xywh {185 559 58 25} shortcut 0xffc0
            }
            Fl_Menu_Button sequence_phrase_choice {
              label {Insert Phrase}
              callback {playlist->insert( playlist_browser->value() - 1, o->value() + 1 );

update_sequence_widgets();

int val = playlist_browser->value();

if ( val )
	playlist_browser->value( playlist_browser->value() + 1 );
else
	playlist_browser->value( playlist_browser->size() );} open
              xywh {5 590 235 30} color 63
            } {}
          }
          Fl_Input sequence_name_field {
            label Name
            callback {playlist->name( o->value() );}
            xywh {10 109 235 27} color 48 labelsize 12 align 1 when 1
          }
          Fl_Light_Button detach_button {
            label Detach
            callback {if ( o->value() )
{
	Fl_Group *g = seq_detached_group;
	seq_window->show();
	g->add( sequence_tab );
	sequence_tab->resize( g->x(), g->y(), g->w(), g->h() );
	tabs->do_callback();
	main_window->redraw();
}
else
{
	seq_window->hide();
	tabs->insert( (Fl_Widget&)*sequence_tab, 0 );
	sequence_tab->resize( pattern_tab->x(), pattern_tab->y(), pattern_tab->w(), pattern_tab->h() );
	tabs->do_callback();	
}}
            xywh {7 749 78 26}
          }
          Fl_Text_Editor sequence_notes_edit {
            label {Notes:}
            callback {playlist->notes( o->buffer()->text() );}
            xywh {254 732 606 48} selection_color 48 labelsize 12 align 5 textcolor 94
            code0 {o->buffer( sequence_notes_buffer = new Fl_Text_Buffer );}
          }
          Fl_Box triggers_widget {
            label Patterns
            xywh {253 118 607 598} box FLAT_BOX color 48 labelsize 12 align 1 resizable
            code0 {o->color( FL_BACKGROUND_COLOR );}
            code1 {o->rows( 32 );}
            class Triggers
          }
          Fl_Group progress_group {
            callback {if ( ! o->visible_r() )
	return;

phrase *p = phrase::phrase_by_number( playlist->playing() );

if ( p )
	phrase_progress->value( p->index() / (double)p->length() );
	
if ( playlist->length() )
	sequence_progress->value( playlist->index() / (double)playlist->length() );} open
            xywh {10 649 233 66}
          } {
            Fl_Slider phrase_progress {
              label Phrase
              xywh {10 649 233 24} type Horizontal labelsize 12 align 1
            }
            Fl_Slider sequence_progress {
              label Sequence
              callback {transport.locate( (tick_t)((double)playlist->length() * o->value()) );}
              xywh {10 691 233 24} type Horizontal labelsize 12 align 1
            }
          }
        }
        Fl_Group phrase_tab {
          xywh {0 91 865 693} box FLAT_BOX color 47 labeltype NO_LABEL hide
          code0 {update_phrase_widgets();}
        } {
          Fl_Box phrase_canvas_widget {
            label Phrase
            xywh {0 91 865 637} box FLAT_BOX color 37 labelsize 100 align 16 resizable
            class Canvas
          }
          Fl_Group phrase_settings_group {open
            xywh {0 728 865 55} box FLAT_BOX color 47
          } {
            Fl_Input phrase_name_field {
              label {name:}
              callback {phrase_canvas_widget->grid()->name( strdup( o->value() ) );

// if the name changed..
update_sequence_widgets();}
              xywh {5 734 185 21} box ROUNDED_BOX color 49 labelfont 2 labelsize 12 labelcolor 55 align 20 textfont 2 textsize 12
              code0 {o->up_box( FL_ROUNDED_BOX );}
              class Fl_Sometimes_Input
            }
            Fl_Light_Button phrase_mute_button {
              label Mute
              xywh {0 751 93 23} color 37 hide
            }
            Fl_Light_Button phrase_solo_button {
              label Solo
              xywh {106 751 87 23} color 37 hide
            }
            Fl_Text_Editor phrase_notes_edit {
              label {Notes:}
              callback {phrase_canvas_widget->grid()->notes( o->buffer()->text() );}
              xywh {200 742 660 36} selection_color 48 labelsize 12 textcolor 94 resizable
              code0 {o->buffer( phrase_notes_buffer = new Fl_Text_Buffer );}
            }
            Fl_Value_Slider phrase_number_spinner {
              label {Phrase:}
              callback {phrase *p = ((phrase *)phrase_canvas_widget->grid())->by_number( o->value() );

if ( p )
    phrase_canvas_widget->grid( p );

o->maximum( phrase::phrases() );}
              xywh {45 760 140 18} type Horizontal labelsize 10 align 4 minimum 1 maximum 128 step 1 value 1 textsize 14
            }
          }
        }
        Fl_Group pattern_tab {open
          xywh {0 91 867 694} box FLAT_BOX color 47 labeltype NO_LABEL
          code0 {update_pattern_widgets();}
        } {
          Fl_Box pattern_canvas_widget {
            label Pattern
            xywh {0 91 865 637} box FLAT_BOX color 37 labelsize 100 align 16 resizable
            class Canvas
          }
          Fl_Group pattern_settings_group {open
            xywh {0 730 867 55} box FLAT_BOX color 47
          } {
            Fl_Group {} {open
              xywh {5 733 420 44}
              code0 {o->resizable(0);}
            } {
              Fl_Input pattern_name_field {
                label {name:}
                callback {pattern_canvas_widget->grid()->name( strdup( o->value() ) );}
                xywh {5 734 185 21} box BORDER_BOX color 49 labelsize 12 align 20 when 8 textsize 12 textcolor 55
                code0 {o->up_box( FL_BORDER_BOX );}
                class Fl_Sometimes_Input
              }
              Fl_Light_Button pattern_mute_button {
                label Mute
                callback {Grid *g = pattern_canvas_widget->grid();

g->mode( g->mode() == MUTE ? PLAY : MUTE );

o->value( g->mode() == MUTE );

pattern_solo_button->value( 0 );}
                xywh {195 734 58 19} type Normal shortcut 0x6d color 37 labelsize 12
              }
              Fl_Light_Button pattern_solo_button {
                label Solo
                callback {Grid *g = pattern_canvas_widget->grid();

g->mode( g->mode() == SOLO ? PLAY : SOLO );

o->value( g->mode() == SOLO );

pattern_mute_button->value( 0 );}
                xywh {195 758 58 19} type Normal shortcut 0x73 color 37 labelsize 12
              }
              Fl_Value_Slider pattern_number_spinner {
                label Pattern
                callback {pattern *p = ((pattern *)pattern_canvas_widget->grid())->by_number( o->value() );

if ( p )
    pattern_canvas_widget->grid( p );

o->maximum( pattern::patterns() );}
                xywh {45 759 140 18} type Horizontal labelsize 10 align 4 minimum 1 maximum 128 step 1 value 1
              }
              Fl_Button pattern_selection_mode {
                label Select
                callback {pattern_canvas_widget->selection_mode( o->value() );}
                tooltip {Enable selection mode (you can also just hold down shift and drag the mouse)} xywh {260 733 45 44} type Toggle selection_color 5 labelsize 10
              }
              Fl_Value_Slider velocity_slider {
                label Velocity
                callback {pattern_canvas_widget->selected_velocity( o->value() );} selected
                xywh {310 742 110 18} type {Horz Fill} labelsize 10 align 1 maximum 127 value 64 textsize 9
              }
            }
            Fl_Group {} {open
              xywh {455 731 409 54}
            } {
              Fl_Output mapping_text {
                label Mapping
                xywh {535 761 105 19} labelsize 10 align 20 textsize 11
              }
              Fl_Menu_Button mapping_menu {
                label {@>}
                callback {mapping_text->value( o->text() );


char picked[80];
mapping_menu->item_pathname(picked, sizeof(picked)-1 );

if ( 0 == strncmp( picked, "Instrument", strlen( "Instrument" ) ) )
{
	((pattern*)pattern_canvas_widget->grid())->mapping.open( Mapping::INSTRUMENT, o->text() );

	pattern_canvas_widget->changed_mapping();

	pattern_key_combo->deactivate();
}
else
if ( 0 == strncmp( picked, "Scale", strlen( "Scale" ) ) )
{
	((pattern*)pattern_canvas_widget->grid())->mapping.open( Mapping::SCALE, o->text() );

	pattern_canvas_widget->changed_mapping();

	pattern_key_combo->activate();
}} open
                xywh {640 761 30 19} labeltype NO_LABEL labelsize 10 textsize 12
                code0 {update_mapping_menu();}
              } {
                Submenu mapping_scale_menu {
                  label Scale open
                  xywh {25 25 74 25}
                } {}
                Submenu mapping_instrument_menu {
                  label Instrument open
                  xywh {10 10 74 25}
                } {}
              }
              Fl_Choice pattern_key_combo {
                label {&Key}
                callback {((pattern*)pattern_canvas_widget->grid())->mapping.key( o->value() );

pattern_canvas_widget->changed_mapping();}
                xywh {700 761 75 19} down_box BORDER_BOX labelsize 10 when 1 textsize 11
              } {
                MenuItem {} {
                  label C
                  xywh {30 30 40 25} labelsize 11
                }
                MenuItem {} {
                  label {C\#/Db}
                  xywh {40 40 40 25} labelsize 11
                }
                MenuItem {} {
                  label D
                  xywh {50 50 40 25} labelsize 11
                }
                MenuItem {} {
                  label {D\#/Eb}
                  xywh {60 60 40 25} labelsize 11
                }
                MenuItem {} {
                  label E
                  xywh {70 70 40 25} labelsize 11
                }
                MenuItem {} {
                  label F
                  xywh {80 80 40 25} labelsize 11
                }
                MenuItem {} {
                  label {F\#/Gb}
                  xywh {90 90 40 25} labelsize 11
                }
                MenuItem {} {
                  label G
                  xywh {100 100 40 25} labelsize 11
                }
                MenuItem {} {
                  label {G\#}
                  xywh {110 110 40 25} labelsize 11
                }
                MenuItem {} {
                  label A
                  xywh {0 0 40 25} labelsize 11
                }
                MenuItem {} {
                  label {A\#/Bb}
                  xywh {10 10 40 25} labelsize 11
                }
                MenuItem {} {
                  label B
                  xywh {20 20 40 25} labelsize 11
                }
              }
              Fl_Choice pattern_note_combo {
                label {&Note 1/}
                callback {((pattern*)pattern_canvas_widget->grid())->note( atoi( o->menu()[ o->value() ].text ));}
                xywh {715 736 45 19} down_box BORDER_BOX labelsize 10 when 1 textsize 12
              } {
                MenuItem {} {
                  label 1
                  xywh {0 0 40 25} labelsize 11
                }
                MenuItem {} {
                  label 2
                  xywh {10 10 40 25} labelsize 11
                }
                MenuItem {} {
                  label 4
                  xywh {20 20 40 25} labelsize 11
                }
                MenuItem {} {
                  label 8
                  xywh {30 30 40 25} labelsize 11
                }
                MenuItem {} {
                  label 16
                  xywh {40 40 40 25} labelsize 11
                }
                MenuItem {} {
                  label 32
                  xywh {50 50 40 25} labelsize 11
                }
                MenuItem {} {
                  label 64
                  xywh {60 60 40 25} labelsize 11 divider
                }
                MenuItem {} {
                  label 3
                  xywh {60 60 40 25} labelsize 11
                }
                MenuItem {} {
                  label 6
                  xywh {70 70 40 25} labelsize 11
                }
                MenuItem {} {
                  label 12
                  xywh {80 80 40 25} labelsize 11
                }
                MenuItem {} {
                  label 24
                  xywh {90 90 40 25} labelsize 11
                }
              }
              Fl_Choice pattern_res_combo {
                label {&Resolution 1/}
                callback {pattern_canvas_widget->grid()->resolution( atoi( o->menu()[ o->value() ].text ));}
                xywh {615 736 55 19} down_box BORDER_BOX labelsize 10 when 1 textsize 12
              } {
                MenuItem {} {
                  label 1
                  xywh {40 40 40 25} labelsize 11
                }
                MenuItem {} {
                  label 2
                  xywh {50 50 40 25} labelsize 11
                }
                MenuItem {} {
                  label 4
                  xywh {30 30 40 25} labelsize 11
                }
                MenuItem {} {
                  label 8
                  xywh {40 40 40 25} labelsize 11
                }
                MenuItem {} {
                  label 16
                  xywh {50 50 40 25} labelsize 11
                }
                MenuItem {} {
                  label 32
                  xywh {60 60 40 25} labelsize 11
                }
                MenuItem {} {
                  label 64
                  xywh {80 80 40 25} labelsize 11
                }
                MenuItem {} {
                  label 128
                  xywh {90 90 40 25} labelsize 11 divider
                }
                MenuItem {} {
                  label 3
                  xywh {70 70 40 25} labelsize 11
                }
                MenuItem {} {
                  label 6
                  xywh {80 80 40 25} labelsize 11
                }
                MenuItem {} {
                  label 12
                  xywh {90 90 40 25} labelsize 11
                }
                MenuItem {} {
                  label 24
                  xywh {100 100 40 25} labelsize 11
                }
              }
              Fl_Choice pattern_channel_choice {
                label {Channel:}
                callback {((pattern *)pattern_canvas_widget->grid())->channel( o->value() );} open
                xywh {810 735 47 19} down_box BORDER_BOX labelsize 10 textsize 12
                code0 {char pat[3]; for ( int i = 1; i <= 16; i++ ) { snprintf( pat, 3, "%i", i ); o->add( pat ); }}
              } {}
              Fl_Choice pattern_port_choice {
                label {Port:}
                callback {((pattern *)pattern_canvas_widget->grid())->port( o->value() );} open
                xywh {810 760 47 19} down_box BORDER_BOX labelsize 10 textsize 12
                code0 {char pat[3]; for ( int i = 1; i <= 16; i++ ) { snprintf( pat, 3, "%i", i ); o->add( pat ); }}
              } {}
              Fl_Input_Choice pattern_bars_choice {
                label {Bars:}
                callback {((pattern *)pattern_canvas_widget->grid())->bars( atoi( o->value() ) );} open
                xywh {486 736 55 19} labelsize 10 textsize 12
                code0 {char pat[4]; for ( int i = 1; i <= 16; i++ ) { snprintf( pat, 3, "%i", i ); o->add( pat ); }}
                code1 {for ( int i = 32; i <= 256; i <<= 1 ) { snprintf( pat, sizeof(pat), "%i", i ); o->add( pat ); }}
              } {}
              Fl_Box {} {
                xywh {455 735 0 46} labelsize 8 align 1 resizable
              }
            }
          }
        }
      }
      Fl_Group {} {open
        xywh {0 784 865 23}
      } {
        Fl_Box status {
          label status
          xywh {1 784 782 23} box UP_BOX align 84
          code0 {o->label( NULL );}
        }
        Fl_Box transport_state {
          label state
          callback {const char *s = "INVALID";

if ( transport.master )
	s = "Master";
else if ( transport.valid )
	s = "Slave";

if ( s != o->label() )
{
	o->label( s );
	if ( ! strcmp( s, "INVALID" ) )
		o->color( fl_darker( FL_RED ) );
	else
		o->color( FL_BACKGROUND_COLOR );
}}
          xywh {783 784 82 23} box THIN_UP_BOX align 64
        }
      }
      Fl_Group {} {open
        xywh {0 0 865 24}
      } {
        Fl_Menu_Bar menu_bar {open
          xywh {0 0 865 24} color 47 resizable
        } {
          Submenu {} {
            label {&File} open
            xywh {0 0 100 20} color 37
          } {
            MenuItem menu_new {
              label {&New}
              callback {if ( maybe_save_song() )
{
	init_song();

	// Sync the GUI.
	update_pattern_widgets();
	update_sequence_widgets();
	update_phrase_widgets();
	
	
	gui_status( "New song." );
}}
              xywh {0 0 40 25}
            }
            MenuItem menu_open {
              label {&Open}
              callback {char *name = fl_file_chooser( "Open File", "Non Files (*.non)", NULL, 0 );

if ( name )
{
	if ( ! load_song( name ) )
		fl_alert( "Could not load song!" );
	else
		gui_status( "Song opened." );
	
	update_sequence_widgets();
	update_pattern_widgets();
	update_phrase_widgets();

	playback_mode_menu->value( song.play_mode );
	playback_mode_menu->redraw();
}}
              xywh {0 0 40 25} shortcut 0x4006f color 37
            }
            MenuItem menu_save {
              label {&Save}
              callback {save_dialog( song.filename );}
              xywh {0 0 40 25} shortcut 0x40073 color 37 deactivate
              code0 {song.signal_dirty.connect( sigc::mem_fun( o, &Fl_Menu_Item::activate ) );}
              code1 {song.signal_clean.connect( sigc::mem_fun( o, &Fl_Menu_Item::deactivate ) );}
            }
            MenuItem menu_save_as {
              label {Save &As}
              callback {save_dialog( NULL );}
              xywh {0 0 40 25}
            }
            MenuItem {} {
              label {&Import}
              callback {char *name = fl_file_chooser( "MIDI Import", "MIDI Files (*.mid)", NULL, 0 );

if ( ! name )
	return;

smf f;

if ( ! f.open( name, smf::READ ) )
{
	fl_message( "could not open file" );
	return;
}

f.read_header();

switch ( f.format() )
{
	case 0:
		if ( ! pattern::import( &f, 0 ) )
			fl_message( "Error importing MIDI" );
		break;
	case 1: case 2:
		{
			char **sa = f.track_listing();

			if ( sa && *sa )
			{
				List_Chooser tc( "Select tracks to import:", "Import" );

			 	char *s;
				for ( int i = 0; (s = sa[i]); ++i )
				{
					tc.add( s );
					free( s );
				}

				free( sa );

				tc.show();

				while( tc.shown() )
					Fl::wait();

				int n = 0;
				for ( int i = 1; i <= tc.browser->size(); ++i )
				{
					if ( tc.browser->selected( i ) )
					{
						if ( pattern::import( &f , i - 1 ) )
							++n;
						else
							WARNING( "error importing track %d", i - 1 );
					}

				}
				// fl_message( "%d patterns imported.", n );
				gui_status( "Imported %d tracks as patterns", n );
			}

			break;
		}
}}
              xywh {0 0 40 25}
              code0 {\#include "../smf.H"}
            }
            MenuItem {} {
              label {&Export}
              callback {// Fl_File_Chooser::custom_filter_label = "*.mid";

Fl_File_Chooser *fc = new Fl_File_Chooser( ".", "MIDI Files (*.mid)", Fl_File_Chooser::CREATE, "MIDI Export" );

fc->show();

// wait for user to make a choice
while( fc->shown() )
      Fl::wait();

if ( ! fc->value() )
	return;

if ( tabs->value() == pattern_tab )
	((pattern*)pattern_canvas_widget->grid())->save( fc->value() );}
              xywh {0 0 40 25}
              code0 {\#include <FL/Fl_File_Chooser.H>}
            }
            MenuItem {} {
              label {&Quit}
              callback {main_window->do_callback();}
              xywh {0 0 40 25} shortcut 0x40071 color 37
            }
          }
          Submenu {} {
            label {&View} open
            xywh {10 10 74 25} color 37
          } {
            MenuItem {} {
              label {&Metronome}
              callback {int val = o->menu()[ o->value() ].value();

if ( val )
	vmetro_widget->show();
else
	vmetro_widget->hide();}
              xywh {0 0 40 25} type Toggle value 1
            }
            MenuItem {} {
              label {&Compacted}
              callback {int val = o->menu()[ o->value() ].value();

pattern_canvas_widget->row_compact( val ? Canvas::ON : Canvas::OFF );

pattern_canvas_widget->redraw();}
              xywh {10 10 40 25} type Toggle value 1
            }
            MenuItem {} {
              label {&Follow Playhead}
              callback {int val = o->menu()[ o->value() ].value();

config.follow_playhead = val ? true : false;}
              xywh {10 10 40 25} type Toggle value 1
            }
            MenuItem {} {
              label {&Theme}
              callback {fl_theme_chooser();}
              xywh {0 0 40 24}
            }
          }
          Submenu {} {
            label {&Help} open
            xywh {100 0 74 25} color 37
          } {
            MenuItem {} {
              label {&Manual}
              callback {show_help_dialog( "MANUAL" );}
              xywh {10 10 40 25} divider
            }
            MenuItem {} {
              label {&About}
              callback {About_Dialog ab( PIXMAP_PATH "/non-sequencer/icon-256x256.png" );

            ab.logo_box->label( VERSION );

        ab.title->label( "Non Sequencer" );

        ab.copyright->label( "Copyright (C) 2007-2013 Jonathan Moore Liles" );
        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" );

        ab.website_url->label( "http://non.tuxfamily.org" );

ab.run();}
              xywh {0 0 40 25} color 37
              code0 {\#include "../non.H"}
            }
          }
          Submenu edit_menu {
            label {&Edit} open
            xywh {0 0 68 18}
          } {
            MenuItem {} {
              label {Add New}
              callback {Grid *g = current_canvas()->grid()->create();

current_canvas()->grid( g );

update_pattern_widgets();
update_sequence_widgets();
update_phrase_widgets();}
              xywh {0 0 34 18} shortcut 0x61
            }
            MenuItem {} {
              label Previous
              callback {if ( tabs->value() == pattern_tab )
{
	pattern_number_spinner->value( max( 0, (int)pattern_number_spinner->value() - 1 ) );
	pattern_number_spinner->do_callback();
}
else
{
	phrase_number_spinner->value( max( 0, (int)phrase_number_spinner->value() - 1 ) );
	phrase_number_spinner->do_callback();
}}
              xywh {10 10 34 18} shortcut 0x5b
            }
            MenuItem {} {
              label Next
              callback {if ( tabs->value() == pattern_tab )
{
	pattern_number_spinner->value( min( 127, (int)pattern_number_spinner->value() + 1 ));
	pattern_number_spinner->do_callback();
}
else
{
	phrase_number_spinner->value( min( 127, (int)phrase_number_spinner->value() + 1 ));
	phrase_number_spinner->do_callback();
}}
              xywh {20 20 34 18} shortcut 0x5d
            }
            MenuItem {} {
              label Duplicate
              callback {Canvas *w = current_canvas();

w->grid( w->grid()->clone() );

// number of phrases may have changed.
ui->update_sequence_widgets();}
              xywh {30 30 34 18} shortcut 0x64
            }
            MenuItem {} {
              label {Delete Selected}
              callback {Canvas *w = current_canvas();

w->grid()->delete_selected();}
              xywh {50 50 34 18} shortcut 0xffff
            }
            MenuItem {} {
              label Clear
              callback {Canvas *w = current_canvas();

w->grid()->clear();}
              xywh {60 60 34 18} shortcut 0x1ffff
            }
            MenuItem {} {
              label {Edit Events}
              callback {event_editor( pattern_canvas_widget->grid() );}
              xywh {10 10 40 25}
            }
            MenuItem {} {
              label {Select All}
              callback {Canvas *w = current_canvas();

w->grid()->select_all();}
              xywh {70 70 34 18} shortcut 0x40061
            }
            MenuItem {} {
              label {Select None}
              callback {Canvas *w = current_canvas();

w->grid()->select_none();}
              xywh {80 80 34 18} shortcut 0x50061
            }
            MenuItem {} {
              label {Invert Selection}
              callback {Canvas *w = current_canvas();

w->grid()->invert_selection();}
              xywh {90 90 34 18} shortcut 0x50069
            }
            MenuItem {} {
              label Cut
              callback {Canvas *w = current_canvas();

w->cut();}
              xywh {110 110 34 18} shortcut 0x40078
            }
            MenuItem {} {
              label Copy
              callback {Canvas *w = current_canvas();

w->copy();}
              xywh {100 100 34 18} shortcut 0x40063
            }
            MenuItem {} {
              label Paste
              callback {Canvas *w = current_canvas();

w->paste();}
              xywh {120 120 34 18} shortcut 0x40076
            }
            MenuItem {} {
              label Undo
              callback {Canvas *w = current_canvas();

w->grid()->undo();}
              xywh {110 110 34 18} shortcut 0x4007a
            }
          }
        }
        Fl_Button sm_indicator {
          label SM
          xywh {825 5 35 15} box ROUNDED_BOX down_box ROUNDED_BOX color 46 selection_color 93 labelfont 3 labelcolor 39 deactivate
        }
      }
    }
  }
  Function {make_seq_window()} {} {
    Fl_Window seq_window {
      label {Non Sequencer - Sequence}
      callback {sequence_tab->activate();
o->hide();
detach_button->value( 0 );}
      xywh {681 189 876 675} type Double hide resizable
    } {
      Fl_Group seq_detached_group {open
        xywh {0 0 876 675} resizable
      } {}
    }
  }
  Function {update_pattern_widgets()} {} {
    code {if ( ! pattern_settings_group )
	return;

if ( !pattern_canvas_widget)
	return;
		
pattern *g = (pattern *)pattern_canvas_widget->grid();

if ( !g )
	return;

pattern_number_spinner->value( g->number() );
pattern_name_field->value( g->name() );
pattern_channel_choice->value( g->channel() );
pattern_port_choice->value( g->port() );
pattern_solo_button->value( g->mode() == SOLO );
pattern_mute_button->value( g->mode() == MUTE );
pattern_selection_mode->value( pattern_canvas_widget->selection_mode() );
{
        char pat[5];
        snprintf( pat, sizeof(pat), "%i", g->bars() );
        pattern_bars_choice->value( pat );
}

if ( g->mapping.key() == -1 )
	pattern_key_combo->deactivate();
else
{
	pattern_key_combo->activate();
	pattern_key_combo->value( g->mapping.key() );
}

mapping_text->value( g->mapping.name() );



pattern_note_combo->value( find_numeric_menu_item( menu_pattern_note_combo, g->note() ));
pattern_res_combo->value( find_numeric_menu_item( menu_pattern_res_combo, g->resolution() ));
/*
if ( g->notes() )
	pattern_notes_buffer->text( g->notes() );
else
	pattern_notes_buffer->text( strdup( "" ) );
*/
pattern_settings_group->redraw();} {}
  }
  Function {update_phrase_widgets()} {} {
    code {if ( ! phrase_canvas_widget )
	return;
	
phrase *g = (phrase *)phrase_canvas_widget->grid();

if ( ! g )
	return;
	
g->viewport.y = 0;
g->viewport.h = pattern::patterns();
phrase_canvas_widget->resize_grid();
phrase_canvas_widget->changed_mapping();
phrase_number_spinner->value( g->number() );
phrase_name_field->value( g->name() );
phrase_solo_button->value( g->mode() == SOLO );
phrase_mute_button->value( g->mode() == MUTE );

if ( g->notes() )
	phrase_notes_buffer->text( g->notes() );
else
	phrase_notes_buffer->text( strdup( "" ) );

phrase_settings_group->redraw();} {}
  }
  Function {update_sequence_widgets()} {} {
    code {if ( playlist->notes() )
	sequence_notes_buffer->text( playlist->notes() );
else
	sequence_notes_buffer->text( strdup( "" ) );
	
sequence_name_field->value( playlist->name() );

sequence_phrase_choice->clear();

for ( int i = 1; i <= phrase::phrases(); i++ )
{
	phrase *p = phrase::phrase_by_number( i );

	if ( p )
		sequence_phrase_choice->add( p->name() );
}


Fl_Browser *o = playlist_browser;

int val = o->value();

o->clear();

char *s = playlist->dump();

char *l = strtok( s, "\\n" );

o->add( "@b@C2Bar\\t@b@C2\#\\t@b@C2Name" );

if ( ! l )
	return;

o->add( l );

while ( ( l = strtok( NULL, "\\n" ) ) )
{
	o->add( l );
}

o->value( val );

free( s );


if ( playback_mode_menu )
	playback_mode_menu->value( song.play_mode );} {}
  }
  Function {update_mapping_menu()} {} {
    code {char **sa = Instrument::listing();

if ( sa )
{

	for ( int i = 0; sa[i]; i++ )
	{
		char pat[512];
		snprintf( pat, 512, "Instrument/%s", sa[i] );
		mapping_menu->add( pat, 0, 0, 0, 0 );
		free( sa[i] );
	}
	free( sa );
}

sa = Scale::listing();
for ( int i = 0; sa[i]; i++ )
{
	char pat[512];
	snprintf( pat, 512, "Scale/%s", sa[i] );
	mapping_menu->add( pat, 0, 0, 0, 0 );
	free( sa[i] );
}
free( sa );} {}
  }
  Function {update_canvas_widgets()} {return_type {static void}
  } {
    code {if ( ui->pattern_canvas_widget->grid() )
	ui->update_pattern_widgets();

        if ( ui->phrase_canvas_widget->grid() )
	ui->update_phrase_widgets();} {}
  }
  Function {find_numeric_menu_item( const Fl_Menu_Item *menu, int n )} {return_type {static int}
  } {
    code {for ( unsigned int i = 0; menu[i].text; i++ )
{
	if ( atoi( menu[i].text ) == n )
		return i;
}

return 0;} {}
  }
  Function {save_dialog( const char *name )} {return_type void
  } {
    code {if ( ! name )
{

	Fl_File_Chooser *fc = new Fl_File_Chooser( ".", "Non Sequences (*.non)", Fl_File_Chooser::CREATE, "Save sequence" );

	fc->show();

	// wait for user to make a choice
	while( fc->shown() )
     		 Fl::wait();

	if ( ! fc->value() )
		return;
	
	name = fc->value();	
}

if ( ! save_song( name ) )
	fl_alert( "Could not save song" );
else
	gui_status( "Saved." );} {}
  }
  Function {show_help_dialog( const char *file )} {return_type void
  } {
    code {char pat[256];

snprintf( pat, 256, "file://%s/non-sequencer/%s.html", DOCUMENT_PATH, file );

open_url( pat );} {}
  }
  Function {maybe_save_song()} {return_type bool
  } {
    code {if ( song.dirty() )
{
	int c = fl_choice( "Song has been modified since last save. What shall I do?", "&Cancel", "&Save", "&Discard" );

	switch ( c )
	{
		case 0:
			return false;
		case 1:
			/* SAVE */
			save_dialog( song.filename );
			break;
		case 2:
			break;
	}	
}

return true;} {}
  }
  Function {switch_to_pattern( int n )} {return_type void
  } {
    code {pattern *p = pattern::pattern_by_number( n );

if ( p )
{


	
	tabs->value( pattern_tab );
	
	pattern_canvas_widget->take_focus();
	
	pattern_canvas_widget->grid( p );
	
//	update_pattern_widgets();
}} {}
  }
  Function {edit_instrument_row( Instrument *i, int n )} {return_type void
  } {
    code {Instrument_Editor ie;

ie.set( i, n );

ie.run();} {}
  }
  Function {current_canvas()} {open return_type {Canvas*}
  } {
    code {if ( tabs->value() == pattern_tab )
	return pattern_canvas_widget;
else if ( tabs->value() == phrase_tab )
	return phrase_canvas_widget;
else
	return NULL;} {}
  }
} 

class Instrument_Editor {} {
  Function {Instrument_Editor()} {open return_type void
  } {
    code {make_window();} {}
  }
  decl {Instrument *_inst;} {private local
  }
  decl {int _note;} {private local
  }
  Function {make_window()} {open
  } {
    Fl_Window window {
      label {Instrument Editor}
      callback {done->do_callback();} open
      xywh {670 458 335 190} type Double hide
    } {
      Fl_Box {} {
        label {Instrument Row}
        xywh {8 15 321 28} box ROUNDED_BOX color 94 labelsize 22 labelcolor 39
      }
      Fl_Input name_field {
        label Name
        callback {_inst->note_name( _note, strdup( o->value() ) );}
        xywh {10 70 321 25} selection_color 48 align 1 when 1 textcolor 32
      }
      Fl_Value_Slider volume_slider {
        label {Volume %}
        callback {_inst->velocity( _note, o->value() );}
        xywh {10 112 321 27} type Horizontal align 1 maximum 100 step 1 textsize 14
      }
      Fl_Value_Output note_field {
        label {Note:}
        xywh {52 158 43 24}
      }
      Fl_Return_Button done {
        label Done
        callback {if ( _inst )
	_inst->save();
	
window->hide();}
        xywh {255 157 76 25}
      }
    }
  }
  Function {set( Instrument *i, int n )} {open return_type void
  } {
    code {_inst = i;
_note = n;

volume_slider->value( i->velocity( n ) );
name_field->value( i->note_name( n ) );
note_field->value( n );} {}
  }
  Function {run()} {open return_type void
  } {
    code {window->show();

while ( window->shown() )
	Fl::wait();} {}
  }
} 

class Trigger {: {public Fl_Progress}
} {
  Function {Trigger( int X, int Y, int W, int H, const char *L =0) : Fl_Progress( X, Y, W, H, L )} {open
  } {
    code {minimum( 0 );
maximum( 1 );
//angles( 0, 360 );
// type( Fl_Dial::ARC_DIAL );
// type(FL_VERTICAL);} {}
  }
  Function {handle( int m )} {open return_type int
  } {
    code {int r = 0;

switch ( m )
{
	case FL_PUSH:
	{
		switch ( Fl::event_button() )
		{
			case 1:
			{
 		      		pattern *p = pattern::pattern_by_number( atoi( label() ) );
		
				if ( p )
				{                                  
                                     if ( TRIGGER == song.play_mode ) 		
                                     {
					if ( p->playing() )
                                            p->stop();
					else
                                            p->trigger();
                                     }
                                     else
                                     {
                                        if ( p->mode() == PLAY )
                                            p->mode( MUTE );
                                        else
                                            p->mode( PLAY );
                                     }
				}
				
				break;
			}
			case 2:
			{
 				pattern *p = pattern::pattern_by_number( atoi( label() ) );
				
				if ( p )
				{
					if ( p->mode() != SOLO )
						p->mode( SOLO );
					else
						p->mode( PLAY );
				}
				
				break;
			}
			case 3:
			{
				ui->switch_to_pattern( atoi( label() ) );
			}
				break;
		}
		r = 1;
		break;
	}
	case FL_RELEASE:
		do_callback();
		r = 1;
		break;
	case FL_DRAG:
		r = 1;
		break;
	default:
		r = Fl_Widget::handle( m );
		break;
}


return r;} {}
  }
} 

widget_class Triggers {
  xywh {390 620 335 390} type Double hide
  code0 {\#include <FL/Fl_Dial.H>}
  code1 {populate();}
  class Fl_Group
} {
  Function {populate( void )} {open private return_type void
  } {
    code {_timer = 0;

         for ( int i = 0; i < 128; i++ )
             {
		Trigger *b = new Trigger( 1,1,1,1 );
			
		char pat[4];
		
		sprintf( pat, "%d",i +1);		
		b->label( strdup( pat ) );
		b->labelsize( 8 );
	        b->color2( FL_GRAY );
		b->box( FL_FLAT_BOX );
//		b->down_box( FL_ROUNDED_BOX );
		b->selection_color( FL_GREEN );
		b->color( FL_BLACK );
		b->color2( FL_GREEN );
		b->align( FL_ALIGN_CENTER );

                add( b );
	}} {}
  }
  Function {update( void )} {open return_type void
  } {
    code {++_timer;

    if ( !visible_r() )
        return;           

if ( ! takesevents() )
	return;

        Fl_Color mode_color[3];

        mode_color[PLAY] = fl_color_average( FL_GRAY, FL_GREEN, 0.5 );
//        mode_color[PLAY] = fl_color;    
        mode_color[MUTE] = FL_LIGHT2;
        mode_color[SOLO] = fl_color_average( FL_GRAY, FL_RED, 0.5 );

if ( ! _rows )
	return;
	
for ( int i = 0; i < MAX_PATTERN; i++ )
{
	Trigger *b = (Trigger*)child( i );
	
	if ( i >= pattern::patterns() )
	{
		b->color( FL_BLACK );
		b->value( 0 );
		continue;
	}
	
	pattern *p = pattern::pattern_by_number( i + 1 );
			
	if ( p->playing() )
	{
		b->color( FL_GRAY );
		
		b->selection_color( mode_color[ p->mode() ] );

                if ( p->queue() >= 0 )
                {
                      if ( _timer % 16 < 8 )
                      {
                            b->color( mode_color[ p->queue() ] );
                      }
                }
		
		b->value( (double)p->index() / p->length() );
	}
	else
	{
		b->value( 0 );
	}
		
}} {}
  }
  decl {unsigned long _timer;} {private local
  }
  decl {int _rows;} {private local
  }
  Function {rows(int v)} {open return_type void
  } {
    code {_rows = v;
redraw();} {}
  }
  Function {draw()} {open return_type void
  } {
    code {int _cols = 128 / _rows;

int bw = w() / _cols;
int bh = h() / _rows;

int t = 0;
for ( int i = 0; i < _rows; i++ )
	for ( int j = 0; j < _cols ; j++, t++ )
		child( t )->resize( x() + (bw * j), y() + (bh * i), bw, bh );

Fl_Group::draw();} {}
  }
  decl {\#include <stdlib.h>} {private local
  }
} 

class List_Chooser {} {
  Function {List_Chooser( const char *name, const char *action )} {} {
    Fl_Window window {open
      xywh {525 313 310 545} type Single hide resizable non_modal size_range {310 524 0 0}
    } {
      Fl_Browser browser {
        label name
        xywh {5 26 300 480} type Multi box THIN_DOWN_BOX color 32 selection_color 0 align 1 textcolor 55 resizable
        code0 {o->label( name );}
      }
      Fl_Group {} {open
        xywh {5 505 300 39}
      } {
        Fl_Button {} {
          label Cancel
          callback {browser->clear();
window->hide();}
          xywh {5 513 75 27}
        }
        Fl_Return_Button button {
          label action
          callback {window->hide();}
          xywh {115 513 190 27}
          code0 {o->label( action );}
        }
      }
    }
  }
  Function {show()} {open
  } {
    code {window->show();} {}
  }
  Function {shown()} {open return_type bool
  } {
    code {return window->shown();} {}
  }
  Function {add( const char *item )} {open
  } {
    code {browser->add( item );} {}
  }
} 

decl {float status_intensity;} {private local
} 

Function {fade_status(void*)} {private return_type {static void}
} {
  code {ui->status->labelcolor( fl_color_average( FL_FOREGROUND_COLOR, FL_BACKGROUND_COLOR, status_intensity ) );

    status_intensity -= 0.01f;

    ui->status->redraw();

    if ( status_intensity >= 0.01f )
        Fl::repeat_timeout( 1 / 15.0f, fade_status );} {}
} 

Function {gui_status( const char *fmt, ... )} {C return_type void
} {
  code {va_list args;

    static char pat[256];

    if ( fmt )
    {
        va_start( args, fmt );
        vsnprintf( pat, 256, fmt, args );
        va_end( args );
    }

    ui->status->label( pat );
    ui->status->redraw();

    status_intensity = 1.0f;
    Fl::remove_timeout( fade_status );
    Fl::add_timeout( 1 / 15.0f, fade_status );} {}
} 
