xwhatsit util: fix code that handles minimum window size
[jackhill/qmk/firmware.git] / keyboards / xwhatsit / util / util / signal_level.cpp
CommitLineData
95520199
PA
1/* Copyright 2020 Purdea Andrei
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
0dfaef40
PA
17#include "signal_level.h"
18#include "ui_signal_level.h"
19#include <QGraphicsView>
20#include <QPainter>
21#include <QFile>
b57f1e31
PA
22#include <QMenu>
23#include <QAction>
0dfaef40
PA
24#include <QMessageBox>
25#include <iostream>
805a7dce 26#include <algorithm>
0dfaef40
PA
27#include "kbd_defs.h"
28
29SignalLevelMonitorWindow::SignalLevelMonitorWindow(HidThread &thread, QWidget *parent) :
30 QDialog(parent),
31 ui(new Ui::SignalLevelMonitorWindow),
32 thread(thread)
33{
34 ui->setupUi(this);
35 keyboard = nullptr;
805a7dce 36 current_layout = nullptr;
0dfaef40
PA
37 connect(&thread, &HidThread::keyboardName, this, &SignalLevelMonitorWindow::on_keyboardName);
38 connect(&thread, &HidThread::reportMonitorError, this, &SignalLevelMonitorWindow::on_reportMonitorError);
39 connect(&thread, &HidThread::reportSignalLevel, this, &SignalLevelMonitorWindow::on_signallevel);
b57f1e31
PA
40 this->setContextMenuPolicy(Qt::CustomContextMenu);
41 connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
42 this, SLOT(ShowContextMenu(const QPoint &)));
9b0419fb
PA
43 HORIZONTAL_MARGIN = 10;
44 VERTICAL_MARGIN = 10;
b57f1e31
PA
45}
46
47void SignalLevelMonitorWindow::ShowContextMenu(const QPoint &pos)
48{
49 QMenu contextMenu(tr("Context menu"), this);
50 QAction action1("Close", this);
51 connect(&action1, SIGNAL(triggered()), this, SLOT(close()));
52 contextMenu.addAction(&action1);
53 contextMenu.exec(mapToGlobal(pos));
0dfaef40
PA
54}
55
56SignalLevelMonitorWindow::~SignalLevelMonitorWindow()
57{
58 delete ui;
59}
60
0c5817c9 61void SignalLevelMonitorWindow::setMinimumSizeUnits(unsigned int width_units_times_8, unsigned int height_units_times_8)
805a7dce 62{
9b0419fb
PA
63 HORIZONTAL_MARGIN = ui->label_keyboardname->pos().x();
64 VERTICAL_MARGIN = ui->label_keyboardname->pos().x();
24e57c23 65 this->setMinimumSize(static_cast<int>(width_units_times_8 * MIN_HORIZONTAL_SCALE / 8 + 2 * HORIZONTAL_MARGIN),
805a7dce 66 ui->last_label->geometry().y() + ui->last_label->geometry().height() +
0c5817c9 67 static_cast<int>(height_units_times_8 * MIN_VERTICAL_SCALE / 8 + 2 * VERTICAL_MARGIN));
805a7dce
PA
68}
69
0dfaef40
PA
70void SignalLevelMonitorWindow::loadLayout(QString name)
71{
72 int i;
0dfaef40
PA
73 ui->layoutSel->clear();
74 for (i=0;i<n_keyboards;i++)
75 {
76 if (name.compare(QString(keyboards[i].kbd_name))==0)
77 {
78 keyboard = &keyboards[i];
6fd6e42a
PA
79 this->signal_level = std::vector<std::vector<uint16_t>>(static_cast<unsigned long>(keyboard->rows), std::vector<uint16_t>(static_cast<unsigned long>(keyboard->cols), 0xFFFFU));
80 this->max_signal_level = std::vector<std::vector<uint16_t>>(static_cast<unsigned long>(keyboard->rows), std::vector<uint16_t>(static_cast<unsigned long>(keyboard->cols), 0xFFFFU));
81 this->min_signal_level = std::vector<std::vector<uint16_t>>(static_cast<unsigned long>(keyboard->rows), std::vector<uint16_t>(static_cast<unsigned long>(keyboard->cols), 0xFFFFU));
0dfaef40
PA
82 int j;
83 for (j=0;j<keyboard->n_layouts;j++)
84 {
85 ui->layoutSel->addItem(QString(keyboard->layouts[j].lay_name));
86 }
87 break;
88 }
89 }
805a7dce 90 ui->layoutSel->addItem(QString("Matrix (without showing skipped columns/rows)"));
0dfaef40
PA
91 QString name_simp = name;
92 if (name.startsWith("keyboards/")) name_simp = name.mid(strlen("keyboards/"));
93 int lastslash = name_simp.lastIndexOf("/");
94 if (lastslash > 0) name_simp = name_simp.left(lastslash);
95 ui->label_keyboardname->setText(QString("Keyboard: ") + name_simp);
96 ui->layoutSel->setEnabled(true);
ff765ccb
PA
97 if (!keyboard)
98 {
99 on_reportMonitorError("Unknown keyboard (you may need to update the util version)!");
100 this->close();
101 return;
102 }
0c5817c9
PA
103 keyboard_width_uis_times_8 = 0;
104 keyboard_height_uis_times_8 = 0;
0dfaef40
PA
105 for (i=0;i<keyboard->n_layouts;i++)
106 {
107 const struct lay_def *layout = &keyboard->layouts[i];
108 int j;
109 for (j=0;j<layout->n_keys;j++)
110 {
0c5817c9
PA
111 unsigned int w8 = static_cast<unsigned int>((layout->keys[j].x + layout->keys[j].w)*8 + 0.5);
112 unsigned int h8 = static_cast<unsigned int>((layout->keys[j].y + layout->keys[j].h)*8 + 0.5);
113 if (w8 > keyboard_width_uis_times_8) keyboard_width_uis_times_8 = w8;
114 if (h8 > keyboard_height_uis_times_8) keyboard_height_uis_times_8 = h8;
0dfaef40
PA
115 }
116 }
0c5817c9 117 setMinimumSizeUnits(keyboard_width_uis_times_8, keyboard_height_uis_times_8);
d82f09a9
PA
118}
119
120QColor SignalLevelMonitorWindow::getColor(uint16_t value, uint16_t mins, uint16_t maxs)
121{
122 double scale = (value - mins + 0.0) / (maxs - mins);
123 uint8_t red = static_cast<uint8_t>(0xff * (1 - scale) + 0xc0 * scale);
124 uint8_t green = static_cast<uint8_t>(0xff * scale + 0xc0 * (1 - scale));
125 uint8_t blue = 0xc0;
126 return QColor(red, green, blue);
0dfaef40
PA
127}
128
805a7dce
PA
129void SignalLevelMonitorWindow::displaySquare(int x, int y, int w, int h, unsigned int col, unsigned int row, uint16_t mins, uint16_t maxs, QPainter &painter)
130{
131 painter.setPen(QPen(Qt::black));
132 painter.setBrush(Qt::NoBrush);
133 QRectF rect(x, y, w, h);
134 painter.drawRect(rect);
135 if ((signal_level.at(row).at(col)!=0xffffu) && (mins!=maxs))
136 {
137 painter.setPen(Qt::NoPen);
138 QString maxstring = QString::number(max_signal_level.at(row).at(col));
139 QString currstring = QString::number(signal_level.at(row).at(col));
140 QString minstring = QString::number(min_signal_level.at(row).at(col));
141 painter.setBrush(QBrush(getColor(max_signal_level.at(row).at(col), mins, maxs)));
142 QRectF recti_max(x+1, y+1, w-1, (h-1) / 3);
143 painter.drawRect(recti_max);
144 painter.setBrush(QBrush(getColor(signal_level.at(row).at(col), mins, maxs)));
145 QRectF recti_curr(x+1, y+1 + (h-1) / 3, w-1, (h-1) / 3);
146 painter.drawRect(recti_curr);
147 painter.setBrush(QBrush(getColor(min_signal_level.at(row).at(col), mins, maxs)));
148 QRectF recti_min(x+1, y+1 + (h-1) / 3 *2, w-1, h-1 - ((h-1) / 3) * 2);
149 painter.drawRect(recti_min);
150 painter.setPen(Qt::black);
151 painter.drawText(recti_max, Qt::AlignCenter, maxstring);
152 painter.drawText(recti_curr, Qt::AlignCenter, currstring);
153 painter.drawText(recti_min, Qt::AlignCenter, minstring);
154
155 } else {
156 painter.setPen(Qt::NoPen);
157 painter.setBrush(QBrush(QColor("#FFFFFF")));
158 QRectF recti(x+1, y+1, w-1, h-1);
159 painter.drawRect(recti);
160 if (signal_level.at(row).at(col)!=0xffffu)
161 {
162 painter.setPen(Qt::black);
163 QString currstring = QString::number(signal_level.at(row).at(col));
164 painter.drawText(recti, Qt::AlignCenter, currstring);
165 }
166 }
167}
168
169void SignalLevelMonitorWindow::updateCurrentLayout()
170{
171 int i;
172 this->current_layout = nullptr;
173 for (i=0;i<keyboard->n_layouts;i++)
174 {
175 if (ui->layoutSel->currentText().compare(QString(keyboard->layouts[i].lay_name))==0)
176 {
177 this->current_layout = &keyboard->layouts[i];
178 return;
179 }
180 }
181}
182
0dfaef40
PA
183void SignalLevelMonitorWindow::paintEvent(QPaintEvent *event)
184{
185 Q_UNUSED(event);
9b0419fb
PA
186 HORIZONTAL_MARGIN = ui->label_keyboardname->pos().x();
187 VERTICAL_MARGIN = ui->label_keyboardname->pos().x();
0dfaef40
PA
188 if (!keyboard) return;
189 QPainter painter(this);
190 int xadd = HORIZONTAL_MARGIN;
191 int yadd = ui->last_label->geometry().y() + ui->last_label->geometry().height() + VERTICAL_MARGIN;
805a7dce
PA
192 updateCurrentLayout();
193 const struct lay_def *layout = this->current_layout;
194 if (layout)
0dfaef40 195 {
0c5817c9
PA
196 double scale_x = (1. * this->width() - 1 - 2 * HORIZONTAL_MARGIN) * 8 / keyboard_width_uis_times_8;
197 double scale_y = (1. * this->height() - 1 - VERTICAL_MARGIN - yadd) * 8 / keyboard_height_uis_times_8;
805a7dce
PA
198 int j;
199 uint16_t mins = 0xffffu, maxs = 0xffffu;
200 for (j=0;j<layout->n_keys;j++)
0dfaef40 201 {
805a7dce
PA
202 const unsigned int col = layout->keys[j].col;
203 const unsigned int row = layout->keys[j].row;
204 if (signal_level.at(row).at(col)!=0xffffu)
205 {
206 if ((mins == 0xffffu) || (mins > min_signal_level.at(row).at(col)))
207 {
208 mins = min_signal_level.at(row).at(col);
209 }
210 if ((maxs == 0xffffu) || (maxs < max_signal_level.at(row).at(col)))
211 {
212 maxs = max_signal_level.at(row).at(col);
213 }
214 }
215 }
216 for (j=0;j<layout->n_keys;j++)
217 {
218 const unsigned int col = layout->keys[j].col;
219 const unsigned int row = layout->keys[j].row;
220 const int x_ = static_cast<int>(layout->keys[j].x * 8 + 0.5);
221 const int y_ = static_cast<int>(layout->keys[j].y * 8 + 0.5);
222 const int w_ = static_cast<int>(layout->keys[j].w * 8 + 0.5);
223 const int h_ = static_cast<int>(layout->keys[j].h * 8 + 0.5);
224 const int x__ = static_cast<int>(scale_x * x_ / 8 + 0.5);
225 const int y__ = static_cast<int>(scale_y * y_ / 8 + 0.5);
226 const int w = static_cast<int>(scale_x * (x_ + w_) / 8 + 0.5) - x__;
227 const int h = static_cast<int>(scale_y * (y_ + h_) / 8 + 0.5) - y__;
228 const int x = x__ + xadd;
229 const int y = y__ + yadd;
230 displaySquare(x, y, w, h, col, row, mins, maxs, painter);
231 }
232 } else {
233 unsigned int col, row;
234 double scale_x = (1. * this->width() - 2 * HORIZONTAL_MARGIN) / keyboard->cols;
235 double scale_y = (1. * this->height() - VERTICAL_MARGIN - yadd) / keyboard->rows;
236 uint16_t mins = 0xffffu, maxs = 0xffffu;
237 for (row = 0; row < keyboard->rows; row++)
238 {
239 for (col = 0; col < keyboard->cols; col++)
0dfaef40 240 {
980b3e50 241 if (signal_level.at(row).at(col)!=0xffffu)
0dfaef40 242 {
980b3e50 243 if ((mins == 0xffffu) || (mins > min_signal_level.at(row).at(col)))
0dfaef40 244 {
980b3e50 245 mins = min_signal_level.at(row).at(col);
0dfaef40 246 }
980b3e50 247 if ((maxs == 0xffffu) || (maxs < max_signal_level.at(row).at(col)))
0dfaef40 248 {
980b3e50 249 maxs = max_signal_level.at(row).at(col);
0dfaef40 250 }
0dfaef40
PA
251 }
252 }
805a7dce
PA
253 }
254 for (row = 0; row < keyboard->rows; row++)
255 {
256 for (col = 0; col < keyboard->cols; col++)
0dfaef40 257 {
805a7dce
PA
258 const int x__ = static_cast<int>(scale_x * col + 0.5);
259 const int y__ = static_cast<int>(scale_y * row + 0.5);
260 const int w = static_cast<int>(scale_x * (col + 1) + 0.5) - x__;
261 const int h = static_cast<int>(scale_y * (row + 1) + 0.5) - y__;
262 const int x = x__ + xadd;
263 const int y = y__ + yadd;
264 displaySquare(x, y, w, h, col, row, mins, maxs, painter);
0dfaef40 265 }
0dfaef40
PA
266 }
267 }
268}
269
270void SignalLevelMonitorWindow::on_layoutSel_activated(const QString &arg1)
271{
272 Q_UNUSED(arg1);
805a7dce
PA
273 updateCurrentLayout();
274 if (this->current_layout)
275 {
0c5817c9 276 setMinimumSizeUnits(this->keyboard_width_uis_times_8, this->keyboard_height_uis_times_8);
805a7dce 277 } else {
0c5817c9 278 setMinimumSizeUnits(this->keyboard->cols * 8, this->keyboard->rows * 8);
805a7dce 279 }
0dfaef40
PA
280 this->repaint();
281}
282
283void SignalLevelMonitorWindow::on_keyboardName(std::string name)
284{
285 loadLayout(QString::fromStdString(name));
286 this->repaint();
287}
288
289void SignalLevelMonitorWindow::on_signallevel(std::vector<uint16_t> data)
290{
ff765ccb
PA
291 if (!keyboard)
292 {
293 return;
294 }
980b3e50
PA
295 uint16_t col = data.at(0);
296 uint16_t row = data.at(1);
0dfaef40
PA
297 unsigned int i;
298 bool different = false;
299 for (i=2;i<data.size();i++)
300 {
980b3e50 301 if (signal_level.at(row).at(col) != data.at(i))
0dfaef40
PA
302 {
303 different = true;
304 }
980b3e50
PA
305 signal_level.at(row).at(col) = data.at(i);
306 if ((min_signal_level.at(row).at(col)==0xffffu) || (data.at(i) < min_signal_level.at(row).at(col)))
d82f09a9 307 {
980b3e50 308 min_signal_level.at(row).at(col) = data.at(i);
d82f09a9 309 }
980b3e50 310 if ((max_signal_level.at(row).at(col)==0xffffu) || (data.at(i) > max_signal_level.at(row).at(col)))
d82f09a9 311 {
980b3e50 312 max_signal_level.at(row).at(col) = data.at(i);
d82f09a9 313 }
0dfaef40
PA
314 col += 1;
315 if (col >= keyboard->cols)
316 {
317 col -= keyboard->cols;
318 row += 1;
319 }
320 if (row >= keyboard->rows)
321 {
322 break;
323 }
324 }
325 if (different)
326 this->repaint();
327}
328
329void SignalLevelMonitorWindow::on_reportMonitorError(std::string error_message)
330{
331 QMessageBox::critical(this, "Error", error_message.c_str());
332}
333
334void SignalLevelMonitorWindow::on_SignalLevelMonitorWindow_finished(int result)
335{
336 Q_UNUSED(result);
337 thread.closeMonitoredDevice();
338}