13
0

(merge from 2.0-ongoing -r1911:1912) fix audio clock handling of key press; fix crash bug caused by mapping over a region list selection that includes rows without regions; also merge sampo's redirect undo/state fixes from 2.0-ongoing

git-svn-id: svn://localhost/ardour2/trunk@1913 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2007-05-23 00:06:16 +00:00
parent dc348fb613
commit 376c5381ed
8 changed files with 241 additions and 62 deletions

View File

@ -337,6 +337,18 @@ AudioClock::setup_events ()
ms_minutes_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Minutes));
ms_seconds_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Seconds));
hours_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), SMPTE_Hours));
minutes_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), SMPTE_Minutes));
seconds_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), SMPTE_Seconds));
frames_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), SMPTE_Frames));
audio_frames_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), AudioFrames));
bars_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), Bars));
beats_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), Beats));
ticks_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), Ticks));
ms_hours_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), MS_Hours));
ms_minutes_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), MS_Minutes));
ms_seconds_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), MS_Seconds));
hours_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), SMPTE_Hours));
minutes_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), SMPTE_Minutes));
seconds_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), SMPTE_Seconds));
@ -372,6 +384,15 @@ AudioClock::setup_events ()
ms_hours_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), MS_Hours));
ms_minutes_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), MS_Minutes));
ms_seconds_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), MS_Seconds));
clock_base.signal_focus_in_event().connect (mem_fun (*this, &AudioClock::drop_focus_handler));
}
bool
AudioClock::drop_focus_handler (GdkEventFocus* ignored)
{
Keyboard::magic_widget_drop_focus ();
return false;
}
void
@ -633,6 +654,13 @@ AudioClock::set_session (Session *s)
}
}
bool
AudioClock::field_key_press_event (GdkEventKey *ev, Field field)
{
/* all key activity is handled on key release */
return true;
}
bool
AudioClock::field_key_release_event (GdkEventKey *ev, Field field)
{
@ -679,7 +707,7 @@ AudioClock::field_key_release_event (GdkEventKey *ev, Field field)
label = &ticks_label;
break;
default:
return FALSE;
return false;
}
switch (ev->keyval) {
@ -729,22 +757,22 @@ AudioClock::field_key_release_event (GdkEventKey *ev, Field field)
if (_mode == MinSec && field == MS_Seconds) {
new_char = '.';
} else {
return FALSE;
return false;
}
break;
case GDK_Return:
case GDK_KP_Enter:
case GDK_Tab:
move_on = true;
break;
case GDK_Escape:
case GDK_Return:
case GDK_KP_Enter:
clock_base.grab_focus ();
return TRUE;
return true;
default:
return FALSE;
return false;
}
if (!move_on) {
@ -865,7 +893,7 @@ AudioClock::field_key_release_event (GdkEventKey *ev, Field field)
}
return TRUE;
return true;
}
bool
@ -873,6 +901,8 @@ AudioClock::field_focus_in_event (GdkEventFocus *ev, Field field)
{
key_entry_state = 0;
Keyboard::magic_widget_grab_focus ();
switch (field) {
case SMPTE_Hours:
hours_ebox.set_flags (Gtk::HAS_FOCUS);
@ -922,7 +952,7 @@ AudioClock::field_focus_in_event (GdkEventFocus *ev, Field field)
break;
}
return FALSE;
return false;
}
bool
@ -979,21 +1009,20 @@ AudioClock::field_focus_out_event (GdkEventFocus *ev, Field field)
break;
}
return FALSE;
Keyboard::magic_widget_drop_focus ();
return false;
}
bool
AudioClock::field_button_release_event (GdkEventButton *ev, Field field)
{
if (dragging) {
gdk_pointer_ungrab(GDK_CURRENT_TIME);
gdk_pointer_ungrab (GDK_CURRENT_TIME);
dragging = false;
if (ev->y > drag_start_y+1 || ev->y < drag_start_y-1 || Keyboard::modifier_state_equals (ev->state, Keyboard::Shift)){
// we actually dragged so return without setting editing focus, or we shift clicked
return TRUE;
// we actually dragged so return without setting editing focus, or we shift clicked
return true;
}
}
@ -1002,7 +1031,7 @@ AudioClock::field_button_release_event (GdkEventButton *ev, Field field)
build_ops_menu ();
}
ops_menu->popup (1, ev->time);
return TRUE;
return true;
}
if (Keyboard::is_context_menu_event (ev)) {
@ -1010,7 +1039,7 @@ AudioClock::field_button_release_event (GdkEventButton *ev, Field field)
build_ops_menu ();
}
ops_menu->popup (1, ev->time);
return TRUE;
return true;
}
switch (ev->button) {
@ -1059,13 +1088,13 @@ AudioClock::field_button_release_event (GdkEventButton *ev, Field field)
break;
}
return TRUE;
return true;
}
bool
AudioClock::field_button_press_event (GdkEventButton *ev, Field field)
{
if (session == 0) return FALSE;
if (session == 0) return false;
nframes_t frames = 0;
@ -1077,7 +1106,7 @@ AudioClock::field_button_press_event (GdkEventButton *ev, Field field)
}
/* make absolutely sure that the pointer is grabbed */
gdk_pointer_grab(ev->window,FALSE ,
gdk_pointer_grab(ev->window,false ,
GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK),
NULL,NULL,ev->time);
dragging = true;
@ -1095,21 +1124,23 @@ AudioClock::field_button_press_event (GdkEventButton *ev, Field field)
case 3:
/* used for context sensitive menu */
return FALSE;
return false;
break;
default:
return FALSE;
return false;
break;
}
return TRUE;
return true;
}
bool
AudioClock::field_button_scroll_event (GdkEventScroll *ev, Field field)
{
if (session == 0) return FALSE;
if (session == 0) {
return false;
}
nframes_t frames = 0;
@ -1144,18 +1175,18 @@ AudioClock::field_button_scroll_event (GdkEventScroll *ev, Field field)
break;
default:
return FALSE;
return false;
break;
}
return TRUE;
return true;
}
bool
AudioClock::field_motion_notify_event (GdkEventMotion *ev, Field field)
{
if (session == 0 || !dragging) {
return FALSE;
return false;
}
float pixel_frame_scale_factor = 0.2f;
@ -1202,7 +1233,7 @@ AudioClock::field_motion_notify_event (GdkEventMotion *ev, Field field)
}
return TRUE;
return true;
}
nframes_t

View File

@ -62,6 +62,8 @@ class AudioClock : public Gtk::HBox
static sigc::signal<void> ModeChanged;
static std::vector<AudioClock*> clocks;
static bool has_focus() { return _has_focus; }
private:
ARDOUR::Session *session;
Mode _mode;
@ -173,9 +175,11 @@ class AudioClock : public Gtk::HBox
bool field_button_press_event (GdkEventButton *ev, Field);
bool field_button_release_event (GdkEventButton *ev, Field);
bool field_button_scroll_event (GdkEventScroll *ev, Field);
bool field_key_press_event (GdkEventKey *, Field);
bool field_key_release_event (GdkEventKey *, Field);
bool field_focus_in_event (GdkEventFocus *, Field);
bool field_focus_out_event (GdkEventFocus *, Field);
bool drop_focus_handler (GdkEventFocus*);
void set_smpte (nframes_t, bool);
void set_bbt (nframes_t, bool);
@ -198,6 +202,8 @@ class AudioClock : public Gtk::HBox
void set_size_requests ();
static const uint32_t field_length[(int)AudioFrames+1];
static bool _has_focus;
};
#endif /* __audio_clock_h__ */

View File

@ -231,12 +231,19 @@ Editor::region_list_selection_changed()
TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
TreeIter iter;
/* just set the first selected region (in fact, the selection model might be SINGLE, which
means there can only be one.
*/
if ((iter = region_list_model->get_iter (*i))) {
set_selected_regionview_from_region_list (((*iter)[region_list_columns.region]), Selection::Set);
boost::shared_ptr<Region> r = (*iter)[region_list_columns.region];
/* they could have clicked on a row that is just a placeholder, like "Hidden" */
if (r) {
/* just set the first selected region (in fact, the selection model might be SINGLE, which
means there can only be one.
*/
set_selected_regionview_from_region_list (r, Selection::Set);
}
}
}
}
@ -564,7 +571,16 @@ Editor::region_list_selection_mapover (slot<void,boost::shared_ptr<Region> > sl)
TreeIter iter;
if ((iter = region_list_model->get_iter (*i))) {
sl (((*iter)[region_list_columns.region]));
/* some rows don't have a region associated with them, but can still be
selected (XXX maybe prevent them from being selected)
*/
boost::shared_ptr<Region> r = (*iter)[region_list_columns.region];
if (r) {
sl (r);
}
}
}
}

View File

@ -54,6 +54,25 @@ Keyboard* Keyboard::_the_keyboard = 0;
GdkModifierType Keyboard::RelevantModifierKeyMask;
bool Keyboard::_some_magic_widget_has_focus = false;
void
Keyboard::magic_widget_grab_focus ()
{
_some_magic_widget_has_focus = true;
}
void
Keyboard::magic_widget_drop_focus ()
{
_some_magic_widget_has_focus = false;
}
bool
Keyboard::some_magic_widget_has_focus ()
{
return _some_magic_widget_has_focus;
}
Keyboard::Keyboard ()
{

View File

@ -90,6 +90,10 @@ class Keyboard : public sigc::trackable, Stateful
static Keyboard& the_keyboard() { return *_the_keyboard; }
static bool some_magic_widget_has_focus ();
static void magic_widget_grab_focus ();
static void magic_widget_drop_focus ();
private:
static Keyboard* _the_keyboard;
@ -104,6 +108,8 @@ class Keyboard : public sigc::trackable, Stateful
static gint _snooper (GtkWidget*, GdkEventKey*, gpointer);
gint snooper (GtkWidget*, GdkEventKey*);
static bool _some_magic_widget_has_focus;
};
#endif /* __ardour_keyboard_h__ */

View File

@ -347,14 +347,14 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
#endif
if (focus) {
if (GTK_IS_ENTRY(focus)) {
if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
special_handling_of_unmodified_accelerators = true;
}
}
#ifdef DEBUG_ACCELERATOR_HANDLING
if (debug) {
cerr << "Key event: code = " << ev->keyval << " state = " << hex << ev->state << dec << " focus is an entry ? "
cerr << "Win = " << win << " Key event: code = " << ev->keyval << " state = " << hex << ev->state << dec << " special handling ? "
<< special_handling_of_unmodified_accelerators
<< endl;
}
@ -456,14 +456,25 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
/* no modifiers, propagate first */
#ifdef DEBUG_ACCELERATOR_HANDLING
if (debug) {
cerr << "\tactivate, then propagate\n";
}
if (debug) {
cerr << "\tpropagate, then activate\n";
}
#endif
if (!gtk_window_propagate_key_event (win, ev)) {
#ifdef DEBUG_ACCELERATOR_HANDLING
if (debug) {
cerr << "\tpropagation didn't handle, so activate\n";
}
#endif
return gtk_window_activate_key (win, ev);
}
} else {
#ifdef DEBUG_ACCELERATOR_HANDLING
if (debug) {
cerr << "\thandled by propagate\n";
}
#endif
return true;
}
#ifdef DEBUG_ACCELERATOR_HANDLING
if (debug) {

View File

@ -324,7 +324,8 @@ class Route : public IO
uint32_t pans_required() const;
ChanCount n_process_buffers ();
virtual int _set_state (const XMLNode&, bool call_base);
virtual int _set_state (const XMLNode&, bool call_base);
virtual void _set_redirect_states (const XMLNodeList&);
private:
void init ();

View File

@ -1804,34 +1804,27 @@ Route::_set_state (const XMLNode& node, bool call_base)
break;
}
}
XMLNodeList redirect_nodes;
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
child = *niter;
if (child->name() == X_("Send")) {
if (child->name() == X_("Send") || child->name() == X_("Insert")) {
redirect_nodes.push_back(child);
}
}
_set_redirect_states(redirect_nodes);
if (!IO::ports_legal) {
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
child = *niter;
// All redirects (sends and inserts) have been applied already
deferred_state->add_child_copy (*child);
} else {
add_redirect_from_xml (*child);
}
} else if (child->name() == X_("Insert")) {
if (!IO::ports_legal) {
deferred_state->add_child_copy (*child);
} else {
add_redirect_from_xml (*child);
}
} else if (child->name() == X_("Automation")) {
if (child->name() == X_("Automation")) {
if ((prop = child->property (X_("path"))) != 0) {
load_automation (prop->value());
@ -1888,6 +1881,102 @@ Route::_set_state (const XMLNode& node, bool call_base)
return 0;
}
void
Route::_set_redirect_states(const XMLNodeList &nlist)
{
XMLNodeConstIterator niter;
char buf[64];
RedirectList::iterator i, o;
// Iterate through existing redirects, remove those which are not in the state list
for (i = _redirects.begin(); i != _redirects.end(); ) {
RedirectList::iterator tmp = i;
++tmp;
bool redirectInStateList = false;
(*i)->id().print (buf, sizeof (buf));
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if (strncmp(buf,(*niter)->child(X_("Redirect"))->child(X_("IO"))->property(X_("id"))->value().c_str(), sizeof(buf)) == 0) {
redirectInStateList = true;
break;
}
}
if (!redirectInStateList) {
remove_redirect ( *i, this);
}
i = tmp;
}
// Iterate through state list and make sure all redirects are on the track and in the correct order,
// set the state of existing redirects according to the new state on the same go
i = _redirects.begin();
for (niter = nlist.begin(); niter != nlist.end(); ++niter, ++i) {
// Check whether the next redirect in the list
o = i;
while (o != _redirects.end()) {
(*o)->id().print (buf, sizeof (buf));
if ( strncmp(buf, (*niter)->child(X_("Redirect"))->child(X_("IO"))->property(X_("id"))->value().c_str(), sizeof(buf)) == 0)
break;
++o;
}
if (o == _redirects.end()) {
// If the redirect (*niter) is not on the route, we need to create it
// and move it to the correct location
RedirectList::iterator prev_last = _redirects.end();
--prev_last; // We need this to check whether adding succeeded
add_redirect_from_xml (**niter);
RedirectList::iterator last = _redirects.end();
--last;
if (prev_last == last) {
cerr << "Could not fully restore state as some redirects were not possible to create" << endl;
continue;
}
boost::shared_ptr<Redirect> tmp = (*last);
// remove the redirect from the wrong location
_redirects.erase(last);
// insert the new redirect at the current location
_redirects.insert(i, tmp);
--i; // move pointer to the newly inserted redirect
continue;
}
// We found the redirect (*niter) on the route, first we must make sure the redirect
// is at the location provided in the XML state
if (i != o) {
boost::shared_ptr<Redirect> tmp = (*o);
// remove the old copy
_redirects.erase(o);
// insert the redirect at the correct location
_redirects.insert(i, tmp);
--i; // move pointer so it points to the right redirect
}
(*i)->set_state( (**niter) );
}
redirects_changed(this);
}
void
Route::curve_reallocate ()
{