Initial repo creation.
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
[submodule "interface"]
|
||||
path = interface
|
||||
url = https://git.teslos.co.uk/Triplehx3/TTK-Interface.git
|
||||
@@ -0,0 +1,17 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2026 Teslos
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should receive a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Teslos Tool Kit
|
||||
|
||||
A simple Qt6 / C++ systray tool that acts as a toolkit for applications loaded via plugins.
|
||||
|
||||
**Please note that you must have at least one TTK-Plugin installed for this toolkit to be of any use!**
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
git clone https://git.teslos.co.uk/Triplehx3/TTK-App.git
|
||||
cd TTK-App
|
||||
git submodule update --init --recursive
|
||||
mkdir build
|
||||
cd build
|
||||
qmake6 ..
|
||||
make
|
||||
```
|
||||
|
||||
Or simply open the TTK.pro file in the cloned directory inside Qt Creator.
|
||||
|
||||
Run the resulting executable from the build directory.
|
||||
|
||||
## License
|
||||
This project is licensed under the GNU General Public License v3.0 - see the [LICENSE](LICENSE) file for details.
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
TARGET = TTK
|
||||
|
||||
CONFIG(release, debug|release) {
|
||||
|
||||
} else {
|
||||
DEFINES += DEVMODE
|
||||
}
|
||||
|
||||
QMAKE_CXXFLAGS += -Wno-sfinae-incomplete
|
||||
|
||||
QT += widgets
|
||||
|
||||
HEADERS = interface/interface.h \
|
||||
plugindialog.h \
|
||||
window.h
|
||||
|
||||
SOURCES = main.cpp \
|
||||
plugindialog.cpp \
|
||||
window.cpp
|
||||
|
||||
RESOURCES = ttk.qrc
|
||||
|
||||
LIBS = -L../plugins
|
||||
@@ -0,0 +1,9 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Name=TTK
|
||||
Comment=A systray based toolkkit of mini but usefull applets.
|
||||
Exec=/usr/bin/TTK
|
||||
Icon=/usr/share/icons/hicolor/16x16/apps/TTK.png
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Utility;Development;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 819 B |
Submodule
+1
Submodule interface added at a60b998305
@@ -0,0 +1,14 @@
|
||||
#include "window.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
||||
|
||||
QApplication app(argc, argv);
|
||||
QApplication::setQuitOnLastWindowClosed(false);
|
||||
|
||||
Window window;
|
||||
return app.exec();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#include "plugindialog.h"
|
||||
#include "interface/interface.h"
|
||||
|
||||
PluginDialog::PluginDialog(const QString &path, const QStringList &fileNames,
|
||||
QWidget *parent) :
|
||||
QDialog(parent),
|
||||
label(new QLabel),
|
||||
treeWidget(new QTreeWidget),
|
||||
okButton(new QPushButton(tr("OK")))
|
||||
{
|
||||
treeWidget->setAlternatingRowColors(false);
|
||||
treeWidget->setSelectionMode(QAbstractItemView::NoSelection);
|
||||
treeWidget->setColumnCount(1);
|
||||
treeWidget->header()->hide();
|
||||
|
||||
okButton->setDefault(true);
|
||||
|
||||
connect(okButton, &QAbstractButton::clicked, this, &QWidget::close);
|
||||
|
||||
QGridLayout *mainLayout = new QGridLayout;
|
||||
mainLayout->setColumnStretch(0, 1);
|
||||
mainLayout->setColumnStretch(2, 1);
|
||||
mainLayout->addWidget(label, 0, 0, 1, 3);
|
||||
mainLayout->addWidget(treeWidget, 1, 0, 1, 3);
|
||||
mainLayout->addWidget(okButton, 2, 1);
|
||||
setLayout(mainLayout);
|
||||
|
||||
interfaceIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirOpenIcon),
|
||||
QIcon::Normal, QIcon::On);
|
||||
interfaceIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirClosedIcon),
|
||||
QIcon::Normal, QIcon::Off);
|
||||
featureIcon.addPixmap(style()->standardPixmap(QStyle::SP_FileIcon));
|
||||
|
||||
setWindowTitle(tr("Plugin Information"));
|
||||
findPlugins(path, fileNames);
|
||||
}
|
||||
|
||||
void PluginDialog::findPlugins(const QString &path,
|
||||
const QStringList &fileNames)
|
||||
{
|
||||
label->setText(tr("TTK found the following plugins\n"
|
||||
"(looked in %1):")
|
||||
.arg(QDir::toNativeSeparators(path)));
|
||||
|
||||
const QDir dir(path);
|
||||
|
||||
const auto staticInstances = QPluginLoader::staticInstances();
|
||||
for (QObject *plugin : staticInstances)
|
||||
populateTreeWidget(plugin, tr("%1 (Static Plugin)")
|
||||
.arg(plugin->metaObject()->className()));
|
||||
|
||||
for (const QString &fileName : fileNames) {
|
||||
QPluginLoader loader(dir.absoluteFilePath(fileName));
|
||||
QObject *plugin = loader.instance();
|
||||
if (plugin)
|
||||
populateTreeWidget(plugin, fileName);
|
||||
}
|
||||
}
|
||||
|
||||
void PluginDialog::populateTreeWidget(QObject *plugin, const QString &text)
|
||||
{
|
||||
auto pluginItem = new QTreeWidgetItem(treeWidget);
|
||||
pluginItem->setText(0, text);
|
||||
pluginItem->setExpanded(true);
|
||||
|
||||
QFont boldFont = pluginItem->font(0);
|
||||
boldFont.setBold(true);
|
||||
pluginItem->setFont(0, boldFont);
|
||||
|
||||
if (plugin) {
|
||||
auto iBrush = qobject_cast<Interface *>(plugin);
|
||||
if (iBrush)
|
||||
addItems(pluginItem, "About", iBrush->pdesc());
|
||||
}
|
||||
}
|
||||
|
||||
void PluginDialog::addItems(QTreeWidgetItem *pluginItem,
|
||||
const char *interfaceName,
|
||||
const QString &feature)
|
||||
{
|
||||
auto interfaceItem = new QTreeWidgetItem(pluginItem);
|
||||
interfaceItem->setText(0, interfaceName);
|
||||
interfaceItem->setIcon(0, interfaceIcon);
|
||||
|
||||
auto featureItem = new QTreeWidgetItem(interfaceItem);
|
||||
featureItem->setText(0, feature);
|
||||
featureItem->setIcon(0, featureIcon);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef PLUGINDIALOG_H
|
||||
#define PLUGINDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDir>
|
||||
#include <QGridLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QPluginLoader>
|
||||
#include <QPushButton>
|
||||
#include <QTreeWidget>
|
||||
|
||||
class PluginDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PluginDialog(const QString &path, const QStringList &fileNames,
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
private:
|
||||
void findPlugins(const QString &path, const QStringList &fileNames);
|
||||
void populateTreeWidget(QObject *plugin, const QString &text);
|
||||
void addItems(QTreeWidgetItem *pluginItem, const char *interfaceName,
|
||||
const QString &feature);
|
||||
|
||||
QLabel *label;
|
||||
QTreeWidget *treeWidget;
|
||||
QPushButton *okButton;
|
||||
QIcon interfaceIcon;
|
||||
QIcon featureIcon;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "settingsdialog.h"
|
||||
|
||||
settingsdialog::settingsdialog(QWidget *parent) :
|
||||
QDialog(parent)//,
|
||||
// label(new QLabel),
|
||||
// treeWidget(new QTreeWidget),
|
||||
// okButton(new QPushButton(tr("OK"))
|
||||
// )
|
||||
{
|
||||
// treeWidget->setAlternatingRowColors(false);
|
||||
// treeWidget->setSelectionMode(QAbstractItemView::NoSelection);
|
||||
// treeWidget->setColumnCount(1);
|
||||
// treeWidget->header()->hide();
|
||||
|
||||
// okButton->setDefault(true);
|
||||
|
||||
// connect(okButton, &QAbstractButton::clicked, this, &QWidget::close);
|
||||
|
||||
// QGridLayout *mainLayout = new QGridLayout;
|
||||
// mainLayout->setColumnStretch(0, 1);
|
||||
// mainLayout->setColumnStretch(2, 1);
|
||||
// mainLayout->addWidget(label, 0, 0, 1, 3);
|
||||
// mainLayout->addWidget(treeWidget, 1, 0, 1, 3);
|
||||
// mainLayout->addWidget(okButton, 2, 1);
|
||||
// setLayout(mainLayout);
|
||||
|
||||
// interfaceIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirOpenIcon),
|
||||
// QIcon::Normal, QIcon::On);
|
||||
// interfaceIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirClosedIcon),
|
||||
// QIcon::Normal, QIcon::Off);
|
||||
// featureIcon.addPixmap(style()->standardPixmap(QStyle::SP_FileIcon));
|
||||
|
||||
// setWindowTitle(tr("Plugin Information"));
|
||||
// findPlugins(path, fileNames);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef SETTINGSDIALOG_H
|
||||
#define SETTINGSDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class settingsdialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit settingsdialog(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
|
||||
};
|
||||
|
||||
#endif // SETTINGSDIALOG_H
|
||||
@@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>images/smile.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
#include "window.h"
|
||||
#include "interface/interface.h"
|
||||
#include "plugindialog.h"
|
||||
|
||||
Window::Window()
|
||||
{
|
||||
createActions();
|
||||
createTrayIcon();
|
||||
loadPlugins();
|
||||
setIcon();
|
||||
trayIcon->show();
|
||||
}
|
||||
|
||||
void Window::loadPlugins()
|
||||
{
|
||||
QString pluginPath = "";
|
||||
|
||||
#ifdef DEVMODE
|
||||
pluginPath = QCoreApplication::applicationDirPath() + "/plugins";
|
||||
#else
|
||||
pluginPath = "/usr/lib/ttk/plugins";
|
||||
#endif
|
||||
|
||||
pluginsDir = QDir(pluginPath);
|
||||
|
||||
const auto entryList = pluginsDir.entryList(QDir::Files);
|
||||
for (const QString &fileName : entryList) {
|
||||
|
||||
QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
|
||||
QObject *plugin = loader.instance();
|
||||
if (plugin) {
|
||||
|
||||
populateMenu(plugin);
|
||||
pluginFileNames += fileName;
|
||||
}
|
||||
}
|
||||
addtrayactions();
|
||||
}
|
||||
|
||||
void Window::changePlugin()
|
||||
{
|
||||
auto action = qobject_cast<QAction *>(sender());
|
||||
if (!action)
|
||||
return;
|
||||
|
||||
auto iPlugin = qobject_cast<Interface *>(action->parent());
|
||||
if (!iPlugin)
|
||||
return;
|
||||
|
||||
QWidget* output = new QWidget();
|
||||
output = iPlugin->pcontent();
|
||||
output->show();
|
||||
}
|
||||
|
||||
void Window::populateMenu(QObject *plugin)
|
||||
{
|
||||
|
||||
auto iPlugin = qobject_cast<Interface *>(plugin);
|
||||
if (iPlugin)
|
||||
|
||||
addToMenu(plugin, iPlugin->pname(), trayIconMenu, &Window::changePlugin);
|
||||
}
|
||||
|
||||
void Window::addToMenu(QObject *plugin, const QString &text,
|
||||
QMenu *menu, Member member)
|
||||
{
|
||||
auto action = new QAction(text, plugin);
|
||||
connect(action, &QAction::triggered, this, member);
|
||||
menu->addAction(action);
|
||||
}
|
||||
|
||||
void Window::setIcon()
|
||||
{
|
||||
QIcon icon = QIcon(":/images/smile.png");
|
||||
setWindowIcon(icon);
|
||||
trayIcon->setIcon(icon);
|
||||
trayIcon->setToolTip("TTK");
|
||||
}
|
||||
|
||||
|
||||
void Window::createActions()
|
||||
{
|
||||
quitAction = new QAction(tr("&Quit"), this);
|
||||
connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
|
||||
|
||||
aboutAct = new QAction(tr("&About"), this);
|
||||
connect(aboutAct, &QAction::triggered, this, &Window::about);
|
||||
|
||||
aboutQtAct = new QAction(tr("About &Qt"), this);
|
||||
connect(aboutQtAct, &QAction::triggered, qApp, &QApplication::aboutQt);
|
||||
|
||||
aboutPluginsAct = new QAction(tr("About &Plugins"), this);
|
||||
connect(aboutPluginsAct, &QAction::triggered, this, &Window::aboutPlugins);
|
||||
}
|
||||
|
||||
void Window::about()
|
||||
{
|
||||
QMessageBox::about(this, tr("About TTK"),
|
||||
tr("This is a wierd handy thing."));
|
||||
}
|
||||
|
||||
|
||||
void Window::aboutPlugins()
|
||||
{
|
||||
PluginDialog dialog(pluginsDir.path(), pluginFileNames, this);
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
void Window::addtrayactions()
|
||||
{
|
||||
trayIconMenu->addSeparator();
|
||||
trayIconMenu->addAction(aboutAct);
|
||||
trayIconMenu->addAction(aboutQtAct);
|
||||
trayIconMenu->addAction(aboutPluginsAct);
|
||||
trayIconMenu->addSeparator();
|
||||
trayIconMenu->addAction(quitAction);
|
||||
}
|
||||
|
||||
void Window::createTrayIcon()
|
||||
{
|
||||
trayIconMenu = new QMenu(this);
|
||||
trayIcon = new QSystemTrayIcon(this);
|
||||
trayIcon->setContextMenu(trayIconMenu);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef WINDOW_H
|
||||
#define WINDOW_H
|
||||
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QDialog>
|
||||
#include <QDir>
|
||||
#include <QMenu>
|
||||
#include <QApplication>
|
||||
#include <QCoreApplication>
|
||||
#include <QMessageBox>
|
||||
|
||||
|
||||
class Window : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Window();
|
||||
|
||||
private:
|
||||
void setIcon();
|
||||
void changePlugin();
|
||||
void about();
|
||||
void aboutPlugins();
|
||||
typedef void (Window::*Member)();
|
||||
void createActions();
|
||||
void createTrayIcon();
|
||||
void loadPlugins();
|
||||
void addtrayactions();
|
||||
void populateMenu(QObject *plugin);
|
||||
void addToMenu(QObject *plugin, const QString &text, QMenu *menu,Member member);
|
||||
|
||||
QAction *quitAction;
|
||||
QStringList pluginFileNames;
|
||||
QDir pluginsDir;
|
||||
QMenu *fileMenu;
|
||||
QMenu *helpMenu;
|
||||
QSystemTrayIcon *trayIcon;
|
||||
QMenu *trayIconMenu;
|
||||
QAction *exitAct;
|
||||
QAction *aboutAct;
|
||||
QAction *aboutQtAct;
|
||||
QAction *aboutPluginsAct;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user