]> Some of my projects - aniplayer2.git/commitdiff
Continue porting
authorAPTX <marek321@gmail.com>
Sat, 2 Mar 2013 12:01:56 +0000 (13:01 +0100)
committerAPTX <marek321@gmail.com>
Sat, 2 Mar 2013 12:01:56 +0000 (13:01 +0100)
32 files changed:
aniplayer2/aniplayer.cpp
aniplayer2/aniplayer.h
aniplayer2/aniplayer2.pri
aniplayer2/aniplayer2.pro
aniplayer2/aniplayerapplication.cpp
aniplayer2/aniplayerapplication.h
aniplayer2/constants.h [new file with mode: 0644]
aniplayer2/volumeslider.cpp [new file with mode: 0644]
aniplayer2/volumeslider.h [new file with mode: 0644]
aniplayer2_dshow/aniplayer2_dshow.pro
aniplayer2_dshow/aniplayerdshow.cpp
aniplayer2_dshow/aniplayerdshow.h
aniplayer2_dshow/aniplayerdshowinternal.cpp
aniplayer2_dshow/aniplayerdshowinternal.h
aniplayer2_dshow/videowidgetdshow.cpp
player/aniplayer.exe.manifest [new file with mode: 0644]
player/aniplayer.qrc [new file with mode: 0644]
player/aniplayer.rc [new file with mode: 0644]
player/main.cpp
player/mainwindow.cpp
player/mainwindow.h
player/menu.cpp [new file with mode: 0644]
player/menu.h [new file with mode: 0644]
player/player.pro
player/seekslider.cpp [new file with mode: 0644]
player/seekslider.h [new file with mode: 0644]
player/versiondialog.cpp [new file with mode: 0644]
player/versiondialog.h [new file with mode: 0644]
resource/aniplayer-mikuru.ico [new file with mode: 0644]
resource/aniplayer.qrc [new file with mode: 0644]
resource/mikuru-icon-base.png [new file with mode: 0644]
resource/mikuru-icon-original.png [new file with mode: 0644]

index cb750cc1fa6ec2efa792124c3534f4f196dc1228..396064f162a1aa0ec28bb7f25182b30b269483c0 100644 (file)
@@ -1,7 +1,9 @@
 #include "aniplayer.h"
 
+#include <QTimerEvent>
+#include <QSettings>
 
-AniPlayer::AniPlayer(QObject *parent) : QObject(parent), m_state(Stopped)
+AniPlayer::AniPlayer(QObject *parent) : QObject(parent), m_state(NoFileLoaded)
 {
 }
 
@@ -19,6 +21,31 @@ QString AniPlayer::currentFile() const
        return m_currentFile;
 }
 
+qint64 AniPlayer::tickInterval() const
+{
+       return m_tickInterval;
+}
+
+ChapterList AniPlayer::chapters() const
+{
+       return m_chapters;
+}
+
+Chapter AniPlayer::chapter(int i) const
+{
+       return m_chapters[i];
+}
+
+StreamList AniPlayer::streams() const
+{
+       return m_streams;
+}
+
+Stream *AniPlayer::stream(int i) const
+{
+       return m_streams[i];
+}
+
 bool AniPlayer::open(const QString &file)
 {
        if (file == m_currentFile)
@@ -31,14 +58,15 @@ bool AniPlayer::open(const QString &file)
        m_currentFile = file;
        emit currentFileChanged(m_currentFile);
        emit totalTimeChanged(totalTime());
+       emit videoSizeChanged(videoSize());
        return true;
 }
 
 void AniPlayer::play()
 {
        if (state() == Paused || state() == Stopped)
-       if (iplay())
-               setState(Playing);
+               if (iplay())
+                       setState(Playing);
 }
 
 void AniPlayer::pause()
@@ -59,10 +87,10 @@ void AniPlayer::stop()
 
 void AniPlayer::togglePause()
 {
-       if (state() == Paused)
-               play();
-       else
+       if (state() == Playing)
                pause();
+       else
+               play();
 }
 
 bool AniPlayer::seek(qint64 position)
@@ -75,9 +103,23 @@ void AniPlayer::skip(qint64 msec)
        seek(currentTime() + msec);
 }
 
+bool AniPlayer::seek(const Chapter &chapter)
+{
+       return seek(chapter.time);
+}
+
+bool AniPlayer::seekToChapter(int i)
+{
+       return seek(m_chapters[i].time);
+}
+
 bool AniPlayer::setVolume(double percent)
 {
-       return isetVolume(percent);
+       if(!isetVolume(percent))
+               return false;
+
+       emit volumeChanged(percent);
+       return true;
 }
 
 void AniPlayer::volumeUp(int by)
@@ -98,14 +140,91 @@ void AniPlayer::changeVolume(int by)
        setVolume(newVolume);
 }
 
+void AniPlayer::setMuted(bool muted)
+{
+       if (isetMuted(muted))
+               emit mutedChanged(muted);
+}
+
+void AniPlayer::setTickInterval(qint64 tickInterval)
+{
+       if (m_tickInterval != tickInterval) {
+               m_tickInterval = tickInterval;
+               emit tickIntervalChanged(tickInterval);
+       }
+}
+
+bool AniPlayer::changeToStream(Stream *stream)
+{
+       return ichangeToStream(stream);
+}
+
+bool AniPlayer::changeToStream(int i)
+{
+       return changeToStream(m_streams[i]);
+}
+
+void AniPlayer::timerEvent(QTimerEvent *e)
+{
+       if (e->timerId() != tickTimer.timerId())
+               return;
+
+       const qint64 ct = currentTime();
+       if (ct < lastTick + m_tickInterval)
+               return;
+
+       lastTick = ct;
+       emit tick(ct);
+}
+
+bool AniPlayer::seekInternal(qint64 position)
+{
+       qint64 ret = seek(position);
+       emit currentTimeChanged(position);
+       return ret;
+}
 
 void AniPlayer::setState(AniPlayer::State newState)
 {
        if (m_state == newState)
                return;
 
+       if (newState == Playing)
+       {
+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
+               tickTimer.start(TICK_TIMER_INTERVAL, this);
+#else
+               tickTimer.start(TICK_TIMER_INTERVAL, Qt::PreciseTimer, this);
+#endif
+               lastTick = 0;
+       }
+       else
+               tickTimer.stop();
+
        State oldState = m_state;
        m_state = newState;
        emit stateChanged(newState);
        emit stateChanged(newState, oldState);
 }
+
+void AniPlayer::setChapters(const ChapterList &chapters)
+{
+       m_chapters = chapters;
+       emit chaptersChanged(chapters);
+}
+
+void AniPlayer::setStreams(const StreamList &streams)
+{
+       qDeleteAll(m_streams);
+       m_streams = streams;
+       emit streamsChanged(streams);
+}
+
+
+void AniPlayer::fileFinished()
+{
+       ifileFinished();
+       setState(Stopped);
+       emit playbackFinished();
+}
+
index 418c1bd9dc0b113f40dd050ec7b700bd521ee365..3ba45e249057bc944c53d2df0dc37198ecb2fa6b 100644 (file)
@@ -6,8 +6,33 @@
 #include <QObject>
 #include <QString>
 #include <QSize>
+#include <QBasicTimer>
 
 class VideoWidget;
+class QTimerEvent;
+
+struct ANIPLAYER2SHARED_EXPORT Chapter
+{
+       QString name;
+       qint64 time;
+};
+typedef QList<Chapter> ChapterList;
+
+enum StreamType
+{
+       VideoStream,
+       AudioStream,
+       SubtitleStream,
+       OtherStream
+};
+
+struct ANIPLAYER2SHARED_EXPORT Stream
+{
+       QString name;
+       StreamType type;
+       QString description;
+};
+typedef QList<Stream *> StreamList;
 
 class ANIPLAYER2SHARED_EXPORT AniPlayer : public QObject
 {
@@ -16,12 +41,17 @@ class ANIPLAYER2SHARED_EXPORT AniPlayer : public QObject
        Q_PROPERTY(qint64 currentTime READ currentTime WRITE seek STORED false)
        Q_PROPERTY(qint64 totalTime READ totalTime STORED false)
        Q_PROPERTY(double volume READ volume WRITE setVolume NOTIFY volumeChanged STORED false)
+       Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
        Q_PROPERTY(QSize videoSize READ videoSize)
        Q_PROPERTY(QString currentFile READ currentFile NOTIFY currentFileChanged)
+       Q_PROPERTY(qint64 tickInterval READ tickInterval WRITE setTickInterval NOTIFY tickIntervalChanged)
+       Q_PROPERTY(ChapterList chapters READ chapters NOTIFY chaptersChanged)
+       Q_PROPERTY(StreamList streams READ streams NOTIFY streamsChanged)
 
 public:
        enum State
        {
+               NoFileLoaded,
                Stopped,
                Playing,
                Paused,
@@ -41,11 +71,20 @@ public:
        virtual qint64 totalTime() const = 0;
 
        virtual double volume() const = 0;
+       virtual bool isMuted() const = 0;
 
        virtual QSize videoSize() const = 0;
 
        QString currentFile() const;
 
+       qint64 tickInterval() const;
+
+       ChapterList chapters() const;
+       Chapter chapter(int i) const;
+
+       StreamList streams() const;
+       Stream *stream(int i) const;
+
 public slots:
        bool open(const QString &file);
        void play();
@@ -56,34 +95,79 @@ public slots:
 
        bool seek(qint64 position);
        void skip(qint64 msec = 85000);
+       bool seek(const Chapter &chapter);
+       bool seekToChapter(int i);
 
 
        bool setVolume(double percent);
        void volumeUp(int by = 5);
        void volumeDown(int by = 5);
        void changeVolume(int by = 5);
+       void setMuted(bool muted);
+
+       void setTickInterval(qint64 tickInterval);
+
+       bool changeToStream(Stream *stream);
+       bool changeToStream(int i);
 
 signals:
        void stateChanged(AniPlayer::State newState);
        void stateChanged(AniPlayer::State newState, AniPlayer::State oldState);
        void volumeChanged(double newPercent);
+       void mutedChanged(bool muted);
        void currentFileChanged(QString file);
 
+       void videoSizeChanged(QSize newSize);
+       void currentTimeChanged(qint64 newCurrentTime);
        void totalTimeChanged(qint64 newTotalTime);
 
+       void playbackFinished();
+
+       void tick(qint64 current);
+       void tickIntervalChanged(qint64 arg);
+       void chaptersChanged(ChapterList chapters);
+       void streamsChanged(StreamList streams);
+
+protected slots:
+       void fileFinished();
+
 protected:
+       // Don't call i* methods directly.
+       // Call the versions without i.
+
+       // Open file
        virtual bool iopen(const QString &file) = 0;
+
+       // Playback
        virtual bool iplay() = 0;
        virtual bool ipause() = 0;
        virtual bool istop() = 0;
+       virtual void ifileFinished() {}
 
+       // Settings
        virtual bool iseek(qint64) = 0;
        virtual bool isetVolume(double) = 0;
+       virtual bool isetMuted(bool) = 0;
+       virtual bool ichangeToStream(Stream *stream) = 0;
+
+       void timerEvent(QTimerEvent *);
+
+       bool seekInternal(qint64 position);
 
        void setState(State newState);
+       void setChapters(const ChapterList &chapters);
+       void setStreams(const StreamList &streams);
 
        State m_state;
        QString m_currentFile;
+
+       ChapterList m_chapters;
+       StreamList m_streams;
+
+       qint64 m_tickInterval;
+       qint64 lastTick;
+       QBasicTimer tickTimer;
+       static const int TICK_TIMER_INTERVAL = 16;
 };
 
 #endif // ANIPLAYER_H
index 7757fbb6189ffd43e0c74f0c2927ed9150f9f152..f7f0ae857d9a2150a894c1d926276b7131db8e6e 100644 (file)
@@ -3,3 +3,5 @@ INCLUDEPATH += $$PWD
 DEPENDPATH += $$PWD
 LIBS += -laniplayer2
 LIBS += -L$$PWD/../build
+
+include(../qtsingleapplication/qtsingleapplication.pri)
index 05d613ed42cb954d34246957accd77e773b18e63..9caf30083f70726bdd0885f7215034bc984353dd 100644 (file)
@@ -9,17 +9,21 @@ TEMPLATE = lib
 
 DEFINES += ANIPLAYER2_LIBRARY
 
-SOURCES += aniplayer.cpp
-
 HEADERS += aniplayer2_global.h \
-       aniplayer.h\
-       videowidget.h
-
+       constants.h \
+       aniplayerapplication.h \
+       aniplayer.h \
+       videowidget.h \
+    volumeslider.h
 
-HEADERS += \
+SOURCES += aniplayer.cpp \
+       videowidget.cpp \
+       aniplayerapplication.cpp \
+    volumeslider.cpp
 
 
-SOURCES += \
-       videowidget.cpp
-
 include(../config.pri)
+include(../qtsingleapplication/qtsingleapplication.pri)
+
+REV = $$system(git show-ref --head -s HEAD)
+DEFINES += REVISION=\"$${REV}\"
index 86b3c39f2b3e4471cedc6ff13ff1562da77b762c..51cebe8cb3f128ff9eba8db29111c3f6324d6ced 100644 (file)
@@ -1,6 +1,46 @@
 #include "aniplayerapplication.h"
 
+#include <QSettings>
+#include "constants.h"
+
 AniPlayerApplication::AniPlayerApplication(int &argc, char **argv) :
        QtSingleApplication(argc, argv)
 {
+       QSettings::setDefaultFormat(QSettings::IniFormat);
+       setApplicationName(::applicationName);
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+       setApplicationDisplayName(::applicationName);
+#endif
+       setApplicationVersion(::applicationVersion);
+       setOrganizationName(::organizationName);
+}
+
+void AniPlayerApplication::handleMessage(const QString &message)
+{
+               if (message.left(4) != "open")
+                       return;
+
+               QString file;
+
+               int pos = -1;
+               if ((pos = message.indexOf(' ')) != -1)
+                       file = message.mid(pos + 1);
+
+               if (!file.isEmpty())
+                       emit openFileRequested(file);
+}
+
+const char * const AniPlayerApplication::revision()
+{
+#ifndef STRINGIFY
+#      define STRINGIFY_INTERNAL(x) #x
+#      define STRINGIFY(x) STRINGIFY_INTERNAL(x)
+#endif
+
+#if defined(REVISION)
+       static const char *const revisionString = STRINGIFY(REVISION);
+#else
+       static const char *const revisionString = "Unknown revision";
+#endif
+       return revisionString;
 }
index 9ba08ae00d2d0f300a8e35cc4d1c973e5afe4fc3..6682941c15b6a3400fb8f5420147e314b48f15d8 100644 (file)
@@ -4,16 +4,32 @@
 #include "aniplayer2_global.h"
 #include <QtSingleApplication>
 
-class AniPlayerApplication : public QtSingleApplication
+class AniPlayer;
+
+#ifdef qApp
+#      undef qApp
+#endif
+#define qApp (AniPlayerApplication::instance())
+
+class ANIPLAYER2SHARED_EXPORT AniPlayerApplication : public QtSingleApplication
 {
        Q_OBJECT
 public:
        explicit AniPlayerApplication(int &argc, char **argv);
 
 signals:
+       void openFileRequested(const QString &file);
 
 public slots:
+       void handleMessage(const QString &message);
+
+public:
+       inline static const AniPlayerApplication *instance()
+       {
+               return static_cast<AniPlayerApplication *>(QtSingleApplication::instance());
+       }
 
+       static const char *const revision();
 };
 
 #endif // ANIPLAYERAPPLICATION_H
diff --git a/aniplayer2/constants.h b/aniplayer2/constants.h
new file mode 100644 (file)
index 0000000..fb69b10
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef CONSTANTS_H
+#define CONSTANTS_H
+
+static const char *applicationName = "AniPlayer";
+static const char *applicationVersion = "2.0.0B1";
+static const char *organizationName = "APTX";
+
+#endif // CONSTANTS_H
diff --git a/aniplayer2/volumeslider.cpp b/aniplayer2/volumeslider.cpp
new file mode 100644 (file)
index 0000000..df19939
--- /dev/null
@@ -0,0 +1,77 @@
+#include "volumeslider.h"
+
+#include <QSlider>
+#include <QPushButton>
+#include <QHBoxLayout>
+#include <QStyle>
+
+VolumeSlider::VolumeSlider(QWidget *parent) :
+       QWidget(parent)
+{
+       QHBoxLayout *layout = new QHBoxLayout(this);
+       layout->setContentsMargins(0, 0, 0, 0);
+
+       muteButton = new QPushButton;
+       muteButton->setCheckable(true);
+       muteButton->setIcon(style()->standardIcon(QStyle::SP_MediaVolume));
+
+       layout->addWidget(muteButton);
+
+       slider = new QSlider;
+       slider->setOrientation(Qt::Horizontal);
+       slider->setMinimum(0);
+       slider->setMaximum(10000);
+
+       layout->addWidget(slider);
+
+       connect(muteButton, SIGNAL(clicked(bool)), this, SLOT(setMutedByUser(bool)));
+       connect(slider, SIGNAL(sliderMoved(int)), this, SLOT(setVolumeByUser(int)));
+}
+
+double VolumeSlider::volume() const
+{
+       return double(slider->value()) / 10000;
+}
+
+bool VolumeSlider::isMuted() const
+{
+       return muteButton->isChecked();
+}
+
+
+void VolumeSlider::setVolume(double newVolume)
+{
+       if (volume() == newVolume)
+               return;
+
+       slider->setValue(int(10000 * newVolume));
+       emit volumeChanged(newVolume);
+}
+
+void VolumeSlider::setMuted(bool mute)
+{
+       if (isMuted() == mute)
+               return;
+
+       muteButton->setChecked(mute);
+       if (mute)
+               muteButton->setIcon(style()->standardIcon(QStyle::SP_MediaVolumeMuted));
+       else
+               muteButton->setIcon(style()->standardIcon(QStyle::SP_MediaVolume));
+
+       emit mutedChanged(mute);
+}
+
+void VolumeSlider::setMutedByUser(bool mute)
+{
+       if (mute)
+               muteButton->setIcon(style()->standardIcon(QStyle::SP_MediaVolumeMuted));
+       else
+               muteButton->setIcon(style()->standardIcon(QStyle::SP_MediaVolume));
+       emit mutedChangedByUser(mute);
+}
+
+void VolumeSlider::setVolumeByUser(int newVolume)
+{
+       emit volumeChangedByUser(double(newVolume) / 10000);
+}
diff --git a/aniplayer2/volumeslider.h b/aniplayer2/volumeslider.h
new file mode 100644 (file)
index 0000000..25e8fc5
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef VOLUMESLIDER_H
+#define VOLUMESLIDER_H
+
+#include "aniplayer2_global.h"
+#include <QWidget>
+
+class QSlider;
+class QPushButton;
+
+class ANIPLAYER2SHARED_EXPORT VolumeSlider : public QWidget
+{
+       Q_OBJECT
+       Q_PROPERTY(double volume READ volume WRITE setVolume NOTIFY volumeChanged USER true)
+       Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
+
+
+public:
+       explicit VolumeSlider(QWidget *parent = 0);
+
+       double volume() const;
+       bool isMuted() const;
+
+signals:
+       void volumeChanged(double volume);
+       void volumeChangedByUser(double volume);
+
+       void mutedChanged(bool muted);
+       void mutedChangedByUser(bool muted);
+
+public slots:
+       void setVolume(double newVolume);
+       void setVolumeByUser(int newVolume);
+
+       void setMuted(bool mute);
+       void setMutedByUser(bool mute);
+
+private:
+       QSlider *slider;
+       QPushButton *muteButton;
+};
+
+#endif // VOLUMESLIDER_H
index 7bef14d21a60c961c837f220f4c4e5665448c324..43f10473f9d37282465caf967fb5a3e432c786f9 100644 (file)
@@ -26,4 +26,4 @@ SOURCES += \
 include(../config.pri)
 include(../aniplayer2/aniplayer2.pri)
 
-LIBS += -lstrmiids -lole32
+LIBS += -lstrmiids -lole32 -lOleAut32 -lUser32
index 67e603ee306b5a36a3f1e3dd6e406e9dafef49ff..5dc361c36edd7e7b1173feef5241c7a9931d9f7d 100644 (file)
@@ -8,19 +8,14 @@
 AniPlayerDShow::AniPlayerDShow(QObject *parent) :
        AniPlayer(parent)
 {
-       HRESULT hr;
-
-       hr = CoInitialize(NULL);
-       if (FAILED(hr))
-               qDebug() << "Failed to initialize COM";
-
        m_videoWidget = new VideoWidgetDShow(this);
        d = new AniPlayerDShowInternal(this);
 }
 
 AniPlayerDShow::~AniPlayerDShow()
 {
-       CoUninitialize();
+       delete d;
+       delete m_videoWidget;
 }
 
 QSize AniPlayerDShow::videoSize() const
@@ -59,6 +54,11 @@ double AniPlayerDShow::volume() const
        return d->volume();
 }
 
+bool AniPlayerDShow::isMuted() const
+{
+       return d->isMuted();
+}
+
 bool AniPlayerDShow::iopen(const QString &file)
 {
        if (!d->OpenFile(reinterpret_cast<const wchar_t *>(file.utf16())))
@@ -80,7 +80,10 @@ bool AniPlayerDShow::ipause()
 
 bool AniPlayerDShow::istop()
 {
-       return d->stop();
+       bool ret = d->stop();
+       if (ret)
+               seekInternal(0);
+       return ret;
 }
 
 bool AniPlayerDShow::iseek(qint64 position)
@@ -92,3 +95,18 @@ bool AniPlayerDShow::isetVolume(double volume)
 {
        return d->setVolume(volume);
 }
+
+bool AniPlayerDShow::isetMuted(bool muted)
+{
+       return d->setMuted(muted);
+}
+
+bool AniPlayerDShow::ichangeToStream(Stream *stream)
+{
+       return d->changeToStream(static_cast<StreamInternal *>(stream));
+}
+
+void AniPlayerDShow::ifileFinished()
+{
+       istop();
+}
index 6d176d71f8e0bb10fd9cfaed1bc5edb6ab41e91a..603dbabb1787d59d0c83f5828c64bb573ca6f43c 100644 (file)
@@ -10,6 +10,7 @@ struct AniPlayerDShowInternal;
 
 class ANIPLAYER2_DSHOWSHARED_EXPORT AniPlayerDShow : public AniPlayer
 {
+       friend struct AniPlayerDShowInternal;
        Q_OBJECT
 public:
        explicit AniPlayerDShow(QObject *parent = 0);
@@ -25,6 +26,7 @@ public:
        qint64 totalTime() const;
 
        double volume() const;
+       bool isMuted() const;
 
 signals:
 
@@ -36,6 +38,9 @@ protected:
 
        bool iseek(qint64 position);
        bool isetVolume(double volume);
+       bool isetMuted(bool muted);
+       bool ichangeToStream(Stream *stream);
+       void ifileFinished();
 
 private:
        AniPlayerDShowInternal *d;
index f181be63faed343e94d7a49eee470f451c93d41f..5f88bccc2eca4fc31d3d34878952b00d2e3f9510 100644 (file)
@@ -3,14 +3,24 @@
 #include "videowidgetdshow.h"
 #include "aniplayerdshow.h"
 
-#include <Dshow.h>
+#include <dshow.h>
+#include <initguid.h>
+#include <qnetwork.h>
+
 #include <Evr.h>
 
+#include <QDebug>
+
 HRESULT IsPinConnected(IPin *pPin, BOOL *pResult);
 HRESULT IsPinDirection(IPin *pPin, PIN_DIRECTION dir, BOOL *pResult);
 HRESULT AddFilterByCLSID(IGraphBuilder *pGraph, REFGUID clsid, IBaseFilter **ppF, LPCWSTR wszName);
 HRESULT FindConnectedPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin);
 
+void _FreeMediaType(AM_MEDIA_TYPE& mt);
+void _DeleteMediaType(AM_MEDIA_TYPE *pmt);
+
+DEFINE_GUID(MEDIATYPE_Subtitle, 0xE487EB08, 0x6B26, 0x4be9, 0x9D, 0xD3, 0x99, 0x34, 0x34, 0xD3, 0x13, 0xFD);
+
 AniPlayerDShowInternal::AniPlayerDShowInternal(AniPlayerDShow *player_) : player(player_)
 {
        pGraph = 0;
@@ -22,11 +32,22 @@ AniPlayerDShowInternal::AniPlayerDShowInternal(AniPlayerDShow *player_) : player
        pVideoDisplay = 0;
 
        pAudioControl = 0;
+
+       mutedVolume = -1;
+
+       HRESULT hr;
+
+       hr = CoInitialize(NULL);
+       if (FAILED(hr))
+               qDebug() << "Failed to initialize COM";
+
 }
 
 AniPlayerDShowInternal::~AniPlayerDShowInternal()
 {
        TearDownGraph();
+
+       CoUninitialize();
 }
 
 bool AniPlayerDShowInternal::play()
@@ -62,6 +83,9 @@ QSize AniPlayerDShowInternal::videoSize() const
 
 qint64 AniPlayerDShowInternal::totalTime() const
 {
+       if (!pSeeking)
+               return -1;
+
        HRESULT hr = pSeeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
        if (FAILED(hr))
                return -1;
@@ -77,6 +101,9 @@ qint64 AniPlayerDShowInternal::totalTime() const
 
 qint64 AniPlayerDShowInternal::currentTime() const
 {
+       if (!pSeeking)
+               return -1;
+
        HRESULT hr = pSeeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
        if (FAILED(hr))
                return -1;
@@ -92,6 +119,9 @@ qint64 AniPlayerDShowInternal::currentTime() const
 
 bool AniPlayerDShowInternal::seek(qint64 position)
 {
+       if (!pSeeking)
+               return false;
+
        // Positions are in 100-nanoseconds, convert from miliseconds
        position *= 10000;
 
@@ -111,6 +141,12 @@ bool AniPlayerDShowInternal::seek(qint64 position)
 
 double AniPlayerDShowInternal::volume() const
 {
+       if (!pAudioControl)
+               return -1;
+
+       if (isMuted())
+               return mutedVolume;
+
        long lvolume;
 
        HRESULT hr = pAudioControl->get_Volume(&lvolume);
@@ -125,6 +161,15 @@ double AniPlayerDShowInternal::volume() const
 
 bool AniPlayerDShowInternal::setVolume(double volume)
 {
+       if (!pAudioControl)
+               return false;
+
+       if (isMuted())
+       {
+               mutedVolume = volume;
+               return true;
+       }
+
        volume = 1 - volume;
        long lvolume = -long(volume * 10000.0);
 
@@ -135,8 +180,77 @@ bool AniPlayerDShowInternal::setVolume(double volume)
        return true;
 }
 
+bool AniPlayerDShowInternal::isMuted() const
+{
+       return mutedVolume >= 0;
+}
+
+bool AniPlayerDShowInternal::setMuted(bool muted)
+{
+       if (muted == isMuted())
+               return true;
+
+       if (muted)
+       {
+               double currentVolume = volume();
+
+               if (currentVolume < 0)
+                       return false;
+
+               if (!setVolume(0))
+                       return false;
+
+               mutedVolume = currentVolume;
+               return true;
+       }
+
+       double newVolume = mutedVolume;
+       mutedVolume = -1;
+
+       if (setVolume(newVolume))
+               return true;
+
+       mutedVolume = newVolume;
+       return false;
+}
+
+bool AniPlayerDShowInternal::changeToStream(StreamInternal *stream)
+{
+       Q_ASSERT(streamFilters.contains(stream->filter));
+
+       IAMStreamSelect *pStreamSelect = 0;
+       HRESULT hr = stream->filter->QueryInterface(IID_PPV_ARGS(&pStreamSelect));
+       if (SUCCEEDED(hr))
+               hr = pStreamSelect->Enable(stream->streamNo, AMSTREAMSELECTENABLE_ENABLE);
+       SafeRelease(&pStreamSelect);
+
+       return SUCCEEDED(hr);
+}
+
 void AniPlayerDShowInternal::handleNotifications()
 {
+       if (!pEvent)
+               return;
+
+       long evCode;
+       LONG_PTR param1, param2;
+       while (SUCCEEDED(pEvent->GetEvent(&evCode, &param1, &param2, 0)))
+       {
+               pEvent->FreeEventParams(evCode, param1, param2);
+               switch (evCode)
+               {
+                       case EC_COMPLETE:  // Fall through.
+                       case EC_USERABORT: // Fall through.
+                       case EC_ERRORABORT:
+                               player->fileFinished();
+                       return;
+                       case EC_LENGTH_CHANGED:
+                               emit player->totalTimeChanged(totalTime());
+                       break;
+                       case EC_VIDEO_SIZE_CHANGED:
+                               emit player->videoSizeChanged(videoSize());
+               }
+       }
 }
 
 HRESULT AniPlayerDShowInternal::InitializeGraph()
@@ -174,14 +288,14 @@ HRESULT AniPlayerDShowInternal::InitializeGraph()
        {
                goto done;
        }
-/*
+
        // Set up event notification.
-       hr = pEvent->SetNotifyWindow((OAHWND)m_hwnd, WM_GRAPH_EVENT, NULL);
+       hr = pEvent->SetNotifyWindow((OAHWND)hwnd(), WM_APP + 1, NULL);
        if (FAILED(hr))
        {
                goto done;
        }
-*/
+
 //     m_state = STATE_STOPPED;
 
 done:
@@ -190,13 +304,16 @@ done:
 
 void AniPlayerDShowInternal::TearDownGraph()
 {
-/*
+
        // Stop sending event messages
        if (pEvent)
        {
                pEvent->SetNotifyWindow((OAHWND)NULL, NULL, NULL);
        }
-*/
+
+       for (auto i = streamFilters.constBegin(); i != streamFilters.constEnd(); ++i)
+               SafeRelease(&const_cast<IBaseFilter *>(*i));
+       streamFilters.clear();
        SafeRelease(&pGraph);
        SafeRelease(&pControl);
        SafeRelease(&pEvent);
@@ -368,6 +485,138 @@ bool AniPlayerDShowInternal::OpenFile(PCWSTR pszFileName)
        // Try to render the streams.
        hr = RenderStreams(pSource);
 
+       {
+               IAMExtendedSeeking *pExtendedSeeking = 0;
+
+               HRESULT hr = pSource->QueryInterface(IID_IAMExtendedSeeking,  IID_PPV_ARGS_Helper(&pExtendedSeeking));
+
+               ChapterList chapters;
+               if (SUCCEEDED(hr))
+               {
+                       long count;
+                       hr = pExtendedSeeking->get_MarkerCount(&count);
+
+                       // These "markers" actually start at 1
+                       for (long i = 1; i <= count; ++i)
+                       {
+                               BSTR name = 0;
+                               double time;
+                               Chapter chapter;
+
+                               hr = pExtendedSeeking->GetMarkerName(i, &name);
+
+                               if (SUCCEEDED(hr))
+                                       chapter.name = QString::fromUtf16((ushort *)name);
+
+                               SysFreeString(name);
+                               if (FAILED(hr))
+                                       continue;
+
+                               // Time is returned in seconds
+                               hr = pExtendedSeeking->GetMarkerTime(i, &time);
+                               if (FAILED(hr))
+                                       continue;
+
+                               chapter.time = qint64(time * 1000.0);
+
+                               chapters << chapter;
+                       }
+                       player->setChapters(chapters);
+               }
+
+               SafeRelease(&pExtendedSeeking);
+       }
+
+       {
+               StreamList streams;
+               IEnumFilters *enumFilters = 0;
+
+               HRESULT hr = pGraph->EnumFilters(&enumFilters);
+
+               if (SUCCEEDED(hr))
+               {
+                       IBaseFilter *filter = 0;
+                       while (enumFilters->Next(1, &filter, NULL) == S_OK)
+                       {
+                               IAMStreamSelect *pStreamSelect = 0;
+                               HRESULT hr = filter->QueryInterface(IID_PPV_ARGS(&pStreamSelect));
+
+                               if (SUCCEEDED(hr))
+                               {
+                                       DWORD streamCount;
+                                       hr = pStreamSelect->Count(&streamCount);
+
+                                       if (SUCCEEDED(hr))
+                                       {
+                                               for (long streamNo = 0; streamNo < (long)streamCount; ++streamNo)
+                                               {
+                                                       AM_MEDIA_TYPE *mediaType = 0;
+                                                       DWORD pdwFlags;
+                                                       LCID lcid;
+                                                       DWORD pdwGroup;
+                                                       WCHAR *wname = 0;
+
+                                                       QString name;
+
+                                                       hr = pStreamSelect->Info(streamNo, &mediaType, &pdwFlags, &lcid, &pdwGroup, &wname, NULL, NULL);
+
+                                                       if (mediaType)
+                                                               _DeleteMediaType(mediaType);
+
+                                                       if (SUCCEEDED(hr))
+                                                               name = QString::fromUtf16((ushort *) wname);
+
+                                                       if (wname)
+                                                               CoTaskMemFree(wname);
+
+                                                       if (FAILED(hr))
+                                                               continue;
+
+                                                       filter->AddRef();
+                                                       streamFilters << filter;
+
+                                                       StreamType type;
+
+                                                       if (IsEqualGUID(mediaType->majortype, MEDIATYPE_Video))
+                                                               type = VideoStream;
+                                                       else if (IsEqualGUID(mediaType->majortype, MEDIATYPE_Audio))
+                                                               type = AudioStream;
+                                                       else if (IsEqualGUID(mediaType->majortype, MEDIATYPE_Subtitle)
+                                                                        || IsEqualGUID(mediaType->majortype, MEDIATYPE_Text))
+                                                               type = SubtitleStream;
+                                                       else
+                                                               type = OtherStream;
+
+
+
+                                                       StreamInternal *stream = new StreamInternal;
+                                                       stream->name = name;
+                                                       stream->type = type;
+                                                       if (lcid)
+                                                       {
+                                                               WCHAR wdesc[85];
+                                                               int rBytes = GetLocaleInfo(lcid, LOCALE_SNAME, wdesc, sizeof(wdesc));
+                                                               if (rBytes)
+                                                                       stream->description = QString::fromUtf16((ushort *)wdesc);
+                                                       }
+                                                       stream->streamNo = streamNo;
+                                                       stream->filter = filter;
+
+                                                       streams << stream;
+//                                                     qDebug() << "Stream" << streamNo << name << "Group:" << pdwGroup << "LCID:" << QString::number(lcid, 16) << stream->description;
+                                               }
+                                       }
+                               }
+                               SafeRelease(&pStreamSelect);
+                               SafeRelease(&filter);
+                       }
+               }
+               SafeRelease(&enumFilters);
+
+               player->setStreams(streams);
+       }
+
+
 done:
        if (FAILED(hr))
        {
@@ -449,6 +698,29 @@ done:
        return hr;
 }
 
+HWND AniPlayerDShowInternal::hwnd() const
+{
+       return (HWND) player->videoWidget()->winId();
+}
+
+
+HRESULT AniPlayerDShowInternal::FinalizeGraph()
+{
+       if (pEVR == NULL)
+       {
+               return S_OK;
+       }
+
+       BOOL bRemoved;
+       HRESULT hr = RemoveUnconnectedRenderer(pGraph, pEVR, &bRemoved);
+       if (bRemoved)
+       {
+               SafeRelease(&pEVR);
+               SafeRelease(&pVideoDisplay);
+       }
+       return hr;
+}
+
 HRESULT IsPinConnected(IPin *pPin, BOOL *pResult)
 {
        IPin *pTmp = NULL;
@@ -554,25 +826,27 @@ HRESULT FindConnectedPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPi
        return hr;
 }
 
-HWND AniPlayerDShowInternal::hwnd() const
-{
-       return (HWND) player->videoWidget()->winId();
-}
-
-
-HRESULT AniPlayerDShowInternal::FinalizeGraph()
+void _FreeMediaType(AM_MEDIA_TYPE& mt)
 {
-       if (pEVR == NULL)
+       if (mt.cbFormat != 0)
        {
-               return S_OK;
+               CoTaskMemFree((PVOID)mt.pbFormat);
+               mt.cbFormat = 0;
+               mt.pbFormat = NULL;
+       }
+       if (mt.pUnk != NULL)
+       {
+               // pUnk should not be used.
+               mt.pUnk->Release();
+               mt.pUnk = NULL;
        }
+}
 
-       BOOL bRemoved;
-       HRESULT hr = RemoveUnconnectedRenderer(pGraph, pEVR, &bRemoved);
-       if (bRemoved)
+void _DeleteMediaType(AM_MEDIA_TYPE *pmt)
+{
+       if (pmt != NULL)
        {
-               SafeRelease(&pEVR);
-               SafeRelease(&pVideoDisplay);
+               _FreeMediaType(*pmt);
+               CoTaskMemFree(pmt);
        }
-       return hr;
 }
index fe4274a6a92b5e41b60581e3a3aeba75fbb83964..ea8523189d648e7fe17f54d8748c5fc9d8f140b7 100644 (file)
@@ -5,16 +5,22 @@
 
 #include <windows.h>
 
-class AniPlayerDShow;
+#include "aniplayerdshow.h"
 
 struct IBaseFilter;
 struct IGraphBuilder;
 struct IMediaControl;
-struct IMediaEvent;
+struct IMediaEventEx;
 struct IMediaSeeking;
 struct IMFVideoDisplayControl;
 struct IBasicAudio;
 
+struct StreamInternal : public Stream
+{
+       int streamNo;
+       IBaseFilter *filter;
+};
+
 struct AniPlayerDShowInternal
 {
 public:
@@ -33,6 +39,10 @@ public:
 
        double volume() const;
        bool setVolume(double volume);
+       bool isMuted() const;
+       bool setMuted(bool muted);
+
+       bool changeToStream(StreamInternal *stream);
 
        void handleNotifications();
 
@@ -51,7 +61,7 @@ public:
 
        IGraphBuilder *pGraph;
        IMediaControl *pControl;
-       IMediaEvent   *pEvent;
+       IMediaEventEx *pEvent;
        IMediaSeeking *pSeeking;
 
        IBaseFilter                *pEVR;
@@ -66,6 +76,10 @@ public:
        HWND hwnd() const;
 
        AniPlayerDShow *player;
+
+       QList<IBaseFilter *> streamFilters;
+
+       double mutedVolume;
 };
 
 template <class T> void SafeRelease(T **ppT)
index 5fec83061e622852b5dd5f0e715390fbc5121769..bae8192d302d2a43764981053d79d7fe31473867 100644 (file)
@@ -5,6 +5,8 @@
 #      include <windows.h>
 #endif
 
+#include <QDebug>
+
 VideoWidgetDShow::VideoWidgetDShow(AniPlayerDShow *player_, QWidget *parent) :
        VideoWidget(parent), player(player_)
 {
@@ -29,13 +31,14 @@ void VideoWidgetDShow::resizeEvent(QResizeEvent *e)
 bool VideoWidgetDShow::nativeEvent(const QByteArray &eventType, void *message, long *result)
 {
 #ifdef Q_OS_WIN
-       if (eventType != "windows_generic_MSG")
-               return false;
-
+       // This is the only type of event on windows.
+       Q_UNUSED(eventType)
+//     if (eventType != "windows_generic_MSG")
+//             return false;
        MSG *msg = static_cast<MSG *>(message);
        if (msg->message != WM_APP + 1)
                return false;
-//     player->ha
+       player->handleNotifications();
        *result = 0;
        return true;
 #else
diff --git a/player/aniplayer.exe.manifest b/player/aniplayer.exe.manifest
new file mode 100644 (file)
index 0000000..bf74870
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
+<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+    <security>
+      <requestedPrivileges>
+        <requestedExecutionLevel level='asInvoker' uiAccess='false' />
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+  <dependency>
+    <dependentAssembly>
+      <assemblyIdentity type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*' />
+    </dependentAssembly>
+  </dependency>
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
+       <application>
+               <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> 
+       </application>
+  </compatibility>
+</assembly>
diff --git a/player/aniplayer.qrc b/player/aniplayer.qrc
new file mode 100644 (file)
index 0000000..4d8ed66
--- /dev/null
@@ -0,0 +1,3 @@
+<RCC>
+    <qresource prefix="/"/>
+</RCC>
diff --git a/player/aniplayer.rc b/player/aniplayer.rc
new file mode 100644 (file)
index 0000000..092cd15
--- /dev/null
@@ -0,0 +1,38 @@
+1 TYPELIB "aniplayer.rc"
+IDI_ICON1              ICON            DISCARDABLE     "../resource/aniplayer-mikuru.ico"
+1 24 "aniplayer.exe.manifest"
+1 VERSIONINFO
+ FILEVERSION 2,0,0,0
+ PRODUCTVERSION 2,0,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904e4"
+        BEGIN
+            VALUE "CompanyName", "APTX\0"
+            VALUE "FileDescription", "aniplayer\0"
+            VALUE "FileExtents", "xxx\0"
+            VALUE "FileOpenName", "Video Files (*.*)\0"
+            VALUE "FileVersion", "2, 0, 0, 0\0"
+            VALUE "InternalName", "aniplayer\0"
+                       VALUE "LegalCopyright", "Copyright Â© 2009 APTX\0"
+                       VALUE "MIMEType", "application/x-aniplayer\0"
+            VALUE "OriginalFilename", "aniplayer.exe\0"
+            VALUE "ProductName", "AniPlayer\0"
+            VALUE "ProductVersion", "2, 0, 0, 0\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1252
+    END
+END
index 0063be919181fd9e6152a900bc7839d49b15aa13..c227a57beae2eef5d9bee8a03d9c1da1534989e2 100644 (file)
@@ -1,11 +1,22 @@
 #include "mainwindow.h"
-#include <QApplication>
+#include <aniplayerapplication.h>
 
 int main(int argc, char *argv[])
 {
-       QApplication a(argc, argv);
+       AniPlayerApplication a(argc, argv);
+
+       if (a.isRunning())
+       {
+               if (a.arguments().count() > 1)
+                       a.sendMessage("open " + a.arguments().at(1));
+
+               return 0;
+       }
+
        MainWindow w;
+       QObject::connect(&a, SIGNAL(openFileRequested(QString)), &w, SLOT(play(QString)));
+
        w.show();
-       
+
        return a.exec();
 }
index 42ee15003ca50b51c8c0c7544b100d5efc287e49..19ee8d6fc7e4a90b1a109787fc67341165908812 100644 (file)
@@ -3,8 +3,14 @@
 
 #include <QMouseEvent>
 #include <QWheelEvent>
-#include <QStandardPaths>
 #include <QFileDialog>
+#include <QSettings>
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
+#      include <QDesktopServices>
+#else
+#      include <QStandardPaths>
+#endif
 
 #ifdef Q_OS_WIN
 #      include <aniplayerdshow.h>
 #include <videowidget.h>
 #include "menu.h"
 #include "seekslider.h"
+#include <volumeslider.h>
+#include "versiondialog.h"
+
+#include <QDebug>
 
 MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
 {
+//     setAttribute(Qt::WA_DeleteOnClose);
        dragged = mouseMoved = false;
 
        player = new AniPlayerDShow(this);
@@ -63,7 +74,7 @@ MainWindow::MainWindow(QWidget *parent) :
 //     connect(videoPlayer->mediaController(), SIGNAL(availableSubtitlesChanged()), this, SLOT(updateSubtitles()));
 //     connect(m_actions["markWatched"], SIGNAL(triggered()), this, SLOT(markWatched()));
 //     connect(m_actions["settings"], SIGNAL(triggered()), this, SLOT(anidbSettings()));
-//     connect(m_actions["about"], SIGNAL(triggered()), this, SLOT(about()));
+       connect(m_actions["about"], SIGNAL(triggered()), this, SLOT(about()));
 
        connect(m_actions["open"], SIGNAL(triggered()), this, SLOT(open()));
        connect(m_actions["play"], SIGNAL(triggered()), player, SLOT(play()));
@@ -71,9 +82,9 @@ MainWindow::MainWindow(QWidget *parent) :
        connect(m_actions["pause"], SIGNAL(triggered()), player, SLOT(pause()));
        connect(m_actions["stop"], SIGNAL(triggered()), player, SLOT(stop()));
 
-//     connect(m_actions["toggleStayOnTop"], SIGNAL(toggled(bool)), this, SLOT(toggleStayOnTop()));
-//     connect(m_actions["toggleFrameless"], SIGNAL(toggled(bool)), this, SLOT(toggleFrameless()));
-//     connect(m_actions["toggleOverlay"], SIGNAL(toggled(bool)), this, SLOT(toggleOverlay()));
+       connect(m_actions["toggleStayOnTop"], SIGNAL(toggled(bool)), this, SLOT(toggleStayOnTop()));
+       connect(m_actions["toggleFrameless"], SIGNAL(toggled(bool)), this, SLOT(toggleFrameless()));
+       connect(m_actions["toggleOverlay"], SIGNAL(toggled(bool)), this, SLOT(toggleOverlay()));
 
        connect(m_actions["volUp"], SIGNAL(triggered()), player, SLOT(volumeUp()));
        connect(m_actions["volDown"], SIGNAL(triggered()), player, SLOT(volumeDown()));
@@ -81,21 +92,32 @@ MainWindow::MainWindow(QWidget *parent) :
        connect(m_actions["opSkip"], SIGNAL(triggered()), this, SLOT(opSkip()));
        connect(m_actions["back1sec"], SIGNAL(triggered()), this, SLOT(skipback()));
 
-//     connect(videoPlayer->videoWidget(), SIGNAL(menuToggleRequested()), this, SLOT(toggleMenu()));
-
 //     connect(m_actions["next"], SIGNAL(triggered()), playlist, SLOT(next()));
 //     connect(m_actions["previous"], SIGNAL(triggered()), playlist, SLOT(previous()));
 
-       connect(player, SIGNAL(totalTimeChanged(qint64)), menu->seekSlider(), SLOT(totalTimeChanged(qint64)));
+       connect(player, SIGNAL(totalTimeChanged(qint64)), menu, SLOT(totalTimeChanged(qint64)));
        connect(menu->seekSlider(), SIGNAL(seekRequested(qint64)), player, SLOT(seek(qint64)));
+       connect(player, SIGNAL(tick(qint64)), menu, SLOT(tick(qint64)));
+       connect(player, SIGNAL(currentFileChanged(QString)), this, SLOT(handleFileChange()));
+       connect(player, SIGNAL(chaptersChanged(ChapterList)), this, SLOT(chaptersChanged()));
+       connect(player, SIGNAL(streamsChanged(StreamList)), this, SLOT(streamsChanged()));
+
+       connect(player, SIGNAL(volumeChanged(double)), menu->volumeSlider(), SLOT(setVolume(double)));
+       connect(menu->volumeSlider(), SIGNAL(volumeChangedByUser(double)), player, SLOT(setVolume(double)));
+       connect(player, SIGNAL(mutedChanged(bool)), menu->volumeSlider(), SLOT(setMuted(bool)));
+       connect(menu->volumeSlider(), SIGNAL(mutedChangedByUser(bool)), player, SLOT(setMuted(bool)));
        setCentralWidget(player->videoWidget());
 
-       open("E:/Anime/Accel World OVA/Accel World OVA - 01 - OVA - [UTW][3e56ee18].mkv");
+       handleStateChange(player->state(), player->state());
 
+       //open("E:/Anime/Accel World OVA/Accel World OVA - 01 - OVA - [UTW][3e56ee18].mkv");
+       updateWindowTitle();
+       loadSettings();
 }
 
 MainWindow::~MainWindow()
 {
+       saveSettings();
        delete ui;
 }
 
@@ -105,7 +127,11 @@ bool MainWindow::open()
 
        if (player->currentFile() == "")
        {
+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
+               dir = QDesktopServices::storageLocation(QDesktopServices::MoviesLocation);
+#else
                dir = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
+#endif
        }
        else
        {
@@ -180,7 +206,7 @@ void MainWindow::skipback()
 
 void MainWindow::opSkip()
 {
-       player->skip(/*m_opSkip*/85 * 1000);
+       player->skip(m_opSkip * 1000);
 }
 
 void MainWindow::toggleMenu()
@@ -197,22 +223,25 @@ void MainWindow::resizeToVideo()
 void MainWindow::toggleStayOnTop()
 {
        updateWindowFlags();
+       player->widgetChanged();
 }
 
 void MainWindow::toggleFrameless()
 {
        updateWindowFlags();
+       player->widgetChanged();
 }
 
 void MainWindow::toggleOverlay()
 {
        updateWindowFlags();
+       player->widgetChanged();
 }
 
 void MainWindow::about()
 {
-//     VersionDialog dialog(this);
-       //      dialog.exec();
+       VersionDialog dialog(this);
+       dialog.exec();
 }
 
 void MainWindow::handleStateChange(AniPlayer::State newState, AniPlayer::State oldState)
@@ -221,6 +250,11 @@ void MainWindow::handleStateChange(AniPlayer::State newState, AniPlayer::State o
 
        switch(newState)
        {
+               case AniPlayer::NoFileLoaded:
+                       m_actions["play"]->setDisabled(true);
+                       m_actions["pause"]->setDisabled(true);
+                       m_actions["stop"]->setDisabled(true);
+               break;
                case AniPlayer::Error:
                        //menu->showMessage(playerlayer->errorString());
 
@@ -232,7 +266,6 @@ void MainWindow::handleStateChange(AniPlayer::State newState, AniPlayer::State o
                        m_actions["play"]->setDisabled(false);
                        m_actions["pause"]->setDisabled(true);
                        m_actions["stop"]->setDisabled(true);
-
                break;
                case AniPlayer::Playing:
                        m_actions["play"]->setDisabled(true);
@@ -249,8 +282,16 @@ void MainWindow::handleStateChange(AniPlayer::State newState, AniPlayer::State o
        }
 }
 
+void MainWindow::handleFileChange()
+{
+       resize(player->videoSize());
+}
+
 void MainWindow::mousePressEvent(QMouseEvent *event)
 {
+       if (player->videoWidget()->isFullScreen())
+               return;
+
        if (event->button() == Qt::LeftButton)
        {
                dragPosition = event->globalPos() - frameGeometry().topLeft();
@@ -356,17 +397,10 @@ void MainWindow::updateWindowTitle(const QFileInfo &file)
 
 void MainWindow::updateCursor()
 {
-#ifdef Q_WS_X11
-       if (isFullScreen() && menu->isHidden())
-               setCursor(QCursor(Qt::BlankCursor));
+       if (player->videoWidget()->isFullScreen() && menu->isHidden())
+               player->videoWidget()->setCursor(QCursor(Qt::BlankCursor));
        else
-               setCursor(QCursor(Qt::ArrowCursor));
-#else
-//     if (videoPlayer->videoWidget()->isFullScreen() && menu->isHidden())
-//             videoPlayer->videoWidget()->setCursor(QCursor(Qt::BlankCursor));
-//     else
-//             videoPlayer->videoWidget()->setCursor(QCursor(Qt::ArrowCursor));
-#endif
+               player->videoWidget()->setCursor(QCursor(Qt::ArrowCursor));
 }
 
 void MainWindow::updateWindowFlags()
@@ -403,3 +437,69 @@ void MainWindow::updateWindowFlags()
 
        show();
 }
+
+void MainWindow::chaptersChanged()
+{
+/*
+       foreach (const Chapter &c, player->chapters())
+       {
+               qDebug() << "Chapter" << c.name << c.time;
+       }
+*/
+}
+
+void MainWindow::streamsChanged()
+{
+/*     foreach (const Stream *c, player->streams())
+       {
+               qDebug() << "Stream" << c->name << c->type << c->description;
+       }
+*/
+}
+
+void MainWindow::saveSettings()
+{
+       QSettings settings;
+
+       settings.beginGroup("settings");
+               settings.setValue("currentFile", player->currentFile());
+               settings.setValue("volume", player->volume());
+               settings.setValue("muted", player->isMuted());
+               settings.setValue("opSkip", m_opSkip);
+       settings.endGroup();
+       settings.beginGroup("videoWindow");
+               settings.setValue("geometry", saveGeometry());
+               settings.setValue("stayOnTop", m_actions["toggleStayOnTop"]->isChecked());
+               settings.setValue("frameless", m_actions["toggleFrameless"]->isChecked());
+       settings.endGroup();
+       settings.beginGroup("menu");
+               settings.setValue("geometry", menu->saveGeometry());
+               settings.setValue("state", menu->saveState());
+               settings.setValue("isVisible", menu->isVisible());
+       settings.endGroup();
+}
+
+void MainWindow::loadSettings()
+{
+       QSettings settings;
+       settings.beginGroup("settings");
+               open(settings.value("currentFile", "").toString());
+               player->setVolume(settings.value("volume", qreal(1.0)).toDouble());
+               player->setMuted(settings.value("muted", false).toBool());
+               m_opSkip = settings.value("opSkip", 85).toInt();
+       settings.endGroup();
+       settings.beginGroup("videoWindow");
+               restoreGeometry(settings.value("geometry", saveGeometry()).toByteArray());
+               m_actions["toggleStayOnTop"]->setChecked(settings.value("stayOnTop", false).toBool());
+               m_actions["toggleFrameless"]->setChecked(settings.value("frameless", false).toBool());
+       settings.endGroup();
+       settings.beginGroup("menu");
+               menu->restoreState(settings.value("state", menu->saveState()).toByteArray());
+               menu->restoreGeometry(settings.value("geometry", menu->saveGeometry()).toByteArray());
+               menu->setVisible(settings.value("isVisible", true).toBool());
+       settings.endGroup();
+       settings.beginGroup("anidbudpapiclient");
+//             m_automark = settings.value("automark", 0).toInt();
+//             m_automarkPaths = settings.value("paths", QStringList()).toStringList();
+       settings.endGroup();
+}
index 8a4690aec55fa9eb7fce589e581e8f4ba841dedb..acf2e5a246c6246a44d3a90b91010cd271d60557 100644 (file)
@@ -39,6 +39,10 @@ public slots:
 
 private slots:
        void handleStateChange(AniPlayer::State newState, AniPlayer::State oldState);
+       void handleFileChange();
+
+       void chaptersChanged();
+       void streamsChanged();
 
 protected:
        void mousePressEvent(QMouseEvent *event);
@@ -58,12 +62,22 @@ private:
 
        void updateWindowFlags();
 
+       void saveSettings();
+       void loadSettings();
+
        QMap<QString, QAction *> m_actions;
 
        Ui::MainWindow *ui;
        Menu *menu;
        AniPlayer *player;
 
+       int m_opSkip;
+
+       int m_automark;
+       QStringList m_automarkPaths;
+       bool m_marked;
+       bool m_automarkable;
+
        bool mouseMoved;
        QPoint dragPosition;
        bool dragged;
diff --git a/player/menu.cpp b/player/menu.cpp
new file mode 100644 (file)
index 0000000..3e0c1ce
--- /dev/null
@@ -0,0 +1,173 @@
+#include "menu.h"
+
+#include <QHBoxLayout>
+#include <QMouseEvent>
+#include <QTime>
+#include <QLabel>
+#include <QToolBar>
+#include <QStatusBar>
+#include <QApplication>
+
+#include "seekslider.h"
+#include <volumeslider.h>
+
+Menu::Menu(QWidget *parent)
+       : QMainWindow(parent), dragged(false)
+{
+       setWindowFlags(Qt::Tool);
+       setAttribute(Qt::WA_QuitOnClose);
+
+       controlBar = new QToolBar(tr("Control"), this);
+       seekBar = new QToolBar(tr("Seek"), this);
+       timeBar = new QToolBar(tr("Time"), this);
+       volumeBar = new QToolBar(tr("Volume"), this);
+
+       statusBar();
+
+       controlBar->setObjectName("controlBar");
+       volumeBar->setObjectName("volumeBar");
+       timeBar->setObjectName("timeBar");
+       seekBar->setObjectName("seekBar");
+
+       addToolBar(controlBar);
+       addToolBar(volumeBar);
+       addToolBarBreak();
+       addToolBar(timeBar);
+       addToolBar(seekBar);
+       {
+               QWidget *seekBarContents = new QWidget(seekBar);
+               seekBarContents->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+               m_seekSlider = new SeekSlider(seekBarContents);
+
+               QHBoxLayout *layout = new QHBoxLayout(seekBarContents);
+//             layout->setContentsMargins(0, 0, 0, 0);
+               layout->addWidget(m_seekSlider);
+               seekBar->addWidget(seekBarContents);
+       }
+       {
+               QWidget *timeBarContents = new QWidget(timeBar);
+               timeBarContents->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+               timeLabel = new QLabel("0:00:00 / 0:00:00 (0%)", timeBarContents);
+
+               QHBoxLayout *layout = new QHBoxLayout(timeBarContents);
+               layout->setContentsMargins(0, 0, 0, 0);
+               layout->addWidget(timeLabel);
+               layout->setSizeConstraint(QLayout::SetMinimumSize);
+               timeBar->addWidget(timeBarContents);
+       }
+       {
+               QWidget *volumeBarContents = new QWidget(volumeBar);
+               m_volumeSlider = new VolumeSlider(this);
+
+               QHBoxLayout *layout = new QHBoxLayout(volumeBarContents);
+               layout->setContentsMargins(0, 0, 0, 0);
+               layout->addWidget(m_volumeSlider);
+               volumeBar->addWidget(volumeBarContents);
+       }
+
+       {
+               QWidget *controlBarContents = new QWidget(controlBar);
+
+               QHBoxLayout *layout = new QHBoxLayout(controlBarContents);
+               layout->setSizeConstraint(QLayout::SetMinimumSize);
+               layout->setContentsMargins(0, 0, 0, 0);
+//             layout->addWidget(timeLabel, 1);
+//             layout->addWidget(m_volumeSlider, 2);
+               controlBar->addWidget(controlBarContents);
+       }
+
+       setWindowTitle(tr("%1 Control Panel").arg(qApp->applicationName()));
+
+       totalTime = " / " + QTime(0, 0, 0, 0).toString("h:mm:ss");
+}
+
+Menu::~Menu()
+{
+}
+
+void Menu::addActions(QList<QAction *> actions)
+{
+       controlBar->addActions(actions);
+}
+
+SeekSlider *Menu::seekSlider() const
+{
+       return m_seekSlider;
+}
+
+VolumeSlider *Menu::volumeSlider() const
+{
+       return m_volumeSlider;
+}
+
+void Menu::showMessage(const QString &message)
+{
+       statusBar()->showMessage(message);
+}
+
+void Menu::tick(qint64 pos)
+{
+       m_seekSlider->tick(pos);
+       int sec = pos / 1000;
+       int min = sec / 60;
+       int hour = min / 60;
+       int msec = pos;
+       timeLabel->setText(
+                       QString("%1 %2 (%3%)").arg(
+                                       QTime(hour, min % 60, sec % 60, msec % 1000).toString("h:mm:ss"),
+                                       totalTime)
+                                       .arg(int(pos * double(100) / length))
+                       );
+}
+
+void Menu::totalTimeChanged(qint64 time)
+{
+       m_seekSlider->totalTimeChanged(time);
+       length = time;
+       int sec = time / 1000;
+       int min = sec / 60;
+       int hour = min / 60;
+       int msec = time;
+       totalTime = " / " + QTime(hour, min % 60, sec % 60, msec % 1000).toString("h:mm:ss");
+}
+
+void Menu::moveEvent(QMoveEvent *event)
+{
+       QMainWindow::moveEvent(event);
+       emit positionChanged();
+}
+
+void Menu::mousePressEvent(QMouseEvent *event)
+{
+       if (event->button() == Qt::LeftButton)
+       {
+               dragPosition = event->globalPos() - frameGeometry().topLeft();
+               dragged = true;
+               event->accept();
+       }
+}
+
+void Menu::mouseMoveEvent(QMouseEvent *event)
+{
+       if (!dragged)
+               return;
+
+       if (event->buttons() & Qt::LeftButton)
+       {
+               move(event->globalPos() - dragPosition);
+               event->accept();
+       }
+}
+
+void Menu::mouseReleaseEvent(QMouseEvent * /*event*/)
+{
+       if (!dragged)
+               return;
+       dragged = false;
+}
+
+void Menu::resizeEvent(QResizeEvent *event)
+{
+       QMainWindow::resizeEvent(event);
+       emit positionChanged();
+}
diff --git a/player/menu.h b/player/menu.h
new file mode 100644 (file)
index 0000000..98a8aaa
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef MENU_H
+#define MENU_H
+
+#include <QMainWindow>
+#include <QList>
+
+class QToolBar;
+class QMouseEvent;
+class QLabel;
+class SeekSlider;
+class VolumeSlider;
+
+class Menu : public QMainWindow
+{
+       Q_OBJECT
+
+public:
+       Menu(QWidget *parent = 0);
+       ~Menu();
+
+       void addActions(QList<QAction *> actions);
+
+       SeekSlider *seekSlider() const;
+       VolumeSlider *volumeSlider() const;
+
+public slots:
+       void showMessage(const QString &message);
+       void tick(qint64 msec);
+       void totalTimeChanged(qint64 time);
+
+signals:
+       void positionChanged();
+
+protected:
+       virtual void moveEvent(QMoveEvent *event);
+       virtual void mouseMoveEvent(QMouseEvent *event);
+       virtual void mousePressEvent(QMouseEvent *event);
+       virtual void mouseReleaseEvent(QMouseEvent *event);
+       virtual void resizeEvent(QResizeEvent *event);
+
+private:
+       SeekSlider *m_seekSlider;
+       VolumeSlider *m_volumeSlider;
+
+       QToolBar *controlBar;
+       QToolBar *seekBar;
+       QToolBar *timeBar;
+       QToolBar *volumeBar;
+
+       QLabel *timeLabel;
+       QString totalTime;
+       qint64 length;
+
+       QPoint dragPosition;
+       bool dragged;
+};
+
+#endif // MENU_H
index 16b28887803b7f37e42fce106b025680495e9bd4..3660ff3fc2e56f79d5cb1bcc8677e99c3b5e3965 100644 (file)
@@ -7,15 +7,16 @@ TEMPLATE = app
 TARGET = player
 DESTDIR = ../build
 
+HEADERS  += mainwindow.h \
+       menu.h \
+       seekslider.h \
+       versiondialog.h
 
 SOURCES += main.cpp\
-               mainwindow.cpp \
+       mainwindow.cpp \
        menu.cpp \
-       seekslider.cpp
-
-HEADERS  += mainwindow.h \
-       menu.h \
-       seekslider.h
+       seekslider.cpp \
+       versiondialog.cpp
 
 FORMS    += mainwindow.ui \
        menu.ui
@@ -23,3 +24,9 @@ FORMS    += mainwindow.ui \
 include(../config.pri)
 include(../aniplayer2/aniplayer2.pri)
 win32:include(../aniplayer2_dshow/aniplayer2_dshow.pri)
+
+win32 {
+       CONFIG -= embed_manifest_exe
+       RC_FILE += aniplayer.rc
+       LIBS += -luser32
+}
diff --git a/player/seekslider.cpp b/player/seekslider.cpp
new file mode 100644 (file)
index 0000000..b76bfb1
--- /dev/null
@@ -0,0 +1,239 @@
+#include "seekslider.h"
+
+#include <QPainter>
+#include <QEvent>
+#include <QMouseEvent>
+#include <QTime>
+#include <QFontMetrics>
+
+#include "aniplayer.h"
+#include <QDebug>
+
+SeekSlider::SeekSlider(QWidget *parent) : QWidget(parent)
+{
+       init();
+}
+
+void SeekSlider::init()
+{
+       ticking = false;
+       m_length = 1000;
+       m_seekPosition = 20;
+       markerWidth = 2;
+       drawMarkerShadow = false;
+       markerShadowEnabled = true;
+       maxPreviousPos = 3;
+
+       setMouseTracking(true);
+       setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+}
+
+SeekSlider::~SeekSlider()
+{
+
+}
+
+bool SeekSlider::isMarkerShadowEnabled() const
+{
+       return markerShadowEnabled;
+}
+
+void SeekSlider::setMarkerShadowEnabled(bool enable)
+{
+       markerShadowEnabled = enable;
+}
+
+QSize SeekSlider::sizeHint() const
+{
+       return QSize();
+}
+
+QSize SeekSlider::minimumSizeHint() const
+{
+       return QSize(100, 20);
+}
+
+QSizePolicy SeekSlider::sizePolicy() const
+{
+       return QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+}
+
+void SeekSlider::setSeekPosition(qint64 value)
+{
+       if (m_seekPosition == value)
+               return;
+
+       m_seekPosition = value;
+       emit seekPositionChanged(value);
+       update();
+}
+
+void SeekSlider::paintEvent(QPaintEvent *event)
+{
+       Q_UNUSED(event);
+
+       QPainter p(this);
+
+       seekerTop = 0;//height() / 3;
+       seekerLeft = 0;
+       seekerHeight = height() - 1;//height() / 3;
+       seekerWidth = width() - 1;
+
+       const int markerWidth = 2;
+       const int markerPos = time2pos(m_seekPosition);
+       const QColor markerColor(255, 0, 0);
+       const QColor markerShadowColor(255, 0, 0, 100);
+       const QColor previousMarkerColor(255, 255, 255);
+       const QColor watchedPartColor(0, 0, 255, 150);
+       const QColor unwatchedPartColor(0, 255, 0, 100);
+       const QColor toolTipBackgroundColor(0, 0, 0, 150);
+       const QColor toolTipForegroundColor(255, 255, 255);
+
+
+       // border
+       p.drawRect(seekerLeft, seekerTop, seekerWidth, seekerHeight);
+
+       // watched part
+       p.fillRect(seekerLeft + 1, seekerTop + 1, markerPos - seekerLeft - 1, seekerHeight - 1, watchedPartColor);
+       // unwatched part
+       p.fillRect(markerPos + markerWidth / 2, seekerTop + 1, seekerWidth - markerPos, seekerHeight - 1, unwatchedPartColor);
+
+       int i = 1;
+       for (QQueue<qint64>::const_iterator it = previuousPos.constBegin(); it != previuousPos.constEnd(); ++it)
+       {
+               int markerPos = seekerLeft + 1 + markerWidth / 2 + qRound(double(*it) / double(m_length) * double(seekerWidth - markerWidth / 2 - 1));
+               QColor c = previousMarkerColor;
+               c.setAlpha(255 / previuousPos.count() * i);
+               p.fillRect(markerPos - markerWidth / 2, seekerTop + 1, markerWidth, seekerHeight - 1, c);
+               ++i;
+       }
+
+       // marker bar
+       p.fillRect(markerPos - markerWidth / 2, seekerTop + 1, markerWidth, seekerHeight - 1, markerColor);
+
+       // marker shadow (where the marker would move when mouse is clicked)
+       if (drawMarkerShadow && isEnabled())
+       {
+               markerShadowPos = qBound(seekerLeft + 1 + markerWidth / 2, markerShadowPos, seekerLeft + seekerWidth - markerWidth / 2);
+               p.fillRect(markerShadowPos - markerWidth / 2, seekerTop + 1, markerWidth, seekerHeight - 1, markerShadowColor);
+
+               QString time = QTime().addMSecs(pos2time(markerShadowPos)).toString("hh:mm:ss");
+               QRect r = p.fontMetrics().boundingRect(time);
+
+               int xdelta = markerShadowPos + markerWidth / 2 + 1;
+               if (xdelta + r.width() < width())
+                       r.translate(xdelta, r.height());
+               else
+                       r.translate(markerShadowPos - (markerWidth / 2 + 1) - r.width(), r.height());
+
+               p.fillRect(r, toolTipBackgroundColor);
+               p.setPen(QPen(toolTipForegroundColor));
+               p.drawText(r, time);
+       }
+
+}
+
+void SeekSlider::mouseMoveEvent(QMouseEvent *event)
+{
+       Q_UNUSED(event);
+
+       markerShadowPos = event->pos().x();
+       update();
+}
+
+void SeekSlider::enterEvent(QEvent *event)
+{
+       Q_UNUSED(event);
+
+       drawMarkerShadow = true;
+       update();
+}
+
+void SeekSlider::leaveEvent(QEvent *event)
+{
+       Q_UNUSED(event);
+
+       drawMarkerShadow = false;
+       update();
+}
+
+void SeekSlider::mouseReleaseEvent(QMouseEvent *event)
+{
+       if (event->button() != Qt::LeftButton)
+               return;
+
+       seek(event->pos().x());
+
+       event->accept();
+}
+
+void SeekSlider::seek(qint64 msec)
+{
+
+}
+
+void SeekSlider::tick(qint64 msec)
+{
+       ticking = true;
+       setSeekPosition(msec);
+       ticking = false;
+}
+
+void SeekSlider::totalTimeChanged(qint64 msec)
+{
+       ticking = true;
+       setLength(msec);
+       previuousPos.clear();
+       ticking = false;
+}
+
+void SeekSlider::seekableChanged(bool isSeekable)
+{
+
+}
+
+void SeekSlider::currentSourceChanged()
+{
+       //this releases the mouse and makes the seek slider stop seeking if the current source has changed
+       QMouseEvent event(QEvent::MouseButtonRelease, QPoint(), Qt::LeftButton, 0, 0);
+//     QApplication::sendEvent(this, &event);
+}
+
+void SeekSlider::setLength(qint64 length)
+{
+       m_length = length;
+       update();
+}
+
+void SeekSlider::seek(int x)
+{
+       int newMarkerPos = qBound(seekerLeft + 1, x, seekerLeft + seekerWidth);
+       qint64 newSeekPos = pos2time(newMarkerPos);
+
+       while (!previuousPos.isEmpty() && previuousPos.count() + 1 > maxPreviousPos) previuousPos.dequeue();
+       previuousPos.enqueue(m_seekPosition);
+
+       ticking = true;
+       setSeekPosition(newSeekPos);
+       emit seekRequested(newSeekPos);
+       ticking = false;
+       seek(newSeekPos);
+}
+
+qint64 SeekSlider::pos2time(int pos) const
+{
+       const int halfMarkerWidth = markerWidth / 2;
+       return qint64(double(pos - (seekerLeft + 1 + halfMarkerWidth)) / double(seekerWidth - halfMarkerWidth - 1) * double(m_length));
+}
+
+int SeekSlider::time2pos(qint64 msec) const
+{
+       const int halfMarkerWidth = markerWidth / 2;
+       return seekerLeft + 1 + halfMarkerWidth + qRound(double(msec) / double(m_length) * double(seekerWidth - halfMarkerWidth - 1));
+}
+
+
+qint64 SeekSlider::seekPosition() const
+{
+       return m_seekPosition;
+}
diff --git a/player/seekslider.h b/player/seekslider.h
new file mode 100644 (file)
index 0000000..09dd954
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef SEEKSLIDER_H
+#define SEEKSLIDER_H
+
+#include <QSlider>
+#include <QQueue>
+
+class SeekSlider : public QWidget
+{
+       Q_OBJECT
+       Q_PROPERTY(qint64 seekPosition READ seekPosition WRITE setSeekPosition NOTIFY seekPositionChanged USER true)
+
+       Q_DISABLE_COPY(SeekSlider)
+
+       Q_PROPERTY(bool markerShadowEnabled READ isMarkerShadowEnabled WRITE setMarkerShadowEnabled)
+/*
+       Q_PROPERTY(bool tracking READ hasTracking WRITE setTracking)
+       Q_PROPERTY(int pageStep READ pageStep WRITE setPageStep)
+       Q_PROPERTY(int singleStep READ singleStep WRITE setSingleStep)
+       Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation)
+*/
+public:
+       explicit SeekSlider(QWidget *parent = 0);
+       ~SeekSlider();
+
+       bool isMarkerShadowEnabled() const;
+       void setMarkerShadowEnabled(bool enable = true);
+
+       QSize sizeHint() const;
+       QSize minimumSizeHint() const;
+       QSizePolicy sizePolicy() const;
+/*     bool hasTracking() const;
+       void setTracking(bool tracking);
+       int pageStep() const;
+       void setPageStep(int milliseconds);
+       int singleStep() const;
+       void setSingleStep(int milliseconds);
+       Qt::Orientation orientation() const;
+*/
+
+
+
+/*
+       bool event(QEvent *event);
+*/
+       qint64 seekPosition() const;
+
+
+public slots:
+//     void setOrientation(Qt::Orientation o);
+
+       void setSeekPosition(qint64 position);
+       void tick(qint64 msec);
+       void totalTimeChanged(qint64 msec);
+
+signals:
+       void seekPositionChanged(qint64 arg);
+       void seekRequested(qint64 position);
+
+protected:
+       void paintEvent(QPaintEvent *event);
+       void mouseMoveEvent(QMouseEvent *event);
+       void enterEvent(QEvent *event);
+       void leaveEvent(QEvent *event);
+       void mouseReleaseEvent(QMouseEvent *ev);
+
+/*     void mousePressEvent(QMouseEvent *ev);
+
+       void initStyleOption(QStyleOptionSlider *option) const;
+*/
+private slots:
+       void seek(qint64 msec);
+       void seekableChanged(bool isSeekable);
+       void currentSourceChanged();
+
+private:
+       void init();
+       void setLength(qint64 totalTimeChanged);
+
+       void seek(int x);
+
+       qint64 pos2time(int pos) const;
+       int time2pos(qint64 msec) const;
+
+       bool ticking;
+       bool markerShadowEnabled;
+
+       qint64 m_length;
+       bool m_tracking;
+       int m_pageStep;
+       int m_singleStep;
+       Qt::Orientation m_orientation;
+
+       bool drawMarkerShadow;
+       int markerShadowPos;
+
+       QQueue<qint64> previuousPos;
+       int maxPreviousPos;
+
+       // Seeker Geometry
+       int seekerTop;
+       int seekerLeft;
+       int seekerHeight;
+       int seekerWidth;
+
+       int markerWidth;
+       qint64 m_seekPosition;
+};
+
+#endif // SEEKSLIDER_H
diff --git a/player/versiondialog.cpp b/player/versiondialog.cpp
new file mode 100644 (file)
index 0000000..b5b3f2f
--- /dev/null
@@ -0,0 +1,63 @@
+#include "versiondialog.h"
+
+#include <QGridLayout>
+#include <QLabel>
+#include <QDialogButtonBox>
+#include <QPushButton>
+#include <QSysInfo>
+
+#include "constants.h"
+#include <aniplayerapplication.h>
+
+VersionDialog::VersionDialog(QWidget *parent) : QDialog(parent)
+{
+       setWindowTitle(tr("About %1").arg(qApp->applicationName()));
+
+       setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+       QGridLayout *layout = new QGridLayout(this);
+       layout->setSizeConstraint(QLayout::SetFixedSize);
+
+       QString revision;
+#ifdef REVISION
+       revision = tr("from revision %1").arg(revisionString);
+#endif
+
+       const QString description = tr(
+               "<h3>%1 %2 <font size=\"3\">(%7 bit)</font></h3>"
+               "<p>Built with\tQt %3<br/>"
+               "Running with\tQt %4<br/>"
+               "<br/>"
+               "Built on " __DATE__ " at " __TIME__ " "
+               "%6"
+               "<br/>"
+               "<br/>"
+               "Application Icon (C) 2009 Watarase_Jun"
+               "<br/>"
+               "<br/>"
+               "Copyright (C) 2009 %5. All rights reserved.</p>"
+               "<p>The program is provided AS IS with NO WARRANTY OF ANY KIND, "
+               "INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A "
+               "PARTICULAR PURPOSE.</p>")
+               .arg(qApp->applicationName())
+               .arg(qApp->applicationVersion())
+               .arg(QLatin1String(QT_VERSION_STR))
+               .arg(QLatin1String(qVersion()))
+               .arg(qApp->organizationName())
+               .arg(revision)
+               .arg(QSysInfo::WordSize);
+
+       QLabel *copyrightLabel = new QLabel(description);
+       copyrightLabel->setWordWrap(true);
+       copyrightLabel->setOpenExternalLinks(true);
+       copyrightLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
+
+       QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
+       QPushButton *closeButton = buttonBox->button(QDialogButtonBox::Close);
+
+       buttonBox->addButton(closeButton, QDialogButtonBox::ButtonRole(QDialogButtonBox::RejectRole | QDialogButtonBox::AcceptRole));
+       connect(buttonBox , SIGNAL(rejected()), this, SLOT(reject()));
+
+       layout->addWidget(copyrightLabel, 0, 1, 4, 4);
+       layout->addWidget(buttonBox, 4, 0, 1, 5);
+}
diff --git a/player/versiondialog.h b/player/versiondialog.h
new file mode 100644 (file)
index 0000000..05cbd9e
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef VERSIONDIALOG_H
+#define VERSIONDIALOG_H
+
+#include <QDialog>
+
+class VersionDialog : public QDialog
+{
+public:
+       VersionDialog(QWidget *parent = 0);
+};
+
+#endif // VERSIONDIALOG_H
diff --git a/resource/aniplayer-mikuru.ico b/resource/aniplayer-mikuru.ico
new file mode 100644 (file)
index 0000000..2439682
Binary files /dev/null and b/resource/aniplayer-mikuru.ico differ
diff --git a/resource/aniplayer.qrc b/resource/aniplayer.qrc
new file mode 100644 (file)
index 0000000..1e4a5e3
--- /dev/null
@@ -0,0 +1,5 @@
+<RCC>
+    <qresource prefix="/">
+        <file alias="icon.png">mikuru-icon-base.png</file>
+    </qresource>
+</RCC>
diff --git a/resource/mikuru-icon-base.png b/resource/mikuru-icon-base.png
new file mode 100644 (file)
index 0000000..7c362f8
Binary files /dev/null and b/resource/mikuru-icon-base.png differ
diff --git a/resource/mikuru-icon-original.png b/resource/mikuru-icon-original.png
new file mode 100644 (file)
index 0000000..7c0c662
Binary files /dev/null and b/resource/mikuru-icon-original.png differ