annotate widgets/PaneStack.cpp @ 77:fd348f36c0d3

* Implement harmonic cursor in spectrogram * Implement layer export. This doesn't quite do the right thing for the SV XML layer export yet -- it doesn't include layer display information, so when imported, it only creates an invisible model. Could also do with fixing CSV file import so as to work correctly for note and text layers.
author Chris Cannam
date Mon, 10 Apr 2006 17:22:59 +0000
parents 705f05ab42e3
children 19bf27e4fb29
rev   line source
Chris@0 1
Chris@58 2 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 3
Chris@0 4 /*
Chris@59 5 Sonic Visualiser
Chris@59 6 An audio file viewer and annotation editor.
Chris@59 7 Centre for Digital Music, Queen Mary, University of London.
Chris@59 8 This file copyright 2006 Chris Cannam.
Chris@0 9
Chris@59 10 This program is free software; you can redistribute it and/or
Chris@59 11 modify it under the terms of the GNU General Public License as
Chris@59 12 published by the Free Software Foundation; either version 2 of the
Chris@59 13 License, or (at your option) any later version. See the file
Chris@59 14 COPYING included with this distribution for more information.
Chris@0 15 */
Chris@0 16
Chris@0 17 #include "PaneStack.h"
Chris@0 18
Chris@0 19 #include "widgets/Pane.h"
Chris@0 20 #include "widgets/PropertyStack.h"
Chris@0 21 #include "base/Layer.h"
Chris@0 22 #include "base/ViewManager.h"
Chris@0 23
Chris@0 24 #include <QApplication>
Chris@0 25 #include <QHBoxLayout>
Chris@0 26 #include <QPainter>
Chris@0 27 #include <QPalette>
Chris@0 28 #include <QLabel>
Chris@0 29
Chris@0 30 #include <iostream>
Chris@0 31
Chris@0 32 PaneStack::PaneStack(QWidget *parent, ViewManager *viewManager) :
Chris@0 33 QSplitter(parent),
Chris@0 34 m_currentPane(0),
Chris@0 35 m_viewManager(viewManager)
Chris@0 36 {
Chris@0 37 setOrientation(Qt::Vertical);
Chris@0 38 setOpaqueResize(false);
Chris@0 39 }
Chris@0 40
Chris@0 41 Pane *
Chris@0 42 PaneStack::addPane(bool suppressPropertyBox)
Chris@0 43 {
Chris@0 44 QFrame *frame = new QFrame;
Chris@0 45 QHBoxLayout *layout = new QHBoxLayout;
Chris@0 46 layout->setMargin(0);
Chris@0 47 layout->setSpacing(2);
Chris@0 48
Chris@0 49 QLabel *currentIndicator = new QLabel(frame);
Chris@0 50 currentIndicator->setFixedWidth(QPainter(this).fontMetrics().width("x"));
Chris@0 51 layout->addWidget(currentIndicator);
Chris@0 52 layout->setStretchFactor(currentIndicator, 1);
Chris@0 53 currentIndicator->setScaledContents(true);
Chris@0 54
Chris@0 55 Pane *pane = new Pane(frame);
Chris@0 56 pane->setViewManager(m_viewManager);
Chris@0 57 layout->addWidget(pane);
Chris@0 58 layout->setStretchFactor(pane, 10);
Chris@0 59
Chris@0 60 QWidget *properties = 0;
Chris@0 61 if (suppressPropertyBox) {
Chris@0 62 properties = new QFrame();
Chris@0 63 } else {
Chris@0 64 properties = new PropertyStack(frame, pane);
Chris@52 65 connect(properties, SIGNAL(propertyContainerSelected(View *, PropertyContainer *)),
Chris@52 66 this, SLOT(propertyContainerSelected(View *, PropertyContainer *)));
Chris@0 67 }
Chris@0 68 layout->addWidget(properties);
Chris@0 69 layout->setStretchFactor(properties, 1);
Chris@52 70
Chris@52 71 PaneRec rec;
Chris@52 72 rec.pane = pane;
Chris@52 73 rec.propertyStack = properties;
Chris@52 74 rec.currentIndicator = currentIndicator;
Chris@52 75 m_panes.push_back(rec);
Chris@0 76
Chris@0 77 frame->setLayout(layout);
Chris@0 78 addWidget(frame);
Chris@0 79
Chris@0 80 connect(pane, SIGNAL(propertyContainerAdded(PropertyContainer *)),
Chris@0 81 this, SLOT(propertyContainerAdded(PropertyContainer *)));
Chris@0 82 connect(pane, SIGNAL(propertyContainerRemoved(PropertyContainer *)),
Chris@0 83 this, SLOT(propertyContainerRemoved(PropertyContainer *)));
Chris@0 84 connect(pane, SIGNAL(paneInteractedWith()),
Chris@0 85 this, SLOT(paneInteractedWith()));
Chris@0 86
Chris@0 87 if (!m_currentPane) {
Chris@0 88 setCurrentPane(pane);
Chris@0 89 }
Chris@0 90
Chris@0 91 return pane;
Chris@0 92 }
Chris@0 93
Chris@0 94 Pane *
Chris@0 95 PaneStack::getPane(int n)
Chris@0 96 {
Chris@52 97 return m_panes[n].pane;
Chris@52 98 }
Chris@52 99
Chris@52 100 Pane *
Chris@52 101 PaneStack::getHiddenPane(int n)
Chris@52 102 {
Chris@52 103 return m_hiddenPanes[n].pane;
Chris@0 104 }
Chris@0 105
Chris@0 106 void
Chris@0 107 PaneStack::deletePane(Pane *pane)
Chris@0 108 {
Chris@52 109 std::vector<PaneRec>::iterator i;
Chris@52 110 bool found = false;
Chris@0 111
Chris@52 112 for (i = m_panes.begin(); i != m_panes.end(); ++i) {
Chris@52 113 if (i->pane == pane) {
Chris@52 114 m_panes.erase(i);
Chris@52 115 found = true;
Chris@52 116 break;
Chris@52 117 }
Chris@0 118 }
Chris@0 119
Chris@52 120 if (!found) {
Chris@52 121
Chris@52 122 for (i = m_hiddenPanes.begin(); i != m_hiddenPanes.end(); ++i) {
Chris@52 123 if (i->pane == pane) {
Chris@52 124 m_hiddenPanes.erase(i);
Chris@52 125 found = true;
Chris@52 126 break;
Chris@52 127 }
Chris@52 128 }
Chris@52 129
Chris@52 130 if (!found) {
Chris@52 131 std::cerr << "WARNING: PaneStack::deletePane(" << pane << "): Pane not found in visible or hidden panes, not deleting" << std::endl;
Chris@52 132 return;
Chris@52 133 }
Chris@52 134 }
Chris@52 135
Chris@52 136 delete pane->parent();
Chris@0 137
Chris@0 138 if (m_currentPane == pane) {
Chris@0 139 if (m_panes.size() > 0) {
Chris@52 140 setCurrentPane(m_panes[0].pane);
Chris@0 141 } else {
Chris@0 142 setCurrentPane(0);
Chris@0 143 }
Chris@0 144 }
Chris@0 145 }
Chris@0 146
Chris@0 147 int
Chris@0 148 PaneStack::getPaneCount() const
Chris@0 149 {
Chris@0 150 return m_panes.size();
Chris@0 151 }
Chris@0 152
Chris@52 153 int
Chris@52 154 PaneStack::getHiddenPaneCount() const
Chris@52 155 {
Chris@52 156 return m_hiddenPanes.size();
Chris@52 157 }
Chris@52 158
Chris@52 159 void
Chris@52 160 PaneStack::hidePane(Pane *pane)
Chris@52 161 {
Chris@52 162 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@52 163
Chris@52 164 while (i != m_panes.end()) {
Chris@52 165 if (i->pane == pane) {
Chris@52 166
Chris@52 167 m_hiddenPanes.push_back(*i);
Chris@52 168 m_panes.erase(i);
Chris@52 169
Chris@52 170 QWidget *pw = dynamic_cast<QWidget *>(pane->parent());
Chris@52 171 if (pw) pw->hide();
Chris@52 172
Chris@52 173 if (m_currentPane == pane) {
Chris@52 174 if (m_panes.size() > 0) {
Chris@52 175 setCurrentPane(m_panes[0].pane);
Chris@52 176 } else {
Chris@52 177 setCurrentPane(0);
Chris@52 178 }
Chris@52 179 }
Chris@52 180
Chris@52 181 return;
Chris@52 182 }
Chris@52 183 ++i;
Chris@52 184 }
Chris@52 185
Chris@52 186 std::cerr << "WARNING: PaneStack::hidePane(" << pane << "): Pane not found in visible panes" << std::endl;
Chris@52 187 }
Chris@52 188
Chris@52 189 void
Chris@52 190 PaneStack::showPane(Pane *pane)
Chris@52 191 {
Chris@52 192 std::vector<PaneRec>::iterator i = m_hiddenPanes.begin();
Chris@52 193
Chris@52 194 while (i != m_hiddenPanes.end()) {
Chris@52 195 if (i->pane == pane) {
Chris@52 196 m_panes.push_back(*i);
Chris@52 197 m_hiddenPanes.erase(i);
Chris@52 198 QWidget *pw = dynamic_cast<QWidget *>(pane->parent());
Chris@52 199 if (pw) pw->show();
Chris@52 200
Chris@52 201 //!!! update current pane
Chris@52 202
Chris@52 203 return;
Chris@52 204 }
Chris@52 205 ++i;
Chris@52 206 }
Chris@52 207
Chris@52 208 std::cerr << "WARNING: PaneStack::showPane(" << pane << "): Pane not found in hidden panes" << std::endl;
Chris@52 209 }
Chris@52 210
Chris@0 211 void
Chris@0 212 PaneStack::setCurrentPane(Pane *pane) // may be null
Chris@0 213 {
Chris@0 214 if (m_currentPane == pane) return;
Chris@0 215
Chris@52 216 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@0 217
Chris@0 218 // We used to do this by setting the foreground and background
Chris@0 219 // role, but it seems the background role is ignored and the
Chris@0 220 // background drawn transparent in Qt 4.1 -- I can't quite see why
Chris@0 221
Chris@0 222 QPixmap selectedMap(1, 1);
Chris@0 223 selectedMap.fill(QApplication::palette().color(QPalette::Foreground));
Chris@0 224
Chris@0 225 QPixmap unselectedMap(1, 1);
Chris@0 226 unselectedMap.fill(QApplication::palette().color(QPalette::Background));
Chris@0 227
Chris@52 228 bool found = false;
Chris@52 229
Chris@0 230 while (i != m_panes.end()) {
Chris@52 231 if (i->pane == pane) {
Chris@52 232 i->currentIndicator->setPixmap(selectedMap);
Chris@52 233 found = true;
Chris@0 234 } else {
Chris@52 235 i->currentIndicator->setPixmap(unselectedMap);
Chris@0 236 }
Chris@0 237 ++i;
Chris@0 238 }
Chris@0 239
Chris@52 240 if (found || pane == 0) {
Chris@52 241 m_currentPane = pane;
Chris@52 242 emit currentPaneChanged(m_currentPane);
Chris@52 243 } else {
Chris@52 244 std::cerr << "WARNING: PaneStack::setCurrentPane(" << pane << "): pane is not a visible pane in this stack" << std::endl;
Chris@52 245 }
Chris@0 246 }
Chris@0 247
Chris@19 248 void
Chris@19 249 PaneStack::setCurrentLayer(Pane *pane, Layer *layer) // may be null
Chris@19 250 {
Chris@19 251 setCurrentPane(pane);
Chris@19 252
Chris@19 253 if (m_currentPane) {
Chris@19 254
Chris@52 255 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@19 256
Chris@19 257 while (i != m_panes.end()) {
Chris@19 258
Chris@52 259 if (i->pane == pane) {
Chris@52 260 PropertyStack *stack = dynamic_cast<PropertyStack *>
Chris@52 261 (i->propertyStack);
Chris@19 262 if (stack) {
Chris@19 263 if (stack->containsContainer(layer)) {
Chris@19 264 stack->setCurrentIndex(stack->getContainerIndex(layer));
Chris@19 265 emit currentLayerChanged(pane, layer);
Chris@19 266 } else {
Chris@33 267 stack->setCurrentIndex
Chris@33 268 (stack->getContainerIndex
Chris@33 269 (pane->getPropertyContainer(0)));
Chris@19 270 emit currentLayerChanged(pane, 0);
Chris@19 271 }
Chris@19 272 }
Chris@19 273 break;
Chris@19 274 }
Chris@19 275 ++i;
Chris@19 276 }
Chris@19 277 }
Chris@19 278 }
Chris@19 279
Chris@0 280 Pane *
Chris@0 281 PaneStack::getCurrentPane()
Chris@0 282 {
Chris@0 283 return m_currentPane;
Chris@0 284 }
Chris@0 285
Chris@0 286 void
Chris@0 287 PaneStack::propertyContainerAdded(PropertyContainer *)
Chris@0 288 {
Chris@0 289 sizePropertyStacks();
Chris@0 290 }
Chris@0 291
Chris@0 292 void
Chris@0 293 PaneStack::propertyContainerRemoved(PropertyContainer *)
Chris@0 294 {
Chris@0 295 sizePropertyStacks();
Chris@0 296 }
Chris@0 297
Chris@0 298 void
Chris@52 299 PaneStack::propertyContainerSelected(View *client, PropertyContainer *pc)
Chris@0 300 {
Chris@52 301 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@0 302
Chris@0 303 while (i != m_panes.end()) {
Chris@52 304 PropertyStack *stack = dynamic_cast<PropertyStack *>(i->propertyStack);
Chris@52 305 if (stack &&
Chris@52 306 stack->getClient() == client &&
Chris@52 307 stack->containsContainer(pc)) {
Chris@52 308 setCurrentPane(i->pane);
Chris@0 309 break;
Chris@0 310 }
Chris@0 311 ++i;
Chris@0 312 }
Chris@17 313
Chris@17 314 Layer *layer = dynamic_cast<Layer *>(pc);
Chris@17 315 if (layer) emit currentLayerChanged(m_currentPane, layer);
Chris@17 316 else emit currentLayerChanged(m_currentPane, 0);
Chris@0 317 }
Chris@0 318
Chris@0 319 void
Chris@0 320 PaneStack::paneInteractedWith()
Chris@0 321 {
Chris@0 322 Pane *pane = dynamic_cast<Pane *>(sender());
Chris@0 323 if (!pane) return;
Chris@0 324 setCurrentPane(pane);
Chris@0 325 }
Chris@0 326
Chris@0 327 void
Chris@0 328 PaneStack::sizePropertyStacks()
Chris@0 329 {
Chris@0 330 int maxMinWidth = 0;
Chris@0 331
Chris@52 332 for (size_t i = 0; i < m_panes.size(); ++i) {
Chris@52 333 if (!m_panes[i].propertyStack) continue;
Chris@0 334 std::cerr << "PaneStack::sizePropertyStacks: " << i << ": min "
Chris@52 335 << m_panes[i].propertyStack->minimumSizeHint().width() << ", current "
Chris@52 336 << m_panes[i].propertyStack->width() << std::endl;
Chris@0 337
Chris@52 338 if (m_panes[i].propertyStack->minimumSizeHint().width() > maxMinWidth) {
Chris@52 339 maxMinWidth = m_panes[i].propertyStack->minimumSizeHint().width();
Chris@0 340 }
Chris@0 341 }
Chris@0 342
Chris@0 343 std::cerr << "PaneStack::sizePropertyStacks: max min width " << maxMinWidth << std::endl;
Chris@0 344
Chris@0 345 #ifdef Q_WS_MAC
Chris@0 346 // This is necessary to compensate for cb->setMinimumSize(10, 10)
Chris@0 347 // in PropertyBox in the Mac version (to avoid a mysterious crash)
Chris@0 348 int setWidth = maxMinWidth * 3 / 2;
Chris@0 349 #else
Chris@0 350 int setWidth = maxMinWidth;
Chris@0 351 #endif
Chris@0 352
Chris@52 353 for (size_t i = 0; i < m_panes.size(); ++i) {
Chris@52 354 if (!m_panes[i].propertyStack) continue;
Chris@52 355 m_panes[i].propertyStack->setMinimumWidth(setWidth);
Chris@0 356 }
Chris@0 357 }
Chris@0 358
Chris@0 359
Chris@0 360 #ifdef INCLUDE_MOCFILES
Chris@0 361 #include "PaneStack.moc.cpp"
Chris@0 362 #endif
Chris@0 363