File indexing completed on 2024-04-21 05:50:05
0001 /* 0002 SPDX-FileCopyrightText: 2012-2013 Evan Teran <evan.teran@gmail.com> 0003 SPDX-FileCopyrightText: 2006 Michel Marti <mma@objectxp.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "kcalc_bitset.h" 0009 #include "bitbutton.h" 0010 0011 #include <KLocalizedString> 0012 #include <QButtonGroup> 0013 #include <QGridLayout> 0014 #include <QHBoxLayout> 0015 #include <QLabel> 0016 0017 // TODO: I think it would actually be appropriate to use a std::bitset<64> 0018 // for the internal representation of this class perhaps 0019 // the only real caveat is the conversion to/from quint64 0020 0021 //------------------------------------------------------------------------------ 0022 // Name: KCalcBitset 0023 // Desc: constructor 0024 //------------------------------------------------------------------------------ 0025 KCalcBitset::KCalcBitset(QWidget *parent) 0026 : QFrame(parent) 0027 , bit_button_group_(new QButtonGroup(this)) 0028 , value_(0) 0029 { 0030 setFrameStyle(QFrame::Panel | QFrame::Sunken); 0031 0032 connect(bit_button_group_, &QButtonGroup::buttonClicked, this, &KCalcBitset::slotToggleBit); 0033 0034 // smaller label font 0035 QFont fnt = font(); 0036 if (fnt.pointSize() > 6) { 0037 fnt.setPointSize(fnt.pointSize() - 1); 0038 } 0039 0040 // main layout 0041 auto layout = new QGridLayout(this); 0042 layout->setContentsMargins(2, 2, 2, 2); 0043 layout->setSpacing(0); 0044 0045 // create bits 0046 int bitCounter = 63; 0047 for (int rows = 0; rows < 2; rows++) { 0048 for (int cols = 0; cols < 4; cols++) { 0049 // two rows of four words 0050 auto const wordlayout = new QHBoxLayout(); 0051 wordlayout->setContentsMargins(2, 2, 2, 2); 0052 wordlayout->setSpacing(2); 0053 layout->addLayout(wordlayout, rows, cols); 0054 0055 for (int bit = 0; bit < 8; bit++) { 0056 auto const tmpBitButton = new BitButton(this); 0057 tmpBitButton->setToolTip(i18n("Bit %1 = %2", bitCounter, 1ULL << bitCounter)); 0058 wordlayout->addWidget(tmpBitButton); 0059 wordlayout->setStretch(bit, 1); 0060 bit_button_group_->addButton(tmpBitButton, bitCounter); 0061 bitCounter--; 0062 } 0063 0064 // label word 0065 auto label = new QLabel(this); 0066 label->setText(QString::number(bitCounter + 1)); 0067 label->setFont(fnt); 0068 label->setMinimumSize(label->fontMetrics().size(Qt::TextSingleLine, QStringLiteral("56"))); // Make all labels have same size 0069 wordlayout->addWidget(label); 0070 wordlayout->setStretch(8, 1); 0071 } 0072 layout->setRowStretch(rows, 1); 0073 } 0074 0075 // layout stretch for columns 0076 for (int cols = 0; cols < 4; cols++) { 0077 layout->setColumnStretch(cols, 1); 0078 } 0079 0080 // store current aspect ratio (using width:height) 0081 QSize initialSize(size()); 0082 if (initialSize.height() != 0.0 && float(initialSize.width()) / float(initialSize.height()) < 2.5) { 0083 ratio_ = float(initialSize.width()) / float(initialSize.height()); 0084 } else { 0085 ratio_ = 1.355163727959698; // 538/397 0086 } 0087 } 0088 0089 //------------------------------------------------------------------------------ 0090 // Name: setValue 0091 // Desc: set the value of the bitset based on an unsigned 64-bit number 0092 //------------------------------------------------------------------------------ 0093 void KCalcBitset::setValue(quint64 value) 0094 { 0095 if (value_ == value) { 0096 // don't waste time if there was no change. 0097 return; 0098 } 0099 0100 value_ = value; 0101 0102 // set each bit button 0103 for (int i = 0; i < 64; i++) { 0104 if (auto bb = qobject_cast<BitButton *>(bit_button_group_->button(i))) { 0105 bb->setOn(value & 1); 0106 } 0107 value >>= 1; 0108 } 0109 } 0110 0111 //------------------------------------------------------------------------------ 0112 // Name: getValue 0113 // Desc: returns the bitset value as an unsigned 64-bit number 0114 //------------------------------------------------------------------------------ 0115 quint64 KCalcBitset::getValue() const 0116 { 0117 return value_; 0118 } 0119 0120 //------------------------------------------------------------------------------ 0121 // Name: slotToggleBit 0122 // Desc: inverts the value of a single bit 0123 //------------------------------------------------------------------------------ 0124 void KCalcBitset::slotToggleBit(QAbstractButton *button) 0125 { 0126 if (button) { 0127 const int bit = bit_button_group_->id(button); 0128 const quint64 nv = getValue() ^ (1LL << bit); 0129 setValue(nv); 0130 Q_EMIT valueChanged(value_); 0131 } 0132 } 0133 0134 //------------------------------------------------------------------------------ 0135 // Name: resizeEvent 0136 // Desc: make sure all bitButtons have the same size 0137 //------------------------------------------------------------------------------ 0138 void KCalcBitset::resizeEvent(QResizeEvent *event) 0139 { 0140 // Call the overridden resize event 0141 QFrame::resizeEvent(event); 0142 0143 // Set our maximum size based on the space available in the parent (to keep aspect ratio) 0144 QWidget *parent = parentWidget(); 0145 if (parent) { 0146 QSize maxSize(parent->contentsRect().width(), parent->contentsRect().height()); 0147 if (maxSize.width() != 0 && maxSize.height() != 0) { 0148 float actualRatio = float(maxSize.width()) / float(maxSize.height()); 0149 0150 if (actualRatio > ratio_) { 0151 // available space is too wide, limit width 0152 maxSize.setWidth(ratio_ * maxSize.height()); 0153 } else if (actualRatio < ratio_) { 0154 // available space is too tall, limit height 0155 maxSize.setHeight(maxSize.width() / ratio_); 0156 } 0157 0158 setMaximumSize(maxSize.width(), maxSize.height()); 0159 } 0160 } 0161 0162 // Get the minimum size of all buttons 0163 int minWidth = INT_MAX; 0164 int minHeight = INT_MAX; 0165 for (QObject *obj : bit_button_group_->buttons()) { 0166 if (auto const button = qobject_cast<BitButton *>(obj)) { 0167 minWidth = qMin(minWidth, button->rect().width()); 0168 minHeight = qMin(minHeight, button->rect().height()); 0169 } 0170 } 0171 0172 // If this worked, set the renderSize for all BitButtons 0173 if (minWidth != INT_MAX && minHeight != INT_MAX) { 0174 // Make sure the size is square 0175 if (minWidth > minHeight) 0176 minWidth = minHeight; 0177 else if (minHeight > minWidth) 0178 minHeight = minWidth; 0179 0180 // Set it for all buttons 0181 for (QObject *obj : bit_button_group_->buttons()) { 0182 if (auto const button = qobject_cast<BitButton *>(obj)) { 0183 QSize size = QSize(button->renderSize()); 0184 size.setWidth(minWidth); 0185 size.setHeight(minHeight); 0186 button->setRenderSize(size); 0187 } 0188 } 0189 } 0190 0191 updateGeometry(); 0192 } 0193 0194 #include "moc_kcalc_bitset.cpp"