#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include "layout.h"
#include "top.h"
#include "log.h"
enum { COLUMN_PADDING = 1 };
struct enlarge_data {
int add;
int maxy;
int count;
};
static bool enlarge_iterator(struct statistic *s, void *ptr) {
struct enlarge_data *data = ptr;
int size;
if(s->request_size.width > s->minimum_size.width) {
size = s->request_size.width;
} else {
size = s->minimum_size.width;
}
if(data->count > 0)
size += COLUMN_PADDING;
s->actual_size.width = size;
s->actual_size.width += data->add;
s->actual_size.height = data->maxy;
data->count += 1;
return true;
}
static void enlarge(struct statistics_controller *c,
int maxy, int toadd) {
struct enlarge_data data;
data.add = toadd;
data.maxy = maxy;
data.count = 0;
c->iterate(c, enlarge_iterator, &data);
}
struct do_layout_data {
int x, y;
bool error;
};
static bool do_layout_iterator(struct statistic *s, void *ptr) {
struct do_layout_data *data = ptr;
struct statistic_size firstsize = {.width = 1, .height = 1};
if(s->callbacks.resize_cells(s, &firstsize)) {
data->error = true;
return false;
}
if(s->callbacks.move_cells(s, data->x, data->y)) {
top_log("error: moving cells for %s!\n", s->header);
top_log("error info: data->x %d data->y %d\n",
data->x, data->y);
data->error = true;
return false;
}
if(s->callbacks.resize_cells(s, &s->actual_size)) {
top_log("error: resizing cells for %s!\n", s->header);
top_log("error info: data->x %d s->actual_size.width %d "
"s->actual_size.height %d\n", data->x, s->actual_size.width,
s->actual_size.height);
data->error = true;
return false;
}
data->x += s->actual_size.width;
return true;
}
static bool do_layout(struct statistics_controller *c, int y) {
struct do_layout_data data;
data.x = 0;
data.y = y;
data.error = false;
c->iterate(c, do_layout_iterator, &data);
return data.error;
}
struct get_size_data {
struct statistic_size *reqsize;
struct statistic_size *minsize;
int count;
};
static bool get_size_iterator(struct statistic *s, void *ptr) {
struct get_size_data *data = ptr;
int minwidth, reqwidth;
s->callbacks.get_request_size(s);
s->callbacks.get_minimum_size(s);
minwidth = s->minimum_size.width;
reqwidth = s->request_size.width;
if(data->count > 0) {
minwidth += COLUMN_PADDING;
reqwidth += COLUMN_PADDING;
}
data->minsize->width += minwidth;
if(s->minimum_size.height > data->minsize->height)
data->minsize->height = s->minimum_size.height;
if(reqwidth > minwidth) {
data->reqsize->width += reqwidth;
} else {
data->reqsize->width += minwidth;
}
if(s->request_size.height > data->reqsize->height)
data->reqsize->height = s->request_size.height;
data->count += 1;
return true;
}
static void get_size(struct statistics_controller *c,
struct statistic_size *reqsize,
struct statistic_size *minsize) {
struct get_size_data data;
reqsize->width = 0;
reqsize->height = 0;
minsize->width = 0;
minsize->height = 0;
data.reqsize = reqsize;
data.minsize = minsize;
data.count = 0;
c->iterate(c, get_size_iterator, &data);
}
struct minsize_fit_data {
int maxy;
int count;
};
static bool minsize_fit_iterator(struct statistic *s, void *ptr) {
struct minsize_fit_data *data = ptr;
s->actual_size.width = s->minimum_size.width;
if(data->count > 0)
s->actual_size.width += COLUMN_PADDING;
s->actual_size.height = data->maxy;
data->count += 1;
return true;
}
static void minsize_fit(struct statistics_controller *c, int maxy) {
struct minsize_fit_data data;
data.maxy = maxy;
data.count = 0;
c->iterate(c, minsize_fit_iterator, &data);
}
bool layout_statistics(struct statistics_controller *c, int maxx, int maxy,
int y) {
struct statistic_size reqsize, minsize;
int total_stats = 0;
int inserts = 0, removes = 0;
if(maxy <= 0)
return false;
while(1) {
get_size(c, &reqsize, &minsize);
total_stats = c->get_total_active(c);
if(minsize.width == maxx) {
minsize_fit(c, maxy);
break;
} else if(minsize.width > maxx) {
if(total_stats > 1) {
++removes;
c->remove_tail(c);
continue;
}
minsize_fit(c, maxy);
break;
} else {
if(0 == removes && total_stats < c->get_total_possible(c)) {
++inserts;
c->insert_tail(c);
continue;
}
minsize_fit(c, maxy);
break;
}
}
total_stats = c->get_total_active(c);
if(total_stats >= c->get_total_possible(c)) {
get_size(c, &reqsize, &minsize);
if(reqsize.width == maxx) {
enlarge(c, maxy, 0);
} else if(reqsize.width > maxx) {
minsize_fit(c, maxy);
} else {
int xdelta = maxx - reqsize.width;
int enlargement = xdelta / c->get_total_possible(c);
if(enlargement > 0) {
enlarge(c, maxy, enlargement);
} else {
enlarge(c, maxy, 0);
}
}
}
top_log("c->get_total_active(c) is %d\n", c->get_total_active(c));
if(do_layout(c, y))
return true;
return false;
}