stop playing silly games with widget packing when editing a route name in the edito

Use a FloatingTextEntry instead. All clever functionality from previous
implementation has been retained.
This commit is contained in:
Paul Davis 2016-05-21 19:17:11 -04:00
parent 30d0b2a354
commit 428ed8ae1b
9 changed files with 118 additions and 193 deletions

View File

@ -798,25 +798,10 @@ style "audio_bus_metrics_inactive" = "track_controls_inactive"
font_name = ""
}
style "track_name_display" = "medium_text"
style "track_name_editor" = "medium_text"
{
xthickness = 0
ythickness = 0
fg[NORMAL] = @foreground
fg[ACTIVE] = @foreground
fg[SELECTED] = @foreground
text[NORMAL] = @foreground
text[ACTIVE] = @foreground
text[SELECTED] = @foreground
base[NORMAL] = @bases
base[ACTIVE] = @bg_selected
base[SELECTED] = @bg_selected
bg[NORMAL] = lighter(@bases)
bg[ACTIVE] = lighter(@bases)
bg[SELECTED] = lighter(@bases)
}
style "track_separator"
@ -1106,8 +1091,8 @@ widget "*AudioBusFader" style:highest "audio_bus_fader"
widget "*BusControlsBaseUnselected" style:highest "audio_bus_base"
widget "*TrackSeparator" style:highest "track_separator"
widget "*EditorTrackNameDisplay" style:highest "track_name_display"
widget "*EditorTrackNameDisplay*" style:highest "track_name_display"
widget "*TrackNameEditor" style:highest "track_name_editor"
widget "*TrackNameEditor*" style:highest "track_name_editor"
widget "*CrossfadeEditAuditionButton" style:highest "bright_when_active"
widget "*CrossfadeEditAuditionButton*" style:highest "bright_when_active"
widget "*CrossfadeEditCurveButton" style:highest "bright_when_active"

View File

@ -30,6 +30,7 @@
FloatingTextEntry::FloatingTextEntry (Gtk::Window* parent, const std::string& initial_contents)
: Gtk::Window (Gtk::WINDOW_POPUP)
, entry_changed (false)
, by_popup_menu (false)
{
set_name (X_("FloatingTextEntry"));
set_position (Gtk::WIN_POS_MOUSE);
@ -42,8 +43,13 @@ FloatingTextEntry::FloatingTextEntry (Gtk::Window* parent, const std::string& in
entry.show ();
entry.signal_changed().connect (sigc::mem_fun (*this, &FloatingTextEntry::changed));
entry.signal_activate().connect (sigc::mem_fun (*this, &FloatingTextEntry::activated));
entry.signal_key_press_event().connect (sigc::mem_fun (*this, &FloatingTextEntry::key_press));
entry.signal_key_press_event().connect (sigc::mem_fun (*this, &FloatingTextEntry::key_press), false);
entry.signal_key_release_event().connect (sigc::mem_fun (*this, &FloatingTextEntry::key_release), false);
entry.signal_button_press_event().connect (sigc::mem_fun (*this, &FloatingTextEntry::button_press));
entry.signal_populate_popup().connect (sigc::mem_fun (*this, &FloatingTextEntry::populate_popup));
entry.select_region (0, -1);
entry.set_state (Gtk::STATE_SELECTED);
if (parent) {
parent->signal_focus_out_event().connect (sigc::mem_fun (*this, &FloatingTextEntry::entry_focus_out));
@ -52,6 +58,12 @@ FloatingTextEntry::FloatingTextEntry (Gtk::Window* parent, const std::string& in
add (entry);
}
void
FloatingTextEntry::populate_popup (Gtk::Menu *)
{
by_popup_menu = true;
}
void
FloatingTextEntry::changed ()
{
@ -69,9 +81,14 @@ FloatingTextEntry::on_realize ()
bool
FloatingTextEntry::entry_focus_out (GdkEventFocus* ev)
{
if (by_popup_menu) {
by_popup_menu = false;
return false;
}
entry.remove_modal_grab ();
if (entry_changed) {
use_text (entry.get_text ());
use_text (entry.get_text (), 0);
}
delete_when_idle ( this);
@ -92,7 +109,7 @@ FloatingTextEntry::button_press (GdkEventButton* ev)
Glib::signal_idle().connect (sigc::bind_return (sigc::bind (sigc::ptr_fun (gtk_main_do_event), gdk_event_copy ((GdkEvent*) ev)), false));
if (entry_changed) {
use_text (entry.get_text ());
use_text (entry.get_text (), 0);
}
delete_when_idle ( this);
@ -103,24 +120,54 @@ FloatingTextEntry::button_press (GdkEventButton* ev)
void
FloatingTextEntry::activated ()
{
use_text (entry.get_text()); // EMIT SIGNAL
use_text (entry.get_text(), 0); // EMIT SIGNAL
delete_when_idle (this);
}
bool
FloatingTextEntry::key_press (GdkEventKey* ev)
{
/* steal escape, tabs from GTK */
switch (ev->keyval) {
case GDK_Escape:
delete_when_idle (this);
case GDK_ISO_Left_Tab:
case GDK_Tab:
return true;
break;
default:
break;
}
return false;
}
bool
FloatingTextEntry::key_release (GdkEventKey* ev)
{
switch (ev->keyval) {
case GDK_Escape:
/* cancel edit */
delete_when_idle (this);
return true;
case GDK_ISO_Left_Tab:
/* Shift+Tab Keys Pressed. Note that for Shift+Tab, GDK actually
* generates a different ev->keyval, rather than setting
* ev->state.
*/
use_text (entry.get_text(), -1); // EMIT SIGNAL, move to prev
delete_when_idle (this);
return true;
case GDK_Tab:
use_text (entry.get_text(), 1); // EMIT SIGNAL, move to next
delete_when_idle (this);
return true;
default:
break;
}
return false;
}
void
FloatingTextEntry::on_hide ()
{

View File

@ -28,18 +28,27 @@ class FloatingTextEntry : public Gtk::Window
public:
FloatingTextEntry (Gtk::Window* parent, const std::string& initial_contents);
sigc::signal1<void,std::string> use_text;
/* 1st argument to handler is the new text
* 2nd argument is 0, 1 or -1 to indicate:
* - do not move to next editable field
* - move to next editable field
* - move to previous editable field.
*/
sigc::signal2<void,std::string,int> use_text;
private:
Gtk::Entry entry;
bool entry_changed;
bool by_popup_menu;
/* handlers for Entry events */
bool entry_focus_out (GdkEventFocus*);
bool entry_focus_out (GdkEventFocus*);
bool key_press (GdkEventKey*);
bool key_release (GdkEventKey*);
void activated ();
bool button_press (GdkEventButton*);
void changed ();
void populate_popup (Gtk::Menu*);
/* handlers for window events */
@ -48,4 +57,3 @@ class FloatingTextEntry : public Gtk::Window
};
#endif // __ardour_window_h__

View File

@ -171,7 +171,7 @@ RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
playlist_button.set_name ("route button");
automation_button.set_name ("route button");
route_group_button.signal_button_release_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::route_group_click), false);
route_group_button.signal_button_release_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::route_group_click), false);
playlist_button.signal_clicked.connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click));
automation_button.signal_clicked.connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click));
@ -470,7 +470,7 @@ RouteTimeAxisView::take_name_changed (void *src)
void
RouteTimeAxisView::playlist_click ()
{
build_playlist_menu ();
build_playlist_menu ();
conditionally_add_to_selection ();
playlist_action_menu->popup (1, gtk_get_current_event_time());
}
@ -1428,33 +1428,30 @@ RouteTimeAxisView::playlist () const
}
}
void
RouteTimeAxisView::name_entry_changed ()
bool
RouteTimeAxisView::name_entry_changed (string const& str)
{
TimeAxisView::name_entry_changed ();
string x = name_entry->get_text ();
if (x == _route->name()) {
return;
if (str == _route->name()) {
return true;
}
string x = str;
strip_whitespace_edges (x);
if (x.length() == 0) {
name_entry->set_text (_route->name());
return;
if (x.empty()) {
return false;
}
if (_session->route_name_internal (x)) {
ARDOUR_UI::instance()->popup_error (string_compose (_("You cannot create a track with that name as it is reserved for %1"),
PROGRAM_NAME));
name_entry->grab_focus ();
ARDOUR_UI::instance()->popup_error (string_compose (_("The name \"%1\" is reserved for %2"), x, PROGRAM_NAME));
return false;
} else if (RouteUI::verify_new_route_name (x)) {
_route->set_name (x);
} else {
name_entry->grab_focus ();
return true;
}
return false;
}
boost::shared_ptr<Region>

View File

@ -207,7 +207,7 @@ protected:
void take_name_changed (void *src);
void route_property_changed (const PBD::PropertyChange&);
void name_entry_changed ();
bool name_entry_changed (std::string const&);
void blink_rec_display (bool onoff);

View File

@ -42,6 +42,7 @@
#include "ardour/profile.h"
#include "ardour_dialog.h"
#include "floating_text_entry.h"
#include "gui_thread.h"
#include "public_editor.h"
#include "time_axis_view.h"
@ -102,9 +103,6 @@ TimeAxisView::TimeAxisView (ARDOUR::Session* sess, PublicEditor& ed, TimeAxisVie
, _canvas_display (0)
, _y_position (0)
, _editor (ed)
, name_entry (0)
, ending_name_edit (false)
, by_popup_menu (false)
, control_parent (0)
, _order (0)
, _effective_height (0)
@ -610,148 +608,42 @@ TimeAxisView::set_height (uint32_t h, TrackHeightMode m)
_editor.override_visible_track_count ();
}
bool
TimeAxisView::name_entry_key_press (GdkEventKey* ev)
{
/* steal escape, tabs from GTK */
switch (ev->keyval) {
case GDK_Escape:
case GDK_ISO_Left_Tab:
case GDK_Tab:
return true;
}
return false;
}
bool
TimeAxisView::name_entry_key_release (GdkEventKey* ev)
{
TrackViewList::iterator i;
switch (ev->keyval) {
case GDK_Escape:
end_name_edit (RESPONSE_CANCEL);
return true;
case GDK_ISO_Left_Tab:
/* Shift+Tab Keys Pressed. Note that for Shift+Tab, GDK actually
* generates a different ev->keyval, rather than setting
* ev->state.
*/
end_name_edit (RESPONSE_APPLY);
return true;
case GDK_Tab:
end_name_edit (RESPONSE_ACCEPT);
return true;
default:
break;
}
return false;
}
bool
TimeAxisView::name_entry_focus_out (GdkEventFocus*)
{
if (by_popup_menu) {
by_popup_menu = false;
return false;
}
end_name_edit (RESPONSE_OK);
return false;
}
void
TimeAxisView::name_entry_populate_popup (Gtk::Menu *)
{
by_popup_menu = true;
}
void
TimeAxisView::begin_name_edit ()
{
if (name_entry) {
if (!can_edit_name()) {
return;
}
if (can_edit_name()) {
Gtk::Window* toplevel = (Gtk::Window*) control_parent->get_toplevel();
FloatingTextEntry* fte = new FloatingTextEntry (toplevel, name_label.get_text ());
name_entry = manage (new Gtkmm2ext::FocusEntry);
fte->set_name ("TrackNameEditor");
fte->use_text.connect (sigc::mem_fun (*this, &TimeAxisView::end_name_edit));
name_entry->set_width_chars(8); // min width, entry expands
/* We want to new toplevel window to overlay the name label, so
* translate the coordinates of the upper left corner of the name label
* into the coordinate space of the top level window.
*/
name_entry->set_name ("EditorTrackNameDisplay");
name_entry->signal_key_press_event().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_key_press), false);
name_entry->signal_key_release_event().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_key_release), false);
name_entry->signal_focus_out_event().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_focus_out));
name_entry->set_text (name_label.get_text());
name_entry->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &TimeAxisView::end_name_edit), RESPONSE_OK));
name_entry->signal_populate_popup().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_populate_popup));
int x, y;
int wx, wy;
if (name_label.is_ancestor (name_hbox)) {
name_hbox.remove (name_label);
}
name_label.translate_coordinates (*toplevel, 0, 0, x, y);
toplevel->get_window()->get_origin (wx, wy);
name_hbox.pack_end (*name_entry, true, true);
name_entry->show ();
name_entry->select_region (0, -1);
name_entry->set_state (STATE_SELECTED);
name_entry->grab_focus ();
name_entry->start_editing (0);
}
fte->move (wx + x, wy + y);
fte->present ();
}
void
TimeAxisView::end_name_edit (int response)
TimeAxisView::end_name_edit (std::string str, int next_dir)
{
if (!name_entry) {
return;
if (!name_entry_changed (str)) {
next_dir = 0;
}
if (ending_name_edit) {
/* already doing this, and focus out or other event has caused
us to re-enter this code.
*/
return;
}
PBD::Unwinder<bool> uw (ending_name_edit, true);
bool edit_next = false;
bool edit_prev = false;
switch (response) {
case RESPONSE_CANCEL:
break;
case RESPONSE_OK:
name_entry_changed ();
break;
case RESPONSE_ACCEPT:
name_entry_changed ();
edit_next = true;
case RESPONSE_APPLY:
name_entry_changed ();
edit_prev = true;
}
/* this will delete the name_entry. but it will also drop focus, which
* will cause another callback to this function, so set name_entry = 0
* first to ensure we don't double-remove etc. etc.
*/
Gtk::Entry* tmp = name_entry;
name_entry = 0;
name_hbox.remove (*tmp);
/* put the name label back */
name_hbox.pack_end (name_label);
name_label.show ();
if (edit_next) {
if (next_dir > 0) {
TrackViewList const & allviews = _editor.get_track_views ();
TrackViewList::const_iterator i = find (allviews.begin(), allviews.end(), this);
@ -781,7 +673,7 @@ TimeAxisView::end_name_edit (int response)
(*i)->begin_name_edit ();
}
} else if (edit_prev) {
} else if (next_dir < 0) {
TrackViewList const & allviews = _editor.get_track_views ();
TrackViewList::const_iterator i = find (allviews.begin(), allviews.end(), this);
@ -814,9 +706,10 @@ TimeAxisView::end_name_edit (int response)
}
}
void
TimeAxisView::name_entry_changed ()
bool
TimeAxisView::name_entry_changed (string const&)
{
return true;
}
bool
@ -851,9 +744,12 @@ TimeAxisView::popup_display_menu (guint32 when)
void
TimeAxisView::set_selected (bool yn)
{
if (can_edit_name() && name_entry && name_entry->get_visible()) {
end_name_edit (RESPONSE_CANCEL);
#if 0
/* end any name edit in progress */
if (can_edit_name()) {
end_name_edit (string(), 0);
}
#endif
if (yn == _selected) {
return;

View File

@ -255,20 +255,12 @@ class TimeAxisView : public virtual AxisView
virtual bool can_edit_name() const;
bool name_entry_key_release (GdkEventKey *ev);
bool name_entry_key_press (GdkEventKey *ev);
bool name_entry_focus_out (GdkEventFocus *ev);
void name_entry_populate_popup (Gtk::Menu *);
Gtk::Entry* name_entry;
bool ending_name_edit;
bool by_popup_menu;
void begin_name_edit ();
void end_name_edit (int);
void end_name_edit (std::string, int);
/* derived classes can override these */
virtual void name_entry_changed ();
virtual bool name_entry_changed (std::string const&);
/** Handle mouse relaese on our LHS control name ebox.
*

View File

@ -468,7 +468,7 @@ VCAMasterStrip::start_name_edit ()
}
void
VCAMasterStrip::finish_name_edit (std::string str)
VCAMasterStrip::finish_name_edit (std::string str, int)
{
_vca->set_name (str);
}

View File

@ -86,7 +86,7 @@ class VCAMasterStrip : public AxisView, public Gtk::EventBox
bool vca_button_release (GdkEventButton*);
void update_vca_display ();
void start_name_edit ();
void finish_name_edit (std::string);
void finish_name_edit (std::string, int);
bool vertical_button_press (GdkEventButton*);
void vca_property_changed (PBD::PropertyChange const & what_changed);
void update_vca_name ();