changeset 1526:0f1601d870db

Rework PaneStack so that the options that generally aren't (or can't be) changed after construction are supplied to the constructor instead of being set through setter methods. This is a more sensible way of doing things in general, but also a workaround for https://code.soundsoftware.ac.uk/issues/1930, a problem that arises when reinitialising hidden property boxes in a context in which they will never be visible at all.
author Chris Cannam
date Fri, 04 Oct 2019 13:51:24 +0100
parents 284a38c43721
children 88fcbc4d93dd
files view/PaneStack.cpp view/PaneStack.h
diffstat 2 files changed, 76 insertions(+), 107 deletions(-) [+]
line wrap: on
line diff
--- a/view/PaneStack.cpp	Fri Oct 04 13:37:39 2019 +0100
+++ b/view/PaneStack.cpp	Fri Oct 04 13:51:24 2019 +0100
@@ -37,37 +37,47 @@
 
 //#define DEBUG_PANE_STACK 1
 
-PaneStack::PaneStack(QWidget *parent, ViewManager *viewManager) :
+PaneStack::PaneStack(QWidget *parent,
+                     ViewManager *viewManager,
+                     int options) :
     QFrame(parent),
     m_currentPane(nullptr),
-    m_showAccessories(true),
-    m_showCloseButtonOnFirstPane(true),
-    m_showAlignmentViews(false),
-    m_splitter(new QSplitter),
-    m_autoResizeStack(new QWidget),
+    m_options(options),
+    m_splitter(nullptr),
+    m_autoResizeStack(nullptr),
     m_propertyStackStack(new QStackedWidget),
     m_viewManager(viewManager),
     m_propertyStackMinWidth(100),
-    m_layoutStyle(PropertyStackPerPaneLayout),
-    m_resizeMode(UserResizeable)
+    m_layoutStyle(PropertyStackPerPaneLayout)
 {
     QHBoxLayout *layout = new QHBoxLayout;
     layout->setMargin(0);
     layout->setSpacing(0);
 
-    m_autoResizeLayout = new QVBoxLayout;
-    m_autoResizeLayout->setMargin(0);
-    m_autoResizeLayout->setSpacing(0);
-    m_autoResizeStack->setLayout(m_autoResizeLayout);
-    m_autoResizeStack->hide();
-    layout->addWidget(m_autoResizeStack);
-    layout->setStretchFactor(m_autoResizeStack, 1);
+    if (m_options & int(Option::NoUserResize)) {
 
-    m_splitter->setOrientation(Qt::Vertical);
-    m_splitter->setOpaqueResize(false);
-    m_splitter->show();
-    layout->addWidget(m_splitter);
-    layout->setStretchFactor(m_splitter, 1);
+        m_autoResizeStack = new QWidget;
+        m_autoResizeLayout = new QVBoxLayout;
+        m_autoResizeLayout->setMargin(0);
+        m_autoResizeLayout->setSpacing(0);
+        m_autoResizeStack->setLayout(m_autoResizeLayout);
+        m_autoResizeStack->hide();
+        layout->addWidget(m_autoResizeStack);
+        layout->setStretchFactor(m_autoResizeStack, 1);
+
+    } else {
+    
+        m_splitter = new QSplitter;
+        m_splitter->setOrientation(Qt::Vertical);
+        m_splitter->setOpaqueResize(false);
+        m_splitter->show();
+        layout->addWidget(m_splitter);
+        layout->setStretchFactor(m_splitter, 1);
+    }
+
+    if (m_options & int(Option::NoPropertyStacks)) {
+        m_layoutStyle = HiddenPropertyStacksLayout;
+    }
     
     m_propertyStackStack->hide();
     layout->addWidget(m_propertyStackStack);
@@ -75,38 +85,15 @@
     setLayout(layout);
 }
 
-void
-PaneStack::setShowPaneAccessories(bool show)
-{
-    m_showAccessories = show;
-}
-
-void
-PaneStack::setShowCloseButtonOnFirstPane(bool show)
-{
-    m_showCloseButtonOnFirstPane = show;
-}
-
-void
-PaneStack::setShowAlignmentViews(bool show)
-{
-    m_showAlignmentViews = show;
-    // each alignment view shows alignment between the pane above and
-    // the pane it is attached to: so pane 0 doesn't have a visible one
-    for (int i = 1; in_range_for(m_panes, i); ++i) {
-        m_panes[i].alignmentView->setVisible(m_showAlignmentViews);
-    }
-}
-
 Pane *
-PaneStack::addPane(bool suppressPropertyBox)
+PaneStack::addPane()
 {
     QFrame *frame = new QFrame;
 
     QGridLayout *layout = new QGridLayout;
     layout->setMargin(0);
     layout->setHorizontalSpacing(m_viewManager->scalePixelSize(2));
-    if (m_showAlignmentViews) {
+    if (m_options & int(Option::ShowAlignmentViews)) {
         layout->setVerticalSpacing(0);
     } else {
         layout->setVerticalSpacing(m_viewManager->scalePixelSize(2));
@@ -122,8 +109,8 @@
     xButton->setIcon(IconLoader().load("cross"));
     xButton->setFixedSize(QSize(16, 16));
     xButton->setFlat(true);
-    xButton->setVisible(m_showAccessories);
-    if (m_panes.empty() && !m_showCloseButtonOnFirstPane) {
+    xButton->setVisible(!(m_options & int(Option::NoPaneAccessories)));
+    if (m_panes.empty() && (m_options & int(Option::NoCloseOnFirstPane))) {
         xButton->setVisible(false);
     }
     layout->addWidget(xButton, 1, 0);
@@ -136,7 +123,7 @@
     currentIndicator->setMinimumWidth(16);
     currentIndicator->setMinimumHeight(16);
     currentIndicator->setScaledContents(true);
-    currentIndicator->setVisible(m_showAccessories);
+    currentIndicator->setVisible(!(m_options & int(Option::NoPaneAccessories)));
 
     sv_frame_t initialCentreFrame = -1;
     if (!m_panes.empty()) {
@@ -153,7 +140,7 @@
     layout->setColumnStretch(1, 20);
 
     QWidget *properties = nullptr;
-    if (suppressPropertyBox) {
+    if (m_options & int(Option::NoPropertyStacks)) {
         properties = new QFrame();
     } else {
         properties = new PropertyStack(frame, pane);
@@ -184,11 +171,11 @@
 
     frame->setLayout(layout);
 
-    if (m_resizeMode == UserResizeable) {
-        m_splitter->addWidget(frame);
-    } else {
+    if (m_options & int(Option::NoUserResize)) {
         m_autoResizeLayout->addWidget(frame);
         frame->adjustSize();
+    } else {
+        m_splitter->addWidget(frame);
     }
 
     connect(pane, SIGNAL(propertyContainerAdded(PropertyContainer *)),
@@ -223,12 +210,15 @@
 PaneStack::relinkAlignmentViews()
 {
     if (m_panes.empty()) return;
-    if (!m_showAlignmentViews) return;
     m_panes[0].alignmentView->hide();
     for (int i = 1; in_range_for(m_panes, i); ++i) {
-        m_panes[i].alignmentView->setViewAbove(m_panes[i-1].pane);
-        m_panes[i].alignmentView->setViewBelow(m_panes[i].pane);
-        m_panes[i].alignmentView->setVisible(true);
+        if (!(m_options & int(Option::ShowAlignmentViews))) {
+            m_panes[i].alignmentView->hide();
+        } else {
+            m_panes[i].alignmentView->setViewAbove(m_panes[i-1].pane);
+            m_panes[i].alignmentView->setViewBelow(m_panes[i].pane);
+            m_panes[i].alignmentView->show();
+        }
     }
 }
 
@@ -254,6 +244,11 @@
 void
 PaneStack::setLayoutStyle(LayoutStyle style)
 {
+    if (m_options & int(Option::NoPropertyStacks)) {
+        SVCERR << "NOTE: PaneStack::setLayoutStyle called on PaneStack with NoPropertyStacks option set - this does nothing, its style is always equivalent to HiddenPropertyStacksLayout" << endl;
+        return;
+    }
+    
     if (style == m_layoutStyle) return;
     m_layoutStyle = style;
 
@@ -261,7 +256,7 @@
 
     switch (style) {
 
-    case NoPropertyStacks:
+    case HiddenPropertyStacksLayout:
     case SinglePropertyStackLayout:
         
         for (i = m_panes.begin(); i != m_panes.end(); ++i) {
@@ -269,7 +264,7 @@
             i->propertyStack->setParent(m_propertyStackStack);
             m_propertyStackStack->addWidget(i->propertyStack);
         }
-        m_propertyStackStack->setVisible(style != NoPropertyStacks);
+        m_propertyStackStack->setVisible(style != HiddenPropertyStacksLayout);
         break;
 
     case PropertyStackPerPaneLayout:
@@ -393,10 +388,10 @@
     bool multi = (getPaneCount() > 1);
     for (std::vector<PaneRec>::iterator i = m_panes.begin();
          i != m_panes.end(); ++i) {
-        bool visible = (multi && m_showAccessories);
+        bool visible = (multi && !(m_options & int(Option::NoPaneAccessories)));
         bool xvisible = visible;
         if (i == m_panes.begin()) {
-            if (!m_showCloseButtonOnFirstPane) {
+            if (m_options & int(Option::NoCloseOnFirstPane)) {
                 xvisible = false;
             }
         }
@@ -689,7 +684,7 @@
 void
 PaneStack::sizePanesEqually()
 {
-    if (m_resizeMode == AutoResizeOnly) {
+    if (m_options & int(Option::NoUserResize)) {
         return;
     }
     
@@ -750,19 +745,3 @@
     m_splitter->setSizes(sizes);
 }
 
-void
-PaneStack::setResizeMode(ResizeMode mode)
-{
-    if (mode == UserResizeable) {
-        m_autoResizeStack->hide();
-        m_splitter->show();
-    } else {
-        m_autoResizeStack->show();
-        m_splitter->hide();
-    }
-    m_resizeMode = mode;
-
-    // we don't actually move any existing panes yet! let's do that
-    // only if we turn out to need it, shall we?
-}
-
--- a/view/PaneStack.h	Fri Oct 04 13:37:39 2019 +0100
+++ b/view/PaneStack.h	Fri Oct 04 13:51:24 2019 +0100
@@ -42,10 +42,23 @@
     Q_OBJECT
 
 public:
+    /// These options are for things that must be set on construction,
+    /// and can't be changed afterwards
+    enum class Option {
+        Default = 0x0,
+        NoUserResize = 0x1,       // Suppress resize handles, auto-size only
+        NoPropertyStacks = 0x2,   // Never create property stacks
+        NoPaneAccessories = 0x4,  // Suppress current-pane and close button
+        NoCloseOnFirstPane = 0x8, // Omit close button from the top pane
+        ShowAlignmentViews = 0x10 // Include AlignmentViews between panes
+    };
+    typedef int Options;
+    
     PaneStack(QWidget *parent,
-              ViewManager *viewManager);
+              ViewManager *viewManager,
+              Options options = 0);
 
-    Pane *addPane(bool suppressPropertyBox = false); // I own the returned value
+    Pane *addPane(); // I own the returned value
     void deletePane(Pane *pane); // Deletes the pane, but _not_ its layers
 
     int getPaneCount() const; // Returns only count of visible panes
@@ -62,8 +75,9 @@
     void setCurrentLayer(Pane *pane, Layer *layer);
     Pane *getCurrentPane();
 
+    /// Runtime-switchable layout style for property stacks
     enum LayoutStyle {
-        NoPropertyStacks = 0,
+        HiddenPropertyStacksLayout = 0,
         SinglePropertyStackLayout = 1,
         PropertyStackPerPaneLayout = 2
     };
@@ -71,28 +85,8 @@
     LayoutStyle getLayoutStyle() const { return m_layoutStyle; }
     void setLayoutStyle(LayoutStyle style);
 
-    enum ResizeMode {
-        UserResizeable = 0,
-        AutoResizeOnly = 1
-    };
-
-    ResizeMode getResizeMode() const { return m_resizeMode; }
-    void setResizeMode(ResizeMode);
-
-    // Set whether the current-pane indicators and close buttons are
-    // shown. The default is true.
-    void setShowPaneAccessories(bool show);
-
-    // Set whether a close button is shown on the first pane as well
-    // as others. (It may be reasonable to omit the close button from
-    // what is presumably the main pane in some applications.)  The
-    // default is true.
-    void setShowCloseButtonOnFirstPane(bool);
-
     void setPropertyStackMinWidth(int mw);
 
-    void setShowAlignmentViews(bool show);
-
     void sizePanesEqually();
 
 signals:
@@ -146,12 +140,9 @@
     std::vector<PaneRec> m_panes;
     std::vector<PaneRec> m_hiddenPanes;
 
-    bool m_showAccessories;
-    bool m_showCloseButtonOnFirstPane;
-    bool m_showAlignmentViews;
-
-    QSplitter *m_splitter; // constitutes the stack in UserResizeable mode
-    QWidget *m_autoResizeStack; // constitutes the stack in AutoResizeOnly mode
+    int m_options;
+    QSplitter *m_splitter; // constitutes the stack in default mode
+    QWidget *m_autoResizeStack; // constitutes the stack in NoUserResize mode
     QVBoxLayout *m_autoResizeLayout;
 
     QStackedWidget *m_propertyStackStack;
@@ -166,7 +157,6 @@
     void relinkAlignmentViews();
 
     LayoutStyle m_layoutStyle;
-    ResizeMode m_resizeMode;
 };
 
 #endif