Blame src-nuklear/nuklear_chart.c

Ivan Mahonin b53a5c
#include "nuklear.h"
Ivan Mahonin b53a5c
#include "nuklear_internal.h"
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
/* ==============================================================
Ivan Mahonin b53a5c
 *
Ivan Mahonin b53a5c
 *                          CHART
Ivan Mahonin b53a5c
 *
Ivan Mahonin b53a5c
 * ===============================================================*/
Ivan Mahonin b53a5c
NK_API nk_bool
Ivan Mahonin b53a5c
nk_chart_begin_colored(struct nk_context *ctx, enum nk_chart_type type,
Ivan Mahonin b53a5c
    struct nk_color color, struct nk_color highlight,
Ivan Mahonin b53a5c
    int count, float min_value, float max_value)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    struct nk_window *win;
Ivan Mahonin b53a5c
    struct nk_chart *chart;
Ivan Mahonin b53a5c
    const struct nk_style *config;
Ivan Mahonin b53a5c
    const struct nk_style_chart *style;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    const struct nk_style_item *background;
Ivan Mahonin b53a5c
    struct nk_rect bounds = {0, 0, 0, 0};
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    NK_ASSERT(ctx);
Ivan Mahonin b53a5c
    NK_ASSERT(ctx->current);
Ivan Mahonin b53a5c
    NK_ASSERT(ctx->current->layout);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    if (!ctx || !ctx->current || !ctx->current->layout) return 0;
Ivan Mahonin b53a5c
    if (!nk_widget(&bounds, ctx)) {
Ivan Mahonin b53a5c
        chart = &ctx->current->layout->chart;
Ivan Mahonin b53a5c
        nk_zero(chart, sizeof(*chart));
Ivan Mahonin b53a5c
        return 0;
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    win = ctx->current;
Ivan Mahonin b53a5c
    config = &ctx->style;
Ivan Mahonin b53a5c
    chart = &win->layout->chart;
Ivan Mahonin b53a5c
    style = &config->chart;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    /* setup basic generic chart  */
Ivan Mahonin b53a5c
    nk_zero(chart, sizeof(*chart));
Ivan Mahonin b53a5c
    chart->x = bounds.x + style->padding.x;
Ivan Mahonin b53a5c
    chart->y = bounds.y + style->padding.y;
Ivan Mahonin b53a5c
    chart->w = bounds.w - 2 * style->padding.x;
Ivan Mahonin b53a5c
    chart->h = bounds.h - 2 * style->padding.y;
Ivan Mahonin b53a5c
    chart->w = NK_MAX(chart->w, 2 * style->padding.x);
Ivan Mahonin b53a5c
    chart->h = NK_MAX(chart->h, 2 * style->padding.y);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    /* add first slot into chart */
Ivan Mahonin b53a5c
    {struct nk_chart_slot *slot = &chart->slots[chart->slot++];
Ivan Mahonin b53a5c
    slot->type = type;
Ivan Mahonin b53a5c
    slot->count = count;
Ivan Mahonin b53a5c
    slot->color = color;
Ivan Mahonin b53a5c
    slot->highlight = highlight;
Ivan Mahonin b53a5c
    slot->min = NK_MIN(min_value, max_value);
Ivan Mahonin b53a5c
    slot->max = NK_MAX(min_value, max_value);
Ivan Mahonin b53a5c
    slot->range = slot->max - slot->min;}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    /* draw chart background */
Ivan Mahonin b53a5c
    background = &style->background;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    switch(background->type) {
Ivan Mahonin b53a5c
        case NK_STYLE_ITEM_IMAGE:
Ivan Mahonin b53a5c
            nk_draw_image(&win->buffer, bounds, &background->data.image, nk_white);
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
        case NK_STYLE_ITEM_NINE_SLICE:
Ivan Mahonin b53a5c
            nk_draw_nine_slice(&win->buffer, bounds, &background->data.slice, nk_white);
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
        case NK_STYLE_ITEM_COLOR:
Ivan Mahonin b53a5c
            nk_fill_rect(&win->buffer, bounds, style->rounding, style->border_color);
Ivan Mahonin b53a5c
            nk_fill_rect(&win->buffer, nk_shrink_rect(bounds, style->border),
Ivan Mahonin b53a5c
                style->rounding, style->background.data.color);
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
    return 1;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API nk_bool
Ivan Mahonin b53a5c
nk_chart_begin(struct nk_context *ctx, const enum nk_chart_type type,
Ivan Mahonin b53a5c
    int count, float min_value, float max_value)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    return nk_chart_begin_colored(ctx, type, ctx->style.chart.color,
Ivan Mahonin b53a5c
                ctx->style.chart.selected_color, count, min_value, max_value);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API void
Ivan Mahonin b53a5c
nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type type,
Ivan Mahonin b53a5c
    struct nk_color color, struct nk_color highlight,
Ivan Mahonin b53a5c
    int count, float min_value, float max_value)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    NK_ASSERT(ctx);
Ivan Mahonin b53a5c
    NK_ASSERT(ctx->current);
Ivan Mahonin b53a5c
    NK_ASSERT(ctx->current->layout);
Ivan Mahonin b53a5c
    NK_ASSERT(ctx->current->layout->chart.slot < NK_CHART_MAX_SLOT);
Ivan Mahonin b53a5c
    if (!ctx || !ctx->current || !ctx->current->layout) return;
Ivan Mahonin b53a5c
    if (ctx->current->layout->chart.slot >= NK_CHART_MAX_SLOT) return;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    /* add another slot into the graph */
Ivan Mahonin b53a5c
    {struct nk_chart *chart = &ctx->current->layout->chart;
Ivan Mahonin b53a5c
    struct nk_chart_slot *slot = &chart->slots[chart->slot++];
Ivan Mahonin b53a5c
    slot->type = type;
Ivan Mahonin b53a5c
    slot->count = count;
Ivan Mahonin b53a5c
    slot->color = color;
Ivan Mahonin b53a5c
    slot->highlight = highlight;
Ivan Mahonin b53a5c
    slot->min = NK_MIN(min_value, max_value);
Ivan Mahonin b53a5c
    slot->max = NK_MAX(min_value, max_value);
Ivan Mahonin b53a5c
    slot->range = slot->max - slot->min;}
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API void
Ivan Mahonin b53a5c
nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type type,
Ivan Mahonin b53a5c
    int count, float min_value, float max_value)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    nk_chart_add_slot_colored(ctx, type, ctx->style.chart.color,
Ivan Mahonin b53a5c
        ctx->style.chart.selected_color, count, min_value, max_value);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_INTERN nk_flags
Ivan Mahonin b53a5c
nk_chart_push_line(struct nk_context *ctx, struct nk_window *win,
Ivan Mahonin b53a5c
    struct nk_chart *g, float value, int slot)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    struct nk_panel *layout = win->layout;
Ivan Mahonin b53a5c
    const struct nk_input *i = &ctx->input;
Ivan Mahonin b53a5c
    struct nk_command_buffer *out = &win->buffer;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    nk_flags ret = 0;
Ivan Mahonin b53a5c
    struct nk_vec2 cur;
Ivan Mahonin b53a5c
    struct nk_rect bounds;
Ivan Mahonin b53a5c
    struct nk_color color;
Ivan Mahonin b53a5c
    float step;
Ivan Mahonin b53a5c
    float range;
Ivan Mahonin b53a5c
    float ratio;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
Ivan Mahonin b53a5c
    step = g->w / (float)g->slots[slot].count;
Ivan Mahonin b53a5c
    range = g->slots[slot].max - g->slots[slot].min;
Ivan Mahonin b53a5c
    ratio = (value - g->slots[slot].min) / range;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    if (g->slots[slot].index == 0) {
Ivan Mahonin b53a5c
        /* first data point does not have a connection */
Ivan Mahonin b53a5c
        g->slots[slot].last.x = g->x;
Ivan Mahonin b53a5c
        g->slots[slot].last.y = (g->y + g->h) - ratio * (float)g->h;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
        bounds.x = g->slots[slot].last.x - 2;
Ivan Mahonin b53a5c
        bounds.y = g->slots[slot].last.y - 2;
Ivan Mahonin b53a5c
        bounds.w = bounds.h = 4;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
        color = g->slots[slot].color;
Ivan Mahonin b53a5c
        if (!(layout->flags & NK_WINDOW_ROM) &&
Ivan Mahonin b53a5c
            NK_INBOX(i->mouse.pos.x,i->mouse.pos.y, g->slots[slot].last.x-3, g->slots[slot].last.y-3, 6, 6)){
Ivan Mahonin b53a5c
            ret = nk_input_is_mouse_hovering_rect(i, bounds) ? NK_CHART_HOVERING : 0;
Ivan Mahonin b53a5c
            ret |= (i->mouse.buttons[NK_BUTTON_LEFT].down &&
Ivan Mahonin b53a5c
                i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
Ivan Mahonin b53a5c
            color = g->slots[slot].highlight;
Ivan Mahonin b53a5c
        }
Ivan Mahonin b53a5c
        nk_fill_rect(out, bounds, 0, color);
Ivan Mahonin b53a5c
        g->slots[slot].index += 1;
Ivan Mahonin b53a5c
        return ret;
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    /* draw a line between the last data point and the new one */
Ivan Mahonin b53a5c
    color = g->slots[slot].color;
Ivan Mahonin b53a5c
    cur.x = g->x + (float)(step * (float)g->slots[slot].index);
Ivan Mahonin b53a5c
    cur.y = (g->y + g->h) - (ratio * (float)g->h);
Ivan Mahonin b53a5c
    nk_stroke_line(out, g->slots[slot].last.x, g->slots[slot].last.y, cur.x, cur.y, 1.0f, color);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    bounds.x = cur.x - 3;
Ivan Mahonin b53a5c
    bounds.y = cur.y - 3;
Ivan Mahonin b53a5c
    bounds.w = bounds.h = 6;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    /* user selection of current data point */
Ivan Mahonin b53a5c
    if (!(layout->flags & NK_WINDOW_ROM)) {
Ivan Mahonin b53a5c
        if (nk_input_is_mouse_hovering_rect(i, bounds)) {
Ivan Mahonin b53a5c
            ret = NK_CHART_HOVERING;
Ivan Mahonin b53a5c
            ret |= (!i->mouse.buttons[NK_BUTTON_LEFT].down &&
Ivan Mahonin b53a5c
                i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
Ivan Mahonin b53a5c
            color = g->slots[slot].highlight;
Ivan Mahonin b53a5c
        }
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
    nk_fill_rect(out, nk_rect(cur.x - 2, cur.y - 2, 4, 4), 0, color);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    /* save current data point position */
Ivan Mahonin b53a5c
    g->slots[slot].last.x = cur.x;
Ivan Mahonin b53a5c
    g->slots[slot].last.y = cur.y;
Ivan Mahonin b53a5c
    g->slots[slot].index  += 1;
Ivan Mahonin b53a5c
    return ret;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_INTERN nk_flags
Ivan Mahonin b53a5c
nk_chart_push_column(const struct nk_context *ctx, struct nk_window *win,
Ivan Mahonin b53a5c
    struct nk_chart *chart, float value, int slot)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    struct nk_command_buffer *out = &win->buffer;
Ivan Mahonin b53a5c
    const struct nk_input *in = &ctx->input;
Ivan Mahonin b53a5c
    struct nk_panel *layout = win->layout;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    float ratio;
Ivan Mahonin b53a5c
    nk_flags ret = 0;
Ivan Mahonin b53a5c
    struct nk_color color;
Ivan Mahonin b53a5c
    struct nk_rect item = {0,0,0,0};
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
Ivan Mahonin b53a5c
    if (chart->slots[slot].index  >= chart->slots[slot].count)
Ivan Mahonin b53a5c
        return nk_false;
Ivan Mahonin b53a5c
    if (chart->slots[slot].count) {
Ivan Mahonin b53a5c
        float padding = (float)(chart->slots[slot].count-1);
Ivan Mahonin b53a5c
        item.w = (chart->w - padding) / (float)(chart->slots[slot].count);
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    /* calculate bounds of current bar chart entry */
Ivan Mahonin b53a5c
    color = chart->slots[slot].color;;
Ivan Mahonin b53a5c
    item.h = chart->h * NK_ABS((value/chart->slots[slot].range));
Ivan Mahonin b53a5c
    if (value >= 0) {
Ivan Mahonin b53a5c
        ratio = (value + NK_ABS(chart->slots[slot].min)) / NK_ABS(chart->slots[slot].range);
Ivan Mahonin b53a5c
        item.y = (chart->y + chart->h) - chart->h * ratio;
Ivan Mahonin b53a5c
    } else {
Ivan Mahonin b53a5c
        ratio = (value - chart->slots[slot].max) / chart->slots[slot].range;
Ivan Mahonin b53a5c
        item.y = chart->y + (chart->h * NK_ABS(ratio)) - item.h;
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
    item.x = chart->x + ((float)chart->slots[slot].index * item.w);
Ivan Mahonin b53a5c
    item.x = item.x + ((float)chart->slots[slot].index);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    /* user chart bar selection */
Ivan Mahonin b53a5c
    if (!(layout->flags & NK_WINDOW_ROM) &&
Ivan Mahonin b53a5c
        NK_INBOX(in->mouse.pos.x,in->mouse.pos.y,item.x,item.y,item.w,item.h)) {
Ivan Mahonin b53a5c
        ret = NK_CHART_HOVERING;
Ivan Mahonin b53a5c
        ret |= (!in->mouse.buttons[NK_BUTTON_LEFT].down &&
Ivan Mahonin b53a5c
                in->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
Ivan Mahonin b53a5c
        color = chart->slots[slot].highlight;
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
    nk_fill_rect(out, item, 0, color);
Ivan Mahonin b53a5c
    chart->slots[slot].index += 1;
Ivan Mahonin b53a5c
    return ret;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API nk_flags
Ivan Mahonin b53a5c
nk_chart_push_slot(struct nk_context *ctx, float value, int slot)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    nk_flags flags;
Ivan Mahonin b53a5c
    struct nk_window *win;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    NK_ASSERT(ctx);
Ivan Mahonin b53a5c
    NK_ASSERT(ctx->current);
Ivan Mahonin b53a5c
    NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
Ivan Mahonin b53a5c
    NK_ASSERT(slot < ctx->current->layout->chart.slot);
Ivan Mahonin b53a5c
    if (!ctx || !ctx->current || slot >= NK_CHART_MAX_SLOT) return nk_false;
Ivan Mahonin b53a5c
    if (slot >= ctx->current->layout->chart.slot) return nk_false;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    win = ctx->current;
Ivan Mahonin b53a5c
    if (win->layout->chart.slot < slot) return nk_false;
Ivan Mahonin b53a5c
    switch (win->layout->chart.slots[slot].type) {
Ivan Mahonin b53a5c
    case NK_CHART_LINES:
Ivan Mahonin b53a5c
        flags = nk_chart_push_line(ctx, win, &win->layout->chart, value, slot); break;
Ivan Mahonin b53a5c
    case NK_CHART_COLUMN:
Ivan Mahonin b53a5c
        flags = nk_chart_push_column(ctx, win, &win->layout->chart, value, slot); break;
Ivan Mahonin b53a5c
    default:
Ivan Mahonin b53a5c
    case NK_CHART_MAX:
Ivan Mahonin b53a5c
        flags = 0;
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
    return flags;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API nk_flags
Ivan Mahonin b53a5c
nk_chart_push(struct nk_context *ctx, float value)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    return nk_chart_push_slot(ctx, value, 0);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API void
Ivan Mahonin b53a5c
nk_chart_end(struct nk_context *ctx)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    struct nk_window *win;
Ivan Mahonin b53a5c
    struct nk_chart *chart;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    NK_ASSERT(ctx);
Ivan Mahonin b53a5c
    NK_ASSERT(ctx->current);
Ivan Mahonin b53a5c
    if (!ctx || !ctx->current)
Ivan Mahonin b53a5c
        return;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    win = ctx->current;
Ivan Mahonin b53a5c
    chart = &win->layout->chart;
Ivan Mahonin b53a5c
    NK_MEMSET(chart, 0, sizeof(*chart));
Ivan Mahonin b53a5c
    return;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API void
Ivan Mahonin b53a5c
nk_plot(struct nk_context *ctx, enum nk_chart_type type, const float *values,
Ivan Mahonin b53a5c
    int count, int offset)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    int i = 0;
Ivan Mahonin b53a5c
    float min_value;
Ivan Mahonin b53a5c
    float max_value;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    NK_ASSERT(ctx);
Ivan Mahonin b53a5c
    NK_ASSERT(values);
Ivan Mahonin b53a5c
    if (!ctx || !values || !count) return;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    min_value = values[offset];
Ivan Mahonin b53a5c
    max_value = values[offset];
Ivan Mahonin b53a5c
    for (i = 0; i < count; ++i) {
Ivan Mahonin b53a5c
        min_value = NK_MIN(values[i + offset], min_value);
Ivan Mahonin b53a5c
        max_value = NK_MAX(values[i + offset], max_value);
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    if (nk_chart_begin(ctx, type, count, min_value, max_value)) {
Ivan Mahonin b53a5c
        for (i = 0; i < count; ++i)
Ivan Mahonin b53a5c
            nk_chart_push(ctx, values[i + offset]);
Ivan Mahonin b53a5c
        nk_chart_end(ctx);
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API void
Ivan Mahonin b53a5c
nk_plot_function(struct nk_context *ctx, enum nk_chart_type type, void *userdata,
Ivan Mahonin b53a5c
    float(*value_getter)(void* user, int index), int count, int offset)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    int i = 0;
Ivan Mahonin b53a5c
    float min_value;
Ivan Mahonin b53a5c
    float max_value;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    NK_ASSERT(ctx);
Ivan Mahonin b53a5c
    NK_ASSERT(value_getter);
Ivan Mahonin b53a5c
    if (!ctx || !value_getter || !count) return;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    max_value = min_value = value_getter(userdata, offset);
Ivan Mahonin b53a5c
    for (i = 0; i < count; ++i) {
Ivan Mahonin b53a5c
        float value = value_getter(userdata, i + offset);
Ivan Mahonin b53a5c
        min_value = NK_MIN(value, min_value);
Ivan Mahonin b53a5c
        max_value = NK_MAX(value, max_value);
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    if (nk_chart_begin(ctx, type, count, min_value, max_value)) {
Ivan Mahonin b53a5c
        for (i = 0; i < count; ++i)
Ivan Mahonin b53a5c
            nk_chart_push(ctx, value_getter(userdata, i + offset));
Ivan Mahonin b53a5c
        nk_chart_end(ctx);
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c