Browse Source

initial commit

master
Amélia Liao 3 years ago
commit
c602bea0ae
8 changed files with 428 additions and 0 deletions
  1. +75
    -0
      .gitignore
  2. +54
    -0
      CMakeLists.txt
  3. +22
    -0
      README.md
  4. +6
    -0
      qml.qrc
  5. +35
    -0
      src/clipboard.hpp
  6. +53
    -0
      src/main.cpp
  7. +144
    -0
      src/main.qml
  8. +39
    -0
      src/widgets/Reaction.qml

+ 75
- 0
.gitignore View File

@ -0,0 +1,75 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe
build
.vscode

+ 54
- 0
CMakeLists.txt View File

@ -0,0 +1,54 @@
cmake_minimum_required(VERSION 3.14)
project(reactionmanager VERSION 0.1 LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Quick REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Quick REQUIRED)
set(PROJECT_SOURCES
src/main.cpp
src/clipboard.hpp
qml.qrc
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(reactionmanager
MANUAL_FINALIZATION
${PROJECT_SOURCES}
)
else()
if(ANDROID)
add_library(reactionmanager SHARED
${PROJECT_SOURCES}
)
else()
add_executable(reactionmanager
${PROJECT_SOURCES}
)
endif()
endif()
target_compile_definitions(reactionmanager
PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
target_link_libraries(reactionmanager
PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Quick)
set_target_properties(reactionmanager PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
)
if(QT_VERSION_MAJOR EQUAL 6)
qt_import_qml_plugins(reactionmanager)
qt_finalize_executable(reactionmanager)
endif()

+ 22
- 0
README.md View File

@ -0,0 +1,22 @@
reactionmanager
===============
don't use this lol
Building
--------
```sh
mkdir -p build; cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make
```
Usage
-----
```
reactionmanager path/to/directory
```
all of the files need to be in the same level of the directory hierarchy so if you like to organise things you're screwed

+ 6
- 0
qml.qrc View File

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>src/main.qml</file>
<file>src/widgets/Reaction.qml</file>
</qresource>
</RCC>

+ 35
- 0
src/clipboard.hpp View File

@ -0,0 +1,35 @@
#pragma once
#include <QClipboard>
#include <QObject>
#include <QImage>
#include <QUrl>
#include <QProcess>
#include <iostream>
#include <QGuiApplication>
class Clipboard : public QObject {
Q_OBJECT
public:
Clipboard(QGuiApplication *owner, const char *app) : _app(app), _owner(owner) { }
virtual ~Clipboard() {};
Q_INVOKABLE void setClipboard(QUrl str) {
QProcess proc;
proc.setProgram(QString(_app));
QStringList args{"clipboard", str.path()};
proc.setArguments(args);
qint64 pid;
proc.startDetached(&pid);
std::cout << "clipboard owner " << _app << " started: " << pid << std::endl;
_owner->quit();
}
private:
const char *_app;
QGuiApplication *_owner;
};

+ 53
- 0
src/main.cpp View File

@ -0,0 +1,53 @@
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <qqmlcontext.h>
#include <QClipboard>
#include "sys/stat.h"
#include "clipboard.hpp"
int selection(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/src/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
engine.rootContext()->setContextProperty("clipboard", new Clipboard(&app, argv[0]));
return app.exec();
}
int clipboard(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QClipboard *clip = QGuiApplication::clipboard();
struct stat buf;
if (stat(argv[2], &buf) == -1) {
perror("stat");
exit(1);
}
QString path(argv[2]);
QImage image(path);
clip->setImage(image);
clip->connect(clip, &QClipboard::dataChanged, [&]() {
app.quit();
});
return app.exec();
}
int main(int argc, char *argv[]) {
if (argc >= 3 && strcmp(argv[1], "clipboard") == 0) {
return clipboard(argc, argv);
} else {
return selection(argc, argv);
}
}

+ 144
- 0
src/main.qml View File

@ -0,0 +1,144 @@
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.3
import Qt.labs.folderlistmodel 2.15
import QtQml.Models 2.15
import "qrc:/src/widgets"
Window {
width: 700
height: 500
visible: true
title: qsTr("reaction image manager")
flags: Qt.Dialog
id: window;
Component {
id: delegate
Item {
width: imageList.cellWidth
height: imageList.cellHeight
clip: true
Column {
anchors.fill: parent
Reaction {
anchors.horizontalCenter: parent.horizontalCenter
path: fileUrl
width: Math.min(parent.width, parent.height) - label.height
height: Math.min(parent.width, parent.height) - label.height
}
Text {
id: label
anchors.horizontalCenter: parent.horizontalCenter
text: fileName
}
}
}
}
Column {
anchors.fill: parent
TextField {
id: text
placeholderText: qsTr("Search")
focus: true
height: 40
width: parent.width
onTextChanged: () => {
backingModel.nameFilters = makeFilter(text.text)
imageList.currentIndex = 0
imageList.moveCurrentIndexRight()
}
Keys.onPressed: {
if (event.key == Qt.Key_Tab || event.key == Qt.Key_Right) {
event.accepted = true
imageList.moveCurrentIndexRight()
} else if (event.key == Qt.Key_Up) {
event.accepted = true
imageList.moveCurrentIndexUp()
} else if (event.key == Qt.Key_Down) {
event.accepted = true
imageList.moveCurrentIndexDown()
} else if (event.key == Qt.Key_Left) {
event.accepted = true
imageList.moveCurrentIndexLeft()
} else if (event.key == Qt.Key_Escape) {
Qt.quit()
}
}
onAccepted: {
clipboard.setClipboard(backingModel.get(imageList.currentIndex, 'fileUrl') || backingModel.get(0, 'fileUrl'));
}
}
Row {
width: parent.width
height: parent.height - 40
Rectangle {
width: 2 * (parent.width / 3)
height: parent.height
GridView {
id: imageList
anchors.fill: parent
clip: true
keyNavigationWraps: true
flickableDirection: Flickable.AutoFlickDirection
cellWidth: parent.width / 3;
cellHeight: imageList.cellWidth
snapMode: GridView.SnapToRow
model: FolderListModel {
id: backingModel
nameFilters: makeFilter("")
folder: "file:" + Qt.application.arguments[1]
}
delegate: delegate
highlight: Rectangle {
color: "lightsteelblue"
radius: 5
}
}
}
Reaction {
width: parent.width / 3
height: parent.height
path: backingModel.get(imageList.currentIndex, 'fileUrl') || backingModel.get(0, 'fileUrl')
}
}
}
function makeFilter(text) {
if (text.indexOf("*") !== -1) {
return [text]
}
return [
"*" + text + "*.png",
"*" + text + "*.gif",
"*" + text + "*.jpg",
"*" + text + "*.jpeg",
]
}
}

+ 39
- 0
src/widgets/Reaction.qml View File

@ -0,0 +1,39 @@
import QtQuick 2.15
Item {
id: container
property alias path: image.source
MouseArea {
id: mouseArea
width: container.width; height: container.height
anchors.fill: container;
drag.target: image;
AnimatedImage {
id: image
anchors.fill: parent
fillMode: Image.PreserveAspectFit
Drag.active: mouseArea.drag.active
Drag.hotSpot.x: 0
Drag.hotSpot.y: 0
Drag.mimeData: {
"text/uri-list": container.path
}
Drag.dragType: Drag.Automatic
Drag.onDragFinished: {
Qt.quit()
}
onStatusChanged: {
if (image.status === Image.Failed) {
container.visible = false
}
}
}
}
}

Loading…
Cancel
Save