annotate widgets/SubdividingMenu.cpp @ 1127:9fb8dfd7ce4c spectrogram-minor-refactor

Fix threshold in spectrogram -- it wasn't working in the last release. There is a new protocol for this. Formerly the threshold parameter had a range from -50dB to 0 with the default at -50, and -50 treated internally as "no threshold". However, there was a hardcoded, hidden internal threshold for spectrogram colour mapping at -80dB with anything below this being rounded to zero. Now the threshold parameter has range -81 to -1 with the default at -80, -81 is treated internally as "no threshold", and there is no hidden internal threshold. So the default behaviour is the same as before, an effective -80dB threshold, but it is now possible to change this in both directions. Sessions reloaded from prior versions may look slightly different because, if the session says there should be no threshold, there will now actually be no threshold instead of having the hidden internal one. Still need to do something in the UI to make it apparent that the -81dB setting removes the threshold entirely. This is at least no worse than the previous, also obscured, magic -50dB setting.
author Chris Cannam
date Mon, 01 Aug 2016 16:21:01 +0100
parents 4a578a360011
children edfc38ade098
rev   line source
Chris@151 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@151 2
Chris@151 3 /*
Chris@151 4 Sonic Visualiser
Chris@151 5 An audio file viewer and annotation editor.
Chris@151 6 Centre for Digital Music, Queen Mary, University of London.
Chris@182 7 This file copyright 2006 QMUL.
Chris@151 8
Chris@151 9 This program is free software; you can redistribute it and/or
Chris@151 10 modify it under the terms of the GNU General Public License as
Chris@151 11 published by the Free Software Foundation; either version 2 of the
Chris@151 12 License, or (at your option) any later version. See the file
Chris@151 13 COPYING included with this distribution for more information.
Chris@151 14 */
Chris@151 15
Chris@151 16 #include "SubdividingMenu.h"
Chris@151 17
Chris@151 18 #include <iostream>
Chris@151 19
Chris@682 20 #include "base/Debug.h"
Chris@682 21
Chris@151 22 using std::set;
Chris@151 23 using std::map;
Chris@151 24
Chris@807 25 SubdividingMenu::SubdividingMenu(int lowerLimit, int upperLimit,
Chris@152 26 QWidget *parent) :
Chris@152 27 QMenu(parent),
Chris@152 28 m_lowerLimit(lowerLimit ? lowerLimit : 14),
Chris@152 29 m_upperLimit(upperLimit ? upperLimit : (m_lowerLimit * 5) / 2),
Chris@152 30 m_entriesSet(false)
Chris@151 31 {
Chris@151 32 }
Chris@151 33
Chris@807 34 SubdividingMenu::SubdividingMenu(const QString &title, int lowerLimit,
Chris@807 35 int upperLimit, QWidget *parent) :
Chris@152 36 QMenu(title, parent),
Chris@152 37 m_lowerLimit(lowerLimit ? lowerLimit : 14),
Chris@152 38 m_upperLimit(upperLimit ? upperLimit : (m_lowerLimit * 5) / 2),
Chris@152 39 m_entriesSet(false)
Chris@151 40 {
Chris@151 41 }
Chris@151 42
Chris@151 43 SubdividingMenu::~SubdividingMenu()
Chris@151 44 {
Chris@152 45 for (map<QString, QObject *>::iterator i = m_pendingEntries.begin();
Chris@152 46 i != m_pendingEntries.end(); ++i) {
Chris@152 47 delete i->second;
Chris@152 48 }
Chris@151 49 }
Chris@151 50
Chris@151 51 void
Chris@151 52 SubdividingMenu::setEntries(const std::set<QString> &entries)
Chris@151 53 {
Chris@152 54 m_entriesSet = true;
Chris@152 55
Chris@908 56 int total = int(entries.size());
Chris@151 57
Chris@152 58 if (total < m_upperLimit) return;
Chris@151 59
Chris@807 60 int count = 0;
Chris@151 61 QMenu *chunkMenu = new QMenu();
Chris@196 62 chunkMenu->setTearOffEnabled(isTearOffEnabled());
Chris@151 63
Chris@151 64 QString firstNameInChunk;
Chris@151 65 QChar firstInitialInChunk;
Chris@151 66 bool discriminateStartInitial = false;
Chris@151 67
Chris@151 68 for (set<QString>::const_iterator j = entries.begin();
Chris@151 69 j != entries.end();
Chris@151 70 ++j) {
Chris@151 71
Chris@587 72 // SVDEBUG << "SubdividingMenu::setEntries: j -> " << j->toStdString() << endl;
Chris@151 73
Chris@151 74 m_nameToChunkMenuMap[*j] = chunkMenu;
Chris@151 75
Chris@151 76 set<QString>::iterator k = j;
Chris@151 77 ++k;
Chris@151 78
Chris@151 79 QChar initial = (*j)[0];
Chris@151 80
Chris@151 81 if (count == 0) {
Chris@151 82 firstNameInChunk = *j;
Chris@151 83 firstInitialInChunk = initial;
Chris@151 84 }
Chris@151 85
Chris@682 86 // cerr << "count = "<< count << ", upper limit = " << m_upperLimit << endl;
Chris@152 87
Chris@151 88 bool lastInChunk = (k == entries.end() ||
Chris@152 89 (count >= m_lowerLimit-1 &&
Chris@152 90 (count == m_upperLimit ||
Chris@151 91 (*k)[0] != initial)));
Chris@151 92
Chris@151 93 ++count;
Chris@151 94
Chris@151 95 if (lastInChunk) {
Chris@151 96
Chris@151 97 bool discriminateEndInitial = (k != entries.end() &&
Chris@151 98 (*k)[0] == initial);
Chris@151 99
Chris@151 100 bool initialsEqual = (firstInitialInChunk == initial);
Chris@151 101
Chris@151 102 QString from = QString("%1").arg(firstInitialInChunk);
Chris@151 103 if (discriminateStartInitial ||
Chris@151 104 (discriminateEndInitial && initialsEqual)) {
Chris@151 105 from = firstNameInChunk.left(3);
Chris@151 106 }
Chris@151 107
Chris@151 108 QString to = QString("%1").arg(initial);
Chris@151 109 if (discriminateEndInitial ||
Chris@151 110 (discriminateStartInitial && initialsEqual)) {
Chris@151 111 to = j->left(3);
Chris@151 112 }
Chris@151 113
Chris@151 114 QString menuText;
Chris@151 115
Chris@151 116 if (from == to) menuText = from;
Chris@151 117 else menuText = tr("%1 - %2").arg(from).arg(to);
Chris@151 118
Chris@151 119 discriminateStartInitial = discriminateEndInitial;
Chris@151 120
Chris@151 121 chunkMenu->setTitle(menuText);
Chris@151 122
Chris@151 123 QMenu::addMenu(chunkMenu);
Chris@151 124
Chris@151 125 chunkMenu = new QMenu();
Chris@196 126 chunkMenu->setTearOffEnabled(isTearOffEnabled());
Chris@151 127
Chris@151 128 count = 0;
Chris@151 129 }
Chris@151 130 }
Chris@151 131
Chris@151 132 if (count == 0) delete chunkMenu;
Chris@151 133 }
Chris@151 134
Chris@151 135 void
Chris@152 136 SubdividingMenu::entriesAdded()
Chris@152 137 {
Chris@152 138 if (m_entriesSet) {
Chris@682 139 cerr << "ERROR: SubdividingMenu::entriesAdded: setEntries was also called -- should use one mechanism or the other, but not both" << endl;
Chris@152 140 return;
Chris@152 141 }
Chris@152 142
Chris@152 143 set<QString> entries;
Chris@152 144 for (map<QString, QObject *>::const_iterator i = m_pendingEntries.begin();
Chris@152 145 i != m_pendingEntries.end(); ++i) {
Chris@152 146 entries.insert(i->first);
Chris@152 147 }
Chris@152 148
Chris@152 149 setEntries(entries);
Chris@152 150
Chris@152 151 for (map<QString, QObject *>::iterator i = m_pendingEntries.begin();
Chris@152 152 i != m_pendingEntries.end(); ++i) {
Chris@152 153
Chris@152 154 QMenu *menu = dynamic_cast<QMenu *>(i->second);
Chris@152 155 if (menu) {
Chris@152 156 addMenu(i->first, menu);
Chris@152 157 continue;
Chris@152 158 }
Chris@152 159
Chris@152 160 QAction *action = dynamic_cast<QAction *>(i->second);
Chris@152 161 if (action) {
Chris@152 162 addAction(i->first, action);
Chris@152 163 continue;
Chris@152 164 }
Chris@152 165 }
Chris@152 166
Chris@152 167 m_pendingEntries.clear();
Chris@152 168 }
Chris@152 169
Chris@152 170 void
Chris@151 171 SubdividingMenu::addAction(QAction *action)
Chris@151 172 {
Chris@151 173 QString name = action->text();
Chris@151 174
Chris@152 175 if (!m_entriesSet) {
Chris@152 176 m_pendingEntries[name] = action;
Chris@152 177 return;
Chris@152 178 }
Chris@152 179
Chris@151 180 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
Chris@587 181 // SVDEBUG << "SubdividingMenu::addAction(" << name << "): not found in name-to-chunk map, adding to main menu" << endl;
Chris@151 182 QMenu::addAction(action);
Chris@151 183 return;
Chris@151 184 }
Chris@151 185
Chris@587 186 // SVDEBUG << "SubdividingMenu::addAction(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl;
Chris@151 187 m_nameToChunkMenuMap[name]->addAction(action);
Chris@151 188 }
Chris@151 189
Chris@151 190 QAction *
Chris@151 191 SubdividingMenu::addAction(const QString &name)
Chris@151 192 {
Chris@152 193 if (!m_entriesSet) {
Chris@152 194 QAction *action = new QAction(name, this);
Chris@152 195 m_pendingEntries[name] = action;
Chris@152 196 return action;
Chris@152 197 }
Chris@152 198
Chris@151 199 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
Chris@587 200 // SVDEBUG << "SubdividingMenu::addAction(" << name << "): not found in name-to-chunk map, adding to main menu" << endl;
Chris@151 201 return QMenu::addAction(name);
Chris@151 202 }
Chris@151 203
Chris@587 204 // SVDEBUG << "SubdividingMenu::addAction(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl;
Chris@151 205 return m_nameToChunkMenuMap[name]->addAction(name);
Chris@151 206 }
Chris@151 207
Chris@151 208 void
Chris@151 209 SubdividingMenu::addAction(const QString &name, QAction *action)
Chris@151 210 {
Chris@152 211 if (!m_entriesSet) {
Chris@152 212 m_pendingEntries[name] = action;
Chris@152 213 return;
Chris@152 214 }
Chris@152 215
Chris@151 216 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
Chris@587 217 // SVDEBUG << "SubdividingMenu::addAction(" << name << "): not found in name-to-chunk map, adding to main menu" << endl;
Chris@151 218 QMenu::addAction(action);
Chris@151 219 return;
Chris@151 220 }
Chris@151 221
Chris@587 222 // SVDEBUG << "SubdividingMenu::addAction(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl;
Chris@151 223 m_nameToChunkMenuMap[name]->addAction(action);
Chris@151 224 }
Chris@151 225
Chris@151 226 void
Chris@151 227 SubdividingMenu::addMenu(QMenu *menu)
Chris@151 228 {
Chris@151 229 QString name = menu->title();
Chris@151 230
Chris@152 231 if (!m_entriesSet) {
Chris@152 232 m_pendingEntries[name] = menu;
Chris@152 233 return;
Chris@152 234 }
Chris@152 235
Chris@151 236 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
Chris@587 237 // SVDEBUG << "SubdividingMenu::addMenu(" << name << "): not found in name-to-chunk map, adding to main menu" << endl;
Chris@151 238 QMenu::addMenu(menu);
Chris@151 239 return;
Chris@151 240 }
Chris@151 241
Chris@587 242 // SVDEBUG << "SubdividingMenu::addMenu(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl;
Chris@151 243 m_nameToChunkMenuMap[name]->addMenu(menu);
Chris@151 244 }
Chris@151 245
Chris@151 246 QMenu *
Chris@151 247 SubdividingMenu::addMenu(const QString &name)
Chris@151 248 {
Chris@152 249 if (!m_entriesSet) {
Chris@152 250 QMenu *menu = new QMenu(name, this);
Chris@196 251 menu->setTearOffEnabled(isTearOffEnabled());
Chris@152 252 m_pendingEntries[name] = menu;
Chris@152 253 return menu;
Chris@152 254 }
Chris@152 255
Chris@151 256 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
Chris@587 257 // SVDEBUG << "SubdividingMenu::addMenu(" << name << "): not found in name-to-chunk map, adding to main menu" << endl;
Chris@151 258 return QMenu::addMenu(name);
Chris@151 259 }
Chris@151 260
Chris@587 261 // SVDEBUG << "SubdividingMenu::addMenu(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl;
Chris@151 262 return m_nameToChunkMenuMap[name]->addMenu(name);
Chris@151 263 }
Chris@151 264
Chris@151 265 void
Chris@151 266 SubdividingMenu::addMenu(const QString &name, QMenu *menu)
Chris@151 267 {
Chris@152 268 if (!m_entriesSet) {
Chris@152 269 m_pendingEntries[name] = menu;
Chris@152 270 return;
Chris@152 271 }
Chris@152 272
Chris@151 273 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
Chris@587 274 // SVDEBUG << "SubdividingMenu::addMenu(" << name << "): not found in name-to-chunk map, adding to main menu" << endl;
Chris@151 275 QMenu::addMenu(menu);
Chris@151 276 return;
Chris@151 277 }
Chris@151 278
Chris@587 279 // SVDEBUG << "SubdividingMenu::addMenu(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl;
Chris@151 280 m_nameToChunkMenuMap[name]->addMenu(menu);
Chris@151 281 }
Chris@151 282