Audacity 3.2.0
RulerUpdater.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 RulerUpdater.cpp
6
7 Dominic Mazzoni
8 Michael Papadopoulos split from Ruler.cpp
9
10*******************************************************************//***************************************************************//******************************************************************/
27
28#include "RulerUpdater.h"
29
30#include "AllThemeResources.h"
31#include "Theme.h"
32
33#include <wx/dc.h>
34
36 double UPP, int orientation, const RulerFormat *format, bool log)
37 {
38 //TODO: better dynamic digit computation for the log case
39 (void)log;
40
41 // Given the dimensions of the ruler, the range of values it
42 // has to display, and the format (i.e. Int, Real, Time),
43 // figure out how many units are in one Minor tick, and
44 // in one Major tick.
45 //
46 // The goal is to always put tick marks on nice round numbers
47 // that are easy for humans to grok. This is the most tricky
48 // with time.
49
50 // As a heuristic, we want at least 22 pixels between each
51 // minor tick. We want to show numbers like "-48"
52 // in that space.
53 // If vertical, we don't need as much space.
54 mUnits = ((orientation == wxHORIZONTAL) ? 22 : 16) * fabs(UPP);
55
56 mDigits = 0;
57
58 if (format)
59 format->SetTickSizes(mUnits, mMajor, mMinor, mMinorMinor, mDigits);
60 }
61
63 double d, const RulerFormat *format) const
64 {
65 // Given a value, turn it into a string according
66 // to the current ruler format. The number of digits of
67 // accuracy depends on the resolution of the ruler,
68 // i.e. how far zoomed in or out you are.
69
70 // Should not be called unless TickSizes is instantiated
71 wxASSERT(mUnits > 0);
72
73 wxString s;
74
75 // PRL Todo: are all these cases properly localized? (Decimal points,
76 // hour-minute-second, etc.?)
77
78 if (format)
79 format->SetLabelString(s, d, mUnits, mMinor, mDigits, tickType);
80
81 auto result = Verbatim(s);
82
83 return result;
84 }
85
87 wxDC& dc, bool twoTone, wxColour c,
88 std::unique_ptr<RulerStruct::Fonts>& fonts) const
89{
90 if (text.has_value() && !text->empty()) {
91 bool altColor = twoTone && value < 0.0;
92
93 dc.SetTextForeground(altColor ? theTheme.Colour(clrTextNegativeNumbers) : c);
94 dc.SetBackgroundMode(wxTRANSPARENT);
95 if (dc.GetFont() == fonts->major) {
96 // Do not draw units as bolded
97 dc.DrawText(text->Translation(), lx, ly);
98 wxSize textSize = dc.GetTextExtent(text->Translation());
99 dc.SetFont(fonts->minor);
100 int unitX = lx + textSize.GetWidth();
101 dc.DrawText(units.Translation(), unitX, ly);
102 dc.SetFont(fonts->major);
103 }
104 else {
105 auto str = *text + units;
106 dc.DrawText(str.Translation(), lx, ly);
107 }
108 }
109}
110
112 Label lab,
113 wxDC& dc, wxFont font,
114 std::vector<bool>& bits,
115 int left, int top, int spacing, int lead,
116 bool flip, int orientation)
117 -> std::pair< wxRect, Label >
118{
119 lab.lx = left - 1000; // don't display
120 lab.ly = top - 1000; // don't display
121
122 auto length = bits.size() - 1;
123 auto pos = lab.pos;
124
125 dc.SetFont(font);
126
127 wxCoord strW, strH, strD, strL;
128 auto strText = lab.text;
129 auto strUnits = lab.units;
130 auto str = (strText ? *strText : TranslatableString{}) + strUnits;
131 // Do not put the text into results until we are sure it does not overlap
132 lab.text = {};
133 lab.units = {};
134 dc.GetTextExtent(str.Translation(), &strW, &strH, &strD, &strL);
135
136 int strPos, strLen, strLeft, strTop;
137 if (orientation == wxHORIZONTAL) {
138 strLen = strW;
139 strPos = pos - strW / 2;
140 if (strPos < 0)
141 strPos = 0;
142 if (strPos + strW >= length)
143 strPos = length - strW;
144 strLeft = left + strPos;
145 if (flip)
146 strTop = top + 4;
147 else
148 strTop = -strH - lead;
149 // strTop = top - lead + 4;// More space was needed...
150 }
151 else {
152 strLen = strH;
153 strPos = pos - strH / 2;
154 if (strPos < 0)
155 strPos = 0;
156 if (strPos + strH >= length)
157 strPos = length - strH;
158 strTop = top + strPos;
159 if (flip)
160 strLeft = left + 5;
161 else
162 strLeft = -strW - 6;
163 }
164
165 // FIXME: we shouldn't even get here if strPos < 0.
166 // Ruler code currently does not handle very small or
167 // negative sized windows (i.e. don't draw) properly.
168 if (strPos < 0)
169 return { {}, lab };
170
171 // See if any of the pixels we need to draw this
172 // label is already covered
173
174 int i;
175 for (i = 0; i < strLen; i++)
176 if (bits[strPos + i])
177 return { {}, lab };
178
179 // If not, position the label
180
181 lab.lx = strLeft;
182 lab.ly = strTop;
183
184 // And mark these pixels, plus some surrounding
185 // ones (the spacing between labels), as covered
186 int leftMargin = spacing;
187 if (strPos < leftMargin)
188 leftMargin = strPos;
189 strPos -= leftMargin;
190 strLen += leftMargin;
191
192 int rightMargin = spacing;
193 if (strPos + strLen > length - spacing)
194 rightMargin = length - strPos - strLen;
195 strLen += rightMargin;
196
197 for (i = 0; i < strLen; i++)
198 bits[strPos + i] = true;
199
200 // Good to display the text
201 lab.text = strText;
202 lab.units = strUnits;
203 return { { strLeft, strTop, strW, strH }, lab };
204}
205
206// Formerly the ending part of Ruler::Updater::Update after a switch
207// on mCustom and mLog; now a base class function used in
208// overrides of RulerUpdater::Update as the common ending step
210 UpdateOutputs& allOutputs,
211 const RulerStruct& context
212)
213const
214{
215 const int mLeft = context.mLeft;
216 const int mTop = context.mTop;
217 const int mBottom = context.mBottom;
218 const int mRight = context.mRight;
219 const int mOrientation = context.mOrientation;
220 const bool mFlip = context.mFlip;
221
222 int displacementx = 0, displacementy = 0;
223 auto& box = allOutputs.box;
224 if (!mFlip) {
225 if (mOrientation == wxHORIZONTAL) {
226 int d = mTop + box.GetHeight() + 5;
227 box.Offset(0, d);
228 box.Inflate(0, 5);
229 displacementx = 0;
230 displacementy = d;
231 }
232 else {
233 int d = mLeft - box.GetLeft() + 5;
234 box.Offset(d, 0);
235 box.Inflate(5, 0);
236 displacementx = d;
237 displacementy = 0;
238 }
239 }
240 else {
241 if (mOrientation == wxHORIZONTAL) {
242 box.Inflate(0, 5);
243 displacementx = 0;
244 displacementy = 0;
245 }
246 }
247 auto update = [=](Label& label) {
248 label.lx += displacementx;
249 label.ly += displacementy;
250 };
251 for (auto& label : allOutputs.majorLabels)
252 update(label);
253 for (auto& label : allOutputs.minorLabels)
254 update(label);
255 for (auto& label : allOutputs.minorMinorLabels)
256 update(label);
257}
258
#define str(a)
TranslatableString label
Definition: TagsEditor.cpp:165
THEME_API Theme theTheme
Definition: Theme.cpp:82
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
void BoxAdjust(UpdateOutputs &allOutputs, const RulerStruct &context) const
virtual ~RulerUpdater()=0
static std::pair< wxRect, Label > MakeTick(RulerUpdater::Label lab, wxDC &dc, wxFont font, std::vector< bool > &bits, int left, int top, int spacing, int lead, bool flip, int orientation)
wxColour & Colour(int iIndex)
Holds a msgid for the translation catalog; may also bind format arguments.
int mOrientation
Definition: RulerUpdater.h:37
An array of these created by the Updater is used to determine what and where text annotations to the ...
Definition: RulerUpdater.h:60
void Draw(wxDC &dc, bool twoTone, wxColour c, std::unique_ptr< RulerStruct::Fonts > &fonts) const
TranslatableString LabelString(double d, const RulerFormat *format) const
TickSizes(double UPP, int orientation, const RulerFormat *format, bool log)