
/***************************************************************************
 *                                                                         *
 *   KCPULoad and KNetLoad are copyright (c) 1999-2000, Markus Gustavsson  *
 *                                       (c) 2002, Ben Burton              *
 *                                                                         *
 *   This program 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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "statdock.h"
#include "statpopup.h"
#include <qpainter.h>

const int StatDock::fillLines = 0;
const int StatDock::fillBars = 1;
const int StatDock::fillShaded = 2;

const QColor StatDock::colorGrid(120, 120, 120);
const QColor StatDock::colorGridInactive(60, 60, 60);
const QColor StatDock::colorLabel(255, 255, 255);
const QColor StatDock::colorLabelInactive(125, 125, 125);
const QColor StatDock::colorLower(255, 255, 255);
const QColor StatDock::colorLowerInactive(125, 125, 125);
const QColor StatDock::colorBlack(0, 0, 0);

#define DOCK_SIZE 24
#define DOCK_SCALE 4.34783 // Approx. 100/23.
#define SOFT_STEP 3

StatDock::StatDock(int whichDock, const QString& useLabel,
        StatPopup *parent, const char *name) :
        KSystemTray(parent,name),
        label(useLabel),
        bufUpper(new int[DOCK_SIZE]),
        bufLower(new int[DOCK_SIZE]),
        pos(0) {
    // Initialise the stored readings.
    for (i = 0; i < DOCK_SIZE; i++)
        bufUpper[i] = bufLower[i] = 0;

    // Initialise the display.
    parent->initDock(this, contextMenu(), whichDock);
    setBackgroundColor(colorBlack);
    resize(24, 24);
    show();
}

StatDock::~StatDock() {
    delete[] bufUpper;
    delete[] bufLower;
}

void StatDock::setGrid(bool set) {
    grid = set;
    repaint();
}

void StatDock::setActive(bool set) {
    active = set;
    repaint();
}

void StatDock::setSoft(bool set) {
    soft = set;
    repaint();
}

void StatDock::setSplit(bool set) {
    split = set;
    repaint();
}

void StatDock::setLabelled(bool set) {
    labelled = set;
    repaint();
}

void StatDock::setLabel(const QString& set) {
    label = set;
    repaint();
}

void StatDock::setFill(int set) {
    fill = set;
    repaint();
}

void StatDock::setColor(const QColor& set) {
    colorUpper = set;
    colorUpperInactive = colorUpper.dark();
    repaint();
}

void StatDock::clearHistory(void) {
    for (i = 0; i < DOCK_SIZE; i++)
        bufUpper[i] = bufLower[i] = 0;
    repaint();
}

void StatDock::addPercentReading(int upper, int lower) {
    // Rescale the readings to a measure in pixels.
    upper = (int) (((float) upper) / DOCK_SCALE);
    lower = (split ? (int) (((float) lower) / DOCK_SCALE) : 0);

    if (soft) {
        // Do a bit of juggling to obtain a soft reading.
        oldUpper = bufUpper[pos];
        oldLower = bufLower[pos];
        if(++pos >= DOCK_SIZE)
            pos = 0;

        // Modify the upper reading.
        if (upper > oldUpper + SOFT_STEP)
            upper = oldUpper + SOFT_STEP;
        else if (upper < oldUpper - SOFT_STEP)
            upper = oldUpper - SOFT_STEP;
        bufUpper[pos] = upper;

        // Modify the lower reading.
        if (split) {
            if (lower > oldLower + SOFT_STEP)
                lower = oldLower + SOFT_STEP;
            else if (lower < oldLower - SOFT_STEP)
                lower = oldLower - SOFT_STEP;
        }
        bufLower[pos] = lower;
    } else {
        // Just a straight update.
        if(++pos >= DOCK_SIZE)
            pos = 0;
        bufUpper[pos] = upper;
        bufLower[pos] = lower;
    }

    // Refresh the diagram.
    repaint();
}

void StatDock::paintEvent(QPaintEvent*) {
    QPainter p(this);

    // Start by drawing the grid.
    if(grid) {
        p.setPen((active) ? colorGrid : colorGridInactive);
        p.drawLine(0, 4, 23, 4);
        p.drawLine(0, 9, 23, 9);
        p.drawLine(0, 14, 23, 14);
        p.drawLine(0, 19, 23, 19);
    }

    if(fill == fillShaded) {
        // Shaded
        for(i = 0; i < 24; i++) {
            tmpPos = (pos + i + 1) % DOCK_SIZE;
            for(j = 0; j <= bufUpper[tmpPos]; j++) {
                if (bufUpper[tmpPos] == 0 || j == 0)
                    p.setPen(colorBlack);
                else if (active)
                    p.setPen(colorUpper.dark((100 * bufUpper[tmpPos]) / j));
                else
                    p.setPen(colorUpper.dark((200 * bufUpper[tmpPos]) / j));

                if(split)
                    p.drawPoint(i, DOCK_SIZE - 1 - j - bufLower[tmpPos]);
                else
                    p.drawPoint(i, DOCK_SIZE - j);
            }

            if(split) {
                for(j = 0; j <= bufLower[tmpPos]; j++) {
                    if (bufLower[tmpPos] == 0 || j == 0)
                        p.setPen(colorBlack);
                    else if (active)
                        p.setPen(colorLower.dark((100 * bufLower[tmpPos]) / j));
                    else
                        p.setPen(colorLower.dark((200 * bufLower[tmpPos]) / j));

                    p.drawPoint(i, 23 - j);
                }
            }
        }
    } else if (fill == fillBars) {
        // Bars
        if(split) {
            // Draw the upper bars, then the lower to save on pen
            // adjustments.
            p.setPen(active ? colorUpper : colorUpperInactive);
            for(i = 0; i < 24; i++) {
                tmpPos = (pos + i + 1) % DOCK_SIZE;
                p.drawLine(i, DOCK_SIZE - 1 - bufUpper[tmpPos] -
                    bufLower[tmpPos], i, DOCK_SIZE - 1 - bufLower[tmpPos]);
            }
            p.setPen(active ? colorLower : colorLowerInactive);
            for(i = 0; i < 24; i++) {
                tmpPos = (pos + i + 1) % DOCK_SIZE;
                p.drawLine(i, DOCK_SIZE - 1 - bufLower[tmpPos],
                    i, DOCK_SIZE - 1);
            }
        } else {
            p.setPen(active ? colorUpper : colorUpperInactive);
            for(i = 0; i < 24; i++) {
                tmpPos = (pos + i + 1) % DOCK_SIZE;
                p.drawLine(i, DOCK_SIZE - 1 - bufUpper[tmpPos],
                    i, DOCK_SIZE - 1);
            }
        }
    } else {
        // Lines
        if(split) {
            // Draw the upper line, then the lower to save on pen
            // adjustments.
            p.setPen(active ? colorUpper : colorUpperInactive);
            for(i = 0; i < 24; i++) {
                tmpPos = (pos + i + 1) % DOCK_SIZE;
                p.drawPoint(i, DOCK_SIZE - 1 -
                    bufUpper[tmpPos] - bufLower[tmpPos]);
            }
            p.setPen(active ? colorLower : colorLowerInactive);
            for(i = 0; i < 24; i++) {
                tmpPos = (pos + i + 1) % DOCK_SIZE;
                p.drawPoint(i, DOCK_SIZE - 1 - bufLower[tmpPos]);
            }
        } else {
            p.setPen(active ? colorUpper : colorUpperInactive);
            for(i = 0; i < 24; i++) {
                tmpPos = (pos + i + 1) % DOCK_SIZE;
                p.drawPoint(i, DOCK_SIZE - 1 - bufUpper[tmpPos]);
            }
        }
    }

    // Finally label the diagrams.
    if(labelled) {
        p.setFont(QFont("Helvetica", 8));
        p.setPen((active) ? colorLabel : colorLabelInactive);
        p.drawText(rect(), AlignLeft | AlignTop, label);
    }
}

#include "statdock.moc"
