Fix startup, and quitting, fixed squishing, added hover and double clicking, added back button

This commit is contained in:
2024-07-03 17:41:33 +02:00
parent abc97d95ef
commit 7ff0f8b71a
12 changed files with 164 additions and 61 deletions

View File

@@ -6,32 +6,35 @@
#include <unordered_map>
FileController::FileController( ) {
#ifdef _WIN32
m_fmWorker = std::make_shared<FileMonitor>(
std::filesystem::path(std::getenv("USERPROFILE")),
std::chrono::milliseconds(1000));
#else
m_fmWorker = std::make_shared<FileMonitor>(
std::filesystem::path(std::getenv("HOME")),
std::chrono::milliseconds(1000));
#endif
m_fmWorker->moveToThread(&m_fsThread);
// starts the directory monitoring thread, forgot why it has to be a signal, only works this way not with a direct call
connect(this, &FileController::operate, m_fmWorker.get( ),
&FileMonitor::start);
// main signal to populate the file grid, passes the path and event each time a file is deleted, created or updated
connect(m_fmWorker.get( ), &FileMonitor::changed, this,
&FileController::update);
// Propagating signal from the monitor that fires when the path is changed
connect(m_fmWorker.get( ), &FileMonitor::pathChanged, this,
&FileController::newPath);
//Why this no workie
//connect(this, &FileController::updatePath, m_fmWorker.get( ), &FileMonitor::SetPath);
#ifdef _WIN32
m_fmWorker.get( )->SetPath(std::filesystem::path(std::getenv("USERPROFILE")));
#else
m_fmWorker.get( )->SetPath(std::filesystem::path(std::getenv("HOME")));
#endif
// Signal to update the path, when fired passes the new path and will be given to the monitor
connect(this, &FileController::updatePath, this, [this](std::filesystem::path p) {
previousPaths.push(m_fmWorker.get( )->GetPath( ));
m_fmWorker.get( )->SetPath(p);
});
connect(this, &FileController::previousPath, this, [this]( ) {
if (previousPaths.empty( )) return;
m_fmWorker.get( )->SetPath(previousPaths.top( ));
previousPaths.pop( );
});
m_fsThread.start( );
emit operate( );
@@ -39,6 +42,7 @@ FileController::FileController( ) {
FileController::~FileController( ) {
m_fsThread.quit( );
m_fmWorker.get( )->stop( );
m_fsThread.wait( );
}

View File

@@ -4,6 +4,9 @@
#include <memory>
#include <unordered_map>
#include <filesystem>
#include <QApplication>
#include <stack>
#include "../../Core/FileMonitor/FileMonitor.hpp"
class FileController : public QObject {
@@ -19,6 +22,8 @@ public:
FileController(const FileController&) = delete;
FileController& operator=(const FileController&) = delete;
std::stack<std::filesystem::path> previousPaths;
private:
// Private constructor to prevent instantiation
FileController( );
@@ -42,4 +47,5 @@ signals:
void pathChanged(const std::filesystem::path p);
void contentChanged(std::filesystem::path path, FileEvent event);
void previousPath( );
};

View File

@@ -3,22 +3,17 @@
#include <iostream>
#include <thread>
FileMonitor::FileMonitor(std::filesystem::path path,
std::chrono::duration<int, std::milli> delay)
: m_path(path), m_delay(delay) { }
FileMonitor::FileMonitor(std::chrono::duration<int, std::milli> delay)
: m_delay(delay) { }
void FileMonitor::SetPath(std::filesystem::path newPath) {
m_path = newPath;
std::cout << m_path.string( ) << std::endl;
emit pathChanged(m_path);
initPathsMap( );
}
void FileMonitor::initPathsMap( ) {
m_paths.clear( );
/* for (auto& file : std::filesystem::directory_iterator(m_path)) {
m_paths[file.path( )] = std::filesystem::last_write_time(file);
} */
}
bool FileMonitor::is_hidden(const std::filesystem::path& p) {

View File

@@ -18,20 +18,23 @@ class FileMonitor : public QObject {
public:
std::chrono::duration<int, std::milli> m_delay;
FileMonitor(std::filesystem::path path,
std::chrono::duration<int, std::milli> delay);
FileMonitor(std::chrono::duration<int, std::milli> delay);
~FileMonitor( ) = default;
void SetPath(std::filesystem::path path);
std::filesystem::path GetPath( ) {
return m_path;
}
void stop( );
public slots:
void start( );
void stop( );
private:
std::unordered_map<std::filesystem::path, std::filesystem::file_time_type>
m_paths;
bool m_running;
bool m_running = true;
std::filesystem::path m_path;
bool contains(const std::filesystem::path& key);

View File

@@ -4,45 +4,57 @@
GridItemView::GridItemView(QWidget* parent)
: QFrame(parent), fileController(FileController::instance( )) {
QGridLayout* mainLayout = new QGridLayout( );
QVBoxLayout* mainLayout = new QVBoxLayout(this);
QGridLayout* gridLayout = new QGridLayout( );
this->setLayout(mainLayout);
gridLayout->setAlignment(Qt::AlignTop);
mainLayout->addLayout(gridLayout);
setLayout(mainLayout);
connect(fileController, &FileController::pathChanged, this,
[this, mainLayout](const std::filesystem::path path) {
[this, gridLayout](const std::filesystem::path path) {
// No, QT Does not offer a better way to clear a layout, at least this solution doesnt segfault
QLayoutItem* wItem;
while ((wItem = mainLayout->takeAt(0)) != 0) {
while ((wItem = gridLayout->takeAt(0)) != 0) {
if (wItem->widget( ))
wItem->widget( )->setParent(nullptr);
delete wItem;
}
gridMap.clear( );
});
connect(fileController, &FileController::contentChanged, this, [this, mainLayout](std::filesystem::path path, FileEvent event) {
connect(fileController, &FileController::contentChanged, this, [this, gridLayout](std::filesystem::path path, FileEvent event) {
if (event == FileEvent::created) {
auto w = new GridItem(path);
gridMap[path] = w;
connect(w, &GridItem::clicked, this, [this, path]( ) {
connect(w, &GridItem::doubleClicked, this, [this, path]( ) {
if (!std::filesystem::is_directory(path))
return;
emit fileController->updatePath(path);
});
connect(w, &GridItem::clicked, this, [this, path]( ) {
if (std::filesystem::is_directory(path))
return;
std::string cmd = "xdg-open \"" + path.string( ) + "\"";
std::system(cmd.c_str( ));
});
int pos = gridMap.size( ) - 1;
mainLayout->addWidget(w, pos / 8, pos % 8);
gridLayout->addWidget(w, pos / 8, pos % 8);
w->show( );
} else if (event == FileEvent::erased) {
mainLayout->removeWidget(gridMap[path]);
gridLayout->removeWidget(gridMap[path]);
delete gridMap[path];
gridMap.erase(path);
int pos = 0;
for (const auto& [key, widget] : gridMap) {
mainLayout->addWidget(widget, pos / 8, pos % 8);
gridLayout->addWidget(widget, pos / 8, pos % 8);
pos++;
}
} else if (event == FileEvent::modified) {
std::cout << "modified" << std::endl;
// Idk what this would be used for
}
});

View File

@@ -1,6 +1,8 @@
#pragma once
#include <QFrame>
#include <QScrollArea>
#include <cstdlib>
#include "../Widgets/GridItem/GridItem.hpp"
#include "../../Controller/FileController/FileController.hpp"

View File

@@ -1,16 +1,29 @@
#include "MainWidget.hpp"
#include <iostream>
MainWidget::MainWidget(QWidget* parent) {
auto path_mainContentLayout = new QVBoxLayout(this);
auto fileTree_fileGridLayout = new QHBoxLayout(this);
auto fileTree_fileGridLayout = new QHBoxLayout( );
auto gridLayout = new GridItemView( );
auto path = new Path( );
auto backButton = new QPushButton("<");
backButton->setFixedSize(40, 40);
auto pathBackLayout = new QHBoxLayout( );
pathBackLayout->addWidget(backButton);
pathBackLayout->addWidget(path);
auto fileController = FileController::instance( );
connect(backButton, &QPushButton::clicked, this, [fileController]( ) {
emit fileController->previousPath( );
});
auto gridLayout = new GridItemView(this);
auto path = new Path(this);
fileTree_fileGridLayout->addWidget(gridLayout);
path_mainContentLayout->addWidget(path);
path_mainContentLayout->addLayout(pathBackLayout);
path_mainContentLayout->addLayout(fileTree_fileGridLayout);
setLayout(path_mainContentLayout);

View File

@@ -4,6 +4,7 @@
#include <QLabel>
#include <QWidget>
#include <QGridLayout>
#include <QPushButton>
#include "../Widgets/GridItem/GridItem.hpp"
#include "../GridItemView/GridItemView.hpp"

View File

@@ -18,10 +18,10 @@ Path::Path(QWidget* parent)
border: 2px solid #414141;
border-radius: 6px;
color: #D8D8D8;
font-size: 20px;
font-size: 22px;
)");
setFixedHeight(40);
setFixedHeight(48);
connect(m_fileController, &FileController::pathChanged, this,
[this](const std::filesystem::path path) {

View File

@@ -6,10 +6,14 @@ GridItem::GridItem(const std::filesystem::path path, QWidget* parent)
m_path(path),
m_name(QString::fromStdString(path.filename( ).string( ))),
m_icon(getIconForFileType(path)) {
widgetSize = QSize(80, 128);
widgetSize = QSize(128, 128);
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setMinimumSize(widgetSize);
setMaximumSize(widgetSize);
setObjectName("gridItem");
setAttribute(Qt::WA_Hover);
auto vLayout = new QVBoxLayout(this);
vLayout->setSpacing(10);
@@ -17,7 +21,8 @@ GridItem::GridItem(const std::filesystem::path path, QWidget* parent)
m_iconLabel->setPixmap(m_icon.pixmap(widgetSize.width( ), widgetSize.height( )));
m_iconLabel->setAlignment(Qt::AlignCenter);
m_nameLabel = new QLabel(m_name, this);
m_nameLabel = new QLabel(this);
formatText(m_name);
m_nameLabel->setAlignment(Qt::AlignCenter);
m_nameLabel->setWordWrap(true);
@@ -27,26 +32,53 @@ GridItem::GridItem(const std::filesystem::path path, QWidget* parent)
GridItem::~GridItem( ) { }
QString GridItem::formatText(const QString& text) {
QFontMetrics fm(font( ));
QString elidedText = fm.elidedText(text, Qt::ElideRight, widgetSize.width( ));
QString result;
QStringList lines = elidedText.split('\n');
for (int i = 0; i < std::min((int)lines.size( ), 3); ++i)
result.append(lines.at(i)).append('\n');
void GridItem::formatText(const QString& text) {
QFontMetrics metrics(m_nameLabel->font( ));
QString elidedText = metrics.elidedText(text, Qt::ElideRight, m_nameLabel->width( ) * 3);
if (lines.size( ) > 3)
result.append("...");
QStringList lines = elidedText.split(' ');
QStringList finalText;
QString currentLine;
return result.trimmed( );
for (const QString& word : lines) {
QString testLine = currentLine.isEmpty( ) ? word : currentLine + ' ' + word;
if (metrics.horizontalAdvance(testLine) <= m_nameLabel->width( )) {
currentLine = testLine;
} else {
finalText.append(currentLine);
currentLine = word;
}
if (finalText.size( ) == 2 && currentLine.isEmpty( ) == false) {
currentLine += "...";
break;
}
}
if (!currentLine.isEmpty( ) && finalText.size( ) < 3) {
finalText.append(currentLine);
}
m_nameLabel->setText(finalText.join('\n'));
}
bool isImageFile(std::filesystem::path path) {
static const std::vector<std::string> imageExtensions = { ".png", ".jpg", ".jpeg", ".bmp", ".gif" };
return std::find(imageExtensions.begin( ), imageExtensions.end( ), path.extension( ).string( )) != imageExtensions.end( );
}
QIcon GridItem::getIconForFileType(const std::filesystem::path path) const {
if (!std::filesystem::is_directory(path)) {
QIcon icon;
if (isImageFile(path)) {
QPixmap pixmap(QString::fromStdString(path.string( )));
icon = QIcon(pixmap);
} else {
auto mdb = new QMimeDatabase( );
QMimeType mime_type = mdb->mimeTypeForFile(QString::fromStdString(path.string( )));
icon = QIcon::fromTheme(mime_type.iconName( ));
delete mdb;
}
if (!icon.isNull( )) {
QPixmap pixmap = icon.pixmap(QSize(64, 64));
@@ -82,6 +114,38 @@ void GridItem::paintEvent(QPaintEvent* event) {
void GridItem::mousePressEvent(QMouseEvent* event) {
if (event->button( ) == Qt::LeftButton) {
emit clicked( );
} else if (event->button( ) == Qt::RightButton) {
}
QWidget::mousePressEvent(event);
}
void GridItem::mouseDoubleClickEvent(QMouseEvent* event) {
if (event->button( ) == Qt::LeftButton) {
emit doubleClicked( );
}
QWidget::mousePressEvent(event);
}
void GridItem::enterEvent(QEnterEvent* event) {
setStyleSheet(R"(
#gridItem{
border: 2px solid #414141;
background-color: #00ACC1;
border-radius: 8px;
}
)");
QWidget::enterEvent(event);
}
void GridItem::leaveEvent(QEvent* event) {
setStyleSheet(R"(
#gridItem{
background-color: none;
border: 0px solid #414141;
border-radius: 8px;
}
)");
QWidget::leaveEvent(event);
}

View File

@@ -21,7 +21,7 @@ private:
QSize widgetSize;
QString formatText(const QString& text);
void formatText(const QString& text);
QIcon getIconForFileType(const std::filesystem::path path) const;
@@ -35,9 +35,13 @@ public:
void setIconSize(const QSize& size);
protected:
void paintEvent(QPaintEvent* event)override;
void paintEvent(QPaintEvent* event) override;
void mousePressEvent(QMouseEvent* event) override;
void mouseDoubleClickEvent(QMouseEvent*) override;
void enterEvent(QEnterEvent* event) override;
void leaveEvent(QEvent* event) override;
signals:
void clicked( );
void doubleClicked( );
};

View File

@@ -2,13 +2,12 @@
#include <QApplication>
#include <memory>
int main(int argc, char *argv[]) {
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
auto w = std::make_unique<MainWindow>();
auto w = std::make_unique<MainWindow>( );
w->setMinimumHeight(200);
w->show();
w->show( );
return app.exec();
return app.exec( );
}