qt GUI
Closed this issue · 3 comments
qt6/5 gui for starfetch, still in works
For now, only "random" and "help" is working. Still figuring out how to display HTML instead 033 ansi color text.
mainwindow.cpp
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <ctime>
#include <filesystem>
#include <regex>
#include <QApplication>
#include <QCompleter>
#include <QStringList>
#include <QColor>
#include <QPalette>
#include <QAbstractItemView>
#include <QRandomGenerator>
#include <QIcon>
#include "include/json.hpp"
#include "mainwindow.h"
#include "./ui_mainwindow.h"
using namespace std;
using json = nlohmann::json;
static inline void PrintConst(string &pathc); //formats the template file with the requested data and prints out the constellation info
static string RandomConst(); //select a random constellation from the available ones
static inline void PrintList(); //prints out the list of the available constellations
static void Error(string &err, int type); //shows an error message
static void Help(); //prints out the help message
/*#ifdef __APPLE__ //selection the right working path based on the OS type
string path = "/usr/local/opt/starfetch/res/";
#else
string path = "/usr/local/starfetch/res/";
#endif*/
#ifdef _WIN32
string path = "C:\\starfetch\\";
string SEP = "\\";
#else
string path = "/usr/local/share/starfetch/";
string SEP = "/";
#endif // _WIN32
static QString oldText = "";
static QStringList wordList = {
"help", "random", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", ""
};
static QCompleter *completer = new QCompleter(wordList, nullptr);
Ui::MainWindow *UI;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
UI = ui;
QPalette p = ui->textEdit->palette();
p.setColor(QPalette::Base, Qt::black);
p.setColor(QPalette::Text, Qt::green);
ui->textEdit->setPalette(p);
ui->textEdit->setText(static_cast<QString>("Type 'help' to see the available constellations"));
ui->lineEdit->setCompleter(completer);
completer->popup()->setStyleSheet("background-color:rgb(54, 57, 63); color:white;");
ui->lineEdit->setClearButtonEnabled(true);
ui->lineEdit->addAction(static_cast<QIcon>("media/linux.png"), QLineEdit::LeadingPosition);
connect(ui->lineEdit, &QLineEdit::returnPressed, this, &MainWindow::on_pushButton_clicked);
}
MainWindow::~MainWindow()
{
delete completer;
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
std::string pathc = path; //path to the constellation file
std::string userInput = static_cast<std::string>(ui->lineEdit->text().toStdString());
if (userInput.empty())
{
return;
}
if(userInput == "random") //if there's no additional arguments
{
pathc += RandomConst(); //selects a random constellation
}
else if (userInput == "h" || userInput == "help")
{
Help();
return;
}
else if (userInput.find("select ") != std::string::npos)
{
pathc += "constellations" + SEP; //updating the path to the constellations folder
string subStr = std::regex_replace(userInput, std::regex("select "), "");
pathc += subStr; //adding the name of the requested constellation to the path
pathc += ".json";
}
else if (userInput == "l" || userInput == "list")
{
PrintList();
return;
}
else
{
Error(userInput, 1); //if the reqeusted option isn't recognized, an error occours
return;
}
PrintConst(pathc); //prints the constellation
ui->lineEdit->setText(static_cast<QString>(""));
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
static inline void PrintConst(string &pathc)
{
ifstream c(pathc); //opens the file containing constellation info
ifstream f(path+"template"); //opens the output template file
stringstream strStream;
string s, l;
json j;
if(f.is_open())
{
strStream << f.rdbuf(); //read the template
s = strStream.str(); //converts it to a string
replace(s.begin(), s.end(), '^', '\033'); //replace '^' with the '\e' to print bold/colored text
f.close(); //closes the template
}
if(c.is_open())
{
c >> j; //parse the selected JSON file
//fills the template with dats
s.replace(s.find("%0"), string("%0").size(), j["title"].get<string>());
s.replace(s.find("%11"), string("%11").size(), j["name"].get<string>());
s.replace(s.find("%12"), string("%12").size(), j["quadrant"].get<string>());
s.replace(s.find("%13"), string("%13").size(), j["right ascension"].get<string>());
s.replace(s.find("%14"), string("%14").size(), j["declination"].get<string>());
s.replace(s.find("%15"), string("%15").size(), j["area"].get<string>());
s.replace(s.find("%16"), string("%16").size(), j["main stars"].get<string>());
//renders the constellation's graph from the coordinates specified in the JSON file
for(int i=1;i<=10;i++) //for each of the lines (10)
{
l="";
for(int k=1;k<=22;k++) //for each of the columns of the graph (22)
//if the JSON file specifies a star at position k
if(j["graph"]["line"+to_string(i)].find(to_string(k)) != j["graph"]["line"+to_string(i)].end())
l+=j["graph"]["line"+to_string(i)][to_string(k)].get<string>(); //put the star (which is stored into the JSON fine, might change this in the future)
else
l+=" "; //put a space
//insert the line into the template
s.replace(s.find("%"+to_string(i)), string("%"+to_string(i)).size(), l);
}
c.close();
UI->textEdit->setText(static_cast<QString>(s.c_str())); //prints the output
}
else
{
//Error(static_cast<string>(""), 2);
}
}
static string RandomConst()
{
size_t pos;
string s;
//SHOULD BE IMPROVED IN THE FUTURE
//gets every constellation name in the "constellation/" directory, and exits when two randomly generated numbers are equal, resulting in picking a random file
for (const auto & entry : filesystem::directory_iterator(path+"constellations" + SEP))
{
pos = entry.path().u8string().find("constellations" + SEP);
s = entry.path().u8string().substr(pos);
if(s != "constellations/.DS_Store" && QRandomGenerator::global()->bounded(0, 11) == QRandomGenerator::global()->bounded(0, 11))
break;
}
return s;
}
static inline void PrintList()
{
string s;
oldText = "";
QString outStr = static_cast<string>("✦ \e[1;37mavailable constellations\e[0m: ").c_str();
UI->textEdit->setText(outStr + oldText + static_cast<QString>("\n"));
//prints every constellation name from the files name in the "constellations/" directory
for (const auto & entry : filesystem::directory_iterator(path+"constellations" + SEP))
{
s = entry.path().u8string().substr(entry.path().u8string().find("constellations" + SEP)+15); //from "/usr/local/opt/starfetch/res/constellations/xxxxxx" to "xxxxxx"
s = s.substr(0, s.length()-5);
if(s != ".DS_")
{
oldText += static_cast<QString>(s.c_str()) + static_cast<QString>("\n");
UI->textEdit->setText(outStr + oldText);
}
}
oldText = "";
}
static void Error(string &err, int code)
{
switch(code) //each error has a specific code
{
case 0: //0 for the missing input
UI->textEdit->setText(static_cast<QString>("Error: you must input a constellation name after -n."));
break;
case 1: //1 for the invalid argument
UI->textEdit->setText(static_cast<QString>(static_cast<string>("Error: '" + err + "' isn't a valid argument.").c_str()));
break;
case 2: //2 for the invalid constellation name
UI->textEdit->setText(static_cast<QString>("Error: the constellation you asked for isn't recognized."));
break;
}
Help(); //after any error occours, the help message is shown
}
static void Help()
{
std::ostringstream ss;
ifstream f(path + "help_message.txt");
ss << f.rdbuf();
string str = ss.str();
UI->textEdit->setText(static_cast<QString>(str.c_str()));
f.close();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(starfetch 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 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_THREAD_LIBS_INIT "-lpthread")
set(CMAKE_HAVE_THREADS_LIBRARY 1)
set(CMAKE_USE_WIN32_THREADS_INIT 0)
set(CMAKE_USE_PTHREADS_INIT 1)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
set(PROJECT_SOURCES
mainwindow.cpp
mainwindow.h
mainwindow.ui
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(starfetch
MANUAL_FINALIZATION
${PROJECT_SOURCES}
)
else()
if(ANDROID)
add_library(starfetch SHARED
${PROJECT_SOURCES}
)
else()
add_executable(starfetch
${PROJECT_SOURCES}
)
endif()
endif()
target_link_libraries(starfetch PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
set_target_properties(starfetch 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}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
install(TARGETS starfetch
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(starfetch)
endif()
mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>hackzyGUI</string>
</property>
<property name="windowIcon">
<iconset>
<normaloff>media/icon.xpm</normaloff>media/icon.xpm</iconset>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QLineEdit" name="lineEdit">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>411</width>
<height>41</height>
</rect>
</property>
<property name="placeholderText">
<string extracomment="Type here">Ask me anything...</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>412</x>
<y>0</y>
<width>391</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string>Okay</string>
</property>
<property name="autoDefault">
<bool>true</bool>
</property>
<property name="default">
<bool>false</bool>
</property>
</widget>
<widget class="QTextEdit" name="textEdit">
<property name="geometry">
<rect>
<x>0</x>
<y>40</y>
<width>811</width>
<height>571</height>
</rect>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>
media/icon.xpm
/* XPM */
static char *pdf2img_c_icon_xpm[] = {"24 24 124 2"," c None",". c #484848","+ c #505050","@ c #818181","# c #4E4E4E","$ c #484848","% c #505050","& c #3D3D3E","* c #494949","= c #808080","- c #575757","; c #383839","> c #828282",", c #4E4E4E","' c #494949",") c #464646","! c #4A4A4A","~ c #4C4C4C","{ c #505050","] c #4E4E4E","^ c #F9C940","/ c #4B4B4B","( c #F8C73D","_ c #494949",": c #4D4D4D","< c #515151","[ c #525252","} c #535353","| c #818181","1 c #545454","2 c #FACA42","3 c #F8C73E","4 c #F8C83E","5 c #F7C63C","6 c #58554C","7 c #373838","8 c #4F4F4F","9 c #59564D","0 c #484848","a c #383839","b c #373738","c c #3F3F3F","d c #39393A","e c #F6C335","f c #FACB43","g c #565656","h c #F6C438","i c #8E7D49","j c #575757","k c #8D7B47","l c #C2A041","m c #363637","n c #F7C73C","o c #383838","p c #8D7B48","q c #404141","r c #FCCE48","s c #FBCC45","t c #474747","u c #F6C333","v c #C4A346","w c #828282","x c #907F4D","y c #F2C749","z c #FCCD47","A c #FBCC44","B c #363738","C c #F9C93F","D c #F9CA40","E c #3A3B3B","F c #F7C63B","G c #EBB82A","H c #8B763A","I c #F7C53B","J c #F6C232","K c #6F664D","L c #DBB547","M c #F9CA41","N c #F8C83F","O c #F7C53A","P c #F6C437","Q c #D6AC36","R c #6B6145","S c #C3A243","T c #C2A142","U c #8D7A46","V c #F6C43A","W c #F6C439","X c #565249","Y c #F6C029","Z c #827349","` c #F8C93F"," . c #806F41",".. c #B89A44","+. c #E2B63D","@. c #E1B53B","#. c #F6C12E","$. c #B59334","%. c #555555","&. c #464646","*. c #B58F25","=. c #FDD04A","-. c #3E3F3F",";. c #615A49",">. c #5E5742",",. c #746438","'. c #414142","). c #BDA24F","!. c #F5BD1C","~. c #EAB41A","{. c #7F6C36","]. c #FED24C","^. c #766A47","/. c #7F6E3D","(. c #EAB621","_. c #817247",":. c #ECBE3D","<. c #817146","[. c #EDC03E","}. c #B79841","|. c #56534A","1. c #56524A","2. c #B6953A","3. c #F5C029"," j g %.1 } } [ < { + # ] : ~ ~ > ","j g %.%.1 } [ [ < { { + # ] ] : ~ ~ w @ ","g %.%.%.1 } [ [ < { { { ] ] ] : ~ ~ w | @ ","%.%.%.1 } } [ [ { { { 8 ] ] ] : ~ ~ w | | @ ","1 1 1 } } [ [ < { { { 9 9 ] ] : ~ ~ w | | | @ ","} } } } [ [ [ { { { { p k ] : ~ ~ ~ | | | | | = ","} [ [ [ [ [ { { { { 8 S T ] : ~ ~ ~ '.E d 7 b m ","[ [ [ [ < { { { { 8 9 ` n 6 ~ ~ ~ / / q d o b B ","< < < { { { { { 8 ] i D ( U ~ ~ ~ / / ! c a 7 7 ","{ { { { { { { 8 ] ] v ^ ( l ~ ~ / / / ! _ -.a a ","+ { { { { ).].=.r s f ^ 3 F W u Y !.*.! _ _ c ; "," + { 8 ] ] x y z A 2 C ( I h J G H ! _ _ _ * "," # ] ] ] ] ] K L f M N ( O P Q R ! _ _ _ _ . ","# ] ] ] ] ] ] ] 6 2 ^ 3 5 V e X ! ! _ _ _ _ 0 . ","] ] ] ] ] : : ~ Z ^ 4 ( I h J .! _ _ _ _ 0 0 0 ",": : : : : ~ ~ ~ ..4 ( +.@.e #.$._ _ _ _ 0 0 0 0 ","~ ~ ~ ~ ~ ~ ~ ~ [.5 }.|.1.2.3.(._ _ _ _ 0 0 0 0 ","~ ~ ~ ~ ~ ~ ~ _.:.<./ / ! ! /.~.{._ _ 0 0 0 0 t ","~ ~ ~ ~ / / / ^.;./ ! ! _ _ _ >.,._ 0 0 0 0 t t ","/ / / / / / / / ! ! ! _ _ _ _ _ _ 0 0 0 0 t t t ","/ / / / / ! ! ! _ _ _ _ _ _ _ 0 0 0 0 0 t t t t ","! ! ! ! ! _ _ _ _ _ _ _ _ _ 0 0 0 0 0 t t t t t ","_ _ _ _ _ _ _ _ _ _ _ * . 0 0 0 0 0 t t t t t &."," _ _ _ _ _ _ _ _ _ . . 0 0 0 t t t t t &. "};
Oh, wow!
I'm not very familiar with graphics environments and Qt, but I understand this makes starfetch render the constellations in a separate windows, right? That's an incredible work!
I need to thank you for the commitment and effort your putting in starfetch! 🙏🏻
I think it would be great to have also a GUI version of starfetch in addition to the CLI one!
I understand this makes starfetch render the constellations in a separate windows, right?
It renders everything in one window, graphical one. :}
It renders everything in one window, graphical one. :}
That's even cooler! :)