mirror of
https://github.com/Syllo/nvtop.git
synced 2026-04-21 22:48:08 -04:00
137 lines
5.1 KiB
C
137 lines
5.1 KiB
C
/*
|
|
*
|
|
* Copyright (C) 2019-2021 Maxime Schmitt <maxime.schmitt91@gmail.com>
|
|
*
|
|
* This file is part of Nvtop.
|
|
*
|
|
* Nvtop 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.
|
|
*
|
|
* Nvtop 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 have received a copy of the GNU General Public License
|
|
* along with nvtop. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "nvtop/plot.h"
|
|
#include "nvtop/common.h"
|
|
|
|
#include <assert.h>
|
|
#include <ncurses.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <tgmath.h>
|
|
|
|
static inline int data_level(double rows, double data, double increment) {
|
|
return (int)(rows - round(data / increment));
|
|
}
|
|
|
|
void nvtop_line_plot(WINDOW *win, size_t num_data, const double *data, unsigned num_lines, bool legend_left,
|
|
char legend[MAX_LINES_PER_PLOT][PLOT_MAX_LEGEND_SIZE]) {
|
|
if (num_data == 0)
|
|
return;
|
|
int rows, cols;
|
|
getmaxyx(win, rows, cols);
|
|
rows -= 1;
|
|
double increment = 100. / (double)(rows);
|
|
|
|
assert(num_lines <= MAX_LINES_PER_PLOT && "Cannot plot more than " EXPAND_AND_QUOTE(MAX_LINES_PER_PLOT) " lines");
|
|
unsigned lvl_before[MAX_LINES_PER_PLOT];
|
|
for (size_t k = 0; k < num_lines; ++k)
|
|
lvl_before[k] = data_level(rows, data[k], increment);
|
|
|
|
for (size_t i = 0; i < num_data || i < (size_t)cols; i += num_lines) {
|
|
for (unsigned k = 0; k < num_lines; ++k) {
|
|
unsigned lvl_now_k = data_level(rows, data[i + k], increment);
|
|
wcolor_set(win, k + 1, NULL);
|
|
// Three cases: has increased, has decreased and remained level
|
|
if (lvl_before[k] < lvl_now_k || lvl_before[k] > lvl_now_k) {
|
|
// Case 1 and 2: has increased/decreased
|
|
|
|
// An increase goes down on the plot because (0,0) is top left
|
|
bool drawing_down = lvl_before[k] < lvl_now_k;
|
|
unsigned bottom = drawing_down ? lvl_before[k] : lvl_now_k;
|
|
unsigned top = drawing_down ? lvl_now_k : lvl_before[k];
|
|
|
|
// Draw the vertical line corners
|
|
mvwaddch(win, bottom, i + k, drawing_down ? ACS_URCORNER : ACS_ULCORNER);
|
|
mvwaddch(win, top, i + k, drawing_down ? ACS_LLCORNER : ACS_LRCORNER);
|
|
// Draw the vertical line between the corners
|
|
if (top - bottom > 1) {
|
|
mvwvline(win, bottom + 1, i + k, 0, top - bottom - 1);
|
|
}
|
|
|
|
// Draw the continuation of the other metrics
|
|
for (unsigned j = 0; j < num_lines; ++j) {
|
|
if (j != k) {
|
|
if (lvl_before[j] == top)
|
|
// The continuation is at the same level as the bottom corner
|
|
mvwaddch(win, top, i + k, ACS_BTEE);
|
|
else if (lvl_before[j] == bottom)
|
|
// The continuation is at the same level as the top corner
|
|
mvwaddch(win, bottom, i + k, ACS_TTEE);
|
|
else if (lvl_before[j] > bottom && lvl_before[j] < top)
|
|
// The continuation lies on the vertical line
|
|
mvwaddch(win, lvl_before[j], i + k, ACS_PLUS);
|
|
else {
|
|
// The continuation lies outside the update interval so keep the
|
|
// color
|
|
wcolor_set(win, j + 1, NULL);
|
|
mvwaddch(win, lvl_before[j], i + k, ACS_HLINE);
|
|
wcolor_set(win, k + 1, NULL);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// Case 3: stayed level
|
|
mvwhline(win, lvl_now_k, i + k, 0, 1);
|
|
for (unsigned j = 0; j < num_lines; ++j) {
|
|
if (j != k) {
|
|
if (lvl_before[j] != lvl_now_k) {
|
|
// Add the continuation of other metric lines
|
|
wcolor_set(win, j + 1, NULL);
|
|
mvwaddch(win, lvl_before[j], i + k, ACS_HLINE);
|
|
wcolor_set(win, k + 1, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
lvl_before[k] = lvl_now_k;
|
|
}
|
|
}
|
|
int plot_y_position = 0;
|
|
for (unsigned i = 0; i < num_lines && plot_y_position < rows; ++i) {
|
|
wcolor_set(win, i + 1, NULL);
|
|
if (legend_left) {
|
|
mvwprintw(win, plot_y_position, 0, "%.*s", cols, legend[i]);
|
|
} else {
|
|
size_t length = strlen(legend[i]);
|
|
if (length <= (size_t)cols) {
|
|
mvwprintw(win, plot_y_position, cols - length, "%s", legend[i]);
|
|
} else {
|
|
mvwprintw(win, plot_y_position, 0, "%.*s", (int)(length - cols), legend[i]);
|
|
}
|
|
}
|
|
plot_y_position++;
|
|
}
|
|
}
|
|
|
|
void draw_rectangle(WINDOW *win, unsigned startX, unsigned startY, unsigned sizeX, unsigned sizeY) {
|
|
mvwhline(win, startY, startX + 1, 0, sizeX - 2);
|
|
mvwhline(win, startY + sizeY - 1, startX + 1, 0, sizeX - 2);
|
|
|
|
mvwvline(win, startY + 1, startX, 0, sizeY - 2);
|
|
mvwvline(win, startY + 1, startX + sizeX - 1, 0, sizeY - 2);
|
|
|
|
mvwaddch(win, startY, startX, ACS_ULCORNER);
|
|
mvwaddch(win, startY, startX + sizeX - 1, ACS_URCORNER);
|
|
mvwaddch(win, startY + sizeY - 1, startX, ACS_LLCORNER);
|
|
mvwaddch(win, startY + sizeY - 1, startX + sizeX - 1, ACS_LRCORNER);
|
|
}
|