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