diff options
| author | vovanec <vovanec@90c681e8-e032-0410-971d-27865f9a5e38> | 2008-02-07 13:36:34 +0000 |
|---|---|---|
| committer | vovanec <vovanec@90c681e8-e032-0410-971d-27865f9a5e38> | 2008-02-07 13:36:34 +0000 |
| commit | 06d1877811fa6aa97dddc0e03bcde4e766928c87 (patch) | |
| tree | c25462d0e58c3d58c728664440412bf4f16a49ec /src/ui | |
| parent | 3f6b60f23c44a8ba8dd97ca6f41a16e2af7ef2f7 (diff) | |
| download | qmmp-06d1877811fa6aa97dddc0e03bcde4e766928c87.tar.gz qmmp-06d1877811fa6aa97dddc0e03bcde4e766928c87.tar.bz2 qmmp-06d1877811fa6aa97dddc0e03bcde4e766928c87.zip | |
new directory structure
git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@232 90c681e8-e032-0410-971d-27865f9a5e38
Diffstat (limited to 'src/ui')
156 files changed, 20811 insertions, 0 deletions
diff --git a/src/ui/aboutdialog.cpp b/src/ui/aboutdialog.cpp new file mode 100644 index 000000000..a8b80e6cd --- /dev/null +++ b/src/ui/aboutdialog.cpp @@ -0,0 +1,63 @@ +/*************************************************************************** +* Copyright (C) 2006 by Ilya Kotov * +* forkotov02@hotmail.ru * +* * +* 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. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * +***************************************************************************/ + + +#include "aboutdialog.h" + +#include <QFile> +#include <QTextStream> + +static QString getstringFromResource(const QString& res_file) +{ + QString ret_string; + QFile file(res_file); + if (file.open(QIODevice::ReadOnly)) + { + QTextStream ts(&file); + ts.setCodec("UTF-8"); + ret_string = ts.readAll(); + file.close(); + } + return ret_string; +} + +AboutDialog::AboutDialog(QWidget* parent, Qt::WFlags fl) + : QDialog( parent, fl ) +{ + setupUi(this); + setAttribute(Qt::WA_QuitOnClose, FALSE); + licenseTextEdit->setPlainText(getstringFromResource(":COPYING")); + aboutTextEdit->setHtml(getstringFromResource(tr(":/html/about_en.html"))); + authorsTextEdit->setPlainText(getstringFromResource(tr(":/html/authors_en.txt"))); + thanksToTextEdit->setPlainText(getstringFromResource(tr(":/html/thanks_en.txt"))); +} + +AboutDialog::~AboutDialog() +{} + +/*$SPECIALIZATION$*/ +void AboutDialog::accept() +{ + QDialog::accept(); +} + + + + diff --git a/src/ui/aboutdialog.h b/src/ui/aboutdialog.h new file mode 100644 index 000000000..10dcde4a5 --- /dev/null +++ b/src/ui/aboutdialog.h @@ -0,0 +1,44 @@ +/*************************************************************************** +* Copyright (C) 2006 by Ilya Kotov * +* forkotov02@hotmail.ru * +* * +* 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. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * +***************************************************************************/ + +#ifndef ABOUTDIALOG_H +#define ABOUTDIALOG_H + +#include <QDialog> +#include "ui_aboutdialog.h" + +/** + @author Vladimir Kuznetsov <vovanec@gmail.com> + */ + +class AboutDialog : public QDialog, private Ui::AboutDialog +{ + Q_OBJECT +public: + AboutDialog(QWidget* parent = 0, Qt::WFlags fl = 0 ); + ~AboutDialog(); + +protected slots: + virtual void accept(); + +}; + +#endif + diff --git a/src/ui/addurldialog.cpp b/src/ui/addurldialog.cpp new file mode 100644 index 000000000..6746a2de1 --- /dev/null +++ b/src/ui/addurldialog.cpp @@ -0,0 +1,67 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "addurldialog.h" + +#include "playlistmodel.h" + +AddUrlDialog::AddUrlDialog( QWidget * parent, Qt::WindowFlags f) : QDialog(parent,f) +{ + setupUi(this); + setAttribute(Qt::WA_DeleteOnClose); +} + +AddUrlDialog::~AddUrlDialog() +{} + + + +QPointer<AddUrlDialog> AddUrlDialog::instance = 0; + +void AddUrlDialog::popup(QWidget* parent,PlayListModel* model ) +{ + if(!instance) + { + instance = new AddUrlDialog(parent); + instance->setModel(model); + } + + instance->show(); + instance->raise(); +} + +void AddUrlDialog::accept( ) +{ + if(!urlComboBox->currentText().isEmpty()) + { + QString s = urlComboBox->currentText(); + if(!s.startsWith("http://")) + s.prepend("http://"); + + m_model->addFile(s); + } + + QDialog::accept(); +} + +void AddUrlDialog::setModel( PlayListModel *m ) +{ + m_model = m; +} diff --git a/src/ui/addurldialog.h b/src/ui/addurldialog.h new file mode 100644 index 000000000..86a065703 --- /dev/null +++ b/src/ui/addurldialog.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef ADDURLDIALOG_H +#define ADDURLDIALOG_H + +#include "ui_addurldialog.h" +#include <QDialog> +#include <QPointer> + + +class PlayListModel; + +/** + @author Vladimir Kuznetsov <vovanec@gmail.com> + */ + +class AddUrlDialog : public QDialog , private Ui::AddUrlDialog +{ + Q_OBJECT +public: + static void popup(QWidget* parent ,PlayListModel*); +protected: + AddUrlDialog( QWidget * parent = 0, Qt::WindowFlags f = 0 ); + ~AddUrlDialog(); +protected slots: + virtual void accept(); +private: + void setModel(PlayListModel*); + static QPointer<AddUrlDialog> instance; + PlayListModel* m_model; + +}; +#endif //ADDURLDIALOG_H diff --git a/src/ui/balancebar.cpp b/src/ui/balancebar.cpp new file mode 100644 index 000000000..3089e0cbd --- /dev/null +++ b/src/ui/balancebar.cpp @@ -0,0 +1,132 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QMouseEvent> +#include <QPainter> +#include <math.h> + +#include "skin.h" +#include "button.h" +#include "mainwindow.h" + +#include "balancebar.h" + + +BalanceBar::BalanceBar(QWidget *parent) + : PixmapWidget(parent) +{ + m_skin = Skin::getPointer(); + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); + setPixmap(m_skin->getBalanceBar(0)); + m_moving = FALSE; + m_min = -100; + m_max = 100; + m_old = m_value = 0; + draw(FALSE); +} + + +BalanceBar::~BalanceBar() +{} + +void BalanceBar::mousePressEvent(QMouseEvent *e) +{ + + m_moving = TRUE; + press_pos = e->x(); + if(m_pos<e->x() && e->x()<m_pos+11) + { + press_pos = e->x()-m_pos; + } + else + { + m_value = convert(qMax(qMin(width()-18,e->x()-6),0)); + press_pos = 6; + if (m_value!=m_old) + { + emit sliderMoved(m_value); + + } + } + draw(); +} + +void BalanceBar::mouseMoveEvent (QMouseEvent *e) +{ + if(m_moving) + { + int po = e->x(); + po = po - press_pos; + + if(0<=po && po<=width()-13) + { + m_value = convert(po); + draw(); + emit sliderMoved(m_value); + } + } +} + +void BalanceBar::mouseReleaseEvent(QMouseEvent*) +{ + m_moving = FALSE; + draw(FALSE); + m_old = m_value; +} + +void BalanceBar::setValue(int v) +{ + if (m_moving || m_max == 0) + return; + m_value = v; + draw(FALSE); +} + +void BalanceBar::setMax(int max) +{ + m_max = max; + draw(FALSE); +} + +void BalanceBar::updateSkin() +{ + draw(FALSE); +} + +void BalanceBar::draw(bool pressed) +{ + if(abs(m_value)<6) + m_value = 0; + int p=int(ceil(double(m_value-m_min)*(width()-13)/(m_max-m_min))); + m_pixmap = m_skin->getBalanceBar(abs(27*m_value/m_max)); + QPainter paint(&m_pixmap); + if(pressed) + paint.drawPixmap(p,1,m_skin->getButton(Skin::BT_BAL_P)); + else + paint.drawPixmap(p,1,m_skin->getButton(Skin::BT_BAL_N)); + setPixmap(m_pixmap); + m_pos = p; +} + +int BalanceBar::convert(int p) +{ + return int(ceil(double(m_max-m_min)*(p)/(width()-13)+m_min)); +} + diff --git a/src/ui/balancebar.h b/src/ui/balancebar.h new file mode 100644 index 000000000..6704671f9 --- /dev/null +++ b/src/ui/balancebar.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef BALANCEBAR_H +#define BALANCEBAR_H + +#include <pixmapwidget.h> + +class Skin; + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class BalanceBar : public PixmapWidget +{ +Q_OBJECT +public: + BalanceBar(QWidget *parent = 0); + + ~BalanceBar(); + + int value() {return m_value; }; + +public slots: + void setValue(int); + void setMax(int); + +signals: + void sliderMoved (int); + +private slots: + void updateSkin(); + +private: + Skin *m_skin; + bool m_moving; + int press_pos; + int m_max, m_min, m_pos, m_value, m_old; + QPixmap m_pixmap; + int convert(int); // value = convert(position); + void draw(bool pressed = TRUE); + +protected: + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + +}; + +#endif diff --git a/src/ui/button.cpp b/src/ui/button.cpp new file mode 100644 index 000000000..8bd006ed3 --- /dev/null +++ b/src/ui/button.cpp @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "button.h" +#include "skin.h" + +Button::Button ( QWidget *parent, uint normal, uint pressed ) + : PixmapWidget ( parent ) +{ + name_normal = normal; + name_pressed = pressed; + skin = Skin::getPointer(); + setON ( FALSE ); + connect ( skin, SIGNAL ( skinChanged() ), this, SLOT ( updateSkin() ) ); +} + + +Button::~Button() +{} + +void Button::updateSkin() +{ + setPixmap ( skin->getButton ( name_normal ) ); +} + +void Button::setON ( bool on ) +{ + if ( on ) + setPixmap ( skin->getButton ( name_pressed ) ); + else + setPixmap ( skin->getButton ( name_normal ) ); +} +void Button::mousePressEvent ( QMouseEvent* ) +{ + setON ( TRUE ); +} + +void Button::mouseReleaseEvent ( QMouseEvent* ) +{ + setON ( FALSE ); + emit clicked(); +} diff --git a/src/ui/button.h b/src/ui/button.h new file mode 100644 index 000000000..7f2d8f314 --- /dev/null +++ b/src/ui/button.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef BUTTON_H +#define BUTTON_H + +#include "pixmapwidget.h" + +class Skin; + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class Button : public PixmapWidget +{ +Q_OBJECT +public: + Button(QWidget *parent, uint normal, uint pressed); + + ~Button(); + +signals: + void clicked(); + +private slots: + void updateSkin(); + +private: + Skin *skin; + void setON(bool); + uint name_normal, name_pressed; + +protected: + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); +}; + +#endif diff --git a/src/ui/commandlineoption.cpp b/src/ui/commandlineoption.cpp new file mode 100644 index 000000000..ca9e8d398 --- /dev/null +++ b/src/ui/commandlineoption.cpp @@ -0,0 +1,216 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QDir> +#include <QPluginLoader> + +#include "commandlineoption.h" +#include "mainwindow.h" +#include <soundcore.h> + + +// Command option manager methods +CommandLineOptionManager::CommandLineOptionManager() +{ + this->registerBuiltingCommandLineOptions(); + this->registerExternalCommandLineOptions(); +} + +bool CommandLineOptionManager::hasOption(const QString &opt) +{ + for(int i = 0; i < m_options.count(); i++) + { + if(m_options[i]->identify(opt)) + { + return true; + } + } + return false; +} + +void CommandLineOptionManager::executeCommand(const QString &opt, MainWindow *mw) +{ + for(int i = 0; i < m_options.count(); i++) + { + if(m_options[i]->identify(opt)) + { + m_options[i]->executeCommand(opt,mw); + } + } +} + +CommandLineOption * CommandLineOptionManager::operator [](int index) +{ + return m_options[index]; +} + +int CommandLineOptionManager::count() const +{ + return m_options.count(); +} + + +void CommandLineOptionManager::registerBuiltingCommandLineOptions() +{ + m_options.append(new BuiltinCommandLineOption()); +} + + +void CommandLineOptionManager::registerExternalCommandLineOptions() +{ + QDir pluginsDir (QDir::homePath()+"/.qmmp/plugins/CommandLineOptions"); + foreach (QString fileName, pluginsDir.entryList(QDir::Files)) + { + QPluginLoader loader(pluginsDir.absoluteFilePath(fileName)); + QObject *plugin = loader.instance(); + if (loader.isLoaded()) + qDebug("CommandLineOption: plugin loaded - %s", qPrintable(fileName)); + else + qWarning(qPrintable(loader.errorString())); + + CommandLineOption *cmd_option = 0; + if (plugin) + cmd_option = qobject_cast<CommandLineOption *>(plugin); + + if (cmd_option) + { + foreach(CommandLineOption* opt,m_options) + { + if (opt->name() == cmd_option->name()) + { + qDebug("CommandLineOption: Plugin with name %s is already registered...", + qPrintable(cmd_option->name())); + return; + } + } + m_options.append(cmd_option); + } + } +} + +/////////////////////////////////////////////////////////////////// + + +// BuiltinCommandLineOption methods implementation +bool BuiltinCommandLineOption::identify(const QString & str) const +{ + if( + str == QString("--help") || + str == QString("--next") || + str == QString("--previous") || + str == QString("--play") || + str == QString("--pause") || + str == QString("--play-pause") || + str == QString("--stop") || + str.startsWith("--volume") || + str.startsWith("--jump-to-file") || + str.startsWith("--toggle-visibility") || + str.startsWith("--add-file") + ) + { + return TRUE; + } + + return FALSE; +} + +const QString BuiltinCommandLineOption::helpString() const +{ + return QString( + "--next Skip forward in playlist\n" + "--previous Skip backwards in playlist\n" + "--play Start playing current song\n" + "--pause Pause current song\n" + "--play-pause Pause if playing, play otherwise\n" + "--stop Stop current song\n" + "--next Skip forward in playlist\n" + "--volume Set playback volume(example: qmmp --volume20, qmmp --volume100)\n" + "--jump-to-file Display Jump to File dialog\n" + "--toggle-visibility Show/hide application\n" + "--add-file Display Add File dialog" + ); +} + +void BuiltinCommandLineOption::executeCommand(const QString & option_string, MainWindow *mw) +{ + if (option_string == "--play") + { + mw->play(); + } + else if (option_string == "--stop") + { + mw->stop(); + mw->mainDisplay()->hideTimeDisplay(); + } + else if (option_string == "--pause") + { + mw->pause(); + } + else if (option_string == "--next") + { + mw->next(); + if(!mw->soundCore()->isInitialized()) + mw->play(); + } + else if (option_string == "--previous") + { + mw->previous(); + if(!mw->soundCore()->isInitialized()) + mw->play(); + } + else if (option_string == "--play-pause") + { + mw->playPause(); + } + else if (option_string == "--jump-to-file") + { + mw->jumpToFile(); + } + else if (option_string == "--toggle-visibility") + { + mw->toggleVisibility(); + } + else if (option_string == "--add-file") + { + mw->addFile(); + } + else if (option_string.startsWith("--volume")) + { + QString vol_str(option_string); + vol_str.remove("--volume"); + bool ok = FALSE; + int volume = vol_str.toUInt(&ok); + if(ok) + { + mw->soundCore()->setVolume(volume,volume); + } + } +} + +const QString BuiltinCommandLineOption::name() const +{ + return "BuiltinCommandLineOption"; +} + + + + + + diff --git a/src/ui/commandlineoption.h b/src/ui/commandlineoption.h new file mode 100644 index 000000000..f5bc78ecf --- /dev/null +++ b/src/ui/commandlineoption.h @@ -0,0 +1,94 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef CommandLineOption_H +#define CommandLineOption_H + +#include <QtPlugin> +#include <QString> +#include <QList> + +class MainWindow; + +/** + @author Vladimir Kuznetsov <vovanec@gmail.ru> + */ +class CommandLineOption +{ +public: + /*! + * Returns \b true if \b opt_str string can be processed, + * otherise \b false + */ + virtual bool identify(const QString& opt_str)const = 0; + + /*! + * Command line option name + */ + virtual const QString name()const = 0; + + /*! + * Help string. + */ + virtual const QString helpString()const = 0; + + /*! + * Parses \b opt_str args(if needed), executes command. + */ + virtual void executeCommand(const QString& opt_str,MainWindow* mw) = 0; + virtual ~CommandLineOption(){;} +}; + +Q_DECLARE_INTERFACE(CommandLineOption,"CommandLineOptionInterface/1.0"); + + + +typedef QList<CommandLineOption*> CommandLineOptionList; + +class CommandLineOptionManager +{ +public: + CommandLineOptionManager(); + bool hasOption(const QString& ); + void executeCommand(const QString&,MainWindow* = NULL); + CommandLineOption* operator[](int); + int count()const; +protected: + void registerBuiltingCommandLineOptions(); + void registerExternalCommandLineOptions(); +private: + void _register(CommandLineOption*); +private: + CommandLineOptionList m_options; +}; + +/*! + * Represens command line option handling for standard operations. + */ +class BuiltinCommandLineOption : public CommandLineOption +{ + virtual bool identify(const QString& str)const; + virtual const QString helpString()const; + virtual void executeCommand(const QString& option,MainWindow* = NULL); + virtual const QString name()const; + virtual ~BuiltinCommandLineOption(){;} +}; + +#endif diff --git a/src/ui/configdialog.cpp b/src/ui/configdialog.cpp new file mode 100644 index 000000000..808c1ac94 --- /dev/null +++ b/src/ui/configdialog.cpp @@ -0,0 +1,509 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QDir> +#include <QSettings> +#include <QFontDialog> +#include <QTreeWidgetItem> +#include <QHeaderView> +#include <QCheckBox> +#include <QRadioButton> +#include <QMenu> + +#include <decoder.h> +#include <output.h> +#include <decoderfactory.h> +#include <outputfactory.h> +#include <visualfactory.h> +#include <effectfactory.h> +#include <effect.h> +#include <qmmpui/generalfactory.h> +#include <qmmpui/general.h> + + +#include "skin.h" +#include "filedialog.h" +#include "pluginitem.h" +#include "configdialog.h" +#include "skinreader.h" + +ConfigDialog::ConfigDialog ( QWidget *parent ) + : QDialog ( parent ) +{ + ui.setupUi ( this ); + setAttribute(Qt::WA_QuitOnClose, FALSE); + setAttribute(Qt::WA_DeleteOnClose, FALSE); + connect ( ui. contentsWidget, + SIGNAL ( currentItemChanged ( QListWidgetItem *, QListWidgetItem * ) ), + this, SLOT ( changePage ( QListWidgetItem *, QListWidgetItem* ) ) ); + connect ( ui.mainFontButton, SIGNAL ( clicked() ), SLOT ( setMainFont() ) ); + connect ( ui.plFontButton, SIGNAL ( clicked() ), SLOT ( setPlFont() ) ); + connect ( ui.preferencesButton, SIGNAL ( clicked() ), SLOT (showPluginSettings())); + connect ( ui.informationButton, SIGNAL ( clicked() ), SLOT (showPluginInfo())); + connect ( this, SIGNAL(accepted()),SLOT(saveSettings())); + ui.listWidget->setIconSize ( QSize ( 69,29 ) ); + m_skin = Skin::getPointer(); + ui.fileDialogComboBox->insertItems(0,FileDialog::registeredFactories()); + readSettings(); + SkinReader reader; + reader.updateCache(); + loadSkins(); + loadPluginsInfo(); + loadFonts(); + createMenus(); +} + +ConfigDialog::~ConfigDialog() +{ + while (!m_outputPluginItems.isEmpty()) + delete m_outputPluginItems.takeFirst(); + while (!m_inputPluginItems.isEmpty()) + delete m_outputPluginItems.takeFirst(); + while (!m_visualPluginItems.isEmpty()) + delete m_visualPluginItems.takeFirst(); + while (!m_effectPluginItems.isEmpty()) + delete m_effectPluginItems.takeFirst(); +} + +void ConfigDialog::readSettings() +{ + QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat ); + ui.formatLineEdit->setText( + settings.value ( "PlayList/title_format", "%p - %t").toString()); + ui.metadataCheckBox->setChecked( + settings.value ( "PlayList/load_metadata", TRUE).toBool()); + QString f_dialogName = + settings.value("FileDialog",QtFileDialogFactory::QtFileDialogFactoryName).toString(); + + int ind = FileDialog::registeredFactories().indexOf(f_dialogName); + if (ind != -1) + ui.fileDialogComboBox->setCurrentIndex(ind); + else + ui.fileDialogComboBox->setCurrentIndex(0); + + //proxy settings + ui.enableProxyCheckBox->setChecked( + settings.value ("Proxy/use_proxy", FALSE).toBool()); + ui.authProxyCheckBox->setChecked( + settings.value ("Proxy/authentication", FALSE).toBool()); + + ui.hostLineEdit->setText(settings.value("Proxy/host").toString()); + ui.portLineEdit->setText(settings.value("Proxy/port").toString()); + ui.proxyUserLineEdit->setText(settings.value("Proxy/user").toString()); + ui.proxyPasswLineEdit->setText(settings.value("Proxy/passw").toString()); + + ui.hostLineEdit->setEnabled(ui.enableProxyCheckBox->isChecked()); + ui.portLineEdit->setEnabled(ui.enableProxyCheckBox->isChecked()); + ui.proxyUserLineEdit->setEnabled(ui.authProxyCheckBox->isChecked()); + ui.proxyPasswLineEdit->setEnabled(ui.authProxyCheckBox->isChecked()); + + ui.softVolumeCheckBox->setChecked(settings.value("Volume/software_volume", FALSE).toBool()); +} + +void ConfigDialog::changePage ( QListWidgetItem *current, QListWidgetItem *previous ) +{ + if ( !current ) + current = previous; + ui.stackedWidget->setCurrentIndex ( ui.contentsWidget->row ( current ) ); +} + +void ConfigDialog::changeSkin() +{ + int row = ui.listWidget->currentRow(); + QString path = m_skinList.at ( row ).canonicalFilePath(); + m_skin->setSkin ( path ); +} + +void ConfigDialog::loadSkins() +{ + m_skinList.clear(); + //findSkins(":/"); + + QFileInfo fileInfo (":/default"); + QPixmap preview = Skin::getPixmap ("main", QDir (fileInfo.filePath())); + QListWidgetItem *item = new QListWidgetItem (fileInfo.fileName ()); + item->setIcon ( preview ); + ui.listWidget->addItem ( item ); + m_skinList << fileInfo; + + findSkins(QDir::homePath() +"/.qmmp/skins"); + findSkins(QDir::homePath() +"/.qmmp/cache/skins"); + findSkins(qApp->applicationDirPath()+"/../share/qmmp/skins"); + connect ( ui.listWidget, SIGNAL ( itemClicked ( QListWidgetItem* ) ), + this, SLOT ( changeSkin() ) ); +} + +void ConfigDialog::findSkins(const QString &path) +{ + QDir dir(path); + dir.setFilter ( QDir::Dirs | QDir::NoDotAndDotDot); + QList <QFileInfo> fileList = dir.entryInfoList(); + if ( fileList.count() == 0 ) + return; + foreach (QFileInfo fileInfo, fileList) + { + QPixmap preview = Skin::getPixmap ( "main", QDir ( fileInfo.filePath() ) ); + if ( !preview.isNull() ) + { + QListWidgetItem *item = new QListWidgetItem ( fileInfo.fileName () ); + item->setIcon ( preview ); + ui.listWidget->addItem ( item ); + m_skinList << fileInfo; + } + } +} + +void ConfigDialog::loadPluginsInfo() +{ + /* + load input plugins information + */ + QList <DecoderFactory *> *decoders = 0; + decoders = Decoder::decoderFactories(); + QStringList files = Decoder::decoderFiles(); + ui.inputPluginTable->setColumnCount ( 3 ); + ui.inputPluginTable->verticalHeader()->hide(); + ui.inputPluginTable->setHorizontalHeaderLabels ( QStringList() + << tr ( "Enabled" ) << tr ( "Description" ) << tr ( "Filename" ) ); + ui.inputPluginTable->setRowCount ( decoders->count () ); + for ( int i = 0; i < decoders->count (); ++i ) + { + InputPluginItem *item = new InputPluginItem(this,decoders->at(i),files.at(i)); + QCheckBox* checkBox = new QCheckBox ( ui.inputPluginTable ); + connect(checkBox, SIGNAL(toggled(bool)), item, SLOT(setSelected(bool))); + checkBox->setChecked(item->isSelected()); + ui.inputPluginTable->setCellWidget ( i, 0, checkBox ); + ui.inputPluginTable->setItem ( i,1, + new QTableWidgetItem (item->factory()->properties().name) ); + ui.inputPluginTable->setItem ( i,2, new QTableWidgetItem (files.at (i)) ); + ui.inputPluginTable->item(i,1)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui.inputPluginTable->item(i,2)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + } + ui.inputPluginTable->resizeColumnToContents ( 0 ); + ui.inputPluginTable->resizeColumnToContents ( 1 ); + ui.inputPluginTable->resizeRowsToContents (); + /* + load output plugins information + */ + QList <OutputFactory *> *outputs = 0; + outputs = Output::outputFactories(); + files = Output::outputFiles(); + ui.outputPluginTable->setColumnCount ( 3 ); + ui.outputPluginTable->verticalHeader()->hide(); + ui.outputPluginTable->setHorizontalHeaderLabels ( QStringList() + << tr ( "Enabled" ) << tr ( "Description" ) << tr ( "Filename" ) ); + ui.outputPluginTable->setRowCount ( outputs->count () ); + + for ( int i = 0; i < outputs->count (); ++i ) + { + OutputPluginItem *item = new OutputPluginItem(this,outputs->at(i),files.at(i)); + m_outputPluginItems.append(item); + QRadioButton* button = new QRadioButton ( ui.outputPluginTable ); + connect(button, SIGNAL(pressed ()), item, SLOT(select())); + button->setChecked ( item->isSelected() ); + ui.outputPluginTable->setCellWidget ( i, 0, button ); + ui.outputPluginTable->setItem (i,1, + new QTableWidgetItem (item->factory()->properties().name)); + ui.outputPluginTable->setItem (i,2, new QTableWidgetItem (files.at(i))); + ui.outputPluginTable->item(i,1)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui.outputPluginTable->item(i,2)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + } + + ui.outputPluginTable->resizeColumnToContents ( 0 ); + ui.outputPluginTable->resizeColumnToContents ( 1 ); + ui.outputPluginTable->resizeRowsToContents (); + /* + load visual plugin information + */ + QList <VisualFactory *> *visuals = 0; + visuals = Visual::visualFactories(); + files = Visual::visualFiles(); + ui.visualPluginTable->setColumnCount ( 3 ); + ui.visualPluginTable->verticalHeader()->hide(); + ui.visualPluginTable->setHorizontalHeaderLabels ( QStringList() + << tr ( "Enabled" ) << tr ( "Description" ) << tr ( "Filename" ) ); + ui.visualPluginTable->setRowCount ( visuals->count () ); + + for ( int i = 0; i < visuals->count (); ++i ) + { + VisualPluginItem *item = new VisualPluginItem(this,visuals->at(i),files.at(i)); + m_visualPluginItems.append(item); + QCheckBox* button = new QCheckBox (ui.visualPluginTable); + connect(button, SIGNAL(clicked (bool)), item, SLOT(select(bool))); + button->setChecked (item->isSelected()); + ui.visualPluginTable->setCellWidget ( i, 0, button ); + ui.visualPluginTable->setItem (i,1, + new QTableWidgetItem (item->factory()->properties().name)); + ui.visualPluginTable->setItem (i,2, new QTableWidgetItem (files.at(i))); + ui.visualPluginTable->item(i,1)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui.visualPluginTable->item(i,2)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + } + + ui.visualPluginTable->resizeColumnToContents ( 0 ); + ui.visualPluginTable->resizeColumnToContents ( 1 ); + ui.visualPluginTable->resizeRowsToContents (); + + /* + load effect plugin information + */ + QList <EffectFactory *> *effects = 0; + effects = Effect::effectFactories(); + files = Effect::effectFiles(); + ui.effectPluginTable->setColumnCount ( 3 ); + ui.effectPluginTable->verticalHeader()->hide(); + ui.effectPluginTable->setHorizontalHeaderLabels ( QStringList() + << tr ( "Enabled" ) << tr ( "Description" ) << tr ( "Filename" ) ); + ui.effectPluginTable->setRowCount ( visuals->count () ); + + for ( int i = 0; i < effects->count (); ++i ) + { + EffectPluginItem *item = new EffectPluginItem(this,effects->at(i),files.at(i)); + m_effectPluginItems.append(item); + QCheckBox* button = new QCheckBox (ui.effectPluginTable); + connect(button, SIGNAL(clicked (bool)), item, SLOT(select(bool))); + button->setChecked (item->isSelected()); + ui.effectPluginTable->setCellWidget ( i, 0, button ); + ui.effectPluginTable->setItem (i,1, + new QTableWidgetItem (item->factory()->properties().name)); + ui.effectPluginTable->setItem (i,2, new QTableWidgetItem (files.at(i))); + ui.effectPluginTable->item(i,1)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui.effectPluginTable->item(i,2)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + } + + ui.effectPluginTable->resizeColumnToContents ( 0 ); + ui.effectPluginTable->resizeColumnToContents ( 1 ); + ui.effectPluginTable->resizeRowsToContents (); + + /* + load general plugin information + */ + QList <GeneralFactory *> *generals = 0; + generals = General::generalFactories(); + files = General::generalFiles(); + ui.generalPluginTable->setColumnCount ( 3 ); + ui.generalPluginTable->verticalHeader()->hide(); + ui.generalPluginTable->setHorizontalHeaderLabels ( QStringList() + << tr ( "Enabled" ) << tr ( "Description" ) << tr ( "Filename" ) ); + ui.generalPluginTable->setRowCount ( generals->count () ); + + for ( int i = 0; i < generals->count (); ++i ) + { + GeneralPluginItem *item = new GeneralPluginItem(this,generals->at(i),files.at(i)); + m_generalPluginItems.append(item); + QCheckBox* button = new QCheckBox (ui.generalPluginTable); + connect(button, SIGNAL(clicked (bool)), item, SLOT(select(bool))); + button->setChecked (item->isSelected()); + ui.generalPluginTable->setCellWidget ( i, 0, button ); + ui.generalPluginTable->setItem (i,1, + new QTableWidgetItem (item->factory()->properties().name)); + ui.generalPluginTable->setItem (i,2, new QTableWidgetItem (files.at(i))); + ui.generalPluginTable->item(i,1)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui.generalPluginTable->item(i,2)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + } + + ui.generalPluginTable->resizeColumnToContents ( 0 ); + ui.generalPluginTable->resizeColumnToContents ( 1 ); + ui.generalPluginTable->resizeRowsToContents (); +} + + +void ConfigDialog::loadFonts() +{ + QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat ); + QString fontname = settings.value ( "PlayList/Font","" ).toString(); + if ( fontname.isEmpty () ) + fontname = QFont ( "Helvetica [Cronyx]", 10 ).toString(); + ui.plFontLabel -> setText ( fontname ); + + fontname = settings.value ( "MainWindow/Font","" ).toString(); + if ( fontname.isEmpty () ) + fontname = QFont ( "Helvetica [Cronyx]", 9 ).toString(); + ui.mainFontLabel -> setText ( fontname ); +} + +void ConfigDialog::setPlFont() +{ + bool ok; + QFont font; + font.fromString ( ui.plFontLabel->text() ); + font = QFontDialog::getFont ( &ok, font, this ); + if ( ok ) + { + ui.plFontLabel -> setText ( font.toString () ); + QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat ); + settings.setValue ( "PlayList/Font", font.toString() ); + } +} + +void ConfigDialog::setMainFont() +{ + bool ok; + QFont font; + font.fromString ( ui.plFontLabel->text() ); + font = QFontDialog::getFont ( &ok, font, this ); + if ( ok ) + { + ui.mainFontLabel -> setText ( font.toString () ); + QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat ); + settings.setValue ( "MainWindow/Font", font.toString() ); + } +} + +void ConfigDialog::showPluginSettings() +{ + switch ( ( int ) ui.pluginsTab -> currentIndex () ) + { + case 0: + { + QList <DecoderFactory *> *decoders = 0; + decoders = Decoder::decoderFactories(); + int row = ui.inputPluginTable->currentRow (); + if ( !decoders || row<0 ) + return; + + decoders->at ( row )->showSettings ( this ); + break; + } + case 1: + { + int row = ui.outputPluginTable->currentRow (); + if ( m_outputPluginItems.isEmpty() || row < 0 ) + return; + m_outputPluginItems.at(row)->factory()->showSettings ( this ); + break; + } + case 2: + { + int row = ui.visualPluginTable->currentRow (); + if ( m_visualPluginItems.isEmpty() || row < 0 ) + return; + m_visualPluginItems.at(row)->factory()->showSettings ( this ); + break; + } + case 3: + { + int row = ui.effectPluginTable->currentRow (); + if ( m_effectPluginItems.isEmpty() || row < 0 ) + return; + m_effectPluginItems.at(row)->factory()->showSettings ( this ); + break; + } + case 4: + { + int row = ui.generalPluginTable->currentRow (); + if ( m_generalPluginItems.isEmpty() || row < 0 ) + return; + m_generalPluginItems.at(row)->factory()->showSettings ( this ); + break; + } + } +} + +void ConfigDialog::showPluginInfo() +{ + switch ( ( int ) ui.pluginsTab -> currentIndex () ) + { + case 0: + { + QList <DecoderFactory *> *decoders = 0; + decoders = Decoder::decoderFactories(); + int row = ui.inputPluginTable->currentRow (); + if ( !decoders || row<0 ) + return; + + decoders->at ( row )->showAbout ( this ); + break; + } + case 1: + { + int row = ui.outputPluginTable->currentRow (); + if ( m_outputPluginItems.isEmpty() || row < 0 ) + return; + m_outputPluginItems.at(row)->factory()->showAbout ( this ); + break; + } + case 2: + { + int row = ui.visualPluginTable->currentRow (); + if ( m_visualPluginItems.isEmpty() || row < 0 ) + return; + m_visualPluginItems.at(row)->factory()->showAbout ( this ); + break; + } + case 3: + { + int row = ui.effectPluginTable->currentRow (); + if ( m_effectPluginItems.isEmpty() || row < 0 ) + return; + m_effectPluginItems.at(row)->factory()->showAbout ( this ); + break; + } + case 4: + { + int row = ui.generalPluginTable->currentRow (); + if ( m_generalPluginItems.isEmpty() || row < 0 ) + return; + m_generalPluginItems.at(row)->factory()->showAbout ( this ); + break; + } + } +} + +void ConfigDialog::createMenus() +{ + QMenu *menu = new QMenu(this); + + menu->addAction(tr("Artist"))->setData("%p"); + menu->addAction(tr("Album"))->setData("%a"); + menu->addAction(tr("Title"))->setData("%t"); + menu->addAction(tr("Tracknumber"))->setData("%n"); + menu->addAction(tr("Genre"))->setData("%g"); + menu->addAction(tr("Filename"))->setData("%f"); + menu->addAction(tr("Filepath"))->setData("%F"); + menu->addAction(tr("Date"))->setData("%d"); + menu->addAction(tr("Year"))->setData("%y"); + menu->addAction(tr("Comment"))->setData("%c"); + ui.titleButton->setMenu(menu); + ui.titleButton->setPopupMode(QToolButton::InstantPopup); + connect( menu, SIGNAL(triggered ( QAction * )), SLOT(addTitleString( QAction * ))); +} + +void ConfigDialog::addTitleString( QAction * a) +{ + if (ui.formatLineEdit->cursorPosition () < 1) + ui.formatLineEdit->insert(a->data().toString()); + else + ui.formatLineEdit->insert(" - "+a->data().toString()); +} + +void ConfigDialog::saveSettings() +{ + QSettings settings (QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat); + settings.setValue ("PlayList/title_format", ui.formatLineEdit->text()); + settings.setValue ("PlayList/load_metadata", ui.metadataCheckBox->isChecked()); + settings.setValue ("FileDialog", ui.fileDialogComboBox->currentText()); + settings.setValue ("Proxy/use_proxy", ui.enableProxyCheckBox->isChecked()); + settings.setValue ("Proxy/authentication", ui.authProxyCheckBox->isChecked()); + settings.setValue ("Proxy/host",ui.hostLineEdit->text()); + settings.setValue ("Proxy/port",ui.portLineEdit->text()); + settings.setValue ("Proxy/user",ui.proxyUserLineEdit->text()); + settings.setValue ("Proxy/passw",ui.proxyPasswLineEdit->text()); + settings.setValue ("Volume/software_volume", ui.softVolumeCheckBox->isChecked()); +} + diff --git a/src/ui/configdialog.h b/src/ui/configdialog.h new file mode 100644 index 000000000..7b9b1fab2 --- /dev/null +++ b/src/ui/configdialog.h @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef CONFIGDIALOG_H +#define CONFIGDIALOG_H + +#include <QDialog> +#include <QTreeWidgetItem> + +#include "ui_configdialog.h" + + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class QFileInfo; + +class Skin; +class InputPluginItem; +class OutputPluginItem; +class VisualPluginItem; +class EffectPluginItem; +class GeneralPluginItem; + +class ConfigDialog : public QDialog +{ + Q_OBJECT +public: + ConfigDialog(QWidget *parent = 0); + + ~ConfigDialog(); + +private slots: + void changePage(QListWidgetItem *current, QListWidgetItem *previous); + void changeSkin(); + void setPlFont(); + void setMainFont(); + void showPluginSettings(); + void showPluginInfo(); + void addTitleString( QAction * ); + void saveSettings(); + +private: + void readSettings(); + void loadSkins(); + void findSkins(const QString &path); + void loadPluginsInfo(); + void loadFonts(); + void createMenus(); + + + QList <QFileInfo> m_skinList; + Ui::ConfigDialog ui; + Skin *m_skin; + QPixmap pixmap; + + QList <InputPluginItem*> m_inputPluginItems; + QList <OutputPluginItem*> m_outputPluginItems; + QList <VisualPluginItem*> m_visualPluginItems; + QList <EffectPluginItem*> m_effectPluginItems; + QList <GeneralPluginItem*> m_generalPluginItems; +}; + +#endif diff --git a/src/ui/default/balance.png b/src/ui/default/balance.png Binary files differnew file mode 100644 index 000000000..5fa10cce8 --- /dev/null +++ b/src/ui/default/balance.png diff --git a/src/ui/default/cbuttons.png b/src/ui/default/cbuttons.png Binary files differnew file mode 100644 index 000000000..7a1369b59 --- /dev/null +++ b/src/ui/default/cbuttons.png diff --git a/src/ui/default/eq_ex.png b/src/ui/default/eq_ex.png Binary files differnew file mode 100644 index 000000000..974004590 --- /dev/null +++ b/src/ui/default/eq_ex.png diff --git a/src/ui/default/eqmain.png b/src/ui/default/eqmain.png Binary files differnew file mode 100644 index 000000000..b28b818de --- /dev/null +++ b/src/ui/default/eqmain.png diff --git a/src/ui/default/main.png b/src/ui/default/main.png Binary files differnew file mode 100644 index 000000000..6b7c8597a --- /dev/null +++ b/src/ui/default/main.png diff --git a/src/ui/default/monoster.png b/src/ui/default/monoster.png Binary files differnew file mode 100644 index 000000000..7ddb9d0e5 --- /dev/null +++ b/src/ui/default/monoster.png diff --git a/src/ui/default/numbers.png b/src/ui/default/numbers.png Binary files differnew file mode 100644 index 000000000..46f1e1f63 --- /dev/null +++ b/src/ui/default/numbers.png diff --git a/src/ui/default/playpaus.png b/src/ui/default/playpaus.png Binary files differnew file mode 100644 index 000000000..0cfbd6835 --- /dev/null +++ b/src/ui/default/playpaus.png diff --git a/src/ui/default/pledit.png b/src/ui/default/pledit.png Binary files differnew file mode 100644 index 000000000..3c2943cea --- /dev/null +++ b/src/ui/default/pledit.png diff --git a/src/ui/default/pledit.txt b/src/ui/default/pledit.txt new file mode 100644 index 000000000..549a81ad1 --- /dev/null +++ b/src/ui/default/pledit.txt @@ -0,0 +1,6 @@ +[Text]
+Normal=#C0C0C0
+Current=#8080FF
+NormalBG=#000080
+SelectedBG=#408080
+Font=Tahoma Bold
\ No newline at end of file diff --git a/src/ui/default/posbar.png b/src/ui/default/posbar.png Binary files differnew file mode 100644 index 000000000..271106557 --- /dev/null +++ b/src/ui/default/posbar.png diff --git a/src/ui/default/shufrep.png b/src/ui/default/shufrep.png Binary files differnew file mode 100644 index 000000000..107fd50bb --- /dev/null +++ b/src/ui/default/shufrep.png diff --git a/src/ui/default/text.png b/src/ui/default/text.png Binary files differnew file mode 100644 index 000000000..d37241405 --- /dev/null +++ b/src/ui/default/text.png diff --git a/src/ui/default/titlebar.png b/src/ui/default/titlebar.png Binary files differnew file mode 100644 index 000000000..c1e7818cd --- /dev/null +++ b/src/ui/default/titlebar.png diff --git a/src/ui/default/viscolor.txt b/src/ui/default/viscolor.txt new file mode 100644 index 000000000..9fbb3f64d --- /dev/null +++ b/src/ui/default/viscolor.txt @@ -0,0 +1,24 @@ +0,64,128
+0,64,128
+55,105,155
+63,111,159
+71,117,163
+79,123,167
+87,129,171
+95,135,175
+103,141,179
+111,147,183
+119,153,187
+127,159,191
+135,165,195
+143,171,199
+151,177,203
+159,183,207
+167,189,211
+175,195,215
+255,255,255
+167,189,211
+135,165,195
+119,153,187
+87,129,171
+114,223,229 diff --git a/src/ui/default/volume.png b/src/ui/default/volume.png Binary files differnew file mode 100644 index 000000000..b4f457453 --- /dev/null +++ b/src/ui/default/volume.png diff --git a/src/ui/display.cpp b/src/ui/display.cpp new file mode 100644 index 000000000..d2cce8165 --- /dev/null +++ b/src/ui/display.cpp @@ -0,0 +1,290 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QCoreApplication> +#include <QPainter> +#include <QPushButton> +#include <QLabel> +#include <QSettings> +#include <QMenu> + +#include <output.h> +#include "skin.h" +#include "mainvisual.h" +#include "button.h" +#include "titlebar.h" +#include "positionbar.h" +#include "number.h" +#include "togglebutton.h" +#include "symboldisplay.h" +#include "textscroller.h" +#include "monostereo.h" +#include "playstatus.h" +#include "volumebar.h" +#include "balancebar.h" +#include "mainwindow.h" +#include "timeindicator.h" + +#include "display.h" + +MainDisplay::MainDisplay ( QWidget *parent ) + : PixmapWidget ( parent ) +{ + m_skin = Skin::getPointer(); + setPixmap ( m_skin->getMain() ); + setMaximumSize ( QSize ( 275,116 ) ); + setMinimumSize ( QSize ( 275,116 ) ); + + m_mw = qobject_cast<MainWindow*>(parent); + + Button *previous = new Button ( this, + Skin::BT_PREVIOUS_N, Skin::BT_PREVIOUS_P ); + previous->move ( 16, 88 ); + connect ( previous,SIGNAL ( clicked() ),parent,SLOT ( previous() ) ); + Button *play = new Button ( this, + Skin::BT_PLAY_N, Skin::BT_PLAY_P ); + play->move ( 39, 88 ); + connect ( play,SIGNAL ( clicked() ),parent,SLOT ( play() ) ); + Button *pause = new Button ( this, Skin::BT_PAUSE_N,Skin::BT_PAUSE_P ); + pause->move ( 62, 88 ); + connect ( pause,SIGNAL ( clicked() ),parent,SLOT ( pause() ) ); + Button *stop = new Button ( this, Skin::BT_STOP_N,Skin::BT_STOP_P ); + stop->move ( 85, 88 ); + connect ( stop,SIGNAL ( clicked() ),parent,SLOT ( stop() ) ); + connect ( stop,SIGNAL ( clicked() ),this,SLOT ( hideTimeDisplay() ) ); + Button *next = new Button ( this, Skin::BT_NEXT_N,Skin::BT_NEXT_P ); + next->move ( 108, 88 ); + connect ( next,SIGNAL ( clicked() ),parent,SLOT ( next() ) ); + Button *eject = new Button ( this, Skin::BT_EJECT_N,Skin::BT_EJECT_P ); + eject->move ( 136, 89 ); + connect ( eject,SIGNAL ( clicked() ),parent,SLOT ( addFile() ) ); + connect ( m_skin, SIGNAL ( skinChanged() ), this, SLOT ( updateSkin() ) ); + posbar = new PositionBar ( this ); + posbar->move ( 16,72 ); + //connect(posbar, SIGNAL(sliderMoved(int)), SLOT(setTime(int))); + MainVisual* vis = new MainVisual (this); + vis->move(24,39); + vis->show(); + + m_eqButton = new ToggleButton ( this,Skin::BT_EQ_ON_N,Skin::BT_EQ_ON_P, + Skin::BT_EQ_OFF_N,Skin::BT_EQ_OFF_P ); + m_eqButton->move ( 219,58 ); + m_eqButton->show(); + m_plButton = new ToggleButton ( this,Skin::BT_PL_ON_N,Skin::BT_PL_ON_P, + Skin::BT_PL_OFF_N,Skin::BT_PL_OFF_P ); + m_plButton->move ( 241,58 ); + m_plButton->show(); + + m_repeatButton = new ToggleButton ( this,Skin::REPEAT_ON_N,Skin::REPEAT_ON_P, + Skin::REPEAT_OFF_N,Skin::REPEAT_OFF_P ); + connect(m_repeatButton,SIGNAL(clicked(bool)),this,SIGNAL(repeatableToggled(bool))); + + m_repeatButton->move ( 210,89 ); + m_repeatButton->show(); + + m_shuffleButton = new ToggleButton ( this,Skin::SHUFFLE_ON_N,Skin::SHUFFLE_ON_P, + Skin::SHUFFLE_OFF_N,Skin::SHUFFLE_OFF_P ); + connect(m_shuffleButton,SIGNAL(clicked(bool)),this,SIGNAL(shuffleToggled(bool))); + m_shuffleButton->move ( 164,89 ); + m_shuffleButton->show(); + + m_kbps = new SymbolDisplay( this,3 ); + m_kbps -> move ( 111,43 ); + m_kbps -> show(); + + m_freq = new SymbolDisplay( this,2 ); + m_freq -> move ( 156,43 ); + m_freq -> show(); + + TextScroller *m_text = new TextScroller ( this ); + m_text->resize ( 154,15 ); + m_text->move ( 109,23 ); + m_text->show(); + + m_monoster = new MonoStereo ( this ); + m_monoster->move ( 212,41 ); + m_monoster->show(); + + m_playstatus = new PlayStatus(this); + m_playstatus->move(24,28); + m_playstatus->show(); + + m_volumeBar = new VolumeBar(this); + connect(m_volumeBar, SIGNAL(sliderMoved(int)),SLOT(updateVolume())); + m_volumeBar->move(107,57); + m_volumeBar->show(); + + m_balanceBar = new BalanceBar(this); + connect(m_balanceBar, SIGNAL(sliderMoved(int)),SLOT(updateVolume())); + m_balanceBar->move(177,57); + m_balanceBar->show(); + m_timeIndicator = new TimeIndicator(this); + m_timeIndicator->move(34,26); + m_timeIndicator->show(); +} + + +MainDisplay::~MainDisplay() +{ + QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat ); + settings.setValue ( "Playlist/visible",m_plButton->isChecked() ); + settings.setValue ( "Equalizer/visible",m_eqButton->isChecked() ); +} + +void MainDisplay::setTime ( int t ) +{ + posbar->setValue ( t ); + m_timeIndicator->setTime(t); +} +void MainDisplay::setMaxTime ( long mt ) // TODO: should be removed +{ + posbar->setMax ( mt ); + m_timeIndicator->setSongDuration(mt); +} + + +void MainDisplay::updateSkin() +{ + setPixmap ( m_skin->getMain() ); +} + +void MainDisplay::setEQ ( QWidget* w ) +{ + m_equlizer = w; + m_eqButton->setON ( m_equlizer->isVisible() ); + connect (m_eqButton, SIGNAL (clicked(bool)), m_equlizer, SLOT (setVisible (bool))); + connect (m_equlizer, SIGNAL (closed ()), m_eqButton, SLOT (click())); +} + +void MainDisplay::setPL ( QWidget* w ) +{ + m_playlist = w; + m_plButton->setON ( m_playlist->isVisible() ); + connect (m_plButton, SIGNAL (clicked (bool)), m_playlist, SLOT (setVisible (bool))); + connect (m_playlist, SIGNAL (closed ()), m_plButton, SLOT (click())); +} + +void MainDisplay::setInfo(const OutputState &st) +{ + + + switch ( ( int ) st.type() ) + { + case OutputState::Info: + { + //if ( seeking ) + // break; + setTime ( st.elapsedSeconds() ); + m_kbps->display ( st.bitrate() ); + m_freq->display ( st.frequency() /1000 ); + m_monoster->setChannels ( st.channels() ); + update(); + break; + } + case OutputState::Playing: + { + m_playstatus->setStatus(PlayStatus::PLAY); + m_timeIndicator->setNeedToShowTime(true); + break; + } + case OutputState::Buffering: + { + //ui.label->setText("Buffering"); + break; + } + case OutputState::Paused: + { + m_playstatus->setStatus(PlayStatus::PAUSE); + break; + } + case OutputState::Stopped: + { + m_playstatus->setStatus(PlayStatus::STOP); + m_monoster->setChannels (0); + //m_timeIndicator->setNeedToShowTime(false); + break; + } + case OutputState::Volume: + //qDebug("volume %d, %d", st.rightVolume(), st.leftVolume()); + int maxVol = qMax(st.leftVolume(),st.rightVolume()); + m_volumeBar->setValue(maxVol); + if (maxVol && !m_volumeBar->isPressed()) + m_balanceBar->setValue((st.rightVolume()-st.leftVolume())*100/maxVol); + break; + + } +} + +bool MainDisplay::isPlaylistVisible() const +{ + return m_plButton->isChecked(); +} + +bool MainDisplay::isEqualizerVisible() const +{ + return m_eqButton->isChecked(); +} + +void MainDisplay::updateVolume() +{ + m_mw->setVolume(m_volumeBar->value(), m_balanceBar->value()); +} + +void MainDisplay::wheelEvent (QWheelEvent *e) +{ + m_mw->setVolume(m_volumeBar->value()+e->delta()/10, m_balanceBar->value()); +} + +bool MainDisplay::isRepeatable() const +{ + return m_repeatButton->isChecked(); +} + +bool MainDisplay::isShuffle() const +{ + return m_shuffleButton->isChecked(); +} + +void MainDisplay::setIsRepeatable(bool yes) +{ + m_repeatButton->setON(yes); +} + +void MainDisplay::setIsShuffle(bool yes) +{ + m_shuffleButton->setON(yes); +} + + +void MainDisplay::hideTimeDisplay() +{ + m_timeIndicator->setNeedToShowTime(false); +} + + +void MainDisplay::mousePressEvent(QMouseEvent *e) +{ + if ( e->button() == Qt::RightButton) + { + m_mw->menu()->exec(e->globalPos()); + } + PixmapWidget::mousePressEvent(e); +} + + diff --git a/src/ui/display.h b/src/ui/display.h new file mode 100644 index 000000000..15e0111d6 --- /dev/null +++ b/src/ui/display.h @@ -0,0 +1,106 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef DISPLAY_H +#define DISPLAY_H + +#include <QPixmap> + +class TimeIndicator; + + +#include "pixmapwidget.h" + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class QPushButton; +class QLabel; + +class TitleBar; +class PositionBar; +class Number; +class Skin; +class ToggleButton; +class OutputState; +class NumberDisplay; +class SymbolDisplay; +class MonoStereo; +class PlayStatus; +class VolumeBar; +class BalanceBar; +class MainWindow; + +class MainDisplay : public PixmapWidget +{ + Q_OBJECT +public: + MainDisplay(QWidget *parent = 0); + + ~MainDisplay(); + + void setMaxTime(long); + void setEQ(QWidget*); + void setPL(QWidget*); + void setInfo(const OutputState &st); + bool isEqualizerVisible()const; + bool isPlaylistVisible()const; + bool isRepeatable()const; + bool isShuffle()const; + void setIsRepeatable(bool); + void setIsShuffle(bool); + +public slots: + void setTime(int); + void hideTimeDisplay(); +signals: + void repeatableToggled(bool); + void shuffleToggled(bool); +protected: + void wheelEvent(QWheelEvent *); + void mousePressEvent(QMouseEvent*); + +private slots: + void updateSkin(); + void updateVolume(); + +private: + QWidget* m_equlizer; + QWidget* m_playlist; + QPixmap pixmap; + QPushButton *button; + QLabel *label; + Skin *m_skin; + TitleBar *titleBar; + PositionBar *posbar; + ToggleButton *m_eqButton; + ToggleButton *m_plButton; + ToggleButton *m_shuffleButton; + ToggleButton *m_repeatButton; + SymbolDisplay* m_kbps; + SymbolDisplay* m_freq; + MonoStereo* m_monoster; + PlayStatus* m_playstatus; + VolumeBar* m_volumeBar; + BalanceBar* m_balanceBar; + MainWindow* m_mw; + TimeIndicator* m_timeIndicator; +}; + +#endif diff --git a/src/ui/dock.cpp b/src/ui/dock.cpp new file mode 100644 index 000000000..2a755a9b9 --- /dev/null +++ b/src/ui/dock.cpp @@ -0,0 +1,257 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QAction> + +#include "dock.h" + + +Dock *Dock::pointer = 0; + +Dock *Dock::getPointer() +{ + if ( !pointer ) + pointer = new Dock(); + return pointer; +} + +Dock::Dock ( QObject *parent ) + : QObject ( parent ) +{ + pointer = this; + m_mainWidget = 0; +} + +Dock::~Dock() +{} + +void Dock::setMainWidget ( QWidget *widget ) +{ + m_mainWidget = widget; + m_widgetList.prepend ( widget ); + m_dockedList.prepend ( FALSE ); +} + + +QPoint Dock::snap ( QPoint npos, QWidget* mv, QWidget* st ) +{ + int nx = npos.x() - st->x(); + int ny = abs ( npos.y() - st->y() + mv->height() ); + + if ( abs ( nx ) < 13 && ny < 13 ) //above + npos.rx() = st->x(); + if ( ny < 13 && nx > -mv->width() && nx < st->width() ) + npos.ry() = st->y() - mv->height(); + nx = abs ( npos.x() + mv->width() - st->x() - st->width() ); + if ( nx < 13 && ny < 13 ) + npos.rx() = st->x() + st->width() - mv->width(); + + /***********/ + nx = npos.x() - st->x(); + ny = abs ( npos.y() - st->y() - st->height() ); + + if ( abs ( nx ) < 13 && ny < 13 ) //near + npos.rx() = st->x(); + if ( ny < 13 && nx > -mv->width() && nx < st->width() ) + npos.ry() = st->y() + st->height(); + nx = abs ( npos.x() + mv->width() - st->x() - st->width() ); + if ( nx < 13 && ny < 13 ) + npos.rx() = st->x() + st->width() - mv->width(); + /**************/ + nx = abs ( npos.x() - st->x() + mv->width() ); + ny = npos.y() - st->y(); + + if ( nx < 13 && abs ( ny ) < 13 ) //left + npos.ry() = st->y(); + if ( nx < 13 && ny > -mv->height() && ny < st->height() ) + npos.rx() = st->x() - mv->width(); + + ny = abs ( npos.y() + mv->height() - st->y() - st->height() ); + if ( nx < 13 && ny < 13 ) + npos.ry() = st->y() + st->height() - mv->height(); + /*****************/ + nx = abs ( npos.x() - st->x() - st->width() ); + ny = npos.y() - st->y(); + + if ( nx < 13 && abs ( ny ) < 13 ) //right + npos.ry() = st->y(); + if ( nx < 13 && ny > -mv->height() && ny < st->height() ) + npos.rx() = st->x() + st->width(); + + ny = abs ( npos.y() + mv->height() - st->y() - st->height() ); + if ( nx < 13 && ny < 13 ) + npos.ry() = st->y() + st->height() - mv->height(); + + return ( npos ); +} + +void Dock::addWidget ( QWidget *widget ) +{ + m_widgetList.append ( widget ); + m_dockedList.append ( FALSE ); + widget->addActions(m_actions); + +} + +void Dock::move ( QWidget* mv, QPoint npos ) +{ + if ( mv == m_mainWidget ) + { + + for ( int i = 1; i<m_widgetList.size(); ++i ) + { + if ( !m_dockedList.at ( i ) ) + { + if ( m_widgetList.at ( i )->isVisible() ) + npos = snap ( npos, mv, m_widgetList.at ( i ) ); + + } + else + { + QPoint pos = QPoint ( npos.x() + x_list.at ( i ), + npos.y() + y_list.at ( i ) ); + for ( int j = 1; j<m_widgetList.size(); ++j ) + { + if ( !m_dockedList.at ( j ) && m_widgetList.at ( j )->isVisible() ) + { + pos = snap ( pos, m_widgetList.at ( i ), m_widgetList.at ( j ) ); + npos = QPoint ( pos.x() - x_list.at ( i ), + pos.y() - y_list.at ( i ) ); + } + } + } + } + mv->move ( npos ); + for ( int i = 1; i<m_widgetList.size(); ++i ) + { + if ( m_dockedList.at ( i ) ) + m_widgetList.at ( i )->move ( npos.x() + x_list.at ( i ), + npos.y() + y_list.at ( i ) ); + } + } + else + { + for ( int i = 0; i<m_widgetList.size(); ++i ) + { + m_dockedList[i] = FALSE; + if ( mv!=m_widgetList.at ( i ) && !m_dockedList.at ( i ) && m_widgetList.at ( i )->isVisible() ) + { + npos = snap ( npos, mv, m_widgetList.at ( i ) ); + } + } + mv->move ( npos ); + } +} + +void Dock::calculateDistances() +{ + x_list.clear(); + y_list.clear(); + foreach ( QWidget *w, m_widgetList ) + { + if ( w!=m_mainWidget ) + { + x_list.append ( - m_mainWidget->x() + w->x() ); + y_list.append ( - m_mainWidget->y() + w->y() ); + } + else + { + x_list.prepend ( 0 ); + y_list.prepend ( 0 ); + } + } +} + +void Dock::updateDock() +{ + QWidget *mv = m_widgetList.at ( 0 ); + for ( int j = 1; j<m_widgetList.size(); ++j ) + { + QWidget *st = m_widgetList.at ( j ); + m_dockedList[j] = isDocked ( mv, st ); + } + for ( int j = 1; j<m_widgetList.size(); ++j ) + { + if ( m_dockedList[j] ) + for ( int i = 1; i<m_widgetList.size(); ++i ) + { + if ( !m_dockedList[i] ) + { + mv = m_widgetList.at ( j ); + QWidget *st = m_widgetList.at ( i ); + m_dockedList[i] = isDocked ( mv, st ); + } + } + } + +} + +bool Dock::isDocked ( QWidget* mv, QWidget* st ) +{ + int nx = mv->x() - st->x(); + int ny = abs ( mv->y() - st->y() + mv->height() ); + if ( ny < 2 && nx > -mv->width() && nx < st->width() ) //above + return TRUE; + + /***********/ + nx = mv->x() - st->x(); + ny = abs ( mv->y() - st->y() - st->height() ); + if ( ny < 2 && nx > -mv->width() && nx < st->width() ) //near + return TRUE; + + /**************/ + nx = abs ( mv->x() - st->x() + mv->width() ); + ny = mv->y() - st->y(); + if ( nx < 2 && ny > -mv->height() && ny < st->height() ) //left + return TRUE; + + /*****************/ + nx = abs ( mv->x() - st->x() - st->width() ); + ny = mv->y() - st->y(); + if ( nx < 2 && ny > -mv->height() && ny < st->height() ) //right + return TRUE; + return FALSE; +} + +void Dock::addActions ( QList<QAction *> actions ) +{ + m_actions << actions; + for ( int i = 0; i<m_widgetList.size(); ++i ) + m_widgetList.at ( i )->addActions ( actions ); +} + +bool Dock::isUnder(QWidget* upper, QWidget* nether, int dy) +{ + int nx = upper->x() - nether->x(); + return abs (upper->y() + upper->height() -dy - nether->y()) < 2 && + nx > -upper->width() && nx < nether->width(); +} + +void Dock::align(QWidget* w, int dy) +{ + for (int i = 0; i<m_dockedList.size(); ++i) + { + if (m_widgetList.at(i) != w && isUnder(w, m_widgetList.at(i), dy)) + { + m_widgetList.at(i)->move(m_widgetList.at(i)->x(), m_widgetList.at(i)->y()+dy); + align(m_widgetList.at(i), dy); + } + } +} diff --git a/src/ui/dock.h b/src/ui/dock.h new file mode 100644 index 000000000..b4b62dda2 --- /dev/null +++ b/src/ui/dock.h @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef DOCK_H +#define DOCK_H + +#include <QObject> +#include <QPoint> +#include <QWidget> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + +class QAction; + +class Dock : public QObject +{ + Q_OBJECT +public: + Dock(QObject *parent = 0); + + ~Dock(); + + static Dock *getPointer(); + void setMainWidget(QWidget*); + void addWidget(QWidget *); + void move(QWidget*, QPoint); + void calculateDistances(); + void updateDock(); + QPoint snap(QPoint, QWidget*, QWidget*); + void addActions(QList<QAction *> actions); + void align(QWidget*, int dy); + +private: + bool isDocked(QWidget*, QWidget*); + bool isUnder(QWidget*, QWidget*, int); + static Dock *pointer; + QWidget *m_mainWidget; + QList <QWidget *> m_widgetList; + QList <bool> m_dockedList; + QList <int> x_list; + QList <int> y_list; + QList <QAction *> m_actions; +}; + +#endif diff --git a/src/ui/eqgraph.cpp b/src/ui/eqgraph.cpp new file mode 100644 index 000000000..314e504d9 --- /dev/null +++ b/src/ui/eqgraph.cpp @@ -0,0 +1,163 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QPainter> + +#include "skin.h" +#include "eqgraph.h" + +EQGraph::EQGraph ( QWidget *parent ) + : PixmapWidget ( parent ) +{ + m_skin = Skin::getPointer(); + setPixmap ( m_skin->getEqPart ( Skin::EQ_GRAPH ) ); + clear(); + draw(); + connect ( m_skin, SIGNAL ( skinChanged() ), this, SLOT ( updateSkin() ) ); +} + + +EQGraph::~EQGraph() +{} + +void EQGraph::addValue ( int value ) +{ + if ( m_values.size() >= 10 ) + return; + m_values.append ( value ); + if ( m_values.size() == 10 ) + { + draw(); + } +} + +void EQGraph::clear () +{ + m_values.clear(); + update(); +} + +void EQGraph::init_spline ( double * x, double * y, int n, double * y2 ) +{ + int i, k; + double p, qn, sig, un, *u; + + //u = ( gfloat * ) g_malloc ( n * sizeof ( gfloat ) ); + u = new double[n]; + + y2[0] = u[0] = 0.0; + + for ( i = 1; i < n - 1; i++ ) + { + sig = ( ( double ) x[i] - x[i - 1] ) / ( ( double ) x[i + 1] - x[i - 1] ); + p = sig * y2[i - 1] + 2.0; + y2[i] = ( sig - 1.0 ) / p; + u[i] = + ( ( ( double ) y[i + 1] - y[i] ) / ( x[i + 1] - x[i] ) ) - + ( ( ( double ) y[i] - y[i - 1] ) / ( x[i] - x[i - 1] ) ); + u[i] = ( 6.0 * u[i] / ( x[i + 1] - x[i - 1] ) - sig * u[i - 1] ) / p; + } + qn = un = 0.0; + + y2[n - 1] = ( un - qn * u[n - 2] ) / ( qn * y2[n - 2] + 1.0 ); + for ( k = n - 2; k >= 0; k-- ) + y2[k] = y2[k] * y2[k + 1] + u[k]; + //g_free ( u ); + delete[] u; +} + +double EQGraph::eval_spline ( double xa[], double ya[], double y2a[], int n, double x ) +{ + int klo, khi, k; + double h, b, a; + + klo = 0; + khi = n - 1; + while ( khi - klo > 1 ) + { + k = ( khi + klo ) >> 1; + if ( xa[k] > x ) + khi = k; + else + klo = k; + } + h = xa[khi] - xa[klo]; + a = ( xa[khi] - x ) / h; + b = ( x - xa[klo] ) / h; + return ( a * ya[klo] + b * ya[khi] + + ( ( a * a * a - a ) * y2a[klo] + + ( b * b * b - b ) * y2a[khi] ) * ( h * h ) / 6.0 ); +} + +void EQGraph::draw() +{ + if(m_values.size()!=10) + { + setPixmap ( m_skin->getEqPart ( Skin::EQ_GRAPH ) ); + return; + } + + int i, y, ymin, ymax, py = 0; + double x[] = { 0, 11, 23, 35, 47, 59, 71, 83, 97, 109 }, yf[10]; + double *bands = new double[10]; + + for ( int i = 0; i<10; ++i ) + { + bands[i] = m_values.at ( i ); + } + QPixmap pixmap = m_skin->getEqPart ( Skin::EQ_GRAPH ); + + init_spline ( x, bands, 10, yf ); + for ( i = 0; i < 109; i++ ) + { + y = 9 - + ( int ) ( ( eval_spline ( x, bands, yf, 10, i ) * + 9.0 ) / 20.0 ); + if ( y < 0 ) + y = 0; + if ( y > 18 ) + y = 18; + if ( !i ) + py = y; + if ( y < py ) + { + ymin = y; + ymax = py; + } + else + { + ymin = py; + ymax = y; + } + py = y; + + QPainter paint ( &pixmap ); + paint.drawPixmap ( i, y, m_skin->getEqSpline ( y ) ) ; + + + } + setPixmap ( pixmap ); + delete [] bands; +} + +void EQGraph::updateSkin() +{ + draw(); +} + diff --git a/src/ui/eqgraph.h b/src/ui/eqgraph.h new file mode 100644 index 000000000..4f6bf1882 --- /dev/null +++ b/src/ui/eqgraph.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef EQGRAPH_H +#define EQGRAPH_H + +#include "pixmapwidget.h" + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + +class Skin; + +class EQGraph : public PixmapWidget +{ + Q_OBJECT +public: + EQGraph ( QWidget *parent = 0 ); + + ~EQGraph(); + + void addValue ( int ); + void clear(); + +/*protected: + void paintEvent ( QPaintEvent * );*/ +private slots: + void updateSkin(); + +private: + QList <int> m_values; + Skin *m_skin; + void init_spline ( double * x, double * y, int n, double * y2 ); + double eval_spline ( double xa[], double ya[], double y2a[], int n, double x ); + void draw(); + +}; + +#endif diff --git a/src/ui/eqpreset.cpp b/src/ui/eqpreset.cpp new file mode 100644 index 000000000..760dea9d2 --- /dev/null +++ b/src/ui/eqpreset.cpp @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "eqpreset.h" + +EQPreset::EQPreset() + : QListWidgetItem() +{ + m_preamp = 0; + for(int i = 0; i < 10; ++i) + m_bands[i] = 0; +} + + +EQPreset::~EQPreset() +{} + +void EQPreset::setGain(int n, int value) +{ + if(n > 9 || n < 0) + return; + m_bands[n] = value; +} + +void EQPreset::setPreamp(int preamp) +{ + m_preamp = preamp; +} + +int EQPreset::gain(int n) +{ + if(n > 9 || n < 0) + return 0; + return m_bands[n]; +} + +int EQPreset::preamp() +{ + return m_preamp; +} diff --git a/src/ui/eqpreset.h b/src/ui/eqpreset.h new file mode 100644 index 000000000..80f31747e --- /dev/null +++ b/src/ui/eqpreset.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef EQPRESET_H +#define EQPRESET_H + +#include <QListWidgetItem> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class EQPreset : public QListWidgetItem +{ +public: + EQPreset(); + + ~EQPreset(); + + void setGain(int n, int value); + void setPreamp(int); + + int gain(int n); + int preamp(); + +private: + int m_bands[10]; + int m_preamp; + +}; + +#endif diff --git a/src/ui/eqslider.cpp b/src/ui/eqslider.cpp new file mode 100644 index 000000000..bdc4ec4e2 --- /dev/null +++ b/src/ui/eqslider.cpp @@ -0,0 +1,147 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QMouseEvent> +#include <QPainter> +#include <QWheelEvent> +#include <math.h> + +#include "skin.h" + +#include "eqslider.h" + + +EqSlider::EqSlider(QWidget *parent) + : PixmapWidget(parent) +{ + m_skin = Skin::getPointer(); + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); + setPixmap(m_skin->getEqSlider(0)); + m_moving = FALSE; + m_min = -20; + m_max = 20; + m_old = m_value = 0; + draw(FALSE); +} + + +EqSlider::~EqSlider() +{} + +void EqSlider::mousePressEvent(QMouseEvent *e) +{ + m_moving = TRUE; + press_pos = e->y(); + if (m_pos<e->y() && e->y()<m_pos+11) + { + press_pos = e->y()-m_pos; + } + else + { + m_value = convert(qMax(qMin(height()-12,e->y()-6),0)); + press_pos = 6; + if (m_value!=m_old) + { + emit sliderMoved(m_value); + m_old = m_value; + //qDebug ("%d",m_value); + } + } + draw(); +} + +void EqSlider::mouseReleaseEvent(QMouseEvent*) +{ + m_moving = FALSE; + draw(FALSE); +} + +void EqSlider::mouseMoveEvent(QMouseEvent* e) +{ + if (m_moving) + { + int po = e->y(); + po = po - press_pos; + + if (0<=po && po<=height()-12) + { + m_value = convert(po); + draw(); + if (m_value!=m_old) + { + + m_old = m_value; + //qDebug ("%d",-m_value); + emit sliderMoved(-m_value); + } + } + } +} + +int EqSlider::value() +{ + return -m_value; +} + +void EqSlider::setValue(int p) +{ + if (m_moving) + return; + m_value = -p; + draw(FALSE); +} + +void EqSlider::setMax(int m) +{ + m_max = m; + draw(FALSE); +} + +void EqSlider::updateSkin() +{ + draw(FALSE); +} + +void EqSlider::draw(bool pressed) +{ + int p=int(ceil(double(m_value-m_min)*(height()-12)/(m_max-m_min))); + m_pixmap = m_skin->getEqSlider(27-27*(m_value-m_min)/(m_max-m_min)); + QPainter paint(&m_pixmap); + if (pressed) + paint.drawPixmap(1,p,m_skin->getButton(Skin::EQ_BT_BAR_P)); + else + paint.drawPixmap(1,p,m_skin->getButton(Skin::EQ_BT_BAR_N)); + setPixmap(m_pixmap); + m_pos = p; +} + +int EqSlider::convert(int p) +{ + return int(ceil(double(m_max-m_min)*(p)/(height()-12)+m_min)); +} + +void EqSlider::wheelEvent(QWheelEvent *e) +{ + m_value -= e->delta()/60; + m_value = m_value > m_max ? m_max : m_value; + m_value = m_value < m_min ? m_min : m_value; + draw(FALSE); + emit sliderMoved(m_value); +} + diff --git a/src/ui/eqslider.h b/src/ui/eqslider.h new file mode 100644 index 000000000..54dc9f285 --- /dev/null +++ b/src/ui/eqslider.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef EQSLIDER_H +#define EQSLIDER_H + +#include <pixmapwidget.h> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class QMouseEvent; +class QWheelEvent; + +class Skin; + +class EqSlider : public PixmapWidget +{ +Q_OBJECT +public: + EqSlider(QWidget *parent = 0); + + ~EqSlider(); + + int value(); + +public slots: + void setValue(int); + void setMax(int); + +signals: + void sliderMoved (int); + +private slots: + void updateSkin(); + +private: + Skin *m_skin; + bool m_moving; + int press_pos; + int m_max, m_min, m_pos, m_value, m_old; + QPixmap m_pixmap; + int convert(int); // value = convert(position); + void draw(bool pressed = TRUE); + +protected: + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + void wheelEvent(QWheelEvent *); + + +}; + +#endif diff --git a/src/ui/eqtitlebar.cpp b/src/ui/eqtitlebar.cpp new file mode 100644 index 000000000..5420831f8 --- /dev/null +++ b/src/ui/eqtitlebar.cpp @@ -0,0 +1,182 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QMouseEvent> +#include <QMenu> +#include <QSettings> + +#include "skin.h" +#include "shadedbar.h" +#include "dock.h" +#include "mainwindow.h" +#include "button.h" + +#include "eqtitlebar.h" + +EqTitleBar::EqTitleBar(QWidget *parent) + : PixmapWidget(parent) +{ + m_volumeBar = 0; + m_balanceBar = 0; + m_shade2 = 0; + m_left = 0; + m_right = 0; + m_shaded = FALSE; + m_align = FALSE; + m_skin = Skin::getPointer(); + m_eq = parentWidget(); + m_mw = qobject_cast<MainWindow*>(m_eq->parent()); + m_close = new Button(this, Skin::EQ_BT_CLOSE_N, Skin::EQ_BT_CLOSE_P); + connect(m_close, SIGNAL(clicked()),m_eq, SIGNAL(closed())); + m_close->move(264,3); + m_shade = new Button(this, Skin::EQ_BT_SHADE1_N, Skin::EQ_BT_SHADE1_P); + connect(m_shade, SIGNAL(clicked()), SLOT(shade())); + m_shade->move(254,3); + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + if (settings.value("Equalizer/shaded", FALSE).toBool()) + shade(); + m_align = TRUE; + setActive(FALSE); +} + + +EqTitleBar::~EqTitleBar() +{ + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + settings.setValue("Equalizer/shaded", m_shaded); +} + +void EqTitleBar::setActive(bool active) +{ + if (active) + { + if (m_shaded) + { + setPixmap(m_skin->getEqPart(Skin::EQ_TITLEBAR_SHADED_A)); + m_shade2->show(); + } + else + { + setPixmap(m_skin->getEqPart(Skin::EQ_TITLEBAR_A)); + m_shade->show(); + } + m_close->show(); + } + else + { + if (m_shaded) + { + setPixmap(m_skin->getEqPart(Skin::EQ_TITLEBAR_SHADED_I)); + m_shade2->hide(); + } + else + { + setPixmap(m_skin->getEqPart(Skin::EQ_TITLEBAR_I)); + m_shade->hide(); + } + m_close->hide(); + } +} + +void EqTitleBar::setVolume(int left, int right) +{ + m_left = left; + m_right = right; + if (m_volumeBar && m_balanceBar) + { + int maxVol = qMax(left, right); + m_volumeBar->setValue(maxVol); + if (maxVol && !m_volumeBar->isPressed()) + m_balanceBar->setValue((right - left)*100/maxVol); + } +} + +void EqTitleBar::mousePressEvent(QMouseEvent* event) +{ + switch ((int) event->button ()) + { + case Qt::LeftButton: + { + m_pos = event->pos(); + break; + } + case Qt::RightButton: + { + m_mw->menu()->exec(event->globalPos()); + } + } +} + +void EqTitleBar::mouseMoveEvent(QMouseEvent* event) +{ + QPoint npos = (event->globalPos()-m_pos); + Dock::getPointer()->move(m_eq, npos); +} + +void EqTitleBar::mouseReleaseEvent(QMouseEvent*) +{ + Dock::getPointer()->updateDock(); +} + +void EqTitleBar::shade() +{ + m_shaded = !m_shaded; + + if (m_shaded) + { + m_eq->setFixedSize(275,14); + setPixmap(m_skin->getEqPart(Skin::EQ_TITLEBAR_SHADED_A)); + m_shade->hide(); + m_shade2 = new Button(this, Skin::EQ_BT_SHADE2_N, Skin::EQ_BT_SHADE2_P); + m_shade2->move(254,3); + connect(m_shade2, SIGNAL(clicked()), SLOT(shade())); + m_shade2->show(); + m_volumeBar = new ShadedBar(this, Skin::EQ_VOLUME1, Skin::EQ_VOLUME2, Skin::EQ_VOLUME3); + m_volumeBar->move(61,4); + m_volumeBar->show(); + connect(m_volumeBar, SIGNAL(sliderMoved(int)),SLOT(updateVolume())); + m_balanceBar = new ShadedBar(this, Skin::EQ_BALANCE1, Skin::EQ_BALANCE2, Skin::EQ_BALANCE3); + m_balanceBar->move(164,4); + m_balanceBar->setFixedSize(42,7); + m_balanceBar->setRange(-100,100); + m_balanceBar->show(); + connect(m_balanceBar, SIGNAL(sliderMoved(int)),SLOT(updateVolume())); + setVolume(m_left, m_right); //show current volume and balance + } + else + { + m_eq->setFixedSize(275,116); + setPixmap(m_skin->getEqPart(Skin::EQ_TITLEBAR_A)); + delete m_shade2; + delete m_volumeBar; + delete m_balanceBar; + m_volumeBar = 0; + m_balanceBar = 0; + m_shade2 = 0; + m_shade->show(); + } + if (m_align) + Dock::getPointer()->align(m_eq, m_shaded? -102: 102); +} + +void EqTitleBar::updateVolume() +{ + m_mw->setVolume(m_volumeBar->value(), m_balanceBar->value()); +} + diff --git a/src/ui/eqtitlebar.h b/src/ui/eqtitlebar.h new file mode 100644 index 000000000..d3e9a0452 --- /dev/null +++ b/src/ui/eqtitlebar.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef EQTITLEBAR_H +#define EQTITLEBAR_H + +#include <pixmapwidget.h> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + +class QMouseEvent; + +class Skin; +class MainWindow; +class Button; +class ShadedBar; + +class EqTitleBar : public PixmapWidget +{ +Q_OBJECT +public: + EqTitleBar(QWidget *parent = 0); + + ~EqTitleBar(); + + void setActive(bool); + void setVolume(int left, int right); + +private slots: + void shade(); + void updateVolume(); + +private: + Skin* m_skin; + bool m_active; + int m_left; + int m_right; + QPoint m_pos; + QWidget* m_eq; + MainWindow* m_mw; + Button* m_close; + Button* m_shade; + Button* m_shade2; + bool m_shaded, m_align; + ShadedBar* m_volumeBar; + ShadedBar* m_balanceBar; + +protected: + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + +}; + +#endif diff --git a/src/ui/eqwidget.cpp b/src/ui/eqwidget.cpp new file mode 100644 index 000000000..d86ab45d2 --- /dev/null +++ b/src/ui/eqwidget.cpp @@ -0,0 +1,417 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QSettings> +#include <QEvent> +#include <QMenu> +#include <QInputDialog> + +#include "filedialog.h" +#include "skin.h" +#include "eqslider.h" +#include "eqtitlebar.h" +#include "togglebutton.h" +#include "eqgraph.h" +#include "button.h" +#include "eqpreset.h" +#include "preseteditor.h" +#include "mainwindow.h" +#include "playlist.h" +#include "eqwidget.h" + + + +EqWidget::EqWidget ( QWidget *parent ) + : PixmapWidget ( parent ) +{ + m_skin = Skin::getPointer(); + setWindowFlags ( Qt::Dialog | Qt::FramelessWindowHint ); + setPixmap ( m_skin->getEqPart ( Skin::EQ_MAIN ) ); + //setPixmap(QPixmap(275,116)); + m_titleBar = new EqTitleBar ( this ); + m_titleBar -> move ( 0,0 ); + m_titleBar -> show(); + connect ( m_skin, SIGNAL ( skinChanged() ), this, SLOT ( updateSkin() ) ); + + m_preamp = new EqSlider ( this ); + m_preamp->show(); + m_preamp->move ( 21,38 ); + connect ( m_preamp,SIGNAL ( sliderMoved ( int ) ),SLOT ( setPreamp () ) ); + + m_on = new ToggleButton ( this,Skin::EQ_BT_ON_N,Skin::EQ_BT_ON_P, + Skin::EQ_BT_OFF_N,Skin::EQ_BT_OFF_P ); + m_on->show(); + m_on->move ( 14,18 ); + connect (m_on, SIGNAL (clicked(bool)), SIGNAL(valueChanged())); + + m_autoButton = new ToggleButton(this, Skin::EQ_BT_AUTO_1_N, Skin::EQ_BT_AUTO_1_P, + Skin::EQ_BT_AUTO_0_N, Skin::EQ_BT_AUTO_0_P); + m_autoButton->move(39, 18); + m_autoButton->show(); + + m_eqg = new EQGraph(this); + m_eqg->move(87,17); + m_eqg->show(); + + m_presetsMenu = new QMenu(this); + + m_presetButton = new Button ( this, Skin::EQ_BT_PRESETS_N, Skin::EQ_BT_PRESETS_P); + m_presetButton->move(217,18); + m_presetButton->show(); + + connect(m_presetButton, SIGNAL(clicked()), SLOT(showPresetsMenu())); + + for ( int i = 0; i<10; ++i ) + { + m_sliders << new EqSlider ( this ); + m_sliders.at ( i )->move ( 78+i*18,38 ); + m_sliders.at ( i )->show(); + connect (m_sliders.at (i), SIGNAL ( sliderMoved (int) ),SLOT (setGain())); + } + readSettings(); + createActions(); +} + +EqWidget::~EqWidget() +{ + while (!m_presets.isEmpty()) + delete m_presets.takeFirst(); + while (!m_autoPresets.isEmpty()) + delete m_autoPresets.takeFirst(); +} + +int EqWidget::preamp() +{ + return m_preamp->value(); +} + +int EqWidget::gain ( int g ) +{ + return m_sliders.at ( g )->value(); +} + +void EqWidget::changeEvent ( QEvent * event ) +{ + if (event->type() == QEvent::ActivationChange) + { + m_titleBar->setActive(isActiveWindow()); + } +} + +void EqWidget::closeEvent ( QCloseEvent* ) +{ + writeSettings(); +} + +void EqWidget::updateSkin() +{ + m_titleBar->setActive ( FALSE ); + setPixmap ( m_skin->getEqPart ( Skin::EQ_MAIN ) ); +} + +void EqWidget::readSettings() +{ + QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat ); + settings.beginGroup ( "Equalizer" ); + //geometry + move ( settings.value ( "pos", QPoint ( 100, 216 ) ).toPoint() ); + //equalizer + for (int i = 0; i < m_sliders.size(); ++i) + m_sliders.at(i)->setValue(settings.value("band_"+ + QString("%1").arg(i), 0).toInt()); + m_preamp->setValue(settings.value("preamp", 0).toInt()); + m_on->setON(settings.value("enabled", FALSE).toBool()); + settings.endGroup(); + setGain(); + //equalizer presets + QSettings eq_preset (QDir::homePath() +"/.qmmp/eq.preset", QSettings::IniFormat ); + for (int i = 1; TRUE; ++i) + { + if (eq_preset.contains("Presets/Preset"+QString("%1").arg(i))) + { + QString name = eq_preset.value("Presets/Preset"+QString("%1").arg(i), + tr("preset")).toString(); + EQPreset *preset = new EQPreset(); + preset->setText(name); + eq_preset.beginGroup(name); + for (int j = 0; j < 10; ++j) + { + preset->setGain(j,eq_preset.value("Band"+QString("%1").arg(j), + 0).toInt()); + } + preset->setPreamp(eq_preset.value("Preamp",0).toInt()); + m_presets.append(preset); + eq_preset.endGroup(); + } + else + break; + } + //equalizer auto-load presets + QSettings eq_auto (QDir::homePath() +"/.qmmp/eq.auto_preset", QSettings::IniFormat ); + for (int i = 1; TRUE; ++i) + { + if (eq_auto.contains("Presets/Preset"+QString("%1").arg(i))) + { + QString name = eq_auto.value("Presets/Preset"+QString("%1").arg(i), + tr("preset")).toString(); + EQPreset *preset = new EQPreset(); + preset->setText(name); + eq_auto.beginGroup(name); + for (int j = 0; j < 10; ++j) + { + preset->setGain(j,eq_auto.value("Band"+QString("%1").arg(j), + 0).toInt()); + } + preset->setPreamp(eq_auto.value("Preamp",0).toInt()); + m_autoPresets.append(preset); + eq_auto.endGroup(); + } + else + break; + } +} + +void EqWidget::writeSettings() +{ + QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat ); + settings.beginGroup ( "Equalizer" ); + //geometry + settings.setValue ( "pos", this->pos() ); + //equalizer + for (int i = 0; i < m_sliders.size(); ++i) + settings.setValue("band_"+QString("%1").arg(i), m_sliders.at(i)->value()); + settings.setValue("preamp", m_preamp->value()); + settings.setValue("enabled",m_on->isChecked()); + settings.endGroup(); + //equalizer presets + QSettings eq_preset (QDir::homePath() +"/.qmmp/eq.preset", QSettings::IniFormat ); + eq_preset.clear (); + for (int i = 0; i < m_presets.size(); ++i) + { + eq_preset.setValue("Presets/Preset"+QString("%1").arg(i+1), + m_presets.at(i)->text()); + eq_preset.beginGroup(m_presets.at(i)->text()); + for (int j = 0; j < 10; ++j) + { + eq_preset.setValue("Band"+QString("%1").arg(j),m_presets.at(i)->gain(j)); + } + eq_preset.setValue("Preamp",m_presets.at(i)->preamp()); + eq_preset.endGroup(); + } + //equalizer auto-load presets + QSettings eq_auto (QDir::homePath() +"/.qmmp/eq.auto_preset", + QSettings::IniFormat ); + eq_auto.clear(); + for (int i = 0; i < m_autoPresets.size(); ++i) + { + eq_auto.setValue("Presets/Preset"+QString("%1").arg(i+1), + m_autoPresets.at(i)->text()); + eq_auto.beginGroup(m_autoPresets.at(i)->text()); + for (int j = 0; j < 10; ++j) + { + eq_auto.setValue("Band"+QString("%1").arg(j),m_autoPresets.at(i)->gain(j)); + } + eq_auto.setValue("Preamp",m_autoPresets.at(i)->preamp()); + eq_auto.endGroup(); + } +} + +void EqWidget::setPreamp () +{ + emit valueChanged(); +} + +void EqWidget::setGain() +{ + m_eqg->clear(); + for (int i=0; i<10; ++i) + { + int value = m_sliders.at(i)->value(); + m_eqg->addValue(value); + } + emit valueChanged(); +} + +bool EqWidget::isEQEnabled() +{ + return m_on->isChecked(); +} + +void EqWidget::createActions() +{ + m_presetsMenu->addAction(tr("&Load/Delete"),this, SLOT(showEditor())); + m_presetsMenu->addSeparator(); + m_presetsMenu->addAction(tr("&Save Preset"),this,SLOT(savePreset())); + m_presetsMenu->addAction(tr("&Save Auto-load Preset"),this,SLOT(saveAutoPreset())); + m_presetsMenu->addAction(tr("&Import"),this,SLOT(importWinampEQF())); + m_presetsMenu->addSeparator(); + m_presetsMenu->addAction(tr("&Clear"),this, SLOT(reset())); +} + +void EqWidget::showPresetsMenu() +{ + m_presetsMenu->exec(m_presetButton->mapToGlobal(QPoint(0, 0))); +} + +void EqWidget::reset() +{ + for (int i = 0; i < m_sliders.size(); ++i) + m_sliders.at(i)->setValue(0); + m_preamp->setValue(0); + setGain(); +} + +void EqWidget::showEditor() +{ + PresetEditor *editor = new PresetEditor(this); + editor->addPresets(m_presets); + editor->addAutoPresets(m_autoPresets); + connect (editor, SIGNAL(presetLoaded(EQPreset*)), SLOT(setPreset(EQPreset*))); + connect (editor, SIGNAL(presetDeleted(EQPreset*)), SLOT(deletePreset(EQPreset*))); + editor->show(); +} + +void EqWidget::savePreset() +{ + bool ok; + QString text = QInputDialog::getText(this, tr("Saving Preset"), + tr("Preset name:"), QLineEdit::Normal, + tr("preset #")+QString("%1").arg(m_presets.size()+1), &ok); + if (ok) + { + EQPreset* preset = new EQPreset; + preset->setText(text); + preset->setPreamp(m_preamp->value()); + for (int i = 0; i<10; ++i) + { + preset->setGain(i, m_sliders.at (i)->value()); + } + m_presets.append(preset); + } +} + +void EqWidget::saveAutoPreset() +{ + PlayList* playlist = qobject_cast<MainWindow*>(parent())->getPLPointer(); + if (!playlist->currentItem()) + return; + //delete preset if it already exists + EQPreset* preset = findPreset(playlist->currentItem()->fileName()); + if (preset) + deletePreset(preset); + //create new preset + preset = new EQPreset(); + preset->setText(playlist->currentItem()->fileName()); + preset->setPreamp(m_preamp->value()); + for (int i = 0; i<10; ++i) + { + preset->setGain(i, m_sliders.at (i)->value()); + } + m_autoPresets.append(preset); +} + +void EqWidget::setPreset(EQPreset* preset) +{ + for (int i = 0; i<10; ++i) + m_sliders.at(i)->setValue(preset->gain(i)); + m_preamp->setValue(preset->preamp()); + setGain(); +} + +void EqWidget::deletePreset(EQPreset* preset) +{ + int p = m_presets.indexOf(preset); + if (p != -1) + { + delete m_presets.takeAt(p); + return; + } + p = m_autoPresets.indexOf(preset); + if (p != -1) + { + delete m_autoPresets.takeAt(p); + return; + } +} + +void EqWidget::loadPreset(const QString &name) +{ + if (m_autoButton->isChecked()) + { + EQPreset *preset = findPreset(name); + if (preset) + setPreset(preset); + else + reset(); + } +} + +void EqWidget::setInfo(const OutputState &st) +{ + if (st.type() == OutputState::Volume) + { + m_titleBar->setVolume(st.leftVolume(),st.rightVolume()); + + } +} + +EQPreset *EqWidget::findPreset(const QString &name) +{ + foreach(EQPreset *preset, m_autoPresets) + { + if (preset->text() == name) + return preset; + } + return 0; +} + +void EqWidget::importWinampEQF() +{ + char header[31]; + char name[257]; + char bands[11]; + QString path = FileDialog::getOpenFileName(this, tr("Import Preset"), + "/home", + QString("Winamp EQF (*.q1)"),NULL,true); + + QFile file(path); + file.open(QIODevice::ReadOnly); + file.read ( header, 31); + if (QString::fromAscii(header).contains("Winamp EQ library file v1.1")) + { + + while (file.read ( name, 257)) + { + EQPreset* preset = new EQPreset; + preset->setText(QString::fromAscii(name)); + + file.read(bands,11); + + for (int i = 0; i<10; ++i) + { + preset->setGain(i, 20 - bands[i]*40/64); + } + preset->setPreamp(20 - bands[10]*40/64); + m_presets.append(preset); + } + + } + file.close(); + +} diff --git a/src/ui/eqwidget.h b/src/ui/eqwidget.h new file mode 100644 index 000000000..94cd564d5 --- /dev/null +++ b/src/ui/eqwidget.h @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef EQWIDGET_H +#define EQWIDGET_H + +#include <pixmapwidget.h> +#include <output.h> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + +class QMenu; +class Skin; +class EqTitleBar; +class EqSlider; +class ToggleButton; +class EQGraph; +class Button; +class EQPreset; +class MediaFile; + +class EqWidget : public PixmapWidget +{ + Q_OBJECT +public: + EqWidget(QWidget *parent = 0); + + ~EqWidget(); + + int preamp(); + int gain(int); + bool isEQEnabled(); + /*! + * necessary for auto-load presets + */ + void loadPreset(const QString &name); + + /*! + * shows output volume and balance. Necessare for the shaded mode + */ + void setInfo(const OutputState &st); + +signals: + void valueChanged(); + void closed(); + +private slots: + void updateSkin(); + void setPreamp(); + void setGain(); + void showPresetsMenu(); + void reset(); + void showEditor(); + void savePreset(); + void saveAutoPreset(); + void setPreset(EQPreset*); + void deletePreset(EQPreset*); + void importWinampEQF(); + +private: + void readSettings(); + void writeSettings(); + void createActions(); + EQPreset *findPreset(const QString &name); + Skin *m_skin; + EqTitleBar *m_titleBar; + EqSlider *m_preamp; + Button *m_presetButton; + QList<EqSlider*> m_sliders; + QPoint m_pos; + ToggleButton *m_on; + ToggleButton *m_autoButton; + EQGraph *m_eqg; + QMenu *m_presetsMenu; + QList<EQPreset*> m_presets; + QList<EQPreset*> m_autoPresets; + QString m_autoName; + +protected: + virtual void changeEvent(QEvent*); + virtual void closeEvent(QCloseEvent*); + +}; + +#endif diff --git a/src/ui/fft.c b/src/ui/fft.c new file mode 100644 index 000000000..7ca1978a5 --- /dev/null +++ b/src/ui/fft.c @@ -0,0 +1,296 @@ +/* fft.c: Iterative implementation of a FFT + * Copyright (C) 1999 Richard Boulton <richard@tartarus.org> + * Convolution stuff by Ralph Loader <suckfish@ihug.co.nz> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * TODO + * Remove compiling in of FFT_BUFFER_SIZE? (Might slow things down, but would + * be nice to be able to change size at runtime.) + * Finish making / checking thread-safety. + * More optimisations. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "fft.h" + +//#include <glib.h> +#include <stdlib.h> +#include <math.h> +#ifndef PI +#ifdef M_PI +#define PI M_PI +#else +#define PI 3.14159265358979323846 /* pi */ +#endif +#endif + +/* ########### */ +/* # Structs # */ +/* ########### */ + +struct _struct_fft_state { + /* Temporary data stores to perform FFT in. */ + float real[FFT_BUFFER_SIZE]; + float imag[FFT_BUFFER_SIZE]; +}; + +/* ############################# */ +/* # Local function prototypes # */ +/* ############################# */ + +static void fft_prepare(const sound_sample * input, float *re, float *im); +static void fft_calculate(float *re, float *im); +static void fft_output(const float *re, const float *im, float *output); +static int reverseBits(unsigned int initial); + +/* #################### */ +/* # Global variables # */ +/* #################### */ + +/* Table to speed up bit reverse copy */ +static unsigned int bitReverse[FFT_BUFFER_SIZE]; + +/* The next two tables could be made to use less space in memory, since they + * overlap hugely, but hey. */ +static float sintable[FFT_BUFFER_SIZE / 2]; +static float costable[FFT_BUFFER_SIZE / 2]; + +/* ############################## */ +/* # Externally called routines # */ +/* ############################## */ + +/* --------- */ +/* FFT stuff */ +/* --------- */ + +/* + * Initialisation routine - sets up tables and space to work in. + * Returns a pointer to internal state, to be used when performing calls. + * On error, returns NULL. + * The pointer should be freed when it is finished with, by fft_close(). + */ +fft_state * +fft_init(void) +{ + fft_state *state; + unsigned int i; + + state = (fft_state *) malloc(sizeof(fft_state)); + if (!state) + return NULL; + + for (i = 0; i < FFT_BUFFER_SIZE; i++) { + bitReverse[i] = reverseBits(i); + } + for (i = 0; i < FFT_BUFFER_SIZE / 2; i++) { + float j = 2 * PI * i / FFT_BUFFER_SIZE; + costable[i] = cos(j); + sintable[i] = sin(j); + } + + return state; +} + +/* + * Do all the steps of the FFT, taking as input sound data (as described in + * sound.h) and returning the intensities of each frequency as floats in the + * range 0 to ((FFT_BUFFER_SIZE / 2) * 32768) ^ 2 + * + * FIXME - the above range assumes no frequencies present have an amplitude + * larger than that of the sample variation. But this is false: we could have + * a wave such that its maximums are always between samples, and it's just + * inside the representable range at the places samples get taken. + * Question: what _is_ the maximum value possible. Twice that value? Root + * two times that value? Hmmm. Think it depends on the frequency, too. + * + * The input array is assumed to have FFT_BUFFER_SIZE elements, + * and the output array is assumed to have (FFT_BUFFER_SIZE / 2 + 1) elements. + * state is a (non-NULL) pointer returned by fft_init. + */ +void +fft_perform(const sound_sample * input, float *output, fft_state * state) +{ + /* Convert data from sound format to be ready for FFT */ + fft_prepare(input, state->real, state->imag); + + /* Do the actual FFT */ + fft_calculate(state->real, state->imag); + + /* Convert the FFT output into intensities */ + fft_output(state->real, state->imag, output); +} + +/* + * Free the state. + */ +void +fft_close(fft_state * state) +{ + if (state) + free(state); +} + +/* ########################### */ +/* # Locally called routines # */ +/* ########################### */ + +/* + * Prepare data to perform an FFT on + */ +static void +fft_prepare(const sound_sample * input, float *re, float *im) +{ + unsigned int i; + float *realptr = re; + float *imagptr = im; + + /* Get input, in reverse bit order */ + for (i = 0; i < FFT_BUFFER_SIZE; i++) { + *realptr++ = input[bitReverse[i]]; + *imagptr++ = 0; + } +} + +/* + * Take result of an FFT and calculate the intensities of each frequency + * Note: only produces half as many data points as the input had. + * This is roughly a consequence of the Nyquist sampling theorm thingy. + * (FIXME - make this comment better, and helpful.) + * + * The two divisions by 4 are also a consequence of this: the contributions + * returned for each frequency are split into two parts, one at i in the + * table, and the other at FFT_BUFFER_SIZE - i, except for i = 0 and + * FFT_BUFFER_SIZE which would otherwise get float (and then 4* when squared) + * the contributions. + */ +static void +fft_output(const float *re, const float *im, float *output) +{ + float *outputptr = output; + const float *realptr = re; + const float *imagptr = im; + float *endptr = output + FFT_BUFFER_SIZE / 2; + +#ifdef DEBUG + unsigned int i, j; +#endif + + while (outputptr <= endptr) { + *outputptr = (*realptr * *realptr) + (*imagptr * *imagptr); + outputptr++; + realptr++; + imagptr++; + } + /* Do divisions to keep the constant and highest frequency terms in scale + * with the other terms. */ + *output /= 4; + *endptr /= 4; + +#ifdef DEBUG + printf("Recalculated input:\n"); + for (i = 0; i < FFT_BUFFER_SIZE; i++) { + float val_real = 0; + float val_imag = 0; + for (j = 0; j < FFT_BUFFER_SIZE; j++) { + float fact_real = cos(-2 * j * i * PI / FFT_BUFFER_SIZE); + float fact_imag = sin(-2 * j * i * PI / FFT_BUFFER_SIZE); + val_real += fact_real * re[j] - fact_imag * im[j]; + val_imag += fact_real * im[j] + fact_imag * re[j]; + } + printf("%5d = %8f + i * %8f\n", i, + val_real / FFT_BUFFER_SIZE, val_imag / FFT_BUFFER_SIZE); + } + printf("\n"); +#endif +} + +/* + * Actually perform the FFT + */ +static void +fft_calculate(float *re, float *im) +{ + unsigned int i, j, k; + unsigned int exchanges; + float fact_real, fact_imag; + float tmp_real, tmp_imag; + unsigned int factfact; + + /* Set up some variables to reduce calculation in the loops */ + exchanges = 1; + factfact = FFT_BUFFER_SIZE / 2; + + /* Loop through the divide and conquer steps */ + for (i = FFT_BUFFER_SIZE_LOG; i != 0; i--) { + /* In this step, we have 2 ^ (i - 1) exchange groups, each with + * 2 ^ (FFT_BUFFER_SIZE_LOG - i) exchanges + */ + /* Loop through the exchanges in a group */ + for (j = 0; j != exchanges; j++) { + /* Work out factor for this exchange + * factor ^ (exchanges) = -1 + * So, real = cos(j * PI / exchanges), + * imag = sin(j * PI / exchanges) + */ + fact_real = costable[j * factfact]; + fact_imag = sintable[j * factfact]; + + /* Loop through all the exchange groups */ + for (k = j; k < FFT_BUFFER_SIZE; k += exchanges << 1) { + int k1 = k + exchanges; + /* newval[k] := val[k] + factor * val[k1] + * newval[k1] := val[k] - factor * val[k1] + **/ +#ifdef DEBUG + printf("%d %d %d\n", i, j, k); + printf("Exchange %d with %d\n", k, k1); + printf("Factor %9f + i * %8f\n", fact_real, fact_imag); +#endif + /* FIXME - potential scope for more optimization here? */ + tmp_real = fact_real * re[k1] - fact_imag * im[k1]; + tmp_imag = fact_real * im[k1] + fact_imag * re[k1]; + re[k1] = re[k] - tmp_real; + im[k1] = im[k] - tmp_imag; + re[k] += tmp_real; + im[k] += tmp_imag; +#ifdef DEBUG + for (k1 = 0; k1 < FFT_BUFFER_SIZE; k1++) { + printf("%5d = %8f + i * %8f\n", k1, real[k1], imag[k1]); + } +#endif + } + } + exchanges <<= 1; + factfact >>= 1; + } +} + +static int +reverseBits(unsigned int initial) +{ + unsigned int reversed = 0, loop; + for (loop = 0; loop < FFT_BUFFER_SIZE_LOG; loop++) { + reversed <<= 1; + reversed += (initial & 1); + initial >>= 1; + } + return reversed; +} diff --git a/src/ui/fft.h b/src/ui/fft.h new file mode 100644 index 000000000..431afa365 --- /dev/null +++ b/src/ui/fft.h @@ -0,0 +1,45 @@ +/* fft.h: Header for iterative implementation of a FFT + * Copyright (C) 1999 Richard Boulton <richard@tartarus.org> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _FFT_H_ +#define _FFT_H_ + +#define FFT_BUFFER_SIZE_LOG 9 + +#define FFT_BUFFER_SIZE (1 << FFT_BUFFER_SIZE_LOG) + +/* sound sample - should be an signed 16 bit value */ +typedef short int sound_sample; + +#ifdef __cplusplus +extern "C" { +#endif + +/* FFT library */ + typedef struct _struct_fft_state fft_state; + fft_state *fft_init(void); + void fft_perform(const sound_sample * input, float *output, + fft_state * state); + void fft_close(fft_state * state); + + + +#ifdef __cplusplus +} +#endif +#endif /* _FFT_H_ */ diff --git a/src/ui/filedialog.cpp b/src/ui/filedialog.cpp new file mode 100644 index 000000000..fb7ecbdaf --- /dev/null +++ b/src/ui/filedialog.cpp @@ -0,0 +1,296 @@ +#include "filedialog.h" + +#include <QSettings> + + +#include <QApplication> +#include <QPluginLoader> + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +#include "playlistmodel.h" + +FileDialog* FileDialog::_instance = 0; + +QMap<QString,FileDialogFactory*> FileDialog::factories = QMap<QString,FileDialogFactory*>(); + +FileDialog::FileDialog() : QObject(), m_initialized(false) +{ +} + + +bool FileDialog::isModal() +{ + return instance()->modal(); +} + + +void FileDialog::init(QObject* o) +{ + if(!m_initialized && !instance()->modal()) + { + PlayListModel* model = NULL; + if( ( model = qobject_cast<PlayListModel*>(o)) ) + { + connect(this,SIGNAL(filesAdded(const QStringList&)),model,SLOT(addFileList(const QStringList&))); + m_initialized = true; + } + } +} + + + +QString FileDialog::getExistingDirectory( QWidget * parent, const QString & caption, const QString & dir,bool def) +{ + QString s; + if(def) + s = defaultInstance()->existingDirectory(parent,caption,dir); + else + s = instance()->existingDirectory(parent,caption,dir); + delete _instance; + _instance = 0; + return s; +} + +QString FileDialog::getOpenFileName(QWidget * parent, + const QString & caption, + const QString & dir, + const QString & filter, + QString * selectedFilter,bool def) +{ + QString s; + if(def) + s = defaultInstance()->openFileName(parent,caption,dir,filter,selectedFilter); + else + s = instance()->openFileName(parent,caption,dir,filter,selectedFilter); + delete _instance; + _instance = 0; + return s; +} + +QStringList FileDialog::getOpenFileNames(QWidget * parent, const QString & caption , const QString & dir , + const QString & filter, QString * selectedFilter,bool def) +{ + QStringList sl; + if(def) + sl = defaultInstance()->openFileNames(parent,caption ,dir ,filter, selectedFilter); + else + sl = instance()->openFileNames(parent,caption,dir,filter,selectedFilter); + delete _instance; + _instance = 0; + return sl; +} + +QString FileDialog::getSaveFileName ( QWidget * parent, const QString & caption, + const QString & dir, const QString & filter, QString * selectedFilter,bool def) +{ + QString s; + if(def) + s = defaultInstance()->saveFileName(parent,caption,dir,filter,selectedFilter); + else + s = instance()->saveFileName(parent,caption,dir,filter,selectedFilter); + delete _instance; + _instance = 0; + return s; +} + + +QString FileDialog::existingDirectory(QWidget *, const QString &, const QString &) +{ + return QString(); +} + +QString FileDialog::openFileName(QWidget *, const QString &, const QString &, const QString &, QString *) +{ + return QString(); +} + +QStringList FileDialog::openFileNames(QWidget *, const QString &, const QString &, const QString &, QString *) +{ + return QStringList(); +} + +QString FileDialog::saveFileName(QWidget *, const QString &, const QString &, const QString &, QString *) +{ + return QString(); +} + + +void FileDialog::registerBuiltinFactories() +{ + registerFactory(new QtFileDialogFactory()); + //registerFactory(new QmmpFileDialogFactory()); +} + +void FileDialog::registerExternalFactories() +{ + QDir pluginsDir (QDir::homePath()+"/.qmmp/plugins/FileDialogs"); + + foreach (QString fileName, pluginsDir.entryList(QDir::Files)) + { + QPluginLoader loader(pluginsDir.absoluteFilePath(fileName)); + QObject *plugin = loader.instance(); + if (loader.isLoaded()) + qDebug("FileDialog: plugin loaded - %s", qPrintable(fileName)); + else + qDebug("FileDialog: %s",qPrintable(loader.errorString())); + + FileDialogFactory *fct = 0; + if (plugin) + fct = qobject_cast<FileDialogFactory *>(plugin); + + if (fct) + if (!registerFactory(fct)) + qDebug("Warning: Plugin with name %s is already registered...", + qPrintable(fct->name())); + } +} + +bool FileDialog::registerFactory(FileDialogFactory *f) +{ + QString name = f->name(); + if (!factories.contains(name)) + { + factories.insert(name,f); + return true; + } + return false; +} + +QString FileDialog::m_current_factory = QString(); + +FileDialog* FileDialog::instance() +{ + if(_instance && _instance->modal()) + { + delete _instance; + _instance = 0; + } + + if(factories.isEmpty()) + { + registerBuiltinFactories(); + registerExternalFactories(); + } + + QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat ); + QString f_dialogName = + settings.value("FileDialog",QtFileDialogFactory::QtFileDialogFactoryName).toString(); + + QStringList names = factories.keys(); + + if(m_current_factory != f_dialogName || !_instance) + { + if(_instance) + delete _instance; + + foreach(QString name,names) + { + if(name == f_dialogName) + { + _instance = factories[name]->create(); + m_current_factory = f_dialogName; + break; + } + } + + if(!_instance) + _instance = factories[QtFileDialogFactory::QtFileDialogFactoryName]->create(); + } + //else if(!_instance->modal()) + //return _instance; + // _instance->raise(); + return _instance; + +} + +FileDialog* FileDialog::defaultInstance() +{ + if(_instance) + { + delete _instance; + _instance = 0; + } + + if(factories.isEmpty()) + { + registerBuiltinFactories(); + registerExternalFactories(); + } + + _instance = factories[QtFileDialogFactory::QtFileDialogFactoryName]->create(); + + return _instance; +} + +QStringList FileDialog::registeredFactories() +{ + if(factories.isEmpty()) + { + registerBuiltinFactories(); + registerExternalFactories(); + } + return factories.keys(); +} + + +void FileDialog::popup(QObject* o,const QString& d,Mode m,const QStringList& f) +{ + FileDialog* inst = instance(); + inst->init(o); + inst->raise(d,m,f); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + +QtFileDialog::~QtFileDialog() +{ + qWarning("QtFileDialog::~QtFileDialog()"); +} + +QString QtFileDialog::existingDirectory(QWidget * parent, const QString & caption, const QString & dir) +{ + return QFileDialog::getExistingDirectory(parent,caption,dir,QFileDialog::DontResolveSymlinks | QFileDialog::ShowDirsOnly); +} + +QString QtFileDialog::openFileName(QWidget * parent,const QString & caption,const QString & dir,const QString & filter, + QString * selectedFilter) +{ + return QFileDialog::getOpenFileName(parent,caption,dir,filter,selectedFilter); +} + +QStringList QtFileDialog::openFileNames(QWidget * parent, const QString & caption , const QString & dir , + const QString & filter, QString * selectedFilter) +{ + return QFileDialog::getOpenFileNames(parent,caption,dir,filter,selectedFilter); +} + + QString QtFileDialog::saveFileName ( QWidget * parent, const QString & caption, + const QString & dir, const QString & filter, QString * selectedFilter) +{ + return QFileDialog::getSaveFileName(parent,caption,dir,filter,selectedFilter); +} + + + + + + +FileDialog* QtFileDialogFactory::create() +{ + return new QtFileDialog(); +} + +QString QtFileDialogFactory::name() +{ + return QtFileDialogFactoryName; +} + +QString QtFileDialogFactory::QtFileDialogFactoryName = "Qt File Dialog"; + + diff --git a/src/ui/filedialog.h b/src/ui/filedialog.h new file mode 100644 index 000000000..f8e6c4f93 --- /dev/null +++ b/src/ui/filedialog.h @@ -0,0 +1,109 @@ +#ifndef FILEDIALOG_H +#define FILEDIALOG_H + +#include <QString> +#include <QStringList> + +#include <QFileDialog> +#include <QMap> + +#define interface struct + +interface FileDialogFactory; + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////// FILE DIALOG ////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class FileDialog : public QObject +{ +Q_OBJECT + public: + enum Mode{AddFiles,AddDirs,SaveFiles}; + static QString getExistingDirectory( QWidget * parent = 0, const QString & caption = QString(), const QString & dir = QString(),bool = FALSE); + static QString getOpenFileName(QWidget * parent = 0,const QString & caption = QString(),const QString & dir = QString(),const QString & filter = QString(), + QString * selectedFilter = 0,bool = FALSE); + static QStringList getOpenFileNames( QWidget * parent = 0, const QString & caption = QString(), const QString & dir = QString(), + const QString & filter = QString(), QString * selectedFilter = 0,bool = FALSE); + static QString getSaveFileName ( QWidget * parent = 0, const QString & caption = QString(), + const QString & dir = QString(), const QString & filter = QString(), QString * selectedFilter = 0,bool = FALSE); + static QStringList registeredFactories(); + + static bool isModal(); + static void popup(QObject* ,const QString& = QString(),Mode = AddFiles,const QStringList& nameFilters = QStringList()); + signals: + void filesAdded(const QStringList&); + protected: + FileDialog(); + virtual QString existingDirectory( QWidget* , const QString& , const QString& ); + virtual QString openFileName( QWidget* ,const QString& ,const QString& ,const QString& , QString* ); + virtual QStringList openFileNames( QWidget* , const QString& , const QString& ,const QString& , QString* ); + virtual QString saveFileName ( QWidget* , const QString& ,const QString& , const QString& , QString* ); + virtual bool modal()const{ return TRUE;} + virtual ~FileDialog(){;} + void init(QObject*); + virtual void raise(const QString& = QString(),Mode = AddFiles,const QStringList& = QStringList()){;} + + static bool registerFactory(FileDialogFactory*); + public: + static void registerBuiltinFactories(); + static void registerExternalFactories(); + protected: + static FileDialog* instance(); + static FileDialog* defaultInstance(); + private: + static QMap <QString,FileDialogFactory*> factories; + static FileDialog* _instance; + static QString m_current_factory; + bool m_initialized; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + + +interface FileDialogFactory +{ + virtual FileDialog* create() = 0; + virtual QString name() = 0; + virtual ~FileDialogFactory(){;} +}; + +Q_DECLARE_INTERFACE(FileDialogFactory, "FileDialogFactory/1.0"); + + +//////////////////////////////////////////// QT FILE DIALOG //////////////////////////////////////////////////////////////////// + +class QtFileDialog : public FileDialog +{ + public: + virtual ~QtFileDialog(); + virtual QString existingDirectory(QWidget * parent , const QString & , const QString & dir); + virtual QString openFileName(QWidget * parent,const QString & caption,const QString & dir,const QString & filter, + QString * selectedFilter); + virtual QStringList openFileNames(QWidget * parent, const QString & caption , const QString & dir , + const QString & filter, QString * selectedFilter); + virtual QString saveFileName ( QWidget * parent, const QString & caption, + const QString & dir, const QString & filter, QString * selectedFilter); +}; + + +class QtFileDialogFactory : public QObject, public FileDialogFactory +{ + Q_OBJECT + Q_INTERFACES(FileDialogFactory); + public: + virtual FileDialog* create(); + virtual QString name(); + virtual ~QtFileDialogFactory(){;} + static QString QtFileDialogFactoryName; +}; + + +#endif + + diff --git a/src/ui/fileloader.cpp b/src/ui/fileloader.cpp new file mode 100644 index 000000000..fda8efdc1 --- /dev/null +++ b/src/ui/fileloader.cpp @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <decoder.h> + +#include "fileloader.h" +#include "mediafile.h" + +FileLoader::FileLoader(QObject *parent) + : QThread(parent),m_files_to_load(),m_directory() +{ + m_filters = Decoder::nameFilters(); + m_finished = false; +} + + +FileLoader::~FileLoader() +{ + qWarning("FileLoader::~FileLoader()"); +} + + +void FileLoader::addFiles(const QStringList &files) +{ + if (files.isEmpty ()) + return; + + foreach(QString s, files) + { + if (Decoder::supports(s)) + emit newMediaFile(new MediaFile(s)); + if(m_finished) return; + } +} + + +void FileLoader::addDirectory(const QString& s) +{ + QDir dir(s); + dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks); + dir.setSorting(QDir::Name); + QFileInfoList l = dir.entryInfoList(m_filters); + for (int i = 0; i < l.size(); ++i) + { + QFileInfo fileInfo = l.at(i); + QString suff = fileInfo.completeSuffix(); + list << fileInfo; + + if (Decoder::supports(fileInfo.absoluteFilePath ())) + emit newMediaFile(new MediaFile(fileInfo.absoluteFilePath ())); + if(m_finished) return; + } + dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); + dir.setSorting(QDir::Name); + l.clear(); + l = dir.entryInfoList(); + if (l.size() > 0) + for (int i = 0; i < l.size(); ++i) + { + QFileInfo fileInfo = l.at(i); + addDirectory(fileInfo.absoluteFilePath ()); + if(m_finished) return; + } +} + + +void FileLoader::run() +{ + if(!m_files_to_load.isEmpty()) + addFiles(m_files_to_load); + else if(!m_directory.isEmpty()) + addDirectory(m_directory); +} + + + +void FileLoader::setFilesToLoad(const QStringList & l) +{ + m_files_to_load = l; + m_directory = QString(); +} + +void FileLoader::setDirectoryToLoad(const QString & d) +{ + m_directory = d; + m_files_to_load.clear(); +} + +void FileLoader::finish() +{ + m_finished = true; +} diff --git a/src/ui/fileloader.h b/src/ui/fileloader.h new file mode 100644 index 000000000..c23d1ed35 --- /dev/null +++ b/src/ui/fileloader.h @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef FILELOADER_H +#define FILELOADER_H + +#include <QObject> +#include <QDir> +#include <QThread> + +class MediaFile; + +/*! + * This class represents fileloader object that + * processes file list in separate thread and emits + * \b newMediaFile(MediaFile*) signal for every newly + * created media file. + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class FileLoader : public QThread +{ +Q_OBJECT +public: + FileLoader(QObject *parent = 0); + + ~FileLoader(); + virtual void run(); + + /*! + * Call this method when you want to notify the thread about finishing + */ + void finish(); + + /*! + * Sets filelist to load( directory to load will be cleaned ) + */ + void setFilesToLoad(const QStringList&); + + /*! + * Sets directory to load( filelist to load will be cleaned ) + */ + void setDirectoryToLoad(const QString&); +signals: + void newMediaFile(MediaFile*); +protected: + void addFiles(const QStringList &files); + void addDirectory(const QString& s); +private: + QFileInfoList list; + QStringList m_filters; + QStringList m_files_to_load; + QString m_directory; + bool m_finished; +}; + +#endif diff --git a/src/ui/forms/aboutdialog.ui b/src/ui/forms/aboutdialog.ui new file mode 100644 index 000000000..56fbef9c5 --- /dev/null +++ b/src/ui/forms/aboutdialog.ui @@ -0,0 +1,174 @@ +<ui version="4.0" > + <class>AboutDialog</class> + <widget class="QDialog" name="AboutDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>518</width> + <height>414</height> + </rect> + </property> + <property name="windowTitle" > + <string>About Qmmp</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QLabel" name="pixmapLabel" > + <property name="text" > + <string/> + </property> + <property name="pixmap" > + <pixmap resource="images/images.qrc" >:/logo-qmmp.png</pixmap> + </property> + <property name="alignment" > + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QTabWidget" name="tabWidget" > + <property name="currentIndex" > + <number>0</number> + </property> + <widget class="QWidget" name="aboutTab" > + <attribute name="title" > + <string>About</string> + </attribute> + <layout class="QGridLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="0" column="0" > + <widget class="QTextEdit" name="aboutTextEdit" > + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="authorsTab" > + <attribute name="title" > + <string>Authors</string> + </attribute> + <layout class="QGridLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="0" column="0" > + <widget class="QTextEdit" name="authorsTextEdit" > + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="thanksToTab" > + <attribute name="title" > + <string>Thanks To</string> + </attribute> + <layout class="QHBoxLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QTextEdit" name="thanksToTextEdit" > + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="licenseTab" > + <attribute name="title" > + <string>License Agreement</string> + </attribute> + <layout class="QGridLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="0" column="0" > + <widget class="QTextEdit" name="licenseTextEdit" > + <property name="readOnly" > + <bool>true</bool> + </property> + <property name="overwriteMode" > + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources> + <include location="images/images.qrc" /> + </resources> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>AboutDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel" > + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>AboutDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel" > + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/ui/forms/addurldialog.ui b/src/ui/forms/addurldialog.ui new file mode 100644 index 000000000..46031b849 --- /dev/null +++ b/src/ui/forms/addurldialog.ui @@ -0,0 +1,76 @@ +<ui version="4.0" > + <class>AddUrlDialog</class> + <widget class="QDialog" name="AddUrlDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>394</width> + <height>80</height> + </rect> + </property> + <property name="windowTitle" > + <string>Enter URL to add</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QComboBox" name="urlComboBox" > + <property name="editable" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>AddUrlDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel" > + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>AddUrlDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel" > + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/ui/forms/configdialog.ui b/src/ui/forms/configdialog.ui new file mode 100644 index 000000000..530786ab4 --- /dev/null +++ b/src/ui/forms/configdialog.ui @@ -0,0 +1,944 @@ +<ui version="4.0" > + <class>ConfigDialog</class> + <widget class="QDialog" name="ConfigDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>601</width> + <height>409</height> + </rect> + </property> + <property name="windowTitle" > + <string>Qmmp Settings</string> + </property> + <layout class="QVBoxLayout" > + <property name="spacing" > + <number>6</number> + </property> + <property name="leftMargin" > + <number>9</number> + </property> + <property name="topMargin" > + <number>9</number> + </property> + <property name="rightMargin" > + <number>9</number> + </property> + <property name="bottomMargin" > + <number>9</number> + </property> + <item> + <layout class="QHBoxLayout" > + <property name="spacing" > + <number>6</number> + </property> + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="QListWidget" name="contentsWidget" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Expanding" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize" > + <size> + <width>170</width> + <height>16777215</height> + </size> + </property> + <property name="iconSize" > + <size> + <width>38</width> + <height>38</height> + </size> + </property> + <property name="movement" > + <enum>QListView::Static</enum> + </property> + <property name="flow" > + <enum>QListView::TopToBottom</enum> + </property> + <property name="isWrapping" stdset="0" > + <bool>false</bool> + </property> + <property name="resizeMode" > + <enum>QListView::Adjust</enum> + </property> + <property name="spacing" > + <number>2</number> + </property> + <property name="viewMode" > + <enum>QListView::ListMode</enum> + </property> + <property name="uniformItemSizes" > + <bool>false</bool> + </property> + <property name="batchSize" > + <number>100</number> + </property> + <property name="wordWrap" > + <bool>false</bool> + </property> + <property name="currentRow" > + <number>-1</number> + </property> + <item> + <property name="text" > + <string>Appearance</string> + </property> + <property name="icon" > + <iconset resource="images/images.qrc" >:/interface.png</iconset> + </property> + </item> + <item> + <property name="text" > + <string>Playlist</string> + </property> + <property name="icon" > + <iconset resource="images/images.qrc" >:/playlist.png</iconset> + </property> + </item> + <item> + <property name="text" > + <string>Plugins</string> + </property> + <property name="icon" > + <iconset resource="images/images.qrc" >:/plugins.png</iconset> + </property> + </item> + <item> + <property name="text" > + <string>Advanced</string> + </property> + <property name="icon" > + <iconset resource="images/images.qrc" >:/advanced.png</iconset> + </property> + </item> + <item> + <property name="text" > + <string>Connectivity</string> + </property> + <property name="icon" > + <iconset resource="images/images.qrc" >:/network.png</iconset> + </property> + </item> + </widget> + </item> + <item> + <widget class="QStackedWidget" name="stackedWidget" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + <property name="currentIndex" > + <number>0</number> + </property> + <widget class="QWidget" name="widget1" > + <layout class="QVBoxLayout" > + <property name="spacing" > + <number>6</number> + </property> + <property name="leftMargin" > + <number>9</number> + </property> + <property name="topMargin" > + <number>9</number> + </property> + <property name="rightMargin" > + <number>9</number> + </property> + <property name="bottomMargin" > + <number>9</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox" > + <property name="title" > + <string>Skins</string> + </property> + <layout class="QVBoxLayout" > + <property name="spacing" > + <number>6</number> + </property> + <property name="leftMargin" > + <number>9</number> + </property> + <property name="topMargin" > + <number>9</number> + </property> + <property name="rightMargin" > + <number>9</number> + </property> + <property name="bottomMargin" > + <number>9</number> + </property> + <item> + <widget class="QListWidget" name="listWidget" > + <property name="movement" > + <enum>QListView::Static</enum> + </property> + <property name="flow" > + <enum>QListView::TopToBottom</enum> + </property> + <property name="viewMode" > + <enum>QListView::ListMode</enum> + </property> + <property name="modelColumn" > + <number>0</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="plGroupBox" > + <property name="title" > + <string>Fonts</string> + </property> + <layout class="QGridLayout" > + <property name="leftMargin" > + <number>9</number> + </property> + <property name="topMargin" > + <number>9</number> + </property> + <property name="rightMargin" > + <number>9</number> + </property> + <property name="bottomMargin" > + <number>9</number> + </property> + <property name="horizontalSpacing" > + <number>6</number> + </property> + <property name="verticalSpacing" > + <number>6</number> + </property> + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="maximumSize" > + <size> + <width>80</width> + <height>16777215</height> + </size> + </property> + <property name="text" > + <string>Player:</string> + </property> + <property name="alignment" > + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="label_2" > + <property name="maximumSize" > + <size> + <width>80</width> + <height>16777215</height> + </size> + </property> + <property name="text" > + <string>Playlist:</string> + </property> + <property name="alignment" > + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QLabel" name="plFontLabel" > + <property name="frameShape" > + <enum>QFrame::Panel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Sunken</enum> + </property> + <property name="text" > + <string>???</string> + </property> + </widget> + </item> + <item row="1" column="2" > + <widget class="QToolButton" name="plFontButton" > + <property name="text" > + <string>...</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QLabel" name="mainFontLabel" > + <property name="frameShape" > + <enum>QFrame::Panel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Sunken</enum> + </property> + <property name="text" > + <string>???</string> + </property> + </widget> + </item> + <item row="0" column="2" > + <widget class="QToolButton" name="mainFontButton" > + <property name="text" > + <string>...</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="page" > + <layout class="QGridLayout" > + <property name="leftMargin" > + <number>9</number> + </property> + <property name="topMargin" > + <number>9</number> + </property> + <property name="rightMargin" > + <number>9</number> + </property> + <property name="bottomMargin" > + <number>9</number> + </property> + <property name="horizontalSpacing" > + <number>6</number> + </property> + <property name="verticalSpacing" > + <number>6</number> + </property> + <item row="0" column="0" > + <widget class="QGroupBox" name="groupBox_3" > + <property name="title" > + <string>Metadata</string> + </property> + <layout class="QGridLayout" > + <property name="leftMargin" > + <number>9</number> + </property> + <property name="topMargin" > + <number>9</number> + </property> + <property name="rightMargin" > + <number>9</number> + </property> + <property name="bottomMargin" > + <number>9</number> + </property> + <property name="horizontalSpacing" > + <number>6</number> + </property> + <property name="verticalSpacing" > + <number>6</number> + </property> + <item row="0" column="0" > + <widget class="QCheckBox" name="metadataCheckBox" > + <property name="text" > + <string>Load metadata from files</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="0" > + <widget class="QGroupBox" name="groupBox_2" > + <property name="title" > + <string>Song Display</string> + </property> + <layout class="QHBoxLayout" > + <property name="spacing" > + <number>6</number> + </property> + <property name="leftMargin" > + <number>9</number> + </property> + <property name="topMargin" > + <number>9</number> + </property> + <property name="rightMargin" > + <number>9</number> + </property> + <property name="bottomMargin" > + <number>9</number> + </property> + <item> + <widget class="QLabel" name="label_4" > + <property name="text" > + <string>Title format:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="formatLineEdit" /> + </item> + <item> + <widget class="QToolButton" name="titleButton" > + <property name="text" > + <string>...</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="2" column="0" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>121</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="widget" > + <layout class="QGridLayout" > + <property name="leftMargin" > + <number>9</number> + </property> + <property name="topMargin" > + <number>9</number> + </property> + <property name="rightMargin" > + <number>9</number> + </property> + <property name="bottomMargin" > + <number>9</number> + </property> + <property name="horizontalSpacing" > + <number>6</number> + </property> + <property name="verticalSpacing" > + <number>6</number> + </property> + <item row="1" column="0" > + <widget class="QPushButton" name="preferencesButton" > + <property name="text" > + <string>Preferences</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QPushButton" name="informationButton" > + <property name="text" > + <string>Information</string> + </property> + </widget> + </item> + <item row="1" column="2" > + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>101</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="0" colspan="3" > + <widget class="QTabWidget" name="pluginsTab" > + <property name="tabPosition" > + <enum>QTabWidget::North</enum> + </property> + <property name="tabShape" > + <enum>QTabWidget::Rounded</enum> + </property> + <property name="currentIndex" > + <number>0</number> + </property> + <widget class="QWidget" name="Input" > + <attribute name="title" > + <string>Input</string> + </attribute> + <layout class="QHBoxLayout" > + <property name="spacing" > + <number>6</number> + </property> + <property name="leftMargin" > + <number>9</number> + </property> + <property name="topMargin" > + <number>9</number> + </property> + <property name="rightMargin" > + <number>9</number> + </property> + <property name="bottomMargin" > + <number>9</number> + </property> + <item> + <widget class="QTableWidget" name="inputPluginTable" > + <property name="selectionMode" > + <enum>QAbstractItemView::SingleSelection</enum> + </property> + <property name="selectionBehavior" > + <enum>QAbstractItemView::SelectRows</enum> + </property> + <property name="rowCount" > + <number>0</number> + </property> + <property name="columnCount" > + <number>0</number> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="Output" > + <attribute name="title" > + <string>Output</string> + </attribute> + <layout class="QHBoxLayout" > + <property name="spacing" > + <number>6</number> + </property> + <property name="leftMargin" > + <number>9</number> + </property> + <property name="topMargin" > + <number>9</number> + </property> + <property name="rightMargin" > + <number>9</number> + </property> + <property name="bottomMargin" > + <number>9</number> + </property> + <item> + <widget class="QTableWidget" name="outputPluginTable" > + <property name="selectionMode" > + <enum>QAbstractItemView::SingleSelection</enum> + </property> + <property name="selectionBehavior" > + <enum>QAbstractItemView::SelectRows</enum> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab" > + <attribute name="title" > + <string>Visualization</string> + </attribute> + <layout class="QHBoxLayout" > + <item> + <widget class="QTableWidget" name="visualPluginTable" > + <property name="selectionMode" > + <enum>QAbstractItemView::SingleSelection</enum> + </property> + <property name="selectionBehavior" > + <enum>QAbstractItemView::SelectRows</enum> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_2" > + <attribute name="title" > + <string>Effects</string> + </attribute> + <layout class="QVBoxLayout" > + <item> + <widget class="QTableWidget" name="effectPluginTable" > + <property name="selectionBehavior" > + <enum>QAbstractItemView::SelectRows</enum> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_3" > + <attribute name="title" > + <string>General</string> + </attribute> + <layout class="QVBoxLayout" > + <item> + <widget class="QTableWidget" name="generalPluginTable" > + <property name="selectionBehavior" > + <enum>QAbstractItemView::SelectRows</enum> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="fileDialogTab" > + <attribute name="title" > + <string>File Dialog</string> + </attribute> + <layout class="QVBoxLayout" > + <property name="spacing" > + <number>6</number> + </property> + <property name="leftMargin" > + <number>9</number> + </property> + <property name="topMargin" > + <number>9</number> + </property> + <property name="rightMargin" > + <number>9</number> + </property> + <property name="bottomMargin" > + <number>9</number> + </property> + <item> + <layout class="QHBoxLayout" > + <property name="spacing" > + <number>6</number> + </property> + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <widget class="QComboBox" name="fileDialogComboBox" /> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="page_2" > + <layout class="QVBoxLayout" > + <item> + <widget class="QGroupBox" name="groupBox_6" > + <property name="title" > + <string>Audio</string> + </property> + <layout class="QVBoxLayout" > + <item> + <widget class="QCheckBox" name="softVolumeCheckBox" > + <property name="text" > + <string>Use software volume control</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>251</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="network" > + <layout class="QVBoxLayout" > + <item> + <widget class="QGroupBox" name="groupBox_5" > + <property name="title" > + <string>Proxy</string> + </property> + <property name="flat" > + <bool>false</bool> + </property> + <property name="checkable" > + <bool>false</bool> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" colspan="2" > + <widget class="QCheckBox" name="enableProxyCheckBox" > + <property name="text" > + <string>Enable proxy usage</string> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="label_5" > + <property name="text" > + <string>Proxy host name:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QLineEdit" name="hostLineEdit" /> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="label_6" > + <property name="text" > + <string>Proxy port:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QLineEdit" name="portLineEdit" /> + </item> + <item row="3" column="0" colspan="2" > + <widget class="QCheckBox" name="authProxyCheckBox" > + <property name="text" > + <string>Use authentication with proxy</string> + </property> + </widget> + </item> + <item row="4" column="0" > + <widget class="QLabel" name="label_7" > + <property name="text" > + <string>Proxy user name:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="4" column="1" > + <widget class="QLineEdit" name="proxyUserLineEdit" /> + </item> + <item row="5" column="0" > + <widget class="QLabel" name="label_8" > + <property name="text" > + <string>Proxy password:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="5" column="1" > + <widget class="QLineEdit" name="proxyPasswLineEdit" > + <property name="echoMode" > + <enum>QLineEdit::Password</enum> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" > + <property name="spacing" > + <number>6</number> + </property> + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>341</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="closeButton" > + <property name="text" > + <string>Close</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources> + <include location="images/images.qrc" /> + </resources> + <connections> + <connection> + <sender>closeButton</sender> + <signal>clicked()</signal> + <receiver>ConfigDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>590</x> + <y>364</y> + </hint> + <hint type="destinationlabel" > + <x>316</x> + <y>340</y> + </hint> + </hints> + </connection> + <connection> + <sender>enableProxyCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>hostLineEdit</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel" > + <x>305</x> + <y>52</y> + </hint> + <hint type="destinationlabel" > + <x>424</x> + <y>82</y> + </hint> + </hints> + </connection> + <connection> + <sender>enableProxyCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>portLineEdit</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel" > + <x>506</x> + <y>56</y> + </hint> + <hint type="destinationlabel" > + <x>506</x> + <y>116</y> + </hint> + </hints> + </connection> + <connection> + <sender>authProxyCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>proxyUserLineEdit</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel" > + <x>318</x> + <y>142</y> + </hint> + <hint type="destinationlabel" > + <x>326</x> + <y>163</y> + </hint> + </hints> + </connection> + <connection> + <sender>authProxyCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>proxyPasswLineEdit</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel" > + <x>264</x> + <y>138</y> + </hint> + <hint type="destinationlabel" > + <x>334</x> + <y>204</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/ui/forms/jumptotrackdialog.ui b/src/ui/forms/jumptotrackdialog.ui new file mode 100644 index 000000000..1418c54fd --- /dev/null +++ b/src/ui/forms/jumptotrackdialog.ui @@ -0,0 +1,110 @@ +<ui version="4.0" > + <class>JumpToTrackDialog</class> + <widget class="QDialog" name="JumpToTrackDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>487</width> + <height>315</height> + </rect> + </property> + <property name="windowTitle" > + <string>Jump To Track</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QLabel" name="label" > + <property name="text" > + <string>Filter</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="filterLineEdit" /> + </item> + </layout> + </item> + <item> + <widget class="QListView" name="songsListView" > + <property name="editTriggers" > + <set>QAbstractItemView::NoEditTriggers</set> + </property> + <property name="alternatingRowColors" > + <bool>true</bool> + </property> + <property name="selectionBehavior" > + <enum>QAbstractItemView::SelectRows</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="queuePushButton" > + <property name="text" > + <string>Queue</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="refreshPushButton" > + <property name="text" > + <string>Refresh</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="jumpToPushButton" > + <property name="text" > + <string>Jump To</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="closePushButton" > + <property name="text" > + <string>Close</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/ui/forms/preseteditor.ui b/src/ui/forms/preseteditor.ui new file mode 100644 index 000000000..2f88d6d53 --- /dev/null +++ b/src/ui/forms/preseteditor.ui @@ -0,0 +1,88 @@ +<ui version="4.0" > + <class>PresetEditor</class> + <widget class="QDialog" name="PresetEditor" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>225</width> + <height>248</height> + </rect> + </property> + <property name="windowTitle" > + <string>Preset Editor</string> + </property> + <property name="modal" > + <bool>false</bool> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="1" column="0" > + <widget class="QPushButton" name="loadButton" > + <property name="text" > + <string>Load</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QPushButton" name="deleteButton" > + <property name="text" > + <string>Delete</string> + </property> + </widget> + </item> + <item row="0" column="0" colspan="2" > + <widget class="QTabWidget" name="tabWidget" > + <property name="currentIndex" > + <number>0</number> + </property> + <widget class="QWidget" name="tab" > + <attribute name="title" > + <string>Preset</string> + </attribute> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QListWidget" name="presetListWidget" /> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_2" > + <attribute name="title" > + <string>Auto-preset</string> + </attribute> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QListWidget" name="autoPresetListWidget" > + <property name="editTriggers" > + <set>QAbstractItemView::NoEditTriggers</set> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11" /> + <pixmapfunction>qPixmapFromMimeSource</pixmapfunction> + <resources/> + <connections/> +</ui> diff --git a/src/ui/html/about_cs.html b/src/ui/html/about_cs.html new file mode 100644 index 000000000..84bd2b42a --- /dev/null +++ b/src/ui/html/about_cs.html @@ -0,0 +1,81 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" +> +<head> + <META content="text/html; charset=utf8"> + <TITLE>Qt-based Multimedia Player</TITLE> +</head> +<div align="left"> + <h3> + Qt-based Multimedia Player (Qmmp) + </h3> +</div> +<p> + Qmmp je přehrávač zvuku založený na knihovně Qt. +</p> +<h4> + Klíčové vlastnosti: +</h4> +<ul type="square"> + <li> + podpora témat programu Winamp; + </li> + <li> + podpora zásuvných modulů (plugin); + </li> + <li> + podpora MPEG1 layer 1/2/3; + </li> + <li> + podpora Ogg-Vorbis; + </li> + <li> + podpora FLAC; + </li> + <li> + podpora Musepack; + </li> + <li> + podpora WMA; + </li> + <li> + zvukový výstup ALSA; + </li> + <li> + zvukový výstup JACK. + </li> +</ul> +<h4> + Požadavky: +</h4> +<ul type="square"> + <li> + operační systém Linux; + </li> + <li> + <A name="Qt" href="http://www.trolltech.com/">Qt</A> >= 4.2; + </li> + <li> + <A name="MAD" href="http://www.underbit.com/products/mad/">MAD</A>; + </li> + <li> + <A name="Vorbis" href="http://www.vorbis.com/">Ogg-Vorbis</A>; + </li> + <li> + <A name="FLAC" href="http://flac.sourceforge.net/">FLAC</A> >= 1.1.3; + </li> + <li> + <A name="ALSA" href="http://www.alsa-project.org/">ALSA</A> >= 1.0.1; + </li> + <li> + <A name="taglib" href="http://developer.kde.org/~wheeler/taglib.html">TagLib</A> >= 1.4. + </li> + <li> + <A name="libmpcdec" href="http://www.musepack.net/">libmpcdec</A> >= 1.2.6 + </li> + <li> + <A name="JACK" href="http://jackaudio.org/">Jack</A> >= 0.102.5 + </li> + <li> + <A name="FFmpeg" href="http://ffmpeg.mplayerhq.hu/">FFmpeg</A> >= 0.4.9-pre1 + </li> +</ul> diff --git a/src/ui/html/about_en.html b/src/ui/html/about_en.html new file mode 100644 index 000000000..d03691cf6 --- /dev/null +++ b/src/ui/html/about_en.html @@ -0,0 +1,81 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" +> +<head> + <META content="text/html; charset=utf8"> + <TITLE>Qt-based Multimedia Player</TITLE> +</head> +<div align="left"> + <h3> + Qt-based Multimedia Player (Qmmp) + </h3> +</div> +<p> + This program is an audio-player, written with help of Qt library. +</p> +<h4> + Main opportunities: +</h4> +<ul type="square"> + <li> + unpacked winamp skins support; + </li> + <li> + plugins support; + </li> + <li> + MPEG1 layer 1/2/3 support; + </li> + <li> + Ogg Vorbis support; + </li> + <li> + native FLAC support; + </li> + <li> + Musepack support; + </li> + <li> + WMA support; + </li> + <li> + ALSA sound output; + </li> + <li> + JACK sound output. + </li> +</ul> +<h4> + Requirements: +</h4> +<ul type="square"> + <li> + OS GNU Linux; + </li> + <li> + <A name="Qt" href="http://www.trolltech.com/">Qt</A> версии >= 4.2; + </li> + <li> + <A name="MAD" href="http://www.underbit.com/products/mad/">MAD</A>; + </li> + <li> + <A name="Vorbis" href="http://www.vorbis.com/">Ogg Vorbis</A>; + </li> + <li> + <A name="FLAC" href="http://flac.sourceforge.net/">FLAC</A> >= 1.1.3; + </li> + <li> + <A name="ALSA" href="http://www.alsa-project.org/">ALSA</A> >= 1.0.1; + </li> + <li> + <A name="taglib" href="http://developer.kde.org/~wheeler/taglib.html">TagLib</A> >= 1.4. + </li> + <li> + <A name="libmpcdec" href="http://www.musepack.net/">libmpcdec</A> >= 1.2.6 + </li> + <li> + <A name="JACK" href="http://jackaudio.org/">Jack</A> >= 0.102.5 + </li> + <li> + <A name="FFmpeg" href="http://ffmpeg.mplayerhq.hu/">FFmpeg</A> >= 0.4.9-pre1 + </li> +</ul> diff --git a/src/ui/html/about_ru.html b/src/ui/html/about_ru.html new file mode 100644 index 000000000..26e5b9906 --- /dev/null +++ b/src/ui/html/about_ru.html @@ -0,0 +1,81 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" +> +<head> + <META content="text/html; charset=UTF-8"> + <TITLE>Qt-based Multimedia Player</TITLE> +</head> +<div align="left"> + <h3> + Qt-based Multimedia Player (Qmmp) + </h3> +</div> +<p> + Данная программа является аудио-плеером, написанным с использованием библиотеки Qt. Программа имеет интерфейс, аналогичный winamp или xmms. +</p> +<h4> + Основные возможности программы: +</h4> +<ul type="square"> + <li> + поддержка тем winamp в распакованном виде; + </li> + <li> + поддержка модулей (плагинов); + </li> + <li> + поддержка файлов MPEG1 layer 1/2/3; + </li> + <li> + поддержка файлов Ogg Vorbis; + </li> + <li> + поддержка файлов Native FLAC; + </li> + <li> + поддержка файлов Musepack; + </li> + <li> + поддержка файлов WMA; + </li> + <li> + вывод звука через ALSA; + </li> + <li> + вывод звука через Jack. + </li> +</ul> +<h4> + Для работы необходимы: +</h4> +<ul type="square"> + <li> + операционная система GNU Linux; + </li> + <li> + <A name="Qt" href="http://www.trolltech.com/">Qt</A> версии >= 4.2; + </li> + <li> + <A name="MAD" href="http://www.underbit.com/products/mad/">MAD</A>; + </li> + <li> + <A name="Vorbis" href="http://www.vorbis.com/">Ogg Vorbis</A>; + </li> + <li> + <A name="FLAC" href="http://flac.sourceforge.net/">FLAC</A> версии >= 1.1.3; + </li> + <li> + <A name="ALSA" href="http://www.alsa-project.org/">ALSA</A> версии >= 1.0.1; + </li> + <li> + <A name="taglib" href="http://developer.kde.org/~wheeler/taglib.html">TagLib</A> версии >= 1.4. + </li> + <li> + <A name="libmpcdec" href="http://www.musepack.net/">libmpcdec</A> версии >= 1.2.6 + </li> + <li> + <A name="JACK" href="http://jackaudio.org/">Jack</A> версии >= 0.102.5 + </li> + <li> + <A name="FFmpeg" href="http://ffmpeg.mplayerhq.hu/">FFmpeg</A> версии >= 0.4.9-pre1 + </li> +</ul> diff --git a/src/ui/html/about_zh_CN.html b/src/ui/html/about_zh_CN.html new file mode 100644 index 000000000..eadc7f78d --- /dev/null +++ b/src/ui/html/about_zh_CN.html @@ -0,0 +1,81 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" +> +<head> + <META content="text/html; charset=utf8"> + <TITLE>基于Qt的多媒体播放器</TITLE> +</head> +<div align="left"> + <h3> + 基于Qt的多媒体播放器(Qmmp)。 + </h3> +</div> +<p> + 此程序是一个音乐播放器,程序的编写基于Qt库。 +</p> +<h4> + 主要功能: +</h4> +<ul type="square"> + <li> + 未压缩的winamp皮肤支持; + </li> + <li> + 插件支持; + </li> + <li> + MPEG1 1/2/3 层支持; + </li> + <li> + Ogg Vorbis 支持; + </li> + <li> + native FLAC 支持; + </li> + <li> + Musepack 支持; + </li> + <li> + WMA 支持; + </li> + <li> + ALSA 声音输出; + </li> + <li> + JACK 声音输出。 + </li> +</ul> +<h4> + 要求: +</h4> +<ul type="square"> + <li> + OS GNU Linux; + </li> + <li> + <A name="Qt" href="http://www.trolltech.com/">Qt</A> версии >= 4.2; + </li> + <li> + <A name="MAD" href="http://www.underbit.com/products/mad/">MAD</A>; + </li> + <li> + <A name="Vorbis" href="http://www.vorbis.com/">Ogg Vorbis</A>; + </li> + <li> + <A name="FLAC" href="http://flac.sourceforge.net/">FLAC</A> >= 1.1.3; + </li> + <li> + <A name="ALSA" href="http://www.alsa-project.org/">ALSA</A> >= 1.0.1; + </li> + <li> + <A name="taglib" href="http://developer.kde.org/~wheeler/taglib.html">TagLib</A> >= 1.4. + </li> + <li> + <A name="libmpcdec" href="http://www.musepack.net/">libmpcdec</A> >= 1.2.6 + </li> + <li> + <A name="JACK" href="http://jackaudio.org/">Jack</A> >= 0.102.5 + </li> + <li> + <A name="FFmpeg" href="http://ffmpeg.mplayerhq.hu/">FFmpeg</A> >= 0.4.9-pre1 + </li> +</ul> diff --git a/src/ui/html/authors_cs.txt b/src/ui/html/authors_cs.txt new file mode 100644 index 000000000..89d585c24 --- /dev/null +++ b/src/ui/html/authors_cs.txt @@ -0,0 +1,12 @@ +Vývojáři programu: + + Илья Котов (Ilja Kotov) <forkotov02@hotmail.ru> (nápad a základní kód) + Владимир Кузнецов (Vladimír Kuzněcov) <vovanec@gmail.com> (vzhled a mnoho vylepšení) + +Vývojáři zásuvných modulů: + + Юрий Журавлёв (Jurij Žuravljov) <stalkerg@gmail.com> (jack plugin) + +Český překlad: + + Karel Volný <kavol@seznam.cz> diff --git a/src/ui/html/authors_en.txt b/src/ui/html/authors_en.txt new file mode 100644 index 000000000..6c11ebd5e --- /dev/null +++ b/src/ui/html/authors_en.txt @@ -0,0 +1,12 @@ +Core Developers: + + Ilya Kotov <forkotov02@hotmail.ru> (idea and base code) + Vladimir Kuznetsov <vovanec@gmail.com> (look&feel and many improvements) + +Plugin Developers: + + Yuriy Zhuravlev <stalkerg@gmail.com> (jack plugin) + +Turkish translation: + + Mustafa GUNAY <mustafagunay@gmail.com> diff --git a/src/ui/html/authors_ru.txt b/src/ui/html/authors_ru.txt new file mode 100644 index 000000000..b95c3887e --- /dev/null +++ b/src/ui/html/authors_ru.txt @@ -0,0 +1,9 @@ +Разработчики ядра: + + Владимир Кузнецов <vovanec@gmail.com> (внешний вид и множество улучшений) + Илья Котов <forkotov02@hotmail.ru> (идея и основной код) + +Разработчики модулей: + + Юрий Журавлёв <stalkerg@gmail.com> (модуль jack) + diff --git a/src/ui/html/authors_zh_CN.txt b/src/ui/html/authors_zh_CN.txt new file mode 100644 index 000000000..f2d8892fd --- /dev/null +++ b/src/ui/html/authors_zh_CN.txt @@ -0,0 +1,16 @@ +核心开发: + + Ilya Kotov <forkotov02@hotmail.ru> (idea and base code) + Vladimir Kuznetsov <vovanec@gmail.com> (look&feel and many improvements) + +插件开发: + + Yuriy Zhuravlev <stalkerg@gmail.com> (jack plugin) + +土耳其语翻译: + + Mustafa GUNAY <mustafagunay@gmail.com> + +简体中文翻译: + + 李红昆 <lon83129@126.com>
\ No newline at end of file diff --git a/src/ui/html/thanks_cs.txt b/src/ui/html/thanks_cs.txt new file mode 100644 index 000000000..9bc0388da --- /dev/null +++ b/src/ui/html/thanks_cs.txt @@ -0,0 +1,3 @@ +Poděkování patří: + + Вадим Калинников (Vadim Kalinnikov) <moose@ylsoftware.com> (hosting projektu) diff --git a/src/ui/html/thanks_en.txt b/src/ui/html/thanks_en.txt new file mode 100644 index 000000000..3ed2fe5d5 --- /dev/null +++ b/src/ui/html/thanks_en.txt @@ -0,0 +1,3 @@ +Thanks to: + + Vadim Kalinnikov <moose@ylsoftware.com> (project hosting) diff --git a/src/ui/html/thanks_ru.txt b/src/ui/html/thanks_ru.txt new file mode 100644 index 000000000..79acc177d --- /dev/null +++ b/src/ui/html/thanks_ru.txt @@ -0,0 +1,3 @@ +Благодарности: + + Вадиму Калинникову <moose@ylsoftware.com> (хотстинг проекта) diff --git a/src/ui/html/thanks_zh_CN.txt b/src/ui/html/thanks_zh_CN.txt new file mode 100644 index 000000000..505d05c72 --- /dev/null +++ b/src/ui/html/thanks_zh_CN.txt @@ -0,0 +1,3 @@ +感谢: + + Vadim Kalinnikov <moose@ylsoftware.com> (project hosting) diff --git a/src/ui/images/advanced.png b/src/ui/images/advanced.png Binary files differnew file mode 100644 index 000000000..25efaf35b --- /dev/null +++ b/src/ui/images/advanced.png diff --git a/src/ui/images/images.qrc b/src/ui/images/images.qrc new file mode 100644 index 000000000..acc7c26f0 --- /dev/null +++ b/src/ui/images/images.qrc @@ -0,0 +1,12 @@ +<!DOCTYPE RCC> +<RCC version="1.0"> + <qresource> + <file>qmmp.xpm</file> + <file>interface.png</file> + <file>playlist.png</file> + <file>advanced.png</file> + <file>plugins.png</file> + <file>network.png</file> + <file>logo-qmmp.png</file> + </qresource> +</RCC> diff --git a/src/ui/images/interface.png b/src/ui/images/interface.png Binary files differnew file mode 100644 index 000000000..53174d71a --- /dev/null +++ b/src/ui/images/interface.png diff --git a/src/ui/images/logo-qmmp.png b/src/ui/images/logo-qmmp.png Binary files differnew file mode 100644 index 000000000..7a4d6ded4 --- /dev/null +++ b/src/ui/images/logo-qmmp.png diff --git a/src/ui/images/network.png b/src/ui/images/network.png Binary files differnew file mode 100644 index 000000000..5f47a5fe1 --- /dev/null +++ b/src/ui/images/network.png diff --git a/src/ui/images/playlist.png b/src/ui/images/playlist.png Binary files differnew file mode 100644 index 000000000..99923dea9 --- /dev/null +++ b/src/ui/images/playlist.png diff --git a/src/ui/images/plugins.png b/src/ui/images/plugins.png Binary files differnew file mode 100644 index 000000000..e9c744e64 --- /dev/null +++ b/src/ui/images/plugins.png diff --git a/src/ui/images/qmmp.xpm b/src/ui/images/qmmp.xpm new file mode 100644 index 000000000..85ea94fc1 --- /dev/null +++ b/src/ui/images/qmmp.xpm @@ -0,0 +1,278 @@ +/* XPM */ +static char *trayicon[]={ +"32 32 243 2", +"#N c None", +"Qt c None", +".# c #000000", +".a c #050d16", +".U c #060e16", +".L c #06101b", +"a9 c #091725", +"b. c #0a0b11", +"bU c #0b1826", +".c c #0c2034", +"bt c #0d1823", +"be c #0d2034", +"bb c #0f0f0f", +".A c #0f253c", +"a7 c #11263d", +".n c #112a45", +"a6 c #12273d", +"aL c #122f4c", +"bV c #131e29", +"bi c #141b23", +"bg c #14212e", +".b c #16385b", +".i c #16385c", +"#L c #191b2b", +"bW c #1a2b3e", +".d c #1a4169", +"aY c #1a416b", +"bm c #1a426b", +"aB c #1b1d2e", +"aZ c #1b1d2f", +".o c #1c1c1c", +"bl c #1c436b", +"aH c #1d436b", +"ah c #1e1f25", +"at c #1e4b7a", +"#o c #1f2236", +"#K c #1f272f", +"bO c #1f2e3e", +"aK c #1f4c7b", +"bk c #202a35", +"bh c #202e3e", +"au c #212331", +"as c #215489", +"a8 c #21548a", +".R c #223952", +"br c #233242", +"#J c #24303e", +".3 c #253647", +".T c #27507b", +".e c #292929", +"#O c #292a30", +"aM c #2967a7", +".x c #2968a9", +"bN c #2a598a", +"aJ c #2c69a9", +"ar c #2d71b7", +"ap c #2d71b8", +".M c #2e2e2e", +"bs c #2f4d6c", +"#w c #2f547b", +"#B c #303030", +"ag c #303453", +"bI c #30353a", +"bc c #30465d", +"bf c #307ac7", +"bP c #314253", +".K c #317bc7", +"#I c #323e4b", +"#p c #333333", +"#8 c #34353d", +"aq c #3484d6", +"aA c #3484d7", +"az c #35404c", +"#d c #363636", +"aN c #373b5e", +"bu c #387ec8", +".4 c #393939", +"a4 c #39414a", +"aI c #3a87d7", +"af c #3b3b3b", +"#j c #3b699a", +".V c #3c3c3c", +"#A c #3c4046", +"bn c #3c6a9a", +".m c #3c95f2", +".l c #3c95f3", +".k c #3c96f4", +".j c #3c96f5", +".z c #3c97f5", +".y c #3c97f6", +"bJ c #3f4954", +"aX c #3f99f6", +"bD c #408ad7", +".J c #419af6", +"aT c #4284c8", +"aW c #459cf6", +"bd c #46688c", +"#X c #474a60", +".I c #479df6", +"## c #48719b", +"bT c #4887c8", +"ba c #494949", +"aU c #4a97e7", +"bE c #4b81b9", +".S c #4b89c9", +"aV c #4b9ff6", +".1 c #4d4d4d", +".p c #545454", +"ay c #555555", +"#M c #555b91", +".2 c #57789c", +"#. c #585d61", +"a5 c #5897d9", +"bC c #59a6f7", +"bM c #5aa6f7", +".f c #606060", +"#G c #616161", +"bv c #62abf7", +"aC c #636785", +"#v c #646464", +"aF c #676767", +"bj c #6a8aac", +"bS c #6bb0f8", +"#a c #6f94bb", +"bB c #6fb2f8", +"aO c #707175", +"bL c #70b2f8", +"#b c #71879d", +"bo c #72b4f8", +"#6 c #747474", +"aR c #757575", +"#7 c #777777", +"bQ c #7798bb", +"#x c #77b6f8", +"#W c #787878", +"#t c #797979", +"#k c #7ab8f8", +".0 c #7b7b7b", +"ai c #7b7f9f", +"bF c #7bb9f8", +".h c #7e7e7e", +"#i c #808080", +"by c #808f9d", +"aG c #828282", +"#F c #838383", +"bR c #83bdf9", +".Q c #848484", +"av c #8487a4", +"#5 c #858585", +"bz c #86a8cb", +"ao c #878787", +"#9 c #878aa2", +"ac c #888888", +"bA c #89c0f9", +"#2 c #8a8a8a", +"bp c #8ac1f9", +".w c #8b8b8b", +".q c #8c8c8c", +"#3 c #8d8d8d", +"#H c #8e8e8e", +"#n c #90979e", +"#U c #919191", +"#Z c #9396ac", +"aS c #969696", +"bw c #96c7fa", +"#4 c #989898", +"bG c #98c8fa", +"ad c #9a9a9a", +"#T c #9b9b9b", +".g c #9c9c9c", +"#e c #9d9d9d", +"#y c #9dcafa", +"ae c #9f9f9f", +"#c c #9fbddc", +"aE c #a0a0a0", +"bH c #a1bedc", +".9 c #a2a2a2", +"a. c #a2a3ad", +"#l c #a3cefa", +"aD c #a4a4a4", +"#Y c #a4a5ad", +"#u c #a5a5a5", +"aw c #a7a7a7", +"al c #a8a8a8", +"#g c #a9a9a9", +"bK c #a9d1fb", +"bq c #aacaeb", +"#h c #acacac", +"am c #afafaf", +"#Q c #afb1bd", +"#1 c #b0b0b0", +".Z c #b1b1b1", +".8 c #b3b3b3", +"#P c #b3b3b9", +"ak c #b4b4b4", +"bx c #b5d7fb", +"#r c #b9b9b9", +"aj c #bababa", +"ax c #bbbbbb", +"a# c #bebebe", +"an c #bfbfbf", +".B c #c0c0c0", +".r c #c2c2c2", +"#R c #c2c3cb", +".6 c #c5c5c5", +"#z c #c5e0fc", +"aa c #c7c7c7", +".Y c #c8c8c8", +"#0 c #c9c9c9", +"#C c #cacaca", +"aP c #cbcbcb", +"#S c #cccccc", +"#E c #cecece", +"b# c #cfcfcf", +".X c #d0d0d0", +".7 c #d1d1d1", +"ab c #d2d2d2", +"#m c #d2e7fc", +"#q c #d5d5d5", +"#f c #d6d6d6", +"#D c #d6d7db", +"aQ c #d7d7d7", +"#s c #d9d9d9", +".t c #dbdbdb", +".s c #dcdcdc", +".5 c #dddddd", +".F c #dedede", +".E c #e0e0e0", +".D c #e1e1e1", +".C c #e3e3e3", +".u c #e5e5e5", +".G c #e6e6e6", +".P c #e7e7e7", +"#V c #eaeaea", +".v c #ebebeb", +".H c #ececec", +".O c #ededed", +"a3 c #eeeeee", +"a0 c #efefef", +"a2 c #f0f0f0", +"a1 c #f1f1f1", +".W c #f7f7f7", +".N c #f9f9f9", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQt.#.#QtQtQtQtQt.a.b.#.c.dQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQt.#.#.e.f.g.h.#QtQtQtQt.i.j.k.l.m.nQtQtQtQtQt", +"QtQtQtQtQtQtQt.#.o.p.q.r.s.t.u.v.w.#QtQtQt.x.y.z.k.k.AQtQtQtQtQt", +"QtQtQtQtQtQt.#.B.u.C.D.E.F.s.s.G.H.q.#Qt.#.I.J.K.c.#.LQtQtQtQtQt", +"QtQtQtQtQtQt.M.N.O.u.C.D.E.F.s.s.P.O.Q.#.R.S.T.UQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQt.V.W.N.O.u.C.F.X.r.Y.X.Z.0.1.2.3QtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQt.4.H.W.N.5.6.7.s.8.9#.###a#b#c.#QtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQt#d.D.H.W.Y#e#f#g#h#i#j#k#l#m#n#oQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQt#p#q.D.H.X#r#s#t#u#v#w#x#y#z#AQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQt#B#C#q#D#E#s.t#F#G#H.w#I#J#K#L#MQt#NQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQt#O#P#Q#R#S.s.F.r#T#U.w.F#V#WQt#MQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQt#X#Y#Z#C#0.F#1#2#3#4#5#6.O#7Qt#MQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQt#8#9a.a#aaabac.E.8adae.1.Eaf.##oQtagQtQtQtQtQtQtQtQt", +"QtQtQtQtQt#Nahaiajak.6al#5am#2an.q.paoap.zaqarasat.A.AQtQtQtQtQt", +"QtQtQtQtQtQtauavan#r.6#i#eawanaxay#4azaAapap.z.j.k.k.l.#QtQtQtQt", +"QtQtQtQtQtQtaBaC.ra##SaD.0aE#3ayaFaGaHaIaJaK.iaLaLataMQtQtQtQtQt", +"QtQtQtQtQtQtQtaNaOa#aPaQaR.1.paS.G.waTaUaVaWaX.y.y.zaYQtQtQtQtQt", +"QtQtQtQtQt#NQtQtaZaF#E#5a0a1a2a3ana4a5.#.#a6a7aKa8.za9QtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtb.#2.Hb#.Qbabb.#bcbdQtQtQtQtQtbebfQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQt.#.#.#.#bgbhbibjbkQtQtQtQtQtblbmQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQt.#bnbobp#lbq.#Qt.#brbsbtbua9QtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQt.#bv#kbwbxbyQt.#bzbAbBbCbD.#QtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQt.#bEbFbGbHbIQtbJbKbpbLbMbNQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQt.#bObP.#QtQt.#bQbRbSbTbUQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.#bVbW.#QtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt"}; diff --git a/src/ui/inlines.h b/src/ui/inlines.h new file mode 100644 index 000000000..3efccf0de --- /dev/null +++ b/src/ui/inlines.h @@ -0,0 +1,505 @@ +// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com> +// +// Use, modification and distribution is allowed without limitation, +// warranty, or liability of any kind. +// + +#ifndef INLINES_H +#define INLINES_H + +#include "fft.h" + +// *fast* convenience functions +static inline void +calc_freq(short* dest, short *src) +{ + static fft_state *state = NULL; + float tmp_out[257]; + int i; + + if (!state) + state = fft_init(); + + fft_perform(src, tmp_out, state); + + for (i = 0; i < 256; i++) + dest[i] = ((int) sqrt(tmp_out[i + 1])) >> 8; +} + +static inline void +calc_mono_freq(short dest[2][256], short src[2][512], int nch) +{ + int i; + short *d, *sl, *sr, tmp[512]; + + if (nch == 1) + calc_freq(dest[0], src[0]); + else + { + d = tmp; + sl = src[0]; + sr = src[1]; + for (i = 0; i < 512; i++) + { + *(d++) = (*(sl++) + *(sr++)) >> 1; + } + calc_freq(dest[0], tmp); + } +} + +static inline void stereo16_from_stereopcm8(register short *l, + register short *r, + register uchar *c, + long cnt) +{ + while (cnt >= 4l) + { + l[0] = c[0]; + r[0] = c[1]; + l[1] = c[2]; + r[1] = c[3]; + l[2] = c[4]; + r[2] = c[5]; + l[3] = c[6]; + r[3] = c[7]; + l += 4; + r += 4; + c += 8; + cnt -= 4l; + } + + if (cnt > 0l) + { + l[0] = c[0]; + r[0] = c[1]; + if (cnt > 1l) + { + l[1] = c[2]; + r[1] = c[3]; + if (cnt > 2l) + { + l[2] = c[4]; + r[2] = c[5]; + } + } + } +} + + +static inline void stereo16_from_stereopcm16(register short *l, + register short *r, + register short *s, + long cnt) +{ + while (cnt >= 4l) + { + l[0] = s[0]; + r[0] = s[1]; + l[1] = s[2]; + r[1] = s[3]; + l[2] = s[4]; + r[2] = s[5]; + l[3] = s[6]; + r[3] = s[7]; + l += 4; + r += 4; + s += 8; + cnt -= 4l; + } + + if (cnt > 0l) + { + l[0] = s[0]; + r[0] = s[1]; + if (cnt > 1l) + { + l[1] = s[2]; + r[1] = s[3]; + if (cnt > 2l) + { + l[2] = s[4]; + r[2] = s[5]; + } + } + } +} + + +static inline void mono16_from_monopcm8(register short *l, + register uchar *c, + long cnt) +{ + while (cnt >= 4l) + { + l[0] = c[0]; + l[1] = c[1]; + l[2] = c[2]; + l[3] = c[3]; + l += 4; + c += 4; + cnt -= 4l; + } + + if (cnt > 0l) + { + l[0] = c[0]; + if (cnt > 1l) + { + l[1] = c[1]; + if (cnt > 2l) + { + l[2] = c[2]; + } + } + } +} + + +static inline void mono16_from_monopcm16(register short *l, + register short *s, + long cnt) +{ + while (cnt >= 4l) + { + l[0] = s[0]; + l[1] = s[1]; + l[2] = s[2]; + l[3] = s[3]; + l += 4; + s += 4; + cnt -= 4l; + } + + if (cnt > 0l) + { + l[0] = s[0]; + if (cnt > 1l) + { + l[1] = s[1]; + if (cnt > 2l) + { + l[2] = s[2]; + } + } + } +} + + +static inline void fast_short_set(register short *p, + short v, + long c) +{ + while (c >= 4l) + { + p[0] = v; + p[1] = v; + p[2] = v; + p[3] = v; + p += 4; + c -= 4l; + } + + if (c > 0l) + { + p[0] = v; + if (c > 1l) + { + p[1] = v; + if (c > 2l) + { + p[2] = v; + } + } + } +} + +#ifdef FFTW +static inline void fast_real_set(register fftw_real *p, + fftw_real v, + long c) +{ + while (c >= 4l) + { + p[0] = v; + p[1] = v; + p[2] = v; + p[3] = v; + p += 4; + c -= 4l; + } + + if (c > 0l) + { + p[0] = v; + if (c > 1l) + { + p[1] = v; + if (c > 2l) + { + p[2] = v; + } + } + } +} + +static inline void fast_complex_set(register fftw_complex *p, + fftw_complex v, + long c) +{ + while (c >= 4l) + { + p[0] = v; + p[1] = v; + p[2] = v; + p[3] = v; + p += 4; + c -= 4l; + } + + if (c > 0l) + { + p[0] = v; + if (c > 1l) + { + p[1] = v; + if (c > 2l) + { + p[2] = v; + } + } + } +} + + +static inline void fast_real_set_from_short(register fftw_real *d, + register short *s, + long c) +{ + while (c >= 4l) + { + d[0] = fftw_real(s[0]); + d[1] = fftw_real(s[1]); + d[2] = fftw_real(s[2]); + d[3] = fftw_real(s[3]); + d += 4; + s += 4; + c -= 4l; + } + + if (c > 0l) + { + d[0] = fftw_real(s[0]); + if (c > 1l) + { + d[1] = fftw_real(s[1]); + if (c > 2l) + { + d[2] = fftw_real(s[2]); + } + } + } +} + +static inline void fast_complex_set_from_short(register fftw_complex *d, + register short *s, + long c) +{ + while (c >= 4l) + { + d[0].re = fftw_real(s[0]); + d[0].im = 0; + d[1].re = fftw_real(s[1]); + d[1].im = 0; + d[2].re = fftw_real(s[2]); + d[2].im = 0; + d[3].re = fftw_real(s[3]); + d[3].im = 0; + d += 4; + s += 4; + c -= 4l; + } + + if (c > 0l) + { + d[0].re = fftw_real(s[0]); + d[0].im = 0; + if (c > 1l) + { + d[1].re = fftw_real(s[1]); + d[1].im = 0; + if (c > 2l) + { + d[2].re = fftw_real(s[2]); + d[2].im = 0; + } + } + } +} + + +static inline void fast_real_avg_from_shorts(register fftw_real *d, + register short *s1, + register short *s2, + long c) +{ + fftw_real t0, t1, t2, t3; + while (c >= 4l) + { + t0 = (s1[0] + s2[0]) / 2; + t1 = (s1[1] + s2[1]) / 2; + t2 = (s1[2] + s2[2]) / 2; + t3 = (s1[3] + s2[3]) / 2; + d[0] = t0; + d[1] = t1; + d[2] = t2; + d[3] = t3; + d += 4; + s1 += 4; + s2 += 4; + c -= 4l; + } + + if (c > 0l) + { + d[0] = fftw_real((s1[0] + s2[0]) / 2); + if (c > 1l) + { + d[1] = fftw_real((s1[1] + s2[1]) / 2); + if (c > 2l) + { + d[2] = fftw_real((s1[2] + s2[2]) / 2); + } + } + } +} + +static inline void fast_complex_avg_from_shorts(register fftw_complex *d, + register short *s1, + register short *s2, + long c) +{ + fftw_real t0, t1, t2, t3; + while (c >= 4l) + { + t0 = (s1[0] + s2[0]) / 2; + t1 = (s1[1] + s2[1]) / 2; + t2 = (s1[2] + s2[2]) / 2; + t3 = (s1[3] + s2[3]) / 2; + d[0].re = t0; + d[0].im = 0; + d[1].re = t1; + d[1].im = 0; + d[2].re = t2; + d[2].im = 0; + d[3].re = t3; + d[3].im = 0; + d += 4; + s1 += 4; + s2 += 4; + c -= 4l; + } + + if (c > 0l) + { + d[0].re = fftw_real((s1[0] + s2[0]) / 2); + d[0].im = 0; + if (c > 1l) + { + d[1].re = fftw_real((s1[1] + s2[1]) / 2); + d[1].im = 0; + if (c > 2l) + { + d[2].re = fftw_real((s1[2] + s2[2]) / 2); + d[2].im = 0; + } + } + } +} + + +static inline fftw_complex fftw_complex_from_real( fftw_real re ) +{ + fftw_complex c; + + c.re = re; + c.im = 0; + + return c; +} + +static inline void fast_reals_set(register fftw_real *p1, + register fftw_real *p2, + fftw_real v, + long c) +{ + while (c >= 4l) + { + p1[0] = v; + p1[1] = v; + p1[2] = v; + p1[3] = v; + p2[0] = v; + p2[1] = v; + p2[2] = v; + p2[3] = v; + p1 += 4; + p2 += 4; + c -= 4l; + } + + if (c > 0l) + { + p1[0] = v; + p2[0] = v; + if (c > 1l) + { + p1[1] = v; + p2[1] = v; + if (c > 2l) + { + p1[2] = v; + p2[2] = v; + } + } + } +} + +static inline void fast_complex_set(register fftw_complex *p1, + register fftw_complex *p2, + fftw_complex v, + long c) +{ + while (c >= 4l) + { + p1[0] = v; + p1[1] = v; + p1[2] = v; + p1[3] = v; + p2[0] = v; + p2[1] = v; + p2[2] = v; + p2[3] = v; + p1 += 4; + p2 += 4; + c -= 4l; + } + + if (c > 0l) + { + p1[0] = v; + p2[0] = v; + if (c > 1l) + { + p1[1] = v; + p2[1] = v; + if (c > 2l) + { + p1[2] = v; + p2[2] = v; + } + } + } +} +#endif // FFTW + +#endif // INLINES_H diff --git a/src/ui/jumptotrackdialog.cpp b/src/ui/jumptotrackdialog.cpp new file mode 100644 index 000000000..bcd0f308c --- /dev/null +++ b/src/ui/jumptotrackdialog.cpp @@ -0,0 +1,128 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "jumptotrackdialog.h" +#include "playlistmodel.h" + +#include <QStringListModel> +#include <QSortFilterProxyModel> +#include <QShortcut> +#include <QKeySequence> + +JumpToTrackDialog::JumpToTrackDialog(QWidget* parent, Qt::WFlags fl) +: QDialog( parent, fl ) +{ + setupUi(this); + setAttribute(Qt::WA_QuitOnClose, FALSE); + m_playListModel = 0; + m_listModel = new QStringListModel(this); + + m_proxyModel = new QSortFilterProxyModel; + m_proxyModel->setDynamicSortFilter(true); + m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + m_proxyModel->setSourceModel(m_listModel); + songsListView->setModel(m_proxyModel); + + connect(songsListView,SIGNAL(doubleClicked(const QModelIndex &)), + this,SLOT(jumpTo(const QModelIndex&))); + + + connect(songsListView->selectionModel(), + SIGNAL(currentRowChanged(const QModelIndex&,const QModelIndex&)), + this,SLOT(queueUnqueue(const QModelIndex&,const QModelIndex&))); + + new QShortcut(QKeySequence("Q"),this,SLOT(on_queuePushButton_clicked())); + new QShortcut(QKeySequence("J"),this,SLOT(on_jumpToPushButton_clicked())); + new QShortcut(QKeySequence("F5"),this,SLOT(on_refreshPushButton_clicked())); +} + +JumpToTrackDialog::~JumpToTrackDialog() +{ +} + + +void JumpToTrackDialog::on_closePushButton_clicked() +{ + hide(); +} + +void JumpToTrackDialog::on_refreshPushButton_clicked() +{ + refresh(); +} + +void JumpToTrackDialog::on_queuePushButton_clicked() +{ + QModelIndexList mi_list = songsListView->selectionModel()->selectedRows(); + if(!mi_list.isEmpty()) + { + int selected = (m_proxyModel->mapToSource(mi_list.at(0))).row(); + m_playListModel->setQueued(m_playListModel->item(selected)); + if(m_playListModel->isQueued(m_playListModel->item(selected))) + queuePushButton->setText(tr("Unqueue")); + else + queuePushButton->setText(tr("Queue")); + } +} + +void JumpToTrackDialog::on_jumpToPushButton_clicked() +{ + QModelIndexList mi_list = songsListView->selectionModel()->selectedRows(); + if(!mi_list.isEmpty()) + { + jumpTo(mi_list.at(0)); + } +} + +void JumpToTrackDialog::refresh() +{ + filterLineEdit->clear(); + QStringList titles = m_playListModel->getTitles(0,m_playListModel->count()); + m_listModel->setStringList(titles); + filterLineEdit->setFocus(); +} + +void JumpToTrackDialog::setModel(PlayListModel * model) +{ + m_playListModel = model; +} + +void JumpToTrackDialog::on_filterLineEdit_textChanged(const QString &str) +{ + m_proxyModel->setFilterFixedString(str); +} + +void JumpToTrackDialog::jumpTo(const QModelIndex & index) +{ + int selected = (m_proxyModel->mapToSource(index)).row(); + m_playListModel->setCurrent(selected); + emit playRequest(); +} + +void JumpToTrackDialog::queueUnqueue(const QModelIndex& curr,const QModelIndex&) +{ + int row = m_proxyModel->mapToSource(curr).row(); + if(m_playListModel->isQueued(m_playListModel->item(row))) + queuePushButton->setText(tr("Unqueue")); + else + queuePushButton->setText(tr("Queue")); +} + + diff --git a/src/ui/jumptotrackdialog.h b/src/ui/jumptotrackdialog.h new file mode 100644 index 000000000..cfe629693 --- /dev/null +++ b/src/ui/jumptotrackdialog.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef JUMPTOTRACKDIALOG_H +#define JUMPTOTRACKDIALOG_H + +#include <QDialog> +#include "ui_jumptotrackdialog.h" + +/** + @author Vladimir Kuznetsov <vovanec@gmail.com> + */ + +class QStringListModel; +class PlayListModel; +class QSortFilterProxyModel; + + +class JumpToTrackDialog : public QDialog, private Ui::JumpToTrackDialog +{ + Q_OBJECT + +public: + JumpToTrackDialog(QWidget* parent = 0, Qt::WFlags fl = 0 ); + ~JumpToTrackDialog(); + void setModel(PlayListModel* model); + void refresh(); +protected slots: + void on_closePushButton_clicked(); + void on_refreshPushButton_clicked(); + void on_queuePushButton_clicked(); + void on_jumpToPushButton_clicked(); + void on_filterLineEdit_textChanged(const QString&); + void jumpTo(const QModelIndex&); + void queueUnqueue(const QModelIndex&,const QModelIndex&); +signals: + void playRequest(); +private: + PlayListModel* m_playListModel; + QStringListModel* m_listModel; + QSortFilterProxyModel* m_proxyModel; +}; + +#endif + diff --git a/src/ui/keyboardmanager.cpp b/src/ui/keyboardmanager.cpp new file mode 100644 index 000000000..5ad32fee7 --- /dev/null +++ b/src/ui/keyboardmanager.cpp @@ -0,0 +1,260 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + + +#include <QKeyEvent> + +#include "playlist.h" +#include "playlistmodel.h" +#include "listwidget.h" +#include "keyboardmanager.h" +#include "mainwindow.h" + + +KeyboardManager::KeyboardManager ( PlayList* pl ) +{ + m_playlist = pl; +} + +bool KeyboardManager::handleKeyPress ( QKeyEvent* ke ) +{ + bool handled = TRUE; + switch ( ke->key() ) + { + case Qt::Key_Up: + keyUp ( ke ); + break; + case Qt::Key_Down: + keyDown ( ke ); + break; + case Qt::Key_PageUp: + keyPgUp ( ke ); + break; + case Qt::Key_PageDown: + keyPgDown ( ke ); + break; + case Qt::Key_Enter: + case Qt::Key_Return: + keyEnter ( ke ); + default: + handled = FALSE; + } + return handled; +} + +bool KeyboardManager::handleKeyRelease ( QKeyEvent* ) +{ + return FALSE; +} + + + +void KeyboardManager::setModel ( PlayListModel *m ) +{ + m_playListModel = m; +} + +void KeyboardManager::keyUp ( QKeyEvent * ke ) +{ + QList<int> rows = m_playListModel->getSelectedRows(); + ListWidget* list_widget = m_playlist->listWidget(); + + if ( rows.count() > 0 ) + { + if(rows[0] == 0 && rows.count() == 1) + return; + + if ( ! ( ke->modifiers() & Qt::ShiftModifier || ke->modifiers() & Qt::AltModifier ) ) + { + m_playListModel->clearSelection(); + list_widget->setAnchorRow(-1); + } + + bool select_top = false; + int first_visible = list_widget->firstVisibleRow(); + int last_visible = list_widget->visibleRows() + first_visible - 1; + foreach ( int i, rows ) + { + if ( i > last_visible || i < first_visible ) + { + select_top = true; + break; + } + } + + if ( !select_top || ke->modifiers() & Qt::ShiftModifier || ke->modifiers() & Qt::AltModifier ) + { + if ( ke->modifiers() == Qt::AltModifier ) + { + m_playListModel->moveItems ( rows[0],rows[0] - 1 ); + list_widget->setAnchorRow ( list_widget->getAnchorRow() - 1 ); + } + else + { + if ( rows.last() > list_widget->getAnchorRow() && ke->modifiers() & Qt::ShiftModifier ) + { + m_playListModel->setSelected ( rows.last(),false ); + } + else if ( rows[0] > 0 ) + { + m_playListModel->setSelected ( rows[0] - 1,true ); + } + else + { + m_playListModel->setSelected ( rows[0],true ); + if(list_widget->getAnchorRow() == -1) + list_widget->setAnchorRow(rows[0]); + } + + if ( ! ( ke->modifiers() & Qt::ShiftModifier ) && rows[0] > 0 ) + list_widget->setAnchorRow ( rows[0] - 1 ); + } + } + else + { + m_playListModel->setSelected ( list_widget->firstVisibleRow(),true ); + list_widget->setAnchorRow(list_widget->firstVisibleRow()); + } + + rows = m_playListModel->getSelectedRows(); + + if ( rows[0] < list_widget->firstVisibleRow() && list_widget->firstVisibleRow() > 0 ) + { + int r = rows.last() > list_widget->getAnchorRow() ? rows.last(): rows.first(); + if(ke->modifiers() & Qt::ShiftModifier && (r >= list_widget->firstVisibleRow() )) + ; + else + list_widget->scroll ( list_widget->firstVisibleRow() - 1 ); + } + } + else + { + //if(list_widget->getAnchorRow() == -1) + list_widget->setAnchorRow(list_widget->firstVisibleRow()); + m_playListModel->setSelected ( list_widget->firstVisibleRow(),true ); + } +} + +void KeyboardManager::keyDown ( QKeyEvent * ke ) +{ + QList<int> rows = m_playListModel->getSelectedRows(); + ListWidget* list_widget = m_playlist->listWidget(); + //qWarning("count: %d",rows.count()); + if ( rows.count() > 0 ) + { + if ( ! ( ke->modifiers() & Qt::ShiftModifier || ke->modifiers() & Qt::AltModifier ) ) + { + m_playListModel->clearSelection(); + list_widget->setAnchorRow(-1); + } + + bool select_top = false; + int first_visible = list_widget->firstVisibleRow(); + int last_visible = list_widget->visibleRows() + first_visible - 1; + foreach ( int i, rows ) + { + if ( i > last_visible || i < first_visible ) + { + select_top = true; + break; + } + } + + if ( !select_top || ke->modifiers() & Qt::ShiftModifier || ke->modifiers() & Qt::AltModifier ) + { + if ( ke->modifiers() == Qt::AltModifier ) + { + m_playListModel->moveItems ( rows.last(),rows.last() + 1 ); + list_widget->setAnchorRow ( list_widget->getAnchorRow() + 1 ); + } + else + { + //qWarning("list_widget %d",list_widget->getAnchorRow()); + //qWarning("model count: %d rows.last(): %d",m_playListModel->count(),rows.last()); + if ( rows[0] < list_widget->getAnchorRow() && ke->modifiers() & Qt::ShiftModifier ) + m_playListModel->setSelected ( rows[0],false ); + else if ( rows.last() < m_playListModel->count() - 1 ) + { + m_playListModel->setSelected ( rows.last() + 1,true ); + } + else + { + m_playListModel->setSelected ( rows.last(),true ); + if(list_widget->getAnchorRow() == -1) + list_widget->setAnchorRow(rows.last()); + } + + if ( ! ( ke->modifiers() & Qt::ShiftModifier ) && rows.last() < m_playListModel->count() - 1 ) + list_widget->setAnchorRow ( rows.last() + 1 ); + } + } + else + { + m_playListModel->setSelected ( list_widget->firstVisibleRow(),true ); + list_widget->setAnchorRow(list_widget->firstVisibleRow()); + } + + rows = m_playListModel->getSelectedRows(); + + if ( !rows.isEmpty() && rows.last() >= list_widget->visibleRows() + list_widget->firstVisibleRow() ) + { + int r = rows.first() < list_widget->getAnchorRow() ? rows.first(): rows.last(); + if(ke->modifiers() & Qt::ShiftModifier && + (r < list_widget->firstVisibleRow() + list_widget->visibleRows() )) + ; + else + list_widget->scroll ( list_widget->firstVisibleRow() + 1 ); + } + } + else + { + m_playListModel->setSelected ( list_widget->firstVisibleRow(),true ); + //if(list_widget->getAnchorRow() == -1) + list_widget->setAnchorRow(list_widget->firstVisibleRow()); + } +} + +void KeyboardManager::keyPgUp ( QKeyEvent * ) +{ + ListWidget* list_widget = m_playlist->listWidget(); + int page_size = list_widget->visibleRows(); + int offset= ( list_widget->firstVisibleRow()-page_size >= 0 ) ?list_widget->firstVisibleRow()-page_size:0; + list_widget->scroll ( offset ); +} + +void KeyboardManager::keyPgDown ( QKeyEvent * ) +{ + ListWidget* list_widget = m_playlist->listWidget(); + int page_size = list_widget->visibleRows(); + int offset = ( list_widget->firstVisibleRow() +page_size < m_playListModel->count() ) ? + list_widget->firstVisibleRow() +page_size:m_playListModel->count() - 1; + list_widget->scroll ( offset ); +} + +void KeyboardManager::keyEnter ( QKeyEvent * ) +{ + QList<int> rows = m_playListModel->getSelectedRows(); + MainWindow* mw = qobject_cast<MainWindow*> ( m_playlist->parentWidget() ); + if ( mw && rows.count() > 0 ) + { + m_playListModel->setCurrent ( rows[0] ); + mw->replay(); + } +} diff --git a/src/ui/keyboardmanager.h b/src/ui/keyboardmanager.h new file mode 100644 index 000000000..2b33b5ef9 --- /dev/null +++ b/src/ui/keyboardmanager.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + + +#ifndef _KEYBOARDMANAGER_H +#define _KEYBOARDMANAGER_H + +class PlayList; +class PlayListModel; +class QKeyEvent; + + +/*! + * Class \b KeyboardManager represents key handler object that processes + * all key events passed to the \b PlayList + * @author Vladimir Kuznetsov <vovanec@gmail.com> + */ +class KeyboardManager +{ + public: + /*! + * Constructor. Takes \b PlayList object as an argument. + */ + KeyboardManager ( PlayList* ); + + /*! + * Handles key press events from \b PlayList object. Returns \b TRUE + * if the key was handled, otherwise \b FALSE. + */ + bool handleKeyPress ( QKeyEvent* ); + + /*! + * Handles key release events from \b PlayList object. Returns \b TRUE + * if the key was handled, otherwise \b FALSE. + */ + bool handleKeyRelease ( QKeyEvent* ); + + /*! + * Inits the \b KeyboardManager object with data model. + */ + void setModel ( PlayListModel* ); + protected: + void keyUp ( QKeyEvent* ke ); + void keyDown ( QKeyEvent* ke ); + void keyPgUp ( QKeyEvent* ke ); + void keyPgDown ( QKeyEvent* ke ); + void keyEnter ( QKeyEvent* ke ); + private: + PlayList* m_playlist; + PlayListModel* m_playListModel; +}; + +#endif + diff --git a/src/ui/listwidget.cpp b/src/ui/listwidget.cpp new file mode 100644 index 000000000..fb2173b33 --- /dev/null +++ b/src/ui/listwidget.cpp @@ -0,0 +1,482 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QPixmap> +#include <QResizeEvent> +#include <QPainter> +#include <QFont> +#include <QFontMetrics> +#include <QSettings> +#include <QMenu> +#include <QUrl> +#include <QApplication> + +#include "mediafile.h" +#include "textscroller.h" +#include "listwidget.h" +#include "skin.h" +#include "playlistmodel.h" +#include "playlist.h" + +#define INVALID_ROW -1 + +ListWidget::ListWidget(QWidget *parent) + : QWidget(parent) +{ + m_update = FALSE; + m_skin = Skin::getPointer(); + loadColors(); + setWindowFlags(Qt::FramelessWindowHint); + m_menu = new QMenu(this); + m_scroll_direction = NONE; + m_prev_y = 0; + m_anchor_row = INVALID_ROW; + + m_first = 0; + m_rows = 0; + m_scroll = FALSE; + m_select_on_release = FALSE; + readSettings(); + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); + setAcceptDrops(true); +} + + +ListWidget::~ListWidget() +{} + +void ListWidget::readSettings() +{ + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + QString fontname = settings.value("PlayList/Font","").toString(); + if (fontname.isEmpty ()) + fontname = QFont("Helvetica [Cronyx]", 10).toString(); + m_font.fromString(fontname); + + if (m_update) + { + delete m_metrics; + m_metrics = new QFontMetrics(m_font); + m_rows = (height() - 10) / m_metrics->ascent (); + updateList(); + } + else + { + m_update = TRUE; + m_metrics = new QFontMetrics(m_font); + } +} + +void ListWidget::loadColors() +{ + m_normal.setNamedColor(m_skin->getPLValue("normal")); + m_current.setNamedColor(m_skin->getPLValue("current")); + m_normal_bg.setNamedColor(m_skin->getPLValue("normalbg")); + m_selected_bg.setNamedColor(m_skin->getPLValue("selectedbg")); +} + +void ListWidget::paintEvent(QPaintEvent *) +{ + + QPainter m_painter(this); + //m_painter.setPen(Qt::white); + m_painter.setFont(m_font); + m_painter.setBrush(QBrush(m_normal_bg)); + m_painter.drawRect(-1,-1,width()+1,height()+1); + + + + for (int i=0; i<m_titles.size(); ++i ) + { + if (m_model->isSelected(i + m_first)) + { + m_painter.setBrush(QBrush(m_selected_bg)); + m_painter.setPen(m_selected_bg); + m_painter.drawRect ( 6, 15+(i-1)*m_metrics->ascent(), + width() - 10, m_metrics->ascent()); + } + + if (m_model->currentRow() == i + m_first) + m_painter.setPen(m_current); + else + m_painter.setPen(m_normal); //243,58 + + m_painter.drawText(10,14+i*m_metrics->ascent(),m_titles.at(i)); + + if (m_model->isQueued(m_model->item(i + m_first))) + { + QString queue_string = "|" + + QString::number(1 + m_model->queuedIndex(m_model->item(m_first + i))) + "|"; + + int old_size = m_font.pointSize(); + m_font.setPointSize(old_size - 1 ); + m_painter.setFont(m_font); + + m_painter.drawText(width() - 10 - m_metrics->width(queue_string) - m_metrics->width(m_times.at(i)), 12+i*m_metrics->ascent (), queue_string); + + m_font.setPointSize(old_size); + m_painter.setFont(m_font); + + + m_painter.setBrush(QBrush(Qt::transparent)); + //m_painter.drawRect(width() - 10 - m_metrics->width(queue_string) - m_metrics->width(m_times.at(i)), + // /*14+*/i*m_metrics->ascent () + 3,10,12); + m_painter.setBrush(QBrush(m_normal_bg)); + } + + + m_painter.drawText(width() - 7 - m_metrics->width(m_times.at(i)), + 14+i*m_metrics->ascent (), m_times.at(i)); + + } + +} + +void ListWidget::mouseDoubleClickEvent (QMouseEvent *e) +{ + int y = e->y(); + int row = rowAt(y); + if (INVALID_ROW != row) + { + m_model->setCurrent(row); + emit selectionChanged(); + update(); + } +} + + +void ListWidget::mousePressEvent(QMouseEvent *e) +{ + m_scroll = TRUE; + int y = e->y(); + int row = rowAt(y); + + if (INVALID_ROW != row && m_model->count() > row) + { + if (!(Qt::ControlModifier & e->modifiers () || + Qt::ShiftModifier & e->modifiers () || + m_model->isSelected(row))) + m_model->clearSelection(); + + if (m_model->isSelected(row) && (e->modifiers() == Qt::NoModifier)) + m_select_on_release = TRUE; + + //qWarning("m_prev_clicked_row: %d",m_prev_clicked_row); + + m_pressed_row = row; + if ((Qt::ShiftModifier & e->modifiers())) + { + + if (m_pressed_row > m_anchor_row) + { + //int upper_selected = m_model->firstSelectedUpper(m_anchor_row); + //if (INVALID_ROW != upper_selected) + //{ + /*for (int j = upper_selected;j < m_anchor_row;j++) + { + m_model->setSelected(j, false); + }*/ + m_model->clearSelection(); + for (int j = m_anchor_row;j <= m_pressed_row;j++) + { + m_model->setSelected(j, true); + } + //} + } + else + { + m_model->clearSelection(); + for (int j = m_anchor_row;j >= m_pressed_row;j--) + { + m_model->setSelected(j, true); + } + } + + /* + int upper_selected = m_model->firstSelectedUpper(row); + int lower_selected = m_model->firstSelectedLower(row); + if (INVALID_ROW != upper_selected) + { + for (int j = upper_selected;j <= row;j++) + { + m_model->setSelected(j, true); + } + } + else if (INVALID_ROW != lower_selected) + { + for (int j = row;j <= lower_selected;j++) + { + m_model->setSelected(j, true); + } + } + else + m_model->setSelected(row, true); + */ + } + else + { + if (!m_model->isSelected(row) || (Qt::ControlModifier & e->modifiers())) + m_model->setSelected(row, !m_model->isSelected(row)); + } + + if (m_model->getSelection(m_pressed_row).count() == 1) + m_anchor_row = m_pressed_row; + //qWarning("m_anchor_row: %d",m_anchor_row); + + update(); + } + QWidget::mousePressEvent(e); +} + +void ListWidget::resizeEvent(QResizeEvent *e) +{ + m_rows = (e->size().height() - 10) / m_metrics->ascent (); + + m_scroll = TRUE; + + updateList(); + QWidget::resizeEvent(e); +} + +void ListWidget::wheelEvent (QWheelEvent *e) +{ + if (m_model->count() <= m_rows) + return; + if ((m_first == 0 && e->delta() > 0) || + ((m_first == m_model->count() - m_rows) && e->delta() < 0)) + return; + m_first -= e->delta()/40; //40*3 TODO: add step to config + if (m_first < 0) + m_first = 0; + + if (m_first > m_model->count() - m_rows) + m_first = m_model->count() - m_rows; + + m_scroll = FALSE; + updateList(); +} + +void ListWidget::updateList() +{ + if (m_model->count() < (m_rows+m_first+1) && m_rows< m_model->count()) + { + m_first = m_model->count() - m_rows; + } + if (m_model->count() < m_rows + 1) + { + m_first = 0; + emit positionChanged(0,0); + } + else + { + //int pos = m_first*99/(m_model->count() - m_rows); + //emit positionChanged(pos); + emit positionChanged(m_first, m_model->count() - m_rows); + } + if (m_model->count() <= m_first) + { + m_first = 0; + emit positionChanged(0, qMax(0, m_model->count() - m_rows)); + } + + m_titles = m_model->getTitles(m_first, m_rows ); + m_times = m_model->getTimes(m_first, m_rows ); + m_scroll = FALSE; + //add numbers + for (int i = 0; i < m_titles.size(); ++i) + { + QString title = m_titles.at(i); + m_titles.replace(i, title.prepend(QString("%1").arg(m_first+i+1)+". ")); + + } + if (m_model->currentItem()) + { + TextScroller::getPointer()->setText("*** "+m_model->currentItem()->title()); + parentWidget()->parentWidget()->setWindowTitle(m_model->currentItem()->title()); + } + cut(); + update(); +} + +void ListWidget::setModel(PlayListModel *model) +{ + m_model = model; + connect (m_model, SIGNAL(listChanged()), SLOT(updateList())); + connect (m_model, SIGNAL(currentChanged()), SLOT(recenterCurrent())); + updateList(); +} + +void ListWidget::scroll(int sc) +{ + if (m_model->count() <= m_rows) + return; + m_first = sc; //*(m_model->count() - m_rows)/99; + m_scroll = TRUE; + updateList(); +} + +void ListWidget::cut() +{ + bool cut; + for (int i=0; i<m_titles.size(); ++i ) + { + QString name; + cut = FALSE; + + int queue_number_space = 0; + if (m_model->isQueued(m_model->item(i + m_first))) + { + int index = m_model->queuedIndex(m_model->item(m_first + i)); + QString queue_string = "|"+QString::number(index)+"|"; + queue_number_space = m_metrics->width(queue_string); + } + while ( m_metrics->width(m_titles.at(i)) > (this->width() - 54 - queue_number_space)) + { + cut = TRUE; + name = m_titles.at(i); + m_titles.replace(i, name.left(name.length()-1) ); + } + if (cut) + { + m_titles.replace(i, name.left(name.length()-3).trimmed()+"..."); + + } + } +} + +void ListWidget::updateSkin() +{ + loadColors(); + update(); +} + +void ListWidget::dragEnterEvent(QDragEnterEvent *event) +{ + if (event->mimeData()->hasFormat("text/uri-list")) + event->acceptProposedAction(); +} + + +void ListWidget::dropEvent(QDropEvent *event) +{ + if (event->mimeData()->hasUrls()) + { + QList<QUrl> list_urls = event->mimeData()->urls(); + event->acceptProposedAction(); + QApplication::restoreOverrideCursor(); + + foreach(QUrl u,list_urls) + { + QString add_string = u.toString(QUrl::RemoveScheme); + if (!add_string.isEmpty()) + processFileInfo(QFileInfo(add_string)); + } + } + +} + +void ListWidget::processFileInfo(const QFileInfo& info) +{ + if (info.isDir()) + { + m_model->addDirectory(info.absoluteFilePath()); + } + else + { + m_model->addFile(info.absoluteFilePath()); + } +} + +void ListWidget::mouseMoveEvent(QMouseEvent *e) +{ + m_scroll = true; + if (m_prev_y > e->y()) + m_scroll_direction = TOP; + else if (m_prev_y < e->y()) + m_scroll_direction = DOWN; + else + m_scroll_direction = NONE; + + int row = rowAt(e->y()); + + if (INVALID_ROW != row) + { + SimpleSelection sel = m_model->getSelection(m_pressed_row); + if ((sel.m_top == 0 && m_scroll_direction == TOP) && sel.count() > 1 || + (sel.m_bottom == m_model->count() - 1 && m_scroll_direction == DOWN && sel.count() > 1) + ) + return; + + if (row + 1 == m_first + m_rows && m_scroll_direction == DOWN) + (m_first + m_rows < m_model->count() ) ? m_first ++ : m_first; + else if (row == m_first && m_scroll_direction == TOP) + (m_first > 0) ? m_first -- : 0; + + m_model->moveItems(m_pressed_row,row); + m_prev_y = e->y(); + m_scroll = false; + m_pressed_row = row; + } +} + +void ListWidget::mouseReleaseEvent(QMouseEvent *e) +{ + if (FALSE != m_select_on_release) + { + m_model->clearSelection(); + m_model->setSelected(m_pressed_row,true); + //if(e->modifiers() != Qt::ShiftModifier) + m_anchor_row = m_pressed_row; + m_select_on_release = FALSE; + } + m_pressed_row = INVALID_ROW; + m_scroll_direction = NONE; + QWidget::mouseReleaseEvent(e); +} + +int ListWidget::rowAt( int y) const +{ + for (int i = 0; i < qMin(m_rows, m_model->count() - m_first); ++i ) + { + if ((y >= 2+i*m_metrics->ascent())&&(y < 2+(i+1)*m_metrics->ascent())) + return m_first + i; + } + return INVALID_ROW; +} + + +void ListWidget::contextMenuEvent(QContextMenuEvent * event) +{ + if (menu()) + menu()->exec(event->globalPos()); +} + +void ListWidget::recenterCurrent() +{ + if (!m_scroll) + { + if (m_first + m_rows < m_model->currentRow() + 1) + m_first = qMin(m_model->count() - m_rows, + m_model->currentRow() - m_rows/2 + 1); + else if (m_first > m_model->currentRow()) + m_first = qMax (m_model->currentRow() - m_rows/2 + 1, 0); + } +} + + diff --git a/src/ui/listwidget.h b/src/ui/listwidget.h new file mode 100644 index 000000000..2f20a3bf8 --- /dev/null +++ b/src/ui/listwidget.h @@ -0,0 +1,126 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef LISTWIDGET_H +#define LISTWIDGET_H + +#include <QWidget> +#include <QDir> +#include <QContextMenuEvent> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class QFont; +class QFontMetrics; +class QMenu; +class QAction; + +class PlayList; +class PlayListModel; +class Skin; +class MediaFile; + +class ListWidget : public QWidget +{ + Q_OBJECT +public: + ListWidget(QWidget *parent = 0); + + ~ListWidget(); + + void setModel(PlayListModel *); + void readSettings(); + /*! + * Returns count of currently visible rows. + */ + int visibleRows()const{return m_rows;} + + /*! + * Returns number of first visible row. + */ + int firstVisibleRow()const{return m_first;} + + int getAnchorRow()const{return m_anchor_row;} + + void setAnchorRow(int r){m_anchor_row = r;} + +public slots: + void updateList(); + void scroll(int); //0-99 + void recenterCurrent(); + + QMenu *menu() + { + return m_menu; + }; + +signals: + void selectionChanged(); + void positionChanged(int, int); //current position, maximum value + +protected: + void paintEvent(QPaintEvent *); + void mouseDoubleClickEvent(QMouseEvent *); + void mousePressEvent(QMouseEvent *); + void mouseMoveEvent(QMouseEvent *); + void mouseReleaseEvent(QMouseEvent *); + void resizeEvent(QResizeEvent *); + void wheelEvent(QWheelEvent *); + int rowAt(int)const; + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent *event); + void contextMenuEvent ( QContextMenuEvent * event ); + +private slots: + void updateSkin(); + +private: + void cut(); + void loadColors(); + void processFileInfo(const QFileInfo&); + bool m_update; + bool m_scroll; + int m_pressed_row; + QMenu *m_menu; + PlayListModel *m_model; + int m_rows, m_first; + QList <QString> m_titles; + QList <QString> m_times; + PlayList *m_pl; + QFont m_font; + QFontMetrics *m_metrics; + Skin *m_skin; + QColor m_normal, m_current, m_normal_bg, m_selected_bg; + int m_anchor_row; + + enum ScrollDirection + { + NONE = 0,TOP,DOWN + }; + + /*! + * Scroll direction that is preforming in current moment. + */ + ScrollDirection m_scroll_direction; + int m_prev_y; + bool m_select_on_release; +}; + +#endif diff --git a/src/ui/logscale.cpp b/src/ui/logscale.cpp new file mode 100644 index 000000000..921004fd9 --- /dev/null +++ b/src/ui/logscale.cpp @@ -0,0 +1,74 @@ +// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com> +// +// Use, modification and distribution is allowed without limitation, +// warranty, or liability of any kind. +// + +#include "logscale.h" + +#include <math.h> +#include <stdio.h> + + +LogScale::LogScale(int maxscale, int maxrange) + : indices(0), s(0), r(0) +{ + setMax(maxscale, maxrange); +} + + +LogScale::~LogScale() +{ + if (indices) + delete [] indices; +} + + +void LogScale::setMax(int maxscale, int maxrange) +{ + if (maxscale == 0 || maxrange == 0) + return; + + s = maxscale; + r = maxrange; + + if (indices) + delete [] indices; + + double alpha; + int i, scaled; + double domain = double(maxscale), + range = double(maxrange), + x = 1.0, + dx = 1.0, + y = 0.0, + yy = 0.0, + t = 0.0, + e4 = double(1.0E-8); + + indices = new int[maxrange]; + for (i = 0; i < maxrange; i++) + indices[i] = 0; + + // initialize log scale + while (fabs(dx) > e4) { + t = log((domain + x) / x); + y = (x * t) - range; + yy = t - (domain / (x + domain)); + dx = y / yy; + x -= dx; + } + + alpha = x; + for (i = 1; i < (int) domain; i++) { + scaled = (int) floor(0.5 + (alpha * log((double(i) + alpha) / alpha))); + if (indices[scaled - 1] < i) + indices[scaled - 1] = i; + } +} + + +int LogScale::operator[](int index) +{ + return indices[index]; +} diff --git a/src/ui/logscale.h b/src/ui/logscale.h new file mode 100644 index 000000000..d74d25207 --- /dev/null +++ b/src/ui/logscale.h @@ -0,0 +1,31 @@ +// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com> +// +// Use, modification and distribution is allowed without limitation, +// warranty, or liability of any kind. +// + +#ifndef __logscale_h +#define __logscale_h + + +class LogScale +{ +public: + LogScale(int = 0, int = 0); + ~LogScale(); + + int scale() const { return s; } + int range() const { return r; } + + void setMax(int, int); + + int operator[](int); + + +private: + int *indices; + int s, r; +}; + + +#endif // __logscale_h diff --git a/src/ui/mainvisual.cpp b/src/ui/mainvisual.cpp new file mode 100644 index 000000000..5bdcbf5cb --- /dev/null +++ b/src/ui/mainvisual.cpp @@ -0,0 +1,628 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QTimer> +#include <QSettings> +#include <QPainter> +#include <QMenu> +#include <QActionGroup> + +#include <buffer.h> +#include <constants.h> +#include <output.h> +#include <math.h> +#include <stdlib.h> + +#include "skin.h" +#include "fft.h" +#include "inlines.h" +#include "mainvisual.h" + + +MainVisual *MainVisual::pointer = 0; + +MainVisual *MainVisual::getPointer() +{ + if ( !pointer ) + qFatal ( "MainVisual: this object not created!" ); + return pointer; +} + +MainVisual::MainVisual (QWidget *parent) + : Visual (parent), m_vis (0), m_playing (FALSE) +{ + m_draw = TRUE; + m_skin = Skin::getPointer(); + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSettings())); + resize(75,20); + m_pixmap = QPixmap (75,20); + m_timer = new QTimer (this); + connect(m_timer, SIGNAL (timeout()), this, SLOT (timeout())); + m_nodes.clear(); + createMenu(); + readSettings(); + pointer = this; +} + +MainVisual::~MainVisual() +{ + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + if (m_vis) + { + settings.setValue("Visualization/type",m_vis->name()); + delete m_vis; + m_vis = 0; + } + else + settings.setValue("Visualization/type", "None"); + settings.setValue("Visualization/rate", 1000/m_timer->interval()); + while (!m_nodes.isEmpty()) + delete m_nodes.takeFirst(); +} + +void MainVisual::setVisual (VisualBase *newvis) +{ + m_timer->stop(); + if (m_vis) + delete m_vis; + m_vis = newvis; + if (m_vis) + m_timer->start(); + else + { + m_pixmap.fill (Qt::transparent); + update(); + } +} + +void MainVisual::clear() +{ + while (!m_nodes.isEmpty()) + delete m_nodes.takeFirst(); + if (m_vis) + m_vis->clear(); + update(); +} + +void MainVisual::add ( Buffer *b, unsigned long w, int c, int p ) +{ + if (!m_timer->isActive () || !m_vis) + return; + long len = b->nbytes, cnt; + short *l = 0, *r = 0; + + len /= c; + len /= ( p / 8 ); + if ( len > 512 ) + len = 512; + cnt = len; + + if ( c == 2 ) + { + l = new short[len]; + r = new short[len]; + + if ( p == 8 ) + stereo16_from_stereopcm8 ( l, r, b->data, cnt ); + else if ( p == 16 ) + stereo16_from_stereopcm16 ( l, r, ( short * ) b->data, cnt ); + } + else if ( c == 1 ) + { + l = new short[len]; + + if ( p == 8 ) + mono16_from_monopcm8 ( l, b->data, cnt ); + else if ( p == 16 ) + mono16_from_monopcm16 ( l, ( short * ) b->data, cnt ); + } + else + len = 0; + + m_nodes.append ( new VisualNode ( l, r, len, w ) ); +} + +void MainVisual::timeout() +{ + VisualNode *node = 0; + + if ( /*playing &&*/ output()) + { + //output()->mutex()->lock (); + //long olat = output()->latency(); + //long owrt = output()->written(); + //output()->mutex()->unlock(); + + //long synctime = owrt < olat ? 0 : owrt - olat; + + mutex()->lock (); + VisualNode *prev = 0; + while ((!m_nodes.isEmpty())) + { + node = m_nodes.first(); + /*if ( node->offset > synctime ) + break;*/ + + if ( prev ) + delete prev; + m_nodes.removeFirst(); + + prev = node; + + } + mutex()->unlock(); + node = prev; + } + + if (m_vis) + m_vis->process ( node ); + delete node; + + if ( m_vis ) + { + if (m_draw) + drawBackGround(); + m_draw = FALSE; + m_pixmap = m_bg; + QPainter p(&m_pixmap); + m_vis->draw (&p); + } + else + m_pixmap.fill("Red"); + update(); +} + +void MainVisual::paintEvent ( QPaintEvent * ) +{ + QPainter painter ( this ); + painter.drawPixmap ( 0,0,m_pixmap ); +} + +void MainVisual::hideEvent ( QHideEvent *) +{ + m_timer->stop(); +} + +void MainVisual::showEvent ( QShowEvent *) +{ + if (m_vis) + m_timer->start(); +} + +void MainVisual::mousePressEvent (QMouseEvent *e) +{ + if (e->button() == Qt::RightButton) + m_menu->exec(e->globalPos()); + else + { + if (!m_vis) + setVisual(new mainvisual::Analyzer); + else if (m_vis->name() == "Analyzer") + setVisual(new mainvisual::Scope); + else if (m_vis->name() == "Scope") + setVisual(0); + + QString str = "Off"; + if (m_vis) + str = m_vis->name(); + foreach(QAction *act, m_visModeGroup->actions ()) + if (str == act->data().toString()) + { + act->setChecked(TRUE); + break; + } + } +} + +void MainVisual::drawBackGround() +{ + m_bg = QPixmap (75,20); + QPainter painter(&m_bg); + for (int x = 0; x < 75; x += 2) + { + painter.setPen(m_skin->getVisColor(0)); + painter.drawLine(x + 1, 0, x + 1, 20); + for (int y = 0; y < 20; y +=2) + { + painter.setPen(m_skin->getVisColor(0)); + painter.drawPoint(x,y); + painter.setPen(m_skin->getVisColor(1)); + painter.drawPoint(x,y + 1); + } + } +} + +void MainVisual::updateSettings() +{ + drawBackGround(); + m_pixmap = m_bg; + update(); + QAction *act = m_fpsGroup->checkedAction (); + if (act) + m_timer->setInterval (1000/act->data().toInt()); + else + m_timer->setInterval (40); + + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + act = m_peaksFalloffGroup->checkedAction (); + if (act) + settings.setValue("Visualization/peaks_falloff", act->data().toInt()); + else + settings.setValue("Visualization/peaks_falloff", 3); + + act = m_analyzerFalloffGroup->checkedAction (); + if (act) + settings.setValue("Visualization/analyzer_falloff", act->data().toInt()); + else + settings.setValue("Visualization/analyzer_falloff", 3); + + settings.setValue("Visualization/show_peaks", m_peaksAction->isChecked()); + + act = m_analyzerModeGroup->checkedAction(); + if (act) + settings.setValue("Visualization/analyzer_mode", act->data().toInt()); + else + settings.setValue("Visualization/analyzer_mode", 0); + + act = m_analyzerTypeGroup->checkedAction(); + if (act) + settings.setValue("Visualization/analyzer_type", act->data().toInt()); + else + settings.setValue("Visualization/analyzer_type", 1); + + act = m_visModeGroup->checkedAction (); + QString visName; + if (act) + visName = act->data().toString(); + else + visName == "Off"; + + if (visName == "Analyzer") + setVisual(new mainvisual::Analyzer); + else if (visName == "Scope") + setVisual(new mainvisual::Scope); + else + setVisual(0); + +} + +void MainVisual::createMenu() +{ + m_menu = new QMenu (this); + connect(m_menu, SIGNAL(triggered (QAction *)),SLOT(updateSettings())); + QMenu *visMode = m_menu->addMenu(tr("Visualization Mode")); + m_visModeGroup = new QActionGroup(this); + m_visModeGroup->setExclusive(TRUE); + m_visModeGroup->addAction(tr("Analyzer"))->setData("Analyzer"); + m_visModeGroup->addAction(tr("Scope"))->setData("Scope"); + m_visModeGroup->addAction(tr("Off"))->setData("Off"); + foreach(QAction *act, m_visModeGroup->actions ()) + { + act->setCheckable(TRUE); + visMode->addAction(act); + } + + QMenu *analyzerMode = m_menu->addMenu(tr("Analyzer Mode")); + m_analyzerModeGroup = new QActionGroup(this); + m_analyzerTypeGroup = new QActionGroup(this); + m_analyzerModeGroup->addAction(tr("Normal"))->setData(0); + m_analyzerModeGroup->addAction(tr("Fire"))->setData(1); + m_analyzerModeGroup->addAction(tr("Vertical Lines"))->setData(2); + m_analyzerTypeGroup->addAction(tr("Lines"))->setData(0); + m_analyzerTypeGroup->addAction(tr("Bars"))->setData(1); + foreach(QAction *act, m_analyzerModeGroup->actions ()) + { + act->setCheckable(TRUE); + analyzerMode->addAction(act); + } + analyzerMode->addSeparator (); + foreach(QAction *act, m_analyzerTypeGroup->actions ()) + { + act->setCheckable(TRUE); + analyzerMode->addAction(act); + } + analyzerMode->addSeparator (); + m_peaksAction = analyzerMode->addAction(tr("Peaks")); + m_peaksAction->setCheckable(TRUE); + + + QMenu *refreshRate = m_menu->addMenu(tr("Refresh Rate")); + m_fpsGroup = new QActionGroup(this); + m_fpsGroup->setExclusive(TRUE); + m_fpsGroup->addAction(tr("50 fps"))->setData(50); + m_fpsGroup->addAction(tr("25 fps"))->setData(25); + m_fpsGroup->addAction(tr("10 fps"))->setData(10); + m_fpsGroup->addAction(tr("5 fps"))->setData(5); + foreach(QAction *act, m_fpsGroup->actions ()) + { + act->setCheckable(TRUE); + refreshRate->addAction(act); + } + + QMenu *analyzerFalloff = m_menu->addMenu(tr("Analyzer Falloff")); + m_analyzerFalloffGroup = new QActionGroup(this); + m_analyzerFalloffGroup->setExclusive(TRUE); + m_analyzerFalloffGroup->addAction(tr("Slowest"))->setData(1); + m_analyzerFalloffGroup->addAction(tr("Slow"))->setData(2); + m_analyzerFalloffGroup->addAction(tr("Medium"))->setData(3); + m_analyzerFalloffGroup->addAction(tr("Fast"))->setData(4); + m_analyzerFalloffGroup->addAction(tr("Fastest"))->setData(5); + foreach(QAction *act, m_analyzerFalloffGroup->actions ()) + { + act->setCheckable(TRUE); + analyzerFalloff->addAction(act); + } + + QMenu *peaksFalloff = m_menu->addMenu(tr("Peaks Falloff")); + m_peaksFalloffGroup = new QActionGroup(this); + m_peaksFalloffGroup->setExclusive(TRUE); + m_peaksFalloffGroup->addAction(tr("Slowest"))->setData(1); + m_peaksFalloffGroup->addAction(tr("Slow"))->setData(2); + m_peaksFalloffGroup->addAction(tr("Medium"))->setData(3); + m_peaksFalloffGroup->addAction(tr("Fast"))->setData(4); + m_peaksFalloffGroup->addAction(tr("Fastest"))->setData(5); + foreach(QAction *act, m_peaksFalloffGroup->actions ()) + { + act->setCheckable(TRUE); + peaksFalloff->addAction(act); + } + update(); +} + + +void MainVisual::readSettings() +{ + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + + QString name = settings.value("Visualization/type","Analyzer").toString(); + m_visModeGroup->actions ()[0]->setChecked(TRUE); + foreach(QAction *act, m_visModeGroup->actions ()) + if (name == act->data().toString()) + act->setChecked(TRUE); + + m_peaksAction->setChecked( + settings.value("Visualization/show_peaks", TRUE).toBool()); + + int fps = settings.value("Visualization/rate", 25).toInt(); + m_fpsGroup->actions ()[1]->setChecked(TRUE); + foreach(QAction *act, m_fpsGroup->actions ()) + if (fps == act->data().toInt()) + act->setChecked(TRUE); + + int mode = settings.value("Visualization/analyzer_mode", 0).toInt(); + m_analyzerModeGroup->actions ()[0]->setChecked(TRUE); + foreach(QAction *act, m_analyzerModeGroup->actions ()) + if (mode == act->data().toInt()) + act->setChecked(TRUE); + + int type = settings.value("Visualization/analyzer_type", 1).toInt(); + m_analyzerTypeGroup->actions ()[1]->setChecked(TRUE); + foreach(QAction *act, m_analyzerTypeGroup->actions ()) + if (type == act->data().toInt()) + act->setChecked(TRUE); + + int speed = settings.value("Visualization/peaks_falloff", 3).toInt(); + m_peaksFalloffGroup->actions ()[2]->setChecked(TRUE); + foreach(QAction *act, m_peaksFalloffGroup->actions ()) + if (speed == act->data().toInt()) + act->setChecked(TRUE); + + speed = settings.value("Visualization/analyzer_falloff", 3).toInt(); + m_analyzerFalloffGroup->actions ()[2]->setChecked(TRUE); + foreach(QAction *act, m_analyzerFalloffGroup->actions ()) + if (speed == act->data().toInt()) + act->setChecked(TRUE); + + updateSettings(); +} + +using namespace mainvisual; + +Analyzer::Analyzer() + : m_analyzerBarWidth ( 4 ), m_fps ( 20 ) +{ + m_size = QSize(75,20); + clear(); + m_skin = Skin::getPointer(); + + double peaks_speed[] = { 0.05, 0.1, 0.2, 0.4, 0.8 }; + double analyzer_speed[] = { 1.2, 1.8, 2.2, 2.8, 2.4 }; + + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + m_peaks_falloff = + peaks_speed[settings.value("Visualization/peaks_falloff", 3).toInt()-1]; + m_analyzer_falloff = + analyzer_speed[settings.value("Visualization/analyzer_falloff", 3).toInt()-1]; + m_show_peaks = settings.value("Visualization/show_peaks", TRUE).toBool(); + + m_lines = settings.value("Visualization/analyzer_type", 1).toInt() == 0; + m_mode = settings.value("Visualization/analyzer_mode", 0).toInt(); +} + +Analyzer::~Analyzer() +{} + +void Analyzer::clear() +{ + for ( int i = 0; i< 75; ++i ) + { + m_intern_vis_data[i] = 0; + m_peaks[i] = 0; + } +} + +bool Analyzer::process ( VisualNode *node ) +{ + static fft_state *state = 0; + if ( !state ) + state = fft_init(); + short dest[256]; + + const int xscale_long[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 61, 66, 71, 76, 81, 87, 93, 100, 107, + 114, 122, 131, 140, 150, 161, 172, 184, 255 + }; + + const int xscale_short[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 15, 20, 27, + 36, 47, 62, 82, 107, 141, 184, 255 + }; + + if ( node ) + { + //i = node->length; + calc_freq ( dest, node->left ); + } + else + return FALSE; + const double y_scale = 3.60673760222; /* 20.0 / log(256) */ + int max = m_lines ? 75 : 19, y, j; + + for ( int i = 0; i < max; i++ ) + { + if (m_lines) + for ( j = xscale_long[i], y = 0; j < xscale_long[i + 1]; j++ ) + { + if ( dest[j] > y ) + y = dest[j]; + } + else + for ( j = xscale_short[i], y = 0; j < xscale_short[i + 1]; j++ ) + { + if ( dest[j] > y ) + y = dest[j]; + } + y >>= 7; + int magnitude = 0; + if ( y != 0 ) + { + magnitude = int(log (y) * y_scale); + if ( magnitude > 15 ) + magnitude = 15; + if ( magnitude < 0 ) + magnitude = 0; + } + + m_intern_vis_data[i] -= m_analyzer_falloff; + m_intern_vis_data[i] = magnitude > m_intern_vis_data[i] + ? magnitude : m_intern_vis_data[i]; + if (m_show_peaks) + { + m_peaks[i] -= m_peaks_falloff; + m_peaks[i] = magnitude > m_peaks[i] + ? magnitude : m_peaks[i]; + } + } + return TRUE; +} + +void Analyzer::draw ( QPainter *p) +{ + if (m_lines) + for ( int j = 0; j < 75; ++j ) + { + for ( int i = 0; i <= m_intern_vis_data[j]; ++i ) + { + if (m_mode == 0) + p->setPen (m_skin->getVisColor (18-i)); + else if (m_mode == 1) + p->setPen (m_skin->getVisColor (3+(int(m_intern_vis_data[j])-i))); + else + p->setPen (m_skin->getVisColor (18-int(m_intern_vis_data[j]))); + p->drawPoint (j, m_size.height()-i); + } + p->setPen (m_skin->getVisColor (23)); + if (m_show_peaks) + p->drawPoint (j, m_size.height()-int(m_peaks[j])); + } + else + for (int j = 0; j < 19; ++j) + { + for (int i = 0; i <= m_intern_vis_data[j]; ++i) + { + if (m_mode == 0) + p->setPen (m_skin->getVisColor (18-i)); + else if (m_mode == 1) + p->setPen (m_skin->getVisColor (3+(int(m_intern_vis_data[j])-i))); + else + p->setPen (m_skin->getVisColor (18-int(m_intern_vis_data[j]))); + p->drawLine (j*4,m_size.height()-i, (j+1)*4-2,m_size.height()-i); + } + p->setPen (m_skin->getVisColor (23)); + if (m_show_peaks) + p->drawLine (j*4,m_size.height()-int(m_peaks[j]), + (j+1) *4-2,m_size.height()-int(m_peaks[j])); + } +} + +Scope::Scope() +{ + clear(); + m_skin = Skin::getPointer(); +} + +void Scope::clear() +{ + for (int i = 0; i< 75; ++i) + m_intern_vis_data[i] = 7; +} + +Scope::~Scope() +{} + +bool Scope::process(VisualNode *node) +{ + if (!node) + return FALSE; + + int step = (node->length << 8)/74; + int pos = 0; + + for (int i = 0; i < 75; ++i) + { + pos += step; + m_intern_vis_data[i] = (node->left[pos >> 8] >> 12); + + if (m_intern_vis_data[i] > 5) + m_intern_vis_data[i] = 5; + else if (m_intern_vis_data[i] < -5) + m_intern_vis_data[i] = -5; + } + return TRUE; +} + +void Scope::draw(QPainter *p) +{ + for ( int i = 0; i<73; ++i ) + { + int h1 = 10 - m_intern_vis_data[i]; + int h2 = 10 - m_intern_vis_data[i+1]; + if (h1 > h2) + qSwap(h1, h2); + p->setPen (m_skin->getVisColor(19 + (10 - h2)/2 )); + p->drawLine(i, h1, i, h2); + } + for ( int i = 0; i< 75; ++i ) + m_intern_vis_data[i] = 0; +} diff --git a/src/ui/mainvisual.h b/src/ui/mainvisual.h new file mode 100644 index 000000000..5c5b76256 --- /dev/null +++ b/src/ui/mainvisual.h @@ -0,0 +1,172 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef MAINVISUAL_H +#define MAINVISUAL_H + +#include <QWidget> +#include <QResizeEvent> +#include <visual.h> +#include <constants.h> + +#include "logscale.h" + +class QSettings; +class QTimer; +class QMenu; +class QActionGroup; + +class Buffer; + + +class VisualNode +{ +public: + VisualNode(short *l, short *r, unsigned long n, unsigned long o) + : left(l), right(r), length(n), offset(o) + { + // left and right are allocated and then passed to this class + // the code that allocated left and right should give up all ownership + } + + ~VisualNode() + { + delete [] left; + delete [] right; + } + + short *left, *right; + long length, offset; +}; + +class VisualBase +{ +public: + virtual ~VisualBase() + {}; + virtual void clear() = 0; + virtual bool process(VisualNode *node) = 0; + virtual void draw(QPainter *) = 0; + virtual const QString name() = 0; +}; + +class Skin; + +class MainVisual : public Visual +{ + Q_OBJECT + +public: + MainVisual( QWidget *parent = 0); + virtual ~MainVisual(); + + static MainVisual *getPointer(); + + void setVisual( VisualBase *newvis ); + + void add(Buffer *, unsigned long, int, int); + void clear(); + void paintEvent(QPaintEvent *); + +protected: + virtual void hideEvent (QHideEvent *); + virtual void showEvent (QShowEvent *); + virtual void mousePressEvent (QMouseEvent *); + +public slots: + void timeout(); + +private slots: + void updateSettings(); + +private: + void drawBackGround(); + void createMenu(); + void readSettings(); + static MainVisual *pointer; + VisualBase *m_vis; + QPixmap m_pixmap; + QPixmap m_bg; + QList <VisualNode*> m_nodes; + QTimer *m_timer; + bool m_playing; + bool m_draw; + Skin *m_skin; + //menu and actions + QMenu *m_menu; + //action groups + QActionGroup *m_visModeGroup; + QActionGroup *m_fpsGroup; + QActionGroup *m_peaksFalloffGroup; + QActionGroup *m_analyzerFalloffGroup; + QActionGroup *m_analyzerModeGroup; + QActionGroup *m_analyzerTypeGroup; + QAction *m_peaksAction; +}; + +namespace mainvisual +{ +class Analyzer : public VisualBase +{ +public: + Analyzer(); + virtual ~Analyzer(); + + void clear(); + bool process(VisualNode *node); + void draw(QPainter *p); + const QString name() + { + return "Analyzer"; + }; + +private: + QSize m_size; + int m_analyzerBarWidth, m_fps; + double m_intern_vis_data[75]; + double m_peaks[75]; + double m_peaks_falloff; + double m_analyzer_falloff; + bool m_show_peaks; + bool m_lines; + int m_mode; + Skin *m_skin; +}; + +class Scope : public VisualBase +{ +public: + Scope(); + virtual ~Scope(); + + void clear(); + bool process(VisualNode *node); + void draw(QPainter *p); + const QString name() + { + return "Scope"; + }; + +private: + int m_intern_vis_data[75]; + Skin *m_skin; +}; +} + +#endif diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp new file mode 100644 index 000000000..d81dbce3b --- /dev/null +++ b/src/ui/mainwindow.cpp @@ -0,0 +1,848 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QtGui> +#include <QFileDialog> +#include <QDir> +#include <QAction> +#include <QMenu> + +#include <math.h> + +#include <soundcore.h> +#include <qmmpui/generalhandler.h> +#include <qmmpui/general.h> + +#include "textscroller.h" +#include "mainwindow.h" +#include "constants.h" +#include "fileloader.h" +#include "skin.h" +#include "playlist.h" +#include "playlistmodel.h" +#include "configdialog.h" +#include "dock.h" +#include "eqwidget.h" +#include "mainvisual.h" +#include "playlistformat.h" +#include "jumptotrackdialog.h" +#include "aboutdialog.h" +#include <addurldialog.h> +#include "filedialog.h" +#include "listwidget.h" +#include "visualmenu.h" +#include "commandlineoption.h" + +#define KEY_OFFSET 10 + +MainWindow::MainWindow(const QStringList& args,CommandLineOptionManager* option_manager, QWidget *parent) + : QMainWindow(parent) +{ + m_vis = 0; + seeking = FALSE; + m_update = FALSE; + m_paused = FALSE; + m_elapsed = 0; + m_option_manager = option_manager; + + setWindowIcon( QIcon(":/qmmp.xpm") ); + + m_skin = new Skin(this); + Dock *dock = new Dock(this); + dock->setMainWidget(this); + + setWindowFlags(Qt::FramelessWindowHint); + setFixedSize (275,116); + + display = new MainDisplay(this); + setCentralWidget(display); + display->show(); + display->setFocus (); + + m_playlistName = tr("Default"); + + m_playlist = new PlayList(this); + + connect (m_playlist,SIGNAL(next()),SLOT(next())); + connect (m_playlist,SIGNAL(prev()),SLOT(previous())); + connect (m_playlist,SIGNAL(play()),SLOT(play())); + connect (m_playlist,SIGNAL(pause()),SLOT(pause())); + connect (m_playlist,SIGNAL(stop()),SLOT(stop())); + connect (m_playlist,SIGNAL(eject()),SLOT(addFile())); + + connect (m_playlist,SIGNAL(newPlaylist()),SLOT(newPlaylist())); + connect (m_playlist,SIGNAL(loadPlaylist()),SLOT(loadPlaylist())); + connect (m_playlist,SIGNAL(savePlaylist()),SLOT(savePlaylist())); + + m_playListModel = new PlayListModel(this); + + connect(display,SIGNAL(shuffleToggled(bool)),m_playListModel,SLOT(prepareForShufflePlaying(bool))); + connect(display,SIGNAL(repeatableToggled(bool)),m_playListModel,SLOT(prepareForRepeatablePlaying(bool))); + + dock->addWidget(m_playlist); + + m_equalizer = new EqWidget(this); + dock->addWidget(m_equalizer); + connect(m_equalizer, SIGNAL(valueChanged()), SLOT(updateEQ())); + + m_playlist->setModel(m_playListModel); + + m_jumpDialog = new JumpToTrackDialog(this); + m_jumpDialog->setModel(m_playListModel); + connect(m_jumpDialog,SIGNAL(playRequest()),this,SLOT(play())); + m_jumpDialog->hide(); + + createActions(); + + m_core = new SoundCore(this); + m_titlebar = new TitleBar(this); + m_titlebar->move(0,0); + m_titlebar->show(); + m_titlebar->setActive(TRUE); + + readSettings(); + dock->updateDock(); + + display->setEQ(m_equalizer); + display->setPL(m_playlist); + + m_vis = MainVisual::getPointer(); + + m_core->addVisualization(m_vis); + m_core->showVisualization(this); + + connect(m_core, SIGNAL(outputStateChanged(const OutputState&)), + SLOT(showOutputState(const OutputState&))); + connect(m_core, SIGNAL(decoderStateChanged(const DecoderState&)), + SLOT(showDecoderState(const DecoderState&))); + connect(m_core, SIGNAL(titleChanged(const QString&)), + SLOT(changeTitle(const QString&))); + + connect ( m_skin, SIGNAL ( skinChanged() ), this, SLOT ( updateSkin() ) ); + updateEQ(); + updateSkin(); + + FileDialog::registerBuiltinFactories(); + FileDialog::registerExternalFactories(); + + m_generalHandler = new GeneralHandler(this); + connect(m_generalHandler, SIGNAL(playCalled()), SLOT(play())); + connect(m_generalHandler, SIGNAL(nextCalled()), SLOT(next())); + connect(m_generalHandler, SIGNAL(previousCalled()), SLOT(previous())); + connect(m_generalHandler, SIGNAL(stopCalled()), SLOT(stop())); + connect(m_generalHandler, SIGNAL(pauseCalled()), SLOT(pause())); + connect(m_generalHandler, SIGNAL(toggleVisibilityCalled()), SLOT(toggleVisibility())); + connect(m_generalHandler, SIGNAL(exitCalled()), SLOT(close())); + + m_playListModel->readSettings(); + char buf[PATH_MAX + 1]; + QString cwd = QString::fromLocal8Bit(getcwd(buf,PATH_MAX)); + processCommandArgs(args,cwd); +} + + +MainWindow::~MainWindow() +{ + stop(); +} + +void MainWindow::play() +{ + m_playListModel->doCurrentVisibleRequest(); + + if (m_core->isPaused()) + { + pause(); + return; + } + stop(); + if (m_playListModel->count() == 0) + return; + + m_equalizer->loadPreset(m_playListModel->currentItem()->fileName()); + m_playListModel->currentItem()->updateTags(); + m_playlist->listWidget()->updateList(); + QString s = m_playListModel->currentItem()->path(); + if (s.isEmpty()) + return; + if (m_core->play(s)) + { + display->setTime(0); + display->setMaxTime(m_core->length()); + } + else + { + //find out the reason why the playback failed + switch ((int) m_core->error()) + { + case SoundCore::OutputError: + { + stop(); + return; //unrecovable error in output, so abort playing + } + case SoundCore::DecoderError: + { + //error in decoder, so we should try to play next song + qApp->processEvents(); + if (!m_playListModel->isEmptyQueue()) + { + m_playListModel->setCurrentToQueued(); + } + else if (!m_playListModel->next()) + { + stop(); + display->hideTimeDisplay(); + return; + } + m_playlist->update(); + play(); + break; + } + } + } +} + +void MainWindow::replay() +{ + stop(); + play(); +} + +void MainWindow::seek(int pos) +{ + if (!seeking) + m_core->seek(pos); +} + + +void MainWindow::forward() +{ + seek(m_elapsed + KEY_OFFSET); +} + +void MainWindow::backward() +{ + seek(qMax(0,m_elapsed - KEY_OFFSET)); +} + +void MainWindow::setVolume(int volume, int balance) +{ + m_core->setVolume(volume-qMax(balance,0)*volume/100, + volume+qMin(balance,0)*volume/100); +} + +void MainWindow::pause(void) +{ + m_core->pause(); +} + +void MainWindow::stop() +{ + display->setTime(0); + m_core->stop(); +} +void MainWindow::next() +{ + if (!m_playListModel->isEmptyQueue()) + { + m_playListModel->setCurrentToQueued(); + } + else if (!m_playListModel->next()) + { + stop(); + display->hideTimeDisplay(); + return; + } + m_playlist->update(); + if (m_core->isInitialized()) + { + stop(); + m_elapsed = 0; + play(); + } + else + display->hideTimeDisplay(); +} +void MainWindow::previous() +{ + if (!m_playListModel->previous()) + { + display->hideTimeDisplay(); + return; + } + + m_playlist->update(); + if (m_core->isInitialized()) + { + stop(); + play(); + } + else + display->hideTimeDisplay(); +} + +void MainWindow::updateEQ() +{ + int b[10]; + for (int i=0; i<10; ++i) + b[i] = m_equalizer->gain(i); + m_core->setEQ(b, m_equalizer->preamp()); + m_core->setEQEnabled(m_equalizer->isEQEnabled()); +} + +void MainWindow::showOutputState(const OutputState &st) + +{ + if (seeking) + return; + + display->setInfo(st); + m_playlist->setInfo(st, m_core->length(), m_playListModel->totalLength()); + m_titlebar->setInfo(st); + m_equalizer->setInfo(st); + switch ((int) st.type()) + { + case OutputState::Playing: + { + m_generalHandler->setState(General::Playing); + if (m_playListModel->currentItem()) + { + SongInfo info; + FileTag *tag = m_playListModel->currentItem()->tag(); + if (tag && !tag->isEmpty()) + { + info.setValue(SongInfo::TITLE, tag->title()); + info.setValue(SongInfo::ARTIST, tag->artist()); + info.setValue(SongInfo::ALBUM, tag->album()); + info.setValue(SongInfo::COMMENT, tag->comment()); + info.setValue(SongInfo::GENRE, tag->genre()); + info.setValue(SongInfo::YEAR, tag->year()); + info.setValue(SongInfo::TRACK, tag->track()); + info.setValue(SongInfo::LENGTH, tag->length()); + } + else + info.setValue(SongInfo::TITLE, m_playlist->currentItem()->title()); + info.setValue(SongInfo::STREAM, + m_playlist->currentItem()->path().startsWith("http://")); + m_generalHandler->setSongInfo(info); + } + break; + } + case OutputState::Paused: + { + m_generalHandler->setState(General::Paused); + break; + } + case OutputState::Stopped: + { + m_generalHandler->setState(General::Stopped); + break; + } + case OutputState::Info: + { + m_elapsed = st.elapsedSeconds(); + } + } + +} +void MainWindow::showDecoderState(const DecoderState &st) +{ + switch ((int) st.type()) + { + case DecoderState::Finished: + { + next(); + break; + } + case DecoderState::Info: + { + qDebug("file info:"); + qDebug("ARTIST = %s", qPrintable(st.tag()->artist())); + qDebug("TITLE = %s", qPrintable(st.tag()->title())); + qDebug("ALBUM = %s", qPrintable(st.tag()->album())); + qDebug("COMMENT = %s", qPrintable(st.tag()->comment())); + qDebug("GENRE = %s", qPrintable(st.tag()->genre())); + qDebug("YEAR = %d", st.tag()->year()); + qDebug("TRACK = %d", st.tag()->track()); + qDebug("LENGTH = %d", st.tag()->length()); + if (m_playlist->currentItem()) + { + if (!st.tag()->isEmpty()) + { + SongInfo info; + info.setValue(SongInfo::TITLE, st.tag()->title()); + info.setValue(SongInfo::ARTIST, st.tag()->artist()); + info.setValue(SongInfo::ALBUM, st.tag()->album()); + info.setValue(SongInfo::COMMENT, st.tag()->comment()); + info.setValue(SongInfo::GENRE, st.tag()->genre()); + info.setValue(SongInfo::YEAR, st.tag()->year()); + info.setValue(SongInfo::TRACK, st.tag()->track()); + info.setValue(SongInfo::LENGTH, st.tag()->length()); + info.setValue(SongInfo::STREAM, + m_playlist->currentItem()->path().startsWith("http://")); + m_generalHandler->setSongInfo(info); + } + m_playlist->currentItem()->updateTags(st.tag()); + m_playlist->listWidget()->updateList(); + } + break; + } + } +} + +void MainWindow::changeTitle(const QString &title) +{ + if (m_playlist->currentItem()) + m_playlist->currentItem()->changeTitle(title); + m_playlist->listWidget()->updateList(); + SongInfo info; + info.setValue(SongInfo::TITLE, title); + info.setValue(SongInfo::STREAM, TRUE); + m_generalHandler->setSongInfo(info); +} + +void MainWindow::closeEvent ( QCloseEvent *) +{ + writeSettings(); + m_playlist->close(); + m_equalizer->close(); + QApplication::quit (); +} + +void MainWindow::addDir() +{ + /* + QString s = QFileDialog::getExistingDirectory( + this, + tr("Choose a directory"), + m_lastDir, + QFileDialog::DontResolveSymlinks | QFileDialog::ShowDirsOnly); + + if (s.isEmpty()) + return; + m_playListModel->addDirectory(s); + m_lastDir = s+"../"; + */ + if (FileDialog::isModal()) + { + qWarning("void MainWindow::addDir()"); + QString s = FileDialog::getExistingDirectory(this,tr("Choose a directory"),m_lastDir); + + if (s.isEmpty()) + return; + m_playListModel->addDirectory(s); + m_lastDir = s+"../"; + } + else + FileDialog::popup(m_playListModel,m_lastDir,FileDialog::AddDirs,Decoder::nameFilters()); +} + +void MainWindow::addFile() +{ + /* + QStringList files = QFileDialog::getOpenFileNames( + this, + tr("Select one or more files to open"), + m_lastDir, + Decoder::filter()); + if (files.isEmpty ()) + return; + + // foreach(QString s, files) + // m_playListModel->load(new MediaFile(s)); + + m_playListModel->addFiles(files); + m_lastDir = files.at(0); + */ + + + if (FileDialog::isModal()) + { + QStringList files = FileDialog::getOpenFileNames( + this, + tr("Select one or more files to open"), + m_lastDir, + Decoder::filter()); + if (files.isEmpty ()) + return; + /* + foreach(QString s, files) + m_playListModel->load(new MediaFile(s)); + */ + m_playListModel->addFiles(files); + m_lastDir = files.at(0); + } + else + FileDialog::popup(m_playListModel,m_lastDir,FileDialog::AddFiles,Decoder::nameFilters()); + +} + +void MainWindow::clear() +{ + m_playListModel->clear(); +} + +void MainWindow::startSeek() +{ + seeking = TRUE; +} + +void MainWindow::endSeek() +{ + seeking = FALSE; +} + +void MainWindow::changeEvent (QEvent * event) +{ + if (event->type() == QEvent::ActivationChange) + { + m_titlebar->setActive(isActiveWindow()); + } +} + +void MainWindow::readSettings() +{ + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + if (!m_update) + { + settings.beginGroup("MainWindow"); + //geometry + move(settings.value("pos", QPoint(100, 100)).toPoint()); + //last directory + m_lastDir = settings.value("last_dir","/").toString(); + settings.endGroup(); + show(); + //visibility + m_playlist->setVisible(settings.value("Playlist/visible",TRUE).toBool()); + m_equalizer->setVisible(settings.value("Equalizer/visible",TRUE).toBool()); + bool val = settings.value("Playlist/repeatable",FALSE).toBool(); + + // Repeat/Shuffle + m_playListModel->prepareForRepeatablePlaying(val); + display->setIsRepeatable(val); + val = settings.value("Playlist/shuffle",FALSE).toBool(); + display->setIsShuffle(val); + m_playListModel->prepareForShufflePlaying(val); + + // Playlist name + m_playlistName = settings.value("Playlist/playlist_name","Default").toString(); + + m_update = TRUE; + } +} + +void MainWindow::writeSettings() +{ + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + settings.beginGroup("MainWindow"); + //geometry + settings.setValue("pos", this->pos()); + //last directory + settings.setValue("last_dir",m_lastDir); + settings.endGroup(); + + // Repeat/Shuffle + settings.beginGroup("Playlist"); + settings.setValue("repeatable",display->isRepeatable()); + settings.setValue("shuffle",display->isShuffle()); + + // Playlist name + settings.setValue("playlist_name",m_playlistName); + settings.endGroup(); +} + +void MainWindow::showSettings() +{ + m_confDialog = new ConfigDialog(this); + if (m_confDialog->exec() == QDialog::Accepted) + { + readSettings(); + m_playlist->readSettings(); + TextScroller::getPointer()->readSettings(); + m_core->updateConfig(); + m_generalHandler->updateConfig(); + m_visMenu->updateActions(); + } + delete m_confDialog; +} + +void MainWindow::toggleVisibility() +{ + if (isHidden()) + { + show(); + m_playlist->setVisible(display->isPlaylistVisible()); + m_equalizer->setVisible(display->isEqualizerVisible()); + if (isMinimized()) + { + if (isMaximized()) + showMaximized(); + else + showNormal(); + } + raise(); + activateWindow(); + } + else + { + hide(); + if (m_playlist->isVisible()) + m_playlist->hide(); + if (m_equalizer->isVisible()) + m_equalizer->hide(); + } +} + +void MainWindow::createActions() +{ + m_mainMenu = new QMenu(this); + m_mainMenu->addAction(tr("&Play"),this, SLOT(play()), tr("X")); + m_mainMenu->addAction(tr("&Pause"),this, SLOT(pause()), tr("C")); + m_mainMenu->addAction(tr("&Stop"),this, SLOT(stop()), tr("V")); + m_mainMenu->addAction(tr("&Previous"),this, SLOT(previous()), tr("Z")); + m_mainMenu->addAction(tr("&Next"),this, SLOT(next()), tr("B")); + m_mainMenu->addAction(tr("P&lay/Pause"),this, SLOT(playPause()), tr("Space")); + m_mainMenu->addAction(tr("&Queue"),m_playListModel, SLOT(addToQueue()), tr("Q")); + m_mainMenu->addSeparator(); + m_mainMenu->addAction(tr("&Jump To File"),this, SLOT(jumpToFile()), tr("J")); + m_mainMenu->addSeparator(); + m_visMenu = new VisualMenu(this); + m_mainMenu->addMenu(m_visMenu); + + m_mainMenu->addSeparator(); + m_mainMenu->addAction(tr("&Settings"),this, SLOT(showSettings()), tr("Ctrl+P")); + m_mainMenu->addSeparator(); + m_mainMenu->addAction(tr("&About"),this, SLOT(about())); + Dock::getPointer()->addActions(m_mainMenu->actions()); + m_mainMenu->addSeparator(); + m_mainMenu->addAction(tr("&Exit"),this, SLOT(close ()), tr("Ctrl+Q")); + + QAction* forward = new QAction(this); + forward->setShortcut(QKeySequence(Qt::Key_Right)); + connect(forward,SIGNAL(triggered(bool)),this,SLOT(forward())); + QAction* backward = new QAction(this); + backward->setShortcut(QKeySequence(Qt::Key_Left)); + connect(backward,SIGNAL(triggered(bool)),this,SLOT(backward())); + + Dock::getPointer()->addActions( QList<QAction*>() << forward << backward ); + Dock::getPointer()->addActions(m_mainMenu->actions()); +} + + +void MainWindow::about() +{ + AboutDialog dlg(this); + dlg.exec(); +} + +QMenu* MainWindow::menu() +{ + return m_mainMenu; +} + +void MainWindow::updateSkin() +{ + clearMask(); + m_equalizer->clearMask(); + /*qt bug workarround */ + setMask(QRegion(0,0,275,116)); + m_equalizer->setMask(QRegion(0,0,275,116)); + update(); + m_equalizer->update(); + + QRegion region = m_skin->getMWRegion(); + if (!region.isEmpty()) + setMask(region); + + region = m_skin->getPLRegion(); + if (!region.isEmpty()) + m_equalizer->setMask(region); +} + +void MainWindow::newPlaylist() +{ + m_playListModel->clear(); + m_playlistName = tr("Default"); +} + +void MainWindow::loadPlaylist() +{ + QStringList l; + QList<PlaylistFormat*> p_list = m_playListModel->registeredPlaylistFormats(); + if (!p_list.isEmpty()) + { + foreach(PlaylistFormat* fmt,p_list) + l << fmt->getExtensions(); + + QString mask = tr("Playlist Files")+" (" + l.join(" *.").prepend("*.") + ")"; + if (FileDialog::isModal()) + { + //qWarning("Modal"); + QString f_name = FileDialog::getOpenFileName(this,tr("Open Playlist"),m_lastDir,mask); + if (!f_name.isEmpty()) + { + m_playListModel->loadPlaylist(f_name); + m_playlistName = QFileInfo(f_name).baseName(); + } + m_lastDir = QFileInfo(f_name).absoluteDir().path(); + } + else //FileDialog::popup(m_playListModel,m_lastDir,FileDialog::AddFiles,Decoder::nameFilters()); + // TODO: implement playlist loading with nonmodal dialogs + // For now we'll use default dialog + { + //qWarning("Modal"); + QString f_name = FileDialog::getOpenFileName(this,tr("Open Playlist"),m_lastDir,mask,0,true); + if (!f_name.isEmpty()) + { + m_playListModel->loadPlaylist(f_name); + m_playlistName = QFileInfo(f_name).baseName(); + } + m_lastDir = QFileInfo(f_name).absoluteDir().path(); + } + } + else + { + //qWarning("Non Modal"); + qWarning("Error: There is no registered playlist parsers"); + } +} + +void MainWindow::savePlaylist() +{ + QStringList l; + QList<PlaylistFormat*> p_list = m_playListModel->registeredPlaylistFormats(); + if (!p_list.isEmpty()) + { + foreach(PlaylistFormat* fmt,p_list) + l << fmt->getExtensions(); + + QString mask = tr("Playlist Files")+" (" + l.join(" *.").prepend("*.") + ")"; + if (FileDialog::isModal()) + { + QString f_name = FileDialog::getSaveFileName(this, tr("Save Playlist"),m_lastDir + "/" + + m_playlistName + "." + l[0],mask); + + if (!f_name.isEmpty()) + { + m_playListModel->savePlaylist(f_name); + m_playlistName = QFileInfo(f_name).baseName(); + } + m_lastDir = QFileInfo(f_name).absoluteDir().path(); + } + else // TODO: implement saving playlists with nonmodal dialogs + // For now we'll use default dialog + { + QString f_name = FileDialog::getSaveFileName(this, tr("Save Playlist"),m_lastDir + "/" + + m_playlistName + "." + l[0],mask,0,true); + + if (!f_name.isEmpty()) + { + m_playListModel->savePlaylist(f_name); + m_playlistName = QFileInfo(f_name).baseName(); + } + m_lastDir = QFileInfo(f_name).absoluteDir().path(); + } + } + else + qWarning("Error: There is no registered playlist parsers"); +} + +void MainWindow::setFileList(const QStringList & l) +{ + if (!m_playListModel->setFileList(l)) + addFile(); +} + +void MainWindow::playPause() +{ + if (m_core->isInitialized()) + pause(); + else + play(); +} + +bool MainWindow::processCommandArgs(const QStringList &slist,const QString& cwd) +{ + if (slist.count() > 0) + { + QString str = slist[0]; + if (str.startsWith("--")) // is it a command? + { + if (m_option_manager->hasOption(str)) + { + m_option_manager->executeCommand(str,this); + } + else + return false; + } + else// maybe it is a list of files or dirs + { + QStringList full_path_list; + foreach(QString s,slist) + { + qWarning(qPrintable(cwd + "/" + s)); + if (s.left(1) == "/") //is it absolute path? + full_path_list << s; + else + full_path_list << cwd + "/" + s; + } + setFileList(full_path_list); + } + } + return true; +} + +void MainWindow::jumpToFile() +{ + if (m_jumpDialog->isHidden()) + { + m_jumpDialog->show(); + m_jumpDialog->refresh(); + } +} + +void MainWindow::handleCloseRequest() +{ + //if (m_hide_on_titlebar_close && m_tray->isVisible()) + /*toggleVisibility(); + else*/ + QApplication::closeAllWindows(); +} + +void MainWindow::addUrl( ) +{ + AddUrlDialog::popup(this,m_playListModel); +} + +SoundCore * MainWindow::soundCore() const +{ + return m_core; +} + +MainDisplay * MainWindow::mainDisplay() const +{ + return display; +} + +void MainWindow::keyPressEvent(QKeyEvent *ke) +{ + QKeyEvent event = QKeyEvent(ke->type(), ke->key(), + ke->modifiers(), ke->text(),ke->isAutoRepeat(), ke->count()); + QApplication::sendEvent(m_playlist,&event); +} diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h new file mode 100644 index 000000000..25b2b3b75 --- /dev/null +++ b/src/ui/mainwindow.h @@ -0,0 +1,141 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QMainWindow> + + +#include "output.h" +#include "decoder.h" +#include "display.h" +#include "mediafile.h" +#include "decoderfactory.h" +#include "titlebar.h" + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class PlayList; +class PlayListModel; +class ConfigDialog; +class EqWidget; +class MainVisual; +class Skin; +class SoundCore; +class JumpToTrackDialog; +class VisualMenu; +class GeneralHandler; + +class QMenu; +class QKeyEvent; +class CommandLineOptionManager; + + +class MainWindow : public QMainWindow +{ + Q_OBJECT +public: + MainWindow(const QStringList& args,CommandLineOptionManager*, QWidget *parent); + + ~MainWindow(); + + PlayList *getPLPointer(){return m_playlist;} + + void seek(int); + QMenu* menu(); + void setVolume(int volume, int balance); + SoundCore* soundCore()const; + MainDisplay* mainDisplay()const; + bool processCommandArgs(const QStringList &list,const QString& cwd); +public slots: + void previous(); + void play(); + void pause(); + void playPause(); + void stop(); + void next(); + void replay(); + void jumpToFile(); + void toggleVisibility(); + + void addDir(); + void addFile(); + void addUrl(); + + void newPlaylist(); + void loadPlaylist(); + void savePlaylist(); + + void setFileList(const QStringList&); + +protected: + virtual void closeEvent ( QCloseEvent *); + virtual void changeEvent ( QEvent * event ); + virtual void keyPressEvent ( QKeyEvent* ); + +private slots: + void showOutputState(const OutputState&); + void showDecoderState(const DecoderState&); + void changeTitle(const QString&); + void clear(); + void startSeek(); + void endSeek(); + void showSettings(); + void updateEQ(); + void updateSkin(); + void forward(); + void backward(); + //void trayActivated(QSystemTrayIcon::ActivationReason); + void about(); + void handleCloseRequest(); + +private: + void readSettings(); + void writeSettings(); + void createActions(); + bool seeking; + SoundCore *m_core; + QMenu *m_mainMenu; + MainDisplay *display; + PlayList *m_playlist; + PlayListModel *m_playListModel; + TitleBar *m_titlebar; + ConfigDialog *m_confDialog; + int m_preamp; + EqWidget *m_equalizer; + MainVisual *m_vis; + QString m_lastDir; + bool m_update; + bool m_showMessage; + int m_messageDelay; + bool m_paused; + bool m_showToolTip; + Skin *m_skin; + QString m_playlistName; + JumpToTrackDialog* m_jumpDialog; + bool m_hide_on_titlebar_close; + int m_elapsed; + VisualMenu *m_visMenu; + CommandLineOptionManager* m_option_manager; + GeneralHandler *m_generalHandler; +}; + +#endif diff --git a/src/ui/mediafile.cpp b/src/ui/mediafile.cpp new file mode 100644 index 000000000..6ffb5514f --- /dev/null +++ b/src/ui/mediafile.cpp @@ -0,0 +1,169 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QSettings> +#include <QDir> + +#include <decoder.h> + +#include "mediafile.h" + +MediaFile::MediaFile(const QString& path) : m_flag(FREE) +{ + m_selected = FALSE; + m_current = FALSE; + m_path = path; + m_tag = 0; + + QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat ); + m_use_meta = settings.value ("PlayList/load_metadata", TRUE).toBool(); + //format + m_format = settings.value("PlayList/title_format", "%p - %t").toString(); + if (m_use_meta && !path.startsWith("http://")) + { + m_tag = Decoder::createTag(path); + readMetadata(); + } + else + m_title = m_path.startsWith("http://") ? m_path: m_path.section('/',-1); +} + + +MediaFile::~MediaFile() +{ + if (m_tag) + delete m_tag; +} + +const QString MediaFile::path()const +{ + return m_path; +} +const QString MediaFile::fileName() const +{ + return m_path.section('/',-1); +} + +const QString MediaFile::title() const +{ + return m_title; +} + +int MediaFile::length() const +{ + if (m_tag) + return m_tag->length(); + else + return 0; +} + +void MediaFile::setSelected(bool yes) +{ + m_selected = yes; +} + +bool MediaFile::isSelected() const +{ + return m_selected; +} + +uint MediaFile::year() const +{ + return m_year; +} + +bool MediaFile::isCurrent() +{ + return m_current; +} + +void MediaFile::setCurrent(bool cur) +{ + m_current = cur; +} + +void MediaFile::updateTags(const FileTag *tag) +{ + if (m_tag) + { + delete m_tag; + m_tag = 0; + } + if (!tag->isEmpty()) + m_tag = new FileTag(*tag); + readMetadata(); +} + +void MediaFile::updateTags() +{ + if (m_path.startsWith("http://")) + return; + if (m_tag) + { + delete m_tag; + m_tag = 0; + } + m_tag = Decoder::createTag(m_path); + readMetadata(); +} + +void MediaFile::readMetadata() +{ + if (m_use_meta && m_tag && !m_tag->isEmpty()) + { + m_year = m_tag->year(); + m_title = m_format; + m_title.replace("%p",m_tag->artist()); + m_title.replace("%a",m_tag->album()); + m_title.replace("%t",m_tag->title()); + m_title.replace("%n",QString("%1").arg(m_tag->track())); + m_title.replace("%g",m_tag->genre ()); + m_title.replace("%f",m_path.section('/',-1)); + m_title.replace("%F",m_path); + //m_title.replace("%d",); + m_title.replace("%y",QString("%1").arg(m_tag->year ())); + //m_title.replace("%c",); + } + else + m_title = m_path.startsWith("http://") ? m_path: m_path.section('/',-1); +} + +void MediaFile::changeTitle(const QString &newtitle) +{ + m_title = newtitle; +} + +void MediaFile::setFlag(FLAGS f) +{ + m_flag = f; +} + + +MediaFile::FLAGS MediaFile::flag() const +{ + return m_flag; +} + +FileTag *MediaFile::tag() +{ + if(m_tag && m_tag->isEmpty()) + return 0; + return m_tag; +} + diff --git a/src/ui/mediafile.h b/src/ui/mediafile.h new file mode 100644 index 000000000..1652bf92d --- /dev/null +++ b/src/ui/mediafile.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef MEDIAFILE_H +#define MEDIAFILE_H + +#include <QString> + +class FileTag; +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + + +class MediaFile +{ +public: + /*! + * Current state of media file. + * FREE - instance is free and may be deleted + * EDITING - instance is currently busy in some kind of operation(tags editing etc.) + * and can't be deleted at the moment. Set flag SCHEDULED_FOR_DELETION for it + * instead of delete operator call. + */ + enum FLAGS{FREE = 0,EDITING,SCHEDULED_FOR_DELETION}; + + MediaFile() : m_flag(FREE) + {}; + MediaFile(const QString&); + + ~MediaFile(); + + const QString path()const; + const QString title()const; + const QString fileName()const; + uint year()const; + int length()const; + void setSelected(bool); + bool isSelected()const; + bool isCurrent(); + void setCurrent(bool); + void updateTags(const FileTag*); + void updateTags(); + void changeTitle(const QString&); + FLAGS flag()const; + void setFlag(FLAGS); + FileTag *tag(); + +private: + void readMetadata(); + QString m_path; + QString m_title; + uint m_year; + FileTag *m_tag; + bool m_selected; + bool m_current; + bool m_use_meta; + QString m_format; + FLAGS m_flag; + +}; + +#endif diff --git a/src/ui/monostereo.cpp b/src/ui/monostereo.cpp new file mode 100644 index 000000000..659fec7be --- /dev/null +++ b/src/ui/monostereo.cpp @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QPainter> + +#include "skin.h" +#include "monostereo.h" + +MonoStereo::MonoStereo ( QWidget *parent ) + : PixmapWidget ( parent ) +{ + m_skin = Skin::getPointer(); + m_pixmap = QPixmap ( 54,12 ); + setChannels ( 0 ); + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); +} + + +MonoStereo::~MonoStereo() +{} + +void MonoStereo::setChannels ( int c ) +{ + m_channels = c; + QPainter paint ( &m_pixmap ); + switch ( ( int ) c ) + { + case 0: + { + paint.drawPixmap ( 0,0,m_skin->getMSPart ( Skin::MONO_I ) ); + paint.drawPixmap ( 27,0,m_skin->getMSPart ( Skin::STEREO_I ) ); + break; + } + case 1: + { + paint.drawPixmap ( 0,0,m_skin->getMSPart ( Skin::MONO_A ) ); + paint.drawPixmap ( 27,0,m_skin->getMSPart ( Skin::STEREO_I ) ); + break; + } + } + if ( c > 1 ) + { + paint.drawPixmap ( 0,0,m_skin->getMSPart ( Skin::MONO_I ) ); + paint.drawPixmap ( 27,0,m_skin->getMSPart ( Skin::STEREO_A ) ); + } + setPixmap ( m_pixmap ); +} + +void MonoStereo::updateSkin() +{ + setChannels ( m_channels ); +} diff --git a/src/ui/monostereo.h b/src/ui/monostereo.h new file mode 100644 index 000000000..be1419c5c --- /dev/null +++ b/src/ui/monostereo.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef MONOSTEREO_H +#define MONOSTEREO_H + +#include <pixmapwidget.h> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class Skin; + +class MonoStereo : public PixmapWidget +{ +Q_OBJECT +public: + MonoStereo(QWidget *parent = 0); + + ~MonoStereo(); + + void setChannels(int); + +private slots: + void updateSkin(); + +private: + Skin *m_skin; + QPixmap m_pixmap; + int m_channels; + +}; + +#endif diff --git a/src/ui/mp3player.cpp b/src/ui/mp3player.cpp new file mode 100644 index 000000000..cf6b27535 --- /dev/null +++ b/src/ui/mp3player.cpp @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <QApplication> +#include <QTranslator> +#include <QLocale> +#include <stdio.h> +#include <stdlib.h> + +#include "mainwindow.h" +#include "playlist.h" +#include "qmmpstarter.h" + +int main(int argc, char *argv[]) +{ + QApplication a (argc, argv ); + QTranslator translator; + QString locale = QLocale::system().name(); + translator.load(QString(":/qmmp_") + locale); + a.installTranslator(&translator); + + QMMPStarter starter(argc,argv); + Q_UNUSED(starter) + + return a.exec(); +} diff --git a/src/ui/number.cpp b/src/ui/number.cpp new file mode 100644 index 000000000..9f127965e --- /dev/null +++ b/src/ui/number.cpp @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "number.h" +#include "skin.h" + +Number::Number(QWidget *parent) + : PixmapWidget(parent) +{ + m_skin = Skin::getPointer(); + //TODO default value?? + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); +} + + +Number::~Number() +{ +} + +void Number::setValue(int n) +{ + setPixmap(m_skin->getNumber(n)); + m_value = n; +} + +void Number::updateSkin(void) +{ + setValue(m_value); +} diff --git a/src/ui/number.h b/src/ui/number.h new file mode 100644 index 000000000..1c89f71d4 --- /dev/null +++ b/src/ui/number.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef NUMBER_H +#define NUMBER_H + +#include "pixmapwidget.h" + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class Skin; + +class Number : public PixmapWidget +{ +Q_OBJECT +public: + Number(QWidget *parent = 0); + + ~Number(); + + void setValue(int); + +private slots: + void updateSkin(void); + +private: + Skin *m_skin; + int m_value; + +}; + +#endif diff --git a/src/ui/pixmapwidget.cpp b/src/ui/pixmapwidget.cpp new file mode 100644 index 000000000..a0f4ff7fd --- /dev/null +++ b/src/ui/pixmapwidget.cpp @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QPixmap> +#include <QPainter> +#include <QPaintEvent> + +#include "pixmapwidget.h" + +PixmapWidget::PixmapWidget(QWidget *parent) + : QWidget(parent) +{} + + +PixmapWidget::~PixmapWidget() +{} + +void PixmapWidget::setPixmap(const QPixmap pixmap) +{ + m_pixmap = pixmap; + resize(m_pixmap.size()); + update(); +} + +void PixmapWidget::paintEvent ( QPaintEvent *) +{ + QPainter paint(this); + paint.drawPixmap(0,0, m_pixmap); +} + diff --git a/src/ui/pixmapwidget.h b/src/ui/pixmapwidget.h new file mode 100644 index 000000000..24d34260e --- /dev/null +++ b/src/ui/pixmapwidget.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef PIXMAPWIDGET_H +#define PIXMAPWIDGET_H + +#include <QWidget> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class QPixmap; + +class PixmapWidget : public QWidget +{ +Q_OBJECT +public: + PixmapWidget(QWidget *parent = 0); + + ~PixmapWidget(); + + virtual void setPixmap(const QPixmap); + +protected: + void paintEvent ( QPaintEvent * event ); + +private: + QPixmap m_pixmap; + + + +}; + +#endif diff --git a/src/ui/playlist.cpp b/src/ui/playlist.cpp new file mode 100644 index 000000000..282463ef0 --- /dev/null +++ b/src/ui/playlist.cpp @@ -0,0 +1,471 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QPainter> +#include <QResizeEvent> +#include <QSettings> +#include <QMenu> +#include <QAction> +#include <QSignalMapper> +#include <QHBoxLayout> + +#include "dock.h" +#include "fileloader.h" +#include "playlist.h" +#include "skin.h" +#include "listwidget.h" +#include "button.h" +#include "mediafile.h" +#include "playlistmodel.h" +#include "playlisttitlebar.h" +#include "playlistslider.h" +#include "pixmapwidget.h" +#include "symboldisplay.h" +#include "playlistcontrol.h" +#include "keyboardmanager.h" +#include <output.h> + +PlayList::PlayList ( QWidget *parent ) + : QWidget ( parent ) +{ + setWindowFlags ( Qt::Dialog | Qt::FramelessWindowHint ); + + m_update = FALSE; + m_resize = FALSE; + m_anchor_row = -1; + + createMenus(); + + + resize ( 275,116 ); + setMinimumSize ( 275,116 ); + setBaseSize ( 275,116 ); + m_listWidget = new ListWidget ( this ); + m_listWidget->show(); + m_listWidget->setGeometry ( 12,20,243,58 ); + + m_plslider = new PlayListSlider ( this ); + m_plslider->show(); + + setSizeIncrement ( 25,29 ); + m_skin = Skin::getPointer(); + + m_buttonAdd = new Button ( this,Skin::PL_BT_ADD,Skin::PL_BT_ADD ); + m_buttonAdd->move ( 11,86 ); + m_buttonSub = new Button ( this,Skin::PL_BT_SUB,Skin::PL_BT_SUB ); + m_buttonSub->move ( 40,86 ); + m_selectButton = new Button ( this,Skin::PL_BT_SEL,Skin::PL_BT_SEL ); + m_selectButton->move ( 70,86 ); + m_sortButton= new Button ( this,Skin::PL_BT_SORT,Skin::PL_BT_SORT ); + m_sortButton->move ( 99,86 ); + m_playlistButton = new Button ( this,Skin::PL_BT_LST,Skin::PL_BT_LST ); + + m_pl_control = new PlaylistControl ( this ); + m_pl_control->move ( 0,0 ); + m_pl_control->show(); + + m_length_totalLength = new SymbolDisplay ( this,14 ); + m_length_totalLength->setAlignment ( Qt::AlignLeft ); + m_length_totalLength -> show(); + + m_current_time = new SymbolDisplay ( this,6 ); + m_current_time->show(); + + m_keyboardManager = new KeyboardManager ( this ); + + connect ( m_listWidget, SIGNAL ( selectionChanged() ), parent, SLOT ( replay() ) ); + + connect ( m_plslider, SIGNAL ( sliderMoved ( int ) ), m_listWidget, SLOT ( scroll ( int ) ) ); + connect ( m_listWidget, SIGNAL ( positionChanged ( int, int ) ), m_plslider, + SLOT ( setPos ( int, int ) ) ); + connect ( m_skin, SIGNAL ( skinChanged() ), this, SLOT ( update() ) ); + connect ( m_buttonAdd, SIGNAL ( clicked() ), SLOT ( showAddMenu() ) ); + connect ( m_buttonSub, SIGNAL ( clicked() ), SLOT ( showSubMenu() ) ); + connect ( m_selectButton, SIGNAL ( clicked() ), SLOT ( showSelectMenu() ) ); + connect ( m_sortButton, SIGNAL ( clicked() ), SLOT ( showSortMenu() ) ); + connect ( m_playlistButton, SIGNAL ( clicked() ), SLOT ( showPlaylistMenu() ) ); + + connect ( m_pl_control, SIGNAL ( nextClicked() ), SIGNAL ( next() ) ); + connect ( m_pl_control, SIGNAL ( previousClicked() ), SIGNAL ( prev() ) ); + connect ( m_pl_control, SIGNAL ( playClicked() ), SIGNAL ( play() ) ); + connect ( m_pl_control, SIGNAL ( pauseClicked() ), SIGNAL ( pause() ) ); + connect ( m_pl_control, SIGNAL ( stopClicked() ), SIGNAL ( stop() ) ); + connect ( m_pl_control, SIGNAL ( ejectClicked() ), SIGNAL ( eject() ) ); + m_titleBar = new PlayListTitleBar ( this ); + m_titleBar->move ( 0,0 ); + readSettings(); +} + + +PlayList::~PlayList() +{} + +void PlayList::createMenus() +{ + m_addMenu = new QMenu ( this ); + m_subMenu = new QMenu ( this ); + m_selectMenu = new QMenu ( this ); + m_sortMenu = new QMenu ( this ); + m_playlistMenu = new QMenu ( this ); +} + +void PlayList::createActions() +{ //add menu + QAction *addFileAct = new QAction ( tr ( "&Add File" ),this ); + addFileAct->setShortcut ( tr ( "F" ) ); + m_addMenu->addAction ( addFileAct ); + connect ( addFileAct, SIGNAL ( triggered() ), parent(), SLOT ( addFile () ) ); + m_actions << addFileAct; + + QAction *addDirAct = new QAction ( tr ( "&Add Directory" ),this ); + addDirAct->setShortcut ( tr ( "D" ) ); + m_addMenu->addAction ( addDirAct ); + connect ( addDirAct, SIGNAL ( triggered() ), parent(), SLOT ( addDir () ) ); + m_actions << addDirAct; + + QAction *addUrlAct = new QAction ( tr ( "&Add Url" ),this ); + addUrlAct->setShortcut ( tr ( "U" ) ); + m_addMenu->addAction ( addUrlAct ); + connect ( addUrlAct, SIGNAL ( triggered() ), parent(), SLOT ( addUrl () ) ); + m_actions << addUrlAct; + + //remove menu + QAction *remSelAct = new QAction ( tr ( "&Remove Selected" ),this ); + remSelAct->setShortcut ( tr ( "Del" ) ); + m_subMenu->addAction ( remSelAct ); + connect ( remSelAct, SIGNAL ( triggered() ), + m_playListModel, SLOT ( removeSelected () ) ); + this->addAction ( remSelAct ); + + QAction *remAllAct = new QAction ( tr ( "&Remove All" ),this ); + //remAllAct->setShortcut(tr("D")); FIXME: add correct shortcat + m_subMenu->addAction ( remAllAct ); + connect ( remAllAct, SIGNAL ( triggered() ), m_playListModel, SLOT ( clear () ) ); + m_actions << remAllAct; + + QAction *remUnselAct = new QAction ( tr ( "&Remove Unselected" ),this ); + m_subMenu->addAction ( remUnselAct ); + connect ( remUnselAct, SIGNAL ( triggered() ), + m_playListModel, SLOT ( removeUnselected () ) ); + + //listwidget menu + QAction *detailsAct = new QAction ( tr ( "&View Track Details" ),this ); + detailsAct->setShortcut ( tr ( "Alt+I" ) ); + m_listWidget->menu()->addAction ( detailsAct ); + connect ( detailsAct, SIGNAL ( triggered() ), m_playListModel, SLOT ( showDetails () ) ); + + // sort menu + m_sortMenu->addAction ( detailsAct ); + m_sortMenu->addSeparator(); + + QMenu* sort_mode_menu = new QMenu ( tr ( "Sort List" ),m_sortMenu ); + + QSignalMapper* signalMapper = new QSignalMapper ( this ); + QAction* titleAct = sort_mode_menu->addAction ( tr ( "By Title" ) ); + connect ( titleAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) ); + signalMapper->setMapping ( titleAct, PlayListModel::TITLE ); + + QAction* nameAct = sort_mode_menu->addAction ( tr ( "By Filename" ) ); + connect ( nameAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) ); + signalMapper->setMapping ( nameAct, PlayListModel::FILENAME ); + + QAction* pathnameAct = sort_mode_menu->addAction ( tr ( "By Path + Filename" ) ); + connect ( pathnameAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) ); + signalMapper->setMapping ( pathnameAct, PlayListModel::PATH_AND_FILENAME ); + + QAction* dateAct = sort_mode_menu->addAction ( tr ( "By Date" ) ); + connect ( dateAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) ); + signalMapper->setMapping ( dateAct, PlayListModel::DATE ); + + connect ( signalMapper, SIGNAL ( mapped ( int ) ), + m_playListModel, SLOT ( sort ( int ) ) ); + + m_sortMenu->addMenu ( sort_mode_menu ); + + sort_mode_menu = new QMenu ( tr ( "Sort Selection" ),m_sortMenu ); + signalMapper = new QSignalMapper ( this ); + titleAct = sort_mode_menu->addAction ( tr ( "By Title" ) ); + connect ( titleAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) ); + signalMapper->setMapping ( titleAct, PlayListModel::TITLE ); + + nameAct = sort_mode_menu->addAction ( tr ( "By Filename" ) ); + connect ( nameAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) ); + signalMapper->setMapping ( nameAct, PlayListModel::FILENAME ); + + pathnameAct = sort_mode_menu->addAction ( tr ( "By Path + Filename" ) ); + connect ( pathnameAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) ); + signalMapper->setMapping ( pathnameAct, PlayListModel::PATH_AND_FILENAME ); + + dateAct = sort_mode_menu->addAction ( tr ( "By Date" ) ); + connect ( dateAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) ); + signalMapper->setMapping ( dateAct, PlayListModel::DATE ); + + connect ( signalMapper, SIGNAL ( mapped ( int ) ), + m_playListModel, SLOT ( sortSelection ( int ) ) ); + + m_sortMenu->addMenu ( sort_mode_menu ); + + m_sortMenu->addSeparator(); + m_sortMenu->addAction ( tr ( "Randomize List" ),m_playListModel,SLOT ( randomizeList() ) ); + m_sortMenu->addAction ( tr ( "Reverse List" ),m_playListModel,SLOT ( reverseList() ) ); + + m_listWidget->menu()->addSeparator(); + m_listWidget->menu()->addActions ( m_subMenu->actions() ); + m_actions << detailsAct; + + //select menu + QAction *invSelAct = new QAction ( tr ( "Invert Selection" ),this ); + m_selectMenu->addAction ( invSelAct ); + connect ( invSelAct, SIGNAL ( triggered() ), + m_playListModel, SLOT ( invertSelection () ) ); + + m_selectMenu->addSeparator(); + + QAction *selNoneAct = new QAction ( tr ( "&Select None" ),this ); + //selNoneAct->setShortcut(tr("Ctrl+Shift+A")); + m_selectMenu->addAction ( selNoneAct ); + connect ( selNoneAct, SIGNAL ( triggered() ), + m_playListModel, SLOT ( clearSelection () ) ); + this->addAction ( selNoneAct ); + + QAction *selAllAct = new QAction ( tr ( "&Select All" ),this ); + selAllAct->setShortcut ( tr ( "Ctrl+A" ) ); + m_selectMenu->addAction ( selAllAct ); + connect ( selAllAct, SIGNAL ( triggered() ), + m_playListModel, SLOT ( selectAll () ) ); + this->addAction ( selAllAct ); + +// Playlist Menu + QAction *newListAct = new QAction ( tr ( "&New List" ),this ); + newListAct->setShortcut ( tr ( "Shift+N" ) ); + m_actions << newListAct; + m_playlistMenu->addAction ( newListAct ); + connect ( newListAct, SIGNAL ( triggered() ), this, SIGNAL ( newPlaylist() ) ); + m_playlistMenu->addSeparator(); + + QAction *loadListAct = new QAction ( tr ( "&Load List" ),this ); + loadListAct->setShortcut ( tr ( "O" ) ); + m_playlistMenu->addAction ( loadListAct ); + connect ( loadListAct, SIGNAL ( triggered() ), this, SIGNAL ( loadPlaylist() ) ); + + QAction *saveListAct = new QAction ( tr ( "&Save List" ),this ); + saveListAct->setShortcut ( tr ( "Shift+S" ) ); + m_playlistMenu->addAction ( saveListAct ); + connect ( saveListAct, SIGNAL ( triggered() ), this, SIGNAL ( savePlaylist() ) ); + this->addActions ( m_playlistMenu->actions() ); + + Dock::getPointer()->addActions ( m_actions ); +} + +void PlayList::closeEvent ( QCloseEvent* ) +{ + writeSettings(); +} + +void PlayList::paintEvent ( QPaintEvent * ) +{ + int m_sx = ( width()-275 ) /25; + int m_sy = ( height()-116 ) /29; + drawPixmap ( m_sx, m_sy ); +} + +void PlayList::drawPixmap ( int sx, int sy ) +{ + QPainter paint; + paint.begin ( this ); + paint.drawPixmap ( 0,20,m_skin->getPlPart ( Skin::PL_LFILL ) ); + for ( int i = 1; i<sy+2; i++ ) + { + paint.drawPixmap ( 0,20+29*i,m_skin->getPlPart ( Skin::PL_LFILL ) ); + } + paint.drawPixmap ( 0,78+29*sy,m_skin->getPlPart ( Skin::PL_LSBAR ) ); + for ( int i = 0; i<sx; i++ ) + { + paint.drawPixmap ( 125+i*25,78+sy*29,m_skin->getPlPart ( Skin::PL_SFILL1 ) ); + } + + paint.drawPixmap ( 125+sx*25,78+sy*29,m_skin->getPlPart ( Skin::PL_RSBAR ) ); + paint.end(); + +} + +void PlayList::resizeEvent ( QResizeEvent *e ) +{ + int sx = ( e->size().width()-275 ) /25; + int sy = ( e->size().height()-116 ) /29; + if (sx < 0 || sy < 0) + return; + + m_titleBar->resize ( 275+25*sx,20 ); + m_plslider->resize ( 20,58+sy*29 ); + + m_listWidget->resize ( 243+25*sx,58+29*sy ); + + m_buttonAdd->move ( 11,86+29*sy ); + m_buttonSub->move ( 40,86+29*sy ); + m_selectButton->move ( 70,86+29*sy ); + m_sortButton->move ( 99,86+29*sy ); + + m_pl_control->move ( 128+sx*25,100+29*sy ); + m_playlistButton->move ( 228+sx*25,86+29*sy ); + + m_length_totalLength -> move ( 131+sx*25,88+29*sy ); + m_current_time->move ( 190+sx*25,101+29*sy ); + + m_plslider->move ( 255+sx*25,20 ); +} +void PlayList::mousePressEvent ( QMouseEvent *e ) +{ + m_pos = e->pos (); + if ( ( m_pos.x() > width()-25 ) && ( m_pos.y() > height()-25 ) ) + { + m_resize = TRUE; + setCursor ( Qt::SizeFDiagCursor ); + } + else + m_resize = FALSE; +} +void PlayList::mouseMoveEvent ( QMouseEvent *e ) +{ + if ( m_resize ) + { + resize ( e->x() +25, e->y() +25 ); + //usleep(32000); + } +} +void PlayList::mouseReleaseEvent ( QMouseEvent * ) +{ + setCursor ( Qt::ArrowCursor ); + /*if (m_resize) + m_listWidget->updateList();*/ + m_resize = FALSE; + Dock::getPointer()->updateDock(); +} +void PlayList::setModel ( PlayListModel *model ) +{ + m_playListModel = model; + m_listWidget->setModel (model); + m_keyboardManager->setModel (model); + m_titleBar->setModel (model); + createActions(); +} + +void PlayList::changeEvent ( QEvent * event ) +{ + if ( event->type() == QEvent::ActivationChange ) + { + m_titleBar->setActive ( isActiveWindow() ); + } +} + +void PlayList::readSettings() +{ + if ( m_update ) + { + m_listWidget->readSettings(); + m_titleBar->readSettings(); + } + else + { + QSettings settings (QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat); + settings.beginGroup ( "PlayList" ); + //position + move ( settings.value ("pos", QPoint ( 100, 332 ) ).toPoint()); + settings.endGroup(); + m_update = TRUE; + } + +} + +void PlayList::writeSettings() +{ + QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat ); + settings.beginGroup ( "PlayList" ); + //position + settings.setValue ( "pos", this->pos() ); + settings.endGroup(); +} + +void PlayList::showAddMenu() +{ + m_addMenu->exec ( m_buttonAdd->mapToGlobal ( QPoint ( 0,0 ) ) ); +} + +void PlayList::showSubMenu() +{ + m_subMenu->exec ( m_buttonSub->mapToGlobal ( QPoint ( 0,0 ) ) ); +} + +void PlayList::showSelectMenu() +{ + m_selectMenu->exec ( m_selectButton->mapToGlobal ( QPoint ( 0,0 ) ) ); +} + +void PlayList::showSortMenu() +{ + m_sortMenu->exec ( m_sortButton->mapToGlobal ( QPoint ( 0,0 ) ) ); +} + + + +QString PlayList::formatTime ( int sec ) +{ + int minutes = sec / 60; + int seconds = sec % 60; + + QString str_minutes = QString::number ( minutes ); + QString str_seconds = QString::number ( seconds ); + + if ( minutes < 10 ) str_minutes.prepend ( "0" ); + if ( seconds < 10 ) str_seconds.prepend ( "0" ); + + return str_minutes + ":" + str_seconds; +} + +void PlayList::setInfo (const OutputState &st,int length_current, int length_total) +{ + if ( st.type() == OutputState::Info ) + { + m_current_time->display ( formatTime ( st.elapsedSeconds() ) ); + m_current_time->update(); + + QString str_length = formatTime ( length_current ) + "/" + formatTime ( length_total ); + m_length_totalLength->display ( str_length ); + m_length_totalLength->update(); + } +} + +MediaFile *PlayList::currentItem() +{ + if ( m_playListModel ) + return m_playListModel->currentItem(); + else + return 0; +} + +void PlayList::showPlaylistMenu() +{ + m_playlistMenu->exec ( m_playlistButton->mapToGlobal ( QPoint ( 0,0 ) ) ); +} + +void PlayList::keyPressEvent ( QKeyEvent *ke ) +{ + if ( m_keyboardManager->handleKeyPress ( ke ) ) + update(); +} diff --git a/src/ui/playlist.h b/src/ui/playlist.h new file mode 100644 index 000000000..4e8bdc1f8 --- /dev/null +++ b/src/ui/playlist.h @@ -0,0 +1,124 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef PLAYLIST_H +#define PLAYLIST_H + +#include <QWidget> + +class KeyboardManager; + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + +class QMenu; + +class Skin; +class ListWidget; +class MediaFile; +class Button; +class PlayListModel; +class PlayListTitleBar; +class PlayListSlider; +class MainWindow; +class SymbolDisplay; +class OutputState; +class PixmapWidget; +class PlaylistControl; + +class PlayList : public QWidget +{ + Q_OBJECT + public: + PlayList ( QWidget *parent = 0 ); + + ~PlayList(); + void load ( MediaFile * ); + void setModel ( PlayListModel * ); + void readSettings(); + void setInfo ( const OutputState &,int,int ); + MediaFile *currentItem(); + ListWidget* listWidget() const{return m_listWidget;} + + signals: + void play(); + void next(); + void prev(); + void pause(); + void stop(); + void eject(); + void loadPlaylist(); + void savePlaylist(); + void newPlaylist(); + void closed(); + + private slots: + void showAddMenu(); + void showSubMenu(); + void showSelectMenu(); + void showSortMenu(); + void showPlaylistMenu(); + + + private: + QString formatTime ( int sec ); + void drawPixmap ( int, int ); + void writeSettings(); + void createMenus(); + void createActions(); + QMenu *m_addMenu; + QMenu *m_subMenu; + QMenu *m_selectMenu; + QMenu *m_sortMenu; + QMenu *m_playlistMenu; + Button *m_buttonAdd; + Button *m_buttonSub; + Button *m_selectButton; + Button *m_sortButton; + Button* m_playlistButton; + + PlaylistControl* m_pl_control; + SymbolDisplay* m_length_totalLength; + SymbolDisplay* m_current_time; + + Skin *m_skin; + ListWidget *m_listWidget; + PlayListModel *m_playListModel; + PlayListTitleBar *m_titleBar; + PlayListSlider *m_plslider; + QList <QAction *> m_actions; + QPoint m_pos; + bool m_resize; + bool m_update; + int m_anchor_row; + KeyboardManager* m_keyboardManager; + + protected: + virtual void paintEvent ( QPaintEvent * ); + virtual void resizeEvent ( QResizeEvent * ); + virtual void mouseMoveEvent ( QMouseEvent * ); + virtual void mousePressEvent ( QMouseEvent * ); + virtual void mouseReleaseEvent ( QMouseEvent * ); + virtual void changeEvent ( QEvent* ); + virtual void closeEvent ( QCloseEvent* ); + virtual void keyPressEvent ( QKeyEvent* ); +}; + +#endif diff --git a/src/ui/playlistcontrol.cpp b/src/ui/playlistcontrol.cpp new file mode 100644 index 000000000..8f111fe4e --- /dev/null +++ b/src/ui/playlistcontrol.cpp @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QPainter> +#include <QPaintEvent> +#include <QMouseEvent> + +#include "playlistcontrol.h" +#include "skin.h" + +PlaylistControl::PlaylistControl(QWidget* parent) : PixmapWidget(parent) +{ + m_skin = Skin::getPointer(); + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(update())); +} + +void PlaylistControl::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + painter.drawPixmap(0,0,m_skin->getPlPart(Skin::PL_CONTROL)); +} + +void PlaylistControl::mouseReleaseEvent(QMouseEvent *me) +{ + QPoint pt = me->pos(); + if(QRect(4,1,7,7).contains(pt)) + emit previousClicked(); + else if(QRect(12,1,7,7).contains(pt)) + emit playClicked(); + else if(QRect(21,1,7,7).contains(pt)) + emit pauseClicked(); + else if(QRect(31,1,7,7).contains(pt)) + emit stopClicked(); + else if(QRect(40,1,7,7).contains(pt)) + emit nextClicked(); + else if(QRect(49,1,7,7).contains(pt)) + emit ejectClicked(); +} diff --git a/src/ui/playlistcontrol.h b/src/ui/playlistcontrol.h new file mode 100644 index 000000000..26c3871d4 --- /dev/null +++ b/src/ui/playlistcontrol.h @@ -0,0 +1,52 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + + /** + @author Vladimir Kuznetsov <vovanec@gmail.ru> + */ + +#ifndef _PALYLISTCONTROL_H +#define _PALYLISTCONTROL_H + +#include "pixmapwidget.h" + +class PaintEvent; +class Skin; +class QMouseEvent; + +class PlaylistControl : public PixmapWidget +{ +Q_OBJECT +public: + PlaylistControl(QWidget* parent = 0); + void paintEvent(QPaintEvent*); + void mouseReleaseEvent(QMouseEvent*); +signals: + void previousClicked(); + void nextClicked(); + void pauseClicked(); + void playClicked(); + void stopClicked(); + void ejectClicked(); +protected: + Skin* m_skin; +}; + +#endif diff --git a/src/ui/playlistformat.cpp b/src/ui/playlistformat.cpp new file mode 100644 index 000000000..d9ce45b77 --- /dev/null +++ b/src/ui/playlistformat.cpp @@ -0,0 +1,287 @@ +/*************************************************************************** +* Copyright (C) 2006 by Ilya Kotov * +* forkotov02@hotmail.ru * +* * +* 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. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QFileInfo> + +#ifndef XSPF_PLUGIN + #include <QDomDocument> + #include <QDomElement> + #include <QUrl> + #include "version.h" +#endif + +#include "playlistformat.h" + +#include "mediafile.h" + +bool PLSPlaylistFormat::hasFormat(const QString & f) +{ + foreach(QString s,m_supported_formats) + if(f == s) + return true; + + return false; +} + +QStringList PLSPlaylistFormat::getExtensions() const +{ + return m_supported_formats; +} + +PLSPlaylistFormat::PLSPlaylistFormat() +{ + m_supported_formats << "pls"; +} + +QString PLSPlaylistFormat::name() const +{ + return "PLSPlaylistFormat"; +} + + +QStringList PLSPlaylistFormat::decode(const QString & contents) +{ + QStringList out; + QStringList splitted = contents.split("\n"); + if(!splitted.isEmpty()) + { + if(splitted.takeAt(0).toLower().contains("[playlist]")) + { + foreach(QString str, splitted) + { + if(str.startsWith("File")) + { + QString unverified = str.remove(0,str.indexOf(QChar('=')) + 1); + if(QFileInfo(unverified).exists()) + out << QFileInfo(unverified).absoluteFilePath(); + else + qWarning("File %s does not exist",unverified.toLocal8Bit().data()); + } + } + return out; + } + } + else + qWarning("Error parsing PLS format"); + + return QStringList(); +} + +QString PLSPlaylistFormat::encode(const QList< MediaFile * > & contents) +{ + QStringList out; + out << QString("[playlist]"); + int counter = 1; + foreach(MediaFile* f,contents) + { + QString begin = "File" + QString::number(counter) + "="; + out.append(begin + f->path()); + begin = "Title" + QString::number(counter) + "="; + out.append(begin + f->title()); + begin = "Length" + QString::number(counter) + "="; + out.append(begin + QString::number(f->length())); + counter ++; + } + out << "NumberOfEntries=" + QString::number(contents.count()); + return out.join("\n"); +} + + + + +bool M3UPlaylistFormat::hasFormat(const QString & f) +{ + foreach(QString s,m_supported_formats) + if(f == s) + return true; + + return false; +} + +QStringList M3UPlaylistFormat::getExtensions() const +{ + return m_supported_formats; +} + +M3UPlaylistFormat::M3UPlaylistFormat() +{ + m_supported_formats << "m3u"; +} + +QStringList M3UPlaylistFormat::decode(const QString & contents) +{ + QStringList out; + QStringList splitted = contents.split("\n"); + if(!splitted.isEmpty()) + { + if(splitted.takeAt(0).contains("#EXTM3U")) + { + foreach(QString str, splitted) + { + if(str.startsWith("#EXTINF:")) + ;//TODO: Let's skip it for now... + else if(QFileInfo(str).exists()) + out << QFileInfo(str).absoluteFilePath(); + else + qWarning("File %s does not exist",str.toLocal8Bit().data()); + } + return out; + } + } + else + qWarning("Error parsing M3U format"); + + return QStringList(); +} + +QString M3UPlaylistFormat::encode(const QList< MediaFile * > & contents) +{ + QStringList out; + out << QString("#EXTM3U"); + foreach(MediaFile* f,contents) + { + QString info = "#EXTINF:" + QString::number(f->length()) + "," + f->title(); + out.append(info); + out.append(f->path()); + } + return out.join("\n"); +} + +QString M3UPlaylistFormat::name() const +{ + return "M3UPlaylistFormat"; +} + + +// Needs more work - it's better use libSpiff there and put it as plugin. + +QStringList XSPFPlaylistFormat::decode(const QString & contents) +{ + QStringList out; + QDomDocument doc; + QString errorMsg; + int errorCol; + int errorRow; + bool ok = doc.setContent(contents, &errorMsg, &errorRow, &errorCol); + + if(!ok) + qDebug("Parse Error: %s\tRow:%d\tCol%d", + qPrintable(errorMsg), errorRow, errorCol ); + + QDomElement rootElement = doc.firstChildElement("playlist"); + if(rootElement.isNull()) + qWarning("Error parsing XSPF: can't find 'playlist' element"); + + QDomElement tracklistElement = rootElement.firstChildElement("trackList"); + if(tracklistElement.isNull()) + qWarning("Error parsing XSPF: can't find 'trackList' element"); + + QDomElement child = tracklistElement.firstChildElement("track"); + + while (!child.isNull()) + { + QString str = QUrl(child.firstChildElement("location").text()).toString(QUrl::RemoveScheme); + out << str; + child = child.nextSiblingElement(); + } + + return out; +} + +// Needs more work - it's better use libSpiff there and put it as plugin. + +QString XSPFPlaylistFormat::encode(const QList< MediaFile * > & files) +{ + QDomDocument doc; + QDomElement root = doc.createElement("playlist"); + root.setAttribute("version",QString("1")); + root.setAttribute("xmlns",QString("http://xspf.org/ns/0")); + + QDomElement creator = doc.createElement("creator"); + QDomText text = doc.createTextNode("qmmp-" + QString(QMMP_STR_VERSION)); + creator.appendChild(text); + root.appendChild(creator); + + QDomElement tracklist = doc.createElement("trackList"); + + int counter = 1; + foreach(MediaFile* f,files) + { + QDomElement track = doc.createElement("track"); + + QDomElement ch = doc.createElement("location"); + QDomText text = doc.createTextNode(/*QString("file://") + */QFileInfo(f->path()).absoluteFilePath()); + ch.appendChild(text); + track.appendChild(ch); + + ch = doc.createElement("title"); + text = doc.createTextNode(f->title()); + ch.appendChild(text); + track.appendChild(ch); + + ch = doc.createElement("trackNum"); + text = doc.createTextNode(QString::number(counter)); + ch.appendChild(text); + track.appendChild(ch); + + ch = doc.createElement("year"); + text = doc.createTextNode(QString::number(f->year())); + ch.appendChild(text); + track.appendChild(ch); + + tracklist.appendChild(track); + counter ++; + } + + root.appendChild(tracklist); + doc.appendChild( root ); + QString xml_header("<?xml version='1.0' encoding='UTF-8'?>\n"); + return doc.toString().prepend(xml_header); +} + +XSPFPlaylistFormat::XSPFPlaylistFormat() +{ + m_supported_formats << "xspf"; +} + +bool XSPFPlaylistFormat::hasFormat(const QString & f) +{ + foreach(QString s,m_supported_formats) + if(f == s) + return true; + + return false; +} + +QStringList XSPFPlaylistFormat::getExtensions() const +{ + return m_supported_formats; +} + + +QString XSPFPlaylistFormat::name() const +{ + return "XSPFPlaylistFormat"; +} + + + + + diff --git a/src/ui/playlistformat.h b/src/ui/playlistformat.h new file mode 100644 index 000000000..a87018d63 --- /dev/null +++ b/src/ui/playlistformat.h @@ -0,0 +1,116 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _PALYLISTFORMAT_H +#define _PALYLISTFORMAT_H +#include <QStringList> + + +class MediaFile; +/*! + * Abstract interface for playlist formats. + * + * @author Vladimir Kuznetsov <vovanec@gmail.com> + */ +class PlaylistFormat +{ +public: + virtual ~PlaylistFormat(){;} + /*! + * Takes raw contents of playlist file, should return string list of + * ready file pathes to fill the playlist. + */ + virtual QStringList decode(const QString& contents) = 0; + + /*! + * Takes the list of MediaFile objects, should return string of + * encoded playlist file + */ + virtual QString encode(const QList<MediaFile*>& contents) = 0; + + /*! + * Returns list of file extensions that current format supports + */ + virtual QStringList getExtensions()const = 0; + + /*! + * Verifies is the \b ext file extension supported by current playlist format. + */ + virtual bool hasFormat(const QString& ext) = 0; + + /// Unique name of playlist format. + virtual QString name()const = 0; +}; + +Q_DECLARE_INTERFACE(PlaylistFormat,"PlaylistFormatInterface/1.0"); + +/*! + * Class for PLS playlist format parsing + */ +class PLSPlaylistFormat : public PlaylistFormat +{ +public: + PLSPlaylistFormat(); + virtual QStringList getExtensions()const; + virtual bool hasFormat(const QString&); + virtual QStringList decode(const QString& contents); + virtual QString encode(const QList<MediaFile*>& contents); + virtual QString name()const; +protected: + QStringList m_supported_formats; + +}; + + + +/*! + * Class for M3U playlist format parsing + */ +class M3UPlaylistFormat : public PlaylistFormat +{ + public: + M3UPlaylistFormat(); + virtual QStringList getExtensions()const; + virtual bool hasFormat(const QString&); + virtual QStringList decode(const QString& contents); + virtual QString encode(const QList<MediaFile*>& contents); + virtual QString name()const; +protected: + QStringList m_supported_formats; +}; + + +/*! + * Class for XSPF playlist format parsing + */ +class XSPFPlaylistFormat : public PlaylistFormat +{ + public: + XSPFPlaylistFormat(); + virtual QStringList getExtensions()const; + virtual bool hasFormat(const QString&); + virtual QStringList decode(const QString& contents); + virtual QString encode(const QList<MediaFile*>& contents); + virtual QString name()const; + protected: + QStringList m_supported_formats; +}; + +#endif diff --git a/src/ui/playlistmodel.cpp b/src/ui/playlistmodel.cpp new file mode 100644 index 000000000..196608438 --- /dev/null +++ b/src/ui/playlistmodel.cpp @@ -0,0 +1,899 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QWidget> +#include <QFile> +#include <QDir> +#include <QtAlgorithms> +#include <QFileInfo> +#include <QTextStream> +#include <QPluginLoader> +#include <QApplication> +#include <QTimer> +#include <QSettings> + +#include <time.h> + +#include <decoder.h> +#include <decoderfactory.h> + +#include "fileloader.h" +#include "playlistmodel.h" +#include "mediafile.h" +#include "playlistformat.h" +#include "playstate.h" + +#include <QMetaType> + +#define INVALID_ROW -1 + +TagUpdater::TagUpdater(QObject* o,MediaFile* f):m_observable(o),m_file(f) +{ + m_file->setFlag(MediaFile::EDITING); + connect (m_observable, SIGNAL(destroyed (QObject * )),SLOT(updateTag())); + connect (m_observable, SIGNAL(destroyed (QObject * )),SLOT(deleteLater())); +} + +void TagUpdater::updateTag() +{ + if(m_file->flag() == MediaFile::SCHEDULED_FOR_DELETION) + { + delete m_file; + m_file = NULL; + } + else + { + m_file->updateTags(); + m_file->setFlag(MediaFile::FREE); + } +} + + +PlayListModel::PlayListModel ( QObject *parent ) + : QObject ( parent ) , m_selection() +{ + qsrand(time(0)); + m_total_length = 0; + m_current = 0; + m_block_update_signals = false; + is_repeatable_list = false; + m_play_state = new NormalPlayState(this); + //readSettings(); + + registerPlaylistFormat( new PLSPlaylistFormat); + registerPlaylistFormat( new M3UPlaylistFormat); +#ifndef XSPF_PLUGIN + registerPlaylistFormat( new XSPFPlaylistFormat); +#endif + loadExternalPlaylistFormats(); +} + +PlayListModel::~PlayListModel() +{ + writeSettings(); + clear(); + delete m_play_state; + qDeleteAll(m_registered_pl_formats); + + foreach(GuardedFileLoader l,m_running_loaders) + { + if (!l.isNull()) + { + l->finish(); + l->wait(); + } + } +} + +void PlayListModel::load ( MediaFile *file ) +{ + if (m_files.isEmpty()) + m_currentItem = file; + + m_total_length += file->length(); + m_files << file; + + //if (!m_block_update_signals) + emit listChanged(); +} + +int PlayListModel::count() +{ + return m_files.size(); +} + +MediaFile* PlayListModel::currentItem() +{ + if ( m_files.isEmpty() ) + return 0; + else + return m_files.at ( qMin(m_files.size() - 1, m_current)); +} + +int PlayListModel::currentRow() +{ + return m_current; +} + +bool PlayListModel::setCurrent ( int c ) +{ + if ( c > count()-1 || c < 0) + return FALSE; + m_current = c; + m_currentItem = m_files.at(c); + emit currentChanged(); + emit listChanged(); + return TRUE; +} + + +bool PlayListModel::next() +{ + if (isFileLoaderRunning()) + m_play_state->prepare(); + + return m_play_state->next(); +} + +bool PlayListModel::previous() +{ + if (isFileLoaderRunning()) + m_play_state->prepare(); + + return m_play_state->previous();//) +} + +void PlayListModel::clear() +{ + foreach(GuardedFileLoader l,m_running_loaders) + { + if (!l.isNull()) + { + l->finish(); + l->wait(); + } + } + + m_running_loaders.clear(); + + m_current = 0; + while ( !m_files.isEmpty() ) + { + MediaFile* mf = m_files.takeFirst(); + + if(mf->flag() == MediaFile::FREE) + { + delete mf; + } + else if(mf->flag() == MediaFile::EDITING) + { + mf->setFlag(MediaFile::SCHEDULED_FOR_DELETION); + } + } + + m_total_length = 0; + m_play_state->resetState(); + emit listChanged(); +} + +void PlayListModel::clearSelection() +{ + for ( int i = 0; i<m_files.size(); ++i ) + m_files.at ( i )->setSelected ( FALSE ); + emit listChanged(); +} + +QList <QString> PlayListModel::getTitles ( int b,int l ) +{ + QList <QString> m_titles; + for ( int i = b; ( i < b + l ) && ( i < m_files.size() ); ++i ) + m_titles << m_files.at ( i )->title(); + return m_titles; +} + +QList <QString> PlayListModel::getTimes ( int b,int l ) +{ + QList <QString> m_times; + for ( int i = b; ( i < b + l ) && ( i < m_files.size() ); ++i ) + m_times << QString ( "%1" ).arg ( m_files.at ( i )->length() /60 ) +":" + +QString ( "%1" ).arg ( m_files.at ( i )->length() %60/10 ) + + QString ( "%1" ).arg ( m_files.at ( i )->length() %60%10 ); + return m_times; +} + +bool PlayListModel::isSelected ( int row ) +{ + if (m_files.count() > row && row >= 0) + return m_files.at ( row )->isSelected(); + + return false; +} + +void PlayListModel::setSelected ( int row, bool yes ) +{ + if (m_files.count() > row && row >= 0) + m_files.at ( row )->setSelected ( yes ); +} + +void PlayListModel::removeSelected() +{ + removeSelection(false); +} + +void PlayListModel::removeUnselected() +{ + removeSelection(true); +} + +void PlayListModel::removeSelection(bool inverted) +{ + int i = 0; + + int select_after_delete = -1; + + while ( !m_files.isEmpty() && i<m_files.size() ) + { + if ( m_files.at ( i )->isSelected() ^ inverted ) + { + MediaFile* f = m_files.takeAt ( i ); + m_total_length -= f->length(); + if (m_total_length < 0) + m_total_length = 0; + + if(f->flag() == MediaFile::FREE) + { + delete f; + f = NULL; + } + else if(f->flag() == MediaFile::EDITING) + f->setFlag(MediaFile::SCHEDULED_FOR_DELETION); + + select_after_delete = i; + + if ( m_current >= i && m_current!=0 ) + m_current--; + } + else + i++; + } + + if (!m_files.isEmpty()) + m_currentItem = m_files.at(m_current); + + if (select_after_delete >= m_files.count()) + select_after_delete = m_files.count() - 1; + + setSelected(select_after_delete,true); + + m_play_state->prepare(); + + emit listChanged(); +} + +void PlayListModel::invertSelection() +{ + for ( int i = 0; i<m_files.size(); ++i ) + m_files.at ( i )->setSelected ( !m_files.at ( i )->isSelected() ); + emit listChanged(); +} + +void PlayListModel::selectAll() +{ + for ( int i = 0; i<m_files.size(); ++i ) + m_files.at ( i )->setSelected ( TRUE ); + emit listChanged(); +} + +void PlayListModel::showDetails() +{ + for ( int i = 0; i<m_files.size(); ++i ) + { + if ( m_files.at ( i )->isSelected() ) + { + DecoderFactory *fact = Decoder::findByPath ( m_files.at ( i )->path() ); + if ( fact ) + { + QObject* o = fact->showDetails ( 0, m_files.at ( i )->path() ); + if(o) + { + TagUpdater *updater = new TagUpdater(o,m_files.at(i)); + m_editing_files.append(m_files.at(i)); + connect (updater, SIGNAL(destroyed (QObject * )),SIGNAL(listChanged())); + } + } + + return; + } + } + +} + + +void PlayListModel::readSettings() +{ + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + m_current = settings.value("Playlist/current",0).toInt(); + + QFile file ( QDir::homePath() +"/.qmmp/playlist.txt" ); + file.open ( QIODevice::ReadOnly ); + + QStringList files; + QByteArray line; + m_files.clear(); + + while (!file.atEnd ()) + { + line = file.readLine(); + files << QString::fromUtf8 ( line ).trimmed (); + } + + file.close (); + + if(m_current > files.count() - 1) + m_current = 0; + + int preload = (files.count() < 100) ? files.count() : 100; + + for (int i = 0;i < preload;i++) + { + load(new MediaFile(files.takeAt(0))); + } + + if (files.isEmpty()) + { + doCurrentVisibleRequest (); + return; + } + + FileLoader* f_loader = createFileLoader(); + connect(f_loader, SIGNAL(finished ()), SLOT(doCurrentVisibleRequest ())); + + f_loader->setFilesToLoad(files); + //f_loader->start(QThread::IdlePriority); + QTimer::singleShot(1000,f_loader,SLOT(start())); + //m_play_state->prepare(); +} + +void PlayListModel::writeSettings() +{ + QFile file ( QDir::homePath() +"/.qmmp/playlist.txt" ); + file.open ( QIODevice::WriteOnly ); + foreach ( MediaFile* m, m_files ) + file.write ( m->path().toUtf8 () +"\n" ); + file.close (); + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + settings.setValue("Playlist/current", m_current); +} + +void PlayListModel::addFile(const QString& path) +{ + if (path.isEmpty ()) + return; + if (path.startsWith("http://")) + load(new MediaFile(path)); + else if (Decoder::supports(path)) + load(new MediaFile(path)); + + m_play_state->prepare(); +} + +FileLoader * PlayListModel::createFileLoader() +{ + FileLoader* f_loader = new FileLoader(this); +// f_loader->setStackSize(20 * 1024 * 1024); + m_running_loaders << f_loader; + connect(f_loader,SIGNAL(newMediaFile(MediaFile*)),this,SLOT(load(MediaFile*)),Qt::QueuedConnection); + connect(f_loader,SIGNAL(finished()),this,SLOT(preparePlayState())); + connect(f_loader,SIGNAL(finished()),f_loader,SLOT(deleteLater())); + return f_loader; +} + +void PlayListModel::addFiles(const QStringList &files) +{ + FileLoader* f_loader = createFileLoader(); + f_loader->setFilesToLoad(files); + f_loader->start(QThread::IdlePriority); +} + +void PlayListModel::addDirectory(const QString& s) +{ + FileLoader* f_loader = createFileLoader(); + f_loader->setDirectoryToLoad(s); + f_loader->start(QThread::IdlePriority); +} + +void PlayListModel::addFileList(const QStringList &l) +{ +// qWarning("void// PlayListModel::addFileList(const QStringList &l)"); + foreach(QString str,l) + { + QFileInfo f_info(str); + if (f_info.exists()) + { + if (f_info.isDir()) + addDirectory(str); + else + addFile(str); + } + // Do processing the rest of events to avoid GUI freezing + QApplication::processEvents(QEventLoop::AllEvents,10); + } +} + +bool PlayListModel::setFileList(const QStringList & l) +{ + bool model_cleared = FALSE; + foreach(QString str,l) + { + QFileInfo f_info(str); + if (f_info.exists()) + { + if (!model_cleared) + { + clear(); + model_cleared = TRUE; + } + if (f_info.isDir()) + addDirectory(str); + else + addFile(str); + } + // Do processing the rest of events to avoid GUI freezing + QApplication::processEvents(QEventLoop::AllEvents,10); + } + + return model_cleared; +} + +int PlayListModel::firstSelectedUpper(int row) +{ + for (int i = row - 1;i >= 0;i--) + { + if (isSelected(i)) + return i; + } + return -1; +} + +int PlayListModel::firstSelectedLower(int row) +{ + for (int i = row + 1;i < count() ;i++) + { + if (isSelected(i)) + return i; + } + return -1; +} + +void PlayListModel::moveItems( int from, int to ) +{ + // Get rid of useless work + if (from == to) + return; + + QList<int> selected_rows = getSelectedRows(); + + if (! (bottommostInSelection(from) == INVALID_ROW || + from == INVALID_ROW || + topmostInSelection(from) == INVALID_ROW) + ) + { + if (from > to) + foreach(int i, selected_rows) + if (i + to - from < 0) + break; + else + m_files.move(i,i + to - from); + else + for (int i = selected_rows.count() - 1; i >= 0; i--) + if (selected_rows[i] + to -from >= m_files.count()) + break; + else + m_files.move(selected_rows[i],selected_rows[i] + to - from); + + m_current = m_files.indexOf(m_currentItem); + + emit listChanged(); + } +} + + + +int PlayListModel::topmostInSelection( int row) +{ + if ( row == 0) + return 0; + + for (int i = row - 1;i >= 0;i--) + { + if (isSelected(i)) + continue; + else + return i + 1; + } + return 0; +} + +int PlayListModel::bottommostInSelection( int row ) +{ + if (row >= m_files.count() - 1) + return row; + + for (int i = row + 1;i < count() ;i++) + { + if (isSelected(i)) + continue; + else + return i - 1; + } + return count() - 1; +} + +const SimpleSelection& PlayListModel::getSelection(int row ) +{ + m_selection.m_top = topmostInSelection( row ); + m_selection.m_anchor = row; + m_selection.m_bottom = bottommostInSelection( row ); + m_selection.m_selected_rows = getSelectedRows(); + return m_selection; +} + +QList<int> PlayListModel::getSelectedRows() const +{ + QList<int>selected_rows; + for (int i = 0;i<m_files.count();i++) + { + if (m_files[i]->isSelected()) + { + selected_rows.append(i); + } + } + return selected_rows; +} + +QList< MediaFile * > PlayListModel::getSelectedItems() const +{ + QList<MediaFile*>selected_items; + for (int i = 0;i<m_files.count();i++) + { + if (m_files[i]->isSelected()) + { + selected_items.append(m_files[i]); + } + } + return selected_items; +} + +void PlayListModel::addToQueue() +{ + QList<MediaFile*> selected_items = getSelectedItems(); + foreach(MediaFile* file,selected_items) + {/* + if (isQueued(file)) + m_queued_songs.removeAt(m_queued_songs.indexOf(file)); + else + m_queued_songs.append(file); + */ + setQueued(file); + } + emit listChanged(); +} + +void PlayListModel::setQueued(MediaFile* file) +{ + if (isQueued(file)) + m_queued_songs.removeAt(m_queued_songs.indexOf(file)); + else + m_queued_songs.append(file); + + emit listChanged(); +} + +bool PlayListModel::isQueued(MediaFile* f) const +{ + return m_queued_songs.contains(f); +} + +void PlayListModel::setCurrentToQueued() +{ + setCurrent(row(m_queued_songs.at(0))); + m_queued_songs.pop_front(); +} + +bool PlayListModel::isEmptyQueue() const +{ + return m_queued_songs.isEmpty(); +} + +void PlayListModel::randomizeList() +{ + for (int i = 0;i < m_files.size();i++) + m_files.swap(qrand()%m_files.size(),qrand()%m_files.size()); + + m_current = m_files.indexOf(m_currentItem); + emit listChanged(); +} + +void PlayListModel::reverseList() +{ + for (int i = 0;i < m_files.size()/2;i++) + m_files.swap(i,m_files.size() - i - 1); + + m_current = m_files.indexOf(m_currentItem); + emit listChanged(); +} + +////===============THE BEGINNING OF SORT IMPLEMENTATION =======================//// + +// First we'll implement bundle of static compare procedures +// to sort items in different ways +static bool _titleLessComparator(MediaFile* s1,MediaFile* s2) +{ + return s1->title() < s2->title(); +} + +static bool _titleGreaterComparator(MediaFile* s1,MediaFile* s2) +{ + return s1->title() > s2->title(); +} + +static bool _pathAndFilenameLessComparator(MediaFile* s1,MediaFile* s2) +{ + return s1->path() < s2->path(); +} + +static bool _pathAndFilenameGreaterComparator(MediaFile* s1,MediaFile* s2) +{ + return s1->path() > s2->path(); +} + +static bool _filenameLessComparator(MediaFile* s1,MediaFile* s2) +{ + QFileInfo i_s1(s1->path()); + QFileInfo i_s2(s2->path()); + return i_s1.baseName() < i_s2.baseName(); +} + +static bool _filenameGreaterComparator(MediaFile* s1,MediaFile* s2) +{ + QFileInfo i_s1(s1->path()); + QFileInfo i_s2(s2->path()); + return i_s1.baseName() > i_s2.baseName(); +} + +static bool _dateLessComparator(MediaFile* s1,MediaFile* s2) +{ + return s1->year() < s2->year(); +} + +static bool _dateGreaterComparator(MediaFile* s1,MediaFile* s2) +{ + return s1->year() > s2->year(); +} + +// This is main sort method +void PlayListModel::doSort(int sort_mode,QList<MediaFile*>& list_to_sort) +{ + QList<MediaFile*>::iterator begin; + QList<MediaFile*>::iterator end; + + begin = list_to_sort.begin(); + end = list_to_sort.end(); + + bool (*compareLessFunc)(MediaFile*,MediaFile*) = 0; + bool (*compareGreaterFunc)(MediaFile*,MediaFile*) = 0; + + switch (sort_mode) + { + case TITLE: + compareLessFunc = _titleLessComparator; + compareGreaterFunc = _titleGreaterComparator; + break; + case FILENAME: + compareLessFunc = _filenameLessComparator; + compareGreaterFunc = _filenameGreaterComparator; + break; + case PATH_AND_FILENAME: + compareLessFunc = _pathAndFilenameLessComparator; + compareGreaterFunc = _pathAndFilenameGreaterComparator; + break; + case DATE: + compareLessFunc = _dateLessComparator; + compareGreaterFunc = _dateGreaterComparator; + break; + //qWarning("TODO Sort by Date: %s\t%d",__FILE__,__LINE__); + default: + compareLessFunc = _titleLessComparator; + compareGreaterFunc = _titleGreaterComparator; + } + + static bool sorted_asc = false; + if (!sorted_asc) + { + qSort(begin,end,compareLessFunc); + sorted_asc = true; + } + else + { + qSort(begin,end,compareGreaterFunc); + sorted_asc = false; + } + + m_current = m_files.indexOf(m_currentItem); +} + +void PlayListModel::sortSelection(int mode) +{ + QList<MediaFile*>selected_items = getSelectedItems(); + QList<int>selected_rows = getSelectedRows(); + + doSort(mode,selected_items); + + for (int i = 0;i < selected_rows.count();i++) + m_files.replace(selected_rows[i],selected_items[i]); + + m_current = m_files.indexOf(m_currentItem); + emit listChanged(); +} + +void PlayListModel::sort(int mode) +{ + doSort(mode,m_files); + emit listChanged(); +} + +////=============== THE END OF SORT IMPLEMENTATION =======================//// + +void PlayListModel::prepareForShufflePlaying(bool val) +{ + if (m_play_state) + delete m_play_state; + + if (val) + m_play_state = new ShufflePlayState(this); + else + m_play_state = new NormalPlayState(this); + +} + +void PlayListModel::prepareForRepeatablePlaying(bool val) +{ + is_repeatable_list = val; +} + +void PlayListModel::doCurrentVisibleRequest() +{ + emit currentChanged(); + emit listChanged(); +} + +void PlayListModel::setUpdatesEnabled(bool yes) +{ + if (yes) + { + m_block_update_signals = false; + emit listChanged(); + } + else + { + m_block_update_signals = true; + } +} + +void PlayListModel::loadPlaylist(const QString & f_name) +{ + + foreach(PlaylistFormat* prs,m_registered_pl_formats.values()) + { + if (prs->hasFormat(QFileInfo(f_name).completeSuffix().toLower())) + { + QFile file(f_name); + if (file.open(QIODevice::ReadOnly)) + { + clear(); + addFiles(prs->decode(QTextStream(&file).readAll())); + file.close(); + } + else + qWarning("Error opening %s",f_name.toLocal8Bit().data()); + } + } +} + +void PlayListModel::savePlaylist(const QString & f_name) +{ + foreach(PlaylistFormat* prs,m_registered_pl_formats.values()) + { + if (prs->hasFormat(QFileInfo(f_name).completeSuffix().toLower())) + { + QFile file(f_name); + if (file.open(QIODevice::WriteOnly)) + { + QTextStream ts(&file); + ts << prs->encode(m_files); + file.close(); + } + else + qWarning("Error opening %s",f_name.toLocal8Bit().data()); + } + } +} + + +void PlayListModel::loadExternalPlaylistFormats() +{ + QDir pluginsDir (QDir::homePath()+"/.qmmp/plugins/PlaylistFormats"); + //pluginsDir.cdUp(); + //pluginsDir.cd("plugins/PlaylistFormats"); + foreach (QString fileName, pluginsDir.entryList(QDir::Files)) + { + QPluginLoader loader(pluginsDir.absoluteFilePath(fileName)); + QObject *plugin = loader.instance(); + if (loader.isLoaded()) + qDebug("PlaylistFormat: plugin loaded - %s", qPrintable(fileName)); + + PlaylistFormat *fmt = 0; + if (plugin) + fmt = qobject_cast<PlaylistFormat *>(plugin); + + if (fmt) + if (!registerPlaylistFormat(fmt)) + qDebug("Warning: Plugin with name %s is already registered...", + qPrintable(fmt->name())); + } +} + +bool PlayListModel::registerPlaylistFormat(PlaylistFormat* p) +{ + QString name = p->name(); + if (!m_registered_pl_formats.contains(name)) + { + m_registered_pl_formats.insert(name,p); + return true; + } + return false; +} + +bool PlayListModel::isFileLoaderRunning() const +{ + foreach(FileLoader* l,m_running_loaders) + if (l && l->isRunning()) + return TRUE; + + return FALSE; +} + +void PlayListModel::preparePlayState() +{ + m_play_state->prepare(); +} + + + + + + + + + + + + + + diff --git a/src/ui/playlistmodel.h b/src/ui/playlistmodel.h new file mode 100644 index 000000000..b3ac19c04 --- /dev/null +++ b/src/ui/playlistmodel.h @@ -0,0 +1,377 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef PLAYLISTMODEL_H +#define PLAYLISTMODEL_H + +#include <QObject> +#include <QString> +#include <QStringList> +#include <QMap> +#include <QPointer> +#include <QVector> + +//#include "fileloader.h" +class FileLoader; + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + +class MediaFile; +class PlayState; +class PlaylistFormat; +class PlayListModel; + +struct SimpleSelection +{ + SimpleSelection() + { + ; + } + inline bool isValid()const + { + return (m_bottom != -1) && (m_anchor != -1) && (m_top != -1); + } + inline void dump()const + { + qWarning("top: %d\tbotom: %d\tanchor: %d",m_top,m_bottom,m_anchor); + } + inline int count()const + { + return m_bottom - m_top + 1; + } + int m_bottom; + int m_top; + int m_anchor; + QList<int>m_selected_rows; +}; + +/*! + * Helper class used for tags update after details dialog closing. + * @author Vladimir Kuznetsov <vovanec@gmail.com> + */ +class TagUpdater : public QObject +{ + Q_OBJECT + QObject* m_observable; + MediaFile* m_file; +public: + TagUpdater(QObject* o,MediaFile* f); +protected slots: + void updateTag(); +}; + + +class PlayListModel : public QObject +{ + Q_OBJECT +public: + PlayListModel(QObject *parent = 0); + + ~PlayListModel(); + + int count(); + MediaFile* currentItem(); + int row(MediaFile* f)const + { + return m_files.indexOf(f); + } + MediaFile* item(int row)const + { + return m_files.at(row); + } + int currentRow(); + bool setCurrent (int); + bool isSelected(int); + void setSelected(int, bool); + + bool next(); + bool previous(); + + QList <QString> getTitles(int,int); + QList <QString> getTimes(int,int); + + void moveItems(int from,int to); + + /*! + * Returns \b true if \b f file is in play queue, else return \b false + */ + bool isQueued(MediaFile* f) const; + + bool isRepeatableList()const + { + return is_repeatable_list; + } + + /*! + * Sets current song to the file that is nex in queue, if queue is empty - does nothing + */ + void setCurrentToQueued(); + + /*! + * Returns \b true if play queue is empty,otherwise - \b false. + */ + bool isEmptyQueue()const; + + /*! + * Returns index of \b f file in queue.e + */ + int queuedIndex(MediaFile* f)const + { + return m_queued_songs.indexOf(f); + } + + /*! + * Returns current selection(playlist can contain a lot of selections, + * this method returns selection which \b row belongs to) + */ + const SimpleSelection& getSelection(int row); + + /*! + * Returns vector with selected rows indexes. + */ + QList<int> getSelectedRows()const; + /*! + * Returns vector of \b MediaFile pointers that are selected. + */ + QList<MediaFile*> getSelectedItems()const; + + QList<MediaFile*> items()const + { + return m_files; + } + + /*! + * Returns number of first item that selected upper the \b row item. + */ + int firstSelectedUpper(int row); + + /*! + * Returns number of first item that selected lower the \b row item. + */ + int firstSelectedLower(int row); + + /*! + * Returns total lenght in seconds of all songs. + */ + int totalLength()const + { + return m_total_length; + } + + /*! + * Registers playlist format parser. + */ + bool registerPlaylistFormat(PlaylistFormat* p); + + /*! + * Checks and loads external playlist format plugins + */ + void loadExternalPlaylistFormats(); + + /*! + * Returns vector of reistered format parsers. + */ + const QList<PlaylistFormat*> registeredPlaylistFormats()const + { + return m_registered_pl_formats.values(); + } + + const QStringList registeredPlaylistFormatNames()const + { + return m_registered_pl_formats.keys(); + } + + /*! + * Loads playlist with \b f_name name. + */ + void loadPlaylist(const QString& f_name); + + /*! + * Saves current songs to the playlist with \b f_name name. + */ + void savePlaylist(const QString& f_name); + + /*! + * Enum of available sort modes + */ + enum SortMode + { + TITLE,FILENAME,PATH_AND_FILENAME,DATE + }; + +signals: + void listChanged(); + void currentChanged(); + +public slots: + void load(MediaFile *); + void clear(); + void clearSelection(); + void removeSelected(); + void removeUnselected(); + void invertSelection(); + void selectAll(); + void showDetails(); + void doCurrentVisibleRequest(); + + void addFile(const QString&); + + /*! + * Adds the list \b l of files to the model. + */ + void addFiles(const QStringList& l); + + /*! + * Adds \b dir to the model. + */ + void addDirectory(const QString& dir); + + /*! + * Loads list of files (regular files or directories), + * returns \b TRUE if at least one file has been successfully loaded, + * otherwise \b FALSE + */ + bool setFileList(const QStringList&); + + void addFileList(const QStringList &l); + + void randomizeList(); + void reverseList(); + + /*! + * Prepares model for shuffle playing. \b yes parameter is true - model iterates in shuffle mode. + */ + void prepareForShufflePlaying(bool yes); + + /*! + * Prepares model for shuffle playing. \b yes parameter is true - model iterates in repeat mode. + */ + void prepareForRepeatablePlaying(bool); + + /*! + * Sorts selected items in \b mode sort mode. + */ + void sortSelection(int mode); + + /*! + * Sorts items in \b mode sort mode. + */ + void sort(int mode); + + /*! + * Adds selected items to play queue. + */ + void addToQueue(); + + /*! + * Sets \b f media file to queue. + */ + void setQueued(MediaFile* f); + + void preparePlayState(); + +private: + + /*! + * This internal method performs sorting of \b list_to_sort list of items. + */ + void doSort(int mode,QList<MediaFile*>& list_to_sort); + /*! + * Returns topmost row in current selection + */ + int topmostInSelection(int); + + /*! + * Returns bottommost row in current selection + */ + int bottommostInSelection(int); + + /*! + * Creates and initializes file loader object. + */ + FileLoader* createFileLoader(); + + + /*! + * Is someone of file loaders is running? + */ + bool isFileLoaderRunning()const; + + /*! + * Removes items from model. If \b inverted is \b false - + * selected items will be removed, else - unselected. + */ + void removeSelection(bool inverted = false); + +private: + + QList <MediaFile*> m_files; + QList <MediaFile*> m_editing_files; + MediaFile* m_currentItem; + + int m_current; + void readSettings(); + void writeSettings(); + + void setUpdatesEnabled(bool); + + bool updatesEnabled()const + { + return !m_block_update_signals; + } + + /*! + * This flyweight object represents current selection. + */ + SimpleSelection m_selection; + + /*! + * Songs in play queue. + */ + QList<MediaFile*>m_queued_songs; + + QMap<QString,PlaylistFormat* > m_registered_pl_formats; + + /*! + * Is playlist repeatable? + */ + bool is_repeatable_list; + + /// Current playing state (Normal or Shuffle) + PlayState* m_play_state; + + bool m_block_update_signals; + + int m_total_length; + + typedef QPointer<FileLoader> GuardedFileLoader; + + /*! Vector of currently running file loaders. + * All loaders are automatically sheduled for deletion + * when finished. + */ + QVector<GuardedFileLoader> m_running_loaders; + + friend class MainWindow; +}; + + +#endif diff --git a/src/ui/playlistslider.cpp b/src/ui/playlistslider.cpp new file mode 100644 index 000000000..098b3bcee --- /dev/null +++ b/src/ui/playlistslider.cpp @@ -0,0 +1,135 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QPainter> +#include <QResizeEvent> +#include <math.h> + +#include "skin.h" +#include "playlistslider.h" +#include "pixmapwidget.h" + +PlayListSlider::PlayListSlider(QWidget *parent) + : QWidget(parent) +{ + m_skin = Skin::getPointer(); + + m_moving = FALSE; + m_pressed = FALSE; + m_min = 0; + m_max = 0; + m_value = 0; + pos = 0; + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); +} + + +PlayListSlider::~PlayListSlider() +{} + +void PlayListSlider::paintEvent(QPaintEvent *) +{ + int sy = (height()-58)/29; + int p=int(ceil(double(m_value-m_min)*(height()-18)/(m_max-m_min))); + QPainter paint(this); + paint.drawPixmap(0,0,m_skin->getPlPart(Skin::PL_RFILL)); + paint.drawPixmap(0,29,m_skin->getPlPart(Skin::PL_RFILL)); + + for (int i = 0; i<sy; i++) + { + paint.drawPixmap(0,58+i*29,m_skin->getPlPart(Skin::PL_RFILL)); + } + if (m_pressed) + paint.drawPixmap(5,p,m_skin->getButton(Skin::PL_BT_SCROLL_P)); + else + paint.drawPixmap(5,p,m_skin->getButton(Skin::PL_BT_SCROLL_N)); + m_pos = p; +} + +void PlayListSlider::mousePressEvent(QMouseEvent *e) +{ + + m_moving = TRUE; + press_pos = e->y(); + if (m_pos<e->y() && e->y()<m_pos+18) + { + press_pos = e->y()-m_pos; + } + else + { + m_value = convert(qMax(qMin(height()-18,e->y()-9),0)); + press_pos = 9; + if (m_value!=m_old) + { + emit sliderMoved(m_value); + m_old = m_value; + //qDebug ("%d",m_value); + } + } + m_pressed = TRUE; + update(); +} + +void PlayListSlider::mouseReleaseEvent(QMouseEvent*) +{ + m_moving = FALSE; + m_pressed = FALSE; + update(); +} + +void PlayListSlider::mouseMoveEvent(QMouseEvent* e) +{ + if (m_moving) + { + int po = e->y(); + po = po - press_pos; + + if (0<=po && po<=height()-18) + { + m_value = convert(po); + update(); + if (m_value!=m_old) + { + + m_old = m_value; + emit sliderMoved(m_value); + } + } + } +} + +void PlayListSlider::setPos(int p, int max) +{ + m_max = max; + m_value = p; + if(m_moving) + return; + update(); +} + +void PlayListSlider::updateSkin() +{ + update(); +} + +int PlayListSlider::convert(int p) +{ + return int(floor(double(m_max-m_min)*(p)/(height()-18)+m_min)); +} + diff --git a/src/ui/playlistslider.h b/src/ui/playlistslider.h new file mode 100644 index 000000000..a8eb45c66 --- /dev/null +++ b/src/ui/playlistslider.h @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef PLAYLISTSLIDER_H +#define PLAYLISTSLIDER_H + +#include <QWidget> + +class Skin; +class PixmapWidget; +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class PlayListSlider : public QWidget +{ +Q_OBJECT +public: + PlayListSlider(QWidget *parent = 0); + + ~PlayListSlider(); + +public slots: + void setPos(int pos, int max); + +signals: + void sliderMoved (int); + +private slots: + void updateSkin(); + +private: + Skin *m_skin; + PixmapWidget *m_scroll; + int m_old; + bool m_moving, m_pressed; + int press_pos; + int m_min, m_max, m_value, pos, m_pos; + int convert(int); // value = convert(position); + +protected: + void paintEvent(QPaintEvent*); + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); +}; + +#endif diff --git a/src/ui/playlisttitlebar.cpp b/src/ui/playlisttitlebar.cpp new file mode 100644 index 000000000..a583065ca --- /dev/null +++ b/src/ui/playlisttitlebar.cpp @@ -0,0 +1,284 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QPainter> +#include <QResizeEvent> +#include <QMenu> +#include <QSettings> + +#include "dock.h" +#include "button.h" +#include "playlistmodel.h" +#include "playlisttitlebar.h" +#include "skin.h" + +PlayListTitleBar::PlayListTitleBar(QWidget *parent) + : PixmapWidget(parent) +{ + m_active = FALSE; + m_resize = FALSE; + m_shade2 = 0; + m_model = 0; + m_shaded = FALSE; + m_align = FALSE; + m_skin = Skin::getPointer(); + setSizeIncrement(25,1); + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); + m_pl = qobject_cast<PlayList*>(parent); + m_mw = qobject_cast<MainWindow*>(m_pl->parent()); + + m_close = new Button(this,Skin::PL_BT_CLOSE_N, Skin::PL_BT_CLOSE_P); + connect (m_close, SIGNAL(clicked()), m_pl, SIGNAL(closed())); + m_close->move(264,3); + m_shade = new Button(this, Skin::PL_BT_SHADE1_N, Skin::PL_BT_SHADE1_P); + connect(m_shade, SIGNAL(clicked()), SLOT(shade())); + m_shade->move(255,3); + resize(275,20); + setMinimumWidth(275); + readSettings(); + QSettings settings (QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat); + m_pl->resize (settings.value ("PlayList/size", QSize (275, 116)).toSize()); + if (settings.value ("PlayList/shaded", FALSE).toBool()) + shade(); + resize(m_pl->width(),height()); + m_align = TRUE; +} + + +PlayListTitleBar::~PlayListTitleBar() +{ + QSettings settings (QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat); + settings.setValue ("PlayList/size", QSize (m_pl->width(), m_shaded ? m_height:m_pl->height())); + settings.setValue ("PlayList/shaded", m_shaded); +} + +void PlayListTitleBar::drawPixmap(int sx) +{ + m_close->move(264+sx*25,3); + m_shade->move(255+sx*25,3); + if (m_shade2) + m_shade2->move(255+sx*25,3); + QPixmap pixmap(275+sx*25,20); + pixmap.fill("black"); + QPainter paint; + paint.begin(&pixmap); + if (m_shaded) + { + paint.drawPixmap(0,0,m_skin->getPlPart(Skin::PL_TITLEBAR_SHADED2)); + for (int i = 1; i<sx+9; i++) + { + paint.drawPixmap(25*i,0,m_skin->getPlPart(Skin::PL_TFILL_SHADED)); + } + } + + if (m_active) + { + if (m_shaded) + { + m_shade2->show(); + paint.drawPixmap(225+sx*25,0,m_skin->getPlPart(Skin::PL_TITLEBAR_SHADED1_A)); + } + else + { + paint.drawPixmap(0,0,m_skin->getPlPart(Skin::PL_CORNER_UL_A)); + for (int i = 1; i<sx+10; i++) + { + paint.drawPixmap(25*i,0,m_skin->getPlPart(Skin::PL_TFILL1_A)); + } + paint.drawPixmap(100-12+12*sx,0,m_skin->getPlPart(Skin::PL_TITLEBAR_A)); + paint.drawPixmap(250+sx*25,0,m_skin->getPlPart(Skin::PL_CORNER_UR_A)); + m_close->show(); + m_shade->show(); + } + } + else + { + if (m_shaded) + { + m_shade2->hide(); + paint.drawPixmap(275-50+sx*25,0,m_skin->getPlPart(Skin::PL_TITLEBAR_SHADED1_I)); + } + else + { + paint.drawPixmap(0,0,m_skin->getPlPart(Skin::PL_CORNER_UL_I)); + for (int i = 1; i<sx+10; i++) + { + paint.drawPixmap(25*i,0,m_skin->getPlPart(Skin::PL_TFILL1_I)); + } + paint.drawPixmap(100-12+12*sx,0,m_skin->getPlPart(Skin::PL_TITLEBAR_I)); + paint.drawPixmap(250+sx*25,0,m_skin->getPlPart(Skin::PL_CORNER_UR_I)); + m_close->hide(); + m_shade->hide(); + } + } + if (m_shaded) + { + //draw text background + for (int i = 0; i < 47 + sx*5; ++i) + { + paint.drawPixmap(8+i*5,2,m_skin->getLetter(' ')); + paint.drawPixmap(8+i*5,6,m_skin->getLetter(' ')); + } + //draw text + paint.setFont(m_font); + paint.setPen(QString(m_skin->getPLValue("normal"))); + paint.drawText(9, 11, m_truncatedText); + } + paint.end(); + setPixmap(pixmap); +} + +void PlayListTitleBar::resizeEvent(QResizeEvent *e) +{ + truncate(); + drawPixmap((e->size().width()-275)/25); +} + +void PlayListTitleBar::mousePressEvent(QMouseEvent* event) +{ + switch ((int) event->button ()) + { + case Qt::LeftButton: + { + pos = event->pos(); + + if (m_shaded && (width() - 30) < pos.x() && pos.x() < (width() - 22)) + { + m_resize = TRUE; + m_pl->setCursor (Qt::SizeHorCursor); + } + + + break; + } + case Qt::RightButton: + { + m_mw->menu()->exec(event->globalPos()); + } + } +} + +void PlayListTitleBar::mouseReleaseEvent(QMouseEvent*) +{ + Dock::getPointer()->updateDock(); + m_resize = FALSE; + m_pl->setCursor (Qt::ArrowCursor); +} + +void PlayListTitleBar::mouseMoveEvent(QMouseEvent* event) +{ + QPoint npos = (event->globalPos()-pos); + QPoint oldpos = npos; + if (m_shaded && m_resize) + { + m_pl->resize((event->x() + 25), m_pl->height()); + resize((event->x() + 25), height()); + } + else + Dock::getPointer()->move(m_pl, npos); +} + +void PlayListTitleBar::setActive(bool a) +{ + m_active = a; + drawPixmap((width()-275)/25); +} + + +void PlayListTitleBar::setModel(PlayListModel *model) +{ + m_model = model; + connect (m_model, SIGNAL(listChanged()), SLOT(showCurrent())); +} + +void PlayListTitleBar::readSettings() +{ + QSettings settings (QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat); + QString fontname = settings.value("PlayList/Font","").toString(); + if (fontname.isEmpty ()) + fontname = QFont("Helvetica [Cronyx]", 8).toString(); + m_font.fromString(fontname); + m_font.setPointSize(8); +} + +void PlayListTitleBar::updateSkin() +{ + drawPixmap((width()-275)/25); +} + +void PlayListTitleBar::shade() +{ + m_shaded = !m_shaded; + + if (m_shaded) + { + m_height = m_pl->height(); + m_pl->setFixedHeight(14); + m_shade->hide(); + m_shade2 = new Button(this, Skin::PL_BT_SHADE2_N, Skin::PL_BT_SHADE2_P); + m_shade2->move(254,3); + connect(m_shade2, SIGNAL(clicked()), SLOT(shade())); + m_shade2->show(); + } + else + { + m_pl->setMinimumSize (275,116); + m_pl->setMaximumSize (10000,10000); + m_pl->resize(width(),m_height); + delete m_shade2; + m_shade2 = 0; + m_shade->show(); + } + showCurrent(); + update(); + if (m_align) + Dock::getPointer()->align(m_pl, m_shaded? -m_height+14: m_height-14); +} + +void PlayListTitleBar::showCurrent() +{ + if (m_model) + { + MediaFile* info = m_model->currentItem(); + if (info) + { + m_text = QString("%1. ").arg(m_model->currentRow()+1); + m_text.append(info->title()); + m_text.append(QString(" (%1:%2)").arg(info->length()/60).arg(info->length()%60)); + } + else + m_text.clear(); + } + truncate(); + drawPixmap((width()-275)/25); +} + +void PlayListTitleBar::truncate() +{ + m_truncatedText = m_text; + QFontMetrics metrics(m_font); + bool truncate = FALSE; + while (metrics.width(m_truncatedText) > (this->width() - 35)) + { + truncate = TRUE; + m_truncatedText = m_truncatedText.left(m_truncatedText.length()-1); + } + if (truncate) + m_truncatedText = m_truncatedText.left(m_truncatedText.length()-3).trimmed()+"..."; +} diff --git a/src/ui/playlisttitlebar.h b/src/ui/playlisttitlebar.h new file mode 100644 index 000000000..f50018371 --- /dev/null +++ b/src/ui/playlisttitlebar.h @@ -0,0 +1,78 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef PLAYLISTTITLEBAR_H +#define PLAYLISTTITLEBAR_H + +#include "playlist.h" +#include "pixmapwidget.h" +#include "mainwindow.h" + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class Skin; +class MainWindow; +class Button; +class PlayListModel; + +class PlayListTitleBar : public PixmapWidget +{ +Q_OBJECT +public: + PlayListTitleBar(QWidget *parent = 0); + + ~PlayListTitleBar(); + + void setActive(bool); + void setModel(PlayListModel *model); + void readSettings(); + +private slots: + void updateSkin(); + void shade(); + void showCurrent(); + +private: + void drawPixmap(int); + void truncate(); + Skin *m_skin; + QPoint pos; + bool m_active; + PlayList* m_pl; + MainWindow* m_mw; + Button* m_close; + Button* m_shade; + Button* m_shade2; + bool m_shaded; + bool m_align, m_resize; + int m_height; + PlayListModel* m_model; + QString m_text; + QString m_truncatedText; + QFont m_font; + +protected: + void resizeEvent(QResizeEvent*); + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); +}; + +#endif diff --git a/src/ui/playstate.cpp b/src/ui/playstate.cpp new file mode 100644 index 000000000..373619574 --- /dev/null +++ b/src/ui/playstate.cpp @@ -0,0 +1,138 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <playstate.h> + +ShufflePlayState::ShufflePlayState(PlayListModel * model) : PlayState(model) +{ + prepare(); +} + +bool ShufflePlayState::next() +{ + int itm_count = m_model->items().count(); + + if (itm_count > 0) + { + if (m_shuffled_current >= m_shuffled_indexes.count() -1 ) + { + if (!m_model->isRepeatableList()) + return FALSE; + else + prepare(); + } + + if (m_shuffled_current < m_shuffled_indexes.count() - 1)m_shuffled_current++; + + return m_model->setCurrent(m_shuffled_indexes.at(m_shuffled_current)); + } + return FALSE; +} + +bool ShufflePlayState::previous() +{ + int itm_count = m_model->items().count(); + + if (itm_count > 0) + { + if (m_shuffled_current <= 0) + { + if (!m_model->isRepeatableList()) + return FALSE; + else + { + prepare(); + m_shuffled_current = m_shuffled_indexes.count() - 1; + } + } + + if (itm_count > 1) m_shuffled_current --; + + m_model->setCurrent(m_shuffled_indexes.at(m_shuffled_current)); + return TRUE; + } + return FALSE; +} + +void ShufflePlayState::prepare() +{ + resetState(); + for (int i = 0;i < m_model->items().count();i++) + { + if (i != m_model->currentRow()) + m_shuffled_indexes << i; + } + + for (int i = 0;i < m_shuffled_indexes.count();i++) + m_shuffled_indexes.swap(qrand()%m_shuffled_indexes.size(),qrand()%m_shuffled_indexes.size()); + + m_shuffled_indexes.prepend(m_model->currentRow()); +} + +void ShufflePlayState::resetState() +{ + m_shuffled_indexes.clear(); + m_shuffled_current = 0; +} + + + + + +NormalPlayState::NormalPlayState(PlayListModel * model) : PlayState(model) +{} + + +bool NormalPlayState::next() +{ + int itm_count = m_model->items().count(); + + if (itm_count > 0) + { + if ( m_model->currentRow() == itm_count - 1) + { + if (m_model->isRepeatableList()) + return m_model->setCurrent(0); + else + return FALSE; + } + return m_model->setCurrent(m_model->currentRow() + 1); + } + else + return FALSE; +} + +bool NormalPlayState::previous() +{ + int itm_count = m_model->items().count(); + + if (itm_count > 0) + { + if ( m_model->currentRow() < 1 && !m_model->isRepeatableList()) + return FALSE; + else if (m_model->setCurrent(m_model->currentRow() - 1)) + return TRUE; + else if (m_model->isRepeatableList()) + return m_model->setCurrent(m_model->items().count() - 1); + } + + return FALSE; +} + diff --git a/src/ui/playstate.h b/src/ui/playstate.h new file mode 100644 index 000000000..e4af7fa6f --- /dev/null +++ b/src/ui/playstate.h @@ -0,0 +1,109 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _PLAYSTATE_H +#define _PLAYSTATE_H + +/** + @author Vladimir Kuznetsov <vovanec@gmail.com> + */ + +#include <playlistmodel.h> + +/*! + * Abstract class that represents data model playing states + */ +class PlayState +{ +public: + /*! Makes single step forward through songs list. + * If the step has done returns \b true, otherwise \b false + */ + virtual bool next() = 0; + + /*! Makes single step back through songs list. + * If the step has done returns \b true, otherwise \b false + */ + virtual bool previous() = 0; + + /*! + * Service method, resets state to it's defaults. + */ + virtual void resetState() + { + ; + }; + + /*! + * Service method, can be used for state initializing. + */ + virtual void prepare() + { + ; + } + virtual ~PlayState() + { + ; + } + PlayState(PlayListModel* model) : m_model(model) + { + ; + } +protected: + + /// Data model + PlayListModel* m_model; +}; + +/*! + * Represents normal playing state. + * @author Vladimir Kuznetsov <vovanec@gmail.com> + */ +class NormalPlayState : public PlayState +{ +public: + virtual bool next(); + virtual bool previous(); + NormalPlayState(PlayListModel* model); +}; + +/*! + * Represents shuffle playing state. + * @author Vladimir Kuznetsov <vovanec@gmail.com> + */ +class ShufflePlayState : public PlayState +{ +public: + virtual bool next(); + virtual bool previous(); + virtual void prepare(); + ShufflePlayState(PlayListModel* model); + virtual void resetState(); +private: + + /// Current shuffled index. + int m_shuffled_current; + + /// List of indexes used for shuffled playing. + QList<int> m_shuffled_indexes; +}; + + +#endif diff --git a/src/ui/playstatus.cpp b/src/ui/playstatus.cpp new file mode 100644 index 000000000..913199c4f --- /dev/null +++ b/src/ui/playstatus.cpp @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "skin.h" +#include "playstatus.h" + +PlayStatus::PlayStatus ( QWidget *parent ) + : PixmapWidget ( parent ) +{ + m_skin = Skin::getPointer(); + setStatus ( STOP ); + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); +} + + +PlayStatus::~PlayStatus() +{} + +void PlayStatus::setStatus ( Type st ) +{ + m_status = st; + switch ( ( uint ) st ) + { + case PLAY: + { + setPixmap ( m_skin->getItem ( Skin::PLAY )); + break; + } + case STOP: + { + setPixmap ( m_skin->getItem ( Skin::STOP )); + break; + } + case PAUSE: + { + setPixmap ( m_skin->getItem ( Skin::PAUSE )); + break; + } + } +} + +void PlayStatus::updateSkin() +{ + setStatus ( m_status ); +} + + diff --git a/src/ui/playstatus.h b/src/ui/playstatus.h new file mode 100644 index 000000000..b050de1ca --- /dev/null +++ b/src/ui/playstatus.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef PLAYSTATUS_H +#define PLAYSTATUS_H + +#include <pixmapwidget.h> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class Skin; + +class PlayStatus : public PixmapWidget +{ +Q_OBJECT +public: + PlayStatus(QWidget *parent = 0); + + ~PlayStatus(); + + enum Type + { + PLAY, + STOP, + PAUSE, + }; + +void setStatus(Type); + +private slots: + void updateSkin(); + +private: + Skin *m_skin; + Type m_status; +}; + +#endif diff --git a/src/ui/pluginitem.cpp b/src/ui/pluginitem.cpp new file mode 100644 index 000000000..2ccd8e41d --- /dev/null +++ b/src/ui/pluginitem.cpp @@ -0,0 +1,182 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QSettings> +#include <QDir> + +#include <decoderfactory.h> +#include <outputfactory.h> +#include <visualfactory.h> +#include <effectfactory.h> +#include <effect.h> +#include <soundcore.h> +#include <qmmpui/generalfactory.h> +#include <qmmpui/general.h> + +#include "pluginitem.h" + +/*Input*/ +InputPluginItem::InputPluginItem(QObject *parent, DecoderFactory *fact, + const QString &filePath) + : QObject(parent) +{ + m_fileName = filePath.section('/',-1); + m_factory = fact; +} + +InputPluginItem::~InputPluginItem() +{} + +bool InputPluginItem::isSelected() +{ + QSettings settings (QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat); + QStringList blacklist = settings.value("Decoder/disabled_plugins").toStringList(); + return !blacklist.contains(m_fileName); +} + +DecoderFactory* InputPluginItem::factory() +{ + return m_factory; +} + +void InputPluginItem::setSelected(bool select) +{ + QSettings settings (QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat); + QStringList blacklist = settings.value("Decoder/disabled_plugins").toStringList(); + if (select) + blacklist.removeAll (m_fileName); + else + blacklist.append (m_fileName); + settings.setValue("Decoder/disabled_plugins", blacklist); +} + +/*Output*/ +OutputPluginItem::OutputPluginItem(QObject *parent, OutputFactory *fact, + const QString &filePath): QObject(parent) +{ + m_fileName = filePath.section('/',-1); + m_factory = fact; +} + + +OutputPluginItem::~OutputPluginItem() +{} + +void OutputPluginItem::select() +{ + QSettings settings (QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat); + settings.setValue("Output/plugin_file", m_fileName); +} + +bool OutputPluginItem::isSelected() +{ + QSettings settings (QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat); + return m_fileName == settings.value("Output/plugin_file","libalsa.so").toString(); +} + +OutputFactory *OutputPluginItem::factory() +{ + return m_factory; +} + +/*Visual*/ +VisualPluginItem::VisualPluginItem(QObject *parent, VisualFactory *fact, + const QString &filePath): QObject(parent) +{ + m_fileName = filePath.section('/',-1); + m_factory = fact; +} + + +VisualPluginItem::~VisualPluginItem() +{} + +void VisualPluginItem::select(bool on) +{ + if(on) + SoundCore::instance()->addVisual(m_factory, 0); + else + SoundCore::instance()->removeVisual(m_factory); +} + +bool VisualPluginItem::isSelected() +{ + return Visual::isEnabled(m_factory); +} + +VisualFactory *VisualPluginItem::factory() +{ + return m_factory; +} + +/*Effect*/ +EffectPluginItem::EffectPluginItem(QObject *parent, EffectFactory *fact, + const QString &filePath): QObject(parent) +{ + m_fileName = filePath.section('/',-1); + m_factory = fact; +} + + +EffectPluginItem::~EffectPluginItem() +{} + +void EffectPluginItem::select(bool on) +{ + Effect::setEnabled(m_factory, on); +} + +bool EffectPluginItem::isSelected() +{ + return Effect::isEnabled(m_factory); +} + +EffectFactory *EffectPluginItem::factory() +{ + return m_factory; +} + +/*General*/ +GeneralPluginItem::GeneralPluginItem(QObject *parent, GeneralFactory *fact, + const QString &filePath): QObject(parent) +{ + m_fileName = filePath.section('/',-1); + m_factory = fact; +} + + +GeneralPluginItem::~GeneralPluginItem() +{} + +void GeneralPluginItem::select(bool on) +{ + General::setEnabled(m_factory, on); +} + +bool GeneralPluginItem::isSelected() +{ + return General::isEnabled(m_factory); +} + +GeneralFactory *GeneralPluginItem::factory() +{ + return m_factory; +} + diff --git a/src/ui/pluginitem.h b/src/ui/pluginitem.h new file mode 100644 index 000000000..8b3dc3b73 --- /dev/null +++ b/src/ui/pluginitem.h @@ -0,0 +1,132 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef PLUGINITEM_H +#define PLUGINITEM_H + +#include <QObject> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + +class DecoderFactory; +class OutputFactory; +class VisualFactory; +class EffectFactory; +class GeneralFactory; + +class InputPluginItem : public QObject +{ + Q_OBJECT +public: + InputPluginItem(QObject *parent, DecoderFactory *fact, const QString &filePath); + + ~InputPluginItem(); + + bool isSelected(); + DecoderFactory * factory(); + +public slots: + void setSelected(bool); + +private: + QString m_fileName; + DecoderFactory *m_factory; + +}; + +class OutputPluginItem : public QObject +{ + Q_OBJECT +public: + OutputPluginItem(QObject *parent, OutputFactory *fact, const QString &filePath); + + ~OutputPluginItem(); + + bool isSelected(); + OutputFactory * factory(); + +public slots: + void select(); + +private: + QString m_fileName; + OutputFactory *m_factory; + +}; + +class VisualPluginItem : public QObject +{ + Q_OBJECT +public: + VisualPluginItem(QObject *parent, VisualFactory *fact, const QString &filePath); + + ~VisualPluginItem(); + + bool isSelected(); + VisualFactory * factory(); + +public slots: + void select(bool); + +private: + QString m_fileName; + VisualFactory *m_factory; +}; + +class EffectPluginItem : public QObject +{ + Q_OBJECT +public: + EffectPluginItem(QObject *parent, EffectFactory *fact, const QString &filePath); + + ~EffectPluginItem(); + + bool isSelected(); + EffectFactory * factory(); + +public slots: + void select(bool); + +private: + QString m_fileName; + EffectFactory *m_factory; +}; + +class GeneralPluginItem : public QObject +{ + Q_OBJECT +public: + GeneralPluginItem(QObject *parent, GeneralFactory *fact, const QString &filePath); + + ~GeneralPluginItem(); + + bool isSelected(); + GeneralFactory * factory(); + +public slots: + void select(bool); + +private: + QString m_fileName; + GeneralFactory *m_factory; +}; + +#endif diff --git a/src/ui/positionbar.cpp b/src/ui/positionbar.cpp new file mode 100644 index 000000000..5431fd4f3 --- /dev/null +++ b/src/ui/positionbar.cpp @@ -0,0 +1,137 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QMouseEvent> +#include <QPainter> +#include <math.h> + +#include "skin.h" +#include "button.h" +#include "mainwindow.h" + +#include "positionbar.h" + + +PositionBar::PositionBar(QWidget *parent) + : PixmapWidget(parent) +{ + m_skin = Skin::getPointer(); + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); + setPixmap(m_skin->getPosBar()); + mw = qobject_cast<MainWindow*>(window()); + m_moving = FALSE; + m_min = 0; + m_max = 50; + m_old = m_value = 0; + draw(FALSE); +} + + +PositionBar::~PositionBar() +{} + +void PositionBar::mousePressEvent(QMouseEvent *e) +{ + + m_moving = TRUE; + press_pos = e->x(); + if(m_pos<e->x() && e->x()<m_pos+29) + { + press_pos = e->x()-m_pos; + } + else + { + m_value = convert(qMax(qMin(width()-30,e->x()-15),0)); + press_pos = 15; + if (m_value!=m_old) + { + emit sliderMoved(m_value); + + } + } + draw(); +} + +void PositionBar::mouseMoveEvent (QMouseEvent *e) +{ + if(m_moving) + { + int po = e->x(); + po = po - press_pos; + + if(0<=po && po<=width()-30) + { + m_value = convert(po); + draw(); + emit sliderMoved(m_value); + } + } +} + +void PositionBar::mouseReleaseEvent(QMouseEvent*) +{ + m_moving = FALSE; + draw(FALSE); + if (m_value!=m_old) + { + m_old = m_value; + mw->seek(m_value); + } + +} + +void PositionBar::setValue(int v) +{ + if (m_moving || m_max == 0) + return; + m_value = v; + draw(FALSE); +} + +void PositionBar::setMax(int max) +{ + m_max = max; + draw(FALSE); +} + +void PositionBar::updateSkin() +{ + draw(FALSE); + //setPixmap(m_skin->getPosBar()); + //setButtonPixmap(Skin::BT_POSBAR_N); +} + +void PositionBar::draw(bool pressed) +{ + int p=int(ceil(double(m_value-m_min)*(width()-30)/(m_max-m_min))); + m_pixmap = m_skin->getPosBar(); + QPainter paint(&m_pixmap); + if(pressed) + paint.drawPixmap(p,0,m_skin->getButton(Skin::BT_POSBAR_P)); + else + paint.drawPixmap(p,0,m_skin->getButton(Skin::BT_POSBAR_N)); + setPixmap(m_pixmap); + m_pos = p; +} + +int PositionBar::convert(int p) +{ + return int(ceil(double(m_max-m_min)*(p)/(width()-30)+m_min)); +} diff --git a/src/ui/positionbar.h b/src/ui/positionbar.h new file mode 100644 index 000000000..ea03ef14a --- /dev/null +++ b/src/ui/positionbar.h @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef POSITIONBAR_H +#define POSITIONBAR_H + +#include "pixmapwidget.h" + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + +class QMouseEvent; + +class MainWindow; +class Skin; + + +class PositionBar : public PixmapWidget +{ + Q_OBJECT +public: + PositionBar(QWidget *parent = 0); + + ~PositionBar(); + +public slots: + void setValue(int); + int value()const{return m_value;} + void setMax(int); + +signals: + void sliderMoved (int); + +private slots: + void updateSkin(); + +private: + Skin *m_skin; + bool m_moving; + int press_pos; + int m_max, m_min, m_pos, m_value, m_old; + QPixmap m_pixmap; + MainWindow *mw; + int convert(int); // value = convert(position); + void draw(bool pressed = TRUE); + +protected: + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + + +}; + +#endif diff --git a/src/ui/preseteditor.cpp b/src/ui/preseteditor.cpp new file mode 100644 index 000000000..1b55a229d --- /dev/null +++ b/src/ui/preseteditor.cpp @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "eqpreset.h" + +#include "preseteditor.h" + +PresetEditor::PresetEditor(QWidget *parent) + : QDialog(parent) +{ + ui.setupUi(this); + setAttribute(Qt::WA_DeleteOnClose); + connect(ui.loadButton,SIGNAL(clicked()),SLOT(loadPreset())); + connect(ui.deleteButton,SIGNAL(clicked()),SLOT(deletePreset())); +} + + +PresetEditor::~PresetEditor() +{ + while (ui.presetListWidget->count () !=0) + ui.presetListWidget->takeItem (0); + + while (ui.autoPresetListWidget->count () !=0) + ui.autoPresetListWidget->takeItem (0); +} + +void PresetEditor::addPresets(const QList<EQPreset*> &presets) +{ + foreach(QListWidgetItem *item, presets) + { + ui.presetListWidget->addItem(item); + } +} + +void PresetEditor::addAutoPresets(const QList<EQPreset*> &presets) +{ + foreach(QListWidgetItem *item, presets) + { + ui.autoPresetListWidget->addItem(item); + } +} + +void PresetEditor::loadPreset() +{ + EQPreset* preset = 0; + if (ui.tabWidget->currentIndex () == 0) + preset = (EQPreset *) ui.presetListWidget->currentItem (); + if (ui.tabWidget->currentIndex () == 1) + preset = (EQPreset *) ui.autoPresetListWidget->currentItem (); + if (preset) + emit presetLoaded(preset); +} + +void PresetEditor::deletePreset() +{ + EQPreset* preset = 0; + if (ui.tabWidget->currentIndex () == 0) + preset = (EQPreset *) ui.presetListWidget->currentItem (); + if (ui.tabWidget->currentIndex () == 1) + preset = (EQPreset *) ui.autoPresetListWidget->currentItem (); + if (preset) + emit presetDeleted(preset); +} diff --git a/src/ui/preseteditor.h b/src/ui/preseteditor.h new file mode 100644 index 000000000..35302b185 --- /dev/null +++ b/src/ui/preseteditor.h @@ -0,0 +1,57 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef PRESETEDITOR_H +#define PRESETEDITOR_H + +#include <QDialog> + +#include "ui_preseteditor.h" + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + +class EQPreset; + +class PresetEditor : public QDialog +{ +Q_OBJECT +public: + PresetEditor(QWidget *parent = 0); + + ~PresetEditor(); + + void addPresets(const QList<EQPreset*>&); + void addAutoPresets(const QList<EQPreset*>&); + +signals: + void presetLoaded(EQPreset*); + void presetDeleted(EQPreset*); + +private slots: + void loadPreset(); + void deletePreset(); + +private: + Ui::PresetEditor ui; + +}; + +#endif diff --git a/src/ui/qmmpstarter.cpp b/src/ui/qmmpstarter.cpp new file mode 100644 index 000000000..b04916983 --- /dev/null +++ b/src/ui/qmmpstarter.cpp @@ -0,0 +1,154 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QApplication> + +#include "unixdomainsocket.h" +#include <unistd.h> + +#include "mainwindow.h" +#include "version.h" +#include "qmmpstarter.h" +#include "commandlineoption.h" + +#define MAXCOMMANDSIZE 1024 + +QMMPStarter::QMMPStarter(int argc,char ** argv,QObject* parent) : QObject(parent),mw(NULL) +{ + m_option_manager = new CommandLineOptionManager(); + QStringList tmp; + for(int i = 1;i < argc;i++) + tmp << QString::fromLocal8Bit(argv[i]); + + argString = tmp.join("\n"); + + if(argString == "--help") + { + printUsage(); + exit(0); + } + else if(argString == "--version") + { + printVersion(); + exit(0); + } + + if(argString.startsWith("--") && // command? + !m_option_manager->hasOption(argString) + ) + { + qFatal("QMMP: Unknown command..."); + exit(1); + } + + m_sock = new UnixDomainSocket(this); + if(m_sock->bind(UDS_PATH)) + { + startMainWindow(); + } + else if(!m_sock->alive(UDS_PATH)){ + // Socket is present but not connectable - application was terminated previously??? + unlink(UDS_PATH); + if(m_sock->bind(UDS_PATH)) + { + startMainWindow(); + } + else + { + qDebug("Fatal socket error, exiting"); + exit(1); + } + } + else // socket is alive, qmmp application is already running. passing command to it! + writeCommand(); +} + +QMMPStarter::~ QMMPStarter() +{ + if(mw) delete mw; +} + +void QMMPStarter::startMainWindow() +{ + connect(m_sock, SIGNAL(readyRead()),this, SLOT(readCommand())); + QStringList arg_l = argString.split("\n", QString::SkipEmptyParts); + mw = new MainWindow(arg_l,m_option_manager,0); +} + +void QMMPStarter::writeCommand() +{ + if(!argString.isEmpty()) + { + char buf[PATH_MAX + 1]; + QString workingDir = QString(getcwd(buf,PATH_MAX)) + "\n"; + + QByteArray barray; + barray.append(workingDir); + barray.append(argString); + m_sock->writeDatagram ( barray.data(),UDS_PATH); + } + else + { + printUsage(); + } + + exit(0); +} + +void QMMPStarter::readCommand() +{ + QByteArray inputArray; + inputArray.resize(MAXCOMMANDSIZE); + bzero(inputArray.data(),inputArray.size()); + m_sock->readDatagram(inputArray.data(), inputArray.size()); + QStringList slist = QString(inputArray).split("\n",QString::SkipEmptyParts); + QString cwd = slist.takeAt(0); + if(mw) + { + mw->processCommandArgs(slist,cwd); + } + +} + +void QMMPStarter::printUsage() +{ + qWarning( + "Usage: qmmp [options] [files] \n" + "Options:\n" + "--------\n" + ); + for(int i = 0; i< m_option_manager->count();i++) + { + qWarning(qPrintable((*m_option_manager)[i]->helpString())); + } + qWarning( + "--help Display this text and exit.\n" + "--version Print version number and exit.\n\n" + "Ideas, patches, bugreports send to forkotov02@hotmail.ru\n" + ); +} + +void QMMPStarter::printVersion() +{ + qWarning("QMMP version: %s",QMMP_STR_VERSION); +} + + + diff --git a/src/ui/qmmpstarter.h b/src/ui/qmmpstarter.h new file mode 100644 index 000000000..010c5385f --- /dev/null +++ b/src/ui/qmmpstarter.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _QMMPSTARTER_H +#define _QMMPSTARTER_H + +#include <QObject> +#include <QAbstractSocket> +#include <QStringList> + +class UnixDomainSocket; +class MainWindow; +class CommandLineOptionManager; + +/*! + * QMMPStarter represents wrapper object that is responsible + * for proper QMMP initialization(only one instance of running + * MainWindow) and passing command line args to application. + * @author Vladimir Kuznetsov <vovanec@gmail.com> + */ +class QMMPStarter : public QObject +{ +Q_OBJECT +public: + QMMPStarter(int argc,char ** argv,QObject* parent = 0); + ~QMMPStarter(); +protected slots: + + /*! + * Passes command args to the running application + */ + void writeCommand(); + + void readCommand(); +private: + /*! + * Prints usage + */ + void printUsage(); + + /*! + * Prints version of program + */ + void printVersion(); + + void startMainWindow(); +private: + MainWindow* mw; + UnixDomainSocket* m_sock; + QString argString; + CommandLineOptionManager* m_option_manager; +}; + +#endif + + diff --git a/src/ui/shadedbar.cpp b/src/ui/shadedbar.cpp new file mode 100644 index 000000000..63b2017c0 --- /dev/null +++ b/src/ui/shadedbar.cpp @@ -0,0 +1,139 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QMouseEvent> +#include <QPainter> +#include <QPainter> +#include <math.h> + +#include "skin.h" + +#include "shadedbar.h" + +ShadedBar::ShadedBar(QWidget *parent, uint slider1, uint slider2, uint slider3) + : QWidget(parent) +{ + m_slider1 = slider1; + m_slider2 = slider2; + m_slider3 = slider3; + setFixedSize(97,7); + //setAutoFillBackground (TRUE); + m_skin = Skin::getPointer(); + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); + m_moving = FALSE; + m_min = 0; + m_max = 100; + m_old = m_value = 0; + draw(); +} + + +ShadedBar::~ShadedBar() +{ +} + +void ShadedBar::mousePressEvent(QMouseEvent *e) +{ + + m_moving = TRUE; + press_pos = e->x(); + if(m_pos<e->x() && e->x()<m_pos+3) + { + press_pos = e->x()-m_pos; + } + else + { + m_value = convert(qMax(qMin(width()-3,e->x()-1),0)); + press_pos = 1; + if (m_value!=m_old) + { + emit sliderMoved(m_value); + } + } + draw(); +} + +void ShadedBar::mouseMoveEvent (QMouseEvent *e) +{ + if(m_moving) + { + int po = e->x(); + po = po - press_pos; + + if(0<=po && po<=width()-3) + { + m_value = convert(po); + draw(); + emit sliderMoved(m_value); + qDebug("%d", m_value); + } + } +} + +void ShadedBar::mouseReleaseEvent(QMouseEvent*) +{ + m_moving = FALSE; + draw(); + m_old = m_value; +} + +void ShadedBar::setValue(int v) +{ + if (m_moving || m_max == 0) + return; + m_value = v; + draw(); +} + +void ShadedBar::setRange(int min, int max) +{ + m_max = max; + m_min = min; + draw(); +} + +void ShadedBar::updateSkin() +{ + draw(); +} + +void ShadedBar::draw() +{ + if (m_value <= m_min + (m_max - m_min)/3) + m_pixmap = m_skin->getEqPart(m_slider1); + else if(m_min + (m_max - m_min)/3 < m_value && m_value <= m_min + 2*(m_max - m_min)/3) + m_pixmap = m_skin->getEqPart(m_slider2); + else + m_pixmap = m_skin->getEqPart(m_slider3); + m_pos = int(ceil(double(m_value-m_min)*(width()-3)/(m_max-m_min))); + update(); +} + +int ShadedBar::convert(int p) +{ + return int(ceil(double(m_max-m_min)*(p)/(width()-3)+m_min)); +} + +void ShadedBar::paintEvent(QPaintEvent*) +{ + QPainter paint(this); + paint.drawPixmap(m_pos,0,m_pixmap); +} + diff --git a/src/ui/shadedbar.h b/src/ui/shadedbar.h new file mode 100644 index 000000000..4ea8c871f --- /dev/null +++ b/src/ui/shadedbar.h @@ -0,0 +1,77 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef SHADEDBAR_H +#define SHADEDBAR_H + +#include <QWidget> + +class QMouseEvent; +class QPaintEvent; + +class Skin; + + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class ShadedBar : public QWidget +{ + Q_OBJECT +public: + ShadedBar(QWidget *parent = 0, uint slider1 = 0, uint slider2 = 0, uint slider3 = 0); + + ~ShadedBar(); + int value() + { + return m_value; + }; + int isPressed() + { + return m_moving; + } + void setRange(int min, int max); + +public slots: + void setValue(int); + +signals: + void sliderMoved (int); + +private slots: + void updateSkin(); + +private: + Skin *m_skin; + bool m_moving; + int press_pos; + int m_max, m_min, m_pos, m_value, m_old, m_x; + QPixmap m_pixmap; + int convert(int); // value = convert(position); + void draw(); + uint m_slider1, m_slider2, m_slider3; + +protected: + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + void paintEvent(QPaintEvent*); +}; + +#endif diff --git a/src/ui/shadedvisual.cpp b/src/ui/shadedvisual.cpp new file mode 100644 index 000000000..2dea3d419 --- /dev/null +++ b/src/ui/shadedvisual.cpp @@ -0,0 +1,205 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QTimer> +#include <math.h> +#include "skin.h" +#include "mainvisual.h" +#include "inlines.h" + + +#include "shadedvisual.h" + +ShadedVisual::ShadedVisual(QWidget *parent) + : Visual(parent) +{ + setFixedSize(38,5); + m_pixmap = QPixmap (38,5); + m_skin = Skin::getPointer(); + m_timer = new QTimer(this); + connect(m_timer, SIGNAL (timeout()), this, SLOT (timeout())); + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); + m_timer->setInterval(50); + m_timer->start(); + clear(); +} + + +ShadedVisual::~ShadedVisual() +{} + +void ShadedVisual::add(Buffer *b, unsigned long w, int c, int p) +{ + if (!m_timer->isActive ()) + return; + long len = b->nbytes, cnt; + short *l = 0, *r = 0; + + len /= c; + len /= ( p / 8 ); + if ( len > 512 ) + len = 512; + cnt = len; + + if ( c == 2 ) + { + l = new short[len]; + r = new short[len]; + + if ( p == 8 ) + stereo16_from_stereopcm8 ( l, r, b->data, cnt ); + else if ( p == 16 ) + stereo16_from_stereopcm16 ( l, r, ( short * ) b->data, cnt ); + } + else if ( c == 1 ) + { + l = new short[len]; + + if ( p == 8 ) + mono16_from_monopcm8 ( l, b->data, cnt ); + else if ( p == 16 ) + mono16_from_monopcm16 ( l, ( short * ) b->data, cnt ); + } + else + len = 0; + + if (len) + m_nodes.append (new VisualNode (l, r, len, w)); +} + +void ShadedVisual::clear() +{ + while (!m_nodes.isEmpty()) + m_nodes.removeFirst(); + m_l = 0; + m_r = 0; + m_pixmap.fill(m_skin->getVisColor(0)); + update(); +}; + +void ShadedVisual::timeout() +{ + VisualNode *node = 0; + m_pixmap.fill(m_skin->getVisColor(0)); + + if ( /*playing &&*/ output()) + { + //output()->mutex()->lock (); + //long olat = output()->latency(); + //long owrt = output()->written(); + //output()->mutex()->unlock(); + + //long synctime = owrt < olat ? 0 : owrt - olat; + + mutex()->lock (); + VisualNode *prev = 0; + while ((!m_nodes.isEmpty())) + { + node = m_nodes.takeFirst(); + /*if ( node->offset > synctime ) + break;*/ + + if (prev) + delete prev; + prev = node; + } + mutex()->unlock(); + node = prev; + } + + if (!node) + return; + process (node); + delete node; + QPainter p(&m_pixmap); + draw (&p); + update(); +} + +void ShadedVisual::process (VisualNode *node) +{ + if (!node) + return; + + int step = (node->length << 8)/74; + int pos = 0; + int l = 0; + int r = 0; + int j_l = 0, j_r = 0; + + for (int i = 0; i < 75; ++i) + { + pos += step; + + if (node->left) + { + j_l = abs((node->left[pos >> 8] >> 12)); + + if (j_l > 15) + j_l = 15; + l = qMax(l, j_l); + } + if (node->right) + { + j_r = abs((node->right[pos >> 8] >> 12)); + if (j_r > 15) + j_r = 15; + r = qMax(r, j_r); + } + } + m_l -= 0.5; + m_l = m_l > l ? m_l : l; + m_r -= 0.5; + m_r = m_r > r ? m_r : r; +} + +void ShadedVisual::draw (QPainter *p) +{ + for (int i = 0; i < m_l; ++i) + { + p->fillRect (i*3, 0, 3, 2, QBrush(m_skin->getVisColor (17-i))); + } + for (int i = 0; i < m_r; ++i) + { + p->fillRect (i*3, 3, 3, 2, QBrush(m_skin->getVisColor (17-i))); + } +} + +void ShadedVisual::paintEvent (QPaintEvent *) +{ + QPainter painter (this); + painter.drawPixmap (0,0,m_pixmap); +} + +void ShadedVisual::hideEvent (QHideEvent *) +{ + m_timer->stop(); +} + +void ShadedVisual::showEvent (QShowEvent *) +{ + m_timer->start(); +} + +void ShadedVisual::updateSkin() +{ + clear(); +} + diff --git a/src/ui/shadedvisual.h b/src/ui/shadedvisual.h new file mode 100644 index 000000000..e46331ecb --- /dev/null +++ b/src/ui/shadedvisual.h @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef SHADEDVISUAL_H +#define SHADEDVISUAL_H + + +#include <QPainter> +#include <visual.h> +#include <buffer.h> + +class QTimer; +class QPixmap; + +class Skin; +class VisualNode; + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class ShadedVisual : public Visual +{ + Q_OBJECT +public: + ShadedVisual(QWidget *parent = 0); + + ~ShadedVisual(); + + void add(Buffer *, unsigned long, int, int); + void clear(); + + void paintEvent (QPaintEvent *); + void hideEvent (QHideEvent *); + void showEvent (QShowEvent *); + +public slots: + void timeout(); + +private slots: + void updateSkin(); + +private: + void process (VisualNode *node); + void draw (QPainter *); + Skin *m_skin; + QTimer *m_timer; + QPixmap m_pixmap; + QList <VisualNode*> m_nodes; + double m_l, m_r; + +}; + +#endif diff --git a/src/ui/skin.cpp b/src/ui/skin.cpp new file mode 100644 index 000000000..b7f787ad4 --- /dev/null +++ b/src/ui/skin.cpp @@ -0,0 +1,771 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QCoreApplication> +#include <QDir> +#include <QSettings> +#include <QPainter> +#include <QPolygon> +#include <QImage> + +#include "skin.h" + +Skin *Skin::pointer = 0; + +Skin *Skin::getPointer() +{ + if ( !pointer ) + pointer = new Skin(); + return pointer; +} + +QPixmap Skin::getPixmap ( const QString& name, QDir dir ) +{ + dir.setFilter ( QDir::Files | QDir::Hidden | QDir::NoSymLinks ); + QFileInfoList f = dir.entryInfoList(); + for ( int j = 0; j < f.size(); ++j ) + { + QFileInfo fileInfo = f.at ( j ); + QString fn = fileInfo.fileName().toLower(); + if ( fn.section ( ".",0,0 ) == name ) + { + return QPixmap ( fileInfo.filePath() ); + } + } + return QPixmap(); +} + +Skin::Skin ( QObject *parent ) + : QObject ( parent ) +{ + pointer = this; + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + QString path = settings.value("skin_path","").toString(); + if (path.isEmpty() || !QDir(path).exists ()) + path = ":/default"; + setSkin (QDir::cleanPath(path)); + /* skin directory */ + QDir skinDir(QDir::homePath()+"/.qmmp"); + skinDir.mkdir ("skins"); +} + + +Skin::~Skin() +{} + +void Skin::setSkin ( const QString& path ) +{ + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + settings.setValue("skin_path",path); + + qDebug ( path.toAscii() ); //TODO don't clear lists + m_skin_dir = QDir ( path ); + + m_pledit_txt.clear(); + loadPLEdit(); + loadMain(); + buttons.clear(); + loadButtons(); + loadShufRep(); + titlebar.clear(); + loadTitleBar(); + loadPosBar(); + m_numbers.clear(); + loadNumbers(); + m_pl_parts.clear(); + loadPlayList(); + m_eq_parts.clear(); + loadEq_ex(); + m_eq_bar.clear(); + m_eq_spline.clear(); + loadEqMain(); + m_vis_colors.clear(); + loadVisColor(); + loadLetters(); + loadMonoSter(); + loadVolume(); + loadBalance(); + loadRegion(); + loadColors(); + + emit skinChanged(); +} + +void Skin::loadMain() +{ + QPixmap *pixmap = getPixmap ("main"); + if (!pixmap) + pixmap = getDummyPixmap("main"); + + m_main = pixmap->copy ( 0,0,275,116 ); + delete pixmap; +} + +void Skin::loadButtons() +{ + + QPixmap *pixmap = getPixmap ("cbuttons"); + + if (!pixmap) + pixmap = getDummyPixmap("cbuttons"); + + buttons[BT_PREVIOUS_N] = pixmap->copy ( 0, 0,23,18 ); + buttons[BT_PREVIOUS_P] = pixmap->copy ( 0,18,23,18 ); + + buttons[BT_PLAY_N] = pixmap->copy ( 23, 0,23,18 ); + buttons[BT_PLAY_P] = pixmap->copy ( 23,18,23,18 ); + + buttons[BT_PAUSE_N] = pixmap->copy ( 46, 0,23,18 ); + buttons[BT_PAUSE_P] = pixmap->copy ( 46,18,23,18 ); + + buttons[BT_STOP_N] = pixmap->copy ( 69, 0,23,18 ); + buttons[BT_STOP_P] = pixmap->copy ( 69,18,23,18 ); + + buttons[BT_NEXT_N] = pixmap->copy ( 92, 0,22,18 ); + buttons[BT_NEXT_P] = pixmap->copy ( 92,18,22,18 ); + + buttons[BT_EJECT_N] = pixmap->copy ( 114, 0,22,16 ); + buttons[BT_EJECT_P] = pixmap->copy ( 114,16,22,16 ); + delete pixmap; + +} + +void Skin::loadTitleBar() +{ + + QPixmap *pixmap = getPixmap ("titlebar"); + + if (!pixmap) + pixmap = getDummyPixmap("titlebar"); + + buttons[BT_MENU_N] = pixmap->copy ( 0,0,9,9 ); + buttons[BT_MENU_P] = pixmap->copy ( 0,9,9,9 ); + buttons[BT_MINIMIZE_N] = pixmap->copy ( 9,0,9,9 ); + buttons[BT_MINIMIZE_P] = pixmap->copy ( 9,9,9,9 ); + buttons[BT_CLOSE_N] = pixmap->copy ( 18,0,9,9 ); + buttons[BT_CLOSE_P] = pixmap->copy ( 18,9,9,9 ); + buttons[BT_SHADE1_N] = pixmap->copy ( 0,18,9,9 ); + buttons[BT_SHADE1_P] = pixmap->copy ( 9,18,9,9 ); + buttons[BT_SHADE2_N] = pixmap->copy ( 0,27,9,9 ); + buttons[BT_SHADE2_P] = pixmap->copy ( 9,27,9,9 ); + titlebar[TITLEBAR_A] = pixmap->copy ( 27, 0,275,14 ); + titlebar[TITLEBAR_I] = pixmap->copy ( 27,15,275,14 ); + titlebar[TITLEBAR_SHADED_A] = pixmap->copy ( 27,29,275,14 ); + titlebar[TITLEBAR_SHADED_I] = pixmap->copy ( 27,42,275,14 ); + delete pixmap; + +} + +void Skin::loadPosBar() +{ + + QPixmap *pixmap = getPixmap ("posbar"); + + if (!pixmap) + pixmap = getDummyPixmap("posbar"); + + if (pixmap->width() > 249) + { + buttons[BT_POSBAR_N] = pixmap->copy ( 248,0,29, pixmap->height()); + buttons[BT_POSBAR_P] = pixmap->copy ( 278,0,29, pixmap->height()); + } + else + { + QPixmap dummy(29, pixmap->height()); + dummy.fill(Qt::transparent); + buttons[BT_POSBAR_N] = dummy; + buttons[BT_POSBAR_P] = dummy; + } + posbar = pixmap->copy ( 0,0,248,pixmap->height() ); + delete pixmap; + +} + +void Skin::loadNumbers() +{ + QPixmap *pixmap = getPixmap ( "numbers" ); + if ( !pixmap ) + { + pixmap = getPixmap ( "nums_ex" ); + } + for ( uint i = 0; i < 10; i++ ) + { + m_numbers << pixmap->copy ( i*9, 0, 9, 13 ); + } + if (pixmap->width() > 107) + { + m_numbers << pixmap->copy(99, 0, 9,13 ); + } + else + { // We didn't find "-" symbol. So we have to extract it from "2". + // Winamp uses this method too. + QPixmap pix = pixmap->copy(90,0,9,13); + QPixmap minus = pixmap->copy(18,6,9,1); + QPainter paint(&pix); + paint.drawPixmap(0,6, minus); + m_numbers << pix; + } + delete pixmap; +} + +void Skin::loadPlayList() +{ + + QPixmap *pixmap = getPixmap ("pledit"); + + if (!pixmap) + pixmap = getDummyPixmap("pledit"); + + m_pl_parts[PL_CORNER_UL_A] = pixmap->copy ( 0,0,25,20 ); + m_pl_parts[PL_CORNER_UL_I] = pixmap->copy ( 0,21,25,20 ); + + m_pl_parts[PL_CORNER_UR_A] = pixmap->copy ( 153,0,25,20 ); + m_pl_parts[PL_CORNER_UR_I] = pixmap->copy ( 153,21,25,20 ); + + m_pl_parts[PL_TITLEBAR_A] = pixmap->copy ( 26,0,100,20 ); + m_pl_parts[PL_TITLEBAR_I] = pixmap->copy ( 26,21,100,20 ); + + m_pl_parts[PL_TFILL1_A] = pixmap->copy ( 127,0,25,20 ); + m_pl_parts[PL_TFILL1_I] = pixmap->copy ( 127,21,25,20 ); + + //m_pl_parts[PL_TFILL2_A] = pixmap->copy();//FIXME: ����� + //m_pl_parts[PL_TFILL2_I] = pixmap->copy(); + + m_pl_parts[PL_LFILL] = pixmap->copy ( 0,42,12,29 ); + m_pl_parts[PL_RFILL] = pixmap->copy ( 31,42,20,29 ); //??? + + m_pl_parts[PL_LSBAR] = pixmap->copy ( 0,72,125,38 ); + m_pl_parts[PL_RSBAR] = pixmap->copy ( 126,72,150,38 ); + m_pl_parts[PL_SFILL1] = pixmap->copy ( 179,0,25,38 ); + m_pl_parts[PL_SFILL2] = pixmap->copy ( 250,21,75,38 ); + m_pl_parts[PL_TITLEBAR_SHADED1_A] = pixmap->copy ( 99,42,50,14 ); + m_pl_parts[PL_TITLEBAR_SHADED1_I] = pixmap->copy ( 99,57,50,14 ); + m_pl_parts[PL_TITLEBAR_SHADED2] = pixmap->copy ( 72,42,25,14 ); + m_pl_parts[PL_TFILL_SHADED] = pixmap->copy ( 72,57,25,14 ); + + m_pl_parts[PL_CONTROL] = pixmap->copy(129,94,60,8); + + buttons[PL_BT_ADD] = pixmap->copy ( 11,80,25,18 ); + buttons[PL_BT_SUB] = pixmap->copy ( 40,80,25,18 ); + buttons[PL_BT_SEL] = pixmap->copy ( 70,80,25,18 ); + buttons[PL_BT_SORT] = pixmap->copy ( 99,80,25,18 ); + buttons[PL_BT_LST] = pixmap->copy(229, 80, 25, 18); + buttons[PL_BT_SCROLL_N] = pixmap->copy ( 52,53,8,18 ); + buttons[PL_BT_SCROLL_P] = pixmap->copy ( 61,53,8,18 ); + + buttons[PL_BT_CLOSE_N] = pixmap->copy (167,3,9,9); + buttons[PL_BT_CLOSE_P] = pixmap->copy (52,42,9,9); + buttons[PL_BT_SHADE1_N] = pixmap->copy (158,3,9,9); + buttons[PL_BT_SHADE1_P] = pixmap->copy (62,42,9,9); + buttons[PL_BT_SHADE2_N] = pixmap->copy (129,45,9,9); + buttons[PL_BT_SHADE2_P] = pixmap->copy (150,42,9,9); + +} + +QPixmap *Skin::getPixmap ( const QString& name ) +{ + m_skin_dir.setFilter ( QDir::Files | QDir::Hidden | QDir::NoSymLinks ); + QFileInfoList f = m_skin_dir.entryInfoList(); + for ( int j = 0; j < f.size(); ++j ) + { + QFileInfo fileInfo = f.at ( j ); + QString fn = fileInfo.fileName().toLower(); + if ( fn.section ( ".",0,0 ) == name ) + { + return new QPixmap ( fileInfo.filePath() ); + } + } + return 0; +} + +void Skin::loadPLEdit() +{ + m_skin_dir.setFilter ( QDir::Files | QDir::Hidden | QDir::NoSymLinks ); + QString path; + QFileInfoList list = m_skin_dir.entryInfoList(); + for ( int i = 0; i < list.size(); ++i ) + { + QFileInfo fileInfo = list.at ( i ); + if ( fileInfo.fileName().toLower() == "pledit.txt" ) + { + path = fileInfo.filePath (); + break; + } + } + + if ( path.isNull () ) + { + qDebug ( "Skin: Cannot find pledit.txt" ); + return; + } + + + QFile file ( path ); + + if ( !file.open ( QIODevice::ReadOnly | QIODevice::Text ) ) + return; + + while ( !file.atEnd () ) + { + QByteArray line = file.readLine (); + QList<QByteArray> l = line.split ( '=' ); + if ( l.count () == 2 ) + { + m_pledit_txt[l[0].toLower () ] = l[1].trimmed(); + } + else if ( line.length() == 0 ) + { + break; + } + } + +} + +void Skin::loadEqMain() +{ + QPixmap *pixmap = getPixmap ("eqmain"); + + if (!pixmap) + pixmap = getDummyPixmap("eqmain"); + + m_eq_parts[ EQ_MAIN ] = pixmap->copy ( 0,0,275,116 ); + m_eq_parts[ EQ_TITLEBAR_A ] = pixmap->copy ( 0,134,275,14 ); + m_eq_parts[ EQ_TITLEBAR_I ] = pixmap->copy ( 0,149,275,14 ); + m_eq_parts[ EQ_GRAPH ] = pixmap->copy ( 0,294,113,19 ); + for ( int i = 0; i < 14; ++i ) + { + m_eq_bar << pixmap->copy ( 13 + i*15,164,14,63 ); + } + for ( int i = 0; i < 14; ++i ) + { + m_eq_bar << pixmap->copy ( 13 + i*15,229,14,63 ); + } + buttons[ EQ_BT_BAR_N ] = pixmap->copy ( 0,164,11,11 ); + buttons[ EQ_BT_BAR_P ] = pixmap->copy ( 0,164+12,11,11 ); + + buttons[ EQ_BT_ON_N ] = pixmap->copy ( 69,119,28,12 ); + buttons[ EQ_BT_ON_P ] = pixmap->copy ( 128,119,28,12 ); + buttons[ EQ_BT_OFF_N ] = pixmap->copy ( 10, 119,28,12 ); + buttons[ EQ_BT_OFF_P ] = pixmap->copy ( 187,119,28,12 ); + + buttons[ EQ_BT_PRESETS_N ] = pixmap->copy ( 224,164,44,12 ); + buttons[ EQ_BT_PRESETS_P ] = pixmap->copy ( 224,176,44,12 ); + + buttons[ EQ_BT_AUTO_1_N ] = pixmap->copy ( 94,119,33,12 ); + buttons[ EQ_BT_AUTO_1_P ] = pixmap->copy ( 153,119,33,12 ); + buttons[ EQ_BT_AUTO_0_N ] = pixmap->copy ( 35, 119,33,12 ); + buttons[ EQ_BT_AUTO_0_P ] = pixmap->copy ( 212,119,33,12 ); + + buttons[ EQ_BT_CLOSE_N ] = pixmap->copy ( 0,116,9,9 ); + buttons[ EQ_BT_CLOSE_P ] = pixmap->copy ( 0,125,9,9 ); + buttons[ EQ_BT_SHADE1_N ] = pixmap->copy ( 254,137,9,9 ); + + for ( int i = 0; i < 19; ++i ) + { + m_eq_spline << pixmap->copy ( 115, 294+i, 1, 1 ); + } + delete pixmap; + +} + +void Skin::loadEq_ex() +{ + QPixmap *pixmap = getPixmap ("eq_ex"); + + if (!pixmap) + pixmap = getDummyPixmap("eq_ex"); + + buttons[ EQ_BT_SHADE1_P ] = pixmap->copy (1,38,9,9); + buttons[ EQ_BT_SHADE2_N ] = pixmap->copy (254,3,9,9); + buttons[ EQ_BT_SHADE2_P ] = pixmap->copy (1,47,9,9); + m_eq_parts[ EQ_TITLEBAR_SHADED_A ] = pixmap->copy(0,0,275,14); + m_eq_parts[ EQ_TITLEBAR_SHADED_I ] = pixmap->copy(0,15,275,14); + m_eq_parts[ EQ_VOLUME1 ] = pixmap->copy(1,30,3,8); + m_eq_parts[ EQ_VOLUME2 ] = pixmap->copy(4,30,3,8); + m_eq_parts[ EQ_VOLUME3 ] = pixmap->copy(7,30,3,8); + m_eq_parts[ EQ_BALANCE1 ] = pixmap->copy(11,30,3,8); + m_eq_parts[ EQ_BALANCE2 ] = pixmap->copy(14,30,3,8); + m_eq_parts[ EQ_BALANCE3 ] = pixmap->copy(17,30,3,8); + + delete pixmap; +} + +void Skin::loadVisColor() +{ + //QList <QColor> colors; + m_skin_dir.setFilter ( QDir::Files | QDir::Hidden | QDir::NoSymLinks ); + QString path; + QFileInfoList list = m_skin_dir.entryInfoList(); + for ( int i = 0; i < list.size(); ++i ) + { + QFileInfo fileInfo = list.at ( i ); + if ( fileInfo.fileName().toLower() == "viscolor.txt" ) + { + path = fileInfo.filePath (); + break; + } + } + + if ( path.isNull () ) + { + qDebug ( "Skin: Cannot find viscolor.txt" ); + return; + } + + + QFile file ( path ); + + if ( !file.open ( QIODevice::ReadOnly | QIODevice::Text ) ) + return; + + int j = 0; + while ( !file.atEnd () && j<24 ) + { + j++; + QByteArray line = file.readLine (); + QString tmp = QString::fromAscii ( line ); + tmp = tmp.trimmed (); + int i = tmp.indexOf ( "//" ); + if ( i>0 ) + tmp.truncate ( tmp.indexOf ( "//" ) ); + QStringList list = tmp.split ( "," ); + if ( list.count () >= 3 ) + { + //colors + int r = list.at ( 0 ).toInt(); + int g = list.at ( 1 ).toInt(); + int b = list.at ( 2 ).toInt(); + m_vis_colors << QColor ( r,g,b ); + } + else if ( line.length() == 0 ) + { + break; + } + } + if (m_vis_colors.size() < 24) + { + qWarning ( "Skin: cannot parse viscolor.txt" ); + while (m_vis_colors.size() < 24) + m_vis_colors << QColor (0,0,0); + } +} + +void Skin::loadShufRep() +{ + QPixmap *pixmap = getPixmap ("shufrep"); + + if (!pixmap) + pixmap = getDummyPixmap("shufrep"); + + buttons[ BT_EQ_ON_N ] = pixmap->copy ( 0,73,23,12 ); + buttons[ BT_EQ_ON_P ] = pixmap->copy ( 46,73,23,12 ); + buttons[ BT_EQ_OFF_N ] = pixmap->copy ( 0,61,23,12 ); + buttons[ BT_EQ_OFF_P ] = pixmap->copy ( 46,61,23,12 ); + + buttons[ BT_PL_ON_N ] = pixmap->copy ( 23,73,23,12 ); + buttons[ BT_PL_ON_P ] = pixmap->copy ( 69,73,23,12 ); + buttons[ BT_PL_OFF_N ] = pixmap->copy ( 23,61,23,12 ); + buttons[ BT_PL_OFF_P ] = pixmap->copy ( 69,61,23,12 ); + + //buttons[ BT_PL_CLOSE_N ] = pixmap->copy (); + //buttons[ BT_PL_CLOSE_P ] = pixmap->copy (); + + buttons[REPEAT_ON_N] = pixmap->copy ( 0,30, 28, 15 ); + buttons[REPEAT_ON_P] = pixmap->copy ( 0,45, 28, 15 ); + + buttons[REPEAT_OFF_N] = pixmap->copy ( 0, 0,28,15 ); + buttons[REPEAT_OFF_P] = pixmap->copy ( 0,15,28,15 ); + + buttons[SHUFFLE_ON_N] = pixmap->copy ( 28,30,46,15 ); + buttons[SHUFFLE_ON_P] = pixmap->copy ( 28,45,46,15 ); + + buttons[SHUFFLE_OFF_N] = pixmap->copy ( 28, 0,46,15 ); + buttons[SHUFFLE_OFF_P] = pixmap->copy ( 28,15,46,15 ); + + delete pixmap; + +} + +void Skin::loadLetters( void ) +{ + QPixmap *img = getPixmap("text"); + + if (!img) + img = getDummyPixmap("text"); + + QList<QList<QPixmap> > ( letters ); + for ( int i = 0; i < 3; i++ ) + { + QList<QPixmap> ( l ); + for ( int j = 0; j < 31; j++ ) + { + l.append ( img->copy ( j*5, i*6, 5, 6 ) ); + } + letters.append ( l ); + } + + delete img; + + + /* alphabet */ + for ( uint i = 97; i < 123; i++ ) + { + m_letters.insert(i, letters[0][i-97]); + } + + /* digits */ + for ( uint i = 0; i <= 9; i++ ) + { + m_letters.insert ( i+48, letters[1][i] ); + } + + /* special characters */ + m_letters.insert('"', letters[0][27]); + m_letters.insert('@', letters[0][28]); + m_letters.insert(':', letters[1][12]); + m_letters.insert('(', letters[1][13]); + m_letters.insert(')', letters[1][14]); + m_letters.insert('-', letters[1][15]); + m_letters.insert('\'', letters[1][16]); + m_letters.insert('`', letters[1][16]); + m_letters.insert('!', letters[1][17]); + m_letters.insert('_', letters[1][18]); + m_letters.insert('+', letters[1][19]); + m_letters.insert('\\', letters[1][20]); + m_letters.insert('/', letters[1][21]); + m_letters.insert('[', letters[1][22]); + m_letters.insert(']', letters[1][23]); + m_letters.insert('^', letters[1][24]); + m_letters.insert('&', letters[1][25]); + m_letters.insert('%', letters[1][26]); + m_letters.insert('.', letters[1][27]); + m_letters.insert(',', letters[1][27]); + m_letters.insert('=', letters[1][28]); + m_letters.insert('$', letters[1][29]); + m_letters.insert('#', letters[1][30]); + + m_letters.insert(229, letters[2][0]); + m_letters.insert(246, letters[2][1]); + m_letters.insert(228, letters[2][2]); + m_letters.insert('?', letters[2][3]); + m_letters.insert('*', letters[2][4]); + m_letters.insert(' ', letters[2][5]); + + /* text background */ + //m_items->insert (TEXTBG, letters[2][6]); +} + +void Skin::loadMonoSter() +{ + QPixmap *pixmap = getPixmap("monoster"); + + if (!pixmap) + pixmap = getDummyPixmap("monoster"); + + m_ms_parts.clear(); + m_ms_parts[ MONO_A ] = pixmap->copy ( 29,0,27,12 ); + m_ms_parts[ MONO_I ] = pixmap->copy ( 29,12,27,12 ); + m_ms_parts[ STEREO_A ] = pixmap->copy ( 0,0,27,12 ); + m_ms_parts[ STEREO_I ] = pixmap->copy ( 0,12,27,12 ); + + delete pixmap; + + m_parts.clear(); + QPainter paint; + pixmap = getPixmap("playpaus"); + + if (!pixmap) + pixmap = getDummyPixmap("playpaus"); + + QPixmap part(11, 9); + paint.begin(&part); + paint.drawPixmap (0, 0, 3, 9, *pixmap, 36, 0, 3, 9); + paint.drawPixmap (3, 0, 8, 9, *pixmap, 1, 0, 8, 9); + paint.end(); + m_parts [PLAY] = part.copy(); + + part = QPixmap(11, 9); + paint.begin(&part); + paint.drawPixmap (0, 0, 2, 9, *pixmap, 27, 0, 2, 9); + paint.drawPixmap (2, 0, 9, 9, *pixmap, 9, 0, 9, 9); + paint.end(); + m_parts [PAUSE] = part.copy(); + + part = QPixmap(11, 9); + paint.begin(&part); + paint.drawPixmap (0, 0, 2, 9, *pixmap, 27, 0, 2, 9); + paint.drawPixmap (2, 0, 9, 9, *pixmap, 18, 0, 9, 9); + paint.end(); + m_parts [STOP] = part.copy(); + + delete pixmap; +} + +void Skin::loadVolume() +{ + QPixmap *pixmap = getPixmap("volume"); + + if (!pixmap) + pixmap = getDummyPixmap("volume"); + + m_volume.clear(); + for (int i = 0; i < 28; ++i) + m_volume.append(pixmap->copy ( 0,i*15,66,13 )); + if (pixmap->height() > 425) + { + buttons [BT_VOL_N] = pixmap->copy (15,422,14, pixmap->height() - 422); + buttons [BT_VOL_P] = pixmap->copy (0, 422,14, pixmap->height() - 422); + } + else + { + buttons [BT_VOL_N] = QPixmap(); + buttons [BT_VOL_P] = QPixmap(); + } + delete pixmap; +} + +void Skin::loadBalance() +{ + QPixmap *pixmap = getPixmap ( "balance" ); + if (!pixmap) + pixmap = getPixmap ( "volume" ); + + if (!pixmap) + pixmap = getDummyPixmap("balance"); + + m_balance.clear(); + for (int i = 0; i < 28; ++i) + m_balance.append(pixmap->copy ( 9,i*15,38,13 )); + if (pixmap->height() > 427) + { + buttons [BT_BAL_N] = pixmap->copy (15, 422,14,pixmap->height()-422); + buttons [BT_BAL_P] = pixmap->copy (0,422,14,pixmap->height()-422); + } + else + { + buttons [BT_BAL_N] = QPixmap(); + buttons [BT_BAL_P] = QPixmap(); + } + delete pixmap; +} + +void Skin::loadRegion() +{ + m_mwRegion = QRegion(); + m_plRegion = QRegion(); + m_skin_dir.setFilter ( QDir::Files | QDir::Hidden | QDir::NoSymLinks ); + QString path; + QFileInfoList list = m_skin_dir.entryInfoList(); + for ( int i = 0; i < list.size(); ++i ) + { + QFileInfo fileInfo = list.at ( i ); + if ( fileInfo.fileName().toLower() == "region.txt" ) + { + path = fileInfo.filePath (); + break; + } + } + + if ( path.isNull () ) + { + qDebug ( "Skin: cannot find region.txt. Transparenty disabled" ); + return; + } + m_mwRegion = createRegion(path, "Normal"); + m_plRegion = createRegion(path, "Equalizer"); +} + +QRegion Skin::createRegion(const QString &path, const QString &key) +{ + QRegion region; + QSettings settings(path, QSettings::IniFormat); + QStringList numPoints = settings.value(key+"/NumPoints").toStringList(); + QStringList value = settings.value(key+"/PointList").toStringList(); + QStringList numbers; + foreach(QString str, value) + numbers << str.split(" ", QString::SkipEmptyParts); + + QList <QRegion> regions; + + QList<QString>::iterator n; + n = numbers.begin(); + for (int i = 0; i < numPoints.size(); ++i) + { + QList <int> lp; + for (int j = 0; j < numPoints.at(i).toInt()*2; j++) + { + lp << n->toInt(); + n ++; + } + QVector<QPoint> points; + + for (int l = 0; l < lp.size(); l+=2) + { + points << QPoint(lp.at(l), lp.at(l+1)); + } + region = region.united(QRegion(QPolygon(points))); + } + return region; +} + +QPixmap * Skin::getDummyPixmap(const QString& name) +{ + QDir dir (":/default"); + dir.setFilter ( QDir::Files | QDir::Hidden | QDir::NoSymLinks ); + QFileInfoList f = dir.entryInfoList(); + for ( int j = 0; j < f.size(); ++j ) + { + QFileInfo fileInfo = f.at ( j ); + QString fn = fileInfo.fileName().toLower(); + if ( fn.section ( ".",0,0 ) == name ) + { + return new QPixmap ( fileInfo.filePath() ); + } + } + qFatal("Skin:: default skin corrupted"); + return 0; +} + +void Skin::loadColors() +{ + //extract color from image + QPixmap pix = m_letters['*']; + QImage img = pix.toImage(); + img = img.convertToFormat(QImage::Format_Indexed8); + + QPixmap pix2 = m_letters[' ']; + QImage img2 = pix2.toImage(); + img2 = img2.convertToFormat(QImage::Format_Indexed8); + QVector<QRgb> c1 = img.colorTable (); + QVector<QRgb> c2 = img2.colorTable (); + //qDebug("%d -- %d", img.numColors (), img2.numColors ()); + QColor color; + color.setNamedColor(getPLValue("normal")); + + for (int i = 0; i < c1.size(); ++i) + { + if (c2.indexOf(c1[i]) == -1) + { + if(img.numColors () == img2.numColors () + 1) + color = QColor(c1[i]); + break; + } + } + m_scroller_color = color; +} diff --git a/src/ui/skin.h b/src/ui/skin.h new file mode 100644 index 000000000..d981c4613 --- /dev/null +++ b/src/ui/skin.h @@ -0,0 +1,340 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef SKIN_H +#define SKIN_H + +#include <QObject> +#include <QMap> +#include <QPixmap> +#include <QDir> +#include <QRegion> + +/* + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + + +class Skin : public QObject +{ + Q_OBJECT +public: + Skin(QObject *parent = 0); + + ~Skin(); + + static Skin *getPointer(); + static QPixmap getPixmap(const QString&, QDir); + void setSkin(const QString& path); + const QPixmap getMain() const + { + return m_main; + }; + const QPixmap getButton(uint bt) const + { + return buttons[bt]; + }; + const QPixmap getTitleBar(uint tb) const + { + return titlebar[tb]; + }; + const QPixmap getPosBar() const + { + return posbar; + }; + const QPixmap getNumber(uint n) const + { + return m_numbers[n]; + }; + /*! + * Returns count of numbers in number list. + * We need this to check if we have "-" in pixmaps. + * if no we should draw it manually. + */ + const uint getNumCount(void) const + { + return m_numbers.count(); + } + const QPixmap getPlPart(uint p) const + { + return m_pl_parts[p]; + }; + const QPixmap getEqPart(uint p) const + { + return m_eq_parts[p]; + }; + const QPixmap getEqSlider(uint n) const + { + return m_eq_bar[n]; + }; + const QPixmap getEqSpline(uint n) const + { + return m_eq_spline[n]; + }; + const QPixmap getMSPart(uint n) const + { + return m_ms_parts[n]; + }; + const QPixmap getLetter(const QChar& ch) + { + return m_letters[ch]; + }; + const QPixmap getItem(uint n) const + { + return m_parts[n]; + }; + const QPixmap getVolumeBar(int n) const + { + return m_volume[n]; + }; + const QPixmap getBalanceBar(int n) const + { + return m_balance[n]; + }; + const QByteArray getPLValue (QByteArray c) const + { + return m_pledit_txt[c]; + }; + const QColor getVisColor(int n) const + { + return m_vis_colors[n]; + }; + const QRegion getMWRegion() const + { + return m_mwRegion; + }; + const QRegion getPLRegion() const + { + return m_plRegion; + }; + const QColor scrollerTextColor() const + { + return m_scroller_color; + }; + + enum Buttons + { + BT_PREVIOUS_N = 0, + BT_PREVIOUS_P, + BT_PLAY_N, + BT_PLAY_P, + BT_PAUSE_N, + BT_PAUSE_P, + BT_STOP_N, + BT_STOP_P, + BT_NEXT_N, + BT_NEXT_P, + BT_EJECT_N, + BT_EJECT_P, + /*titlebar.* */ + BT_MENU_N, + BT_MENU_P, + BT_MINIMIZE_N, + BT_MINIMIZE_P, + BT_CLOSE_N, + BT_CLOSE_P, + BT_SHADE1_N, + BT_SHADE1_P, + BT_SHADE2_N, + BT_SHADE2_P, + BT_CLOSE_SHADED_N, + BT_CLOSE_SHADED_P, + + /* posbar.* */ + BT_POSBAR_N, + BT_POSBAR_P, + /* pledit.* */ + PL_BT_ADD, + PL_BT_SUB, + PL_BT_SEL, + PL_BT_SORT, + PL_BT_LST, + PL_BT_SCROLL_N, + PL_BT_SCROLL_P, + PL_BT_CLOSE_N, + PL_BT_CLOSE_P, + PL_BT_SHADE1_N, + PL_BT_SHADE1_P, + PL_BT_SHADE2_N, + PL_BT_SHADE2_P, + + /* eqmain.* */ + EQ_BT_BAR_N, + EQ_BT_BAR_P, + EQ_BT_ON_N, + EQ_BT_ON_P, + EQ_BT_OFF_N, + EQ_BT_OFF_P, + EQ_BT_PRESETS_N, + EQ_BT_PRESETS_P, + EQ_BT_AUTO_1_N, + EQ_BT_AUTO_1_P, + EQ_BT_AUTO_0_N, + EQ_BT_AUTO_0_P, + EQ_BT_CLOSE_N, + EQ_BT_CLOSE_P, + EQ_BT_SHADE1_N, + + /* eq_ex.* */ + EQ_BT_SHADE1_P, + EQ_BT_SHADE2_N, + EQ_BT_SHADE2_P, + + /* shufrep.* */ + BT_EQ_ON_N, + BT_EQ_ON_P, + BT_EQ_OFF_N, + BT_EQ_OFF_P, + BT_PL_ON_N, + BT_PL_ON_P, + BT_PL_OFF_N, + BT_PL_OFF_P, + BT_PL_CLOSE_N, + BT_PL_CLOSE_P, + REPEAT_ON_N, + REPEAT_ON_P, + REPEAT_OFF_N, + REPEAT_OFF_P, + SHUFFLE_ON_N, + SHUFFLE_ON_P, + SHUFFLE_OFF_N, + SHUFFLE_OFF_P, + /* volume.* */ + BT_VOL_N, + BT_VOL_P, + /* balance.* */ + BT_BAL_N, + BT_BAL_P, + }; + enum TitleBar + { + TITLEBAR_A = 0, + TITLEBAR_I, + TITLEBAR_SHADED_A, + TITLEBAR_SHADED_I, + }; + enum PlayList + { + PL_CORNER_UL_A = 0, + PL_CORNER_UL_I, + PL_CORNER_UR_A, + PL_CORNER_UR_I, + PL_TITLEBAR_A, + PL_TITLEBAR_I, + PL_TFILL1_A, + PL_TFILL1_I, + PL_TFILL2_A, + PL_TFILL2_I, + PL_LFILL, + PL_RFILL, + PL_LSBAR, + PL_RSBAR, + PL_SFILL1, + PL_SFILL2, + PL_CONTROL, + PL_TITLEBAR_SHADED1_A, + PL_TITLEBAR_SHADED1_I, + PL_TITLEBAR_SHADED2, + PL_TFILL_SHADED, + }; + enum Equalizer + { + EQ_MAIN = 0, + EQ_TITLEBAR_A, + EQ_TITLEBAR_I, + EQ_GRAPH, + EQ_TITLEBAR_SHADED_A, + EQ_TITLEBAR_SHADED_I, + EQ_VOLUME1, + EQ_VOLUME2, + EQ_VOLUME3, + EQ_BALANCE1, + EQ_BALANCE2, + EQ_BALANCE3, + }; + enum MonoSter + { + MONO_A = 0, + MONO_I, + STEREO_A, + STEREO_I, + }; + enum OtherParts + { + PLAY = 0, + PAUSE, + STOP, + }; +signals: + void skinChanged(); + +private: + QPixmap *getPixmap(const QString&); + + /*! + * As far as there is no standard in skin making we cannot be sure + * that all needful images we can find in skin :( This will cause + * segfaults and asserts. So to prevent this we need such method + * to load pixmap from default skin. + */ + QPixmap *getDummyPixmap(const QString&); + static Skin *pointer; + QDir m_skin_dir; + QMap<uint, QPixmap> buttons; + QMap<uint, QPixmap> titlebar; + QMap<uint, QPixmap> m_pl_parts; + QMap<uint, QPixmap> m_eq_parts; + QMap<uint, QPixmap> m_ms_parts; + QMap<uint, QPixmap> m_parts; + QMap<QChar, QPixmap> m_letters; + QMap<QByteArray, QByteArray> m_pledit_txt; + QColor m_scroller_color; + QPixmap m_main; + QPixmap posbar; + QList<QPixmap> m_numbers; + QList<QPixmap> m_eq_bar; + QList<QPixmap> m_eq_spline; + QList<QPixmap> m_volume; + QList<QPixmap> m_balance; + QList<QColor> m_vis_colors; + QRegion m_mwRegion; + QRegion m_plRegion; + + void loadMain(); + void loadButtons(); + void loadTitleBar(); + void loadPosBar(); + void loadNumbers(); + void loadPlayList(); + void loadPLEdit(); + void loadEqMain(); + void loadEq_ex(); + void loadVisColor(); + void loadShufRep(); + void loadLetters(); + void loadMonoSter(); + void loadVolume(); + void loadBalance(); + void loadRegion(); + void loadColors(); + QRegion createRegion(const QString &path, const QString &key); + +}; + +#endif diff --git a/src/ui/skinreader.cpp b/src/ui/skinreader.cpp new file mode 100644 index 000000000..c29246d8d --- /dev/null +++ b/src/ui/skinreader.cpp @@ -0,0 +1,148 @@ +/*************************************************************************** + * Copyright (C) 2008 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QDir> +#include <QList> +#include <QFileInfo> +#include <QProcess> +#include <QByteArray> +#include <QApplication> +#include <QFile> + +#include "skinreader.h" + +SkinReader::SkinReader(QObject *parent) + : QObject(parent) +{ + m_process = new QProcess(this); + //create cache dir + QDir dir(QDir::homePath() +"/.qmmp/"); + dir.mkdir("cache"); + dir.cd("cache"); + dir.mkdir("skins"); +} + + +SkinReader::~SkinReader() +{} + +void SkinReader::updateCache() +{ + QDir dir(QDir::homePath() +"/.qmmp/skins"); + dir.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks); + QFileInfoList f = dir.entryInfoList(); + dir.setPath(qApp->applicationDirPath()+"/../share/qmmp/skins"); + dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks); + f << dir.entryInfoList(); + //clear removed skins from cache + QDir cache_dir(QDir::homePath() +"/.qmmp/cache/skins"); + cache_dir.setFilter(QDir::Dirs | QDir::Hidden | QDir::NoDotAndDotDot); + QFileInfoList d = cache_dir.entryInfoList(); + + foreach(QFileInfo dirInfo, d) + { + bool del = TRUE; + foreach(QFileInfo fileInfo, f) + { + if (fileInfo.baseName () == dirInfo.fileName ()) + { + del = FALSE; + break; + } + } + if (del) + { + qDebug("SkinReader: deleting %s from cache", + qPrintable(dirInfo.fileName ())); + + cache_dir.cd(dirInfo.fileName ()); + cache_dir.setFilter(QDir::Files | QDir::Hidden); + QFileInfoList removeList = cache_dir.entryInfoList(); + foreach(QFileInfo to_remove, removeList) + cache_dir.remove(to_remove.fileName ()); + cache_dir.cdUp(); + cache_dir.rmdir(dirInfo.fileName ()); + } + } + //add new skins to cache + foreach(QFileInfo fileInfo, f) + { + bool create = TRUE; + foreach(QFileInfo dirInfo, d) + { + if (fileInfo.baseName () == dirInfo.fileName ()) + { + create = FALSE; + break; + } + } + if (create) + { + qDebug("SkinReader: adding %s to cache", + qPrintable(fileInfo.fileName ())); + cache_dir.mkdir(fileInfo.baseName ()); + QString name = fileInfo.fileName ().toLower(); + + if (name.endsWith(".tgz") || name.endsWith(".tar.gz")) + untar(fileInfo.filePath (), cache_dir.absolutePath ()+"/"+ + fileInfo.baseName ()); + if (name.endsWith(".zip") || name.endsWith(".wsz")) + unzip(fileInfo.filePath (), cache_dir.absolutePath ()+"/"+ + fileInfo.baseName ()); + } + } +} + +void SkinReader::untar(const QString &from, const QString &to) +{ + QByteArray array; + QStringList args; + //list archive + args << "tf" <<from; + m_process->start("tar", args); + m_process->waitForFinished(); + array = m_process->readAllStandardOutput (); + QString str = QString(array); + QStringList outputList = str.split("\n",QString::SkipEmptyParts); + foreach(QString str, outputList) + { + str = str.trimmed(); + args.clear(); + args << "xvfk" << from << "-O" << str; + m_process->start("tar", args); + m_process->waitForFinished(); + array = m_process->readAllStandardOutput (); + QString name = str.right(str.size() - str.indexOf("/",Qt::CaseInsensitive) - 1).trimmed().toLower(); + + QFile file(to+"/"+name); + file.open(QIODevice::WriteOnly); + file.write(array); + file.close(); + } +} + +void SkinReader::unzip(const QString &from, const QString &to) +{ + QStringList args; + args << "-j" << "-o" << "-d" << to << from; + m_process->start("unzip", args); + m_process->waitForFinished(); +} + diff --git a/src/ui/skinreader.h b/src/ui/skinreader.h new file mode 100644 index 000000000..321a5fbbf --- /dev/null +++ b/src/ui/skinreader.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2008 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef SKINREADER_H +#define SKINREADER_H + +#include <QObject> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class QProcess; + +class SkinReader : public QObject +{ + Q_OBJECT +public: + SkinReader(QObject *parent = 0); + + ~SkinReader(); + + void updateCache(); + +private: + QProcess *m_process; + void untar(const QString &from, const QString &to); + void unzip(const QString &from, const QString &to); +}; + +#endif diff --git a/src/ui/stuff.qrc b/src/ui/stuff.qrc new file mode 100644 index 000000000..e9c99d558 --- /dev/null +++ b/src/ui/stuff.qrc @@ -0,0 +1,28 @@ +<!DOCTYPE RCC> +<RCC version="1.0"> + <qresource> + <file>../../COPYING</file> + <file>html/about_en.html</file> + <file>html/about_ru.html</file> + <file>html/authors_en.txt</file> + <file>html/thanks_en.txt</file> + <file>html/authors_ru.txt</file> + <file>html/thanks_ru.txt</file> + <file>default/balance.png</file> + <file>default/eqmain.png</file> + <file>default/numbers.png</file> + <file>default/pledit.txt</file> + <file>default/text.png</file> + <file>default/volume.png</file> + <file>default/cbuttons.png</file> + <file>default/main.png</file> + <file>default/playpaus.png</file> + <file>default/posbar.png</file> + <file>default/titlebar.png</file> + <file>default/eq_ex.png</file> + <file>default/monoster.png</file> + <file>default/pledit.png</file> + <file>default/shufrep.png</file> + <file>default/viscolor.txt</file> + </qresource> +</RCC> diff --git a/src/ui/symboldisplay.cpp b/src/ui/symboldisplay.cpp new file mode 100644 index 000000000..b3942a6bb --- /dev/null +++ b/src/ui/symboldisplay.cpp @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QPainter> +#include <math.h> + +#include "skin.h" + +#include "symboldisplay.h" + +SymbolDisplay::SymbolDisplay ( QWidget *parent, int digits ) + : PixmapWidget ( parent ), m_digits ( digits ), m_text(), m_max(0) +{ + m_alignment = Qt::AlignRight; + m_skin = Skin::getPointer(); + connect ( m_skin, SIGNAL ( skinChanged() ), this, SLOT (draw())); + draw(); + for (int i=0; i<m_digits; ++i) +#ifdef Q_OS_FREEBSD + m_max += 9 * (int) pow(10,i); +#else + m_max += 9 * (int) exp10(i); +#endif +} + + +SymbolDisplay::~SymbolDisplay() +{} + +void SymbolDisplay::display (const QString& str) +{ + m_text = str; + if (!str.isEmpty()) + draw(); +} + +void SymbolDisplay::draw() +{ + QString str = m_text; + QPixmap bg = m_skin->getLetter ( ' ' ); + int w = bg.size().width(); + int h = bg.size().height(); + QPixmap tmp ( m_digits*w,h ); + QPainter paint ( &tmp ); + int j; + for ( int i = 0; i < m_digits; ++i ) + { + if (m_alignment == Qt::AlignRight) // TODO: add align Center + { + j = str.size() -1 - i; + if ( j >= 0 ) + paint.drawPixmap ( ( m_digits-1-i ) *w,0,m_skin->getLetter ( str.at ( j ) ) ); + else + paint.drawPixmap ( ( m_digits-1-i ) *w,0,m_skin->getLetter ( ' ' ) ); + } + else + { + if (i < str.size()) + paint.drawPixmap ( i * w,0,m_skin->getLetter ( str.at ( i ) ) ); + else + paint.drawPixmap ( i * w,0,m_skin->getLetter ( ' ' ) ); + ; + } + } + setPixmap(tmp); +} + +void SymbolDisplay::display(int val) +{ + if (val < m_max) + display(QString::number(val)); + else + display(QString("%1h").arg(val/100)); +} + diff --git a/src/ui/symboldisplay.h b/src/ui/symboldisplay.h new file mode 100644 index 000000000..065579b7a --- /dev/null +++ b/src/ui/symboldisplay.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef SYMBOLDISPLAY_H +#define SYMBOLDISPLAY_H + +#include <QPixmap> + +#include "pixmapwidget.h" + +/** + @author Vladimir Kuznetsov <vovanec@gmail.com> + */ + +class Skin; + +class SymbolDisplay : public PixmapWidget +{ + Q_OBJECT +public: + SymbolDisplay(QWidget *parent = 0, int digits = 3); + + ~SymbolDisplay(); + void display(const QString&); + void display(int); + void setAlignment(Qt::Alignment a) + { + m_alignment = a; + } + Qt::Alignment alignment()const + { + return m_alignment; + } + +private slots: + void draw(); + +private: + Skin* m_skin; + QPixmap m_pixmap; + int m_digits; + QString m_text; + Qt::Alignment m_alignment; + int m_max; + +}; + +#endif diff --git a/src/ui/textscroller.cpp b/src/ui/textscroller.cpp new file mode 100644 index 000000000..35e4ed4eb --- /dev/null +++ b/src/ui/textscroller.cpp @@ -0,0 +1,116 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QPainter> +#include <QTimer> +#include <QSettings> + +#include "skin.h" +#include "textscroller.h" +#include "version.h" + +TextScroller *TextScroller::pointer = 0; + +TextScroller *TextScroller::getPointer() +{ + return pointer; +} + + +TextScroller::TextScroller ( QWidget *parent ) + : PixmapWidget ( parent ) +{ + pointer = this; + m_skin = Skin::getPointer(); + m_pixmap = QPixmap ( 154,15 ); + x = 0; + m_text = "Qt-based Multimedia Player (Qmmp " + QString(QMMP_STR_VERSION) + ")"; + m_update = FALSE; + readSettings(); + m_timer = new QTimer ( this ); + connect ( m_timer, SIGNAL ( timeout() ),SLOT ( addOffset() ) ); + m_timer->setInterval(50); + m_timer->start(); + updateSkin(); + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); +} + + +TextScroller::~TextScroller() +{} + +void TextScroller::addOffset() +{ + m_pixmap.fill ( Qt::transparent ); + QPainter paint ( &m_pixmap ); + x--; + paint.setPen(m_color); + paint.setFont(m_font); + paint.drawText ( 154+x,12, m_text ); + paint.drawText ( 154+x+m_metrics->width ( m_text ) + 15,12, m_text ); + if ( 154 + x < - m_metrics->width ( m_text ) - 15 +1) + { + x=-154; + } + setPixmap ( m_pixmap ); +} + +void TextScroller::setText(const QString& text) +{ + if (m_text != text) + { + m_text = text; + x = -50; + } +} + +void TextScroller::updateSkin() +{ + m_color.setNamedColor(m_skin->getPLValue("normal")); +} + +void TextScroller::readSettings() +{ + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + QString fontname = settings.value("MainWindow/Font","").toString(); + if (fontname.isEmpty ()) + fontname = QFont("Helvetica [Cronyx]", 9).toString(); + m_font.fromString(fontname); + + if (m_update) + { + delete m_metrics; + m_metrics = new QFontMetrics(m_font); + } + else + { + m_update = TRUE; + m_metrics = new QFontMetrics(m_font); + } +} + +void TextScroller::hideEvent ( QHideEvent *) +{ + m_timer->stop(); +} + +void TextScroller::showEvent ( QShowEvent *) +{ + m_timer->start(); +} diff --git a/src/ui/textscroller.h b/src/ui/textscroller.h new file mode 100644 index 000000000..7346ce29a --- /dev/null +++ b/src/ui/textscroller.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef TEXTSCROLLER_H +#define TEXTSCROLLER_H + +#include <pixmapwidget.h> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + +class QTimer; + +class Skin; + +class TextScroller : public PixmapWidget +{ +Q_OBJECT +public: + TextScroller(QWidget *parent = 0); + + ~TextScroller(); + + static TextScroller *getPointer(); + void setText(const QString&); + void readSettings(); + +private slots: + void addOffset(); + void updateSkin(); + +protected: + void hideEvent ( QHideEvent *); + void showEvent ( QShowEvent *); + +private: + bool m_update; + static TextScroller *pointer; + QPixmap m_pixmap; + int x; + QFont m_font; + QFontMetrics *m_metrics; + QString m_text; + Skin *m_skin; + QColor m_color; + QTimer *m_timer; +}; + +#endif diff --git a/src/ui/timeindicator.cpp b/src/ui/timeindicator.cpp new file mode 100644 index 000000000..9b81ba040 --- /dev/null +++ b/src/ui/timeindicator.cpp @@ -0,0 +1,127 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QPainter> +#include <QSettings> +#include <QMouseEvent> + +#include "skin.h" +#include "timeindicator.h" + +TimeIndicator::TimeIndicator ( QWidget *parent ) + : PixmapWidget ( parent ) +{ + m_skin = Skin::getPointer(); + m_pixmap = QPixmap ( 65,13 ); + m_elapsed = true; + m_time = m_songDuration = 0; + readSettings(); + m_needToShowTime = false; + updateSkin(); + reset(); + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); +} + +void TimeIndicator::setTime ( int t ) +{ + m_time = t; + m_pixmap.fill ( Qt::transparent ); + QPainter paint ( &m_pixmap ); + + if (!m_elapsed) + { + t = m_songDuration - t; + paint.drawPixmap(QPoint(2,0),m_skin->getNumber( 10 )); + } + if(t < 0) + t = 0; + + paint.drawPixmap(QPoint(13,0),m_skin->getNumber( t/600%10 )); + paint.drawPixmap(QPoint(26,0),m_skin->getNumber( t/60%10 )); + paint.drawPixmap(QPoint(43,0),m_skin->getNumber( t%60/10 )); + paint.drawPixmap(QPoint(56,0),m_skin->getNumber( t%60%10 )); + + setPixmap ( m_pixmap ); + +} + +void TimeIndicator::reset() +{ + m_pixmap.fill ( Qt::transparent ); + QPainter paint ( &m_pixmap ); + setPixmap ( m_pixmap ); +} + +void TimeIndicator::mousePressEvent(QMouseEvent* e ) +{ + if (m_needToShowTime && e->button() & Qt::LeftButton) + { + m_elapsed = m_elapsed ? false : true; + setTime(m_time); + } + PixmapWidget::mousePressEvent(e); +} + +void TimeIndicator::setSongDuration(int d) +{ + m_songDuration = d; +} + +TimeIndicator::~TimeIndicator() +{ + writeSettings(); +} + + +void TimeIndicator::updateSkin() +{ + if (m_needToShowTime) + setTime(m_time); +} + +void TimeIndicator::readSettings() +{ + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + settings.beginGroup("Display"); + m_elapsed = settings.value("Elapsed",true).toBool(); + settings.endGroup(); +} + + +void TimeIndicator::writeSettings() +{ + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + settings.beginGroup("Display"); + settings.setValue("Elapsed",m_elapsed); + settings.endGroup(); +} + + +void TimeIndicator::setNeedToShowTime(bool need) +{ + m_needToShowTime = need; + if (!need) reset(); +} + +void TimeIndicator::mouseMoveEvent(QMouseEvent *) +{} + +void TimeIndicator::mouseReleaseEvent(QMouseEvent *) +{} + diff --git a/src/ui/timeindicator.h b/src/ui/timeindicator.h new file mode 100644 index 000000000..19981a4b3 --- /dev/null +++ b/src/ui/timeindicator.h @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef TIMEINDICATOR_H +#define TIMEINDICATOR_H + +#include <pixmapwidget.h> + +class QMouseEvent; + +class Skin; + + +/** Class TimeIndicator + * @author Vladimir Kuznetsov <vovanec@gmail.com> + * + * Represents time indicator in the main display. Can show elapsed + * and rest time of song (mouse press on indicator changes mode) + */ +class TimeIndicator : public PixmapWidget +{ + Q_OBJECT +public: + TimeIndicator(QWidget *parent = 0); + ~TimeIndicator(); + void setTime ( int t ); + void setSongDuration(int); + void setNeedToShowTime(bool); +protected: + virtual void mousePressEvent(QMouseEvent*); + virtual void mouseMoveEvent(QMouseEvent*); + virtual void mouseReleaseEvent(QMouseEvent*); + void writeSettings(); + void readSettings(); + void reset(); +private slots: + void updateSkin(); +private: + QPixmap m_pixmap; + Skin *m_skin; + int m_time; + int m_songDuration; + bool m_elapsed; + bool m_needToShowTime; +}; + +#endif diff --git a/src/ui/titlebar.cpp b/src/ui/titlebar.cpp new file mode 100644 index 000000000..bdbd86b2e --- /dev/null +++ b/src/ui/titlebar.cpp @@ -0,0 +1,226 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QMainWindow> +#include <QApplication> +#include <QMouseEvent> +#include <QMenu> +#include <QSettings> + +#include <soundcore.h> +#include "symboldisplay.h" +#include "skin.h" +#include "button.h" +#include "dock.h" +#include "titlebarcontrol.h" +#include "shadedvisual.h" +#include "titlebar.h" + +TitleBar::TitleBar(QWidget *parent) + : PixmapWidget(parent) +{ + m_align = FALSE; + m_skin = Skin::getPointer(); + setPixmap(m_skin->getTitleBar(Skin::TITLEBAR_A)); + m_mw = qobject_cast<MainWindow*>(parent); + m_shaded = FALSE; + m_currentTime = 0; + //buttons + m_menu = new Button(this,Skin::BT_MENU_N,Skin::BT_MENU_P); + connect(m_menu,SIGNAL(clicked()),this,SLOT(showMainMenu())); + m_menu->move(6,3); + m_minimize = new Button(this,Skin::BT_MINIMIZE_N,Skin::BT_MINIMIZE_P); + m_minimize->move(244,3); + connect(m_minimize, SIGNAL(clicked()), m_mw, SLOT(showMinimized())); + m_shade = new Button(this,Skin::BT_SHADE1_N,Skin::BT_SHADE1_P); + m_shade->move(254,3); + connect(m_shade, SIGNAL(clicked()), SLOT(shade())); + m_close = new Button(this,Skin::BT_CLOSE_N,Skin::BT_CLOSE_P); + m_close->move(264,3); + connect(m_close, SIGNAL(clicked()), m_mw, SLOT(handleCloseRequest())); + setActive(FALSE); + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); + + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + if (settings.value("Display/shaded", FALSE).toBool()) + shade(); + m_align = TRUE; +} + + +TitleBar::~TitleBar() +{ + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + settings.setValue("Display/shaded", m_shaded); +} + +void TitleBar::mousePressEvent(QMouseEvent* event) +{ + switch ((int) event->button ()) + { + case Qt::LeftButton: + { + m_pos = event->pos(); + Dock::getPointer()->calculateDistances(); + break; + } + case Qt::RightButton: + { + m_mw->menu()->exec(event->globalPos()); + } + } +} + +void TitleBar::mouseReleaseEvent(QMouseEvent*) +{ + Dock::getPointer()->updateDock(); +} +void TitleBar::mouseMoveEvent(QMouseEvent* event) +{ + QPoint npos = (event->globalPos()-m_pos); + Dock::getPointer()->move(m_mw, npos); +} + +void TitleBar::setActive(bool a) +{ + if (a) + { + if (m_shaded) + { + setPixmap(m_skin->getTitleBar(Skin::TITLEBAR_SHADED_A)); + m_shade2->show(); + } + else + { + setPixmap(m_skin->getTitleBar(Skin::TITLEBAR_A)); + m_shade->show(); + } + m_menu->show(); + m_minimize->show(); + m_close->show(); + } + else + { + if (m_shaded) + { + setPixmap(m_skin->getTitleBar(Skin::TITLEBAR_SHADED_I)); + m_shade2->hide(); + } + else + { + setPixmap(m_skin->getTitleBar(Skin::TITLEBAR_I)); + m_shade->hide(); + } + m_menu->hide(); + m_minimize->hide(); + m_close->hide(); + } +} + +void TitleBar::updateSkin() +{ + setActive(FALSE); +} + +void TitleBar::showMainMenu() +{ + m_mw->menu()->exec(m_menu->mapToGlobal(m_menu->pos())); +} + +void TitleBar::shade() +{ + m_shaded = !m_shaded; + + if (m_shaded) + { + m_mw->setFixedSize(275,14); + setPixmap(m_skin->getTitleBar(Skin::TITLEBAR_SHADED_A)); + m_shade->hide(); + m_shade2 = new Button(this,Skin::BT_SHADE2_N, Skin::BT_SHADE2_P); + m_shade2->move(254,3); + connect(m_shade2, SIGNAL(clicked()), SLOT(shade())); + m_shade2->show(); + m_currentTime = new SymbolDisplay(this, 6); + m_currentTime->move(127,4); + m_currentTime->show(); + m_currentTime->display("--:--"); + m_control = new TitleBarControl(this); + m_control->move(168,2); + m_control->show(); + connect (m_control, SIGNAL (nextClicked()), parent(), SLOT (next())); + connect (m_control, SIGNAL (previousClicked()), parent(), SLOT (previous())); + connect (m_control, SIGNAL (playClicked()), parent(), SLOT (play())); + connect (m_control, SIGNAL (pauseClicked()), parent(), SLOT (pause())); + connect (m_control, SIGNAL (stopClicked()), parent(), SLOT (stop())); + connect (m_control, SIGNAL (ejectClicked()), parent(), SLOT (addFile())); + m_visual = new ShadedVisual(this); + SoundCore::instance()->addVisualization(m_visual); + m_visual->show(); + m_visual->move(79,5); + } + else + { + m_mw->setFixedSize(275,116); + setPixmap(m_skin->getTitleBar(Skin::TITLEBAR_A)); + delete m_shade2; + delete m_currentTime; + delete m_control; + SoundCore::instance()->removeVisual(m_visual); + delete m_visual; + m_shade2 = 0; + m_currentTime = 0; + m_shade->show(); + } + if(m_align) + Dock::getPointer()->align(m_mw, m_shaded? -102: 102); +} + +QString TitleBar::formatTime ( int sec ) +{ + int minutes = sec / 60; + int seconds = sec % 60; + + QString str_minutes = QString::number ( minutes ); + QString str_seconds = QString::number ( seconds ); + + if ( minutes < 10 ) str_minutes.prepend ( "0" ); + if ( seconds < 10 ) str_seconds.prepend ( "0" ); + + return str_minutes + ":" + str_seconds; +} + +void TitleBar::setInfo(const OutputState &st) +{ + if (!m_currentTime) + return; + switch ( ( int ) st.type() ) + { + case OutputState::Info: + { + m_currentTime->display(formatTime(st.elapsedSeconds())); + break; + } + case OutputState::Stopped: + { + m_currentTime->display("--:--"); + break; + } + } +} diff --git a/src/ui/titlebar.h b/src/ui/titlebar.h new file mode 100644 index 000000000..4428a188c --- /dev/null +++ b/src/ui/titlebar.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef TITLEBAR_H +#define TITLEBAR_H + +#include <QMainWindow> +#include <QPoint> + +#include "pixmapwidget.h" +#include "playlist.h" +#include "mainwindow.h" + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class MainWindow; +class QMouseEvent; + +class Skin; +class Button; +class SymbolDisplay; +class TitleBarControl; +class ShadedVisual; + +class TitleBar : public PixmapWidget +{ +Q_OBJECT +public: + TitleBar(QWidget *parent = 0); + + ~TitleBar(); + + void setActive(bool); + void setInfo(const OutputState &st); + +private slots: + void updateSkin(); + void showMainMenu(); + void shade(); + +private: + Skin *m_skin; + QPoint m_pos; + MainWindow *m_mw; + Button *m_menu; + Button *m_minimize; + Button *m_shade; + Button *m_shade2; + Button *m_close; + SymbolDisplay *m_currentTime; + QString formatTime (int); + bool m_shaded; + bool m_align; + TitleBarControl *m_control; + ShadedVisual *m_visual; + +protected: + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); +}; + + + +#endif diff --git a/src/ui/titlebarcontrol.cpp b/src/ui/titlebarcontrol.cpp new file mode 100644 index 000000000..8238c287a --- /dev/null +++ b/src/ui/titlebarcontrol.cpp @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QMouseEvent> + +#include "titlebarcontrol.h" + +TitleBarControl::TitleBarControl(QWidget *parent) + : QWidget(parent) +{ + //setAutoFillBackground(TRUE); + setFixedSize(57,10); +} + + +TitleBarControl::~TitleBarControl() +{ +} + +void TitleBarControl::mousePressEvent (QMouseEvent *) +{} + +void TitleBarControl::mouseReleaseEvent (QMouseEvent * event) +{ + QPoint pt = event->pos(); + if(QRect(0,0,8,10).contains(pt)) + emit previousClicked(); + else if(QRect(8,0,11,10).contains(pt)) + emit playClicked(); + else if(QRect(19,0,10,10).contains(pt)) + emit pauseClicked(); + else if(QRect(29,0,8,10).contains(pt)) + emit stopClicked(); + else if(QRect(37,0,10,10).contains(pt)) + emit nextClicked(); + else if(QRect(47,0,10,10).contains(pt)) + emit ejectClicked(); +} + +void TitleBarControl::mouseMoveEvent(QMouseEvent*) +{} diff --git a/src/ui/titlebarcontrol.h b/src/ui/titlebarcontrol.h new file mode 100644 index 000000000..c368b2186 --- /dev/null +++ b/src/ui/titlebarcontrol.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef TITLEBARCONTROL_H +#define TITLEBARCONTROL_H + +#include <QWidget> + +class QMouseEvent; + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class TitleBarControl : public QWidget +{ +Q_OBJECT +public: + TitleBarControl(QWidget *parent = 0); + ~TitleBarControl(); + +signals: + void previousClicked(); + void nextClicked(); + void pauseClicked(); + void playClicked(); + void stopClicked(); + void ejectClicked(); + +protected: + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + + + +}; + +#endif diff --git a/src/ui/togglebutton.cpp b/src/ui/togglebutton.cpp new file mode 100644 index 000000000..86b809ef2 --- /dev/null +++ b/src/ui/togglebutton.cpp @@ -0,0 +1,81 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "skin.h" +#include "togglebutton.h" + + +ToggleButton::ToggleButton ( QWidget *parent,uint on_n,uint on_p,uint off_n,uint off_p ) + : PixmapWidget ( parent ) +{ + m_on_n = on_n; + m_on_p = on_p; + m_off_n = off_n; + m_off_p = off_p; + m_on = FALSE; + skin = Skin::getPointer(); + setON ( FALSE ); + connect ( skin, SIGNAL ( skinChanged() ), this, SLOT ( updateSkin() ) ); +} + + +ToggleButton::~ToggleButton() +{} + +bool ToggleButton::isChecked() +{ + return m_on; +} + +void ToggleButton::updateSkin() +{ + //setPixmap ( skin->getButton ( name_normal ) ); + setON ( m_on ); +} + +void ToggleButton::click() +{ + m_on = !m_on; + setON (m_on); + emit clicked(m_on); +} + +void ToggleButton::setON ( bool on ) +{ + m_on = on; + if ( on ) + setPixmap ( skin->getButton ( m_on_n ) ); + else + setPixmap ( skin->getButton ( m_off_n ) ); +} +void ToggleButton::mousePressEvent ( QMouseEvent* ) +{ + if ( m_on ) + setPixmap ( skin->getButton ( m_off_p ) ); + else + setPixmap ( skin->getButton ( m_on_p ) ); +} + +void ToggleButton::mouseReleaseEvent ( QMouseEvent* ) +{ + m_on = !m_on; + setON ( m_on ); + emit clicked( m_on ); +} diff --git a/src/ui/togglebutton.h b/src/ui/togglebutton.h new file mode 100644 index 000000000..a15d7476f --- /dev/null +++ b/src/ui/togglebutton.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef TOGGLEBUTTON_H +#define TOGGLEBUTTON_H + +#include <pixmapwidget.h> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class Skin; + +class ToggleButton : public PixmapWidget +{ +Q_OBJECT +public: + ToggleButton( QWidget *parent, uint on_n, uint on_p, uint off_n, uint off_p ); + + ~ToggleButton(); + + bool isChecked(); + void setON(bool); + +signals: + void clicked(bool); + +public slots: + void click(); + +private slots: + void updateSkin(); + +private: + Skin *skin; + uint m_on_n, m_on_p, m_off_n, m_off_p; + bool m_on; + +protected: + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); +}; + + +#endif diff --git a/src/ui/translations/qmmp_cs.ts b/src/ui/translations/qmmp_cs.ts new file mode 100644 index 000000000..faba9c1b9 --- /dev/null +++ b/src/ui/translations/qmmp_cs.ts @@ -0,0 +1,716 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS><TS version="1.1" language="cs"> +<defaultcodec></defaultcodec> +<context> + <name>AboutDialog</name> + <message> + <location filename="../aboutdialog.cpp" line="47"/> + <source>:/html/about_en.html</source> + <translation>:/html/about_cs.html</translation> + </message> + <message> + <location filename="../aboutdialog.cpp" line="48"/> + <source>:/html/authors_en.txt</source> + <translation>:/html/authors_cs.txt</translation> + </message> + <message> + <location filename="../aboutdialog.cpp" line="49"/> + <source>:/html/thanks_en.txt</source> + <translation>:/html/thanks_cs.txt</translation> + </message> + <message> + <location filename="../aboutdialog.ui" line="13"/> + <source>About Qmmp</source> + <translation>O Qmmp</translation> + </message> + <message> + <location filename="../aboutdialog.ui" line="42"/> + <source>About</source> + <translation>O aplikaci</translation> + </message> + <message> + <location filename="../aboutdialog.ui" line="62"/> + <source>Authors</source> + <translation>Autoři</translation> + </message> + <message> + <location filename="../aboutdialog.ui" line="82"/> + <source>Thanks To</source> + <translation>Poděkování</translation> + </message> + <message> + <location filename="../aboutdialog.ui" line="102"/> + <source>License Agreement</source> + <translation>Licence</translation> + </message> +</context> +<context> + <name>AddUrlDialog</name> + <message> + <location filename="../addurldialog.ui" line="13"/> + <source>Enter URL to add</source> + <translation>Přidat URL</translation> + </message> +</context> +<context> + <name>ConfigDialog</name> + <message> + <location filename="../configdialog.cpp" line="210"/> + <source>Enabled</source> + <translation>Povoleno</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="210"/> + <source>Description</source> + <translation>Popis</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="334"/> + <source>Filename</source> + <translation>Soubor</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="329"/> + <source>Artist</source> + <translation>Umělec</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="330"/> + <source>Album</source> + <translation>Album</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="331"/> + <source>Title</source> + <translation>Název</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="332"/> + <source>Tracknumber</source> + <translation>Číslo stopy</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="333"/> + <source>Genre</source> + <translation>Žánr</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="335"/> + <source>Filepath</source> + <translation>Soubor</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="336"/> + <source>Date</source> + <translation>Datum</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="337"/> + <source>Year</source> + <translation>Rok</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="338"/> + <source>Comment</source> + <translation>Komentář</translation> + </message> + <message> + <location filename="../configdialog.ui" line="13"/> + <source>Qmmp Settings</source> + <translation>Nastavení Qmmp</translation> + </message> + <message> + <location filename="../configdialog.ui" line="97"/> + <source>Appearance</source> + <translation>Vzhled</translation> + </message> + <message> + <location filename="../configdialog.ui" line="105"/> + <source>Playlist</source> + <translation>Seznam skladeb</translation> + </message> + <message> + <location filename="../configdialog.ui" line="113"/> + <source>Plugins</source> + <translation>Moduly</translation> + </message> + <message> + <location filename="../configdialog.ui" line="121"/> + <source>Advanced</source> + <translation>Pokročilé</translation> + </message> + <message> + <location filename="../configdialog.ui" line="168"/> + <source>Skins</source> + <translation>Témata</translation> + </message> + <message> + <location filename="../configdialog.ui" line="208"/> + <source>Fonts</source> + <translation>Písma</translation> + </message> + <message> + <location filename="../configdialog.ui" line="238"/> + <source>Player:</source> + <translation>Přehrávač:</translation> + </message> + <message> + <location filename="../configdialog.ui" line="254"/> + <source>Playlist:</source> + <translation>Seznam skladeb:</translation> + </message> + <message> + <location filename="../configdialog.ui" line="290"/> + <source>???</source> + <translation>???</translation> + </message> + <message> + <location filename="../configdialog.ui" line="397"/> + <source>...</source> + <translation>...</translation> + </message> + <message> + <location filename="../configdialog.ui" line="329"/> + <source>Metadata</source> + <translation>Metadata</translation> + </message> + <message> + <location filename="../configdialog.ui" line="353"/> + <source>Load metadata from files</source> + <translation>Číst ze souborů metadata</translation> + </message> + <message> + <location filename="../configdialog.ui" line="363"/> + <source>Song Display</source> + <translation>Zobrazení skladby</translation> + </message> + <message> + <location filename="../configdialog.ui" line="384"/> + <source>Title format:</source> + <translation>Formát titulku:</translation> + </message> + <message> + <location filename="../configdialog.ui" line="442"/> + <source>Preferences</source> + <translation>Nastavení</translation> + </message> + <message> + <location filename="../configdialog.ui" line="449"/> + <source>Information</source> + <translation>Informace</translation> + </message> + <message> + <location filename="../configdialog.ui" line="479"/> + <source>Input</source> + <translation>Vstup</translation> + </message> + <message> + <location filename="../configdialog.ui" line="517"/> + <source>Output</source> + <translation>Výstup</translation> + </message> + <message> + <location filename="../configdialog.ui" line="641"/> + <source>Tray Icon</source> + <translation>Ikona v doku</translation> + </message> + <message> + <location filename="../configdialog.ui" line="665"/> + <source>Show tooltip</source> + <translation>Zobrazovat tooltip</translation> + </message> + <message> + <location filename="../configdialog.ui" line="672"/> + <source>Show message</source> + <translation>Zobrazovat zprávy</translation> + </message> + <message> + <location filename="../configdialog.ui" line="695"/> + <source>Message delay, ms:</source> + <translation>Doba zobrazení zpráv, v ms:</translation> + </message> + <message> + <location filename="../configdialog.ui" line="705"/> + <source>Show tray icon</source> + <translation>Zobrazovat ikonu v doku</translation> + </message> + <message> + <location filename="../configdialog.ui" line="715"/> + <source>Action On Close</source> + <translation>Při zavření okna</translation> + </message> + <message> + <location filename="../configdialog.ui" line="736"/> + <source>Hide to tray</source> + <translation>Schovat do doku</translation> + </message> + <message> + <location filename="../configdialog.ui" line="743"/> + <source>Quit</source> + <translation>Ukončit</translation> + </message> + <message> + <location filename="../configdialog.ui" line="914"/> + <source>Close</source> + <translation>Zavřít</translation> + </message> + <message> + <location filename="../configdialog.ui" line="129"/> + <source>Connectivity</source> + <translation>Síť</translation> + </message> + <message> + <location filename="../configdialog.ui" line="549"/> + <source>File Dialog</source> + <translation>Souborový dialog</translation> + </message> + <message> + <location filename="../configdialog.ui" line="773"/> + <source>Proxy</source> + <translation>Proxy</translation> + </message> + <message> + <location filename="../configdialog.ui" line="785"/> + <source>Enable proxy usage</source> + <translation>Povolit používání proxy</translation> + </message> + <message> + <location filename="../configdialog.ui" line="792"/> + <source>Proxy host name:</source> + <translation>Adresa proxy:</translation> + </message> + <message> + <location filename="../configdialog.ui" line="805"/> + <source>Proxy port:</source> + <translation>Port proxy:</translation> + </message> + <message> + <location filename="../configdialog.ui" line="818"/> + <source>Use authentication with proxy</source> + <translation>Použít autorizaci pro proxy</translation> + </message> + <message> + <location filename="../configdialog.ui" line="825"/> + <source>Proxy user name:</source> + <translation>Uživatelské jméno:</translation> + </message> + <message> + <location filename="../configdialog.ui" line="838"/> + <source>Proxy password:</source> + <translation>Heslo:</translation> + </message> +</context> +<context> + <name>Decoder</name> + <message> + <location filename="../../lib/decoder.cpp" line="229"/> + <source>All Supported Bitstreams (</source> + <translation>Všechny podporované formáty (</translation> + </message> +</context> +<context> + <name>EqWidget</name> + <message> + <location filename="../eqwidget.cpp" line="172"/> + <source>preset</source> + <translation>předvolba</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="258"/> + <source>&Load/Delete</source> + <translation>&Načíst/Odstranit</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="260"/> + <source>&Save Preset</source> + <translation>&Uložit předvolbu</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="261"/> + <source>&Save Auto-load Preset</source> + <translation>Uložit &automatickou předvolbu</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="262"/> + <source>&Import</source> + <translation>&Importovat</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="264"/> + <source>&Clear</source> + <translation>&Vynulovat</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="293"/> + <source>Saving Preset</source> + <translation>Uložení předvolby</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="294"/> + <source>Preset name:</source> + <translation>Název předvolby:</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="295"/> + <source>preset #</source> + <translation>předvolba #</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="380"/> + <source>Import Preset</source> + <translation>Importovat předvolbu</translation> + </message> +</context> +<context> + <name>JumpToTrackDialog</name> + <message> + <location filename="../jumptotrackdialog.cpp" line="123"/> + <source>Unqueue</source> + <translation>Vyřadit</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="79"/> + <source>Queue</source> + <translation>Zařadit</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="13"/> + <source>Jump To Track</source> + <translation>Přeskočit na skladbu</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="33"/> + <source>Filter</source> + <translation>Filtr</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="86"/> + <source>Refresh</source> + <translation>Načíst znovu</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="93"/> + <source>Jump To</source> + <translation>Přeskočit na</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="100"/> + <source>Close</source> + <translation>Zavřít</translation> + </message> +</context> +<context> + <name>MainWindow</name> + <message> + <location filename="../mainwindow.cpp" line="651"/> + <source>Default</source> + <translation>Seznam</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="322"/> + <source>Now Playing</source> + <translation>Nyní se přehrává</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="405"/> + <source>Choose a directory</source> + <translation>Výběr adresáře</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="439"/> + <source>Select one or more files to open</source> + <translation>Vyberte jeden či více souborů k otevření</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="590"/> + <source>&Play</source> + <translation>Pře&hrát</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="590"/> + <source>X</source> + <translation>X</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="591"/> + <source>&Pause</source> + <translation>Pau&za</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="591"/> + <source>C</source> + <translation>C</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="592"/> + <source>&Stop</source> + <translation>&Stop</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="592"/> + <source>V</source> + <translation>V</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="593"/> + <source>&Previous</source> + <translation>&Předchozí</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="593"/> + <source>Z</source> + <translation>Z</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="594"/> + <source>&Next</source> + <translation>&Další</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="594"/> + <source>B</source> + <translation>B</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="595"/> + <source>&Queue</source> + <translation>&Fronta</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="595"/> + <source>Q</source> + <translation>Q</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="597"/> + <source>&Jump To File</source> + <translation>Přeskočit na soubo&r</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="597"/> + <source>J</source> + <translation>J</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="599"/> + <source>&Settings</source> + <translation>&Nastavení</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="599"/> + <source>Ctrl+P</source> + <translation>Ctrl+P</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="601"/> + <source>&About</source> + <translation>O &aplikaci</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="604"/> + <source>&Exit</source> + <translation>U&končit</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="604"/> + <source>Ctrl+Q</source> + <translation>Ctrl+Q</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="705"/> + <source>Playlist Files</source> + <translation>Seznamy skladeb</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="680"/> + <source>Open Playlist</source> + <translation>Načíst seznam skladeb</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="721"/> + <source>Save Playlist</source> + <translation>Uložit seznam skladeb</translation> + </message> +</context> +<context> + <name>PlayList</name> + <message> + <location filename="../playlist.cpp" line="131"/> + <source>&Add File</source> + <translation>Přidat &soubor</translation> + </message> + <message> + <location filename="../playlist.cpp" line="132"/> + <source>F</source> + <translation>F</translation> + </message> + <message> + <location filename="../playlist.cpp" line="137"/> + <source>&Add Directory</source> + <translation>Přidat &adresář</translation> + </message> + <message> + <location filename="../playlist.cpp" line="138"/> + <source>D</source> + <translation>D</translation> + </message> + <message> + <location filename="../playlist.cpp" line="150"/> + <source>&Remove Selected</source> + <translation>&Odstranit vybrané</translation> + </message> + <message> + <location filename="../playlist.cpp" line="151"/> + <source>Del</source> + <translation>Del</translation> + </message> + <message> + <location filename="../playlist.cpp" line="157"/> + <source>&Remove All</source> + <translation>Odstranit &vše</translation> + </message> + <message> + <location filename="../playlist.cpp" line="163"/> + <source>&Remove Unselected</source> + <translation>Odstranit &nevybrané</translation> + </message> + <message> + <location filename="../playlist.cpp" line="169"/> + <source>&View Track Details</source> + <translation>Zobrazit &informace o skladbě</translation> + </message> + <message> + <location filename="../playlist.cpp" line="170"/> + <source>Alt+I</source> + <translation>Alt+I</translation> + </message> + <message> + <location filename="../playlist.cpp" line="178"/> + <source>Sort List</source> + <translation>Seřadit seznam</translation> + </message> + <message> + <location filename="../playlist.cpp" line="204"/> + <source>By Title</source> + <translation>Podle názvu skladby</translation> + </message> + <message> + <location filename="../playlist.cpp" line="208"/> + <source>By Filename</source> + <translation>Podle názvu souboru</translation> + </message> + <message> + <location filename="../playlist.cpp" line="212"/> + <source>By Path + Filename</source> + <translation>Podle cesty a názvu souboru</translation> + </message> + <message> + <location filename="../playlist.cpp" line="216"/> + <source>By Date</source> + <translation>Podle data</translation> + </message> + <message> + <location filename="../playlist.cpp" line="202"/> + <source>Sort Selection</source> + <translation>Seřadit výběr</translation> + </message> + <message> + <location filename="../playlist.cpp" line="226"/> + <source>Randomize List</source> + <translation>Zamíchat seznam</translation> + </message> + <message> + <location filename="../playlist.cpp" line="227"/> + <source>Reverse List</source> + <translation>Obrátit pořadí seznamu</translation> + </message> + <message> + <location filename="../playlist.cpp" line="234"/> + <source>Invert Selection</source> + <translation>Invertovat výběr</translation> + </message> + <message> + <location filename="../playlist.cpp" line="241"/> + <source>&Select None</source> + <translation>&Zrušit výběr</translation> + </message> + <message> + <location filename="../playlist.cpp" line="248"/> + <source>&Select All</source> + <translation>&Vybrat vše</translation> + </message> + <message> + <location filename="../playlist.cpp" line="249"/> + <source>Ctrl+A</source> + <translation>Ctrl+A</translation> + </message> + <message> + <location filename="../playlist.cpp" line="256"/> + <source>&New List</source> + <translation>&Nový seznam</translation> + </message> + <message> + <location filename="../playlist.cpp" line="257"/> + <source>Shift+N</source> + <translation>Shift+N</translation> + </message> + <message> + <location filename="../playlist.cpp" line="263"/> + <source>&Load List</source> + <translation>Načíst &seznam</translation> + </message> + <message> + <location filename="../playlist.cpp" line="264"/> + <source>O</source> + <translation>O</translation> + </message> + <message> + <location filename="../playlist.cpp" line="268"/> + <source>&Save List</source> + <translation>&Uložit seznam</translation> + </message> + <message> + <location filename="../playlist.cpp" line="269"/> + <source>Shift+S</source> + <translation>Shift+S</translation> + </message> + <message> + <location filename="../playlist.cpp" line="143"/> + <source>&Add Url</source> + <translation>Přidat &URL</translation> + </message> + <message> + <location filename="../playlist.cpp" line="144"/> + <source>U</source> + <translation>U</translation> + </message> +</context> +<context> + <name>PresetEditor</name> + <message> + <location filename="../preseteditor.ui" line="13"/> + <source>Preset Editor</source> + <translation>Editor předvoleb</translation> + </message> + <message> + <location filename="../preseteditor.ui" line="28"/> + <source>Load</source> + <translation>Načíst</translation> + </message> + <message> + <location filename="../preseteditor.ui" line="35"/> + <source>Delete</source> + <translation>Odstranit</translation> + </message> + <message> + <location filename="../preseteditor.ui" line="46"/> + <source>Preset</source> + <translation>Předvolba</translation> + </message> + <message> + <location filename="../preseteditor.ui" line="62"/> + <source>Auto-preset</source> + <translation>Automatická předvolba</translation> + </message> +</context> +</TS> diff --git a/src/ui/translations/qmmp_locales.qrc b/src/ui/translations/qmmp_locales.qrc new file mode 100644 index 000000000..64ac204fa --- /dev/null +++ b/src/ui/translations/qmmp_locales.qrc @@ -0,0 +1,8 @@ +<!DOCTYPE RCC> +<RCC version="1.0"> + <qresource> + <file>qmmp_ru.qm</file> + <file>qmmp_tr.qm</file> + <file>qmmp_zh_CN.qm</file> + </qresource> +</RCC> diff --git a/src/ui/translations/qmmp_ru.qm b/src/ui/translations/qmmp_ru.qm Binary files differnew file mode 100644 index 000000000..38c82d0e8 --- /dev/null +++ b/src/ui/translations/qmmp_ru.qm diff --git a/src/ui/translations/qmmp_ru.ts b/src/ui/translations/qmmp_ru.ts new file mode 100644 index 000000000..32fdd757d --- /dev/null +++ b/src/ui/translations/qmmp_ru.ts @@ -0,0 +1,645 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS><TS version="1.1" language="ru"> +<defaultcodec></defaultcodec> +<context> + <name>AboutDialog</name> + <message> + <location filename="../aboutdialog.ui" line="13"/> + <source>About Qmmp</source> + <translation>О Qmmp</translation> + </message> + <message> + <location filename="../aboutdialog.ui" line="42"/> + <source>About</source> + <translation>О программе</translation> + </message> + <message> + <location filename="../aboutdialog.ui" line="102"/> + <source>License Agreement</source> + <translation>Лицензия</translation> + </message> + <message> + <location filename="../aboutdialog.cpp" line="46"/> + <source>:/html/about_en.html</source> + <translation>:/html/about_ru.html</translation> + </message> + <message> + <location filename="../aboutdialog.cpp" line="47"/> + <source>:/html/authors_en.txt</source> + <translation>:/html/authors_ru.txt</translation> + </message> + <message> + <location filename="../aboutdialog.cpp" line="48"/> + <source>:/html/thanks_en.txt</source> + <translation>:/html/thanks_ru.txt</translation> + </message> + <message> + <location filename="../aboutdialog.ui" line="62"/> + <source>Authors</source> + <translation>Авторы</translation> + </message> + <message> + <location filename="../aboutdialog.ui" line="82"/> + <source>Thanks To</source> + <translation>Благодарности</translation> + </message> +</context> +<context> + <name>ConfigDialog</name> + <message> + <location filename="../configdialog.cpp" line="179"/> + <source>Enabled</source> + <translation>Включён</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="179"/> + <source>Description</source> + <translation>Описание</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="303"/> + <source>Filename</source> + <translation>Имя файла</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="298"/> + <source>Artist</source> + <translation>Исполнитель</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="299"/> + <source>Album</source> + <translation>Альбом</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="300"/> + <source>Title</source> + <translation>Название</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="301"/> + <source>Tracknumber</source> + <translation>Номер трека</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="302"/> + <source>Genre</source> + <translation>Жанр</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="304"/> + <source>Filepath</source> + <translation>Путь к файлу</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="305"/> + <source>Date</source> + <translation>Дата</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="306"/> + <source>Year</source> + <translation>Год</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="307"/> + <source>Comment</source> + <translation>Комментарий</translation> + </message> + <message> + <location filename="../configdialog.ui" line="13"/> + <source>Qmmp Settings</source> + <translation>Настройки Qmmp</translation> + </message> + <message> + <location filename="../configdialog.ui" line="134"/> + <source>Skins</source> + <translation>Обложки</translation> + </message> + <message> + <location filename="../configdialog.ui" line="165"/> + <source>Fonts</source> + <translation>Шрифты</translation> + </message> + <message> + <location filename="../configdialog.ui" line="183"/> + <source>Player:</source> + <translation>Плеер:</translation> + </message> + <message> + <location filename="../configdialog.ui" line="199"/> + <source>Playlist:</source> + <translation>Список:</translation> + </message> + <message> + <location filename="../configdialog.ui" line="235"/> + <source>???</source> + <translation>???</translation> + </message> + <message> + <location filename="../configdialog.ui" line="309"/> + <source>...</source> + <translation>...</translation> + </message> + <message> + <location filename="../configdialog.ui" line="262"/> + <source>Metadata</source> + <translation>Метаданные</translation> + </message> + <message> + <location filename="../configdialog.ui" line="274"/> + <source>Load metadata from files</source> + <translation>Считывать метаданные из файлов</translation> + </message> + <message> + <location filename="../configdialog.ui" line="284"/> + <source>Song Display</source> + <translation>Список песен</translation> + </message> + <message> + <location filename="../configdialog.ui" line="296"/> + <source>Title format:</source> + <translation>Формат названия:</translation> + </message> + <message> + <location filename="../configdialog.ui" line="379"/> + <source>Input</source> + <translation>Ввод</translation> + </message> + <message> + <location filename="../configdialog.ui" line="408"/> + <source>Output</source> + <translation>Вывод</translation> + </message> + <message> + <location filename="../configdialog.ui" line="342"/> + <source>Preferences</source> + <translation>Настройки</translation> + </message> + <message> + <location filename="../configdialog.ui" line="349"/> + <source>Information</source> + <translation>Информация</translation> + </message> + <message> + <location filename="../configdialog.ui" line="444"/> + <source>Tray Icon</source> + <translation>Системный значок</translation> + </message> + <message> + <location filename="../configdialog.ui" line="456"/> + <source>Show tooltip</source> + <translation>Всплывающая подсказка</translation> + </message> + <message> + <location filename="../configdialog.ui" line="463"/> + <source>Show message</source> + <translation>Показывать сообщение</translation> + </message> + <message> + <location filename="../configdialog.ui" line="486"/> + <source>Message delay, ms:</source> + <translation>Задержка сообщения, мс:</translation> + </message> + <message> + <location filename="../configdialog.ui" line="496"/> + <source>Show tray icon</source> + <translation>Показывать системный значок</translation> + </message> + <message> + <location filename="../configdialog.ui" line="75"/> + <source>Appearance</source> + <translation>Внешний вид</translation> + </message> + <message> + <location filename="../configdialog.ui" line="83"/> + <source>Playlist</source> + <translation>Список</translation> + </message> + <message> + <location filename="../configdialog.ui" line="91"/> + <source>Plugins</source> + <translation>Модули</translation> + </message> + <message> + <location filename="../configdialog.ui" line="99"/> + <source>Advanced</source> + <translation>Дополнительно</translation> + </message> + <message> + <location filename="../configdialog.ui" line="585"/> + <source>Close</source> + <translation>Закрыть</translation> + </message> + <message> + <location filename="../configdialog.ui" line="506"/> + <source>Action On Close</source> + <translation>Реакция на закрытие</translation> + </message> + <message> + <location filename="../configdialog.ui" line="518"/> + <source>Hide to tray</source> + <translation>Свернуть в системный лоток</translation> + </message> + <message> + <location filename="../configdialog.ui" line="525"/> + <source>Quit</source> + <translation>Выход</translation> + </message> +</context> +<context> + <name>EqWidget</name> + <message> + <location filename="../eqwidget.cpp" line="172"/> + <source>preset</source> + <translation>предустановка</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="258"/> + <source>&Load/Delete</source> + <translation>&Загрузить/Удалить</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="260"/> + <source>&Save Preset</source> + <translation>&Сохранить предустановку</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="261"/> + <source>&Save Auto-load Preset</source> + <translation>&Сохранить авто-предустановку</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="264"/> + <source>&Clear</source> + <translation>&Очистить</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="293"/> + <source>Saving Preset</source> + <translation>Сохранение предустановки</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="294"/> + <source>Preset name:</source> + <translation>Имя предустановки:</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="295"/> + <source>preset #</source> + <translation>предустановка #</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="262"/> + <source>&Import</source> + <translation>&Импортировать</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="380"/> + <source>Import Preset</source> + <translation>Импорт предустановки</translation> + </message> +</context> +<context> + <name>JumpToTrackDialog</name> + <message> + <location filename="../jumptotrackdialog.cpp" line="122"/> + <source>Unqueue</source> + <translation>Снять с очереди</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="79"/> + <source>Queue</source> + <translation>В очередь</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="13"/> + <source>Jump To Track</source> + <translation>Перейти к треку</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="33"/> + <source>Filter</source> + <translation>Фильтр</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="86"/> + <source>Refresh</source> + <translation>Обновить</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="93"/> + <source>Jump To</source> + <translation>Перейти к</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="100"/> + <source>Close</source> + <translation>Закрыть</translation> + </message> +</context> +<context> + <name>MainWindow</name> + <message> + <location filename="../mainwindow.cpp" line="554"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="297"/> + <source>Now Playing</source> + <translation>Сейчас играет</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="341"/> + <source>Choose a directory</source> + <translation>Выберите директорию</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="355"/> + <source>Select one or more files to open</source> + <translation>Выберите один или несколько файлов</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="502"/> + <source>&Play</source> + <translation>&Воспроизвести</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="502"/> + <source>X</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="503"/> + <source>&Pause</source> + <translation>&Приостановить</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="503"/> + <source>C</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="504"/> + <source>&Stop</source> + <translation>&Стоп</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="504"/> + <source>V</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="505"/> + <source>&Previous</source> + <translation>&Назад</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="505"/> + <source>Z</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="506"/> + <source>&Next</source> + <translation>&Вперёд</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="506"/> + <source>B</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="507"/> + <source>&Queue</source> + <translation>&В очередь</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="507"/> + <source>Q</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="509"/> + <source>&Jump To File</source> + <translation>&Перейти к файлу</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="509"/> + <source>J</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="511"/> + <source>&Settings</source> + <translation>&Настройки</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="511"/> + <source>Ctrl+P</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="516"/> + <source>&Exit</source> + <translation>&Выход</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="516"/> + <source>Ctrl+Q</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="567"/> + <source>Open Playlist</source> + <translation>Открыть список</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="589"/> + <source>Save Playlist</source> + <translation>Сохранить список</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="513"/> + <source>&About</source> + <translation>&О программе</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="588"/> + <source>Playlist Files</source> + <translation>Файлы списков</translation> + </message> +</context> +<context> + <name>PlayList</name> + <message> + <location filename="../playlist.cpp" line="132"/> + <source>F</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../playlist.cpp" line="138"/> + <source>D</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../playlist.cpp" line="163"/> + <source>Alt+I</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../playlist.cpp" line="242"/> + <source>Ctrl+A</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../playlist.cpp" line="256"/> + <source>O</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../playlist.cpp" line="131"/> + <source>&Add File</source> + <translation>&Добавить файл</translation> + </message> + <message> + <location filename="../playlist.cpp" line="137"/> + <source>&Add Directory</source> + <translation>&Добавить директорию</translation> + </message> + <message> + <location filename="../playlist.cpp" line="143"/> + <source>&Remove Selected</source> + <translation>&Удалить выделенное</translation> + </message> + <message> + <location filename="../playlist.cpp" line="150"/> + <source>&Remove All</source> + <translation>&Удалить всё</translation> + </message> + <message> + <location filename="../playlist.cpp" line="156"/> + <source>&Remove Unselected</source> + <translation>&Удалить невыделенное</translation> + </message> + <message> + <location filename="../playlist.cpp" line="162"/> + <source>&View Track Details</source> + <translation>&Информация</translation> + </message> + <message> + <location filename="../playlist.cpp" line="171"/> + <source>Sort List</source> + <translation>Сортировать</translation> + </message> + <message> + <location filename="../playlist.cpp" line="197"/> + <source>By Title</source> + <translation>По названию</translation> + </message> + <message> + <location filename="../playlist.cpp" line="201"/> + <source>By Filename</source> + <translation>По имени файла</translation> + </message> + <message> + <location filename="../playlist.cpp" line="205"/> + <source>By Path + Filename</source> + <translation>По пути и файлу</translation> + </message> + <message> + <location filename="../playlist.cpp" line="209"/> + <source>By Date</source> + <translation>По дате</translation> + </message> + <message> + <location filename="../playlist.cpp" line="195"/> + <source>Sort Selection</source> + <translation>Сортировать выделенное</translation> + </message> + <message> + <location filename="../playlist.cpp" line="219"/> + <source>Randomize List</source> + <translation>Перемешать</translation> + </message> + <message> + <location filename="../playlist.cpp" line="220"/> + <source>Reverse List</source> + <translation>Перевернуть</translation> + </message> + <message> + <location filename="../playlist.cpp" line="227"/> + <source>Invert Selection</source> + <translation>Инвертировать выделение</translation> + </message> + <message> + <location filename="../playlist.cpp" line="234"/> + <source>&Select None</source> + <translation>&Снять выделение</translation> + </message> + <message> + <location filename="../playlist.cpp" line="241"/> + <source>&Select All</source> + <translation>&Выделить всё</translation> + </message> + <message> + <location filename="../playlist.cpp" line="249"/> + <source>&New List</source> + <translation>&Новый лист</translation> + </message> + <message> + <location filename="../playlist.cpp" line="250"/> + <source>Shift+N</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../playlist.cpp" line="255"/> + <source>&Load List</source> + <translation>&Загрузить лист</translation> + </message> + <message> + <location filename="../playlist.cpp" line="260"/> + <source>&Save List</source> + <translation>&Сохранить лист</translation> + </message> + <message> + <location filename="../playlist.cpp" line="261"/> + <source>Shift+S</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../playlist.cpp" line="144"/> + <source>Del</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PresetEditor</name> + <message> + <location filename="../preseteditor.ui" line="13"/> + <source>Preset Editor</source> + <translation>Редактор предустановок</translation> + </message> + <message> + <location filename="../preseteditor.ui" line="28"/> + <source>Load</source> + <translation>Загрузить</translation> + </message> + <message> + <location filename="../preseteditor.ui" line="35"/> + <source>Delete</source> + <translation>Удалить</translation> + </message> + <message> + <location filename="../preseteditor.ui" line="46"/> + <source>Preset</source> + <translation>Предустановка</translation> + </message> + <message> + <location filename="../preseteditor.ui" line="62"/> + <source>Auto-preset</source> + <translation>Авто-предустановка</translation> + </message> +</context> +</TS> diff --git a/src/ui/translations/qmmp_tr.qm b/src/ui/translations/qmmp_tr.qm Binary files differnew file mode 100644 index 000000000..1180e41d5 --- /dev/null +++ b/src/ui/translations/qmmp_tr.qm diff --git a/src/ui/translations/qmmp_tr.ts b/src/ui/translations/qmmp_tr.ts new file mode 100644 index 000000000..73f8206d6 --- /dev/null +++ b/src/ui/translations/qmmp_tr.ts @@ -0,0 +1,644 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS><TS version="1.1"> +<context> + <name>AboutDialog</name> + <message> + <location filename="../aboutdialog.ui" line="13"/> + <source>About Qmmp</source> + <translation>Qmmp Hakkında</translation> + </message> + <message> + <location filename="../aboutdialog.ui" line="42"/> + <source>About</source> + <translation>Hakkında</translation> + </message> + <message> + <location filename="../aboutdialog.ui" line="102"/> + <source>License Agreement</source> + <translation>Lisans Anlaşması</translation> + </message> + <message> + <location filename="../aboutdialog.cpp" line="46"/> + <source>:/html/about_en.html</source> + <translation>:/html/about_en.html</translation> + </message> + <message> + <location filename="../aboutdialog.cpp" line="47"/> + <source>:/html/authors_en.txt</source> + <translation>:/html/authors_en.txt</translation> + </message> + <message> + <location filename="../aboutdialog.cpp" line="48"/> + <source>:/html/thanks_en.txt</source> + <translation>:/html/thanks_en.txt</translation> + </message> + <message> + <location filename="../aboutdialog.ui" line="62"/> + <source>Authors</source> + <translation>Yazarlar</translation> + </message> + <message> + <location filename="../aboutdialog.ui" line="82"/> + <source>Thanks To</source> + <translation>Teşekkürler</translation> + </message> +</context> +<context> + <name>ConfigDialog</name> + <message> + <location filename="../configdialog.cpp" line="179"/> + <source>Enabled</source> + <translation>Etkinleştirildi</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="179"/> + <source>Description</source> + <translation>Açıklama</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="303"/> + <source>Filename</source> + <translation>Dosya adı</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="298"/> + <source>Artist</source> + <translation>Sanatçı</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="299"/> + <source>Album</source> + <translation>Albüm</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="300"/> + <source>Title</source> + <translation>Başlık</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="301"/> + <source>Tracknumber</source> + <translation>Parça Numarası</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="302"/> + <source>Genre</source> + <translation>Tarz</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="304"/> + <source>Filepath</source> + <translation>Dosya yolu</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="305"/> + <source>Date</source> + <translation>Tarih</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="306"/> + <source>Year</source> + <translation>Yıl</translation> + </message> + <message> + <location filename="../configdialog.cpp" line="307"/> + <source>Comment</source> + <translation>Yorum</translation> + </message> + <message> + <location filename="../configdialog.ui" line="13"/> + <source>Qmmp Settings</source> + <translation>Qmmp Ayarları</translation> + </message> + <message> + <location filename="../configdialog.ui" line="134"/> + <source>Skins</source> + <translation>Kabuklar</translation> + </message> + <message> + <location filename="../configdialog.ui" line="165"/> + <source>Fonts</source> + <translation>Fontlar</translation> + </message> + <message> + <location filename="../configdialog.ui" line="183"/> + <source>Player:</source> + <translation>Oynatıcı:</translation> + </message> + <message> + <location filename="../configdialog.ui" line="199"/> + <source>Playlist:</source> + <translation>Çalma Listesi:</translation> + </message> + <message> + <location filename="../configdialog.ui" line="235"/> + <source>???</source> + <translation>???</translation> + </message> + <message> + <location filename="../configdialog.ui" line="309"/> + <source>...</source> + <translation>...</translation> + </message> + <message> + <location filename="../configdialog.ui" line="262"/> + <source>Metadata</source> + <translation>Veri bilgisi</translation> + </message> + <message> + <location filename="../configdialog.ui" line="274"/> + <source>Load metadata from files</source> + <translation>Veri bilgisini dosyadan yükle</translation> + </message> + <message> + <location filename="../configdialog.ui" line="284"/> + <source>Song Display</source> + <translation>Şarkı Göstergesi</translation> + </message> + <message> + <location filename="../configdialog.ui" line="296"/> + <source>Title format:</source> + <translation>Başlık formatı:</translation> + </message> + <message> + <location filename="../configdialog.ui" line="379"/> + <source>Input</source> + <translation>Giriş</translation> + </message> + <message> + <location filename="../configdialog.ui" line="408"/> + <source>Output</source> + <translation>Çıkış</translation> + </message> + <message> + <location filename="../configdialog.ui" line="342"/> + <source>Preferences</source> + <translation>Tercihler</translation> + </message> + <message> + <location filename="../configdialog.ui" line="349"/> + <source>Information</source> + <translation>Bilgi</translation> + </message> + <message> + <location filename="../configdialog.ui" line="444"/> + <source>Tray Icon</source> + <translation>Sistem Çekmecesi Simgesi</translation> + </message> + <message> + <location filename="../configdialog.ui" line="456"/> + <source>Show tooltip</source> + <translation>İpuçlarını göster</translation> + </message> + <message> + <location filename="../configdialog.ui" line="463"/> + <source>Show message</source> + <translation>Mesaj göster</translation> + </message> + <message> + <location filename="../configdialog.ui" line="486"/> + <source>Message delay, ms:</source> + <translation>Mesaj görüntü süresi, ms:</translation> + </message> + <message> + <location filename="../configdialog.ui" line="496"/> + <source>Show tray icon</source> + <translation>Sistem çekmecesi simgesini göster</translation> + </message> + <message> + <location filename="../configdialog.ui" line="75"/> + <source>Appearance</source> + <translation>Görünüm</translation> + </message> + <message> + <location filename="../configdialog.ui" line="83"/> + <source>Playlist</source> + <translation>Çalma Listesi</translation> + </message> + <message> + <location filename="../configdialog.ui" line="91"/> + <source>Plugins</source> + <translation>Eklentiler</translation> + </message> + <message> + <location filename="../configdialog.ui" line="99"/> + <source>Advanced</source> + <translation>Gelişmiş</translation> + </message> + <message> + <location filename="../configdialog.ui" line="585"/> + <source>Close</source> + <translation>Kapat</translation> + </message> + <message> + <location filename="../configdialog.ui" line="506"/> + <source>Action On Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../configdialog.ui" line="518"/> + <source>Hide to tray</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../configdialog.ui" line="525"/> + <source>Quit</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>EqWidget</name> + <message> + <location filename="../eqwidget.cpp" line="172"/> + <source>preset</source> + <translation>tanımlanmış ayar</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="258"/> + <source>&Load/Delete</source> + <translation>&Yükle/Sil</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="260"/> + <source>&Save Preset</source> + <translation>Tanımlanmış &Ayarları Kaydet</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="261"/> + <source>&Save Auto-load Preset</source> + <translation>&Otomatik Tanımlanmış Ayarları Kaydet</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="264"/> + <source>&Clear</source> + <translation>&Temizle</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="293"/> + <source>Saving Preset</source> + <translation>Tanımlanmış Ayarla Kaydediliyor</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="294"/> + <source>Preset name:</source> + <translation>Tanımlanmış ayar adı:</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="295"/> + <source>preset #</source> + <translation>tanımlanmış ayar #</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="262"/> + <source>&Import</source> + <translation>&İçe Aktar</translation> + </message> + <message> + <location filename="../eqwidget.cpp" line="380"/> + <source>Import Preset</source> + <translation>Tanımlanmış Ayarları Al</translation> + </message> +</context> +<context> + <name>JumpToTrackDialog</name> + <message> + <location filename="../jumptotrackdialog.cpp" line="122"/> + <source>Unqueue</source> + <translation>Kuyrukta Değil</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="79"/> + <source>Queue</source> + <translation>Kuyruk</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="13"/> + <source>Jump To Track</source> + <translation>Parçaya Git</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="33"/> + <source>Filter</source> + <translation>Filtre</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="86"/> + <source>Refresh</source> + <translation>Yenile</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="93"/> + <source>Jump To</source> + <translation>Git</translation> + </message> + <message> + <location filename="../jumptotrackdialog.ui" line="100"/> + <source>Close</source> + <translation>Kapat</translation> + </message> +</context> +<context> + <name>MainWindow</name> + <message> + <location filename="../mainwindow.cpp" line="554"/> + <source>Default</source> + <translation>Öntanımlı</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="297"/> + <source>Now Playing</source> + <translation>Şimdi Çalınıyor</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="341"/> + <source>Choose a directory</source> + <translation>Bir dizin seçin</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="355"/> + <source>Select one or more files to open</source> + <translation>Açmak için bir yada daha çok dosya seçin</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="502"/> + <source>&Play</source> + <translation>&Çal</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="502"/> + <source>X</source> + <translation>X</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="503"/> + <source>&Pause</source> + <translation>&Duraklat</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="503"/> + <source>C</source> + <translation>C</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="504"/> + <source>&Stop</source> + <translation>&Durdur</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="504"/> + <source>V</source> + <translation>V</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="505"/> + <source>&Previous</source> + <translation>&Önceki</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="505"/> + <source>Z</source> + <translation>Z</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="506"/> + <source>&Next</source> + <translation>&Sonraki</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="506"/> + <source>B</source> + <translation>B</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="507"/> + <source>&Queue</source> + <translation>&Kuyruğa ekle</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="507"/> + <source>Q</source> + <translation>Q</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="509"/> + <source>&Jump To File</source> + <translation>&Parçaya Git</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="509"/> + <source>J</source> + <translation>J</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="511"/> + <source>&Settings</source> + <translation>&Ayarlar</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="511"/> + <source>Ctrl+P</source> + <translation>Ctrl+P</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="516"/> + <source>&Exit</source> + <translation>&Çıkış</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="516"/> + <source>Ctrl+Q</source> + <translation>Ctrl+Q</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="567"/> + <source>Open Playlist</source> + <translation>Çalma Listesini Aç</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="589"/> + <source>Save Playlist</source> + <translation>Çalma Listesini Kaydet</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="513"/> + <source>&About</source> + <translation>&Hakkında</translation> + </message> + <message> + <location filename="../mainwindow.cpp" line="588"/> + <source>Playlist Files</source> + <translation>Çalma Listesi Dosyaları</translation> + </message> +</context> +<context> + <name>PlayList</name> + <message> + <location filename="../playlist.cpp" line="132"/> + <source>F</source> + <translation>F</translation> + </message> + <message> + <location filename="../playlist.cpp" line="138"/> + <source>D</source> + <translation>D</translation> + </message> + <message> + <location filename="../playlist.cpp" line="163"/> + <source>Alt+I</source> + <translation>Alt+I</translation> + </message> + <message> + <location filename="../playlist.cpp" line="242"/> + <source>Ctrl+A</source> + <translation>Ctrl+A</translation> + </message> + <message> + <location filename="../playlist.cpp" line="256"/> + <source>O</source> + <translation>O</translation> + </message> + <message> + <location filename="../playlist.cpp" line="131"/> + <source>&Add File</source> + <translation>&Dosya Ekle</translation> + </message> + <message> + <location filename="../playlist.cpp" line="137"/> + <source>&Add Directory</source> + <translation>&Dizin Ekle</translation> + </message> + <message> + <location filename="../playlist.cpp" line="143"/> + <source>&Remove Selected</source> + <translation>&Seçileni Kaldır</translation> + </message> + <message> + <location filename="../playlist.cpp" line="150"/> + <source>&Remove All</source> + <translation>&Hepsini Kaldır</translation> + </message> + <message> + <location filename="../playlist.cpp" line="156"/> + <source>&Remove Unselected</source> + <translation>&Seçilmemişleri Kaldır</translation> + </message> + <message> + <location filename="../playlist.cpp" line="162"/> + <source>&View Track Details</source> + <translation>&Parça Detaylarını Göster</translation> + </message> + <message> + <location filename="../playlist.cpp" line="171"/> + <source>Sort List</source> + <translation>Listeyi Sınıflandır</translation> + </message> + <message> + <location filename="../playlist.cpp" line="197"/> + <source>By Title</source> + <translation>Başlığa Göre</translation> + </message> + <message> + <location filename="../playlist.cpp" line="201"/> + <source>By Filename</source> + <translation>Dosya Adına Göre</translation> + </message> + <message> + <location filename="../playlist.cpp" line="205"/> + <source>By Path + Filename</source> + <translation>Dosya Yolu + Dosya Adına Göre</translation> + </message> + <message> + <location filename="../playlist.cpp" line="209"/> + <source>By Date</source> + <translation>Tarihe Göre</translation> + </message> + <message> + <location filename="../playlist.cpp" line="195"/> + <source>Sort Selection</source> + <translation>Seçilenleri Sınıflandır</translation> + </message> + <message> + <location filename="../playlist.cpp" line="219"/> + <source>Randomize List</source> + <translation>Rastgele Listele</translation> + </message> + <message> + <location filename="../playlist.cpp" line="220"/> + <source>Reverse List</source> + <translation>Listeyi Ters Çevir</translation> + </message> + <message> + <location filename="../playlist.cpp" line="227"/> + <source>Invert Selection</source> + <translation>Seçimi Tersine Çevir</translation> + </message> + <message> + <location filename="../playlist.cpp" line="234"/> + <source>&Select None</source> + <translation>&Hiçbirini Seçme</translation> + </message> + <message> + <location filename="../playlist.cpp" line="241"/> + <source>&Select All</source> + <translation>&Tümünü Seç</translation> + </message> + <message> + <location filename="../playlist.cpp" line="249"/> + <source>&New List</source> + <translation>&Yeni Liste</translation> + </message> + <message> + <location filename="../playlist.cpp" line="250"/> + <source>Shift+N</source> + <translation>Shift+N</translation> + </message> + <message> + <location filename="../playlist.cpp" line="255"/> + <source>&Load List</source> + <translation>&Liste Yükle</translation> + </message> + <message> + <location filename="../playlist.cpp" line="260"/> + <source>&Save List</source> + <translation>&Listeyi Kaydet</translation> + </message> + <message> + <location filename="../playlist.cpp" line="261"/> + <source>Shift+S</source> + <translation>Shift+S</translation> + </message> + <message> + <location filename="../playlist.cpp" line="144"/> + <source>Del</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PresetEditor</name> + <message> + <location filename="../preseteditor.ui" line="13"/> + <source>Preset Editor</source> + <translation>Tanımlanmış Ayar Düzenleyici</translation> + </message> + <message> + <location filename="../preseteditor.ui" line="28"/> + <source>Load</source> + <translation>Yükle</translation> + </message> + <message> + <location filename="../preseteditor.ui" line="35"/> + <source>Delete</source> + <translation>Sil</translation> + </message> + <message> + <location filename="../preseteditor.ui" line="46"/> + <source>Preset</source> + <translation>Tanımlanmış Ayar</translation> + </message> + <message> + <location filename="../preseteditor.ui" line="62"/> + <source>Auto-preset</source> + <translation>Ayarları Otomatik Tanımla</translation> + </message> +</context> +</TS> diff --git a/src/ui/translations/qmmp_zh_CN.qm b/src/ui/translations/qmmp_zh_CN.qm Binary files differnew file mode 100644 index 000000000..2e3e3f2ea --- /dev/null +++ b/src/ui/translations/qmmp_zh_CN.qm diff --git a/src/ui/translations/qmmp_zh_CN.ts b/src/ui/translations/qmmp_zh_CN.ts new file mode 100644 index 000000000..3aeefd569 --- /dev/null +++ b/src/ui/translations/qmmp_zh_CN.ts @@ -0,0 +1,507 @@ +<!DOCTYPE TS><TS> +<context> + <name>AboutDialog</name> + <message> + <source>About Qmmp</source> + <translation>关于 Qmmp</translation> + </message> + <message> + <source>About</source> + <translation>关于</translation> + </message> + <message> + <source>License Agreement</source> + <translation>许可协议</translation> + </message> + <message> + <source>:/html/about_en.html</source> + <translation>:/html/about_zh_CN.html</translation> + </message> + <message> + <source>:/html/authors_en.txt</source> + <translation>:/html/authors_zh_CN.txt</translation> + </message> + <message> + <source>:/html/thanks_en.txt</source> + <translation>:/html/thanks_zh_CN.txt</translation> + </message> + <message> + <source>Authors</source> + <translation>作者</translation> + </message> + <message> + <source>Thanks To</source> + <translation>感谢</translation> + </message> +</context> +<context> + <name>ConfigDialog</name> + <message> + <source>Enabled</source> + <translation>启用</translation> + </message> + <message> + <source>Description</source> + <translation>描述</translation> + </message> + <message> + <source>Filename</source> + <translation>文件名</translation> + </message> + <message> + <source>Artist</source> + <translation>艺术家</translation> + </message> + <message> + <source>Album</source> + <translation>专辑</translation> + </message> + <message> + <source>Title</source> + <translation>标题</translation> + </message> + <message> + <source>Tracknumber</source> + <translation>轨迹</translation> + </message> + <message> + <source>Genre</source> + <translation>流派</translation> + </message> + <message> + <source>Filepath</source> + <translation>文件路径</translation> + </message> + <message> + <source>Date</source> + <translation>日期</translation> + </message> + <message> + <source>Year</source> + <translation>年</translation> + </message> + <message> + <source>Comment</source> + <translation>注释</translation> + </message> + <message> + <source>Qmmp Settings</source> + <translation>Qmmp 设置</translation> + </message> + <message> + <source>Skins</source> + <translation>皮肤</translation> + </message> + <message> + <source>Fonts</source> + <translation>字体</translation> + </message> + <message> + <source>Player:</source> + <translation>播放器:</translation> + </message> + <message> + <source>Playlist:</source> + <translation>播放列表:</translation> + </message> + <message> + <source>???</source> + <translation>???</translation> + </message> + <message> + <source>...</source> + <translation>...</translation> + </message> + <message> + <source>Metadata</source> + <translation>元数据</translation> + </message> + <message> + <source>Load metadata from files</source> + <translation>从文件载入元数据</translation> + </message> + <message> + <source>Song Display</source> + <translation>显示歌曲</translation> + </message> + <message> + <source>Title format:</source> + <translation>标题格式:</translation> + </message> + <message> + <source>Input</source> + <translation>输入</translation> + </message> + <message> + <source>Output</source> + <translation>输出</translation> + </message> + <message> + <source>Preferences</source> + <translation>参数设置</translation> + </message> + <message> + <source>Information</source> + <translation>信息</translation> + </message> + <message> + <source>Tray Icon</source> + <translation>托盘图标</translation> + </message> + <message> + <source>Show tooltip</source> + <translation>显示工具栏</translation> + </message> + <message> + <source>Show message</source> + <translation>显示通知</translation> + </message> + <message> + <source>Message delay, ms:</source> + <translation>消息延迟,毫秒:</translation> + </message> + <message> + <source>Show tray icon</source> + <translation>显示托盘图标</translation> + </message> + <message> + <source>Appearance</source> + <translation>外观</translation> + </message> + <message> + <source>Playlist</source> + <translation>播放列表</translation> + </message> + <message> + <source>Plugins</source> + <translation>插件</translation> + </message> + <message> + <source>Advanced</source> + <translation>高级</translation> + </message> + <message> + <source>Close</source> + <translation>关闭</translation> + </message> +</context> +<context> + <name>EqWidget</name> + <message> + <source>preset</source> + <translation>预设</translation> + </message> + <message> + <source>&Load/Delete</source> + <translation>载入/删除(&L)</translation> + </message> + <message> + <source>&Save Preset</source> + <translation>保存预设(&S)</translation> + </message> + <message> + <source>&Save Auto-load Preset</source> + <translation>保存自动载入预设(&S)</translation> + </message> + <message> + <source>&Clear</source> + <translation>清除(&C)</translation> + </message> + <message> + <source>Saving Preset</source> + <translation>保存预设</translation> + </message> + <message> + <source>Preset name:</source> + <translation>预设名字:</translation> + </message> + <message> + <source>preset #</source> + <translation>预设 #</translation> + </message> + <message> + <source>&Import</source> + <translation>导入(&I)</translation> + </message> + <message> + <source>Import Preset</source> + <translation>导入预设</translation> + </message> +</context> +<context> + <name>JumpToTrackDialog</name> + <message> + <source>Unqueue</source> + <translation>移出队列</translation> + </message> + <message> + <source>Queue</source> + <translation>加入队列</translation> + </message> + <message> + <source>Jump To Track</source> + <translation>跳跃至音轨</translation> + </message> + <message> + <source>Filter</source> + <translation>过滤</translation> + </message> + <message> + <source>Refresh</source> + <translation>刷新</translation> + </message> + <message> + <source>Jump To</source> + <translation>跳跃至</translation> + </message> + <message> + <source>Close</source> + <translation>关闭</translation> + </message> +</context> +<context> + <name>MainWindow</name> + <message> + <source>Default</source> + <translation>默认</translation> + </message> + <message> + <source>Now Playing</source> + <translation>正在播放</translation> + </message> + <message> + <source>Choose a directory</source> + <translation>选择一个目录</translation> + </message> + <message> + <source>Select one or more files to open</source> + <translation>选择打开一个或更多文件</translation> + </message> + <message> + <source>&Play</source> + <translation>播放(&P)</translation> + </message> + <message> + <source>X</source> + <translation>X</translation> + </message> + <message> + <source>&Pause</source> + <translation>暂停(&P)</translation> + </message> + <message> + <source>C</source> + <translation>C</translation> + </message> + <message> + <source>&Stop</source> + <translation>停止(&S)</translation> + </message> + <message> + <source>V</source> + <translation>V</translation> + </message> + <message> + <source>&Previous</source> + <translation>上一个(&P)</translation> + </message> + <message> + <source>Z</source> + <translation>Z</translation> + </message> + <message> + <source>&Next</source> + <translation>下一个(&N)</translation> + </message> + <message> + <source>B</source> + <translation>B</translation> + </message> + <message> + <source>&Queue</source> + <translation>队列&Q)</translation> + </message> + <message> + <source>Q</source> + <translation>Q</translation> + </message> + <message> + <source>&Jump To File</source> + <translation>跳跃至文件(&J)</translation> + </message> + <message> + <source>J</source> + <translation>J</translation> + </message> + <message> + <source>&Settings</source> + <translation>设置(&S)</translation> + </message> + <message> + <source>Ctrl+P</source> + <translation>Ctrl+P</translation> + </message> + <message> + <source>&Exit</source> + <translation>退出(&E)</translation> + </message> + <message> + <source>Ctrl+Q</source> + <translation>Q</translation> + </message> + <message> + <source>Open Playlist</source> + <translation>打开播放列表</translation> + </message> + <message> + <source>Save Playlist</source> + <translation>保存播放列表</translation> + </message> + <message> + <source>&About</source> + <translation>关于(&A)</translation> + </message> + <message> + <source>Playlist Files</source> + <translation>播放列表文件</translation> + </message> +</context> +<context> + <name>PlayList</name> + <message> + <source>F</source> + <translation>F</translation> + </message> + <message> + <source>D</source> + <translation>D</translation> + </message> + <message> + <source>Delete</source> + <translation>删除</translation> + </message> + <message> + <source>Alt+I</source> + <translation>Alt+I</translation> + </message> + <message> + <source>Ctrl+A</source> + <translation>Ctrl+A</translation> + </message> + <message> + <source>O</source> + <translation>O</translation> + </message> + <message> + <source>&Add File</source> + <translation>添加文件(&A)</translation> + </message> + <message> + <source>&Add Directory</source> + <translation>添加文件夹(&A)</translation> + </message> + <message> + <source>&Remove Selected</source> + <translation>移除所选(&R)</translation> + </message> + <message> + <source>&Remove All</source> + <translation>移除全部(&R)</translation> + </message> + <message> + <source>&Remove Unselected</source> + <translation>移除未选(&R)</translation> + </message> + <message> + <source>&View Track Details</source> + <translation>查看音轨详细信息(&V)</translation> + </message> + <message> + <source>Sort List</source> + <translation>列表排序</translation> + </message> + <message> + <source>By Title</source> + <translation>按标题</translation> + </message> + <message> + <source>By Filename</source> + <translation>按文件名</translation> + </message> + <message> + <source>By Path + Filename</source> + <translation>按路径+文件名</translation> + </message> + <message> + <source>By Date</source> + <translation>按日期</translation> + </message> + <message> + <source>Sort Selection</source> + <translation>选择排序</translation> + </message> + <message> + <source>Randomize List</source> + <translation>随机产生列表</translation> + </message> + <message> + <source>Reverse List</source> + <translation>逆序列表</translation> + </message> + <message> + <source>Invert Selection</source> + <translation>反选</translation> + </message> + <message> + <source>&Select None</source> + <translation>选择无(&S)</translation> + </message> + <message> + <source>&Select All</source> + <translation>全选(&S)</translation> + </message> + <message> + <source>&New List</source> + <translation>新建列表(&N)</translation> + </message> + <message> + <source>Shift+N</source> + <translation>Shift+N</translation> + </message> + <message> + <source>&Load List</source> + <translation>载入列表(&L)</translation> + </message> + <message> + <source>&Save List</source> + <translation>保存列表(&S)</translation> + </message> + <message> + <source>Shift+S</source> + <translation>Shift+S</translation> + </message> +</context> +<context> + <name>PresetEditor</name> + <message> + <source>Preset Editor</source> + <translation>预设编辑器</translation> + </message> + <message> + <source>Load</source> + <translation>装入</translation> + </message> + <message> + <source>Delete</source> + <translation>删除</translation> + </message> + <message> + <source>Preset</source> + <translation>预设</translation> + </message> + <message> + <source>Auto-preset</source> + <translation>预设自动</translation> + </message> +</context> +</TS> diff --git a/src/ui/ui.pro b/src/ui/ui.pro new file mode 100644 index 000000000..527c205f2 --- /dev/null +++ b/src/ui/ui.pro @@ -0,0 +1,149 @@ +# ???? ?????? ? KDevelop ?????????? qmake. +# ------------------------------------------- +# ?????????? ???????????? ???????? ???????? ???????: ./src +# ???? - ??????????: ../bin/mp3player + +include(../qmmp.pri) + +FORMS += ./forms/configdialog.ui \ + ./forms/preseteditor.ui \ + ./forms/jumptotrackdialog.ui \ + ./forms/aboutdialog.ui \ + ./forms/addurldialog.ui + +HEADERS += mainwindow.h \ + fileloader.h \ + button.h \ + display.h \ + skin.h \ + titlebar.h \ + positionbar.h \ + number.h \ + playlist.h \ + mediafile.h \ + listwidget.h \ + playlistmodel.h \ + pixmapwidget.h \ + playlisttitlebar.h \ + configdialog.h \ + playlistslider.h \ + dock.h \ + eqwidget.h \ + eqtitlebar.h \ + eqslider.h \ + togglebutton.h \ + eqgraph.h \ + mainvisual.h \ + inlines.h \ + fft.h \ + logscale.h \ + textscroller.h \ + monostereo.h \ + playstatus.h \ + pluginitem.h \ + volumebar.h \ + balancebar.h \ + playstate.h \ + symboldisplay.h \ + playlistformat.h \ + playlistcontrol.h \ + version.h \ + qmmpstarter.h \ + eqpreset.h \ + preseteditor.h \ + jumptotrackdialog.h \ + aboutdialog.h \ + timeindicator.h \ + keyboardmanager.h \ + filedialog.h \ + unixdomainsocket.h \ + commandlineoption.h \ + addurldialog.h \ + skinreader.h \ + visualmenu.h \ + titlebarcontrol.h \ + shadedvisual.h \ + shadedbar.h + +SOURCES += mainwindow.cpp \ + mp3player.cpp \ + fileloader.cpp \ + button.cpp \ + display.cpp \ + skin.cpp \ + titlebar.cpp \ + positionbar.cpp \ + number.cpp \ + playlist.cpp \ + mediafile.cpp \ + listwidget.cpp \ + playlistmodel.cpp \ + pixmapwidget.cpp \ + playlisttitlebar.cpp \ + configdialog.cpp \ + playlistslider.cpp \ + dock.cpp \ + eqwidget.cpp \ + eqtitlebar.cpp \ + eqslider.cpp \ + togglebutton.cpp \ + eqgraph.cpp \ + mainvisual.cpp \ + fft.c \ + logscale.cpp \ + textscroller.cpp \ + monostereo.cpp \ + playstatus.cpp \ + pluginitem.cpp \ + volumebar.cpp \ + balancebar.cpp \ + playstate.cpp \ + symboldisplay.cpp \ + playlistformat.cpp \ + playlistcontrol.cpp \ + qmmpstarter.cpp \ + eqpreset.cpp \ + preseteditor.cpp \ + jumptotrackdialog.cpp \ + aboutdialog.cpp \ + timeindicator.cpp \ + keyboardmanager.cpp \ + filedialog.cpp \ + unixdomainsocket.cpp \ + commandlineoption.cpp \ + addurldialog.cpp \ + skinreader.cpp \ + visualmenu.cpp \ + titlebarcontrol.cpp \ + shadedvisual.cpp \ + shadedbar.cpp + +#Some conf to redirect intermediate stuff in separate dirs +UI_DIR=./.build/ui/ +MOC_DIR=./.build/moc/ +OBJECTS_DIR=./.build/obj + + +QT += network xml +TARGET = ../../bin/qmmp +CONFIG += thread release \ +warn_on +QMAKE_LIBDIR += ../../lib qmmpui +LIBS += -Wl,-rpath,../lib +LIBS += -L../../lib -lqmmp -lqmmpui +INCLUDEPATH += ../qmmp ../ +RESOURCES = images/images.qrc \ + stuff.qrc +TEMPLATE = app +target.path = /bin +INSTALLS += target + + +#RESOURCES += translations/qmmp_locales.qrc + +#TRANSLATIONS = translations/qmmp_ru.ts \ +# translations/qmmp_tr.ts \ +# translations/qmmp_zh_CN.ts + + + diff --git a/src/ui/unixdomainsocket.cpp b/src/ui/unixdomainsocket.cpp new file mode 100644 index 000000000..5769676be --- /dev/null +++ b/src/ui/unixdomainsocket.cpp @@ -0,0 +1,67 @@ +#include <unistd.h> +#include <strings.h> +#include <string.h> +#include <errno.h> + +#include "unixdomainsocket.h" + + +UnixDomainSocket::UnixDomainSocket(QObject * parent ) : QUdpSocket(parent){ + _bound = false; + _s = socket(AF_UNIX, SOCK_DGRAM, 0); + this->setSocketDescriptor(_s); +} + +UnixDomainSocket::~UnixDomainSocket(){ + + if(_bound){ + ::unlink(_local.sun_path); + } +} + +bool UnixDomainSocket::bind(const QString& path){ + + int len; + bzero(&_local,sizeof(_local)); + _local.sun_family = AF_UNIX; + strcpy(_local.sun_path,path.toLocal8Bit().data()); + len = strlen(_local.sun_path) + sizeof(_local.sun_family); + bool res = !(::bind(_s, (struct sockaddr *)&_local, len)); + if(res) + _bound = true; + return res; +} + + +bool UnixDomainSocket::alive(const QString& path) +{ + socklen_t len; + struct sockaddr_un server; + bzero(&server,sizeof(server)); + server.sun_family = AF_UNIX; + strcpy(server.sun_path,path.toLocal8Bit().data()); + len = strlen(server.sun_path) + sizeof(server.sun_family); + + if (::connect(_s, (struct sockaddr *)&server, len) == -1) + { + perror("connect"); + return false; + } + return true; +} +// +void UnixDomainSocket::writeDatagram(const char* command,const QString& path) +{ + socklen_t len; + struct sockaddr_un server; + bzero(&server,sizeof(server)); + server.sun_family = AF_UNIX; + strcpy(server.sun_path,path.toLocal8Bit().data()); + + len = strlen(server.sun_path) + sizeof(server.sun_family); + + sendto(_s,command,strlen(command),0,(struct sockaddr*)&server,len); +} + + + diff --git a/src/ui/unixdomainsocket.h b/src/ui/unixdomainsocket.h new file mode 100644 index 000000000..37e5a364b --- /dev/null +++ b/src/ui/unixdomainsocket.h @@ -0,0 +1,46 @@ +#ifndef UNIXDOMAINSOCKET_H +#define UNIXDOMAINSOCKET_H + +#include <QUdpSocket> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/types.h> +#include <linux/un.h> + + +/*! + * UnixDomainSocket class is a wrapper around the unix domain sockets implementation. + * Used for QMMP interprocess communications. + * @author Vladimir Kuznetsov <vovanec@gmail.com> + */ +class UnixDomainSocket : public QUdpSocket +{ +Q_OBJECT +public: + UnixDomainSocket(QObject * parent = 0 ); + + /*! + * Try to bind socket to \b path. Returns \b true on success, otherwise \b false + */ + bool bind(const QString& file); + + /*! + * Checks if socket at \b path path is alive( i.e. connectable). + */ + bool alive(const QString& path); + ~UnixDomainSocket(); + +public slots: + /*! + * Sends the datagram \b command to the socket at \b path path. + */ + void writeDatagram(const char* command,const QString& path); +private: + unsigned int _s; + struct sockaddr_un _local; + bool _bound; +}; + + +#endif + diff --git a/src/ui/version.h b/src/ui/version.h new file mode 100644 index 000000000..61fbc902e --- /dev/null +++ b/src/ui/version.h @@ -0,0 +1,11 @@ +#ifndef _QMMP_VERSION_H +#define _QMMP_VERSION_H + +#define QMMP_VERSION 0.1.4 + +#define QMMP_STR_VERSION "0.1.4" + +#define LISTEN_PORT_BASE 33000 +#define UDS_PATH "/tmp/qmmp.sock" + +#endif diff --git a/src/ui/visualmenu.cpp b/src/ui/visualmenu.cpp new file mode 100644 index 000000000..2b0ad6797 --- /dev/null +++ b/src/ui/visualmenu.cpp @@ -0,0 +1,53 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QAction> + +#include <visual.h> +#include <visualfactory.h> + +#include "pluginitem.h" +#include "visualmenu.h" + +VisualMenu::VisualMenu(QWidget *parent) + : QMenu(tr("Visualization"), parent) +{ + VisualFactory *factory = 0; + foreach(factory, *Visual::visualFactories()) + { + QAction *act = this->addAction(factory->properties().name); + act->setCheckable (TRUE); + act->setChecked (Visual::isEnabled(factory)); + VisualPluginItem *vi = new VisualPluginItem(this,factory, ""); + connect(act, SIGNAL(toggled(bool)), vi, SLOT(select(bool))); + } +} + +VisualMenu::~VisualMenu() +{ +} + +void VisualMenu::updateActions() +{ + for(int i = 0; i < Visual::visualFactories()->size(); ++i) + { + actions()[i]->setChecked(Visual::isEnabled(Visual::visualFactories()->at(i))); + } +} diff --git a/src/ui/visualmenu.h b/src/ui/visualmenu.h new file mode 100644 index 000000000..9202a8a7d --- /dev/null +++ b/src/ui/visualmenu.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef VISUALMENU_H +#define VISUALMENU_H + +#include <QMenu> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class VisualMenu : public QMenu +{ +Q_OBJECT +public: + VisualMenu(QWidget *parent = 0); + + ~VisualMenu(); + +void updateActions(); + +}; + +#endif diff --git a/src/ui/volumebar.cpp b/src/ui/volumebar.cpp new file mode 100644 index 000000000..15c7db867 --- /dev/null +++ b/src/ui/volumebar.cpp @@ -0,0 +1,130 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QMouseEvent> +#include <QPainter> +#include <math.h> + +#include "skin.h" +#include "button.h" +#include "mainwindow.h" + +#include "volumebar.h" + + +VolumeBar::VolumeBar(QWidget *parent) + : PixmapWidget(parent) +{ + m_skin = Skin::getPointer(); + connect(m_skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); + setPixmap(m_skin->getVolumeBar(0)); + mw = qobject_cast<MainWindow*>(window()); + m_moving = FALSE; + m_min = 0; + m_max = 100; + m_old = m_value = 0; + draw(FALSE); +} + + +VolumeBar::~VolumeBar() +{} + +void VolumeBar::mousePressEvent(QMouseEvent *e) +{ + + m_moving = TRUE; + press_pos = e->x(); + if(m_pos<e->x() && e->x()<m_pos+11) + { + press_pos = e->x()-m_pos; + } + else + { + m_value = convert(qMax(qMin(width()-18,e->x()-6),0)); + press_pos = 6; + if (m_value!=m_old) + { + emit sliderMoved(m_value); + + } + } + draw(); +} + +void VolumeBar::mouseMoveEvent (QMouseEvent *e) +{ + if(m_moving) + { + int po = e->x(); + po = po - press_pos; + + if(0<=po && po<=width()-18) + { + m_value = convert(po); + draw(); + emit sliderMoved(m_value); + } + } +} + +void VolumeBar::mouseReleaseEvent(QMouseEvent*) +{ + m_moving = FALSE; + draw(FALSE); + m_old = m_value; +} + +void VolumeBar::setValue(int v) +{ + if (m_moving || m_max == 0) + return; + m_value = v; + draw(FALSE); +} + +void VolumeBar::setMax(int max) +{ + m_max = max; + draw(FALSE); +} + +void VolumeBar::updateSkin() +{ + draw(FALSE); +} + +void VolumeBar::draw(bool pressed) +{ + int p=int(ceil(double(m_value-m_min)*(width()-18)/(m_max-m_min))); + m_pixmap = m_skin->getVolumeBar(27*(m_value-m_min)/(m_max-m_min)); + QPainter paint(&m_pixmap); + if(pressed) + paint.drawPixmap(p,1,m_skin->getButton(Skin::BT_VOL_P)); + else + paint.drawPixmap(p,1,m_skin->getButton(Skin::BT_VOL_N)); + setPixmap(m_pixmap); + m_pos = p; +} + +int VolumeBar::convert(int p) +{ + return int(ceil(double(m_max-m_min)*(p)/(width()-18)+m_min)); +} diff --git a/src/ui/volumebar.h b/src/ui/volumebar.h new file mode 100644 index 000000000..51bc7ac46 --- /dev/null +++ b/src/ui/volumebar.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef VOLUMEBAR_H +#define VOLUMEBAR_H + +#include <pixmapwidget.h> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + +class Skin; +class MainWindow; + +class VolumeBar : public PixmapWidget +{ +Q_OBJECT +public: + VolumeBar(QWidget *parent = 0); + + ~VolumeBar(); + + int value() { return m_value; }; + int isPressed() {return m_moving; } + +public slots: + void setValue(int); + void setMax(int); + +signals: + void sliderMoved (int); + +private slots: + void updateSkin(); + +private: + Skin *m_skin; + bool m_moving; + int press_pos; + int m_max, m_min, m_pos, m_value, m_old; + QPixmap m_pixmap; + MainWindow *mw; + int convert(int); // value = convert(position); + void draw(bool pressed = TRUE); + +protected: + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + + +}; + +#endif |
