#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <curses.h>
#include "libtop.h"
#include "generic.h"
#include "log.h"
#include "top.h"
enum { HEADER_SIZE = 1 };
int generic_draw_header(struct statistic *s, int x, int y, int anchor) {
if(s->header) {
generic_draw_extended(s, x, y, anchor, s->header, strlen(s->header));
y += HEADER_SIZE;
}
return y;
}
void generic_draw_aligned(struct statistic *s, int x) {
int y = 0;
struct generic_cells *cells;
int peaklength = 0;
int maxy;
size_t i;
cells = s->cells;
if(NULL == cells)
return;
werase(s->window);
y = generic_draw_header(s, x, y, GENERIC_DRAW_LEFT);
maxy = s->actual_size.height;
peaklength = s->actual_size.width;
for(i = 0; i < cells->length && y < maxy; ++i, ++y) {
int len = cells->array[i].length;
int localx;
localx = peaklength - len;
if(len <= 0)
continue;
if(ERR == mvwaddnstr(s->window, y, localx,
cells->array[i].string, len)) {
int erry, errx;
getmaxyx(s->window, erry, errx);
top_log("mvwaddnstr error in %s\n", __func__);
top_log("error info: s->header %s y %d x %d n %d string: %s\n"
"s->window width %d height %d\n",
s->header, y, localx + x, len,
cells->array[i].string,
errx, erry);
}
}
}
void generic_draw(struct statistic *s, int x) {
int y = 0;
size_t i;
struct generic_cells *cells;
int maxy;
cells = s->cells;
if(NULL == cells)
return;
werase(s->window);
y = generic_draw_header(s, x, y, GENERIC_DRAW_LEFT);
maxy = s->actual_size.height;
for(i = 0; i < cells->length && y < maxy; ++i, ++y) {
generic_draw_extended(s, x, y, GENERIC_DRAW_LEFT,
cells->array[i].string,
cells->array[i].length);
}
}
void generic_draw_extended(struct statistic *s, int xoffset, int yoffset, int anchor, const char *string, int slen) {
int yheight, xwidth, xpos;
int n;
xwidth = s->actual_size.width;
yheight = s->actual_size.height;
switch(anchor) {
case GENERIC_DRAW_LEFT:
n = xwidth - xoffset;
if(n > slen)
n = slen;
mvwaddnstr(s->window, yoffset, xoffset, string, n);
break;
case GENERIC_DRAW_CENTERED:
xpos = ((xwidth - xoffset) / 2) - (slen / 2);
if(xpos < 0) {
xpos = 0;
}
n = slen;
if((slen + xpos) >= xwidth) {
n = xwidth - xpos - xoffset;
}
if(n < 0) {
xpos = 0;
n = 0;
}
mvwaddnstr(s->window, yoffset, xpos + xoffset, string, n);
break;
case GENERIC_DRAW_RIGHT:
xpos = xwidth - slen - xoffset;
if(xpos < xoffset) {
xpos = xoffset;
}
n = xwidth - xpos;
if(n > slen)
n = slen;
mvwaddnstr(s->window, yoffset, xpos + xoffset, string, n);
break;
}
wsyncup(s->window);
}
void generic_draw_centered(struct statistic *s, int x) {
struct generic_cells *cells;
size_t i;
int y = 0;
cells = s->cells;
if(NULL == cells)
return;
y = generic_draw_header(s, x, y, GENERIC_DRAW_CENTERED);
for(i = 0; i < cells->length; ++i) {
generic_draw_extended(s, x, y, GENERIC_DRAW_CENTERED,
cells->array[i].string,
cells->array[i].length);
++y;
}
}
void generic_draw_right(struct statistic *s, int x) {
struct generic_cells *cells;
size_t i;
int y = 0;
cells = s->cells;
if(NULL == cells)
return;
y = generic_draw_header(s, x, y, GENERIC_DRAW_RIGHT);
for(i = 0; i < cells->length; ++i) {
generic_draw_extended(s, x, y, GENERIC_DRAW_RIGHT,
cells->array[i].string,
cells->array[i].length);
++y;
}
}
bool generic_resize_cells(struct statistic *s, struct statistic_size *size) {
if(ERR == wresize(s->window, size->height, size->width))
return true;
return false;
}
bool generic_move_cells(struct statistic *s, int x, int y) {
if(ERR == move_panel(s->panel, y, x))
return true;
return false;
}
void generic_get_request_size(struct statistic *s) {
struct generic_cells *cells;
cells = s->cells;
if(NULL == cells)
return;
s->request_size.width = cells->max_width;
s->request_size.height = cells->length;
}
static struct generic_cells *alloc_generic_cells(void) {
size_t i, length = 10;
struct generic_cells *cells;
cells = malloc(sizeof *cells);
if(NULL == cells)
return NULL;
cells->array = malloc(sizeof(*(cells->array)) * length);
if(NULL == cells->array) {
free(cells);
return NULL;
}
for(i = 0; i < length; ++i) {
cells->array[i].string = NULL;
cells->array[i].length = 0;
cells->array[i].allocated_length = 0;
}
cells->max_width = 0;
cells->length = 0;
cells->length_allocated = length;
return cells;
}
static void free_generic_cells(struct generic_cells *cells) {
size_t i;
for(i = 0; i < cells->length_allocated; ++i) {
if(cells->array[i].string) {
free(cells->array[i].string);
}
}
free(cells->array);
free(cells);
}
static void generic_cell_destructor(struct statistic *s, void *ptr) {
free_generic_cells(s->cells);
}
bool generic_insert_cell(struct statistic *s, const char *sample) {
struct generic_cells *cells = s->cells;
size_t offset;
int sample_length = (int)strlen(sample);
int sample_z_length = sample_length + 1;
#if 0
top_log("%s %s\n", __func__, sample);
#endif
if(NULL == cells) {
cells = s->cells = alloc_generic_cells();
if(NULL == cells)
return true;
if(create_statistic_destructor(s, generic_cell_destructor, NULL))
return true;
}
if(sample_length > cells->max_width) {
cells->max_width = sample_length;
if(cells->max_width > s->actual_size.width) {
top_relayout(s->controller, s->type, cells->max_width);
}
}
offset = cells->length;
cells->length += 1;
if(cells->length >= cells->length_allocated) {
size_t newlength = cells->length_allocated * 2;
size_t i;
cells->array = realloc(cells->array,
sizeof(*(cells->array)) * newlength);
if(NULL == cells->array)
return true;
for(i = cells->length_allocated; i < newlength; ++i) {
cells->array[i].string = NULL;
cells->array[i].length = 0;
cells->array[i].allocated_length = 0;
}
cells->length_allocated = newlength;
}
if(0 == sample_length) {
cells->array[offset].length = 0;
return false;
}
if(cells->array[offset].string
&& cells->array[offset].allocated_length >= sample_z_length) {
memcpy(cells->array[offset].string, sample, sample_z_length);
cells->array[offset].length = sample_length;
} else {
free(cells->array[offset].string);
cells->array[offset].string = malloc(cells->max_width + 1);
if(NULL == cells->array[offset].string) {
cells->array[offset].length = 0;
return true;
}
cells->array[offset].length = sample_length;
cells->array[offset].allocated_length = cells->max_width + 1;
memcpy(cells->array[offset].string, sample, sample_z_length);
}
return false;
}
void generic_reset_insertion(struct statistic *s) {
struct generic_cells *cells;
cells = s->cells;
if(NULL == cells)
return;
cells->length = 0;
}
void generic_get_minimum_size(struct statistic *s) {
struct generic_cells *cells;
cells = s->cells;
if(NULL == cells)
return;
s->minimum_size.width = cells->max_width;
s->minimum_size.height = cells->length;
if(s->minimum_size.width < 4)
s->minimum_size.width = 4;
}