Added a logo to the project and changed the "settings" button to "menu"

and added some options to the menu that changes the behaviour of the
app. such as turning on/off the auto playing of files and the directory
and volume control. this is all kept persistent using an IDM formated
file in the app's config directory. still having issues with it not
calculating the durations properly but i now know why. it's because
QMediaPlayer can't calculate the durations of VBR files (variable bit-
rate) properly. other than that, everything seems to be working
perfectly. i'll add more feasures such as a next/previous file button
and a stop button.
This commit is contained in:
Maurice O'Neal 2016-10-16 17:04:21 -04:00 committed by Maurice O'Neal
parent 10e5af0588
commit 73a8c03fa1
23 changed files with 1029 additions and 275 deletions

View File

@ -16,10 +16,21 @@ TEMPLATE = app
SOURCES += main.cpp\ SOURCES += main.cpp\
gui/ui.cpp\ gui/ui.cpp\
gui/icon.cpp \ gui/icon.cpp \
io/aud_file.cpp io/aud_file.cpp \
io/conf.cpp \
io/idm.cpp \
io/int.cpp
HEADERS += gui/ui.h\ HEADERS += gui/ui.h\
gui/icon.h \ gui/icon.h \
io/aud_file.h io/aud_file.h \
io/conf.h \
io/idm.h \
io/int.h
RESOURCES += icon_files.qrc RESOURCES += icon_files.qrc
RC_FILE = logo.rc
DISTFILES += app_logo.ico \
logo.rc

BIN
app_logo.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -1,56 +1,64 @@
#include "icon.h" #include "icon.h"
Icon::Icon(IconType t, QWidget *parent) : QLabel(parent) Icon::Icon(IconType t, QWidget *parent) : QToolButton(parent)
{ {
QRect rect = QApplication::desktop()->screenGeometry(); QRect rect = QApplication::desktop()->screenGeometry();
setMinimumHeight(rect.height() / 40); setMinimumHeight(rect.height() / 40);
setMinimumWidth(rect.height() / 40); setMinimumWidth(rect.height() / 40);
setCursor(Qt::PointingHandCursor); setCursor(Qt::PointingHandCursor);
setToolButtonStyle(Qt::ToolButtonIconOnly);
setPopupMode(QToolButton::InstantPopup);
switch (t) switch (t)
{ {
case PAUSE_PLAY: stateChanged(QMediaPlayer::StoppedState); break; case PAUSE_PLAY:
case SETTINGS: loadImg(":/settings"); break; {
case OPEN: loadImg(":/open"); break; stateChanged(QMediaPlayer::StoppedState);
setToolTip(tr("Pause/Play"));
connect(this, SIGNAL(clicked()), this, SLOT(buttonClicked()));
break;
}
case MENU:
{
loadImg(":/menu");
setToolTip(tr("Menu"));
break;
}
case OPEN:
{
loadImg(":/open");
setToolTip(tr("Open File"));
connect(this, SIGNAL(clicked()), this, SLOT(buttonClicked()));
break;
}
} }
type = t; type = t;
} }
void Icon::mouseReleaseEvent(QMouseEvent *event) void Icon::buttonClicked()
{ {
if (event->button() == Qt::LeftButton) if (type == PAUSE_PLAY)
{ {
switch (type) if (playerState == QMediaPlayer::PlayingState)
{ {
case PAUSE_PLAY: emit pause();
}
else
{ {
if (playerState == QMediaPlayer::PlayingState) emit play();
{
emit pause();
}
else
{
emit play();
}
break;
}
case SETTINGS:
{
emit settings();
break;
}
case OPEN:
{
emit open();
break;
}
} }
} }
else if (type == OPEN)
{
emit open();
}
} }
void Icon::paintEvent(QPaintEvent *) void Icon::paintEvent(QPaintEvent *)

View File

@ -2,7 +2,7 @@
#define ICON_H #define ICON_H
#include <QWidget> #include <QWidget>
#include <QLabel> #include <QToolButton>
#include <QMediaPlayer> #include <QMediaPlayer>
#include <QMouseEvent> #include <QMouseEvent>
#include <QSvgRenderer> #include <QSvgRenderer>
@ -13,7 +13,7 @@
#include <QRect> #include <QRect>
#include <QDesktopWidget> #include <QDesktopWidget>
class Icon : public QLabel class Icon : public QToolButton
{ {
Q_OBJECT Q_OBJECT
@ -22,7 +22,7 @@ public:
enum IconType enum IconType
{ {
PAUSE_PLAY, PAUSE_PLAY,
SETTINGS, MENU,
OPEN OPEN
}; };
@ -38,10 +38,13 @@ private:
QMediaPlayer::State playerState; QMediaPlayer::State playerState;
QString svgFile; QString svgFile;
void mouseReleaseEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *); void paintEvent(QPaintEvent *);
void loadImg(const QString &path); void loadImg(const QString &path);
private slots:
void buttonClicked();
signals: signals:
void pause(); void pause();

View File

@ -8,35 +8,34 @@ Ui::Ui(const QStringList &args, QWidget *parent) : QWidget(parent)
fileName = new QLabel(this); fileName = new QLabel(this);
slider = new QSlider(this); slider = new QSlider(this);
menu = new QMenu(this);
trayIcon = new QSystemTrayIcon(QIcon(":/logo"), this);
settings = new Icon(Icon::MENU, this);
pausePlay = new Icon(Icon::PAUSE_PLAY, this); pausePlay = new Icon(Icon::PAUSE_PLAY, this);
settings = new Icon(Icon::SETTINGS, this);
open = new Icon(Icon::OPEN, this); open = new Icon(Icon::OPEN, this);
player = new QMediaPlayer(this); player = new QMediaPlayer(this);
ioDev = new AudFile(this); ioDev = new AudFile(this);
conf = new Conf(this);
pressed = false; pressed = false;
QFont fnt = fileName->font(); QFont fnt = fileName->font();
QRect rect = QApplication::desktop()->screenGeometry();
fnt.setBold(true); fnt.setBold(true);
setMinimumHeight(rect.height() / 6);
setMinimumWidth(rect.width() / 5);
setMaximumHeight(rect.height() / 6);
setMaximumWidth(rect.width() / 5);
setStyleSheet("background-color:white;"); setStyleSheet("background-color:white;");
fileName->setText(QApplication::applicationName()); settings->setMenu(menu);
fileName->setText(tr("Ready"));
fileName->setFont(fnt); fileName->setFont(fnt);
slider->setOrientation(Qt::Horizontal); slider->setOrientation(Qt::Horizontal);
slider->setMinimumWidth((rect.width() / 5) - 100); trayIcon->show();
btnLayout->addWidget(pausePlay, 0, Qt::AlignCenter); conf->populateOptionsMenu(menu, this);
btnLayout->addSpacing(rect.height() / 40); player->setVolume(conf->getVolume());
btnLayout->addWidget(open, 0, Qt::AlignCenter); btnLayout->addWidget(pausePlay);
btnLayout->addSpacing(rect.height() / 40); btnLayout->addWidget(open);
btnLayout->addWidget(settings, 0, Qt::AlignCenter); btnLayout->addWidget(settings);
mainLayout->addWidget(fileName, 0, Qt::AlignCenter); mainLayout->addWidget(fileName);
mainLayout->addWidget(slider, 0, Qt::AlignCenter); mainLayout->addWidget(slider);
mainLayout->addWidget(btnWid, 0, Qt::AlignCenter); mainLayout->addWidget(btnWid, 0, Qt::AlignCenter);
connect(pausePlay, SIGNAL(pause()), player, SLOT(pause())); connect(pausePlay, SIGNAL(pause()), player, SLOT(pause()));
@ -44,10 +43,11 @@ Ui::Ui(const QStringList &args, QWidget *parent) : QWidget(parent)
connect(open, SIGNAL(open()), this, SLOT(openDialog())); connect(open, SIGNAL(open()), this, SLOT(openDialog()));
connect(player, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(error(QMediaPlayer::Error))); connect(player, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(error(QMediaPlayer::Error)));
connect(player, SIGNAL(stateChanged(QMediaPlayer::State)), pausePlay, SLOT(stateChanged(QMediaPlayer::State))); connect(player, SIGNAL(stateChanged(QMediaPlayer::State)), pausePlay, SLOT(stateChanged(QMediaPlayer::State)));
connect(player, SIGNAL(durationChanged(qint64)), this, SLOT(durationChanged(qint64)));
connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(posChanged(qint64))); connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(posChanged(qint64)));
connect(player, SIGNAL(durationChanged(qint64)), this, SLOT(durChanged(qint64)));
connect(slider, SIGNAL(sliderPressed()), this, SLOT(sliderPressed())); connect(slider, SIGNAL(sliderPressed()), this, SLOT(sliderPressed()));
connect(slider, SIGNAL(sliderReleased()), this, SLOT(sliderReleased())); connect(slider, SIGNAL(sliderReleased()), this, SLOT(sliderReleased()));
connect(conf, SIGNAL(volume(int)), player, SLOT(setVolume(int)));
if (args.size() > 1) if (args.size() > 1)
{ {
@ -57,17 +57,30 @@ Ui::Ui(const QStringList &args, QWidget *parent) : QWidget(parent)
void Ui::play(const QString &path) void Ui::play(const QString &path)
{ {
QFileInfo info(path); player->blockSignals(true);
fileDir = info.path();
slider->setMinimum(0);
fileName->setText(info.fileName());
player->stop(); player->stop();
ioDev->close(); pausePlay->stateChanged(QMediaPlayer::StoppedState);
ioDev->openFile(path);
player->setMedia(0, ioDev); if (ioDev->openFile(path))
player->play(); {
QFileInfo info(path);
conf->setLastPath(info.path());
fileName->setText(info.fileName());
player->setMedia(0, ioDev);
slider->setValue(0);
slider->setMinimum(0);
pausePlay->stateChanged(QMediaPlayer::PlayingState);
player->play();
adjustSize();
}
else
{
error(QMediaPlayer::ResourceError);
}
player->blockSignals(false);
} }
void Ui::openDialog() void Ui::openDialog()
@ -76,6 +89,7 @@ void Ui::openDialog()
fileDialog.setFileMode(QFileDialog::ExistingFile); fileDialog.setFileMode(QFileDialog::ExistingFile);
fileDialog.setNameFilter(tr("Audio Files (*.mp3 *.ogg *.wav *.flac)")); fileDialog.setNameFilter(tr("Audio Files (*.mp3 *.ogg *.wav *.flac)"));
fileDialog.setDirectory(conf->getLastPath());
if (fileDialog.exec()) if (fileDialog.exec())
{ {
@ -90,18 +104,26 @@ void Ui::error(QMediaPlayer::Error error)
if (error == QMediaPlayer::NoError) if (error == QMediaPlayer::NoError)
{ {
box.setText(tr("An unknown error has occured")); box.setText(tr("An unknown error has occured"));
}
else
{
box.setText(player->errorString());
}
if (error == QMediaPlayer::FormatError)
{
box.setIcon(QMessageBox::Warning); box.setIcon(QMessageBox::Warning);
} }
else else if (error == QMediaPlayer::FormatError)
{ {
box.setText(tr("The format of the media resource isn't fully supported. Playback may still be possible."));
box.setIcon(QMessageBox::Warning);
}
else if (error == QMediaPlayer::AccessDeniedError)
{
box.setText(tr("The appropriate permissions to play the media resource are not present"));
box.setIcon(QMessageBox::Critical);
}
else if (error == QMediaPlayer::ServiceMissingError)
{
box.setText(tr("A valid playback service was not found, playback cannot proceed."));
box.setIcon(QMessageBox::Critical);
}
else if (error == QMediaPlayer::ResourceError)
{
box.setText(tr("Media resource couldn't be resolved."));
box.setIcon(QMessageBox::Critical); box.setIcon(QMessageBox::Critical);
} }
@ -124,20 +146,20 @@ void Ui::posChanged(qint64 pos)
{ {
if (!pressed) slider->setSliderPosition(pos); if (!pressed) slider->setSliderPosition(pos);
// if (slider->sliderPosition() == slider->maximum()) if ((slider->sliderPosition() == slider->maximum()) && conf->nextFile())
// { {
// QTimer::singleShot(750, this, SLOT(nextFile())); QTimer::singleShot(1000, this, SLOT(nextFile()));
// } }
} }
void Ui::durationChanged(qint64 len) void Ui::durChanged(qint64 len)
{ {
slider->setMaximum(len); slider->setMaximum(len);
} }
void Ui::nextFile() void Ui::nextFile()
{ {
QDir dir(fileDir); QDir dir(conf->getLastPath());
QStringList filterList; QStringList filterList;
@ -155,7 +177,7 @@ void Ui::nextFile()
if (pos < list.size()) if (pos < list.size())
{ {
play(fileDir + list[pos]); play(conf->getLastPath() + QDir::separator() + list[pos]);
} }
} }
} }

View File

@ -2,6 +2,7 @@
#define UI_H #define UI_H
#include <QWidget> #include <QWidget>
#include <QMainWindow>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QSlider> #include <QSlider>
@ -9,18 +10,20 @@
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QMediaPlayer> #include <QMediaPlayer>
#include <QUrl>
#include <QFileDialog> #include <QFileDialog>
#include <QStringList> #include <QStringList>
#include <QMessageBox> #include <QMessageBox>
#include <QFont> #include <QFont>
#include <QApplication> #include <QApplication>
#include <QRect>
#include <QDesktopWidget>
#include <QTimer> #include <QTimer>
#include <QToolButton>
#include <QMenu>
#include <QSystemTrayIcon>
#include <QIcon>
#include "icon.h" #include "icon.h"
#include "../io/aud_file.h" #include "../io/aud_file.h"
#include "../io/conf.h"
class Ui : public QWidget class Ui : public QWidget
{ {
@ -28,15 +31,17 @@ class Ui : public QWidget
private: private:
QLabel *fileName; QLabel *fileName;
QSlider *slider; QSlider *slider;
QMediaPlayer *player; QMediaPlayer *player;
AudFile *ioDev; AudFile *ioDev;
Icon *pausePlay; QToolButton *settings;
Icon *settings; QSystemTrayIcon *trayIcon;
Icon *open; Conf *conf;
QString fileDir; QMenu *menu;
bool pressed; Icon *pausePlay;
Icon *open;
bool pressed;
private slots: private slots:
@ -44,7 +49,7 @@ private slots:
void sliderPressed(); void sliderPressed();
void sliderReleased(); void sliderReleased();
void posChanged(qint64 pos); void posChanged(qint64 pos);
void durationChanged(qint64 len); void durChanged(qint64 len);
void openDialog(); void openDialog();
void nextFile(); void nextFile();
void play(const QString &path); void play(const QString &path);

View File

@ -1,8 +1,9 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file alias="play">svg/play-button.svg</file> <file alias="open">svg/open.svg</file>
<file alias="pause">svg/pause.svg</file> <file alias="pause">svg/pause.svg</file>
<file alias="settings">svg/list.svg</file> <file alias="play">svg/play.svg</file>
<file alias="open">svg/eject.svg</file> <file alias="menu">svg/menu.svg</file>
<file alias="logo">app_logo.ico</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -12,12 +12,16 @@ AudFile::~AudFile()
bool AudFile::openFile(const QString &path) bool AudFile::openFile(const QString &path)
{ {
close();
setFileName(path); setFileName(path);
bool ret = open(QFile::ReadOnly); bool ret = open(QFile::ReadOnly);
if (ret) if (ret)
{ {
offset = 0;
if (peek(3) == "ID3") if (peek(3) == "ID3")
{ {
QByteArray header = read(10); QByteArray header = read(10);
@ -43,15 +47,20 @@ bool AudFile::openFile(const QString &path)
} }
offset += num; offset += num;
seek(0);
} }
seek(0);
} }
return ret; return ret;
} }
bool AudFile::seek(qint64 pos) bool AudFile::seek(qint64 off)
{ {
return QFile::seek(pos + offset); return QFile::seek(offset + off);
}
qint64 AudFile::size() const
{
return QFile::size() - offset;
} }

View File

@ -1,9 +1,11 @@
#ifndef AUD_FILE_H #ifndef AUD_FILE_H
#define AUD_FILE_H #define AUD_FILE_H
#include <QBuffer>
#include <QFile> #include <QFile>
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include <QTimerEvent>
class AudFile : public QFile class AudFile : public QFile
{ {
@ -17,8 +19,9 @@ public:
AudFile(QObject *parent = 0); AudFile(QObject *parent = 0);
bool openFile(const QString &path); bool openFile(const QString &path);
bool seek(qint64 pos); bool seek(qint64 off);
qint64 size() const;
~AudFile(); ~AudFile();
}; };

150
io/conf.cpp Normal file
View File

@ -0,0 +1,150 @@
#include "io/conf.h"
MenuItem::MenuItem(const QString &label, QWidget *widget, QObject *parent) : QWidgetAction(parent)
{
str = label;
wid = widget;
}
QWidget *MenuItem::createWidget(QWidget *parent)
{
QWidget *widget = new QWidget(parent);
QHBoxLayout *layout = new QHBoxLayout(widget);
layout->addWidget(new QLabel(str, parent));
layout->addStretch();
layout->addWidget(wid, 0, Qt::AlignRight);
return widget;
}
Conf::Conf(QObject *parent) : QObject(parent)
{
QFile file(confPath(), this);
QByteArray data;
if (file.open(QFile::ReadOnly))
{
data = file.readAll();
}
file.close();
Idm idm(data, this);
idm.rdHeader();
QByteArray pathBa = idm.value(LAST_PATH);
QByteArray nextBa = idm.value(NEXT_FILE);
QByteArray volBa = idm.value(VOLUME);
if (!pathBa.isEmpty()) lastPath = pathBa;
else lastPath = QDir::homePath();
if (!nextBa.isEmpty()) nextFileState = (nextBa == "Y");
else nextFileState = true;
if (!volBa.isEmpty()) volumeValue = rdInt(volBa);
else volumeValue = 50;
}
void Conf::sync()
{
Idm idm(this);
idm.wrHeader();
idm.insert(LAST_PATH, lastPath.toUtf8());
idm.insert(VOLUME, wrInt(volumeValue));
if (nextFileState) idm.insert(NEXT_FILE, "Y");
else idm.insert(NEXT_FILE, "N");
QFile file(confPath(), this);
file.open(QFile::WriteOnly | QFile::Truncate);
file.write(idm.getBuff());
}
void Conf::populateOptionsMenu(QMenu *menu, QWidget *parent)
{
QWidget *volWidget = new QWidget(parent);
QHBoxLayout *volLayout = new QHBoxLayout(volWidget);
QSlider *volSlider = new QSlider(parent);
QCheckBox *nextBox = new QCheckBox(parent);
volSlider->setMinimum(0);
volSlider->setMaximum(100);
volSlider->setValue(getVolume());
volSlider->setOrientation(Qt::Horizontal);
volLayout->addWidget(new QLabel("-"));
volLayout->addWidget(volSlider);
volLayout->addWidget(new QLabel("+"));
nextBox->setText("");
nextBox->setChecked(nextFile());
connect(volSlider, SIGNAL(valueChanged(int)), this, SLOT(setVolume(int)));
connect(volSlider, SIGNAL(valueChanged(int)), this, SIGNAL(volume(int)));
connect(nextBox, SIGNAL(clicked(bool)), this, SLOT(setNextFile(bool)));
menu->addAction(new MenuItem(tr("Volume"), volWidget, this));
menu->addAction(new MenuItem(tr("Auto play next file in directory"), nextBox, this));
}
void Conf::setLastPath(const QString &path)
{
lastPath = path; sync();
}
void Conf::setNextFile(bool state)
{
nextFileState = state; sync();
}
void Conf::setVolume(int value)
{
emit volume(value);
volumeValue = value; sync();
}
QString Conf::getLastPath()
{
if (!QDir(lastPath).exists())
{
lastPath = QDir::homePath();
}
return lastPath;
}
bool Conf::nextFile()
{
return nextFileState;
}
int Conf::getVolume()
{
return volumeValue;
}
QString Conf::confPath()
{
QString path = QDir::homePath() + '/';
#ifndef Q_OS_WIN32
path.append("/.config/");
#else
path.append("AppData/Local/");
#endif
QDir dir;
path.append(QApplication::applicationName() + '/');
dir.mkpath(path);
return path + "conf.idm";
}

74
io/conf.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef CONF_H
#define CONF_H
#include <QObject>
#include <QWidgetAction>
#include <QMenu>
#include <QSlider>
#include <QWidget>
#include <QHBoxLayout>
#include <QLabel>
#include <QCheckBox>
#include <QFile>
#include <QDir>
#include <QApplication>
#include "idm.h"
class MenuItem : public QWidgetAction
{
Q_OBJECT
private:
QString str;
QWidget *wid;
QWidget *createWidget(QWidget *parent);
public:
MenuItem(const QString &label, QWidget *widget, QObject *parent = 0);
};
class Conf : public QObject
{
Q_OBJECT
private:
enum DataType
{
LAST_PATH = 1,
NEXT_FILE,
VOLUME
};
QString lastPath;
bool nextFileState;
int volumeValue;
void sync();
QString confPath();
public slots:
void setLastPath(const QString &path);
void setNextFile(bool state);
void setVolume(int value);
public:
QString getLastPath();
bool nextFile();
void populateOptionsMenu(QMenu *menu, QWidget *parent);
int getVolume();
Conf(QObject *parent = 0);
signals:
void volume(int);
};
#endif // CONF_H

432
io/idm.cpp Normal file
View File

@ -0,0 +1,432 @@
#include "idm.h"
const QByteArray Idm::TAG = "IDM";
const int Idm::MAX_MAJOR = 1;
const int Idm::MAX_MINOR = 0;
int Idm::DEFAULT_INT_SIZE = 3;
int Idm::DEFAULT_FLAGS = 1; // FIXED_KEY_LEN
int Idm::DEFAULT_KEY_LEN = 1;
int Idm::CURRENT_MAJOR = Idm::MAX_MAJOR;
int Idm::CURRENT_MINOR = Idm::MAX_MINOR;
Idm::Idm(const QByteArray &data, QObject *parent) : QObject(parent)
{
buffPtr = data;
init();
}
Idm::Idm(QObject *parent) : QObject(parent)
{
init();
}
void Idm::init()
{
header = 0;
intSize = DEFAULT_INT_SIZE;
keyLen = DEFAULT_KEY_LEN;
flags = DEFAULT_FLAGS;
}
void Idm::loadData(const QByteArray &data)
{
op(RELOAD, data);
}
QByteArray &Idm::getBuff()
{
op(GET_BUFF, QByteArray(), QByteArray(), new QByteArray());
return buffPtr;
}
bool Idm::rdHeader()
{
return rdExHeader(buffPtr);
}
bool Idm::rdExHeader(const QByteArray &data)
{
bool ret;
op(RD_HEADER, data, QByteArray(), 0, 0, 0, &ret);
return ret;
}
bool Idm::rdExHeader(const QByteArray &data, int &major, int &minor, int &intSz, int &flgs, int &keyLen)
{
bool ret = false;
if (data.startsWith(TAG))
{
int pos = TAG.size();
major = rdInt(data.mid(pos++, 1));
minor = rdInt(data.mid(pos++, 1));
intSz = rdInt(data.mid(pos++, 1));
keyLen = rdInt(data.mid(pos++, 1));
flgs = rdInt(data.mid(pos, 4));
if ((major <= MAX_MAJOR) && (minor <= MAX_MINOR))
{
ret = true;
}
}
return ret;
}
bool Idm::verifyExHeader(const QByteArray &data, int major, int minor)
{
bool ret = false;
if (data.startsWith(TAG) && (data.size() == 11))
{
int pos = TAG.size();
int ma = rdInt(data.mid(pos++, 1));
int mi = rdInt(data.mid(pos++, 1));
ret = ((ma <= major) && (mi <= minor));
}
return ret;
}
QByteArray Idm::buildHeader(int major, int minor, int intSz, int flgs, int keyLen)
{
QByteArray ret = TAG;
ret.append(wrInt(major, 1));
ret.append(wrInt(minor, 1));
ret.append(wrInt(intSz, 1));
ret.append(wrInt(keyLen, 1));
ret.append(wrInt(flgs, 4));
return ret;
}
void Idm::setKeyLen(int len)
{
op(SET_KEY_LEN, QByteArray(), QByteArray(), 0, len);
}
void Idm::setFlags(int flgs)
{
op(SET_FLAGS, QByteArray(), QByteArray(), 0, flgs);
}
void Idm::wrHeader()
{
op(WR_HEADER);
}
void Idm::setIntSize(int bytes)
{
op(SET_INT_SIZE, QByteArray(), QByteArray(), 0, bytes);
}
void Idm::setVersion(int major, int minor)
{
op(SET_VERSION, QByteArray(), QByteArray(), 0, major, minor);
}
QByteArray Idm::rdData(int addr, int len, bool *ret)
{
bool ok = false;
if ((addr < buffPtr.size()) && (addr >= 0))
{
if ((len + addr) <= buffPtr.size())
{
ok = true;
}
}
if (ret) *ret = ok;
if (ok)
{
return QByteArray::fromRawData(buffPtr.data() + addr, len);
}
else
{
return QByteArray();
}
}
bool Idm::findKey(int &addr, int &dataLen, const QByteArray &key)
{
bool ok = true;
bool found = false;
while(addr < buffPtr.size() && ok)
{
int keySize;
if (flags & FIXED_KEY_LEN)
{
keySize = keyLen;
}
else
{
keySize = rdInt(rdData(addr, intSize, &ok));
addr += intSize;
}
if (ok)
{
if (key == rdData(addr, keySize, &ok))
{
found = true;
}
addr += keySize;
if (ok)
{
dataLen = rdInt(rdData(addr, intSize, &ok));
addr += intSize;
if (found && ok)
{
break;
}
else
{
addr += dataLen;
}
}
}
}
return found;
}
QByteArray Idm::value(const QByteArray &key)
{
QByteArray ret;
op(RD_VALUE, key, QByteArray(), &ret);
return ret;
}
QByteArray Idm::value(quint64 key)
{
int keySize;
if (flags & FIXED_KEY_LEN) keySize = keyLen;
else keySize = intSize;
return value(wrInt(key, keySize));
}
quint64 Idm::intValue(const QByteArray &key)
{
return rdInt(value(key));
}
quint64 Idm::intValue(quint64 key)
{
return rdInt(value(key));
}
bool Idm::remove(const QByteArray &key)
{
bool ret;
op(RM_VALUE, key, QByteArray(), 0, 0, 0, &ret);
return ret;
}
bool Idm::remove(quint64 key)
{
int keySize;
if (flags & FIXED_KEY_LEN) keySize = keyLen;
else keySize = intSize;
return remove(wrInt(key, keySize));
}
bool Idm::insert(const QByteArray &key, const QByteArray &data)
{
bool ret;
op(WR_VALUE, key, data, 0, 0, 0, &ret);
return ret;
}
bool Idm::insert(quint64 key, quint64 num)
{
int keySize;
if (flags & FIXED_KEY_LEN) keySize = keyLen;
else keySize = intSize;
return insert(wrInt(key, keySize), wrInt(num, intSize));
}
bool Idm::insert(quint64 key, const QByteArray &data)
{
int keySize;
if (flags & FIXED_KEY_LEN) keySize = keyLen;
else keySize = intSize;
return insert(wrInt(key, keySize), data);
}
void Idm::op(Operation opr,
const QByteArray &inA,
const QByteArray &inB,
QByteArray *out,
int intA,
int intB,
bool *ok)
{
QMutex m;
m.lock();
switch(opr)
{
case SET_KEY_LEN:
{
keyLen = intA; break;
}
case SET_FLAGS:
{
flags = intA; break;
}
case GET_BUFF:
{
out = &buffPtr; break;
}
case RELOAD:
{
buffPtr = inA; break;
}
case SET_INT_SIZE:
{
intSize = intA; break;
}
case SET_VERSION:
{
CURRENT_MAJOR = intA;
CURRENT_MINOR = intB;
break;
}
case WR_HEADER:
{
if (buffPtr.startsWith(TAG))
{
int pos = TAG.size();
buffPtr.replace(pos++, 1, wrInt(CURRENT_MAJOR, 1));
buffPtr.replace(pos++, 1, wrInt(CURRENT_MINOR, 1));
buffPtr.replace(pos++, 1, wrInt(intSize, 1));
buffPtr.replace(pos++, 1, wrInt(keyLen, 1));
buffPtr.replace(pos++, 4, wrInt(flags, 4));
}
else
{
buffPtr.insert(0, wrInt(flags, 4));
buffPtr.insert(0, wrInt(keyLen, 1));
buffPtr.insert(0, wrInt(intSize, 1));
buffPtr.insert(0, wrInt(CURRENT_MINOR, 1));
buffPtr.insert(0, wrInt(CURRENT_MAJOR, 1));
buffPtr.insert(0, TAG);
}
header = 8 + TAG.size();
break;
}
case RD_HEADER:
{
*ok = rdExHeader(inA, CURRENT_MAJOR, CURRENT_MINOR, intSize, flags, keyLen);
if (*ok) header = 8 + TAG.size();
break;
}
case RD_VALUE:
{
int pos = header;
int len = 0;
if (findKey(pos, len, inA))
{
out->clear();
out->append(buffPtr.mid(pos, len));
}
break;
}
case RM_VALUE:
{
int pos = header;
int len = 0;
*ok = false;
if (findKey(pos, len, inA))
{
if (flags & FIXED_KEY_LEN)
{
pos -= keyLen + intSize;
len += keyLen + intSize;
}
else
{
pos -= inA.size() + (intSize * 2);
len += inA.size() + (intSize * 2);
}
buffPtr.remove(pos, len);
*ok = true;
}
break;
}
case WR_VALUE:
{
*ok = false;
remove(inA);
if (flags & FIXED_KEY_LEN)
{
if (inA.size() == keyLen)
{
buffPtr.append(inA + wrInt(inB.size(), intSize) + inB);
*ok = true;
}
}
else
{
if (!inA.isEmpty())
{
buffPtr.append(wrInt(inA.size(), intSize) + inA);
buffPtr.append(wrInt(inB.size(), intSize) + inB);
*ok = true;
}
}
break;
}
}
m.unlock();
}

92
io/idm.h Normal file
View File

@ -0,0 +1,92 @@
#ifndef IDM_H
#define IDM_H
#include <QObject>
#include <QByteArray>
#include <QMutex>
#include "int.h"
class Idm : public QObject
{
Q_OBJECT
public:
enum Flags
{
FIXED_KEY_LEN = 1
};
static const QByteArray TAG;
static const int MAX_MAJOR;
static const int MAX_MINOR;
static int CURRENT_MAJOR;
static int CURRENT_MINOR;
static int DEFAULT_INT_SIZE;
static int DEFAULT_FLAGS;
static int DEFAULT_KEY_LEN;
static bool verifyExHeader(const QByteArray &data, int major, int minor);
static bool rdExHeader(const QByteArray &data, int &major, int &minor, int &intSz, int &flgs, int &keyLen);
static QByteArray buildHeader(int major, int minor, int intSz, int flgs, int keyLen);
explicit Idm(const QByteArray &data, QObject *parent = 0);
explicit Idm(QObject *parent = 0);
void setVersion(int major, int minor);
void setFlags(int flgs);
void setIntSize(int bytes);
void wrHeader();
void setKeyLen(int len);
void loadData(const QByteArray &data);
bool insert(const QByteArray &key, const QByteArray &data);
bool insert(quint64 key, quint64 num);
bool insert(quint64 key, const QByteArray &data);
bool remove(const QByteArray &key);
bool remove(quint64 key);
bool rdHeader();
bool rdExHeader(const QByteArray &data);
quint64 intValue(quint64 key);
quint64 intValue(const QByteArray &key);
QByteArray value(const QByteArray &key);
QByteArray value(quint64 key);
QByteArray &getBuff();
private:
enum Operation
{
RELOAD,
GET_BUFF,
RD_HEADER,
WR_HEADER,
SET_KEY_LEN,
SET_FLAGS,
SET_INT_SIZE,
SET_VERSION,
RD_VALUE,
WR_VALUE,
RM_VALUE
};
QByteArray buffPtr;
int header;
int intSize;
int keyLen;
int flags;
void op(Operation opr,
const QByteArray &inA = QByteArray(),
const QByteArray &inB = QByteArray(),
QByteArray *out = 0,
int intA = 0,
int intB = 0,
bool *ok = 0);
void init();
bool findKey(int &addr, int &dataLen, const QByteArray &key);
QByteArray rdData(int, int, bool *ok = 0);
};
#endif // IDM_H

58
io/int.cpp Normal file
View File

@ -0,0 +1,58 @@
#include "int.h"
quint64 rdInt(const QByteArray &data)
{
quint64 out = 0;
quint64 outBit = 1;
for (int i = data.size() - 1; i >= 0; --i)
{
int byte = data[i];
for (int inBit = 1; inBit <= 128; inBit *= 2, outBit *= 2)
{
if ((byte & inBit) != 0) out |= outBit;
}
}
return out;
}
float rdFloat(const QByteArray &data)
{
return data.toFloat();
}
QByteArray wrInt(quint64 value, int intSize)
{
QByteArray out;
quint64 inBit = 1;
while (value != 0)
{
int byte = 0;
for (int outBit = 1; outBit <= 128; outBit *= 2, inBit *= 2)
{
if (value & inBit)
{
byte |= outBit;
value ^= inBit;
}
}
out.insert(0, byte);
}
return out.rightJustified(intSize, 0);
}
QByteArray wrInt(quint64 value)
{
return wrInt(value, INT_SIZE);
}
QByteArray wrFloat(float value)
{
return QByteArray().setNum(value);
}

15
io/int.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef INT_H
#define INT_H
#include <QByteArray>
#include <QList>
#define INT_SIZE 6
float rdFloat(const QByteArray &data);
quint64 rdInt(const QByteArray &data);
QByteArray wrInt(quint64 value);
QByteArray wrInt(quint64 value, int);
QByteArray wrFloat(float value);
#endif // INT_H

1
logo.rc Normal file
View File

@ -0,0 +1 @@
IDI_ICON1 ICON DISCARDABLE "app_logo.ico"

View File

@ -1,46 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 56.654 56.654" style="enable-background:new 0 0 56.654 56.654;" xml:space="preserve">
<g>
<path d="M55.043,27.283L31.977,4.306c-0.946-0.942-2.27-1.479-3.66-1.479c-1.389,0-2.714,0.535-3.66,1.478L1.348,27.525
C1.29,27.582,1.235,27.64,1.18,27.699c-0.362,0.398-0.641,0.838-0.836,1.297c-0.193,0.459-0.311,0.949-0.338,1.463
C0.002,30.537,0,30.613,0,30.69c0,0.021,0,0.037,0,0.06c0.009,0.635,0.155,1.242,0.414,1.791c0.259,0.553,0.638,1.063,1.135,1.504
c0.002,0.002,0.004,0.004,0.004,0.004c0.07,0.063,0.144,0.123,0.218,0.182c0.002,0,0.002,0.002,0.004,0.002
c0.438,0.344,0.924,0.605,1.434,0.787c0.481,0.172,0.999,0.275,1.538,0.303c0.002,0,0.003,0,0.005,0
c0.086,0.002,0.142,0.002,0.262,0.004H51.62c0.006,0,0.01,0,0.015,0c0.007,0,0.015,0,0.019,0c2.762,0,5-2.073,5-4.635
C56.654,29.344,56.033,28.131,55.043,27.283z"/>
<path d="M56.654,48.161c0,3.129-2.537,5.666-5.668,5.666H5.667C2.537,53.827,0,51.29,0,48.161l0,0c0-3.131,2.537-5.668,5.667-5.668
h45.318C54.117,42.493,56.654,45.03,56.654,48.161L56.654,48.161z"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,46 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 62.246 62.246" style="enable-background:new 0 0 62.246 62.246;" xml:space="preserve">
<g>
<path d="M57.548,45.107H19.965c-2.595,0-4.699,2.105-4.699,4.701c0,2.594,2.104,4.699,4.699,4.699h37.583
c2.594,0,4.698-2.105,4.698-4.699C62.246,47.213,60.142,45.107,57.548,45.107z"/>
<path d="M57.548,26.402H19.965c-2.595,0-4.699,2.104-4.699,4.7c0,2.595,2.104,4.699,4.699,4.699h37.583
c2.594,0,4.698-2.104,4.698-4.699S60.142,26.402,57.548,26.402z"/>
<path d="M19.965,17.096h37.583c2.594,0,4.698-2.104,4.698-4.7s-2.104-4.699-4.698-4.699H19.965c-2.595,0-4.699,2.104-4.699,4.699
C15.266,14.991,17.37,17.096,19.965,17.096z"/>
<circle cx="4.77" cy="12.439" r="4.77"/>
<circle cx="4.77" cy="31.102" r="4.769"/>
<circle cx="4.77" cy="49.807" r="4.77"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

12
svg/menu.svg Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="500px" height="500px" viewBox="0 0 5000 5000" preserveAspectRatio="xMidYMid meet">
<g id="layer1" fill="#ffffff" stroke="none">
<path d="M3880 3027 c-83 -30 -135 -63 -197 -126 -94 -95 -143 -219 -143 -361 0 -179 78 -329 225 -430 155 -107 390 -108 544 -4 151 102 231 252 231 434 0 50 -7 109 -16 141 -50 170 -182 306 -343 353 -83 24 -221 21 -301 -7z"/>
<path d="M850 3017 c-160 -57 -275 -180 -324 -346 -21 -71 -21 -211 0 -282 35 -119 107 -219 209 -289 155 -107 390 -108 544 -4 151 102 231 252 231 434 0 50 -7 109 -16 141 -50 170 -182 306 -343 353 -83 24 -221 21 -301 -7z"/>
<path d="M2360 3017 c-83 -30 -135 -63 -197 -126 -94 -95 -143 -219 -143 -361 0 -179 78 -329 225 -430 155 -107 390 -108 544 -4 151 102 231 252 231 434 0 50 -7 109 -16 141 -50 170 -182 306 -343 353 -83 24 -221 21 -301 -7z"/>
</g>
<g id="layer2" fill="#b6748b" stroke="none">
<path d="M0 2500 l0 -2500 2500 0 2500 0 0 2500 0 2500 -2500 0 -2500 0 0 -2500z m4181 534 c161 -47 293 -183 343 -353 9 -32 16 -91 16 -141 0 -182 -80 -332 -231 -434 -154 -104 -389 -103 -544 4 -147 101 -225 251 -225 430 0 289 214 509 496 510 54 0 112 -6 145 -16z m-3030 -10 c161 -47 293 -183 343 -353 9 -32 16 -91 16 -141 0 -182 -80 -332 -231 -434 -154 -104 -389 -103 -544 4 -147 101 -225 251 -225 430 0 289 214 509 496 510 54 0 112 -6 145 -16z m1510 0 c161 -47 293 -183 343 -353 9 -32 16 -91 16 -141 0 -182 -80 -332 -231 -434 -154 -104 -389 -103 -544 4 -147 101 -225 251 -225 430 0 289 214 509 496 510 54 0 112 -6 145 -16z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

10
svg/open.svg Normal file
View File

@ -0,0 +1,10 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 5010 5000" preserveAspectRatio="xMidYMid meet">
<g id="layer1" fill="#ffffff" stroke="none">
<path d="M770 2490 l0 -1200 895 0 895 0 0 160 0 160 825 0 825 0 0 1040 0 1040 -1720 0 -1720 0 0 -1200z"/>
</g>
<g id="layer2" fill="#10715B" stroke="none">
<path d="M0 2500 l0 -2500 2505 0 2505 0 0 2500 0 2500 -2505 0 -2505 0 0 -2500z m4210 150 l0 -1040 -825 0 -825 0 0 -160 0 -160 -895 0 -895 0 0 1200 0 1200 1720 0 1720 0 0 -1040z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 624 B

View File

@ -1,41 +1,11 @@
<?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <svg version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 5010 5000" preserveAspectRatio="xMidYMid meet">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <g id="layer1" fill="#ffffff" stroke="none">
viewBox="0 0 47.607 47.607" style="enable-background:new 0 0 47.607 47.607;" xml:space="preserve"> <path d="M1220 2575 l0 -1925 385 0 385 0 0 1925 0 1925 -385 0 -385 0 0 -1925z"/>
<g> <path d="M2870 2575 l0 -1925 385 0 385 0 0 1925 0 1925 -385 0 -385 0 0 -1925z"/>
<path d="M17.991,40.976c0,3.662-2.969,6.631-6.631,6.631l0,0c-3.662,0-6.631-2.969-6.631-6.631V6.631C4.729,2.969,7.698,0,11.36,0 </g>
l0,0c3.662,0,6.631,2.969,6.631,6.631V40.976z"/> <g id="layer2" fill="#1134c1" stroke="none">
<path d="M42.877,40.976c0,3.662-2.969,6.631-6.631,6.631l0,0c-3.662,0-6.631-2.969-6.631-6.631V6.631 <path d="M0 2500 l0 -2500 2505 0 2505 0 0 2500 0 2500 -2505 0 -2505 0 0 -2500z m1990 75 l0 -1925 -385 0 -385 0 0 1925 0 1925 385 0 385 0 0 -1925z m1650 0 l0 -1925 -385 0 -385 0 0 1925 0 1925 385 0 385 0 0 -1925z"/>
C29.616,2.969,32.585,0,36.246,0l0,0c3.662,0,6.631,2.969,6.631,6.631V40.976z"/> </g>
</g>
<g> </svg>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 875 B

After

Width:  |  Height:  |  Size: 716 B

View File

@ -1,40 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 47.604 47.604" style="enable-background:new 0 0 47.604 47.604;" xml:space="preserve">
<g>
<path d="M43.331,21.237L7.233,0.397c-0.917-0.529-2.044-0.529-2.96,0c-0.916,0.528-1.48,1.505-1.48,2.563v41.684
c0,1.058,0.564,2.035,1.48,2.563c0.458,0.268,0.969,0.397,1.48,0.397c0.511,0,1.022-0.133,1.48-0.397l36.098-20.84
c0.918-0.529,1.479-1.506,1.479-2.564S44.247,21.767,43.331,21.237z"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 811 B

10
svg/play.svg Normal file
View File

@ -0,0 +1,10 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 5010 5000" preserveAspectRatio="xMidYMid meet">
<g id="layer1" fill="#ffffff" stroke="none">
<path d="M1395 4388 c-3 -7 -4 -870 -3 -1918 3 -1803 4 -1905 20 -1905 24 0 2658 1893 2658 1910 0 14 -2628 1918 -2654 1923 -9 2 -18 -2 -21 -10z"/>
</g>
<g id="layer2" fill="#1134c1" stroke="none">
<path d="M0 2500 l0 -2500 2505 0 2505 0 0 2500 0 2500 -2505 0 -2505 0 0 -2500z m2751 942 c725 -525 1319 -960 1319 -967 0 -17 -2634 -1910 -2658 -1910 -16 0 -17 102 -20 1905 -1 1048 0 1911 3 1918 3 8 12 12 21 10 8 -2 609 -432 1335 -956z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 721 B