1/*
2 SPDX-FileCopyrightText: 2001-2013 Evan Teran <evan.teran@gmail.com>
3 SPDX-FileCopyrightText: 1996-2000 Bernd Johannes Wuebben <wuebben@kde.org>
4
5 SPDX-License-Identifier: GPL-2.0-or-later
6*/
7
8#include "kcalc_button.h"
9
10#include <QAbstractTextDocumentLayout>
11#include <QPainter>
12#include <QStyleOptionButton>
13#include <QTextDocument>
14
15//------------------------------------------------------------------------------
16// Name: KCalcButton
17// Desc: constructor
18//------------------------------------------------------------------------------
19KCalcButton::KCalcButton(QWidget *parent)
20 : QPushButton(parent)
21 , mode_flags_(ModeNormal)
22 , size_()
23{
24 setAcceptDrops(true); // allow color drops
25 setFocusPolicy(Qt::TabFocus);
26 setAutoDefault(false);
27
28 // use preferred size policy for vertical
29 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
30 setAttribute(Qt::WA_LayoutUsesWidgetRect);
31}
32
33//------------------------------------------------------------------------------
34// Name: KCalcButton
35// Desc: constructor
36//------------------------------------------------------------------------------
37KCalcButton::KCalcButton(const QString &label, QWidget *parent, const QString &tooltip)
38 : QPushButton(label, parent)
39 , mode_flags_(ModeNormal)
40 , size_()
41{
42 setAutoDefault(false);
43 addMode(ModeNormal, label, tooltip);
44
45 // use preferred size policy for vertical
46 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
47 setAttribute(Qt::WA_LayoutUsesWidgetRect);
48}
49
50//------------------------------------------------------------------------------
51// Name: addMode
52// Desc:
53//------------------------------------------------------------------------------
54void KCalcButton::addMode(ButtonModeFlags mode, const QString &label, const QString &tooltip)
55{
56 if (mode_.contains(mode)) {
57 mode_.remove(mode);
58 }
59
60 mode_[mode] = ButtonMode(label, tooltip);
61 calcSizeHint();
62
63 // Need to put each button into default mode first
64 if (mode == ModeNormal) {
65 slotSetMode(ModeNormal, true);
66 }
67}
68
69//------------------------------------------------------------------------------
70// Name: slotSetMode
71// Desc:
72//------------------------------------------------------------------------------
73void KCalcButton::slotSetMode(ButtonModeFlags mode, bool flag)
74{
75 ButtonModeFlags new_mode;
76
77 if (flag) { // if the specified mode is to be set (i.e. flag = true)
78 new_mode = ButtonModeFlags(mode_flags_ | mode);
79 } else if (mode_flags_ & mode) { // if the specified mode is to be cleared (i.e. flag = false)
80 new_mode = ButtonModeFlags(mode_flags_ - mode);
81 } else {
82 return; // nothing to do
83 }
84
85 if (mode_.contains(new_mode)) {
86 // save shortcut, because setting label erases it
87 QKeySequence current_shortcut = shortcut();
88
89 setText(mode_[new_mode].label);
90 this->setToolTip(mode_[new_mode].tooltip);
91 mode_flags_ = new_mode;
92
93 // restore shortcut
94 setShortcut(current_shortcut);
95 }
96
97 // this is necessary for people pressing CTRL and changing mode at
98 // the same time...
99 if (show_shortcut_mode_) {
100 slotSetAccelDisplayMode(flag: true);
101 }
102
103 update();
104}
105
106//------------------------------------------------------------------------------
107// Name: slotSetAccelDisplayMode
108// Desc:
109//------------------------------------------------------------------------------
110void KCalcButton::slotSetAccelDisplayMode(bool flag)
111{
112 show_shortcut_mode_ = flag;
113
114 // save shortcut, because setting label erases it
115 QKeySequence current_shortcut = shortcut();
116
117 if (flag) {
118 setText(shortcut().toString(QKeySequence::NativeText));
119 } else {
120 setText(mode_[mode_flags_].label);
121 }
122
123 // restore shortcut
124 setShortcut(current_shortcut);
125 update();
126}
127
128//------------------------------------------------------------------------------
129// Name: paintEvent
130// Desc: draws the button
131//------------------------------------------------------------------------------
132void KCalcButton::paintEvent(QPaintEvent *)
133{
134 QPainter p(this);
135 QStyleOptionButton option;
136 initStyleOption(&option);
137 const bool is_down = isDown() || isChecked();
138 const int x_offset = is_down ? style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, &option, this) : 0;
139 const int y_offset = is_down ? style()->pixelMetric(QStyle::PM_ButtonShiftVertical, &option, this) : 0;
140
141 // draw bevel
142 style()->drawControl(QStyle::CE_PushButtonBevel, &option, &p, this);
143
144 // draw label...
145 p.save();
146
147 // rant: Qt4 needs QSimpleRichText, dammit!
148 QTextDocument doc;
149 QAbstractTextDocumentLayout::PaintContext context;
150 doc.setHtml(QLatin1String("<center>") + text() + QLatin1String("</center>"));
151 doc.setDefaultFont(font());
152 context.palette = palette();
153 QColor color = text_color_;
154 if (!isEnabled()) {
155 color.setAlphaF(0.6);
156 }
157 context.palette.setColor(QPalette::Text, color);
158
159 p.translate((width() / 2 - doc.size().width() / 2) + x_offset, (height() / 2 - doc.size().height() / 2) + y_offset);
160 doc.documentLayout()->draw(&p, context);
161 p.restore();
162
163 // draw focus
164 if (hasFocus()) {
165 QStyleOptionFocusRect fropt;
166 fropt.QStyleOption::operator=(option);
167 fropt.rect = style()->subElementRect(QStyle::SE_PushButtonFocusRect, &option, this);
168 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &fropt, &p, this);
169 }
170}
171
172//------------------------------------------------------------------------------
173// Name: sizeHint
174// Desc:
175//------------------------------------------------------------------------------
176QSize KCalcButton::sizeHint() const
177{
178 // reimplemented to provide a smaller button
179 return size_;
180}
181
182//------------------------------------------------------------------------------
183// Name: calcSizeHint
184// Desc:
185//------------------------------------------------------------------------------
186void KCalcButton::calcSizeHint()
187{
188 int margin = style()->pixelMetric(QStyle::PM_ButtonMargin, nullptr, this);
189
190 // want narrower margin than normal
191 margin = qMax(margin / 2, 3);
192
193 // simply use font size of a single letter
194 size_ = fontMetrics().size(0, QStringLiteral("M"));
195
196 size_ += QSize(margin * 2, margin * 2);
197}
198
199//------------------------------------------------------------------------------
200// Name: setFont
201// Desc:
202//------------------------------------------------------------------------------
203void KCalcButton::setFont(const QFont &fnt)
204{
205 QPushButton::setFont(fnt);
206 calcSizeHint();
207}
208
209//------------------------------------------------------------------------------
210// Name: setTextColor
211// Desc:
212//------------------------------------------------------------------------------
213void KCalcButton::setTextColor(const QColor &color)
214{
215 text_color_ = color;
216 update();
217}
218
219//------------------------------------------------------------------------------
220// Name: setText
221// Desc:
222//------------------------------------------------------------------------------
223void KCalcButton::setText(const QString &text)
224{
225 QPushButton::setText(text);
226
227 // normal mode may not have been explicitly set
228 if (mode_[ModeNormal].label.isEmpty()) {
229 mode_[ModeNormal].label = text;
230 }
231
232 calcSizeHint();
233}
234
235//------------------------------------------------------------------------------
236// Name: setToolTip
237// Desc:
238//------------------------------------------------------------------------------
239void KCalcButton::setToolTip(const QString &tip)
240{
241 QPushButton::setToolTip(tip);
242
243 // normal mode may not have been explicitly set
244 if (mode_[ModeNormal].tooltip.isEmpty()) {
245 mode_[ModeNormal].tooltip = tip;
246 }
247}
248
249#include "moc_kcalc_button.cpp"
250

source code of kcalc/kcalc_button.cpp