Audacity 3.2.0
CommonTrackInfo.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5CommonTrackInfo.cpp
6
7Paul Licameli split from TrackInfo.cpp
8
9********************************************************************/
27#include "CommonTrackInfo.h"
28
29#include <wx/dc.h>
30#include "AColor.h"
31#include "AllThemeResources.h"
32#include "SyncLock.h"
33#include "Theme.h"
34#include "Track.h"
35#include "TrackControls.h"
37#include "UIHandle.h"
38#include "ViewInfo.h"
40
41#define RANGE(array) std::begin(array), std::end(array)
44
46{
47 static const TCPLines theLines{
50 };
51 return theLines;
52}
53
55{
56 return commonTrackTCPLines();
57}
58
59namespace {
60
61int totalTCPLines( const TCPLines &lines, bool omitLastExtra )
62{
63 int total = 0;
64 int lastExtra = 0;
65 for ( const auto line : lines ) {
66 lastExtra = line.extraSpace;
67 total += line.height + lastExtra;
68 }
69 if (omitLastExtra)
70 total -= lastExtra;
71 return total;
72}
73}
74
75namespace {
76
77// Items for the bottom of the panel, listed bottom-upwards
78// As also with the top items, the extra space is below the item
80 // The '0' avoids impinging on bottom line of TCP
81 // Use -1 if you do want to do so.
84};
86
87// return y value and height
88std::pair< int, int > CalcBottomItemY
89 ( const TCPLines &lines, unsigned iItem, int height )
90{
91 int y = height;
92 auto pLines = lines.begin();
93 while ( pLines != lines.end() &&
94 0 == (pLines->items & iItem) ) {
95 y -= pLines->height + pLines->extraSpace;
96 ++pLines;
97 }
98 if (pLines != lines.end())
99 y -= (pLines->height + pLines->extraSpace );
100 return { y, pLines->height };
101}
102
103}
104
106{
107 unsigned height = 0;
108 if (!commonTrackTCPLines().empty())
109 height += commonTrackTCPLines().front().height;
110 if (!commonTrackTCPBottomLines.empty())
111 height += commonTrackTCPBottomLines.front().height;
112 // + 1 prevents the top item from disappearing for want of enough space,
113 // according to the rules in HideTopItem.
114 return height + kVerticalPadding + 1;
115}
116
117bool CommonTrackInfo::HideTopItem( const wxRect &rect, const wxRect &subRect,
118 int allowance ) {
119 auto limit = CalcBottomItemY
121 // Return true if the rectangle is even touching the limit
122 // without an overlap. That was the behavior as of 2.1.3.
123 return subRect.y + subRect.height - allowance >= rect.y + limit;
124}
125
127( TrackPanelDrawingContext &context,
128 const wxRect &rect, const Track &track )
129{
130 auto &trackControl = TrackControls::Get(track);
131 const auto &topLines = trackControl.GetTCPLines();
132 const auto &bottomLines = commonTrackTCPBottomLines;
134 ( context, rect, &track, topLines, bottomLines );
135}
136
138( TrackPanelDrawingContext &context,
139 const wxRect &rect, const Track *pTrack,
140 const std::vector<TCPLine> &topLines, const std::vector<TCPLine> &bottomLines )
141{
142 auto dc = &context.dc;
144 dc->SetTextForeground(theTheme.Colour(clrTrackPanelText));
145
146 {
147 int yy = 0;
148 for ( const auto &line : topLines ) {
149 wxRect itemRect{
150 rect.x, rect.y + yy,
151 rect.width, line.height
152 };
153 if ( !CommonTrackInfo::HideTopItem( rect, itemRect ) &&
154 line.drawFunction )
155 line.drawFunction( context, itemRect, pTrack );
156 yy += line.height + line.extraSpace;
157 }
158 }
159 {
160 int yy = rect.height;
161 for ( const auto &line : bottomLines ) {
162 yy -= line.height + line.extraSpace;
163 if ( line.drawFunction ) {
164 wxRect itemRect{
165 rect.x, rect.y + yy,
166 rect.width, line.height
167 };
168 line.drawFunction( context, itemRect, pTrack );
169 }
170 }
171 }
172}
173
175 TrackPanelDrawingContext &context, const wxRect &bev,
176 const Track *pTrack, UIHandle *target)
177{
178 auto dc = &context.dc;
179 bool selected = pTrack ? pTrack->GetSelected() : true;
180 bool hit = target &&
181 target->FindChannel().get() == dynamic_cast<const Channel*>(pTrack);
182 bool captured = hit && target->IsDragging();
183 bool down = captured && bev.Contains( context.lastState.GetPosition());
184 AColor::Bevel2(*dc, !down, bev, selected, hit );
185
186#ifdef EXPERIMENTAL_THEMING
187 wxPen pen( theTheme.Colour( clrTrackPanelText ));
188 dc->SetPen( pen );
189#else
190 dc->SetPen(*wxBLACK_PEN);
191#endif
192 bev.Inflate( -1, -1 );
193 // Draw the "X"
194 const int s = 6;
195
196 int ls = bev.x + ((bev.width - s) / 2);
197 int ts = bev.y + ((bev.height - s) / 2);
198 int rs = ls + s;
199 int bs = ts + s;
200
201 AColor::Line(*dc, ls, ts, rs, bs);
202 AColor::Line(*dc, ls + 1, ts, rs + 1, bs);
203 AColor::Line(*dc, rs, ts, ls, bs);
204 AColor::Line(*dc, rs + 1, ts, ls + 1, bs);
205 // bev.Inflate(-1, -1);
206}
207
209( TrackPanelDrawingContext &context,
210 const wxRect &rect, const Track *pTrack )
211{
212 auto dc = &context.dc;
213 bool selected = pTrack ? pTrack->GetSelected() : true;
214 {
215 wxRect bev = rect;
216 GetCloseBoxHorizontalBounds( rect, bev );
217 auto target = context.target.get();
218 DrawCloseButton( context, bev, pTrack, target );
219 }
220
221 {
222 wxRect bev = rect;
223 GetTitleBarHorizontalBounds( rect, bev );
224 auto target = context.target.get();
225 bool hit = target &&
226 target->FindChannel().get() == dynamic_cast<const Channel*>(pTrack);
227 bool captured = hit && target->IsDragging();
228 bool down = captured && bev.Contains( context.lastState.GetPosition());
229 wxString titleStr =
230 pTrack ? pTrack->GetName() : _("Name");
231
232 //bev.Inflate(-1, -1);
233 AColor::Bevel2(*dc, !down, bev, selected, hit);
234
235 // Draw title text
237
238 // Bug 1660 The 'k' of 'Audio Track' was being truncated.
239 // Constant of 32 found by counting pixels on a windows machine.
240 // I believe it's the size of the X close button + the size of the
241 // drop down arrow.
242 int allowableWidth = rect.width - 32;
243
244 wxCoord textWidth, textHeight;
245 dc->GetTextExtent(titleStr, &textWidth, &textHeight);
246 while (textWidth > allowableWidth) {
247 titleStr = titleStr.Left(titleStr.length() - 1);
248 dc->GetTextExtent(titleStr, &textWidth, &textHeight);
249 }
250
251 // Pop-up triangle
252 #ifdef EXPERIMENTAL_THEMING
253 wxColour c = theTheme.Colour( clrTrackPanelText );
254 #else
255 wxColour c = *wxBLACK;
256 #endif
257
258 // wxGTK leaves little scraps (antialiasing?) of the
259 // characters if they are repeatedly drawn. This
260 // happens when holding down mouse button and moving
261 // in and out of the title bar. So clear it first.
262 // AColor::MediumTrackInfo(dc, t->GetSelected());
263 // dc->DrawRectangle(bev);
264
265 dc->SetTextForeground( c );
266 dc->SetTextBackground( wxTRANSPARENT );
267 dc->DrawText(titleStr, bev.x + 2, bev.y + (bev.height - textHeight) / 2);
268
269
270
271 dc->SetPen(c);
272 dc->SetBrush(c);
273
274 int s = 10; // Width of dropdown arrow...height is half of width
275 AColor::Arrow(*dc,
276 bev.GetRight() - s - 3, // 3 to offset from right border
277 bev.y + ((bev.height - (s / 2)) / 2),
278 s);
279
280 }
281}
282
284( TrackPanelDrawingContext &context,
285 const wxRect &rect, const Track *pTrack )
286{
287 auto dc = &context.dc;
288 bool selected = pTrack ? pTrack->GetSelected() : true;
289 bool syncLockSelected = pTrack ? SyncLock::IsSyncLockSelected(pTrack) : true;
290 bool minimized =
291 pTrack ? ChannelView::Get(*pTrack->GetChannel(0)).GetMinimized() : false;
292 {
293 wxRect bev = rect;
295 auto target = context.target.get();
296 bool hit = target &&
297 target->FindChannel().get() == dynamic_cast<const Channel*>(pTrack);
298 bool captured = hit && target->IsDragging();
299 bool down = captured && bev.Contains( context.lastState.GetPosition());
300
301 // Clear background to get rid of previous arrow
302 //AColor::MediumTrackInfo(dc, t->GetSelected());
303 //dc->DrawRectangle(bev);
304
305 AColor::Bevel2(*dc, !down, bev, selected, hit);
306
307#ifdef EXPERIMENTAL_THEMING
308 wxColour c = theTheme.Colour(clrTrackPanelText);
309 dc->SetBrush(c);
310 dc->SetPen(c);
311#else
312 AColor::Dark(dc, selected);
313#endif
314
315 AColor::Arrow(*dc,
316 bev.x - 5 + bev.width / 2,
317 bev.y - 2 + bev.height / 2,
318 10,
319 minimized);
320 }
321
322 {
323 wxRect bev = rect;
325 auto target = context.target.get();
326 bool hit = target &&
327 target->FindChannel().get() == dynamic_cast<const Channel*>(pTrack);
328 bool captured = hit && target->IsDragging();
329 bool down = captured && bev.Contains( context.lastState.GetPosition());
330
331 AColor::Bevel2(*dc, !down, bev, selected, hit);
332
333#ifdef EXPERIMENTAL_THEMING
334 wxColour c = theTheme.Colour(clrTrackPanelText);
335 dc->SetBrush(c);
336 dc->SetPen(c);
337#else
338 AColor::Dark(dc, selected);
339#endif
340
341 wxString str = _("Select");
342 wxCoord textWidth;
343 wxCoord textHeight;
345 dc->GetTextExtent(str, &textWidth, &textHeight);
346
347 dc->SetTextForeground( c );
348 dc->SetTextBackground( wxTRANSPARENT );
349 dc->DrawText(str, bev.x + 2 + (bev.width-textWidth)/2, bev.y + (bev.height - textHeight) / 2);
350 }
351
352
353 // Draw the sync-lock indicator if this track is in a sync-lock selected group.
354 if (syncLockSelected)
355 {
356 wxRect syncLockIconRect = rect;
357
358 GetSyncLockHorizontalBounds( rect, syncLockIconRect );
359 wxBitmap syncLockBitmap(theTheme.Image(bmpSyncLockIcon));
360 // Icon is 12x12 and syncLockIconRect is 16x16.
361 dc->DrawBitmap(syncLockBitmap,
362 syncLockIconRect.x + 3,
363 syncLockIconRect.y + 2,
364 true);
365 }
366}
367
368void CommonTrackInfo::GetCloseBoxHorizontalBounds( const wxRect & rect, wxRect &dest )
369{
370 dest.x = rect.x;
371 dest.width = kTrackInfoBtnSize;
372}
373
374void CommonTrackInfo::GetCloseBoxRect(const wxRect & rect, wxRect & dest)
375{
376 GetCloseBoxHorizontalBounds( rect, dest );
378 dest.y = rect.y + results.first;
379 dest.height = results.second;
380}
381
382void CommonTrackInfo::GetTitleBarHorizontalBounds( const wxRect & rect, wxRect &dest )
383{
384 // to right of CloseBoxRect, plus a little more
385 wxRect closeRect;
386 GetCloseBoxHorizontalBounds( rect, closeRect );
387 dest.x = rect.x + closeRect.width + 1;
388 dest.width = rect.x + rect.width - dest.x + TitleSoloBorderOverlap;
389}
390
391void CommonTrackInfo::GetTitleBarRect(const wxRect & rect, wxRect & dest)
392{
393 GetTitleBarHorizontalBounds( rect, dest );
395 dest.y = rect.y + results.first;
396 dest.height = results.second;
397}
398
399void CommonTrackInfo::GetSliderHorizontalBounds( const wxPoint &topleft, wxRect &dest )
400{
401 dest.x = topleft.x + 6;
402 dest.width = kTrackInfoSliderWidth;
403}
404
405void CommonTrackInfo::GetMinimizeHorizontalBounds( const wxRect &rect, wxRect &dest )
406{
407 const int space = 0;// was 3.
408 dest.x = rect.x + space;
409
410 wxRect syncLockRect;
411 GetSyncLockHorizontalBounds( rect, syncLockRect );
412
413 // Width is rect.width less space on left for track select
414 // and on right for sync-lock icon.
415 dest.width = kTrackInfoBtnSize;
416// rect.width - (space + syncLockRect.width);
417}
418
419void CommonTrackInfo::GetMinimizeRect(const wxRect & rect, wxRect &dest)
420{
421 GetMinimizeHorizontalBounds( rect, dest );
422 auto results = CalcBottomItemY
424 dest.y = rect.y + results.first;
425 dest.height = results.second;
426}
427
428void CommonTrackInfo::GetSelectButtonHorizontalBounds( const wxRect &rect, wxRect &dest )
429{
430 const int space = 0;// was 3.
431 dest.x = rect.x + space;
432
433 wxRect syncLockRect;
434 GetSyncLockHorizontalBounds( rect, syncLockRect );
435 wxRect minimizeRect;
436 GetMinimizeHorizontalBounds( rect, minimizeRect );
437
438 dest.x = dest.x + space + minimizeRect.width;
439 // Width is rect.width less space on left for track select
440 // and on right for sync-lock icon.
441 dest.width = rect.width - (space + syncLockRect.width) - (space + minimizeRect.width);
442}
443
444
445void CommonTrackInfo::GetSelectButtonRect(const wxRect & rect, wxRect &dest)
446{
448 auto results = CalcBottomItemY
450 dest.y = rect.y + results.first;
451 dest.height = results.second;
452}
453
454void CommonTrackInfo::GetSyncLockHorizontalBounds( const wxRect &rect, wxRect &dest )
455{
456 dest.width = kTrackInfoBtnSize;
457 dest.x = rect.x + rect.width - dest.width;
458}
459
460void CommonTrackInfo::GetSyncLockIconRect(const wxRect & rect, wxRect &dest)
461{
462 GetSyncLockHorizontalBounds( rect, dest );
463 auto results = CalcBottomItemY
465 dest.y = rect.y + results.first;
466 dest.height = results.second;
467}
468
470{
471 int needed =
473 totalTCPLines( topLines, true ) +
475 return (unsigned) std::max(needed, (int) ChannelView::DefaultHeight);
476}
std::vector< TrackInfo::TCPLine > TCPLines
TrackInfo::TCPLine TCPLine
static const TCPLines & commonTrackTCPLines()
#define RANGE(array)
static const int TitleSoloBorderOverlap
#define str(a)
#define _(s)
Definition: Internat.h:73
THEME_API Theme theTheme
Definition: Theme.cpp:82
declares abstract base class Track, TrackList, and iterators over TrackList
@ kTrackInfoSliderWidth
Definition: ViewInfo.h:99
@ kTrackInfoBtnSize
Definition: ViewInfo.h:96
@ kVerticalPadding
Definition: ViewInfo.h:92
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:443
std::shared_ptr< ChannelType > GetChannel(size_t iChannel)
Retrieve a channel, cast to the given type.
Definition: Channel.h:344
static ChannelView & Get(Channel &channel)
bool GetMinimized() const
Definition: ChannelView.h:68
static bool IsSyncLockSelected(const Track *pTrack)
Definition: SyncLock.cpp:82
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:122
bool GetSelected() const
Selectedness is always the same for all channels of a group.
Definition: Track.cpp:70
const wxString & GetName() const
Name is always the same for all channels of a group.
Definition: Track.cpp:56
Short-lived drawing and event-handling object associated with a TrackPanelCell.
Definition: UIHandle.h:36
virtual std::shared_ptr< const Channel > FindChannel() const =0
virtual bool IsDragging() const
Definition: UIHandle.cpp:58
AUDACITY_DLL_API void GetSyncLockIconRect(const wxRect &rect, wxRect &dest)
AUDACITY_DLL_API void GetCloseBoxHorizontalBounds(const wxRect &rect, wxRect &dest)
AUDACITY_DLL_API void CloseTitleDrawFunction(TrackPanelDrawingContext &context, const wxRect &rect, const Track *pTrack)
AUDACITY_DLL_API void GetTitleBarHorizontalBounds(const wxRect &rect, wxRect &dest)
AUDACITY_DLL_API void GetSyncLockHorizontalBounds(const wxRect &rect, wxRect &dest)
AUDACITY_DLL_API void DrawItems(TrackPanelDrawingContext &context, const wxRect &rect, const Track &track)
AUDACITY_DLL_API void GetCloseBoxRect(const wxRect &rect, wxRect &dest)
AUDACITY_DLL_API void GetSelectButtonHorizontalBounds(const wxRect &rect, wxRect &dest)
TrackInfo::TCPLines TCPLines
AUDACITY_DLL_API unsigned DefaultTrackHeight(const TCPLines &topLines)
AUDACITY_DLL_API void GetSelectButtonRect(const wxRect &rect, wxRect &dest)
AUDACITY_DLL_API void GetMinimizeRect(const wxRect &rect, wxRect &dest)
AUDACITY_DLL_API void MinimizeSyncLockDrawFunction(TrackPanelDrawingContext &context, const wxRect &rect, const Track *pTrack)
AUDACITY_DLL_API void GetMinimizeHorizontalBounds(const wxRect &rect, wxRect &dest)
AUDACITY_DLL_API void GetTitleBarRect(const wxRect &rect, wxRect &dest)
AUDACITY_DLL_API void GetSliderHorizontalBounds(const wxPoint &topleft, wxRect &dest)
AUDACITY_DLL_API void DrawCloseButton(TrackPanelDrawingContext &context, const wxRect &bev, const Track *pTrack, UIHandle *target)
AUDACITY_DLL_API const TCPLines & StaticTCPLines()
AUDACITY_DLL_API unsigned MinimumTrackHeight()
AUDACITY_DLL_API bool HideTopItem(const wxRect &rect, const wxRect &subRect, int allowance=0)
AUDACITY_DLL_API void SetTrackInfoFont(wxDC *dc)
Definition: TrackInfo.cpp:95
std::vector< TCPLine > TCPLines
Definition: TrackInfo.h:59
AUDACITY_DLL_API std::pair< int, int > CalcItemY(const TCPLines &lines, unsigned iItem)
Definition: TrackInfo.cpp:79
const TrackInfo::TCPLine defaultCommonTrackTCPBottomLines[]
std::pair< int, int > CalcBottomItemY(const TCPLines &lines, unsigned iItem, int height)
int totalTCPLines(const TCPLines &lines, bool omitLastExtra)