MuseScore/mscore/palettebox.cpp
2019-08-31 14:16:19 +03:00

547 lines
20 KiB
C++

//=============================================================================
// MuseScore
// Music Composition & Notation
//
// 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"
#include "workspacecombobox.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 WorkspaceComboBox(mscore);
workspaceList->setObjectName("workspace-list");
hl->addWidget(workspaceList);
addWorkspaceButton = new QToolButton;
addWorkspaceButton->setDefaultAction(getAction("create-new-workspace"));
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();
retranslate();
}
//---------------------------------------------------------
// retranslate
//---------------------------------------------------------
void PaletteBox::retranslate()
{
setWindowTitle(tr("Palettes"));
singlePaletteAction->setText(tr("Single Palette"));
workspaceList->retranslate();
}
//---------------------------------------------------------
// filterPalettes
//---------------------------------------------------------
void PaletteBox::filterPalettes(const QString& text)
{
for (int i = 0; i < vbox->count(); i++) {
QWidgetItem* wi = static_cast<QWidgetItem*>(vbox->itemAt(i));
PaletteBoxButton* b = static_cast<PaletteBoxButton*>(wi->widget());
i++;
wi = static_cast<QWidgetItem*>(vbox->itemAt(i));
if (!wi) return;
Palette* p = static_cast<Palette*>(wi->widget());
bool f = p->filter(text);
b->setVisible(!f);
if (b->isVisible()) {
b->showPalette(!text.isEmpty());
}
else
b->showPalette(false);
}
}
//---------------------------------------------------------
// selectWorkspace
//---------------------------------------------------------
void PaletteBox::selectWorkspace(QString path)
{
int idx = workspaceList->findData(path);
selectWorkspace(idx);
}
///---------------------------------------------------------
/// selectWorkspace
/// Selects the workspace in the workspaceList dropdown widget using specified @idx
/// If @idx value is out of valid range:
/// If currentIndex is valid, keep the index
/// 1st element of the list is selected othrwise
///---------------------------------------------------------
void PaletteBox::selectWorkspace(int idx)
{
if (idx < 0 || idx >= workspaceList->count()) {
//if selected index is valid, keep the index selection
if (workspaceList->currentIndex() < workspaceList->count())
idx = workspaceList->currentIndex();
else
idx = 0;
}
workspaceList->setCurrentIndex(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<PaletteBoxButton*>(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<PaletteBoxButton*>(item->widget());
Palette* palette = static_cast<Palette*>(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<PaletteBoxButton*>(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 = 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<PaletteBoxButton*>(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<PaletteBoxButton*>(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<PaletteBoxButton*>(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<PaletteBoxButton*> (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<Palette*>(vbox->itemAt(i+1)->widget());
palette->write(xml);
}
xml.etag();
}
//---------------------------------------------------------
// palettes
//---------------------------------------------------------
QList<Palette*> PaletteBox::palettes()const
{
QList<Palette*> pl;
for (int i = 0; i < (vbox->count() - 1); i += 2)
pl.append(static_cast<Palette*>(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<PaletteCell*> 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)
{
const QList<Palette*> palettesList = palettes();
if (palettesList.empty() || !palettesList.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<PaletteCell*> 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<QKeyEvent*>(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);
}
}