annotate view/PaneStack.cpp @ 1613:fe9a643b83bf

Merge from branch csv-import-headers
author Chris Cannam
date Thu, 18 Jun 2020 13:45:11 +0100
parents d6976d231efb
children c6f5c822b10d
rev   line source
Chris@127 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@127 2
Chris@127 3 /*
Chris@127 4 Sonic Visualiser
Chris@127 5 An audio file viewer and annotation editor.
Chris@127 6 Centre for Digital Music, Queen Mary, University of London.
Chris@182 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@127 8
Chris@127 9 This program is free software; you can redistribute it and/or
Chris@127 10 modify it under the terms of the GNU General Public License as
Chris@127 11 published by the Free Software Foundation; either version 2 of the
Chris@127 12 License, or (at your option) any later version. See the file
Chris@127 13 COPYING included with this distribution for more information.
Chris@127 14 */
Chris@127 15
Chris@127 16 #include "PaneStack.h"
Chris@127 17
Chris@128 18 #include "Pane.h"
Chris@127 19 #include "widgets/PropertyStack.h"
Chris@323 20 #include "widgets/IconLoader.h"
Chris@500 21 #include "widgets/ClickableLabel.h"
Chris@128 22 #include "layer/Layer.h"
Chris@128 23 #include "ViewManager.h"
Chris@867 24 #include "AlignmentView.h"
Chris@127 25
Chris@127 26 #include <QApplication>
Chris@127 27 #include <QHBoxLayout>
Chris@323 28 #include <QVBoxLayout>
Chris@127 29 #include <QPainter>
Chris@127 30 #include <QPalette>
Chris@127 31 #include <QLabel>
Chris@323 32 #include <QPushButton>
Chris@127 33 #include <QSplitter>
Chris@127 34 #include <QStackedWidget>
Chris@1606 35 #include <QResizeEvent>
Chris@127 36
Chris@127 37 #include <iostream>
Chris@127 38
Chris@247 39 //#define DEBUG_PANE_STACK 1
Chris@247 40
Chris@1526 41 PaneStack::PaneStack(QWidget *parent,
Chris@1526 42 ViewManager *viewManager,
Chris@1526 43 int options) :
Chris@127 44 QFrame(parent),
Chris@1408 45 m_currentPane(nullptr),
Chris@1526 46 m_options(options),
Chris@1526 47 m_splitter(nullptr),
Chris@1526 48 m_autoResizeStack(nullptr),
Chris@127 49 m_propertyStackStack(new QStackedWidget),
Chris@127 50 m_viewManager(viewManager),
Chris@615 51 m_propertyStackMinWidth(100),
Chris@1526 52 m_layoutStyle(PropertyStackPerPaneLayout)
Chris@127 53 {
Chris@127 54 QHBoxLayout *layout = new QHBoxLayout;
Chris@127 55 layout->setMargin(0);
Chris@127 56 layout->setSpacing(0);
Chris@127 57
Chris@1526 58 if (m_options & int(Option::NoUserResize)) {
Chris@1447 59
Chris@1526 60 m_autoResizeStack = new QWidget;
Chris@1526 61 m_autoResizeLayout = new QVBoxLayout;
Chris@1526 62 m_autoResizeLayout->setMargin(0);
Chris@1526 63 m_autoResizeLayout->setSpacing(0);
Chris@1526 64 m_autoResizeStack->setLayout(m_autoResizeLayout);
Chris@1526 65 layout->addWidget(m_autoResizeStack);
Chris@1526 66 layout->setStretchFactor(m_autoResizeStack, 1);
Chris@1526 67
Chris@1526 68 } else {
Chris@1526 69
Chris@1526 70 m_splitter = new QSplitter;
Chris@1526 71 m_splitter->setOrientation(Qt::Vertical);
Chris@1526 72 m_splitter->setOpaqueResize(false);
Chris@1526 73 layout->addWidget(m_splitter);
Chris@1526 74 layout->setStretchFactor(m_splitter, 1);
Chris@1526 75 }
Chris@1526 76
Chris@1526 77 if (m_options & int(Option::NoPropertyStacks)) {
Chris@1526 78 m_layoutStyle = HiddenPropertyStacksLayout;
Chris@1526 79 }
Chris@1447 80
Chris@1447 81 m_propertyStackStack->hide();
Chris@127 82 layout->addWidget(m_propertyStackStack);
Chris@127 83
Chris@127 84 setLayout(layout);
Chris@127 85 }
Chris@127 86
Chris@127 87 Pane *
Chris@1526 88 PaneStack::addPane()
Chris@127 89 {
Chris@127 90 QFrame *frame = new QFrame;
Chris@495 91
Chris@495 92 QGridLayout *layout = new QGridLayout;
Chris@127 93 layout->setMargin(0);
Chris@1447 94 layout->setHorizontalSpacing(m_viewManager->scalePixelSize(2));
Chris@1530 95
Chris@1530 96 AlignmentView *av = nullptr;
Chris@1530 97
Chris@1526 98 if (m_options & int(Option::ShowAlignmentViews)) {
Chris@1447 99 layout->setVerticalSpacing(0);
Chris@1530 100 av = new AlignmentView(frame);
Chris@1530 101 av->setFixedHeight(ViewManager::scalePixelSize(20));
Chris@1530 102 av->setViewManager(m_viewManager);
Chris@1530 103 av->setVisible(false); // for now
Chris@1530 104 layout->addWidget(av, 0, 1);
Chris@1447 105 } else {
Chris@1447 106 layout->setVerticalSpacing(m_viewManager->scalePixelSize(2));
Chris@1447 107 }
Chris@1447 108
Chris@323 109 QPushButton *xButton = new QPushButton(frame);
Chris@323 110 xButton->setIcon(IconLoader().load("cross"));
Chris@323 111 xButton->setFixedSize(QSize(16, 16));
Chris@497 112 xButton->setFlat(true);
Chris@1526 113 xButton->setVisible(!(m_options & int(Option::NoPaneAccessories)));
Chris@1526 114 if (m_panes.empty() && (m_options & int(Option::NoCloseOnFirstPane))) {
Chris@1460 115 xButton->setVisible(false);
Chris@1460 116 }
Chris@1447 117 layout->addWidget(xButton, 1, 0);
Chris@323 118 connect(xButton, SIGNAL(clicked()), this, SLOT(paneDeleteButtonClicked()));
Chris@323 119
Chris@500 120 ClickableLabel *currentIndicator = new ClickableLabel(frame);
Chris@500 121 connect(currentIndicator, SIGNAL(clicked()), this, SLOT(indicatorClicked()));
Chris@1447 122 layout->addWidget(currentIndicator, 2, 0);
Chris@1462 123 layout->setRowStretch(2, 20);
Chris@1460 124 currentIndicator->setMinimumWidth(16);
Chris@1460 125 currentIndicator->setMinimumHeight(16);
Chris@127 126 currentIndicator->setScaledContents(true);
Chris@1526 127 currentIndicator->setVisible(!(m_options & int(Option::NoPaneAccessories)));
Chris@127 128
Chris@908 129 sv_frame_t initialCentreFrame = -1;
Chris@855 130 if (!m_panes.empty()) {
Chris@855 131 initialCentreFrame = m_panes[0].pane->getCentreFrame();
Chris@516 132 }
Chris@516 133
Chris@127 134 Pane *pane = new Pane(frame);
Chris@516 135 if (initialCentreFrame >= 0) {
Chris@516 136 pane->setViewManager(m_viewManager, initialCentreFrame);
Chris@516 137 } else {
Chris@516 138 pane->setViewManager(m_viewManager);
Chris@516 139 }
Chris@1447 140 layout->addWidget(pane, 1, 1, 2, 1);
Chris@495 141 layout->setColumnStretch(1, 20);
Chris@127 142
Chris@1408 143 QWidget *properties = nullptr;
Chris@1526 144 if (m_options & int(Option::NoPropertyStacks)) {
Chris@1266 145 properties = new QFrame();
Chris@127 146 } else {
Chris@1266 147 properties = new PropertyStack(frame, pane);
Chris@1266 148 connect(properties, SIGNAL(propertyContainerSelected(View *, PropertyContainer *)),
Chris@1266 149 this, SLOT(propertyContainerSelected(View *, PropertyContainer *)));
Chris@1582 150 connect(properties, SIGNAL(propertyContainerContextMenuRequested(View *, PropertyContainer *, QPoint)),
Chris@1582 151 this, SLOT(propertyContainerContextMenuRequested(View *, PropertyContainer *, QPoint)));
Chris@190 152 connect(properties, SIGNAL(viewSelected(View *)),
Chris@190 153 this, SLOT(viewSelected(View *)));
Chris@189 154 connect(properties, SIGNAL(contextHelpChanged(const QString &)),
Chris@189 155 this, SIGNAL(contextHelpChanged(const QString &)));
Chris@127 156 }
Chris@127 157 if (m_layoutStyle == PropertyStackPerPaneLayout) {
Chris@1447 158 layout->addWidget(properties, 1, 2, 2, 1);
Chris@127 159 } else {
Chris@127 160 properties->setParent(m_propertyStackStack);
Chris@127 161 m_propertyStackStack->addWidget(properties);
Chris@127 162 }
Chris@606 163 layout->setColumnStretch(2, 0);
Chris@127 164
Chris@127 165 PaneRec rec;
Chris@127 166 rec.pane = pane;
Chris@127 167 rec.propertyStack = properties;
Chris@605 168 rec.xButton = xButton;
Chris@127 169 rec.currentIndicator = currentIndicator;
Chris@127 170 rec.frame = frame;
Chris@127 171 rec.layout = layout;
Chris@867 172 rec.alignmentView = av;
Chris@127 173 m_panes.push_back(rec);
Chris@127 174
Chris@127 175 frame->setLayout(layout);
Chris@1447 176
Chris@1526 177 if (m_options & int(Option::NoUserResize)) {
Chris@1447 178 m_autoResizeLayout->addWidget(frame);
Chris@1447 179 frame->adjustSize();
Chris@1526 180 } else {
Chris@1526 181 m_splitter->addWidget(frame);
Chris@1447 182 }
Chris@127 183
Chris@127 184 connect(pane, SIGNAL(propertyContainerAdded(PropertyContainer *)),
Chris@1266 185 this, SLOT(propertyContainerAdded(PropertyContainer *)));
Chris@127 186 connect(pane, SIGNAL(propertyContainerRemoved(PropertyContainer *)),
Chris@1266 187 this, SLOT(propertyContainerRemoved(PropertyContainer *)));
Chris@127 188 connect(pane, SIGNAL(paneInteractedWith()),
Chris@1266 189 this, SLOT(paneInteractedWith()));
Chris@127 190 connect(pane, SIGNAL(rightButtonMenuRequested(QPoint)),
Chris@127 191 this, SLOT(rightButtonMenuRequested(QPoint)));
Chris@312 192 connect(pane, SIGNAL(dropAccepted(QStringList)),
Chris@312 193 this, SLOT(paneDropAccepted(QStringList)));
Chris@312 194 connect(pane, SIGNAL(dropAccepted(QString)),
Chris@312 195 this, SLOT(paneDropAccepted(QString)));
Chris@908 196 connect(pane, SIGNAL(doubleClickSelectInvoked(sv_frame_t)),
Chris@908 197 this, SIGNAL(doubleClickSelectInvoked(sv_frame_t)));
Chris@127 198
Chris@271 199 emit paneAdded(pane);
Chris@271 200 emit paneAdded();
Chris@271 201
Chris@127 202 if (!m_currentPane) {
Chris@1266 203 setCurrentPane(pane);
Chris@127 204 }
Chris@127 205
Chris@605 206 showOrHidePaneAccessories();
Chris@867 207 relinkAlignmentViews();
Chris@605 208
Chris@127 209 return pane;
Chris@127 210 }
Chris@127 211
Chris@127 212 void
Chris@867 213 PaneStack::relinkAlignmentViews()
Chris@867 214 {
Chris@1447 215 if (m_panes.empty()) return;
Chris@1530 216 auto av = m_panes[0].alignmentView;
Chris@1530 217 if (av) av->hide();
Chris@1447 218 for (int i = 1; in_range_for(m_panes, i); ++i) {
Chris@1530 219 av = m_panes[i].alignmentView;
Chris@1530 220 if (!av) continue;
Chris@1526 221 if (!(m_options & int(Option::ShowAlignmentViews))) {
Chris@1530 222 av->hide();
Chris@1526 223 } else {
Chris@1530 224 av->setViewAbove(m_panes[i-1].pane);
Chris@1530 225 av->setViewBelow(m_panes[i].pane);
Chris@1530 226 av->show();
Chris@1526 227 }
Chris@867 228 }
Chris@1606 229
Chris@1606 230 adjustAlignmentViewHeights(size().height());
Chris@867 231 }
Chris@867 232
Chris@867 233 void
Chris@867 234 PaneStack::unlinkAlignmentViews()
Chris@867 235 {
Chris@1447 236 for (int i = 0; in_range_for(m_panes, i); ++i) {
Chris@1530 237 auto av = m_panes[i].alignmentView;
Chris@1530 238 if (!av) continue;
Chris@1530 239 av->setViewAbove(nullptr);
Chris@1530 240 av->setViewBelow(nullptr);
Chris@867 241 }
Chris@867 242 }
Chris@867 243
Chris@867 244 void
Chris@1606 245 PaneStack::resizeEvent(QResizeEvent *ev)
Chris@1606 246 {
Chris@1606 247 adjustAlignmentViewHeights(ev->size().height());
Chris@1606 248 }
Chris@1606 249
Chris@1606 250 void
Chris@1606 251 PaneStack::adjustAlignmentViewHeights(int forMyHeight)
Chris@1606 252 {
Chris@1606 253 if (!(m_options & int(Option::ShowAlignmentViews))) return;
Chris@1606 254 if (!(m_options & int(Option::NoUserResize))) return;
Chris@1606 255 if (!isVisible()) return;
Chris@1606 256
Chris@1606 257 int heightPerPane = forMyHeight / int(m_panes.size());
Chris@1606 258
Chris@1606 259 SVCERR << "heightPerPane = " << heightPerPane << " ("
Chris@1606 260 << forMyHeight << "/" << m_panes.size() << ")" << endl;
Chris@1606 261
Chris@1606 262 int roomForAlignmentView = heightPerPane / 4;
Chris@1606 263 int min = ViewManager::scalePixelSize(6);
Chris@1606 264 int max = ViewManager::scalePixelSize(25);
Chris@1606 265 int alignmentHeight = roomForAlignmentView;
Chris@1606 266 if (alignmentHeight < min) {
Chris@1606 267 alignmentHeight = min;
Chris@1606 268 }
Chris@1606 269 if (alignmentHeight > max) {
Chris@1606 270 alignmentHeight = max;
Chris@1606 271 }
Chris@1606 272
Chris@1606 273 SVCERR << "alignmentHeight = " << alignmentHeight << endl;
Chris@1606 274
Chris@1606 275 for (int i = 0; in_range_for(m_panes, i); ++i) {
Chris@1606 276 auto av = m_panes[i].alignmentView;
Chris@1606 277 if (!av) continue;
Chris@1606 278 av->setFixedHeight(alignmentHeight);
Chris@1606 279 }
Chris@1606 280 }
Chris@1606 281
Chris@1606 282 void
Chris@235 283 PaneStack::setPropertyStackMinWidth(int mw)
Chris@235 284 {
Chris@235 285 for (std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@235 286 i != m_panes.end(); ++i) {
Chris@235 287 i->propertyStack->setMinimumWidth(mw);
Chris@235 288 }
Chris@235 289 m_propertyStackMinWidth = mw;
Chris@235 290 }
Chris@235 291
Chris@235 292 void
Chris@127 293 PaneStack::setLayoutStyle(LayoutStyle style)
Chris@127 294 {
Chris@1526 295 if (m_options & int(Option::NoPropertyStacks)) {
Chris@1526 296 SVCERR << "NOTE: PaneStack::setLayoutStyle called on PaneStack with NoPropertyStacks option set - this does nothing, its style is always equivalent to HiddenPropertyStacksLayout" << endl;
Chris@1526 297 return;
Chris@1526 298 }
Chris@1526 299
Chris@127 300 if (style == m_layoutStyle) return;
Chris@127 301 m_layoutStyle = style;
Chris@127 302
Chris@127 303 std::vector<PaneRec>::iterator i;
Chris@127 304
Chris@127 305 switch (style) {
Chris@127 306
Chris@1526 307 case HiddenPropertyStacksLayout:
Chris@127 308 case SinglePropertyStackLayout:
Chris@127 309
Chris@127 310 for (i = m_panes.begin(); i != m_panes.end(); ++i) {
Chris@127 311 i->layout->removeWidget(i->propertyStack);
Chris@127 312 i->propertyStack->setParent(m_propertyStackStack);
Chris@127 313 m_propertyStackStack->addWidget(i->propertyStack);
Chris@127 314 }
Chris@1526 315 m_propertyStackStack->setVisible(style != HiddenPropertyStacksLayout);
Chris@127 316 break;
Chris@127 317
Chris@127 318 case PropertyStackPerPaneLayout:
Chris@127 319
Chris@127 320 for (i = m_panes.begin(); i != m_panes.end(); ++i) {
Chris@127 321 m_propertyStackStack->removeWidget(i->propertyStack);
Chris@127 322 i->propertyStack->setParent(i->frame);
Chris@1529 323 i->layout->addWidget(i->propertyStack, 1, 2, 2, 1);
Chris@127 324 i->propertyStack->show();
Chris@127 325 }
Chris@127 326 m_propertyStackStack->hide();
Chris@127 327 break;
Chris@127 328 }
Chris@127 329 }
Chris@127 330
Chris@127 331 Pane *
Chris@127 332 PaneStack::getPane(int n)
Chris@127 333 {
Chris@806 334 if (n < (int)m_panes.size()) {
Chris@277 335 return m_panes[n].pane;
Chris@277 336 } else {
Chris@1408 337 return nullptr;
Chris@277 338 }
Chris@277 339 }
Chris@277 340
Chris@277 341 int
Chris@277 342 PaneStack::getPaneIndex(Pane *pane)
Chris@277 343 {
Chris@277 344 for (int i = 0; i < getPaneCount(); ++i) {
Chris@277 345 if (pane == getPane(i)) {
Chris@277 346 return i;
Chris@277 347 }
Chris@277 348 }
Chris@277 349 return -1;
Chris@127 350 }
Chris@127 351
Chris@127 352 Pane *
Chris@127 353 PaneStack::getHiddenPane(int n)
Chris@127 354 {
Chris@127 355 return m_hiddenPanes[n].pane;
Chris@127 356 }
Chris@127 357
Chris@127 358 void
Chris@127 359 PaneStack::deletePane(Pane *pane)
Chris@127 360 {
Chris@1362 361 #ifdef DEBUG_PANE_STACK
Chris@1362 362 SVCERR << "PaneStack::deletePane(" << pane << ")" << endl;
Chris@1362 363 #endif
Chris@729 364
Chris@127 365 std::vector<PaneRec>::iterator i;
Chris@127 366 bool found = false;
Chris@127 367
Chris@1408 368 QWidget *stack = nullptr;
Chris@729 369
Chris@127 370 for (i = m_panes.begin(); i != m_panes.end(); ++i) {
Chris@1266 371 if (i->pane == pane) {
Chris@729 372 stack = i->propertyStack;
Chris@1266 373 m_panes.erase(i);
Chris@1266 374 found = true;
Chris@1266 375 break;
Chris@1266 376 }
Chris@127 377 }
Chris@127 378
Chris@127 379 if (!found) {
Chris@127 380
Chris@1266 381 for (i = m_hiddenPanes.begin(); i != m_hiddenPanes.end(); ++i) {
Chris@1266 382 if (i->pane == pane) {
Chris@729 383 stack = i->propertyStack;
Chris@1266 384 m_hiddenPanes.erase(i);
Chris@1266 385 found = true;
Chris@1266 386 break;
Chris@1266 387 }
Chris@1266 388 }
Chris@127 389
Chris@1266 390 if (!found) {
Chris@1266 391 cerr << "WARNING: PaneStack::deletePane(" << pane << "): Pane not found in visible or hidden panes, not deleting" << endl;
Chris@1266 392 return;
Chris@1266 393 }
Chris@127 394 }
Chris@127 395
Chris@271 396 emit paneAboutToBeDeleted(pane);
Chris@867 397 unlinkAlignmentViews();
Chris@271 398
Chris@1362 399 #ifdef DEBUG_PANE_STACK
Chris@1362 400 SVCERR << "PaneStack::deletePane: about to delete parent " << pane->parent() << " of pane " << pane << endl;
Chris@1362 401 #endif
Chris@729 402
Chris@729 403 // The property stack associated with the parent was initially
Chris@729 404 // created with the same parent as it, so it would be deleted when
Chris@729 405 // we delete the pane's parent in a moment -- but it may have been
Chris@729 406 // reparented depending on the layout. We'd better delete it
Chris@729 407 // separately first. (This fixes a crash on opening a new layer
Chris@729 408 // with a new unit type in it, when a long-defunct property box
Chris@729 409 // could be signalled from the unit database to tell it that a new
Chris@729 410 // unit had appeared.)
Chris@729 411 delete stack;
Chris@729 412
Chris@127 413 delete pane->parent();
Chris@127 414
Chris@127 415 if (m_currentPane == pane) {
Chris@1266 416 if (m_panes.size() > 0) {
Chris@127 417 setCurrentPane(m_panes[0].pane);
Chris@1266 418 } else {
Chris@1408 419 setCurrentPane(nullptr);
Chris@1266 420 }
Chris@127 421 }
Chris@271 422
Chris@605 423 showOrHidePaneAccessories();
Chris@867 424 relinkAlignmentViews();
Chris@605 425
Chris@271 426 emit paneDeleted();
Chris@127 427 }
Chris@127 428
Chris@605 429 void
Chris@605 430 PaneStack::showOrHidePaneAccessories()
Chris@605 431 {
Chris@1362 432 #ifdef DEBUG_PANE_STACK
Chris@1362 433 SVCERR << "PaneStack::showOrHidePaneAccessories: count == " << getPaneCount() << endl;
Chris@1362 434 #endif
Chris@605 435
Chris@605 436 bool multi = (getPaneCount() > 1);
Chris@605 437 for (std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@605 438 i != m_panes.end(); ++i) {
Chris@1526 439 bool visible = (multi && !(m_options & int(Option::NoPaneAccessories)));
Chris@1460 440 bool xvisible = visible;
Chris@1460 441 if (i == m_panes.begin()) {
Chris@1526 442 if (m_options & int(Option::NoCloseOnFirstPane)) {
Chris@1460 443 xvisible = false;
Chris@1460 444 }
Chris@1460 445 }
Chris@1460 446 i->xButton->setVisible(xvisible);
Chris@1460 447 i->currentIndicator->setVisible(visible);
Chris@605 448 }
Chris@605 449 }
Chris@605 450
Chris@127 451 int
Chris@127 452 PaneStack::getPaneCount() const
Chris@127 453 {
Chris@908 454 return int(m_panes.size());
Chris@127 455 }
Chris@127 456
Chris@127 457 int
Chris@127 458 PaneStack::getHiddenPaneCount() const
Chris@127 459 {
Chris@908 460 return int(m_hiddenPanes.size());
Chris@127 461 }
Chris@127 462
Chris@127 463 void
Chris@127 464 PaneStack::hidePane(Pane *pane)
Chris@127 465 {
Chris@127 466 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@127 467
Chris@127 468 while (i != m_panes.end()) {
Chris@1266 469 if (i->pane == pane) {
Chris@127 470
Chris@1266 471 m_hiddenPanes.push_back(*i);
Chris@1266 472 m_panes.erase(i);
Chris@127 473
Chris@1266 474 QWidget *pw = dynamic_cast<QWidget *>(pane->parent());
Chris@1266 475 if (pw) pw->hide();
Chris@127 476
Chris@1266 477 if (m_currentPane == pane) {
Chris@1266 478 if (m_panes.size() > 0) {
Chris@1266 479 setCurrentPane(m_panes[0].pane);
Chris@1266 480 } else {
Chris@1408 481 setCurrentPane(nullptr);
Chris@1266 482 }
Chris@1266 483 }
Chris@1266 484
Chris@605 485 showOrHidePaneAccessories();
Chris@605 486 emit paneHidden(pane);
Chris@605 487 emit paneHidden();
cannam@1444 488 relinkAlignmentViews();
Chris@1266 489 return;
Chris@1266 490 }
Chris@1266 491 ++i;
Chris@127 492 }
Chris@127 493
Chris@1362 494 SVCERR << "WARNING: PaneStack::hidePane(" << pane << "): Pane not found in visible panes" << endl;
Chris@127 495 }
Chris@127 496
Chris@127 497 void
Chris@127 498 PaneStack::showPane(Pane *pane)
Chris@127 499 {
Chris@127 500 std::vector<PaneRec>::iterator i = m_hiddenPanes.begin();
Chris@127 501
Chris@127 502 while (i != m_hiddenPanes.end()) {
Chris@1266 503 if (i->pane == pane) {
Chris@1266 504 m_panes.push_back(*i);
Chris@1266 505 m_hiddenPanes.erase(i);
Chris@1266 506 QWidget *pw = dynamic_cast<QWidget *>(pane->parent());
Chris@1266 507 if (pw) pw->show();
Chris@127 508
Chris@1266 509 //!!! update current pane
Chris@127 510
Chris@605 511 showOrHidePaneAccessories();
cannam@1444 512 relinkAlignmentViews();
Chris@605 513
Chris@1266 514 return;
Chris@1266 515 }
Chris@1266 516 ++i;
Chris@127 517 }
Chris@127 518
Chris@1362 519 SVCERR << "WARNING: PaneStack::showPane(" << pane << "): Pane not found in hidden panes" << endl;
Chris@127 520 }
Chris@127 521
Chris@127 522 void
Chris@127 523 PaneStack::setCurrentPane(Pane *pane) // may be null
Chris@127 524 {
Chris@127 525 if (m_currentPane == pane) return;
Chris@127 526
Chris@127 527 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@127 528
Chris@127 529 // We used to do this by setting the foreground and background
Chris@127 530 // role, but it seems the background role is ignored and the
Chris@127 531 // background drawn transparent in Qt 4.1 -- I can't quite see why
Chris@127 532
Chris@127 533 QPixmap selectedMap(1, 1);
Chris@127 534 selectedMap.fill(QApplication::palette().color(QPalette::Foreground));
Chris@127 535
Chris@127 536 QPixmap unselectedMap(1, 1);
Chris@127 537 unselectedMap.fill(QApplication::palette().color(QPalette::Background));
Chris@127 538
Chris@127 539 bool found = false;
Chris@127 540
Chris@127 541 while (i != m_panes.end()) {
Chris@1266 542 if (i->pane == pane) {
Chris@1266 543 i->currentIndicator->setPixmap(selectedMap);
Chris@179 544 if (m_layoutStyle != PropertyStackPerPaneLayout) {
Chris@127 545 m_propertyStackStack->setCurrentWidget(i->propertyStack);
Chris@127 546 }
Chris@1266 547 found = true;
Chris@1266 548 } else {
Chris@1266 549 i->currentIndicator->setPixmap(unselectedMap);
Chris@1266 550 }
Chris@1266 551 ++i;
Chris@127 552 }
Chris@127 553
Chris@1408 554 if (found || pane == nullptr) {
Chris@1266 555 m_currentPane = pane;
Chris@1266 556 emit currentPaneChanged(m_currentPane);
Chris@127 557 } else {
Chris@1362 558 SVCERR << "WARNING: PaneStack::setCurrentPane(" << pane << "): pane is not a visible pane in this stack" << endl;
Chris@127 559 }
Chris@127 560 }
Chris@127 561
Chris@127 562 void
Chris@127 563 PaneStack::setCurrentLayer(Pane *pane, Layer *layer) // may be null
Chris@127 564 {
Chris@127 565 setCurrentPane(pane);
Chris@127 566
Chris@127 567 if (m_currentPane) {
Chris@127 568
Chris@1266 569 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@127 570
Chris@1266 571 while (i != m_panes.end()) {
Chris@127 572
Chris@1266 573 if (i->pane == pane) {
Chris@1266 574 PropertyStack *stack = dynamic_cast<PropertyStack *>
Chris@1266 575 (i->propertyStack);
Chris@1266 576 if (stack) {
Chris@1266 577 if (stack->containsContainer(layer)) {
Chris@1266 578 stack->setCurrentIndex(stack->getContainerIndex(layer));
Chris@1266 579 emit currentLayerChanged(pane, layer);
Chris@1266 580 } else {
Chris@1266 581 stack->setCurrentIndex
Chris@1266 582 (stack->getContainerIndex
Chris@1266 583 (pane->getPropertyContainer(0)));
Chris@1408 584 emit currentLayerChanged(pane, nullptr);
Chris@1266 585 }
Chris@1266 586 }
Chris@1266 587 break;
Chris@1266 588 }
Chris@1266 589 ++i;
Chris@1266 590 }
Chris@127 591 }
Chris@127 592 }
Chris@127 593
Chris@127 594 Pane *
Chris@127 595 PaneStack::getCurrentPane()
Chris@127 596 {
Chris@127 597 return m_currentPane;
Chris@127 598 }
Chris@127 599
Chris@127 600 void
Chris@127 601 PaneStack::propertyContainerAdded(PropertyContainer *)
Chris@127 602 {
Chris@127 603 sizePropertyStacks();
Chris@127 604 }
Chris@127 605
Chris@127 606 void
Chris@127 607 PaneStack::propertyContainerRemoved(PropertyContainer *)
Chris@127 608 {
Chris@127 609 sizePropertyStacks();
Chris@127 610 }
Chris@127 611
Chris@127 612 void
Chris@127 613 PaneStack::propertyContainerSelected(View *client, PropertyContainer *pc)
Chris@127 614 {
Chris@127 615 std::vector<PaneRec>::iterator i = m_panes.begin();
Chris@127 616
Chris@127 617 while (i != m_panes.end()) {
Chris@1266 618 PropertyStack *stack = dynamic_cast<PropertyStack *>(i->propertyStack);
Chris@1266 619 if (stack &&
Chris@1266 620 stack->getClient() == client &&
Chris@1266 621 stack->containsContainer(pc)) {
Chris@1266 622 setCurrentPane(i->pane);
Chris@1266 623 break;
Chris@1266 624 }
Chris@1266 625 ++i;
Chris@127 626 }
Chris@127 627
Chris@127 628 Layer *layer = dynamic_cast<Layer *>(pc);
Chris@127 629 if (layer) emit currentLayerChanged(m_currentPane, layer);
Chris@1408 630 else emit currentLayerChanged(m_currentPane, nullptr);
Chris@127 631 }
Chris@127 632
Chris@127 633 void
Chris@1582 634 PaneStack::propertyContainerContextMenuRequested(View *client,
Chris@1582 635 PropertyContainer *pc,
Chris@1582 636 QPoint pos)
Chris@1582 637 {
Chris@1582 638 Pane *pane = dynamic_cast<Pane *>(client);
Chris@1582 639 Layer *layer = dynamic_cast<Layer *>(pc);
Chris@1582 640
Chris@1582 641 if (pane) {
Chris@1582 642 if (layer) {
Chris@1582 643 emit layerPropertiesRightButtonMenuRequested(pane, layer, pos);
Chris@1582 644 } else {
Chris@1582 645 emit panePropertiesRightButtonMenuRequested(pane, pos);
Chris@1582 646 }
Chris@1582 647 }
Chris@1582 648 }
Chris@1582 649
Chris@1582 650 void
Chris@190 651 PaneStack::viewSelected(View *v)
Chris@190 652 {
Chris@190 653 Pane *p = dynamic_cast<Pane *>(v);
Chris@190 654 if (p) setCurrentPane(p);
Chris@190 655 }
Chris@190 656
Chris@190 657 void
Chris@127 658 PaneStack::paneInteractedWith()
Chris@127 659 {
Chris@127 660 Pane *pane = dynamic_cast<Pane *>(sender());
Chris@127 661 if (!pane) return;
Chris@127 662 setCurrentPane(pane);
Chris@127 663 }
Chris@127 664
Chris@127 665 void
Chris@127 666 PaneStack::rightButtonMenuRequested(QPoint position)
Chris@127 667 {
Chris@127 668 Pane *pane = dynamic_cast<Pane *>(sender());
Chris@127 669 if (!pane) return;
Chris@1582 670 emit paneRightButtonMenuRequested(pane, position);
Chris@127 671 }
Chris@127 672
Chris@127 673 void
Chris@127 674 PaneStack::sizePropertyStacks()
Chris@127 675 {
Chris@127 676 int maxMinWidth = 0;
Chris@127 677
Chris@235 678 if (m_propertyStackMinWidth > 0) maxMinWidth = m_propertyStackMinWidth;
Chris@235 679
Chris@806 680 for (int i = 0; i < (int)m_panes.size(); ++i) {
Chris@1266 681 if (!m_panes[i].propertyStack) continue;
Chris@247 682 #ifdef DEBUG_PANE_STACK
Chris@1266 683 SVDEBUG << "PaneStack::sizePropertyStacks: " << i << ": min "
Chris@1266 684 << m_panes[i].propertyStack->minimumSizeHint().width() << ", hint "
Chris@243 685 << m_panes[i].propertyStack->sizeHint().width() << ", current "
Chris@1266 686 << m_panes[i].propertyStack->width() << endl;
Chris@247 687 #endif
Chris@127 688
Chris@1266 689 if (m_panes[i].propertyStack->sizeHint().width() > maxMinWidth) {
Chris@1266 690 maxMinWidth = m_panes[i].propertyStack->sizeHint().width();
Chris@1266 691 }
Chris@127 692 }
Chris@127 693
Chris@247 694 #ifdef DEBUG_PANE_STACK
Chris@587 695 SVDEBUG << "PaneStack::sizePropertyStacks: max min width " << maxMinWidth << endl;
Chris@247 696 #endif
Chris@127 697
Chris@127 698 int setWidth = maxMinWidth;
Chris@127 699
Chris@127 700 m_propertyStackStack->setMaximumWidth(setWidth + 10);
Chris@127 701
Chris@806 702 for (int i = 0; i < (int)m_panes.size(); ++i) {
Chris@1266 703 if (!m_panes[i].propertyStack) continue;
Chris@1266 704 m_panes[i].propertyStack->setMinimumWidth(setWidth);
Chris@127 705 }
Chris@180 706
Chris@363 707 emit propertyStacksResized(setWidth);
Chris@180 708 emit propertyStacksResized();
Chris@127 709 }
Chris@127 710
Chris@312 711 void
Chris@312 712 PaneStack::paneDropAccepted(QStringList uriList)
Chris@312 713 {
Chris@312 714 Pane *pane = dynamic_cast<Pane *>(sender());
Chris@312 715 emit dropAccepted(pane, uriList);
Chris@312 716 }
Chris@312 717
Chris@312 718 void
Chris@312 719 PaneStack::paneDropAccepted(QString text)
Chris@312 720 {
Chris@312 721 Pane *pane = dynamic_cast<Pane *>(sender());
Chris@312 722 emit dropAccepted(pane, text);
Chris@312 723 }
Chris@127 724
Chris@320 725 void
Chris@323 726 PaneStack::paneDeleteButtonClicked()
Chris@323 727 {
Chris@323 728 QObject *s = sender();
Chris@806 729 for (int i = 0; i < (int)m_panes.size(); ++i) {
Chris@1266 730 if (m_panes[i].xButton == s) {
Chris@605 731 emit paneDeleteButtonClicked(m_panes[i].pane);
Chris@323 732 }
Chris@323 733 }
Chris@323 734 }
Chris@323 735
Chris@323 736 void
Chris@500 737 PaneStack::indicatorClicked()
Chris@500 738 {
Chris@500 739 QObject *s = sender();
Chris@500 740
Chris@806 741 for (int i = 0; i < (int)m_panes.size(); ++i) {
Chris@1266 742 if (m_panes[i].currentIndicator == s) {
Chris@500 743 setCurrentPane(m_panes[i].pane);
Chris@500 744 return;
Chris@500 745 }
Chris@500 746 }
Chris@500 747 }
Chris@500 748
Chris@500 749 void
Chris@320 750 PaneStack::sizePanesEqually()
Chris@320 751 {
Chris@1526 752 if (m_options & int(Option::NoUserResize)) {
Chris@1447 753 return;
Chris@1447 754 }
Chris@1447 755
Chris@320 756 QList<int> sizes = m_splitter->sizes();
Chris@320 757 if (sizes.empty()) return;
Chris@320 758
Chris@320 759 int count = sizes.size();
Chris@320 760
Chris@687 761 int fixed = 0, variable = 0, total = 0;
Chris@687 762 int varicount = 0;
Chris@687 763
Chris@320 764 for (int i = 0; i < count; ++i) {
Chris@320 765 total += sizes[i];
Chris@320 766 }
Chris@320 767
Chris@687 768 variable = total;
Chris@687 769
Chris@687 770 for (int i = 0; i < count; ++i) {
Chris@687 771 int minh = m_panes[i].pane->minimumSize().height();
Chris@687 772 if (minh == m_panes[i].pane->maximumSize().height()) {
Chris@687 773 fixed += minh;
Chris@687 774 variable -= minh;
Chris@687 775 } else {
Chris@687 776 varicount++;
Chris@687 777 }
Chris@687 778 }
Chris@687 779
Chris@320 780 if (total == 0) return;
Chris@320 781
Chris@320 782 sizes.clear();
Chris@320 783
Chris@687 784 int each = (varicount > 0 ? (variable / varicount) : 0);
Chris@320 785 int remaining = total;
Chris@320 786
Chris@320 787 for (int i = 0; i < count; ++i) {
Chris@320 788 if (i == count - 1) {
Chris@320 789 sizes.push_back(remaining);
Chris@320 790 } else {
Chris@687 791 int minh = m_panes[i].pane->minimumSize().height();
Chris@687 792 if (minh == m_panes[i].pane->maximumSize().height()) {
Chris@687 793 sizes.push_back(minh);
Chris@687 794 remaining -= minh;
Chris@687 795 } else {
Chris@687 796 sizes.push_back(each);
Chris@687 797 remaining -= each;
Chris@687 798 }
Chris@320 799 }
Chris@320 800 }
Chris@320 801
Chris@320 802 /*
Chris@682 803 cerr << "sizes: ";
Chris@320 804 for (int i = 0; i < sizes.size(); ++i) {
Chris@682 805 cerr << sizes[i] << " ";
Chris@320 806 }
Chris@682 807 cerr << endl;
Chris@320 808 */
Chris@320 809
Chris@320 810 m_splitter->setSizes(sizes);
Chris@320 811 }
Chris@320 812