1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 LabelTrackView.h
6 
7 Paul Licameli split from class LabelTrack
8 
9 **********************************************************************/
10 
11 #ifndef __AUDACITY_LABEL_TRACK_VIEW__
12 #define __AUDACITY_LABEL_TRACK_VIEW__
13 
14 #include "../../ui/CommonTrackView.h"
15 
16 class LabelGlyphHandle;
17 class LabelTextHandle;
18 class LabelDefaultClickHandle;
19 class LabelStruct;
20 class LabelTrack;
21 struct LabelTrackEvent;
22 struct LabelTrackHit;
23 class NotifyingSelectedRegion;
24 class SelectedRegion;
25 struct TrackPanelDrawingContext;
26 class ZoomInfo;
27 
28 class wxBitmap;
29 class wxCommandEvent;
30 class wxDC;
31 class wxMouseEvent;
32 
33 constexpr int NUM_GLYPH_CONFIGS = 3;
34 constexpr int NUM_GLYPH_HIGHLIGHTS = 4;
35 constexpr int MAX_NUM_ROWS =80;
36 
37 class wxKeyEvent;
38 
39 class AUDACITY_DLL_API LabelTrackView final : public CommonTrackView
40 {
41    LabelTrackView( const LabelTrackView& ) = delete;
42    LabelTrackView &operator=( const LabelTrackView& ) = delete;
43 
44    void Reparent( const std::shared_ptr<Track> &parent ) override;
45 
46 public:
47    enum : int { DefaultFontSize = 0 }; //system preferred
48    static constexpr int TextFramePadding { 2 };
49    static constexpr int TextFrameYOffset { -1 };
50    static constexpr int LabelBarHeight { 6 };
51 
52    explicit
53    LabelTrackView( const std::shared_ptr<Track> &pTrack );
54    ~LabelTrackView() override;
55 
56    static LabelTrackView &Get( LabelTrack& );
57    static const LabelTrackView &Get( const LabelTrack& );
58 
59    bool DoCaptureKey( AudacityProject &project, wxKeyEvent &event );
60    bool DoKeyDown(
61       AudacityProject &project, NotifyingSelectedRegion &sel, wxKeyEvent & event);
62    bool DoChar(
63       AudacityProject &project, NotifyingSelectedRegion &sel, wxKeyEvent & event);
64 
65    //This returns the index of the label we just added.
66    int AddLabel(const SelectedRegion &region,
67       const wxString &title = {},
68       int restoreFocus = -1);
69 
70 private:
71    void BindTo( LabelTrack *pParent );
72    void UnbindFrom( LabelTrack *pParent );
73 
74    std::vector<UIHandlePtr> DetailedHitTest
75       (const TrackPanelMouseState &state,
76        const AudacityProject *pProject, int currentTool, bool bMultiTool)
77       override;
78 
79    unsigned CaptureKey
80      (wxKeyEvent &event, ViewInfo &viewInfo, wxWindow *pParent,
81       AudacityProject *project) override;
82 
83    unsigned KeyDown
84       (wxKeyEvent &event, ViewInfo &viewInfo, wxWindow *pParent,
85       AudacityProject *project) override;
86 
87    unsigned Char
88       (wxKeyEvent &event, ViewInfo &viewInfo, wxWindow *pParent,
89       AudacityProject *project) override;
90 
91    std::shared_ptr<TrackVRulerControls> DoGetVRulerControls() override;
92 
93    // Preserve some view state too for undo/redo purposes
94    void CopyTo( Track &track ) const override;
95 
96 public:
97    static void DoEditLabels(
98       AudacityProject &project, LabelTrack *lt = nullptr, int index = -1);
99 
100    static int DialogForLabelName(
101       AudacityProject &project, const SelectedRegion& region,
102       const wxString& initialValue, wxString& value);
103 
104    bool IsTextSelected( AudacityProject &project ) const;
105 
106 private:
107    void CreateCustomGlyphs();
108 
109 public:
110    static wxFont GetFont(const wxString &faceName, int size = DefaultFontSize);
111    static void ResetFont();
112 
113    void Draw( TrackPanelDrawingContext &context, const wxRect & r ) const;
114 
115    bool CutSelectedText( AudacityProject &project );
116    bool CopySelectedText( AudacityProject &project );
117    bool SelectAllText(AudacityProject& project);
118 
119    bool PasteSelectedText(
120       AudacityProject &project, double sel0, double sel1 );
121 
122    static void OverGlyph(
123       const LabelTrack &track, LabelTrackHit &hit, int x, int y );
124 
125 private:
126    static wxBitmap & GetGlyph( int i);
127 
128    struct Index
129    {
130       Index();
131       Index(int index);
132       operator int() const;
133       Index &operator =(int index);
134       Index &operator ++();
135       Index &operator --();
136 
137       bool IsModified() const;
138       void SetModified(bool modified);
139 
140    private:
141       int mIndex;
142       bool mModified;
143    };
144 
145 public:
146    struct Flags {
147       int mInitialCursorPos, mCurrentCursorPos;
148       Index mNavigationIndex;
149       Index mTextEditIndex;
150       wxString mUndoLabel;
151    };
152 
153    void ResetFlags();
154    Flags SaveFlags() const;
155    void RestoreFlags( const Flags& flags );
156 
157    static int OverATextBox( const LabelTrack &track, int xx, int yy );
158 
159    static bool OverTextBox( const LabelStruct *pLabel, int x, int y );
160 
161 private:
162    static bool IsTextClipSupported();
163 
164 public:
165    void AddedLabel( const wxString &title, int pos );
166    void DeletedLabel( int index );
167 
168 private:
169    //And this tells us the index, if there is a label already there.
170    int GetLabelIndex(double t, double t1);
171 
172 public:
173    //get current cursor position,
174    // relative to the left edge of the track panel
175    bool CalcCursorX( AudacityProject &project, int * x ) const;
176 
177 private:
178    void CalcHighlightXs(int *x1, int *x2) const;
179 
180 public:
181    void ShowContextMenu( AudacityProject &project );
182 
183 private:
184    void OnContextMenu( AudacityProject &project, wxCommandEvent & evt);
185 
186    /// Keeps track of the currently selected label (not same as selection region)
187    /// used for navigation between labels
188    mutable Index mNavigationIndex{ -1 };
189    /// Index of the current label text beeing edited
190    mutable Index mTextEditIndex{ -1 };
191 
192    mutable wxString mUndoLabel;
193 
194    static int mIconHeight;
195    static int mIconWidth;
196    static int mTextHeight;
197 
198    static bool mbGlyphsReady;
199    static wxBitmap mBoundaryGlyphs[NUM_GLYPH_CONFIGS * NUM_GLYPH_HIGHLIGHTS];
200 
201    static int mFontHeight;
202    mutable int mCurrentCursorPos;                  /// current cursor position
203    mutable int mInitialCursorPos;                  /// initial cursor position
204 
205 
206    int mRestoreFocus{-2};                          /// Restore focus to this track
207                                                    /// when done editing
208 
209    void ComputeTextPosition(const wxRect & r, int index) const;
210    void ComputeLayout(const wxRect & r, const ZoomInfo &zoomInfo) const;
211    static void DrawLines( wxDC & dc, const LabelStruct &ls, const wxRect & r);
212    static void DrawGlyphs( wxDC & dc, const LabelStruct &ls, const wxRect & r,
213       int GlyphLeft, int GlyphRight);
214    static int GetTextFrameHeight();
215    static void DrawText( wxDC & dc, const LabelStruct &ls, const wxRect & r);
216    static void DrawTextBox( wxDC & dc, const LabelStruct &ls, const wxRect & r);
217    static void DrawBar(wxDC& dc, const LabelStruct& ls, const wxRect& r);
218    static void DrawHighlight(
219       wxDC & dc, const LabelStruct &ls, int xPos1, int xPos2, int charHeight);
220 
221 public:
222    /// convert pixel coordinate to character position in text box
223    int FindCursorPosition(int labelIndex, wxCoord xPos);
GetCurrentCursorPosition()224    int GetCurrentCursorPosition() const { return mCurrentCursorPos; }
225    void SetCurrentCursorPosition(int pos);
GetInitialCursorPosition()226    int GetInitialCursorPosition() const { return mInitialCursorPos; }
227 
228    /// Sets the label with specified index for editing,
229    /// optionaly selection may be specified with [start, end]
230    void SetTextSelection(int labelIndex, int start = 1, int end = 1);
231    int GetTextEditIndex(AudacityProject& project) const;
232    void ResetTextSelection();
233 
234    void SetNavigationIndex(int index);
235    int GetNavigationIndex(AudacityProject& project) const;
236 
237 private:
238 
239    // TrackPanelDrawable implementation
240    void Draw(
241       TrackPanelDrawingContext &context,
242       const wxRect &rect, unsigned iPass ) override;
243 
244    static void calculateFontHeight(wxDC & dc);
245 
246    bool IsValidIndex(const Index& index, AudacityProject& project) const;
247 
248 private:
249    void RemoveSelectedText();
250 
251    void OnLabelAdded( LabelTrackEvent& );
252    void OnLabelDeleted( LabelTrackEvent& );
253    void OnLabelPermuted( LabelTrackEvent& );
254    void OnSelectionChange( LabelTrackEvent& );
255 
256    std::shared_ptr<LabelTrack> FindLabelTrack();
257    std::shared_ptr<const LabelTrack> FindLabelTrack() const;
258 
259    std::weak_ptr<LabelGlyphHandle> mGlyphHandle;
260    std::weak_ptr<LabelTextHandle> mTextHandle;
261 
262    static wxFont msFont;
263 
264    // Bug #2571: See explanation in ShowContextMenu()
265    int mEditIndex;
266 };
267 
268 #endif
269