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