forked from audacity/audacity
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathOverlayPanel.cpp
More file actions
153 lines (131 loc) · 4.09 KB
/
Copy pathOverlayPanel.cpp
File metadata and controls
153 lines (131 loc) · 4.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//
// OverlayPanel.cpp
// Audacity
//
// Created by Paul Licameli on 5/7/16.
//
//
#include "../Audacity.h"
#include "OverlayPanel.h"
#include "Overlay.h"
#include <algorithm>
#include <wx/dcclient.h>
OverlayPanel::OverlayPanel(wxWindow * parent, wxWindowID id,
const wxPoint & pos,
const wxSize & size,
long style)
: BackedPanel(parent, id, pos, size, style)
{}
void OverlayPanel::AddOverlay( const std::weak_ptr<Overlay> &pOverlay)
{
if (pOverlay.expired())
return;
Compress();
auto iter = std::lower_bound( mOverlays.begin(), mOverlays.end(),
pOverlay.lock()->SequenceNumber(),
[]( const OverlayPtr &p, unsigned value ) {
return p.expired() || p.lock()->SequenceNumber() < value;
}
);
mOverlays.insert(iter, pOverlay);
}
void OverlayPanel::ClearOverlays()
{
mOverlays.clear();
}
void OverlayPanel::DrawOverlays(bool repaint_all, wxDC *pDC)
{
if ( !IsShownOnScreen() )
return;
size_t n_pairs = mOverlays.size();
using Pair = std::pair<wxRect, bool /*out of date?*/>;
std::vector< Pair > pairs;
pairs.reserve(n_pairs);
// First...
Compress();
// ... then assume pointers are not expired
// Find out the rectangles and outdatedness for each overlay
wxSize size(GetBackingDC().GetSize());
for (const auto pOverlay : mOverlays)
pairs.push_back( pOverlay.lock()->GetRectangle(size) );
// See what requires redrawing. If repainting, all.
// If not, then whatever is outdated, and whatever will be damaged by
// undrawing.
// By redrawing only what needs it, we avoid flashing things like
// the cursor that are drawn with invert, and also avoid
// unnecessary work.
// But first, a quick exit test.
bool some_overlays_need_repainting =
repaint_all ||
std::any_of( pairs.begin(), pairs.end(),
[]( const Pair &pair ){ return pair.second; } );
if (!some_overlays_need_repainting) {
// This function (OverlayPanel::DrawOverlays()) is called at
// fairly high frequency through a timer in TrackPanel. In case
// there is nothing to do, we exit early because creating the
// wxClientDC below is expensive, at least on Linux.
return;
}
if (!repaint_all) {
// For each overlay that needs update, any other overlay whose
// rectangle intersects it will also need update.
bool done;
do {
done = true;
for (size_t ii = 0; ii < n_pairs - 1; ++ii) {
for (size_t jj = ii + 1; jj < n_pairs; ++jj) {
if (pairs[ii].second != pairs[jj].second &&
pairs[ii].first.Intersects(pairs[jj].first)) {
done = false;
pairs[ii].second = pairs[jj].second = true;
}
}
}
} while (!done);
}
Optional<wxClientDC> myDC;
auto &dc = pDC ? *pDC : (myDC.emplace(this), *myDC);
// Erase
auto it2 = pairs.begin();
for (auto pOverlay : mOverlays) {
if (repaint_all || it2->second)
pOverlay.lock()->Erase(dc, GetBackingDC());
++it2;
}
// Draw
it2 = pairs.begin();
for (auto pOverlay : mOverlays) {
if (repaint_all || it2->second) {
// Guarantee a clean state of the dc each pass:
ADCChanger changer{ &dc };
pOverlay.lock()->Draw(*this, dc);
}
++it2;
}
}
void OverlayPanel::Compress()
{
// remove any expired pointers
auto begin = mOverlays.begin();
auto end = mOverlays.end();
auto newEnd = std::remove_if( begin, end,
[]( const std::weak_ptr<Overlay> &pOverlay ){
return pOverlay.expired(); } );
if ( end != newEnd )
mOverlays.resize( newEnd - begin );
}
BEGIN_EVENT_TABLE(OverlayPanel, BackedPanel)
END_EVENT_TABLE()
// Maybe this class needs a better home
void DCUnchanger::operator () (wxDC *pDC) const
{
if (pDC) {
pDC->SetPen(pen);
pDC->SetBrush(brush);
pDC->SetLogicalFunction(wxRasterOperationMode(logicalOperation));
}
}
ADCChanger::ADCChanger(wxDC *pDC)
: Base{ pDC, ::DCUnchanger{ pDC->GetBrush(), pDC->GetPen(),
long(pDC->GetLogicalFunction()) } }
{}