File indexing completed on 2024-04-14 05:42:54

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