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
17// TODO: I think it would actually be appropriate to use a std::bitset<64>
18// for the internal representation of this class perhaps
19// the only real caveat is the conversion to/from quint64
20
21//------------------------------------------------------------------------------
22// Name: KCalcBitset
23// Desc: constructor
24//------------------------------------------------------------------------------
25KCalcBitset::KCalcBitset(QWidget *parent)
26 : QFrame(parent)
27 , bit_button_group_(new QButtonGroup(this))
28 , value_(0)
29{
30 setFrameStyle(QFrame::Panel | QFrame::Sunken);
31
32 connect(bit_button_group_, &QButtonGroup::buttonClicked, this, &KCalcBitset::slotToggleBit);
33
34 // smaller label font
35 QFont fnt = font();
36 if (fnt.pointSize() > 6) {
37 fnt.setPointSize(fnt.pointSize() - 1);
38 }
39
40 // main layout
41 auto layout = new QGridLayout(this);
42 layout->setContentsMargins(2, 2, 2, 2);
43 layout->setSpacing(0);
44
45 // create bits
46 int bitCounter = 63;
47 for (int rows = 0; rows < 2; rows++) {
48 for (int cols = 0; cols < 4; cols++) {
49 // two rows of four words
50 auto const wordlayout = new QHBoxLayout();
51 wordlayout->setContentsMargins(2, 2, 2, 2);
52 wordlayout->setSpacing(2);
53 layout->addLayout(wordlayout, rows, cols);
54
55 for (int bit = 0; bit < 8; bit++) {
56 auto const tmpBitButton = new BitButton(this);
57 tmpBitButton->setToolTip(i18n("Bit %1 = %2", bitCounter, 1ULL << bitCounter));
58 wordlayout->addWidget(tmpBitButton);
59 wordlayout->setStretch(bit, 1);
60 bit_button_group_->addButton(tmpBitButton, bitCounter);
61 bitCounter--;
62 }
63
64 // label word
65 auto label = new QLabel(this);
66 label->setText(QString::number(bitCounter + 1));
67 label->setFont(fnt);
68 label->setMinimumSize(label->fontMetrics().size(Qt::TextSingleLine, QStringLiteral("56"))); // Make all labels have same size
69 wordlayout->addWidget(label);
70 wordlayout->setStretch(8, 1);
71 }
72 layout->setRowStretch(rows, 1);
73 }
74
75 // layout stretch for columns
76 for (int cols = 0; cols < 4; cols++) {
77 layout->setColumnStretch(cols, 1);
78 }
79
80 // store current aspect ratio (using width:height)
81 QSize initialSize(size());
82 if (initialSize.height() != 0.0 && float(initialSize.width()) / float(initialSize.height()) < 2.5) {
83 ratio_ = float(initialSize.width()) / float(initialSize.height());
84 } else {
85 ratio_ = 1.355163727959698; // 538/397
86 }
87}
88
89//------------------------------------------------------------------------------
90// Name: setValue
91// Desc: set the value of the bitset based on an unsigned 64-bit number
92//------------------------------------------------------------------------------
93void KCalcBitset::setValue(quint64 value)
94{
95 if (value_ == value) {
96 // don't waste time if there was no change.
97 return;
98 }
99
100 value_ = value;
101
102 // set each bit button
103 for (int i = 0; i < 64; i++) {
104 if (auto bb = qobject_cast<BitButton *>(bit_button_group_->button(i))) {
105 bb->setOn(value & 1);
106 }
107 value >>= 1;
108 }
109}
110
111//------------------------------------------------------------------------------
112// Name: getValue
113// Desc: returns the bitset value as an unsigned 64-bit number
114//------------------------------------------------------------------------------
115quint64 KCalcBitset::getValue() const
116{
117 return value_;
118}
119
120//------------------------------------------------------------------------------
121// Name: slotToggleBit
122// Desc: inverts the value of a single bit
123//------------------------------------------------------------------------------
124void KCalcBitset::slotToggleBit(QAbstractButton *button)
125{
126 if (button) {
127 const int bit = bit_button_group_->id(button);
128 const quint64 nv = getValue() ^ (1LL << bit);
129 setValue(nv);
130 Q_EMIT valueChanged(value_);
131 }
132}
133
134//------------------------------------------------------------------------------
135// Name: resizeEvent
136// Desc: make sure all bitButtons have the same size
137//------------------------------------------------------------------------------
138void KCalcBitset::resizeEvent(QResizeEvent *event)
139{
140 // Call the overridden resize event
141 QFrame::resizeEvent(event);
142
143 // Set our maximum size based on the space available in the parent (to keep aspect ratio)
144 QWidget *parent = parentWidget();
145 if (parent) {
146 QSize maxSize(parent->contentsRect().width(), parent->contentsRect().height());
147 if (maxSize.width() != 0 && maxSize.height() != 0) {
148 float actualRatio = float(maxSize.width()) / float(maxSize.height());
149
150 if (actualRatio > ratio_) {
151 // available space is too wide, limit width
152 maxSize.setWidth(ratio_ * maxSize.height());
153 } else if (actualRatio < ratio_) {
154 // available space is too tall, limit height
155 maxSize.setHeight(maxSize.width() / ratio_);
156 }
157
158 setMaximumSize(maxSize.width(), maxSize.height());
159 }
160 }
161
162 // Get the minimum size of all buttons
163 int minWidth = INT_MAX;
164 int minHeight = INT_MAX;
165 for (QObject *obj : bit_button_group_->buttons()) {
166 if (auto const button = qobject_cast<BitButton *>(obj)) {
167 minWidth = qMin(minWidth, button->rect().width());
168 minHeight = qMin(minHeight, button->rect().height());
169 }
170 }
171
172 // If this worked, set the renderSize for all BitButtons
173 if (minWidth != INT_MAX && minHeight != INT_MAX) {
174 // Make sure the size is square
175 if (minWidth > minHeight)
176 minWidth = minHeight;
177 else if (minHeight > minWidth)
178 minHeight = minWidth;
179
180 // Set it for all buttons
181 for (QObject *obj : bit_button_group_->buttons()) {
182 if (auto const button = qobject_cast<BitButton *>(obj)) {
183 QSize size = QSize(button->renderSize());
184 size.setWidth(minWidth);
185 size.setHeight(minHeight);
186 button->setRenderSize(size);
187 }
188 }
189 }
190
191 updateGeometry();
192}
193
194#include "moc_kcalc_bitset.cpp"
195

source code of kcalc/kcalc_bitset.cpp