You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
474 lines
15 KiB
474 lines
15 KiB
/*
|
|
Rosegarden
|
|
A MIDI and audio sequencer and musical notation editor.
|
|
|
|
This program is Copyright 2000-2008
|
|
Guillaume Laurent <glaurent@telegraph-road.org>,
|
|
Chris Cannam <cannam@all-day-breakfast.com>,
|
|
Richard Bown <richard.bown@ferventsoftware.com>
|
|
|
|
The moral rights of Guillaume Laurent, Chris Cannam, and Richard
|
|
Bown to claim authorship of this work have been asserted.
|
|
|
|
Other copyrights also apply to some parts of this work. Please
|
|
see the AUTHORS file and individual file headers for details.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version. See the file
|
|
COPYING included with this distribution for more information.
|
|
*/
|
|
|
|
#include "GuitarChordSelectorDialog.h"
|
|
#include "GuitarChordEditorDialog.h"
|
|
#include "ChordXmlHandler.h"
|
|
#include "FingeringBox.h"
|
|
#include "FingeringListBoxItem.h"
|
|
|
|
#include "misc/Debug.h"
|
|
#include <tqlistbox.h>
|
|
#include <tqlayout.h>
|
|
#include <tqcombobox.h>
|
|
#include <tqpushbutton.h>
|
|
#include <tqlabel.h>
|
|
#include <tdelocale.h>
|
|
#include <tdemessagebox.h>
|
|
#include <kstddirs.h>
|
|
|
|
namespace Rosegarden
|
|
{
|
|
|
|
GuitarChordSelectorDialog::GuitarChordSelectorDialog(TQWidget *parent)
|
|
: KDialogBase(parent, "GuitarChordSelector", true, i18n("Guitar Chord Selector"), Ok|Cancel)
|
|
{
|
|
TQWidget *page = new TQWidget(this);
|
|
setMainWidget(page);
|
|
TQGridLayout *topLayout = new TQGridLayout(page, 3, 4, spacingHint());
|
|
|
|
topLayout->addWidget(new TQLabel(i18n("Root"), page), 0, 0);
|
|
m_rootNotesList = new TQListBox(page);
|
|
topLayout->addWidget(m_rootNotesList, 1, 0);
|
|
|
|
topLayout->addWidget(new TQLabel(i18n("Extension"), page), 0, 1);
|
|
m_chordExtList = new TQListBox(page);
|
|
topLayout->addWidget(m_chordExtList, 1, 1);
|
|
|
|
m_newFingeringButton = new TQPushButton(i18n("New"), page);
|
|
m_deleteFingeringButton = new TQPushButton(i18n("Delete"), page);
|
|
m_editFingeringButton = new TQPushButton(i18n("Edit"), page);
|
|
|
|
m_chordComplexityCombo = new TQComboBox(page);
|
|
m_chordComplexityCombo->insertItem(i18n("beginner"));
|
|
m_chordComplexityCombo->insertItem(i18n("common"));
|
|
m_chordComplexityCombo->insertItem(i18n("all"));
|
|
|
|
connect(m_chordComplexityCombo, TQ_SIGNAL(activated(int)),
|
|
this, TQ_SLOT(slotComplexityChanged(int)));
|
|
|
|
TQVBoxLayout* vboxLayout = new TQVBoxLayout(page, 5);
|
|
topLayout->addMultiCellLayout(vboxLayout, 1, 3, 2, 2);
|
|
vboxLayout->addWidget(m_chordComplexityCombo);
|
|
vboxLayout->addStretch(10);
|
|
vboxLayout->addWidget(m_newFingeringButton);
|
|
vboxLayout->addWidget(m_deleteFingeringButton);
|
|
vboxLayout->addWidget(m_editFingeringButton);
|
|
|
|
connect(m_newFingeringButton, TQ_SIGNAL(clicked()),
|
|
this, TQ_SLOT(slotNewFingering()));
|
|
connect(m_deleteFingeringButton, TQ_SIGNAL(clicked()),
|
|
this, TQ_SLOT(slotDeleteFingering()));
|
|
connect(m_editFingeringButton, TQ_SIGNAL(clicked()),
|
|
this, TQ_SLOT(slotEditFingering()));
|
|
|
|
topLayout->addWidget(new TQLabel(i18n("Fingerings"), page), 0, 3);
|
|
m_fingeringsList = new TQListBox(page);
|
|
topLayout->addMultiCellWidget(m_fingeringsList, 1, 2, 3, 3);
|
|
|
|
m_fingeringBox = new FingeringBox(false, page);
|
|
topLayout->addMultiCellWidget(m_fingeringBox, 2, 2, 0, 1);
|
|
|
|
connect(m_rootNotesList, TQ_SIGNAL(highlighted(int)),
|
|
this, TQ_SLOT(slotRootHighlighted(int)));
|
|
connect(m_chordExtList, TQ_SIGNAL(highlighted(int)),
|
|
this, TQ_SLOT(slotChordExtHighlighted(int)));
|
|
connect(m_fingeringsList, TQ_SIGNAL(highlighted(TQListBoxItem*)),
|
|
this, TQ_SLOT(slotFingeringHighlighted(TQListBoxItem*)));
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::init()
|
|
{
|
|
// populate the listboxes
|
|
//
|
|
std::vector<TQString> chordFiles = getAvailableChordFiles();
|
|
|
|
parseChordFiles(chordFiles);
|
|
|
|
// m_chordMap.debugDump();
|
|
|
|
populate();
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::populate()
|
|
{
|
|
TQStringList rootList = m_chordMap.getRootList();
|
|
if (rootList.count() > 0) {
|
|
m_rootNotesList->insertStringList(rootList);
|
|
|
|
TQStringList extList = m_chordMap.getExtList(rootList.first());
|
|
populateExtensions(extList);
|
|
|
|
Guitar::ChordMap::chordarray chords = m_chordMap.getChords(rootList.first(), extList.first());
|
|
populateFingerings(chords);
|
|
|
|
m_chord.setRoot(rootList.first());
|
|
m_chord.setExt(extList.first());
|
|
}
|
|
|
|
m_rootNotesList->sort();
|
|
|
|
m_rootNotesList->setCurrentItem(0);
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::clear()
|
|
{
|
|
m_rootNotesList->clear();
|
|
m_chordExtList->clear();
|
|
m_fingeringsList->clear();
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::refresh()
|
|
{
|
|
clear();
|
|
populate();
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::slotRootHighlighted(int i)
|
|
{
|
|
NOTATION_DEBUG << "GuitarChordSelectorDialog::slotRootHighlighted " << i << endl;
|
|
|
|
m_chord.setRoot(m_rootNotesList->text(i));
|
|
|
|
TQStringList extList = m_chordMap.getExtList(m_chord.getRoot());
|
|
populateExtensions(extList);
|
|
if (m_chordExtList->count() > 0)
|
|
m_chordExtList->setCurrentItem(0);
|
|
else
|
|
m_fingeringsList->clear(); // clear any previous fingerings
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::slotChordExtHighlighted(int i)
|
|
{
|
|
NOTATION_DEBUG << "GuitarChordSelectorDialog::slotChordExtHighlighted " << i << endl;
|
|
|
|
Guitar::ChordMap::chordarray chords = m_chordMap.getChords(m_chord.getRoot(), m_chordExtList->text(i));
|
|
populateFingerings(chords);
|
|
|
|
m_fingeringsList->setCurrentItem(0);
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::slotFingeringHighlighted(TQListBoxItem* listBoxItem)
|
|
{
|
|
NOTATION_DEBUG << "GuitarChordSelectorDialog::slotFingeringHighlighted\n";
|
|
|
|
FingeringListBoxItem* fingeringItem = dynamic_cast<FingeringListBoxItem*>(listBoxItem);
|
|
if (fingeringItem) {
|
|
m_chord = fingeringItem->getChord();
|
|
m_fingeringBox->setFingering(m_chord.getFingering());
|
|
setEditionEnabled(m_chord.isUserChord());
|
|
}
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::slotComplexityChanged(int)
|
|
{
|
|
// simply repopulate the extension list box
|
|
//
|
|
TQStringList extList = m_chordMap.getExtList(m_chord.getRoot());
|
|
populateExtensions(extList);
|
|
if (m_chordExtList->count() > 0)
|
|
m_chordExtList->setCurrentItem(0);
|
|
else
|
|
m_fingeringsList->clear(); // clear any previous fingerings
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::slotNewFingering()
|
|
{
|
|
Guitar::Chord newChord;
|
|
newChord.setRoot(m_chord.getRoot());
|
|
newChord.setExt(m_chord.getExt());
|
|
|
|
GuitarChordEditorDialog* chordEditorDialog = new GuitarChordEditorDialog(newChord, m_chordMap, this);
|
|
|
|
if (chordEditorDialog->exec() == TQDialog::Accepted) {
|
|
m_chordMap.insert(newChord);
|
|
// populate lists
|
|
//
|
|
if (!m_rootNotesList->findItem(newChord.getRoot(), TQt::ExactMatch)) {
|
|
m_rootNotesList->insertItem(newChord.getRoot());
|
|
m_rootNotesList->sort();
|
|
}
|
|
|
|
if (!m_chordExtList->findItem(newChord.getExt(), TQt::ExactMatch)) {
|
|
m_chordExtList->insertItem(newChord.getExt());
|
|
m_chordExtList->sort();
|
|
}
|
|
}
|
|
|
|
delete chordEditorDialog;
|
|
|
|
refresh();
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::slotDeleteFingering()
|
|
{
|
|
if (m_chord.isUserChord()) {
|
|
m_chordMap.remove(m_chord);
|
|
delete m_fingeringsList->selectedItem();
|
|
}
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::slotEditFingering()
|
|
{
|
|
Guitar::Chord newChord = m_chord;
|
|
GuitarChordEditorDialog* chordEditorDialog = new GuitarChordEditorDialog(newChord, m_chordMap, this);
|
|
|
|
if (chordEditorDialog->exec() == TQDialog::Accepted) {
|
|
NOTATION_DEBUG << "GuitarChordSelectorDialog::slotEditFingering() - current map state :\n";
|
|
m_chordMap.debugDump();
|
|
m_chordMap.substitute(m_chord, newChord);
|
|
NOTATION_DEBUG << "GuitarChordSelectorDialog::slotEditFingering() - new map state :\n";
|
|
m_chordMap.debugDump();
|
|
setChord(newChord);
|
|
}
|
|
|
|
delete chordEditorDialog;
|
|
|
|
refresh();
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::slotOk()
|
|
{
|
|
if (m_chordMap.needSave()) {
|
|
saveUserChordMap();
|
|
m_chordMap.clearNeedSave();
|
|
}
|
|
|
|
KDialogBase::slotOk();
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::setChord(const Guitar::Chord& chord)
|
|
{
|
|
NOTATION_DEBUG << "GuitarChordSelectorDialog::setChord " << chord << endl;
|
|
|
|
m_chord = chord;
|
|
|
|
// select the chord's root
|
|
//
|
|
m_rootNotesList->setCurrentItem(0);
|
|
TQListBoxItem* correspondingRoot = m_rootNotesList->findItem(chord.getRoot(), TQt::ExactMatch);
|
|
if (correspondingRoot)
|
|
m_rootNotesList->setSelected(correspondingRoot, true);
|
|
|
|
// update the dialog's complexity setting if needed, then populate the extension list
|
|
//
|
|
TQString chordExt = chord.getExt();
|
|
int complexityLevel = m_chordComplexityCombo->currentItem();
|
|
int chordComplexity = evaluateChordComplexity(chordExt);
|
|
|
|
if (chordComplexity > complexityLevel) {
|
|
m_chordComplexityCombo->setCurrentItem(chordComplexity);
|
|
}
|
|
|
|
TQStringList extList = m_chordMap.getExtList(chord.getRoot());
|
|
populateExtensions(extList);
|
|
|
|
// select the chord's extension
|
|
//
|
|
if (chordExt.isEmpty()) {
|
|
chordExt = "";
|
|
m_chordExtList->setSelected(0, true);
|
|
} else {
|
|
TQListBoxItem* correspondingExt = m_chordExtList->findItem(chordExt, TQt::ExactMatch);
|
|
if (correspondingExt)
|
|
m_chordExtList->setSelected(correspondingExt, true);
|
|
}
|
|
|
|
// populate fingerings and pass the current chord's fingering so it is selected
|
|
//
|
|
Guitar::ChordMap::chordarray similarChords = m_chordMap.getChords(chord.getRoot(), chord.getExt());
|
|
populateFingerings(similarChords, chord.getFingering());
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::populateFingerings(const Guitar::ChordMap::chordarray& chords, const Guitar::Fingering& refFingering)
|
|
{
|
|
m_fingeringsList->clear();
|
|
|
|
for(Guitar::ChordMap::chordarray::const_iterator i = chords.begin(); i != chords.end(); ++i) {
|
|
const Guitar::Chord& chord = *i;
|
|
TQString fingeringString = chord.getFingering().toString().c_str();
|
|
NOTATION_DEBUG << "GuitarChordSelectorDialog::populateFingerings " << chord << endl;
|
|
TQPixmap fingeringPixmap = getFingeringPixmap(chord.getFingering());
|
|
FingeringListBoxItem *item = new FingeringListBoxItem(chord, m_fingeringsList, fingeringPixmap, fingeringString);
|
|
if (refFingering == chord.getFingering()) {
|
|
NOTATION_DEBUG << "GuitarChordSelectorDialog::populateFingerings - fingering found " << fingeringString << endl;
|
|
m_fingeringsList->setSelected(item, true);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
TQPixmap
|
|
GuitarChordSelectorDialog::getFingeringPixmap(const Guitar::Fingering& fingering) const
|
|
{
|
|
TQPixmap pixmap(FINGERING_PIXMAP_WIDTH, FINGERING_PIXMAP_HEIGHT);
|
|
pixmap.fill();
|
|
|
|
TQPainter pp(&pixmap);
|
|
TQPainter *p = &pp;
|
|
|
|
p->setViewport(FINGERING_PIXMAP_H_MARGIN, FINGERING_PIXMAP_W_MARGIN,
|
|
FINGERING_PIXMAP_WIDTH - FINGERING_PIXMAP_W_MARGIN,
|
|
FINGERING_PIXMAP_HEIGHT - FINGERING_PIXMAP_H_MARGIN);
|
|
|
|
Guitar::NoteSymbols::drawFingeringPixmap(fingering, m_fingeringBox->getNoteSymbols(), p);
|
|
|
|
return pixmap;
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::populateExtensions(const TQStringList& extList)
|
|
{
|
|
m_chordExtList->clear();
|
|
|
|
if (m_chordComplexityCombo->currentItem() != COMPLEXITY_ALL) {
|
|
// some filtering needs to be done
|
|
int complexityLevel = m_chordComplexityCombo->currentItem();
|
|
|
|
TQStringList filteredList;
|
|
for(TQStringList::const_iterator i = extList.constBegin(); i != extList.constEnd(); ++i) {
|
|
if (evaluateChordComplexity((*i).lower().stripWhiteSpace()) <= complexityLevel) {
|
|
NOTATION_DEBUG << "GuitarChordSelectorDialog::populateExtensions - adding '" << *i << "'\n";
|
|
filteredList.append(*i);
|
|
}
|
|
}
|
|
|
|
m_chordExtList->insertStringList(filteredList);
|
|
|
|
} else {
|
|
m_chordExtList->insertStringList(extList);
|
|
}
|
|
}
|
|
|
|
int
|
|
GuitarChordSelectorDialog::evaluateChordComplexity(const TQString& ext)
|
|
{
|
|
if (ext.isEmpty() ||
|
|
ext == "7" ||
|
|
ext == "m" ||
|
|
ext == "5")
|
|
return COMPLEXITY_BEGINNER;
|
|
|
|
if (ext == "dim" ||
|
|
ext == "dim7" ||
|
|
ext == "aug" ||
|
|
ext == "sus2" ||
|
|
ext == "sus4" ||
|
|
ext == "maj7" ||
|
|
ext == "m7" ||
|
|
ext == "mmaj7" ||
|
|
ext == "m7b5" ||
|
|
ext == "7sus4")
|
|
|
|
return COMPLEXITY_COMMON;
|
|
|
|
return COMPLEXITY_ALL;
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::parseChordFiles(const std::vector<TQString>& chordFiles)
|
|
{
|
|
for(std::vector<TQString>::const_iterator i = chordFiles.begin(); i != chordFiles.end(); ++i) {
|
|
parseChordFile(*i);
|
|
}
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::parseChordFile(const TQString& chordFileName)
|
|
{
|
|
ChordXmlHandler handler(m_chordMap);
|
|
TQFile chordFile(chordFileName);
|
|
bool ok = chordFile.open(IO_ReadOnly);
|
|
if (!ok)
|
|
KMessageBox::error(0, i18n("couldn't open file '%1'").arg(handler.errorString()));
|
|
|
|
TQXmlInputSource source(chordFile);
|
|
TQXmlSimpleReader reader;
|
|
reader.setContentHandler(&handler);
|
|
reader.setErrorHandler(&handler);
|
|
NOTATION_DEBUG << "GuitarChordSelectorDialog::parseChordFile() parsing " << chordFileName << endl;
|
|
reader.parse(source);
|
|
if (!ok)
|
|
KMessageBox::error(0, i18n("couldn't parse chord dictionnary : %1").arg(handler.errorString()));
|
|
|
|
}
|
|
|
|
void
|
|
GuitarChordSelectorDialog::setEditionEnabled(bool enabled)
|
|
{
|
|
m_deleteFingeringButton->setEnabled(enabled);
|
|
m_editFingeringButton->setEnabled(enabled);
|
|
}
|
|
|
|
std::vector<TQString>
|
|
GuitarChordSelectorDialog::getAvailableChordFiles()
|
|
{
|
|
std::vector<TQString> names;
|
|
|
|
// Read config for default directory
|
|
TQStringList chordDictFiles = TDEGlobal::dirs()->findAllResources("appdata", "chords/*.xml");
|
|
|
|
for(TQStringList::iterator i = chordDictFiles.begin(); i != chordDictFiles.end(); ++i) {
|
|
NOTATION_DEBUG << "GuitarChordSelectorDialog::getAvailableChordFiles : adding file " << *i << endl;
|
|
names.push_back(*i);
|
|
}
|
|
|
|
return names;
|
|
}
|
|
|
|
bool
|
|
GuitarChordSelectorDialog::saveUserChordMap()
|
|
{
|
|
// Read config for user directory
|
|
TQString userDir = TDEGlobal::dirs()->saveLocation("appdata", "chords/");
|
|
|
|
TQString userChordDictPath = userDir + "/user_chords.xml";
|
|
|
|
NOTATION_DEBUG << "GuitarChordSelectorDialog::saveUserChordMap() : saving user chord map to " << userChordDictPath << endl;
|
|
TQString errMsg;
|
|
|
|
m_chordMap.saveDocument(userChordDictPath, true, errMsg);
|
|
|
|
return errMsg.isEmpty();
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#include "GuitarChordSelectorDialog.moc"
|