2021-07-21 18:44:41 -04:00
/*
* Copyright ( C ) 2021 Paul Davis < paul @ linuxaudiosystems . com >
*
* 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 . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
2021-12-13 16:51:16 -05:00
# include <vector>
2021-08-05 14:11:19 -04:00
# include <gtkmm/filechooserdialog.h>
2021-08-05 17:04:02 -04:00
# include <gtkmm/menu.h>
# include <gtkmm/menuitem.h>
2021-08-05 14:11:19 -04:00
# include <gtkmm/stock.h>
2021-12-30 11:25:00 -05:00
# include "gtkmm/sizegroup.h"
2021-08-05 14:11:19 -04:00
2021-07-27 22:39:55 -04:00
# include "pbd/compose.h"
2021-07-28 00:40:35 -04:00
# include "pbd/convert.h"
2021-12-17 18:17:58 -05:00
# include "pbd/unwind.h"
2021-07-27 22:39:55 -04:00
2021-12-29 12:21:44 -05:00
# include "pbd/basename.h"
# include "pbd/file_utils.h"
# include "pbd/pathexpand.h"
# include "pbd/search_path.h"
# include "ardour/directory_names.h"
# include "ardour/filesystem_paths.h"
2021-07-28 00:40:35 -04:00
# include "ardour/region.h"
2021-07-21 19:22:09 -04:00
# include "ardour/triggerbox.h"
2021-07-27 22:39:55 -04:00
# include "canvas/polygon.h"
# include "canvas/text.h"
2021-10-17 19:58:08 -04:00
# include "gtkmm2ext/colors.h"
2021-07-21 19:22:09 -04:00
# include "gtkmm2ext/utils.h"
2021-08-05 17:04:02 -04:00
# include "ardour_ui.h"
2021-08-05 18:20:56 -04:00
# include "gui_thread.h"
2021-12-27 17:48:13 -05:00
# include "keyboard.h"
2021-08-05 17:04:02 -04:00
# include "public_editor.h"
2021-10-24 11:25:49 -04:00
# include "region_view.h"
# include "selection.h"
2021-10-04 01:47:47 -04:00
# include "timers.h"
2021-12-17 10:32:52 -05:00
# include "trigger_ui.h"
# include "triggerbox_ui.h"
2021-12-30 11:25:00 -05:00
# include "slot_properties_box.h"
2021-07-28 00:40:35 -04:00
# include "ui_config.h"
2021-08-05 17:04:02 -04:00
# include "utils.h"
2021-07-21 18:44:41 -04:00
2021-09-27 10:28:10 -04:00
# include "pbd/i18n.h"
2021-07-21 18:44:41 -04:00
using namespace ARDOUR ;
using namespace ArdourCanvas ;
2021-07-21 19:22:09 -04:00
using namespace Gtkmm2ext ;
2021-07-28 00:40:35 -04:00
using namespace PBD ;
2021-07-21 18:44:41 -04:00
2021-12-21 15:38:22 -05:00
TriggerEntry : : TriggerEntry ( Item * item , TriggerReference tr )
2021-12-05 11:56:42 -05:00
: ArdourCanvas : : Rectangle ( item )
2021-07-21 18:44:41 -04:00
{
2021-12-17 10:32:52 -05:00
set_layout_sensitive ( true ) ; // why???
2021-07-28 00:40:35 -04:00
2021-12-30 13:10:50 -05:00
name = string_compose ( " trigger %1 " , tr . slot ) ;
2021-10-19 16:41:05 -04:00
2021-12-05 11:56:42 -05:00
set_outline ( false ) ;
2021-07-21 18:44:41 -04:00
2021-08-13 19:08:23 -04:00
play_button = new ArdourCanvas : : Rectangle ( this ) ;
2021-12-21 14:31:37 -05:00
play_button - > set_outline ( false ) ;
2021-12-17 10:32:52 -05:00
play_button - > set_fill ( true ) ;
2021-12-30 13:10:50 -05:00
play_button - > name = string_compose ( " playbutton %1 " , tr . slot ) ;
2021-12-05 11:56:42 -05:00
play_button - > show ( ) ;
2021-07-21 19:22:09 -04:00
2021-12-21 14:31:37 -05:00
follow_button = new ArdourCanvas : : Rectangle ( this ) ;
follow_button - > set_outline ( false ) ;
follow_button - > set_fill ( true ) ;
follow_button - > name = ( " slot_selector_button " ) ;
follow_button - > show ( ) ;
2021-12-05 11:56:42 -05:00
name_button = new ArdourCanvas : : Rectangle ( this ) ;
name_button - > set_outline ( true ) ;
2021-12-17 10:32:52 -05:00
name_button - > set_fill ( true ) ;
2021-12-05 11:56:42 -05:00
name_button - > name = ( " slot_selector_button " ) ;
name_button - > show ( ) ;
name_text = new Text ( name_button ) ;
name_text - > set_ignore_events ( false ) ;
2021-12-17 10:32:52 -05:00
name_text - > show ( ) ;
2021-12-30 13:10:50 -05:00
/* this will trigger a call to on_trigger_changed() */
set_trigger ( tr ) ;
2021-12-30 21:27:26 -05:00
/* event handling */
play_button - > Event . connect ( sigc : : mem_fun ( * this , & TriggerEntry : : play_button_event ) ) ;
name_button - > Event . connect ( sigc : : mem_fun ( * this , & TriggerEntry : : name_button_event ) ) ;
follow_button - > Event . connect ( sigc : : mem_fun ( * this , & TriggerEntry : : follow_button_event ) ) ;
2021-12-05 11:56:42 -05:00
/* watch for change in theme */
2021-12-17 10:32:52 -05:00
UIConfiguration : : instance ( ) . ParameterChanged . connect ( sigc : : mem_fun ( * this , & TriggerEntry : : ui_parameter_changed ) ) ;
set_default_colors ( ) ;
2021-08-05 18:20:56 -04:00
2021-12-30 21:27:26 -05:00
/* owner color changes (?) */
2021-12-24 16:13:36 -05:00
dynamic_cast < Stripable * > ( tref . box - > owner ( ) ) - > presentation_info ( ) . Change . connect ( owner_prop_connection , MISSING_INVALIDATOR , boost : : bind ( & TriggerEntry : : owner_prop_change , this , _1 ) , gui_context ( ) ) ;
2021-08-05 18:20:56 -04:00
2021-12-17 10:32:52 -05:00
selection_change ( ) ;
2021-07-27 22:39:55 -04:00
}
2021-07-27 19:08:31 -04:00
2021-07-27 22:39:55 -04:00
TriggerEntry : : ~ TriggerEntry ( )
{
2021-07-21 19:22:09 -04:00
}
2021-10-17 19:58:08 -04:00
void
2021-12-17 10:32:52 -05:00
TriggerEntry : : owner_prop_change ( PropertyChange const & pc )
2021-10-17 19:58:08 -04:00
{
if ( pc . contains ( Properties : : color ) ) {
owner_color_changed ( ) ;
}
}
void
TriggerEntry : : owner_color_changed ( )
{
2021-12-17 10:32:52 -05:00
// TODO
2021-10-17 19:58:08 -04:00
}
2021-11-10 19:51:04 -05:00
void
TriggerEntry : : selection_change ( )
{
2021-12-17 10:32:52 -05:00
if ( PublicEditor : : instance ( ) . get_selection ( ) . selected ( this ) ) {
name_button - > set_outline_color ( UIConfiguration : : instance ( ) . color ( " alert:red " ) ) ;
2021-11-10 19:51:04 -05:00
} else {
2021-12-17 10:32:52 -05:00
set_default_colors ( ) ;
2021-11-10 19:51:04 -05:00
}
2021-10-07 09:47:55 -04:00
}
2021-10-04 01:47:47 -04:00
void
TriggerEntry : : maybe_update ( )
{
2021-12-30 14:22:17 -05:00
if ( trigger ( ) - > active ( ) ) {
redraw ( ) ;
}
2021-10-04 01:47:47 -04:00
}
2021-08-07 20:55:05 -04:00
void
2021-12-17 10:32:52 -05:00
TriggerEntry : : _size_allocate ( ArdourCanvas : : Rect const & alloc )
2021-10-03 18:46:39 -04:00
{
Rectangle : : _size_allocate ( alloc ) ;
2021-12-17 10:32:52 -05:00
const Distance width = _rect . width ( ) ;
const Distance height = _rect . height ( ) ;
2021-10-03 18:46:39 -04:00
2021-12-05 11:56:42 -05:00
play_button - > set ( ArdourCanvas : : Rect ( 0 , 0 , height , height ) ) ;
2021-12-21 14:31:37 -05:00
name_button - > set ( ArdourCanvas : : Rect ( height , 0 , width - height , height ) ) ;
follow_button - > set ( ArdourCanvas : : Rect ( width - height , 0 , width , height ) ) ;
2021-10-03 18:46:39 -04:00
2021-12-17 10:32:52 -05:00
const double scale = UIConfiguration : : instance ( ) . get_ui_scale ( ) ;
2021-12-17 18:17:58 -05:00
_poly_margin = 2. * scale ;
_poly_size = height - 2 * _poly_margin ;
2021-10-03 18:46:39 -04:00
2021-12-27 10:20:15 -05:00
name_text - > size_allocate ( ArdourCanvas : : Rect ( 0 , 0 , width , height - _poly_margin * 2 ) ) ;
2021-12-17 10:32:52 -05:00
float tleft = height ; // make room for the play button
2021-12-27 10:20:15 -05:00
name_text - > set_position ( Duple ( tleft + _poly_margin , _poly_margin ) ) ; //@paul why do we need tleft here? isn't name_text a child of name_button?
name_text - > clamp_width ( width - height * 2 - _poly_margin * 3 ) ;
2021-10-17 19:58:34 -04:00
2021-12-17 10:32:52 -05:00
/* font scale may have changed. uiconfig 'embeds' the ui-scale in the font */
name_text - > set_font_description ( UIConfiguration : : instance ( ) . get_NormalFont ( ) ) ;
2021-12-05 11:56:42 -05:00
}
2021-12-17 10:32:52 -05:00
void
2021-12-21 14:31:37 -05:00
TriggerEntry : : draw_follow_icon ( Cairo : : RefPtr < Cairo : : Context > context , Trigger : : FollowAction icon , float size , float scale ) const
2021-12-17 10:32:52 -05:00
{
2021-12-27 17:49:22 -05:00
//in the case where there is a random follow-action, just put a "?"
if ( trigger ( ) - > follow_action_probability ( ) > 0 ) {
Glib : : RefPtr < Pango : : Layout > layout = Pango : : Layout : : create ( context ) ;
layout - > set_font_description ( UIConfiguration : : instance ( ) . get_SmallMonospaceFont ( ) ) ;
layout - > set_text ( " ? " ) ;
int tw , th ;
layout - > get_pixel_size ( tw , th ) ;
context - > move_to ( size / 2 , size / 2 ) ;
context - > rel_move_to ( - tw / 2 , - th / 2 ) ;
layout - > show_in_cairo_context ( context ) ;
return ;
}
2021-12-17 10:32:52 -05:00
context - > set_line_width ( 1 * scale ) ;
2021-12-14 21:35:28 -05:00
switch ( icon ) {
case Trigger : : Stop :
2021-12-17 10:32:52 -05:00
context - > rectangle ( 6 * scale , 6 * scale , size - 12 * scale , size - 12 * scale ) ;
context - > stroke ( ) ;
break ;
2021-12-14 21:35:28 -05:00
case Trigger : : Again :
2021-12-17 10:32:52 -05:00
context - > arc ( size / 2 , size / 2 , size * 0.20 , 60. * ( M_PI / 180.0 ) , 2 * M_PI ) ;
context - > stroke ( ) ;
context - > arc ( size / 2 + size * 0.2 , size / 2 , 1.5 * scale , 0 , 2 * M_PI ) ; // arrow head
context - > fill ( ) ;
break ;
2021-12-14 21:35:28 -05:00
case Trigger : : NextTrigger :
2021-12-17 10:32:52 -05:00
context - > move_to ( size / 2 , 3 * scale ) ;
context - > line_to ( size / 2 , size - 5 * scale ) ;
context - > stroke ( ) ;
context - > arc ( size / 2 , size - 5 * scale , 1.5 * scale , 0 , 2 * M_PI ) ; // arrow head
context - > fill ( ) ;
break ;
2021-12-14 21:35:28 -05:00
case Trigger : : PrevTrigger :
2021-12-17 10:32:52 -05:00
context - > move_to ( size / 2 , 5 * scale ) ;
context - > line_to ( size / 2 , size - 3 * scale ) ;
2022-01-02 19:10:18 -05:00
context - > stroke ( ) ;
context - > arc ( size / 2 , 5 * scale , 1.5 * scale , 0 , 2 * M_PI ) ; // arrow head
context - > fill ( ) ;
break ;
/* XXX Ben to add new icons for next two */
case Trigger : : ForwardTrigger :
context - > move_to ( size / 2 , 3 * scale ) ;
context - > line_to ( size / 2 , size - 5 * scale ) ;
context - > stroke ( ) ;
context - > arc ( size / 2 , size - 5 * scale , 1.5 * scale , 0 , 2 * M_PI ) ; // arrow head
context - > fill ( ) ;
break ;
case Trigger : : ReverseTrigger :
context - > move_to ( size / 2 , 5 * scale ) ;
context - > line_to ( size / 2 , size - 3 * scale ) ;
2021-12-17 10:32:52 -05:00
context - > stroke ( ) ;
context - > arc ( size / 2 , 5 * scale , 1.5 * scale , 0 , 2 * M_PI ) ; // arrow head
context - > fill ( ) ;
break ;
2021-12-14 21:35:28 -05:00
case Trigger : : QueuedTrigger : {
Glib : : RefPtr < Pango : : Layout > layout = Pango : : Layout : : create ( context ) ;
2021-12-17 10:32:52 -05:00
layout - > set_font_description ( UIConfiguration : : instance ( ) . get_SmallMonospaceFont ( ) ) ;
2021-12-14 21:35:28 -05:00
layout - > set_text ( icon = = Trigger : : AnyTrigger ? " & " : " @ " ) ;
2021-12-17 10:32:52 -05:00
int tw , th ;
layout - > get_pixel_size ( tw , th ) ;
context - > move_to ( size / 2 , size / 2 ) ;
context - > rel_move_to ( - tw / 2 , - th / 2 ) ;
2021-12-14 21:35:28 -05:00
layout - > show_in_cairo_context ( context ) ;
} break ;
case Trigger : : AnyTrigger : {
2021-12-27 09:38:47 -05:00
for ( int i = 0 ; i < 6 ; i + + ) {
Cairo : : Matrix m = context - > get_matrix ( ) ;
context - > translate ( size / 2 , size / 2 ) ;
context - > rotate ( i * M_PI / 3 ) ;
context - > move_to ( 0 , 0 ) ;
context - > line_to ( 0 , ( size / 2 ) - 4 * scale ) ;
context - > stroke ( ) ;
context - > set_matrix ( m ) ;
}
context - > set_identity_matrix ( ) ;
2021-12-14 21:35:28 -05:00
} break ;
case Trigger : : OtherTrigger : {
2021-12-27 09:38:47 -05:00
for ( int i = 0 ; i < 6 ; i + + ) {
Cairo : : Matrix m = context - > get_matrix ( ) ;
context - > translate ( size / 2 , size / 2 ) ;
context - > rotate ( i * M_PI / 3 ) ;
context - > move_to ( 0 , 2 * scale ) ;
context - > line_to ( 0 , ( size / 2 ) - 4 * scale ) ;
context - > stroke ( ) ;
context - > set_matrix ( m ) ;
}
context - > set_identity_matrix ( ) ;
2021-12-14 21:35:28 -05:00
} break ;
2021-12-23 23:29:37 -05:00
case Trigger : : None :
2021-12-14 21:35:28 -05:00
default :
2021-12-17 10:32:52 -05:00
break ;
2021-12-14 21:35:28 -05:00
}
}
2021-12-21 14:31:37 -05:00
void
2021-12-21 15:55:08 -05:00
TriggerEntry : : draw_launch_icon ( Cairo : : RefPtr < Cairo : : Context > context , float sz , float scale ) const
2021-12-21 14:31:37 -05:00
{
context - > set_line_width ( 1 * scale ) ;
2021-12-21 15:55:08 -05:00
float margin = 4 * scale ;
float size = sz - 2 * margin ;
2021-12-21 19:55:48 -05:00
if ( trigger ( ) - > active ( ) ) {
if ( trigger ( ) - > launch_style ( ) = = Trigger : : Toggle ) {
2021-12-21 14:31:37 -05:00
//clicking again will Stop this clip
set_source_rgba ( context , UIConfiguration : : instance ( ) . color ( " neutral:foreground " ) ) ;
2021-12-21 15:55:08 -05:00
context - > move_to ( margin , margin ) ;
context - > rel_line_to ( size , 0 ) ;
context - > rel_line_to ( 0 , size ) ;
context - > rel_line_to ( - size , 0 ) ;
context - > rel_line_to ( 0 , - size ) ;
2021-12-21 14:31:37 -05:00
context - > fill ( ) ;
return ; //done
} else {
//actively playing; draw a filled play triangle
set_source_rgba ( context , UIConfiguration : : instance ( ) . color ( " neutral:foreground " ) ) ;
2021-12-21 15:55:08 -05:00
context - > move_to ( margin , margin ) ;
context - > rel_line_to ( 0 , size ) ;
context - > rel_line_to ( size , - size / 2 ) ;
2021-12-21 14:31:37 -05:00
context - > fill ( ) ;
return ; //done
}
}
set_source_rgba ( context , UIConfiguration : : instance ( ) . color ( " neutral:midground " ) ) ;
2021-12-21 19:55:48 -05:00
if ( ! trigger ( ) - > region ( ) ) {
2021-12-21 14:31:37 -05:00
//no content in this slot, it is only a Stop button
2021-12-21 15:55:08 -05:00
context - > move_to ( margin , margin ) ;
context - > rel_line_to ( size , 0 ) ;
context - > rel_line_to ( 0 , size ) ;
context - > rel_line_to ( - size , 0 ) ;
context - > rel_line_to ( 0 , - size ) ;
2021-12-21 14:31:37 -05:00
context - > stroke ( ) ;
return ; //done
}
2021-12-21 19:55:48 -05:00
switch ( trigger ( ) - > launch_style ( ) ) {
2021-12-21 14:31:37 -05:00
case Trigger : : Toggle :
case Trigger : : OneShot :
2021-12-21 15:55:08 -05:00
context - > move_to ( margin , margin ) ;
context - > rel_line_to ( 0 , size ) ;
context - > rel_line_to ( size , - size / 2 ) ;
context - > line_to ( margin , margin ) ;
2021-12-21 14:31:37 -05:00
context - > stroke ( ) ;
break ;
2022-01-03 19:45:13 -05:00
/* XXX ben this needs a new icon */
case Trigger : : ReTrigger :
context - > move_to ( margin , margin ) ;
context - > rel_line_to ( 0 , size ) ;
context - > rel_line_to ( size , - size / 2 ) ;
context - > line_to ( margin , margin ) ;
context - > stroke ( ) ;
break ;
2021-12-21 14:31:37 -05:00
case Trigger : : Gate : //diamond shape
2021-12-21 15:55:08 -05:00
context - > move_to ( margin + size / 2 , margin ) ;
context - > rel_line_to ( size / 2 , size / 2 ) ;
context - > rel_line_to ( - size / 2 , size / 2 ) ;
context - > rel_line_to ( - size / 2 , - size / 2 ) ;
context - > rel_line_to ( size / 2 , - size / 2 ) ;
2021-12-21 14:31:37 -05:00
context - > stroke ( ) ;
break ;
case Trigger : : Repeat : //'stutter' shape
2021-12-22 13:29:28 -05:00
set_source_rgba ( context , HSV ( UIConfiguration : : instance ( ) . color ( " neutral:midground " ) ) . lighter ( 0.25 ) . color ( ) ) ; //stutter shape needs to be brighter to maintain balance
2021-12-21 14:31:37 -05:00
context - > set_line_width ( 1 * scale ) ;
2021-12-21 15:55:08 -05:00
context - > move_to ( margin , margin ) ;
context - > rel_line_to ( 0 , size ) ;
2021-12-21 14:31:37 -05:00
2021-12-21 15:55:08 -05:00
context - > move_to ( margin + scale * 3 , margin + scale * 2 ) ;
context - > rel_line_to ( 0 , size - scale * 4 ) ;
2021-12-21 14:31:37 -05:00
2021-12-21 15:55:08 -05:00
context - > move_to ( margin + scale * 6 , margin + scale * 3 ) ;
context - > rel_line_to ( 0 , size - scale * 6 ) ;
2021-12-21 14:31:37 -05:00
context - > stroke ( ) ;
break ;
default :
break ;
}
context - > set_line_width ( 1 ) ;
}
2021-12-05 11:56:42 -05:00
void
2021-12-17 10:32:52 -05:00
TriggerEntry : : render ( ArdourCanvas : : Rect const & area , Cairo : : RefPtr < Cairo : : Context > context ) const
2021-12-05 11:56:42 -05:00
{
2021-12-17 10:32:52 -05:00
Rectangle : : render ( area , context ) ;
2021-12-12 12:20:11 -05:00
/* Note that item_to_window() already takes _position into account (as
part of item_to_canvas ( )
*/
2021-12-17 10:32:52 -05:00
ArdourCanvas : : Rect self ( item_to_window ( _rect ) ) ;
2021-12-15 11:32:58 -05:00
const ArdourCanvas : : Rect draw = self . intersection ( area ) ;
2021-12-12 12:20:11 -05:00
if ( ! draw ) {
return ;
}
2021-12-17 10:32:52 -05:00
float width = _rect . width ( ) ;
float height = _rect . height ( ) ;
2021-12-12 12:20:11 -05:00
2021-12-17 10:32:52 -05:00
const double scale = UIConfiguration : : instance ( ) . get_ui_scale ( ) ;
2021-12-12 12:20:11 -05:00
if ( _fill & & ! _transparent ) {
setup_fill_context ( context ) ;
2021-12-17 10:32:52 -05:00
context - > rectangle ( draw . x0 , draw . y0 , draw . width ( ) , draw . height ( ) ) ;
2021-12-12 12:20:11 -05:00
context - > fill ( ) ;
}
render_children ( area , context ) ;
2021-12-21 15:38:22 -05:00
if ( trigger ( ) - > scene_isolated ( ) ) {
2021-12-17 18:17:58 -05:00
/* left shadow */
context - > set_identity_matrix ( ) ;
context - > translate ( self . x0 , self . y0 - 0.5 ) ;
Cairo : : RefPtr < Cairo : : LinearGradient > l_shadow = Cairo : : LinearGradient : : create ( 0 , 0 , scale * 12 , 0 ) ;
l_shadow - > add_color_stop_rgba ( 0.0 , 0.0 , 0.0 , 0.0 , 0.8 ) ;
l_shadow - > add_color_stop_rgba ( 1.0 , 0.0 , 0.0 , 0.0 , 0.0 ) ;
2021-12-17 10:45:34 -05:00
context - > set_source ( l_shadow ) ;
2021-12-17 18:17:58 -05:00
context - > rectangle ( 0 , 0 , scale * 12 , height ) ;
2021-12-17 10:45:34 -05:00
context - > fill ( ) ;
2021-12-17 18:17:58 -05:00
context - > set_identity_matrix ( ) ;
2021-12-17 10:45:34 -05:00
}
2021-12-21 15:38:22 -05:00
if ( tref . slot = = 1 ) {
2021-12-17 18:17:58 -05:00
/* drop-shadow at top */
Cairo : : RefPtr < Cairo : : LinearGradient > drop_shadow_pattern = Cairo : : LinearGradient : : create ( 0.0 , 0.0 , 0.0 , 6 * scale ) ;
drop_shadow_pattern - > add_color_stop_rgba ( 0 , 0 , 0 , 0 , 0.7 ) ;
drop_shadow_pattern - > add_color_stop_rgba ( 1 , 0 , 0 , 0 , 0.0 ) ;
2021-12-17 09:18:06 -05:00
context - > set_source ( drop_shadow_pattern ) ;
2021-12-17 10:32:52 -05:00
context - > rectangle ( 0 , 0 , width , 6 * scale ) ;
2021-12-12 12:20:11 -05:00
context - > fill ( ) ;
}
2021-12-21 14:31:37 -05:00
/* launch icon */
{
context - > set_identity_matrix ( ) ;
context - > translate ( self . x0 , self . y0 - 0.5 ) ;
context - > translate ( 0 , 0 ) ; // left side of the widget
draw_launch_icon ( context , height , scale ) ;
context - > set_identity_matrix ( ) ;
}
2021-12-17 10:32:52 -05:00
/* follow-action icon */
2021-12-27 17:49:22 -05:00
if ( trigger ( ) - > region ( ) & & trigger ( ) - > use_follow ( ) ) {
2021-12-17 10:32:52 -05:00
context - > set_identity_matrix ( ) ;
context - > translate ( self . x0 , self . y0 - 0.5 ) ;
context - > translate ( width - height , 0 ) ; // right side of the widget
set_source_rgba ( context , UIConfiguration : : instance ( ) . color ( " neutral:midground " ) ) ;
2021-12-21 15:38:22 -05:00
draw_follow_icon ( context , trigger ( ) - > follow_action ( 0 ) , height , scale ) ;
2021-12-17 10:32:52 -05:00
context - > set_identity_matrix ( ) ;
2021-12-14 21:35:28 -05:00
}
2021-10-03 18:46:39 -04:00
}
2021-08-05 18:20:56 -04:00
void
2021-12-30 13:10:50 -05:00
TriggerEntry : : on_trigger_changed ( PropertyChange const & change )
2021-08-05 18:20:56 -04:00
{
if ( change . contains ( ARDOUR : : Properties : : name ) ) {
2021-12-21 15:38:22 -05:00
if ( trigger ( ) - > region ( ) ) {
name_text - > set ( short_version ( trigger ( ) - > name ( ) , 16 ) ) ;
2021-08-05 18:20:56 -04:00
} else {
2021-08-07 20:55:05 -04:00
name_text - > set ( " " ) ;
}
}
2021-12-27 12:40:39 -05:00
name_text - > set_color ( trigger ( ) - > color ( ) ) ;
2021-12-17 18:17:58 -05:00
PropertyChange interesting_stuff ;
2021-12-21 14:31:37 -05:00
interesting_stuff . add ( ARDOUR : : Properties : : name ) ;
2021-12-27 12:40:39 -05:00
interesting_stuff . add ( ARDOUR : : Properties : : color ) ;
2021-12-21 14:31:37 -05:00
interesting_stuff . add ( ARDOUR : : Properties : : launch_style ) ;
2021-12-17 18:17:58 -05:00
interesting_stuff . add ( ARDOUR : : Properties : : follow_action0 ) ;
2021-12-27 17:49:22 -05:00
interesting_stuff . add ( ARDOUR : : Properties : : follow_action1 ) ;
interesting_stuff . add ( ARDOUR : : Properties : : use_follow ) ;
interesting_stuff . add ( ARDOUR : : Properties : : follow_action_probability ) ;
interesting_stuff . add ( ARDOUR : : Properties : : follow_count ) ;
2021-12-17 18:17:58 -05:00
interesting_stuff . add ( ARDOUR : : Properties : : isolated ) ;
2021-12-21 14:31:37 -05:00
interesting_stuff . add ( ARDOUR : : Properties : : running ) ;
2021-12-14 21:35:28 -05:00
2021-12-17 18:17:58 -05:00
if ( change . contains ( interesting_stuff ) ) {
redraw ( ) ;
2021-12-17 10:45:34 -05:00
}
2021-08-05 18:20:56 -04:00
}
2021-12-05 11:56:42 -05:00
void
TriggerEntry : : set_default_colors ( )
{
2021-12-17 10:32:52 -05:00
set_fill_color ( UIConfiguration : : instance ( ) . color ( " theme:bg " ) ) ;
play_button - > set_fill_color ( UIConfiguration : : instance ( ) . color ( " theme:bg " ) ) ;
name_button - > set_fill_color ( UIConfiguration : : instance ( ) . color ( " theme:bg " ) ) ;
name_button - > set_outline_color ( UIConfiguration : : instance ( ) . color ( " theme:bg " ) ) ;
2021-12-21 14:31:37 -05:00
follow_button - > set_fill_color ( UIConfiguration : : instance ( ) . color ( " theme:bg " ) ) ;
2021-12-21 15:38:22 -05:00
if ( ( tref . slot / 2 ) % 2 = = 0 ) {
2021-12-17 10:32:52 -05:00
set_fill_color ( HSV ( fill_color ( ) ) . darker ( 0.15 ) . color ( ) ) ;
play_button - > set_fill_color ( HSV ( fill_color ( ) ) . darker ( 0.15 ) . color ( ) ) ;
name_button - > set_fill_color ( HSV ( fill_color ( ) ) . darker ( 0.15 ) . color ( ) ) ;
name_button - > set_outline_color ( HSV ( fill_color ( ) ) . darker ( 0.15 ) . color ( ) ) ;
2021-12-21 14:31:37 -05:00
follow_button - > set_fill_color ( HSV ( fill_color ( ) ) . darker ( 0.15 ) . color ( ) ) ;
2021-12-17 10:32:52 -05:00
}
name_text - > set_fill_color ( UIConfiguration : : instance ( ) . color ( " neutral:midground " ) ) ;
2021-12-05 11:56:42 -05:00
/*preserve selection border*/
2021-12-17 10:32:52 -05:00
if ( PublicEditor : : instance ( ) . get_selection ( ) . selected ( this ) ) {
name_button - > set_outline_color ( UIConfiguration : : instance ( ) . color ( " alert:red " ) ) ;
2021-12-05 11:56:42 -05:00
}
}
void
TriggerEntry : : ui_parameter_changed ( std : : string const & p )
{
if ( p = = " color-file " ) {
2021-12-17 10:32:52 -05:00
set_default_colors ( ) ;
2021-12-05 11:56:42 -05:00
}
}
2021-08-05 17:04:02 -04:00
bool
2021-12-30 21:27:26 -05:00
TriggerEntry : : name_button_event ( GdkEvent * ev )
2021-08-05 17:04:02 -04:00
{
switch ( ev - > type ) {
2021-12-17 10:32:52 -05:00
case GDK_ENTER_NOTIFY :
if ( ev - > crossing . detail ! = GDK_NOTIFY_INFERIOR ) {
2021-12-30 21:27:26 -05:00
set_default_colors ( ) ;
name_button - > set_fill_color ( HSV ( fill_color ( ) ) . lighter ( 0.15 ) . color ( ) ) ;
name_button - > set_outline_color ( HSV ( fill_color ( ) ) . lighter ( 0.15 ) . color ( ) ) ;
follow_button - > set_fill_color ( HSV ( fill_color ( ) ) . lighter ( 0.15 ) . color ( ) ) ;
play_button - > set_fill_color ( HSV ( fill_color ( ) ) . lighter ( 0.15 ) . color ( ) ) ;
2021-12-21 15:55:08 -05:00
/*preserve selection border*/
2021-12-30 21:27:26 -05:00
if ( PublicEditor : : instance ( ) . get_selection ( ) . selected ( this ) ) {
name_button - > set_outline_color ( UIConfiguration : : instance ( ) . color ( " alert:red " ) ) ;
2021-12-21 15:55:08 -05:00
}
2021-12-17 10:32:52 -05:00
}
break ;
case GDK_LEAVE_NOTIFY :
if ( ev - > crossing . detail ! = GDK_NOTIFY_INFERIOR ) {
2021-12-30 21:27:26 -05:00
set_default_colors ( ) ;
2021-12-17 10:32:52 -05:00
}
break ;
case GDK_BUTTON_PRESS :
2021-12-30 21:27:26 -05:00
PublicEditor : : instance ( ) . get_selection ( ) . set ( this ) ;
2021-12-21 16:20:05 -05:00
/* a side-effect of selection-change is that the slot's color is reset. retain the "entered-color" here: */
2021-12-30 21:27:26 -05:00
name_button - > set_fill_color ( HSV ( fill_color ( ) ) . lighter ( 0.15 ) . color ( ) ) ;
name_button - > set_outline_color ( UIConfiguration : : instance ( ) . color ( " alert:red " ) ) ;
follow_button - > set_fill_color ( HSV ( fill_color ( ) ) . lighter ( 0.15 ) . color ( ) ) ;
2021-12-17 10:32:52 -05:00
break ;
case GDK_2BUTTON_PRESS :
2021-12-30 21:27:26 -05:00
edit_trigger ( ) ;
2021-08-05 17:04:02 -04:00
return true ;
2021-12-17 10:32:52 -05:00
case GDK_BUTTON_RELEASE :
switch ( ev - > button . button ) {
case 3 :
2021-12-30 21:27:26 -05:00
context_menu ( ) ;
2021-12-17 10:32:52 -05:00
return true ;
default :
break ;
}
break ;
2021-08-05 17:04:02 -04:00
default :
break ;
}
return false ;
}
2021-07-27 22:39:55 -04:00
bool
2021-12-30 21:27:26 -05:00
TriggerEntry : : play_button_event ( GdkEvent * ev )
2021-07-27 22:39:55 -04:00
{
2021-12-30 21:27:26 -05:00
if ( ! trigger ( ) - > region ( ) ) {
2021-12-21 14:31:37 -05:00
/* empty slot; this is just a stop button */
2021-08-06 23:27:38 -04:00
switch ( ev - > type ) {
2021-12-17 10:32:52 -05:00
case GDK_BUTTON_PRESS :
if ( ev - > button . button = = 1 ) {
2021-12-27 17:48:13 -05:00
if ( Keyboard : : modifier_state_equals ( ev - > button . state , Keyboard : : PrimaryModifier ) ) {
2021-12-30 21:27:26 -05:00
trigger ( ) - > box ( ) . stop_all_immediately ( ) ;
2021-12-27 17:48:13 -05:00
} else {
2021-12-30 21:27:26 -05:00
trigger ( ) - > box ( ) . stop_all_quantized ( ) ;
2021-12-27 17:48:13 -05:00
}
2021-12-17 10:32:52 -05:00
return true ;
}
2021-12-17 18:17:58 -05:00
break ;
2021-12-17 10:32:52 -05:00
default :
break ;
2021-08-06 23:27:38 -04:00
}
}
2021-07-27 22:39:55 -04:00
switch ( ev - > type ) {
2021-12-17 10:32:52 -05:00
case GDK_BUTTON_PRESS :
switch ( ev - > button . button ) {
case 1 :
2021-12-30 21:27:26 -05:00
trigger ( ) - > bang ( ) ;
2021-12-17 10:32:52 -05:00
return true ;
default :
break ;
}
2021-08-05 17:04:02 -04:00
break ;
2021-12-17 10:32:52 -05:00
case GDK_BUTTON_RELEASE :
switch ( ev - > button . button ) {
case 1 :
2021-12-30 21:27:26 -05:00
if ( trigger ( ) - > launch_style ( ) = = Trigger : : Gate | |
trigger ( ) - > launch_style ( ) = = Trigger : : Repeat ) {
trigger ( ) - > unbang ( ) ;
2021-12-17 10:32:52 -05:00
}
break ;
2021-12-21 14:31:37 -05:00
case 3 :
2021-12-30 21:27:26 -05:00
launch_context_menu ( ) ;
2021-12-21 14:31:37 -05:00
return true ;
2021-12-17 10:32:52 -05:00
default :
break ;
}
break ;
case GDK_ENTER_NOTIFY :
if ( ev - > crossing . detail ! = GDK_NOTIFY_INFERIOR ) {
2021-12-30 21:27:26 -05:00
set_default_colors ( ) ;
play_button - > set_fill_color ( HSV ( fill_color ( ) ) . lighter ( 0.15 ) . color ( ) ) ;
2021-12-17 10:32:52 -05:00
}
break ;
case GDK_LEAVE_NOTIFY :
if ( ev - > crossing . detail ! = GDK_NOTIFY_INFERIOR ) {
2021-12-30 21:27:26 -05:00
set_default_colors ( ) ;
2021-08-05 17:04:02 -04:00
}
break ;
default :
break ;
2021-07-27 22:39:55 -04:00
}
return false ;
}
2021-12-21 14:31:37 -05:00
bool
2021-12-30 21:27:26 -05:00
TriggerEntry : : follow_button_event ( GdkEvent * ev )
2021-12-21 14:31:37 -05:00
{
switch ( ev - > type ) {
case GDK_BUTTON_RELEASE :
switch ( ev - > button . button ) {
case 3 :
2021-12-30 21:27:26 -05:00
follow_context_menu ( ) ;
2021-12-21 14:31:37 -05:00
return true ;
default :
break ;
}
break ;
case GDK_ENTER_NOTIFY :
if ( ev - > crossing . detail ! = GDK_NOTIFY_INFERIOR ) {
2021-12-30 21:27:26 -05:00
set_default_colors ( ) ;
follow_button - > set_fill_color ( HSV ( fill_color ( ) ) . lighter ( 0.15 ) . color ( ) ) ;
2021-12-21 14:31:37 -05:00
}
break ;
case GDK_LEAVE_NOTIFY :
if ( ev - > crossing . detail ! = GDK_NOTIFY_INFERIOR ) {
2021-12-30 21:27:26 -05:00
set_default_colors ( ) ;
2021-12-21 14:31:37 -05:00
}
break ;
default :
break ;
}
return false ;
}
2021-12-30 21:27:26 -05:00
/* ***************************************************** */
TriggerBoxUI : : TriggerBoxUI ( ArdourCanvas : : Item * parent , TriggerBox & tb )
: Rectangle ( parent )
, _triggerbox ( tb )
{
set_layout_sensitive ( true ) ; // why???
set_fill_color ( UIConfiguration : : instance ( ) . color ( X_ ( " theme:bg " ) ) ) ;
set_fill ( true ) ;
build ( ) ;
2021-08-05 14:11:19 -04:00
2021-12-30 21:27:26 -05:00
_selection_connection = PublicEditor : : instance ( ) . get_selection ( ) . TriggersChanged . connect ( sigc : : mem_fun ( * this , & TriggerBoxUI : : selection_changed ) ) ;
std : : vector < Gtk : : TargetEntry > target_table ;
target_table . push_back ( Gtk : : TargetEntry ( " regions " ) ) ;
target_table . push_back ( Gtk : : TargetEntry ( " text/uri-list " ) ) ;
target_table . push_back ( Gtk : : TargetEntry ( " text/plain " ) ) ;
target_table . push_back ( Gtk : : TargetEntry ( " application/x-rootwin-drop " ) ) ;
GtkCanvas * gtkcanvas = static_cast < GtkCanvas * > ( canvas ( ) ) ;
assert ( gtkcanvas ) ;
gtkcanvas - > drag_dest_set ( target_table ) ;
gtkcanvas - > signal_drag_motion ( ) . connect ( sigc : : mem_fun ( * this , & TriggerBoxUI : : drag_motion ) ) ;
gtkcanvas - > signal_drag_leave ( ) . connect ( sigc : : mem_fun ( * this , & TriggerBoxUI : : drag_leave ) ) ;
gtkcanvas - > signal_drag_data_received ( ) . connect ( sigc : : mem_fun ( * this , & TriggerBoxUI : : drag_data_received ) ) ;
}
2021-08-05 14:11:19 -04:00
2021-12-30 21:27:26 -05:00
TriggerBoxUI : : ~ TriggerBoxUI ( )
{
/* sigc connection's are not scoped (i.e. they do not disconnect the
functor from the signal when they are destroyed ) .
*/
_selection_connection . disconnect ( ) ;
_update_connection . disconnect ( ) ;
2021-08-05 14:11:19 -04:00
}
void
2021-12-30 21:27:26 -05:00
TriggerBoxUI : : selection_changed ( )
2021-08-05 14:11:19 -04:00
{
2021-12-30 21:27:26 -05:00
for ( auto & slot : _slots ) {
slot - > selection_change ( ) ;
}
}
2021-08-05 14:11:19 -04:00
2021-12-30 21:27:26 -05:00
void
TriggerBoxUI : : build ( )
{
TriggerPtr t ;
uint64_t n = 0 ;
// clear_items (true);
_slots . clear ( ) ;
while ( true ) {
t = _triggerbox . trigger ( n ) ;
if ( ! t ) {
2021-12-17 10:32:52 -05:00
break ;
2021-12-30 21:27:26 -05:00
}
TriggerEntry * te = new TriggerEntry ( this , TriggerReference ( _triggerbox , n ) ) ;
_slots . push_back ( te ) ;
2021-08-05 14:11:19 -04:00
2021-12-30 21:27:26 -05:00
#if 0
te - > Event . connect ( sigc : : bind ( sigc : : mem_fun ( * this , & TriggerBoxUI : : event ) , n ) ) ;
# endif
2021-08-05 14:11:19 -04:00
2021-10-11 19:58:51 -04:00
+ + n ;
}
2021-08-05 14:11:19 -04:00
}
2021-12-30 21:27:26 -05:00
void
TriggerBoxUI : : _size_allocate ( ArdourCanvas : : Rect const & alloc )
{
Rectangle : : _size_allocate ( alloc ) ;
const float width = alloc . width ( ) ;
const float height = alloc . height ( ) ;
const float slot_h = height / TriggerBox : : default_triggers_per_box ; // TODO
float ypos = 0 ;
for ( auto & slot : _slots ) {
slot - > size_allocate ( ArdourCanvas : : Rect ( 0 , 0 , width , slot_h ) ) ;
slot - > set_position ( Duple ( 0 , ypos ) ) ;
ypos + = slot_h ;
slot - > show ( ) ;
}
}
2021-12-13 18:45:16 -05:00
uint64_t
TriggerBoxUI : : slot_at_y ( int y ) const
2021-12-13 16:51:16 -05:00
{
2021-12-13 18:45:16 -05:00
uint64_t n = 0 ;
2021-12-13 17:05:03 -05:00
for ( auto & slot : _slots ) {
if ( slot - > height ( ) < y ) {
+ + n ;
y - = slot - > height ( ) ;
}
}
2021-12-13 18:45:16 -05:00
return n ;
}
bool
2021-12-17 10:32:52 -05:00
TriggerBoxUI : : drag_motion ( Glib : : RefPtr < Gdk : : DragContext > const & context , int , int y , guint time )
2021-12-13 18:45:16 -05:00
{
2021-12-17 10:32:52 -05:00
bool can_drop = true ;
uint64_t n = slot_at_y ( y ) ;
2021-12-13 18:45:16 -05:00
if ( n > = _slots . size ( ) ) {
assert ( 0 ) ;
can_drop = false ;
}
if ( can_drop ) {
2021-12-17 10:32:52 -05:00
context - > drag_status ( Gdk : : ACTION_COPY , time ) ;
2021-12-13 18:45:16 -05:00
/* prelight */
GdkEventCrossing ev ;
ev . detail = GDK_NOTIFY_ANCESTOR ;
for ( size_t i = 0 ; i < _slots . size ( ) ; + + i ) {
ev . type = ( i = = n ) ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY ;
2021-12-30 21:27:26 -05:00
_slots [ i ] - > name_button_event ( ( GdkEvent * ) & ev ) ;
2021-12-13 18:45:16 -05:00
}
return true ;
} else {
context - > drag_status ( Gdk : : DragAction ( 0 ) , time ) ;
return false ;
}
}
void
2021-12-17 10:32:52 -05:00
TriggerBoxUI : : drag_leave ( Glib : : RefPtr < Gdk : : DragContext > const & , guint )
2021-12-13 18:45:16 -05:00
{
GdkEventCrossing ev ;
2021-12-17 10:32:52 -05:00
ev . type = GDK_LEAVE_NOTIFY ;
2021-12-13 18:45:16 -05:00
ev . detail = GDK_NOTIFY_ANCESTOR ;
for ( size_t i = 0 ; i < _slots . size ( ) ; + + i ) {
2021-12-30 21:27:26 -05:00
_slots [ i ] - > name_button_event ( ( GdkEvent * ) & ev ) ;
2021-12-13 18:45:16 -05:00
}
}
2021-12-13 17:05:03 -05:00
2021-12-13 18:45:16 -05:00
void
TriggerBoxUI : : drag_data_received ( Glib : : RefPtr < Gdk : : DragContext > const & context , int /*x*/ , int y , Gtk : : SelectionData const & data , guint /*info*/ , guint time )
{
uint64_t n = slot_at_y ( y ) ;
if ( n > = _slots . size ( ) ) {
context - > drag_finish ( false , false , time ) ;
return ;
}
2021-12-17 10:32:52 -05:00
if ( data . get_target ( ) = = X_ ( " regions " ) ) {
boost : : shared_ptr < Region > region = PublicEditor : : instance ( ) . get_dragged_region_from_sidebar ( ) ;
2021-12-13 16:51:16 -05:00
if ( region ) {
2021-12-13 17:05:03 -05:00
_triggerbox . set_from_selection ( n , region ) ;
2021-12-13 16:51:16 -05:00
context - > drag_finish ( true , false , time ) ;
2021-12-14 15:34:21 -05:00
} else {
context - > drag_finish ( false , false , time ) ;
2021-12-13 16:51:16 -05:00
}
return ;
}
std : : vector < std : : string > paths ;
if ( ARDOUR_UI_UTILS : : convert_drop_to_paths ( paths , data ) ) {
for ( std : : vector < std : : string > : : iterator s = paths . begin ( ) ; s ! = paths . end ( ) ; + + s ) {
/* this will do nothing if n is too large */
_triggerbox . set_from_path ( n , * s ) ;
+ + n ;
}
}
context - > drag_finish ( true , false , time ) ;
}
2021-10-24 11:25:49 -04:00
void
2021-10-04 01:47:47 -04:00
TriggerBoxUI : : start_updating ( )
{
2021-12-17 10:32:52 -05:00
_update_connection = Timers : : rapid_connect ( sigc : : mem_fun ( * this , & TriggerBoxUI : : rapid_update ) ) ;
2021-10-04 01:47:47 -04:00
}
void
TriggerBoxUI : : stop_updating ( )
{
2021-12-17 10:32:52 -05:00
_update_connection . disconnect ( ) ;
2021-10-04 01:47:47 -04:00
}
void
TriggerBoxUI : : rapid_update ( )
{
2021-12-17 10:32:52 -05:00
for ( auto & slot : _slots ) {
2021-11-10 19:51:04 -05:00
slot - > maybe_update ( ) ;
2021-10-04 01:47:47 -04:00
}
}
2021-12-30 13:10:50 -05:00
/* ********************************************** */
2021-12-17 10:32:52 -05:00
TriggerBoxWidget : : TriggerBoxWidget ( float w , float h )
: FittedCanvasWidget ( w , h )
, ui ( 0 )
2021-07-21 19:22:09 -04:00
{
2021-12-17 10:32:52 -05:00
set_background_color ( UIConfiguration : : instance ( ) . color ( X_ ( " theme:bg " ) ) ) ;
2021-07-21 19:22:09 -04:00
}
2021-07-22 12:33:47 -04:00
2021-10-04 01:47:47 -04:00
void
2021-12-16 17:15:14 -05:00
TriggerBoxWidget : : set_triggerbox ( TriggerBox * tb )
2021-10-04 01:47:47 -04:00
{
2021-12-16 17:15:14 -05:00
if ( ui ) {
2021-12-17 10:32:52 -05:00
root ( ) - > remove ( ui ) ;
2021-12-16 17:15:14 -05:00
delete ui ;
ui = 0 ;
}
2021-10-04 01:47:47 -04:00
2021-12-16 17:15:14 -05:00
if ( ! tb ) {
return ;
}
2021-12-17 10:32:52 -05:00
ui = new TriggerBoxUI ( root ( ) , * tb ) ;
2021-12-16 20:55:05 -05:00
repeat_size_allocation ( ) ;
2021-12-16 17:15:14 -05:00
2021-12-17 10:32:52 -05:00
if ( is_mapped ( ) ) {
2021-12-16 17:15:14 -05:00
ui - > start_updating ( ) ;
}
2021-10-04 01:47:47 -04:00
}
2021-12-16 17:09:20 -05:00
void
TriggerBoxWidget : : on_map ( )
2021-07-22 12:33:47 -04:00
{
2021-12-16 17:09:20 -05:00
FittedCanvasWidget : : on_map ( ) ;
2021-08-05 17:04:02 -04:00
2021-12-16 17:09:20 -05:00
if ( ui ) {
ui - > start_updating ( ) ;
}
2021-08-05 17:04:02 -04:00
}
2021-12-16 17:09:20 -05:00
void
TriggerBoxWidget : : on_unmap ( )
2021-08-05 17:04:02 -04:00
{
2021-12-16 17:09:20 -05:00
FittedCanvasWidget : : on_unmap ( ) ;
if ( ui ) {
ui - > stop_updating ( ) ;
}
2021-08-05 17:04:02 -04:00
}