#include "pbd/enumwriter.h"
#include <gtkmm/style.h>
+#include <sigc++/bind.h>
#include "gtkmm2ext/cairocell.h"
#include "gtkmm2ext/utils.h"
#include "gtkmm2ext/rgb_macros.h"
-#include "ardour/ardour.h"
+#include "ardour/types.h"
#include "ardour/session.h"
#include "ardour/tempo.h"
#include "ardour/profile.h"
-#include "ardour/slave.h"
-#include <sigc++/bind.h>
#include "ardour_ui.h"
#include "audio_clock.h"
AudioClock::AudioClock (const string& clock_name, bool transient, const string& widget_name,
bool allow_edit, bool follows_playhead, bool duration, bool with_info)
- : _name (clock_name)
+ : ops_menu (0)
+ , _name (clock_name)
, is_transient (transient)
, is_duration (duration)
, editable (allow_edit)
, _off (false)
, _fixed_width (true)
, layout_x_offset (0)
- , ops_menu (0)
+ , em_width (0)
+ , _edit_by_click_field (false)
, editing_attr (0)
, foreground_attr (0)
, first_height (0)
info_attributes.change (*font_attr);
delete font_attr;
+
+ /* get the figure width for the font. This doesn't have to super
+ * accurate since we only use it to measure the (roughly 1 character)
+ * offset from the position Pango tells us for the "cursor"
+ */
+
+ Glib::RefPtr<Pango::Layout> tmp = Pango::Layout::create (get_pango_context());
+ int ignore_height;
+
+ tmp->set_text ("8");
+ tmp->get_pixel_size (em_width, ignore_height);
}
void
}
if (editing) {
- const double cursor_width = 12; /* need em width here, not 16 */
-
if (!insert_map.empty()) {
cairo_set_source_rgba (cr, cursor_r, cursor_g, cursor_b, cursor_a);
if (!_fixed_width) {
cairo_rectangle (cr,
- layout_x_offset + cursor.get_x()/PANGO_SCALE + cursor_width,
- 0,
+ min (get_width() - 2.0,
+ (double) cursor.get_x()/PANGO_SCALE + layout_x_offset + em_width), 0,
2.0, cursor.get_height()/PANGO_SCALE);
} else {
cairo_rectangle (cr,
- layout_x_offset + cursor.get_x()/PANGO_SCALE + cursor_width,
+ min (get_width() - 2.0,
+ (double) layout_x_offset + cursor.get_x()/PANGO_SCALE + em_width),
(upper_height - layout_height)/2.0,
2.0, cursor.get_height()/PANGO_SCALE);
}
/* left justify */
layout_x_offset = 0;
}
-
}
void
}
void
-AudioClock::start_edit ()
+AudioClock::start_edit (Field f)
{
pre_edit_string = _layout->get_text ();
if (!insert_map.empty()) {
input_string.clear ();
editing = true;
+ if (f) {
+ input_string = get_field (f);
+ show_edit_status (merge_input_and_edit_string ());
+ _layout->set_text (edit_string);
+ }
+
queue_draw ();
Keyboard::magic_widget_grab_focus ();
grab_focus ();
}
+string
+AudioClock::get_field (Field f)
+{
+ switch (f) {
+ case Timecode_Hours:
+ return edit_string.substr (1, 2);
+ break;
+ case Timecode_Minutes:
+ return edit_string.substr (4, 2);
+ break;
+ case Timecode_Seconds:
+ return edit_string.substr (7, 2);
+ break;
+ case Timecode_Frames:
+ return edit_string.substr (10, 2);
+ break;
+ case MS_Hours:
+ return edit_string.substr (1, 2);
+ break;
+ case MS_Minutes:
+ return edit_string.substr (4, 2);
+ break;
+ case MS_Seconds:
+ return edit_string.substr (7, 2);
+ break;
+ case MS_Milliseconds:
+ return edit_string.substr (10, 3);
+ break;
+ case Bars:
+ return edit_string.substr (1, 3);
+ break;
+ case Beats:
+ return edit_string.substr (5, 2);
+ break;
+ case Ticks:
+ return edit_string.substr (8, 4);
+ break;
+ case AudioFrames:
+ return edit_string;
+ break;
+ }
+ return "";
+}
+
void
AudioClock::end_edit (bool modify)
{
break;
case MinSec:
+ ok = minsec_validate_edit (edit_string);
break;
case Frames:
}
framecnt_t
-AudioClock::parse_as_bbt_distance (const std::string& str)
+AudioClock::parse_as_bbt_distance (const std::string&)
{
return 0;
}
void
AudioClock::end_edit_relative (bool add)
{
+ bool ok = true;
+
+ switch (_mode) {
+ case Timecode:
+ ok = timecode_validate_edit (edit_string);
+ break;
+
+ case BBT:
+ ok = bbt_validate_edit (edit_string);
+ break;
+
+ case MinSec:
+ ok = minsec_validate_edit (edit_string);
+ break;
+
+ case Frames:
+ break;
+ }
+
+ if (!ok) {
+ edit_string = pre_edit_string;
+ input_string.clear ();
+ _layout->set_text (edit_string);
+ show_edit_status (0);
+ /* edit attributes remain in use */
+ queue_draw ();
+ return;
+ }
+
framecnt_t frames = parse_as_distance (input_string);
editing = false;
}
void
-AudioClock::set_minsec (framepos_t when, bool force)
+AudioClock::set_minsec (framepos_t when, bool /*force*/)
{
char buf[32];
framecnt_t left;
}
void
-AudioClock::set_timecode (framepos_t when, bool force)
+AudioClock::set_timecode (framepos_t when, bool /*force*/)
{
char buf[32];
Timecode::Time TC;
}
void
-AudioClock::set_bbt (framepos_t when, bool force)
+AudioClock::set_bbt (framepos_t when, bool /*force*/)
{
char buf[16];
Timecode::BBT_Time BBT;
sprintf (buf, "%-5.2f", m.tempo().beats_per_minute());
_left_layout->set_text (buf);
- sprintf (buf, "%g/%g", m.meter().beats_per_bar(), m.meter().note_divisor());
+ sprintf (buf, "%g/%g", m.meter().divisions_per_bar(), m.meter().note_divisor());
_right_layout->set_text (buf);
}
}
string new_text;
char new_char = 0;
+ int highlight_length;
+ framepos_t pos;
switch (ev->keyval) {
case GDK_0:
use_input_string:
- int highlight_length = 0;
- framepos_t pos;
-
- /* merge with pre-edit-string into edit string */
-
switch (_mode) {
case Frames:
/* get this one in the right order, and to the right width */
- if (ev->keyval != GDK_Delete && ev->keyval != GDK_BackSpace) {
- edit_string.push_back (new_char);
- } else {
+ if (ev->keyval == GDK_Delete || ev->keyval == GDK_BackSpace) {
edit_string = edit_string.substr (0, edit_string.length() - 1);
+ } else {
+ edit_string.push_back (new_char);
}
if (!edit_string.empty()) {
char buf[32];
/* highlight the whole thing */
highlight_length = edit_string.length();
break;
-
- default:
- edit_string = pre_edit_string;
- if (input_string.empty()) {
- highlight_length = 0;
- } else {
- // for (int i = input_string.length() - 1; i >= 0; --i) {
- string::size_type target;
- for (string::size_type i = 0; i < input_string.length(); ++i) {
- target = insert_map[input_string.length() - 1 - i];
- edit_string[target] = input_string[i];
- }
- /* highlight from end to wherever the last character was added */
- highlight_length = edit_string.length() - insert_map[input_string.length()-1];
- }
- break;
+ default:
+ highlight_length = merge_input_and_edit_string ();
}
-
-
+
show_edit_status (highlight_length);
_layout->set_text (edit_string);
queue_draw ();
return true;
}
+int
+AudioClock::merge_input_and_edit_string ()
+{
+ /* merge with pre-edit-string into edit string */
+
+ edit_string = pre_edit_string;
+
+ if (input_string.empty()) {
+ return 0;
+ }
+
+ string::size_type target;
+ for (string::size_type i = 0; i < input_string.length(); ++i) {
+ target = insert_map[input_string.length() - 1 - i];
+ edit_string[target] = input_string[i];
+ }
+ /* highlight from end to wherever the last character was added */
+ return edit_string.length() - insert_map[input_string.length()-1];
+}
+
bool
AudioClock::on_key_release_event (GdkEventKey *ev)
switch (ev->button) {
case 1:
if (editable && !_off) {
- dragging = true;
- /* make absolutely sure that the pointer is grabbed */
- gdk_pointer_grab(ev->window,false ,
- GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK),
- NULL,NULL,ev->time);
- drag_accum = 0;
- drag_start_y = ev->y;
- drag_y = ev->y;
-
int index;
int trailing;
int y;
y = ev->y - ((upper_height - layout_height)/2);
x = ev->x - layout_x_offset;
- if (_layout->xy_to_index (x * PANGO_SCALE, y * PANGO_SCALE, index, trailing)) {
+ if (_layout->xy_to_index (x * PANGO_SCALE, y * PANGO_SCALE, index, trailing)) {
drag_field = index_to_field (index);
- } else {
- drag_field = Field (0);
+ dragging = true;
+ /* make absolutely sure that the pointer is grabbed */
+ gdk_pointer_grab(ev->window,false ,
+ GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK),
+ NULL,NULL,ev->time);
+ drag_accum = 0;
+ drag_start_y = ev->y;
+ drag_y = ev->y;
}
}
break;
return true;
} else {
if (ev->button == 1) {
- start_edit ();
+
+ if (_edit_by_click_field) {
+
+ int index = 0;
+ int trailing;
+ int y = ev->y - ((upper_height - layout_height)/2);
+ int x = ev->x - layout_x_offset;
+ Field f;
+
+ if (!_layout->xy_to_index (x * PANGO_SCALE, y * PANGO_SCALE, index, trailing)) {
+ return true;
+ }
+
+ f = index_to_field (index);
+
+ switch (f) {
+ case Timecode_Frames:
+ case MS_Milliseconds:
+ case Ticks:
+ f = Field (0);
+ break;
+ default:
+ break;
+ }
+ start_edit (f);
+ } else {
+ start_edit ();
+ }
}
}
-
}
}
int dir;
dir = (drag_accum < 0 ? 1:-1);
pos = current_time();
- frames = get_frame_step (drag_field,pos,dir);
+ frames = get_frame_step (drag_field, pos, dir);
if (frames != 0 && frames * drag_accum < current_time()) {
set ((framepos_t) floor (pos - drag_accum * frames), false); // minus because up is negative in GTK
}
framepos_t
-AudioClock::current_time (framepos_t pos) const
+AudioClock::current_time (framepos_t) const
{
return last_when;
}
if (sscanf (str.c_str(), BBT_SCANF_FORMAT, &any.bbt.bars, &any.bbt.beats, &any.bbt.ticks) != 3) {
return false;
}
-
+
+ if (any.bbt.ticks > Timecode::BBT_Time::ticks_per_beat) {
+ return false;
+ }
+
if (!is_duration && any.bbt.bars == 0) {
return false;
}
}
bool
-AudioClock::timecode_validate_edit (const string& str)
+AudioClock::timecode_validate_edit (const string&)
{
Timecode::Time TC;
return false;
}
- if (TC.minutes > 59U || TC.seconds > 59U) {
+ if (TC.hours > 23U || TC.minutes > 59U || TC.seconds > 59U) {
return false;
}
- if (TC.frames > (long)rint(_session->timecode_frames_per_second()) - 1) {
+ if (TC.frames > (uint32_t) rint (_session->timecode_frames_per_second()) - 1) {
return false;
}
return true;
}
+bool
+AudioClock::minsec_validate_edit (const string& str)
+{
+ int hrs, mins, secs, millisecs;
+
+ if (sscanf (str.c_str(), "%d:%d:%d.%d", &hrs, &mins, &secs, &millisecs) != 4) {
+ return false;
+ }
+
+ if (hrs > 23 || mins > 59 || secs > 59 || millisecs > 999) {
+ return false;
+ }
+
+ return true;
+}
+
framepos_t
AudioClock::frames_from_timecode_string (const string& str) const
{
Timecode::BBT_Time bbt;
- if (sscanf (str.c_str(), BBT_SCANF_FORMAT, &bbt.bars, &bbt.beats, &bbt.ticks) != 0) {
+ if (sscanf (str.c_str(), BBT_SCANF_FORMAT, &bbt.bars, &bbt.beats, &bbt.ticks) != 3) {
return 0;
}
-
+
return _session->tempo_map().bbt_duration_at(pos,bbt,1);
}
void
AudioClock::focus ()
{
- start_edit ();
+ start_edit (Field (0));
}
void