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 <tools/poly.hxx>
22 #include <vcl/image.hxx>
23 #include <vcl/bitmapex.hxx>
24 #include <vcl/decoview.hxx>
25 #include <vcl/event.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/settings.hxx>
28 #include <vcl/toolkit/dialog.hxx>
29 #include <vcl/toolkit/fixed.hxx>
30 #include <vcl/toolkit/button.hxx>
31 #include <vcl/salnativewidgets.hxx>
32 #include <vcl/toolkit/edit.hxx>
33 #include <vcl/layout.hxx>
34 #include <vcl/stdtext.hxx>
35 #include <vcl/uitest/uiobject.hxx>
37 #include <bitmaps.hlst>
40 #include <controldata.hxx>
41 #include <vclstatuslistener.hxx>
42 #include <osl/diagnose.h>
44 #include <comphelper/dispatchcommand.hxx>
45 #include <comphelper/lok.hxx>
46 #include <officecfg/Office/Common.hxx>
47 #include <boost/property_tree/ptree.hpp>
48 #include <tools/json_writer.hxx>
53 constexpr auto PUSHBUTTON_VIEW_STYLE
= WB_3DLOOK
|
54 WB_LEFT
| WB_CENTER
| WB_RIGHT
|
55 WB_TOP
| WB_VCENTER
| WB_BOTTOM
|
56 WB_WORDBREAK
| WB_NOLABEL
|
57 WB_DEFBUTTON
| WB_NOLIGHTBORDER
|
58 WB_RECTSTYLE
| WB_SMALLSTYLE
|
60 constexpr auto RADIOBUTTON_VIEW_STYLE
= WB_3DLOOK
|
61 WB_LEFT
| WB_CENTER
| WB_RIGHT
|
62 WB_TOP
| WB_VCENTER
| WB_BOTTOM
|
63 WB_WORDBREAK
| WB_NOLABEL
;
64 constexpr auto CHECKBOX_VIEW_STYLE
= WB_3DLOOK
|
65 WB_LEFT
| WB_CENTER
| WB_RIGHT
|
66 WB_TOP
| WB_VCENTER
| WB_BOTTOM
|
67 WB_WORDBREAK
| WB_NOLABEL
;
69 #define STYLE_RADIOBUTTON_MONO (sal_uInt16(0x0001)) // legacy
70 #define STYLE_CHECKBOX_MONO (sal_uInt16(0x0001)) // legacy
72 class ImplCommonButtonData
75 ImplCommonButtonData();
77 tools::Rectangle maFocusRect
;
78 tools::Long mnSeparatorX
;
79 DrawButtonFlags mnButtonState
;
83 ImageAlign meImageAlign
;
84 SymbolAlign meSymbolAlign
;
86 /** StatusListener. Updates the button as the slot state changes */
87 rtl::Reference
<VclStatusListener
<Button
>> mpStatusListener
;
90 ImplCommonButtonData::ImplCommonButtonData() : maFocusRect(), mnSeparatorX(0), mnButtonState(DrawButtonFlags::NONE
),
91 mbSmallSymbol(false), maImage(), meImageAlign(ImageAlign::Top
), meSymbolAlign(SymbolAlign::LEFT
)
95 Button::Button( WindowType nType
) :
97 mpButtonData( std::make_unique
<ImplCommonButtonData
>() )
106 void Button::dispose()
108 if (mpButtonData
->mpStatusListener
.is())
109 mpButtonData
->mpStatusListener
->dispose();
113 void Button::SetCommandHandler(const OUString
& aCommand
)
115 maCommand
= aCommand
;
116 SetClickHdl( LINK( this, Button
, dispatchCommandHandler
) );
118 mpButtonData
->mpStatusListener
= new VclStatusListener
<Button
>(this, aCommand
);
119 mpButtonData
->mpStatusListener
->startListening();
124 ImplCallEventListenersAndHandler( VclEventId::ButtonClick
, [this] () { maClickHdl
.Call(this); } );
127 void Button::SetModeImage( const Image
& rImage
)
129 if ( rImage
!= mpButtonData
->maImage
)
131 mpButtonData
->maImage
= rImage
;
132 StateChanged( StateChangedType::Data
);
137 Image
const & Button::GetModeImage( ) const
139 return mpButtonData
->maImage
;
142 bool Button::HasImage() const
144 return !!(mpButtonData
->maImage
);
147 void Button::SetImageAlign( ImageAlign eAlign
)
149 if ( mpButtonData
->meImageAlign
!= eAlign
)
151 mpButtonData
->meImageAlign
= eAlign
;
152 StateChanged( StateChangedType::Data
);
156 ImageAlign
Button::GetImageAlign() const
158 return mpButtonData
->meImageAlign
;
161 tools::Long
Button::ImplGetSeparatorX() const
163 return mpButtonData
->mnSeparatorX
;
166 void Button::ImplSetSeparatorX( tools::Long nX
)
168 mpButtonData
->mnSeparatorX
= nX
;
171 DrawTextFlags
Button::ImplGetTextStyle( WinBits nWinStyle
, DrawFlags nDrawFlags
)
173 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
174 DrawTextFlags nTextStyle
= FixedText::ImplGetTextStyle(nWinStyle
& ~WB_DEFBUTTON
);
177 nTextStyle
|= DrawTextFlags::Disable
;
179 if ((nDrawFlags
& DrawFlags::Mono
) ||
180 (rStyleSettings
.GetOptions() & StyleSettingsOptions::Mono
))
182 nTextStyle
|= DrawTextFlags::Mono
;
188 void Button::ImplDrawAlignedImage(OutputDevice
* pDev
, Point
& rPos
,
191 DrawTextFlags nTextStyle
, tools::Rectangle
*pSymbolRect
,
194 OUString
aText(GetText());
195 bool bDrawImage
= HasImage();
196 bool bDrawText
= !aText
.isEmpty();
197 bool bHasSymbol
= pSymbolRect
!= nullptr;
199 // No text and no image => nothing to do => return
200 if (!bDrawImage
&& !bDrawText
&& !bHasSymbol
)
203 WinBits nWinStyle
= GetStyle();
204 tools::Rectangle
aOutRect( rPos
, rSize
);
205 ImageAlign eImageAlign
= mpButtonData
->meImageAlign
;
206 Size aImageSize
= mpButtonData
->maImage
.GetSizePixel();
208 aImageSize
.setWidth( CalcZoom( aImageSize
.Width() ) );
209 aImageSize
.setHeight( CalcZoom( aImageSize
.Height() ) );
211 // Drawing text or symbol only is simple, use style and output rectangle
212 if (bHasSymbol
&& !bDrawImage
&& !bDrawText
)
214 *pSymbolRect
= aOutRect
;
217 else if (bDrawText
&& !bDrawImage
&& !bHasSymbol
)
219 aOutRect
= DrawControlText(*pDev
, aOutRect
, aText
, nTextStyle
, nullptr, nullptr);
220 tools::Rectangle textRect
= GetTextRect(
221 tools::Rectangle(Point(), Size(0x7fffffff, 0x7fffffff)), aText
, nTextStyle
);
222 // If the button text doesn't fit into it, put it into a tooltip (might happen in sidebar)
223 if (GetQuickHelpText().isEmpty() && textRect
.getWidth() > rSize
.getWidth())
224 SetQuickHelpText(aText
);
226 ImplSetFocusRect(aOutRect
);
227 rSize
= aOutRect
.GetSize();
228 rPos
= aOutRect
.TopLeft();
233 // check for HC mode ( image only! )
234 Image
* pImage
= &(mpButtonData
->maImage
);
238 Size aDeviceTextSize
;
239 Point aImagePos
= rPos
;
240 Point aTextPos
= rPos
;
241 tools::Rectangle
aUnion(aImagePos
, aImageSize
);
242 tools::Long nSymbolHeight
= 0;
244 if (bDrawText
|| bHasSymbol
)
246 // Get the size of the text output area ( the symbol will be drawn in
247 // this area as well, so the symbol rectangle will be calculated here, too )
249 tools::Rectangle
aRect(Point(), rSize
);
254 tools::Rectangle aSymbol
;
257 nSymbolHeight
= pDev
->GetTextHeight();
258 if (mpButtonData
->mbSmallSymbol
)
259 nSymbolHeight
= nSymbolHeight
* 3 / 4;
261 aSymbol
= tools::Rectangle(Point(), Size(nSymbolHeight
, nSymbolHeight
));
262 ImplCalcSymbolRect(aSymbol
);
263 aRect
.AdjustLeft(3 * nSymbolHeight
/ 2 );
264 aTSSize
.setWidth( 3 * nSymbolHeight
/ 2 );
268 aSymbol
= tools::Rectangle(Point(), rSize
);
269 ImplCalcSymbolRect(aSymbol
);
270 aTSSize
.setWidth( aSymbol
.GetWidth() );
272 aTSSize
.setHeight( aSymbol
.GetHeight() );
273 aSymbolSize
= aSymbol
.GetSize();
278 if ((eImageAlign
== ImageAlign::LeftTop
) ||
279 (eImageAlign
== ImageAlign::Left
) ||
280 (eImageAlign
== ImageAlign::LeftBottom
) ||
281 (eImageAlign
== ImageAlign::RightTop
) ||
282 (eImageAlign
== ImageAlign::Right
) ||
283 (eImageAlign
== ImageAlign::RightBottom
))
285 aRect
.AdjustRight( -sal_Int32(aImageSize
.Width() + nImageSep
) );
287 else if ((eImageAlign
== ImageAlign::TopLeft
) ||
288 (eImageAlign
== ImageAlign::Top
) ||
289 (eImageAlign
== ImageAlign::TopRight
) ||
290 (eImageAlign
== ImageAlign::BottomLeft
) ||
291 (eImageAlign
== ImageAlign::Bottom
) ||
292 (eImageAlign
== ImageAlign::BottomRight
))
294 aRect
.AdjustBottom( -sal_Int32(aImageSize
.Height() + nImageSep
) );
297 aRect
= GetControlTextRect(*pDev
, aRect
, aText
, nTextStyle
, &aDeviceTextSize
);
298 aTextSize
= aRect
.GetSize();
300 aTSSize
.AdjustWidth(aTextSize
.Width() );
302 if (aTSSize
.Height() < aTextSize
.Height())
303 aTSSize
.setHeight( aTextSize
.Height() );
305 if (bAddImageSep
&& bDrawImage
)
307 tools::Long nDiff
= (aImageSize
.Height() - aTextSize
.Height()) / 3;
314 aMax
.setWidth( std::max(aTSSize
.Width(), aImageSize
.Width()) );
315 aMax
.setHeight( std::max(aTSSize
.Height(), aImageSize
.Height()) );
317 // Now calculate the output area for the image and the text according to the image align flags
319 if ((eImageAlign
== ImageAlign::Left
) ||
320 (eImageAlign
== ImageAlign::Right
))
322 aImagePos
.setY( rPos
.Y() + (aMax
.Height() - aImageSize
.Height()) / 2 );
323 aTextPos
.setY( rPos
.Y() + (aMax
.Height() - aTSSize
.Height()) / 2 );
325 else if ((eImageAlign
== ImageAlign::LeftBottom
) ||
326 (eImageAlign
== ImageAlign::RightBottom
))
328 aImagePos
.setY( rPos
.Y() + aMax
.Height() - aImageSize
.Height() );
329 aTextPos
.setY( rPos
.Y() + aMax
.Height() - aTSSize
.Height() );
331 else if ((eImageAlign
== ImageAlign::Top
) ||
332 (eImageAlign
== ImageAlign::Bottom
))
334 aImagePos
.setX( rPos
.X() + (aMax
.Width() - aImageSize
.Width()) / 2 );
335 aTextPos
.setX( rPos
.X() + (aMax
.Width() - aTSSize
.Width()) / 2 );
337 else if ((eImageAlign
== ImageAlign::TopRight
) ||
338 (eImageAlign
== ImageAlign::BottomRight
))
340 aImagePos
.setX( rPos
.X() + aMax
.Width() - aImageSize
.Width() );
341 aTextPos
.setX( rPos
.X() + aMax
.Width() - aTSSize
.Width() );
344 if ((eImageAlign
== ImageAlign::LeftTop
) ||
345 (eImageAlign
== ImageAlign::Left
) ||
346 (eImageAlign
== ImageAlign::LeftBottom
))
348 aTextPos
.setX( rPos
.X() + aImageSize
.Width() + nImageSep
);
350 else if ((eImageAlign
== ImageAlign::RightTop
) ||
351 (eImageAlign
== ImageAlign::Right
) ||
352 (eImageAlign
== ImageAlign::RightBottom
))
354 aImagePos
.setX( rPos
.X() + aTSSize
.Width() + nImageSep
);
356 else if ((eImageAlign
== ImageAlign::TopLeft
) ||
357 (eImageAlign
== ImageAlign::Top
) ||
358 (eImageAlign
== ImageAlign::TopRight
))
360 aTextPos
.setY( rPos
.Y() + aImageSize
.Height() + nImageSep
);
362 else if ((eImageAlign
== ImageAlign::BottomLeft
) ||
363 (eImageAlign
== ImageAlign::Bottom
) ||
364 (eImageAlign
== ImageAlign::BottomRight
))
366 aImagePos
.setY( rPos
.Y() + aTSSize
.Height() + nImageSep
);
368 else if (eImageAlign
== ImageAlign::Center
)
370 aImagePos
.setX( rPos
.X() + (aMax
.Width() - aImageSize
.Width()) / 2 );
371 aImagePos
.setY( rPos
.Y() + (aMax
.Height() - aImageSize
.Height()) / 2 );
372 aTextPos
.setX( rPos
.X() + (aMax
.Width() - aTSSize
.Width()) / 2 );
373 aTextPos
.setY( rPos
.Y() + (aMax
.Height() - aTSSize
.Height()) / 2 );
375 aUnion
= tools::Rectangle(aImagePos
, aImageSize
);
376 aUnion
.Union(tools::Rectangle(aTextPos
, aTSSize
));
379 // Now place the combination of text and image in the output area of the button
380 // according to the window style (WinBits)
381 tools::Long nXOffset
= 0;
382 tools::Long nYOffset
= 0;
384 if (nWinStyle
& WB_CENTER
)
386 nXOffset
= (rSize
.Width() - aUnion
.GetWidth()) / 2;
388 else if (nWinStyle
& WB_RIGHT
)
390 nXOffset
= rSize
.Width() - aUnion
.GetWidth();
393 if (nWinStyle
& WB_VCENTER
)
395 nYOffset
= (rSize
.Height() - aUnion
.GetHeight()) / 2;
397 else if (nWinStyle
& WB_BOTTOM
)
399 nYOffset
= rSize
.Height() - aUnion
.GetHeight();
402 // the top left corner should always be visible, so we don't allow negative offsets
403 if (nXOffset
< 0) nXOffset
= 0;
404 if (nYOffset
< 0) nYOffset
= 0;
406 aImagePos
.AdjustX(nXOffset
);
407 aImagePos
.AdjustY(nYOffset
);
408 aTextPos
.AdjustX(nXOffset
);
409 aTextPos
.AdjustY(nYOffset
);
411 // set rPos and rSize to the union
412 rSize
= aUnion
.GetSize();
413 rPos
.AdjustX(nXOffset
);
414 rPos
.AdjustY(nYOffset
);
418 if (mpButtonData
->meSymbolAlign
== SymbolAlign::RIGHT
)
420 Point
aRightPos(aTextPos
.X() + aTextSize
.Width() + aSymbolSize
.Width() / 2, aTextPos
.Y());
421 *pSymbolRect
= tools::Rectangle(aRightPos
, aSymbolSize
);
425 *pSymbolRect
= tools::Rectangle(aTextPos
, aSymbolSize
);
426 aTextPos
.AdjustX(3 * nSymbolHeight
/ 2 );
428 if (mpButtonData
->mbSmallSymbol
)
430 nYOffset
= (aUnion
.GetHeight() - aSymbolSize
.Height()) / 2;
431 pSymbolRect
->setY(aTextPos
.Y() + nYOffset
);
435 DrawImageFlags nStyle
= DrawImageFlags::NONE
;
439 nStyle
|= DrawImageFlags::Disable
;
443 pDev
->DrawImage(aImagePos
, aImageSize
, *pImage
, nStyle
);
445 pDev
->DrawImage(aImagePos
, *pImage
, nStyle
);
449 const tools::Rectangle
aTOutRect(aTextPos
, aTextSize
);
450 ImplSetFocusRect(aTOutRect
);
451 DrawControlText(*pDev
, aTOutRect
, aText
, nTextStyle
, nullptr, nullptr, &aDeviceTextSize
);
455 ImplSetFocusRect(tools::Rectangle(aImagePos
, aImageSize
));
459 void Button::ImplSetFocusRect(const tools::Rectangle
&rFocusRect
)
461 tools::Rectangle aFocusRect
= rFocusRect
;
462 tools::Rectangle
aOutputRect(Point(), GetOutputSizePixel());
464 if (!aFocusRect
.IsEmpty())
466 aFocusRect
.AdjustLeft( -1 );
467 aFocusRect
.AdjustTop( -1 );
468 aFocusRect
.AdjustRight( 1 );
469 aFocusRect
.AdjustBottom( 1 );
472 if (aFocusRect
.Left() < aOutputRect
.Left())
473 aFocusRect
.SetLeft( aOutputRect
.Left() );
474 if (aFocusRect
.Top() < aOutputRect
.Top())
475 aFocusRect
.SetTop( aOutputRect
.Top() );
476 if (aFocusRect
.Right() > aOutputRect
.Right())
477 aFocusRect
.SetRight( aOutputRect
.Right() );
478 if (aFocusRect
.Bottom() > aOutputRect
.Bottom())
479 aFocusRect
.SetBottom( aOutputRect
.Bottom() );
481 mpButtonData
->maFocusRect
= aFocusRect
;
484 const tools::Rectangle
& Button::ImplGetFocusRect() const
486 return mpButtonData
->maFocusRect
;
489 DrawButtonFlags
& Button::GetButtonState()
491 return mpButtonData
->mnButtonState
;
494 DrawButtonFlags
Button::GetButtonState() const
496 return mpButtonData
->mnButtonState
;
499 void Button::ImplSetSymbolAlign( SymbolAlign eAlign
)
501 if ( mpButtonData
->meSymbolAlign
!= eAlign
)
503 mpButtonData
->meSymbolAlign
= eAlign
;
504 StateChanged( StateChangedType::Data
);
508 void Button::SetSmallSymbol()
510 mpButtonData
->mbSmallSymbol
= true;
513 bool Button::IsSmallSymbol () const
515 return mpButtonData
->mbSmallSymbol
;
518 bool Button::set_property(const OString
&rKey
, const OUString
&rValue
)
520 if (rKey
== "image-position")
522 ImageAlign eAlign
= ImageAlign::Left
;
523 if (rValue
== "left")
524 eAlign
= ImageAlign::Left
;
525 else if (rValue
== "right")
526 eAlign
= ImageAlign::Right
;
527 else if (rValue
== "top")
528 eAlign
= ImageAlign::Top
;
529 else if (rValue
== "bottom")
530 eAlign
= ImageAlign::Bottom
;
531 SetImageAlign(eAlign
);
533 else if (rKey
== "focus-on-click")
535 WinBits nBits
= GetStyle();
536 nBits
&= ~WB_NOPOINTERFOCUS
;
538 nBits
|= WB_NOPOINTERFOCUS
;
542 return Control::set_property(rKey
, rValue
);
546 void Button::statusChanged(const css::frame::FeatureStateEvent
& rEvent
)
548 Enable(rEvent
.IsEnabled
);
551 FactoryFunction
Button::GetUITestFactory() const
553 return ButtonUIObject::create
;
556 void Button::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
558 Control::DumpAsPropertyTree(rJsonWriter
);
559 rJsonWriter
.put("text", GetText());
562 IMPL_STATIC_LINK( Button
, dispatchCommandHandler
, Button
*, pButton
, void )
564 if (pButton
== nullptr)
567 comphelper::dispatchCommand(pButton
->maCommand
, uno::Sequence
<beans::PropertyValue
>());
570 void PushButton::ImplInitPushButtonData()
572 mpWindowImpl
->mbPushButton
= true;
574 meSymbol
= SymbolType::DONTKNOW
;
575 meState
= TRISTATE_FALSE
;
576 mnDDStyle
= PushButtonDropdownStyle::NONE
;
584 vcl::Window
* getPreviousSibling(vcl::Window
const *pParent
)
586 return pParent
? pParent
->GetWindow(GetWindowType::LastChild
) : nullptr;
590 void PushButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
592 nStyle
= ImplInitStyle(getPreviousSibling(pParent
), nStyle
);
593 Button::ImplInit( pParent
, nStyle
, nullptr );
595 if ( nStyle
& WB_NOLIGHTBORDER
)
596 GetButtonState() |= DrawButtonFlags::NoLightBorder
;
598 ImplInitSettings( true );
601 WinBits
PushButton::ImplInitStyle( const vcl::Window
* pPrevWindow
, WinBits nStyle
)
603 if ( !(nStyle
& WB_NOTABSTOP
) )
604 nStyle
|= WB_TABSTOP
;
606 // if no alignment is given, default to "vertically centered". This is because since
607 // #i26046#, we respect the vertical alignment flags (previously we didn't completely),
608 // but we of course want to look as before when no vertical alignment is specified
609 if ( ( nStyle
& ( WB_TOP
| WB_VCENTER
| WB_BOTTOM
) ) == 0 )
610 nStyle
|= WB_VCENTER
;
612 if ( !(nStyle
& WB_NOGROUP
) &&
614 ((pPrevWindow
->GetType() != WindowType::PUSHBUTTON
) &&
615 (pPrevWindow
->GetType() != WindowType::OKBUTTON
) &&
616 (pPrevWindow
->GetType() != WindowType::CANCELBUTTON
) &&
617 (pPrevWindow
->GetType() != WindowType::HELPBUTTON
)) ) )
622 const vcl::Font
& PushButton::GetCanonicalFont( const StyleSettings
& _rStyle
) const
624 return _rStyle
.GetPushButtonFont();
627 const Color
& PushButton::GetCanonicalTextColor( const StyleSettings
& _rStyle
) const
629 return _rStyle
.GetButtonTextColor();
632 void PushButton::ImplInitSettings( bool bBackground
)
634 Button::ImplInitSettings();
640 // #i38498#: do not check for GetParent()->IsChildTransparentModeEnabled()
641 // otherwise the formcontrol button will be overdrawn due to ParentClipMode::NoClip
642 // for radio and checkbox this is ok as they should appear transparent in documents
643 if ( IsNativeControlSupported( ControlType::Pushbutton
, ControlPart::Entire
) ||
644 (GetStyle() & WB_FLATBUTTON
) != 0 )
646 EnableChildTransparentMode();
647 SetParentClipMode( ParentClipMode::NoClip
);
648 SetPaintTransparent( true );
650 if ((GetStyle() & WB_FLATBUTTON
) == 0)
651 mpWindowImpl
->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
653 mpWindowImpl
->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRectsForFlatButtons
;
657 EnableChildTransparentMode( false );
659 SetPaintTransparent( false );
663 void PushButton::ImplDrawPushButtonFrame(vcl::RenderContext
& rRenderContext
,
664 tools::Rectangle
& rRect
, DrawButtonFlags nStyle
)
666 if (!(GetStyle() & (WB_RECTSTYLE
| WB_SMALLSTYLE
)))
668 StyleSettings aStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
669 if (IsControlBackground())
670 aStyleSettings
.Set3DColors(GetControlBackground());
673 DecorationView
aDecoView(&rRenderContext
);
674 if (IsControlBackground())
676 AllSettings aSettings
= rRenderContext
.GetSettings();
677 AllSettings aOldSettings
= aSettings
;
678 StyleSettings aStyleSettings
= aSettings
.GetStyleSettings();
679 aStyleSettings
.Set3DColors(GetControlBackground());
680 aSettings
.SetStyleSettings(aStyleSettings
);
682 // Call OutputDevice::SetSettings() explicitly, as rRenderContext may
683 // be a vcl::Window in fact, and vcl::Window::SetSettings() will call
684 // Invalidate(), which is a problem, since we're in Paint().
685 rRenderContext
.OutputDevice::SetSettings(aSettings
);
686 rRect
= aDecoView
.DrawButton(rRect
, nStyle
);
687 rRenderContext
.OutputDevice::SetSettings(aOldSettings
);
690 rRect
= aDecoView
.DrawButton(rRect
, nStyle
);
693 bool PushButton::ImplHitTestPushButton( vcl::Window
const * pDev
,
696 tools::Rectangle
aTestRect( Point(), pDev
->GetOutputSizePixel() );
698 return aTestRect
.IsInside( rPos
);
701 DrawTextFlags
PushButton::ImplGetTextStyle( DrawFlags nDrawFlags
) const
703 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
705 DrawTextFlags nTextStyle
= DrawTextFlags::Mnemonic
| DrawTextFlags::MultiLine
| DrawTextFlags::EndEllipsis
;
707 if ( ( rStyleSettings
.GetOptions() & StyleSettingsOptions::Mono
) ||
708 ( nDrawFlags
& DrawFlags::Mono
) )
709 nTextStyle
|= DrawTextFlags::Mono
;
711 if ( GetStyle() & WB_WORDBREAK
)
712 nTextStyle
|= DrawTextFlags::WordBreak
;
713 if ( GetStyle() & WB_NOLABEL
)
714 nTextStyle
&= ~DrawTextFlags::Mnemonic
;
716 if ( GetStyle() & WB_LEFT
)
717 nTextStyle
|= DrawTextFlags::Left
;
718 else if ( GetStyle() & WB_RIGHT
)
719 nTextStyle
|= DrawTextFlags::Right
;
721 nTextStyle
|= DrawTextFlags::Center
;
723 if ( GetStyle() & WB_TOP
)
724 nTextStyle
|= DrawTextFlags::Top
;
725 else if ( GetStyle() & WB_BOTTOM
)
726 nTextStyle
|= DrawTextFlags::Bottom
;
728 nTextStyle
|= DrawTextFlags::VCenter
;
731 nTextStyle
|= DrawTextFlags::Disable
;
736 void PushButton::ImplDrawPushButtonContent(OutputDevice
*pDev
, DrawFlags nDrawFlags
,
737 const tools::Rectangle
&rRect
, bool bMenuBtnSep
,
738 DrawButtonFlags nButtonFlags
)
740 const StyleSettings
&rStyleSettings
= GetSettings().GetStyleSettings();
741 tools::Rectangle aInRect
= rRect
;
743 DrawTextFlags nTextStyle
= ImplGetTextStyle(nDrawFlags
);
744 DrawSymbolFlags nStyle
;
746 if (aInRect
.Right() < aInRect
.Left() || aInRect
.Bottom() < aInRect
.Top())
749 pDev
->Push(PushFlags::CLIPREGION
);
750 pDev
->IntersectClipRegion(aInRect
);
752 if (nDrawFlags
& DrawFlags::Mono
)
755 // Custom foreground color is reasonable on stock controls only. Stock controls are used if a custom background has been set
756 // (and thus no native controls are able to be used) or no native controls are available.
758 else if (IsControlForeground()
759 && (IsControlBackground() || !IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Entire
)))
760 aColor
= GetControlForeground();
762 // Button types with possibly different text coloring are flat buttons and regular buttons. Regular buttons may be action
763 // buttons and may have an additional default status. Moreover all buttons may have an additional pressed and rollover
764 // (highlight) status. Pressed buttons are always in rollover status.
766 else if (GetStyle() & WB_FLATBUTTON
)
767 if (nButtonFlags
& DrawButtonFlags::Pressed
)
768 aColor
= rStyleSettings
.GetFlatButtonPressedRolloverTextColor();
769 else if (nButtonFlags
& DrawButtonFlags::Highlight
)
770 aColor
= rStyleSettings
.GetFlatButtonRolloverTextColor();
772 aColor
= rStyleSettings
.GetFlatButtonTextColor();
774 if (isAction() && (nButtonFlags
& DrawButtonFlags::Default
))
775 if (nButtonFlags
& DrawButtonFlags::Pressed
)
776 aColor
= rStyleSettings
.GetDefaultActionButtonPressedRolloverTextColor();
777 else if (nButtonFlags
& DrawButtonFlags::Highlight
)
778 aColor
= rStyleSettings
.GetDefaultActionButtonRolloverTextColor();
780 aColor
= rStyleSettings
.GetDefaultActionButtonTextColor();
782 if (nButtonFlags
& DrawButtonFlags::Pressed
)
783 aColor
= rStyleSettings
.GetActionButtonPressedRolloverTextColor();
784 else if (nButtonFlags
& DrawButtonFlags::Highlight
)
785 aColor
= rStyleSettings
.GetActionButtonRolloverTextColor();
787 aColor
= rStyleSettings
.GetActionButtonTextColor();
788 else if (nButtonFlags
& DrawButtonFlags::Default
)
789 if (nButtonFlags
& DrawButtonFlags::Pressed
)
790 aColor
= rStyleSettings
.GetDefaultButtonPressedRolloverTextColor();
791 else if (nButtonFlags
& DrawButtonFlags::Highlight
)
792 aColor
= rStyleSettings
.GetDefaultButtonRolloverTextColor();
794 aColor
= rStyleSettings
.GetDefaultButtonTextColor();
796 if (nButtonFlags
& DrawButtonFlags::Pressed
)
797 aColor
= rStyleSettings
.GetButtonPressedRolloverTextColor();
798 else if (nButtonFlags
& DrawButtonFlags::Highlight
)
799 aColor
= rStyleSettings
.GetButtonRolloverTextColor();
801 aColor
= rStyleSettings
.GetButtonTextColor();
803 pDev
->SetTextColor(aColor
);
806 nStyle
= DrawSymbolFlags::NONE
;
808 nStyle
= DrawSymbolFlags::Disable
;
810 Size aSize
= rRect
.GetSize();
811 Point aPos
= rRect
.TopLeft();
813 sal_uLong nImageSep
= 1 + (pDev
->GetTextHeight()-10)/2;
816 if ( mnDDStyle
== PushButtonDropdownStyle::MenuButton
||
817 mnDDStyle
== PushButtonDropdownStyle::SplitMenuButton
)
819 tools::Long nSeparatorX
= 0;
820 tools::Rectangle aSymbolRect
= aInRect
;
822 // calculate symbol size
823 tools::Long nSymbolSize
= pDev
->GetTextHeight() / 2 + 1;
824 if (nSymbolSize
> aSize
.Width() / 2)
825 nSymbolSize
= aSize
.Width() / 2;
827 nSeparatorX
= aInRect
.Right() - 2*nSymbolSize
;
829 // tdf#141761 Minimum width should be (1) Pixel, see comment
830 // with same task number above for more info
831 const tools::Long
nWidthAdjust(2*nSymbolSize
);
832 aSize
.setWidth(std::max(static_cast<tools::Long
>(1), aSize
.getWidth() - nWidthAdjust
));
834 // center symbol rectangle in the separated area
835 aSymbolRect
.AdjustRight( -(nSymbolSize
/2) );
836 aSymbolRect
.SetLeft( aSymbolRect
.Right() - nSymbolSize
);
838 ImplDrawAlignedImage( pDev
, aPos
, aSize
, nImageSep
,
839 nTextStyle
, nullptr, true );
841 tools::Long nDistance
= (aSymbolRect
.GetHeight() > 10) ? 2 : 1;
842 DecorationView
aDecoView( pDev
);
843 if( bMenuBtnSep
&& nSeparatorX
> 0 )
845 Point
aStartPt( nSeparatorX
, aSymbolRect
.Top()+nDistance
);
846 Point
aEndPt( nSeparatorX
, aSymbolRect
.Bottom()-nDistance
);
847 aDecoView
.DrawSeparator( aStartPt
, aEndPt
);
849 ImplSetSeparatorX( nSeparatorX
);
851 aDecoView
.DrawSymbol( aSymbolRect
, SymbolType::SPIN_DOWN
, aColor
, nStyle
);
856 tools::Rectangle aSymbolRect
;
857 ImplDrawAlignedImage( pDev
, aPos
, aSize
, nImageSep
,
858 nTextStyle
, IsSymbol() ? &aSymbolRect
: nullptr, true );
862 DecorationView
aDecoView( pDev
);
863 aDecoView
.DrawSymbol( aSymbolRect
, meSymbol
, aColor
, nStyle
);
867 pDev
->Pop(); // restore clipregion
870 void PushButton::ImplDrawPushButton(vcl::RenderContext
& rRenderContext
)
874 DrawButtonFlags nButtonStyle
= GetButtonState();
875 Size
aOutSz(GetOutputSizePixel());
876 tools::Rectangle
aRect(Point(), aOutSz
);
877 tools::Rectangle aInRect
= aRect
;
878 bool bNativeOK
= false;
880 // adjust style if button should be rendered 'pressed'
881 if (mbPressed
|| mbIsActive
)
882 nButtonStyle
|= DrawButtonFlags::Pressed
;
884 // TODO: move this to Window class or make it a member !!!
885 ControlType aCtrlType
= ControlType::Generic
;
886 switch(GetParent()->GetType())
888 case WindowType::LISTBOX
:
889 case WindowType::MULTILISTBOX
:
890 case WindowType::TREELISTBOX
:
891 aCtrlType
= ControlType::Listbox
;
894 case WindowType::COMBOBOX
:
895 case WindowType::PATTERNBOX
:
896 case WindowType::NUMERICBOX
:
897 case WindowType::METRICBOX
:
898 case WindowType::CURRENCYBOX
:
899 case WindowType::DATEBOX
:
900 case WindowType::TIMEBOX
:
901 case WindowType::LONGCURRENCYBOX
:
902 aCtrlType
= ControlType::Combobox
;
908 bool bDropDown
= (IsSymbol() && (GetSymbol() == SymbolType::SPIN_DOWN
) && GetText().isEmpty());
910 if( bDropDown
&& (aCtrlType
== ControlType::Combobox
|| aCtrlType
== ControlType::Listbox
))
912 if (GetParent()->IsNativeControlSupported(aCtrlType
, ControlPart::Entire
))
914 // skip painting if the button was already drawn by the theme
915 if (aCtrlType
== ControlType::Combobox
)
917 Edit
* pEdit
= static_cast<Edit
*>(GetParent());
918 if (pEdit
->ImplUseNativeBorder(rRenderContext
, pEdit
->GetStyle()))
921 else if (GetParent()->IsNativeControlSupported(aCtrlType
, ControlPart::HasBackgroundTexture
))
926 if (!bNativeOK
&& GetParent()->IsNativeControlSupported(aCtrlType
, ControlPart::ButtonDown
))
928 // let the theme draw it, note we then need support
929 // for ControlType::Listbox/ControlPart::ButtonDown and ControlType::Combobox/ControlPart::ButtonDown
931 ImplControlValue aControlValue
;
932 ControlState nState
= ControlState::NONE
;
934 if (mbPressed
|| mbIsActive
)
935 nState
|= ControlState::PRESSED
;
936 if (GetButtonState() & DrawButtonFlags::Pressed
)
937 nState
|= ControlState::PRESSED
;
939 nState
|= ControlState::FOCUSED
;
940 if (GetButtonState() & DrawButtonFlags::Default
)
941 nState
|= ControlState::DEFAULT
;
942 if (Window::IsEnabled())
943 nState
|= ControlState::ENABLED
;
945 if (IsMouseOver() && aInRect
.IsInside(GetPointerPosPixel()))
946 nState
|= ControlState::ROLLOVER
;
948 if ( IsMouseOver() && aInRect
.IsInside(GetPointerPosPixel()) && mbIsActive
)
950 nState
|= ControlState::ROLLOVER
;
951 nButtonStyle
&= ~DrawButtonFlags::Pressed
;
954 bNativeOK
= rRenderContext
.DrawNativeControl(aCtrlType
, ControlPart::ButtonDown
, aInRect
, nState
,
955 aControlValue
, OUString());
963 bool bRollOver
= (IsMouseOver() && aInRect
.IsInside(GetPointerPosPixel()));
965 nButtonStyle
|= DrawButtonFlags::Highlight
;
966 bool bDrawMenuSep
= mnDDStyle
== PushButtonDropdownStyle::SplitMenuButton
;
967 if (GetStyle() & WB_FLATBUTTON
)
969 if (!bRollOver
&& !HasFocus())
970 bDrawMenuSep
= false;
972 // tdf#123175 if there is a custom control bg set, draw the button without outsourcing to the NWF
973 bNativeOK
= !IsControlBackground() && rRenderContext
.IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Entire
);
976 PushButtonValue aControlValue
;
977 aControlValue
.mbIsAction
= isAction();
979 tools::Rectangle
aCtrlRegion(aInRect
);
980 ControlState nState
= ControlState::NONE
;
982 if (mbPressed
|| IsChecked() || mbIsActive
)
984 nState
|= ControlState::PRESSED
;
985 nButtonStyle
|= DrawButtonFlags::Pressed
;
987 if (GetButtonState() & DrawButtonFlags::Pressed
)
988 nState
|= ControlState::PRESSED
;
990 nState
|= ControlState::FOCUSED
;
991 if (GetButtonState() & DrawButtonFlags::Default
)
992 nState
|= ControlState::DEFAULT
;
993 if (Window::IsEnabled())
994 nState
|= ControlState::ENABLED
;
996 if (bRollOver
|| mbIsActive
)
998 nButtonStyle
|= DrawButtonFlags::Highlight
;
999 nState
|= ControlState::ROLLOVER
;
1002 if (mbIsActive
&& bRollOver
)
1004 nState
&= ~ControlState::PRESSED
;
1005 nButtonStyle
&= ~DrawButtonFlags::Pressed
;
1008 if (GetStyle() & WB_FLATBUTTON
)
1009 aControlValue
.m_bFlatButton
= true;
1010 if (GetStyle() & WB_BEVELBUTTON
)
1011 aControlValue
.mbBevelButton
= true;
1013 // draw frame into invisible window to have aInRect modified correctly
1014 // but do not shift the inner rect for pressed buttons (ie remove DrawButtonFlags::Pressed)
1015 // this assumes the theme has enough visual cues to signalize the button was pressed
1016 //Window aWin( this );
1017 //ImplDrawPushButtonFrame( &aWin, aInRect, nButtonStyle & ~DrawButtonFlags::Pressed );
1019 // looks better this way as symbols were displaced slightly using the above approach
1020 aInRect
.AdjustTop(4 );
1021 aInRect
.AdjustBottom( -4 );
1022 aInRect
.AdjustLeft(4 );
1023 aInRect
.AdjustRight( -4 );
1025 // prepare single line hint (needed on mac to decide between normal push button and
1026 // rectangular bevel button look)
1027 Size
aFontSize(Application::GetSettings().GetStyleSettings().GetPushButtonFont().GetFontSize());
1028 aFontSize
= rRenderContext
.LogicToPixel(aFontSize
, MapMode(MapUnit::MapPoint
));
1029 Size
aInRectSize(rRenderContext
.LogicToPixel(Size(aInRect
.GetWidth(), aInRect
.GetHeight())));
1030 aControlValue
.mbSingleLine
= (aInRectSize
.Height() < 2 * aFontSize
.Height());
1032 if ((nState
& ControlState::ROLLOVER
) || !(GetStyle() & WB_FLATBUTTON
)
1033 || (HasFocus() && mpWindowImpl
->mbUseNativeFocus
1034 && !IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Focus
)))
1036 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Pushbutton
, ControlPart::Entire
, aCtrlRegion
, nState
,
1037 aControlValue
, OUString() /*PushButton::GetText()*/);
1044 // draw content using the same aInRect as non-native VCL would do
1045 ImplDrawPushButtonContent(&rRenderContext
, DrawFlags::NONE
,
1046 aInRect
, bDrawMenuSep
, nButtonStyle
);
1049 ShowFocus(ImplGetFocusRect());
1055 // draw PushButtonFrame, aInRect has content size afterwards
1056 if (GetStyle() & WB_FLATBUTTON
)
1058 tools::Rectangle
aTempRect(aInRect
);
1060 ImplDrawPushButtonFrame(rRenderContext
, aTempRect
, nButtonStyle
);
1061 aInRect
.AdjustLeft(2 );
1062 aInRect
.AdjustTop(2 );
1063 aInRect
.AdjustRight( -2 );
1064 aInRect
.AdjustBottom( -2 );
1068 ImplDrawPushButtonFrame(rRenderContext
, aInRect
, nButtonStyle
);
1072 ImplDrawPushButtonContent(&rRenderContext
, DrawFlags::NONE
, aInRect
, bDrawMenuSep
, nButtonStyle
);
1076 ShowFocus(ImplGetFocusRect());
1080 void PushButton::ImplSetDefButton( bool bSet
)
1082 Size
aSize( GetSizePixel() );
1083 Point
aPos( GetPosPixel() );
1084 int dLeft(0), dRight(0), dTop(0), dBottom(0);
1085 bool bSetPos
= false;
1087 if ( IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Entire
) )
1089 tools::Rectangle aBound
, aCont
;
1090 tools::Rectangle
aCtrlRegion( 0, 0, 80, 20 ); // use a constant size to avoid accumulating
1091 // will not work if the theme has dynamic adornment sizes
1092 ImplControlValue aControlValue
;
1094 // get native size of a 'default' button
1095 // and adjust the VCL button if more space for adornment is required
1096 if( GetNativeControlRegion( ControlType::Pushbutton
, ControlPart::Entire
, aCtrlRegion
,
1097 ControlState::DEFAULT
|ControlState::ENABLED
,
1101 dLeft
= aCont
.Left() - aBound
.Left();
1102 dTop
= aCont
.Top() - aBound
.Top();
1103 dRight
= aBound
.Right() - aCont
.Right();
1104 dBottom
= aBound
.Bottom() - aCont
.Bottom();
1105 bSetPos
= dLeft
|| dTop
|| dRight
|| dBottom
;
1111 if( !(GetButtonState() & DrawButtonFlags::Default
) && bSetPos
)
1113 // adjust pos/size when toggling from non-default to default
1114 aPos
.Move(-dLeft
, -dTop
);
1115 aSize
.AdjustWidth(dLeft
+ dRight
);
1116 aSize
.AdjustHeight(dTop
+ dBottom
);
1118 GetButtonState() |= DrawButtonFlags::Default
;
1122 if( (GetButtonState() & DrawButtonFlags::Default
) && bSetPos
)
1124 // adjust pos/size when toggling from default to non-default
1125 aPos
.Move(dLeft
, dTop
);
1126 aSize
.AdjustWidth( -(dLeft
+ dRight
) );
1127 aSize
.AdjustHeight( -(dTop
+ dBottom
) );
1129 GetButtonState() &= ~DrawButtonFlags::Default
;
1132 setPosSizePixel( aPos
.X(), aPos
.Y(), aSize
.Width(), aSize
.Height() );
1137 bool PushButton::ImplIsDefButton() const
1139 return bool(GetButtonState() & DrawButtonFlags::Default
);
1142 PushButton::PushButton( WindowType nType
) :
1145 ImplInitPushButtonData();
1148 PushButton::PushButton( vcl::Window
* pParent
, WinBits nStyle
) :
1149 Button( WindowType::PUSHBUTTON
)
1151 ImplInitPushButtonData();
1152 ImplInit( pParent
, nStyle
);
1155 void PushButton::MouseButtonDown( const MouseEvent
& rMEvt
)
1157 if ( !(rMEvt
.IsLeft() &&
1158 ImplHitTestPushButton( this, rMEvt
.GetPosPixel() )) )
1161 StartTrackingFlags nTrackFlags
= StartTrackingFlags::NONE
;
1163 if ( ( GetStyle() & WB_REPEAT
) &&
1164 ! ( GetStyle() & WB_TOGGLE
) )
1165 nTrackFlags
|= StartTrackingFlags::ButtonRepeat
;
1167 GetButtonState() |= DrawButtonFlags::Pressed
;
1169 StartTracking( nTrackFlags
);
1171 if ( nTrackFlags
& StartTrackingFlags::ButtonRepeat
)
1175 void PushButton::Tracking( const TrackingEvent
& rTEvt
)
1177 if ( rTEvt
.IsTrackingEnded() )
1179 if ( GetButtonState() & DrawButtonFlags::Pressed
)
1181 if ( !(GetStyle() & WB_NOPOINTERFOCUS
) && !rTEvt
.IsTrackingCanceled() )
1184 if ( GetStyle() & WB_TOGGLE
)
1186 // Don't toggle, when aborted
1187 if ( !rTEvt
.IsTrackingCanceled() )
1192 GetButtonState() &= ~DrawButtonFlags::Pressed
;
1199 GetButtonState() &= ~DrawButtonFlags::Pressed
;
1203 // do not call Click handler if aborted
1204 if ( !rTEvt
.IsTrackingCanceled() )
1206 if ( ! ( GetStyle() & WB_REPEAT
) || ( GetStyle() & WB_TOGGLE
) )
1213 if ( ImplHitTestPushButton( this, rTEvt
.GetMouseEvent().GetPosPixel() ) )
1215 if ( GetButtonState() & DrawButtonFlags::Pressed
)
1217 if ( rTEvt
.IsTrackingRepeat() && (GetStyle() & WB_REPEAT
) &&
1218 ! ( GetStyle() & WB_TOGGLE
) )
1223 GetButtonState() |= DrawButtonFlags::Pressed
;
1229 if ( GetButtonState() & DrawButtonFlags::Pressed
)
1231 GetButtonState() &= ~DrawButtonFlags::Pressed
;
1238 void PushButton::KeyInput( const KeyEvent
& rKEvt
)
1240 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
1242 if ( !aKeyCode
.GetModifier() &&
1243 ((aKeyCode
.GetCode() == KEY_RETURN
) || (aKeyCode
.GetCode() == KEY_SPACE
)) )
1245 if ( !(GetButtonState() & DrawButtonFlags::Pressed
) )
1247 GetButtonState() |= DrawButtonFlags::Pressed
;
1251 if ( ( GetStyle() & WB_REPEAT
) &&
1252 ! ( GetStyle() & WB_TOGGLE
) )
1255 else if ( (GetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_ESCAPE
) )
1257 GetButtonState() &= ~DrawButtonFlags::Pressed
;
1261 Button::KeyInput( rKEvt
);
1264 void PushButton::KeyUp( const KeyEvent
& rKEvt
)
1266 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
1268 if ( (GetButtonState() & DrawButtonFlags::Pressed
) &&
1269 ((aKeyCode
.GetCode() == KEY_RETURN
) || (aKeyCode
.GetCode() == KEY_SPACE
)) )
1271 if ( GetStyle() & WB_TOGGLE
)
1276 GetButtonState() &= ~DrawButtonFlags::Pressed
;
1284 GetButtonState() &= ~DrawButtonFlags::Pressed
;
1288 if ( !( GetStyle() & WB_REPEAT
) || ( GetStyle() & WB_TOGGLE
) )
1292 Button::KeyUp( rKEvt
);
1295 void PushButton::FillLayoutData() const
1297 mpControlData
->mpLayoutData
.reset( new vcl::ControlLayoutData
);
1298 const_cast<PushButton
*>(this)->Invalidate();
1301 void PushButton::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
1303 ImplDrawPushButton(rRenderContext
);
1306 void PushButton::Draw( OutputDevice
* pDev
, const Point
& rPos
,
1309 Point aPos
= pDev
->LogicToPixel( rPos
);
1310 Size aSize
= GetSizePixel();
1311 tools::Rectangle
aRect( aPos
, aSize
);
1312 vcl::Font aFont
= GetDrawPixelFont( pDev
);
1316 pDev
->SetFont( aFont
);
1317 if ( nFlags
& DrawFlags::Mono
)
1319 pDev
->SetTextColor( COL_BLACK
);
1323 pDev
->SetTextColor( GetTextColor() );
1325 // DecoView uses the FaceColor...
1326 AllSettings aSettings
= pDev
->GetSettings();
1327 StyleSettings aStyleSettings
= aSettings
.GetStyleSettings();
1328 if ( IsControlBackground() )
1329 aStyleSettings
.SetFaceColor( GetControlBackground() );
1331 aStyleSettings
.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() );
1332 aSettings
.SetStyleSettings( aStyleSettings
);
1333 pDev
->OutputDevice::SetSettings( aSettings
);
1335 pDev
->SetTextFillColor();
1337 DecorationView
aDecoView( pDev
);
1338 DrawButtonFlags nButtonStyle
= DrawButtonFlags::NONE
;
1339 if ( nFlags
& DrawFlags::Mono
)
1340 nButtonStyle
|= DrawButtonFlags::Mono
;
1342 nButtonStyle
|= DrawButtonFlags::Checked
;
1343 aRect
= aDecoView
.DrawButton( aRect
, nButtonStyle
);
1345 ImplDrawPushButtonContent( pDev
, nFlags
, aRect
, true, nButtonStyle
);
1349 void PushButton::Resize()
1355 void PushButton::GetFocus()
1357 ShowFocus( ImplGetFocusRect() );
1358 SetInputContext( InputContext( GetFont() ) );
1362 void PushButton::LoseFocus()
1366 Button::LoseFocus();
1369 void PushButton::StateChanged( StateChangedType nType
)
1371 Button::StateChanged( nType
);
1373 if ( (nType
== StateChangedType::Enable
) ||
1374 (nType
== StateChangedType::Text
) ||
1375 (nType
== StateChangedType::Data
) ||
1376 (nType
== StateChangedType::State
) ||
1377 (nType
== StateChangedType::UpdateMode
) )
1379 if ( IsReallyVisible() && IsUpdateMode() )
1382 else if ( nType
== StateChangedType::Style
)
1384 SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev
), GetStyle() ) );
1386 bool bIsDefButton
= ( GetStyle() & WB_DEFBUTTON
) != 0;
1387 bool bWasDefButton
= ( GetPrevStyle() & WB_DEFBUTTON
) != 0;
1388 if ( bIsDefButton
!= bWasDefButton
)
1389 ImplSetDefButton( bIsDefButton
);
1391 if ( IsReallyVisible() && IsUpdateMode() )
1393 if ( (GetPrevStyle() & PUSHBUTTON_VIEW_STYLE
) !=
1394 (GetStyle() & PUSHBUTTON_VIEW_STYLE
) )
1398 else if ( (nType
== StateChangedType::Zoom
) ||
1399 (nType
== StateChangedType::ControlFont
) )
1401 ImplInitSettings( false );
1404 else if ( nType
== StateChangedType::ControlForeground
)
1406 ImplInitSettings( false );
1409 else if ( nType
== StateChangedType::ControlBackground
)
1411 ImplInitSettings( true );
1416 void PushButton::DataChanged( const DataChangedEvent
& rDCEvt
)
1418 Button::DataChanged( rDCEvt
);
1420 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
1421 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
1422 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
1423 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
1425 ImplInitSettings( true );
1430 bool PushButton::PreNotify( NotifyEvent
& rNEvt
)
1432 if( rNEvt
.GetType() == MouseNotifyEvent::MOUSEMOVE
)
1434 const MouseEvent
* pMouseEvt
= rNEvt
.GetMouseEvent();
1435 if( pMouseEvt
&& (pMouseEvt
->IsEnterWindow() || pMouseEvt
->IsLeaveWindow()) )
1437 // trigger redraw as mouse over state has changed
1439 // TODO: move this to Window class or make it a member !!!
1440 ControlType aCtrlType
= ControlType::Generic
;
1441 switch( GetParent()->GetType() )
1443 case WindowType::LISTBOX
:
1444 case WindowType::MULTILISTBOX
:
1445 case WindowType::TREELISTBOX
:
1446 aCtrlType
= ControlType::Listbox
;
1449 case WindowType::COMBOBOX
:
1450 case WindowType::PATTERNBOX
:
1451 case WindowType::NUMERICBOX
:
1452 case WindowType::METRICBOX
:
1453 case WindowType::CURRENCYBOX
:
1454 case WindowType::DATEBOX
:
1455 case WindowType::TIMEBOX
:
1456 case WindowType::LONGCURRENCYBOX
:
1457 aCtrlType
= ControlType::Combobox
;
1463 bool bDropDown
= ( IsSymbol() && (GetSymbol()==SymbolType::SPIN_DOWN
) && GetText().isEmpty() );
1465 if( bDropDown
&& GetParent()->IsNativeControlSupported( aCtrlType
, ControlPart::Entire
) &&
1466 !GetParent()->IsNativeControlSupported( aCtrlType
, ControlPart::ButtonDown
) )
1468 vcl::Window
*pBorder
= GetParent()->GetWindow( GetWindowType::Border
);
1469 if(aCtrlType
== ControlType::Combobox
)
1471 // only paint the button part to avoid flickering of the combobox text
1472 tools::Rectangle
aClipRect( Point(), GetOutputSizePixel() );
1473 aClipRect
.SetPos(pBorder
->ScreenToOutputPixel(OutputToScreenPixel(aClipRect
.TopLeft())));
1474 pBorder
->Invalidate( aClipRect
);
1478 pBorder
->Invalidate( InvalidateFlags::NoErase
);
1481 else if( (GetStyle() & WB_FLATBUTTON
) ||
1482 IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Entire
) )
1489 return Button::PreNotify(rNEvt
);
1492 void PushButton::Toggle()
1494 ImplCallEventListenersAndHandler( VclEventId::PushbuttonToggle
, nullptr );
1497 void PushButton::SetSymbol( SymbolType eSymbol
)
1499 if ( meSymbol
!= eSymbol
)
1502 CompatStateChanged( StateChangedType::Data
);
1506 void PushButton::SetSymbolAlign( SymbolAlign eAlign
)
1508 ImplSetSymbolAlign( eAlign
);
1511 void PushButton::SetDropDown( PushButtonDropdownStyle nStyle
)
1513 if ( mnDDStyle
!= nStyle
)
1516 CompatStateChanged( StateChangedType::Data
);
1520 void PushButton::SetState( TriState eState
)
1522 if ( meState
== eState
)
1526 if ( meState
== TRISTATE_FALSE
)
1527 GetButtonState() &= ~DrawButtonFlags(DrawButtonFlags::Checked
| DrawButtonFlags::DontKnow
);
1528 else if ( meState
== TRISTATE_TRUE
)
1530 GetButtonState() &= ~DrawButtonFlags::DontKnow
;
1531 GetButtonState() |= DrawButtonFlags::Checked
;
1533 else // TRISTATE_INDET
1535 GetButtonState() &= ~DrawButtonFlags::Checked
;
1536 GetButtonState() |= DrawButtonFlags::DontKnow
;
1539 CompatStateChanged( StateChangedType::State
);
1543 void PushButton::statusChanged(const css::frame::FeatureStateEvent
& rEvent
)
1545 Button::statusChanged(rEvent
);
1546 if (rEvent
.State
.has
<bool>())
1547 SetPressed(rEvent
.State
.get
<bool>());
1550 void PushButton::SetPressed( bool bPressed
)
1552 if ( mbPressed
!= bPressed
)
1554 mbPressed
= bPressed
;
1555 CompatStateChanged( StateChangedType::Data
);
1559 void PushButton::EndSelection()
1561 EndTracking( TrackingEventFlags::Cancel
);
1562 if ( !IsDisposed() &&
1563 GetButtonState() & DrawButtonFlags::Pressed
)
1565 GetButtonState() &= ~DrawButtonFlags::Pressed
;
1571 Size
PushButton::CalcMinimumSize() const
1577 if ( IsSmallSymbol ())
1578 aSize
= Size( 16, 12 );
1580 aSize
= Size( 26, 24 );
1582 else if ( Button::HasImage() )
1583 aSize
= GetModeImage().GetSizePixel();
1584 if( mnDDStyle
== PushButtonDropdownStyle::MenuButton
||
1585 mnDDStyle
== PushButtonDropdownStyle::SplitMenuButton
)
1587 tools::Long nSymbolSize
= GetTextHeight() / 2 + 1;
1588 aSize
.AdjustWidth(2*nSymbolSize
);
1590 if (!PushButton::GetText().isEmpty())
1592 Size textSize
= GetTextRect( tools::Rectangle( Point(), Size( 0x7fffffff, 0x7fffffff ) ),
1593 PushButton::GetText(), ImplGetTextStyle( DrawFlags::NONE
) ).GetSize();
1594 aSize
.AdjustWidth(textSize
.Width() );
1595 aSize
.setHeight( std::max( aSize
.Height(), tools::Long( textSize
.Height() * 1.15 ) ) );
1598 // cf. ImplDrawPushButton ...
1599 if( (GetStyle() & WB_SMALLSTYLE
) == 0 )
1601 aSize
.AdjustWidth(24 );
1602 aSize
.AdjustHeight(12 );
1605 return CalcWindowSize( aSize
);
1608 Size
PushButton::GetOptimalSize() const
1610 return CalcMinimumSize();
1613 bool PushButton::set_property(const OString
&rKey
, const OUString
&rValue
)
1615 if (rKey
== "has-default")
1617 WinBits nBits
= GetStyle();
1618 nBits
&= ~WB_DEFBUTTON
;
1620 nBits
|= WB_DEFBUTTON
;
1624 return Button::set_property(rKey
, rValue
);
1628 void PushButton::ShowFocus(const tools::Rectangle
& rRect
)
1630 if (IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Focus
))
1632 PushButtonValue aControlValue
;
1633 aControlValue
.mbIsAction
= isAction();
1634 tools::Rectangle
aInRect(Point(), GetOutputSizePixel());
1635 GetOutDev()->DrawNativeControl(ControlType::Pushbutton
, ControlPart::Focus
, aInRect
,
1636 ControlState::FOCUSED
, aControlValue
, OUString());
1638 Button::ShowFocus(rRect
);
1641 void OKButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
1644 PushButton::ImplInit( pParent
, nStyle
);
1646 SetText( GetStandardText( StandardButtonType::OK
) );
1649 OKButton::OKButton( vcl::Window
* pParent
, WinBits nStyle
) :
1650 PushButton( WindowType::OKBUTTON
)
1652 ImplInit( pParent
, nStyle
);
1655 void OKButton::Click()
1657 // close parent if no link set
1658 if ( !GetClickHdl() )
1660 vcl::Window
* pParent
= getNonLayoutParent(this);
1661 if ( pParent
->IsSystemWindow() )
1663 if ( pParent
->IsDialog() )
1665 VclPtr
<Dialog
> xParent( static_cast<Dialog
*>(pParent
) );
1666 if ( xParent
->IsInExecute() )
1667 xParent
->EndDialog( RET_OK
);
1668 // prevent recursive calls
1669 else if ( !xParent
->IsInClose() )
1671 if ( pParent
->GetStyle() & WB_CLOSEABLE
)
1677 if ( pParent
->GetStyle() & WB_CLOSEABLE
)
1678 static_cast<SystemWindow
*>(pParent
)->Close();
1684 PushButton::Click();
1688 void CancelButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
1691 PushButton::ImplInit( pParent
, nStyle
);
1693 SetText( GetStandardText( StandardButtonType::Cancel
) );
1696 CancelButton::CancelButton( vcl::Window
* pParent
, WinBits nStyle
) :
1697 PushButton( WindowType::CANCELBUTTON
)
1699 ImplInit( pParent
, nStyle
);
1702 void CancelButton::Click()
1704 // close parent if link not set
1705 if ( !GetClickHdl() )
1707 vcl::Window
* pParent
= getNonLayoutParent(this);
1708 if ( pParent
->IsSystemWindow() )
1710 if ( pParent
->IsDialog() )
1712 if ( static_cast<Dialog
*>(pParent
)->IsInExecute() )
1713 static_cast<Dialog
*>(pParent
)->EndDialog();
1714 // prevent recursive calls
1715 else if ( !static_cast<Dialog
*>(pParent
)->IsInClose() )
1717 if ( pParent
->GetStyle() & WB_CLOSEABLE
)
1718 static_cast<Dialog
*>(pParent
)->Close();
1723 if ( pParent
->GetStyle() & WB_CLOSEABLE
)
1724 static_cast<SystemWindow
*>(pParent
)->Close();
1730 PushButton::Click();
1734 CloseButton::CloseButton( vcl::Window
* pParent
, WinBits nStyle
)
1735 : CancelButton(pParent
, nStyle
)
1737 SetText( GetStandardText( StandardButtonType::Close
) );
1740 void HelpButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
1743 PushButton::ImplInit( pParent
, nStyle
| WB_NOPOINTERFOCUS
);
1745 SetText( GetStandardText( StandardButtonType::Help
) );
1748 HelpButton::HelpButton( vcl::Window
* pParent
, WinBits nStyle
) :
1749 PushButton( WindowType::HELPBUTTON
)
1751 ImplInit( pParent
, nStyle
);
1754 void HelpButton::Click()
1756 // trigger help if no link set
1757 if ( !GetClickHdl() )
1759 vcl::Window
* pFocusWin
= Application::GetFocusWindow();
1763 HelpEvent
aEvt( pFocusWin
->GetPointerPosPixel(), HelpEventMode::CONTEXT
);
1764 pFocusWin
->RequestHelp( aEvt
);
1766 PushButton::Click();
1769 void HelpButton::StateChanged( StateChangedType nStateChange
)
1771 // Hide when we have no help URL.
1772 if (comphelper::LibreOfficeKit::isActive() &&
1773 officecfg::Office::Common::Help::HelpRootURL::get().isEmpty())
1776 PushButton::StateChanged(nStateChange
);
1779 void RadioButton::ImplInitRadioButtonData()
1782 mbRadioCheck
= true;
1783 mbStateChanged
= false;
1786 void RadioButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
1788 nStyle
= ImplInitStyle(getPreviousSibling(pParent
), nStyle
);
1789 Button::ImplInit( pParent
, nStyle
, nullptr );
1791 ImplInitSettings( true );
1794 WinBits
RadioButton::ImplInitStyle( const vcl::Window
* pPrevWindow
, WinBits nStyle
)
1796 if ( !(nStyle
& WB_NOGROUP
) &&
1797 (!pPrevWindow
|| (pPrevWindow
->GetType() != WindowType::RADIOBUTTON
)) )
1799 if ( !(nStyle
& WB_NOTABSTOP
) )
1802 nStyle
|= WB_TABSTOP
;
1804 nStyle
&= ~WB_TABSTOP
;
1810 const vcl::Font
& RadioButton::GetCanonicalFont( const StyleSettings
& _rStyle
) const
1812 return _rStyle
.GetRadioCheckFont();
1815 const Color
& RadioButton::GetCanonicalTextColor( const StyleSettings
& _rStyle
) const
1817 return _rStyle
.GetRadioCheckTextColor();
1820 void RadioButton::ImplInitSettings( bool bBackground
)
1822 Button::ImplInitSettings();
1827 vcl::Window
* pParent
= GetParent();
1828 if ( !IsControlBackground() &&
1829 (pParent
->IsChildTransparentModeEnabled() || IsNativeControlSupported( ControlType::Radiobutton
, ControlPart::Entire
) ) )
1831 EnableChildTransparentMode();
1832 SetParentClipMode( ParentClipMode::NoClip
);
1833 SetPaintTransparent( true );
1835 if( IsNativeControlSupported( ControlType::Radiobutton
, ControlPart::Entire
) )
1836 mpWindowImpl
->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
1840 EnableChildTransparentMode( false );
1841 SetParentClipMode();
1842 SetPaintTransparent( false );
1844 if ( IsControlBackground() )
1845 SetBackground( GetControlBackground() );
1847 SetBackground( pParent
->GetBackground() );
1851 void RadioButton::ImplDrawRadioButtonState(vcl::RenderContext
& rRenderContext
)
1853 bool bNativeOK
= false;
1855 // no native drawing for image radio buttons
1856 if (!maImage
&& rRenderContext
.IsNativeControlSupported(ControlType::Radiobutton
, ControlPart::Entire
))
1858 ImplControlValue
aControlValue( mbChecked
? ButtonValue::On
: ButtonValue::Off
);
1859 tools::Rectangle
aCtrlRect(maStateRect
.TopLeft(), maStateRect
.GetSize());
1860 ControlState nState
= ControlState::NONE
;
1862 if (GetButtonState() & DrawButtonFlags::Pressed
)
1863 nState
|= ControlState::PRESSED
;
1865 nState
|= ControlState::FOCUSED
;
1866 if (GetButtonState() & DrawButtonFlags::Default
)
1867 nState
|= ControlState::DEFAULT
;
1869 nState
|= ControlState::ENABLED
;
1871 if (IsMouseOver() && maMouseRect
.IsInside(GetPointerPosPixel()))
1872 nState
|= ControlState::ROLLOVER
;
1874 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Radiobutton
, ControlPart::Entire
, aCtrlRect
,
1875 nState
, aControlValue
, OUString());
1883 DrawButtonFlags nStyle
= GetButtonState();
1885 nStyle
|= DrawButtonFlags::Disabled
;
1887 nStyle
|= DrawButtonFlags::Checked
;
1888 Image aImage
= GetRadioImage(rRenderContext
.GetSettings(), nStyle
);
1890 rRenderContext
.DrawImage(maStateRect
.TopLeft(), maStateRect
.GetSize(), aImage
);
1892 rRenderContext
.DrawImage(maStateRect
.TopLeft(), aImage
);
1898 DecorationView
aDecoView(&rRenderContext
);
1899 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
1900 tools::Rectangle aImageRect
= maStateRect
;
1901 Size aImageSize
= maImage
.GetSizePixel();
1902 bool bEnabled
= IsEnabled();
1904 aImageSize
.setWidth( CalcZoom(aImageSize
.Width()) );
1905 aImageSize
.setHeight( CalcZoom(aImageSize
.Height()) );
1907 aImageRect
.AdjustLeft( 1 );
1908 aImageRect
.AdjustTop( 1 );
1909 aImageRect
.AdjustRight( -1 );
1910 aImageRect
.AdjustBottom( -1 );
1912 // display border and selection status
1913 aImageRect
= aDecoView
.DrawFrame(aImageRect
, DrawFrameStyle::DoubleIn
);
1914 if ((GetButtonState() & DrawButtonFlags::Pressed
) || !bEnabled
)
1915 rRenderContext
.SetFillColor( rStyleSettings
.GetFaceColor());
1917 rRenderContext
.SetFillColor(rStyleSettings
.GetFieldColor());
1918 rRenderContext
.SetLineColor();
1919 rRenderContext
.DrawRect(aImageRect
);
1922 DrawImageFlags nImageStyle
= DrawImageFlags::NONE
;
1924 nImageStyle
|= DrawImageFlags::Disable
;
1926 Image
* pImage
= &maImage
;
1928 Point
aImagePos(aImageRect
.TopLeft());
1929 aImagePos
.AdjustX((aImageRect
.GetWidth() - aImageSize
.Width()) / 2 );
1930 aImagePos
.AdjustY((aImageRect
.GetHeight() - aImageSize
.Height()) / 2 );
1932 rRenderContext
.DrawImage(aImagePos
, aImageSize
, *pImage
, nImageStyle
);
1934 rRenderContext
.DrawImage(aImagePos
, *pImage
, nImageStyle
);
1936 aImageRect
.AdjustLeft( 1 );
1937 aImageRect
.AdjustTop( 1 );
1938 aImageRect
.AdjustRight( -1 );
1939 aImageRect
.AdjustBottom( -1 );
1941 ImplSetFocusRect(aImageRect
);
1945 rRenderContext
.SetLineColor(rStyleSettings
.GetHighlightColor());
1946 rRenderContext
.SetFillColor();
1947 if ((aImageSize
.Width() >= 20) || (aImageSize
.Height() >= 20))
1949 aImageRect
.AdjustLeft( 1 );
1950 aImageRect
.AdjustTop( 1 );
1951 aImageRect
.AdjustRight( -1 );
1952 aImageRect
.AdjustBottom( -1 );
1954 rRenderContext
.DrawRect(aImageRect
);
1955 aImageRect
.AdjustLeft( 1 );
1956 aImageRect
.AdjustTop( 1 );
1957 aImageRect
.AdjustRight( -1 );
1958 aImageRect
.AdjustBottom( -1 );
1959 rRenderContext
.DrawRect(aImageRect
);
1963 ShowFocus(ImplGetFocusRect());
1967 void RadioButton::ImplDraw( OutputDevice
* pDev
, DrawFlags nDrawFlags
,
1968 const Point
& rPos
, const Size
& rSize
,
1969 const Size
& rImageSize
, tools::Rectangle
& rStateRect
,
1970 tools::Rectangle
& rMouseRect
)
1972 WinBits nWinStyle
= GetStyle();
1973 OUString
aText( GetText() );
1975 pDev
->Push( PushFlags::CLIPREGION
);
1976 pDev
->IntersectClipRegion( tools::Rectangle( rPos
, rSize
) );
1978 // no image radio button
1981 if (!aText
.isEmpty() || HasImage())
1983 DrawTextFlags nTextStyle
= Button::ImplGetTextStyle( nWinStyle
, nDrawFlags
);
1985 const tools::Long nImageSep
= GetDrawPixel( pDev
, ImplGetImageToTextDistance() );
1986 Size
aSize( rSize
);
1988 aPos
.AdjustX(rImageSize
.Width() + nImageSep
);
1990 // tdf#141761 Old (convenience?) adjustment of width may lead to empty
1991 // or negative(!) Size, that needs to be avoided. The coordinate context
1992 // is pixel-oriented (all Paints of Controls are, historically), so
1993 // the minimum width should be '1' Pixel.
1994 // Hint: nImageSep is based on Zoom (using Window::CalcZoom) and
1995 // MapModes (using Window::GetDrawPixel) - so potenially a wide range
1996 // of unpredictable values is possible
1997 const tools::Long
nWidthAdjust(rImageSize
.Width() + nImageSep
);
1998 aSize
.setWidth(std::max(static_cast<tools::Long
>(1), aSize
.getWidth() - nWidthAdjust
));
2000 // if the text rect height is smaller than the height of the image
2001 // then for single lines the default should be centered text
2002 if( (nWinStyle
& (WB_TOP
|WB_VCENTER
|WB_BOTTOM
)) == 0 &&
2003 (rImageSize
.Height() > rSize
.Height() || ! (nWinStyle
& WB_WORDBREAK
) ) )
2005 nTextStyle
&= ~DrawTextFlags(DrawTextFlags::Top
|DrawTextFlags::Bottom
);
2006 nTextStyle
|= DrawTextFlags::VCenter
;
2007 aSize
.setHeight( rImageSize
.Height() );
2010 ImplDrawAlignedImage( pDev
, aPos
, aSize
, 1, nTextStyle
);
2012 rMouseRect
= tools::Rectangle(aPos
, aSize
);
2013 rMouseRect
.SetLeft(rPos
.X());
2015 rStateRect
.SetLeft( rPos
.X() );
2016 rStateRect
.SetTop( rMouseRect
.Top() );
2018 if ( aSize
.Height() > rImageSize
.Height() )
2019 rStateRect
.AdjustTop(( aSize
.Height() - rImageSize
.Height() ) / 2 );
2022 rStateRect
.AdjustTop( -(( rImageSize
.Height() - aSize
.Height() ) / 2) );
2023 if( rStateRect
.Top() < 0 )
2024 rStateRect
.SetTop( 0 );
2027 rStateRect
.SetRight( rStateRect
.Left() + rImageSize
.Width()-1 );
2028 rStateRect
.SetBottom( rStateRect
.Top() + rImageSize
.Height()-1 );
2030 if ( rStateRect
.Bottom() > rMouseRect
.Bottom() )
2031 rMouseRect
.SetBottom( rStateRect
.Bottom() );
2035 rStateRect
.SetLeft( rPos
.X() );
2036 if ( nWinStyle
& WB_VCENTER
)
2037 rStateRect
.SetTop( rPos
.Y()+((rSize
.Height()-rImageSize
.Height())/2) );
2038 else if ( nWinStyle
& WB_BOTTOM
)
2039 rStateRect
.SetTop( rPos
.Y()+rSize
.Height()-rImageSize
.Height() ); //-1;
2041 rStateRect
.SetTop( rPos
.Y() );
2042 rStateRect
.SetRight( rStateRect
.Left()+rImageSize
.Width()-1 );
2043 rStateRect
.SetBottom( rStateRect
.Top()+rImageSize
.Height()-1 );
2044 rMouseRect
= rStateRect
;
2046 ImplSetFocusRect( rStateRect
);
2051 bool bTopImage
= (nWinStyle
& WB_TOP
) != 0;
2052 Size aImageSize
= maImage
.GetSizePixel();
2053 tools::Rectangle
aImageRect( rPos
, rSize
);
2054 tools::Long nTextHeight
= pDev
->GetTextHeight();
2055 tools::Long nTextWidth
= pDev
->GetCtrlTextWidth( aText
);
2057 // calculate position and sizes
2058 if (!aText
.isEmpty())
2060 Size
aTmpSize( (aImageSize
.Width()+8), (aImageSize
.Height()+8) );
2063 aImageRect
.SetLeft( (rSize
.Width()-aTmpSize
.Width())/2 );
2064 aImageRect
.SetTop( (rSize
.Height()-(aTmpSize
.Height()+nTextHeight
+6))/2 );
2067 aImageRect
.SetTop( (rSize
.Height()-aTmpSize
.Height())/2 );
2069 aImageRect
.SetRight( aImageRect
.Left()+aTmpSize
.Width() );
2070 aImageRect
.SetBottom( aImageRect
.Top()+aTmpSize
.Height() );
2073 Point aTxtPos
= rPos
;
2076 aTxtPos
.AdjustX((rSize
.Width()-nTextWidth
)/2 );
2077 aTxtPos
.AdjustY(aImageRect
.Bottom()+6 );
2081 aTxtPos
.AdjustX(aImageRect
.Right()+8 );
2082 aTxtPos
.AdjustY((rSize
.Height()-nTextHeight
)/2 );
2084 pDev
->DrawCtrlText( aTxtPos
, aText
, 0, aText
.getLength() );
2087 rMouseRect
= aImageRect
;
2088 rStateRect
= aImageRect
;
2094 void RadioButton::ImplDrawRadioButton(vcl::RenderContext
& rRenderContext
)
2100 aImageSize
= ImplGetRadioImageSize();
2102 aImageSize
= maImage
.GetSizePixel();
2104 aImageSize
.setWidth( CalcZoom(aImageSize
.Width()) );
2105 aImageSize
.setHeight( CalcZoom(aImageSize
.Height()) );
2107 // Draw control text
2108 ImplDraw(&rRenderContext
, DrawFlags::NONE
, Point(), GetOutputSizePixel(),
2109 aImageSize
, maStateRect
, maMouseRect
);
2111 if (!maImage
&& HasFocus())
2112 ShowFocus(ImplGetFocusRect());
2114 ImplDrawRadioButtonState(rRenderContext
);
2117 void RadioButton::group(RadioButton
&rOther
)
2119 if (&rOther
== this)
2124 m_xGroup
= std::make_shared
<std::vector
<VclPtr
<RadioButton
> >>();
2125 m_xGroup
->push_back(this);
2128 auto aFind
= std::find(m_xGroup
->begin(), m_xGroup
->end(), VclPtr
<RadioButton
>(&rOther
));
2129 if (aFind
== m_xGroup
->end())
2131 m_xGroup
->push_back(&rOther
);
2133 if (rOther
.m_xGroup
)
2135 std::vector
< VclPtr
<RadioButton
> > aOthers(rOther
.GetRadioButtonGroup(false));
2136 //make all members of the group share the same button group
2137 for (auto const& elem
: aOthers
)
2139 aFind
= std::find(m_xGroup
->begin(), m_xGroup
->end(), elem
);
2140 if (aFind
== m_xGroup
->end())
2141 m_xGroup
->push_back(elem
);
2145 //make all members of the group share the same button group
2146 for (VclPtr
<RadioButton
> const & pButton
: *m_xGroup
)
2148 pButton
->m_xGroup
= m_xGroup
;
2152 //if this one is checked, uncheck all the others
2154 ImplUncheckAllOther();
2157 std::vector
< VclPtr
<RadioButton
> > RadioButton::GetRadioButtonGroup(bool bIncludeThis
) const
2163 std::vector
< VclPtr
<RadioButton
> > aGroup
;
2164 for (VclPtr
<RadioButton
> const & pRadioButton
: *m_xGroup
)
2166 if (pRadioButton
== this)
2168 aGroup
.push_back(pRadioButton
);
2173 std::vector
<VclPtr
<RadioButton
>> aGroup
;
2174 if (mbUsesExplicitGroup
)
2179 // go back to first in group;
2180 vcl::Window
* pFirst
= const_cast<RadioButton
*>(this);
2181 while( ( pFirst
->GetStyle() & WB_GROUP
) == 0 )
2183 vcl::Window
* pWindow
= pFirst
->GetWindow( GetWindowType::Prev
);
2189 // insert radiobuttons up to next group
2192 if( pFirst
->GetType() == WindowType::RADIOBUTTON
)
2194 if( pFirst
!= this || bIncludeThis
)
2195 aGroup
.emplace_back(static_cast<RadioButton
*>(pFirst
) );
2197 pFirst
= pFirst
->GetWindow( GetWindowType::Next
);
2198 } while( pFirst
&& ( ( pFirst
->GetStyle() & WB_GROUP
) == 0 ) );
2203 void RadioButton::ImplUncheckAllOther()
2205 mpWindowImpl
->mnStyle
|= WB_TABSTOP
;
2207 std::vector
<VclPtr
<RadioButton
> > aGroup(GetRadioButtonGroup(false));
2208 // iterate over radio button group and checked buttons
2209 for (VclPtr
<RadioButton
>& pWindow
: aGroup
)
2211 if ( pWindow
->IsChecked() )
2213 pWindow
->SetState( false );
2214 if ( pWindow
->IsDisposed() )
2218 // not inside if clause to always remove wrongly set WB_TABSTOPS
2219 pWindow
->mpWindowImpl
->mnStyle
&= ~WB_TABSTOP
;
2223 void RadioButton::ImplCallClick( bool bGrabFocus
, GetFocusFlags nFocusFlags
)
2225 mbStateChanged
= !mbChecked
;
2227 mpWindowImpl
->mnStyle
|= WB_TABSTOP
;
2229 VclPtr
<vcl::Window
> xWindow
= this;
2231 ImplUncheckAllOther();
2232 if ( xWindow
->IsDisposed() )
2235 ImplGrabFocus( nFocusFlags
);
2236 if ( xWindow
->IsDisposed() )
2238 if ( mbStateChanged
)
2240 if ( xWindow
->IsDisposed() )
2243 if ( xWindow
->IsDisposed() )
2245 mbStateChanged
= false;
2248 RadioButton::RadioButton(vcl::Window
* pParent
, bool bUsesExplicitGroup
, WinBits nStyle
)
2249 : Button(WindowType::RADIOBUTTON
)
2250 , mbUsesExplicitGroup(bUsesExplicitGroup
)
2252 ImplInitRadioButtonData();
2253 ImplInit( pParent
, nStyle
);
2256 RadioButton::~RadioButton()
2261 void RadioButton::dispose()
2265 m_xGroup
->erase(std::remove(m_xGroup
->begin(), m_xGroup
->end(), VclPtr
<RadioButton
>(this)),
2272 void RadioButton::MouseButtonDown( const MouseEvent
& rMEvt
)
2274 if ( rMEvt
.IsLeft() && maMouseRect
.IsInside( rMEvt
.GetPosPixel() ) )
2276 GetButtonState() |= DrawButtonFlags::Pressed
;
2282 Button::MouseButtonDown( rMEvt
);
2285 void RadioButton::Tracking( const TrackingEvent
& rTEvt
)
2287 if ( rTEvt
.IsTrackingEnded() )
2289 if ( GetButtonState() & DrawButtonFlags::Pressed
)
2291 if ( !(GetStyle() & WB_NOPOINTERFOCUS
) && !rTEvt
.IsTrackingCanceled() )
2294 GetButtonState() &= ~DrawButtonFlags::Pressed
;
2296 // do not call click handler if aborted
2297 if ( !rTEvt
.IsTrackingCanceled() )
2307 if ( maMouseRect
.IsInside( rTEvt
.GetMouseEvent().GetPosPixel() ) )
2309 if ( !(GetButtonState() & DrawButtonFlags::Pressed
) )
2311 GetButtonState() |= DrawButtonFlags::Pressed
;
2317 if ( GetButtonState() & DrawButtonFlags::Pressed
)
2319 GetButtonState() &= ~DrawButtonFlags::Pressed
;
2326 void RadioButton::KeyInput( const KeyEvent
& rKEvt
)
2328 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
2330 if ( !aKeyCode
.GetModifier() && (aKeyCode
.GetCode() == KEY_SPACE
) )
2332 if ( !(GetButtonState() & DrawButtonFlags::Pressed
) )
2334 GetButtonState() |= DrawButtonFlags::Pressed
;
2338 else if ( (GetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_ESCAPE
) )
2340 GetButtonState() &= ~DrawButtonFlags::Pressed
;
2344 Button::KeyInput( rKEvt
);
2347 void RadioButton::KeyUp( const KeyEvent
& rKEvt
)
2349 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
2351 if ( (GetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_SPACE
) )
2353 GetButtonState() &= ~DrawButtonFlags::Pressed
;
2357 Button::KeyUp( rKEvt
);
2360 void RadioButton::FillLayoutData() const
2362 mpControlData
->mpLayoutData
.reset( new vcl::ControlLayoutData
);
2363 const_cast<RadioButton
*>(this)->Invalidate();
2366 void RadioButton::Paint( vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& )
2368 ImplDrawRadioButton(rRenderContext
);
2371 void RadioButton::Draw( OutputDevice
* pDev
, const Point
& rPos
,
2376 MapMode
aResMapMode( MapUnit::Map100thMM
);
2377 Point aPos
= pDev
->LogicToPixel( rPos
);
2378 Size aSize
= GetSizePixel();
2379 Size aImageSize
= pDev
->LogicToPixel( Size( 300, 300 ), aResMapMode
);
2380 Size aBrd1Size
= pDev
->LogicToPixel( Size( 20, 20 ), aResMapMode
);
2381 Size aBrd2Size
= pDev
->LogicToPixel( Size( 60, 60 ), aResMapMode
);
2382 vcl::Font aFont
= GetDrawPixelFont( pDev
);
2383 tools::Rectangle aStateRect
;
2384 tools::Rectangle aMouseRect
;
2386 aImageSize
.setWidth( CalcZoom( aImageSize
.Width() ) );
2387 aImageSize
.setHeight( CalcZoom( aImageSize
.Height() ) );
2388 aBrd1Size
.setWidth( CalcZoom( aBrd1Size
.Width() ) );
2389 aBrd1Size
.setHeight( CalcZoom( aBrd1Size
.Height() ) );
2390 aBrd2Size
.setWidth( CalcZoom( aBrd2Size
.Width() ) );
2391 aBrd2Size
.setHeight( CalcZoom( aBrd2Size
.Height() ) );
2393 if ( !aBrd1Size
.Width() )
2394 aBrd1Size
.setWidth( 1 );
2395 if ( !aBrd1Size
.Height() )
2396 aBrd1Size
.setHeight( 1 );
2397 if ( !aBrd2Size
.Width() )
2398 aBrd2Size
.setWidth( 1 );
2399 if ( !aBrd2Size
.Height() )
2400 aBrd2Size
.setHeight( 1 );
2404 pDev
->SetFont( aFont
);
2405 if ( nFlags
& DrawFlags::Mono
)
2406 pDev
->SetTextColor( COL_BLACK
);
2408 pDev
->SetTextColor( GetTextColor() );
2409 pDev
->SetTextFillColor();
2411 ImplDraw( pDev
, nFlags
, aPos
, aSize
,
2412 aImageSize
, aStateRect
, aMouseRect
);
2414 Point aCenterPos
= aStateRect
.Center();
2415 tools::Long nRadX
= aImageSize
.Width()/2;
2416 tools::Long nRadY
= aImageSize
.Height()/2;
2418 pDev
->SetLineColor();
2419 pDev
->SetFillColor( COL_BLACK
);
2420 pDev
->DrawPolygon( tools::Polygon( aCenterPos
, nRadX
, nRadY
) );
2421 nRadX
-= aBrd1Size
.Width();
2422 nRadY
-= aBrd1Size
.Height();
2423 pDev
->SetFillColor( COL_WHITE
);
2424 pDev
->DrawPolygon( tools::Polygon( aCenterPos
, nRadX
, nRadY
) );
2427 nRadX
-= aBrd1Size
.Width();
2428 nRadY
-= aBrd1Size
.Height();
2433 pDev
->SetFillColor( COL_BLACK
);
2434 pDev
->DrawPolygon( tools::Polygon( aCenterPos
, nRadX
, nRadY
) );
2441 OSL_FAIL( "RadioButton::Draw() - not implemented for RadioButton with Image" );
2445 void RadioButton::Resize()
2451 void RadioButton::GetFocus()
2453 ShowFocus( ImplGetFocusRect() );
2454 SetInputContext( InputContext( GetFont() ) );
2458 void RadioButton::LoseFocus()
2460 if ( GetButtonState() & DrawButtonFlags::Pressed
)
2462 GetButtonState() &= ~DrawButtonFlags::Pressed
;
2467 Button::LoseFocus();
2470 void RadioButton::StateChanged( StateChangedType nType
)
2472 Button::StateChanged( nType
);
2474 if ( nType
== StateChangedType::State
)
2476 if ( IsReallyVisible() && IsUpdateMode() )
2477 Invalidate( maStateRect
);
2479 else if ( (nType
== StateChangedType::Enable
) ||
2480 (nType
== StateChangedType::Text
) ||
2481 (nType
== StateChangedType::Data
) ||
2482 (nType
== StateChangedType::UpdateMode
) )
2484 if ( IsUpdateMode() )
2487 else if ( nType
== StateChangedType::Style
)
2489 SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev
), GetStyle() ) );
2491 if ( (GetPrevStyle() & RADIOBUTTON_VIEW_STYLE
) !=
2492 (GetStyle() & RADIOBUTTON_VIEW_STYLE
) )
2494 if ( IsUpdateMode() )
2498 else if ( (nType
== StateChangedType::Zoom
) ||
2499 (nType
== StateChangedType::ControlFont
) )
2501 ImplInitSettings( false );
2504 else if ( nType
== StateChangedType::ControlForeground
)
2506 ImplInitSettings( false );
2509 else if ( nType
== StateChangedType::ControlBackground
)
2511 ImplInitSettings( true );
2516 void RadioButton::DataChanged( const DataChangedEvent
& rDCEvt
)
2518 Button::DataChanged( rDCEvt
);
2520 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
2521 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
2522 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
2523 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
2525 ImplInitSettings( true );
2530 bool RadioButton::PreNotify( NotifyEvent
& rNEvt
)
2532 if( rNEvt
.GetType() == MouseNotifyEvent::MOUSEMOVE
)
2534 const MouseEvent
* pMouseEvt
= rNEvt
.GetMouseEvent();
2535 if( pMouseEvt
&& !pMouseEvt
->GetButtons() && !pMouseEvt
->IsSynthetic() && !pMouseEvt
->IsModifierChanged() )
2537 // trigger redraw if mouse over state has changed
2538 if( IsNativeControlSupported(ControlType::Radiobutton
, ControlPart::Entire
) )
2540 if (maMouseRect
.IsInside(GetPointerPosPixel()) != maMouseRect
.IsInside(GetLastPointerPosPixel()) ||
2541 pMouseEvt
->IsLeaveWindow() || pMouseEvt
->IsEnterWindow())
2543 Invalidate( maStateRect
);
2549 return Button::PreNotify(rNEvt
);
2552 void RadioButton::Toggle()
2554 ImplCallEventListenersAndHandler( VclEventId::RadiobuttonToggle
, [this] () { maToggleHdl
.Call(*this); } );
2557 void RadioButton::SetModeRadioImage( const Image
& rImage
)
2559 if ( rImage
!= maImage
)
2562 CompatStateChanged( StateChangedType::Data
);
2568 void RadioButton::SetState( bool bCheck
)
2570 // carry the TabStop flag along correctly
2572 mpWindowImpl
->mnStyle
|= WB_TABSTOP
;
2574 mpWindowImpl
->mnStyle
&= ~WB_TABSTOP
;
2576 if ( mbChecked
!= bCheck
)
2579 CompatStateChanged( StateChangedType::State
);
2584 bool RadioButton::set_property(const OString
&rKey
, const OUString
&rValue
)
2586 if (rKey
== "active")
2587 SetState(toBool(rValue
));
2588 else if (rKey
== "image-position")
2590 WinBits nBits
= GetStyle();
2591 if (rValue
== "left")
2593 nBits
&= ~(WB_CENTER
| WB_RIGHT
);
2596 else if (rValue
== "right")
2598 nBits
&= ~(WB_CENTER
| WB_LEFT
);
2601 else if (rValue
== "top")
2603 nBits
&= ~(WB_VCENTER
| WB_BOTTOM
);
2606 else if (rValue
== "bottom")
2608 nBits
&= ~(WB_VCENTER
| WB_TOP
);
2611 //It's rather mad to have to set these bits when there is the other
2612 //image align. Looks like e.g. the radiobuttons etc weren't converted
2613 //over to image align fully.
2615 //Deliberate to set the sane ImageAlign property
2616 return Button::set_property(rKey
, rValue
);
2619 return Button::set_property(rKey
, rValue
);
2623 void RadioButton::Check( bool bCheck
)
2625 // TabStop-Flag richtig mitfuehren
2627 mpWindowImpl
->mnStyle
|= WB_TABSTOP
;
2629 mpWindowImpl
->mnStyle
&= ~WB_TABSTOP
;
2631 if ( mbChecked
== bCheck
)
2635 VclPtr
<vcl::Window
> xWindow
= this;
2636 CompatStateChanged( StateChangedType::State
);
2637 if ( xWindow
->IsDisposed() )
2639 if ( bCheck
&& mbRadioCheck
)
2640 ImplUncheckAllOther();
2641 if ( xWindow
->IsDisposed() )
2646 tools::Long
RadioButton::ImplGetImageToTextDistance() const
2648 // 4 pixels, but take zoom into account, so the text doesn't "jump" relative to surrounding elements,
2649 // which might have been aligned with the text of the check box
2650 return CalcZoom( 4 );
2653 Size
RadioButton::ImplGetRadioImageSize() const
2656 bool bDefaultSize
= true;
2657 if( IsNativeControlSupported( ControlType::Radiobutton
, ControlPart::Entire
) )
2659 ImplControlValue aControlValue
;
2660 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), GetSizePixel() );
2661 tools::Rectangle aBoundingRgn
, aContentRgn
;
2663 // get native size of a radio button
2664 if( GetNativeControlRegion( ControlType::Radiobutton
, ControlPart::Entire
, aCtrlRegion
,
2665 ControlState::DEFAULT
|ControlState::ENABLED
,
2667 aBoundingRgn
, aContentRgn
) )
2669 aSize
= aContentRgn
.GetSize();
2670 bDefaultSize
= false;
2674 aSize
= GetRadioImage( GetSettings(), DrawButtonFlags::NONE
).GetSizePixel();
2678 static void LoadThemedImageList(const StyleSettings
&rStyleSettings
,
2679 std::vector
<Image
>& rList
, const std::vector
<OUString
> &rResources
)
2681 Color aColorAry1
[6];
2682 Color aColorAry2
[6];
2683 aColorAry1
[0] = Color( 0xC0, 0xC0, 0xC0 );
2684 aColorAry1
[1] = Color( 0xFF, 0xFF, 0x00 );
2685 aColorAry1
[2] = Color( 0xFF, 0xFF, 0xFF );
2686 aColorAry1
[3] = Color( 0x80, 0x80, 0x80 );
2687 aColorAry1
[4] = Color( 0x00, 0x00, 0x00 );
2688 aColorAry1
[5] = Color( 0x00, 0xFF, 0x00 );
2689 aColorAry2
[0] = rStyleSettings
.GetFaceColor();
2690 aColorAry2
[1] = rStyleSettings
.GetWindowColor();
2691 aColorAry2
[2] = rStyleSettings
.GetLightColor();
2692 aColorAry2
[3] = rStyleSettings
.GetShadowColor();
2693 aColorAry2
[4] = rStyleSettings
.GetDarkShadowColor();
2694 aColorAry2
[5] = rStyleSettings
.GetWindowTextColor();
2696 static_assert( sizeof(aColorAry1
) == sizeof(aColorAry2
), "aColorAry1 must match aColorAry2" );
2698 for (const auto &a
: rResources
)
2701 aBmpEx
.Replace(aColorAry1
, aColorAry2
, SAL_N_ELEMENTS(aColorAry1
));
2702 rList
.emplace_back(aBmpEx
);
2706 Image
RadioButton::GetRadioImage( const AllSettings
& rSettings
, DrawButtonFlags nFlags
)
2708 ImplSVData
* pSVData
= ImplGetSVData();
2709 const StyleSettings
& rStyleSettings
= rSettings
.GetStyleSettings();
2710 sal_uInt16 nStyle
= 0;
2712 if ( rStyleSettings
.GetOptions() & StyleSettingsOptions::Mono
)
2713 nStyle
= STYLE_RADIOBUTTON_MONO
;
2715 if ( pSVData
->maCtrlData
.maRadioImgList
.empty() ||
2716 (pSVData
->maCtrlData
.mnRadioStyle
!= nStyle
) ||
2717 (pSVData
->maCtrlData
.mnLastRadioFColor
!= rStyleSettings
.GetFaceColor()) ||
2718 (pSVData
->maCtrlData
.mnLastRadioWColor
!= rStyleSettings
.GetWindowColor()) ||
2719 (pSVData
->maCtrlData
.mnLastRadioLColor
!= rStyleSettings
.GetLightColor()) )
2721 pSVData
->maCtrlData
.maRadioImgList
.clear();
2723 pSVData
->maCtrlData
.mnLastRadioFColor
= rStyleSettings
.GetFaceColor();
2724 pSVData
->maCtrlData
.mnLastRadioWColor
= rStyleSettings
.GetWindowColor();
2725 pSVData
->maCtrlData
.mnLastRadioLColor
= rStyleSettings
.GetLightColor();
2727 std::vector
<OUString
> aResources
;
2730 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO1
);
2731 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO2
);
2732 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO3
);
2733 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO4
);
2734 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO5
);
2735 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO6
);
2739 aResources
.emplace_back(SV_RESID_BITMAP_RADIO1
);
2740 aResources
.emplace_back(SV_RESID_BITMAP_RADIO2
);
2741 aResources
.emplace_back(SV_RESID_BITMAP_RADIO3
);
2742 aResources
.emplace_back(SV_RESID_BITMAP_RADIO4
);
2743 aResources
.emplace_back(SV_RESID_BITMAP_RADIO5
);
2744 aResources
.emplace_back(SV_RESID_BITMAP_RADIO6
);
2746 LoadThemedImageList( rStyleSettings
, pSVData
->maCtrlData
.maRadioImgList
, aResources
);
2747 pSVData
->maCtrlData
.mnRadioStyle
= nStyle
;
2751 if ( nFlags
& DrawButtonFlags::Disabled
)
2753 if ( nFlags
& DrawButtonFlags::Checked
)
2758 else if ( nFlags
& DrawButtonFlags::Pressed
)
2760 if ( nFlags
& DrawButtonFlags::Checked
)
2767 if ( nFlags
& DrawButtonFlags::Checked
)
2772 return pSVData
->maCtrlData
.maRadioImgList
[nIndex
];
2775 void RadioButton::ImplAdjustNWFSizes()
2777 Push( PushFlags::MAPMODE
);
2778 SetMapMode(MapMode(MapUnit::MapPixel
));
2780 ImplControlValue aControlValue
;
2781 Size
aCurSize( GetSizePixel() );
2782 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), aCurSize
);
2783 tools::Rectangle aBoundingRgn
, aContentRgn
;
2785 // get native size of a radiobutton
2786 if( GetNativeControlRegion( ControlType::Radiobutton
, ControlPart::Entire
, aCtrlRegion
,
2787 ControlState::DEFAULT
|ControlState::ENABLED
, aControlValue
,
2788 aBoundingRgn
, aContentRgn
) )
2790 Size aSize
= aContentRgn
.GetSize();
2792 if( aSize
.Height() > aCurSize
.Height() )
2794 aCurSize
.setHeight( aSize
.Height() );
2795 SetSizePixel( aCurSize
);
2802 Size
RadioButton::CalcMinimumSize(tools::Long nMaxWidth
) const
2806 aSize
= ImplGetRadioImageSize();
2809 aSize
= maImage
.GetSizePixel();
2810 aSize
.AdjustWidth(8);
2811 aSize
.AdjustHeight(8);
2814 if (Button::HasImage())
2816 Size aImgSize
= GetModeImage().GetSizePixel();
2817 aSize
= Size(std::max(aImgSize
.Width(), aSize
.Width()),
2818 std::max(aImgSize
.Height(), aSize
.Height()));
2821 OUString aText
= GetText();
2822 if (!aText
.isEmpty())
2824 bool bTopImage
= (GetStyle() & WB_TOP
) != 0;
2826 Size aTextSize
= GetTextRect( tools::Rectangle( Point(), Size( nMaxWidth
> 0 ? nMaxWidth
: 0x7fffffff, 0x7fffffff ) ),
2827 aText
, FixedText::ImplGetTextStyle( GetStyle() ) ).GetSize();
2829 aSize
.AdjustWidth(2 ); // for focus rect
2833 aSize
.AdjustWidth(ImplGetImageToTextDistance() );
2834 aSize
.AdjustWidth(aTextSize
.Width() );
2835 if ( aSize
.Height() < aTextSize
.Height() )
2836 aSize
.setHeight( aTextSize
.Height() );
2840 aSize
.AdjustHeight(6 );
2841 aSize
.AdjustHeight(GetTextHeight() );
2842 if ( aSize
.Width() < aTextSize
.Width() )
2843 aSize
.setWidth( aTextSize
.Width() );
2847 return CalcWindowSize( aSize
);
2850 Size
RadioButton::GetOptimalSize() const
2852 return CalcMinimumSize();
2855 void RadioButton::ShowFocus(const tools::Rectangle
& rRect
)
2857 if (IsNativeControlSupported(ControlType::Radiobutton
, ControlPart::Focus
))
2859 ImplControlValue aControlValue
;
2860 tools::Rectangle
aInRect(Point(0, 0), GetSizePixel());
2862 aInRect
.SetLeft( rRect
.Left() ); // exclude the radio element itself from the focusrect
2864 DrawNativeControl(ControlType::Radiobutton
, ControlPart::Focus
, aInRect
,
2865 ControlState::FOCUSED
, aControlValue
, OUString());
2867 Button::ShowFocus(rRect
);
2870 void RadioButton::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
2872 Button::DumpAsPropertyTree(rJsonWriter
);
2873 rJsonWriter
.put("checked", IsChecked());
2876 FactoryFunction
RadioButton::GetUITestFactory() const
2878 return RadioButtonUIObject::create
;
2881 void CheckBox::ImplInitCheckBoxData()
2883 meState
= TRISTATE_FALSE
;
2887 void CheckBox::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
2889 nStyle
= ImplInitStyle(getPreviousSibling(pParent
), nStyle
);
2890 Button::ImplInit( pParent
, nStyle
, nullptr );
2892 ImplInitSettings( true );
2895 WinBits
CheckBox::ImplInitStyle( const vcl::Window
* pPrevWindow
, WinBits nStyle
)
2897 if ( !(nStyle
& WB_NOTABSTOP
) )
2898 nStyle
|= WB_TABSTOP
;
2899 if ( !(nStyle
& WB_NOGROUP
) &&
2900 (!pPrevWindow
|| (pPrevWindow
->GetType() != WindowType::CHECKBOX
)) )
2905 const vcl::Font
& CheckBox::GetCanonicalFont( const StyleSettings
& _rStyle
) const
2907 return _rStyle
.GetRadioCheckFont();
2910 const Color
& CheckBox::GetCanonicalTextColor( const StyleSettings
& _rStyle
) const
2912 return _rStyle
.GetRadioCheckTextColor();
2915 void CheckBox::ImplInitSettings( bool bBackground
)
2917 Button::ImplInitSettings();
2922 vcl::Window
* pParent
= GetParent();
2923 if ( !IsControlBackground() &&
2924 (pParent
->IsChildTransparentModeEnabled() || IsNativeControlSupported( ControlType::Checkbox
, ControlPart::Entire
) ) )
2926 EnableChildTransparentMode();
2927 SetParentClipMode( ParentClipMode::NoClip
);
2928 SetPaintTransparent( true );
2930 if( IsNativeControlSupported( ControlType::Checkbox
, ControlPart::Entire
) )
2931 ImplGetWindowImpl()->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
2935 EnableChildTransparentMode( false );
2936 SetParentClipMode();
2937 SetPaintTransparent( false );
2939 if ( IsControlBackground() )
2940 SetBackground( GetControlBackground() );
2942 SetBackground( pParent
->GetBackground() );
2946 void CheckBox::ImplDrawCheckBoxState(vcl::RenderContext
& rRenderContext
)
2948 bool bNativeOK
= rRenderContext
.IsNativeControlSupported(ControlType::Checkbox
, ControlPart::Entire
);
2951 ImplControlValue
aControlValue(meState
== TRISTATE_TRUE
? ButtonValue::On
: ButtonValue::Off
);
2952 tools::Rectangle
aCtrlRegion(maStateRect
);
2953 ControlState nState
= ControlState::NONE
;
2956 nState
|= ControlState::FOCUSED
;
2957 if (GetButtonState() & DrawButtonFlags::Default
)
2958 nState
|= ControlState::DEFAULT
;
2959 if (GetButtonState() & DrawButtonFlags::Pressed
)
2960 nState
|= ControlState::PRESSED
;
2962 nState
|= ControlState::ENABLED
;
2964 if (meState
== TRISTATE_TRUE
)
2965 aControlValue
.setTristateVal(ButtonValue::On
);
2966 else if (meState
== TRISTATE_INDET
)
2967 aControlValue
.setTristateVal(ButtonValue::Mixed
);
2969 if (IsMouseOver() && maMouseRect
.IsInside(GetPointerPosPixel()))
2970 nState
|= ControlState::ROLLOVER
;
2972 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Checkbox
, ControlPart::Entire
, aCtrlRegion
,
2973 nState
, aControlValue
, OUString());
2979 DrawButtonFlags nStyle
= GetButtonState();
2981 nStyle
|= DrawButtonFlags::Disabled
;
2982 if (meState
== TRISTATE_INDET
)
2983 nStyle
|= DrawButtonFlags::DontKnow
;
2984 else if (meState
== TRISTATE_TRUE
)
2985 nStyle
|= DrawButtonFlags::Checked
;
2986 Image aImage
= GetCheckImage(GetSettings(), nStyle
);
2988 rRenderContext
.DrawImage(maStateRect
.TopLeft(), maStateRect
.GetSize(), aImage
);
2990 rRenderContext
.DrawImage(maStateRect
.TopLeft(), aImage
);
2993 void CheckBox::ImplDraw( OutputDevice
* pDev
, DrawFlags nDrawFlags
,
2994 const Point
& rPos
, const Size
& rSize
,
2995 const Size
& rImageSize
, tools::Rectangle
& rStateRect
,
2996 tools::Rectangle
& rMouseRect
)
2998 WinBits nWinStyle
= GetStyle();
2999 OUString
aText( GetText() );
3001 pDev
->Push( PushFlags::CLIPREGION
| PushFlags::LINECOLOR
);
3002 pDev
->IntersectClipRegion( tools::Rectangle( rPos
, rSize
) );
3004 if (!aText
.isEmpty() || HasImage())
3006 DrawTextFlags nTextStyle
= Button::ImplGetTextStyle( nWinStyle
, nDrawFlags
);
3008 const tools::Long nImageSep
= GetDrawPixel( pDev
, ImplGetImageToTextDistance() );
3009 Size
aSize( rSize
);
3011 aPos
.AdjustX(rImageSize
.Width() + nImageSep
);
3013 // tdf#141761 See comment with same ID above
3014 const tools::Long
nWidthAdjust(rImageSize
.Width() + nImageSep
);
3015 aSize
.setWidth(std::max(static_cast<tools::Long
>(1), aSize
.getWidth() - nWidthAdjust
));
3017 // if the text rect height is smaller than the height of the image
3018 // then for single lines the default should be centered text
3019 if( (nWinStyle
& (WB_TOP
|WB_VCENTER
|WB_BOTTOM
)) == 0 &&
3020 (rImageSize
.Height() > rSize
.Height() || ! (nWinStyle
& WB_WORDBREAK
) ) )
3022 nTextStyle
&= ~DrawTextFlags(DrawTextFlags::Top
|DrawTextFlags::Bottom
);
3023 nTextStyle
|= DrawTextFlags::VCenter
;
3024 aSize
.setHeight( rImageSize
.Height() );
3027 ImplDrawAlignedImage( pDev
, aPos
, aSize
, 1, nTextStyle
);
3029 rMouseRect
= tools::Rectangle( aPos
, aSize
);
3030 rMouseRect
.SetLeft( rPos
.X() );
3032 rStateRect
.SetLeft( rPos
.X() );
3033 rStateRect
.SetTop( rMouseRect
.Top() );
3035 if ( aSize
.Height() > rImageSize
.Height() )
3036 rStateRect
.AdjustTop(( aSize
.Height() - rImageSize
.Height() ) / 2 );
3039 rStateRect
.AdjustTop( -(( rImageSize
.Height() - aSize
.Height() ) / 2) );
3040 if( rStateRect
.Top() < 0 )
3041 rStateRect
.SetTop( 0 );
3044 rStateRect
.SetRight( rStateRect
.Left()+rImageSize
.Width()-1 );
3045 rStateRect
.SetBottom( rStateRect
.Top()+rImageSize
.Height()-1 );
3046 if ( rStateRect
.Bottom() > rMouseRect
.Bottom() )
3047 rMouseRect
.SetBottom( rStateRect
.Bottom() );
3051 rStateRect
.SetLeft( rPos
.X() );
3052 if ( nWinStyle
& WB_VCENTER
)
3053 rStateRect
.SetTop( rPos
.Y()+((rSize
.Height()-rImageSize
.Height())/2) );
3054 else if ( nWinStyle
& WB_BOTTOM
)
3055 rStateRect
.SetTop( rPos
.Y()+rSize
.Height()-rImageSize
.Height() );
3057 rStateRect
.SetTop( rPos
.Y() );
3058 rStateRect
.SetRight( rStateRect
.Left()+rImageSize
.Width()-1 );
3059 rStateRect
.SetBottom( rStateRect
.Top()+rImageSize
.Height()-1 );
3060 // provide space for focusrect
3061 // note: this assumes that the control's size was adjusted
3062 // accordingly in Get/LoseFocus, so the onscreen position won't change
3064 rStateRect
.Move( 1, 1 );
3065 rMouseRect
= rStateRect
;
3067 ImplSetFocusRect( rStateRect
);
3073 void CheckBox::ImplDrawCheckBox(vcl::RenderContext
& rRenderContext
)
3075 Size aImageSize
= ImplGetCheckImageSize();
3076 aImageSize
.setWidth( CalcZoom( aImageSize
.Width() ) );
3077 aImageSize
.setHeight( CalcZoom( aImageSize
.Height() ) );
3081 ImplDraw(&rRenderContext
, DrawFlags::NONE
, Point(), GetOutputSizePixel(),
3082 aImageSize
, maStateRect
, maMouseRect
);
3084 ImplDrawCheckBoxState(rRenderContext
);
3086 ShowFocus(ImplGetFocusRect());
3089 void CheckBox::ImplCheck()
3092 if ( meState
== TRISTATE_FALSE
)
3093 eNewState
= TRISTATE_TRUE
;
3094 else if ( !mbTriState
)
3095 eNewState
= TRISTATE_FALSE
;
3096 else if ( meState
== TRISTATE_TRUE
)
3097 eNewState
= TRISTATE_INDET
;
3099 eNewState
= TRISTATE_FALSE
;
3100 meState
= eNewState
;
3102 VclPtr
<vcl::Window
> xWindow
= this;
3105 if ( xWindow
->IsDisposed() )
3110 CheckBox::CheckBox( vcl::Window
* pParent
, WinBits nStyle
) :
3111 Button( WindowType::CHECKBOX
)
3113 ImplInitCheckBoxData();
3114 ImplInit( pParent
, nStyle
);
3117 void CheckBox::MouseButtonDown( const MouseEvent
& rMEvt
)
3119 if ( rMEvt
.IsLeft() && maMouseRect
.IsInside( rMEvt
.GetPosPixel() ) )
3121 GetButtonState() |= DrawButtonFlags::Pressed
;
3127 Button::MouseButtonDown( rMEvt
);
3130 void CheckBox::Tracking( const TrackingEvent
& rTEvt
)
3132 if ( rTEvt
.IsTrackingEnded() )
3134 if ( GetButtonState() & DrawButtonFlags::Pressed
)
3136 if ( !(GetStyle() & WB_NOPOINTERFOCUS
) && !rTEvt
.IsTrackingCanceled() )
3139 GetButtonState() &= ~DrawButtonFlags::Pressed
;
3141 // do not call click handler if aborted
3142 if ( !rTEvt
.IsTrackingCanceled() )
3152 if ( maMouseRect
.IsInside( rTEvt
.GetMouseEvent().GetPosPixel() ) )
3154 if ( !(GetButtonState() & DrawButtonFlags::Pressed
) )
3156 GetButtonState() |= DrawButtonFlags::Pressed
;
3162 if ( GetButtonState() & DrawButtonFlags::Pressed
)
3164 GetButtonState() &= ~DrawButtonFlags::Pressed
;
3171 void CheckBox::KeyInput( const KeyEvent
& rKEvt
)
3173 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
3175 if ( !aKeyCode
.GetModifier() && (aKeyCode
.GetCode() == KEY_SPACE
) )
3177 if ( !(GetButtonState() & DrawButtonFlags::Pressed
) )
3179 GetButtonState() |= DrawButtonFlags::Pressed
;
3183 else if ( (GetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_ESCAPE
) )
3185 GetButtonState() &= ~DrawButtonFlags::Pressed
;
3189 Button::KeyInput( rKEvt
);
3192 void CheckBox::KeyUp( const KeyEvent
& rKEvt
)
3194 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
3196 if ( (GetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_SPACE
) )
3198 GetButtonState() &= ~DrawButtonFlags::Pressed
;
3202 Button::KeyUp( rKEvt
);
3205 void CheckBox::FillLayoutData() const
3207 mpControlData
->mpLayoutData
.reset( new vcl::ControlLayoutData
);
3208 const_cast<CheckBox
*>(this)->Invalidate();
3211 void CheckBox::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
3213 ImplDrawCheckBox(rRenderContext
);
3216 void CheckBox::Draw( OutputDevice
* pDev
, const Point
& rPos
,
3219 MapMode
aResMapMode( MapUnit::Map100thMM
);
3220 Point aPos
= pDev
->LogicToPixel( rPos
);
3221 Size aSize
= GetSizePixel();
3222 Size aImageSize
= pDev
->LogicToPixel( Size( 300, 300 ), aResMapMode
);
3223 Size aBrd1Size
= pDev
->LogicToPixel( Size( 20, 20 ), aResMapMode
);
3224 Size aBrd2Size
= pDev
->LogicToPixel( Size( 30, 30 ), aResMapMode
);
3225 tools::Long nCheckWidth
= pDev
->LogicToPixel( Size( 20, 20 ), aResMapMode
).Width();
3226 vcl::Font aFont
= GetDrawPixelFont( pDev
);
3227 tools::Rectangle aStateRect
;
3228 tools::Rectangle aMouseRect
;
3230 aImageSize
.setWidth( CalcZoom( aImageSize
.Width() ) );
3231 aImageSize
.setHeight( CalcZoom( aImageSize
.Height() ) );
3232 aBrd1Size
.setWidth( CalcZoom( aBrd1Size
.Width() ) );
3233 aBrd1Size
.setHeight( CalcZoom( aBrd1Size
.Height() ) );
3234 aBrd2Size
.setWidth( CalcZoom( aBrd2Size
.Width() ) );
3235 aBrd2Size
.setHeight( CalcZoom( aBrd2Size
.Height() ) );
3237 if ( !aBrd1Size
.Width() )
3238 aBrd1Size
.setWidth( 1 );
3239 if ( !aBrd1Size
.Height() )
3240 aBrd1Size
.setHeight( 1 );
3241 if ( !aBrd2Size
.Width() )
3242 aBrd2Size
.setWidth( 1 );
3243 if ( !aBrd2Size
.Height() )
3244 aBrd2Size
.setHeight( 1 );
3250 pDev
->SetFont( aFont
);
3251 if ( nFlags
& DrawFlags::Mono
)
3252 pDev
->SetTextColor( COL_BLACK
);
3254 pDev
->SetTextColor( GetTextColor() );
3255 pDev
->SetTextFillColor();
3257 ImplDraw( pDev
, nFlags
, aPos
, aSize
,
3258 aImageSize
, aStateRect
, aMouseRect
);
3260 pDev
->SetLineColor();
3261 pDev
->SetFillColor( COL_BLACK
);
3262 pDev
->DrawRect( aStateRect
);
3263 aStateRect
.AdjustLeft(aBrd1Size
.Width() );
3264 aStateRect
.AdjustTop(aBrd1Size
.Height() );
3265 aStateRect
.AdjustRight( -(aBrd1Size
.Width()) );
3266 aStateRect
.AdjustBottom( -(aBrd1Size
.Height()) );
3267 if ( meState
== TRISTATE_INDET
)
3268 pDev
->SetFillColor( COL_LIGHTGRAY
);
3270 pDev
->SetFillColor( COL_WHITE
);
3271 pDev
->DrawRect( aStateRect
);
3273 if ( meState
== TRISTATE_TRUE
)
3275 aStateRect
.AdjustLeft(aBrd2Size
.Width() );
3276 aStateRect
.AdjustTop(aBrd2Size
.Height() );
3277 aStateRect
.AdjustRight( -(aBrd2Size
.Width()) );
3278 aStateRect
.AdjustBottom( -(aBrd2Size
.Height()) );
3279 Point
aPos11( aStateRect
.TopLeft() );
3280 Point
aPos12( aStateRect
.BottomRight() );
3281 Point
aPos21( aStateRect
.TopRight() );
3282 Point
aPos22( aStateRect
.BottomLeft() );
3283 Point
aTempPos11( aPos11
);
3284 Point
aTempPos12( aPos12
);
3285 Point
aTempPos21( aPos21
);
3286 Point
aTempPos22( aPos22
);
3287 pDev
->SetLineColor( COL_BLACK
);
3288 tools::Long nDX
= 0;
3289 for ( tools::Long i
= 0; i
< nCheckWidth
; i
++ )
3293 aTempPos11
.setX( aPos11
.X()+nDX
);
3294 aTempPos12
.setX( aPos12
.X()+nDX
);
3295 aTempPos21
.setX( aPos21
.X()+nDX
);
3296 aTempPos22
.setX( aPos22
.X()+nDX
);
3301 aTempPos11
.setX( aPos11
.X()-nDX
);
3302 aTempPos12
.setX( aPos12
.X()-nDX
);
3303 aTempPos21
.setX( aPos21
.X()-nDX
);
3304 aTempPos22
.setX( aPos22
.X()-nDX
);
3306 pDev
->DrawLine( aTempPos11
, aTempPos12
);
3307 pDev
->DrawLine( aTempPos21
, aTempPos22
);
3314 void CheckBox::Resize()
3320 void CheckBox::GetFocus()
3322 if (GetText().isEmpty())
3324 // increase button size to have space for focus rect
3325 // checkboxes without text will draw focusrect around the check
3326 // See CheckBox::ImplDraw()
3327 Point
aPos( GetPosPixel() );
3328 Size
aSize( GetSizePixel() );
3330 aSize
.AdjustHeight(2 );
3331 aSize
.AdjustWidth(2 );
3332 setPosSizePixel( aPos
.X(), aPos
.Y(), aSize
.Width(), aSize
.Height() );
3334 // Trigger drawing to initialize the mouse rectangle, otherwise the mouse button down
3335 // handler would ignore the mouse event.
3339 ShowFocus( ImplGetFocusRect() );
3341 SetInputContext( InputContext( GetFont() ) );
3345 void CheckBox::LoseFocus()
3347 if ( GetButtonState() & DrawButtonFlags::Pressed
)
3349 GetButtonState() &= ~DrawButtonFlags::Pressed
;
3354 Button::LoseFocus();
3356 if (GetText().isEmpty())
3358 // decrease button size again (see GetFocus())
3359 // checkboxes without text will draw focusrect around the check
3360 Point
aPos( GetPosPixel() );
3361 Size
aSize( GetSizePixel() );
3363 aSize
.AdjustHeight( -2 );
3364 aSize
.AdjustWidth( -2 );
3365 setPosSizePixel( aPos
.X(), aPos
.Y(), aSize
.Width(), aSize
.Height() );
3370 void CheckBox::StateChanged( StateChangedType nType
)
3372 Button::StateChanged( nType
);
3374 if ( nType
== StateChangedType::State
)
3376 if ( IsReallyVisible() && IsUpdateMode() )
3377 Invalidate( maStateRect
);
3379 else if ( (nType
== StateChangedType::Enable
) ||
3380 (nType
== StateChangedType::Text
) ||
3381 (nType
== StateChangedType::Data
) ||
3382 (nType
== StateChangedType::UpdateMode
) )
3384 if ( IsUpdateMode() )
3387 else if ( nType
== StateChangedType::Style
)
3389 SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev
), GetStyle() ) );
3391 if ( (GetPrevStyle() & CHECKBOX_VIEW_STYLE
) !=
3392 (GetStyle() & CHECKBOX_VIEW_STYLE
) )
3394 if ( IsUpdateMode() )
3398 else if ( (nType
== StateChangedType::Zoom
) ||
3399 (nType
== StateChangedType::ControlFont
) )
3401 ImplInitSettings( false );
3404 else if ( nType
== StateChangedType::ControlForeground
)
3406 ImplInitSettings( false );
3409 else if ( nType
== StateChangedType::ControlBackground
)
3411 ImplInitSettings( true );
3416 void CheckBox::DataChanged( const DataChangedEvent
& rDCEvt
)
3418 Button::DataChanged( rDCEvt
);
3420 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
3421 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
3422 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
3423 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
3425 ImplInitSettings( true );
3430 bool CheckBox::PreNotify( NotifyEvent
& rNEvt
)
3432 if( rNEvt
.GetType() == MouseNotifyEvent::MOUSEMOVE
)
3434 const MouseEvent
* pMouseEvt
= rNEvt
.GetMouseEvent();
3435 if( pMouseEvt
&& !pMouseEvt
->GetButtons() && !pMouseEvt
->IsSynthetic() && !pMouseEvt
->IsModifierChanged() )
3437 // trigger redraw if mouse over state has changed
3438 if( IsNativeControlSupported(ControlType::Checkbox
, ControlPart::Entire
) )
3440 if (maMouseRect
.IsInside(GetPointerPosPixel()) != maMouseRect
.IsInside(GetLastPointerPosPixel()) ||
3441 pMouseEvt
->IsLeaveWindow() || pMouseEvt
->IsEnterWindow())
3443 Invalidate( maStateRect
);
3449 return Button::PreNotify(rNEvt
);
3452 void CheckBox::Toggle()
3454 ImplCallEventListenersAndHandler( VclEventId::CheckboxToggle
, [this] () { maToggleHdl
.Call(*this); } );
3457 void CheckBox::SetState( TriState eState
)
3459 if ( !mbTriState
&& (eState
== TRISTATE_INDET
) )
3460 eState
= TRISTATE_FALSE
;
3462 if ( meState
!= eState
)
3465 StateChanged( StateChangedType::State
);
3470 bool CheckBox::set_property(const OString
&rKey
, const OUString
&rValue
)
3472 if (rKey
== "active")
3473 SetState(toBool(rValue
) ? TRISTATE_TRUE
: TRISTATE_FALSE
);
3475 return Button::set_property(rKey
, rValue
);
3479 void CheckBox::EnableTriState( bool bTriState
)
3481 if ( mbTriState
!= bTriState
)
3483 mbTriState
= bTriState
;
3485 if ( !bTriState
&& (meState
== TRISTATE_INDET
) )
3486 SetState( TRISTATE_FALSE
);
3490 tools::Long
CheckBox::ImplGetImageToTextDistance() const
3492 // 4 pixels, but take zoom into account, so the text doesn't "jump" relative to surrounding elements,
3493 // which might have been aligned with the text of the check box
3494 return CalcZoom( 4 );
3497 Size
CheckBox::ImplGetCheckImageSize() const
3500 bool bDefaultSize
= true;
3501 if( IsNativeControlSupported( ControlType::Checkbox
, ControlPart::Entire
) )
3503 ImplControlValue aControlValue
;
3504 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), GetSizePixel() );
3505 tools::Rectangle aBoundingRgn
, aContentRgn
;
3507 // get native size of a check box
3508 if( GetNativeControlRegion( ControlType::Checkbox
, ControlPart::Entire
, aCtrlRegion
,
3509 ControlState::DEFAULT
|ControlState::ENABLED
,
3511 aBoundingRgn
, aContentRgn
) )
3513 aSize
= aContentRgn
.GetSize();
3514 bDefaultSize
= false;
3518 aSize
= GetCheckImage( GetSettings(), DrawButtonFlags::NONE
).GetSizePixel();
3522 Image
CheckBox::GetCheckImage( const AllSettings
& rSettings
, DrawButtonFlags nFlags
)
3524 ImplSVData
* pSVData
= ImplGetSVData();
3525 const StyleSettings
& rStyleSettings
= rSettings
.GetStyleSettings();
3526 sal_uInt16 nStyle
= 0;
3528 if ( rStyleSettings
.GetOptions() & StyleSettingsOptions::Mono
)
3529 nStyle
= STYLE_CHECKBOX_MONO
;
3531 if ( pSVData
->maCtrlData
.maCheckImgList
.empty() ||
3532 (pSVData
->maCtrlData
.mnCheckStyle
!= nStyle
) ||
3533 (pSVData
->maCtrlData
.mnLastCheckFColor
!= rStyleSettings
.GetFaceColor()) ||
3534 (pSVData
->maCtrlData
.mnLastCheckWColor
!= rStyleSettings
.GetWindowColor()) ||
3535 (pSVData
->maCtrlData
.mnLastCheckLColor
!= rStyleSettings
.GetLightColor()) )
3537 pSVData
->maCtrlData
.maCheckImgList
.clear();
3539 pSVData
->maCtrlData
.mnLastCheckFColor
= rStyleSettings
.GetFaceColor();
3540 pSVData
->maCtrlData
.mnLastCheckWColor
= rStyleSettings
.GetWindowColor();
3541 pSVData
->maCtrlData
.mnLastCheckLColor
= rStyleSettings
.GetLightColor();
3543 std::vector
<OUString
> aResources
;
3546 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO1
);
3547 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO2
);
3548 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO3
);
3549 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO4
);
3550 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO5
);
3551 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO6
);
3552 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO7
);
3553 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO8
);
3554 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO9
);
3558 aResources
.emplace_back(SV_RESID_BITMAP_CHECK1
);
3559 aResources
.emplace_back(SV_RESID_BITMAP_CHECK2
);
3560 aResources
.emplace_back(SV_RESID_BITMAP_CHECK3
);
3561 aResources
.emplace_back(SV_RESID_BITMAP_CHECK4
);
3562 aResources
.emplace_back(SV_RESID_BITMAP_CHECK5
);
3563 aResources
.emplace_back(SV_RESID_BITMAP_CHECK6
);
3564 aResources
.emplace_back(SV_RESID_BITMAP_CHECK7
);
3565 aResources
.emplace_back(SV_RESID_BITMAP_CHECK8
);
3566 aResources
.emplace_back(SV_RESID_BITMAP_CHECK9
);
3568 LoadThemedImageList(rStyleSettings
, pSVData
->maCtrlData
.maCheckImgList
, aResources
);
3569 pSVData
->maCtrlData
.mnCheckStyle
= nStyle
;
3573 if ( nFlags
& DrawButtonFlags::Disabled
)
3575 if ( nFlags
& DrawButtonFlags::DontKnow
)
3577 else if ( nFlags
& DrawButtonFlags::Checked
)
3582 else if ( nFlags
& DrawButtonFlags::Pressed
)
3584 if ( nFlags
& DrawButtonFlags::DontKnow
)
3586 else if ( nFlags
& DrawButtonFlags::Checked
)
3593 if ( nFlags
& DrawButtonFlags::DontKnow
)
3595 else if ( nFlags
& DrawButtonFlags::Checked
)
3600 return pSVData
->maCtrlData
.maCheckImgList
[nIndex
];
3603 void CheckBox::ImplAdjustNWFSizes()
3605 Push( PushFlags::MAPMODE
);
3606 SetMapMode(MapMode(MapUnit::MapPixel
));
3608 ImplControlValue aControlValue
;
3609 Size
aCurSize( GetSizePixel() );
3610 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), aCurSize
);
3611 tools::Rectangle aBoundingRgn
, aContentRgn
;
3613 // get native size of a radiobutton
3614 if( GetNativeControlRegion( ControlType::Checkbox
, ControlPart::Entire
, aCtrlRegion
,
3615 ControlState::DEFAULT
|ControlState::ENABLED
, aControlValue
,
3616 aBoundingRgn
, aContentRgn
) )
3618 Size aSize
= aContentRgn
.GetSize();
3620 if( aSize
.Height() > aCurSize
.Height() )
3622 aCurSize
.setHeight( aSize
.Height() );
3623 SetSizePixel( aCurSize
);
3630 Size
CheckBox::CalcMinimumSize( tools::Long nMaxWidth
) const
3632 Size aSize
= ImplGetCheckImageSize();
3633 nMaxWidth
-= aSize
.Width();
3635 OUString aText
= GetText();
3636 if (!aText
.isEmpty())
3638 // subtract what will be added later
3640 nMaxWidth
-= ImplGetImageToTextDistance();
3642 Size aTextSize
= GetTextRect( tools::Rectangle( Point(), Size( nMaxWidth
> 0 ? nMaxWidth
: 0x7fffffff, 0x7fffffff ) ),
3643 aText
, FixedText::ImplGetTextStyle( GetStyle() ) ).GetSize();
3644 aSize
.AdjustWidth(2 ); // for focus rect
3645 aSize
.AdjustWidth(ImplGetImageToTextDistance() );
3646 aSize
.AdjustWidth(aTextSize
.Width() );
3647 if ( aSize
.Height() < aTextSize
.Height() )
3648 aSize
.setHeight( aTextSize
.Height() );
3652 // is this still correct ? since the checkbox now
3653 // shows a focus rect it should be 2 pixels wider and longer
3654 /* since otherwise the controls in the Writer hang too far up
3656 aSize.Height() += 2;
3660 return CalcWindowSize( aSize
);
3663 Size
CheckBox::GetOptimalSize() const
3665 int nWidthRequest(get_width_request());
3666 return CalcMinimumSize(nWidthRequest
!= -1 ? nWidthRequest
: 0);
3669 void CheckBox::ShowFocus(const tools::Rectangle
& rRect
)
3671 if (IsNativeControlSupported(ControlType::Checkbox
, ControlPart::Focus
))
3673 ImplControlValue aControlValue
;
3674 tools::Rectangle
aInRect(Point(0, 0), GetSizePixel());
3676 aInRect
.SetLeft( rRect
.Left() ); // exclude the checkbox itself from the focusrect
3678 DrawNativeControl(ControlType::Checkbox
, ControlPart::Focus
, aInRect
,
3679 ControlState::FOCUSED
, aControlValue
, OUString());
3681 Button::ShowFocus(rRect
);
3684 void CheckBox::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
3686 Button::DumpAsPropertyTree(rJsonWriter
);
3687 rJsonWriter
.put("checked", IsChecked());
3690 FactoryFunction
CheckBox::GetUITestFactory() const
3692 return CheckBoxUIObject::create
;
3695 ImageButton::ImageButton( vcl::Window
* pParent
, WinBits nStyle
) :
3696 PushButton( pParent
, nStyle
)
3701 void ImageButton::ImplInitStyle()
3703 WinBits nStyle
= GetStyle();
3705 if ( ! ( nStyle
& ( WB_RIGHT
| WB_LEFT
) ) )
3706 nStyle
|= WB_CENTER
;
3708 if ( ! ( nStyle
& ( WB_TOP
| WB_BOTTOM
) ) )
3709 nStyle
|= WB_VCENTER
;
3714 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */