2012-05-31 23:14:03 +00:00
/*
2019-08-02 23:26:43 +02:00
* Copyright ( C ) 2012 - 2017 Robin Gareus < robin @ gareus . org >
* Copyright ( C ) 2013 - 2017 Paul Davis < paul @ linuxaudiosystems . com >
* Copyright ( C ) 2015 Colin Fletcher < colin . m . fletcher @ googlemail . com >
* Copyright ( C ) 2015 Tim Mayberry < mojofunk @ gmail . com >
* Copyright ( C ) 2016 Nick Mainsbridge < mainsbridge @ gmail . 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 .
*/
2012-05-31 23:14:03 +00:00
2017-11-22 22:10:37 +01:00
# include "pbd/unwind.h"
2021-11-13 17:49:03 -07:00
# include "ardour/audioengine.h"
# include "ardour/session.h"
2016-12-11 17:24:30 +01:00
# include "ardour/tempo.h"
2014-12-22 13:39:41 -05:00
2025-01-07 18:28:31 +01:00
# include "gtkmm2ext/colors.h"
2016-12-11 17:24:30 +01:00
# include "actions.h"
# include "main_clock.h"
# include "public_editor.h"
2024-09-27 10:10:10 -05:00
# include "ardour_ui.h"
2015-01-02 21:44:54 +07:00
2016-07-14 14:44:52 -04:00
# include "pbd/i18n.h"
2012-05-31 23:14:03 +00:00
using namespace Gtk ;
2017-11-22 22:10:37 +01:00
using namespace ARDOUR ;
2024-09-27 10:10:10 -05:00
using namespace std ;
2012-05-31 23:14:03 +00:00
MainClock : : MainClock (
const std : : string & clock_name ,
2024-09-27 10:10:10 -05:00
const std : : string & widget_name ,
ClockDisposition d
2012-05-31 23:14:03 +00:00
)
2015-02-15 12:56:25 +00:00
: AudioClock ( clock_name , false , widget_name , true , true , false , true )
2024-09-27 10:10:10 -05:00
, _disposition ( d )
2017-11-22 22:10:37 +01:00
, _suspend_delta_mode_signal ( false )
2022-11-06 19:12:20 +01:00
, _widget_name ( widget_name )
2025-01-07 18:28:31 +01:00
, _delta_mode ( NoDelta )
, _layout_width ( 0 )
, _layout_height ( 0 )
2012-05-31 23:14:03 +00:00
{
2024-09-27 10:10:10 -05:00
ValueChanged . connect ( sigc : : mem_fun ( * this , & MainClock : : clock_value_changed ) ) ;
UIConfiguration : : instance ( ) . ParameterChanged . connect ( sigc : : mem_fun ( * this , & MainClock : : parameter_changed ) ) ;
std : : function < void ( std : : string ) > pc ( std : : bind ( & MainClock : : parameter_changed , this , _1 ) ) ;
UIConfiguration : : instance ( ) . map_parameters ( pc ) ;
2025-01-07 18:28:31 +01:00
_layout = Pango : : Layout : : create ( get_pango_context ( ) ) ;
_layout - > set_text ( " \u0394 " ) ;
2016-12-11 17:24:30 +01:00
}
2012-05-31 23:14:03 +00:00
2016-12-11 17:24:30 +01:00
void
MainClock : : set_session ( ARDOUR : : Session * s )
{
AudioClock : : set_session ( s ) ;
_left_btn . set_related_action ( ActionManager : : get_action ( X_ ( " Editor " ) , X_ ( " edit-current-tempo " ) ) ) ;
_right_btn . set_related_action ( ActionManager : : get_action ( X_ ( " Editor " ) , X_ ( " edit-current-meter " ) ) ) ;
2012-05-31 23:14:03 +00:00
}
2024-09-27 10:10:10 -05:00
void
MainClock : : parameter_changed ( std : : string p )
{
if ( p = = " primary-clock-delta-mode " & & _disposition = = PrimaryClock ) {
set_display_delta_mode ( UIConfiguration : : instance ( ) . get_primary_clock_delta_mode ( ) ) ;
} else if ( p = = " secondary-clock-delta-mode " & & _disposition = = SecondaryClock ) {
set_display_delta_mode ( UIConfiguration : : instance ( ) . get_secondary_clock_delta_mode ( ) ) ;
}
}
void
MainClock : : clock_value_changed ( )
{
if ( _session ) {
_session - > request_locate ( last_when ( ) . samples ( ) ) ;
}
}
2012-05-31 23:14:03 +00:00
void
MainClock : : build_ops_menu ( )
{
using namespace Menu_Helpers ;
AudioClock : : build_ops_menu ( ) ;
MenuList & ops_items = ops_menu - > items ( ) ;
ops_items . push_back ( SeparatorElem ( ) ) ;
2022-11-06 19:12:20 +01:00
2017-11-22 22:10:37 +01:00
RadioMenuItem : : Group group ;
PBD : : Unwinder < bool > uw ( _suspend_delta_mode_signal , true ) ;
2022-11-20 00:48:29 +01:00
ops_items . push_back ( RadioMenuElem ( group , _ ( " Display absolute time " ) , sigc : : bind ( sigc : : mem_fun ( * this , & MainClock : : change_display_delta_mode ) , NoDelta ) ) ) ;
2022-11-06 19:12:20 +01:00
if ( _delta_mode = = NoDelta ) {
2017-11-22 22:10:37 +01:00
RadioMenuItem * i = dynamic_cast < RadioMenuItem * > ( & ops_items . back ( ) ) ;
i - > set_active ( true ) ;
}
2022-11-20 00:48:29 +01:00
ops_items . push_back ( RadioMenuElem ( group , _ ( " Display delta to edit cursor " ) , sigc : : bind ( sigc : : mem_fun ( * this , & MainClock : : change_display_delta_mode ) , DeltaEditPoint ) ) ) ;
2022-11-06 19:12:20 +01:00
if ( _delta_mode = = DeltaEditPoint ) {
2017-11-22 22:10:37 +01:00
RadioMenuItem * i = dynamic_cast < RadioMenuItem * > ( & ops_items . back ( ) ) ;
i - > set_active ( true ) ;
}
2022-11-20 00:48:29 +01:00
ops_items . push_back ( RadioMenuElem ( group , _ ( " Display delta to origin marker " ) , sigc : : bind ( sigc : : mem_fun ( * this , & MainClock : : change_display_delta_mode ) , DeltaOriginMarker ) ) ) ;
2022-11-06 19:12:20 +01:00
if ( _delta_mode = = DeltaOriginMarker ) {
2017-11-22 22:10:37 +01:00
RadioMenuItem * i = dynamic_cast < RadioMenuItem * > ( & ops_items . back ( ) ) ;
i - > set_active ( true ) ;
2012-05-31 23:14:03 +00:00
}
2015-02-03 19:25:10 +00:00
ops_items . push_back ( SeparatorElem ( ) ) ;
2017-11-22 22:10:37 +01:00
2015-02-03 19:25:10 +00:00
ops_items . push_back ( MenuElem ( _ ( " Edit Tempo " ) , sigc : : mem_fun ( * this , & MainClock : : edit_current_tempo ) ) ) ;
2022-04-05 18:56:10 +02:00
ops_items . push_back ( MenuElem ( _ ( " Edit Time Signature " ) , sigc : : mem_fun ( * this , & MainClock : : edit_current_meter ) ) ) ;
2015-02-03 19:25:10 +00:00
ops_items . push_back ( MenuElem ( _ ( " Insert Tempo Change " ) , sigc : : mem_fun ( * this , & MainClock : : insert_new_tempo ) ) ) ;
2022-04-05 18:56:10 +02:00
ops_items . push_back ( MenuElem ( _ ( " Insert Time Signature Change " ) , sigc : : mem_fun ( * this , & MainClock : : insert_new_meter ) ) ) ;
2012-05-31 23:14:03 +00:00
}
void
2024-12-18 18:30:15 +01:00
MainClock : : set ( timepos_t const & when , bool force , bool round_to_beat )
2017-11-22 22:10:37 +01:00
{
2021-11-13 17:49:03 -07:00
if ( ! AudioEngine : : instance ( ) - > session ( ) ) {
2022-11-06 19:12:20 +01:00
_delta_mode = NoDelta ;
2017-11-22 22:10:37 +01:00
}
2022-11-06 19:12:20 +01:00
switch ( _delta_mode ) {
2017-11-22 22:10:37 +01:00
case NoDelta :
2020-10-19 12:37:54 -06:00
AudioClock : : set ( when , force ) ;
2017-11-22 22:10:37 +01:00
break ;
case DeltaEditPoint :
2022-11-07 13:00:19 +01:00
set_duration ( when . distance ( PublicEditor : : instance ( ) . get_preferred_edit_position ( Editing : : EDIT_IGNORE_PHEAD ) ) , force ) ;
2017-11-22 22:10:37 +01:00
break ;
case DeltaOriginMarker :
{
2021-11-13 17:49:03 -07:00
Location * loc = AudioEngine : : instance ( ) - > session ( ) - > locations ( ) - > clock_origin_location ( ) ;
2022-11-07 13:00:19 +01:00
set_duration ( - when . distance ( loc ? loc - > start ( ) : timepos_t ( when . time_domain ( ) ) ) , force ) ;
2017-11-22 22:10:37 +01:00
}
break ;
}
2024-09-27 10:10:10 -05:00
CanonicalClockChanged ( ) ; //signal
2017-11-22 22:10:37 +01:00
}
void
2022-11-20 00:48:29 +01:00
MainClock : : change_display_delta_mode ( ClockDeltaMode m )
2012-05-31 23:14:03 +00:00
{
2017-11-22 22:10:37 +01:00
if ( _suspend_delta_mode_signal ) {
return ;
}
2022-11-18 12:08:18 +01:00
change_display_delta_mode_signal ( m ) ;
2012-05-31 23:14:03 +00:00
}
2015-02-03 19:25:10 +00:00
2022-11-06 19:12:20 +01:00
void
MainClock : : set_display_delta_mode ( ClockDeltaMode m )
{
2025-01-03 19:13:38 +01:00
if ( _delta_mode = = m ) {
return ;
}
2022-11-06 19:12:20 +01:00
_delta_mode = m ;
if ( _delta_mode ! = NoDelta ) {
set_editable ( false ) ;
set_widget_name ( _widget_name + " delta " ) ;
} else {
set_editable ( true ) ;
set_widget_name ( _widget_name ) ;
}
2025-01-03 19:13:38 +01:00
if ( _session ) {
set ( timepos_t ( _session - > audible_sample ( ) ) , true ) ;
}
2022-11-06 19:12:20 +01:00
}
2025-01-07 18:28:31 +01:00
void
MainClock : : on_size_request ( Gtk : : Requisition * req )
{
AudioClock : : on_size_request ( req ) ;
Glib : : RefPtr < Pango : : Layout > tmp ;
Glib : : RefPtr < Gtk : : Style > style = get_style ( ) ;
Pango : : FontDescription font ;
if ( ! get_realized ( ) ) {
font = ARDOUR_UI_UTILS : : get_font_for_style ( get_name ( ) ) ;
} else {
font = style - > get_font ( ) ;
}
_layout - > set_font_description ( font ) ;
_layout - > get_pixel_size ( _layout_width , _layout_height ) ;
req - > width + = _layout_width * 1.5 ;
req - > height = std : : max ( req - > height , _layout_height ) ;
}
void
MainClock : : render ( Cairo : : RefPtr < Cairo : : Context > const & ctx , cairo_rectangle_t * rect )
{
AudioClock : : render ( ctx , rect ) ;
if ( ! _delta_mode ) {
return ;
}
cairo_t * cr = ctx - > cobj ( ) ;
uint32_t text_color = UIConfiguration : : instance ( ) . color ( string_compose ( " %1: text " , get_name ( ) ) ) ;
Gtkmm2ext : : set_source_rgba ( ctx , text_color ) ;
cairo_move_to ( cr , get_width ( ) - _layout_width * 1.5 , ( get_height ( ) - _layout_height ) / 2.0 ) ;
pango_cairo_show_layout ( cr , _layout - > gobj ( ) ) ;
}
2015-02-03 19:25:10 +00:00
void
MainClock : : edit_current_tempo ( )
{
2015-08-18 11:02:34 +10:00
if ( ! PublicEditor : : instance ( ) . session ( ) ) return ;
2022-11-18 11:29:01 +01:00
PublicEditor : : instance ( ) . edit_tempo_section ( Temporal : : TempoMap : : use ( ) - > metric_at ( last_when ( ) ) . get_editable_tempo ( ) ) ;
2015-02-03 19:25:10 +00:00
}
void
MainClock : : edit_current_meter ( )
{
2015-08-18 11:02:34 +10:00
if ( ! PublicEditor : : instance ( ) . session ( ) ) return ;
2022-11-18 11:29:01 +01:00
PublicEditor : : instance ( ) . edit_meter_section ( Temporal : : TempoMap : : use ( ) - > metric_at ( last_when ( ) ) . get_editable_meter ( ) ) ;
2015-02-03 19:25:10 +00:00
}
void
MainClock : : insert_new_tempo ( )
{
2022-11-18 11:29:01 +01:00
PublicEditor : : instance ( ) . mouse_add_new_tempo_event ( last_when ( ) ) ;
2015-02-03 19:25:10 +00:00
}
void
MainClock : : insert_new_meter ( )
{
2022-11-18 11:29:01 +01:00
PublicEditor : : instance ( ) . mouse_add_new_meter_event ( last_when ( ) ) ;
2015-02-03 19:25:10 +00:00
}
2024-09-27 10:10:10 -05:00
TransportClock : : TransportClock (
const std : : string & clock_name ,
const std : : string & widget_name ,
ClockDisposition d
)
: MainClock ( clock_name , widget_name , d )
{
if ( _disposition = = PrimaryClock ) {
ARDOUR_UI : : instance ( ) - > primary_clock - > CanonicalClockChanged . connect ( sigc : : mem_fun ( * this , & TransportClock : : follow_canonical_clock ) ) ;
ARDOUR_UI : : instance ( ) - > primary_clock - > mode_changed . connect ( sigc : : mem_fun ( * this , & TransportClock : : follow_canonical_clock ) ) ;
change_display_delta_mode_signal . connect ( sigc : : mem_fun ( UIConfiguration : : instance ( ) , & UIConfiguration : : set_primary_clock_delta_mode ) ) ;
} else {
ARDOUR_UI : : instance ( ) - > secondary_clock - > CanonicalClockChanged . connect ( sigc : : mem_fun ( * this , & TransportClock : : follow_canonical_clock ) ) ;
ARDOUR_UI : : instance ( ) - > secondary_clock - > mode_changed . connect ( sigc : : mem_fun ( * this , & TransportClock : : follow_canonical_clock ) ) ;
change_display_delta_mode_signal . connect ( sigc : : mem_fun ( UIConfiguration : : instance ( ) , & UIConfiguration : : set_secondary_clock_delta_mode ) ) ;
}
}
void
TransportClock : : set_mode ( Mode m )
{
//we don't set the mode for ourselves; instead we set the canonical clock and then 'follow' it
if ( _disposition = = PrimaryClock ) {
ARDOUR_UI : : instance ( ) - > primary_clock - > set_mode ( m ) ;
} else {
ARDOUR_UI : : instance ( ) - > secondary_clock - > set_mode ( m ) ;
}
}
void
TransportClock : : follow_canonical_clock ( )
{
if ( ! _session ) {
return ;
}
set ( timepos_t ( _session - > audible_sample ( ) ) ) ;
if ( _disposition = = PrimaryClock ) {
AudioClock : : set_mode ( ARDOUR_UI : : instance ( ) - > primary_clock - > mode ( ) ) ;
set_display_delta_mode ( ARDOUR_UI : : instance ( ) - > primary_clock - > display_delta_mode ( ) ) ;
} else {
AudioClock : : set_mode ( ARDOUR_UI : : instance ( ) - > secondary_clock - > mode ( ) ) ;
set_display_delta_mode ( ARDOUR_UI : : instance ( ) - > secondary_clock - > display_delta_mode ( ) ) ;
}
}