diff options
Diffstat (limited to 'src')
140 files changed, 17238 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 000000000..a7dd13e8a --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,158 @@ +project(libsrc) + +cmake_minimum_required(VERSION 2.4.0) + +SET(QT_USE_QTXML TRUE) +SET(QT_USE_QTNETWORK TRUE) + +INCLUDE(UsePkgConfig) +INCLUDE(FindQt4) + +find_package(Qt4 REQUIRED) # find and setup Qt4 for this project +include(${QT_USE_FILE}) + +ADD_DEFINITIONS( -Wall ) +ADD_DEFINITIONS(-DQT_NO_DEBUG) +ADD_DEFINITIONS(-DQT_THREAD) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +SET(QT_INCLUDES + ${QT_INCLUDES} + ${CMAKE_CURRENT_BINARY_DIR}/../../../ +) + +# libqmmp +include_directories(${CMAKE_CURRENT_BINARY_DIR}/../lib) +link_directories(${CMAKE_CURRENT_BINARY_DIR}/../lib) +link_directories(${CMAKE_INSTALL_PREFIX}/lib) + +SET(libsrc_SRCS + 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 + tcpserver.cpp + guard.cpp + eqpreset.cpp + preseteditor.cpp + jumptotrackdialog.cpp + aboutdialog.cpp + timeindicator.cpp + keyboardmanager.cpp +) + +SET(libsrc_MOC_HDRS + 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 + tcpserver.h + qmmpstarter.h + guard.h + eqpreset.h + preseteditor.h + jumptotrackdialog.h + aboutdialog.h + timeindicator.h + keyboardmanager.h +) + +SET(libsrc_RCCS images/images.qrc stuff.qrc translations/qmmp_locales.qrc) + +QT4_ADD_RESOURCES(libsrc_RCC_SRCS ${libsrc_RCCS}) + +QT4_AUTOMOC(${libsrc_MOC_SRC}) +QT4_WRAP_CPP(libsrc_MOC_SRCS ${libsrc_MOC_HDRS}) + +# user interface + + +SET(libsrc_UIS + configdialog.ui + preseteditor.ui + jumptotrackdialog.ui + aboutdialog.ui +) + +SET(src_FILES + ../bin/qmmp +) + +QT4_WRAP_UI(libsrc_UIS_H ${libsrc_UIS}) +# Don't forget to include output directory, otherwise +# the UI file won't be wrapped! +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +ADD_EXECUTABLE(qmmp.real ${libsrc_SRCS} ${libsrc_MOC_SRCS} ${libsrc_UIS_H} + ${libsrc_RCC_SRCS}) +target_link_libraries(qmmp.real ${QT_LIBRARIES} -lqmmp) +install(TARGETS qmmp.real DESTINATION bin PERMISSIONS WORLD_EXECUTE OWNER_READ OWNER_WRITE) +install(FILES ${src_FILES} DESTINATION bin PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ +WORLD_EXECUTE WORLD_READ) diff --git a/src/aboutdialog.cpp b/src/aboutdialog.cpp new file mode 100644 index 000000000..d9d1d0043 --- /dev/null +++ b/src/aboutdialog.cpp @@ -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. * +***************************************************************************/ + + +#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); + 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/aboutdialog.h b/src/aboutdialog.h new file mode 100644 index 000000000..10dcde4a5 --- /dev/null +++ b/src/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/aboutdialog.ui b/src/aboutdialog.ui new file mode 100644 index 000000000..56fbef9c5 --- /dev/null +++ b/src/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/balancebar.cpp b/src/balancebar.cpp new file mode 100644 index 000000000..32792b327 --- /dev/null +++ b/src/balancebar.cpp @@ -0,0 +1,136 @@ +/*************************************************************************** + * 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); + if (m_value!=m_old) + { + 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/balancebar.h b/src/balancebar.h new file mode 100644 index 000000000..6704671f9 --- /dev/null +++ b/src/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/button.cpp b/src/button.cpp new file mode 100644 index 000000000..8bd006ed3 --- /dev/null +++ b/src/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/button.h b/src/button.h new file mode 100644 index 000000000..7f2d8f314 --- /dev/null +++ b/src/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/configdialog.cpp b/src/configdialog.cpp new file mode 100644 index 000000000..e91139efc --- /dev/null +++ b/src/configdialog.cpp @@ -0,0 +1,334 @@ +/*************************************************************************** + * 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 <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 "skin.h" +#include "pluginitem.h" +#include "configdialog.h" + +ConfigDialog::ConfigDialog ( QWidget *parent ) + : QDialog ( parent ) +{ + ui.setupUi ( this ); + 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(); + readSettings(); + loadSkins(); + loadPluginsInfo(); + loadFonts(); + createMenus(); +} + +ConfigDialog::~ConfigDialog() +{ + while (!m_outputPluginItems.isEmpty()) + delete m_outputPluginItems.takeFirst(); + while (!m_inputPluginItems.isEmpty()) + delete m_outputPluginItems.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()); + ui.trayCheckBox->setChecked( + settings.value("Tray/enabled",TRUE).toBool()); + ui.messageCheckBox->setChecked( + settings.value("Tray/show_message",TRUE).toBool()); + ui.messageDelaySpinBox->setValue(settings.value("Tray/message_delay", + 2000).toInt()); + ui.messageCheckBox->setEnabled(ui.trayCheckBox->isChecked()); + ui.messageDelaySpinBox->setEnabled(ui.trayCheckBox->isChecked() || + ui.messageCheckBox->isChecked() ); + ui.toolTipCheckBox->setEnabled(ui.trayCheckBox->isChecked()); + ui.toolTipCheckBox->setChecked( + settings.value("Tray/show_tooltip",FALSE).toBool()); + + ui.hideToTrayRadioButton->setChecked(settings.value("Tray/hide_on_close", FALSE).toBool()); + ui.closeGroupBox->setEnabled(ui.trayCheckBox->isChecked()); +} + +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"); + connect ( ui.listWidget, SIGNAL ( itemClicked ( QListWidgetItem* ) ), + this, SLOT ( changeSkin() ) ); +} + +void ConfigDialog::findSkins(const QString &path) +{ + QDir dir(path); + dir.setFilter ( QDir::Dirs ); + QList <QFileInfo> fileList = dir.entryInfoList(); + if ( fileList.count() == 2 ) + return; + for ( int i = 2; i < fileList.size(); ++i ) + { + QFileInfo fileInfo = fileList.at ( i ); + 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()->name()) ); + ui.inputPluginTable->setItem ( i,2, new QTableWidgetItem (files.at (i)) ); + } + 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()->name())); + ui.outputPluginTable->setItem (i,2, new QTableWidgetItem (files.at(i))); + } + + ui.outputPluginTable->resizeColumnToContents ( 0 ); + ui.outputPluginTable->resizeColumnToContents ( 1 ); + ui.outputPluginTable->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; + } + } +} + +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; + } + } +} + +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 ("MainWindow/tray_enabled", ui.trayCheckBox->isChecked()); + settings.setValue ("Tray/enabled", ui.trayCheckBox->isChecked()); + settings.setValue ("Tray/show_message", ui.messageCheckBox->isChecked()); + settings.setValue ("Tray/message_delay", ui.messageDelaySpinBox->value()); + settings.setValue ("Tray/show_tooltip", ui.toolTipCheckBox->isChecked()); + settings.setValue ("Tray/hide_on_close",ui.hideToTrayRadioButton->isChecked()); +} + + diff --git a/src/configdialog.h b/src/configdialog.h new file mode 100644 index 000000000..879034d26 --- /dev/null +++ b/src/configdialog.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * 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 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 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; +}; + +#endif diff --git a/src/configdialog.ui b/src/configdialog.ui new file mode 100644 index 000000000..65e92eabe --- /dev/null +++ b/src/configdialog.ui @@ -0,0 +1,694 @@ +<ui version="4.0" > + <class>ConfigDialog</class> + <widget class="QDialog" name="ConfigDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>521</width> + <height>375</height> + </rect> + </property> + <property name="windowTitle" > + <string>Qmmp Settings</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="QListWidget" name="contentsWidget" > + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize" > + <size> + <width>140</width> + <height>16777215</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="viewMode" > + <enum>QListView::IconMode</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>0</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> + </widget> + </item> + <item> + <widget class="QStackedWidget" name="stackedWidget" > + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <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="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox" > + <property name="title" > + <string>Skins</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</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="margin" > + <number>9</number> + </property> + <property name="spacing" > + <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::AlignRight|Qt::AlignTrailing|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::AlignRight|Qt::AlignTrailing|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="margin" > + <number>9</number> + </property> + <property name="spacing" > + <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="margin" > + <number>9</number> + </property> + <property name="spacing" > + <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="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</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="margin" > + <number>9</number> + </property> + <property name="spacing" > + <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="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</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="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</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> + </item> + </layout> + </widget> + <widget class="QWidget" name="page_2" > + <layout class="QVBoxLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox_4" > + <property name="title" > + <string>Tray Icon</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="2" column="0" > + <widget class="QCheckBox" name="toolTipCheckBox" > + <property name="text" > + <string>Show tooltip</string> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QCheckBox" name="messageCheckBox" > + <property name="text" > + <string>Show message</string> + </property> + </widget> + </item> + <item row="3" column="1" > + <widget class="QSpinBox" name="messageDelaySpinBox" > + <property name="maximum" > + <number>10000</number> + </property> + <property name="minimum" > + <number>100</number> + </property> + <property name="singleStep" > + <number>100</number> + </property> + <property name="value" > + <number>1000</number> + </property> + </widget> + </item> + <item row="3" column="0" > + <widget class="QLabel" name="label_3" > + <property name="text" > + <string>Message delay, ms:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="0" column="0" colspan="2" > + <widget class="QCheckBox" name="trayCheckBox" > + <property name="text" > + <string>Show tray icon</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="closeGroupBox" > + <property name="title" > + <string>Action On Close</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QRadioButton" name="hideToTrayRadioButton" > + <property name="text" > + <string>Hide to tray</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="quitRadioButton" > + <property name="text" > + <string>Quit</string> + </property> + <property name="checked" > + <bool>true</bool> + </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="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>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>510</x> + <y>364</y> + </hint> + <hint type="destinationlabel" > + <x>316</x> + <y>340</y> + </hint> + </hints> + </connection> + <connection> + <sender>trayCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>toolTipCheckBox</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel" > + <x>344</x> + <y>66</y> + </hint> + <hint type="destinationlabel" > + <x>177</x> + <y>113</y> + </hint> + </hints> + </connection> + <connection> + <sender>trayCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>messageDelaySpinBox</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel" > + <x>208</x> + <y>55</y> + </hint> + <hint type="destinationlabel" > + <x>469</x> + <y>148</y> + </hint> + </hints> + </connection> + <connection> + <sender>trayCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>messageCheckBox</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel" > + <x>262</x> + <y>55</y> + </hint> + <hint type="destinationlabel" > + <x>258</x> + <y>76</y> + </hint> + </hints> + </connection> + <connection> + <sender>messageCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>messageDelaySpinBox</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel" > + <x>307</x> + <y>82</y> + </hint> + <hint type="destinationlabel" > + <x>469</x> + <y>148</y> + </hint> + </hints> + </connection> + <connection> + <sender>trayCheckBox</sender> + <signal>clicked(bool)</signal> + <receiver>closeGroupBox</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel" > + <x>376</x> + <y>56</y> + </hint> + <hint type="destinationlabel" > + <x>436</x> + <y>175</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/default/balance.png b/src/default/balance.png Binary files differnew file mode 100644 index 000000000..5fa10cce8 --- /dev/null +++ b/src/default/balance.png diff --git a/src/default/cbuttons.png b/src/default/cbuttons.png Binary files differnew file mode 100644 index 000000000..7a1369b59 --- /dev/null +++ b/src/default/cbuttons.png diff --git a/src/default/eq_ex.png b/src/default/eq_ex.png Binary files differnew file mode 100644 index 000000000..974004590 --- /dev/null +++ b/src/default/eq_ex.png diff --git a/src/default/eqmain.png b/src/default/eqmain.png Binary files differnew file mode 100644 index 000000000..b28b818de --- /dev/null +++ b/src/default/eqmain.png diff --git a/src/default/main.png b/src/default/main.png Binary files differnew file mode 100644 index 000000000..6b7c8597a --- /dev/null +++ b/src/default/main.png diff --git a/src/default/monoster.png b/src/default/monoster.png Binary files differnew file mode 100644 index 000000000..7ddb9d0e5 --- /dev/null +++ b/src/default/monoster.png diff --git a/src/default/numbers.png b/src/default/numbers.png Binary files differnew file mode 100644 index 000000000..46f1e1f63 --- /dev/null +++ b/src/default/numbers.png diff --git a/src/default/playpaus.png b/src/default/playpaus.png Binary files differnew file mode 100644 index 000000000..0cfbd6835 --- /dev/null +++ b/src/default/playpaus.png diff --git a/src/default/pledit.png b/src/default/pledit.png Binary files differnew file mode 100644 index 000000000..3c2943cea --- /dev/null +++ b/src/default/pledit.png diff --git a/src/default/pledit.txt b/src/default/pledit.txt new file mode 100644 index 000000000..5435dd2fd --- /dev/null +++ b/src/default/pledit.txt @@ -0,0 +1,6 @@ +[Text]
+Normal=#C0C0C0
+Current=#8080FF
+NormalBG=#400080
+SelectedBG=#408080
+Font=Tahoma Bold
\ No newline at end of file diff --git a/src/default/posbar.png b/src/default/posbar.png Binary files differnew file mode 100644 index 000000000..271106557 --- /dev/null +++ b/src/default/posbar.png diff --git a/src/default/shufrep.png b/src/default/shufrep.png Binary files differnew file mode 100644 index 000000000..107fd50bb --- /dev/null +++ b/src/default/shufrep.png diff --git a/src/default/text.png b/src/default/text.png Binary files differnew file mode 100644 index 000000000..d37241405 --- /dev/null +++ b/src/default/text.png diff --git a/src/default/titlebar.png b/src/default/titlebar.png Binary files differnew file mode 100644 index 000000000..c1e7818cd --- /dev/null +++ b/src/default/titlebar.png diff --git a/src/default/viscolor.txt b/src/default/viscolor.txt new file mode 100644 index 000000000..1a88c6ed5 --- /dev/null +++ b/src/default/viscolor.txt @@ -0,0 +1,23 @@ +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
diff --git a/src/default/volume.png b/src/default/volume.png Binary files differnew file mode 100644 index 000000000..b4f457453 --- /dev/null +++ b/src/default/volume.png diff --git a/src/display.cpp b/src/display.cpp new file mode 100644 index 000000000..f401d2f54 --- /dev/null +++ b/src/display.cpp @@ -0,0 +1,275 @@ +/*************************************************************************** + * 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 <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->setGeometry ( 24,39,75,20 ); + 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 ) ) ); +} + +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 ) ) ); +} + +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); +} + diff --git a/src/display.h b/src/display.h new file mode 100644 index 000000000..7ab2074bc --- /dev/null +++ b/src/display.h @@ -0,0 +1,104 @@ +/*************************************************************************** + * 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 *); + +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/dock.cpp b/src/dock.cpp new file mode 100644 index 000000000..17edc44bf --- /dev/null +++ b/src/dock.cpp @@ -0,0 +1,239 @@ +/*************************************************************************** + * 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 ) < 15 && ny < 15 ) //above + npos.rx() = st->x(); + if ( ny < 15 && nx > -mv->width() && nx < st->width() ) + npos.ry() = st->y() - mv->height(); + nx = abs ( npos.x() + mv->width() - st->x() - st->width() ); + if ( nx < 15 && ny < 15 ) + npos.rx() = st->x() + st->width() - mv->width(); + + /***********/ + nx = npos.x() - st->x(); + ny = abs ( npos.y() - st->y() - st->height() ); + + if ( abs ( nx ) < 15 && ny < 15 ) //near + npos.rx() = st->x(); + if ( ny < 15 && nx > -mv->width() && nx < st->width() ) + npos.ry() = st->y() + st->height(); + nx = abs ( npos.x() + mv->width() - st->x() - st->width() ); + if ( nx < 15 && ny < 15 ) + npos.rx() = st->x() + st->width() - mv->width(); + /**************/ + nx = abs ( npos.x() - st->x() + mv->width() ); + ny = npos.y() - st->y(); + + if ( nx < 15 && abs ( ny ) < 15 ) //left + npos.ry() = st->y(); + if ( nx < 15 && ny > -mv->height() && ny < st->height() ) + npos.rx() = st->x() - mv->width(); + + ny = abs ( npos.y() + mv->height() - st->y() - st->height() ); + if ( nx < 15 && ny < 15 ) + npos.ry() = st->y() + st->height() - mv->height(); + /*****************/ + nx = abs ( npos.x() - st->x() - st->width() ); + ny = npos.y() - st->y(); + + if ( nx < 15 && abs ( ny ) < 15 ) //right + npos.ry() = st->y(); + if ( nx < 15 && ny > -mv->height() && ny < st->height() ) + npos.rx() = st->x() + st->width(); + + ny = abs ( npos.y() + mv->height() - st->y() - st->height() ); + if ( nx < 15 && ny < 15 ) + 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 ); +} + diff --git a/src/dock.h b/src/dock.h new file mode 100644 index 000000000..5622de675 --- /dev/null +++ b/src/dock.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 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); + + 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); + + + ~Dock(); + +private: + bool isDocked(QWidget*, QWidget*); + 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/eqgraph.cpp b/src/eqgraph.cpp new file mode 100644 index 000000000..314e504d9 --- /dev/null +++ b/src/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/eqgraph.h b/src/eqgraph.h new file mode 100644 index 000000000..4f6bf1882 --- /dev/null +++ b/src/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/eqpreset.cpp b/src/eqpreset.cpp new file mode 100644 index 000000000..760dea9d2 --- /dev/null +++ b/src/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/eqpreset.h b/src/eqpreset.h new file mode 100644 index 000000000..80f31747e --- /dev/null +++ b/src/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/eqslider.cpp b/src/eqslider.cpp new file mode 100644 index 000000000..bdc4ec4e2 --- /dev/null +++ b/src/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/eqslider.h b/src/eqslider.h new file mode 100644 index 000000000..54dc9f285 --- /dev/null +++ b/src/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/eqtitlebar.cpp b/src/eqtitlebar.cpp new file mode 100644 index 000000000..af4547bd7 --- /dev/null +++ b/src/eqtitlebar.cpp @@ -0,0 +1,76 @@ +/*************************************************************************** + * 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 <QMenu> + +#include "skin.h" +#include "dock.h" +#include "mainwindow.h" + +#include "eqtitlebar.h" + +EqTitleBar::EqTitleBar(QWidget *parent) + : PixmapWidget(parent) +{ + m_skin = Skin::getPointer(); + setActive(FALSE); + m_eq = parentWidget(); + m_mw = qobject_cast<MainWindow*>(m_eq->parent()); +} + + +EqTitleBar::~EqTitleBar() +{} + +void EqTitleBar::setActive(bool active) +{ + if (active) + setPixmap(m_skin->getEqPart(Skin::EQ_TITLEBAR_A)); + else + setPixmap(m_skin->getEqPart(Skin::EQ_TITLEBAR_I)); +} + +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); + //parentWidget()->move(npos); + Dock::getPointer()->move(m_eq, npos); +} + +void EqTitleBar::mouseReleaseEvent(QMouseEvent*) +{ + Dock::getPointer()->updateDock(); +} diff --git a/src/eqtitlebar.h b/src/eqtitlebar.h new file mode 100644 index 000000000..840577272 --- /dev/null +++ b/src/eqtitlebar.h @@ -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. * + ***************************************************************************/ +#ifndef EQTITLEBAR_H +#define EQTITLEBAR_H + +#include <pixmapwidget.h> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + +class QMouseEvent; + +class Skin; +class MainWindow; + +class EqTitleBar : public PixmapWidget +{ +Q_OBJECT +public: + EqTitleBar(QWidget *parent = 0); + + ~EqTitleBar(); + + void setActive(bool); + +private: + Skin* m_skin; + bool m_active; + QPoint m_pos; + QWidget* m_eq; + MainWindow* m_mw; + +protected: + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + +}; + +#endif diff --git a/src/eqwidget.cpp b/src/eqwidget.cpp new file mode 100644 index 000000000..627958dfd --- /dev/null +++ b/src/eqwidget.cpp @@ -0,0 +1,407 @@ +/*************************************************************************** + * 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 <QFileDialog> + +#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(); + } +} + +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 = QFileDialog::getOpenFileName(this, tr("Import Preset"), + "/home", + "Winamp EQF (*.q1)"); + 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/eqwidget.h b/src/eqwidget.h new file mode 100644 index 000000000..095935fe3 --- /dev/null +++ b/src/eqwidget.h @@ -0,0 +1,96 @@ +/*************************************************************************** + * 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> + +/** + @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); + +signals: + void valueChanged(); + +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/fft.c b/src/fft.c new file mode 100644 index 000000000..7ca1978a5 --- /dev/null +++ b/src/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/fft.h b/src/fft.h new file mode 100644 index 000000000..431afa365 --- /dev/null +++ b/src/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/fileloader.cpp b/src/fileloader.cpp new file mode 100644 index 000000000..fda8efdc1 --- /dev/null +++ b/src/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/fileloader.h b/src/fileloader.h new file mode 100644 index 000000000..c23d1ed35 --- /dev/null +++ b/src/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/guard.cpp b/src/guard.cpp new file mode 100644 index 000000000..d9c701951 --- /dev/null +++ b/src/guard.cpp @@ -0,0 +1,125 @@ +/*************************************************************************** + * 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 "guard.h" + +//#define USE_SEMAPHORE + +#ifdef USE_SEMAPHORE + #include <sys/types.h> + #include <sys/ipc.h> + #include <errno.h> + #include <sys/sem.h> +#else + #include <QSettings> +#endif + +#include <QDir> + +bool Guard::create(const QString& filepath) +{ +#ifdef USE_SEMAPHORE + key_t key; + int sem_num = 1; + if( (key = ftok(filepath.toAscii().data(),'A')) < 0) + { + qWarning("Warning: Unable get access to key..."); + return false; + } + + if(semget(key,sem_num,IPC_CREAT | IPC_EXCL ) < 0) + { + if(errno == EEXIST) + { + qWarning("Warning: Semaphore with %d key already exists...",key); + } + return false; + } + + return true; +#else + Q_UNUSED(filepath) + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + settings.beginGroup("Application"); + settings.setValue("IS_RUNNING",TRUE); + settings.endGroup(); + return true; +#endif +} + +bool Guard::exists(const QString& filepath) +{ +#ifdef USE_SEMAPHORE + key_t key; + int sem_num = 1; + int sem_id; + + if( (key = ftok(filepath.toAscii().data(),'A')) < 0) + { + qWarning("Warning: Unable get access to key"); + return false; + } + + if( (sem_id = semget(key,sem_num,0)) < 0 ) + return false; + return true; +#else + Q_UNUSED(filepath) + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + settings.beginGroup("Application"); + bool res = settings.value("IS_RUNNING",FALSE).toBool(); + settings.endGroup(); + return res; +#endif +} + +bool Guard::destroy(const QString& filepath) +{ +#ifdef USE_SEMAPHORE + key_t key; + int sem_num = 1; + int sem_id; + + if( (key = ftok(filepath.toAscii().data(),'A')) < 0) + { + qWarning("Warning: Unable get access to key"); + return false; + } + if( (sem_id = semget(key,sem_num,0)) < 0 ) + { + qWarning("Unable get semaphore with key %d",key); + return false; + } + + if(semctl(sem_id,1,IPC_RMID) < 0) + { + qWarning("Unable remove semaphore with key %d",key); + return false; + } + return true; +#else + Q_UNUSED(filepath) + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + settings.beginGroup("Application"); + settings.setValue("IS_RUNNING",FALSE); + settings.endGroup(); + return true; +#endif +} diff --git a/src/guard.h b/src/guard.h new file mode 100644 index 000000000..2ae05be4a --- /dev/null +++ b/src/guard.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * 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 _GUARD_H +#define _GUARD_H + +#include <QString> + +/** + @author Vladimir Kuznetsov <vovanec@gmail.com> + */ +struct Guard +{ + static bool create(const QString& filepath); + static bool exists(const QString& filepath); + static bool destroy(const QString& filepath); +}; +#endif + diff --git a/src/html/about_en.html b/src/html/about_en.html new file mode 100644 index 000000000..d03691cf6 --- /dev/null +++ b/src/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/html/about_ru.html b/src/html/about_ru.html new file mode 100644 index 000000000..26e5b9906 --- /dev/null +++ b/src/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/html/about_zh_CN.html b/src/html/about_zh_CN.html new file mode 100644 index 000000000..eadc7f78d --- /dev/null +++ b/src/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/html/authors_en.txt b/src/html/authors_en.txt new file mode 100644 index 000000000..6c11ebd5e --- /dev/null +++ b/src/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/html/authors_ru.txt b/src/html/authors_ru.txt new file mode 100644 index 000000000..b95c3887e --- /dev/null +++ b/src/html/authors_ru.txt @@ -0,0 +1,9 @@ +Разработчики ядра: + + Владимир Кузнецов <vovanec@gmail.com> (внешний вид и множество улучшений) + Илья Котов <forkotov02@hotmail.ru> (идея и основной код) + +Разработчики модулей: + + Юрий Журавлёв <stalkerg@gmail.com> (модуль jack) + diff --git a/src/html/authors_zh_CN.txt b/src/html/authors_zh_CN.txt new file mode 100644 index 000000000..f2d8892fd --- /dev/null +++ b/src/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/html/thanks_en.txt b/src/html/thanks_en.txt new file mode 100644 index 000000000..3ed2fe5d5 --- /dev/null +++ b/src/html/thanks_en.txt @@ -0,0 +1,3 @@ +Thanks to: + + Vadim Kalinnikov <moose@ylsoftware.com> (project hosting) diff --git a/src/html/thanks_ru.txt b/src/html/thanks_ru.txt new file mode 100644 index 000000000..79acc177d --- /dev/null +++ b/src/html/thanks_ru.txt @@ -0,0 +1,3 @@ +Благодарности: + + Вадиму Калинникову <moose@ylsoftware.com> (хотстинг проекта) diff --git a/src/html/thanks_zh_CN.txt b/src/html/thanks_zh_CN.txt new file mode 100644 index 000000000..505d05c72 --- /dev/null +++ b/src/html/thanks_zh_CN.txt @@ -0,0 +1,3 @@ +感谢: + + Vadim Kalinnikov <moose@ylsoftware.com> (project hosting) diff --git a/src/images/advanced.png b/src/images/advanced.png Binary files differnew file mode 100644 index 000000000..30e9a7074 --- /dev/null +++ b/src/images/advanced.png diff --git a/src/images/images.qrc b/src/images/images.qrc new file mode 100644 index 000000000..8dcc2efe2 --- /dev/null +++ b/src/images/images.qrc @@ -0,0 +1,14 @@ +<!DOCTYPE RCC> +<RCC version="1.0"> + <qresource> + <file>play.png</file> + <file>pause.png</file> + <file>stop.png</file> + <file>qmmp.xpm</file> + <file>interface.png</file> + <file>playlist.png</file> + <file>advanced.png</file> + <file>plugins.png</file> + <file>logo-qmmp.png</file> + </qresource> +</RCC> diff --git a/src/images/interface.png b/src/images/interface.png Binary files differnew file mode 100644 index 000000000..e056d2b24 --- /dev/null +++ b/src/images/interface.png diff --git a/src/images/logo-qmmp.png b/src/images/logo-qmmp.png Binary files differnew file mode 100644 index 000000000..7a4d6ded4 --- /dev/null +++ b/src/images/logo-qmmp.png diff --git a/src/images/pause.png b/src/images/pause.png Binary files differnew file mode 100644 index 000000000..885c397da --- /dev/null +++ b/src/images/pause.png diff --git a/src/images/play.png b/src/images/play.png Binary files differnew file mode 100644 index 000000000..9ff85ebce --- /dev/null +++ b/src/images/play.png diff --git a/src/images/playlist.png b/src/images/playlist.png Binary files differnew file mode 100644 index 000000000..2afc1d720 --- /dev/null +++ b/src/images/playlist.png diff --git a/src/images/plugins.png b/src/images/plugins.png Binary files differnew file mode 100644 index 000000000..a88b78c2b --- /dev/null +++ b/src/images/plugins.png diff --git a/src/images/qmmp.xpm b/src/images/qmmp.xpm new file mode 100644 index 000000000..85ea94fc1 --- /dev/null +++ b/src/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/images/stop.png b/src/images/stop.png Binary files differnew file mode 100644 index 000000000..296ef1ce3 --- /dev/null +++ b/src/images/stop.png diff --git a/src/inlines.h b/src/inlines.h new file mode 100644 index 000000000..3efccf0de --- /dev/null +++ b/src/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/jumptotrackdialog.cpp b/src/jumptotrackdialog.cpp new file mode 100644 index 000000000..42069b91c --- /dev/null +++ b/src/jumptotrackdialog.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 "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); + 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/jumptotrackdialog.h b/src/jumptotrackdialog.h new file mode 100644 index 000000000..cfe629693 --- /dev/null +++ b/src/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/jumptotrackdialog.ui b/src/jumptotrackdialog.ui new file mode 100644 index 000000000..1418c54fd --- /dev/null +++ b/src/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/keyboardmanager.cpp b/src/keyboardmanager.cpp new file mode 100644 index 000000000..5ad32fee7 --- /dev/null +++ b/src/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/keyboardmanager.h b/src/keyboardmanager.h new file mode 100644 index 000000000..2b33b5ef9 --- /dev/null +++ b/src/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/listwidget.cpp b/src/listwidget.cpp new file mode 100644 index 000000000..a21508b5f --- /dev/null +++ b/src/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/listwidget.h b/src/listwidget.h new file mode 100644 index 000000000..2f20a3bf8 --- /dev/null +++ b/src/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/logscale.cpp b/src/logscale.cpp new file mode 100644 index 000000000..921004fd9 --- /dev/null +++ b/src/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/logscale.h b/src/logscale.h new file mode 100644 index 000000000..d74d25207 --- /dev/null +++ b/src/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/mainvisual.cpp b/src/mainvisual.cpp new file mode 100644 index 000000000..1376457b4 --- /dev/null +++ b/src/mainvisual.cpp @@ -0,0 +1,921 @@ +/*************************************************************************** + * 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 <QTimer> +#include <QSettings> +#include <QPainter> +#include <buffer.h> +#include <constants.h> +#include <output.h> +#include <math.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, const char *name ) + : QWidget ( parent ), vis ( 0 ), playing ( FALSE ), fps ( 20 ) +{ + //setVisual(new MonoScope); + setVisual ( new StereoAnalyzer ); + timer = new QTimer ( this ); + connect ( timer, SIGNAL ( timeout() ), this, SLOT ( timeout() ) ); + timer->start ( 1000 / fps ); + nodes.clear(); + pointer = this; + +} + +MainVisual::~MainVisual() +{ + delete vis; + vis = 0; +} + +/*void MainVisual::setVisual( const QString &visualname ) +{ + VisualBase *newvis = 0; + + if ( visualname == "Mono Scope" ) + newvis = new MonoScope; + else if (visualname == "Stereo Scope" ) + newvis = new StereoScope; +#ifdef FFTW + else if ( visualname == "Mono Analyzer" ) + newvis = new MonoAnalyzer; + else if ( visualname == "Stereo Analyzer" ) + newvis = new StereoAnalyzer; + else if ( visualname == "Mono Topograph" ) + newvis = new MonoTopograph; + else if ( visualname == "Stereo Topograph" ) + newvis = new StereoTopograph; + else if ( visualname == "Stereo Spectroscope" ) + newvis = new StereoSpectroscope; + else if ( visualname == "Mono Spectroscope" ) + newvis = new MonoSpectroscope; +#endif // FFTW + + setVisual( newvis ); +}*/ + +void MainVisual::setVisual ( VisualBase *newvis ) +{ + //delete vis; + + vis = newvis; + if ( vis ) + vis->resize ( size() ); + + // force an update + //timer->stop(); +// timer->start( 1000 / fps ); +} + +void MainVisual::configChanged ( QSettings &settings ) +{ + /*QString newvis = settings.readEntry( "/MQ3/Visual/mode", "Mono Analyzer" ); + setVisual( newvis );*/ + + //fps = settings.readNumEntry("/MQ3/Visual/frameRate", 20); + fps = 20; + timer->stop(); + timer->start ( 1000 / fps ); + if ( vis ) + vis->configChanged ( settings ); +} + +void MainVisual::prepare() +{ + //nodes.setAutoDelete(TRUE); + nodes.clear(); //TODO memory leak?? + //nodes.setAutoDelete(FALSE); +} + +void MainVisual::add ( Buffer *b, unsigned long w, int c, int p ) +{ + long len = b->nbytes, cnt; + short *l = 0, *r = 0; + + len /= c; + len /= ( p / 8 ); + if ( len > 512 ) + 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; + + 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 ( ( !nodes.isEmpty() ) ) + { + node = nodes.first(); + /*if ( node->offset > synctime ) + break;*/ + + if ( prev ) + delete prev; + nodes.removeFirst(); + + prev = node; + + } + mutex()->unlock(); + node = prev; + } + + bool stop = TRUE; + if ( vis ) + stop = vis->process ( node ); + delete node; + + if ( vis ) + { + pixmap.fill ( Qt::transparent ); + QPainter p ( &pixmap ); + //vis->draw( &p, backgroundColor() ); + vis->draw ( &p, "Green" ); + } + else + //pixmap.fill( backgroundColor() ); + pixmap.fill ( "Red" ); + //bitBlt(this, 0, 0, &pixmap); +// QPainter painter(this); +// painter.drawPixmap(0,0,pixmap); + update(); + /*if (! playing && stop) + timer->stop();*/ +} + +void MainVisual::paintEvent ( QPaintEvent * ) +{ + //bitBlt(this, 0, 0, &pixmap); + QPainter painter ( this ); + painter.drawPixmap ( 0,0,pixmap ); +} + +void MainVisual::resizeEvent ( QResizeEvent *event ) +{ + pixmap = QPixmap ( event->size() ); + /*pixmap.resize(event->size()); + pixmap.fill(backgroundColor()); + QWidget::resizeEvent( event );*/ + if ( vis ) + vis->resize ( size() ); +} + +/*void MainVisual::customEvent(QCustomEvent *event) +{ + switch (event->type()) { + case OutputEvent::Playing: + playing = TRUE; + // fall through intended + + case OutputEvent::Info: + case OutputEvent::Buffering: + case OutputEvent::Paused: + if (! timer->isActive()) + timer->start(1000 / fps); + + break; + + case OutputEvent::Stopped: + case OutputEvent::Error: + playing = FALSE; + break; + + default: + ; + } +}*/ + +QStringList MainVisual::visuals() +{ + QStringList list; + list << "Stereo Scope"; + list << "Mono Scope"; +#ifdef FFTW + list << "Stereo Analyzer"; + list << "Mono Analyzer"; + list << "Stereo Topograph"; + list << "Mono Topograph"; + list << "Stereo Spectroscope"; + list << "Mono Spectroscope"; +#endif // FFTW + + return list; +} + + +MonoScope::MonoScope() +{} + +MonoScope::~MonoScope() +{} + +bool MonoScope::process ( VisualNode *node ) +{ + bool allZero = TRUE; + int i; + long s, index, indexTo, step = 512 / size.width(); + double *magnitudesp = magnitudes.data(); + double val, tmp; + + if ( node ) + { + + index = 0; + for ( i = 0; i < size.width(); i++ ) + { + indexTo = index + step; + + if ( rubberband ) + { + val = magnitudesp[ i ]; + if ( val < 0. ) + { + val += falloff; + if ( val > 0. ) + val = 0.; + } + else + { + val -= falloff; + if ( val < 0. ) + val = 0.; + } + } + else + val = 0.; + + for ( s = index; s < indexTo && s < node->length; s++ ) + { + tmp = ( double ( node->left[s] ) + + ( node->right ? double ( node->right[s] ) : 0 ) * + double ( size.height() / 2 ) ) / 65536.; + if ( tmp > 0 ) + val = ( tmp > val ) ? tmp : val; + else + val = ( tmp < val ) ? tmp : val; + } + + if ( val != 0. ) + allZero = FALSE; + magnitudesp[ i ] = val; + index = indexTo; + } + } + else if ( rubberband ) + { + for ( i = 0; i < size.width(); i++ ) + { + val = magnitudesp[ i ]; + if ( val < 0 ) + { + val += 2; + if ( val > 0. ) + val = 0.; + } + else + { + val -= 2; + if ( val < 0. ) + val = 0.; + } + + if ( val != 0. ) + allZero = FALSE; + magnitudesp[ i ] = val; + } + } + else + { + for ( i = 0; i < size.width(); i++ ) + magnitudesp[ i ] = 0.; + } + + return allZero; +} + +void MonoScope::draw ( QPainter *p, const QColor &back ) +{ + double *magnitudesp = magnitudes.data(); + double r, g, b, per; + + p->fillRect ( 0, 0, size.width(), size.height(), back ); + for ( int i = 1; i < size.width(); i++ ) + { + per = double ( magnitudesp[ i ] ) / + double ( size.height() / 4 ); + if ( per < 0.0 ) + per = -per; + if ( per > 1.0 ) + per = 1.0; + else if ( per < 0.0 ) + per = 0.0; + + r = startColor.red() + ( targetColor.red() - + startColor.red() ) * ( per * per ); + g = startColor.green() + ( targetColor.green() - + startColor.green() ) * ( per * per ); + b = startColor.blue() + ( targetColor.blue() - + startColor.blue() ) * ( per * per ); + + if ( r > 255.0 ) + r = 255.0; + else if ( r < 0.0 ) + r = 0; + + if ( g > 255.0 ) + g = 255.0; + else if ( g < 0.0 ) + g = 0; + + if ( b > 255.0 ) + b = 255.0; + else if ( b < 0.0 ) + b = 0; + + p->setPen ( QColor ( int ( r ), int ( g ), int ( b ) ) ); + p->drawLine ( i - 1, size.height() / 2 + int ( magnitudesp[ i - 1 ] ), + i, int ( size.height() / 2 + magnitudesp[ i ] ) ); + //qDebug("draw %d", int(magnitudesp[ i ])); + } +} + +StereoScope::StereoScope() + : rubberband ( true ), falloff ( 1.0 ), fps ( 20 ) +{ + startColor = Qt::white; + + /*val = settings.readEntry("/MQ3/Scope/targetColor"); + if (! val.isEmpty()) + targetColor = QColor(val); + else*/ + targetColor = Qt::red; +} + +StereoScope::~StereoScope() +{} + +void StereoScope::resize ( const QSize &newsize ) +{ + size = newsize; + + uint os = magnitudes.size(); + magnitudes.resize ( size.width() * 2 ); + for ( ; os < magnitudes.size(); os++ ) + magnitudes[os] = 0.0; +} + +void StereoScope::configChanged ( QSettings &settings ) +{ + QString val; + + // need the framerate for the fall off speed + //fps = settings.readNumEntry("/MQ3/Visual/frameRate", 20); + fps = 20; + /*val = settings.readEntry("/MQ3/Scope/startColor"); + if (! val.isEmpty()) + startColor = QColor(val); + else*/ + startColor = Qt::green; + + /*val = settings.readEntry("/MQ3/Scope/targetColor"); + if (! val.isEmpty()) + targetColor = QColor(val); + else*/ + targetColor = Qt::red; + + //rubberband = settings.readBoolEntry( "/MQ3/Scope/enableRubberBand", true ); + rubberband = TRUE; + //val = settings.readEntry( "/MQ3/Scope/fallOffSpeed", "Normal" ); + val == "Normal"; + if ( val == "Slow" ) + falloff = .125; + else if ( val == "Fast" ) + falloff = .5; + else + falloff = .25; + + falloff *= ( 80. / double ( fps ) ); + + resize ( size ); +} + +bool StereoScope::process ( VisualNode *node ) +{ + bool allZero = TRUE; + int i; + long s, index, indexTo, step = 256 / size.width(); + double *magnitudesp = magnitudes.data(); + double valL, valR, tmpL, tmpR; + + if ( node ) + { + index = 0; + for ( i = 0; i < size.width(); i++ ) + { + indexTo = index + step; + + if ( rubberband ) + { + valL = magnitudesp[ i ]; + valR = magnitudesp[ i + size.width() ]; + if ( valL < 0. ) + { + valL += falloff; + if ( valL > 0. ) + valL = 0.; + } + else + { + valL -= falloff; + if ( valL < 0. ) + valL = 0.; + } + if ( valR < 0. ) + { + valR += falloff; + if ( valR > 0. ) + valR = 0.; + } + else + { + valR -= falloff; + if ( valR < 0. ) + valR = 0.; + } + } + else + valL = valR = 0.; + + for ( s = index; s < indexTo && s < node->length; s++ ) + { + tmpL = ( ( node->left ? + double ( node->left[s] ) : 0. ) * + double ( size.height() / 4 ) ) / 32768.; + tmpR = ( ( node->right ? + double ( node->right[s] ) : 0. ) * + double ( size.height() / 4 ) ) / 32768.; + if ( tmpL > 0 ) + valL = ( tmpL > valL ) ? tmpL : valL; + else + valL = ( tmpL < valL ) ? tmpL : valL; + if ( tmpR > 0 ) + valR = ( tmpR > valR ) ? tmpR : valR; + else + valR = ( tmpR < valR ) ? tmpR : valR; + } + + if ( valL != 0. || valR != 0. ) + allZero = FALSE; + + magnitudesp[ i ] = valL; + magnitudesp[ i + size.width() ] = valR; + + index = indexTo; + } + } + else if ( rubberband ) + { + for ( i = 0; i < size.width(); i++ ) + { + valL = magnitudesp[ i ]; + if ( valL < 0 ) + { + valL += 2; + if ( valL > 0. ) + valL = 0.; + } + else + { + valL -= 2; + if ( valL < 0. ) + valL = 0.; + } + + valR = magnitudesp[ i + size.width() ]; + if ( valR < 0. ) + { + valR += falloff; + if ( valR > 0. ) + valR = 0.; + } + else + { + valR -= falloff; + if ( valR < 0. ) + valR = 0.; + } + + if ( valL != 0. || valR != 0. ) + allZero = FALSE; + + magnitudesp[ i ] = valL; + magnitudesp[ i + size.width() ] = valR; + } + } + else + { + for ( i = 0; ( unsigned ) i < magnitudes.size(); i++ ) + magnitudesp[ i ] = 0.; + } + + return allZero; +} + +void StereoScope::draw ( QPainter *p, const QColor &back ) +{ + double *magnitudesp = magnitudes.data(); + double r, g, b, per; + + p->fillRect ( 0, 0, size.width(), size.height(), back ); + for ( int i = 1; i < size.width(); i++ ) + { + // left + per = double ( magnitudesp[ i ] * 2 ) / + double ( size.height() / 4 ); + if ( per < 0.0 ) + per = -per; + if ( per > 1.0 ) + per = 1.0; + else if ( per < 0.0 ) + per = 0.0; + + r = startColor.red() + ( targetColor.red() - + startColor.red() ) * ( per * per ); + g = startColor.green() + ( targetColor.green() - + startColor.green() ) * ( per * per ); + b = startColor.blue() + ( targetColor.blue() - + startColor.blue() ) * ( per * per ); + + if ( r > 255.0 ) + r = 255.0; + else if ( r < 0.0 ) + r = 0; + + if ( g > 255.0 ) + g = 255.0; + else if ( g < 0.0 ) + g = 0; + + if ( b > 255.0 ) + b = 255.0; + else if ( b < 0.0 ) + b = 0; + + p->setPen ( QColor ( int ( r ), int ( g ), int ( b ) ) ); + /*p->drawLine ( i - 1, ( size.height() / 4 ) + int ( magnitudesp[ i - 1 ] ), + i, ( size.height() / 4 ) + int ( magnitudesp[ i ] ) );*/ + + //right + per = double ( magnitudesp[ i + size.width() ] * 2 ) / + double ( size.height() / 4 ); + if ( per < 0.0 ) + per = -per; + if ( per > 1.0 ) + per = 1.0; + else if ( per < 0.0 ) + per = 0.0; + + r = startColor.red() + ( targetColor.red() - + startColor.red() ) * ( per * per ); + g = startColor.green() + ( targetColor.green() - + startColor.green() ) * ( per * per ); + b = startColor.blue() + ( targetColor.blue() - + startColor.blue() ) * ( per * per ); + + if ( r > 255.0 ) + r = 255.0; + else if ( r < 0.0 ) + r = 0; + + if ( g > 255.0 ) + g = 255.0; + else if ( g < 0.0 ) + g = 0; + + if ( b > 255.0 ) + b = 255.0; + else if ( b < 0.0 ) + b = 0; + + p->setPen ( QColor ( int ( r ), int ( g ), int ( b ) ) ); + /*p->drawLine ( i - 1, ( size.height() * 3 / 4 ) + + int ( magnitudesp[ i + size.width() - 1 ] ), + i, ( size.height() * 3 / 4 ) + int ( magnitudesp[ i + size.width() ] ) );*/ + } +} + +StereoAnalyzer::StereoAnalyzer() + : scaleFactor ( 1.0 ), falloff ( 1.0 ), analyzerBarWidth ( 4 ), fps ( 20 ) +{ + //plan = rfftw_create_plan(512, FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE); + startColor = Qt::green; + targetColor = Qt::red; + falloff = .5; + for ( int i = 0; i< 19; ++i ) + intern_vis_data[i] = 0; + m_skin = Skin::getPointer(); +} + +StereoAnalyzer::~StereoAnalyzer() +{ + //rfftw_destroy_plan(plan); +} + +void StereoAnalyzer::resize ( const QSize &newsize ) +{ + size = newsize; + + scale.setMax ( 192, size.width() / analyzerBarWidth ); + + rects.resize ( scale.range() ); + int i = 0, w = 0; + for ( ; ( unsigned ) i < rects.count(); i++, w += analyzerBarWidth ) + rects[i].setRect ( w, size.height() / 2, analyzerBarWidth - 1, 1 ); + + int os = magnitudes.size(); + magnitudes.resize ( scale.range() * 2 ); + for ( ; ( unsigned ) os < magnitudes.size(); os++ ) + magnitudes[os] = 0.0; + + // scaleFactor = double( size.height() / 2 ) / log( 512.0 ); +} + +void StereoAnalyzer::configChanged ( QSettings &settings ) +{ + QString val; + + // need the framerate for the fall off speed + /*fps = settings.readNumEntry("/MQ3/Visual/frameRate", 20); + + val = settings.readEntry("/MQ3/Analyzer/startColor"); + if (! val.isEmpty()) + startColor = QColor(val); + else + startColor = Qt::green; + + val = settings.readEntry("/MQ3/Analyzer/targetColor"); + if (! val.isEmpty()) + targetColor = QColor(val); + else + targetColor = Qt::red; + + analyzerBarWidth = settings.readNumEntry( "/MQ3/Analyzer/barWidth", 4 ); + + val = settings.readEntry( "/MQ3/Analyzer/fallOffSpeed", "Normal" ); + if ( val == "Slow" ) + falloff = .25; + else if ( val == "Fast" ) + falloff = 1.; + else + falloff = .5; + + falloff *= ( 80. / double( fps ) ); + + resize( size );*/ +} + +bool StereoAnalyzer::process ( VisualNode *node ) +{ + bool allZero = TRUE; + uint i; + long w = 0, index; + QRect *rectsp = rects.data(); + double *magnitudesp = magnitudes.data(); + double magL, magR, tmp; + static fft_state *state = 0; + if ( !state ) + state = fft_init(); + //if(node) + //float tmp_out[512]; + short dest[256]; + + const int xscale[] = + { + 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; + //fast_real_set_from_short(lin, node->left, node->length); + //if (node->right) + //fast_real_set_from_short(rin, node->right, node->length); + //fft_perform ( node->left, tmp_out, state ); + /*for(int j = 0; j<256; ++j ) + dest*/ + + //calc_mono_freq ( short dest[2][256], short src[2][512], int nch ) + + calc_freq ( dest, node->left ); + + } + else + return FALSE; + const double y_scale = 3.60673760222; /* 20.0 / log(256) */ + int max = 19, y, j; + //int intern_vis_data[19]; + + for ( int i = 0; i < max; i++ ) + { + for ( j = xscale[i], y = 0; j < xscale[i + 1]; j++ ) + { + if ( dest[j] > y ) + y = dest[j]; + } + y >>= 7; + if ( y != 0 ) + { + intern_vis_data[i] = log ( y ) * y_scale; + //qDebug("%d",y); + if ( intern_vis_data[i] > 15 ) + intern_vis_data[i] = 15; + if ( intern_vis_data[i] < 0 ) + intern_vis_data[i] = 0; + } + } + return TRUE; + +// fast_reals_set(lin + i, rin + i, 0, 512 - i); + + //rfftw_one(plan, lin, lout); + //rfftw_one(plan, rin, rout); + + /*index = 1; + for ( i = 0; i < rects.count(); i++, w += analyzerBarWidth ) + { + magL = (log(lout[index] * lout[index] + + lout[512 - index] * lout[512 - index]) - 22.0) * + scaleFactor; + magR = (log(rout[index] * rout[index] + + rout[512 - index] * rout[512 - index]) - 22.0) * + scaleFactor;*/ + //magL = fftperform()*/ + /*magL = ( log ( tmp_out[index] * tmp_out[index] + + tmp_out[512 - index] * tmp_out[512 - index] ) - 22.0 ) * + scaleFactor; + + if ( magL > size.height() ) + magL = size.height() ; + if ( magL < magnitudesp[i] ) + { + tmp = magnitudesp[i] - falloff; + if ( tmp < magL ) + tmp = magL; + magL = tmp; + } + if ( magL < 1. ) + magL = 1.; + + if ( magR > size.height() ) + magR = size.height(); + if ( magR < magnitudesp[i + scale.range() ] ) + { + tmp = magnitudesp[i + scale.range() ] - falloff; + if ( tmp < magR ) + tmp = magR; + magR = tmp; + } + if ( magR < 1. ) + magR = 1.; + + if ( magR != 1 || magL != 1 ) + allZero = FALSE; + + magnitudesp[i] = magL; + magnitudesp[i + scale.range() ] = magR; + + //rectsp[i].setTop ( size.height() / 2 - int ( magL ) ); + //rectsp[i].setBottom ( size.height() / 2 + int ( magR ) ); + rectsp[i].setTop ( size.height() - int ( magL ) ); + rectsp[i].setBottom ( size.height() ); + + index = scale[i]; + } + + return allZero;*/ +} + +void StereoAnalyzer::draw ( QPainter *p, const QColor &back ) +{ + p->setPen ( "Cyan" ); + //p->fillRect ( 0, 0, size.width(), size.height(), Qt::transparent ); + //int intern_vis_data[19]; + //qDebug("%d",int(intern_vis_data[3])); + //p->fill(Qt::transparent); + for ( int j= 0; j<19; ++j ) + { + for ( int i = 0; i<=intern_vis_data[j]; ++i ) + { + p->setPen ( m_skin->getVisBarColor ( i ) ); + p->drawLine ( j*4,size.height()-i, ( j+1 ) *4-2,size.height()-i ); + } + } + for ( int i = 0; i< 19; ++i ) + intern_vis_data[i] = 0; + //update(); + /*QRect *rectsp = rects.data(); + double r, g, b, per; + + p->fillRect ( 0, 0, size.width(), size.height(), back ); + for ( uint i = 0; i < rects.count(); i++ ) + { + per = double ( rectsp[i].height() - 2 ) / double ( size.height() ); + if ( per > 1.0 ) + per = 1.0; + else if ( per < 0.0 ) + per = 0.0; + + r = startColor.red() + ( targetColor.red() - + startColor.red() ) * ( per * per ); + g = startColor.green() + ( targetColor.green() - + startColor.green() ) * ( per * per ); + b = startColor.blue() + ( targetColor.blue() - + startColor.blue() ) * ( per * per ); + + if ( r > 255.0 ) + r = 255.0; + else if ( r < 0.0 ) + r = 0; + + if ( g > 255.0 ) + g = 255.0; + else if ( g < 0.0 ) + g = 0; + + if ( b > 255.0 ) + b = 255.0; + else if ( b < 0.0 ) + b = 0; + + p->fillRect ( rectsp[i], QColor ( int ( r ), int ( g ), int ( b ) ) ); + }*/ + +} diff --git a/src/mainvisual.h b/src/mainvisual.h new file mode 100644 index 000000000..043a0154b --- /dev/null +++ b/src/mainvisual.h @@ -0,0 +1,179 @@ +/*************************************************************************** + * 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 MAINVISUAL_H +#define MAINVISUAL_H + +#include <QWidget> +#include <QResizeEvent> +#include <visualization.h> +#include <constants.h> + +#include "logscale.h" + +class QSettings; +class QTimer; +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() {} + // return true if the output should stop + virtual bool process( VisualNode *node ) = 0; + virtual void draw( QPainter *, const QColor & ) = 0; + virtual void resize( const QSize &size ) = 0; + virtual void configChanged( QSettings & ) = 0; +}; + +class StereoScope : public VisualBase +{ +public: + StereoScope(); + virtual ~StereoScope(); + + void resize( const QSize &size ); + void configChanged(QSettings &settings); + bool process( VisualNode *node ); + void draw( QPainter *p, const QColor &back ); + +protected: + QColor startColor, targetColor; + //QMemArray<double> magnitudes; + QVector <double> magnitudes; + QSize size; + bool rubberband; + double falloff; + int fps; +}; + +class MonoScope : public StereoScope +{ +public: + MonoScope(); + virtual ~MonoScope(); + + bool process( VisualNode *node ); + void draw( QPainter *p, const QColor &back ); +}; + + + + +class MainVisual : public QWidget, public Visualization +{ + Q_OBJECT + +public: + MainVisual( QWidget *parent = 0, const char * = 0 ); + virtual ~MainVisual(); + + //static Prefs *createPrefs( const QString &visualname, + // QWidget *parent, const char *name ); + static MainVisual *getPointer(); + + VisualBase *visual() const { return vis; } + void setVisual( VisualBase *newvis ); + //void setVisual( const QString &visualname ); + + void add(Buffer *, unsigned long, int, int); + void prepare(); + + void configChanged(QSettings &settings); + + QSize minimumSizeHint() const { return sizeHint(); } + QSize sizeHint() const { return QSize(4*4*4*2, 3*3*3*2); } + + void paintEvent( QPaintEvent * ); + void resizeEvent( QResizeEvent * ); + //void customEvent( QCustomEvent * ); + + static QStringList visuals(); + + void setFrameRate( int newfps ); + int frameRate() const { return fps; } + +public slots: +void timeout(); + +private: + static MainVisual *pointer; + VisualBase *vis; + QPixmap pixmap; + //QPtrList<VisualNode> nodes; + QList <VisualNode*> nodes; + QTimer *timer; + bool playing; + int fps; +}; + +class Skin; + +class StereoAnalyzer : public VisualBase +{ +public: + StereoAnalyzer(); + virtual ~StereoAnalyzer(); + + + void resize( const QSize &size ); + void configChanged(QSettings &settings); + bool process( VisualNode *node ); + void draw( QPainter *p, const QColor &back ); + +protected: + QColor startColor, targetColor; + //QMemArray<QRect> rects; + QVector <QRect> rects; + QVector <double> magnitudes; + //QMemArray<double> magnitudes; + QSize size; + LogScale scale; + double scaleFactor, falloff; + int analyzerBarWidth, fps; + //rfftw_plan plan; + //fftw_real lin[512], rin[512], lout[1024], rout[1024]; + int intern_vis_data[19]; + +private: + Skin *m_skin; +}; + +#endif diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp new file mode 100644 index 000000000..645bbecdb --- /dev/null +++ b/src/mainwindow.cpp @@ -0,0 +1,677 @@ +/*************************************************************************** + * 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 "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 "tcpserver.h" +#include "jumptotrackdialog.h" +#include "aboutdialog.h" + +MainWindow::MainWindow(const QStringList& args, QWidget *parent) + : QMainWindow(parent) +{ + m_vis = 0; + seeking = FALSE; + m_update = FALSE; + m_paused = FALSE; + + 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_titlebar = new TitleBar(this); + m_titlebar->move(0,0); + m_titlebar->show(); + m_titlebar->setActive(TRUE); + + m_tray = new QSystemTrayIcon( this ); + m_tray->setIcon ( QIcon(":/stop.png") ); + m_tray->setContextMenu( m_mainMenu ); + connect(m_tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason))); + + readSettings(); + dock->updateDock(); + + display->setEQ(m_equalizer); + display->setPL(m_playlist); + + m_vis = MainVisual::getPointer(); + + m_core = new SoundCore(this); + m_core -> addVisualization(m_vis); + + connect(m_core, SIGNAL(outputStateChanged(const OutputState&)), + SLOT(showOutputState(const OutputState&))); + connect(m_core, SIGNAL(decoderStateChanged(const DecoderState&)), + SLOT(showDecoderState(const DecoderState&))); + + connect ( m_skin, SIGNAL ( skinChanged() ), this, SLOT ( updateSkin() ) ); + updateEQ(); + updateSkin(); + + // Starting the TcpServer + + new TcpServer(this); + + 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()); + 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 + 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) +{ + m_core->seek(pos); +} + +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(); + 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::updatePreset() +{ + //if(m_playListModel->currentItem()) + // m_equalizer->setPresetName(m_playListModel->currentItem()->fileName()); +} + +void MainWindow::showOutputState(const OutputState &st) + +{ + if (seeking) + return; + + display->setInfo(st); + m_playlist->setInfo(st, m_core->length(), m_playListModel->totalLength()); + switch ((int) st.type()) + { + case OutputState::Playing: + { + m_tray->setIcon ( QIcon(":/play.png") ); + if (m_showMessage && m_playListModel->currentItem()) + m_tray->showMessage ( tr("Now Playing"), + m_playListModel->currentItem()->title(), + QSystemTrayIcon::Information, m_messageDelay ); + if (m_showToolTip && m_playListModel->currentItem()) + m_tray->setToolTip (m_playListModel->currentItem()->title()); + break; + } + case OutputState::Paused: + { + m_tray->setIcon ( QIcon(":/pause.png") ); + break; + } + case OutputState::Stopped: + { + m_tray->setIcon ( QIcon(":/stop.png") ); + break; + } + } + +} +void MainWindow::showDecoderState(const DecoderState &st) +{ + switch ((int) st.type()) + { + case DecoderState::Finished: + { + next(); + break; + } + } +} + +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+"../"; +} + +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); +} + +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; + } + //tray + settings.beginGroup("Tray"); + m_tray->setVisible(settings.value("enabled",TRUE).toBool()); + m_showMessage = settings.value("show_message",TRUE).toBool(); + m_messageDelay = settings.value("message_delay",2000).toInt(); + m_showToolTip = settings.value("show_tooltip", FALSE).toBool(); + m_hide_on_titlebar_close = settings.value("hide_on_close",FALSE).toBool(); + if (!m_showToolTip) + m_tray->setToolTip(QString()); + settings.endGroup(); + +} + +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(); + } + 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::trayActivated(QSystemTrayIcon::ActivationReason reason) +{ + if (reason == QSystemTrayIcon::Trigger) + toggleVisibility(); +} + +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("&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_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")); + 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("*.") + ")"; + QString f_name = QFileDialog::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 + 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("*.") + ")"; + QString f_name = QFileDialog::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 + 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 (str == "--play") + play(); + else if (str == "--stop") + { + stop(); + display->hideTimeDisplay(); + } + else if (str == "--pause") + pause(); + else if (str == "--next") + next(); + else if (str == "--previous") + previous(); + else if (str == "--play-pause") + playPause(); + else + return false; + } + else// maybe it is a list of files or dirs + { + QStringList full_path_list; + foreach(QString s,slist) + { + if (s.left(1) == "/") //is it absolute path? + full_path_list << s; + else + full_path_list << cwd + "/" + s; + //qWarning("Current working dir: %s",qPrintable(workingDir)); + //qWarning("Full path to play: %s",qPrintable(workingDir + "/" + 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(); +} + + diff --git a/src/mainwindow.h b/src/mainwindow.h new file mode 100644 index 000000000..751f20939 --- /dev/null +++ b/src/mainwindow.h @@ -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. * + ***************************************************************************/ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QMainWindow> +#include <QSystemTrayIcon> + +#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 QMenu; +class QKeyEvent; + + + +class MainWindow : public QMainWindow +{ + Q_OBJECT +public: + MainWindow(const QStringList& args, QWidget *parent); + + ~MainWindow(); + + PlayList *getPLPointer() + { + return m_playlist; + } + + void seek(int); + QMenu* menu(); + void setVolume(int volume, int balance); + + bool processCommandArgs(const QStringList &slist,const QString& cwd); + +public slots: + void previous(); + void play(); + void pause(); + void playPause(); + void stop(); + void next(); + void replay(); + + void newPlaylist(); + void loadPlaylist(); + void savePlaylist(); + + void setFileList(const QStringList&); + +protected: + virtual void closeEvent ( QCloseEvent *); + virtual void changeEvent ( QEvent * event ); + +private slots: + void showOutputState(const OutputState&); + void showDecoderState(const DecoderState&); + void clear(); + void startSeek(); + void endSeek(); + void showSettings(); + void addDir(); + void addFile(); + void updateEQ(); + void updatePreset(); + void updateSkin(); + + void jumpToFile(); + + void toggleVisibility(); + void trayActivated(QSystemTrayIcon::ActivationReason); + void about(); + + void handleCloseRequest(); + +private: + void readSettings(); + void writeSettings(); + void createActions(); + double 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; + QSystemTrayIcon *m_tray; + 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; +}; + +#endif diff --git a/src/mediafile.cpp b/src/mediafile.cpp new file mode 100644 index 000000000..305f4c32d --- /dev/null +++ b/src/mediafile.cpp @@ -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. * + ***************************************************************************/ +#include <QSettings> +#include <QDir> + +#include <decoder.h> + +#include "mediafile.h" + +MediaFile::MediaFile(QString path) +{ + m_selected = FALSE; + m_current = FALSE; + m_path = path; + m_tag = Decoder::createTag(path); + //format + QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat ); + QString format = settings.value("PlayList/title_format", "%p - %t").toString(); + bool use_meta = settings.value ("PlayList/load_metadata", TRUE).toBool(); + if (use_meta && m_tag && !m_tag->isEmpty()) + { + m_year = m_tag->year(); + //m_title = m_tag->artist()+" - "+m_tag->title(); + m_title = 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.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; +} diff --git a/src/mediafile.h b/src/mediafile.h new file mode 100644 index 000000000..d7e566145 --- /dev/null +++ b/src/mediafile.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 MEDIAFILE_H +#define MEDIAFILE_H + +#include <QString> + +class FileTag; +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + + +class MediaFile +{ +public: + MediaFile() + {}; + MediaFile(QString); + + ~MediaFile(); + MediaFile &operator=(const MediaFile &other); + + 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); + + +private: + QString m_path; + QString m_title; + uint m_year; + FileTag *m_tag; + bool m_selected; + bool m_current; + +}; + +#endif diff --git a/src/monostereo.cpp b/src/monostereo.cpp new file mode 100644 index 000000000..659fec7be --- /dev/null +++ b/src/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/monostereo.h b/src/monostereo.h new file mode 100644 index 000000000..be1419c5c --- /dev/null +++ b/src/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/mp3player.cpp b/src/mp3player.cpp new file mode 100644 index 000000000..cf6b27535 --- /dev/null +++ b/src/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/number.cpp b/src/number.cpp new file mode 100644 index 000000000..9f127965e --- /dev/null +++ b/src/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/number.h b/src/number.h new file mode 100644 index 000000000..1c89f71d4 --- /dev/null +++ b/src/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/pixmapwidget.cpp b/src/pixmapwidget.cpp new file mode 100644 index 000000000..a0f4ff7fd --- /dev/null +++ b/src/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/pixmapwidget.h b/src/pixmapwidget.h new file mode 100644 index 000000000..24d34260e --- /dev/null +++ b/src/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/playlist.cpp b/src/playlist.cpp new file mode 100644 index 000000000..d65debb85 --- /dev/null +++ b/src/playlist.cpp @@ -0,0 +1,462 @@ +/*************************************************************************** + * 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_titleBar = new PlayListTitleBar ( this ); + m_titleBar->show(); + m_titleBar->move ( 0,0 ); + 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() ) ); + 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; + //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_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; + + 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 ); + createActions(); +} + +void PlayList::changeEvent ( QEvent * event ) +{ + if ( event->type() == QEvent::ActivationChange ) + { + m_titleBar->setActive ( isActiveWindow() ); + } +} + +void PlayList::readSettings() +{ + if ( m_update ) + { + m_listWidget->readSettings(); + } + else + { + QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat ); + settings.beginGroup ( "PlayList" ); + //geometry + resize ( settings.value ( "size", QSize ( 275, 116 ) ).toSize() ); + 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" ); + //geometry + settings.setValue ( "size", size() ); + 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/playlist.h b/src/playlist.h new file mode 100644 index 000000000..d8b4fba2c --- /dev/null +++ b/src/playlist.h @@ -0,0 +1,123 @@ +/*************************************************************************** + * 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(); + + 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/playlistcontrol.cpp b/src/playlistcontrol.cpp new file mode 100644 index 000000000..8f111fe4e --- /dev/null +++ b/src/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/playlistcontrol.h b/src/playlistcontrol.h new file mode 100644 index 000000000..26c3871d4 --- /dev/null +++ b/src/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/playlistformat.cpp b/src/playlistformat.cpp new file mode 100644 index 000000000..505805c88 --- /dev/null +++ b/src/playlistformat.cpp @@ -0,0 +1,289 @@ +/*************************************************************************** +* 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"; +} + +#ifndef XSPF_PLUGIN + +// 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"; +} + +#endif + + + + diff --git a/src/playlistformat.h b/src/playlistformat.h new file mode 100644 index 000000000..70af82764 --- /dev/null +++ b/src/playlistformat.h @@ -0,0 +1,120 @@ +/*************************************************************************** + * 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; +}; + + +// Format below is made also as plugin - experimental. To enable it +// uncomment 'CONFIG += XSPF_PLUGIN' line in qmmp.pri +#ifndef XSPF_PLUGIN +/*! + * 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 + +#endif diff --git a/src/playlistmodel.cpp b/src/playlistmodel.cpp new file mode 100644 index 000000000..f50eca956 --- /dev/null +++ b/src/playlistmodel.cpp @@ -0,0 +1,821 @@ +/*************************************************************************** + * 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 <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 + +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(); + + //qRegisterMetaType<MediaFile*>("MediaFileStar"); +} + +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 ( 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()) + { + qWarning("void PlayListModel::clear()"); + l->finish(); + l->wait(); + } + } + + m_running_loaders.clear(); + + m_current = 0; + while ( !m_files.isEmpty() ) + delete m_files.takeFirst(); + + 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() +{ + int i = 0; + while ( !m_files.isEmpty() && i<m_files.size() ) + { + if ( m_files.at ( i )->isSelected() ) + { + MediaFile* f = m_files.takeAt ( i ); + m_total_length -= f->length(); + if (m_total_length < 0) + m_total_length = 0; + delete f; + + if ( m_current >= i && m_current!=0 ) + m_current--; + } + else + i++; + } + if (!m_files.isEmpty()) + m_currentItem = m_files.at(m_current); + + m_play_state->prepare(); + + emit listChanged(); +} + +void PlayListModel::removeUnselected() +{ + int i = 0; + while ( !m_files.isEmpty() &&i<m_files.size() ) + { + if ( !m_files.at ( i )->isSelected() ) + { + MediaFile* f = m_files.takeAt ( i ); + m_total_length -= f->length(); + if (m_total_length < 0) + m_total_length = 0; + delete f; + + if ( m_current >= i && m_current!=0 ) + m_current--; + } + else + i++; + } + + if (!m_files.isEmpty()) + m_currentItem = m_files.at(m_current); + + 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::findFactory ( m_files.at ( i )->path() ); + if ( fact ) + fact->showDetails ( 0, m_files.at ( i )->path() ); + + return; + } + } + +} + + +void PlayListModel::readSettings() +{ + 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 (); + + int preload = (files.count() < 100) ? files.count() : 100; + + for (int i = 0;i < preload;i++) + { + load(new MediaFile(files.takeAt(0))); + } + + + if (files.isEmpty()) + return; + + FileLoader* f_loader = createFileLoader(); + + 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 (); +} + +void PlayListModel::addFile(const QString& path) +{ + if (path.isEmpty ()) + return; + 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); +} + +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 the 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 (qApp->applicationDirPath()); + 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/playlistmodel.h b/src/playlistmodel.h new file mode 100644 index 000000000..8b520f7c0 --- /dev/null +++ b/src/playlistmodel.h @@ -0,0 +1,331 @@ +/*************************************************************************** + * 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; +}; + +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 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 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 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; + +private: + QList <MediaFile*> m_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/playlistslider.cpp b/src/playlistslider.cpp new file mode 100644 index 000000000..098b3bcee --- /dev/null +++ b/src/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/playlistslider.h b/src/playlistslider.h new file mode 100644 index 000000000..a8eb45c66 --- /dev/null +++ b/src/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/playlisttitlebar.cpp b/src/playlisttitlebar.cpp new file mode 100644 index 000000000..9aaed74ca --- /dev/null +++ b/src/playlisttitlebar.cpp @@ -0,0 +1,118 @@ +/*************************************************************************** + * 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 <QMenu> + +#include "dock.h" +#include "playlisttitlebar.h" +#include "skin.h" + +PlayListTitleBar::PlayListTitleBar(QWidget *parent) + : PixmapWidget(parent) +{ + m_active = FALSE; + m_skin = Skin::getPointer(); + resize(275,20); + 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()); +} + + +PlayListTitleBar::~PlayListTitleBar() +{} +void PlayListTitleBar::drawPixmap(int sx) +{ + QPixmap pixmap(275+sx*25,20); + pixmap.fill("black"); + QPainter paint; + paint.begin(&pixmap); + if (m_active) + { + 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)); + } + 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)); + } + paint.end(); + setPixmap(pixmap); +} + +void PlayListTitleBar::resizeEvent(QResizeEvent *e) +{ + int m_sx = (e->size().width()-275)/25; + drawPixmap(m_sx); + +} + +void PlayListTitleBar::mousePressEvent(QMouseEvent* event) +{ + switch((int) event->button ()) + { + case Qt::LeftButton: + { + pos = event->pos(); + break; + } + case Qt::RightButton: + { + m_mw->menu()->exec(event->globalPos()); + } + } +} + +void PlayListTitleBar::mouseReleaseEvent(QMouseEvent*) +{ + Dock::getPointer()->updateDock(); +} + +void PlayListTitleBar::mouseMoveEvent(QMouseEvent* event) +{ + QPoint npos = (event->globalPos()-pos); + QPoint oldpos = npos; + Dock::getPointer()->move(m_pl, npos); +} + +void PlayListTitleBar::setActive(bool a) +{ + m_active = a; + int m_sx = (width()-275)/25; + drawPixmap(m_sx); +} + +void PlayListTitleBar::updateSkin() +{ + drawPixmap((width()-275)/25); +} diff --git a/src/playlisttitlebar.h b/src/playlisttitlebar.h new file mode 100644 index 000000000..bea68c946 --- /dev/null +++ b/src/playlisttitlebar.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 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 PlayListTitleBar : public PixmapWidget +{ +Q_OBJECT +public: + PlayListTitleBar(QWidget *parent = 0); + + ~PlayListTitleBar(); + + void setActive(bool); + +private slots: + void updateSkin(); + +private: + void drawPixmap(int); + Skin *m_skin; + QPoint pos; + bool m_active; + PlayList* m_pl; + MainWindow* m_mw; + +protected: + void resizeEvent(QResizeEvent*); + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); +}; + +#endif diff --git a/src/playstate.cpp b/src/playstate.cpp new file mode 100644 index 000000000..373619574 --- /dev/null +++ b/src/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/playstate.h b/src/playstate.h new file mode 100644 index 000000000..e4af7fa6f --- /dev/null +++ b/src/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/playstatus.cpp b/src/playstatus.cpp new file mode 100644 index 000000000..913199c4f --- /dev/null +++ b/src/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/playstatus.h b/src/playstatus.h new file mode 100644 index 000000000..b050de1ca --- /dev/null +++ b/src/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/pluginitem.cpp b/src/pluginitem.cpp new file mode 100644 index 000000000..a0498df34 --- /dev/null +++ b/src/pluginitem.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 <QSettings> +#include <QDir> + +#include <decoderfactory.h> +#include <outputfactory.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; +} diff --git a/src/pluginitem.h b/src/pluginitem.h new file mode 100644 index 000000000..a8877e61c --- /dev/null +++ b/src/pluginitem.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 PLUGINITEM_H +#define PLUGINITEM_H + +#include <QObject> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + +class DecoderFactory; +class OutputFactory; + +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; + +}; + +#endif diff --git a/src/positionbar.cpp b/src/positionbar.cpp new file mode 100644 index 000000000..5431fd4f3 --- /dev/null +++ b/src/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/positionbar.h b/src/positionbar.h new file mode 100644 index 000000000..7bb822f6e --- /dev/null +++ b/src/positionbar.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 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); + 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/preseteditor.cpp b/src/preseteditor.cpp new file mode 100644 index 000000000..1b55a229d --- /dev/null +++ b/src/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/preseteditor.h b/src/preseteditor.h new file mode 100644 index 000000000..35302b185 --- /dev/null +++ b/src/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/preseteditor.ui b/src/preseteditor.ui new file mode 100644 index 000000000..2f88d6d53 --- /dev/null +++ b/src/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/qmmpstarter.cpp b/src/qmmpstarter.cpp new file mode 100644 index 000000000..4aab25da6 --- /dev/null +++ b/src/qmmpstarter.cpp @@ -0,0 +1,156 @@ +/*************************************************************************** + * 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 <QTcpSocket> + +#include <unistd.h> + +#include "mainwindow.h" +#include "version.h" +#include "qmmpstarter.h" +#include "guard.h" + +QMMPStarter::QMMPStarter(int argc,char ** argv,QObject* parent) : QObject(parent),mw(0) +{ + 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? + argString != "--play" && + argString != "--previous" && + argString != "--next" && + argString != "--stop" && + argString != "--pause" && + argString != "--play-pause" + ) + { + qFatal("QMMP: Unknown command..."); + exit(1); + } + + if(Guard::exists(QApplication::applicationFilePath())) + { + m_tcpSocket = new QTcpSocket(this); + connect(m_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(displayError(QAbstractSocket::SocketError))); + connect(m_tcpSocket, SIGNAL(connected()),this, SLOT(writeCommand())); + + m_tcpSocket->connectToHost("127.0.0.1",TCPSERVER_PORT_NUMBER + getuid()); + + } + else + { + Guard::create(QApplication::applicationFilePath()); + QStringList arg_l = argString.split("\n", QString::SkipEmptyParts); + mw = new MainWindow(arg_l,0); + } +} + +void QMMPStarter::displayError(QAbstractSocket::SocketError socketError) +{ + switch (socketError) + { + case QAbstractSocket::RemoteHostClosedError: + break; + case QAbstractSocket::HostNotFoundError: + qWarning("The host was not found"); + break; + case QAbstractSocket::ConnectionRefusedError: + qWarning("The connection was refused by the peer. "); + break; + default: + qWarning("The following error: %s:",qPrintable(m_tcpSocket->errorString())); + } + + Guard::create(QApplication::applicationFilePath()); + mw = new MainWindow(argString.split("\n", QString::SkipEmptyParts),0); +} + +QMMPStarter::~ QMMPStarter() +{ + if(mw) + { + Guard::destroy(QApplication::applicationFilePath()); + delete mw; + } +} + +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_tcpSocket->write(barray); + m_tcpSocket->flush(); + } + else + { + qWarning("It seems that another version of application is already running ...\n"); + printUsage(); + } + + m_tcpSocket->close(); + QApplication::quit(); +} + +void QMMPStarter::printUsage() +{ + qWarning( + "Usage: qmmp [options] [files] \n" + "Options:\n" + "--------\n" + "--help Display this text and exit.\n" + "--previous Skip backwards in playlist\n" + "--play Start playing current playlist\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" + "--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/qmmpstarter.h b/src/qmmpstarter.h new file mode 100644 index 000000000..b3094eb69 --- /dev/null +++ b/src/qmmpstarter.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 _QMMPSTARTER_H +#define _QMMPSTARTER_H + +#include <QObject> +#include <QAbstractSocket> +#include <QStringList> + +class QTcpSocket; +class MainWindow; + + +/*! + * QMMPStarter represents wrapper object that is responsible + * for proper QMMP initialization(only one instance of running + * MainWindow) and passing command line args to the TcpServer. + * @author Vladimir Kuznetsov <vovanec@gmail.com> + */ +class QMMPStarter : public QObject +{ +Q_OBJECT +public: + QMMPStarter(int argc,char ** argv,QObject* parent = 0); + ~QMMPStarter(); +protected slots: + /*! + * Displays error message. + */ + void displayError(QAbstractSocket::SocketError socketError); + + /*! + * Passes command args to the running TCP server + */ + void writeCommand(); +private: + /*! + * Prints usage + */ + void printUsage(); + + /*! + * Prints version of program + */ + void printVersion(); +private: + MainWindow* mw; + QTcpSocket* m_tcpSocket; + QString argString; +}; + +#endif + + diff --git a/src/skin.cpp b/src/skin.cpp new file mode 100644 index 000000000..37e393b25 --- /dev/null +++ b/src/skin.cpp @@ -0,0 +1,697 @@ +/*************************************************************************** + * 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 <QDir> +#include <QSettings> +#include <QPainter> +#include <QPolygon> + +#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(); + m_eq_bar.clear(); + m_eq_spline.clear(); + loadEqMain(); + loadVisColor(); + loadLetters(); + loadMonoSter(); + loadVolume(); + loadBalance(); + loadRegion(); + + 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,16,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[STATUSBAR_A] = pixmap->copy ( 27,29,275,14 ); + titlebar[STATUSBAR_I] = pixmap->copy ( 27,42,275,14 ); + delete pixmap; + +} + +void Skin::loadPosBar() +{ + + QPixmap *pixmap = getPixmap ("posbar"); + + if (!pixmap) + pixmap = getDummyPixmap("posbar"); + + buttons[BT_POSBAR_N] = pixmap->copy ( 248,0,29, pixmap->height()); + buttons[BT_POSBAR_P] = pixmap->copy ( 278,0,29, pixmap->height()); + 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_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 ( 69,80,25,18 ); + buttons[PL_BT_SORT] = pixmap->copy ( 98,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 ); + +} + +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 ); + + for ( int i = 0; i < 19; ++i ) + { + m_eq_spline << pixmap->copy ( 115, 294+i, 1, 1 ); + } + 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(); + colors << QColor ( r,g,b ); + } + else if ( line.length() == 0 ) + { + break; + } + } + if ( colors.size() <24 ) + { + qWarning ( "Skin: cannot parse viscolor.txt" ); + while ( colors.size() <24 ) + colors << QColor ( 0,0,0 ); + } + m_vis_bars.clear(); + for ( j = 17; j > 1; --j ) + m_vis_bars << colors.at ( j ); + +} + +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[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; +} + diff --git a/src/skin.h b/src/skin.h new file mode 100644 index 000000000..47ca70fb7 --- /dev/null +++ b/src/skin.h @@ -0,0 +1,308 @@ +/*************************************************************************** + * 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 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 getVisBarColor(int n) const + { + return m_vis_bars[n]; + }; + const QRegion getMWRegion() const + { + return m_mwRegion; + }; + const QRegion getPLRegion() const + { + return m_plRegion; + }; + + enum Buttons + { + BT_PREVIOUS_N, + 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, + /* 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, + /* 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, + /* 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, + 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, + // Playlist play/stop buttons + /*BT_PL_PLAY, + BT_PL_STOP, + BT_PL_PAUSE, + BT_PL_NEXT, + BT_PL_PREV, + BT_PL_EJECT*/ + }; + enum TitleBar + { + TITLEBAR_A, + TITLEBAR_I, + STATUSBAR_A, + STATUSBAR_I + }; + enum PlayList + { + PL_CORNER_UL_A, + 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 + }; + enum Equalizer + { + EQ_MAIN, + EQ_TITLEBAR_A, + EQ_TITLEBAR_I, + EQ_GRAPH, + }; + enum MonoSter + { + MONO_A, + MONO_I, + STEREO_A, + STEREO_I, + }; + enum OtherParts + { + PLAY, + 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; + 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_bars; + QRegion m_mwRegion; + QRegion m_plRegion; + + void loadMain(); + void loadButtons(); + void loadTitleBar(); + void loadPosBar(); + void loadNumbers(); + void loadPlayList(); + void loadPLEdit(); + void loadEqMain(); + void loadVisColor(); + void loadShufRep(); + void loadLetters(); + void loadMonoSter(); + void loadVolume(); + void loadBalance(); + void loadRegion(); + QRegion createRegion(const QString &path, const QString &key); + +}; + +#endif diff --git a/src/src.pro b/src/src.pro new file mode 100644 index 000000000..908b0a133 --- /dev/null +++ b/src/src.pro @@ -0,0 +1,134 @@ +# ???? ?????? ? KDevelop ?????????? qmake. +# ------------------------------------------- +# ?????????? ???????????? ???????? ???????? ???????: ./src +# ???? - ??????????: ../bin/mp3player + +include(../qmmp.pri) + +FORMS += configdialog.ui \ + preseteditor.ui \ + jumptotrackdialog.ui \ + aboutdialog.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 \ + tcpserver.h \ + qmmpstarter.h \ + guard.h \ + eqpreset.h \ + preseteditor.h \ + jumptotrackdialog.h \ + aboutdialog.h \ + timeindicator.h \ + keyboardmanager.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 \ + tcpserver.cpp \ + guard.cpp \ + eqpreset.cpp \ + preseteditor.cpp \ + jumptotrackdialog.cpp \ + aboutdialog.cpp \ + timeindicator.cpp \ + keyboardmanager.cpp +contains(CONFIG,XSPF_PLUGIN){ + message(*********************************************) + message(* XSPF support will be compiled as plugin *) + message(*********************************************) + DEFINES += XSPF_PLUGIN +}else { + DEFINES -= XSPF_PLUGIN + message(*******************************************) + message(* XSPF support will be compiled in QMMP *) + message(*******************************************) + QT += xml +} + +QT += network +TARGET = ../bin/qmmp.real +CONFIG += thread release \ +warn_on +QMAKE_LIBDIR += ../lib +LIBS += -Wl,-rpath,../lib -lqmmp +INCLUDEPATH += ../lib +RESOURCES = images/images.qrc \ + stuff.qrc +# translations/qmmp_locales.qrc + +#TRANSLATIONS = translations/qmmp_ru.ts \ +# translations/qmmp_tr.ts \ +# translations/qmmp_zh_CN.ts +TEMPLATE = app +script.files += ../bin/qmmp +script.path = /bin +target.path = /bin +INSTALLS += target script diff --git a/src/stuff.qrc b/src/stuff.qrc new file mode 100644 index 000000000..dfffed67d --- /dev/null +++ b/src/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/symboldisplay.cpp b/src/symboldisplay.cpp new file mode 100644 index 000000000..df55057f2 --- /dev/null +++ b/src/symboldisplay.cpp @@ -0,0 +1,87 @@ +/*************************************************************************** + * 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) + m_max += 9 * (int) exp10(i); +} + + +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/symboldisplay.h b/src/symboldisplay.h new file mode 100644 index 000000000..065579b7a --- /dev/null +++ b/src/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/tcpserver.cpp b/src/tcpserver.cpp new file mode 100644 index 000000000..735df2716 --- /dev/null +++ b/src/tcpserver.cpp @@ -0,0 +1,69 @@ +/*************************************************************************** + * 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 <QStringList> +#include <QApplication> +#include <QTcpSocket> +#include <QRegExp> +#include <QTimer> + +#include <unistd.h> + +#include "mainwindow.h" +#include "tcpserver.h" +#include "version.h" + +TcpServer::TcpServer(MainWindow* parent) : QTcpServer(parent) , m_mainWindow(parent) +{ + if (!listen(QHostAddress::LocalHost,TCPSERVER_PORT_NUMBER + getuid())) + { + qFatal("Unable to start the server: %s ",qPrintable(errorString())); + QApplication::exit(1); + } + + connect(this, SIGNAL(newConnection()), this, SLOT(handleNewConnection())); + qDebug("TcpServer running at localost port %d",TCPSERVER_PORT_NUMBER + getuid()); +} + +void TcpServer::handleNewConnection() +{ + clientConnection = nextPendingConnection(); + connect(clientConnection, SIGNAL(readyRead()),this, SLOT(readCommand())); +} + + +void TcpServer::readCommand() +{ + QByteArray inputArray(clientConnection->readAll()); + QStringList slist = QString(inputArray).split("\n",QString::SkipEmptyParts); + QString cwd = slist.takeAt(0); + m_mainWindow->processCommandArgs(slist,cwd); + + if(clientConnection) + { + clientConnection->disconnectFromHost(); + if(clientConnection) + delete clientConnection; + } +} + + + + diff --git a/src/tcpserver.h b/src/tcpserver.h new file mode 100644 index 000000000..4438f712c --- /dev/null +++ b/src/tcpserver.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 _TCPSERVER_H +#define _TCPSERVER_H + +#include <QTcpServer> +#include <QPointer> + +class TcpSocket; +class MainWindow; + +/*! + * Class TcpServer represents server for frocessing external command line args. + @author Vladimir Kuznetsov <vovanec@gmail.com> + */ + +class TcpServer : public QTcpServer +{ +Q_OBJECT +public: + TcpServer(MainWindow* parent = 0); +protected slots: + void handleNewConnection(); + /*! + * Reads external commands and dispatches it to the MainWindow + */ + void readCommand(); +private: + MainWindow* m_mainWindow; + QPointer <QTcpSocket>clientConnection; +}; + +#endif diff --git a/src/textscroller.cpp b/src/textscroller.cpp new file mode 100644 index 000000000..98460b62b --- /dev/null +++ b/src/textscroller.cpp @@ -0,0 +1,105 @@ +/*************************************************************************** + * 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 -> start ( 50 ); + 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); + } +} diff --git a/src/textscroller.h b/src/textscroller.h new file mode 100644 index 000000000..ef469cd15 --- /dev/null +++ b/src/textscroller.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 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(); + +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/timeindicator.cpp b/src/timeindicator.cpp new file mode 100644 index 000000000..3e2b04ee0 --- /dev/null +++ b/src/timeindicator.cpp @@ -0,0 +1,125 @@ +/*************************************************************************** + * 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 "skin.h" +#include "timeindicator.h" + +TimeIndicator::TimeIndicator ( QWidget *parent ) + : PixmapWidget ( parent ) +{ + m_skin = Skin::getPointer(); + m_pixmap = QPixmap ( 65,20 ); + m_elapsed = true; + m_time = m_songDuration = 0; + readSettings(); + m_needToShowTime = false; + updateSkin(); + 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) + { + 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/timeindicator.h b/src/timeindicator.h new file mode 100644 index 000000000..19981a4b3 --- /dev/null +++ b/src/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/titlebar.cpp b/src/titlebar.cpp new file mode 100644 index 000000000..db9b272fc --- /dev/null +++ b/src/titlebar.cpp @@ -0,0 +1,111 @@ +/*************************************************************************** + * 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 <QMainWindow> +#include <QApplication> +#include <QMouseEvent> +#include <QMenu> + +#include "titlebar.h" +#include "skin.h" +#include "button.h" +#include "dock.h" + +TitleBar::TitleBar(QWidget *parent) + : PixmapWidget(parent) +{ + skin = Skin::getPointer(); + setPixmap(skin->getTitleBar(Skin::TITLEBAR_A)); + mw = qobject_cast<MainWindow*>(parent); + //buttons + menu = new Button(this,Skin::BT_MENU_N,Skin::BT_MENU_P); + menu->move(6,3); + minimize = new Button(this,Skin::BT_MINIMIZE_N,Skin::BT_MINIMIZE_P); + minimize->move(244,3); + connect(minimize, SIGNAL(clicked()), mw, SLOT(showMinimized())); + shade = new Button(this,Skin::BT_SHADE1_N,Skin::BT_SHADE1_P); + shade->move(254,3); + close = new Button(this,Skin::BT_CLOSE_N,Skin::BT_CLOSE_P); + close->move(264,3); + connect(close, SIGNAL(clicked()), mw, SLOT(handleCloseRequest())); + setActive(FALSE); + connect(skin, SIGNAL(skinChanged()), this, SLOT(updateSkin())); +} + + +TitleBar::~TitleBar() +{} + + + +void TitleBar::mousePressEvent(QMouseEvent* event) +{ + switch((int) event->button ()) + { + case Qt::LeftButton: + { + pos = event->pos(); + PlayList *pl = mw->getPLPointer(); + Dock::getPointer()->calculateDistances(); + x_diff = - mw->x() + pl->x(); + y_diff = - mw->y() + pl->y(); + break; + } + case Qt::RightButton: + { + mw->menu()->exec(event->globalPos()); + } + } +} + +void TitleBar::mouseReleaseEvent(QMouseEvent*) +{ + Dock::getPointer()->updateDock(); +} +void TitleBar::mouseMoveEvent(QMouseEvent* event) +{ + QPoint npos = (event->globalPos()-pos); + Dock::getPointer()->move(mw, npos); +} + +void TitleBar::setActive(bool a) +{ + if(a) + { + setPixmap(skin->getTitleBar(Skin::TITLEBAR_A)); + menu->show(); + minimize->show(); + shade->show(); + close->show(); + } + else + { + setPixmap(skin->getTitleBar(Skin::TITLEBAR_I)); + menu->hide(); + minimize->hide(); + shade->hide(); + close->hide(); + } +} + +void TitleBar::updateSkin() +{ + setActive(FALSE); +} diff --git a/src/titlebar.h b/src/titlebar.h new file mode 100644 index 000000000..7b8874f17 --- /dev/null +++ b/src/titlebar.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 TITLEBAR_H +#define TITLEBAR_H + +#include <QMainWindow> +#include "pixmapwidget.h" + +#include "playlist.h" +#include <QPoint> +#include "mainwindow.h" +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class MainWindow; +class QMouseEvent; + +class Skin; +class Button; + + +class TitleBar : public PixmapWidget +{ +Q_OBJECT +public: + TitleBar(QWidget *parent = 0); + + ~TitleBar(); + + void setActive(bool); + +private slots: + void updateSkin(); + +private: + Skin *skin; + QPoint pos; + MainWindow *mw; + Button *menu; + Button *minimize; + Button *shade; + Button *close; + int x_diff, y_diff; + + +protected: + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); +}; + + + +#endif diff --git a/src/togglebutton.cpp b/src/togglebutton.cpp new file mode 100644 index 000000000..0405ab344 --- /dev/null +++ b/src/togglebutton.cpp @@ -0,0 +1,74 @@ +/*************************************************************************** + * 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::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/togglebutton.h b/src/togglebutton.h new file mode 100644 index 000000000..07a7ec452 --- /dev/null +++ b/src/togglebutton.h @@ -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. * + ***************************************************************************/ +#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); + +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/translations/qmmp_locales.qrc b/src/translations/qmmp_locales.qrc new file mode 100644 index 000000000..64ac204fa --- /dev/null +++ b/src/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/translations/qmmp_ru.qm b/src/translations/qmmp_ru.qm Binary files differnew file mode 100644 index 000000000..0b543721d --- /dev/null +++ b/src/translations/qmmp_ru.qm diff --git a/src/translations/qmmp_ru.ts b/src/translations/qmmp_ru.ts new file mode 100644 index 000000000..7e4a8499d --- /dev/null +++ b/src/translations/qmmp_ru.ts @@ -0,0 +1,644 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS><TS version="1.1" language="ru"> +<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/translations/qmmp_tr.qm b/src/translations/qmmp_tr.qm Binary files differnew file mode 100644 index 000000000..1180e41d5 --- /dev/null +++ b/src/translations/qmmp_tr.qm diff --git a/src/translations/qmmp_tr.ts b/src/translations/qmmp_tr.ts new file mode 100644 index 000000000..73f8206d6 --- /dev/null +++ b/src/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/translations/qmmp_zh_CN.qm b/src/translations/qmmp_zh_CN.qm Binary files differnew file mode 100644 index 000000000..2e3e3f2ea --- /dev/null +++ b/src/translations/qmmp_zh_CN.qm diff --git a/src/translations/qmmp_zh_CN.ts b/src/translations/qmmp_zh_CN.ts new file mode 100644 index 000000000..3aeefd569 --- /dev/null +++ b/src/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/version.h b/src/version.h new file mode 100644 index 000000000..8d6fabe5b --- /dev/null +++ b/src/version.h @@ -0,0 +1,10 @@ +#ifndef _QMMP_VERSION_H +#define _QMMP_VERSION_H + +#define QMMP_VERSION 0.1.2 + +#define QMMP_STR_VERSION "0.1.2" + +#define TCPSERVER_PORT_NUMBER 33000 + +#endif diff --git a/src/volumebar.cpp b/src/volumebar.cpp new file mode 100644 index 000000000..c29794033 --- /dev/null +++ b/src/volumebar.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 <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); + if (m_value!=m_old) + { + m_old = m_value; + //mw->seek(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/volumebar.h b/src/volumebar.h new file mode 100644 index 000000000..51bc7ac46 --- /dev/null +++ b/src/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 |
