Audacity 3.2.0
TrackInfo.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5TrackInfo.cpp
6
7Paul Licameli split from TrackPanel.cpp
8
9********************************************************************/
29#include "TrackInfo.h"
30
31#include <wx/app.h>
32#include <wx/dc.h>
33#include <wx/frame.h>
34
35#include "AColor.h"
36#include "AllThemeResources.h"
37#include "Prefs.h"
38#include "Project.h"
39#include "SyncLock.h"
40#include "Theme.h"
41#include "Track.h"
43#include "ViewInfo.h"
45#include "tracks/ui/TrackView.h"
46
47// Subscribe to preference changes to update static variables
49 wxString gSoloPref;
50 wxFont gFont;
51
52 bool mInitialized{ false };
53
54 void UpdatePrefs() override
55 {
57
58 // Calculation of best font size depends on language, so it should be redone in case
59 // the language preference changed.
60
61 // wxWidgets seems to need a window to do this portably.
62 if ( !wxTheApp )
63 return;
64 auto window = wxTheApp->GetTopWindow();
65 if ( !window )
66 return;
67
68 int fontSize = 10;
69 gFont.Create(fontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
70
71 int allowableWidth =
72 // PRL: was it correct to include the margin?
74 - 2; // 2 to allow for left/right borders
75 int textWidth;
76 do {
77 gFont.SetPointSize(fontSize);
78 window->GetTextExtent(_("Stereo, 999999Hz"),
79 &textWidth, nullptr, nullptr, nullptr, &gFont);
80 fontSize--;
81 } while (textWidth >= allowableWidth);
82
83 mInitialized = true;
84 }
85};
86
88{
89 static Settings theSettings;
90 if ( !theSettings.mInitialized )
91 theSettings.UpdatePrefs();
92 return theSettings;
93}
94
96{
97 return settings().gSoloPref != wxT("None");
98}
99
100#define RANGE(array) (array), (array) + sizeof(array)/sizeof(*(array))
103
105{
106 static const TCPLines theLines{
107#ifdef EXPERIMENTAL_DA
108
111
112#else
113
116
117#endif
118 };
119 return theLines;
120}
121
124{
125 return commonTrackTCPLines();
126}
127
128namespace {
129
130int totalTCPLines( const TCPLines &lines, bool omitLastExtra )
131{
132 int total = 0;
133 int lastExtra = 0;
134 for ( const auto line : lines ) {
135 lastExtra = line.extraSpace;
136 total += line.height + lastExtra;
137 }
138 if (omitLastExtra)
139 total -= lastExtra;
140 return total;
141}
142}
143
144// return y value and height
145std::pair< int, int >
146TrackInfo::CalcItemY( const TCPLines &lines, unsigned iItem )
147{
148 int y = 0;
149 auto pLines = lines.begin();
150 while ( pLines != lines.end() &&
151 0 == (pLines->items & iItem) ) {
152 y += pLines->height + pLines->extraSpace;
153 ++pLines;
154 }
155 int height = 0;
156 if ( pLines != lines.end() )
157 height = pLines->height;
158 return { y, height };
159}
160
161namespace {
162
163// Items for the bottom of the panel, listed bottom-upwards
164// As also with the top items, the extra space is below the item
166 // The '0' avoids impinging on bottom line of TCP
167 // Use -1 if you do want to do so.
170};
172
173// return y value and height
174std::pair< int, int > CalcBottomItemY
175 ( const TCPLines &lines, unsigned iItem, int height )
176{
177 int y = height;
178 auto pLines = lines.begin();
179 while ( pLines != lines.end() &&
180 0 == (pLines->items & iItem) ) {
181 y -= pLines->height + pLines->extraSpace;
182 ++pLines;
183 }
184 if (pLines != lines.end())
185 y -= (pLines->height + pLines->extraSpace );
186 return { y, pLines->height };
187}
188
189}
190
192{
193 return commonTrackTCPLines();
194}
195
197{
198 unsigned height = 0;
199 if (!commonTrackTCPLines().empty())
200 height += commonTrackTCPLines().front().height;
201 if (!commonTrackTCPBottomLines.empty())
202 height += commonTrackTCPBottomLines.front().height;
203 // + 1 prevents the top item from disappearing for want of enough space,
204 // according to the rules in HideTopItem.
205 return height + kVerticalPadding + 1;
206}
207
208bool TrackInfo::HideTopItem( const wxRect &rect, const wxRect &subRect,
209 int allowance ) {
210 auto limit = CalcBottomItemY
212 // Return true if the rectangle is even touching the limit
213 // without an overlap. That was the behavior as of 2.1.3.
214 return subRect.y + subRect.height - allowance >= rect.y + limit;
215}
216
218( TrackPanelDrawingContext &context,
219 const wxRect &rect, const Track &track )
220{
221 auto &trackControl = static_cast<const CommonTrackControls&>(
222 TrackControls::Get( track ) );
223 const auto &topLines = trackControl.GetTCPLines();
224 const auto &bottomLines = commonTrackTCPBottomLines;
226 ( context, rect, &track, topLines, bottomLines );
227}
228
230( TrackPanelDrawingContext &context,
231 const wxRect &rect, const Track *pTrack,
232 const std::vector<TCPLine> &topLines, const std::vector<TCPLine> &bottomLines )
233{
234 auto dc = &context.dc;
236 dc->SetTextForeground(theTheme.Colour(clrTrackPanelText));
237
238 {
239 int yy = 0;
240 for ( const auto &line : topLines ) {
241 wxRect itemRect{
242 rect.x, rect.y + yy,
243 rect.width, line.height
244 };
245 if ( !TrackInfo::HideTopItem( rect, itemRect ) &&
246 line.drawFunction )
247 line.drawFunction( context, itemRect, pTrack );
248 yy += line.height + line.extraSpace;
249 }
250 }
251 {
252 int yy = rect.height;
253 for ( const auto &line : bottomLines ) {
254 yy -= line.height + line.extraSpace;
255 if ( line.drawFunction ) {
256 wxRect itemRect{
257 rect.x, rect.y + yy,
258 rect.width, line.height
259 };
260 line.drawFunction( context, itemRect, pTrack );
261 }
262 }
263 }
264}
265
268 TrackPanelDrawingContext &context, const wxRect &bev,
269 const Track *pTrack, ButtonHandle *target )
270{
271 auto dc = &context.dc;
272 bool selected = pTrack ? pTrack->GetSelected() : true;
273 bool hit = target && target->GetTrack().get() == pTrack;
274 bool captured = hit && target->IsClicked();
275 bool down = captured && bev.Contains( context.lastState.GetPosition());
276 AColor::Bevel2(*dc, !down, bev, selected, hit );
277
278#ifdef EXPERIMENTAL_THEMING
279 wxPen pen( theTheme.Colour( clrTrackPanelText ));
280 dc->SetPen( pen );
281#else
282 dc->SetPen(*wxBLACK_PEN);
283#endif
284 bev.Inflate( -1, -1 );
285 // Draw the "X"
286 const int s = 6;
287
288 int ls = bev.x + ((bev.width - s) / 2);
289 int ts = bev.y + ((bev.height - s) / 2);
290 int rs = ls + s;
291 int bs = ts + s;
292
293 AColor::Line(*dc, ls, ts, rs, bs);
294 AColor::Line(*dc, ls + 1, ts, rs + 1, bs);
295 AColor::Line(*dc, rs, ts, ls, bs);
296 AColor::Line(*dc, rs + 1, ts, ls + 1, bs);
297 // bev.Inflate(-1, -1);
298}
299
301( TrackPanelDrawingContext &context,
302 const wxRect &rect, const Track *pTrack )
303{
304 auto dc = &context.dc;
305 bool selected = pTrack ? pTrack->GetSelected() : true;
306 {
307 wxRect bev = rect;
308 GetCloseBoxHorizontalBounds( rect, bev );
309 auto target = dynamic_cast<CloseButtonHandle*>( context.target.get() );
310 DrawCloseButton( context, bev, pTrack, target );
311 }
312
313 {
314 wxRect bev = rect;
315 GetTitleBarHorizontalBounds( rect, bev );
316 auto target = dynamic_cast<MenuButtonHandle*>( context.target.get() );
317 bool hit = target && target->GetTrack().get() == pTrack;
318 bool captured = hit && target->IsClicked();
319 bool down = captured && bev.Contains( context.lastState.GetPosition());
320 wxString titleStr =
321 pTrack ? pTrack->GetName() : _("Name");
322
323 //bev.Inflate(-1, -1);
324 AColor::Bevel2(*dc, !down, bev, selected, hit);
325
326 // Draw title text
328
329 // Bug 1660 The 'k' of 'Audio Track' was being truncated.
330 // Constant of 32 found by counting pixels on a windows machine.
331 // I believe it's the size of the X close button + the size of the
332 // drop down arrow.
333 int allowableWidth = rect.width - 32;
334
335 wxCoord textWidth, textHeight;
336 dc->GetTextExtent(titleStr, &textWidth, &textHeight);
337 while (textWidth > allowableWidth) {
338 titleStr = titleStr.Left(titleStr.length() - 1);
339 dc->GetTextExtent(titleStr, &textWidth, &textHeight);
340 }
341
342 // Pop-up triangle
343 #ifdef EXPERIMENTAL_THEMING
344 wxColour c = theTheme.Colour( clrTrackPanelText );
345 #else
346 wxColour c = *wxBLACK;
347 #endif
348
349 // wxGTK leaves little scraps (antialiasing?) of the
350 // characters if they are repeatedly drawn. This
351 // happens when holding down mouse button and moving
352 // in and out of the title bar. So clear it first.
353 // AColor::MediumTrackInfo(dc, t->GetSelected());
354 // dc->DrawRectangle(bev);
355
356 dc->SetTextForeground( c );
357 dc->SetTextBackground( wxTRANSPARENT );
358 dc->DrawText(titleStr, bev.x + 2, bev.y + (bev.height - textHeight) / 2);
359
360
361
362 dc->SetPen(c);
363 dc->SetBrush(c);
364
365 int s = 10; // Width of dropdown arrow...height is half of width
366 AColor::Arrow(*dc,
367 bev.GetRight() - s - 3, // 3 to offset from right border
368 bev.y + ((bev.height - (s / 2)) / 2),
369 s);
370
371 }
372}
373
375( TrackPanelDrawingContext &context,
376 const wxRect &rect, const Track *pTrack )
377{
378 auto dc = &context.dc;
379 bool selected = pTrack ? pTrack->GetSelected() : true;
380 bool syncLockSelected = pTrack ? SyncLock::IsSyncLockSelected(pTrack) : true;
381 bool minimized =
382 pTrack ? TrackView::Get( *pTrack ).GetMinimized() : false;
383 {
384 wxRect bev = rect;
386 auto target = dynamic_cast<MinimizeButtonHandle*>( context.target.get() );
387 bool hit = target && target->GetTrack().get() == pTrack;
388 bool captured = hit && target->IsClicked();
389 bool down = captured && bev.Contains( context.lastState.GetPosition());
390
391 // Clear background to get rid of previous arrow
392 //AColor::MediumTrackInfo(dc, t->GetSelected());
393 //dc->DrawRectangle(bev);
394
395 AColor::Bevel2(*dc, !down, bev, selected, hit);
396
397#ifdef EXPERIMENTAL_THEMING
398 wxColour c = theTheme.Colour(clrTrackPanelText);
399 dc->SetBrush(c);
400 dc->SetPen(c);
401#else
402 AColor::Dark(dc, selected);
403#endif
404
405 AColor::Arrow(*dc,
406 bev.x - 5 + bev.width / 2,
407 bev.y - 2 + bev.height / 2,
408 10,
409 minimized);
410 }
411
412 {
413 wxRect bev = rect;
415 auto target = dynamic_cast<SelectButtonHandle*>( context.target.get() );
416 bool hit = target && target->GetTrack().get() == pTrack;
417 bool captured = hit && target->IsClicked();
418 bool down = captured && bev.Contains( context.lastState.GetPosition());
419
420 AColor::Bevel2(*dc, !down, bev, selected, hit);
421
422#ifdef EXPERIMENTAL_THEMING
423 wxColour c = theTheme.Colour(clrTrackPanelText);
424 dc->SetBrush(c);
425 dc->SetPen(c);
426#else
427 AColor::Dark(dc, selected);
428#endif
429
430 wxString str = _("Select");
431 wxCoord textWidth;
432 wxCoord textHeight;
434 dc->GetTextExtent(str, &textWidth, &textHeight);
435
436 dc->SetTextForeground( c );
437 dc->SetTextBackground( wxTRANSPARENT );
438 dc->DrawText(str, bev.x + 2 + (bev.width-textWidth)/2, bev.y + (bev.height - textHeight) / 2);
439 }
440
441
442 // Draw the sync-lock indicator if this track is in a sync-lock selected group.
443 if (syncLockSelected)
444 {
445 wxRect syncLockIconRect = rect;
446
447 GetSyncLockHorizontalBounds( rect, syncLockIconRect );
448 wxBitmap syncLockBitmap(theTheme.Image(bmpSyncLockIcon));
449 // Icon is 12x12 and syncLockIconRect is 16x16.
450 dc->DrawBitmap(syncLockBitmap,
451 syncLockIconRect.x + 3,
452 syncLockIconRect.y + 2,
453 true);
454 }
455}
456
457void TrackInfo::GetCloseBoxHorizontalBounds( const wxRect & rect, wxRect &dest )
458{
459 dest.x = rect.x;
460 dest.width = kTrackInfoBtnSize;
461}
462
463void TrackInfo::GetCloseBoxRect(const wxRect & rect, wxRect & dest)
464{
465 GetCloseBoxHorizontalBounds( rect, dest );
467 dest.y = rect.y + results.first;
468 dest.height = results.second;
469}
470
471void TrackInfo::GetTitleBarHorizontalBounds( const wxRect & rect, wxRect &dest )
472{
473 // to right of CloseBoxRect, plus a little more
474 wxRect closeRect;
475 GetCloseBoxHorizontalBounds( rect, closeRect );
476 dest.x = rect.x + closeRect.width + 1;
477 dest.width = rect.x + rect.width - dest.x + TitleSoloBorderOverlap;
478}
479
480void TrackInfo::GetTitleBarRect(const wxRect & rect, wxRect & dest)
481{
482 GetTitleBarHorizontalBounds( rect, dest );
484 dest.y = rect.y + results.first;
485 dest.height = results.second;
486}
487
488void TrackInfo::GetSliderHorizontalBounds( const wxPoint &topleft, wxRect &dest )
489{
490 dest.x = topleft.x + 6;
491 dest.width = kTrackInfoSliderWidth;
492}
493
494void TrackInfo::GetMinimizeHorizontalBounds( const wxRect &rect, wxRect &dest )
495{
496 const int space = 0;// was 3.
497 dest.x = rect.x + space;
498
499 wxRect syncLockRect;
500 GetSyncLockHorizontalBounds( rect, syncLockRect );
501
502 // Width is rect.width less space on left for track select
503 // and on right for sync-lock icon.
504 dest.width = kTrackInfoBtnSize;
505// rect.width - (space + syncLockRect.width);
506}
507
508void TrackInfo::GetMinimizeRect(const wxRect & rect, wxRect &dest)
509{
510 GetMinimizeHorizontalBounds( rect, dest );
511 auto results = CalcBottomItemY
513 dest.y = rect.y + results.first;
514 dest.height = results.second;
515}
516
517void TrackInfo::GetSelectButtonHorizontalBounds( const wxRect &rect, wxRect &dest )
518{
519 const int space = 0;// was 3.
520 dest.x = rect.x + space;
521
522 wxRect syncLockRect;
523 GetSyncLockHorizontalBounds( rect, syncLockRect );
524 wxRect minimizeRect;
525 GetMinimizeHorizontalBounds( rect, minimizeRect );
526
527 dest.x = dest.x + space + minimizeRect.width;
528 // Width is rect.width less space on left for track select
529 // and on right for sync-lock icon.
530 dest.width = rect.width - (space + syncLockRect.width) - (space + minimizeRect.width);
531}
532
533
534void TrackInfo::GetSelectButtonRect(const wxRect & rect, wxRect &dest)
535{
537 auto results = CalcBottomItemY
539 dest.y = rect.y + results.first;
540 dest.height = results.second;
541}
542
543void TrackInfo::GetSyncLockHorizontalBounds( const wxRect &rect, wxRect &dest )
544{
545 dest.width = kTrackInfoBtnSize;
546 dest.x = rect.x + rect.width - dest.width;
547}
548
549void TrackInfo::GetSyncLockIconRect(const wxRect & rect, wxRect &dest)
550{
551 GetSyncLockHorizontalBounds( rect, dest );
552 auto results = CalcBottomItemY
554 dest.y = rect.y + results.first;
555 dest.height = results.second;
556}
557
560{
561 dc->SetFont(settings().gFont);
562}
563
564//#define USE_BEVELS
565
566unsigned TrackInfo::DefaultTrackHeight( const TCPLines &topLines )
567{
568 int needed =
570 totalTCPLines( topLines, true ) +
572 return (unsigned) std::max( needed, (int) TrackView::DefaultHeight );
573}
#define str(a)
#define _(s)
Definition: Internat.h:75
THEME_API Theme theTheme
Definition: Theme.cpp:82
declares abstract base class Track, TrackList, and iterators over TrackList
TrackInfo::TCPLines TCPLines
Definition: TrackInfo.cpp:102
TrackInfo::TCPLine TCPLine
Definition: TrackInfo.cpp:101
static Settings & settings()
Definition: TrackInfo.cpp:87
static const TCPLines & commonTrackTCPLines()
Definition: TrackInfo.cpp:104
#define RANGE(array)
Definition: TrackInfo.cpp:100
static const int TitleSoloBorderOverlap
Definition: TrackInfo.h:29
ChoiceSetting TracksBehaviorsSolo
@ kVerticalPadding
Definition: ViewInfo.h:91
@ kTrackInfoSliderWidth
Definition: ViewInfo.h:98
@ kTrackInfoBtnSize
Definition: ViewInfo.h:95
@ kTrackInfoWidth
Definition: ZoomInfo.h:36
@ kLeftMargin
Definition: ZoomInfo.h:33
static void Arrow(wxDC &dc, wxCoord x, wxCoord y, int width, bool down=true)
Definition: AColor.cpp:160
static void Bevel2(wxDC &dc, bool up, const wxRect &r, bool bSel=false, bool bHighlight=false)
Definition: AColor.cpp:294
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:187
static void Dark(wxDC *dc, bool selected, bool highlight=false)
Definition: AColor.cpp:420
A UIHandle for a TrackPanel button, such as the Mute and Solo buttons.
Definition: ButtonHandle.h:26
std::shared_ptr< Track > GetTrack() const
Definition: ButtonHandle.h:30
bool IsClicked() const
Definition: ButtonHandle.h:31
wxString Read() const
Definition: Prefs.cpp:354
virtual const TCPLines & GetTCPLines() const
Definition: TrackInfo.cpp:191
static const TCPLines & StaticTCPLines()
Definition: TrackInfo.cpp:123
A listener notified of changes in preferences.
Definition: Prefs.h:543
static bool IsSyncLockSelected(const Track *pTrack)
Definition: SyncLock.cpp:43
wxColour & Colour(int iIndex)
wxImage & Image(int iIndex)
static TrackControls & Get(Track &track)
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:225
bool GetSelected() const
Definition: Track.h:469
wxString GetName() const
Definition: Track.h:466
@ DefaultHeight
Definition: TrackView.h:30
bool GetMinimized() const
Definition: TrackView.h:52
static TrackView & Get(Track &)
Definition: TrackView.cpp:69
AUDACITY_DLL_API void GetSliderHorizontalBounds(const wxPoint &topleft, wxRect &dest)
Definition: TrackInfo.cpp:488
AUDACITY_DLL_API bool HideTopItem(const wxRect &rect, const wxRect &subRect, int allowance=0)
Definition: TrackInfo.cpp:208
AUDACITY_DLL_API void GetCloseBoxRect(const wxRect &rect, wxRect &dest)
Definition: TrackInfo.cpp:463
AUDACITY_DLL_API void GetTitleBarRect(const wxRect &rect, wxRect &dest)
Definition: TrackInfo.cpp:480
AUDACITY_DLL_API void GetSyncLockHorizontalBounds(const wxRect &rect, wxRect &dest)
Definition: TrackInfo.cpp:543
AUDACITY_DLL_API void SetTrackInfoFont(wxDC *dc)
Definition: TrackInfo.cpp:559
AUDACITY_DLL_API void GetCloseBoxHorizontalBounds(const wxRect &rect, wxRect &dest)
Definition: TrackInfo.cpp:457
std::vector< TCPLine > TCPLines
Definition: TrackInfo.h:67
AUDACITY_DLL_API void GetMinimizeHorizontalBounds(const wxRect &rect, wxRect &dest)
Definition: TrackInfo.cpp:494
AUDACITY_DLL_API void GetMinimizeRect(const wxRect &rect, wxRect &dest)
Definition: TrackInfo.cpp:508
AUDACITY_DLL_API void GetSelectButtonRect(const wxRect &rect, wxRect &dest)
Definition: TrackInfo.cpp:534
AUDACITY_DLL_API bool HasSoloButton()
Definition: TrackInfo.cpp:95
AUDACITY_DLL_API void GetTitleBarHorizontalBounds(const wxRect &rect, wxRect &dest)
Definition: TrackInfo.cpp:471
AUDACITY_DLL_API void GetSyncLockIconRect(const wxRect &rect, wxRect &dest)
Definition: TrackInfo.cpp:549
AUDACITY_DLL_API unsigned DefaultTrackHeight(const TCPLines &topLines)
Definition: TrackInfo.cpp:566
AUDACITY_DLL_API void DrawCloseButton(TrackPanelDrawingContext &context, const wxRect &bev, const Track *pTrack, ButtonHandle *target)
Definition: TrackInfo.cpp:267
AUDACITY_DLL_API void MinimizeSyncLockDrawFunction(TrackPanelDrawingContext &context, const wxRect &rect, const Track *pTrack)
Definition: TrackInfo.cpp:375
AUDACITY_DLL_API void DrawItems(TrackPanelDrawingContext &context, const wxRect &rect, const Track &track)
Definition: TrackInfo.cpp:218
AUDACITY_DLL_API std::pair< int, int > CalcItemY(const TCPLines &lines, unsigned iItem)
Definition: TrackInfo.cpp:146
AUDACITY_DLL_API void GetSelectButtonHorizontalBounds(const wxRect &rect, wxRect &dest)
Definition: TrackInfo.cpp:517
AUDACITY_DLL_API void CloseTitleDrawFunction(TrackPanelDrawingContext &context, const wxRect &rect, const Track *pTrack)
Definition: TrackInfo.cpp:301
AUDACITY_DLL_API unsigned MinimumTrackHeight()
Definition: TrackInfo.cpp:196
const TrackInfo::TCPLine defaultCommonTrackTCPBottomLines[]
Definition: TrackInfo.cpp:165
int totalTCPLines(const TCPLines &lines, bool omitLastExtra)
Definition: TrackInfo.cpp:130
std::pair< int, int > CalcBottomItemY(const TCPLines &lines, unsigned iItem, int height)
Definition: TrackInfo.cpp:175
wxString gSoloPref
Definition: TrackInfo.cpp:49
bool mInitialized
Definition: TrackInfo.cpp:52
void UpdatePrefs() override
Definition: TrackInfo.cpp:54
wxFont gFont
Definition: TrackInfo.cpp:50