2010-01-23 19:44:49 +00:00
|
|
|
/**********************************************************************
|
|
|
|
|
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
|
|
|
|
LabelTrack.h
|
|
|
|
|
|
|
|
Dominic Mazzoni
|
|
|
|
James Crook
|
|
|
|
Jun Wan
|
|
|
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
#ifndef _LABELTRACK_
|
|
|
|
#define _LABELTRACK_
|
|
|
|
|
2014-10-05 17:10:09 +00:00
|
|
|
#include "SelectedRegion.h"
|
2010-01-23 19:44:49 +00:00
|
|
|
#include "Track.h"
|
|
|
|
|
|
|
|
|
2018-11-14 20:01:44 +00:00
|
|
|
class wxFont;
|
2010-01-23 19:44:49 +00:00
|
|
|
class wxKeyEvent;
|
|
|
|
class wxMouseEvent;
|
|
|
|
class wxTextFile;
|
|
|
|
class wxWindow;
|
|
|
|
class wxIcon;
|
|
|
|
class wxBitmap;
|
|
|
|
class TrackList;
|
|
|
|
|
|
|
|
class AudacityProject;
|
|
|
|
class DirManager;
|
|
|
|
class TimeWarper;
|
2015-04-20 04:17:26 +00:00
|
|
|
class ZoomInfo;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
|
2017-06-18 01:37:41 +00:00
|
|
|
struct LabelTrackHit;
|
2017-06-23 23:28:38 +00:00
|
|
|
struct TrackPanelDrawingContext;
|
2017-06-18 01:37:41 +00:00
|
|
|
|
2014-06-03 20:30:19 +00:00
|
|
|
class LabelStruct
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
public:
|
2014-10-05 17:10:09 +00:00
|
|
|
// Copies region
|
|
|
|
LabelStruct(const SelectedRegion& region, const wxString &aTitle);
|
|
|
|
// Copies region but then overwrites other times
|
|
|
|
LabelStruct(const SelectedRegion& region, double t0, double t1,
|
|
|
|
const wxString &aTitle);
|
2016-06-23 19:03:30 +00:00
|
|
|
void DrawLines( wxDC & dc, const wxRect & r) const;
|
|
|
|
void DrawGlyphs
|
|
|
|
( wxDC & dc, const wxRect & r, int GlyphLeft, int GlyphRight) const;
|
|
|
|
void DrawText( wxDC & dc, const wxRect & r) const;
|
|
|
|
void DrawTextBox( wxDC & dc, const wxRect & r) const;
|
2016-06-30 19:56:57 +00:00
|
|
|
void DrawHighlight( wxDC & dc, int xPos1, int xPos2, int charHeight) const;
|
2016-02-27 17:12:40 +00:00
|
|
|
void getXPos( wxDC & dc, int * xPos1, int cursorPos) const;
|
2015-04-10 03:37:39 +00:00
|
|
|
const SelectedRegion &getSelectedRegion() const { return selectedRegion; }
|
2014-10-05 17:10:09 +00:00
|
|
|
double getDuration() const { return selectedRegion.duration(); }
|
|
|
|
double getT0() const { return selectedRegion.t0(); }
|
|
|
|
double getT1() const { return selectedRegion.t1(); }
|
|
|
|
// Returns true iff the label got inverted:
|
|
|
|
bool AdjustEdge( int iEdge, double fNewTime);
|
2010-02-07 11:11:35 +00:00
|
|
|
void MoveLabel( int iEdge, double fNewTime);
|
2014-06-03 20:30:19 +00:00
|
|
|
|
2016-07-10 23:09:48 +00:00
|
|
|
struct BadFormatException {};
|
2016-07-13 02:16:15 +00:00
|
|
|
static LabelStruct Import(wxTextFile &file, int &index);
|
2016-07-10 23:09:48 +00:00
|
|
|
|
|
|
|
void Export(wxTextFile &file) const;
|
|
|
|
|
2010-09-18 17:41:15 +00:00
|
|
|
/// Relationships between selection region and labels
|
|
|
|
enum TimeRelations
|
|
|
|
{
|
|
|
|
BEFORE_LABEL,
|
|
|
|
AFTER_LABEL,
|
|
|
|
SURROUNDS_LABEL,
|
|
|
|
WITHIN_LABEL,
|
|
|
|
BEGINS_IN_LABEL,
|
|
|
|
ENDS_IN_LABEL
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Returns relationship between a region described and this label; if
|
|
|
|
/// parent is set, it will consider point labels at the very beginning
|
|
|
|
/// and end of parent to be within a region that borders them (this makes
|
2016-02-14 23:50:45 +00:00
|
|
|
/// it possible to DELETE capture all labels with a Select All).
|
2010-09-18 17:41:15 +00:00
|
|
|
TimeRelations RegionRelation(double reg_t0, double reg_t1,
|
2016-06-23 19:03:30 +00:00
|
|
|
const LabelTrack *parent = NULL) const;
|
2014-06-03 20:30:19 +00:00
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
public:
|
2014-10-05 17:10:09 +00:00
|
|
|
SelectedRegion selectedRegion;
|
2010-01-23 19:44:49 +00:00
|
|
|
wxString title; /// Text of the label.
|
2016-06-30 19:56:57 +00:00
|
|
|
mutable int width; /// width of the text in pixels.
|
2014-06-03 20:30:19 +00:00
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
// Working storage for on-screen layout.
|
2016-06-30 19:56:57 +00:00
|
|
|
mutable int x; /// Pixel position of left hand glyph
|
|
|
|
mutable int x1; /// Pixel position of right hand glyph
|
|
|
|
mutable int xText; /// Pixel position of left hand side of text box
|
|
|
|
mutable int y; /// Pixel position of label.
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
bool updated; /// flag to tell if the label times were updated
|
|
|
|
};
|
|
|
|
|
2016-06-30 19:56:57 +00:00
|
|
|
using LabelArray = std::vector<LabelStruct>;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
const int NUM_GLYPH_CONFIGS = 3;
|
|
|
|
const int NUM_GLYPH_HIGHLIGHTS = 4;
|
|
|
|
const int MAX_NUM_ROWS =80;
|
|
|
|
|
Changed lifetime management of UIHandle objects, no singletons...
... Rather, construct them during hit tests (also capturing more state sooner
rather than at Click time, and adding some accessors for later use)
This also fixes bug 1677 by other means and avoids similar problems.
A cell may be implemented to re-use a previously hit handle object, not yet
clicked, in a later hit test, by remembering a weak pointer, but TrackPanel
holds the strong pointers that determine when the object is destroyed.
And the objects will surely be destroyed after drag-release, or ESC key.
For now they are also destroyed whenever not dragging, and hit-testing is
re-invoked; that will be changed later, so that the re-use mentioned above
becomes effective, but still they will be destroyed when the pointer moves
from one cell to another.
2017-07-05 20:45:55 +00:00
|
|
|
class LabelGlyphHandle;
|
|
|
|
class LabelTextHandle;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2016-02-24 06:06:39 +00:00
|
|
|
class AUDACITY_DLL_API LabelTrack final : public Track
|
2013-08-22 20:52:56 +00:00
|
|
|
{
|
2010-01-23 19:44:49 +00:00
|
|
|
friend class LabelStruct;
|
|
|
|
|
|
|
|
public:
|
2018-10-22 12:51:16 +00:00
|
|
|
static void DoEditLabels(
|
|
|
|
AudacityProject &project, LabelTrack *lt = nullptr, int index = -1);
|
|
|
|
static int DialogForLabelName(
|
|
|
|
AudacityProject &project, const SelectedRegion& region,
|
|
|
|
const wxString& initialValue, wxString& value);
|
|
|
|
|
2015-08-08 05:01:24 +00:00
|
|
|
bool IsGoodLabelFirstKey(const wxKeyEvent & evt);
|
|
|
|
bool IsGoodLabelEditKey(const wxKeyEvent & evt);
|
2019-06-09 00:35:21 +00:00
|
|
|
bool IsTextSelected() const;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
void CreateCustomGlyphs();
|
2016-08-13 04:38:31 +00:00
|
|
|
LabelTrack(const std::shared_ptr<DirManager> &projDirManager);
|
2010-01-23 19:44:49 +00:00
|
|
|
LabelTrack(const LabelTrack &orig);
|
|
|
|
|
|
|
|
virtual ~ LabelTrack();
|
2015-07-07 03:12:16 +00:00
|
|
|
|
2017-06-29 14:34:57 +00:00
|
|
|
std::vector<UIHandlePtr> DetailedHitTest
|
2017-06-29 03:21:20 +00:00
|
|
|
(const TrackPanelMouseState &state,
|
2017-06-19 19:02:45 +00:00
|
|
|
const AudacityProject *pProject, int currentTool, bool bMultiTool)
|
|
|
|
override;
|
2015-07-07 03:12:16 +00:00
|
|
|
|
2015-08-17 21:49:00 +00:00
|
|
|
bool DoCaptureKey(wxKeyEvent &event);
|
|
|
|
unsigned CaptureKey
|
|
|
|
(wxKeyEvent &event, ViewInfo &viewInfo, wxWindow *pParent) override;
|
|
|
|
|
|
|
|
unsigned KeyDown
|
|
|
|
(wxKeyEvent &event, ViewInfo &viewInfo, wxWindow *pParent) override;
|
|
|
|
|
|
|
|
unsigned Char
|
|
|
|
(wxKeyEvent &event, ViewInfo &viewInfo, wxWindow *pParent) override;
|
|
|
|
|
2016-02-24 06:06:47 +00:00
|
|
|
void SetOffset(double dOffset) override;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2016-06-23 17:45:22 +00:00
|
|
|
static const int DefaultFontSize = 12;
|
|
|
|
|
|
|
|
static wxFont GetFont(const wxString &faceName, int size = DefaultFontSize);
|
2010-01-23 19:44:49 +00:00
|
|
|
static void ResetFont();
|
|
|
|
|
2018-11-03 17:34:48 +00:00
|
|
|
void Draw( TrackPanelDrawingContext &context, const wxRect & r ) const;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
int getSelectedIndex() const { return mSelIndex; }
|
|
|
|
|
2016-02-24 06:06:47 +00:00
|
|
|
double GetOffset() const override;
|
|
|
|
double GetStartTime() const override;
|
|
|
|
double GetEndTime() const override;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2018-11-19 04:07:05 +00:00
|
|
|
using Holder = std::shared_ptr<LabelTrack>;
|
2016-03-02 19:37:47 +00:00
|
|
|
Track::Holder Duplicate() const override;
|
2015-08-23 23:02:06 +00:00
|
|
|
|
2016-02-24 06:06:47 +00:00
|
|
|
void SetSelected(bool s) override;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2016-02-24 06:06:47 +00:00
|
|
|
bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) override;
|
|
|
|
XMLTagHandler *HandleXMLChild(const wxChar *tag) override;
|
2017-02-22 19:23:35 +00:00
|
|
|
void WriteXML(XMLWriter &xmlFile) const override;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
#if LEGACY_PROJECT_FILE_SUPPORT
|
2016-02-24 06:06:47 +00:00
|
|
|
bool Load(wxTextFile * in, DirManager * dirManager) override;
|
|
|
|
bool Save(wxTextFile * out, bool overwrite) override;
|
2010-01-23 19:44:49 +00:00
|
|
|
#endif
|
|
|
|
|
2016-03-02 20:36:44 +00:00
|
|
|
Track::Holder Cut (double t0, double t1) override;
|
2016-11-26 13:48:08 +00:00
|
|
|
Track::Holder Copy (double t0, double t1, bool forClipboard = true) const override;
|
2017-03-23 15:10:14 +00:00
|
|
|
void Clear(double t0, double t1) override;
|
|
|
|
void Paste(double t, const Track * src) override;
|
2010-01-23 19:44:49 +00:00
|
|
|
bool Repeat(double t0, double t1, int n);
|
|
|
|
|
2017-03-23 15:10:14 +00:00
|
|
|
void Silence(double t0, double t1) override;
|
|
|
|
void InsertSilence(double t, double len) override;
|
2017-06-18 01:37:41 +00:00
|
|
|
void OverGlyph(LabelTrackHit &hit, int x, int y) const;
|
2010-01-23 19:44:49 +00:00
|
|
|
static wxBitmap & GetGlyph( int i);
|
|
|
|
|
|
|
|
|
2015-08-17 21:49:00 +00:00
|
|
|
struct Flags {
|
|
|
|
int mInitialCursorPos, mCurrentCursorPos, mSelIndex;
|
|
|
|
bool mRightDragging, mDrawCursor;
|
|
|
|
};
|
2010-01-23 19:44:49 +00:00
|
|
|
void ResetFlags();
|
2015-08-17 21:49:00 +00:00
|
|
|
Flags SaveFlags() const
|
|
|
|
{
|
|
|
|
return {
|
|
|
|
mInitialCursorPos, mCurrentCursorPos, mSelIndex,
|
|
|
|
mRightDragging, mDrawCursor
|
|
|
|
};
|
|
|
|
}
|
|
|
|
void RestoreFlags( const Flags& flags );
|
|
|
|
|
2015-08-18 01:26:34 +00:00
|
|
|
int OverATextBox(int xx, int yy) const;
|
|
|
|
bool OverTextBox(const LabelStruct *pLabel, int x, int y) const;
|
2010-01-23 19:44:49 +00:00
|
|
|
bool CutSelectedText();
|
|
|
|
bool CopySelectedText();
|
|
|
|
bool PasteSelectedText(double sel0, double sel1);
|
|
|
|
static bool IsTextClipSupported();
|
2014-06-03 20:30:19 +00:00
|
|
|
|
2015-08-17 21:49:00 +00:00
|
|
|
void HandleGlyphClick
|
2017-06-18 01:37:41 +00:00
|
|
|
(LabelTrackHit &hit,
|
|
|
|
const wxMouseEvent & evt, const wxRect & r, const ZoomInfo &zoomInfo,
|
2015-08-17 21:49:00 +00:00
|
|
|
SelectedRegion *newSel);
|
|
|
|
void HandleTextClick
|
|
|
|
(const wxMouseEvent & evt, const wxRect & r, const ZoomInfo &zoomInfo,
|
|
|
|
SelectedRegion *newSel);
|
2017-06-18 01:37:41 +00:00
|
|
|
bool HandleGlyphDragRelease
|
|
|
|
(LabelTrackHit &hit,
|
|
|
|
const wxMouseEvent & evt, wxRect & r, const ZoomInfo &zoomInfo,
|
|
|
|
SelectedRegion *newSel);
|
2015-08-11 00:02:24 +00:00
|
|
|
void HandleTextDragRelease(const wxMouseEvent & evt);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2014-10-05 17:10:09 +00:00
|
|
|
bool OnKeyDown(SelectedRegion &sel, wxKeyEvent & event);
|
|
|
|
bool OnChar(SelectedRegion &sel, wxKeyEvent & event);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
void Import(wxTextFile & f);
|
2016-06-23 19:03:30 +00:00
|
|
|
void Export(wxTextFile & f) const;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
void Unselect();
|
|
|
|
|
2018-11-08 16:07:42 +00:00
|
|
|
// Whether any label box is selected -- not, whether the track is selected.
|
|
|
|
bool HasSelection() const;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
int GetNumLabels() const;
|
|
|
|
const LabelStruct *GetLabel(int index) const;
|
2019-06-09 00:35:21 +00:00
|
|
|
const LabelArray &GetLabels() const { return mLabels; }
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
//This returns the index of the label we just added.
|
2019-03-15 18:28:30 +00:00
|
|
|
int AddLabel(const SelectedRegion ®ion, const wxString &title = {},
|
2016-01-23 16:35:37 +00:00
|
|
|
int restoreFocus = -1);
|
2010-01-23 19:44:49 +00:00
|
|
|
//And this tells us the index, if there is a label already there.
|
|
|
|
int GetLabelIndex(double t, double t1);
|
|
|
|
|
|
|
|
//This deletes the label at given index.
|
|
|
|
void DeleteLabel(int index);
|
|
|
|
|
2016-06-23 18:39:14 +00:00
|
|
|
//get current cursor position,
|
|
|
|
// relative to the left edge of the track panel
|
|
|
|
bool CalcCursorX(int * x) const;
|
2014-06-03 20:30:19 +00:00
|
|
|
|
2016-06-23 23:49:31 +00:00
|
|
|
void CalcHighlightXs(int *x1, int *x2) const;
|
|
|
|
|
2017-06-18 01:37:41 +00:00
|
|
|
void MayAdjustLabel
|
|
|
|
( LabelTrackHit &hit,
|
|
|
|
int iLabel, int iEdge, bool bAllowSwapping, double fNewTime);
|
2010-02-07 11:11:35 +00:00
|
|
|
void MayMoveLabel( int iLabel, int iEdge, double fNewTime);
|
|
|
|
|
2010-02-16 20:50:38 +00:00
|
|
|
// This pastes labels without shifting existing ones
|
2016-02-27 17:54:57 +00:00
|
|
|
bool PasteOver(double t, const Track *src);
|
2016-02-23 19:27:43 +00:00
|
|
|
|
|
|
|
// PRL: These functions were not used because they were not overrides! Was that right?
|
2016-03-02 20:36:44 +00:00
|
|
|
//Track::Holder SplitCut(double b, double e) /* not override */;
|
2016-02-23 19:27:43 +00:00
|
|
|
//bool SplitDelete(double b, double e) /* not override */;
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
void ShiftLabelsOnInsert(double length, double pt);
|
|
|
|
void ChangeLabelsOnReverse(double b, double e);
|
|
|
|
void ScaleLabels(double b, double e, double change);
|
|
|
|
double AdjustTimeStampOnScale(double t, double b, double e, double change);
|
|
|
|
void WarpLabels(const TimeWarper &warper);
|
2014-06-03 20:30:19 +00:00
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
// Returns tab-separated text of all labels completely within given region
|
2016-06-23 19:03:30 +00:00
|
|
|
wxString GetTextOfLabels(double t0, double t1) const;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2016-10-18 14:50:42 +00:00
|
|
|
int FindNextLabel(const SelectedRegion& currentSelection);
|
|
|
|
int FindPrevLabel(const SelectedRegion& currentSelection);
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
public:
|
2017-06-18 01:37:41 +00:00
|
|
|
void SortLabels(LabelTrackHit *pHit = nullptr);
|
2010-01-23 19:44:49 +00:00
|
|
|
private:
|
2017-01-06 18:55:57 +00:00
|
|
|
TrackKind GetKind() const override { return TrackKind::Label; }
|
|
|
|
|
2015-07-30 15:38:03 +00:00
|
|
|
void ShowContextMenu();
|
|
|
|
void OnContextMenu(wxCommandEvent & evt);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
int mSelIndex; /// Keeps track of the currently selected label
|
|
|
|
int mxMouseDisplacement; /// Displacement of mouse cursor from the centre being dragged.
|
|
|
|
LabelArray mLabels;
|
|
|
|
|
|
|
|
static int mIconHeight;
|
|
|
|
static int mIconWidth;
|
|
|
|
static int mTextHeight;
|
|
|
|
static bool mbGlyphsReady;
|
|
|
|
static wxBitmap mBoundaryGlyphs[NUM_GLYPH_CONFIGS * NUM_GLYPH_HIGHLIGHTS];
|
|
|
|
|
|
|
|
static int mFontHeight;
|
2016-06-23 19:12:46 +00:00
|
|
|
int mCurrentCursorPos; /// current cursor position
|
|
|
|
int mInitialCursorPos; /// initial cursor position
|
2016-06-23 19:03:30 +00:00
|
|
|
|
|
|
|
bool mRightDragging; /// flag to tell if it's a valid dragging
|
2016-06-23 19:12:46 +00:00
|
|
|
bool mDrawCursor; /// flag to tell if drawing the
|
|
|
|
/// cursor or not
|
2016-06-23 19:03:30 +00:00
|
|
|
int mRestoreFocus; /// Restore focus to this track
|
|
|
|
/// when done editing
|
2014-06-03 20:30:19 +00:00
|
|
|
|
2010-02-16 20:50:38 +00:00
|
|
|
// Set in copied label tracks
|
2010-01-23 19:44:49 +00:00
|
|
|
double mClipLen;
|
|
|
|
|
2016-10-18 14:50:42 +00:00
|
|
|
int miLastLabel; // used by FindNextLabel and FindPrevLabel
|
|
|
|
|
2016-02-27 17:12:40 +00:00
|
|
|
void ComputeLayout(const wxRect & r, const ZoomInfo &zoomInfo) const;
|
|
|
|
void ComputeTextPosition(const wxRect & r, int index) const;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2016-06-23 19:12:46 +00:00
|
|
|
public:
|
2016-07-11 17:59:29 +00:00
|
|
|
int FindCurrentCursorPosition(int xPos);
|
2016-06-23 19:12:46 +00:00
|
|
|
void SetCurrentCursorPosition(int xPos);
|
|
|
|
|
|
|
|
private:
|
2016-02-27 17:12:40 +00:00
|
|
|
void calculateFontHeight(wxDC & dc) const;
|
2010-01-23 19:44:49 +00:00
|
|
|
void RemoveSelectedText();
|
|
|
|
|
|
|
|
static wxFont msFont;
|
2015-07-07 03:12:16 +00:00
|
|
|
|
Changed lifetime management of UIHandle objects, no singletons...
... Rather, construct them during hit tests (also capturing more state sooner
rather than at Click time, and adding some accessors for later use)
This also fixes bug 1677 by other means and avoids similar problems.
A cell may be implemented to re-use a previously hit handle object, not yet
clicked, in a later hit test, by remembering a weak pointer, but TrackPanel
holds the strong pointers that determine when the object is destroyed.
And the objects will surely be destroyed after drag-release, or ESC key.
For now they are also destroyed whenever not dragging, and hit-testing is
re-invoked; that will be changed later, so that the re-use mentioned above
becomes effective, but still they will be destroyed when the pointer moves
from one cell to another.
2017-07-05 20:45:55 +00:00
|
|
|
std::weak_ptr<LabelGlyphHandle> mGlyphHandle;
|
|
|
|
std::weak_ptr<LabelTextHandle> mTextHandle;
|
|
|
|
|
2015-07-07 03:12:16 +00:00
|
|
|
protected:
|
2018-11-07 23:16:22 +00:00
|
|
|
std::shared_ptr<TrackView> DoGetView() override;
|
2018-11-06 16:02:03 +00:00
|
|
|
std::shared_ptr<TrackControls> DoGetControls() override;
|
2018-11-07 23:16:22 +00:00
|
|
|
|
2018-02-09 19:12:25 +00:00
|
|
|
friend class GetInfoCommand; // to get labels.
|
|
|
|
friend class SetLabelCommand; // to set labels.
|
2010-01-23 19:44:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|