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