next iteration of clock work. still far from complete, and probably waiting on a rethink of text rendering+layout. but it has the info block now, and it semi-works

git-svn-id: svn://localhost/ardour2/branches/3.0@9676 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2011-06-03 22:18:47 +00:00
parent 11bcfd8429
commit e77b5261d2
11 changed files with 696 additions and 525 deletions

View file

@ -942,7 +942,7 @@ style "recording_big_clock_display" = "non_recording_big_clock_display"
style "transport_clock_display"
{
font_name = "@FONT_BOLD_BIG@"
font_name = "monospace @FONT_BOLD_BIG@"
fg[ACTIVE] = darker(@@COLPREFIX@_bright_indicator)
fg[SELECTED] = darker(@@COLPREFIX@_bright_indicator)
@ -989,6 +989,35 @@ style "default_clock_display" = "medium_text"
bg[ACTIVE] = @@COLPREFIX@_darkest
}
style "selection_clock_display"
{
font_name = "monospace @FONT_SMALLER@"
text[NORMAL] = @@COLPREFIX@_contrasting_indicator
text[ACTIVE] = @@COLPREFIX@_bright_indicator
fg[NORMAL] = @@COLPREFIX@_contrasting_indicator
fg[ACTIVE] = @@COLPREFIX@_bright_indicator
fg[SELECTED] = @@COLPREFIX@_bright_indicator
base[NORMAL] = @@COLPREFIX@_darkest
base[ACTIVE] = @@COLPREFIX@_darkest
bg[NORMAL] = @@COLPREFIX@_darkest
bg[ACTIVE] = @@COLPREFIX@_darkest
}
style "punch_clock_display" = "very_small_text"
{
font_name = "monospace @FONT_SMALLER@"
text[NORMAL] = @@COLPREFIX@_contrasting_indicator
text[ACTIVE] = @@COLPREFIX@_bright_indicator
fg[NORMAL] = @@COLPREFIX@_contrasting_indicator
fg[ACTIVE] = @@COLPREFIX@_bright_indicator
fg[SELECTED] = @@COLPREFIX@_bright_indicator
base[NORMAL] = @@COLPREFIX@_darkest
base[ACTIVE] = @@COLPREFIX@_darkest
bg[NORMAL] = @@COLPREFIX@_darkest
bg[ACTIVE] = @@COLPREFIX@_darkest
}
style "white_on_black_clock_display" = "medium_text"
{
@ -1599,6 +1628,8 @@ widget "*InfoMessage" style:highest "info_message"
widget "*WarningMessage" style:highest "warning_message"
widget "*BigClockNonRecording" style:highest "non_recording_big_clock_display"
widget "*BigClockRecording" style:highest "recording_big_clock_display"
widget "*SelectionClockDisplay" style:highest "selection_clock_display"
widget "*PunchClockDisplay" style:highest "punch_clock_display"
widget "*TransportClockDisplay" style:highest "transport_clock_display"
widget "*SecondaryClockDisplay" style:highest "transport_clock_display"
widget "*TransportClockDisplayDelta" style:highest "transport_clock_display_delta"

View file

@ -86,6 +86,7 @@ class ShuttleControl;
class Splash;
class SpeakerDialog;
class ThemeManager;
class TimeInfoBox;
class MidiTracer;
class WindowProxyBase;
class GlobalPortMatrixWindow;
@ -197,6 +198,8 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
AudioClock* preroll_clock;
AudioClock* postroll_clock;
TimeInfoBox* time_info_box;
void store_clock_modes ();
void restore_clock_modes ();
void reset_main_clocks ();

View file

@ -32,6 +32,7 @@
#include "pbd/error.h"
#include "pbd/basename.h"
#include "pbd/fastlog.h"
#include <gtkmm2ext/cairocell.h>
#include <gtkmm2ext/utils.h>
#include <gtkmm2ext/click_box.h>
#include <gtkmm2ext/tearoff.h>
@ -54,6 +55,7 @@
#include "global_port_matrix.h"
#include "location_ui.h"
#include "rc_option_editor.h"
#include "time_info_box.h"
#include "i18n.h"
@ -385,8 +387,13 @@ ARDOUR_UI::setup_transport ()
transport_hbox->pack_start (rec_button, false, false, 6);
HBox* clock_box = manage (new HBox);
clock_box->set_border_width (2);
primary_clock->main_display().set_ypad (2);
primary_clock->set_border_width (2);
clock_box->pack_start (*primary_clock, false, false);
if (!ARDOUR::Profile->get_small_screen()) {
secondary_clock->set_border_width (2);
secondary_clock->main_display().set_ypad (2);
clock_box->pack_start (*secondary_clock, false, false);
}
@ -410,6 +417,9 @@ ARDOUR_UI::setup_transport ()
transport_tearoff_hbox.pack_start (*transport_vbox, false, false, 0);
transport_tearoff_hbox.pack_start (*clock_box, false, false, 0);
time_info_box = manage (new TimeInfoBox);
transport_tearoff_hbox.pack_start (*time_info_box, false, false);
HBox* toggle_box = manage(new HBox);
VBox* punch_box = manage (new VBox);

View file

@ -44,6 +44,7 @@
#include "speaker_dialog.h"
#include "sfdb_ui.h"
#include "theme_manager.h"
#include "time_info_box.h"
#include "i18n.h"
@ -97,6 +98,7 @@ ARDOUR_UI::set_session (Session *s)
big_clock->set_session (s);
preroll_clock->set_session (s);
postroll_clock->set_session (s);
time_info_box->set_session (s);
/* sensitize menu bar options that are now valid */

View file

@ -54,34 +54,19 @@ using PBD::atof;
sigc::signal<void> AudioClock::ModeChanged;
vector<AudioClock*> AudioClock::clocks;
std::map<AudioClock::Field,uint32_t> AudioClock::field_length;
void
AudioClock::fill_field_lengths()
{
field_length[Timecode_Hours] = 2;
field_length[Timecode_Minutes] = 2;
field_length[Timecode_Seconds] = 2;
field_length[Timecode_Frames] = 2;
field_length[MS_Hours] = 2;
field_length[MS_Minutes] = 2;
field_length[MS_Seconds] = 2;
field_length[MS_Milliseconds] = 3;
field_length[Bars] = 4;
field_length[Beats] = 2;
field_length[Ticks] = 4;
field_length[AudioFrames] = 10;
field_length[Timecode_LowerLeft1] = 4;
field_length[Timecode_LowerLeft2] = 4;
field_length[Timecode_LowerRight1] = 3;
field_length[Timecode_LowerRight2] = 6; // 29.97 D
field_length[BBT_LowerLeft1] = 1;
field_length[BBT_LowerLeft2] = 7;
field_length[BBT_LowerRight1] = 1;
field_length[BBT_LowerRight2] = 3;
uint32_t AudioClock::field_length[] = {
2, /* Timecode_Hours */
2, /* Timecode_Minutes */
2, /* Timecode_Seconds */
2, /* Timecode_Frames */
2, /* MS_Hours */
2, /* MS_Minutes */
2, /* MS_Seconds */
3, /* MS_Milliseconds */
4, /* Bars */
2, /* Beats */
4, /* Ticks */
10, /* AudioFrames */
};
AudioClock::AudioClock (const string& clock_name, bool transient, const string& widget_name,
@ -91,22 +76,12 @@ AudioClock::AudioClock (const string& clock_name, bool transient, const string&
, is_duration (duration)
, editable (allow_edit)
, _follows_playhead (follows_playhead)
, timecode_supplemental_left (0)
, timecode_supplemental_right (0)
, bbt_supplemental_left (0)
, bbt_supplemental_right (0)
, supplemental_left (0)
, supplemental_right (0)
, last_when(0)
, _canonical_time_is_displayed (true)
, _canonical_time (0)
{
CairoTextCell* tc;
CairoBarCell* bc;
CairoColonCell* cc;
if (field_length.empty()) {
fill_field_lengths ();
}
last_when = 0;
last_hrs = 9999;
@ -128,193 +103,71 @@ AudioClock::AudioClock (const string& clock_name, bool transient, const string&
dragging = false;
bbt_reference_time = -1;
editing_field = (Field) 0;
current_cet = 0;
frames_upper_info_label = 0;
frames_lower_info_label = 0;
/* basic per-mode editable text "arrays" */
timecode = new CairoEditableText ();
minsec = new CairoEditableText ();
bbt = new CairoEditableText ();
frames = new CairoEditableText ();
display = new CairoEditableText ();
// add an extra 0.6 "average char width" for the negative sign
tc = new CairoTextCell (field_length[Timecode_Hours] + 0.6);
_text_cells[Timecode_Hours] = tc;
timecode->add_cell (Timecode_Hours, tc);
cc = new CairoColonCell ();
_fixed_cells[Timecode_Colon1] = cc;
timecode->add_cell (Timecode_Colon1, cc);
tc = new CairoTextCell (field_length[Timecode_Minutes]);
_text_cells[Timecode_Minutes] = tc;
timecode->add_cell (Timecode_Minutes, tc);
_fixed_cells[Colon1] = new CairoColonCell (Colon1);
_fixed_cells[Colon2] = new CairoColonCell (Colon2);
_fixed_cells[Colon3] = new CairoColonCell (Colon3);
_fixed_cells[Bar1] = new CairoBarCell (Bar1);
_fixed_cells[Bar2] = new CairoBarCell (Bar2);
cc = new CairoColonCell ();
_fixed_cells[Timecode_Colon2] = cc;
timecode->add_cell (Timecode_Colon2, cc);
tc = new CairoTextCell (field_length[Timecode_Seconds]);
_text_cells[Timecode_Seconds] = tc;
timecode->add_cell (Timecode_Seconds, tc);
cc = new CairoColonCell ();
_fixed_cells[Timecode_Colon3] = cc;
timecode->add_cell (Timecode_Colon3, cc);
tc = new CairoTextCell (field_length[Timecode_Frames]);
_text_cells[Timecode_Frames] = tc;
timecode->add_cell (Timecode_Frames, tc);
// add an extra 0.6 "average char width" for the negative sign
_text_cells[Timecode_Hours] = new CairoTextCell (Timecode_Hours, field_length[Timecode_Hours] + 0.6);
_text_cells[Timecode_Minutes] = new CairoTextCell (Timecode_Minutes, field_length[Timecode_Minutes]);
_text_cells[Timecode_Seconds] = new CairoTextCell (Timecode_Seconds, field_length[Timecode_Seconds]);
_text_cells[Timecode_Frames] = new CairoTextCell (Timecode_Frames, field_length[Timecode_Frames]);
/* Minutes/Seconds */
tc = new CairoTextCell (field_length[MS_Hours]);
_text_cells[MS_Hours] = tc;
minsec->add_cell (MS_Hours, tc);
cc = new CairoColonCell ();
_fixed_cells[MS_Colon1] = cc;
minsec->add_cell (MS_Colon1, cc);
tc = new CairoTextCell (field_length[MS_Minutes]);
_text_cells[MS_Minutes] = tc;
minsec->add_cell (MS_Minutes, tc);
cc = new CairoColonCell ();
_fixed_cells[MS_Colon2] = cc;
minsec->add_cell (MS_Colon2, cc);
tc = new CairoTextCell (field_length[MS_Seconds]);
_text_cells[MS_Seconds] = tc;
minsec->add_cell (MS_Seconds, tc);
cc = new CairoColonCell ();
_fixed_cells[MS_Colon3] = cc;
minsec->add_cell (MS_Colon3, cc);
tc = new CairoTextCell (field_length[MS_Milliseconds]);
_text_cells[MS_Milliseconds] = tc;
minsec->add_cell (MS_Milliseconds, tc);
_text_cells[MS_Hours] = new CairoTextCell (MS_Hours, field_length[MS_Hours]);
_text_cells[MS_Minutes] = new CairoTextCell (MS_Minutes, field_length[MS_Minutes]);
_text_cells[MS_Seconds] = new CairoTextCell (MS_Seconds, field_length[MS_Seconds]);
_text_cells[MS_Milliseconds] = new CairoTextCell (MS_Milliseconds, field_length[MS_Milliseconds]);
/* Beats/Bars/Ticks */
tc = new CairoTextCell (field_length[Bars]);
_text_cells[Bars] = tc;
bbt->add_cell (Bars, tc);
bc = new CairoBarCell ();
_fixed_cells[BBT_Bar1] = bc;
bbt->add_cell (BBT_Bar1, bc);
tc = new CairoTextCell (field_length[Beats]);
_text_cells[Beats] = tc;
bbt->add_cell (Beats, tc);
bc = new CairoBarCell ();
_fixed_cells[BBT_Bar2] = bc;
bbt->add_cell (BBT_Bar2, bc);
tc = new CairoTextCell (field_length[Ticks]);
_text_cells[Ticks] = tc;
bbt->add_cell (Ticks, tc);
_text_cells[Bars] = new CairoTextCell (Bars, field_length[Bars]);
_text_cells[Beats] = new CairoTextCell (Beats, field_length[Beats]);
_text_cells[Ticks] = new CairoTextCell (Ticks, field_length[Ticks]);
/* Audio Frames */
tc = new CairoTextCell (field_length[AudioFrames]);
_text_cells[AudioFrames] = tc;
frames->add_cell (AudioFrames, tc);
_text_cells[AudioFrames] = new CairoTextCell (AudioFrames, field_length[AudioFrames]);
frames_packer.set_homogeneous (false);
frames_packer.set_border_width (2);
frames_packer.pack_start (*frames);
/* Timecode */
timecode_packer.set_homogeneous (false);
timecode_packer.set_border_width (2);
packer.set_homogeneous (false);
if (with_info) {
timecode_supplemental_left = new CairoEditableText ();
tc = new CairoTextCell (field_length[Timecode_LowerLeft1]);
_text_cells[Timecode_LowerLeft1] = tc;
timecode_supplemental_left->add_cell (Timecode_LowerLeft1, tc);
tc = new CairoTextCell (field_length[Timecode_LowerLeft2]);
_text_cells[Timecode_LowerLeft2] = tc;
timecode_supplemental_left->add_cell (Timecode_LowerLeft2, tc);
timecode_supplemental_right = new CairoEditableText ();
tc = new CairoTextCell (field_length[Timecode_LowerRight1]);
_text_cells[Timecode_LowerRight1] = tc;
timecode_supplemental_right->add_cell (Timecode_LowerRight1, tc);
tc = new CairoTextCell (field_length[Timecode_LowerRight2]);
_text_cells[Timecode_LowerRight2] = tc;
timecode_supplemental_right->add_cell (Timecode_LowerRight2, tc);
timecode_supplemental_right->set_text (Timecode_LowerRight1, "FPS");
/* LowerRight2 is set dynamically */
timecode_bottom.set_spacing (1);
timecode_bottom.set_homogeneous (false);
timecode_bottom.pack_start (*timecode_supplemental_left, true, true);
timecode_bottom.pack_start (*timecode_supplemental_right, true, true);
supplemental_left = new CairoEditableText ();
supplemental_right = new CairoEditableText ();
timecode_top.pack_start (*timecode, true, true);
/* field lengths of these cells will be set dynamically by ::set_mode()
*/
_text_cells[LowerLeft1] = new CairoTextCell (LowerLeft1, 0);
_text_cells[LowerLeft2] = new CairoTextCell (LowerLeft2, 0);
_text_cells[LowerRight1] = new CairoTextCell (LowerRight1, 0);
_text_cells[LowerRight2] = new CairoTextCell (LowerRight2, 0);
timecode_packer.set_spacing (1);
timecode_packer.pack_start (timecode_top, true, true);
timecode_packer.pack_start (timecode_bottom, false, false);
bottom.set_spacing (1);
bottom.set_homogeneous (false);
bottom.pack_start (*supplemental_left, true, true);
bottom.pack_start (*supplemental_right, true, true);
top.pack_start (*display, true, true);
packer.set_spacing (1);
packer.pack_start (top, true, true);
packer.pack_start (bottom, false, false);
} else {
timecode_packer.pack_start (*timecode, true, true);
packer.pack_start (*display, true, true);
}
/* BBT */
bbt_packer.set_homogeneous (false);
bbt_packer.set_border_width (2);
if (with_info) {
bbt_supplemental_left = new CairoEditableText ();
tc = new CairoTextCell (field_length[BBT_LowerLeft1]);
_text_cells[BBT_LowerLeft1] = tc;
bbt_supplemental_left->add_cell (BBT_LowerLeft1, tc);
tc = new CairoTextCell (field_length[BBT_LowerLeft2]);
_text_cells[BBT_LowerLeft2] = tc;
bbt_supplemental_left->add_cell (BBT_LowerLeft2, tc);
bbt_supplemental_right = new CairoEditableText ();
tc = new CairoTextCell (field_length[BBT_LowerRight1]);
_text_cells[BBT_LowerRight1] = tc;
bbt_supplemental_right->add_cell (BBT_LowerRight1, tc);
tc = new CairoTextCell (field_length[BBT_LowerRight2]);
_text_cells[BBT_LowerRight2] = tc;
bbt_supplemental_right->add_cell (BBT_LowerRight2, tc);
bbt_supplemental_left->set_text (BBT_LowerLeft1, _("M")); // M is for meter
bbt_supplemental_right->set_text (BBT_LowerRight1, _("T")); // T is for tempo
/* LowerLeft2 and LowerRight2 are set dynamically */
bbt_bottom.set_spacing (1);
bbt_bottom.set_homogeneous (false);
bbt_bottom.pack_start (*bbt_supplemental_left, true, true);
bbt_bottom.pack_start (*bbt_supplemental_right, true, true);
bbt_top.pack_start (*bbt, true, true);
bbt_packer.set_spacing (1);
bbt_packer.pack_start (bbt_top, true, true);
bbt_packer.pack_start (bbt_bottom, false, false);
} else {
bbt_packer.pack_start (*bbt);
}
minsec_packer.set_homogeneous (false);
minsec_packer.set_border_width (2);
minsec_packer.pack_start (*minsec);
add (packer);
show_all ();
set_widget_name (widget_name);
@ -332,16 +185,21 @@ AudioClock::~AudioClock ()
/* these are not manage()'d, so that we can add/remove
them from containers as necessary.
*/
delete timecode;
delete minsec;
delete bbt;
delete frames;
delete timecode_supplemental_left;
delete timecode_supplemental_right;
delete display;
delete supplemental_left;
delete supplemental_right;
/* XXX need to delete all cells too */
}
void
AudioClock::set_widget_name (string name)
AudioClock::set_font (const string& font)
{
display->set_font (font);
/* XXX supplemental ... */
}
void
AudioClock::set_widget_name (const string& name)
{
Widget::set_name (name);
@ -366,18 +224,13 @@ AudioClock::set_theme ()
font = style->get_font();
}
timecode->set_font (font);
minsec->set_font (font);
bbt->set_font (font);
frames->set_font (font);
display->set_font (font);
if (timecode_supplemental_right) {
if (supplemental_right) {
Pango::FontDescription smaller_font ("Sans 8");
timecode_supplemental_right->set_font (smaller_font);
timecode_supplemental_left->set_font (smaller_font);
bbt_supplemental_right->set_font (smaller_font);
bbt_supplemental_left->set_font (smaller_font);
supplemental_right->set_font (smaller_font);
supplemental_left->set_font (smaller_font);
}
Gdk::Color bg = style->get_base (Gtk::STATE_NORMAL);
@ -389,16 +242,11 @@ AudioClock::set_theme ()
b = bg.get_blue_p ();
a = 1.0;
timecode->set_bg (r, g, b, a);
minsec->set_bg (r, g, b, a);
bbt->set_bg (r, g, b, a);
frames->set_bg (r, g, b, a);
display->set_bg (r, g, b, a);
if (timecode_supplemental_right) {
timecode_supplemental_right->set_bg (r,g,b,a);
timecode_supplemental_left->set_bg (r,g,b,a);
bbt_supplemental_right->set_bg (r,g,b,a);
bbt_supplemental_left->set_bg (r,g,b,a);
if (supplemental_right) {
supplemental_right->set_bg (r,g,b,a);
supplemental_left->set_bg (r,g,b,a);
}
r = fg.get_red_p ();
@ -406,16 +254,11 @@ AudioClock::set_theme ()
b = fg.get_blue_p ();
a = 1.0;
timecode->set_colors (r, g, b, a);
minsec->set_colors (r, g, b, a);
bbt->set_colors (r, g, b, a);
frames->set_colors (r, g, b, a);
display->set_colors (r, g, b, a);
if (timecode_supplemental_right) {
timecode_supplemental_right->set_colors (r,g,b,a);
timecode_supplemental_left->set_colors (r,g,b,a);
bbt_supplemental_right->set_colors (r,g,b,a);
bbt_supplemental_left->set_colors (r,g,b,a);
if (supplemental_right) {
supplemental_right->set_colors (r,g,b,a);
supplemental_left->set_colors (r,g,b,a);
}
r = eg.get_red_p ();
@ -423,16 +266,11 @@ AudioClock::set_theme ()
b = eg.get_blue_p ();
a = 1.0;
timecode->set_edit_colors (r, g, b, a);
minsec->set_edit_colors (r, g, b, a);
bbt->set_edit_colors (r, g, b, a);
frames->set_edit_colors (r, g, b, a);
display->set_edit_colors (r, g, b, a);
if (timecode_supplemental_right) {
timecode_supplemental_right->set_edit_colors (r,g,b,a);
timecode_supplemental_left->set_edit_colors (r,g,b,a);
bbt_supplemental_right->set_edit_colors (r,g,b,a);
bbt_supplemental_left->set_edit_colors (r,g,b,a);
if (supplemental_right) {
supplemental_right->set_edit_colors (r,g,b,a);
supplemental_left->set_edit_colors (r,g,b,a);
}
queue_draw ();
@ -446,7 +284,7 @@ AudioClock::focus ()
void
AudioClock::end_edit ()
{
current_cet->stop_editing ();
display->stop_editing ();
editing_field = (Field) 0;
key_entry_state = 0;
@ -563,32 +401,26 @@ AudioClock::set_frames (framepos_t when, bool /*force*/)
char buf[32];
snprintf (buf, sizeof (buf), "%" PRId64, when);
frames->set_text (AudioFrames, buf);
display->set_text (_text_cells[AudioFrames], buf);
if (frames_upper_info_label) {
if (supplemental_left) {
framecnt_t rate = _session->frame_rate();
if (fmod (rate, 1000.0) == 0.000) {
sprintf (buf, "%" PRId64 "K", rate/1000);
} else {
sprintf (buf, "%.3fK", rate/1000.0f);
sprintf (buf, "%" PRId64, rate);
}
if (frames_upper_info_label->get_text() != buf) {
frames_upper_info_label->set_text (buf);
}
supplemental_left->set_text (_text_cells[LowerLeft2], buf);
float vid_pullup = _session->config.get_video_pullup();
if (vid_pullup == 0.0) {
if (frames_lower_info_label->get_text () != _("none")) {
frames_lower_info_label->set_text(_("none"));
}
supplemental_right->set_text (_text_cells[LowerRight2], _("none"));
} else {
sprintf (buf, "%-6.4f", vid_pullup);
if (frames_lower_info_label->get_text() != buf) {
frames_lower_info_label->set_text (buf);
}
supplemental_right->set_text (_text_cells[LowerRight2], buf);
}
}
}
@ -614,25 +446,25 @@ AudioClock::set_minsec (framepos_t when, bool force)
if (force || hrs != ms_last_hrs) {
sprintf (buf, "%02d", hrs);
minsec->set_text (MS_Hours, buf);
display->set_text (_text_cells[MS_Hours], buf);
ms_last_hrs = hrs;
}
if (force || mins != ms_last_mins) {
sprintf (buf, "%02d", mins);
minsec->set_text (MS_Minutes, buf);
display->set_text (_text_cells[MS_Minutes], buf);
ms_last_mins = mins;
}
if (force || secs != ms_last_secs) {
sprintf (buf, "%02d", secs);
minsec->set_text (MS_Seconds, buf);
display->set_text (_text_cells[MS_Seconds], buf);
ms_last_secs = secs;
}
if (force || millisecs != ms_last_millisecs) {
sprintf (buf, "%03d", millisecs);
minsec->set_text (MS_Milliseconds, buf);
display->set_text (_text_cells[MS_Milliseconds], buf);
ms_last_millisecs = millisecs;
}
}
@ -655,30 +487,30 @@ AudioClock::set_timecode (framepos_t when, bool force)
} else {
sprintf (buf, " %0*" PRIu32, field_length[Timecode_Hours], TC.hours);
}
timecode->set_text (Timecode_Hours, buf);
display->set_text (_text_cells[Timecode_Hours], buf);
last_hrs = TC.hours;
last_negative = TC.negative;
}
if (force || TC.minutes != last_mins) {
sprintf (buf, "%0*" PRIu32, field_length[Timecode_Minutes], TC.minutes);
timecode->set_text (Timecode_Minutes, buf);
display->set_text (_text_cells[Timecode_Minutes], buf);
last_mins = TC.minutes;
}
if (force || TC.seconds != last_secs) {
sprintf (buf, "%0*" PRIu32, field_length[Timecode_Seconds], TC.seconds);
timecode->set_text (Timecode_Seconds, buf);
display->set_text (_text_cells[Timecode_Seconds], buf);
last_secs = TC.seconds;
}
if (force || TC.frames != last_frames) {
sprintf (buf, "%0*" PRIu32, field_length[Timecode_Frames], TC.frames);
timecode->set_text (Timecode_Frames, buf);
display->set_text (_text_cells[Timecode_Frames], buf);
last_frames = TC.frames;
}
if (timecode_supplemental_right) {
if (supplemental_right) {
double timecode_frames = _session->timecode_frames_per_second();
bool drop;
@ -696,7 +528,7 @@ AudioClock::set_timecode (framepos_t when, bool force)
sprintf (buf, "%.2f %s", timecode_frames, (drop ? "D" : ""));
}
timecode_supplemental_right->set_text (Timecode_LowerRight2, buf);
supplemental_right->set_text (_text_cells[LowerRight2], buf);
}
}
@ -723,19 +555,18 @@ AudioClock::set_bbt (framepos_t when, bool force)
sprintf (buf, "%0*" PRIu32, field_length[Bars], BBT.bars);
if (force || _text_cells[Bars]->get_text () != buf) {
bbt->set_text (Bars, buf);
_text_cells[Bars]->set_text (buf);
display->set_text (_text_cells[Bars], buf);
}
sprintf (buf, "%0*" PRIu32, field_length[Beats], BBT.beats);
if (force || _text_cells[Beats]->get_text () != buf) {
bbt->set_text (Beats, buf);
display->set_text (_text_cells[Beats], buf);
}
sprintf (buf, "%0*" PRIu32, field_length[Ticks], BBT.ticks);
if (force || _text_cells[Ticks]->get_text () != buf) {
bbt->set_text (Ticks, buf);
display->set_text (_text_cells[Ticks], buf);
}
if (bbt_supplemental_right) {
if (supplemental_right) {
framepos_t pos;
if (bbt_reference_time < 0) {
@ -747,10 +578,10 @@ AudioClock::set_bbt (framepos_t when, bool force)
TempoMetric m (_session->tempo_map().metric_at (pos));
sprintf (buf, "%-5.2f", m.tempo().beats_per_minute());
bbt_supplemental_left->set_text (BBT_LowerLeft2, buf);
supplemental_left->set_text (_text_cells[LowerLeft2], buf);
sprintf (buf, "%g|%g", m.meter().beats_per_bar(), m.meter().note_divisor());
bbt_supplemental_right->set_text (BBT_LowerRight2, buf);
supplemental_right->set_text (_text_cells[LowerRight2], buf);
}
}
@ -790,15 +621,15 @@ AudioClock::edit_next_field ()
case Timecode_Hours:
editing_field = Timecode_Minutes;
timecode->start_editing (Timecode_Minutes);
display->start_editing (_text_cells[Timecode_Minutes]);
break;
case Timecode_Minutes:
editing_field = Timecode_Seconds;
timecode->start_editing (Timecode_Seconds);
display->start_editing (_text_cells[Timecode_Seconds]);
break;
case Timecode_Seconds:
editing_field = Timecode_Frames;
timecode->start_editing (Timecode_Frames);
display->start_editing (_text_cells[Timecode_Frames]);
break;
case Timecode_Frames:
end_edit ();
@ -808,15 +639,15 @@ AudioClock::edit_next_field ()
case MS_Hours:
editing_field = MS_Minutes;
minsec->start_editing (MS_Minutes);
display->start_editing (_text_cells[MS_Minutes]);
break;
case MS_Minutes:
editing_field = MS_Seconds;
minsec->start_editing (MS_Seconds);
display->start_editing (_text_cells[MS_Seconds]);
break;
case MS_Seconds:
editing_field = MS_Milliseconds;
minsec->start_editing (MS_Milliseconds);
display->start_editing (_text_cells[MS_Milliseconds]);
break;
case MS_Milliseconds:
end_edit ();
@ -826,11 +657,11 @@ AudioClock::edit_next_field ()
case Bars:
editing_field = Beats;
bbt->start_editing (Beats);
display->start_editing (_text_cells[Beats]);
break;
case Beats:
editing_field = Ticks;
bbt->start_editing (Ticks);
display->start_editing (_text_cells[Ticks]);
break;
case Ticks:
end_edit ();
@ -997,11 +828,7 @@ AudioClock::on_key_release_event (GdkEventKey *ev)
}
new_text += new_char;
if (current_cet) {
current_cet->set_text (editing_field, new_text);
}
display->set_text (cell, new_text);
_canonical_time_is_displayed = true;
key_entry_state++;
}
@ -1033,13 +860,13 @@ AudioClock::on_key_release_event (GdkEventKey *ev)
// Bars should never be zero, unless this clock is for a duration
if (atoi (_text_cells[Bars]->get_text()) == 0 && !is_duration) {
snprintf (buf, sizeof (buf), "%0*" PRIu32, field_length[Bars], 1);
_text_cells[Bars]->set_text (buf);
display->set_text (_text_cells[Bars], buf);
_canonical_time_is_displayed = true;
}
// beats should never be zero, unless this clock is for a duration
if (atoi (_text_cells[Beats]->get_text()) == 0 && !is_duration) {
snprintf (buf, sizeof (buf), "%0*" PRIu32, field_length[Beats], 1);
_text_cells[Beats]->set_text (buf);
display->set_text (_text_cells[Beats], buf);
_canonical_time_is_displayed = true;
}
break;
@ -1064,14 +891,14 @@ AudioClock::on_key_release_event (GdkEventKey *ev)
}
bool
AudioClock::button_press (GdkEventButton *ev, uint32_t id)
AudioClock::button_press (GdkEventButton *ev, CairoCell* cell)
{
Field field = (Field) id;
switch (ev->button) {
case 1:
editing_field = field;
current_cet->start_editing (field);
if (cell) {
editing_field = (Field) cell->id ();
display->start_editing (cell);
}
Keyboard::magic_widget_grab_focus ();
@ -1094,7 +921,7 @@ AudioClock::button_press (GdkEventButton *ev, uint32_t id)
}
bool
AudioClock::button_release (GdkEventButton *ev, uint32_t id)
AudioClock::button_release (GdkEventButton *ev, CairoCell*)
{
if (dragging) {
gdk_pointer_ungrab (GDK_CURRENT_TIME);
@ -1125,10 +952,8 @@ AudioClock::button_release (GdkEventButton *ev, uint32_t id)
}
bool
AudioClock::scroll (GdkEventScroll *ev, uint32_t id)
AudioClock::scroll (GdkEventScroll *ev, CairoCell* cell)
{
Field field = (Field) id;
if (_session == 0) {
return false;
}
@ -1138,38 +963,38 @@ AudioClock::scroll (GdkEventScroll *ev, uint32_t id)
switch (ev->direction) {
case GDK_SCROLL_UP:
frames = get_frames (field);
if (frames != 0) {
if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
frames *= 10;
}
set (current_time() + frames, true);
ValueChanged (); /* EMIT_SIGNAL */
}
break;
frames = get_frames ((Field) cell->id());
if (frames != 0) {
if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
frames *= 10;
}
set (current_time() + frames, true);
ValueChanged (); /* EMIT_SIGNAL */
}
break;
case GDK_SCROLL_DOWN:
frames = get_frames (field);
if (frames != 0) {
if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
frames *= 10;
}
if ((double)current_time() - (double)frames < 0.0) {
set (0, true);
} else {
set (current_time() - frames, true);
}
ValueChanged (); /* EMIT_SIGNAL */
}
break;
frames = get_frames ((Field) cell->id());
if (frames != 0) {
if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
frames *= 10;
}
if ((double)current_time() - (double)frames < 0.0) {
set (0, true);
} else {
set (current_time() - frames, true);
}
ValueChanged (); /* EMIT_SIGNAL */
}
break;
default:
return false;
break;
}
return true;
}
@ -1355,31 +1180,31 @@ AudioClock::timecode_sanitize_display()
{
// Check Timecode fields for sanity, possibly adjusting values
if (atoi (_text_cells[Timecode_Minutes]->get_text()) > 59) {
_text_cells[Timecode_Minutes]->set_text("59");
display->set_text (_text_cells[Timecode_Minutes], "59");
_canonical_time_is_displayed = true;
}
if (atoi (_text_cells[Timecode_Seconds]->get_text()) > 59) {
_text_cells[Timecode_Seconds]->set_text("59");
display->set_text (_text_cells[Timecode_Seconds], "59");
_canonical_time_is_displayed = true;
}
switch ((long)rint(_session->timecode_frames_per_second())) {
case 24:
if (atoi (_text_cells[Timecode_Frames]->get_text()) > 23) {
_text_cells[Timecode_Frames]->set_text("23");
display->set_text (_text_cells[Timecode_Frames], "23");
_canonical_time_is_displayed = true;
}
break;
case 25:
if (atoi (_text_cells[Timecode_Frames]->get_text()) > 24) {
_text_cells[Timecode_Frames]->set_text("24");
display->set_text (_text_cells[Timecode_Frames], "24");
_canonical_time_is_displayed = true;
}
break;
case 30:
if (atoi (_text_cells[Timecode_Frames]->get_text()) > 29) {
_text_cells[Timecode_Frames]->set_text("29");
display->set_text (_text_cells[Timecode_Frames], "29");
_canonical_time_is_displayed = true;
}
break;
@ -1389,7 +1214,7 @@ AudioClock::timecode_sanitize_display()
if (_session->timecode_drop_frames()) {
if ((atoi (_text_cells[Timecode_Minutes]->get_text()) % 10) && (atoi (_text_cells[Timecode_Seconds]->get_text()) == 0) && (atoi (_text_cells[Timecode_Frames]->get_text()) < 2)) {
_text_cells[Timecode_Frames]->set_text("02");
display->set_text (_text_cells[Timecode_Frames], "02");
_canonical_time_is_displayed = true;
}
}
@ -1924,67 +1749,124 @@ AudioClock::connect_signals ()
{
disconnect_signals ();
if (editable && current_cet) {
scroll_connection = current_cet->scroll.connect (sigc::mem_fun (*this, &AudioClock::scroll));
button_press_connection = current_cet->button_press.connect (sigc::mem_fun (*this, &AudioClock::button_press));
button_release_connection = current_cet->button_release.connect (sigc::mem_fun (*this, &AudioClock::button_release));
if (editable) {
scroll_connection = display->scroll.connect (sigc::mem_fun (*this, &AudioClock::scroll));
button_press_connection = display->button_press.connect (sigc::mem_fun (*this, &AudioClock::button_press));
button_release_connection = display->button_release.connect (sigc::mem_fun (*this, &AudioClock::button_release));
}
}
void
AudioClock::set_mode (Mode m)
{
/* slightly tricky: this is called from within the ARDOUR_UI
constructor by some of its clock members. at that time
the instance pointer is unset, so we have to be careful.
the main idea is to drop keyboard focus in case we had
started editing the clock and then we switch clock mode.
*/
// clock_base.grab_focus ();
if (_mode == m) {
return;
}
remove ();
_mode = m;
display->clear_cells ();
if (supplemental_left) {
supplemental_left->clear_cells ();
supplemental_right->clear_cells ();
}
switch (_mode) {
case Timecode:
current_cet = timecode;
add (timecode_packer);
display->add_cell (_text_cells[Timecode_Hours]);
display->add_cell (_fixed_cells[Colon1]);
display->add_cell (_text_cells[Timecode_Minutes]);
display->add_cell (_fixed_cells[Colon2]);
display->add_cell (_text_cells[Timecode_Seconds]);
display->add_cell (_fixed_cells[Colon3]);
display->add_cell (_text_cells[Timecode_Frames]);
if (supplemental_left) {
supplemental_left->add_cell (_text_cells[LowerLeft1]);
supplemental_left->add_cell (_text_cells[LowerLeft2]);
supplemental_right->add_cell (_text_cells[LowerRight1]);
supplemental_right->add_cell (_text_cells[LowerRight2]);
supplemental_left->set_width_chars (_text_cells[LowerLeft1], 4);
supplemental_left->set_width_chars (_text_cells[LowerLeft2], 8);
supplemental_right->set_width_chars (_text_cells[LowerRight1], 4);
supplemental_right->set_width_chars (_text_cells[LowerRight2], 6.25);
supplemental_left->set_text (_text_cells[LowerLeft1], _("EXT"));
supplemental_right->set_text (_text_cells[LowerRight1], _("FPS"));
}
break;
case BBT:
current_cet = bbt;
add (bbt_packer);
display->add_cell (_text_cells[Bars]);
display->add_cell (_fixed_cells[Bar1]);
display->add_cell (_text_cells[Beats]);
display->add_cell (_fixed_cells[Bar2]);
display->add_cell (_text_cells[Ticks]);
if (supplemental_left) {
supplemental_left->add_cell (_text_cells[LowerLeft1]);
supplemental_left->add_cell (_text_cells[LowerLeft2]);
supplemental_right->add_cell (_text_cells[LowerRight1]);
supplemental_right->add_cell (_text_cells[LowerRight2]);
supplemental_left->set_width_chars (_text_cells[LowerLeft1], 1);
supplemental_left->set_width_chars (_text_cells[LowerLeft2], 5.25);
supplemental_right->set_width_chars (_text_cells[LowerRight1], 1);
supplemental_right->set_width_chars (_text_cells[LowerRight2], 5);
supplemental_left->set_text (_text_cells[LowerLeft1], _("M"));
supplemental_right->set_text (_text_cells[LowerRight1], _("T"));
}
break;
case MinSec:
current_cet = minsec;
add (minsec_packer);
display->add_cell (_text_cells[MS_Hours]);
display->add_cell (_fixed_cells[Colon1]);
display->add_cell (_text_cells[MS_Minutes]);
display->add_cell (_fixed_cells[Colon2]);
display->add_cell (_text_cells[MS_Seconds]);
display->add_cell (_fixed_cells[Colon3]);
display->add_cell (_text_cells[MS_Milliseconds]);
break;
case Frames:
current_cet = frames;
add (frames_packer);
display->add_cell (_text_cells[AudioFrames]);
if (supplemental_left) {
supplemental_left->add_cell (_text_cells[LowerLeft1]);
supplemental_left->add_cell (_text_cells[LowerLeft2]);
supplemental_right->add_cell (_text_cells[LowerRight1]);
supplemental_right->add_cell (_text_cells[LowerRight2]);
supplemental_left->set_width_chars (_text_cells[LowerLeft1], 3);
supplemental_left->set_width_chars (_text_cells[LowerLeft2], 5);
supplemental_right->set_width_chars (_text_cells[LowerRight1], 5);
supplemental_right->set_width_chars (_text_cells[LowerRight2], 5);
supplemental_left->set_text (_text_cells[LowerLeft1], _("SR"));
supplemental_right->set_text (_text_cells[LowerRight1], _("Pull"));
}
break;
case Off:
current_cet = 0;
add (off_hbox);
break;
}
if (current_cet) {
if (supplemental_left) {
/* clear information cells */
supplemental_left->set_text (_text_cells[LowerLeft2], _(""));
supplemental_right->set_text (_text_cells[LowerRight2], _(""));
}
if (_mode != Off) {
connect_signals ();
} else {
disconnect_signals ();
}
get_child()->show_all ();
set (last_when, true);
if (!is_transient) {
@ -2017,3 +1899,4 @@ AudioClock::set_is_duration (bool yn)
is_duration = yn;
set (last_when, true, 0, 's');
}

View file

@ -25,9 +25,7 @@
#include <gtkmm/alignment.h>
#include <gtkmm/box.h>
#include <gtkmm/menu.h>
#include <gtkmm/eventbox.h>
#include <gtkmm/label.h>
#include <gtkmm/frame.h>
#include "ardour/ardour.h"
#include "ardour/session_handle.h"
@ -66,7 +64,8 @@ class AudioClock : public Gtk::Alignment, public ARDOUR::SessionHandlePtr
void set_bbt_reference (framepos_t);
void set_is_duration (bool);
void set_widget_name (std::string);
void set_widget_name (const std::string&);
void set_font (const std::string&);
std::string name() const { return _name; }
@ -83,6 +82,10 @@ class AudioClock : public Gtk::Alignment, public ARDOUR::SessionHandlePtr
static bool has_focus() { return _has_focus; }
CairoEditableText& main_display () const { return *display; }
CairoEditableText* supplemental_left_display () const { return supplemental_left; }
CairoEditableText* supplemental_right_display () const { return supplemental_right; }
private:
Mode _mode;
uint32_t key_entry_state;
@ -95,46 +98,32 @@ class AudioClock : public Gtk::Alignment, public ARDOUR::SessionHandlePtr
Gtk::Menu *ops_menu;
CairoEditableText* timecode;
CairoEditableText* minsec;
CairoEditableText* bbt;
CairoEditableText* frames;
CairoEditableText* display;
enum Field {
/* Field IDs must start at 1. Cell ID zero
is reserved in CairoEditableText
*/
Timecode_Hours = 1,
Timecode_Colon1,
Timecode_Hours,
Timecode_Minutes,
Timecode_Colon2,
Timecode_Seconds,
Timecode_Colon3,
Timecode_Frames,
MS_Hours,
MS_Colon1,
MS_Minutes,
MS_Colon2,
MS_Colon3, // to become a dot cell
MS_Seconds,
MS_Milliseconds,
Bars,
BBT_Bar1,
Beats,
BBT_Bar2,
Ticks,
AudioFrames,
Timecode_LowerLeft1,
Timecode_LowerLeft2,
Timecode_LowerRight1,
Timecode_LowerRight2,
Colon1,
Colon2,
Colon3,
Bar1,
Bar2,
BBT_LowerLeft1,
BBT_LowerLeft2,
BBT_LowerRight1,
BBT_LowerRight2,
LowerLeft1,
LowerLeft2,
LowerRight1,
LowerRight2,
};
/** CairoCells of various kinds for each of our non-text Fields */
@ -145,25 +134,13 @@ class AudioClock : public Gtk::Alignment, public ARDOUR::SessionHandlePtr
Gtk::HBox off_hbox;
CairoEditableText* timecode_supplemental_left;
CairoEditableText* timecode_supplemental_right;
CairoEditableText* bbt_supplemental_left;
CairoEditableText* bbt_supplemental_right;
CairoEditableText* supplemental_left;
CairoEditableText* supplemental_right;
Gtk::VBox timecode_packer;
Gtk::HBox timecode_top;
Gtk::HBox timecode_bottom;
Gtk::HBox minsec_packer;
Gtk::HBox bbt_top;
Gtk::HBox bbt_bottom;
Gtk::VBox bbt_packer;
Gtk::HBox frames_packer;
Gtk::VBox packer;
Gtk::HBox top;
Gtk::HBox bottom;
Gtk::Label* frames_upper_info_label;
Gtk::Label* frames_lower_info_label;
Gtk::VBox frames_info_box;
CairoEditableText* current_cet;
Field editing_field;
framepos_t bbt_reference_time;
framepos_t last_when;
@ -200,9 +177,9 @@ class AudioClock : public Gtk::Alignment, public ARDOUR::SessionHandlePtr
/* proxied from CairoEditableText */
bool scroll (GdkEventScroll *ev, uint32_t);
bool button_press (GdkEventButton *ev, uint32_t);
bool button_release (GdkEventButton *ev, uint32_t);
bool scroll (GdkEventScroll *ev, CairoCell*);
bool button_press (GdkEventButton *ev, CairoCell*);
bool button_release (GdkEventButton *ev, CairoCell*);
sigc::connection scroll_connection;
sigc::connection button_press_connection;
sigc::connection button_release_connection;
@ -230,8 +207,7 @@ class AudioClock : public Gtk::Alignment, public ARDOUR::SessionHandlePtr
void session_configuration_changed (std::string);
static std::map<AudioClock::Field,uint32_t> field_length;
static void fill_field_lengths();
static uint32_t field_length[];
static bool _has_focus;
void on_style_changed (const Glib::RefPtr<Gtk::Style>&);

View file

@ -0,0 +1,206 @@
/*
Copyright (C) 2011 Paul Davis
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "pbd/compose.h"
#include "gtkmm2ext/cairocell.h"
#include "gtkmm2ext/gui_thread.h"
#include "gtkmm2ext/utils.h"
#include "ardour/location.h"
#include "ardour/session.h"
#include "time_info_box.h"
#include "audio_clock.h"
#include "editor.h"
#include "i18n.h"
using namespace Gtk;
using namespace ARDOUR;
TimeInfoBox::TimeInfoBox ()
: Table (4, 4)
{
selection_start = new AudioClock ("selection-start", false, "SelectionClockDisplay", false, false, false, false);
selection_end = new AudioClock ("selection-end", false, "SelectionClockDisplay", false, false, false, false);
selection_length = new AudioClock ("selection-length", false, "SelectionClockDisplay", false, false, true, false);
punch_start = new AudioClock ("punch-start", false, "PunchClockDisplay", false, false, false, false);
punch_end = new AudioClock ("punch-end", false, "PunchClockDisplay", false, false, false, false);
CairoEditableText& ss (selection_start->main_display());
ss.set_ypad (1);
ss.set_xpad (1);
ss.set_corner_radius (0);
ss.set_draw_background (false);
CairoEditableText& se (selection_end->main_display());
se.set_ypad (1);
se.set_xpad (1);
se.set_corner_radius (0);
se.set_draw_background (false);
CairoEditableText& sl (selection_length->main_display());
sl.set_ypad (1);
sl.set_xpad (2);
sl.set_corner_radius (0);
sl.set_draw_background (false);
CairoEditableText& ps (punch_start->main_display());
ps.set_ypad (1);
ps.set_xpad (2);
ps.set_corner_radius (0);
ps.set_draw_background (false);
CairoEditableText& pe (punch_end->main_display());
pe.set_ypad (1);
pe.set_xpad (2);
pe.set_corner_radius (0);
pe.set_draw_background (false);
selection_title.set_markup (string_compose ("<span size=\"x-small\">%1</span>", _("Selection")));
punch_title.set_markup (string_compose ("<span size=\"x-small\">%1</span>", _("Punch")));
set_homogeneous (false);
set_spacings (0);
Gtk::Label* l;
attach (selection_title, 0, 2, 0, 1);
l = manage (new Label);
l->set_markup (string_compose ("<span size=\"x-small\">%1</span>", _("Start")));
attach (*l, 0, 1, 1, 2);
attach (*selection_start, 1, 2, 1, 2);
l = manage (new Label);
l->set_markup (string_compose ("<span size=\"x-small\">%1</span>", _("End")));
attach (*l, 0, 1, 2, 3);
attach (*selection_end, 1, 2, 2, 3);
l = manage (new Label);
l->set_markup (string_compose ("<span size=\"x-small\">%1</span>", _("Length")));
attach (*l, 0, 1, 3, 4);
attach (*selection_length, 1, 2, 3, 4);
attach (punch_title, 2, 4, 0, 1);
l = manage (new Label);
l->set_markup (string_compose ("<span size=\"x-small\">%1</span>", _("Start")));
attach (*l, 2, 3, 1, 2);
attach (*punch_start, 3, 4, 1, 2);
l = manage (new Label);
l->set_markup (string_compose ("<span size=\"x-small\">%1</span>", _("End")));
attach (*l, 2, 3, 2, 3);
attach (*punch_end, 3, 4, 2, 3);
show_all ();
Editor::instance().get_selection().TimeChanged.connect (sigc::mem_fun (*this, &TimeInfoBox::selection_changed));
}
TimeInfoBox::~TimeInfoBox ()
{
delete selection_length;
delete selection_end;
delete selection_start;
delete punch_start;
delete punch_end;
}
void
TimeInfoBox::set_session (Session* s)
{
SessionHandlePtr::set_session (s);
selection_start->set_session (s);
selection_end->set_session (s);
selection_length->set_session (s);
punch_start->set_session (s);
punch_end->set_session (s);
if (s) {
Location* punch = s->locations()->auto_punch_location ();
if (punch) {
watch_punch (punch);
}
_session->auto_punch_location_changed.connect (_session_connections, MISSING_INVALIDATOR,
boost::bind (&TimeInfoBox::punch_location_changed, this, _1), gui_context());
}
}
void
TimeInfoBox::selection_changed ()
{
selection_start->set (Editor::instance().get_selection().time.start());
selection_end->set (Editor::instance().get_selection().time.end_frame());
selection_length->set (Editor::instance().get_selection().time.length());
}
void
TimeInfoBox::punch_location_changed (Location* loc)
{
if (loc) {
watch_punch (loc);
}
}
void
TimeInfoBox::watch_punch (Location* punch)
{
punch_connections.drop_connections ();
punch->start_changed.connect (punch_connections, MISSING_INVALIDATOR, boost::bind (&TimeInfoBox::punch_changed, this, _1), gui_context());
punch->end_changed.connect (punch_connections, MISSING_INVALIDATOR, boost::bind (&TimeInfoBox::punch_changed, this, _1), gui_context());
punch_changed (punch);
}
void
TimeInfoBox::punch_changed (Location* loc)
{
if (!loc) {
punch_start->set (99999999);
punch_end->set (999999999);
return;
}
punch_start->set (loc->start());
punch_end->set (loc->end());
}
bool
TimeInfoBox::on_expose_event (GdkEventExpose* ev)
{
Table::on_expose_event (ev);
{
Cairo::RefPtr<Cairo::Context> context = get_window()->create_cairo_context();
context->rectangle (ev->area.x, ev->area.y, ev->area.width, ev->area.height);
context->clip ();
context->set_source_rgba (0.01, 0.02, 0.21, 1.0);
Gtkmm2ext::rounded_rectangle (context, 0, 0, get_allocation().get_width(), get_allocation().get_height(), 5);
context->fill ();
}
return false;
}

View file

@ -0,0 +1,73 @@
/*
Copyright (C) 2011 Paul Davis
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __time_info_box_h__
#define __time_info_box_h__
#include <map>
#include <gtkmm/box.h>
#include <gtkmm/label.h>
#include "ardour/ardour.h"
#include "ardour/session_handle.h"
class CairoEditableText;
class CairoCell;
class CairoTextCell;
namespace ARDOUR {
class Session;
class Location;
}
class AudioClock;
class TimeInfoBox : public Gtk::Table, public ARDOUR::SessionHandlePtr
{
public:
TimeInfoBox ();
~TimeInfoBox ();
void set_session (ARDOUR::Session*);
protected:
bool on_expose_event (GdkEventExpose*);
private:
AudioClock* selection_start;
AudioClock* selection_end;
AudioClock* selection_length;
AudioClock* punch_start;
AudioClock* punch_end;
Gtk::Label selection_title;
Gtk::Label punch_title;
void punch_changed (ARDOUR::Location*);
void punch_location_changed (ARDOUR::Location*);
void watch_punch (ARDOUR::Location*);
PBD::ScopedConnectionList punch_connections;
void selection_changed ();
};
#endif /* __time_info_box_h__ */

View file

@ -217,6 +217,7 @@ gtk2_ardour_sources = [
'time_axis_view.cc',
'time_axis_view_item.cc',
'time_fx_dialog.cc',
'time_info_box.cc',
'time_selection.cc',
'track_selection.cc',
'track_view_list.cc',

View file

@ -30,9 +30,10 @@ using std::cerr;
using std::endl;
using namespace Gtkmm2ext;
CairoCell::CairoCell ()
: _visible (true)
, _xpad (5)
CairoCell::CairoCell (int32_t id)
: _id (id)
, _visible (true)
, _xpad (2)
{
bbox.x = 0;
bbox.y = 0;
@ -58,8 +59,9 @@ CairoColonCell::set_size (Glib::RefPtr<Pango::Context>& context, const Pango::Fo
bbox.height = (metrics.get_ascent() + metrics.get_descent()) / PANGO_SCALE;
}
CairoTextCell::CairoTextCell (double wc)
: _width_chars (wc)
CairoTextCell::CairoTextCell (int32_t id, double wc)
: CairoCell (id)
, _width_chars (wc)
{
}
@ -96,18 +98,9 @@ CairoTextCell::set_size (Glib::RefPtr<Pango::Context>& context, const Pango::Fon
bbox.height = (metrics.get_ascent() + metrics.get_descent()) / PANGO_SCALE;
}
CairoCell*
CairoEditableText::get_cell (uint32_t id)
{
CellMap::iterator i = cells.find (id);
if (i == cells.end()) {
return 0;
}
return i->second;
}
CairoEditableText::CairoEditableText ()
: editing_id (0)
: editing_cell (0)
, _draw_bg (true)
, width (0)
, max_cell_height (0)
, height (0)
@ -125,19 +118,16 @@ CairoEditableText::CairoEditableText ()
CairoEditableText::~CairoEditableText ()
{
for (CellMap::iterator i = cells.begin(); i != cells.end(); ++i) {
delete i->second;
}
/* we don't own cells */
}
bool
CairoEditableText::on_scroll_event (GdkEventScroll* ev)
{
uint32_t id;
CairoCell* cell = find_cell (ev->x, ev->y, id);
CairoCell* cell = find_cell (ev->x, ev->y);
if (cell) {
return scroll (ev, id);
return scroll (ev, cell);
}
return false;
@ -152,38 +142,37 @@ CairoEditableText::on_focus_in_event (GdkEventFocus* ev)
bool
CairoEditableText::on_focus_out_event (GdkEventFocus* ev)
{
if (editing_id) {
CairoCell* cell = get_cell (editing_id);
queue_draw_cell (cell);
editing_id = 0;
if (editing_cell) {
queue_draw_cell (editing_cell);
editing_cell = 0;
}
return false;
}
void
CairoEditableText::add_cell (uint32_t id, CairoCell* cell)
CairoEditableText::add_cell (CairoCell* cell)
{
if (id > 0) {
Glib::RefPtr<Pango::Context> context = get_pango_context ();
cell->set_size (context, font);
cells[id] = cell; /* we own it */
}
Glib::RefPtr<Pango::Context> context = get_pango_context ();
cell->set_size (context, _font);
cells.push_back (cell);
queue_resize ();
queue_draw ();
}
void
CairoEditableText::set_text (uint32_t id, const string& text)
CairoEditableText::clear_cells ()
{
CellMap::iterator i = cells.find (id);
cells.clear ();
queue_resize ();
queue_draw ();
}
if (i == cells.end()) {
return;
}
CairoTextCell* textcell = dynamic_cast<CairoTextCell*> (i->second);
if (textcell) {
set_text (textcell, text);
void
CairoEditableText::set_width_chars (CairoTextCell* cell, uint32_t wc)
{
if (cell) {
cell->set_width_chars (wc);
queue_resize ();
}
}
@ -206,24 +195,25 @@ CairoEditableText::on_expose_event (GdkEventExpose* ev)
context->rectangle (ev->area.x, ev->area.y, ev->area.width, ev->area.height);
context->clip ();
context->set_source_rgba (bg_r, bg_g, bg_b, bg_a);
if (_corner_radius) {
rounded_rectangle (context, 0, 0, width, height, _corner_radius);
} else {
context->rectangle (0, 0, width, height);
if (_draw_bg) {
context->set_source_rgba (bg_r, bg_g, bg_b, bg_a);
if (_corner_radius) {
rounded_rectangle (context, 0, 0, width, height, _corner_radius);
} else {
context->rectangle (0, 0, width, height);
}
context->fill ();
}
context->fill ();
for (CellMap::iterator i = cells.begin(); i != cells.end(); ++i) {
uint32_t id = i->first;
CairoCell* cell = i->second;
CairoCell* cell = (*i);
/* is cell inside the expose area?
*/
if (cell->intersects (ev->area)) {
if (id == editing_id) {
if (cell == editing_cell) {
context->set_source_rgba (edit_r, edit_b, edit_g, edit_a);
} else {
context->set_source_rgba (r, g, b, a);
@ -257,12 +247,11 @@ CairoEditableText::queue_draw_cell (CairoCell* cell)
}
CairoCell*
CairoEditableText::find_cell (uint32_t x, uint32_t y, uint32_t& id)
CairoEditableText::find_cell (uint32_t x, uint32_t y)
{
for (CellMap::iterator i = cells.begin(); i != cells.end(); ++i) {
if (i->second->covers (x, y)) {
id = i->first;
return i->second;
if ((*i)->covers (x, y)) {
return (*i);
}
}
@ -272,38 +261,24 @@ CairoEditableText::find_cell (uint32_t x, uint32_t y, uint32_t& id)
bool
CairoEditableText::on_button_press_event (GdkEventButton* ev)
{
uint32_t id;
CairoCell* cell = find_cell (ev->x, ev->y, id);
if (!cell) {
return false;
}
return button_press (ev, id);
CairoCell* cell = find_cell (ev->x, ev->y);
return button_press (ev, cell);
}
bool
CairoEditableText::on_button_release_event (GdkEventButton* ev)
{
uint32_t id;
CairoCell* cell = find_cell (ev->x, ev->y, id);
if (!cell) {
return false;
}
return button_release (ev, id);
CairoCell* cell = find_cell (ev->x, ev->y);
return button_release (ev, cell);
}
void
CairoEditableText::start_editing (uint32_t id)
CairoEditableText::start_editing (CairoCell* cell)
{
CairoCell* cell = get_cell (id);
stop_editing ();
if (cell) {
editing_id = id;
editing_cell = cell;
queue_draw_cell (cell);
grab_focus ();
}
@ -312,12 +287,9 @@ CairoEditableText::start_editing (uint32_t id)
void
CairoEditableText::stop_editing ()
{
if (editing_id) {
CairoCell* cell;
if ((cell = get_cell (editing_id))) {
queue_draw_cell (cell);
}
editing_id = 0;
if (editing_cell) {
queue_draw_cell (editing_cell);
editing_cell = 0;
}
}
@ -333,7 +305,7 @@ CairoEditableText::on_size_request (GtkRequisition* req)
CellMap::iterator i = cells.begin();
while (i != cells.end()) {
CairoCell* cell = i->second;
CairoCell* cell = (*i);
if (cell->visible()) {
cell->set_position (x, _ypad);
@ -378,8 +350,10 @@ CairoEditableText::set_font (const Pango::FontDescription& fd)
{
Glib::RefPtr<Pango::Context> context = get_pango_context ();
_font = fd;
for (CellMap::iterator i = cells.begin(); i != cells.end(); ++i) {
i->second->set_size (context, fd);
(*i)->set_size (context, _font);
}
queue_resize ();

View file

@ -28,9 +28,11 @@
class CairoCell
{
public:
CairoCell();
public:
CairoCell(int32_t id);
virtual ~CairoCell() {}
int32_t id() const { return _id; }
virtual void render (Cairo::RefPtr<Cairo::Context>&) = 0;
@ -61,7 +63,8 @@ public:
virtual void set_size (Glib::RefPtr<Pango::Context>&,
const Pango::FontDescription&) {}
protected:
protected:
int32_t _id;
GdkRectangle bbox;
bool _visible;
uint32_t _xpad;
@ -69,30 +72,32 @@ protected:
class CairoBarCell : public CairoCell
{
public:
CairoBarCell() {};
public:
CairoBarCell(int32_t id) : CairoCell (id) {};
void render (Cairo::RefPtr<Cairo::Context>& context) {
context->move_to (bbox.x, bbox.y);
context->set_line_width (bbox.width);
context->rel_line_to (0, bbox.height);
context->stroke ();
if (bbox.height > 4) {
context->move_to (bbox.x, bbox.y + 2);
context->set_line_width (bbox.width);
context->rel_line_to (0, bbox.height - 2);
context->stroke ();
}
}
void set_size (Glib::RefPtr<Pango::Context>& context,
const Pango::FontDescription& font) {
Pango::FontMetrics metrics = context->get_metrics (font);
bbox.width = 2;
bbox.width = std::max (1.5, (0.1 * metrics.get_approximate_digit_width() / PANGO_SCALE));
bbox.height = (metrics.get_ascent() + metrics.get_descent()) / PANGO_SCALE;
}
private:
private:
};
class CairoColonCell : public CairoCell
{
public:
CairoColonCell() {};
public:
CairoColonCell (int32_t id) : CairoCell (id) {};
void render (Cairo::RefPtr<Cairo::Context>& context);
void set_size (Glib::RefPtr<Pango::Context>& context,
@ -101,19 +106,23 @@ public:
class CairoTextCell : public CairoCell
{
public:
CairoTextCell (double width_chars);
public:
CairoTextCell (int32_t id, double width_chars);
void set_size (Glib::RefPtr<Pango::Context>&, const Pango::FontDescription&);
void set_text (const std::string& txt);
std::string get_text() const {
return layout->get_text ();
}
double width_chars() const { return _width_chars; }
void render (Cairo::RefPtr<Cairo::Context>&);
protected:
protected:
friend class CairoEditableText;
void set_width_chars (double wc) { _width_chars = wc; }
void set_text (const std::string& txt);
private:
double _width_chars;
Glib::RefPtr<Pango::Layout> layout;
};
@ -124,15 +133,17 @@ public:
CairoEditableText ();
~CairoEditableText ();
void add_cell (uint32_t id, CairoCell*);
CairoCell* get_cell (uint32_t id);
void add_cell (CairoCell*);
void clear_cells ();
void start_editing (uint32_t id);
void start_editing (CairoCell*);
void stop_editing ();
void set_text (uint32_t id, const std::string& text);
void set_text (CairoTextCell* cell, const std::string&);
void set_width_chars (CairoTextCell* cell, uint32_t);
void set_draw_background (bool yn) { _draw_bg = yn; }
void set_colors (double cr, double cg, double cb, double ca) {
r = cr;
g = cg;
@ -168,9 +179,9 @@ public:
double corner_radius() const { return _corner_radius; }
void set_corner_radius (double r) { _corner_radius = r; queue_draw (); }
sigc::signal<bool,GdkEventScroll*,uint32_t> scroll;
sigc::signal<bool,GdkEventButton*,uint32_t> button_press;
sigc::signal<bool,GdkEventButton*,uint32_t> button_release;
sigc::signal<bool,GdkEventScroll*,CairoCell*> scroll;
sigc::signal<bool,GdkEventButton*,CairoCell*> button_press;
sigc::signal<bool,GdkEventButton*,CairoCell*> button_release;
protected:
bool on_expose_event (GdkEventExpose*);
@ -183,11 +194,12 @@ protected:
bool on_scroll_event (GdkEventScroll*);
private:
typedef std::map<uint32_t,CairoCell*> CellMap;
typedef std::vector<CairoCell*> CellMap;
CellMap cells;
Pango::FontDescription font;
uint32_t editing_id;
Pango::FontDescription _font;
CairoCell* editing_cell;
bool _draw_bg;
double width;
double max_cell_height;
double height;
@ -207,7 +219,7 @@ private:
double bg_b;
double bg_a;
CairoCell* find_cell (uint32_t x, uint32_t y, uint32_t& cell_id);
CairoCell* find_cell (uint32_t x, uint32_t y);
void queue_draw_cell (CairoCell* target);
};