1 // Copyright (C) 2020 by Yuri Victorovich. All rights reserved.
2 
3 #include "util.h"
4 #include "misc.h"
5 
6 #include <QApplication>
7 #include <QScreen>
8 #include <QCursor>
9 #include <QString>
10 #include <QMessageBox>
11 #include <QFile>
12 #include <QPixmap>
13 #include <QGuiApplication>
14 #include <QWindow>
15 #include <QStringList>
16 #include <QImage>
17 #include <QByteArray>
18 #include <QSize>
19 #include <QPainter>
20 #include <QSvgRenderer>
21 #include <QComboBox>
22 
23 #include <limits>
24 #include <cstring>
25 #include <memory>
26 
27 #include <unistd.h> // sleep,readlink
28 #include <sys/stat.h>
29 #include <assert.h>
30 
31 namespace Util {
32 
QStringToStlString(const QString & qs)33 std::string QStringToStlString(const QString &qs) {
34 	return std::string(qs.toUtf8().constData());
35 }
36 
warningOk(QWidget * parent,const QString & msg)37 bool warningOk(QWidget *parent, const QString &msg) {
38   QMessageBox::warning(parent, "Warning", msg, QMessageBox::Ok);
39   return false; // for convenience of callers
40 }
41 
getScreenDPI()42 float getScreenDPI() {
43 	static float dpi = QApplication::screens().at(0)->logicalDotsPerInch();
44 	return dpi;
45 }
46 
getGlobalMousePos()47 QPoint getGlobalMousePos() {
48 	return QCursor::pos(QApplication::screens().at(0));
49 }
50 
formatUIntHumanReadable(size_t u)51 std::string formatUIntHumanReadable(size_t u) {
52 	if (u <= 999)
53 		return STR(u);
54 	else {
55 		auto ddd = STR(u%1000);
56 		while (ddd.size() < 3)
57 			ddd = std::string("0")+ddd;
58 		return STR(formatUIntHumanReadable(u/1000) << "," << ddd);
59 	}
60 }
61 
formatUIntHumanReadableSuffixed(size_t u)62 std::string formatUIntHumanReadableSuffixed(size_t u) {
63 	auto one = [](size_t u, size_t degree, char chr) {
64 		auto du = u/degree;
65 		if (du >= 10)
66 			return STR(formatUIntHumanReadable(du) << ' ' << chr);
67 		else
68 			return STR(formatUIntHumanReadable(du) << '.' << (u%degree)/(degree/10) << ' ' << chr);
69 	};
70 	if (u >= 1000000000000) // in Tera-range
71 		return one(u, 1000000000000, 'T');
72 	if (u >= 1000000000) // in Giga-range
73 		return one(u, 1000000000, 'G');
74 	else if (u >= 1000000) // in Mega-range
75 		return one(u, 1000000, 'M');
76 	else if (u >= 1000) // in kilo-range
77 		return one(u, 1000, 'k');
78 	return STR(u << ' '); // because it is followed by the unit name
79 
80 }
81 
formatFlops(size_t flops)82 std::string formatFlops(size_t flops) {
83 	return STR(formatUIntHumanReadableSuffixed(flops) << "flops");
84 }
85 
copyFpArray(const float * a,size_t sz)86 float* copyFpArray(const float *a, size_t sz) {
87 	auto n = new float[sz];
88 	std::memcpy(n, a, sz*sizeof(float));
89 	return n;
90 }
91 
getFileSize(const QString & fileName)92 size_t getFileSize(const QString &fileName) {
93 	size_t size = 0;
94 	QFile file(fileName);
95 	if (file.open(QIODevice::ReadOnly)) {
96 		size = file.size();
97 		file.close();
98 	}
99 	return size;
100 }
101 
getScreenshot(bool hideOurWindows)102 QPixmap getScreenshot(bool hideOurWindows) {
103 	QScreen *screen = QGuiApplication::primaryScreen();
104 
105 	std::vector<QWidget*> windowsToHide = hideOurWindows ? std::vector<QWidget*>{QApplication::activeWindow()} : std::vector<QWidget*>{};
106 	for (auto w : windowsToHide)
107 		w->hide();
108 
109 	QApplication::beep(); // ha ha
110 
111 	if (!windowsToHide.empty()) {
112 		QCoreApplication::processEvents();
113 		::sleep(1); // without this sleep screen doesn't have enough time to hide our window when complex windows are behind (like a browser)
114 	}
115 
116 	auto pixmap = screen->grabWindow(0);
117 
118 	for (auto w : windowsToHide)
119 		w->show();
120 
121 	return pixmap;
122 }
123 
convertArrayFloatToUInt8(const float * a,size_t size)124 unsigned char* convertArrayFloatToUInt8(const float *a, size_t size) { // ASSUME that a is normalized to 0..255
125 	std::unique_ptr<unsigned char> cc(new unsigned char[size]);
126 
127 	auto c = cc.get();
128 	for (const float *ae = a+size; a<ae; )
129 		*c++ = *a++;
130 
131 	return cc.release();
132 }
133 
doesFileExist(const char * filePath)134 bool doesFileExist(const char *filePath) {
135 	struct stat s;
136 	return ::stat(filePath, &s)==0 && (s.st_mode&S_IFREG);
137 }
138 
readListFromFile(const char * fileName)139 QStringList readListFromFile(const char *fileName) {
140 	QString data;
141 	QFile file(fileName);
142 	if (!file.open(QIODevice::ReadOnly))
143 		FAIL("failed to open the file " << fileName)
144 	data = file.readAll();
145 	file.close();
146 	return data.split("\n", QString::SkipEmptyParts);
147 }
148 
getMyOwnExecutablePath()149 std::string getMyOwnExecutablePath() {
150 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__)
151 	const char* selfExeLink = "/proc/curproc/file";
152 #elif defined(__linux__)
153 	const char* selfExeLink = "/proc/self/exe";
154 #else
155 #  error "Your OS is not yet supported"
156 #endif
157 
158 	char buf[PATH_MAX+1];
159 	auto res = ::readlink(selfExeLink, buf, sizeof(buf) - 1);
160 	if (res == -1)
161 		FAIL("Failed to read the link " << selfExeLink << " to determine our executable path")
162 	buf[res] = 0;
163 
164 	return buf;
165 }
166 
svgToImage(const QByteArray & svgContent,const QSize & size,QPainter::CompositionMode mode)167 QImage svgToImage(const QByteArray& svgContent, const QSize& size, QPainter::CompositionMode mode) {
168 	QImage image(size.width(), size.height(), QImage::Format_ARGB32);
169 
170 	QPainter painter(&image);
171 	painter.setCompositionMode(mode);
172 	image.fill(Qt::transparent);
173 	QSvgRenderer(svgContent).render(&painter);
174 
175 	return image;
176 }
177 
selectComboBoxItemWithItemData(QComboBox & comboBox,int value)178 void selectComboBoxItemWithItemData(QComboBox &comboBox, int value) {
179 	for (unsigned i=0, ie=comboBox.count(); i<ie; i++)
180 		if (comboBox.itemData(i).toInt() == value) {
181 			comboBox.setCurrentIndex(i);
182 			return;
183 		}
184 	assert(false); // item with itemData=value not found
185 }
186 
setWidgetColor(QWidget * widget,const char * color)187 void setWidgetColor(QWidget *widget, const char *color) {
188 	widget->setStyleSheet(S2Q(STR("color: " << color)));
189 }
190 
charToSubscript(char ch)191 std::string charToSubscript(char ch) {
192 	switch (ch) {
193 	case '0': return STR("₀");
194 	case '1': return STR("₁");
195 	case '2': return STR("₂");
196 	case '3': return STR("₃");
197 	case '4': return STR("₄");
198 	case '5': return STR("₅");
199 	case '6': return STR("₆");
200 	case '7': return STR("₇");
201 	case '8': return STR("₈");
202 	case '9': return STR("₉");
203 	case '+': return STR("₊");
204 	case '-': return STR("₋");
205 	case '=': return STR("=");
206 	case '(': return STR("₍");
207 	case ')': return STR("₎");
208 	case 'x': return STR("ₓ");
209 	default:
210 		assert(false);
211 		return " ";
212 	}
213 }
214 
stringToSubscript(const std::string & str)215 std::string stringToSubscript(const std::string &str) {
216 	std::ostringstream ss;
217 	for (auto ch : str)
218 		ss << charToSubscript(ch);
219 	return ss.str();
220 }
221 
222 }
223 
224