annotate view/PaneStack.cpp @ 150:b1a3a9400284

* Add a bit of resistance to pane dragging so as to make it harder to inadvertently drag in the other axis from the one you intended
author Chris Cannam
date Fri, 22 Sep 2006 16:46:10 +0000
parents 33929e0c3c6b
children 6a0d54f3f21a
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@127 8 This file copyright 2006 Chris Cannam.
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@127 129 case SinglePropertyStackLayout:
Chris@127 130
Chris@127 131 for (i = m_panes.begin(); i != m_panes.end(); ++i) {
Chris@127 132 i->layout->removeWidget(i->propertyStack);
Chris@127 133 i->propertyStack->setParent(m_propertyStackStack);
Chris@127 134 m_propertyStackStack->addWidget(i->propertyStack);
Chris@127 135 }
Chris@127 136 m_propertyStackStack->show();
Chris@127 137 break;
Chris@127 138
Chris@127 139 case PropertyStackPerPaneLayout:
Chris@127 140
Chris@127 141 for (i = m_panes.begin(); i != m_panes.end(); ++i) {
Chris@127 142 m_propertyStackStack->removeWidget(i->propertyStack);
Chris@127 143 i->propertyStack->setParent(i->frame);
Chris@127 144 i->layout->addWidget(i->propertyStack);
Chris@127 145 i->propertyStack->show();
Chris@127 146 }
Chris@127 147 m_propertyStackStack->hide();
Chris@127 148 break;
Chris@127 149 }
Chris@127 150 }
Chris@127 151
Chris@127 152 Pane *
Chris@127 153 PaneStack::getPane(int n)
Chris@127 154 {
Chris@127 155 return m_panes[n].pane;
Chris@127 156 }
Chris@127 157
Chris@127 158 Pane *
Chris@127 159 PaneStack::getHiddenPane(int n)
Chris@127 160 {
Chris@127 161 return m_hiddenPanes[n].pane;
Chris@127 162 }
Chris@127 163
Chris@127 164 void
Chris@127 165 PaneStack::deletePane(Pane *pane)
Chris@127 166 {
Chris@127 167 std::vector<PaneRec>::iterator i;
Chris@127 168 bool found = false;
Chris@127 169
Chris@127 170 for (i = m_panes.begin(); i != m_panes.end(); ++i) {
Chris@127 171 if (i->pane == pane) {
Chris@127 172 m_panes.erase(i);
Chris@127 173 found = true;
Chris@127 174 break;
Chris@127 175 }
Chris@127 176 }
Chris@127 177
Chris@127 178 if (!found) {
Chris@127 179
Chris@127 180 for (i = m_hiddenPanes.begin(); i != m_hiddenPanes.end(); ++i) {
Chris@127 181 if (i->pane == pane) {
Chris@127 182 m_hiddenPanes.erase(i);
Chris@127 183 found = true;
Chris@127 184 break;
Chris@127 185 }
Chris@127 186 }
Chris@127 187
Chris@127 188 if (!found) {
Chris@127 189 std::cerr << "WARNING: PaneStack::deletePane(" << pane << "): Pane not found in visible or hidden panes, not deleting" << std::endl;
Chris@127 190 return;
Chris@127 191 }
Chris@127 192 }
Chris@127 193
Chris@127 194 delete pane->parent();
Chris@127 195
Chris@127 196 if (m_currentPane == pane) {
Chris@127 197 if (m_panes.size() > 0) {
Chris@127 198 setCurrentPane(m_panes[0].pane);
Chris@127 199 } else {
Chris@127 200 setCurrentPane(0);
Chris@127 201 }
Chris@127 202 }
Chris@127 203 }
Chris@127 204
Chris@127 205 int
Chris@127 206 PaneStack::getPaneCount() const
Chris@127 207 {
Chris@127 208 return m_panes.size();
Chris@127 209 }
Chris@127 210
Chris@127 211 int
Chris@127 212 PaneStack::getHiddenPaneCount() const
Chris@127 213 {
Chris@127 214 return m_hiddenPanes.size();
Chris@127 215 }
Chris@127 216
Chris@127 217 void
Chris@127 218 PaneStack::hidePane(Pane *pane)
Chris@127 219 {
Chris@127 220 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@127 221
Chris@127 222 while (i != m_panes.end()) {
Chris@127 223 if (i->pane == pane) {
Chris@127 224
Chris@127 225 m_hiddenPanes.push_back(*i);
Chris@127 226 m_panes.erase(i);
Chris@127 227
Chris@127 228 QWidget *pw = dynamic_cast<QWidget *>(pane->parent());
Chris@127 229 if (pw) pw->hide();
Chris@127 230
Chris@127 231 if (m_currentPane == pane) {
Chris@127 232 if (m_panes.size() > 0) {
Chris@127 233 setCurrentPane(m_panes[0].pane);
Chris@127 234 } else {
Chris@127 235 setCurrentPane(0);
Chris@127 236 }
Chris@127 237 }
Chris@127 238
Chris@127 239 return;
Chris@127 240 }
Chris@127 241 ++i;
Chris@127 242 }
Chris@127 243
Chris@127 244 std::cerr << "WARNING: PaneStack::hidePane(" << pane << "): Pane not found in visible panes" << std::endl;
Chris@127 245 }
Chris@127 246
Chris@127 247 void
Chris@127 248 PaneStack::showPane(Pane *pane)
Chris@127 249 {
Chris@127 250 std::vector<PaneRec>::iterator i = m_hiddenPanes.begin();
Chris@127 251
Chris@127 252 while (i != m_hiddenPanes.end()) {
Chris@127 253 if (i->pane == pane) {
Chris@127 254 m_panes.push_back(*i);
Chris@127 255 m_hiddenPanes.erase(i);
Chris@127 256 QWidget *pw = dynamic_cast<QWidget *>(pane->parent());
Chris@127 257 if (pw) pw->show();
Chris@127 258
Chris@127 259 //!!! update current pane
Chris@127 260
Chris@127 261 return;
Chris@127 262 }
Chris@127 263 ++i;
Chris@127 264 }
Chris@127 265
Chris@127 266 std::cerr << "WARNING: PaneStack::showPane(" << pane << "): Pane not found in hidden panes" << std::endl;
Chris@127 267 }
Chris@127 268
Chris@127 269 void
Chris@127 270 PaneStack::setCurrentPane(Pane *pane) // may be null
Chris@127 271 {
Chris@127 272 if (m_currentPane == pane) return;
Chris@127 273
Chris@127 274 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@127 275
Chris@127 276 // We used to do this by setting the foreground and background
Chris@127 277 // role, but it seems the background role is ignored and the
Chris@127 278 // background drawn transparent in Qt 4.1 -- I can't quite see why
Chris@127 279
Chris@127 280 QPixmap selectedMap(1, 1);
Chris@127 281 selectedMap.fill(QApplication::palette().color(QPalette::Foreground));
Chris@127 282
Chris@127 283 QPixmap unselectedMap(1, 1);
Chris@127 284 unselectedMap.fill(QApplication::palette().color(QPalette::Background));
Chris@127 285
Chris@127 286 bool found = false;
Chris@127 287
Chris@127 288 while (i != m_panes.end()) {
Chris@127 289 if (i->pane == pane) {
Chris@127 290 i->currentIndicator->setPixmap(selectedMap);
Chris@127 291 if (m_layoutStyle == SinglePropertyStackLayout) {
Chris@127 292 m_propertyStackStack->setCurrentWidget(i->propertyStack);
Chris@127 293 }
Chris@127 294 found = true;
Chris@127 295 } else {
Chris@127 296 i->currentIndicator->setPixmap(unselectedMap);
Chris@127 297 }
Chris@127 298 ++i;
Chris@127 299 }
Chris@127 300
Chris@127 301 if (found || pane == 0) {
Chris@127 302 m_currentPane = pane;
Chris@127 303 emit currentPaneChanged(m_currentPane);
Chris@127 304 } else {
Chris@127 305 std::cerr << "WARNING: PaneStack::setCurrentPane(" << pane << "): pane is not a visible pane in this stack" << std::endl;
Chris@127 306 }
Chris@127 307 }
Chris@127 308
Chris@127 309 void
Chris@127 310 PaneStack::setCurrentLayer(Pane *pane, Layer *layer) // may be null
Chris@127 311 {
Chris@127 312 setCurrentPane(pane);
Chris@127 313
Chris@127 314 if (m_currentPane) {
Chris@127 315
Chris@127 316 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@127 317
Chris@127 318 while (i != m_panes.end()) {
Chris@127 319
Chris@127 320 if (i->pane == pane) {
Chris@127 321 PropertyStack *stack = dynamic_cast<PropertyStack *>
Chris@127 322 (i->propertyStack);
Chris@127 323 if (stack) {
Chris@127 324 if (stack->containsContainer(layer)) {
Chris@127 325 stack->setCurrentIndex(stack->getContainerIndex(layer));
Chris@127 326 emit currentLayerChanged(pane, layer);
Chris@127 327 } else {
Chris@127 328 stack->setCurrentIndex
Chris@127 329 (stack->getContainerIndex
Chris@127 330 (pane->getPropertyContainer(0)));
Chris@127 331 emit currentLayerChanged(pane, 0);
Chris@127 332 }
Chris@127 333 }
Chris@127 334 break;
Chris@127 335 }
Chris@127 336 ++i;
Chris@127 337 }
Chris@127 338 }
Chris@127 339 }
Chris@127 340
Chris@127 341 Pane *
Chris@127 342 PaneStack::getCurrentPane()
Chris@127 343 {
Chris@127 344 return m_currentPane;
Chris@127 345 }
Chris@127 346
Chris@127 347 void
Chris@127 348 PaneStack::propertyContainerAdded(PropertyContainer *)
Chris@127 349 {
Chris@127 350 sizePropertyStacks();
Chris@127 351 }
Chris@127 352
Chris@127 353 void
Chris@127 354 PaneStack::propertyContainerRemoved(PropertyContainer *)
Chris@127 355 {
Chris@127 356 sizePropertyStacks();
Chris@127 357 }
Chris@127 358
Chris@127 359 void
Chris@127 360 PaneStack::propertyContainerSelected(View *client, PropertyContainer *pc)
Chris@127 361 {
Chris@127 362 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@127 363
Chris@127 364 while (i != m_panes.end()) {
Chris@127 365 PropertyStack *stack = dynamic_cast<PropertyStack *>(i->propertyStack);
Chris@127 366 if (stack &&
Chris@127 367 stack->getClient() == client &&
Chris@127 368 stack->containsContainer(pc)) {
Chris@127 369 setCurrentPane(i->pane);
Chris@127 370 break;
Chris@127 371 }
Chris@127 372 ++i;
Chris@127 373 }
Chris@127 374
Chris@127 375 Layer *layer = dynamic_cast<Layer *>(pc);
Chris@127 376 if (layer) emit currentLayerChanged(m_currentPane, layer);
Chris@127 377 else emit currentLayerChanged(m_currentPane, 0);
Chris@127 378 }
Chris@127 379
Chris@127 380 void
Chris@127 381 PaneStack::paneInteractedWith()
Chris@127 382 {
Chris@127 383 Pane *pane = dynamic_cast<Pane *>(sender());
Chris@127 384 if (!pane) return;
Chris@127 385 setCurrentPane(pane);
Chris@127 386 }
Chris@127 387
Chris@127 388 void
Chris@127 389 PaneStack::rightButtonMenuRequested(QPoint position)
Chris@127 390 {
Chris@127 391 Pane *pane = dynamic_cast<Pane *>(sender());
Chris@127 392 if (!pane) return;
Chris@127 393 emit rightButtonMenuRequested(pane, position);
Chris@127 394 }
Chris@127 395
Chris@127 396 void
Chris@127 397 PaneStack::sizePropertyStacks()
Chris@127 398 {
Chris@127 399 int maxMinWidth = 0;
Chris@127 400
Chris@127 401 for (size_t i = 0; i < m_panes.size(); ++i) {
Chris@127 402 if (!m_panes[i].propertyStack) continue;
Chris@127 403 // std::cerr << "PaneStack::sizePropertyStacks: " << i << ": min "
Chris@127 404 // << m_panes[i].propertyStack->minimumSizeHint().width() << ", current "
Chris@127 405 // << m_panes[i].propertyStack->width() << std::endl;
Chris@127 406
Chris@127 407 if (m_panes[i].propertyStack->minimumSizeHint().width() > maxMinWidth) {
Chris@127 408 maxMinWidth = m_panes[i].propertyStack->minimumSizeHint().width();
Chris@127 409 }
Chris@127 410 }
Chris@127 411
Chris@127 412 // std::cerr << "PaneStack::sizePropertyStacks: max min width " << maxMinWidth << std::endl;
Chris@127 413
Chris@127 414 #ifdef Q_WS_MAC
Chris@127 415 // This is necessary to compensate for cb->setMinimumSize(10, 10)
Chris@127 416 // in PropertyBox in the Mac version (to avoid a mysterious crash)
Chris@127 417 int setWidth = maxMinWidth * 3 / 2;
Chris@127 418 #else
Chris@127 419 int setWidth = maxMinWidth;
Chris@127 420 #endif
Chris@127 421
Chris@127 422 m_propertyStackStack->setMaximumWidth(setWidth + 10);
Chris@127 423
Chris@127 424 for (size_t i = 0; i < m_panes.size(); ++i) {
Chris@127 425 if (!m_panes[i].propertyStack) continue;
Chris@127 426 m_panes[i].propertyStack->setMinimumWidth(setWidth);
Chris@127 427 }
Chris@127 428 }
Chris@127 429
Chris@127 430
Chris@127 431 #ifdef INCLUDE_MOCFILES
Chris@127 432 #include "PaneStack.moc.cpp"
Chris@127 433 #endif
Chris@127 434