annotate layer/PaintAssistant.cpp @ 1447:8afea53332f3 single-point

Add option to make pane sizes auto-resize-only (i.e. remove user control via a splitter); also place alignment views above panes instead of below, meaning the extra bit of space that we currently have for the pane without one at least goes to the primary pane
author Chris Cannam
date Tue, 30 Apr 2019 15:53:21 +0100
parents 28075cc658c9
children f2525e6cbdf1
rev   line source
Chris@195 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@195 2
Chris@195 3 /*
Chris@195 4 Sonic Visualiser
Chris@195 5 An audio file viewer and annotation editor.
Chris@195 6 Centre for Digital Music, Queen Mary, University of London.
Chris@195 7 This file copyright 2006-2007 Chris Cannam and QMUL.
Chris@195 8
Chris@195 9 This program is free software; you can redistribute it and/or
Chris@195 10 modify it under the terms of the GNU General Public License as
Chris@195 11 published by the Free Software Foundation; either version 2 of the
Chris@195 12 License, or (at your option) any later version. See the file
Chris@195 13 COPYING included with this distribution for more information.
Chris@195 14 */
Chris@195 15
Chris@195 16 #include "PaintAssistant.h"
Chris@195 17
Chris@1078 18 #include "LayerGeometryProvider.h"
Chris@1078 19
Chris@195 20 #include "base/AudioLevel.h"
Chris@1147 21 #include "base/Strings.h"
Chris@1228 22 #include "base/Debug.h"
Chris@195 23
Chris@195 24 #include <QPaintDevice>
Chris@195 25 #include <QPainter>
Chris@195 26
Chris@198 27 #include <iostream>
Chris@230 28 #include <cmath>
Chris@198 29
Chris@195 30 void
Chris@195 31 PaintAssistant::paintVerticalLevelScale(QPainter &paint, QRect rect,
Chris@1266 32 double minVal, double maxVal,
Chris@220 33 Scale scale, int &mult,
Chris@220 34 std::vector<int> *vy)
Chris@195 35 {
Chris@905 36 static double meterdbs[] = { -40, -30, -20, -15, -10,
Chris@195 37 -5, -3, -2, -1, -0.5, 0 };
Chris@195 38
Chris@195 39 int h = rect.height(), w = rect.width();
Chris@195 40 int textHeight = paint.fontMetrics().height();
Chris@195 41 int toff = -textHeight/2 + paint.fontMetrics().ascent() + 1;
Chris@195 42
Chris@195 43 int lastLabelledY = -1;
Chris@195 44
Chris@195 45 int n = 10;
Chris@195 46 if (vy) vy->clear();
Chris@195 47
Chris@905 48 double step = 0;
Chris@220 49 mult = 1;
Chris@220 50 if (scale == LinearScale) {
Chris@220 51 step = (maxVal - minVal) / n;
Chris@220 52 int round = 0, limit = 10000000;
Chris@220 53 do {
Chris@220 54 round = int(minVal + step * mult);
Chris@220 55 mult *= 10;
Chris@220 56 } while (!round && mult < limit);
Chris@220 57 if (round) {
Chris@220 58 mult /= 10;
Chris@905 59 step = double(round) / mult;
Chris@905 60 n = int(lrint((maxVal - minVal) / step));
Chris@220 61 if (mult > 1) {
Chris@220 62 mult /= 10;
Chris@220 63 }
Chris@220 64 }
Chris@220 65 }
Chris@220 66
Chris@195 67 for (int i = 0; i <= n; ++i) {
Chris@195 68
Chris@905 69 double val = 0.0, nval = 0.0;
Chris@195 70 QString text = "";
Chris@195 71
Chris@195 72 switch (scale) {
Chris@195 73
Chris@195 74 case LinearScale:
Chris@220 75 val = (minVal + (i * step));
Chris@220 76 text = QString("%1").arg(mult * val);
Chris@195 77 break;
Chris@195 78
Chris@195 79 case MeterScale: // ... min, max
Chris@195 80 val = AudioLevel::dB_to_multiplier(meterdbs[i]);
Chris@195 81 text = QString("%1").arg(meterdbs[i]);
Chris@195 82 if (i == n) text = "0dB";
Chris@195 83 if (i == 0) {
Chris@1147 84 text = Strings::minus_infinity;
Chris@195 85 val = 0.0;
Chris@195 86 }
Chris@195 87 break;
Chris@195 88
Chris@195 89 case dBScale: // ... min, max
Chris@195 90 val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10);
Chris@195 91 text = QString("%1").arg(-(10*n) + i * 10);
Chris@195 92 if (i == n) text = "0dB";
Chris@195 93 if (i == 0) {
Chris@1147 94 text = Strings::minus_infinity;
Chris@195 95 val = 0.0;
Chris@195 96 }
Chris@195 97 break;
Chris@195 98 }
Chris@195 99
Chris@195 100 if (val < minVal || val > maxVal) continue;
Chris@195 101
Chris@198 102 int y = getYForValue(scale, val, minVal, maxVal, rect.y(), h);
Chris@195 103
Chris@195 104 int ny = y;
Chris@195 105 if (nval != 0.0) {
Chris@198 106 ny = getYForValue(scale, nval, minVal, maxVal, rect.y(), h);
Chris@195 107 }
Chris@195 108
Chris@587 109 // SVDEBUG << "PaintAssistant::paintVerticalLevelScale: val = "
Chris@585 110 // << val << ", y = " << y << ", h = " << h << endl;
Chris@198 111
Chris@195 112 bool spaceForLabel = (i == 0 ||
Chris@195 113 abs(y - lastLabelledY) >= textHeight - 1);
Chris@195 114
Chris@195 115 if (spaceForLabel) {
Chris@195 116
Chris@195 117 int tx = 3;
Chris@220 118 if (paint.fontMetrics().width(text) < w - 10) {
Chris@195 119 tx = w - 10 - paint.fontMetrics().width(text);
Chris@195 120 }
Chris@195 121
Chris@195 122 int ty = y;
Chris@198 123
Chris@195 124 if (ty < paint.fontMetrics().ascent()) {
Chris@195 125 ty = paint.fontMetrics().ascent();
Chris@195 126 } else {
Chris@195 127 ty += toff;
Chris@195 128 }
Chris@198 129
Chris@195 130 paint.drawText(tx, ty, text);
Chris@195 131
Chris@195 132 lastLabelledY = ty - toff;
Chris@1283 133
Chris@195 134 paint.drawLine(w - 7, y, w, y);
Chris@195 135 if (vy) vy->push_back(y);
Chris@195 136
Chris@195 137 if (ny != y) {
Chris@195 138 paint.drawLine(w - 7, ny, w, ny);
Chris@195 139 if (vy) vy->push_back(ny);
Chris@195 140 }
Chris@195 141
Chris@195 142 } else {
Chris@195 143
Chris@195 144 paint.drawLine(w - 4, y, w, y);
Chris@195 145 if (vy) vy->push_back(y);
Chris@195 146
Chris@195 147 if (ny != y) {
Chris@195 148 paint.drawLine(w - 4, ny, w, ny);
Chris@195 149 if (vy) vy->push_back(ny);
Chris@195 150 }
Chris@195 151 }
Chris@195 152 }
Chris@195 153 }
Chris@195 154
Chris@195 155 static int
Chris@905 156 dBscale(double sample, int m, double maxVal, double minVal)
Chris@195 157 {
Chris@195 158 if (sample < 0.0) return dBscale(-sample, m, maxVal, minVal);
Chris@905 159 double dB = AudioLevel::multiplier_to_dB(sample);
Chris@905 160 double mindB = AudioLevel::multiplier_to_dB(minVal);
Chris@905 161 double maxdB = AudioLevel::multiplier_to_dB(maxVal);
Chris@195 162 if (dB < mindB) return 0;
Chris@195 163 if (dB > 0.0) return m;
Chris@195 164 return int(((dB - mindB) * m) / (maxdB - mindB) + 0.1);
Chris@195 165 }
Chris@195 166
Chris@195 167 int
Chris@905 168 PaintAssistant::getYForValue(Scale scale, double value,
Chris@905 169 double minVal, double maxVal,
Chris@195 170 int minY, int height)
Chris@195 171 {
Chris@195 172 int vy = 0;
Chris@195 173
Chris@195 174 switch (scale) {
Chris@195 175
Chris@195 176 case LinearScale:
Chris@195 177 vy = minY + height - int(((value - minVal) / (maxVal - minVal)) * height);
Chris@195 178 break;
Chris@195 179
Chris@195 180 case MeterScale:
Chris@195 181 vy = minY + height - AudioLevel::multiplier_to_preview
Chris@195 182 ((value - minVal) / (maxVal - minVal), height);
Chris@195 183 break;
Chris@195 184
Chris@195 185 case dBScale:
Chris@195 186 vy = minY + height - dBscale(value, height, maxVal, minVal);
Chris@195 187 break;
Chris@195 188 }
Chris@195 189
Chris@195 190 return vy;
Chris@195 191 }
Chris@1078 192
Chris@1078 193 void
Chris@1078 194 PaintAssistant::drawVisibleText(const LayerGeometryProvider *v,
Chris@1078 195 QPainter &paint, int x, int y,
Chris@1078 196 QString text, TextStyle style)
Chris@1078 197 {
Chris@1078 198 if (style == OutlinedText || style == OutlinedItalicText) {
Chris@1078 199
Chris@1078 200 paint.save();
Chris@1078 201
Chris@1078 202 if (style == OutlinedItalicText) {
Chris@1078 203 QFont f(paint.font());
Chris@1078 204 f.setItalic(true);
Chris@1078 205 paint.setFont(f);
Chris@1078 206 }
Chris@1078 207
Chris@1078 208 QColor penColour, surroundColour, boxColour;
Chris@1078 209
Chris@1078 210 penColour = v->getForeground();
Chris@1078 211 surroundColour = v->getBackground();
Chris@1078 212 boxColour = surroundColour;
Chris@1078 213 boxColour.setAlpha(127);
Chris@1078 214
Chris@1078 215 paint.setPen(Qt::NoPen);
Chris@1078 216 paint.setBrush(boxColour);
Chris@1078 217
Chris@1078 218 QRect r = paint.fontMetrics().boundingRect(text);
Chris@1078 219 r.translate(QPoint(x, y));
Chris@1078 220 paint.drawRect(r);
Chris@1078 221 paint.setBrush(Qt::NoBrush);
Chris@1078 222
Chris@1266 223 paint.setPen(surroundColour);
Chris@1078 224
Chris@1266 225 for (int dx = -1; dx <= 1; ++dx) {
Chris@1266 226 for (int dy = -1; dy <= 1; ++dy) {
Chris@1266 227 if (!(dx || dy)) continue;
Chris@1266 228 paint.drawText(x + dx, y + dy, text);
Chris@1266 229 }
Chris@1266 230 }
Chris@1078 231
Chris@1266 232 paint.setPen(penColour);
Chris@1078 233
Chris@1266 234 paint.drawText(x, y, text);
Chris@1078 235
Chris@1078 236 paint.restore();
Chris@1078 237
Chris@1078 238 } else {
Chris@1078 239
Chris@1078 240 std::cerr << "ERROR: PaintAssistant::drawVisibleText: Boxed style not yet implemented!" << std::endl;
Chris@1078 241 }
Chris@1078 242 }
Chris@1228 243
Chris@1228 244