From 8ca1ee831a70f1539b13ac865a541b610b1f24b8 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 11 Nov 2026 17:18:15 +0000 Subject: [PATCH] Initial repo creation. --- .gitmodules | 3 ++ LICENSE | 17 +++++++ README.md | 24 +++++++++ TTK-App.pro | 23 +++++++++ TTK.desktop | 9 ++++ images/smile.png | Bin 0 -> 819 bytes interface | 1 + main.cpp | 14 +++++ plugindialog.cpp | 88 ++++++++++++++++++++++++++++++++ plugindialog.h | 34 +++++++++++++ settingsdialog.cpp | 35 +++++++++++++ settingsdialog.h | 16 ++++++ ttk.qrc | 5 ++ window.cpp | 124 +++++++++++++++++++++++++++++++++++++++++++++ window.h | 46 +++++++++++++++++ 15 files changed, 439 insertions(+) create mode 100644 .gitmodules create mode 100644 LICENSE create mode 100644 README.md create mode 100644 TTK-App.pro create mode 100644 TTK.desktop create mode 100644 images/smile.png create mode 160000 interface create mode 100644 main.cpp create mode 100644 plugindialog.cpp create mode 100644 plugindialog.h create mode 100644 settingsdialog.cpp create mode 100644 settingsdialog.h create mode 100644 ttk.qrc create mode 100644 window.cpp create mode 100644 window.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..f2caaa0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "interface"] + path = interface + url = https://git.teslos.co.uk/Triplehx3/TTK-Interface.git diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3a63ecb --- /dev/null +++ b/LICENSE @@ -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 . \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4eb6258 --- /dev/null +++ b/README.md @@ -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. \ No newline at end of file diff --git a/TTK-App.pro b/TTK-App.pro new file mode 100644 index 0000000..12583cd --- /dev/null +++ b/TTK-App.pro @@ -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 diff --git a/TTK.desktop b/TTK.desktop new file mode 100644 index 0000000..60fe284 --- /dev/null +++ b/TTK.desktop @@ -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; \ No newline at end of file diff --git a/images/smile.png b/images/smile.png new file mode 100644 index 0000000000000000000000000000000000000000..0852619f749ea5e5093e5b0369d49cdec1033b1b GIT binary patch literal 819 zcmV-31I+x1P)P}sixAXME8Jv~Ey{)MTO_WG7PjgUw5V062o^*T8H8k1U_y%aLuw_4WlC5* z)BG9d&EK8dxi2xPWdoP<-OKsD^PMw?2_f)5U&`MPZWq&iAI*Z}DCamx7=%X%_ffnW zX%WWee74yEk;{FKE@gj3K8sdB1a|?x2Y+=2-rNw(q5f$SYKpdsXa5MeovhB!j^0xX zk3)nr;V!=hH-ADnHf05%>V;so0&}bn=G3zz%uq{z&p;E-}TsO$cp2C<|RHO>^)~p_=(M6E*Od>lbI<73y#UpDTy4wj_ z7TowWTyqlP@*17HXqMch0IAiooN91mf~r~YiP&^5kc`6f(0In8A~XxjhWm8_TC`Yd z*KQUlLMV$YFA>QllKY!%6D9{fCHM}fcMiU`MvR0smcJoDlTQd|6`*Q2VjuA4`Hv(~ z5`21-cyuIz_HH971{xUmq5ctYF%5f#P%0Wu@4(RDGTyx)H!e9K!q}?>hQ}S$S8GsI z4cygWCoq*uhNj7t{^olAFH!d zpmFp{E=x;G!}J9!lL~#xIN73eYaHI#Sk_^TUh6O%7X@_> z1M`YySuFb^7Ayy6SB7s>f4NA>EQOMyQ~x6Q|J7g!X?gqLhs*Hg$s^b{nvV5|dAUPO zwxMa-R*I4HWnSf}BGI<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(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); +} diff --git a/plugindialog.h b/plugindialog.h new file mode 100644 index 0000000..ae9bae5 --- /dev/null +++ b/plugindialog.h @@ -0,0 +1,34 @@ +#ifndef PLUGINDIALOG_H +#define PLUGINDIALOG_H + +#include +#include +#include +#include +#include +#include +#include +#include + +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 diff --git a/settingsdialog.cpp b/settingsdialog.cpp new file mode 100644 index 0000000..969ab5f --- /dev/null +++ b/settingsdialog.cpp @@ -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); +} diff --git a/settingsdialog.h b/settingsdialog.h new file mode 100644 index 0000000..0a2253c --- /dev/null +++ b/settingsdialog.h @@ -0,0 +1,16 @@ +#ifndef SETTINGSDIALOG_H +#define SETTINGSDIALOG_H + +#include + +class settingsdialog : public QDialog +{ + Q_OBJECT +public: + explicit settingsdialog(QWidget *parent = nullptr); + +signals: + +}; + +#endif // SETTINGSDIALOG_H diff --git a/ttk.qrc b/ttk.qrc new file mode 100644 index 0000000..d005968 --- /dev/null +++ b/ttk.qrc @@ -0,0 +1,5 @@ + + + images/smile.png + + diff --git a/window.cpp b/window.cpp new file mode 100644 index 0000000..b9ad2ee --- /dev/null +++ b/window.cpp @@ -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(sender()); + if (!action) + return; + + auto iPlugin = qobject_cast(action->parent()); + if (!iPlugin) + return; + + QWidget* output = new QWidget(); + output = iPlugin->pcontent(); + output->show(); +} + +void Window::populateMenu(QObject *plugin) +{ + + auto iPlugin = qobject_cast(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); +} diff --git a/window.h b/window.h new file mode 100644 index 0000000..5fc05eb --- /dev/null +++ b/window.h @@ -0,0 +1,46 @@ +#ifndef WINDOW_H +#define WINDOW_H + +#include +#include +#include +#include +#include +#include +#include + + +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