Changeset View
Changeset View
Standalone View
Standalone View
kstyle/widgets/combobox.cpp
- This file was added.
1 | #include "combobox_p.h" | ||||
---|---|---|---|---|---|
2 | | ||||
3 | #include <QComboBox> | ||||
4 | | ||||
5 | #if BREEZE_HAVE_QTQUICK | ||||
6 | #include <QQuickWindow> | ||||
7 | #endif | ||||
8 | | ||||
9 | namespace BreezePrivate | ||||
10 | { | ||||
11 | } | ||||
12 | | ||||
13 | namespace Breeze | ||||
14 | { | ||||
15 | //_________________________________________________________ | ||||
16 | bool Style::eventFilterComboBoxContainer(QWidget *widget, QEvent *event) | ||||
17 | { | ||||
18 | if (event->type() == QEvent::Paint) { | ||||
19 | QPainter painter(widget); | ||||
20 | auto paintEvent = static_cast<QPaintEvent *>(event); | ||||
21 | painter.setClipRegion(paintEvent->region()); | ||||
22 | | ||||
23 | const auto rect(widget->rect()); | ||||
24 | const auto &palette(widget->palette()); | ||||
25 | const auto background(_helper->frameBackgroundColor(palette)); | ||||
26 | const auto outline(_helper->frameOutlineColor(palette)); | ||||
27 | | ||||
28 | const bool hasAlpha(_helper->hasAlphaChannel(widget)); | ||||
29 | if (hasAlpha) { | ||||
30 | painter.setCompositionMode(QPainter::CompositionMode_Source); | ||||
31 | _helper->renderMenuFrame(&painter, rect, background, outline, true); | ||||
32 | | ||||
33 | } else { | ||||
34 | _helper->renderMenuFrame(&painter, rect, background, outline, false); | ||||
35 | } | ||||
36 | } | ||||
37 | | ||||
38 | return false; | ||||
39 | } | ||||
40 | | ||||
41 | //___________________________________________________________________________________________________________________ | ||||
42 | QRect Style::comboBoxSubControlRect(const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const | ||||
43 | { | ||||
44 | // cast option and check | ||||
45 | const auto comboBoxOption(qstyleoption_cast<const QStyleOptionComboBox *>(option)); | ||||
46 | if (!comboBoxOption) | ||||
47 | return ParentStyleClass::subControlRect(CC_ComboBox, option, subControl, widget); | ||||
48 | | ||||
49 | const bool editable(comboBoxOption->editable); | ||||
50 | const bool flat(editable && !comboBoxOption->frame); | ||||
51 | | ||||
52 | // copy rect | ||||
53 | auto rect(option->rect); | ||||
54 | | ||||
55 | switch (subControl) { | ||||
56 | case SC_ComboBoxFrame: | ||||
57 | return flat ? rect : QRect(); | ||||
58 | case SC_ComboBoxListBoxPopup: | ||||
59 | return rect; | ||||
60 | | ||||
61 | case SC_ComboBoxArrow: { | ||||
62 | // take out frame width | ||||
63 | if (!flat) | ||||
64 | rect = insideMargin(rect, Metrics::Frame_FrameWidth); | ||||
65 | | ||||
66 | QRect arrowRect(rect.right() - Metrics::MenuButton_IndicatorWidth + 1, rect.top(), Metrics::MenuButton_IndicatorWidth, rect.height()); | ||||
67 | | ||||
68 | arrowRect = centerRect(arrowRect, Metrics::MenuButton_IndicatorWidth, Metrics::MenuButton_IndicatorWidth); | ||||
69 | return visualRect(option, arrowRect); | ||||
70 | } | ||||
71 | | ||||
72 | case SC_ComboBoxEditField: { | ||||
73 | QRect labelRect; | ||||
74 | const int frameWidth(pixelMetric(PM_ComboBoxFrameWidth, option, widget)); | ||||
75 | labelRect = QRect(rect.left(), rect.top(), rect.width() - Metrics::MenuButton_IndicatorWidth, rect.height()); | ||||
76 | | ||||
77 | // remove margins | ||||
78 | if (!flat && rect.height() >= option->fontMetrics.height() + 2 * frameWidth) { | ||||
79 | labelRect.adjust(frameWidth, frameWidth, 0, -frameWidth); | ||||
80 | } | ||||
81 | | ||||
82 | return visualRect(option, labelRect); | ||||
83 | } | ||||
84 | | ||||
85 | default: | ||||
86 | break; | ||||
87 | } | ||||
88 | | ||||
89 | return ParentStyleClass::subControlRect(CC_ComboBox, option, subControl, widget); | ||||
90 | } | ||||
91 | | ||||
92 | //______________________________________________________________ | ||||
93 | QSize Style::comboBoxSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const | ||||
94 | { | ||||
95 | // cast option and check | ||||
96 | const auto comboBoxOption(qstyleoption_cast<const QStyleOptionComboBox *>(option)); | ||||
97 | if (!comboBoxOption) | ||||
98 | return contentsSize; | ||||
99 | | ||||
100 | // copy size | ||||
101 | QSize size(contentsSize); | ||||
102 | | ||||
103 | // add relevant margin | ||||
104 | const bool flat(!comboBoxOption->frame); | ||||
105 | const int frameWidth(pixelMetric(PM_ComboBoxFrameWidth, option, widget)); | ||||
106 | if (!flat) | ||||
107 | size = expandSize(size, frameWidth); | ||||
108 | | ||||
109 | // make sure there is enough height for the button | ||||
110 | size.setHeight(qMax(size.height(), int(Metrics::MenuButton_IndicatorWidth))); | ||||
111 | | ||||
112 | // add button width and spacing | ||||
113 | size.rwidth() += Metrics::MenuButton_IndicatorWidth + 2; | ||||
114 | | ||||
115 | return size; | ||||
116 | } | ||||
117 | | ||||
118 | //___________________________________________________________________________________ | ||||
119 | bool Style::drawComboBoxLabelControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const | ||||
120 | { | ||||
121 | const auto comboBoxOption(qstyleoption_cast<const QStyleOptionComboBox *>(option)); | ||||
122 | if (!comboBoxOption) | ||||
123 | return false; | ||||
124 | if (comboBoxOption->editable) | ||||
125 | return false; | ||||
126 | | ||||
127 | // need to alter palette for focused buttons | ||||
128 | const State &state(option->state); | ||||
129 | const bool enabled(state & State_Enabled); | ||||
130 | const bool sunken(state & (State_On | State_Sunken)); | ||||
131 | const bool mouseOver(enabled && (option->state & State_MouseOver)); | ||||
132 | const bool hasFocus(enabled && !mouseOver && (option->state & State_HasFocus)); | ||||
133 | const bool flat(!comboBoxOption->frame); | ||||
134 | | ||||
135 | QPalette::ColorRole textRole; | ||||
136 | if (flat) { | ||||
137 | if (hasFocus && sunken) | ||||
138 | textRole = QPalette::HighlightedText; | ||||
139 | else | ||||
140 | textRole = QPalette::WindowText; | ||||
141 | | ||||
142 | } else if (hasFocus) | ||||
143 | textRole = QPalette::HighlightedText; | ||||
144 | else | ||||
145 | textRole = QPalette::ButtonText; | ||||
146 | | ||||
147 | // change pen color directly | ||||
148 | painter->setPen(QPen(option->palette.color(textRole), 1)); | ||||
149 | | ||||
150 | // translate painter for pressed down comboboxes | ||||
151 | if (sunken && !flat) { | ||||
152 | painter->translate(1, 1); | ||||
153 | } | ||||
154 | | ||||
155 | #if QT_VERSION >= 0x050000 | ||||
156 | if (const auto cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) { | ||||
157 | auto editRect = proxy()->subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget); | ||||
158 | painter->save(); | ||||
159 | painter->setClipRect(editRect); | ||||
160 | if (!cb->currentIcon.isNull()) { | ||||
161 | QIcon::Mode mode; | ||||
162 | | ||||
163 | if ((cb->state & QStyle::State_Selected) && (cb->state & QStyle::State_Active)) { | ||||
164 | mode = QIcon::Selected; | ||||
165 | } else if (cb->state & QStyle::State_Enabled) { | ||||
166 | mode = QIcon::Normal; | ||||
167 | } else { | ||||
168 | mode = QIcon::Disabled; | ||||
169 | } | ||||
170 | | ||||
171 | QWindow *window = nullptr; | ||||
172 | if (widget && widget->window()) { | ||||
173 | window = widget->window()->windowHandle(); | ||||
174 | #if BREEZE_HAVE_QTQUICK | ||||
175 | } else if (QQuickItem *quickItem = qobject_cast<QQuickItem *>(option->styleObject)) { | ||||
176 | window = quickItem->window(); | ||||
177 | #endif | ||||
178 | } | ||||
179 | | ||||
180 | const auto pixmap = cb->currentIcon.pixmap(window, cb->iconSize, mode); | ||||
181 | auto iconRect(editRect); | ||||
182 | iconRect.setWidth(cb->iconSize.width() + 4); | ||||
183 | iconRect = alignedRect(cb->direction, Qt::AlignLeft | Qt::AlignVCenter, iconRect.size(), editRect); | ||||
184 | if (cb->editable) | ||||
185 | painter->fillRect(iconRect, option->palette.brush(QPalette::Base)); | ||||
186 | proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); | ||||
187 | | ||||
188 | if (cb->direction == Qt::RightToLeft) | ||||
189 | editRect.translate(-4 - cb->iconSize.width(), 0); | ||||
190 | else | ||||
191 | editRect.translate(cb->iconSize.width() + 4, 0); | ||||
192 | } | ||||
193 | if (!cb->currentText.isEmpty() && !cb->editable) { | ||||
194 | proxy()->drawItemText(painter, editRect.adjusted(1, 0, -1, 0), visualAlignment(cb->direction, Qt::AlignLeft | Qt::AlignVCenter), cb->palette, cb->state & State_Enabled, cb->currentText); | ||||
195 | } | ||||
196 | painter->restore(); | ||||
197 | } | ||||
198 | #else | ||||
199 | // call base class method | ||||
200 | ParentStyleClass::drawControl(CE_ComboBoxLabel, option, painter, widget); | ||||
201 | #endif | ||||
202 | | ||||
203 | return true; | ||||
204 | } | ||||
205 | | ||||
206 | //______________________________________________________________ | ||||
207 | bool Style::drawComboBoxComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const | ||||
208 | { | ||||
209 | // cast option and check | ||||
210 | const auto comboBoxOption(qstyleoption_cast<const QStyleOptionComboBox *>(option)); | ||||
211 | if (!comboBoxOption) | ||||
212 | return true; | ||||
213 | | ||||
214 | // rect and palette | ||||
215 | const auto &rect(option->rect); | ||||
216 | const auto &palette(option->palette); | ||||
217 | | ||||
218 | // state | ||||
219 | const State &state(option->state); | ||||
220 | const bool enabled(state & State_Enabled); | ||||
221 | const bool mouseOver(enabled && (state & State_MouseOver)); | ||||
222 | const bool hasFocus(enabled && (state & (State_HasFocus | State_Sunken))); | ||||
223 | const bool editable(comboBoxOption->editable); | ||||
224 | const bool sunken(state & (State_On | State_Sunken)); | ||||
225 | bool flat(!comboBoxOption->frame); | ||||
226 | | ||||
227 | // frame | ||||
228 | if (option->subControls & SC_ComboBoxFrame) { | ||||
229 | if (editable) { | ||||
230 | flat |= (rect.height() <= 2 * Metrics::Frame_FrameWidth + Metrics::MenuButton_IndicatorWidth); | ||||
231 | if (flat) { | ||||
232 | const auto &background = palette.color(QPalette::Base); | ||||
233 | | ||||
234 | painter->setBrush(background); | ||||
235 | painter->setPen(Qt::NoPen); | ||||
236 | painter->drawRect(rect); | ||||
237 | | ||||
238 | } else { | ||||
239 | drawPrimitive(PE_FrameLineEdit, option, painter, widget); | ||||
240 | } | ||||
241 | | ||||
242 | } else { | ||||
243 | // update animation state | ||||
244 | // hover takes precedence over focus | ||||
245 | _animations->inputWidgetEngine().updateState(widget, AnimationHover, mouseOver); | ||||
246 | _animations->inputWidgetEngine().updateState(widget, AnimationFocus, hasFocus && !mouseOver); | ||||
247 | const AnimationMode mode(_animations->inputWidgetEngine().buttonAnimationMode(widget)); | ||||
248 | const qreal opacity(_animations->inputWidgetEngine().buttonOpacity(widget)); | ||||
249 | | ||||
250 | if (flat) { | ||||
251 | // define colors and render | ||||
252 | const auto color(_helper->toolButtonColor(palette, mouseOver, hasFocus, sunken, opacity, mode)); | ||||
253 | _helper->renderToolButtonFrame(painter, rect, color, sunken); | ||||
254 | | ||||
255 | } else { | ||||
256 | // define colors | ||||
257 | const auto shadow(_helper->shadowColor(palette)); | ||||
258 | const auto outline(_helper->buttonOutlineColor(palette, mouseOver, hasFocus, opacity, mode)); | ||||
259 | const auto background(_helper->buttonBackgroundColor(palette, mouseOver, hasFocus, false, opacity, mode)); | ||||
260 | | ||||
261 | // render | ||||
262 | _helper->renderButtonFrame(painter, rect, background, outline, shadow, hasFocus, sunken); | ||||
263 | } | ||||
264 | } | ||||
265 | } | ||||
266 | | ||||
267 | // arrow | ||||
268 | if (option->subControls & SC_ComboBoxArrow) { | ||||
269 | // detect empty comboboxes | ||||
270 | const auto comboBox = qobject_cast<const QComboBox *>(widget); | ||||
271 | const bool empty(comboBox && !comboBox->count()); | ||||
272 | | ||||
273 | // arrow color | ||||
274 | QColor arrowColor; | ||||
275 | if (editable) { | ||||
276 | if (empty || !enabled) | ||||
277 | arrowColor = palette.color(QPalette::Disabled, QPalette::Text); | ||||
278 | else { | ||||
279 | // check animation state | ||||
280 | const bool subControlHover(enabled && mouseOver && comboBoxOption->activeSubControls & SC_ComboBoxArrow); | ||||
281 | _animations->comboBoxEngine().updateState(widget, AnimationHover, subControlHover); | ||||
282 | | ||||
283 | const bool animated(enabled && _animations->comboBoxEngine().isAnimated(widget, AnimationHover)); | ||||
284 | const qreal opacity(_animations->comboBoxEngine().opacity(widget, AnimationHover)); | ||||
285 | | ||||
286 | // color | ||||
287 | const auto normal(_helper->arrowColor(palette, QPalette::WindowText)); | ||||
288 | const auto hover(_helper->hoverColor(palette)); | ||||
289 | | ||||
290 | if (animated) { | ||||
291 | arrowColor = KColorUtils::mix(normal, hover, opacity); | ||||
292 | | ||||
293 | } else if (subControlHover) { | ||||
294 | arrowColor = hover; | ||||
295 | | ||||
296 | } else | ||||
297 | arrowColor = normal; | ||||
298 | } | ||||
299 | | ||||
300 | } else if (flat) { | ||||
301 | if (empty || !enabled) | ||||
302 | arrowColor = _helper->arrowColor(palette, QPalette::Disabled, QPalette::WindowText); | ||||
303 | else if (hasFocus && !mouseOver && sunken) | ||||
304 | arrowColor = palette.color(QPalette::HighlightedText); | ||||
305 | else | ||||
306 | arrowColor = _helper->arrowColor(palette, QPalette::WindowText); | ||||
307 | | ||||
308 | } else if (empty || !enabled) | ||||
309 | arrowColor = _helper->arrowColor(palette, QPalette::Disabled, QPalette::ButtonText); | ||||
310 | else if (hasFocus && !mouseOver) | ||||
311 | arrowColor = palette.color(QPalette::HighlightedText); | ||||
312 | else | ||||
313 | arrowColor = _helper->arrowColor(palette, QPalette::ButtonText); | ||||
314 | | ||||
315 | // arrow rect | ||||
316 | auto arrowRect(subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget)); | ||||
317 | | ||||
318 | // translate for non editable, non flat, sunken comboboxes | ||||
319 | if (sunken && !flat && !editable) | ||||
320 | arrowRect.translate(1, 1); | ||||
321 | | ||||
322 | // render | ||||
323 | _helper->renderArrow(painter, arrowRect, arrowColor, ArrowDown); | ||||
324 | } | ||||
325 | | ||||
326 | return true; | ||||
327 | } | ||||
328 | | ||||
329 | } |