annotate view/PaneStack.cpp @ 299:5c59c433b358

* Show colour swatch next to layer name in pane (if available) * Fix for incorrect layer name prefix handling (was making some layers appear to have the same model name in cases where the model names differed by the final character only)
author Chris Cannam
date Wed, 05 Sep 2007 15:17:15 +0000
parents 8acd30ed735c
children 6de6f78b13a1
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@247 34 //#define DEBUG_PANE_STACK 1
Chris@247 35
Chris@127 36 PaneStack::PaneStack(QWidget *parent, ViewManager *viewManager) :
Chris@127 37 QFrame(parent),
Chris@127 38 m_currentPane(0),
Chris@127 39 m_splitter(new QSplitter),
Chris@127 40 m_propertyStackStack(new QStackedWidget),
Chris@127 41 m_viewManager(viewManager),
Chris@127 42 m_layoutStyle(PropertyStackPerPaneLayout)
Chris@127 43 {
Chris@127 44 QHBoxLayout *layout = new QHBoxLayout;
Chris@127 45 layout->setMargin(0);
Chris@127 46 layout->setSpacing(0);
Chris@127 47
Chris@127 48 m_splitter->setOrientation(Qt::Vertical);
Chris@127 49 m_splitter->setOpaqueResize(false);
Chris@127 50
Chris@127 51 layout->addWidget(m_splitter);
Chris@127 52 layout->setStretchFactor(m_splitter, 1);
Chris@127 53 layout->addWidget(m_propertyStackStack);
Chris@127 54 m_propertyStackStack->hide();
Chris@127 55
Chris@127 56 setLayout(layout);
Chris@127 57 }
Chris@127 58
Chris@127 59 Pane *
Chris@127 60 PaneStack::addPane(bool suppressPropertyBox)
Chris@127 61 {
Chris@127 62 QFrame *frame = new QFrame;
Chris@127 63 QHBoxLayout *layout = new QHBoxLayout;
Chris@127 64 layout->setMargin(0);
Chris@127 65 layout->setSpacing(2);
Chris@127 66
Chris@127 67 QLabel *currentIndicator = new QLabel(frame);
Chris@127 68 currentIndicator->setFixedWidth(QPainter(this).fontMetrics().width("x"));
Chris@127 69 layout->addWidget(currentIndicator);
Chris@127 70 layout->setStretchFactor(currentIndicator, 1);
Chris@127 71 currentIndicator->setScaledContents(true);
Chris@127 72
Chris@127 73 Pane *pane = new Pane(frame);
Chris@127 74 pane->setViewManager(m_viewManager);
Chris@127 75 layout->addWidget(pane);
Chris@127 76 layout->setStretchFactor(pane, 10);
Chris@127 77
Chris@127 78 QWidget *properties = 0;
Chris@127 79 if (suppressPropertyBox) {
Chris@127 80 properties = new QFrame();
Chris@127 81 } else {
Chris@127 82 properties = new PropertyStack(frame, pane);
Chris@127 83 connect(properties, SIGNAL(propertyContainerSelected(View *, PropertyContainer *)),
Chris@127 84 this, SLOT(propertyContainerSelected(View *, PropertyContainer *)));
Chris@190 85 connect(properties, SIGNAL(viewSelected(View *)),
Chris@190 86 this, SLOT(viewSelected(View *)));
Chris@189 87 connect(properties, SIGNAL(contextHelpChanged(const QString &)),
Chris@189 88 this, SIGNAL(contextHelpChanged(const QString &)));
Chris@127 89 }
Chris@127 90 if (m_layoutStyle == PropertyStackPerPaneLayout) {
Chris@127 91 layout->addWidget(properties);
Chris@127 92 } else {
Chris@127 93 properties->setParent(m_propertyStackStack);
Chris@127 94 m_propertyStackStack->addWidget(properties);
Chris@127 95 }
Chris@127 96 layout->setStretchFactor(properties, 1);
Chris@127 97
Chris@127 98 PaneRec rec;
Chris@127 99 rec.pane = pane;
Chris@127 100 rec.propertyStack = properties;
Chris@127 101 rec.currentIndicator = currentIndicator;
Chris@127 102 rec.frame = frame;
Chris@127 103 rec.layout = layout;
Chris@127 104 m_panes.push_back(rec);
Chris@127 105
Chris@127 106 frame->setLayout(layout);
Chris@127 107 m_splitter->addWidget(frame);
Chris@127 108
Chris@127 109 connect(pane, SIGNAL(propertyContainerAdded(PropertyContainer *)),
Chris@127 110 this, SLOT(propertyContainerAdded(PropertyContainer *)));
Chris@127 111 connect(pane, SIGNAL(propertyContainerRemoved(PropertyContainer *)),
Chris@127 112 this, SLOT(propertyContainerRemoved(PropertyContainer *)));
Chris@127 113 connect(pane, SIGNAL(paneInteractedWith()),
Chris@127 114 this, SLOT(paneInteractedWith()));
Chris@127 115 connect(pane, SIGNAL(rightButtonMenuRequested(QPoint)),
Chris@127 116 this, SLOT(rightButtonMenuRequested(QPoint)));
Chris@127 117
Chris@271 118 emit paneAdded(pane);
Chris@271 119 emit paneAdded();
Chris@271 120
Chris@127 121 if (!m_currentPane) {
Chris@127 122 setCurrentPane(pane);
Chris@127 123 }
Chris@127 124
Chris@127 125 return pane;
Chris@127 126 }
Chris@127 127
Chris@127 128 void
Chris@235 129 PaneStack::setPropertyStackMinWidth(int mw)
Chris@235 130 {
Chris@235 131 for (std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@235 132 i != m_panes.end(); ++i) {
Chris@235 133 i->propertyStack->setMinimumWidth(mw);
Chris@235 134 }
Chris@235 135 m_propertyStackMinWidth = mw;
Chris@235 136 }
Chris@235 137
Chris@235 138 void
Chris@127 139 PaneStack::setLayoutStyle(LayoutStyle style)
Chris@127 140 {
Chris@127 141 if (style == m_layoutStyle) return;
Chris@127 142 m_layoutStyle = style;
Chris@127 143
Chris@127 144 std::vector<PaneRec>::iterator i;
Chris@127 145
Chris@127 146 switch (style) {
Chris@127 147
Chris@179 148 case NoPropertyStacks:
Chris@127 149 case SinglePropertyStackLayout:
Chris@127 150
Chris@127 151 for (i = m_panes.begin(); i != m_panes.end(); ++i) {
Chris@127 152 i->layout->removeWidget(i->propertyStack);
Chris@127 153 i->propertyStack->setParent(m_propertyStackStack);
Chris@127 154 m_propertyStackStack->addWidget(i->propertyStack);
Chris@127 155 }
Chris@179 156 m_propertyStackStack->setVisible(style != NoPropertyStacks);
Chris@127 157 break;
Chris@127 158
Chris@127 159 case PropertyStackPerPaneLayout:
Chris@127 160
Chris@127 161 for (i = m_panes.begin(); i != m_panes.end(); ++i) {
Chris@127 162 m_propertyStackStack->removeWidget(i->propertyStack);
Chris@127 163 i->propertyStack->setParent(i->frame);
Chris@127 164 i->layout->addWidget(i->propertyStack);
Chris@127 165 i->propertyStack->show();
Chris@127 166 }
Chris@127 167 m_propertyStackStack->hide();
Chris@127 168 break;
Chris@127 169 }
Chris@127 170 }
Chris@127 171
Chris@127 172 Pane *
Chris@127 173 PaneStack::getPane(int n)
Chris@127 174 {
Chris@277 175 if (n < m_panes.size()) {
Chris@277 176 return m_panes[n].pane;
Chris@277 177 } else {
Chris@277 178 return 0;
Chris@277 179 }
Chris@277 180 }
Chris@277 181
Chris@277 182 int
Chris@277 183 PaneStack::getPaneIndex(Pane *pane)
Chris@277 184 {
Chris@277 185 for (int i = 0; i < getPaneCount(); ++i) {
Chris@277 186 if (pane == getPane(i)) {
Chris@277 187 return i;
Chris@277 188 }
Chris@277 189 }
Chris@277 190 return -1;
Chris@127 191 }
Chris@127 192
Chris@127 193 Pane *
Chris@127 194 PaneStack::getHiddenPane(int n)
Chris@127 195 {
Chris@127 196 return m_hiddenPanes[n].pane;
Chris@127 197 }
Chris@127 198
Chris@127 199 void
Chris@127 200 PaneStack::deletePane(Pane *pane)
Chris@127 201 {
Chris@127 202 std::vector<PaneRec>::iterator i;
Chris@127 203 bool found = false;
Chris@127 204
Chris@127 205 for (i = m_panes.begin(); i != m_panes.end(); ++i) {
Chris@127 206 if (i->pane == pane) {
Chris@127 207 m_panes.erase(i);
Chris@127 208 found = true;
Chris@127 209 break;
Chris@127 210 }
Chris@127 211 }
Chris@127 212
Chris@127 213 if (!found) {
Chris@127 214
Chris@127 215 for (i = m_hiddenPanes.begin(); i != m_hiddenPanes.end(); ++i) {
Chris@127 216 if (i->pane == pane) {
Chris@127 217 m_hiddenPanes.erase(i);
Chris@127 218 found = true;
Chris@127 219 break;
Chris@127 220 }
Chris@127 221 }
Chris@127 222
Chris@127 223 if (!found) {
Chris@127 224 std::cerr << "WARNING: PaneStack::deletePane(" << pane << "): Pane not found in visible or hidden panes, not deleting" << std::endl;
Chris@127 225 return;
Chris@127 226 }
Chris@127 227 }
Chris@127 228
Chris@271 229 emit paneAboutToBeDeleted(pane);
Chris@271 230
Chris@127 231 delete pane->parent();
Chris@127 232
Chris@127 233 if (m_currentPane == pane) {
Chris@127 234 if (m_panes.size() > 0) {
Chris@127 235 setCurrentPane(m_panes[0].pane);
Chris@127 236 } else {
Chris@127 237 setCurrentPane(0);
Chris@127 238 }
Chris@127 239 }
Chris@271 240
Chris@271 241 emit paneDeleted();
Chris@127 242 }
Chris@127 243
Chris@127 244 int
Chris@127 245 PaneStack::getPaneCount() const
Chris@127 246 {
Chris@127 247 return m_panes.size();
Chris@127 248 }
Chris@127 249
Chris@127 250 int
Chris@127 251 PaneStack::getHiddenPaneCount() const
Chris@127 252 {
Chris@127 253 return m_hiddenPanes.size();
Chris@127 254 }
Chris@127 255
Chris@127 256 void
Chris@127 257 PaneStack::hidePane(Pane *pane)
Chris@127 258 {
Chris@127 259 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@127 260
Chris@127 261 while (i != m_panes.end()) {
Chris@127 262 if (i->pane == pane) {
Chris@127 263
Chris@127 264 m_hiddenPanes.push_back(*i);
Chris@127 265 m_panes.erase(i);
Chris@127 266
Chris@127 267 QWidget *pw = dynamic_cast<QWidget *>(pane->parent());
Chris@127 268 if (pw) pw->hide();
Chris@127 269
Chris@127 270 if (m_currentPane == pane) {
Chris@127 271 if (m_panes.size() > 0) {
Chris@127 272 setCurrentPane(m_panes[0].pane);
Chris@127 273 } else {
Chris@127 274 setCurrentPane(0);
Chris@127 275 }
Chris@127 276 }
Chris@127 277
Chris@127 278 return;
Chris@127 279 }
Chris@127 280 ++i;
Chris@127 281 }
Chris@127 282
Chris@127 283 std::cerr << "WARNING: PaneStack::hidePane(" << pane << "): Pane not found in visible panes" << std::endl;
Chris@127 284 }
Chris@127 285
Chris@127 286 void
Chris@127 287 PaneStack::showPane(Pane *pane)
Chris@127 288 {
Chris@127 289 std::vector<PaneRec>::iterator i = m_hiddenPanes.begin();
Chris@127 290
Chris@127 291 while (i != m_hiddenPanes.end()) {
Chris@127 292 if (i->pane == pane) {
Chris@127 293 m_panes.push_back(*i);
Chris@127 294 m_hiddenPanes.erase(i);
Chris@127 295 QWidget *pw = dynamic_cast<QWidget *>(pane->parent());
Chris@127 296 if (pw) pw->show();
Chris@127 297
Chris@127 298 //!!! update current pane
Chris@127 299
Chris@127 300 return;
Chris@127 301 }
Chris@127 302 ++i;
Chris@127 303 }
Chris@127 304
Chris@127 305 std::cerr << "WARNING: PaneStack::showPane(" << pane << "): Pane not found in hidden panes" << std::endl;
Chris@127 306 }
Chris@127 307
Chris@127 308 void
Chris@127 309 PaneStack::setCurrentPane(Pane *pane) // may be null
Chris@127 310 {
Chris@127 311 if (m_currentPane == pane) return;
Chris@127 312
Chris@127 313 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@127 314
Chris@127 315 // We used to do this by setting the foreground and background
Chris@127 316 // role, but it seems the background role is ignored and the
Chris@127 317 // background drawn transparent in Qt 4.1 -- I can't quite see why
Chris@127 318
Chris@127 319 QPixmap selectedMap(1, 1);
Chris@127 320 selectedMap.fill(QApplication::palette().color(QPalette::Foreground));
Chris@127 321
Chris@127 322 QPixmap unselectedMap(1, 1);
Chris@127 323 unselectedMap.fill(QApplication::palette().color(QPalette::Background));
Chris@127 324
Chris@127 325 bool found = false;
Chris@127 326
Chris@127 327 while (i != m_panes.end()) {
Chris@127 328 if (i->pane == pane) {
Chris@127 329 i->currentIndicator->setPixmap(selectedMap);
Chris@179 330 if (m_layoutStyle != PropertyStackPerPaneLayout) {
Chris@127 331 m_propertyStackStack->setCurrentWidget(i->propertyStack);
Chris@127 332 }
Chris@127 333 found = true;
Chris@127 334 } else {
Chris@127 335 i->currentIndicator->setPixmap(unselectedMap);
Chris@127 336 }
Chris@127 337 ++i;
Chris@127 338 }
Chris@127 339
Chris@127 340 if (found || pane == 0) {
Chris@127 341 m_currentPane = pane;
Chris@127 342 emit currentPaneChanged(m_currentPane);
Chris@127 343 } else {
Chris@127 344 std::cerr << "WARNING: PaneStack::setCurrentPane(" << pane << "): pane is not a visible pane in this stack" << std::endl;
Chris@127 345 }
Chris@127 346 }
Chris@127 347
Chris@127 348 void
Chris@127 349 PaneStack::setCurrentLayer(Pane *pane, Layer *layer) // may be null
Chris@127 350 {
Chris@127 351 setCurrentPane(pane);
Chris@127 352
Chris@127 353 if (m_currentPane) {
Chris@127 354
Chris@127 355 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@127 356
Chris@127 357 while (i != m_panes.end()) {
Chris@127 358
Chris@127 359 if (i->pane == pane) {
Chris@127 360 PropertyStack *stack = dynamic_cast<PropertyStack *>
Chris@127 361 (i->propertyStack);
Chris@127 362 if (stack) {
Chris@127 363 if (stack->containsContainer(layer)) {
Chris@127 364 stack->setCurrentIndex(stack->getContainerIndex(layer));
Chris@127 365 emit currentLayerChanged(pane, layer);
Chris@127 366 } else {
Chris@127 367 stack->setCurrentIndex
Chris@127 368 (stack->getContainerIndex
Chris@127 369 (pane->getPropertyContainer(0)));
Chris@127 370 emit currentLayerChanged(pane, 0);
Chris@127 371 }
Chris@127 372 }
Chris@127 373 break;
Chris@127 374 }
Chris@127 375 ++i;
Chris@127 376 }
Chris@127 377 }
Chris@127 378 }
Chris@127 379
Chris@127 380 Pane *
Chris@127 381 PaneStack::getCurrentPane()
Chris@127 382 {
Chris@127 383 return m_currentPane;
Chris@127 384 }
Chris@127 385
Chris@127 386 void
Chris@127 387 PaneStack::propertyContainerAdded(PropertyContainer *)
Chris@127 388 {
Chris@127 389 sizePropertyStacks();
Chris@127 390 }
Chris@127 391
Chris@127 392 void
Chris@127 393 PaneStack::propertyContainerRemoved(PropertyContainer *)
Chris@127 394 {
Chris@127 395 sizePropertyStacks();
Chris@127 396 }
Chris@127 397
Chris@127 398 void
Chris@127 399 PaneStack::propertyContainerSelected(View *client, PropertyContainer *pc)
Chris@127 400 {
Chris@127 401 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@127 402
Chris@127 403 while (i != m_panes.end()) {
Chris@127 404 PropertyStack *stack = dynamic_cast<PropertyStack *>(i->propertyStack);
Chris@127 405 if (stack &&
Chris@127 406 stack->getClient() == client &&
Chris@127 407 stack->containsContainer(pc)) {
Chris@127 408 setCurrentPane(i->pane);
Chris@127 409 break;
Chris@127 410 }
Chris@127 411 ++i;
Chris@127 412 }
Chris@127 413
Chris@127 414 Layer *layer = dynamic_cast<Layer *>(pc);
Chris@127 415 if (layer) emit currentLayerChanged(m_currentPane, layer);
Chris@127 416 else emit currentLayerChanged(m_currentPane, 0);
Chris@127 417 }
Chris@127 418
Chris@127 419 void
Chris@190 420 PaneStack::viewSelected(View *v)
Chris@190 421 {
Chris@190 422 Pane *p = dynamic_cast<Pane *>(v);
Chris@190 423 if (p) setCurrentPane(p);
Chris@190 424 }
Chris@190 425
Chris@190 426 void
Chris@127 427 PaneStack::paneInteractedWith()
Chris@127 428 {
Chris@127 429 Pane *pane = dynamic_cast<Pane *>(sender());
Chris@127 430 if (!pane) return;
Chris@127 431 setCurrentPane(pane);
Chris@127 432 }
Chris@127 433
Chris@127 434 void
Chris@127 435 PaneStack::rightButtonMenuRequested(QPoint position)
Chris@127 436 {
Chris@127 437 Pane *pane = dynamic_cast<Pane *>(sender());
Chris@127 438 if (!pane) return;
Chris@127 439 emit rightButtonMenuRequested(pane, position);
Chris@127 440 }
Chris@127 441
Chris@127 442 void
Chris@127 443 PaneStack::sizePropertyStacks()
Chris@127 444 {
Chris@127 445 int maxMinWidth = 0;
Chris@127 446
Chris@235 447 if (m_propertyStackMinWidth > 0) maxMinWidth = m_propertyStackMinWidth;
Chris@235 448
Chris@127 449 for (size_t i = 0; i < m_panes.size(); ++i) {
Chris@127 450 if (!m_panes[i].propertyStack) continue;
Chris@247 451 #ifdef DEBUG_PANE_STACK
Chris@243 452 std::cerr << "PaneStack::sizePropertyStacks: " << i << ": min "
Chris@243 453 << m_panes[i].propertyStack->minimumSizeHint().width() << ", hint "
Chris@243 454 << m_panes[i].propertyStack->sizeHint().width() << ", current "
Chris@243 455 << m_panes[i].propertyStack->width() << std::endl;
Chris@247 456 #endif
Chris@127 457
Chris@246 458 if (m_panes[i].propertyStack->sizeHint().width() > maxMinWidth) {
Chris@246 459 maxMinWidth = m_panes[i].propertyStack->sizeHint().width();
Chris@127 460 }
Chris@127 461 }
Chris@127 462
Chris@247 463 #ifdef DEBUG_PANE_STACK
Chris@247 464 std::cerr << "PaneStack::sizePropertyStacks: max min width " << maxMinWidth << std::endl;
Chris@247 465 #endif
Chris@127 466
Chris@238 467 //#ifdef Q_WS_MAC
Chris@127 468 // This is necessary to compensate for cb->setMinimumSize(10, 10)
Chris@127 469 // in PropertyBox in the Mac version (to avoid a mysterious crash)
Chris@247 470 // ... no longer necessary with qt4.2
Chris@238 471 // int setWidth = maxMinWidth * 3 / 2;
Chris@238 472 //#else
Chris@127 473 int setWidth = maxMinWidth;
Chris@238 474 //#endif
Chris@127 475
Chris@127 476 m_propertyStackStack->setMaximumWidth(setWidth + 10);
Chris@127 477
Chris@127 478 for (size_t i = 0; i < m_panes.size(); ++i) {
Chris@127 479 if (!m_panes[i].propertyStack) continue;
Chris@127 480 m_panes[i].propertyStack->setMinimumWidth(setWidth);
Chris@127 481 }
Chris@180 482
Chris@180 483 emit propertyStacksResized();
Chris@127 484 }
Chris@127 485
Chris@127 486