1 /*
2     SPDX-FileCopyrightText: 2012-2013 Evan Teran <evan.teran@gmail.com>
3     SPDX-FileCopyrightText: 2006 Michel Marti <mma@objectxp.com>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #include "kcalc_bitset.h"
9 #include "bitbutton.h"
10 
11 #include <KLocalizedString>
12 #include <QButtonGroup>
13 #include <QGridLayout>
14 #include <QHBoxLayout>
15 #include <QLabel>
16 #include <QPainter>
17 
18 // TODO: I think it would actually be appropriate to use a std::bitset<64>
19 //       for the internal representation of this class perhaps
20 //       the only real caveat is the conversion to/from quint64
21 
22 //------------------------------------------------------------------------------
23 // Name: paintEvent
24 // Desc: draws the button
25 //------------------------------------------------------------------------------
paintEvent(QPaintEvent *)26 void BitButton::paintEvent(QPaintEvent *)
27 {
28     uint8_t alpha = 0x60;
29     QPainter painter(this);
30     painter.setRenderHint(QPainter::Antialiasing, true);
31     QPen pen(palette().text(), 1);
32     pen.setJoinStyle(Qt::MiterJoin);
33     painter.setPen(pen);
34 
35     if (on_) {
36         painter.setBrush(palette().text());
37         alpha = 0xB0;
38     } else {
39         painter.setBrush(palette().base());
40     }
41 
42     if (over_) {
43         painter.setBrush(QColor(palette().text().color().red(), palette().text().color().green(), palette().text().color().blue(), alpha));
44     }
45 
46     painter.drawRect(rect().adjusted(1, 1, -1, -1));
47 }
48 
49 //------------------------------------------------------------------------------
50 // Name: KCalcBitset
51 // Desc: constructor
52 //------------------------------------------------------------------------------
KCalcBitset(QWidget * parent)53 KCalcBitset::KCalcBitset(QWidget *parent)
54     : QFrame(parent)
55     , bit_button_group_(new QButtonGroup(this))
56     , value_(0)
57 {
58     setFrameStyle(QFrame::Panel | QFrame::Sunken);
59 
60     connect(bit_button_group_, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &KCalcBitset::slotToggleBit);
61 
62     // smaller label font
63     QFont fnt = font();
64     if (fnt.pointSize() > 6) {
65         fnt.setPointSize(fnt.pointSize() - 1);
66     }
67 
68     // main layout
69     auto layout = new QGridLayout(this);
70     layout->setContentsMargins(2, 2, 2, 2);
71     layout->setSpacing(0);
72 
73     // create bits
74     int bitCounter = 63;
75     for (int rows = 0; rows < 2; rows++) {
76         for (int cols = 0; cols < 4; cols++) {
77             // two rows of four words
78             auto const wordlayout = new QHBoxLayout();
79             wordlayout->setContentsMargins(2, 2, 2, 2);
80             wordlayout->setSpacing(2);
81             layout->addLayout(wordlayout, rows, cols);
82 
83             for (int bit = 0; bit < 8; bit++) {
84                 auto const tmpBitButton = new BitButton(this);
85                 tmpBitButton->setToolTip(i18n("Bit %1 = %2", bitCounter, 1ULL << bitCounter));
86                 wordlayout->addWidget(tmpBitButton);
87                 bit_button_group_->addButton(tmpBitButton, bitCounter);
88                 bitCounter--;
89             }
90 
91             // label word
92             auto label = new QLabel(this);
93             label->setText(QString::number(bitCounter + 1));
94             label->setFont(fnt);
95             wordlayout->addWidget(label);
96         }
97     }
98 }
99 
100 //------------------------------------------------------------------------------
101 // Name: setValue
102 // Desc: set the value of the bitset based on an unsigned 64-bit number
103 //------------------------------------------------------------------------------
setValue(quint64 value)104 void KCalcBitset::setValue(quint64 value)
105 {
106     if (value_ == value) {
107         // don't waste time if there was no change..
108         return;
109     }
110 
111     value_ = value;
112 
113     // set each bit button
114     for (int i = 0; i < 64; i++) {
115         if (auto bb = qobject_cast<BitButton *>(bit_button_group_->button(i))) {
116             bb->setOn(value & 1);
117         }
118         value >>= 1;
119     }
120 }
121 
122 //------------------------------------------------------------------------------
123 // Name: getValue
124 // Desc: returns the bitset value as an unsigned 64-bit number
125 //------------------------------------------------------------------------------
getValue() const126 quint64 KCalcBitset::getValue() const
127 {
128     return value_;
129 }
130 
131 //------------------------------------------------------------------------------
132 // Name: slotToggleBit
133 // Desc: inverts the value of a single bit
134 //------------------------------------------------------------------------------
slotToggleBit(QAbstractButton * button)135 void KCalcBitset::slotToggleBit(QAbstractButton *button)
136 {
137     if (button) {
138         const int bit = bit_button_group_->id(button);
139         const quint64 nv = getValue() ^ (1LL << bit);
140         setValue(nv);
141         Q_EMIT valueChanged(value_);
142     }
143 }
144