Centralize color schemes.
[nondaw.git] / Mixer / Mixer_Strip.C
bloba1178ca75936b979197d370ba0dbf08e02523deb
2 /*******************************************************************************/
3 /* Copyright (C) 2009 Jonathan Moore Liles                                     */
4 /*                                                                             */
5 /* This program is free software; you can redistribute it and/or modify it     */
6 /* under the terms of the GNU General Public License as published by the       */
7 /* Free Software Foundation; either version 2 of the License, or (at your      */
8 /* option) any later version.                                                  */
9 /*                                                                             */
10 /* This program is distributed in the hope that it will be useful, but WITHOUT */
11 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       */
12 /* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for   */
13 /* more details.                                                               */
14 /*                                                                             */
15 /* You should have received a copy of the GNU General Public License along     */
16 /* with This program; see the file COPYING.  If not,write to the Free Software */
17 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18 /*******************************************************************************/
20 /* Mixer strip control. Handles GUI and control I/O for this strip. */
22 /* A mixer strip is home to some (JACK) input ports, a fader, some
23  * meters, and a filter chain which can terminate either at the input
24  * to the spacializer or some (JACK) output ports. Since mixer strips
25  * are not necessarily in a 1:1 association with Non-DAW tracks, there
26  * is no need for busses per se. If you want to route the output of
27  * several strips into a single fader or filter chain, then you just
28  * gives those strips JACK outputs and connect them to the common
29  * inputs. This mechanism can also do away with the need for 'sends'
30  * and 'inserts'.
32  */
33 /* Each mixer strip comprises a fader and a panner */
35 #include "Mixer_Strip.H"
36 #include "Engine/Engine.H"
37 #include <dsp.h>
38 #include <string.h>
39 #include "debug.h"
42 #include "FL/Fl_Flowpack.H"
43 #include <FL/Fl_Input.H>
44 #include <FL/fl_ask.H>
45 #include <FL/Fl_Color_Chooser.H>
46 #include <FL/Fl.H>
47 #include "Mixer.H"
49 #include "Chain.H"
50 #include "Gain_Module.H"
51 #include "Meter_Module.H"
52 #include "Controller_Module.H"
53 #include "Meter_Indicator_Module.H"
54 #include "util/debug.h"
56 #include <FL/Fl_Menu_Button.H>
57 #include "FL/test_press.H"
58 #include "FL/menu_popup.H"
60 extern Mixer *mixer;
64 /* add a new mixer strip (with default configuration) */
65 Mixer_Strip::Mixer_Strip( const char *strip_name ) : Fl_Group( 0, 0, 120, 600 )
67     label( strdup( strip_name ) );
68     labeltype( FL_NO_LABEL );
70     init();
72     chain( new Chain() );
74     _chain->initialize_with_default();
76     _chain->configure_ports();
78     color( (Fl_Color)rand() );
80 //    name( strdup( strip_name ) );
82     log_create();
85 /* virgin strip created from journal */
86 Mixer_Strip::Mixer_Strip() : Fl_Group( 0, 0, 120, 600 )
88     init();
90     log_create();
93 Mixer_Strip::~Mixer_Strip ( )
95     DMESSAGE( "Destroying mixer strip" );
97     delete _chain;
98     _chain = NULL;
100     log_destroy();
102     mixer->remove( this );
107 void
108 Mixer_Strip::get ( Log_Entry &e ) const
110     e.add( ":name",            name()           );
111     e.add( ":width",      width_button->value() ? "wide" : "narrow" );
112     e.add( ":tab",      tab_button->value() ? "signal" : "fader" );
113     e.add( ":color",           (unsigned long)color());
116 void
117 Mixer_Strip::set ( Log_Entry &e )
119     for ( int i = 0; i < e.size(); ++i )
120     {
121         const char *s, *v;
123         e.get( i, &s, &v );
125         if ( ! strcmp( s, ":name" ) )
126             name( v );
127         else if ( ! strcmp( s, ":width" ) )
128         {
129             width_button->value( strcmp( v, "wide" ) == 0 );
130             width_button->do_callback();
131         }
132         else if ( ! strcmp( s, ":tab" ) )
133         {
134             tab_button->value( strcmp( v, "signal" ) == 0 );
135             tab_button->do_callback();
136         }
137         else if ( ! strcmp( s, ":color" ) )
138         {
139             color( (Fl_Color)atoll( v ) );
140             redraw();
141         }
142     }
144     if ( ! mixer->contains( this ) )
145         mixer->add( this );
148 void
149 Mixer_Strip::log_children ( void )
151     log_create();
153     _chain->log_children();
156 void
157 Mixer_Strip::color ( Fl_Color c )
159     _color = c;
160     name_field->color( _color );
161     name_field->redraw();
164 Fl_Color
165 Mixer_Strip::color ( void ) const
167     return _color;
170 void
171 Mixer_Strip::chain ( Chain *c )
173     if ( _chain )
174         delete _chain;
176     _chain = c;
178     c->strip( this );
180     Fl_Group *g = signal_tab;
182     c->resize( g->x(), g->y(), g->w(), g->h() );
183     g->add( c );
184     g->resizable( c );
186     c->labelsize( 10 );
187     c->align( FL_ALIGN_TOP );
188     c->color( FL_RED );
189     c->configure_outputs_callback( configure_outputs, this );
190     c->name( name() );
192     gain_controller->chain( c );
193     jack_input_controller->chain( c );
194     meter_indicator->chain( c );
198 void Mixer_Strip::cb_handle(Fl_Widget* o) {
199     // parent()->parent()->damage( FL_DAMAGE_ALL, x(), y(), w(), h() );
200     if ( o == tab_button )
201     {
202         if ( tab_button->value() == 0 )
203         {
204             fader_tab->show();
205             signal_tab->hide();
206         }
207         else
208         {
209             signal_tab->show();
210             fader_tab->hide();
211         }
213     }
214     else if ( o == left_button )
215         command_move_left();
216     else if ( o == right_button )
217         command_move_right();
218     else if ( o == close_button )
219     {
220         if ( Fl::event_shift() || 1 == fl_choice( "Are you sure you want to remove this strip?\n\n(this action cannot be undone)", "Cancel", "Remove", NULL ) )
221             command_close();
222     }
223     else if ( o == name_field )
224         name( name_field->value() );
225     else if ( o == width_button )
226     {
227         if ( ((Fl_Button*)o)->value() )
228             size( 300, h() );
229         else
230             size( 120, h() );
232         if ( parent() )
233             parent()->parent()->redraw();
234     }
237 void Mixer_Strip::cb_handle(Fl_Widget* o, void* v) {
238     ((Mixer_Strip*)(v))->cb_handle(o);
243 void
244 Mixer_Strip::name ( const char *name ) {
245     char *s = strdup( name );
246     name_field->value( s );
247     label( s );
248     if ( _chain )
249         _chain->name( s );
252 void
253 Mixer_Strip::configure_outputs ( Fl_Widget *o, void *v )
255     ((Mixer_Strip*)v)->configure_outputs();
258 void
259 Mixer_Strip::configure_outputs ( void )
261     DMESSAGE( "Got signal to configure outputs" );
264 /* called by the chain to let us know that a module has been added */
265 void
266 Mixer_Strip::handle_module_added ( Module *m )
268     if ( m->is_default() )
269     {
270         DMESSAGE( "Connecting controls to default module \"%s\"", m->name() );
272         /* connect default modules to their default controllers/indicators */
273         if ( 0 == strcmp( m->name(), "JACK" ) && m->ninputs() == 0 )
274         {
275             if ( !jack_input_controller->control_output[0].connected() )
276                 jack_input_controller->connect_to( &m->control_input[1] );
277         }
278         else if ( 0 == strcmp( m->name(), "Gain" ) )
279         {
280             gain_controller->connect_to( &m->control_input[0] );
281         }
282         else if ( 0 == strcmp( m->name(), "Meter" ) )
283         {
284             meter_indicator->connect_to( &m->control_output[0] );
285         }
286     }
289 /* update GUI with values from RT thread */
290 void
291 Mixer_Strip::update ( void )
293     THREAD_ASSERT( UI );
296 void
297 Mixer_Strip::init ( )
299     selection_color( FL_FOREGROUND_COLOR );
301     _chain = 0;
303 //    box(FL_THIN_UP_BOX);
304     box( FL_RFLAT_BOX );
306     Fl_Group::color( FL_BACKGROUND_COLOR );
308     clip_children( 1 );
310     Fl_Pack *gain_pack;
312     { Fl_Pack *o = new Fl_Pack( 2, 2, 114, 100 );
313         o->type( Fl_Pack::VERTICAL );
314         o->spacing( 2 );
315         {
316             Fl_Sometimes_Input *o = new Fl_Sometimes_Input( 2, 2, 144, 24 );
317             name_field = o;
319             o->color( color() );
320             o->up_box( FL_ROUNDED_BOX );
321             o->box( FL_ROUNDED_BOX );
322             o->labeltype( FL_NO_LABEL );
323             o->labelcolor( FL_GRAY0 );
324             o->textcolor( FL_FOREGROUND_COLOR );
325             o->value( name() );
326             o->callback( cb_handle, (void*)this );
328         }
329         { Fl_Scalepack *o = new Fl_Scalepack( 7, 143, 110, 25 );
330             o->type( Fl_Pack::HORIZONTAL );
331             { Fl_Button* o = left_button = new Fl_Button(7, 143, 35, 25, "@<-");
332                 o->tooltip( "Move left" );
333                 o->type(0);
334                 o->labelsize(10);
335                 o->when( FL_WHEN_RELEASE );
336                 o->callback( ((Fl_Callback*)cb_handle), this );
337             } // Fl_Button* o
339             { Fl_Button* o = close_button = new Fl_Button(7, 143, 35, 25, "X");
340                 o->tooltip( "Remove strip" );
341                 o->type(0);
342                 o->labeltype( FL_EMBOSSED_LABEL );
343                 o->color( FL_LIGHT1 );
344                 o->selection_color( FL_RED );
345                 o->labelsize(10);
346                 o->when( FL_WHEN_RELEASE );
347                 o->callback( ((Fl_Callback*)cb_handle), this );
348             } // Fl_Button* o
350             { Fl_Button* o = right_button = new Fl_Button(7, 143, 35, 25, "@->");
351                 o->tooltip( "Move right" );
352                 o->type(0);
353                 o->labelsize(10);
354                 o->when( FL_WHEN_RELEASE );
355                 o->callback( ((Fl_Callback*)cb_handle), this );
356             } // Fl_Button* o
358             o->end();
359         } // Fl_Group* o
360         { Fl_Flip_Button* o = width_button = new Fl_Flip_Button(61, 183, 45, 22, "narrow/wide");
361             o->type(1);
362             o->labelsize(14);
363             o->callback( ((Fl_Callback*)cb_handle), this );
364             o->when(FL_WHEN_RELEASE);
365         } // Fl_Flip_Button* o
366         { Fl_Flip_Button* o = tab_button = new Fl_Flip_Button(61, 183, 45, 22, "fader/signal");
367             o->type(1);
368             o->labelsize( 14 );
369             o->callback( cb_handle, this );
370             o->when(FL_WHEN_RELEASE);
371         }
372 //    { Fl_Pack* o = new Fl_Pack(8, 208, 103, 471);
373 //    { Fl_Pack* o = gain_pack = new Fl_Pack(8, 208, 103, 516 );
375         o->end();
376     }
378     Fl_Pack *fader_pack;
380     { Fl_Group *o = fader_tab = new Fl_Group( 7, 115, 105, 330, "Fader" );
381         o->box( FL_NO_BOX );
382         o->labeltype( FL_NO_LABEL );
383         { Fl_Pack* o = fader_pack = new Fl_Pack(7, 116, 103, 330 );
384             o->spacing( 20 );
385             o->type( Fl_Pack::HORIZONTAL );
386             { Controller_Module *o = gain_controller = new Controller_Module( true );
387                 o->pad( false );
388                 o->size( 33, 0 );
389             }
390             { Meter_Indicator_Module *o = meter_indicator = new Meter_Indicator_Module( true );
391                 o->pad( false );
392                 o->size( 58, 0 );
393                 o->clip_children( 0 );
394                 Fl_Group::current()->resizable(o);
396             }
397             o->end();
398             Fl_Group::current()->resizable(o);
399         } // Fl_Group* o
400         o->end();
401         Fl_Group::current()->resizable(o);
402     }
403     { Fl_Group *o = signal_tab = new Fl_Group( 7, 115, 105, 330 );
404         o->box( FL_NO_BOX );
405         o->labeltype( FL_NO_LABEL );
406         o->hide();
407         o->end();
408     }
409     { Fl_Pack *o = panner_pack = new Fl_Pack( 2, 443, 114, 40 );
410         o->spacing( 2 );
411         o->type( Fl_Pack::VERTICAL );
412         o->box( FL_NO_BOX );
414         { Fl_Box *o = new Fl_Box( 0, 0, 100, 24 );
415             o->align( (Fl_Align)(FL_ALIGN_BOTTOM | FL_ALIGN_INSIDE) );
416             o->labelsize( 10 );
417             o->label( "Spatialization" );
418         }
419         { Panner* o = new Panner(0, 0, 110, 90);
420             o->deactivate();
421             o->box(FL_THIN_UP_BOX);
422             o->color(FL_GRAY0);
423             o->selection_color(FL_BACKGROUND_COLOR);
424             o->labeltype(FL_NORMAL_LABEL);
425             o->labelfont(0);
426             o->labelsize(11);
427             o->labelcolor(FL_FOREGROUND_COLOR);
428             o->align(FL_ALIGN_TOP);
429             o->when(FL_WHEN_RELEASE);
430         } // Panner* o
431         { Fl_Box *o = new Fl_Box( 0, 0, 100, 12 );
432             o->align( (Fl_Align)(FL_ALIGN_BOTTOM | FL_ALIGN_INSIDE) );
433             o->labelsize( 10 );
434             o->label( "Inputs" );
435         }
436         {
437             Controller_Module *m = jack_input_controller = new Controller_Module( true );
438             m->labeltype( FL_NO_LABEL );
439             m->chain( _chain );
440             m->pad( false );
441 //            m->connect_to( &_chain->module( 0 )->control_input[1] );
442             m->size( 33, 24 );
443         }
444         o->end();
445     }
447     end();
449     color( FL_BLACK );
451     //  _chain->configure_ports();
454 void
455 Mixer_Strip::draw ( void )
457     if ( !fl_not_clipped( x(), y(), w(), h() ) )
458         return;
460     /* don't bother drawing anything else, all we're doing is drawing the focus. */
461     if ( damage() != FL_DAMAGE_USER1 )
462         Fl_Group::draw();
464     Fl_Group::draw_box( FL_ROUNDED_FRAME, x(), y(), w(), h(), _focused ? Fl_Group::selection_color() : FL_BLACK );
469 void
470 Mixer_Strip::menu_cb ( const Fl_Menu_ *m )
472     char picked[256];
474     m->item_pathname( picked, sizeof( picked ) );
476     Logger log( this );
478     if ( ! strcmp( picked, "Width/Narrow" ) )
479         command_width( false );
480     else if ( ! strcmp( picked, "Width/Wide" ) )
481         command_width( true );
482     else if ( ! strcmp( picked, "View/Fader" ) )
483         command_view( false );
484     else if ( ! strcmp( picked, "View/Signal" ) )
485         command_view( true );
486     else if ( ! strcmp( picked, "/Move Left" ) )
487         command_move_left();
488     else if ( ! strcmp( picked, "/Move Right" ) )
489         command_move_right();
490     else if ( ! strcmp( picked, "/Rename" ) )
491         name_field->take_focus();
492     else if ( ! strcmp( picked, "/Color" ) )
493     {
494         unsigned char r, g, b;
496         Fl::get_color( color(), r, g, b );
498         if ( fl_color_chooser( "Strip Color", r, g, b ) )
499             color( fl_rgb_color( r, g, b ) );
501         redraw();
502     }
503     else if ( ! strcmp( picked, "/Remove" ) )
504     {
505         if ( Fl::event_shift() || 1 == fl_choice( "Are you sure you want to remove this strip?\n\n(this action cannot be undone)", "Cancel", "Remove", NULL ) )
506             command_close();
507     }
510 void
511 Mixer_Strip::menu_cb ( Fl_Widget *w, void *v )
513     ((Mixer_Strip*)v)->menu_cb( (Fl_Menu_*) w );
517 /** build the context menu */
518 Fl_Menu_Button &
519 Mixer_Strip::menu ( void ) const
521     static Fl_Menu_Button m( 0, 0, 0, 0, "Strip" );
522     static char label[256];
524     snprintf( label, sizeof(label), "Strip/%s", name() );
525     m.label( label );
527 //    int c = output.size();
529     Fl_Menu_Item menu[] =
530         {
531             { "Width",            0, 0, 0, FL_SUBMENU    },
532             { "Narrow",         'n', 0, 0, FL_MENU_RADIO | ( ! width_button->value() ? FL_MENU_VALUE : 0 ) },
533             { "Wide",           'w', 0, 0, FL_MENU_RADIO | ( width_button->value() ? FL_MENU_VALUE : 0 ) },
534             { 0                  },
535             { "View",            0, 0, 0, FL_SUBMENU    },
536             { "Fader",          'f', 0, 0, FL_MENU_RADIO | ( 0 == tab_button->value() ? FL_MENU_VALUE : 0 ) },
537             { "Signal",         's', 0, 0, FL_MENU_RADIO | ( 1 == tab_button->value() ? FL_MENU_VALUE : 0 ) },
538             { 0                  },
539             { "Move Left",      '[', 0, 0  },
540             { "Move Right",     ']', 0, 0 },
541             { "Color",           0, 0, 0 },
542             { "Rename",          FL_CTRL + 'n', 0, 0 },
543             { "Remove",          FL_Delete, 0, 0 },
544             { 0 },
545         };
547     menu_set_callback( menu, &Mixer_Strip::menu_cb, (void*)this );
549     m.copy( menu, (void*)this );
551     return m;
555 Mixer_Strip::handle ( int m )
557     Logger log( this );
559     switch ( m )
560     {
561         case FL_KEYBOARD:
562         {
563             if ( Fl_Group::handle( m ) )
564                 return 1;
566             if ( Fl::event_key() == FL_Menu )
567             {
568                 menu_popup( &menu(), x(), y() );
569                 return 1;
570             }
571              else
572                 return menu().test_shortcut() != 0;
573         }
574         break;
575         case FL_PUSH:
576         {
577             if ( Fl_Group::handle( m ) )
578                 return 1;
579             else if ( test_press( FL_BUTTON3 ) )
580             {
581                 menu_popup( &menu() );
582                 return 1;
583             }
585             return 0;
586         }
587         case FL_FOCUS:
588             _focused = true;
589             damage( FL_DAMAGE_USER1 );
590             return 1;
591         case FL_UNFOCUS:
592             _focused = false;
593             damage( FL_DAMAGE_USER1 );
594             return 1;
595     }
597     return Fl_Group::handle( m );
601 /************/
602 /* Commands */
603 /************/
605 void
606 Mixer_Strip::command_move_left ( void )
608     mixer->move_left( this );
611 void
612 Mixer_Strip::command_move_right ( void )
614     mixer->move_right( this );
617 void
618 Mixer_Strip::command_close ( void )
620         mixer->remove( this );
621         Fl::delete_widget( this );
624 void
625 Mixer_Strip::command_rename ( const char * s )
627     name( s );
630 void
631 Mixer_Strip::command_width ( bool b )
633     width_button->value( b );
634     width_button->do_callback();
637 void
638 Mixer_Strip::command_view ( bool b )
640     tab_button->value( b );
641     tab_button->do_callback();