mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-15 15:49:36 +02:00
Adds Track::IsSynchroSelected() and visuals for synchro (group) selection
This commit is contained in:
parent
319903dbf7
commit
b646b10df2
@ -217,6 +217,8 @@ from there. Audacity will look for a file called "Pause.png".
|
||||
DEFINE_IMAGE( bmpAudacityLogo, wxImage( 215, 190 ), wxT("AudacityLogo")); //vvv
|
||||
DEFINE_IMAGE( bmpAudacityLogo48x48, wxImage( 48, 48 ), wxT("AudacityLogo48x48"));
|
||||
|
||||
DEFINE_IMAGE( bmpLinkSelect, wxImage(30, 30), wxT("LinkSelect"));
|
||||
|
||||
#ifdef OLD_COLOURS
|
||||
DEFINE_COLOUR( clrBlank, wxColour(214, 214, 214), wxT("Blank"));
|
||||
DEFINE_COLOUR( clrUnselected, wxColour(192, 192, 192), wxT("Unselected"));
|
||||
|
@ -55,6 +55,7 @@ for drawing different aspects of the label and its text box.
|
||||
#include "AllThemeResources.h"
|
||||
#include "AColor.h"
|
||||
#include "Project.h"
|
||||
#include "TrackArtist.h"
|
||||
#include "commands/CommandManager.h"
|
||||
|
||||
#include "CaptureEvents.h"
|
||||
@ -730,6 +731,11 @@ void LabelTrack::Draw(wxDC & dc, const wxRect & r, double h, double pps,
|
||||
dc.SetPen(AColor::labelSelectedPen);
|
||||
dc.DrawRectangle(selr);
|
||||
|
||||
// If selection is synchro, draw in linked graphics
|
||||
if (IsSynchroSelected() && !GetSelected() && selr.width > 0) {
|
||||
TrackArtist::DrawLinkTiles(&dc, selr);
|
||||
}
|
||||
|
||||
wxRect after = r;
|
||||
after.x += (before.width + selr.width);
|
||||
after.width -= (before.width + selr.width);
|
||||
|
12004
src/ThemeAsCeeCode.h
12004
src/ThemeAsCeeCode.h
File diff suppressed because it is too large
Load Diff
137
src/Track.cpp
137
src/Track.cpp
@ -205,6 +205,30 @@ Track *Track::GetLink() const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Track::IsSynchroSelected()
|
||||
{
|
||||
#ifdef EXPERIMENTAL_LINKING
|
||||
AudacityProject *p = GetActiveProject();
|
||||
if (!p || !p->IsSticky())
|
||||
return false;
|
||||
|
||||
TrackGroupIterator git(mList);
|
||||
Track *t = git.First(this);
|
||||
|
||||
if (!t) {
|
||||
// Not in a group.
|
||||
return GetSelected();
|
||||
}
|
||||
|
||||
for (; t; t = git.Next()) {
|
||||
if (t->GetSelected())
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// TrackListIterator
|
||||
TrackListIterator::TrackListIterator(TrackList * val)
|
||||
{
|
||||
@ -450,36 +474,35 @@ bool VisibleTrackIterator::Condition(Track *t)
|
||||
// in which the starting track is a member.
|
||||
//
|
||||
TrackGroupIterator::TrackGroupIterator(TrackList * val)
|
||||
: TrackListIterator(val)
|
||||
: TrackListIterator(val),
|
||||
mInLabelSection(false)
|
||||
{
|
||||
mEndOfGroup = false;
|
||||
}
|
||||
|
||||
Track *TrackGroupIterator::First(Track * member)
|
||||
{
|
||||
Track *t = NULL;
|
||||
|
||||
// Scan forward for a label track
|
||||
while (member && member->GetKind() == Track::Wave) {
|
||||
member = l->GetNext(member);
|
||||
// A group consists of any positive number of wave tracks followed by any
|
||||
// non-negative number of label tracks. Step back through any label tracks,
|
||||
// and then through the wave tracks above them.
|
||||
|
||||
while (member && member->GetKind() == Track::Label) {
|
||||
member = l->GetPrev(member);
|
||||
}
|
||||
|
||||
// It's not part of a group if one wasn't found
|
||||
if (!member || member->GetKind() != Track::Label) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Find first wave track in the group
|
||||
member = l->GetPrev(member);
|
||||
while (member && member->GetKind() == Track::Wave) {
|
||||
t = member;
|
||||
member = l->GetPrev(member);
|
||||
}
|
||||
|
||||
// Make it current
|
||||
// Make it current (if t is still NULL there are no wave tracks, so we're
|
||||
// not in a group).
|
||||
if (t)
|
||||
cur = (TrackListNode *) t->GetNode();
|
||||
|
||||
mInLabelSection = false;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
@ -487,30 +510,59 @@ Track *TrackGroupIterator::Next(bool skiplinked)
|
||||
{
|
||||
Track *t = TrackListIterator::Next(skiplinked);
|
||||
|
||||
// End of the group has been reached
|
||||
if (!t || mEndOfGroup) {
|
||||
//
|
||||
// Ways to end a group
|
||||
//
|
||||
|
||||
// End of tracks
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
// In the label section, encounter a non-label track
|
||||
if (mInLabelSection && t->GetKind() != Track::Label) {
|
||||
cur = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Found the end of the group, so signal for next iteration
|
||||
if (t->GetKind() == Track::Label) {
|
||||
mEndOfGroup = true;
|
||||
// Encounter a non-wave non-label track
|
||||
if (t->GetKind() != Track::Wave && t->GetKind() != Track::Label) {
|
||||
cur = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Otherwise, check if we're in the label section
|
||||
mInLabelSection = (t->GetKind() == Track::Label);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
Track *TrackGroupIterator::Prev(bool skiplinked)
|
||||
{
|
||||
// AWD: currently grouping as it works here allows only one label track per
|
||||
// group, but this should change
|
||||
|
||||
Track *t = TrackListIterator::Prev(skiplinked);
|
||||
|
||||
if (!t || t->GetKind() != Track::Wave) {
|
||||
//
|
||||
// Ways to end a group in reverse
|
||||
//
|
||||
|
||||
// Beginning of tracks
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
// In wave section, encounter a label track
|
||||
if (!mInLabelSection && t->GetKind() == Track::Label) {
|
||||
cur = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Encounter a non-wave non-label track
|
||||
if (t->GetKind() != Track::Wave && t->GetKind() != Track::Label) {
|
||||
cur = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Otherwise, check if we're in the label section
|
||||
mInLabelSection = (t->GetKind() == Track::Label);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
@ -521,7 +573,14 @@ Track *TrackGroupIterator::Last(bool skiplinked)
|
||||
|
||||
Track *t = cur->t;
|
||||
|
||||
while (!mEndOfGroup) {
|
||||
while (l->GetNext(t)) {
|
||||
// Check if this is the last track in the group
|
||||
int nextKind = l->GetNext(t)->GetKind();
|
||||
if (mInLabelSection && nextKind != Track::Label)
|
||||
break;
|
||||
if (nextKind != Track::Label && nextKind != Track::Wave)
|
||||
break;
|
||||
|
||||
t = Next(skiplinked);
|
||||
}
|
||||
|
||||
@ -543,26 +602,24 @@ Track *TrackAndGroupIterator::NextGroup(bool skiplinked)
|
||||
return NULL;
|
||||
|
||||
Track* t = cur->t;
|
||||
|
||||
if (t->GetKind() == Track::Label) {
|
||||
// the next group when we have a LabelTrack is the next track
|
||||
return TrackListIterator::Next(skiplinked);
|
||||
}
|
||||
|
||||
TrackGroupIterator git(l);
|
||||
if (git.First(t) == NULL) {
|
||||
//not part of a group
|
||||
return TrackListIterator::Next(skiplinked);
|
||||
}
|
||||
|
||||
//skip the remaining tracks of the current group
|
||||
for (; t != NULL && t->GetKind() != Track::Label; t = TrackListIterator::Next(skiplinked) );
|
||||
|
||||
if (t) {
|
||||
//Reached final Label track, let's go to the next group
|
||||
while(t) {
|
||||
int prevKind = t->GetKind();
|
||||
t = TrackListIterator::Next(skiplinked);
|
||||
}
|
||||
|
||||
// Check if we've exited a group
|
||||
|
||||
// End of tracks
|
||||
if (!t)
|
||||
break;
|
||||
// Non-wave non-label track
|
||||
if (t->GetKind() != Track::Wave && t->GetKind() != Track::Label)
|
||||
break;
|
||||
// From label section to non-label track
|
||||
if (prevKind == Track::Label && t->GetKind() != Track::Label)
|
||||
break;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
@ -179,6 +179,9 @@ class AUDACITY_DLL_API Track: public XMLTagHandler
|
||||
|
||||
virtual double GetStartTime() { return 0.0; }
|
||||
virtual double GetEndTime() { return 0.0; }
|
||||
|
||||
// Checks if linking is on and any track in its group is selected
|
||||
bool IsSynchroSelected();
|
||||
};
|
||||
|
||||
struct TrackListNode
|
||||
@ -298,7 +301,7 @@ class AUDACITY_DLL_API TrackGroupIterator: public TrackListIterator
|
||||
Track *Last(bool skiplinked = false);
|
||||
|
||||
private:
|
||||
bool mEndOfGroup;
|
||||
bool mInLabelSection;
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -662,7 +662,7 @@ void TrackArtist::DrawWaveformBackground(wxDC &dc, const wxRect &r, const double
|
||||
float zoomMin, float zoomMax, bool dB,
|
||||
const sampleCount where[],
|
||||
sampleCount ssel0, sampleCount ssel1,
|
||||
bool drawEnvelope)
|
||||
bool drawEnvelope, bool synchroSelection)
|
||||
{
|
||||
// Visually (one vertical slice of the waveform background, on its side;
|
||||
// the "*" is the actual waveform background we're drawing
|
||||
@ -752,6 +752,17 @@ void TrackArtist::DrawWaveformBackground(wxDC &dc, const wxRect &r, const double
|
||||
dc.DrawRectangle(l, r.y + lmaxtop, w, lminbot - lmaxtop);
|
||||
}
|
||||
|
||||
// If selection is synchro, draw in linked graphics
|
||||
if (synchroSelection && ssel0 < ssel1) {
|
||||
// Find the beginning/end of the selection
|
||||
int begin, end;
|
||||
for (x = 0; x < r.width && where[x] < ssel0; ++x);
|
||||
begin = x;
|
||||
for (; x < r.width && where[x] < ssel1; ++x);
|
||||
end = x;
|
||||
DrawLinkTiles(&dc, wxRect(r.x + begin, r.y, end - 1 - begin, r.height));
|
||||
}
|
||||
|
||||
//OK, the display bounds are between min and max, which
|
||||
//is spread across r.height. Draw the line at the proper place.
|
||||
|
||||
@ -1136,7 +1147,7 @@ void TrackArtist::DrawClipWaveform(WaveTrack *track,
|
||||
double sps = 1./rate; //seconds-per-sample
|
||||
|
||||
//If the track isn't selected, make the selection empty
|
||||
if (!track->GetSelected()) {
|
||||
if (!track->GetSelected() && !track->IsSynchroSelected()) {
|
||||
sel0 = sel1 = 0.0;
|
||||
}
|
||||
|
||||
@ -1281,7 +1292,8 @@ void TrackArtist::DrawClipWaveform(WaveTrack *track,
|
||||
// the envelope and using a colored pen for the selected
|
||||
// part of the waveform
|
||||
DrawWaveformBackground(dc, mid, envValues, zoomMin, zoomMax, dB,
|
||||
where, ssel0, ssel1, drawEnvelope);
|
||||
where, ssel0, ssel1, drawEnvelope,
|
||||
!track->GetSelected());
|
||||
|
||||
if (!showIndividualSamples) {
|
||||
DrawMinMaxRMS(dc, mid, envValues, zoomMin, zoomMax, dB,
|
||||
@ -2522,7 +2534,7 @@ void TrackArtist::DrawLabelTrack(LabelTrack *track,
|
||||
double sel0 = viewInfo->sel0;
|
||||
double sel1 = viewInfo->sel1;
|
||||
|
||||
if (!track->GetSelected())
|
||||
if (!track->GetSelected() && !track->IsSynchroSelected())
|
||||
sel0 = sel1 = 0.0;
|
||||
|
||||
track->Draw(dc, r, viewInfo->h, viewInfo->zoom, sel0, sel1);
|
||||
@ -2623,6 +2635,26 @@ void TrackArtist::SetSpectrumLogMaxFreq(int freq)
|
||||
mLogMaxFreq = freq;
|
||||
}
|
||||
|
||||
void TrackArtist::DrawLinkTiles(wxDC *dc, wxRect r)
|
||||
{
|
||||
wxBitmap sync(theTheme.Image(bmpLinkSelect));
|
||||
|
||||
// Draw in full-width copies
|
||||
int x;
|
||||
for (x = 0; x + sync.GetWidth() < r.width; x += sync.GetWidth()) {
|
||||
for (int y = 0; y < r.height; y += sync.GetHeight()) {
|
||||
dc->DrawBitmap(sync, r.x + x, r.y + y, true);
|
||||
}
|
||||
}
|
||||
// Draw in partial column at end of selection
|
||||
if (r.width - x > 0) {
|
||||
sync = sync.GetSubBitmap(wxRect(0, 0, r.width - x, sync.GetHeight()));
|
||||
for (int y = 0; y < r.height; y += sync.GetHeight()) {
|
||||
dc->DrawBitmap(sync, r.x + x, r.y + y, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Indentation settings for Vim and Emacs and unique identifier for Arch, a
|
||||
// version control system. Please do not modify past this point.
|
||||
//
|
||||
|
@ -91,6 +91,9 @@ class AUDACITY_DLL_API TrackArtist {
|
||||
this->selectedPen = selectedPen;
|
||||
}
|
||||
|
||||
// Helper: draws the "linked" watermark tiled to a rectangle
|
||||
static void DrawLinkTiles(wxDC *dc, wxRect r);
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
@ -135,7 +138,7 @@ class AUDACITY_DLL_API TrackArtist {
|
||||
float zoomMin, float zoomMax, bool dB,
|
||||
const sampleCount where[],
|
||||
sampleCount ssel0, sampleCount ssel1,
|
||||
bool drawEnvelope);
|
||||
bool drawEnvelope, bool synchroSelection);
|
||||
|
||||
void DrawMinMaxRMS(wxDC & dc, const wxRect & r, const double env[],
|
||||
float zoomMin, float zoomMax, bool dB,
|
||||
|
@ -3779,7 +3779,7 @@ void TrackPanel::HandleLabelClick(wxMouseEvent & event)
|
||||
// the selection on this track.
|
||||
if (event.ShiftDown()) {
|
||||
mTracks->Select(t, !t->GetSelected());
|
||||
RefreshTrack(t);
|
||||
Refresh(false);
|
||||
#ifdef EXPERIMENTAL_MIXER_BOARD
|
||||
MixerBoard* pMixerBoard = this->GetMixerBoard();
|
||||
if (pMixerBoard && (t->GetKind() == Track::Wave))
|
||||
@ -5132,7 +5132,8 @@ void TrackPanel::DrawOutside(Track * t, wxDC * dc, const wxRect rec,
|
||||
|
||||
bool bIsWave = (t->GetKind() == Track::Wave);
|
||||
|
||||
mTrackInfo.DrawBackground(dc, r, t->GetSelected(), bIsWave, labelw, vrul);
|
||||
mTrackInfo.DrawBackground(dc, r, t->GetSelected(), t->IsSynchroSelected(),
|
||||
bIsWave, labelw, vrul);
|
||||
|
||||
DrawBordersAroundTrack(t, dc, r, labelw, vrul);
|
||||
DrawShadow(t, dc, r);
|
||||
@ -7235,14 +7236,19 @@ void TrackInfo::DrawBordersWithin(wxDC * dc, const wxRect r, bool bHasMuteSolo )
|
||||
}
|
||||
|
||||
void TrackInfo::DrawBackground(wxDC * dc, const wxRect r, bool bSelected,
|
||||
bool bHasMuteSolo, const int labelw, const int vrul)
|
||||
bool bSyncSel, bool bHasMuteSolo, const int labelw, const int vrul)
|
||||
{
|
||||
// fill in label
|
||||
wxRect fill = r;
|
||||
fill.width = labelw-4;
|
||||
AColor::MediumTrackInfo(dc, bSelected);
|
||||
AColor::MediumTrackInfo(dc, bSelected || bSyncSel);
|
||||
dc->DrawRectangle(fill);
|
||||
|
||||
// Draw in linked tiles for synchro selection
|
||||
if (bSyncSel && !bSelected) {
|
||||
TrackArtist::DrawLinkTiles(dc, fill);
|
||||
}
|
||||
|
||||
if( bHasMuteSolo )
|
||||
{
|
||||
fill=wxRect( r.x+1, r.y+17, vrul-6, 32);
|
||||
@ -7322,7 +7328,7 @@ void TrackInfo::DrawTitleBar(wxDC * dc, const wxRect r, Track * t,
|
||||
// characters if they are repeatedly drawn. This
|
||||
// happens when holding down mouse button and moving
|
||||
// in and out of the title bar. So clear it first.
|
||||
AColor::MediumTrackInfo(dc, t->GetSelected());
|
||||
AColor::MediumTrackInfo(dc, t->GetSelected() || t->IsSynchroSelected());
|
||||
dc->DrawRectangle(bev);
|
||||
dc->DrawText(titleStr, r.x + 19, r.y + 2);
|
||||
|
||||
@ -7358,19 +7364,21 @@ void TrackInfo::DrawMuteSolo(wxDC * dc, const wxRect r, Track * t,
|
||||
if (bev.y + bev.height >= r.y + r.height - 19)
|
||||
return; // don't draw mute and solo buttons, because they don't fit into track label
|
||||
|
||||
AColor::MediumTrackInfo( dc, t->GetSelected() );
|
||||
AColor::MediumTrackInfo( dc, t->GetSelected() || t->IsSynchroSelected());
|
||||
if( solo )
|
||||
{
|
||||
if( t->GetSolo() )
|
||||
{
|
||||
AColor::Solo(dc, t->GetSolo(), t->GetSelected());
|
||||
AColor::Solo(dc, t->GetSolo(),
|
||||
t->GetSelected() || t->IsSynchroSelected());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( t->GetMute() )
|
||||
{
|
||||
AColor::Mute(dc, t->GetMute(), t->GetSelected(), t->GetSolo());
|
||||
AColor::Mute(dc, t->GetMute(),
|
||||
t->GetSelected() || t->IsSynchroSelected(), t->GetSolo());
|
||||
}
|
||||
}
|
||||
//(solo) ? AColor::Solo(dc, t->GetSolo(), t->GetSelected()) :
|
||||
@ -7400,7 +7408,7 @@ void TrackInfo::DrawMinimize(wxDC * dc, const wxRect r, Track * t, bool down, bo
|
||||
GetMinimizeRect(r, bev, minimized);
|
||||
|
||||
// Clear background to get rid of previous arrow
|
||||
AColor::MediumTrackInfo(dc, t->GetSelected());
|
||||
AColor::MediumTrackInfo(dc, t->GetSelected() || t->IsSynchroSelected());
|
||||
dc->DrawRectangle(bev);
|
||||
|
||||
#ifdef EXPERIMENTAL_THEMING
|
||||
|
@ -94,7 +94,7 @@ private:
|
||||
void EnsureSufficientSliders(int index);
|
||||
|
||||
void SetTrackInfoFont(wxDC *dc);
|
||||
void DrawBackground(wxDC * dc, const wxRect r, bool bSelected, bool bHasMuteSolo, const int labelw, const int vrul);
|
||||
void DrawBackground(wxDC * dc, const wxRect r, bool bSelected, bool bSyncSel, bool bHasMuteSolo, const int labelw, const int vrul);
|
||||
void DrawBordersWithin(wxDC * dc, const wxRect r, bool bHasMuteSolo );
|
||||
void DrawCloseBox(wxDC * dc, const wxRect r, bool down);
|
||||
void DrawTitleBar(wxDC * dc, const wxRect r, Track * t, bool down);
|
||||
|
@ -247,6 +247,7 @@ void EditToolBar::OnButton(wxCommandEvent &event)
|
||||
else
|
||||
mButtons[ETBLinkID]->PopUp();
|
||||
p->ModifyToolbarMenus();
|
||||
p->GetTrackPanel()->Refresh(false);
|
||||
}
|
||||
return;//avoiding the call to SetButton()
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user