Chris@127: Chris@127: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@127: Chris@127: /* Chris@127: Sonic Visualiser Chris@127: An audio file viewer and annotation editor. Chris@127: Centre for Digital Music, Queen Mary, University of London. Chris@182: This file copyright 2006 Chris Cannam and QMUL. Chris@127: Chris@127: This program is free software; you can redistribute it and/or Chris@127: modify it under the terms of the GNU General Public License as Chris@127: published by the Free Software Foundation; either version 2 of the Chris@127: License, or (at your option) any later version. See the file Chris@127: COPYING included with this distribution for more information. Chris@127: */ Chris@127: Chris@127: #include "PaneStack.h" Chris@127: Chris@128: #include "Pane.h" Chris@127: #include "widgets/PropertyStack.h" Chris@128: #include "layer/Layer.h" Chris@128: #include "ViewManager.h" Chris@127: Chris@127: #include Chris@127: #include Chris@127: #include Chris@127: #include Chris@127: #include Chris@127: #include Chris@127: #include Chris@127: Chris@127: #include Chris@127: Chris@127: PaneStack::PaneStack(QWidget *parent, ViewManager *viewManager) : Chris@127: QFrame(parent), Chris@127: m_currentPane(0), Chris@127: m_splitter(new QSplitter), Chris@127: m_propertyStackStack(new QStackedWidget), Chris@127: m_viewManager(viewManager), Chris@127: m_layoutStyle(PropertyStackPerPaneLayout) Chris@127: { Chris@127: QHBoxLayout *layout = new QHBoxLayout; Chris@127: layout->setMargin(0); Chris@127: layout->setSpacing(0); Chris@127: Chris@127: m_splitter->setOrientation(Qt::Vertical); Chris@127: m_splitter->setOpaqueResize(false); Chris@127: Chris@127: layout->addWidget(m_splitter); Chris@127: layout->setStretchFactor(m_splitter, 1); Chris@127: layout->addWidget(m_propertyStackStack); Chris@127: m_propertyStackStack->hide(); Chris@127: Chris@127: setLayout(layout); Chris@127: } Chris@127: Chris@127: Pane * Chris@127: PaneStack::addPane(bool suppressPropertyBox) Chris@127: { Chris@127: QFrame *frame = new QFrame; Chris@127: QHBoxLayout *layout = new QHBoxLayout; Chris@127: layout->setMargin(0); Chris@127: layout->setSpacing(2); Chris@127: Chris@127: QLabel *currentIndicator = new QLabel(frame); Chris@127: currentIndicator->setFixedWidth(QPainter(this).fontMetrics().width("x")); Chris@127: layout->addWidget(currentIndicator); Chris@127: layout->setStretchFactor(currentIndicator, 1); Chris@127: currentIndicator->setScaledContents(true); Chris@127: Chris@127: Pane *pane = new Pane(frame); Chris@127: pane->setViewManager(m_viewManager); Chris@127: layout->addWidget(pane); Chris@127: layout->setStretchFactor(pane, 10); Chris@127: Chris@127: QWidget *properties = 0; Chris@127: if (suppressPropertyBox) { Chris@127: properties = new QFrame(); Chris@127: } else { Chris@127: properties = new PropertyStack(frame, pane); Chris@127: connect(properties, SIGNAL(propertyContainerSelected(View *, PropertyContainer *)), Chris@127: this, SLOT(propertyContainerSelected(View *, PropertyContainer *))); Chris@190: connect(properties, SIGNAL(viewSelected(View *)), Chris@190: this, SLOT(viewSelected(View *))); Chris@189: connect(properties, SIGNAL(contextHelpChanged(const QString &)), Chris@189: this, SIGNAL(contextHelpChanged(const QString &))); Chris@127: } Chris@127: if (m_layoutStyle == PropertyStackPerPaneLayout) { Chris@127: layout->addWidget(properties); Chris@127: } else { Chris@127: properties->setParent(m_propertyStackStack); Chris@127: m_propertyStackStack->addWidget(properties); Chris@127: } Chris@127: layout->setStretchFactor(properties, 1); Chris@127: Chris@127: PaneRec rec; Chris@127: rec.pane = pane; Chris@127: rec.propertyStack = properties; Chris@127: rec.currentIndicator = currentIndicator; Chris@127: rec.frame = frame; Chris@127: rec.layout = layout; Chris@127: m_panes.push_back(rec); Chris@127: Chris@127: frame->setLayout(layout); Chris@127: m_splitter->addWidget(frame); Chris@127: Chris@127: connect(pane, SIGNAL(propertyContainerAdded(PropertyContainer *)), Chris@127: this, SLOT(propertyContainerAdded(PropertyContainer *))); Chris@127: connect(pane, SIGNAL(propertyContainerRemoved(PropertyContainer *)), Chris@127: this, SLOT(propertyContainerRemoved(PropertyContainer *))); Chris@127: connect(pane, SIGNAL(paneInteractedWith()), Chris@127: this, SLOT(paneInteractedWith())); Chris@127: connect(pane, SIGNAL(rightButtonMenuRequested(QPoint)), Chris@127: this, SLOT(rightButtonMenuRequested(QPoint))); Chris@127: Chris@127: if (!m_currentPane) { Chris@127: setCurrentPane(pane); Chris@127: } Chris@127: Chris@127: return pane; Chris@127: } Chris@127: Chris@127: void Chris@235: PaneStack::setPropertyStackMinWidth(int mw) Chris@235: { Chris@235: for (std::vector::iterator i = m_panes.begin(); Chris@235: i != m_panes.end(); ++i) { Chris@235: i->propertyStack->setMinimumWidth(mw); Chris@235: } Chris@235: m_propertyStackMinWidth = mw; Chris@235: } Chris@235: Chris@235: void Chris@127: PaneStack::setLayoutStyle(LayoutStyle style) Chris@127: { Chris@127: if (style == m_layoutStyle) return; Chris@127: m_layoutStyle = style; Chris@127: Chris@127: std::vector::iterator i; Chris@127: Chris@127: switch (style) { Chris@127: Chris@179: case NoPropertyStacks: Chris@127: case SinglePropertyStackLayout: Chris@127: Chris@127: for (i = m_panes.begin(); i != m_panes.end(); ++i) { Chris@127: i->layout->removeWidget(i->propertyStack); Chris@127: i->propertyStack->setParent(m_propertyStackStack); Chris@127: m_propertyStackStack->addWidget(i->propertyStack); Chris@127: } Chris@179: m_propertyStackStack->setVisible(style != NoPropertyStacks); Chris@127: break; Chris@127: Chris@127: case PropertyStackPerPaneLayout: Chris@127: Chris@127: for (i = m_panes.begin(); i != m_panes.end(); ++i) { Chris@127: m_propertyStackStack->removeWidget(i->propertyStack); Chris@127: i->propertyStack->setParent(i->frame); Chris@127: i->layout->addWidget(i->propertyStack); Chris@127: i->propertyStack->show(); Chris@127: } Chris@127: m_propertyStackStack->hide(); Chris@127: break; Chris@127: } Chris@127: } Chris@127: Chris@127: Pane * Chris@127: PaneStack::getPane(int n) Chris@127: { Chris@127: return m_panes[n].pane; Chris@127: } Chris@127: Chris@127: Pane * Chris@127: PaneStack::getHiddenPane(int n) Chris@127: { Chris@127: return m_hiddenPanes[n].pane; Chris@127: } Chris@127: Chris@127: void Chris@127: PaneStack::deletePane(Pane *pane) Chris@127: { Chris@127: std::vector::iterator i; Chris@127: bool found = false; Chris@127: Chris@127: for (i = m_panes.begin(); i != m_panes.end(); ++i) { Chris@127: if (i->pane == pane) { Chris@127: m_panes.erase(i); Chris@127: found = true; Chris@127: break; Chris@127: } Chris@127: } Chris@127: Chris@127: if (!found) { Chris@127: Chris@127: for (i = m_hiddenPanes.begin(); i != m_hiddenPanes.end(); ++i) { Chris@127: if (i->pane == pane) { Chris@127: m_hiddenPanes.erase(i); Chris@127: found = true; Chris@127: break; Chris@127: } Chris@127: } Chris@127: Chris@127: if (!found) { Chris@127: std::cerr << "WARNING: PaneStack::deletePane(" << pane << "): Pane not found in visible or hidden panes, not deleting" << std::endl; Chris@127: return; Chris@127: } Chris@127: } Chris@127: Chris@127: delete pane->parent(); Chris@127: Chris@127: if (m_currentPane == pane) { Chris@127: if (m_panes.size() > 0) { Chris@127: setCurrentPane(m_panes[0].pane); Chris@127: } else { Chris@127: setCurrentPane(0); Chris@127: } Chris@127: } Chris@127: } Chris@127: Chris@127: int Chris@127: PaneStack::getPaneCount() const Chris@127: { Chris@127: return m_panes.size(); Chris@127: } Chris@127: Chris@127: int Chris@127: PaneStack::getHiddenPaneCount() const Chris@127: { Chris@127: return m_hiddenPanes.size(); Chris@127: } Chris@127: Chris@127: void Chris@127: PaneStack::hidePane(Pane *pane) Chris@127: { Chris@127: std::vector::iterator i = m_panes.begin(); Chris@127: Chris@127: while (i != m_panes.end()) { Chris@127: if (i->pane == pane) { Chris@127: Chris@127: m_hiddenPanes.push_back(*i); Chris@127: m_panes.erase(i); Chris@127: Chris@127: QWidget *pw = dynamic_cast(pane->parent()); Chris@127: if (pw) pw->hide(); Chris@127: Chris@127: if (m_currentPane == pane) { Chris@127: if (m_panes.size() > 0) { Chris@127: setCurrentPane(m_panes[0].pane); Chris@127: } else { Chris@127: setCurrentPane(0); Chris@127: } Chris@127: } Chris@127: Chris@127: return; Chris@127: } Chris@127: ++i; Chris@127: } Chris@127: Chris@127: std::cerr << "WARNING: PaneStack::hidePane(" << pane << "): Pane not found in visible panes" << std::endl; Chris@127: } Chris@127: Chris@127: void Chris@127: PaneStack::showPane(Pane *pane) Chris@127: { Chris@127: std::vector::iterator i = m_hiddenPanes.begin(); Chris@127: Chris@127: while (i != m_hiddenPanes.end()) { Chris@127: if (i->pane == pane) { Chris@127: m_panes.push_back(*i); Chris@127: m_hiddenPanes.erase(i); Chris@127: QWidget *pw = dynamic_cast(pane->parent()); Chris@127: if (pw) pw->show(); Chris@127: Chris@127: //!!! update current pane Chris@127: Chris@127: return; Chris@127: } Chris@127: ++i; Chris@127: } Chris@127: Chris@127: std::cerr << "WARNING: PaneStack::showPane(" << pane << "): Pane not found in hidden panes" << std::endl; Chris@127: } Chris@127: Chris@127: void Chris@127: PaneStack::setCurrentPane(Pane *pane) // may be null Chris@127: { Chris@127: if (m_currentPane == pane) return; Chris@127: Chris@127: std::vector::iterator i = m_panes.begin(); Chris@127: Chris@127: // We used to do this by setting the foreground and background Chris@127: // role, but it seems the background role is ignored and the Chris@127: // background drawn transparent in Qt 4.1 -- I can't quite see why Chris@127: Chris@127: QPixmap selectedMap(1, 1); Chris@127: selectedMap.fill(QApplication::palette().color(QPalette::Foreground)); Chris@127: Chris@127: QPixmap unselectedMap(1, 1); Chris@127: unselectedMap.fill(QApplication::palette().color(QPalette::Background)); Chris@127: Chris@127: bool found = false; Chris@127: Chris@127: while (i != m_panes.end()) { Chris@127: if (i->pane == pane) { Chris@127: i->currentIndicator->setPixmap(selectedMap); Chris@179: if (m_layoutStyle != PropertyStackPerPaneLayout) { Chris@127: m_propertyStackStack->setCurrentWidget(i->propertyStack); Chris@127: } Chris@127: found = true; Chris@127: } else { Chris@127: i->currentIndicator->setPixmap(unselectedMap); Chris@127: } Chris@127: ++i; Chris@127: } Chris@127: Chris@127: if (found || pane == 0) { Chris@127: m_currentPane = pane; Chris@127: emit currentPaneChanged(m_currentPane); Chris@127: } else { Chris@127: std::cerr << "WARNING: PaneStack::setCurrentPane(" << pane << "): pane is not a visible pane in this stack" << std::endl; Chris@127: } Chris@127: } Chris@127: Chris@127: void Chris@127: PaneStack::setCurrentLayer(Pane *pane, Layer *layer) // may be null Chris@127: { Chris@127: setCurrentPane(pane); Chris@127: Chris@127: if (m_currentPane) { Chris@127: Chris@127: std::vector::iterator i = m_panes.begin(); Chris@127: Chris@127: while (i != m_panes.end()) { Chris@127: Chris@127: if (i->pane == pane) { Chris@127: PropertyStack *stack = dynamic_cast Chris@127: (i->propertyStack); Chris@127: if (stack) { Chris@127: if (stack->containsContainer(layer)) { Chris@127: stack->setCurrentIndex(stack->getContainerIndex(layer)); Chris@127: emit currentLayerChanged(pane, layer); Chris@127: } else { Chris@127: stack->setCurrentIndex Chris@127: (stack->getContainerIndex Chris@127: (pane->getPropertyContainer(0))); Chris@127: emit currentLayerChanged(pane, 0); Chris@127: } Chris@127: } Chris@127: break; Chris@127: } Chris@127: ++i; Chris@127: } Chris@127: } Chris@127: } Chris@127: Chris@127: Pane * Chris@127: PaneStack::getCurrentPane() Chris@127: { Chris@127: return m_currentPane; Chris@127: } Chris@127: Chris@127: void Chris@127: PaneStack::propertyContainerAdded(PropertyContainer *) Chris@127: { Chris@127: sizePropertyStacks(); Chris@127: } Chris@127: Chris@127: void Chris@127: PaneStack::propertyContainerRemoved(PropertyContainer *) Chris@127: { Chris@127: sizePropertyStacks(); Chris@127: } Chris@127: Chris@127: void Chris@127: PaneStack::propertyContainerSelected(View *client, PropertyContainer *pc) Chris@127: { Chris@127: std::vector::iterator i = m_panes.begin(); Chris@127: Chris@127: while (i != m_panes.end()) { Chris@127: PropertyStack *stack = dynamic_cast(i->propertyStack); Chris@127: if (stack && Chris@127: stack->getClient() == client && Chris@127: stack->containsContainer(pc)) { Chris@127: setCurrentPane(i->pane); Chris@127: break; Chris@127: } Chris@127: ++i; Chris@127: } Chris@127: Chris@127: Layer *layer = dynamic_cast(pc); Chris@127: if (layer) emit currentLayerChanged(m_currentPane, layer); Chris@127: else emit currentLayerChanged(m_currentPane, 0); Chris@127: } Chris@127: Chris@127: void Chris@190: PaneStack::viewSelected(View *v) Chris@190: { Chris@190: Pane *p = dynamic_cast(v); Chris@190: if (p) setCurrentPane(p); Chris@190: } Chris@190: Chris@190: void Chris@127: PaneStack::paneInteractedWith() Chris@127: { Chris@127: Pane *pane = dynamic_cast(sender()); Chris@127: if (!pane) return; Chris@127: setCurrentPane(pane); Chris@127: } Chris@127: Chris@127: void Chris@127: PaneStack::rightButtonMenuRequested(QPoint position) Chris@127: { Chris@127: Pane *pane = dynamic_cast(sender()); Chris@127: if (!pane) return; Chris@127: emit rightButtonMenuRequested(pane, position); Chris@127: } Chris@127: Chris@127: void Chris@127: PaneStack::sizePropertyStacks() Chris@127: { Chris@127: int maxMinWidth = 0; Chris@127: Chris@235: if (m_propertyStackMinWidth > 0) maxMinWidth = m_propertyStackMinWidth; Chris@235: Chris@127: for (size_t i = 0; i < m_panes.size(); ++i) { Chris@127: if (!m_panes[i].propertyStack) continue; Chris@127: // std::cerr << "PaneStack::sizePropertyStacks: " << i << ": min " Chris@127: // << m_panes[i].propertyStack->minimumSizeHint().width() << ", current " Chris@127: // << m_panes[i].propertyStack->width() << std::endl; Chris@127: Chris@127: if (m_panes[i].propertyStack->minimumSizeHint().width() > maxMinWidth) { Chris@127: maxMinWidth = m_panes[i].propertyStack->minimumSizeHint().width(); Chris@127: } Chris@127: } Chris@127: Chris@127: // std::cerr << "PaneStack::sizePropertyStacks: max min width " << maxMinWidth << std::endl; Chris@127: Chris@238: //#ifdef Q_WS_MAC Chris@127: // This is necessary to compensate for cb->setMinimumSize(10, 10) Chris@127: // in PropertyBox in the Mac version (to avoid a mysterious crash) Chris@235: Chris@235: //!!! is this still necessary with qt4.2? Chris@238: // int setWidth = maxMinWidth * 3 / 2; Chris@238: //#else Chris@127: int setWidth = maxMinWidth; Chris@238: //#endif Chris@127: Chris@127: m_propertyStackStack->setMaximumWidth(setWidth + 10); Chris@127: Chris@127: for (size_t i = 0; i < m_panes.size(); ++i) { Chris@127: if (!m_panes[i].propertyStack) continue; Chris@127: m_panes[i].propertyStack->setMinimumWidth(setWidth); Chris@127: } Chris@180: Chris@180: emit propertyStacksResized(); Chris@127: } Chris@127: Chris@127: