Merge branch 'master' of https://github.com/NautiluX/slide into NautiluX-master
This commit is contained in:
@@ -47,6 +47,8 @@ slide [-t rotation_seconds] [-a aspect] [-o background_opacity(0..255)] [-b blur
|
|||||||
* `<path>`path to the current image without filename
|
* `<path>`path to the current image without filename
|
||||||
* Example: `slide -p ./images -O "20|60|Time: <time>;;;Picture taken at <exifdatetime>"`
|
* Example: `slide -p ./images -O "20|60|Time: <time>;;;Picture taken at <exifdatetime>"`
|
||||||
|
|
||||||
|
To exit the application, press escape. If you're using a touch display, touch all 4 corners at the same time.
|
||||||
|
|
||||||
## Folder Options file
|
## Folder Options file
|
||||||
When using the default or recursive folder mode we support having per folder display options. The options are stored in a file called "options.json" and currently support the following option
|
When using the default or recursive folder mode we support having per folder display options. The options are stored in a file called "options.json" and currently support the following option
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ ImageSelector::ImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char
|
|||||||
|
|
||||||
ImageSelector::~ImageSelector(){}
|
ImageSelector::~ImageSelector(){}
|
||||||
|
|
||||||
int ImageSelector::getImageRotation(const std::string &fileName)
|
int ImageSelector::getImageRotation(const std::string& fileName)
|
||||||
{
|
{
|
||||||
int orientation = 0;
|
int orientation = 0;
|
||||||
ExifData *exifData = exif_data_new_from_file(fileName.c_str());
|
ExifData *exifData = exif_data_new_from_file(fileName.c_str());
|
||||||
@@ -50,6 +50,28 @@ int ImageSelector::getImageRotation(const std::string &fileName)
|
|||||||
return degrees;
|
return degrees;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ImageSelector::imageMatchesFilter(const std::string& fileName, int rotation)
|
||||||
|
{
|
||||||
|
if(!QFileInfo::exists(QString(fileName.c_str())))
|
||||||
|
{
|
||||||
|
if(debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "file not found: " << fileName << std::endl;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!imageValidForAspect(fileName, rotation)) {
|
||||||
|
if(debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "image aspect ratio doesn't match filter '" << aspect << "' : " << fileName << std::endl;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ImageSelector::imageValidForAspect(const std::string &fileName, const int rotation)
|
bool ImageSelector::imageValidForAspect(const std::string &fileName, const int rotation)
|
||||||
{
|
{
|
||||||
QPixmap p( fileName.c_str() );
|
QPixmap p( fileName.c_str() );
|
||||||
@@ -94,20 +116,18 @@ const std::string RandomImageSelector::getNextImage(ImageOptions_t &options)
|
|||||||
{
|
{
|
||||||
std:: string filename;
|
std:: string filename;
|
||||||
try
|
try
|
||||||
{
|
|
||||||
while (filename.empty())
|
|
||||||
{
|
{
|
||||||
QStringList images = pathTraverser->getImages();
|
QStringList images = pathTraverser->getImages();
|
||||||
unsigned int selectedImage = selectRandom(images);
|
unsigned int selectedImage = selectRandom(images);
|
||||||
filename = pathTraverser->getImagePath(images.at(selectedImage).toStdString());
|
filename = pathTraverser->getImagePath(images.at(selectedImage).toStdString());
|
||||||
options.rotation = getImageRotation(filename);
|
options.rotation = getImageRotation(filename);
|
||||||
if (!imageValidForAspect(filename, options.rotation))
|
while(!imageMatchesFilter(filename, options.rotation))
|
||||||
{
|
{
|
||||||
filename.clear();
|
unsigned int selectedImage = selectRandom(images);
|
||||||
|
filename = pathTraverser->getImagePath(images.at(selectedImage).toStdString());
|
||||||
|
options.rotation = getImageRotation(filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
catch(const std::string& err)
|
catch(const std::string& err)
|
||||||
{
|
{
|
||||||
std::cerr << "Error: " << err << std::endl;
|
std::cerr << "Error: " << err << std::endl;
|
||||||
@@ -145,6 +165,29 @@ ShuffleImageSelector::~ShuffleImageSelector()
|
|||||||
}
|
}
|
||||||
|
|
||||||
const std::string ShuffleImageSelector::getNextImage(ImageOptions_t &options)
|
const std::string ShuffleImageSelector::getNextImage(ImageOptions_t &options)
|
||||||
|
{
|
||||||
|
reloadImagesIfNoneLeft();
|
||||||
|
if (images.size() == 0)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
std::string filename = pathTraverser->getImagePath(images.at(current_image_shuffle).toStdString());
|
||||||
|
current_image_shuffle = current_image_shuffle + 1; // ignore and move to next image
|
||||||
|
options.rotation = getImageRotation(filename);
|
||||||
|
while(!imageMatchesFilter(filename, options.rotation)) {
|
||||||
|
reloadImagesIfNoneLeft();
|
||||||
|
std::string filename = pathTraverser->getImagePath(images.at(current_image_shuffle).toStdString());
|
||||||
|
options.rotation = getImageRotation(filename);
|
||||||
|
current_image_shuffle = current_image_shuffle + 1; // ignore and move to next image
|
||||||
|
}
|
||||||
|
std::cout << "updating image: " << filename << std::endl;
|
||||||
|
options.aspect = aspect;
|
||||||
|
options.fitAspectAxisToWindow = fitAspectAxisToWindow;
|
||||||
|
pathTraverser->UpdateOptionsForImage(filename, options);
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShuffleImageSelector::reloadImagesIfNoneLeft()
|
||||||
{
|
{
|
||||||
if (images.size() == 0 || current_image_shuffle >= images.size())
|
if (images.size() == 0 || current_image_shuffle >= images.size())
|
||||||
{
|
{
|
||||||
@@ -155,40 +198,10 @@ const std::string ShuffleImageSelector::getNextImage(ImageOptions_t &options)
|
|||||||
std::mt19937 randomizer(rd());
|
std::mt19937 randomizer(rd());
|
||||||
std::shuffle(images.begin(), images.end(), randomizer);
|
std::shuffle(images.begin(), images.end(), randomizer);
|
||||||
}
|
}
|
||||||
if (images.size() == 0)
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
std::string filename = pathTraverser->getImagePath(images.at(current_image_shuffle).toStdString());
|
|
||||||
if(!QFileInfo::exists(QString(filename.c_str())))
|
|
||||||
{
|
|
||||||
if(debugMode)
|
|
||||||
{
|
|
||||||
std::cout << "file not found: " << filename << std::endl;
|
|
||||||
}
|
|
||||||
current_image_shuffle = current_image_shuffle + 1; // ignore and move to next image
|
|
||||||
return getNextImage(options);
|
|
||||||
}
|
|
||||||
options.rotation = getImageRotation(filename);
|
|
||||||
if (!imageValidForAspect(filename, options.rotation))
|
|
||||||
{
|
|
||||||
if(debugMode)
|
|
||||||
{
|
|
||||||
std::cout << "image has invalid aspect: " << filename << "(images left:" << (images.size()-current_image_shuffle) << ")" << std::endl;
|
|
||||||
}
|
|
||||||
current_image_shuffle = current_image_shuffle + 1; // ignore and move to next image
|
|
||||||
return getNextImage(options);
|
|
||||||
}
|
|
||||||
std::cout << "updating image: " << filename << std::endl;
|
|
||||||
current_image_shuffle = current_image_shuffle + 1;
|
|
||||||
options.aspect = aspect;
|
|
||||||
options.fitAspectAxisToWindow = fitAspectAxisToWindow;
|
|
||||||
pathTraverser->UpdateOptionsForImage(filename, options);
|
|
||||||
return filename;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SortedImageSelector::SortedImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspect, bool fitAspectAxisToWindow):
|
SortedImageSelector::SortedImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspect):
|
||||||
ImageSelector(pathTraverser, aspect, fitAspectAxisToWindow),
|
ImageSelector(pathTraverser, aspect),
|
||||||
images()
|
images()
|
||||||
{
|
{
|
||||||
srand (time(NULL));
|
srand (time(NULL));
|
||||||
@@ -212,40 +225,17 @@ bool operator<(const QString& lhs, const QString& rhs) noexcept{
|
|||||||
|
|
||||||
const std::string SortedImageSelector::getNextImage(ImageOptions_t &options)
|
const std::string SortedImageSelector::getNextImage(ImageOptions_t &options)
|
||||||
{
|
{
|
||||||
if (images.size() == 0)
|
reloadImagesIfEmpty();
|
||||||
{
|
|
||||||
images = pathTraverser->getImages();
|
|
||||||
std::sort(images.begin(), images.end());
|
|
||||||
if(debugMode)
|
|
||||||
{
|
|
||||||
std::cout << "read " << images.size() << " images." << std::endl;
|
|
||||||
for (int i = 0;i <images.size();i++){
|
|
||||||
|
|
||||||
std::cout << images[i].toStdString() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (images.size() == 0)
|
if (images.size() == 0)
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
std::string filename = pathTraverser->getImagePath(images.takeFirst().toStdString());
|
std::string filename = pathTraverser->getImagePath(images.takeFirst().toStdString());
|
||||||
if(!QFileInfo::exists(QString(filename.c_str())))
|
|
||||||
{
|
|
||||||
if(debugMode)
|
|
||||||
{
|
|
||||||
std::cout << "file not found: " << filename << std::endl;
|
|
||||||
}
|
|
||||||
return getNextImage(options);
|
|
||||||
}
|
|
||||||
options.rotation = getImageRotation(filename);
|
options.rotation = getImageRotation(filename);
|
||||||
if (!imageValidForAspect(filename, options.rotation))
|
while(!imageMatchesFilter(filename, options.rotation)) {
|
||||||
{
|
reloadImagesIfEmpty();
|
||||||
if(debugMode)
|
filename = pathTraverser->getImagePath(images.takeFirst().toStdString());
|
||||||
{
|
options.rotation = getImageRotation(filename);
|
||||||
std::cout << "image has invalid aspect: " << filename << std::endl;
|
|
||||||
}
|
|
||||||
return getNextImage(options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "updating image: " << filename << std::endl;
|
std::cout << "updating image: " << filename << std::endl;
|
||||||
@@ -254,3 +244,19 @@ const std::string SortedImageSelector::getNextImage(ImageOptions_t &options)
|
|||||||
pathTraverser->UpdateOptionsForImage(filename, options);
|
pathTraverser->UpdateOptionsForImage(filename, options);
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SortedImageSelector::reloadImagesIfEmpty()
|
||||||
|
{
|
||||||
|
if (images.size() == 0)
|
||||||
|
{
|
||||||
|
images = pathTraverser->getImages();
|
||||||
|
std::sort(images.begin(), images.end());
|
||||||
|
if(debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "read " << images.size() << " images." << std::endl;
|
||||||
|
for (int i = 0;i <images.size();i++){
|
||||||
|
std::cout << images[i].toStdString() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
int getImageRotation(const std::string &fileName);
|
int getImageRotation(const std::string &fileName);
|
||||||
bool imageValidForAspect(const std::string &fileName, const int rotation);
|
bool imageValidForAspect(const std::string &fileName, const int rotation);
|
||||||
|
bool imageMatchesFilter(const std::string& fileName);
|
||||||
std::unique_ptr<PathTraverser>& pathTraverser;
|
std::unique_ptr<PathTraverser>& pathTraverser;
|
||||||
char aspect;
|
char aspect;
|
||||||
bool fitAspectAxisToWindow = false;
|
bool fitAspectAxisToWindow = false;
|
||||||
@@ -51,6 +52,7 @@ public:
|
|||||||
virtual const std::string getNextImage(ImageOptions_t &options);
|
virtual const std::string getNextImage(ImageOptions_t &options);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void reloadImagesIfNoneLeft();
|
||||||
int current_image_shuffle;
|
int current_image_shuffle;
|
||||||
QStringList images;
|
QStringList images;
|
||||||
};
|
};
|
||||||
@@ -63,6 +65,7 @@ public:
|
|||||||
virtual const std::string getNextImage(ImageOptions_t &options);
|
virtual const std::string getNextImage(ImageOptions_t &options);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void reloadImagesIfEmpty();
|
||||||
QStringList images;
|
QStringList images;
|
||||||
};
|
};
|
||||||
#endif // IMAGESELECTOR_H
|
#endif // IMAGESELECTOR_H
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
||||||
|
|
||||||
|
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||||
|
|
||||||
QTimer::singleShot(5, this, SLOT(showFullScreen()));
|
QTimer::singleShot(5, this, SLOT(showFullScreen()));
|
||||||
QApplication::setOverrideCursor(Qt::BlankCursor);
|
QApplication::setOverrideCursor(Qt::BlankCursor);
|
||||||
QLabel *label = this->findChild<QLabel*>("image");
|
QLabel *label = this->findChild<QLabel*>("image");
|
||||||
@@ -47,6 +49,59 @@ void MainWindow::keyPressEvent(QKeyEvent* event)
|
|||||||
QWidget::keyPressEvent(event);
|
QWidget::keyPressEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isTouchEvent(const QEvent &event)
|
||||||
|
{
|
||||||
|
if(event.type() == QEvent::TouchBegin)
|
||||||
|
return true;
|
||||||
|
if(event.type() == QEvent::TouchUpdate)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isQuitCombination(const QTouchEvent &touchEvent)
|
||||||
|
{
|
||||||
|
bool topLeftTouched = false;
|
||||||
|
bool topRightTouched = false;
|
||||||
|
bool bottomLeftTouched = false;
|
||||||
|
bool bottomRightTouched = false;
|
||||||
|
for(const auto &touchPoint : touchEvent.touchPoints())
|
||||||
|
{
|
||||||
|
const qreal normalizedCornerSize = 0.1;
|
||||||
|
const qreal x = touchPoint.normalizedPos().x();
|
||||||
|
const qreal y = touchPoint.normalizedPos().y();
|
||||||
|
if(x < normalizedCornerSize)
|
||||||
|
{
|
||||||
|
if(y < normalizedCornerSize)
|
||||||
|
topLeftTouched = true;
|
||||||
|
else if(y > 1-normalizedCornerSize)
|
||||||
|
bottomLeftTouched = true;
|
||||||
|
}
|
||||||
|
else if(x > 1-normalizedCornerSize)
|
||||||
|
{
|
||||||
|
if(y < normalizedCornerSize)
|
||||||
|
topRightTouched = true;
|
||||||
|
else if(y > 1-normalizedCornerSize)
|
||||||
|
bottomRightTouched = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return topLeftTouched && topRightTouched
|
||||||
|
&& bottomLeftTouched && bottomRightTouched;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::event(QEvent* event)
|
||||||
|
{
|
||||||
|
if(isTouchEvent(*event))
|
||||||
|
{
|
||||||
|
if(isQuitCombination(dynamic_cast<QTouchEvent&>(*event)))
|
||||||
|
QCoreApplication::quit();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return QMainWindow::event(event);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::resizeEvent(QResizeEvent* event)
|
void MainWindow::resizeEvent(QResizeEvent* event)
|
||||||
{
|
{
|
||||||
QMainWindow::resizeEvent(event);
|
QMainWindow::resizeEvent(event);
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ class MainWindow : public QMainWindow
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit MainWindow(QWidget *parent = 0);
|
explicit MainWindow(QWidget *parent = 0);
|
||||||
void keyPressEvent(QKeyEvent* event);
|
void keyPressEvent(QKeyEvent* event) override;
|
||||||
void resizeEvent(QResizeEvent* event);
|
bool event(QEvent* event) override;
|
||||||
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
~MainWindow();
|
~MainWindow();
|
||||||
void setImage(const std::string& path, const ImageOptions_t &options);
|
void setImage(const std::string& path, const ImageOptions_t &options);
|
||||||
void setBlurRadius(unsigned int blurRadius);
|
void setBlurRadius(unsigned int blurRadius);
|
||||||
|
|||||||
Reference in New Issue
Block a user