mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-18 04:36:30 +01:00
Make waveform show / scale / shape a global option in the prefs dialog to clean things up a bit. Options to make exceptions for individual tracks could be re-added, if people want them.
git-svn-id: svn://localhost/ardour2/branches/3.0@5160 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
2efc80da17
commit
52fc310cfb
20 changed files with 77 additions and 316 deletions
|
|
@ -282,11 +282,6 @@
|
||||||
<menuitem action='track-height-smaller'/>
|
<menuitem action='track-height-smaller'/>
|
||||||
<menuitem action='track-height-small'/>
|
<menuitem action='track-height-small'/>
|
||||||
</menu>
|
</menu>
|
||||||
<menu action='WaveformMenu'>
|
|
||||||
<menuitem action='toggle-waveform-visible'/>
|
|
||||||
<menuitem action='linear-waveforms'/>
|
|
||||||
<menuitem action='logarithmic-waveforms'/>
|
|
||||||
</menu>
|
|
||||||
<menuitem action='toggle-track-active'/>
|
<menuitem action='toggle-track-active'/>
|
||||||
<menuitem action='remove-track'/>
|
<menuitem action='remove-track'/>
|
||||||
</menu>
|
</menu>
|
||||||
|
|
@ -396,7 +391,6 @@
|
||||||
<menuitem action='show-editor-mixer'/>
|
<menuitem action='show-editor-mixer'/>
|
||||||
<menuitem action='show-editor-list'/>
|
<menuitem action='show-editor-list'/>
|
||||||
<menuitem action='ToggleMeasureVisibility'/>
|
<menuitem action='ToggleMeasureVisibility'/>
|
||||||
<menuitem action='toggle-waveform-visible'/>
|
|
||||||
<menuitem action='ToggleWaveformsWhileRecording'/>
|
<menuitem action='ToggleWaveformsWhileRecording'/>
|
||||||
</menu>
|
</menu>
|
||||||
<menu name='JACK' action='JACK'>
|
<menu name='JACK' action='JACK'>
|
||||||
|
|
|
||||||
|
|
@ -1125,7 +1125,7 @@ AudioRegionView::set_waveform_shape (WaveformShape shape)
|
||||||
void
|
void
|
||||||
AudioRegionView::set_waveform_scale (WaveformScale scale)
|
AudioRegionView::set_waveform_scale (WaveformScale scale)
|
||||||
{
|
{
|
||||||
bool yn = (scale == LogWaveform);
|
bool yn = (scale == Logarithmic);
|
||||||
|
|
||||||
if (yn != (bool) (_flags & WaveformLogScaled)) {
|
if (yn != (bool) (_flags & WaveformLogScaled)) {
|
||||||
for (vector<WaveView *>::iterator wave = waves.begin(); wave != waves.end() ; ++wave) {
|
for (vector<WaveView *>::iterator wave = waves.begin(); wave != waves.end() ; ++wave) {
|
||||||
|
|
|
||||||
|
|
@ -84,8 +84,8 @@ class AudioRegionView : public RegionView
|
||||||
|
|
||||||
void set_envelope_visible (bool);
|
void set_envelope_visible (bool);
|
||||||
void set_waveform_visible (bool yn);
|
void set_waveform_visible (bool yn);
|
||||||
void set_waveform_shape (Editing::WaveformShape);
|
void set_waveform_shape (ARDOUR::WaveformShape);
|
||||||
void set_waveform_scale (Editing::WaveformScale);
|
void set_waveform_scale (ARDOUR::WaveformScale);
|
||||||
|
|
||||||
bool waveform_rectified() const { return _flags & WaveformRectified; }
|
bool waveform_rectified() const { return _flags & WaveformRectified; }
|
||||||
bool waveform_logscaled() const { return _flags & WaveformLogScaled; }
|
bool waveform_logscaled() const { return _flags & WaveformLogScaled; }
|
||||||
|
|
|
||||||
|
|
@ -59,12 +59,12 @@ AudioStreamView::AudioStreamView (AudioTimeAxisView& tv)
|
||||||
: StreamView (tv)
|
: StreamView (tv)
|
||||||
{
|
{
|
||||||
crossfades_visible = true;
|
crossfades_visible = true;
|
||||||
_waveform_scale = LinearWaveform;
|
|
||||||
_waveform_shape = Traditional;
|
|
||||||
color_handler ();
|
color_handler ();
|
||||||
_amplitude_above_axis = 1.0;
|
_amplitude_above_axis = 1.0;
|
||||||
|
|
||||||
use_rec_regions = tv.editor().show_waveforms_recording ();
|
use_rec_regions = tv.editor().show_waveforms_recording ();
|
||||||
|
|
||||||
|
Config->ParameterChanged.connect (sigc::mem_fun (*this, &AudioStreamView::parameter_changed));
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioStreamView::~AudioStreamView ()
|
AudioStreamView::~AudioStreamView ()
|
||||||
|
|
@ -148,30 +148,9 @@ AudioStreamView::create_region_view (boost::shared_ptr<Region> r, bool wait_for_
|
||||||
region_view->set_sensitive (false);
|
region_view->set_sensitive (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if this was the first one, then lets query the waveform scale and shape.
|
region_view->set_waveform_scale (Config->get_waveform_scale ());
|
||||||
otherwise, we set it to the current value */
|
region_view->set_waveform_shape (Config->get_waveform_shape ());
|
||||||
|
region_view->set_waveform_visible (Config->get_show_waveforms ());
|
||||||
if (region_views.size() == 1) {
|
|
||||||
|
|
||||||
if (region_view->waveform_logscaled()) {
|
|
||||||
_waveform_scale = LogWaveform;
|
|
||||||
} else {
|
|
||||||
_waveform_scale = LinearWaveform;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (region_view->waveform_rectified()) {
|
|
||||||
_waveform_shape = Rectified;
|
|
||||||
} else {
|
|
||||||
_waveform_shape = Traditional;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
region_view->set_waveform_scale(_waveform_scale);
|
|
||||||
region_view->set_waveform_shape(_waveform_shape);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* follow global waveform setting */
|
|
||||||
region_view->set_waveform_visible(_trackview.editor().show_waveforms());
|
|
||||||
|
|
||||||
return region_view;
|
return region_view;
|
||||||
}
|
}
|
||||||
|
|
@ -460,7 +439,6 @@ AudioStreamView::set_waveform_shape (WaveformShape shape)
|
||||||
if (arv)
|
if (arv)
|
||||||
arv->set_waveform_shape (shape);
|
arv->set_waveform_shape (shape);
|
||||||
}
|
}
|
||||||
_waveform_shape = shape;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -468,10 +446,10 @@ AudioStreamView::set_waveform_scale (WaveformScale scale)
|
||||||
{
|
{
|
||||||
for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
|
for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
|
||||||
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
|
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
|
||||||
if (arv)
|
if (arv) {
|
||||||
arv->set_waveform_scale (scale);
|
arv->set_waveform_scale (scale);
|
||||||
}
|
}
|
||||||
_waveform_scale = scale;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -832,3 +810,15 @@ AudioStreamView::update_contents_height ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioStreamView::parameter_changed (string const & p)
|
||||||
|
{
|
||||||
|
if (p == "show-waveforms") {
|
||||||
|
set_show_waveforms (Config->get_show_waveforms ());
|
||||||
|
} else if (p == "waveform-scale") {
|
||||||
|
set_waveform_scale (Config->get_waveform_scale ());
|
||||||
|
} else if (p == "waveform-shape") {
|
||||||
|
set_waveform_shape (Config->get_waveform_shape ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,11 +57,6 @@ class AudioStreamView : public StreamView
|
||||||
AudioStreamView (AudioTimeAxisView&);
|
AudioStreamView (AudioTimeAxisView&);
|
||||||
~AudioStreamView ();
|
~AudioStreamView ();
|
||||||
|
|
||||||
void set_waveform_shape (Editing::WaveformShape);
|
|
||||||
Editing::WaveformShape get_waveform_shape () const { return _waveform_shape; }
|
|
||||||
void set_waveform_scale (Editing::WaveformScale);
|
|
||||||
Editing::WaveformScale get_waveform_scale () const { return _waveform_scale; }
|
|
||||||
|
|
||||||
int set_samples_per_unit (gdouble spp);
|
int set_samples_per_unit (gdouble spp);
|
||||||
|
|
||||||
int set_amplitude_above_axis (gdouble app);
|
int set_amplitude_above_axis (gdouble app);
|
||||||
|
|
@ -106,21 +101,21 @@ class AudioStreamView : public StreamView
|
||||||
|
|
||||||
void update_contents_height ();
|
void update_contents_height ();
|
||||||
|
|
||||||
|
void parameter_changed (std::string const &);
|
||||||
|
void set_waveform_shape (ARDOUR::WaveformShape);
|
||||||
|
void set_waveform_scale (ARDOUR::WaveformScale);
|
||||||
|
|
||||||
double _amplitude_above_axis;
|
double _amplitude_above_axis;
|
||||||
|
|
||||||
typedef std::list<CrossfadeView*> CrossfadeViewList;
|
typedef std::list<CrossfadeView*> CrossfadeViewList;
|
||||||
CrossfadeViewList crossfade_views;
|
CrossfadeViewList crossfade_views;
|
||||||
bool crossfades_visible;
|
bool crossfades_visible;
|
||||||
|
|
||||||
|
|
||||||
std::list<sigc::connection> rec_data_ready_connections;
|
std::list<sigc::connection> rec_data_ready_connections;
|
||||||
nframes_t last_rec_data_frame;
|
nframes_t last_rec_data_frame;
|
||||||
std::map<boost::shared_ptr<ARDOUR::Source>, bool> rec_data_ready_map;
|
std::map<boost::shared_ptr<ARDOUR::Source>, bool> rec_data_ready_map;
|
||||||
|
|
||||||
bool outline_region;
|
bool outline_region;
|
||||||
|
|
||||||
Editing::WaveformShape _waveform_shape;
|
|
||||||
Editing::WaveformScale _waveform_scale;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __ardour_audio_streamview_h__ */
|
#endif /* __ardour_audio_streamview_h__ */
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,6 @@ AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
|
||||||
assert(!is_track() || is_audio_track());
|
assert(!is_track() || is_audio_track());
|
||||||
|
|
||||||
subplugin_menu.set_name ("ArdourContextMenu");
|
subplugin_menu.set_name ("ArdourContextMenu");
|
||||||
waveform_item = 0;
|
|
||||||
|
|
||||||
_view = new AudioStreamView (*this);
|
_view = new AudioStreamView (*this);
|
||||||
|
|
||||||
|
|
@ -185,60 +184,6 @@ AudioTimeAxisView::append_extra_display_menu_items ()
|
||||||
items.push_back (MenuElem (_("Hide all crossfades"), mem_fun(*this, &AudioTimeAxisView::hide_all_xfades)));
|
items.push_back (MenuElem (_("Hide all crossfades"), mem_fun(*this, &AudioTimeAxisView::hide_all_xfades)));
|
||||||
items.push_back (MenuElem (_("Show all crossfades"), mem_fun(*this, &AudioTimeAxisView::show_all_xfades)));
|
items.push_back (MenuElem (_("Show all crossfades"), mem_fun(*this, &AudioTimeAxisView::show_all_xfades)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// waveform menu
|
|
||||||
Menu *waveform_menu = manage(new Menu);
|
|
||||||
MenuList& waveform_items = waveform_menu->items();
|
|
||||||
waveform_menu->set_name ("ArdourContextMenu");
|
|
||||||
|
|
||||||
waveform_items.push_back (CheckMenuElem (_("Show waveforms"), mem_fun(*this, &AudioTimeAxisView::toggle_waveforms)));
|
|
||||||
waveform_item = static_cast<CheckMenuItem *> (&waveform_items.back());
|
|
||||||
ignore_toggle = true;
|
|
||||||
waveform_item->set_active (_editor.show_waveforms());
|
|
||||||
ignore_toggle = false;
|
|
||||||
|
|
||||||
waveform_items.push_back (SeparatorElem());
|
|
||||||
|
|
||||||
RadioMenuItem::Group group;
|
|
||||||
|
|
||||||
waveform_items.push_back (RadioMenuElem (group, _("Traditional"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_shape), Traditional)));
|
|
||||||
traditional_item = static_cast<RadioMenuItem *> (&waveform_items.back());
|
|
||||||
|
|
||||||
if (!Profile->get_sae()) {
|
|
||||||
waveform_items.push_back (RadioMenuElem (group, _("Rectified"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_shape), Rectified)));
|
|
||||||
rectified_item = static_cast<RadioMenuItem *> (&waveform_items.back());
|
|
||||||
} else {
|
|
||||||
rectified_item = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
waveform_items.push_back (SeparatorElem());
|
|
||||||
|
|
||||||
RadioMenuItem::Group group2;
|
|
||||||
|
|
||||||
waveform_items.push_back (RadioMenuElem (group2, _("Linear"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_scale), LinearWaveform)));
|
|
||||||
linearscale_item = static_cast<RadioMenuItem *> (&waveform_items.back());
|
|
||||||
|
|
||||||
waveform_items.push_back (RadioMenuElem (group2, _("Logarithmic"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_scale), LogWaveform)));
|
|
||||||
logscale_item = static_cast<RadioMenuItem *> (&waveform_items.back());
|
|
||||||
|
|
||||||
// setting initial item state
|
|
||||||
AudioStreamView* asv = audio_view();
|
|
||||||
if (asv) {
|
|
||||||
ignore_toggle = true;
|
|
||||||
if (asv->get_waveform_shape() == Rectified && rectified_item) {
|
|
||||||
rectified_item->set_active(true);
|
|
||||||
} else {
|
|
||||||
traditional_item->set_active(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asv->get_waveform_scale() == LogWaveform)
|
|
||||||
logscale_item->set_active(true);
|
|
||||||
else linearscale_item->set_active(true);
|
|
||||||
ignore_toggle = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
items.push_back (MenuElem (_("Waveform"), *waveform_menu));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Gtk::Menu*
|
Gtk::Menu*
|
||||||
|
|
@ -279,30 +224,6 @@ AudioTimeAxisView::build_mode_menu()
|
||||||
return mode_menu;
|
return mode_menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
AudioTimeAxisView::toggle_waveforms ()
|
|
||||||
{
|
|
||||||
AudioStreamView* asv = audio_view();
|
|
||||||
assert(asv);
|
|
||||||
|
|
||||||
if (asv && waveform_item && !ignore_toggle) {
|
|
||||||
asv->set_show_waveforms (waveform_item->get_active());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AudioTimeAxisView::set_show_waveforms (bool yn)
|
|
||||||
{
|
|
||||||
AudioStreamView* asv = audio_view();
|
|
||||||
assert(asv);
|
|
||||||
|
|
||||||
if (waveform_item) {
|
|
||||||
waveform_item->set_active (yn);
|
|
||||||
} else {
|
|
||||||
asv->set_show_waveforms (yn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioTimeAxisView::set_show_waveforms_recording (bool yn)
|
AudioTimeAxisView::set_show_waveforms_recording (bool yn)
|
||||||
{
|
{
|
||||||
|
|
@ -313,30 +234,6 @@ AudioTimeAxisView::set_show_waveforms_recording (bool yn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
AudioTimeAxisView::set_waveform_shape (WaveformShape shape)
|
|
||||||
{
|
|
||||||
AudioStreamView* asv = audio_view();
|
|
||||||
|
|
||||||
if (asv && !ignore_toggle) {
|
|
||||||
asv->set_waveform_shape (shape);
|
|
||||||
}
|
|
||||||
|
|
||||||
map_frozen ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AudioTimeAxisView::set_waveform_scale (WaveformScale scale)
|
|
||||||
{
|
|
||||||
AudioStreamView* asv = audio_view();
|
|
||||||
|
|
||||||
if (asv && !ignore_toggle) {
|
|
||||||
asv->set_waveform_scale (scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
map_frozen ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
|
AudioTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
|
||||||
{
|
{
|
||||||
|
|
@ -591,4 +488,3 @@ AudioTimeAxisView::update_control_names ()
|
||||||
controls_ebox.set_name (controls_base_unselected_name);
|
controls_ebox.set_name (controls_base_unselected_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,6 @@ class AudioTimeAxisView : public RouteTimeAxisView
|
||||||
|
|
||||||
AudioStreamView* audio_view();
|
AudioStreamView* audio_view();
|
||||||
|
|
||||||
void set_show_waveforms (bool yn);
|
|
||||||
void set_show_waveforms_recording (bool yn);
|
void set_show_waveforms_recording (bool yn);
|
||||||
void show_all_xfades ();
|
void show_all_xfades ();
|
||||||
void hide_all_xfades ();
|
void hide_all_xfades ();
|
||||||
|
|
@ -88,9 +87,6 @@ class AudioTimeAxisView : public RouteTimeAxisView
|
||||||
|
|
||||||
XMLNode* get_child_xml_node (const std::string & childname);
|
XMLNode* get_child_xml_node (const std::string & childname);
|
||||||
|
|
||||||
void set_waveform_shape (Editing::WaveformShape);
|
|
||||||
void set_waveform_scale (Editing::WaveformScale);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class AudioStreamView;
|
friend class AudioStreamView;
|
||||||
friend class AudioRegionView;
|
friend class AudioRegionView;
|
||||||
|
|
@ -100,9 +96,6 @@ class AudioTimeAxisView : public RouteTimeAxisView
|
||||||
void append_extra_display_menu_items ();
|
void append_extra_display_menu_items ();
|
||||||
Gtk::Menu* build_mode_menu();
|
Gtk::Menu* build_mode_menu();
|
||||||
|
|
||||||
void toggle_show_waveforms ();
|
|
||||||
void toggle_waveforms ();
|
|
||||||
|
|
||||||
void show_all_automation ();
|
void show_all_automation ();
|
||||||
void show_existing_automation ();
|
void show_existing_automation ();
|
||||||
void hide_all_automation ();
|
void hide_all_automation ();
|
||||||
|
|
@ -112,12 +105,6 @@ class AudioTimeAxisView : public RouteTimeAxisView
|
||||||
|
|
||||||
void ensure_pan_views (bool show = true);
|
void ensure_pan_views (bool show = true);
|
||||||
void update_control_names ();
|
void update_control_names ();
|
||||||
|
|
||||||
Gtk::CheckMenuItem* waveform_item;
|
|
||||||
Gtk::RadioMenuItem* traditional_item;
|
|
||||||
Gtk::RadioMenuItem* rectified_item;
|
|
||||||
Gtk::RadioMenuItem* linearscale_item;
|
|
||||||
Gtk::RadioMenuItem* logscale_item;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __ardour_audio_time_axis_h__ */
|
#endif /* __ardour_audio_time_axis_h__ */
|
||||||
|
|
|
||||||
|
|
@ -182,28 +182,6 @@ enum EditPoint {
|
||||||
#undef EDITPOINT
|
#undef EDITPOINT
|
||||||
#define EDITPOINT(a) /*empty*/
|
#define EDITPOINT(a) /*empty*/
|
||||||
|
|
||||||
// WAVEFORMSCALE
|
|
||||||
#undef WAVEFORMSCALE
|
|
||||||
#define WAVEFORMSCALE(a) a,
|
|
||||||
enum WaveformScale {
|
|
||||||
#include "editing_syms.h"
|
|
||||||
};
|
|
||||||
|
|
||||||
#undef WAVEFORMSCALE
|
|
||||||
#define WAVEFORMSCALE(a) /*empty*/
|
|
||||||
|
|
||||||
|
|
||||||
// WAVEFORMSHAPE
|
|
||||||
#undef WAVEFORMSHAPE
|
|
||||||
#define WAVEFORMSHAPE(a) a,
|
|
||||||
enum WaveformShape {
|
|
||||||
#include "editing_syms.h"
|
|
||||||
};
|
|
||||||
|
|
||||||
#undef WAVEFORMSHAPE
|
|
||||||
#define WAVEFORMSHAPE(a) /*empty*/
|
|
||||||
|
|
||||||
|
|
||||||
// INSERTTIMEOPT
|
// INSERTTIMEOPT
|
||||||
#undef INSERTTIMEOPT
|
#undef INSERTTIMEOPT
|
||||||
#define INSERTTIMEOPT(a) a,
|
#define INSERTTIMEOPT(a) a,
|
||||||
|
|
|
||||||
|
|
@ -97,18 +97,10 @@ IMPORTDISPOSITION(ImportMergeFiles=1)
|
||||||
IMPORTDISPOSITION(ImportSerializeFiles=2)
|
IMPORTDISPOSITION(ImportSerializeFiles=2)
|
||||||
IMPORTDISPOSITION(ImportDistinctChannels=3)
|
IMPORTDISPOSITION(ImportDistinctChannels=3)
|
||||||
|
|
||||||
|
|
||||||
EDITPOINT(EditAtPlayhead)
|
EDITPOINT(EditAtPlayhead)
|
||||||
EDITPOINT(EditAtSelectedMarker)
|
EDITPOINT(EditAtSelectedMarker)
|
||||||
EDITPOINT(EditAtMouse)
|
EDITPOINT(EditAtMouse)
|
||||||
|
|
||||||
WAVEFORMSCALE(LinearWaveform)
|
|
||||||
WAVEFORMSCALE(LogWaveform)
|
|
||||||
|
|
||||||
WAVEFORMSHAPE(Traditional)
|
|
||||||
WAVEFORMSHAPE(Rectified)
|
|
||||||
|
|
||||||
|
|
||||||
INSERTTIMEOPT(LeaveIntersected)
|
INSERTTIMEOPT(LeaveIntersected)
|
||||||
INSERTTIMEOPT(MoveIntersected)
|
INSERTTIMEOPT(MoveIntersected)
|
||||||
INSERTTIMEOPT(SplitIntersected)
|
INSERTTIMEOPT(SplitIntersected)
|
||||||
|
|
|
||||||
|
|
@ -290,7 +290,6 @@ Editor::Editor ()
|
||||||
|
|
||||||
current_interthread_info = 0;
|
current_interthread_info = 0;
|
||||||
_show_measures = true;
|
_show_measures = true;
|
||||||
_show_waveforms = true;
|
|
||||||
_show_waveforms_recording = true;
|
_show_waveforms_recording = true;
|
||||||
show_gain_after_trim = false;
|
show_gain_after_trim = false;
|
||||||
route_redisplay_does_not_sync_order_keys = false;
|
route_redisplay_does_not_sync_order_keys = false;
|
||||||
|
|
@ -2554,18 +2553,6 @@ Editor::set_state (const XMLNode& node)
|
||||||
set_mouse_mode (MouseObject, true);
|
set_mouse_mode (MouseObject, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((prop = node.property ("show-waveforms"))) {
|
|
||||||
bool yn = (prop->value() == "yes");
|
|
||||||
_show_waveforms = !yn;
|
|
||||||
RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-waveform-visible"));
|
|
||||||
if (act) {
|
|
||||||
RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
|
|
||||||
/* do it twice to force the change */
|
|
||||||
tact->set_active (!yn);
|
|
||||||
tact->set_active (yn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((prop = node.property ("show-waveforms-recording"))) {
|
if ((prop = node.property ("show-waveforms-recording"))) {
|
||||||
bool yn = (prop->value() == "yes");
|
bool yn = (prop->value() == "yes");
|
||||||
_show_waveforms_recording = !yn;
|
_show_waveforms_recording = !yn;
|
||||||
|
|
@ -2701,7 +2688,6 @@ Editor::get_state ()
|
||||||
snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
|
snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
|
||||||
node->add_property ("playhead", buf);
|
node->add_property ("playhead", buf);
|
||||||
|
|
||||||
node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
|
|
||||||
node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
|
node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
|
||||||
node->add_property ("show-measures", _show_measures ? "yes" : "no");
|
node->add_property ("show-measures", _show_measures ? "yes" : "no");
|
||||||
node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
|
node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
|
||||||
|
|
|
||||||
|
|
@ -198,11 +198,6 @@ class Editor : public PublicEditor
|
||||||
|
|
||||||
/* option editor-access */
|
/* option editor-access */
|
||||||
|
|
||||||
void set_show_waveforms (bool yn);
|
|
||||||
bool show_waveforms() const { return _show_waveforms; }
|
|
||||||
|
|
||||||
void set_waveform_scale (Editing::WaveformScale);
|
|
||||||
|
|
||||||
void set_show_waveforms_recording (bool yn);
|
void set_show_waveforms_recording (bool yn);
|
||||||
bool show_waveforms_recording() const { return _show_waveforms_recording; }
|
bool show_waveforms_recording() const { return _show_waveforms_recording; }
|
||||||
|
|
||||||
|
|
@ -338,7 +333,6 @@ class Editor : public PublicEditor
|
||||||
bool follow_playhead() const { return _follow_playhead; }
|
bool follow_playhead() const { return _follow_playhead; }
|
||||||
bool dragging_playhead () const { return _dragging_playhead; }
|
bool dragging_playhead () const { return _dragging_playhead; }
|
||||||
|
|
||||||
void toggle_waveform_visibility ();
|
|
||||||
void toggle_zero_line_visibility ();
|
void toggle_zero_line_visibility ();
|
||||||
void toggle_waveforms_while_recording ();
|
void toggle_waveforms_while_recording ();
|
||||||
void toggle_measure_visibility ();
|
void toggle_measure_visibility ();
|
||||||
|
|
@ -1511,8 +1505,6 @@ public:
|
||||||
/* display control */
|
/* display control */
|
||||||
|
|
||||||
bool _show_measures;
|
bool _show_measures;
|
||||||
/// true to show waveforms, otherwise false
|
|
||||||
bool _show_waveforms;
|
|
||||||
/// true if the editor should follow the playhead, otherwise false
|
/// true if the editor should follow the playhead, otherwise false
|
||||||
bool _follow_playhead;
|
bool _follow_playhead;
|
||||||
/// true if waveforms should be shown while recording audio tracks, otherwise false
|
/// true if waveforms should be shown while recording audio tracks, otherwise false
|
||||||
|
|
@ -2210,7 +2202,6 @@ public:
|
||||||
|
|
||||||
void remove_tracks ();
|
void remove_tracks ();
|
||||||
void toggle_tracks_active ();
|
void toggle_tracks_active ();
|
||||||
void waveform_scale_chosen (Editing::WaveformScale);
|
|
||||||
|
|
||||||
bool _have_idled;
|
bool _have_idled;
|
||||||
int resize_idle_id;
|
int resize_idle_id;
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
#include "time_axis_view.h"
|
#include "time_axis_view.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
#include "audio_time_axis.h"
|
||||||
|
|
||||||
using namespace Gtk;
|
using namespace Gtk;
|
||||||
using namespace Glib;
|
using namespace Glib;
|
||||||
|
|
@ -94,7 +95,6 @@ Editor::register_actions ()
|
||||||
ActionManager::register_action (editor_actions, X_("Tools"), _("Tools"));
|
ActionManager::register_action (editor_actions, X_("Tools"), _("Tools"));
|
||||||
ActionManager::register_action (editor_actions, X_("TrimMenu"), _("Trim"));
|
ActionManager::register_action (editor_actions, X_("TrimMenu"), _("Trim"));
|
||||||
ActionManager::register_action (editor_actions, X_("View"), _("View"));
|
ActionManager::register_action (editor_actions, X_("View"), _("View"));
|
||||||
ActionManager::register_action (editor_actions, X_("WaveformMenu"), _("Waveforms"));
|
|
||||||
ActionManager::register_action (editor_actions, X_("ZoomFocus"), _("Zoom Focus"));
|
ActionManager::register_action (editor_actions, X_("ZoomFocus"), _("Zoom Focus"));
|
||||||
ActionManager::register_action (editor_actions, X_("ZoomMenu"), _("Zoom"));
|
ActionManager::register_action (editor_actions, X_("ZoomMenu"), _("Zoom"));
|
||||||
|
|
||||||
|
|
@ -805,19 +805,9 @@ Editor::register_actions ()
|
||||||
|
|
||||||
ActionManager::register_action (editor_actions, X_("importFromSession"), _("Import From Session"), mem_fun(*this, &Editor::session_import_dialog));
|
ActionManager::register_action (editor_actions, X_("importFromSession"), _("Import From Session"), mem_fun(*this, &Editor::session_import_dialog));
|
||||||
|
|
||||||
act = ActionManager::register_toggle_action (editor_actions, X_("toggle-waveform-visible"), _("Show Waveforms"), mem_fun (*this, &Editor::toggle_waveform_visibility));
|
|
||||||
ActionManager::track_selection_sensitive_actions.push_back (act);
|
|
||||||
|
|
||||||
ActionManager::register_toggle_action (editor_actions, X_("ToggleWaveformsWhileRecording"), _("Show Waveforms While Recording"), mem_fun (*this, &Editor::toggle_waveforms_while_recording));
|
ActionManager::register_toggle_action (editor_actions, X_("ToggleWaveformsWhileRecording"), _("Show Waveforms While Recording"), mem_fun (*this, &Editor::toggle_waveforms_while_recording));
|
||||||
ActionManager::register_toggle_action (editor_actions, X_("ToggleMeasureVisibility"), _("Show Measures"), mem_fun (*this, &Editor::toggle_measure_visibility));
|
ActionManager::register_toggle_action (editor_actions, X_("ToggleMeasureVisibility"), _("Show Measures"), mem_fun (*this, &Editor::toggle_measure_visibility));
|
||||||
|
|
||||||
|
|
||||||
RadioAction::Group waveform_scale_group;
|
|
||||||
act = ActionManager::register_radio_action (editor_actions, waveform_scale_group, X_("linear-waveforms"), _("Linear"), bind (mem_fun (*this, &Editor::waveform_scale_chosen), Editing::LinearWaveform));
|
|
||||||
ActionManager::track_selection_sensitive_actions.push_back (act);
|
|
||||||
act = ActionManager::register_radio_action (editor_actions, waveform_scale_group, X_("logarithmic-waveforms"), _("Logarithmic"), bind (mem_fun (*this, &Editor::waveform_scale_chosen), Editing::LogWaveform));
|
|
||||||
ActionManager::track_selection_sensitive_actions.push_back (act);
|
|
||||||
|
|
||||||
/* if there is a logo in the editor canvas, its always visible at startup */
|
/* if there is a logo in the editor canvas, its always visible at startup */
|
||||||
|
|
||||||
act = ActionManager::register_toggle_action (editor_actions, X_("ToggleLogoVisibility"), _("Show Logo"), mem_fun (*this, &Editor::toggle_logo_visibility));
|
act = ActionManager::register_toggle_action (editor_actions, X_("ToggleLogoVisibility"), _("Show Logo"), mem_fun (*this, &Editor::toggle_logo_visibility));
|
||||||
|
|
@ -882,16 +872,6 @@ Editor::toggle_ruler_visibility (RulerType rt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Editor::toggle_waveform_visibility ()
|
|
||||||
{
|
|
||||||
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-waveform-visible"));
|
|
||||||
if (act) {
|
|
||||||
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
|
|
||||||
set_show_waveforms (tact->get_active());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Editor::toggle_waveforms_while_recording ()
|
Editor::toggle_waveforms_while_recording ()
|
||||||
{
|
{
|
||||||
|
|
@ -929,33 +909,6 @@ Editor::toggle_logo_visibility ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Editor::waveform_scale_chosen (Editing::WaveformScale ws)
|
|
||||||
{
|
|
||||||
RefPtr<Action> act;
|
|
||||||
|
|
||||||
/* this is driven by a toggle on a radio group, and so is invoked twice,
|
|
||||||
once for the item that became inactive and once for the one that became
|
|
||||||
active.
|
|
||||||
*/
|
|
||||||
|
|
||||||
switch (ws) {
|
|
||||||
case LinearWaveform:
|
|
||||||
act = ActionManager::get_action (X_("Editor"), X_("linear-waveforms"));
|
|
||||||
break;
|
|
||||||
case LogWaveform:
|
|
||||||
act = ActionManager::get_action (X_("Editor"), X_("logarithmic-waveforms"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (act) {
|
|
||||||
RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
|
|
||||||
if (ract && ract->get_active()) {
|
|
||||||
set_waveform_scale (ws);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<RadioAction>
|
RefPtr<RadioAction>
|
||||||
Editor::snap_type_action (SnapType type)
|
Editor::snap_type_action (SnapType type)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -33,21 +33,6 @@
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
|
|
||||||
void
|
|
||||||
Editor::set_show_waveforms (bool yn)
|
|
||||||
{
|
|
||||||
AudioTimeAxisView* atv;
|
|
||||||
|
|
||||||
if (_show_waveforms != yn) {
|
|
||||||
_show_waveforms = yn;
|
|
||||||
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
||||||
if ((atv = dynamic_cast<AudioTimeAxisView*>(*i)) != 0) {
|
|
||||||
atv->set_show_waveforms (yn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Editor::set_show_waveforms_recording (bool yn)
|
Editor::set_show_waveforms_recording (bool yn)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6159,23 +6159,6 @@ Editor::remove_tracks ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Editor::set_waveform_scale (WaveformScale ws)
|
|
||||||
{
|
|
||||||
TrackSelection& ts (selection->tracks);
|
|
||||||
|
|
||||||
if (ts.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
|
|
||||||
AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (*x);
|
|
||||||
if (atv) {
|
|
||||||
atv->set_waveform_scale (ws);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Editor::do_insert_time ()
|
Editor::do_insert_time ()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,6 @@ setup_gtk_ardour_enums ()
|
||||||
Width width;
|
Width width;
|
||||||
ImportMode import_mode;
|
ImportMode import_mode;
|
||||||
EditPoint edit_point;
|
EditPoint edit_point;
|
||||||
WaveformScale waveform_scale;
|
|
||||||
WaveformShape waveform_shape;
|
|
||||||
|
|
||||||
#define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
|
#define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
|
||||||
#define REGISTER_BITS(e) enum_writer.register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
|
#define REGISTER_BITS(e) enum_writer.register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
|
||||||
|
|
@ -68,12 +66,4 @@ setup_gtk_ardour_enums ()
|
||||||
REGISTER_ENUM (EditAtMouse);
|
REGISTER_ENUM (EditAtMouse);
|
||||||
REGISTER_ENUM (EditAtSelectedMarker);
|
REGISTER_ENUM (EditAtSelectedMarker);
|
||||||
REGISTER (edit_point);
|
REGISTER (edit_point);
|
||||||
|
|
||||||
REGISTER_ENUM (LinearWaveform);
|
|
||||||
REGISTER_ENUM (LogWaveform);
|
|
||||||
REGISTER (waveform_scale);
|
|
||||||
|
|
||||||
REGISTER_ENUM (Traditional);
|
|
||||||
REGISTER_ENUM (Rectified);
|
|
||||||
REGISTER (waveform_shape);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -172,14 +172,6 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulThingWithGoingAway
|
||||||
*/
|
*/
|
||||||
virtual void consider_auditioning (boost::shared_ptr<ARDOUR::Region> r) = 0;
|
virtual void consider_auditioning (boost::shared_ptr<ARDOUR::Region> r) = 0;
|
||||||
|
|
||||||
/** Set whether waveforms should be shown for audio tracks.
|
|
||||||
* @param yn true to show waveforms, otherwise false.
|
|
||||||
*/
|
|
||||||
virtual void set_show_waveforms (bool yn) = 0;
|
|
||||||
|
|
||||||
/** @return true if waveforms are being shown, otherwise false */
|
|
||||||
virtual bool show_waveforms () const = 0;
|
|
||||||
|
|
||||||
/** Set whether waveforms should be shown while recording audio tracks.
|
/** Set whether waveforms should be shown while recording audio tracks.
|
||||||
* @param yn true to show waveforms, otherwise false.
|
* @param yn true to show waveforms, otherwise false.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1038,6 +1038,38 @@ RCOptionEditor::RCOptionEditor ()
|
||||||
mem_fun (*_rc_config, &RCConfiguration::set_rubberbanding_snaps_to_grid)
|
mem_fun (*_rc_config, &RCConfiguration::set_rubberbanding_snaps_to_grid)
|
||||||
));
|
));
|
||||||
|
|
||||||
|
add_option (_("Editor"),
|
||||||
|
new BoolOption (
|
||||||
|
"show-waveforms",
|
||||||
|
_("Show waveforms in regions"),
|
||||||
|
mem_fun (*_rc_config, &RCConfiguration::get_show_waveforms),
|
||||||
|
mem_fun (*_rc_config, &RCConfiguration::set_show_waveforms)
|
||||||
|
));
|
||||||
|
|
||||||
|
ComboOption<WaveformScale>* wfs = new ComboOption<WaveformScale> (
|
||||||
|
"waveform-scale",
|
||||||
|
_("Waveform scale"),
|
||||||
|
mem_fun (*_rc_config, &RCConfiguration::get_waveform_scale),
|
||||||
|
mem_fun (*_rc_config, &RCConfiguration::set_waveform_scale)
|
||||||
|
);
|
||||||
|
|
||||||
|
wfs->add (Linear, _("linear"));
|
||||||
|
wfs->add (Logarithmic, _("logarithmic"));
|
||||||
|
|
||||||
|
add_option (_("Editor"), wfs);
|
||||||
|
|
||||||
|
ComboOption<WaveformShape>* wfsh = new ComboOption<WaveformShape> (
|
||||||
|
"waveform-shape",
|
||||||
|
_("Waveform shape"),
|
||||||
|
mem_fun (*_rc_config, &RCConfiguration::get_waveform_shape),
|
||||||
|
mem_fun (*_rc_config, &RCConfiguration::set_waveform_shape)
|
||||||
|
);
|
||||||
|
|
||||||
|
wfsh->add (Traditional, _("traditional"));
|
||||||
|
wfsh->add (Rectified, _("rectified"));
|
||||||
|
|
||||||
|
add_option (_("Editor"), wfsh);
|
||||||
|
|
||||||
/* AUDIO */
|
/* AUDIO */
|
||||||
|
|
||||||
add_option (_("Audio"), new OptionEditorHeading (_("Solo")));
|
add_option (_("Audio"), new OptionEditorHeading (_("Solo")));
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,9 @@ CONFIG_VARIABLE (bool, name_new_markers, "name-new-markers", false)
|
||||||
CONFIG_VARIABLE (bool, rubberbanding_snaps_to_grid, "rubberbanding-snaps-to-grid", false)
|
CONFIG_VARIABLE (bool, rubberbanding_snaps_to_grid, "rubberbanding-snaps-to-grid", false)
|
||||||
CONFIG_VARIABLE (long, font_scale, "font-scale", 102400)
|
CONFIG_VARIABLE (long, font_scale, "font-scale", 102400)
|
||||||
CONFIG_VARIABLE (std::string, default_session_parent_dir, "default-session-parent-dir", "~")
|
CONFIG_VARIABLE (std::string, default_session_parent_dir, "default-session-parent-dir", "~")
|
||||||
|
CONFIG_VARIABLE (bool, show_waveforms, "show-waveforms", true)
|
||||||
|
CONFIG_VARIABLE (WaveformScale, waveform_scale, "waveform-scale", Linear)
|
||||||
|
CONFIG_VARIABLE (WaveformShape, waveform_shape, "waveform-shape", Traditional)
|
||||||
|
|
||||||
/* denormal management */
|
/* denormal management */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -436,6 +436,16 @@ namespace ARDOUR {
|
||||||
class Bundle;
|
class Bundle;
|
||||||
typedef std::vector<boost::shared_ptr<Bundle> > BundleList;
|
typedef std::vector<boost::shared_ptr<Bundle> > BundleList;
|
||||||
|
|
||||||
|
enum WaveformScale {
|
||||||
|
Linear,
|
||||||
|
Logarithmic
|
||||||
|
};
|
||||||
|
|
||||||
|
enum WaveformShape {
|
||||||
|
Traditional,
|
||||||
|
Rectified
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace ARDOUR
|
} // namespace ARDOUR
|
||||||
|
|
||||||
std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf);
|
std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf);
|
||||||
|
|
@ -452,6 +462,8 @@ std::istream& operator>>(std::istream& o, ARDOUR::ShuttleBehaviour& sf);
|
||||||
std::istream& operator>>(std::istream& o, ARDOUR::ShuttleUnits& sf);
|
std::istream& operator>>(std::istream& o, ARDOUR::ShuttleUnits& sf);
|
||||||
std::istream& operator>>(std::istream& o, ARDOUR::SmpteFormat& sf);
|
std::istream& operator>>(std::istream& o, ARDOUR::SmpteFormat& sf);
|
||||||
std::istream& operator>>(std::istream& o, ARDOUR::DenormalModel& sf);
|
std::istream& operator>>(std::istream& o, ARDOUR::DenormalModel& sf);
|
||||||
|
std::istream& operator>>(std::istream& o, ARDOUR::WaveformScale& sf);
|
||||||
|
std::istream& operator>>(std::istream& o, ARDOUR::WaveformShape& sf);
|
||||||
|
|
||||||
using ARDOUR::nframes_t;
|
using ARDOUR::nframes_t;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -606,4 +606,6 @@ std::istream& operator>>(std::istream& o, ShuttleBehaviour& var) { return int_to
|
||||||
std::istream& operator>>(std::istream& o, ShuttleUnits& var) { return int_to_type<ShuttleUnits> (o, var); }
|
std::istream& operator>>(std::istream& o, ShuttleUnits& var) { return int_to_type<ShuttleUnits> (o, var); }
|
||||||
std::istream& operator>>(std::istream& o, SmpteFormat& var) { return int_to_type<SmpteFormat> (o, var); }
|
std::istream& operator>>(std::istream& o, SmpteFormat& var) { return int_to_type<SmpteFormat> (o, var); }
|
||||||
std::istream& operator>>(std::istream& o, DenormalModel& var) { return int_to_type<DenormalModel> (o, var); }
|
std::istream& operator>>(std::istream& o, DenormalModel& var) { return int_to_type<DenormalModel> (o, var); }
|
||||||
|
std::istream& operator>>(std::istream& o, WaveformScale& var) { return int_to_type<WaveformScale> (o, var); }
|
||||||
|
std::istream& operator>>(std::istream& o, WaveformShape& var) { return int_to_type<WaveformShape> (o, var); }
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue