annotate view/PaneStack.cpp @ 183:5f86ae638b04

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