> If it's okay with you, I'd like to rename "LabelPanel" into
> "TrackLabels" and stick it in its own source file. I'm also
> going to take all of the code in TrackPanel::DisplaySelection()
> and put it in its own source file.
No problem with that, but I'd suggest you make the name singular.
Although currently one instance of the class draws all the labels,
the iteration is outside the class, so it is a singular (flyweight)
(The fact that gains and pans are in there as arrays is a
GUI or Gui?
I have a preference - I use abbreviations in variable
names by capitalising only the first letter:
Rather than 'GUIRGBOKDlg', I'd use instead 'GuiRgbOkDlg'.
Does anyone mind if we use Gui not GUI in class and function names?
I'd feel happier. :-)
> Sounds good. I only have two concerns:
> * wxWindows is far from optimal in its hit-testing routines, - it often
> does a linear scan of a list of controls. We should investigate its
> speed at handling hundreds of controls inside the project window
> before committing to this.
Yes, I'm concerned about this step too, especially about transitioning
from lightweight/flyweight controls to real pucka ones. 'large numbers
of controls' is something that needs to be investigated. I'll have a
look at it when I have time and report back.
> * It would make it slightly more difficult to handle actions that go
> between tracks, e.g. selecting two tracks by clicking in one and
> releasing in the other. Perhaps selecting should be handled by the
> parent class, rather than the Track class, because it needs to know
> about all of the tracks, not just the one that initially receives the
If this is the only case I don't see it as a difficult to solve. Can you
think of other cases of events that span multiple tracks that
might not easily ripple up?
> If you disagree with my opinion, or Josh's, or anyone else's, please
> keep discussing it until we can come to consensus.
Will do, have done, am doing - where I disagree. The trouble is you
guys are too reasonable and too ready to listen to other points of
view to get a real ding-dong argument going.
> Though I don't want to do much more refactoring until after the freeze,
> I'd be happy to continue discussing it. Let's go into more detail as
> to exactly how the new track hierarchy might work. In particular, I
> like your idea of making use of a generic wxWindows widget for a
> user-resizable "sizer", and I'd like to discuss how that might fit in.
TrackPanel would use InteractiveBoxSizer (other names welcome)
to organise its tracks; StereoGuiTrack would use it again (in a
slightly different way) between its two channels.
TrackPanel's existing support for reordering would also move
to InteractiveBoxSizer. It could be enabled or disabled by a
I also have in mind a 'FlowSizer' - the kind that one would
use for text line breaking. It would be the right thing to pour the
control panels into, because then people with large screens would
get all three control panels on the same line and more space for
the waveforms underneath.
I don't see any real problem with any of this. I think this would fit in
well with other refactoring plans. As well, not instead.
> Should GUITrack derive from that [InteractiveBoxSizer] class?
No I don't think so. If you buy this plan an InteractiveBoxSizer
will be a member variable of TrackPanel and we'll be using
InteractiveBoxSizer::Add() to add each GuiTrack into
TrackPanel to get sized and positioned.
So, GuiTrack only needs to be something that a wxSizer can
Add(), it should support GetSize(), GetSizeHints(),
SetSize() [I need to check that list] - It would certainly
be advisable if GuiTrack was (derived from) a wxWindow or
a wxSizer, but not an absolute necessity.
> Other open questions: What is a TrackList now? Should there be a
I think TrackList still exists.
A TrackList is a Track as well. A StereoTrack in my view must
contain Tracks and also be a Track, so StereoTrack might as
well derive from TrackList to achieve this.
I take on board Josh's comment about TrackList/TrackGroup
with waves with different formats in it. [Or even as not
suggested, a mix of rulers, timetracks and wavetracks].
Some operations on a TrackList won't 'make sense'. I
don't think we need to worry about it unduly though - or
go as far as making the TrackList class abstract as you
suggest Dominic - as long as StereoGuiTrack and
StereoTrack and the cases we care about work. We shouldn't
be scared of returning 'unsupported operation' errors.
If we were, we would have to have a class for every
combination of sample rate and format if there were some
operations disallowed on certain combinations.
I think, yes we should have a GuiTrackList too, though I'm open
to more arguments against.
Whatever way we cut it, somewhere there will have
to be real code that takes a TrackList and assembles the
corresponding part of the Gui. It might as well do it by
constructing a GuiTrackList which is then self-display.
If we can pass a TrackList to a GuiTrackList constructor and
have it generate the GuiTrackList, that would be cool, but
other solutions would be satisfactory too.
> Is there a way that effects could see
> a flattened view of the tracks, but the TrackPanel could see a
> hierarchical view?
Yes. We can provide iterators over the TrackList hierarchy
that work in different ways. I think TrackList itself should be
hierarchical, i.e. it can contain both Tracks and TrackLists.
GuiTrackList certainly will be hierarchical. If TrackList isn't
hierarchical the parallel Track / GuiTrack hierarchy attempt
is just a myth.
It's clear that the purely audio side will need different iterators.
There are cases where you mix everything down (perhaps
mixed stereo and mono) to one mono track and other cases
where you mix everything down to a stereo track. The
audio-level mixing code should just get an iterator to tell it
what to work on.
> This assumes that you accept our basic idea of the Track/GUITrack/
> WaveTrack/GUIWaveTrack diamond. If not, please continue to discuss
> until either you're happy or you've convinced us otherwise.
OK, this is my opinion:
The diamond is fine, though it may turn out to be a halfway house.
Some of those lines may turn out to be references rather than inheritance.
That shouldn't worry us. It's not a big change to make later if it is
The diamond certainly progresses us from having everything mixed up
in one big jumbo TrackPanel class.
The crunch for me in the design is what is a GuiStereoTrack and how
does it relate to a StereoTrack and to a GuiTrack?
\ / \
\ / \
\ / \
\ / \
Both are true.
Is this over complex? No. We have a very regular structure.
We could rub out some links in the diagram to pretend life
is simpler but that doesn't really change anything.
I believe it is possible by delving into the arcana of C++ to
have both multiple inheritances at the same time, without
duplicting shared ancestors.
If we use that trick, it will probably deserve a discreet
comment in the code :-)
At the end of the day, I don't actually care whether some lines
are inheritance or membership or reference. If you get down into
compiler technology, the difference between Is-a and has-a
is way less than it's cracked up to be. To be blunt it's actually
an arbitrary and often time-wasting decision that C++ forces on
you because of a deficiency in C++'s syntactic sugar - but heck,
that's a whole holy-war crusade. I thought I should at least
say where I was coming from. I feel better now.
Thank you :-)
Back to the issue:
The StereoTrack contains two WaveTracks. These are distinct from the
'WaveTrack' which the StereoTrack 'is'. If you apply 'Cut' to either left
or right track you get a different result from applying 'Cut' to the
The GuiStereoTrack contains two GuiWaveTracks.
In both cases the containers take pointers to objects not objects.
> If we end up using classes like a GUITrackGroup,
> does that mean that there will have to be a TrackGroup that non-GUI
> classes (e.g. effects) see?
If we have TrackList we don't need TrackGroup.
If we have GuiTrackList we can dispense with GuiTrackGroup
(or just rename it perhaps?).
Just as a TrackList is a Track, a GuiTrackList is a GuiTrack.
TrackPanel contains a GuiTrackList (which contains an
InteractiveBoxSizer) and we add GuiTracks into
the GuiTrackList. Under the hood this adds the GuiTracks
into the InteractiveBoxSizer, but that's an implementation
Cut to the chase:
The crunch is what is a StereoTrack and what is a StereoGuiTrack?
A StereoTrack is a TrackList, it contains two Tracks.
A GuiStereoTrack is a GuiTrackList in which there are
two ordinary GuiTracks.
The other crunch for me is 'what happens to the two TrackLabels for the
two GuiTracks that are in the GuiStereoTrack'?
In my view of things they never existed at all! GuiTracks can be
displayed perfectly well without a TrackLabel. TrackPanel has
a special feature (by default it is enabled) that ensures every top
level GuiTrack has a TrackLabel. It inserts the TrackLabels
and sizers into the internal sizers to achieve this. We're adding
Gui elements into Gui components, a special customising of a
GuiTrackList for display. My view is that TrackLabels are
optional decoration to GuiWaveTracks - as comes clear
from tracks within a stereo track.
And more... sometimes when I am editing I'd prefer a single
pop-up TrackLabel that drives rate, format, pan and gain
on ALL wave tracks across the project and to not see this panel
most of the time. In the scheme described it's possible to add that
way of working as an option for people who want it.