//============================================================================= // MuseScore // Music Composition & Notation // $Id: palettebox.cpp 5576 2012-04-24 19:15:22Z wschweer $ // // Copyright (C) 2011-2016 Werner Schweer and others // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 // as published by the Free Software Foundation and appearing in // the file LICENSE.GPL //============================================================================= #include "palette.h" #include "palettebox.h" #include "musescore.h" #include "preferences.h" #include "libmscore/xml.h" #include "workspace.h" namespace Ms { //--------------------------------------------------------- // PaletteBox //--------------------------------------------------------- PaletteBox::PaletteBox(QWidget* parent) : QDockWidget(tr("Palettes"), parent) { setContextMenuPolicy(Qt::ActionsContextMenu); setObjectName("palette-box"); setAllowedAreas(Qt::DockWidgetAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea)); singlePaletteAction = new QAction(this); singlePaletteAction->setCheckable(true); singlePaletteAction->setChecked(preferences.getBool(PREF_APP_USESINGLEPALETTE)); addAction(singlePaletteAction); connect(singlePaletteAction, SIGNAL(toggled(bool)), SLOT(setSinglePalette(bool))); QWidget* w = new QWidget(this); w->setContextMenuPolicy(Qt::NoContextMenu); QVBoxLayout* vl = new QVBoxLayout(w); vl->setMargin(0); QHBoxLayout* hl = new QHBoxLayout; hl->setContentsMargins(5,0,5,0); workspaceList = new QComboBox; hl->addWidget(workspaceList); addWorkspaceButton = new QToolButton; addWorkspaceButton->setMinimumHeight(24); hl->addWidget(addWorkspaceButton); setWidget(w); _searchBox = new QLineEdit(this); _searchBox->setFocusPolicy(Qt::StrongFocus); _searchBox->installEventFilter(this); _searchBox->setClearButtonEnabled(true); _searchBox->setPlaceholderText(tr("Search")); connect(_searchBox, SIGNAL(textChanged(const QString&)), this, SLOT(filterPalettes(const QString&))); QHBoxLayout* hlSearch = new QHBoxLayout; hlSearch->setContentsMargins(5,0,5,0); hlSearch->addWidget(_searchBox); PaletteBoxScrollArea* sa = new PaletteBoxScrollArea; sa->setFocusPolicy(Qt::NoFocus); sa->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); sa->setContextMenuPolicy(Qt::CustomContextMenu); sa->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); sa->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); sa->setWidgetResizable(true); sa->setFrameShape(QFrame::NoFrame); vl->addWidget(sa); vl->addLayout(hlSearch); vl->addLayout(hl); QWidget* paletteList = new QWidget; sa->setWidget(paletteList); vbox = new QVBoxLayout; paletteList->setLayout(vbox); vbox->setMargin(0); vbox->setSpacing(1); vbox->addStretch(); paletteList->show(); connect(addWorkspaceButton, SIGNAL(clicked()), SLOT(newWorkspaceClicked())); connect(workspaceList, SIGNAL(activated(int)), SLOT(workspaceSelected(int))); retranslate(); } //--------------------------------------------------------- // retranslate //--------------------------------------------------------- void PaletteBox::retranslate() { setWindowTitle(tr("Palettes")); singlePaletteAction->setText(tr("Single Palette")); workspaceList->setToolTip(tr("Select workspace")); addWorkspaceButton->setText(tr("+")); addWorkspaceButton->setToolTip(tr("Add new workspace")); updateWorkspaces(); } //--------------------------------------------------------- // filterPalettes //--------------------------------------------------------- void PaletteBox::filterPalettes(const QString& text) { for (int i = 0; i < vbox->count(); i++) { QWidgetItem* wi = static_cast(vbox->itemAt(i)); PaletteBoxButton* b = static_cast(wi->widget()); i++; wi = static_cast(vbox->itemAt(i)); if (!wi) return; Palette* p = static_cast(wi->widget()); bool f = p->filter(text); b->setVisible(!f); if (b->isVisible()) { b->showPalette(!text.isEmpty()); } else b->showPalette(false); // disable editing while palette is filtered b->enableEditing(text.isEmpty()); } } //--------------------------------------------------------- // workspaceSelected //--------------------------------------------------------- void PaletteBox::workspaceSelected(int idx) { Workspace* w = Workspace::workspaces().at(idx); preferences.setPreference(PREF_APP_WORKSPACE, w->name()); mscore->changeWorkspace(w); } //--------------------------------------------------------- // newWorkspaceClicked //--------------------------------------------------------- void PaletteBox::newWorkspaceClicked() { mscore->createNewWorkspace(); updateWorkspaces(); } //--------------------------------------------------------- // updateWorkspaces //--------------------------------------------------------- void PaletteBox::updateWorkspaces() { workspaceList->clear(); const QList pl = Workspace::workspaces(); int idx = 0; int curIdx = -1; for (Workspace* p : pl) { workspaceList->addItem(qApp->translate("Ms::Workspace", p->name().toUtf8()), p->path()); if (p->name() == preferences.getString(PREF_APP_WORKSPACE)) curIdx = idx; ++idx; } if (curIdx != -1) workspaceList->setCurrentIndex(curIdx); } //--------------------------------------------------------- // selectWorkspace //--------------------------------------------------------- void PaletteBox::selectWorkspace(QString path) { int idx = workspaceList->findData(path); workspaceList->setCurrentIndex(idx); workspaceSelected(idx); } //--------------------------------------------------------- // clear //--------------------------------------------------------- void PaletteBox::clear() { int n = vbox->count() - 1; // do not delete stretch item while (n--) { QLayoutItem* item = vbox->takeAt(0); if (item->widget()) item->widget()->hide(); delete item; } vbox->invalidate(); } //--------------------------------------------------------- // addPalette //--------------------------------------------------------- void PaletteBox::addPalette(Palette* w) { PaletteBoxButton* b = new PaletteBoxButton(w); int slotIdx = vbox->count() - 1; // insert before stretch b->setId(slotIdx); vbox->insertWidget(slotIdx, b); vbox->insertWidget(slotIdx+1, w, paletteStretch); connect(b, SIGNAL(paletteCmd(PaletteCommand,int)), SLOT(paletteCmd(PaletteCommand,int))); connect(b, SIGNAL(closeAll()), SLOT(closeAll())); connect(w, SIGNAL(changed()), SIGNAL(changed())); } //--------------------------------------------------------- // newPalette //--------------------------------------------------------- Palette* PaletteBox::newPalette(const QString& name, int slot) { Palette* p = new Palette; p->setReadOnly(false); p->setName(name); PaletteBoxButton* b = new PaletteBoxButton(p); vbox->insertWidget(slot, b); vbox->insertWidget(slot+1, p, paletteStretch); connect(b, SIGNAL(paletteCmd(PaletteCommand, int)), SLOT(paletteCmd(PaletteCommand, int))); connect(p, SIGNAL(changed()), Workspace::currentWorkspace, SLOT(setDirty())); for (int i = 0; i < (vbox->count() - 1) / 2; ++i) static_cast(vbox->itemAt(i * 2)->widget())->setId(i*2); return p; } //--------------------------------------------------------- // paletteCmd //--------------------------------------------------------- void PaletteBox::paletteCmd(PaletteCommand cmd, int slot) { QLayoutItem* item = vbox->itemAt(slot); PaletteBoxButton* b = static_cast(item->widget()); Palette* palette = static_cast(vbox->itemAt(slot+1)->widget()); switch(cmd) { case PaletteCommand::PDELETE: { QMessageBox::StandardButton reply; reply = QMessageBox::question(0, QWidget::tr("Are you sure?"), QWidget::tr("Do you really want to delete the '%1' palette?").arg(palette->name()), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes ); if (reply == QMessageBox::Yes) { vbox->removeItem(item); b->deleteLater(); // this is the button widget delete item; item = vbox->itemAt(slot); vbox->removeItem(item); delete item->widget(); delete item; for (int i = 0; i < (vbox->count() - 1) / 2; ++i) static_cast(vbox->itemAt(i * 2)->widget())->setId(i*2); emit changed(); } } break; case PaletteCommand::SAVE: { QString path = mscore->getPaletteFilename(false, palette->name()); if (!path.isEmpty()) palette->write(path); } break; case PaletteCommand::LOAD: { QString path = mscore->getPaletteFilename(true); if (!path.isEmpty()) { QFileInfo fi(path); Palette* palette = newPalette(fi.completeBaseName(), slot); palette->read(path); } } emit changed(); break; case PaletteCommand::NEW: palette = newPalette(tr("new Palette"), slot); item = vbox->itemAt(slot); b = static_cast(item->widget()); // fall through case PaletteCommand::EDIT: { PaletteProperties pp(palette, 0); int rv = pp.exec(); if (rv == 1) { emit changed(); b->setText(palette->name()); palette->update(); } } emit changed(); break; case PaletteCommand::UP: if (slot) { QLayoutItem* i1 = vbox->itemAt(slot); QLayoutItem* i2 = vbox->itemAt(slot+1); vbox->removeItem(i1); vbox->removeItem(i2); vbox->insertWidget(slot-2, i2->widget(), paletteStretch); vbox->insertWidget(slot-2, i1->widget()); delete i1; delete i2; for (int i = 0; i < (vbox->count() - 1) / 2; ++i) static_cast(vbox->itemAt(i * 2)->widget())->setId(i*2); emit changed(); } break; case PaletteCommand::DOWN: if (slot < (vbox->count() - 3)) { QLayoutItem* i1 = vbox->itemAt(slot); QLayoutItem* i2 = vbox->itemAt(slot+1); vbox->removeItem(i1); vbox->removeItem(i2); vbox->insertWidget(slot+2, i2->widget(), paletteStretch); vbox->insertWidget(slot+2, i1->widget()); delete i1; delete i2; for (int i = 0; i < (vbox->count() - 1) / 2; ++i) static_cast(vbox->itemAt(i * 2)->widget())->setId(i*2); emit changed(); } break; } } //--------------------------------------------------------- // closeAll //--------------------------------------------------------- void PaletteBox::closeAll() { for (int i = 0; i < (vbox->count() - 1); i += 2) { PaletteBoxButton* b = static_cast (vbox->itemAt(i)->widget() ); b->showPalette(false); } } //--------------------------------------------------------- // write //--------------------------------------------------------- void PaletteBox::write(XmlWriter& xml) { xml.stag("PaletteBox"); for (int i = 0; i < (vbox->count() - 1); i += 2) { Palette* palette = static_cast(vbox->itemAt(i+1)->widget()); palette->write(xml); } xml.etag(); } //--------------------------------------------------------- // palettes //--------------------------------------------------------- QList PaletteBox::palettes()const { QList pl; for (int i = 0; i < (vbox->count() - 1); i += 2) pl.append(static_cast(vbox->itemAt(i+1)->widget())); return pl; } //--------------------------------------------------------- // read // return false on error //--------------------------------------------------------- bool PaletteBox::read(XmlReader& e) { while (e.readNextStartElement()) { const QStringRef& tag(e.name()); if (tag == "Palette") { Palette* p = new Palette(); QString name = e.attribute("name"); p->setName(name); p->read(e); addPalette(p); connect(p, SIGNAL(displayMore(const QString&)), mscore, SLOT(showMasterPalette(const QString&))); } else e.unknown(); } return true; } //--------------------------------------------------------- // sizeHint //--------------------------------------------------------- QSize PaletteBoxScrollArea::sizeHint() const { return QSize(170 * guiScaling, 170 * guiScaling); } //--------------------------------------------------------- // setSinglePalette //--------------------------------------------------------- void PaletteBox::setSinglePalette(bool val) { preferences.setPreference(PREF_APP_USESINGLEPALETTE, val); } //--------------------------------------------------------- // changeEvent //--------------------------------------------------------- void PaletteBox::changeEvent(QEvent *event) { QDockWidget::changeEvent(event); if (event->type() == QEvent::LanguageChange) retranslate(); } //--------------------------------------------------------- // noSelection //--------------------------------------------------------- bool PaletteBox::noSelection() { for (Palette* p : palettes()) { if (p->getCurrentIdx() != -1) return false; } return true; } //--------------------------------------------------------- // mousePressEvent //--------------------------------------------------------- void PaletteBox::mousePressEvent(QMouseEvent* ev, Palette* p1) { for (Palette* p : palettes()) { QList cells = p->getDragCells(); if (cells.isEmpty()) continue; if (p->getCurrentIdx() != -1) { p->setCurrentIdx(-1); p->update(); } } p1->setCurrentIdx(p1->idx(ev->pos())); p1->update(); _searchBox->setFocus(); } //--------------------------------------------------------- // navigation //--------------------------------------------------------- void PaletteBox::navigation(QKeyEvent *event) { if (!palettes().first()->isFilterActive()) return; if (event->key() == Qt::Key_Down) { for (Palette* p : palettes()) { if (p->getCurrentIdx() == -1) continue; if (p->getCurrentIdx() != p->getDragCells().size() - 1) { p->nextPaletteElement(); return; } else { int index = palettes().indexOf(p); p->setCurrentIdx(-1); p->update(); for (int i = index + 1; i < palettes().size(); i++) { Palette* next = palettes()[i]; if (!next->getDragCells().isEmpty()) { next->setCurrentIdx(0); next->update(); return; } } } } for (Palette* p : palettes()) { if (!p->getDragCells().isEmpty()) { p->setCurrentIdx(0); p->update(); keyboardNavigation = true; return; } } } else if (event->key() == Qt::Key_Up) { for (Palette* p : palettes()) { if (p->getCurrentIdx() == -1) continue; if (p->getCurrentIdx() != 0) { p->prevPaletteElement(); return; } else { int index = palettes().indexOf(p); p->setCurrentIdx(-1); p->update(); for (int i = index - 1; i >= 0; i--) { Palette* prev = palettes()[i]; if (!prev->getDragCells().isEmpty()) { QList cells = p->getDragCells(); int l = prev->getDragCells().size() - 1; prev->setCurrentIdx(l); prev->update(); return; } } } } for (int j = palettes().size() - 1; j >= 0; j--) { Palette* p = palettes()[j]; if (!p->getDragCells().isEmpty()) { int l = p->getDragCells().size() - 1; p->setCurrentIdx(l); p->update(); keyboardNavigation = true; return; } } } else if ((event->key() == Qt::Key_Enter) || (event->key() == Qt::Key_Return)) { for (Palette* p : palettes()) { if (p->getCurrentIdx() != -1) { p->applyPaletteElement(); return; } } } } bool PaletteBox::eventFilter(QObject* obj, QEvent *event) { if (obj == _searchBox) { if (event->type() == QEvent::KeyPress) { QKeyEvent* keyEvent = static_cast(event); if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down || keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return) { navigation(keyEvent); return true; } } return false; } return QDockWidget::eventFilter(obj, event); } }