1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <Qt5Graphics_Controls.hxx>
22 #include <QtGui/QPainter>
23 #include <QtWidgets/QApplication>
24 #include <QtWidgets/QPushButton>
25 #include <QtWidgets/QStyle>
26 #include <QtWidgets/QStyleOption>
27 #include <QtWidgets/QFrame>
28 #include <QtWidgets/QLabel>
30 #include <qt5/Qt5Tools.hxx>
31 #include <vcl/decoview.hxx>
34 Conversion function between VCL ControlState together with
35 ImplControlValue and Qt state flags.
36 @param nControlState State of the widget (default, focused, ...) in Native Widget Framework.
37 @param aValue Value held by the widget (on, off, ...)
39 static QStyle::State
vclStateValue2StateFlag(ControlState nControlState
,
40 const ImplControlValue
& aValue
)
43 = ((nControlState
& ControlState::ENABLED
) ? QStyle::State_Enabled
: QStyle::State_None
)
44 | ((nControlState
& ControlState::FOCUSED
) ? QStyle::State_HasFocus
: QStyle::State_None
)
45 | ((nControlState
& ControlState::PRESSED
) ? QStyle::State_Sunken
: QStyle::State_None
)
46 | ((nControlState
& ControlState::SELECTED
) ? QStyle::State_Selected
: QStyle::State_None
)
47 | ((nControlState
& ControlState::ROLLOVER
) ? QStyle::State_MouseOver
48 : QStyle::State_None
);
50 switch (aValue
.getTristateVal())
53 nState
|= QStyle::State_On
;
55 case ButtonValue::Off
:
56 nState
|= QStyle::State_Off
;
58 case ButtonValue::Mixed
:
59 nState
|= QStyle::State_NoChange
;
68 Qt5Graphics_Controls::Qt5Graphics_Controls() { initStyles(); }
70 bool Qt5Graphics_Controls::IsNativeControlSupported(ControlType type
, ControlPart part
)
74 case ControlType::Tooltip
:
75 case ControlType::Progress
:
76 case ControlType::ListNode
:
77 return (part
== ControlPart::Entire
);
79 case ControlType::Radiobutton
:
80 case ControlType::Checkbox
:
81 case ControlType::Pushbutton
:
82 return (part
== ControlPart::Entire
) || (part
== ControlPart::Focus
);
84 case ControlType::ListHeader
:
85 return (part
== ControlPart::Button
);
87 case ControlType::Menubar
:
88 case ControlType::MenuPopup
:
89 case ControlType::Editbox
:
90 case ControlType::MultilineEditbox
:
91 case ControlType::Combobox
:
92 case ControlType::Toolbar
:
93 case ControlType::Frame
:
94 case ControlType::Scrollbar
:
95 case ControlType::WindowBackground
:
96 case ControlType::Fixedline
:
99 case ControlType::Listbox
:
100 return (part
== ControlPart::Entire
|| part
== ControlPart::HasBackgroundTexture
);
102 case ControlType::Spinbox
:
103 return (part
== ControlPart::Entire
|| part
== ControlPart::HasBackgroundTexture
);
105 case ControlType::Slider
:
106 return (part
== ControlPart::TrackHorzArea
|| part
== ControlPart::TrackVertArea
);
115 /// helper drawing methods
118 void draw(QStyle::ControlElement element
, QStyleOption
* option
, QImage
* image
,
119 QStyle::State
const& state
, QRect rect
= QRect())
121 option
->state
|= state
;
122 option
->rect
= !rect
.isNull() ? rect
: image
->rect();
124 QPainter
painter(image
);
125 QApplication::style()->drawControl(element
, option
, &painter
);
128 void draw(QStyle::PrimitiveElement element
, QStyleOption
* option
, QImage
* image
,
129 QStyle::State
const& state
, QRect rect
= QRect())
131 option
->state
|= state
;
132 option
->rect
= !rect
.isNull() ? rect
: image
->rect();
134 QPainter
painter(image
);
135 QApplication::style()->drawPrimitive(element
, option
, &painter
);
138 void draw(QStyle::ComplexControl element
, QStyleOptionComplex
* option
, QImage
* image
,
139 QStyle::State
const& state
)
141 option
->state
|= state
;
142 option
->rect
= image
->rect();
144 QPainter
painter(image
);
145 QApplication::style()->drawComplexControl(element
, option
, &painter
);
148 void lcl_drawFrame(QStyle::PrimitiveElement element
, QImage
* image
, QStyle::State
const& state
,
150 QStyle::PixelMetric eLineMetric
= QStyle::PM_DefaultFrameWidth
)
152 const int fw
= QApplication::style()->pixelMetric(eLineMetric
);
153 QStyleOptionFrame option
;
154 option
.frameShape
= QFrame::StyledPanel
;
155 option
.state
= QStyle::State_Sunken
| state
;
156 option
.lineWidth
= fw
;
158 QRect
aRect(image
->rect());
161 QPainter
painter(image
);
163 painter
.setClipRegion(QRegion(aRect
).subtracted(aRect
.adjusted(fw
, fw
, -fw
, -fw
)));
164 QApplication::style()->drawPrimitive(element
, &option
, &painter
);
168 bool Qt5Graphics_Controls::drawNativeControl(ControlType type
, ControlPart part
,
169 const tools::Rectangle
& rControlRegion
,
170 ControlState nControlState
,
171 const ImplControlValue
& value
, const OUString
&)
173 bool nativeSupport
= IsNativeControlSupported(type
, part
);
176 assert(!nativeSupport
&& "drawNativeControl called without native support!");
180 if (m_lastPopupRect
.isValid()
181 && (type
!= ControlType::MenuPopup
|| part
!= ControlPart::MenuItem
))
182 m_lastPopupRect
= QRect();
184 bool returnVal
= true;
186 QRect widgetRect
= toQRect(rControlRegion
);
188 //if no image, or resized, make a new image
189 if (!m_image
|| m_image
->size() != widgetRect
.size())
191 m_image
.reset(new QImage(widgetRect
.width(), widgetRect
.height(),
192 QImage::Format_ARGB32_Premultiplied
));
195 // Default image color - just once
198 case ControlType::MenuPopup
:
199 if (part
== ControlPart::MenuItemCheckMark
|| part
== ControlPart::MenuItemRadioMark
)
201 // it is necessary to fill the background transparently first, as this
202 // is painted after menuitem highlight, otherwise there would be a grey area
203 m_image
->fill(Qt::transparent
);
206 [[fallthrough
]]; // QPalette::Window
207 case ControlType::Menubar
:
208 case ControlType::WindowBackground
:
209 m_image
->fill(QApplication::palette().color(QPalette::Window
).rgb());
211 case ControlType::Tooltip
:
212 m_image
->fill(QApplication::palette().color(QPalette::ToolTipBase
).rgb());
214 case ControlType::Scrollbar
:
215 if ((part
== ControlPart::DrawBackgroundVert
)
216 || (part
== ControlPart::DrawBackgroundHorz
))
218 m_image
->fill(QApplication::palette().color(QPalette::Window
).rgb());
221 [[fallthrough
]]; // Qt::transparent
223 m_image
->fill(Qt::transparent
);
227 if (type
== ControlType::Pushbutton
)
229 if (part
== ControlPart::Entire
)
231 QStyleOptionButton option
;
232 draw(QStyle::CE_PushButton
, &option
, m_image
.get(),
233 vclStateValue2StateFlag(nControlState
, value
));
235 else if (part
== ControlPart::Focus
)
237 QStyleOptionButton option
;
238 option
.state
= QStyle::State_HasFocus
;
239 option
.rect
= m_image
->rect();
240 QPainter
painter(m_image
.get());
241 m_focusedButton
->style()->drawControl(QStyle::CE_PushButton
, &option
, &painter
,
242 m_focusedButton
.get());
245 else if (type
== ControlType::Menubar
)
247 if (part
== ControlPart::MenuItem
)
249 QStyleOptionMenuItem option
;
250 if ((nControlState
& ControlState::ROLLOVER
)
251 && QApplication::style()->styleHint(QStyle::SH_MenuBar_MouseTracking
))
252 option
.state
|= QStyle::State_Selected
;
255 & ControlState::SELECTED
) // Passing State_Sunken is currently not documented.
256 option
.state
|= QStyle::State_Sunken
; // But some kinds of QStyle interpret it.
258 draw(QStyle::CE_MenuBarItem
, &option
, m_image
.get(),
259 vclStateValue2StateFlag(nControlState
, value
));
261 else if (part
== ControlPart::Entire
)
263 QStyleOptionMenuItem option
;
264 draw(QStyle::CE_MenuBarEmptyArea
, &option
, m_image
.get(),
265 vclStateValue2StateFlag(nControlState
, value
));
272 else if (type
== ControlType::MenuPopup
)
274 assert(part
== ControlPart::MenuItem
? m_lastPopupRect
.isValid()
275 : !m_lastPopupRect
.isValid());
276 if (part
== ControlPart::MenuItem
)
278 QStyleOptionMenuItem option
;
279 draw(QStyle::CE_MenuItem
, &option
, m_image
.get(),
280 vclStateValue2StateFlag(nControlState
, value
));
281 // HACK: LO core first paints the entire popup and only then it paints menu items,
282 // but QMenu::paintEvent() paints popup frame after all items. That means highlighted
283 // items here would paint the highlight over the frame border. Since calls to ControlPart::MenuItem
284 // are always preceded by calls to ControlPart::Entire, just remember the size for the whole
285 // popup (otherwise not possible to get here) and draw the border afterwards.
286 QRect
framerect(m_lastPopupRect
.topLeft() - widgetRect
.topLeft(),
287 widgetRect
.size().expandedTo(m_lastPopupRect
.size()));
288 QStyleOptionFrame frame
;
289 draw(QStyle::PE_FrameMenu
, &frame
, m_image
.get(),
290 vclStateValue2StateFlag(nControlState
, value
), framerect
);
292 else if (part
== ControlPart::Separator
)
294 QStyleOptionMenuItem option
;
295 option
.menuItemType
= QStyleOptionMenuItem::Separator
;
296 // Painting the whole menu item area results in different background
297 // with at least Plastique style, so clip only to the separator itself
298 // (QSize( 2, 2 ) is hardcoded in Qt)
299 option
.rect
= m_image
->rect();
300 QSize size
= QApplication::style()->sizeFromContents(QStyle::CT_MenuItem
, &option
,
302 QRect rect
= m_image
->rect();
303 QPoint center
= rect
.center();
304 rect
.setHeight(size
.height());
305 rect
.moveCenter(center
);
306 option
.state
|= vclStateValue2StateFlag(nControlState
, value
);
309 QPainter
painter(m_image
.get());
310 // don't paint over popup frame border (like the hack above, but here it can be simpler)
311 const int fw
= QApplication::style()->pixelMetric(QStyle::PM_MenuPanelWidth
);
312 painter
.setClipRect(rect
.adjusted(fw
, 0, -fw
, 0));
313 QApplication::style()->drawControl(QStyle::CE_MenuItem
, &option
, &painter
);
315 else if (part
== ControlPart::MenuItemCheckMark
|| part
== ControlPart::MenuItemRadioMark
)
317 QStyleOptionMenuItem option
;
318 option
.checkType
= (part
== ControlPart::MenuItemCheckMark
)
319 ? QStyleOptionMenuItem::NonExclusive
320 : QStyleOptionMenuItem::Exclusive
;
321 option
.checked
= bool(nControlState
& ControlState::PRESSED
);
322 // widgetRect is now the rectangle for the checkbox/radiobutton itself, but Qt
323 // paints the whole menu item, so translate position (and it'll be clipped);
324 // it is also necessary to fill the background transparently first, as this
325 // is painted after menuitem highlight, otherwise there would be a grey area
326 assert(value
.getType() == ControlType::MenuPopup
);
327 const MenupopupValue
* menuVal
= static_cast<const MenupopupValue
*>(&value
);
328 QRect
menuItemRect(toQRect(menuVal
->maItemRect
));
329 QRect
rect(menuItemRect
.topLeft() - widgetRect
.topLeft(),
330 widgetRect
.size().expandedTo(menuItemRect
.size()));
331 // checkboxes are always displayed next to images in menus, so are never centered
332 const int focus_size
= QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin
);
333 rect
.moveTo(-focus_size
, rect
.y());
334 draw(QStyle::CE_MenuItem
, &option
, m_image
.get(),
335 vclStateValue2StateFlag(nControlState
& ~ControlState::PRESSED
, value
), rect
);
337 else if (part
== ControlPart::Entire
)
339 QStyleOptionMenuItem option
;
340 draw(QStyle::PE_PanelMenu
, &option
, m_image
.get(),
341 vclStateValue2StateFlag(nControlState
, value
));
342 // Try hard to get any frame!
343 QStyleOptionFrame frame
;
344 draw(QStyle::PE_FrameMenu
, &frame
, m_image
.get(),
345 vclStateValue2StateFlag(nControlState
, value
));
346 draw(QStyle::PE_FrameWindow
, &frame
, m_image
.get(),
347 vclStateValue2StateFlag(nControlState
, value
));
348 m_lastPopupRect
= widgetRect
;
353 else if ((type
== ControlType::Toolbar
) && (part
== ControlPart::Button
))
355 QStyleOptionToolButton option
;
357 option
.arrowType
= Qt::NoArrow
;
358 option
.subControls
= QStyle::SC_ToolButton
;
360 option
.state
= vclStateValue2StateFlag(nControlState
, value
);
361 option
.state
|= QStyle::State_Raised
| QStyle::State_Enabled
| QStyle::State_AutoRaise
;
363 draw(QStyle::CC_ToolButton
, &option
, m_image
.get(),
364 vclStateValue2StateFlag(nControlState
, value
));
366 else if ((type
== ControlType::Toolbar
) && (part
== ControlPart::Entire
))
368 QStyleOptionToolBar option
;
370 option
.rect
= QRect(0, 0, widgetRect
.width(), widgetRect
.height());
371 option
.state
= vclStateValue2StateFlag(nControlState
, value
);
373 draw(QStyle::CE_ToolBar
, &option
, m_image
.get(),
374 vclStateValue2StateFlag(nControlState
, value
));
376 else if ((type
== ControlType::Toolbar
)
377 && (part
== ControlPart::ThumbVert
|| part
== ControlPart::ThumbHorz
))
378 { // reduce paint area only to the handle area
379 const int handleExtend
= QApplication::style()->pixelMetric(QStyle::PM_ToolBarHandleExtent
);
381 option
.state
= vclStateValue2StateFlag(nControlState
, value
);
383 QPainter
painter(m_image
.get());
384 if (part
== ControlPart::ThumbVert
)
386 option
.rect
= QRect(0, 0, handleExtend
, widgetRect
.height());
387 painter
.setClipRect(widgetRect
.x(), widgetRect
.y(), handleExtend
, widgetRect
.height());
388 option
.state
|= QStyle::State_Horizontal
;
392 option
.rect
= QRect(0, 0, widgetRect
.width(), handleExtend
);
393 painter
.setClipRect(widgetRect
.x(), widgetRect
.y(), widgetRect
.width(), handleExtend
);
395 QApplication::style()->drawPrimitive(QStyle::PE_IndicatorToolBarHandle
, &option
, &painter
);
397 else if (type
== ControlType::Editbox
|| type
== ControlType::MultilineEditbox
)
399 lcl_drawFrame(QStyle::PE_FrameLineEdit
, m_image
.get(),
400 vclStateValue2StateFlag(nControlState
, value
), false);
402 else if (type
== ControlType::Combobox
)
404 QStyleOptionComboBox option
;
405 option
.editable
= true;
406 draw(QStyle::CC_ComboBox
, &option
, m_image
.get(),
407 vclStateValue2StateFlag(nControlState
, value
));
409 else if (type
== ControlType::Listbox
)
411 QStyleOptionComboBox option
;
412 option
.editable
= false;
415 case ControlPart::ListboxWindow
:
416 lcl_drawFrame(QStyle::PE_Frame
, m_image
.get(),
417 vclStateValue2StateFlag(nControlState
, value
), true,
418 QStyle::PM_ComboBoxFrameWidth
);
420 case ControlPart::SubEdit
:
421 draw(QStyle::CE_ComboBoxLabel
, &option
, m_image
.get(),
422 vclStateValue2StateFlag(nControlState
, value
));
424 case ControlPart::Entire
:
425 draw(QStyle::CC_ComboBox
, &option
, m_image
.get(),
426 vclStateValue2StateFlag(nControlState
, value
));
428 case ControlPart::ButtonDown
:
429 option
.subControls
= QStyle::SC_ComboBoxArrow
;
430 draw(QStyle::CC_ComboBox
, &option
, m_image
.get(),
431 vclStateValue2StateFlag(nControlState
, value
));
438 else if (type
== ControlType::ListNode
)
441 option
.state
= QStyle::State_Item
| QStyle::State_Children
;
443 if (value
.getTristateVal() == ButtonValue::On
)
444 option
.state
|= QStyle::State_Open
;
446 draw(QStyle::PE_IndicatorBranch
, &option
, m_image
.get(),
447 vclStateValue2StateFlag(nControlState
, value
));
449 else if (type
== ControlType::ListHeader
)
451 QStyleOptionHeader option
;
452 draw(QStyle::CE_HeaderSection
, &option
, m_image
.get(),
453 vclStateValue2StateFlag(nControlState
, value
));
455 else if (type
== ControlType::Checkbox
)
457 if (part
== ControlPart::Entire
)
459 QStyleOptionButton option
;
460 // clear FOCUSED bit, focus is drawn separately
461 nControlState
&= ~ControlState::FOCUSED
;
462 draw(QStyle::CE_CheckBox
, &option
, m_image
.get(),
463 vclStateValue2StateFlag(nControlState
, value
));
465 else if (part
== ControlPart::Focus
)
467 QStyleOptionFocusRect option
;
468 draw(QStyle::PE_FrameFocusRect
, &option
, m_image
.get(),
469 vclStateValue2StateFlag(nControlState
, value
));
472 else if (type
== ControlType::Scrollbar
)
474 if ((part
== ControlPart::DrawBackgroundVert
) || (part
== ControlPart::DrawBackgroundHorz
))
476 QStyleOptionSlider option
;
477 assert(value
.getType() == ControlType::Scrollbar
);
478 const ScrollbarValue
* sbVal
= static_cast<const ScrollbarValue
*>(&value
);
480 //if the scroll bar is active (aka not degenerate... allow for hover events)
481 if (sbVal
->mnVisibleSize
< sbVal
->mnMax
)
482 option
.state
= QStyle::State_MouseOver
;
484 bool horizontal
= (part
== ControlPart::DrawBackgroundHorz
); //horizontal or vertical
485 option
.orientation
= horizontal
? Qt::Horizontal
: Qt::Vertical
;
487 option
.state
|= QStyle::State_Horizontal
;
489 //setup parameters from the OO values
490 option
.minimum
= sbVal
->mnMin
;
491 option
.maximum
= sbVal
->mnMax
- sbVal
->mnVisibleSize
;
492 option
.maximum
= qMax(option
.maximum
, option
.minimum
); // bnc#619772
493 option
.sliderValue
= sbVal
->mnCur
;
494 option
.sliderPosition
= sbVal
->mnCur
;
495 option
.pageStep
= sbVal
->mnVisibleSize
;
496 if (part
== ControlPart::DrawBackgroundHorz
)
497 option
.upsideDown
= sbVal
->maButton1Rect
.Left() > sbVal
->maButton2Rect
.Left();
499 //setup the active control... always the slider
500 if (sbVal
->mnThumbState
& ControlState::ROLLOVER
)
501 option
.activeSubControls
= QStyle::SC_ScrollBarSlider
;
503 draw(QStyle::CC_ScrollBar
, &option
, m_image
.get(),
504 vclStateValue2StateFlag(nControlState
, value
));
511 else if (type
== ControlType::Spinbox
)
513 QStyleOptionSpinBox option
;
516 // determine active control
517 if (value
.getType() == ControlType::SpinButtons
)
519 const SpinbuttonValue
* pSpinVal
= static_cast<const SpinbuttonValue
*>(&value
);
520 if (pSpinVal
->mnUpperState
& ControlState::PRESSED
)
521 option
.activeSubControls
|= QStyle::SC_SpinBoxUp
;
522 if (pSpinVal
->mnLowerState
& ControlState::PRESSED
)
523 option
.activeSubControls
|= QStyle::SC_SpinBoxDown
;
524 if (pSpinVal
->mnUpperState
& ControlState::ENABLED
)
525 option
.stepEnabled
|= QAbstractSpinBox::StepUpEnabled
;
526 if (pSpinVal
->mnLowerState
& ControlState::ENABLED
)
527 option
.stepEnabled
|= QAbstractSpinBox::StepDownEnabled
;
528 if (pSpinVal
->mnUpperState
& ControlState::ROLLOVER
)
529 option
.state
= QStyle::State_MouseOver
;
530 if (pSpinVal
->mnLowerState
& ControlState::ROLLOVER
)
531 option
.state
= QStyle::State_MouseOver
;
534 draw(QStyle::CC_SpinBox
, &option
, m_image
.get(),
535 vclStateValue2StateFlag(nControlState
, value
));
537 else if (type
== ControlType::Radiobutton
)
539 if (part
== ControlPart::Entire
)
541 QStyleOptionButton option
;
542 // clear FOCUSED bit, focus is drawn separately
543 nControlState
&= ~ControlState::FOCUSED
;
544 draw(QStyle::CE_RadioButton
, &option
, m_image
.get(),
545 vclStateValue2StateFlag(nControlState
, value
));
547 else if (part
== ControlPart::Focus
)
549 QStyleOptionFocusRect option
;
550 draw(QStyle::PE_FrameFocusRect
, &option
, m_image
.get(),
551 vclStateValue2StateFlag(nControlState
, value
));
554 else if (type
== ControlType::Tooltip
)
557 draw(QStyle::PE_PanelTipLabel
, &option
, m_image
.get(),
558 vclStateValue2StateFlag(nControlState
, value
));
560 else if (type
== ControlType::Frame
)
562 lcl_drawFrame(QStyle::PE_Frame
, m_image
.get(),
563 vclStateValue2StateFlag(nControlState
, value
));
565 else if (type
== ControlType::WindowBackground
)
567 // Nothing to do - see "Default image color" switch ^^
569 else if (type
== ControlType::Fixedline
)
571 QStyleOptionMenuItem option
;
572 option
.menuItemType
= QStyleOptionMenuItem::Separator
;
573 option
.state
|= QStyle::State_Item
;
575 draw(QStyle::CE_MenuItem
, &option
, m_image
.get(),
576 vclStateValue2StateFlag(nControlState
, value
));
578 else if (type
== ControlType::Slider
579 && (part
== ControlPart::TrackHorzArea
|| part
== ControlPart::TrackVertArea
))
581 assert(value
.getType() == ControlType::Slider
);
582 const SliderValue
* slVal
= static_cast<const SliderValue
*>(&value
);
583 QStyleOptionSlider option
;
585 option
.rect
= QRect(0, 0, widgetRect
.width(), widgetRect
.height());
586 option
.state
= vclStateValue2StateFlag(nControlState
, value
);
587 option
.maximum
= slVal
->mnMax
;
588 option
.minimum
= slVal
->mnMin
;
589 option
.sliderPosition
= option
.sliderValue
= slVal
->mnCur
;
590 bool horizontal
= (part
== ControlPart::TrackHorzArea
); //horizontal or vertical
591 option
.orientation
= horizontal
? Qt::Horizontal
: Qt::Vertical
;
593 option
.state
|= QStyle::State_Horizontal
;
595 draw(QStyle::CC_Slider
, &option
, m_image
.get(),
596 vclStateValue2StateFlag(nControlState
, value
));
598 else if (type
== ControlType::Progress
&& part
== ControlPart::Entire
)
600 SAL_WNODEPRECATED_DECLARATIONS_PUSH
601 QStyleOptionProgressBarV2 option
;
602 SAL_WNODEPRECATED_DECLARATIONS_POP
604 option
.maximum
= widgetRect
.width();
605 option
.progress
= value
.getNumericVal();
606 option
.rect
= QRect(0, 0, widgetRect
.width(), widgetRect
.height());
607 option
.state
= vclStateValue2StateFlag(nControlState
, value
);
609 draw(QStyle::CE_ProgressBar
, &option
, m_image
.get(),
610 vclStateValue2StateFlag(nControlState
, value
));
620 bool Qt5Graphics_Controls::getNativeControlRegion(ControlType type
, ControlPart part
,
621 const tools::Rectangle
& controlRegion
,
622 ControlState controlState
,
623 const ImplControlValue
& val
, const OUString
&,
624 tools::Rectangle
& nativeBoundingRegion
,
625 tools::Rectangle
& nativeContentRegion
)
629 QRect boundingRect
= toQRect(controlRegion
);
630 QRect contentRect
= boundingRect
;
631 QStyleOptionComplex styleOption
;
635 // Metrics of the push button
636 case ControlType::Pushbutton
:
637 if (part
== ControlPart::Entire
)
639 styleOption
.state
= vclStateValue2StateFlag(controlState
, val
);
641 if (controlState
& ControlState::DEFAULT
)
643 int size
= QApplication::style()->pixelMetric(QStyle::PM_ButtonDefaultIndicator
,
645 boundingRect
.adjust(-size
, -size
, size
, size
);
650 case ControlType::Editbox
:
651 case ControlType::MultilineEditbox
:
653 QStyleOptionFrame fo
;
654 fo
.frameShape
= QFrame::StyledPanel
;
655 fo
.state
= QStyle::State_Sunken
;
656 fo
.lineWidth
= QApplication::style()->pixelMetric(QStyle::PM_DefaultFrameWidth
);
657 QSize aMinSize
= QApplication::style()->sizeFromContents(QStyle::CT_LineEdit
, &fo
,
659 if (aMinSize
.height() > boundingRect
.height())
661 int nHeight
= (aMinSize
.height() - boundingRect
.height()) / 2;
662 assert(0 == (aMinSize
.height() - boundingRect
.height()) % 2);
663 boundingRect
.adjust(0, -nHeight
, 0, nHeight
);
665 if (aMinSize
.width() > boundingRect
.width())
667 int nWidth
= (aMinSize
.width() - boundingRect
.width()) / 2;
668 assert(0 == (aMinSize
.width() - boundingRect
.width()) % 2);
669 boundingRect
.adjust(-nWidth
, 0, nWidth
, 0);
674 case ControlType::Checkbox
:
675 if (part
== ControlPart::Entire
)
677 styleOption
.state
= vclStateValue2StateFlag(controlState
, val
);
679 contentRect
.setWidth(
680 QApplication::style()->pixelMetric(QStyle::PM_IndicatorWidth
, &styleOption
));
681 contentRect
.setHeight(
682 QApplication::style()->pixelMetric(QStyle::PM_IndicatorHeight
, &styleOption
));
684 contentRect
.adjust(0, 0,
686 * QApplication::style()->pixelMetric(
687 QStyle::PM_FocusFrameHMargin
, &styleOption
),
689 * QApplication::style()->pixelMetric(
690 QStyle::PM_FocusFrameVMargin
, &styleOption
));
692 boundingRect
= contentRect
;
697 case ControlType::Combobox
:
698 case ControlType::Listbox
:
700 QStyleOptionComboBox cbo
;
702 cbo
.rect
= QRect(0, 0, contentRect
.width(), contentRect
.height());
703 cbo
.state
= vclStateValue2StateFlag(controlState
, val
);
707 case ControlPart::Entire
:
709 // find out the minimum size that should be used
710 // assume contents is a text line
711 int nHeight
= QApplication::fontMetrics().height();
712 QSize
aContentSize(contentRect
.width(), nHeight
);
713 QSize aMinSize
= QApplication::style()->sizeFromContents(QStyle::CT_ComboBox
,
715 if (aMinSize
.height() > contentRect
.height())
716 contentRect
.adjust(0, 0, 0, aMinSize
.height() - contentRect
.height());
717 boundingRect
= contentRect
;
721 case ControlPart::ButtonDown
:
722 contentRect
= QApplication::style()->subControlRect(QStyle::CC_ComboBox
, &cbo
,
723 QStyle::SC_ComboBoxArrow
);
724 contentRect
.translate(boundingRect
.left(), boundingRect
.top());
727 case ControlPart::SubEdit
:
729 contentRect
= QApplication::style()->subControlRect(
730 QStyle::CC_ComboBox
, &cbo
, QStyle::SC_ComboBoxEditField
);
731 contentRect
.translate(boundingRect
.left(), boundingRect
.top());
740 case ControlType::Spinbox
:
742 QStyleOptionSpinBox sbo
;
745 sbo
.rect
= QRect(0, 0, contentRect
.width(), contentRect
.height());
746 sbo
.state
= vclStateValue2StateFlag(controlState
, val
);
750 case ControlPart::Entire
:
752 int nHeight
= QApplication::fontMetrics().height();
753 QSize
aContentSize(contentRect
.width(), nHeight
);
754 QSize aMinSize
= QApplication::style()->sizeFromContents(QStyle::CT_SpinBox
,
756 if (aMinSize
.height() > contentRect
.height())
757 contentRect
.adjust(0, 0, 0, aMinSize
.height() - contentRect
.height());
758 boundingRect
= contentRect
;
762 case ControlPart::ButtonUp
:
763 contentRect
= QApplication::style()->subControlRect(QStyle::CC_SpinBox
, &sbo
,
764 QStyle::SC_SpinBoxUp
);
765 contentRect
.translate(boundingRect
.left(), boundingRect
.top());
767 boundingRect
= QRect();
770 case ControlPart::ButtonDown
:
771 contentRect
= QApplication::style()->subControlRect(QStyle::CC_SpinBox
, &sbo
,
772 QStyle::SC_SpinBoxDown
);
774 contentRect
.translate(boundingRect
.left(), boundingRect
.top());
775 boundingRect
= QRect();
778 case ControlPart::SubEdit
:
779 contentRect
= QApplication::style()->subControlRect(
780 QStyle::CC_SpinBox
, &sbo
, QStyle::SC_SpinBoxEditField
);
782 contentRect
.translate(boundingRect
.left(), boundingRect
.top());
789 case ControlType::MenuPopup
:
794 case ControlPart::MenuItemCheckMark
:
795 h
= QApplication::style()->pixelMetric(QStyle::PM_IndicatorHeight
);
796 w
= QApplication::style()->pixelMetric(QStyle::PM_IndicatorWidth
);
799 case ControlPart::MenuItemRadioMark
:
800 h
= QApplication::style()->pixelMetric(QStyle::PM_ExclusiveIndicatorHeight
);
801 w
= QApplication::style()->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth
);
809 contentRect
= QRect(0, 0, w
, h
);
810 boundingRect
= contentRect
;
814 case ControlType::Frame
:
816 if (part
== ControlPart::Border
)
818 auto nStyle
= static_cast<DrawFrameFlags
>(val
.getNumericVal() & 0xFFF0);
819 if (nStyle
& DrawFrameFlags::NoDraw
)
822 = QApplication::style()->pixelMetric(QStyle::PM_DefaultFrameWidth
);
823 contentRect
.adjust(nFrameWidth
, nFrameWidth
, -nFrameWidth
, -nFrameWidth
);
829 case ControlType::Radiobutton
:
831 const int h
= QApplication::style()->pixelMetric(QStyle::PM_ExclusiveIndicatorHeight
);
832 const int w
= QApplication::style()->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth
);
834 contentRect
= QRect(boundingRect
.left(), boundingRect
.top(), w
, h
);
837 2 * QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin
, &styleOption
),
838 2 * QApplication::style()->pixelMetric(QStyle::PM_FocusFrameVMargin
, &styleOption
));
839 boundingRect
= contentRect
;
844 case ControlType::Slider
:
846 const int w
= QApplication::style()->pixelMetric(QStyle::PM_SliderLength
);
847 if (part
== ControlPart::ThumbHorz
)
850 = QRect(boundingRect
.left(), boundingRect
.top(), w
, boundingRect
.height());
851 boundingRect
= contentRect
;
854 else if (part
== ControlPart::ThumbVert
)
857 = QRect(boundingRect
.left(), boundingRect
.top(), boundingRect
.width(), w
);
858 boundingRect
= contentRect
;
863 case ControlType::Toolbar
:
865 const int nWorH
= QApplication::style()->pixelMetric(QStyle::PM_ToolBarHandleExtent
);
866 if (part
== ControlPart::ThumbHorz
)
869 = QRect(boundingRect
.left(), boundingRect
.top(), boundingRect
.width(), nWorH
);
870 boundingRect
= contentRect
;
873 else if (part
== ControlPart::ThumbVert
)
876 = QRect(boundingRect
.left(), boundingRect
.top(), nWorH
, boundingRect
.height());
877 boundingRect
= contentRect
;
882 case ControlType::Scrollbar
:
884 // core can't handle 3-button scrollbars well, so we fix that in hitTestNativeControl(),
885 // for the rest also provide the track area (i.e. area not taken by buttons)
886 if (part
== ControlPart::TrackVertArea
|| part
== ControlPart::TrackHorzArea
)
888 QStyleOptionSlider option
;
889 bool horizontal
= (part
== ControlPart::TrackHorzArea
); //horizontal or vertical
890 option
.orientation
= horizontal
? Qt::Horizontal
: Qt::Vertical
;
892 option
.state
|= QStyle::State_Horizontal
;
893 // getNativeControlRegion usually gets ImplControlValue as 'val' (i.e. not the proper
894 // subclass), so use random sensible values (doesn't matter anyway, as the wanted
895 // geometry here depends only on button sizes)
898 option
.sliderPosition
= option
.sliderValue
= 4;
900 // Adjust coordinates to make the widget appear to be at (0,0), i.e. make
901 // widget and screen coordinates the same. QStyle functions should use screen
902 // coordinates but at least QPlastiqueStyle::subControlRect() is buggy
903 // and sometimes uses widget coordinates.
904 QRect rect
= contentRect
;
907 rect
= QApplication::style()->subControlRect(QStyle::CC_ScrollBar
, &option
,
908 QStyle::SC_ScrollBarGroove
);
909 rect
.translate(contentRect
.topLeft()); // reverse the workaround above
910 contentRect
= boundingRect
= rect
;
920 nativeBoundingRegion
= toRectangle(boundingRect
);
921 nativeContentRegion
= toRectangle(contentRect
);
927 /** Test whether the position is in the native widget.
928 If the return value is true, bIsInside contains information whether
929 aPos was or was not inside the native widget specified by the
930 nType/nPart combination.
932 bool Qt5Graphics_Controls::hitTestNativeControl(ControlType nType
, ControlPart nPart
,
933 const tools::Rectangle
& rControlRegion
,
934 const Point
& rPos
, bool& rIsInside
)
936 if (nType
== ControlType::Scrollbar
)
938 if (nPart
!= ControlPart::ButtonUp
&& nPart
!= ControlPart::ButtonDown
939 && nPart
!= ControlPart::ButtonLeft
&& nPart
!= ControlPart::ButtonRight
)
940 { // we adjust only for buttons (because some scrollbars have 3 buttons,
941 // and LO core doesn't handle such scrollbars well)
945 bool bHorizontal
= (nPart
== ControlPart::ButtonLeft
|| nPart
== ControlPart::ButtonRight
);
946 QRect rect
= toQRect(rControlRegion
);
947 QPoint
pos(rPos
.X(), rPos
.Y());
948 // Adjust coordinates to make the widget appear to be at (0,0), i.e. make
949 // widget and screen coordinates the same. QStyle functions should use screen
950 // coordinates but at least QPlastiqueStyle::subControlRect() is buggy
951 // and sometimes uses widget coordinates.
952 pos
-= rect
.topLeft();
954 QStyleOptionSlider options
;
955 options
.orientation
= bHorizontal
? Qt::Horizontal
: Qt::Vertical
;
957 options
.state
|= QStyle::State_Horizontal
;
959 // some random sensible values, since we call this code only for scrollbar buttons,
960 // the slider position does not exactly matter
961 options
.maximum
= 10;
963 options
.sliderPosition
= options
.sliderValue
= 4;
964 options
.pageStep
= 2;
965 QStyle::SubControl control
966 = QApplication::style()->hitTestComplexControl(QStyle::CC_ScrollBar
, &options
, pos
);
967 if (nPart
== ControlPart::ButtonUp
|| nPart
== ControlPart::ButtonLeft
)
968 rIsInside
= (control
== QStyle::SC_ScrollBarSubLine
);
970 rIsInside
= (control
== QStyle::SC_ScrollBarAddLine
);
976 void Qt5Graphics_Controls::initStyles()
979 m_focusedButton
.reset(new QPushButton());
980 QString aHighlightColor
= QApplication::palette().color(QPalette::Highlight
).name();
981 QString
focusStyleSheet("background-color: rgb(0,0,0,0%); border: 1px; border-radius: 2px; "
982 "border-color: %1; border-style:solid;");
983 focusStyleSheet
.replace("%1", aHighlightColor
);
984 m_focusedButton
->setStyleSheet(focusStyleSheet
);
987 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */