Changeset View
Changeset View
Standalone View
Standalone View
kstyle/widgets/pushbutton.cpp
- This file was added.
1 | #include "breezestyle.h" | ||||
---|---|---|---|---|---|
2 | | ||||
3 | namespace Breeze | ||||
4 | { | ||||
5 | //____________________________________________________________________ | ||||
6 | QColor Helper::buttonFocusOutlineColor(const QPalette &palette) const | ||||
7 | { | ||||
8 | return KColorUtils::mix(focusColor(palette), palette.color(QPalette::ButtonText), 0.15); | ||||
9 | } | ||||
10 | | ||||
11 | //____________________________________________________________________ | ||||
12 | QColor Helper::buttonHoverOutlineColor(const QPalette &palette) const | ||||
13 | { | ||||
14 | return KColorUtils::mix(hoverColor(palette), palette.color(QPalette::ButtonText), 0.15); | ||||
15 | } | ||||
16 | | ||||
17 | //____________________________________________________________________ | ||||
18 | QColor Helper::buttonOutlineColor(const QPalette &palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode) const | ||||
19 | { | ||||
20 | QColor outline(KColorUtils::mix(palette.color(QPalette::Button), palette.color(QPalette::ButtonText), 0.3)); | ||||
21 | if (mode == AnimationHover) { | ||||
22 | if (hasFocus) { | ||||
23 | const QColor focus(buttonFocusOutlineColor(palette)); | ||||
24 | const QColor hover(buttonHoverOutlineColor(palette)); | ||||
25 | outline = KColorUtils::mix(focus, hover, opacity); | ||||
26 | | ||||
27 | } else { | ||||
28 | const QColor hover(hoverColor(palette)); | ||||
29 | outline = KColorUtils::mix(outline, hover, opacity); | ||||
30 | } | ||||
31 | | ||||
32 | } else if (mouseOver) { | ||||
33 | if (hasFocus) | ||||
34 | outline = buttonHoverOutlineColor(palette); | ||||
35 | else | ||||
36 | outline = hoverColor(palette); | ||||
37 | | ||||
38 | } else if (mode == AnimationFocus) { | ||||
39 | const QColor focus(buttonFocusOutlineColor(palette)); | ||||
40 | outline = KColorUtils::mix(outline, focus, opacity); | ||||
41 | | ||||
42 | } else if (hasFocus) { | ||||
43 | outline = buttonFocusOutlineColor(palette); | ||||
44 | } | ||||
45 | | ||||
46 | return outline; | ||||
47 | } | ||||
48 | | ||||
49 | //____________________________________________________________________ | ||||
50 | QColor Helper::buttonBackgroundColor(const QPalette &palette, bool mouseOver, bool hasFocus, bool sunken, qreal opacity, AnimationMode mode) const | ||||
51 | { | ||||
52 | QColor background(sunken ? KColorUtils::mix(palette.color(QPalette::Button), palette.color(QPalette::ButtonText), 0.2) : palette.color(QPalette::Button)); | ||||
53 | | ||||
54 | if (mode == AnimationHover) { | ||||
55 | const QColor focus(focusColor(palette)); | ||||
56 | const QColor hover(hoverColor(palette)); | ||||
57 | if (hasFocus) | ||||
58 | background = KColorUtils::mix(focus, hover, opacity); | ||||
59 | | ||||
60 | } else if (mouseOver && hasFocus) { | ||||
61 | background = hoverColor(palette); | ||||
62 | | ||||
63 | } else if (mode == AnimationFocus) { | ||||
64 | const QColor focus(focusColor(palette)); | ||||
65 | background = KColorUtils::mix(background, focus, opacity); | ||||
66 | | ||||
67 | } else if (hasFocus) { | ||||
68 | background = focusColor(palette); | ||||
69 | } | ||||
70 | | ||||
71 | return background; | ||||
72 | } | ||||
73 | | ||||
74 | //______________________________________________________________________________ | ||||
75 | void Helper::renderButtonFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, const QColor &shadow, bool hasFocus, bool sunken) const | ||||
76 | { | ||||
77 | // setup painter | ||||
78 | painter->setRenderHint(QPainter::Antialiasing, true); | ||||
79 | | ||||
80 | // copy rect | ||||
81 | QRectF frameRect(rect); | ||||
82 | frameRect.adjust(1, 1, -1, -1); | ||||
83 | qreal radius(frameRadius()); | ||||
84 | | ||||
85 | // shadow | ||||
86 | if (sunken) { | ||||
87 | frameRect.translate(1, 1); | ||||
88 | | ||||
89 | } else if (shadow.isValid()) { | ||||
90 | const qreal shadowRadius = qMax(radius - 1, qreal(0.0)); | ||||
91 | painter->setPen(QPen(shadow, 2)); | ||||
92 | painter->setBrush(Qt::NoBrush); | ||||
93 | painter->drawRoundedRect(shadowRect(frameRect), shadowRadius, shadowRadius); | ||||
94 | } | ||||
95 | | ||||
96 | if (outline.isValid()) { | ||||
97 | QLinearGradient gradient(frameRect.topLeft(), frameRect.bottomLeft()); | ||||
98 | gradient.setColorAt(0, outline.lighter(hasFocus ? 103 : 101)); | ||||
99 | gradient.setColorAt(1, outline.darker(hasFocus ? 110 : 103)); | ||||
100 | painter->setPen(QPen(QBrush(gradient), 1.0)); | ||||
101 | | ||||
102 | frameRect.adjust(0.5, 0.5, -0.5, -0.5); | ||||
103 | radius = qMax(radius - 1, qreal(0.0)); | ||||
104 | | ||||
105 | } else | ||||
106 | painter->setPen(Qt::NoPen); | ||||
107 | | ||||
108 | // content | ||||
109 | if (color.isValid()) { | ||||
110 | QLinearGradient gradient(frameRect.topLeft(), frameRect.bottomLeft()); | ||||
111 | gradient.setColorAt(0, color.lighter(hasFocus ? 103 : 101)); | ||||
112 | gradient.setColorAt(1, color.darker(hasFocus ? 110 : 103)); | ||||
113 | painter->setBrush(gradient); | ||||
114 | | ||||
115 | } else | ||||
116 | painter->setBrush(Qt::NoBrush); | ||||
117 | | ||||
118 | // render | ||||
119 | painter->drawRoundedRect(frameRect, radius, radius); | ||||
120 | } | ||||
121 | | ||||
122 | //____________________________________________________________________________ | ||||
123 | #if QT_VERSION >= 0x050000 | ||||
124 | bool Style::eventFilterCommandLinkButton(QCommandLinkButton *button, QEvent *event) | ||||
125 | { | ||||
126 | if (event->type() == QEvent::Paint) { | ||||
127 | // painter | ||||
128 | QPainter painter(button); | ||||
129 | painter.setClipRegion(static_cast<QPaintEvent *>(event)->region()); | ||||
130 | | ||||
131 | const bool isFlat = false; | ||||
132 | | ||||
133 | // option | ||||
134 | QStyleOptionButton option; | ||||
135 | option.initFrom(button); | ||||
136 | option.features |= QStyleOptionButton::CommandLinkButton; | ||||
137 | if (isFlat) | ||||
138 | option.features |= QStyleOptionButton::Flat; | ||||
139 | option.text = QString(); | ||||
140 | option.icon = QIcon(); | ||||
141 | | ||||
142 | if (button->isChecked()) | ||||
143 | option.state |= State_On; | ||||
144 | if (button->isDown()) | ||||
145 | option.state |= State_Sunken; | ||||
146 | | ||||
147 | // frame | ||||
148 | drawControl(QStyle::CE_PushButton, &option, &painter, button); | ||||
149 | | ||||
150 | // offset | ||||
151 | const int margin(Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth); | ||||
152 | QPoint offset(margin, margin); | ||||
153 | | ||||
154 | if (button->isDown() && !isFlat) | ||||
155 | painter.translate(1, 1); | ||||
156 | { | ||||
157 | offset += QPoint(1, 1); | ||||
158 | } | ||||
159 | | ||||
160 | // state | ||||
161 | const State &state(option.state); | ||||
162 | const bool enabled(state & State_Enabled); | ||||
163 | bool mouseOver(enabled && (state & State_MouseOver)); | ||||
164 | bool hasFocus(enabled && (state & State_HasFocus)); | ||||
165 | | ||||
166 | // icon | ||||
167 | if (!button->icon().isNull()) { | ||||
168 | const auto pixmapSize(button->icon().actualSize(button->iconSize())); | ||||
169 | const QRect pixmapRect(QPoint(offset.x(), button->description().isEmpty() ? (button->height() - pixmapSize.height()) / 2 : offset.y()), pixmapSize); | ||||
170 | const QPixmap pixmap(button->icon().pixmap(pixmapSize, enabled ? QIcon::Normal : QIcon::Disabled, button->isChecked() ? QIcon::On : QIcon::Off)); | ||||
171 | drawItemPixmap(&painter, pixmapRect, Qt::AlignCenter, pixmap); | ||||
172 | | ||||
173 | offset.rx() += pixmapSize.width() + Metrics::Button_ItemSpacing; | ||||
174 | } | ||||
175 | | ||||
176 | // text rect | ||||
177 | QRect textRect(offset, QSize(button->size().width() - offset.x() - margin, button->size().height() - 2 * margin)); | ||||
178 | const QPalette::ColorRole textRole = (enabled && hasFocus && !mouseOver && !isFlat) ? QPalette::HighlightedText : QPalette::ButtonText; | ||||
179 | if (!button->text().isEmpty()) { | ||||
180 | QFont font(button->font()); | ||||
181 | font.setBold(true); | ||||
182 | painter.setFont(font); | ||||
183 | if (button->description().isEmpty()) { | ||||
184 | drawItemText(&painter, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextHideMnemonic, button->palette(), enabled, button->text(), textRole); | ||||
185 | | ||||
186 | } else { | ||||
187 | drawItemText(&painter, textRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextHideMnemonic, button->palette(), enabled, button->text(), textRole); | ||||
188 | textRect.setTop(textRect.top() + QFontMetrics(font).height()); | ||||
189 | } | ||||
190 | | ||||
191 | painter.setFont(button->font()); | ||||
192 | } | ||||
193 | | ||||
194 | if (!button->description().isEmpty()) { | ||||
195 | drawItemText(&painter, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextWordWrap, button->palette(), enabled, button->description(), textRole); | ||||
196 | } | ||||
197 | | ||||
198 | return true; | ||||
199 | } | ||||
200 | | ||||
201 | // continue with normal painting | ||||
202 | return false; | ||||
203 | } | ||||
204 | #endif | ||||
205 | | ||||
206 | //___________________________________________________________________________________________________________________ | ||||
207 | QRect Style::pushButtonContentsRect(const QStyleOption *option, const QWidget *) const | ||||
208 | { | ||||
209 | return insideMargin(option->rect, Metrics::Frame_FrameWidth); | ||||
210 | } | ||||
211 | | ||||
212 | //______________________________________________________________ | ||||
213 | QSize Style::pushButtonSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const | ||||
214 | { | ||||
215 | // cast option and check | ||||
216 | const auto buttonOption(qstyleoption_cast<const QStyleOptionButton *>(option)); | ||||
217 | if (!buttonOption) | ||||
218 | return contentsSize; | ||||
219 | | ||||
220 | // output | ||||
221 | QSize size; | ||||
222 | | ||||
223 | // check text and icon | ||||
224 | const bool hasText(!buttonOption->text.isEmpty()); | ||||
225 | const bool flat(buttonOption->features & QStyleOptionButton::Flat); | ||||
226 | bool hasIcon(!buttonOption->icon.isNull()); | ||||
227 | | ||||
228 | if (!(hasText || hasIcon)) { | ||||
229 | /* | ||||
230 | no text nor icon is passed. | ||||
231 | assume custom button and use contentsSize as a starting point | ||||
232 | */ | ||||
233 | size = contentsSize; | ||||
234 | | ||||
235 | } else { | ||||
236 | /* | ||||
237 | rather than trying to guess what Qt puts into its contents size calculation, | ||||
238 | we recompute the button size entirely, based on button option | ||||
239 | this ensures consistency with the rendering stage | ||||
240 | */ | ||||
241 | | ||||
242 | // update has icon to honour showIconsOnPushButtons, when possible | ||||
243 | hasIcon &= (showIconsOnPushButtons() || flat || !hasText); | ||||
244 | | ||||
245 | // text | ||||
246 | if (hasText) | ||||
247 | size = buttonOption->fontMetrics.size(Qt::TextShowMnemonic, buttonOption->text); | ||||
248 | | ||||
249 | // icon | ||||
250 | if (hasIcon) { | ||||
251 | QSize iconSize = buttonOption->iconSize; | ||||
252 | if (!iconSize.isValid()) | ||||
253 | iconSize = QSize(pixelMetric(PM_SmallIconSize, option, widget), pixelMetric(PM_SmallIconSize, option, widget)); | ||||
254 | | ||||
255 | size.setHeight(qMax(size.height(), iconSize.height())); | ||||
256 | size.rwidth() += iconSize.width(); | ||||
257 | | ||||
258 | if (hasText) | ||||
259 | size.rwidth() += Metrics::Button_ItemSpacing; | ||||
260 | } | ||||
261 | } | ||||
262 | | ||||
263 | // menu | ||||
264 | const bool hasMenu(buttonOption->features & QStyleOptionButton::HasMenu); | ||||
265 | if (hasMenu) { | ||||
266 | size.rwidth() += Metrics::MenuButton_IndicatorWidth; | ||||
267 | if (hasText || hasIcon) | ||||
268 | size.rwidth() += Metrics::Button_ItemSpacing; | ||||
269 | } | ||||
270 | | ||||
271 | // expand with buttons margin | ||||
272 | size = expandSize(size, Metrics::Button_MarginWidth); | ||||
273 | | ||||
274 | // make sure buttons have a minimum width | ||||
275 | if (hasText) { | ||||
276 | size.setWidth(qMax(size.width(), int(Metrics::Button_MinWidth))); | ||||
277 | } | ||||
278 | | ||||
279 | // finally add frame margins | ||||
280 | return expandSize(size, Metrics::Frame_FrameWidth); | ||||
281 | } | ||||
282 | | ||||
283 | //______________________________________________________________ | ||||
284 | bool Style::drawPanelButtonCommandPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const | ||||
285 | { | ||||
286 | // cast option and check | ||||
287 | const auto buttonOption(qstyleoption_cast<const QStyleOptionButton *>(option)); | ||||
288 | if (!buttonOption) | ||||
289 | return true; | ||||
290 | | ||||
291 | // rect and palette | ||||
292 | const auto &rect(option->rect); | ||||
293 | | ||||
294 | // button state | ||||
295 | const State &state(option->state); | ||||
296 | const bool enabled(state & State_Enabled); | ||||
297 | const bool mouseOver(enabled && (state & State_MouseOver)); | ||||
298 | const bool hasFocus((enabled && (state & State_HasFocus)) && !(widget && widget->focusProxy())); | ||||
299 | const bool sunken(state & (State_On | State_Sunken)); | ||||
300 | const bool flat(buttonOption->features & QStyleOptionButton::Flat); | ||||
301 | | ||||
302 | // update animation state | ||||
303 | // mouse over takes precedence over focus | ||||
304 | _animations->widgetStateEngine().updateState(widget, AnimationHover, mouseOver); | ||||
305 | _animations->widgetStateEngine().updateState(widget, AnimationFocus, hasFocus && !mouseOver); | ||||
306 | | ||||
307 | const AnimationMode mode(_animations->widgetStateEngine().buttonAnimationMode(widget)); | ||||
308 | const qreal opacity(_animations->widgetStateEngine().buttonOpacity(widget)); | ||||
309 | | ||||
310 | if (flat) { | ||||
311 | // define colors and render | ||||
312 | const auto &palette(option->palette); | ||||
313 | const auto color(_helper->toolButtonColor(palette, mouseOver, hasFocus, sunken, opacity, mode)); | ||||
314 | _helper->renderToolButtonFrame(painter, rect, color, sunken); | ||||
315 | | ||||
316 | } else { | ||||
317 | // update button color from palette in case button is default | ||||
318 | QPalette palette(option->palette); | ||||
319 | if (enabled && buttonOption->features & QStyleOptionButton::DefaultButton) { | ||||
320 | const auto button(palette.color(QPalette::Button)); | ||||
321 | const auto base(palette.color(QPalette::Base)); | ||||
322 | palette.setColor(QPalette::Button, KColorUtils::mix(button, base, 0.7)); | ||||
323 | } | ||||
324 | | ||||
325 | const auto shadow(_helper->shadowColor(palette)); | ||||
326 | const auto outline(_helper->buttonOutlineColor(palette, mouseOver, hasFocus, opacity, mode)); | ||||
327 | const auto background(_helper->buttonBackgroundColor(palette, mouseOver, hasFocus, sunken, opacity, mode)); | ||||
328 | | ||||
329 | // render | ||||
330 | _helper->renderButtonFrame(painter, rect, background, outline, shadow, hasFocus, sunken); | ||||
331 | } | ||||
332 | | ||||
333 | return true; | ||||
334 | } | ||||
335 | | ||||
336 | //___________________________________________________________________________________ | ||||
337 | bool Style::drawPushButtonLabelControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const | ||||
338 | { | ||||
339 | // cast option and check | ||||
340 | const auto buttonOption(qstyleoption_cast<const QStyleOptionButton *>(option)); | ||||
341 | if (!buttonOption) | ||||
342 | return true; | ||||
343 | | ||||
344 | // copy rect and palette | ||||
345 | const auto &rect(option->rect); | ||||
346 | const auto &palette(option->palette); | ||||
347 | | ||||
348 | // state | ||||
349 | const State &state(option->state); | ||||
350 | const bool enabled(state & State_Enabled); | ||||
351 | const bool sunken(state & (State_On | State_Sunken)); | ||||
352 | const bool mouseOver(enabled && (option->state & State_MouseOver)); | ||||
353 | const bool hasFocus(enabled && !mouseOver && (option->state & State_HasFocus)); | ||||
354 | const bool flat(buttonOption->features & QStyleOptionButton::Flat); | ||||
355 | | ||||
356 | // content | ||||
357 | const bool hasText(!buttonOption->text.isEmpty()); | ||||
358 | const bool hasIcon((showIconsOnPushButtons() || flat || !hasText) && !buttonOption->icon.isNull()); | ||||
359 | | ||||
360 | // contents | ||||
361 | auto contentsRect(rect); | ||||
362 | if (sunken && !flat) | ||||
363 | contentsRect.translate(1, 1); | ||||
364 | | ||||
365 | // color role | ||||
366 | QPalette::ColorRole textRole; | ||||
367 | if (flat) { | ||||
368 | if (hasFocus && sunken) | ||||
369 | textRole = QPalette::HighlightedText; | ||||
370 | else | ||||
371 | textRole = QPalette::WindowText; | ||||
372 | | ||||
373 | } else if (hasFocus) | ||||
374 | textRole = QPalette::HighlightedText; | ||||
375 | else | ||||
376 | textRole = QPalette::ButtonText; | ||||
377 | | ||||
378 | // menu arrow | ||||
379 | if (buttonOption->features & QStyleOptionButton::HasMenu) { | ||||
380 | // define rect | ||||
381 | auto arrowRect(contentsRect); | ||||
382 | arrowRect.setLeft(contentsRect.right() - Metrics::MenuButton_IndicatorWidth + 1); | ||||
383 | arrowRect = centerRect(arrowRect, Metrics::MenuButton_IndicatorWidth, Metrics::MenuButton_IndicatorWidth); | ||||
384 | | ||||
385 | contentsRect.setRight(arrowRect.left() - Metrics::Button_ItemSpacing - 1); | ||||
386 | contentsRect.adjust(Metrics::Button_MarginWidth, 0, 0, 0); | ||||
387 | | ||||
388 | arrowRect = visualRect(option, arrowRect); | ||||
389 | | ||||
390 | // define color | ||||
391 | const auto arrowColor(_helper->arrowColor(palette, textRole)); | ||||
392 | _helper->renderArrow(painter, arrowRect, arrowColor, ArrowDown); | ||||
393 | } | ||||
394 | | ||||
395 | // icon size | ||||
396 | QSize iconSize; | ||||
397 | if (hasIcon) { | ||||
398 | iconSize = buttonOption->iconSize; | ||||
399 | if (!iconSize.isValid()) { | ||||
400 | const int metric(pixelMetric(PM_SmallIconSize, option, widget)); | ||||
401 | iconSize = QSize(metric, metric); | ||||
402 | } | ||||
403 | } | ||||
404 | | ||||
405 | // text size | ||||
406 | const int textFlags(_mnemonics->textFlags() | Qt::AlignCenter); | ||||
407 | const QSize textSize(option->fontMetrics.size(textFlags, buttonOption->text)); | ||||
408 | | ||||
409 | // adjust text and icon rect based on options | ||||
410 | QRect iconRect; | ||||
411 | QRect textRect; | ||||
412 | | ||||
413 | if (hasText && !hasIcon) | ||||
414 | textRect = contentsRect; | ||||
415 | else if (hasIcon && !hasText) | ||||
416 | iconRect = contentsRect; | ||||
417 | else { | ||||
418 | const int contentsWidth(iconSize.width() + textSize.width() + Metrics::Button_ItemSpacing); | ||||
419 | iconRect = QRect(QPoint(contentsRect.left() + (contentsRect.width() - contentsWidth) / 2, contentsRect.top() + (contentsRect.height() - iconSize.height()) / 2), iconSize); | ||||
420 | textRect = QRect(QPoint(iconRect.right() + Metrics::ToolButton_ItemSpacing + 1, contentsRect.top() + (contentsRect.height() - textSize.height()) / 2), textSize); | ||||
421 | } | ||||
422 | | ||||
423 | // handle right to left | ||||
424 | if (iconRect.isValid()) | ||||
425 | iconRect = visualRect(option, iconRect); | ||||
426 | if (textRect.isValid()) | ||||
427 | textRect = visualRect(option, textRect); | ||||
428 | | ||||
429 | // make sure there is enough room for icon | ||||
430 | if (iconRect.isValid()) | ||||
431 | iconRect = centerRect(iconRect, iconSize); | ||||
432 | | ||||
433 | // render icon | ||||
434 | if (hasIcon && iconRect.isValid()) { | ||||
435 | // icon state and mode | ||||
436 | const QIcon::State iconState(sunken ? QIcon::On : QIcon::Off); | ||||
437 | QIcon::Mode iconMode; | ||||
438 | if (!enabled) | ||||
439 | iconMode = QIcon::Disabled; | ||||
440 | else if (!flat && hasFocus) | ||||
441 | iconMode = QIcon::Selected; | ||||
442 | else if (mouseOver && flat) | ||||
443 | iconMode = QIcon::Active; | ||||
444 | else | ||||
445 | iconMode = QIcon::Normal; | ||||
446 | | ||||
447 | const auto pixmap = buttonOption->icon.pixmap(iconSize, iconMode, iconState); | ||||
448 | drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); | ||||
449 | } | ||||
450 | | ||||
451 | // render text | ||||
452 | if (hasText && textRect.isValid()) { | ||||
453 | drawItemText(painter, textRect, textFlags, palette, enabled, buttonOption->text, textRole); | ||||
454 | } | ||||
455 | | ||||
456 | return true; | ||||
457 | } | ||||
458 | | ||||
459 | //____________________________________________________________________ | ||||
460 | bool Style::showIconsOnPushButtons() const | ||||
461 | { | ||||
462 | const KConfigGroup g(KSharedConfig::openConfig(), "KDE"); | ||||
463 | return g.readEntry("ShowIconsOnPushButtons", true); | ||||
464 | } | ||||
465 | | ||||
466 | } |