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 | //------------------------------------------------------------------------------ |
19 | KCalcButton::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 | //------------------------------------------------------------------------------ |
37 | KCalcButton::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 | //------------------------------------------------------------------------------ |
54 | void 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 | //------------------------------------------------------------------------------ |
73 | void 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 | //------------------------------------------------------------------------------ |
110 | void 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 | //------------------------------------------------------------------------------ |
132 | void 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 | //------------------------------------------------------------------------------ |
176 | QSize KCalcButton::sizeHint() const |
177 | { |
178 | // reimplemented to provide a smaller button |
179 | return size_; |
180 | } |
181 | |
182 | //------------------------------------------------------------------------------ |
183 | // Name: calcSizeHint |
184 | // Desc: |
185 | //------------------------------------------------------------------------------ |
186 | void 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 | //------------------------------------------------------------------------------ |
203 | void KCalcButton::setFont(const QFont &fnt) |
204 | { |
205 | QPushButton::setFont(fnt); |
206 | calcSizeHint(); |
207 | } |
208 | |
209 | //------------------------------------------------------------------------------ |
210 | // Name: setTextColor |
211 | // Desc: |
212 | //------------------------------------------------------------------------------ |
213 | void KCalcButton::setTextColor(const QColor &color) |
214 | { |
215 | text_color_ = color; |
216 | update(); |
217 | } |
218 | |
219 | //------------------------------------------------------------------------------ |
220 | // Name: setText |
221 | // Desc: |
222 | //------------------------------------------------------------------------------ |
223 | void 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 | //------------------------------------------------------------------------------ |
239 | void 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 | |