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:
parent
30d0b2a354
commit
428ed8ae1b
|
@ -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"
|
||||
|
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
@ -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__
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 ();
|
||||
|
|
Loading…
Reference in New Issue