/*
    Copyright (C) 2006  Michel Marti <mma@objectxp.com>

    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.

    This program 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 this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

*/

#include "kcalc_bitset.h"

#include <QApplication>
#include <QGridLayout>
#include <QLabel>
#include <QHBoxLayout>
#include <QPainter>

#include "kcalc_bitset.moc"

BitButton::BitButton(QWidget *parent) : QAbstractButton(parent), on(false)
{
    setFocusPolicy(Qt::ClickFocus);   // too many bits for tab focus

    // size button by font
    QSize size = fontMetrics().size(0, "M");
    if (size.width() < size.height()) {
        size.setHeight(size.width());
    } else {
        size.setWidth(size.height());
    }
    setFixedSize(size.expandedTo(QApplication::globalStrut()));
}

bool BitButton::isOn() const
{
    return on;
}

void BitButton::setOn(bool value)
{
    on = value;
    update();
}

void BitButton::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    QPen pen(palette().text(), 2);
    pen.setJoinStyle(Qt::MiterJoin);
    painter.setPen(pen);

    if (on) painter.setBrush(palette().text());
    else    painter.setBrush(palette().base());

    painter.drawRect(rect().adjusted(1, 1, -1, -1));
}


KCalcBitset::KCalcBitset(QWidget *parent)
        : QFrame(parent), mValue(0)
{
    setFrameStyle(QFrame::Panel | QFrame::Sunken);
    bitButtonGroup = new QButtonGroup(this);
    connect(bitButtonGroup, SIGNAL(buttonClicked(int)),
            SLOT(slotToggleBit(int)));

    // smaller label font
    QFont fnt = font();
    if (fnt.pointSize() > 6) fnt.setPointSize(fnt.pointSize() - 1);

    // main layout
    QGridLayout *layout = new QGridLayout(this);
    layout->setMargin(2);
    layout->setSpacing(0);

    // create bits
    int bitCounter = 63;
    for (int rows = 0; rows < 2; rows++) {
        for (int cols = 0; cols < 4; cols++) {
            // two rows of four words
            QHBoxLayout *wordlayout = new QHBoxLayout();
            wordlayout->setMargin(2);
            wordlayout->setSpacing(2);
            layout->addLayout(wordlayout, rows, cols);

            for (int bit = 0; bit < 8; bit++) {
                BitButton *tmpBitButton = new BitButton(this);
                wordlayout->addWidget(tmpBitButton);
                bitButtonGroup->addButton(tmpBitButton, bitCounter);
                bitCounter--;
            }

            // label word
            QLabel *label = new QLabel(this);
            label->setText(QString::number(bitCounter + 1));
            label->setFont(fnt);
            wordlayout->addWidget(label);

        }
    }
}

void KCalcBitset::setValue(unsigned long long value)
{
    if (mValue == value) return;

    mValue = value;
    for (int i = 0; i < 64; i++) {
        BitButton *bb = qobject_cast<BitButton*>(bitButtonGroup->button(i));
        if (bb) bb->setOn(value & 1);
        value >>= 1;
    }
}

unsigned long long KCalcBitset::getValue()
{
    return mValue;
}

void KCalcBitset::slotToggleBit(int bit)
{
    unsigned long long nv = getValue() ^(1LL << bit);
    setValue(nv);
    emit valueChanged(mValue);
}

