File indexing completed on 2022-07-03 17:05:47

0001 /*
0002     SPDX-FileCopyrightText: 2001-2013 Evan Teran <evan.teran@gmail.com>
0003     SPDX-FileCopyrightText: 1996-2000 Bernd Johannes Wuebben <wuebben@kde.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "kcalc_button.h"
0009 
0010 #include <QAbstractTextDocumentLayout>
0011 #include <QApplication>
0012 #include <QPainter>
0013 #include <QStyleOptionButton>
0014 #include <QTextDocument>
0015 
0016 //------------------------------------------------------------------------------
0017 // Name: KCalcButton
0018 // Desc: constructor
0019 //------------------------------------------------------------------------------
0020 KCalcButton::KCalcButton(QWidget *parent)
0021     : QPushButton(parent)
0022     , mode_flags_(ModeNormal)
0023     , size_()
0024 {
0025     setAcceptDrops(true); // allow color drops
0026     setFocusPolicy(Qt::TabFocus);
0027     setAutoDefault(false);
0028 
0029     // use preferred size policy for vertical
0030     setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
0031     setAttribute(Qt::WA_LayoutUsesWidgetRect);
0032 }
0033 
0034 //------------------------------------------------------------------------------
0035 // Name: KCalcButton
0036 // Desc: constructor
0037 //------------------------------------------------------------------------------
0038 KCalcButton::KCalcButton(const QString &label, QWidget *parent, const QString &tooltip)
0039     : QPushButton(label, parent)
0040     , mode_flags_(ModeNormal)
0041     , size_()
0042 {
0043     setAutoDefault(false);
0044     addMode(ModeNormal, label, tooltip);
0045 
0046     // use preferred size policy for vertical
0047     setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
0048     setAttribute(Qt::WA_LayoutUsesWidgetRect);
0049 }
0050 
0051 //------------------------------------------------------------------------------
0052 // Name: addMode
0053 // Desc:
0054 //------------------------------------------------------------------------------
0055 void KCalcButton::addMode(ButtonModeFlags mode, const QString &label, const QString &tooltip)
0056 {
0057     if (mode_.contains(mode)) {
0058         mode_.remove(mode);
0059     }
0060 
0061     mode_[mode] = ButtonMode(label, tooltip);
0062     calcSizeHint();
0063 
0064     // Need to put each button into default mode first
0065     if (mode == ModeNormal) {
0066         slotSetMode(ModeNormal, true);
0067     }
0068 }
0069 
0070 //------------------------------------------------------------------------------
0071 // Name: slotSetMode
0072 // Desc:
0073 //------------------------------------------------------------------------------
0074 void KCalcButton::slotSetMode(ButtonModeFlags mode, bool flag)
0075 {
0076     ButtonModeFlags new_mode;
0077 
0078     if (flag) { // if the specified mode is to be set (i.e. flag = true)
0079         new_mode = ButtonModeFlags(mode_flags_ | mode);
0080     } else if (mode_flags_ & mode) { // if the specified mode is to be cleared (i.e. flag = false)
0081         new_mode = ButtonModeFlags(mode_flags_ - mode);
0082     } else {
0083         return; // nothing to do
0084     }
0085 
0086     if (mode_.contains(new_mode)) {
0087         // save shortcut, because setting label erases it
0088         QKeySequence current_shortcut = shortcut();
0089 
0090         setText(mode_[new_mode].label);
0091         this->setToolTip(mode_[new_mode].tooltip);
0092         mode_flags_ = new_mode;
0093 
0094         // restore shortcut
0095         setShortcut(current_shortcut);
0096     }
0097 
0098     // this is necessary for people pressing CTRL and changing mode at
0099     // the same time...
0100     if (show_shortcut_mode_) {
0101         slotSetAccelDisplayMode(true);
0102     }
0103 
0104     update();
0105 }
0106 
0107 //------------------------------------------------------------------------------
0108 // Name: slotSetAccelDisplayMode
0109 // Desc:
0110 //------------------------------------------------------------------------------
0111 void KCalcButton::slotSetAccelDisplayMode(bool flag)
0112 {
0113     show_shortcut_mode_ = flag;
0114 
0115     // save shortcut, because setting label erases it
0116     QKeySequence current_shortcut = shortcut();
0117 
0118     if (flag) {
0119         setText(shortcut().toString(QKeySequence::NativeText));
0120     } else {
0121         setText(mode_[mode_flags_].label);
0122     }
0123 
0124     // restore shortcut
0125     setShortcut(current_shortcut);
0126     update();
0127 }
0128 
0129 //------------------------------------------------------------------------------
0130 // Name: paintEvent
0131 // Desc: draws the button
0132 //------------------------------------------------------------------------------
0133 void KCalcButton::paintEvent(QPaintEvent *)
0134 {
0135     QPainter p(this);
0136     QStyleOptionButton option;
0137     initStyleOption(&option);
0138     const bool is_down = isDown() || isChecked();
0139     const int x_offset = is_down ? style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, &option, this) : 0;
0140     const int y_offset = is_down ? style()->pixelMetric(QStyle::PM_ButtonShiftVertical, &option, this) : 0;
0141 
0142     // draw bevel
0143     style()->drawControl(QStyle::CE_PushButtonBevel, &option, &p, this);
0144 
0145     // draw label...
0146     p.save();
0147 
0148     // rant: Qt4 needs QSimpleRichText, dammit!
0149     QTextDocument doc;
0150     QAbstractTextDocumentLayout::PaintContext context;
0151     doc.setHtml(QLatin1String("<center>") + text() + QLatin1String("</center>"));
0152     doc.setDefaultFont(font());
0153     context.palette = palette();
0154     QColor color = text_color_;
0155     if (!isEnabled()) {
0156         color.setAlphaF(0.6);
0157     }
0158     context.palette.setColor(QPalette::Text, color);
0159 
0160     p.translate((width() / 2 - doc.size().width() / 2) + x_offset, (height() / 2 - doc.size().height() / 2) + y_offset);
0161     doc.documentLayout()->draw(&p, context);
0162     p.restore();
0163 
0164     // draw focus
0165     if (hasFocus()) {
0166         QStyleOptionFocusRect fropt;
0167         fropt.QStyleOption::operator=(option);
0168         fropt.rect = style()->subElementRect(QStyle::SE_PushButtonFocusRect, &option, this);
0169         style()->drawPrimitive(QStyle::PE_FrameFocusRect, &fropt, &p, this);
0170     }
0171 }
0172 
0173 //------------------------------------------------------------------------------
0174 // Name: sizeHint
0175 // Desc:
0176 //------------------------------------------------------------------------------
0177 QSize KCalcButton::sizeHint() const
0178 {
0179     // reimplemented to provide a smaller button
0180     return size_;
0181 }
0182 
0183 //------------------------------------------------------------------------------
0184 // Name: calcSizeHint
0185 // Desc:
0186 //------------------------------------------------------------------------------
0187 void KCalcButton::calcSizeHint()
0188 {
0189     int margin = style()->pixelMetric(QStyle::PM_ButtonMargin, nullptr, this);
0190 
0191     // want narrower margin than normal
0192     margin = qMax(margin / 2, 3);
0193 
0194     // simply use font size of a single letter
0195     size_ = fontMetrics().size(0, QStringLiteral("M"));
0196 
0197     size_ += QSize(margin * 2, margin * 2);
0198 }
0199 
0200 //------------------------------------------------------------------------------
0201 // Name: setFont
0202 // Desc:
0203 //------------------------------------------------------------------------------
0204 void KCalcButton::setFont(const QFont &fnt)
0205 {
0206     QPushButton::setFont(fnt);
0207     calcSizeHint();
0208 }
0209 
0210 //------------------------------------------------------------------------------
0211 // Name: setTextColor
0212 // Desc:
0213 //------------------------------------------------------------------------------
0214 void KCalcButton::setTextColor(const QColor &color)
0215 {
0216     text_color_ = color;
0217     update();
0218 }
0219 
0220 //------------------------------------------------------------------------------
0221 // Name: setText
0222 // Desc:
0223 //------------------------------------------------------------------------------
0224 void KCalcButton::setText(const QString &text)
0225 {
0226     QPushButton::setText(text);
0227 
0228     // normal mode may not have been explicitly set
0229     if (mode_[ModeNormal].label.isEmpty()) {
0230         mode_[ModeNormal].label = text;
0231     }
0232 
0233     calcSizeHint();
0234 }
0235 
0236 //------------------------------------------------------------------------------
0237 // Name: setToolTip
0238 // Desc:
0239 //------------------------------------------------------------------------------
0240 void KCalcButton::setToolTip(const QString &tip)
0241 {
0242     QPushButton::setToolTip(tip);
0243 
0244     // normal mode may not have been explicitly set
0245     if (mode_[ModeNormal].tooltip.isEmpty()) {
0246         mode_[ModeNormal].tooltip = tip;
0247     }
0248 }