annotate widgets/PaneStack.cpp @ 25:dcdb21b62dbb

* Refactor sparse models. Previously the 1D and time-value models duplicated a lot of code; now there is a base class (SparseModel) templated on the stored point type, and the subclasses define point types with the necessary characteristics. * Add NoteModel, a new SparseModel subclass. * Reorganise local feature description display. Instead of asking the layer to draw its own, just query it for a textual description and draw that in Pane. Greatly simplifies this part of the layer code. * Add local feature descriptions to colour 3D plot and waveform layers. * Add pitch in MIDI-pitch-and-cents to spectrogram layer. * Give AudioGenerator its own mutex to shorten lock times in CallbackPlaySource. * Minor adjustments to layers menu &c
author Chris Cannam
date Thu, 02 Feb 2006 16:10:19 +0000
parents 46d8f5add6f0
children 651e4e868bcc
rev   line source
Chris@0 1
Chris@0 2 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 3
Chris@0 4 /*
Chris@0 5 A waveform viewer and audio annotation editor.
Chris@5 6 Chris Cannam, Queen Mary University of London, 2005-2006
Chris@0 7
Chris@0 8 This is experimental software. Not for distribution.
Chris@0 9 */
Chris@0 10
Chris@0 11 #include "PaneStack.h"
Chris@0 12
Chris@0 13 #include "widgets/Pane.h"
Chris@0 14 #include "widgets/PropertyStack.h"
Chris@0 15 #include "base/Layer.h"
Chris@0 16 #include "base/ViewManager.h"
Chris@0 17
Chris@0 18 #include <QApplication>
Chris@0 19 #include <QHBoxLayout>
Chris@0 20 #include <QPainter>
Chris@0 21 #include <QPalette>
Chris@0 22 #include <QLabel>
Chris@0 23
Chris@0 24 #include <iostream>
Chris@0 25
Chris@0 26 PaneStack::PaneStack(QWidget *parent, ViewManager *viewManager) :
Chris@0 27 QSplitter(parent),
Chris@0 28 m_currentPane(0),
Chris@0 29 m_viewManager(viewManager)
Chris@0 30 {
Chris@0 31 setOrientation(Qt::Vertical);
Chris@0 32 setOpaqueResize(false);
Chris@0 33 }
Chris@0 34
Chris@0 35 Pane *
Chris@0 36 PaneStack::addPane(bool suppressPropertyBox)
Chris@0 37 {
Chris@0 38 QFrame *frame = new QFrame;
Chris@0 39 QHBoxLayout *layout = new QHBoxLayout;
Chris@0 40 layout->setMargin(0);
Chris@0 41 layout->setSpacing(2);
Chris@0 42
Chris@0 43 QLabel *currentIndicator = new QLabel(frame);
Chris@0 44 currentIndicator->setFixedWidth(QPainter(this).fontMetrics().width("x"));
Chris@0 45 layout->addWidget(currentIndicator);
Chris@0 46 layout->setStretchFactor(currentIndicator, 1);
Chris@0 47 currentIndicator->setScaledContents(true);
Chris@0 48 m_currentIndicators.push_back(currentIndicator);
Chris@0 49
Chris@0 50 Pane *pane = new Pane(frame);
Chris@0 51 pane->setViewManager(m_viewManager);
Chris@0 52 layout->addWidget(pane);
Chris@0 53 layout->setStretchFactor(pane, 10);
Chris@0 54 m_panes.push_back(pane);
Chris@0 55
Chris@0 56 QWidget *properties = 0;
Chris@0 57 if (suppressPropertyBox) {
Chris@0 58 properties = new QFrame();
Chris@0 59 } else {
Chris@0 60 properties = new PropertyStack(frame, pane);
Chris@0 61 connect(properties, SIGNAL(propertyContainerSelected(PropertyContainer *)),
Chris@0 62 this, SLOT(propertyContainerSelected(PropertyContainer *)));
Chris@0 63 }
Chris@0 64 layout->addWidget(properties);
Chris@0 65 layout->setStretchFactor(properties, 1);
Chris@0 66 m_propertyStacks.push_back(properties);
Chris@0 67
Chris@0 68 frame->setLayout(layout);
Chris@0 69 addWidget(frame);
Chris@0 70
Chris@0 71 connect(pane, SIGNAL(propertyContainerAdded(PropertyContainer *)),
Chris@0 72 this, SLOT(propertyContainerAdded(PropertyContainer *)));
Chris@0 73 connect(pane, SIGNAL(propertyContainerRemoved(PropertyContainer *)),
Chris@0 74 this, SLOT(propertyContainerRemoved(PropertyContainer *)));
Chris@0 75 connect(pane, SIGNAL(paneInteractedWith()),
Chris@0 76 this, SLOT(paneInteractedWith()));
Chris@0 77
Chris@0 78 if (!m_currentPane) {
Chris@0 79 setCurrentPane(pane);
Chris@0 80 }
Chris@0 81
Chris@0 82 return pane;
Chris@0 83 }
Chris@0 84
Chris@0 85 Pane *
Chris@0 86 PaneStack::getPane(int n)
Chris@0 87 {
Chris@0 88 return m_panes[n];
Chris@0 89 }
Chris@0 90
Chris@0 91 void
Chris@0 92 PaneStack::deletePane(Pane *pane)
Chris@0 93 {
Chris@0 94 int n = 0;
Chris@0 95 std::vector<Pane *>::iterator i = m_panes.begin();
Chris@0 96 std::vector<QWidget *>::iterator j = m_propertyStacks.begin();
Chris@0 97 std::vector<QLabel *>::iterator k = m_currentIndicators.begin();
Chris@0 98
Chris@0 99 while (i != m_panes.end()) {
Chris@0 100 if (*i == pane) break;
Chris@0 101 ++i;
Chris@0 102 ++j;
Chris@0 103 ++k;
Chris@0 104 ++n;
Chris@0 105 }
Chris@0 106 if (n >= int(m_panes.size())) return;
Chris@0 107
Chris@0 108 m_panes.erase(i);
Chris@0 109 m_propertyStacks.erase(j);
Chris@0 110 m_currentIndicators.erase(k);
Chris@0 111 delete widget(n);
Chris@0 112
Chris@0 113 if (m_currentPane == pane) {
Chris@0 114 if (m_panes.size() > 0) {
Chris@0 115 setCurrentPane(m_panes[0]);
Chris@0 116 } else {
Chris@0 117 setCurrentPane(0);
Chris@0 118 }
Chris@0 119 }
Chris@0 120 }
Chris@0 121
Chris@0 122 int
Chris@0 123 PaneStack::getPaneCount() const
Chris@0 124 {
Chris@0 125 return m_panes.size();
Chris@0 126 }
Chris@0 127
Chris@0 128 void
Chris@0 129 PaneStack::setCurrentPane(Pane *pane) // may be null
Chris@0 130 {
Chris@0 131 if (m_currentPane == pane) return;
Chris@0 132
Chris@0 133 std::vector<Pane *>::iterator i = m_panes.begin();
Chris@0 134 std::vector<QLabel *>::iterator k = m_currentIndicators.begin();
Chris@0 135
Chris@0 136 // We used to do this by setting the foreground and background
Chris@0 137 // role, but it seems the background role is ignored and the
Chris@0 138 // background drawn transparent in Qt 4.1 -- I can't quite see why
Chris@0 139
Chris@0 140 QPixmap selectedMap(1, 1);
Chris@0 141 selectedMap.fill(QApplication::palette().color(QPalette::Foreground));
Chris@0 142
Chris@0 143 QPixmap unselectedMap(1, 1);
Chris@0 144 unselectedMap.fill(QApplication::palette().color(QPalette::Background));
Chris@0 145
Chris@0 146 while (i != m_panes.end()) {
Chris@0 147 if (*i == pane) {
Chris@0 148 (*k)->setPixmap(selectedMap);
Chris@0 149 } else {
Chris@0 150 (*k)->setPixmap(unselectedMap);
Chris@0 151 }
Chris@0 152 ++i;
Chris@0 153 ++k;
Chris@0 154 }
Chris@0 155 m_currentPane = pane;
Chris@0 156
Chris@0 157 emit currentPaneChanged(m_currentPane);
Chris@0 158 }
Chris@0 159
Chris@19 160 void
Chris@19 161 PaneStack::setCurrentLayer(Pane *pane, Layer *layer) // may be null
Chris@19 162 {
Chris@19 163 setCurrentPane(pane);
Chris@19 164
Chris@19 165 if (m_currentPane) {
Chris@19 166
Chris@19 167 std::vector<Pane *>::iterator i = m_panes.begin();
Chris@19 168 std::vector<QWidget *>::iterator j = m_propertyStacks.begin();
Chris@19 169
Chris@19 170 while (i != m_panes.end()) {
Chris@19 171
Chris@19 172 if (*i == pane) {
Chris@19 173 PropertyStack *stack = dynamic_cast<PropertyStack *>(*j);
Chris@19 174 if (stack) {
Chris@19 175 if (stack->containsContainer(layer)) {
Chris@19 176 stack->setCurrentIndex(stack->getContainerIndex(layer));
Chris@19 177 emit currentLayerChanged(pane, layer);
Chris@19 178 } else {
Chris@19 179 stack->setCurrentIndex(stack->getContainerIndex(pane));
Chris@19 180 emit currentLayerChanged(pane, 0);
Chris@19 181 }
Chris@19 182 }
Chris@19 183 break;
Chris@19 184 }
Chris@19 185 ++i;
Chris@19 186 ++j;
Chris@19 187 }
Chris@19 188 }
Chris@19 189 }
Chris@19 190
Chris@0 191 Pane *
Chris@0 192 PaneStack::getCurrentPane()
Chris@0 193 {
Chris@0 194 return m_currentPane;
Chris@0 195 }
Chris@0 196
Chris@0 197 void
Chris@0 198 PaneStack::propertyContainerAdded(PropertyContainer *)
Chris@0 199 {
Chris@0 200 sizePropertyStacks();
Chris@0 201 }
Chris@0 202
Chris@0 203 void
Chris@0 204 PaneStack::propertyContainerRemoved(PropertyContainer *)
Chris@0 205 {
Chris@0 206 sizePropertyStacks();
Chris@0 207 }
Chris@0 208
Chris@0 209 void
Chris@0 210 PaneStack::propertyContainerSelected(PropertyContainer *pc)
Chris@0 211 {
Chris@0 212 std::vector<Pane *>::iterator i = m_panes.begin();
Chris@0 213 std::vector<QWidget *>::iterator j = m_propertyStacks.begin();
Chris@0 214
Chris@0 215 while (i != m_panes.end()) {
Chris@0 216 PropertyStack *stack = dynamic_cast<PropertyStack *>(*j);
Chris@0 217 if (stack && stack->containsContainer(pc)) {
Chris@0 218 setCurrentPane(*i);
Chris@0 219 break;
Chris@0 220 }
Chris@0 221 ++i;
Chris@0 222 ++j;
Chris@0 223 }
Chris@17 224
Chris@17 225 Layer *layer = dynamic_cast<Layer *>(pc);
Chris@17 226 if (layer) emit currentLayerChanged(m_currentPane, layer);
Chris@17 227 else emit currentLayerChanged(m_currentPane, 0);
Chris@0 228 }
Chris@0 229
Chris@0 230 void
Chris@0 231 PaneStack::paneInteractedWith()
Chris@0 232 {
Chris@0 233 Pane *pane = dynamic_cast<Pane *>(sender());
Chris@0 234 if (!pane) return;
Chris@0 235 setCurrentPane(pane);
Chris@0 236 }
Chris@0 237
Chris@0 238 void
Chris@0 239 PaneStack::sizePropertyStacks()
Chris@0 240 {
Chris@0 241 int maxMinWidth = 0;
Chris@0 242
Chris@0 243 for (unsigned int i = 0; i < m_propertyStacks.size(); ++i) {
Chris@0 244 if (!m_propertyStacks[i]) continue;
Chris@0 245 std::cerr << "PaneStack::sizePropertyStacks: " << i << ": min "
Chris@0 246 << m_propertyStacks[i]->minimumSizeHint().width() << ", current "
Chris@0 247 << m_propertyStacks[i]->width() << std::endl;
Chris@0 248
Chris@0 249 if (m_propertyStacks[i]->minimumSizeHint().width() > maxMinWidth) {
Chris@0 250 maxMinWidth = m_propertyStacks[i]->minimumSizeHint().width();
Chris@0 251 }
Chris@0 252 }
Chris@0 253
Chris@0 254 std::cerr << "PaneStack::sizePropertyStacks: max min width " << maxMinWidth << std::endl;
Chris@0 255
Chris@0 256 #ifdef Q_WS_MAC
Chris@0 257 // This is necessary to compensate for cb->setMinimumSize(10, 10)
Chris@0 258 // in PropertyBox in the Mac version (to avoid a mysterious crash)
Chris@0 259 int setWidth = maxMinWidth * 3 / 2;
Chris@0 260 #else
Chris@0 261 int setWidth = maxMinWidth;
Chris@0 262 #endif
Chris@0 263
Chris@0 264 for (unsigned int i = 0; i < m_propertyStacks.size(); ++i) {
Chris@0 265 if (!m_propertyStacks[i]) continue;
Chris@0 266 m_propertyStacks[i]->setMinimumWidth(setWidth);
Chris@0 267 }
Chris@0 268 }
Chris@0 269
Chris@0 270
Chris@0 271 #ifdef INCLUDE_MOCFILES
Chris@0 272 #include "PaneStack.moc.cpp"
Chris@0 273 #endif
Chris@0 274