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/dialog.hxx>
29 #include <vcl/fixed.hxx>
30 #include <vcl/button.hxx>
31 #include <vcl/salnativewidgets.hxx>
32 #include <vcl/edit.hxx>
33 #include <vcl/layout.hxx>
34 #include <vcl/vclstatuslistener.hxx>
35 #include <vcl/uitest/uiobject.hxx>
37 #include <strings.hrc>
38 #include <bitmaps.hlst>
41 #include <controldata.hxx>
42 #include <osl/diagnose.h>
44 #include <comphelper/dispatchcommand.hxx>
45 #include <comphelper/lok.hxx>
46 #include <officecfg/Office/Common.hxx>
51 static constexpr auto PUSHBUTTON_VIEW_STYLE
= WB_3DLOOK
|
52 WB_LEFT
| WB_CENTER
| WB_RIGHT
|
53 WB_TOP
| WB_VCENTER
| WB_BOTTOM
|
54 WB_WORDBREAK
| WB_NOLABEL
|
55 WB_DEFBUTTON
| WB_NOLIGHTBORDER
|
56 WB_RECTSTYLE
| WB_SMALLSTYLE
|
58 static constexpr auto RADIOBUTTON_VIEW_STYLE
= WB_3DLOOK
|
59 WB_LEFT
| WB_CENTER
| WB_RIGHT
|
60 WB_TOP
| WB_VCENTER
| WB_BOTTOM
|
61 WB_WORDBREAK
| WB_NOLABEL
;
62 static constexpr auto CHECKBOX_VIEW_STYLE
= WB_3DLOOK
|
63 WB_LEFT
| WB_CENTER
| WB_RIGHT
|
64 WB_TOP
| WB_VCENTER
| WB_BOTTOM
|
65 WB_WORDBREAK
| WB_NOLABEL
;
67 #define STYLE_RADIOBUTTON_MONO (sal_uInt16(0x0001)) // legacy
68 #define STYLE_CHECKBOX_MONO (sal_uInt16(0x0001)) // legacy
70 class ImplCommonButtonData
73 ImplCommonButtonData();
75 tools::Rectangle maFocusRect
;
77 DrawButtonFlags mnButtonState
;
81 ImageAlign meImageAlign
;
82 SymbolAlign meSymbolAlign
;
84 /** StatusListener. Updates the button as the slot state changes */
85 rtl::Reference
<VclStatusListener
<Button
>> mpStatusListener
;
88 ImplCommonButtonData::ImplCommonButtonData() : maFocusRect(), mnSeparatorX(0), mnButtonState(DrawButtonFlags::NONE
),
89 mbSmallSymbol(false), maImage(), meImageAlign(ImageAlign::Top
), meSymbolAlign(SymbolAlign::LEFT
)
93 Button::Button( WindowType nType
) :
95 mpButtonData( std::make_unique
<ImplCommonButtonData
>() )
104 void Button::dispose()
106 if (mpButtonData
->mpStatusListener
.is())
107 mpButtonData
->mpStatusListener
->dispose();
111 void Button::SetCommandHandler(const OUString
& aCommand
)
113 maCommand
= aCommand
;
114 SetClickHdl( LINK( this, Button
, dispatchCommandHandler
) );
116 mpButtonData
->mpStatusListener
= new VclStatusListener
<Button
>(this, aCommand
);
117 mpButtonData
->mpStatusListener
->startListening();
122 ImplCallEventListenersAndHandler( VclEventId::ButtonClick
, [this] () { maClickHdl
.Call(this); } );
125 OUString
Button::GetStandardText(StandardButtonType eButton
)
127 static const char* aResIdAry
[static_cast<int>(StandardButtonType::Count
)] =
129 // http://lists.freedesktop.org/archives/libreoffice/2013-January/044513.html
130 // Under windows we don't want accelerators on ok/cancel but do on other
133 SV_BUTTONTEXT_OK_NOMNEMONIC
,
134 SV_BUTTONTEXT_CANCEL_NOMNEMONIC
,
137 SV_BUTTONTEXT_CANCEL
,
145 SV_BUTTONTEXT_IGNORE
,
153 return VclResId(aResIdAry
[static_cast<sal_uInt16
>(eButton
)]);
156 void Button::SetModeImage( const Image
& rImage
)
158 if ( rImage
!= mpButtonData
->maImage
)
160 mpButtonData
->maImage
= rImage
;
161 StateChanged( StateChangedType::Data
);
166 Image
const & Button::GetModeImage( ) const
168 return mpButtonData
->maImage
;
171 bool Button::HasImage() const
173 return !!(mpButtonData
->maImage
);
176 void Button::SetImageAlign( ImageAlign eAlign
)
178 if ( mpButtonData
->meImageAlign
!= eAlign
)
180 mpButtonData
->meImageAlign
= eAlign
;
181 StateChanged( StateChangedType::Data
);
185 ImageAlign
Button::GetImageAlign() const
187 return mpButtonData
->meImageAlign
;
190 long Button::ImplGetSeparatorX() const
192 return mpButtonData
->mnSeparatorX
;
195 void Button::ImplSetSeparatorX( long nX
)
197 mpButtonData
->mnSeparatorX
= nX
;
200 DrawTextFlags
Button::ImplGetTextStyle( WinBits nWinStyle
, DrawFlags nDrawFlags
)
202 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
203 DrawTextFlags nTextStyle
= FixedText::ImplGetTextStyle(nWinStyle
& ~WB_DEFBUTTON
);
206 nTextStyle
|= DrawTextFlags::Disable
;
208 if ((nDrawFlags
& DrawFlags::Mono
) ||
209 (rStyleSettings
.GetOptions() & StyleSettingsOptions::Mono
))
211 nTextStyle
|= DrawTextFlags::Mono
;
217 void Button::ImplDrawAlignedImage(OutputDevice
* pDev
, Point
& rPos
,
220 DrawTextFlags nTextStyle
, tools::Rectangle
*pSymbolRect
,
223 OUString
aText(GetText());
224 bool bDrawImage
= HasImage();
225 bool bDrawText
= !aText
.isEmpty();
226 bool bHasSymbol
= pSymbolRect
!= nullptr;
228 // No text and no image => nothing to do => return
229 if (!bDrawImage
&& !bDrawText
&& !bHasSymbol
)
232 WinBits nWinStyle
= GetStyle();
233 tools::Rectangle
aOutRect( rPos
, rSize
);
234 ImageAlign eImageAlign
= mpButtonData
->meImageAlign
;
235 Size aImageSize
= mpButtonData
->maImage
.GetSizePixel();
237 aImageSize
.setWidth( CalcZoom( aImageSize
.Width() ) );
238 aImageSize
.setHeight( CalcZoom( aImageSize
.Height() ) );
240 // Drawing text or symbol only is simple, use style and output rectangle
241 if (bHasSymbol
&& !bDrawImage
&& !bDrawText
)
243 *pSymbolRect
= aOutRect
;
246 else if (bDrawText
&& !bDrawImage
&& !bHasSymbol
)
248 aOutRect
= DrawControlText(*pDev
, aOutRect
, aText
, nTextStyle
, nullptr, nullptr);
250 ImplSetFocusRect(aOutRect
);
251 rSize
= aOutRect
.GetSize();
252 rPos
= aOutRect
.TopLeft();
257 // check for HC mode ( image only! )
258 Image
* pImage
= &(mpButtonData
->maImage
);
262 Size aDeviceTextSize
;
264 Point aImagePos
= rPos
;
265 Point aTextPos
= rPos
;
266 tools::Rectangle
aUnion(aImagePos
, aImageSize
);
267 tools::Rectangle aSymbol
;
268 long nSymbolHeight
= 0;
270 if (bDrawText
|| bHasSymbol
)
272 // Get the size of the text output area ( the symbol will be drawn in
273 // this area as well, so the symbol rectangle will be calculated here, too )
275 tools::Rectangle
aRect(Point(), rSize
);
282 nSymbolHeight
= pDev
->GetTextHeight();
283 if (mpButtonData
->mbSmallSymbol
)
284 nSymbolHeight
= nSymbolHeight
* 3 / 4;
286 aSymbol
= tools::Rectangle(Point(), Size(nSymbolHeight
, nSymbolHeight
));
287 ImplCalcSymbolRect(aSymbol
);
288 aRect
.AdjustLeft(3 * nSymbolHeight
/ 2 );
289 aTSSize
.setWidth( 3 * nSymbolHeight
/ 2 );
293 aSymbol
= tools::Rectangle(Point(), rSize
);
294 ImplCalcSymbolRect(aSymbol
);
295 aTSSize
.setWidth( aSymbol
.GetWidth() );
297 aTSSize
.setHeight( aSymbol
.GetHeight() );
298 aSymbolSize
= aSymbol
.GetSize();
303 if ((eImageAlign
== ImageAlign::LeftTop
) ||
304 (eImageAlign
== ImageAlign::Left
) ||
305 (eImageAlign
== ImageAlign::LeftBottom
) ||
306 (eImageAlign
== ImageAlign::RightTop
) ||
307 (eImageAlign
== ImageAlign::Right
) ||
308 (eImageAlign
== ImageAlign::RightBottom
))
310 aRect
.AdjustRight( -sal_Int32(aImageSize
.Width() + nImageSep
) );
312 else if ((eImageAlign
== ImageAlign::TopLeft
) ||
313 (eImageAlign
== ImageAlign::Top
) ||
314 (eImageAlign
== ImageAlign::TopRight
) ||
315 (eImageAlign
== ImageAlign::BottomLeft
) ||
316 (eImageAlign
== ImageAlign::Bottom
) ||
317 (eImageAlign
== ImageAlign::BottomRight
))
319 aRect
.AdjustBottom( -sal_Int32(aImageSize
.Height() + nImageSep
) );
322 aRect
= GetControlTextRect(*pDev
, aRect
, aText
, nTextStyle
, &aDeviceTextSize
);
323 aTextSize
= aRect
.GetSize();
325 aTSSize
.AdjustWidth(aTextSize
.Width() );
327 if (aTSSize
.Height() < aTextSize
.Height())
328 aTSSize
.setHeight( aTextSize
.Height() );
330 if (bAddImageSep
&& bDrawImage
)
332 long nDiff
= (aImageSize
.Height() - aTextSize
.Height()) / 3;
338 aMax
.setWidth( std::max(aTSSize
.Width(), aImageSize
.Width()) );
339 aMax
.setHeight( std::max(aTSSize
.Height(), aImageSize
.Height()) );
341 // Now calculate the output area for the image and the text according to the image align flags
343 if ((eImageAlign
== ImageAlign::Left
) ||
344 (eImageAlign
== ImageAlign::Right
))
346 aImagePos
.setY( rPos
.Y() + (aMax
.Height() - aImageSize
.Height()) / 2 );
347 aTextPos
.setY( rPos
.Y() + (aMax
.Height() - aTSSize
.Height()) / 2 );
349 else if ((eImageAlign
== ImageAlign::LeftBottom
) ||
350 (eImageAlign
== ImageAlign::RightBottom
))
352 aImagePos
.setY( rPos
.Y() + aMax
.Height() - aImageSize
.Height() );
353 aTextPos
.setY( rPos
.Y() + aMax
.Height() - aTSSize
.Height() );
355 else if ((eImageAlign
== ImageAlign::Top
) ||
356 (eImageAlign
== ImageAlign::Bottom
))
358 aImagePos
.setX( rPos
.X() + (aMax
.Width() - aImageSize
.Width()) / 2 );
359 aTextPos
.setX( rPos
.X() + (aMax
.Width() - aTSSize
.Width()) / 2 );
361 else if ((eImageAlign
== ImageAlign::TopRight
) ||
362 (eImageAlign
== ImageAlign::BottomRight
))
364 aImagePos
.setX( rPos
.X() + aMax
.Width() - aImageSize
.Width() );
365 aTextPos
.setX( rPos
.X() + aMax
.Width() - aTSSize
.Width() );
368 if ((eImageAlign
== ImageAlign::LeftTop
) ||
369 (eImageAlign
== ImageAlign::Left
) ||
370 (eImageAlign
== ImageAlign::LeftBottom
))
372 aTextPos
.setX( rPos
.X() + aImageSize
.Width() + nImageSep
);
374 else if ((eImageAlign
== ImageAlign::RightTop
) ||
375 (eImageAlign
== ImageAlign::Right
) ||
376 (eImageAlign
== ImageAlign::RightBottom
))
378 aImagePos
.setX( rPos
.X() + aTSSize
.Width() + nImageSep
);
380 else if ((eImageAlign
== ImageAlign::TopLeft
) ||
381 (eImageAlign
== ImageAlign::Top
) ||
382 (eImageAlign
== ImageAlign::TopRight
))
384 aTextPos
.setY( rPos
.Y() + aImageSize
.Height() + nImageSep
);
386 else if ((eImageAlign
== ImageAlign::BottomLeft
) ||
387 (eImageAlign
== ImageAlign::Bottom
) ||
388 (eImageAlign
== ImageAlign::BottomRight
))
390 aImagePos
.setY( rPos
.Y() + aTSSize
.Height() + nImageSep
);
392 else if (eImageAlign
== ImageAlign::Center
)
394 aImagePos
.setX( rPos
.X() + (aMax
.Width() - aImageSize
.Width()) / 2 );
395 aImagePos
.setY( rPos
.Y() + (aMax
.Height() - aImageSize
.Height()) / 2 );
396 aTextPos
.setX( rPos
.X() + (aMax
.Width() - aTSSize
.Width()) / 2 );
397 aTextPos
.setY( rPos
.Y() + (aMax
.Height() - aTSSize
.Height()) / 2 );
399 aUnion
= tools::Rectangle(aImagePos
, aImageSize
);
400 aUnion
.Union(tools::Rectangle(aTextPos
, aTSSize
));
403 // Now place the combination of text and image in the output area of the button
404 // according to the window style (WinBits)
408 if (nWinStyle
& WB_CENTER
)
410 nXOffset
= (rSize
.Width() - aUnion
.GetWidth()) / 2;
412 else if (nWinStyle
& WB_RIGHT
)
414 nXOffset
= rSize
.Width() - aUnion
.GetWidth();
417 if (nWinStyle
& WB_VCENTER
)
419 nYOffset
= (rSize
.Height() - aUnion
.GetHeight()) / 2;
421 else if (nWinStyle
& WB_BOTTOM
)
423 nYOffset
= rSize
.Height() - aUnion
.GetHeight();
426 // the top left corner should always be visible, so we don't allow negative offsets
427 if (nXOffset
< 0) nXOffset
= 0;
428 if (nYOffset
< 0) nYOffset
= 0;
430 aImagePos
.AdjustX(nXOffset
);
431 aImagePos
.AdjustY(nYOffset
);
432 aTextPos
.AdjustX(nXOffset
);
433 aTextPos
.AdjustY(nYOffset
);
435 // set rPos and rSize to the union
436 rSize
= aUnion
.GetSize();
437 rPos
.AdjustX(nXOffset
);
438 rPos
.AdjustY(nYOffset
);
442 if (mpButtonData
->meSymbolAlign
== SymbolAlign::RIGHT
)
444 Point
aRightPos(aTextPos
.X() + aTextSize
.Width() + aSymbolSize
.Width() / 2, aTextPos
.Y());
445 *pSymbolRect
= tools::Rectangle(aRightPos
, aSymbolSize
);
449 *pSymbolRect
= tools::Rectangle(aTextPos
, aSymbolSize
);
450 aTextPos
.AdjustX(3 * nSymbolHeight
/ 2 );
452 if (mpButtonData
->mbSmallSymbol
)
454 nYOffset
= (aUnion
.GetHeight() - aSymbolSize
.Height()) / 2;
455 pSymbolRect
->setY(aTextPos
.Y() + nYOffset
);
459 DrawImageFlags nStyle
= DrawImageFlags::NONE
;
463 nStyle
|= DrawImageFlags::Disable
;
467 pDev
->DrawImage(aImagePos
, aImageSize
, *pImage
, nStyle
);
469 pDev
->DrawImage(aImagePos
, *pImage
, nStyle
);
473 const tools::Rectangle
aTOutRect(aTextPos
, aTextSize
);
474 ImplSetFocusRect(aTOutRect
);
475 DrawControlText(*pDev
, aTOutRect
, aText
, nTextStyle
, nullptr, nullptr, &aDeviceTextSize
);
479 ImplSetFocusRect(tools::Rectangle(aImagePos
, aImageSize
));
483 void Button::ImplSetFocusRect(const tools::Rectangle
&rFocusRect
)
485 tools::Rectangle aFocusRect
= rFocusRect
;
486 tools::Rectangle
aOutputRect(Point(), GetOutputSizePixel());
488 if (!aFocusRect
.IsEmpty())
490 aFocusRect
.AdjustLeft( -1 );
491 aFocusRect
.AdjustTop( -1 );
492 aFocusRect
.AdjustRight( 1 );
493 aFocusRect
.AdjustBottom( 1 );
496 if (aFocusRect
.Left() < aOutputRect
.Left())
497 aFocusRect
.SetLeft( aOutputRect
.Left() );
498 if (aFocusRect
.Top() < aOutputRect
.Top())
499 aFocusRect
.SetTop( aOutputRect
.Top() );
500 if (aFocusRect
.Right() > aOutputRect
.Right())
501 aFocusRect
.SetRight( aOutputRect
.Right() );
502 if (aFocusRect
.Bottom() > aOutputRect
.Bottom())
503 aFocusRect
.SetBottom( aOutputRect
.Bottom() );
505 mpButtonData
->maFocusRect
= aFocusRect
;
508 const tools::Rectangle
& Button::ImplGetFocusRect() const
510 return mpButtonData
->maFocusRect
;
513 DrawButtonFlags
& Button::ImplGetButtonState()
515 return mpButtonData
->mnButtonState
;
518 DrawButtonFlags
Button::ImplGetButtonState() const
520 return mpButtonData
->mnButtonState
;
523 void Button::ImplSetSymbolAlign( SymbolAlign eAlign
)
525 if ( mpButtonData
->meSymbolAlign
!= eAlign
)
527 mpButtonData
->meSymbolAlign
= eAlign
;
528 StateChanged( StateChangedType::Data
);
532 void Button::SetSmallSymbol()
534 mpButtonData
->mbSmallSymbol
= true;
537 bool Button::IsSmallSymbol () const
539 return mpButtonData
->mbSmallSymbol
;
542 bool Button::set_property(const OString
&rKey
, const OUString
&rValue
)
544 if (rKey
== "image-position")
546 ImageAlign eAlign
= ImageAlign::Left
;
547 if (rValue
== "left")
548 eAlign
= ImageAlign::Left
;
549 else if (rValue
== "right")
550 eAlign
= ImageAlign::Right
;
551 else if (rValue
== "top")
552 eAlign
= ImageAlign::Top
;
553 else if (rValue
== "bottom")
554 eAlign
= ImageAlign::Bottom
;
555 SetImageAlign(eAlign
);
557 else if (rKey
== "focus-on-click")
559 WinBits nBits
= GetStyle();
560 nBits
&= ~WB_NOPOINTERFOCUS
;
562 nBits
|= WB_NOPOINTERFOCUS
;
566 return Control::set_property(rKey
, rValue
);
570 void Button::statusChanged(const css::frame::FeatureStateEvent
& rEvent
)
572 Enable(rEvent
.IsEnabled
);
575 FactoryFunction
Button::GetUITestFactory() const
577 return ButtonUIObject::create
;
580 IMPL_STATIC_LINK( Button
, dispatchCommandHandler
, Button
*, pButton
, void )
582 if (pButton
== nullptr)
585 comphelper::dispatchCommand(pButton
->maCommand
, uno::Sequence
<beans::PropertyValue
>());
588 void PushButton::ImplInitPushButtonData()
590 mpWindowImpl
->mbPushButton
= true;
592 meSymbol
= SymbolType::DONTKNOW
;
593 meState
= TRISTATE_FALSE
;
594 mnDDStyle
= PushButtonDropdownStyle::NONE
;
602 vcl::Window
* getPreviousSibling(vcl::Window
const *pParent
)
604 return pParent
? pParent
->GetWindow(GetWindowType::LastChild
) : nullptr;
608 void PushButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
610 nStyle
= ImplInitStyle(getPreviousSibling(pParent
), nStyle
);
611 Button::ImplInit( pParent
, nStyle
, nullptr );
613 if ( nStyle
& WB_NOLIGHTBORDER
)
614 ImplGetButtonState() |= DrawButtonFlags::NoLightBorder
;
616 ImplInitSettings( true );
619 WinBits
PushButton::ImplInitStyle( const vcl::Window
* pPrevWindow
, WinBits nStyle
)
621 if ( !(nStyle
& WB_NOTABSTOP
) )
622 nStyle
|= WB_TABSTOP
;
624 // if no alignment is given, default to "vertically centered". This is because since
625 // #i26046#, we respect the vertical alignment flags (previously we didn't completely),
626 // but we of course want to look as before when no vertical alignment is specified
627 if ( ( nStyle
& ( WB_TOP
| WB_VCENTER
| WB_BOTTOM
) ) == 0 )
628 nStyle
|= WB_VCENTER
;
630 if ( !(nStyle
& WB_NOGROUP
) &&
632 ((pPrevWindow
->GetType() != WindowType::PUSHBUTTON
) &&
633 (pPrevWindow
->GetType() != WindowType::OKBUTTON
) &&
634 (pPrevWindow
->GetType() != WindowType::CANCELBUTTON
) &&
635 (pPrevWindow
->GetType() != WindowType::HELPBUTTON
)) ) )
640 const vcl::Font
& PushButton::GetCanonicalFont( const StyleSettings
& _rStyle
) const
642 return _rStyle
.GetPushButtonFont();
645 const Color
& PushButton::GetCanonicalTextColor( const StyleSettings
& _rStyle
) const
647 return _rStyle
.GetButtonTextColor();
650 void PushButton::ImplInitSettings( bool bBackground
)
652 Button::ImplInitSettings();
657 // #i38498#: do not check for GetParent()->IsChildTransparentModeEnabled()
658 // otherwise the formcontrol button will be overdrawn due to ParentClipMode::NoClip
659 // for radio and checkbox this is ok as they should appear transparent in documents
660 if ( IsNativeControlSupported( ControlType::Pushbutton
, ControlPart::Entire
) ||
661 (GetStyle() & WB_FLATBUTTON
) != 0 )
663 EnableChildTransparentMode();
664 SetParentClipMode( ParentClipMode::NoClip
);
665 SetPaintTransparent( true );
667 if ((GetStyle() & WB_FLATBUTTON
) == 0)
668 mpWindowImpl
->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
670 mpWindowImpl
->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRectsForFlatButtons
;
674 EnableChildTransparentMode( false );
676 SetPaintTransparent( false );
681 void PushButton::ImplDrawPushButtonFrame(vcl::RenderContext
& rRenderContext
,
682 tools::Rectangle
& rRect
, DrawButtonFlags nStyle
)
684 if (!(GetStyle() & (WB_RECTSTYLE
| WB_SMALLSTYLE
)))
686 StyleSettings aStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
687 if (IsControlBackground())
688 aStyleSettings
.Set3DColors(GetControlBackground());
691 DecorationView
aDecoView(&rRenderContext
);
692 if (IsControlBackground())
694 AllSettings aSettings
= rRenderContext
.GetSettings();
695 AllSettings aOldSettings
= aSettings
;
696 StyleSettings aStyleSettings
= aSettings
.GetStyleSettings();
697 aStyleSettings
.Set3DColors(GetControlBackground());
698 aSettings
.SetStyleSettings(aStyleSettings
);
700 // Call OutputDevice::SetSettings() explicitly, as rRenderContext may
701 // be a vcl::Window in fact, and vcl::Window::SetSettings() will call
702 // Invalidate(), which is a problem, since we're in Paint().
703 rRenderContext
.OutputDevice::SetSettings(aSettings
);
704 rRect
= aDecoView
.DrawButton(rRect
, nStyle
);
705 rRenderContext
.OutputDevice::SetSettings(aOldSettings
);
708 rRect
= aDecoView
.DrawButton(rRect
, nStyle
);
711 bool PushButton::ImplHitTestPushButton( vcl::Window
const * pDev
,
714 tools::Rectangle
aTestRect( Point(), pDev
->GetOutputSizePixel() );
716 return aTestRect
.IsInside( rPos
);
719 DrawTextFlags
PushButton::ImplGetTextStyle( DrawFlags nDrawFlags
) const
721 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
723 DrawTextFlags nTextStyle
= DrawTextFlags::Mnemonic
| DrawTextFlags::MultiLine
| DrawTextFlags::EndEllipsis
;
725 if ( ( rStyleSettings
.GetOptions() & StyleSettingsOptions::Mono
) ||
726 ( nDrawFlags
& DrawFlags::Mono
) )
727 nTextStyle
|= DrawTextFlags::Mono
;
729 if ( GetStyle() & WB_WORDBREAK
)
730 nTextStyle
|= DrawTextFlags::WordBreak
;
731 if ( GetStyle() & WB_NOLABEL
)
732 nTextStyle
&= ~DrawTextFlags::Mnemonic
;
734 if ( GetStyle() & WB_LEFT
)
735 nTextStyle
|= DrawTextFlags::Left
;
736 else if ( GetStyle() & WB_RIGHT
)
737 nTextStyle
|= DrawTextFlags::Right
;
739 nTextStyle
|= DrawTextFlags::Center
;
741 if ( GetStyle() & WB_TOP
)
742 nTextStyle
|= DrawTextFlags::Top
;
743 else if ( GetStyle() & WB_BOTTOM
)
744 nTextStyle
|= DrawTextFlags::Bottom
;
746 nTextStyle
|= DrawTextFlags::VCenter
;
749 nTextStyle
|= DrawTextFlags::Disable
;
754 static void ImplDrawBtnDropDownArrow( OutputDevice
* pDev
,
756 Color
const & rColor
, bool bBlack
)
758 Color aOldLineColor
= pDev
->GetLineColor();
759 Color aOldFillColor
= pDev
->GetFillColor();
761 pDev
->SetLineColor();
763 pDev
->SetFillColor( COL_BLACK
);
765 pDev
->SetFillColor( rColor
);
766 pDev
->DrawRect( tools::Rectangle( nX
+0, nY
+0, nX
+6, nY
+0 ) );
767 pDev
->DrawRect( tools::Rectangle( nX
+1, nY
+1, nX
+5, nY
+1 ) );
768 pDev
->DrawRect( tools::Rectangle( nX
+2, nY
+2, nX
+4, nY
+2 ) );
769 pDev
->DrawRect( tools::Rectangle( nX
+3, nY
+3, nX
+3, nY
+3 ) );
772 pDev
->SetFillColor( rColor
);
773 pDev
->DrawRect( tools::Rectangle( nX
+2, nY
+1, nX
+4, nY
+1 ) );
774 pDev
->DrawRect( tools::Rectangle( nX
+3, nY
+2, nX
+3, nY
+2 ) );
776 pDev
->SetLineColor( aOldLineColor
);
777 pDev
->SetFillColor( aOldFillColor
);
780 void PushButton::ImplDrawPushButtonContent(OutputDevice
* pDev
, DrawFlags nDrawFlags
,
781 const tools::Rectangle
& rRect
, bool bMenuBtnSep
,
782 DrawButtonFlags nButtonFlags
)
784 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
785 tools::Rectangle aInRect
= rRect
;
787 DrawTextFlags nTextStyle
= ImplGetTextStyle( nDrawFlags
);
788 DrawSymbolFlags nStyle
;
790 if( aInRect
.Right() < aInRect
.Left() || aInRect
.Bottom() < aInRect
.Top() )
791 return; // nothing to do
793 pDev
->Push( PushFlags::CLIPREGION
);
794 pDev
->IntersectClipRegion( aInRect
);
796 if ( nDrawFlags
& DrawFlags::Mono
)
799 else if ((nButtonFlags
& DrawButtonFlags::Default
) && !(GetStyle() & WB_FLATBUTTON
))
801 // Make text color white if the button is a default control on macOS.
802 // Without this you get a button with a blue background and blue text
803 // which stands out as not looking right on macOS where default buttons
804 // have white text and a blue background.
808 else if( (nButtonFlags
& DrawButtonFlags::Highlight
) && IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Entire
) )
810 if (nButtonFlags
& DrawButtonFlags::Pressed
)
811 aColor
= rStyleSettings
.GetButtonPressedRolloverTextColor();
813 aColor
= rStyleSettings
.GetButtonRolloverTextColor();
815 else if ( IsControlForeground() )
816 aColor
= GetControlForeground();
817 else if( nButtonFlags
& DrawButtonFlags::Highlight
)
819 if (nButtonFlags
& DrawButtonFlags::Pressed
)
820 aColor
= rStyleSettings
.GetButtonPressedRolloverTextColor();
822 aColor
= rStyleSettings
.GetButtonRolloverTextColor();
825 aColor
= rStyleSettings
.GetButtonTextColor();
827 pDev
->SetTextColor( aColor
);
830 nStyle
= DrawSymbolFlags::NONE
;
832 nStyle
= DrawSymbolFlags::Disable
;
834 Size aSize
= rRect
.GetSize();
835 Point aPos
= rRect
.TopLeft();
837 sal_uLong nImageSep
= 1 + (pDev
->GetTextHeight()-10)/2;
840 if ( mnDDStyle
== PushButtonDropdownStyle::MenuButton
||
841 mnDDStyle
== PushButtonDropdownStyle::SplitMenuButton
)
843 long nSeparatorX
= 0;
844 tools::Rectangle aSymbolRect
= aInRect
;
846 // calculate symbol size
847 long nSymbolSize
= pDev
->GetTextHeight() / 2 + 1;
849 nSeparatorX
= aInRect
.Right() - 2*nSymbolSize
;
850 aSize
.AdjustWidth( -(2*nSymbolSize
) );
852 // center symbol rectangle in the separated area
853 aSymbolRect
.AdjustRight( -(nSymbolSize
/2) );
854 aSymbolRect
.SetLeft( aSymbolRect
.Right() - nSymbolSize
);
856 ImplDrawAlignedImage( pDev
, aPos
, aSize
, nImageSep
,
857 nTextStyle
, nullptr, true );
859 long nDistance
= (aSymbolRect
.GetHeight() > 10) ? 2 : 1;
860 DecorationView
aDecoView( pDev
);
861 if( bMenuBtnSep
&& nSeparatorX
> 0 )
863 Point
aStartPt( nSeparatorX
, aSymbolRect
.Top()+nDistance
);
864 Point
aEndPt( nSeparatorX
, aSymbolRect
.Bottom()-nDistance
);
865 aDecoView
.DrawSeparator( aStartPt
, aEndPt
);
867 ImplSetSeparatorX( nSeparatorX
);
869 aDecoView
.DrawSymbol( aSymbolRect
, SymbolType::SPIN_DOWN
, aColor
, nStyle
);
874 tools::Rectangle aSymbolRect
;
875 ImplDrawAlignedImage( pDev
, aPos
, aSize
, nImageSep
,
876 nTextStyle
, IsSymbol() ? &aSymbolRect
: nullptr, true );
880 DecorationView
aDecoView( pDev
);
881 aDecoView
.DrawSymbol( aSymbolRect
, meSymbol
, aColor
, nStyle
);
884 if ( mnDDStyle
== PushButtonDropdownStyle::Toolbox
)
887 Color
aArrowColor( COL_BLACK
);
889 if ( !(nDrawFlags
& DrawFlags::Mono
) )
892 aArrowColor
= rStyleSettings
.GetShadowColor();
895 aArrowColor
= COL_LIGHTGREEN
;
900 ImplDrawBtnDropDownArrow( pDev
, aInRect
.Right()-6, aInRect
.Top()+1,
901 aArrowColor
, bBlack
);
905 pDev
->Pop(); // restore clipregion
908 void PushButton::ImplDrawPushButton(vcl::RenderContext
& rRenderContext
)
912 DrawButtonFlags nButtonStyle
= ImplGetButtonState();
913 Size
aOutSz(GetOutputSizePixel());
914 tools::Rectangle
aRect(Point(), aOutSz
);
915 tools::Rectangle aInRect
= aRect
;
916 bool bNativeOK
= false;
918 // adjust style if button should be rendered 'pressed'
919 if (mbPressed
|| mbIsActive
)
920 nButtonStyle
|= DrawButtonFlags::Pressed
;
922 // TODO: move this to Window class or make it a member !!!
923 ControlType aCtrlType
= ControlType::Generic
;
924 switch(GetParent()->GetType())
926 case WindowType::LISTBOX
:
927 case WindowType::MULTILISTBOX
:
928 case WindowType::TREELISTBOX
:
929 aCtrlType
= ControlType::Listbox
;
932 case WindowType::COMBOBOX
:
933 case WindowType::PATTERNBOX
:
934 case WindowType::NUMERICBOX
:
935 case WindowType::METRICBOX
:
936 case WindowType::CURRENCYBOX
:
937 case WindowType::DATEBOX
:
938 case WindowType::TIMEBOX
:
939 case WindowType::LONGCURRENCYBOX
:
940 aCtrlType
= ControlType::Combobox
;
946 bool bDropDown
= (IsSymbol() && (GetSymbol() == SymbolType::SPIN_DOWN
) && GetText().isEmpty());
948 if( bDropDown
&& (aCtrlType
== ControlType::Combobox
|| aCtrlType
== ControlType::Listbox
))
950 if (GetParent()->IsNativeControlSupported(aCtrlType
, ControlPart::Entire
))
952 // skip painting if the button was already drawn by the theme
953 if (aCtrlType
== ControlType::Combobox
)
955 Edit
* pEdit
= static_cast<Edit
*>(GetParent());
956 if (pEdit
->ImplUseNativeBorder(rRenderContext
, pEdit
->GetStyle()))
959 else if (GetParent()->IsNativeControlSupported(aCtrlType
, ControlPart::HasBackgroundTexture
))
964 if (!bNativeOK
&& GetParent()->IsNativeControlSupported(aCtrlType
, ControlPart::ButtonDown
))
966 // let the theme draw it, note we then need support
967 // for ControlType::Listbox/ControlPart::ButtonDown and ControlType::Combobox/ControlPart::ButtonDown
969 ImplControlValue aControlValue
;
970 ControlState nState
= ControlState::NONE
;
972 if (mbPressed
|| mbIsActive
)
973 nState
|= ControlState::PRESSED
;
974 if (ImplGetButtonState() & DrawButtonFlags::Pressed
)
975 nState
|= ControlState::PRESSED
;
977 nState
|= ControlState::FOCUSED
;
978 if (ImplGetButtonState() & DrawButtonFlags::Default
)
979 nState
|= ControlState::DEFAULT
;
980 if (Window::IsEnabled())
981 nState
|= ControlState::ENABLED
;
983 if (IsMouseOver() && aInRect
.IsInside(GetPointerPosPixel()))
984 nState
|= ControlState::ROLLOVER
;
986 if ( IsMouseOver() && aInRect
.IsInside(GetPointerPosPixel()) && mbIsActive
)
988 nState
|= ControlState::ROLLOVER
;
989 nButtonStyle
&= ~DrawButtonFlags::Pressed
;
992 bNativeOK
= rRenderContext
.DrawNativeControl(aCtrlType
, ControlPart::ButtonDown
, aInRect
, nState
,
993 aControlValue
, OUString());
1001 bool bRollOver
= (IsMouseOver() && aInRect
.IsInside(GetPointerPosPixel()));
1003 nButtonStyle
|= DrawButtonFlags::Highlight
;
1004 bool bDrawMenuSep
= mnDDStyle
== PushButtonDropdownStyle::SplitMenuButton
;
1005 if (GetStyle() & WB_FLATBUTTON
)
1007 if (!bRollOver
&& !HasFocus())
1008 bDrawMenuSep
= false;
1010 // tdf#123175 if there is a custom control bg set, draw the button without outsourcing to the NWF
1011 bNativeOK
= !IsControlBackground() && rRenderContext
.IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Entire
);
1014 PushButtonValue aControlValue
;
1015 aControlValue
.mbIsAction
= isAction();
1017 tools::Rectangle
aCtrlRegion(aInRect
);
1018 ControlState nState
= ControlState::NONE
;
1020 if (mbPressed
|| IsChecked() || mbIsActive
)
1022 nState
|= ControlState::PRESSED
;
1023 nButtonStyle
|= DrawButtonFlags::Pressed
;
1025 if (ImplGetButtonState() & DrawButtonFlags::Pressed
)
1026 nState
|= ControlState::PRESSED
;
1028 nState
|= ControlState::FOCUSED
;
1029 if (ImplGetButtonState() & DrawButtonFlags::Default
)
1030 nState
|= ControlState::DEFAULT
;
1031 if (Window::IsEnabled())
1032 nState
|= ControlState::ENABLED
;
1034 if (bRollOver
|| mbIsActive
)
1036 nButtonStyle
|= DrawButtonFlags::Highlight
;
1037 nState
|= ControlState::ROLLOVER
;
1040 if (mbIsActive
&& bRollOver
)
1042 nState
&= ~ControlState::PRESSED
;
1043 nButtonStyle
&= ~DrawButtonFlags::Pressed
;
1046 if (GetStyle() & WB_BEVELBUTTON
)
1047 aControlValue
.mbBevelButton
= true;
1049 // draw frame into invisible window to have aInRect modified correctly
1050 // but do not shift the inner rect for pressed buttons (ie remove DrawButtonFlags::Pressed)
1051 // this assumes the theme has enough visual cues to signalize the button was pressed
1052 //Window aWin( this );
1053 //ImplDrawPushButtonFrame( &aWin, aInRect, nButtonStyle & ~DrawButtonFlags::Pressed );
1055 // looks better this way as symbols were displaced slightly using the above approach
1056 aInRect
.AdjustTop(4 );
1057 aInRect
.AdjustBottom( -4 );
1058 aInRect
.AdjustLeft(4 );
1059 aInRect
.AdjustRight( -4 );
1061 // prepare single line hint (needed on mac to decide between normal push button and
1062 // rectangular bevel button look)
1063 Size
aFontSize(Application::GetSettings().GetStyleSettings().GetPushButtonFont().GetFontSize());
1064 aFontSize
= rRenderContext
.LogicToPixel(aFontSize
, MapMode(MapUnit::MapPoint
));
1065 Size
aInRectSize(rRenderContext
.LogicToPixel(Size(aInRect
.GetWidth(), aInRect
.GetHeight())));
1066 aControlValue
.mbSingleLine
= (aInRectSize
.Height() < 2 * aFontSize
.Height());
1068 if ((nState
& ControlState::ROLLOVER
) || !(GetStyle() & WB_FLATBUTTON
))
1070 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Pushbutton
, ControlPart::Entire
, aCtrlRegion
, nState
,
1071 aControlValue
, OUString() /*PushButton::GetText()*/);
1078 // draw content using the same aInRect as non-native VCL would do
1079 ImplDrawPushButtonContent(&rRenderContext
, DrawFlags::NONE
,
1080 aInRect
, bDrawMenuSep
, nButtonStyle
);
1083 ShowFocus(ImplGetFocusRect());
1088 // draw PushButtonFrame, aInRect has content size afterwards
1089 if (GetStyle() & WB_FLATBUTTON
)
1091 tools::Rectangle
aTempRect(aInRect
);
1093 ImplDrawPushButtonFrame(rRenderContext
, aTempRect
, nButtonStyle
);
1094 aInRect
.AdjustLeft(2 );
1095 aInRect
.AdjustTop(2 );
1096 aInRect
.AdjustRight( -2 );
1097 aInRect
.AdjustBottom( -2 );
1101 ImplDrawPushButtonFrame(rRenderContext
, aInRect
, nButtonStyle
);
1105 ImplDrawPushButtonContent(&rRenderContext
, DrawFlags::NONE
, aInRect
, bDrawMenuSep
, nButtonStyle
);
1109 ShowFocus(ImplGetFocusRect());
1114 void PushButton::ImplSetDefButton( bool bSet
)
1116 Size
aSize( GetSizePixel() );
1117 Point
aPos( GetPosPixel() );
1118 int dLeft(0), dRight(0), dTop(0), dBottom(0);
1119 bool bSetPos
= false;
1121 if ( IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Entire
) )
1123 tools::Rectangle aBound
, aCont
;
1124 tools::Rectangle
aCtrlRegion( 0, 0, 80, 20 ); // use a constant size to avoid accumulating
1125 // will not work if the theme has dynamic adornment sizes
1126 ImplControlValue aControlValue
;
1128 // get native size of a 'default' button
1129 // and adjust the VCL button if more space for adornment is required
1130 if( GetNativeControlRegion( ControlType::Pushbutton
, ControlPart::Entire
, aCtrlRegion
,
1131 ControlState::DEFAULT
|ControlState::ENABLED
,
1135 dLeft
= aCont
.Left() - aBound
.Left();
1136 dTop
= aCont
.Top() - aBound
.Top();
1137 dRight
= aBound
.Right() - aCont
.Right();
1138 dBottom
= aBound
.Bottom() - aCont
.Bottom();
1139 bSetPos
= dLeft
|| dTop
|| dRight
|| dBottom
;
1145 if( !(ImplGetButtonState() & DrawButtonFlags::Default
) && bSetPos
)
1147 // adjust pos/size when toggling from non-default to default
1148 aPos
.Move(-dLeft
, -dTop
);
1149 aSize
.AdjustWidth(dLeft
+ dRight
);
1150 aSize
.AdjustHeight(dTop
+ dBottom
);
1152 ImplGetButtonState() |= DrawButtonFlags::Default
;
1156 if( (ImplGetButtonState() & DrawButtonFlags::Default
) && bSetPos
)
1158 // adjust pos/size when toggling from default to non-default
1159 aPos
.Move(dLeft
, dTop
);
1160 aSize
.AdjustWidth( -(dLeft
+ dRight
) );
1161 aSize
.AdjustHeight( -(dTop
+ dBottom
) );
1163 ImplGetButtonState() &= ~DrawButtonFlags::Default
;
1166 setPosSizePixel( aPos
.X(), aPos
.Y(), aSize
.Width(), aSize
.Height() );
1171 bool PushButton::ImplIsDefButton() const
1173 return bool(ImplGetButtonState() & DrawButtonFlags::Default
);
1176 PushButton::PushButton( WindowType nType
) :
1179 ImplInitPushButtonData();
1182 PushButton::PushButton( vcl::Window
* pParent
, WinBits nStyle
) :
1183 Button( WindowType::PUSHBUTTON
)
1185 ImplInitPushButtonData();
1186 ImplInit( pParent
, nStyle
);
1189 void PushButton::MouseButtonDown( const MouseEvent
& rMEvt
)
1191 if ( rMEvt
.IsLeft() &&
1192 ImplHitTestPushButton( this, rMEvt
.GetPosPixel() ) )
1194 StartTrackingFlags nTrackFlags
= StartTrackingFlags::NONE
;
1196 if ( ( GetStyle() & WB_REPEAT
) &&
1197 ! ( GetStyle() & WB_TOGGLE
) )
1198 nTrackFlags
|= StartTrackingFlags::ButtonRepeat
;
1200 ImplGetButtonState() |= DrawButtonFlags::Pressed
;
1202 StartTracking( nTrackFlags
);
1204 if ( nTrackFlags
& StartTrackingFlags::ButtonRepeat
)
1209 void PushButton::Tracking( const TrackingEvent
& rTEvt
)
1211 if ( rTEvt
.IsTrackingEnded() )
1213 if ( ImplGetButtonState() & DrawButtonFlags::Pressed
)
1215 if ( !(GetStyle() & WB_NOPOINTERFOCUS
) && !rTEvt
.IsTrackingCanceled() )
1218 if ( GetStyle() & WB_TOGGLE
)
1220 // Don't toggle, when aborted
1221 if ( !rTEvt
.IsTrackingCanceled() )
1226 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
1233 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
1237 // do not call Click handler if aborted
1238 if ( !rTEvt
.IsTrackingCanceled() )
1240 if ( ! ( ( GetStyle() & WB_REPEAT
) &&
1241 ! ( GetStyle() & WB_TOGGLE
) ) )
1248 if ( ImplHitTestPushButton( this, rTEvt
.GetMouseEvent().GetPosPixel() ) )
1250 if ( ImplGetButtonState() & DrawButtonFlags::Pressed
)
1252 if ( rTEvt
.IsTrackingRepeat() && (GetStyle() & WB_REPEAT
) &&
1253 ! ( GetStyle() & WB_TOGGLE
) )
1258 ImplGetButtonState() |= DrawButtonFlags::Pressed
;
1264 if ( ImplGetButtonState() & DrawButtonFlags::Pressed
)
1266 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
1273 void PushButton::KeyInput( const KeyEvent
& rKEvt
)
1275 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
1277 if ( !aKeyCode
.GetModifier() &&
1278 ((aKeyCode
.GetCode() == KEY_RETURN
) || (aKeyCode
.GetCode() == KEY_SPACE
)) )
1280 if ( !(ImplGetButtonState() & DrawButtonFlags::Pressed
) )
1282 ImplGetButtonState() |= DrawButtonFlags::Pressed
;
1286 if ( ( GetStyle() & WB_REPEAT
) &&
1287 ! ( GetStyle() & WB_TOGGLE
) )
1290 else if ( (ImplGetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_ESCAPE
) )
1292 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
1296 Button::KeyInput( rKEvt
);
1299 void PushButton::KeyUp( const KeyEvent
& rKEvt
)
1301 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
1303 if ( (ImplGetButtonState() & DrawButtonFlags::Pressed
) &&
1304 ((aKeyCode
.GetCode() == KEY_RETURN
) || (aKeyCode
.GetCode() == KEY_SPACE
)) )
1306 if ( GetStyle() & WB_TOGGLE
)
1311 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
1319 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
1323 if ( !( ( GetStyle() & WB_REPEAT
) &&
1324 ! ( GetStyle() & WB_TOGGLE
) ) )
1328 Button::KeyUp( rKEvt
);
1331 void PushButton::FillLayoutData() const
1333 mpControlData
->mpLayoutData
.reset( new vcl::ControlLayoutData
);
1334 const_cast<PushButton
*>(this)->Invalidate();
1337 void PushButton::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
1339 ImplDrawPushButton(rRenderContext
);
1342 void PushButton::Draw( OutputDevice
* pDev
, const Point
& rPos
, const Size
& rSize
,
1345 Point aPos
= pDev
->LogicToPixel( rPos
);
1346 Size aSize
= pDev
->LogicToPixel( rSize
);
1347 tools::Rectangle
aRect( aPos
, aSize
);
1348 vcl::Font aFont
= GetDrawPixelFont( pDev
);
1352 pDev
->SetFont( aFont
);
1353 if ( nFlags
& DrawFlags::Mono
)
1355 pDev
->SetTextColor( COL_BLACK
);
1359 pDev
->SetTextColor( GetTextColor() );
1361 // DecoView uses the FaceColor...
1362 AllSettings aSettings
= pDev
->GetSettings();
1363 StyleSettings aStyleSettings
= aSettings
.GetStyleSettings();
1364 if ( IsControlBackground() )
1365 aStyleSettings
.SetFaceColor( GetControlBackground() );
1367 aStyleSettings
.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() );
1368 aSettings
.SetStyleSettings( aStyleSettings
);
1369 pDev
->OutputDevice::SetSettings( aSettings
);
1371 pDev
->SetTextFillColor();
1373 DecorationView
aDecoView( pDev
);
1374 DrawButtonFlags nButtonStyle
= DrawButtonFlags::NONE
;
1375 if ( nFlags
& DrawFlags::Mono
)
1376 nButtonStyle
|= DrawButtonFlags::Mono
;
1378 nButtonStyle
|= DrawButtonFlags::Checked
;
1379 aRect
= aDecoView
.DrawButton( aRect
, nButtonStyle
);
1381 ImplDrawPushButtonContent( pDev
, nFlags
, aRect
, true, nButtonStyle
);
1385 void PushButton::Resize()
1391 void PushButton::GetFocus()
1393 ShowFocus( ImplGetFocusRect() );
1394 SetInputContext( InputContext( GetFont() ) );
1398 void PushButton::LoseFocus()
1402 Button::LoseFocus();
1405 void PushButton::StateChanged( StateChangedType nType
)
1407 Button::StateChanged( nType
);
1409 if ( (nType
== StateChangedType::Enable
) ||
1410 (nType
== StateChangedType::Text
) ||
1411 (nType
== StateChangedType::Data
) ||
1412 (nType
== StateChangedType::State
) ||
1413 (nType
== StateChangedType::UpdateMode
) )
1415 if ( IsReallyVisible() && IsUpdateMode() )
1418 else if ( nType
== StateChangedType::Style
)
1420 SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev
), GetStyle() ) );
1422 bool bIsDefButton
= ( GetStyle() & WB_DEFBUTTON
) != 0;
1423 bool bWasDefButton
= ( GetPrevStyle() & WB_DEFBUTTON
) != 0;
1424 if ( bIsDefButton
!= bWasDefButton
)
1425 ImplSetDefButton( bIsDefButton
);
1427 if ( IsReallyVisible() && IsUpdateMode() )
1429 if ( (GetPrevStyle() & PUSHBUTTON_VIEW_STYLE
) !=
1430 (GetStyle() & PUSHBUTTON_VIEW_STYLE
) )
1434 else if ( (nType
== StateChangedType::Zoom
) ||
1435 (nType
== StateChangedType::ControlFont
) )
1437 ImplInitSettings( false );
1440 else if ( nType
== StateChangedType::ControlForeground
)
1442 ImplInitSettings( false );
1445 else if ( nType
== StateChangedType::ControlBackground
)
1447 ImplInitSettings( true );
1452 void PushButton::DataChanged( const DataChangedEvent
& rDCEvt
)
1454 Button::DataChanged( rDCEvt
);
1456 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
1457 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
1458 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
1459 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
1461 ImplInitSettings( true );
1466 bool PushButton::PreNotify( NotifyEvent
& rNEvt
)
1468 const MouseEvent
* pMouseEvt
= nullptr;
1470 if( (rNEvt
.GetType() == MouseNotifyEvent::MOUSEMOVE
) && (pMouseEvt
= rNEvt
.GetMouseEvent()) != nullptr )
1472 if( pMouseEvt
->IsEnterWindow() || pMouseEvt
->IsLeaveWindow() )
1474 // trigger redraw as mouse over state has changed
1476 // TODO: move this to Window class or make it a member !!!
1477 ControlType aCtrlType
= ControlType::Generic
;
1478 switch( GetParent()->GetType() )
1480 case WindowType::LISTBOX
:
1481 case WindowType::MULTILISTBOX
:
1482 case WindowType::TREELISTBOX
:
1483 aCtrlType
= ControlType::Listbox
;
1486 case WindowType::COMBOBOX
:
1487 case WindowType::PATTERNBOX
:
1488 case WindowType::NUMERICBOX
:
1489 case WindowType::METRICBOX
:
1490 case WindowType::CURRENCYBOX
:
1491 case WindowType::DATEBOX
:
1492 case WindowType::TIMEBOX
:
1493 case WindowType::LONGCURRENCYBOX
:
1494 aCtrlType
= ControlType::Combobox
;
1500 bool bDropDown
= ( IsSymbol() && (GetSymbol()==SymbolType::SPIN_DOWN
) && GetText().isEmpty() );
1502 if( bDropDown
&& GetParent()->IsNativeControlSupported( aCtrlType
, ControlPart::Entire
) &&
1503 !GetParent()->IsNativeControlSupported( aCtrlType
, ControlPart::ButtonDown
) )
1505 vcl::Window
*pBorder
= GetParent()->GetWindow( GetWindowType::Border
);
1506 if(aCtrlType
== ControlType::Combobox
)
1508 // only paint the button part to avoid flickering of the combobox text
1509 tools::Rectangle
aClipRect( Point(), GetOutputSizePixel() );
1510 aClipRect
.SetPos(pBorder
->ScreenToOutputPixel(OutputToScreenPixel(aClipRect
.TopLeft())));
1511 pBorder
->Invalidate( aClipRect
);
1515 pBorder
->Invalidate( InvalidateFlags::NoErase
);
1519 else if( (GetStyle() & WB_FLATBUTTON
) ||
1520 IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Entire
) )
1527 return Button::PreNotify(rNEvt
);
1530 void PushButton::Toggle()
1532 ImplCallEventListenersAndHandler( VclEventId::PushbuttonToggle
, nullptr );
1535 void PushButton::SetSymbol( SymbolType eSymbol
)
1537 if ( meSymbol
!= eSymbol
)
1540 CompatStateChanged( StateChangedType::Data
);
1544 void PushButton::SetSymbolAlign( SymbolAlign eAlign
)
1546 ImplSetSymbolAlign( eAlign
);
1549 void PushButton::SetDropDown( PushButtonDropdownStyle nStyle
)
1551 if ( mnDDStyle
!= nStyle
)
1554 CompatStateChanged( StateChangedType::Data
);
1558 void PushButton::SetState( TriState eState
)
1560 if ( meState
!= eState
)
1563 if ( meState
== TRISTATE_FALSE
)
1564 ImplGetButtonState() &= ~DrawButtonFlags(DrawButtonFlags::Checked
| DrawButtonFlags::DontKnow
);
1565 else if ( meState
== TRISTATE_TRUE
)
1567 ImplGetButtonState() &= ~DrawButtonFlags::DontKnow
;
1568 ImplGetButtonState() |= DrawButtonFlags::Checked
;
1570 else // TRISTATE_INDET
1572 ImplGetButtonState() &= ~DrawButtonFlags::Checked
;
1573 ImplGetButtonState() |= DrawButtonFlags::DontKnow
;
1576 CompatStateChanged( StateChangedType::State
);
1581 void PushButton::statusChanged(const css::frame::FeatureStateEvent
& rEvent
)
1583 Button::statusChanged(rEvent
);
1584 if (rEvent
.State
.has
<bool>())
1585 SetPressed(rEvent
.State
.get
<bool>());
1588 void PushButton::SetPressed( bool bPressed
)
1590 if ( mbPressed
!= bPressed
)
1592 mbPressed
= bPressed
;
1593 CompatStateChanged( StateChangedType::Data
);
1597 void PushButton::EndSelection()
1599 EndTracking( TrackingEventFlags::Cancel
);
1600 if ( !IsDisposed() &&
1601 ImplGetButtonState() & DrawButtonFlags::Pressed
)
1603 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
1609 Size
PushButton::CalcMinimumSize() const
1615 if ( IsSmallSymbol ())
1616 aSize
= Size( 16, 12 );
1618 aSize
= Size( 26, 24 );
1620 else if ( Button::HasImage() )
1621 aSize
= GetModeImage().GetSizePixel();
1622 if( mnDDStyle
== PushButtonDropdownStyle::MenuButton
||
1623 mnDDStyle
== PushButtonDropdownStyle::SplitMenuButton
)
1625 long nSymbolSize
= GetTextHeight() / 2 + 1;
1626 aSize
.AdjustWidth(2*nSymbolSize
);
1628 if (!PushButton::GetText().isEmpty())
1630 Size textSize
= GetTextRect( tools::Rectangle( Point(), Size( 0x7fffffff, 0x7fffffff ) ),
1631 PushButton::GetText(), ImplGetTextStyle( DrawFlags::NONE
) ).GetSize();
1632 aSize
.AdjustWidth(textSize
.Width() );
1633 aSize
.setHeight( std::max( aSize
.Height(), long( textSize
.Height() * 1.15 ) ) );
1636 // cf. ImplDrawPushButton ...
1637 if( (GetStyle() & WB_SMALLSTYLE
) == 0 )
1639 aSize
.AdjustWidth(24 );
1640 aSize
.AdjustHeight(12 );
1643 return CalcWindowSize( aSize
);
1646 Size
PushButton::GetOptimalSize() const
1648 return CalcMinimumSize();
1651 bool PushButton::set_property(const OString
&rKey
, const OUString
&rValue
)
1653 if (rKey
== "has-default")
1655 WinBits nBits
= GetStyle();
1656 nBits
&= ~WB_DEFBUTTON
;
1658 nBits
|= WB_DEFBUTTON
;
1662 return Button::set_property(rKey
, rValue
);
1666 void PushButton::ShowFocus(const tools::Rectangle
& rRect
)
1668 if (IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Focus
))
1670 PushButtonValue aControlValue
;
1671 aControlValue
.mbIsAction
= isAction();
1672 tools::Rectangle
aInRect(Point(), GetOutputSizePixel());
1673 GetOutDev()->DrawNativeControl(ControlType::Pushbutton
, ControlPart::Focus
, aInRect
,
1674 ControlState::FOCUSED
, aControlValue
, OUString());
1676 Button::ShowFocus(rRect
);
1679 void OKButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
1682 PushButton::ImplInit( pParent
, nStyle
);
1684 SetText( Button::GetStandardText( StandardButtonType::OK
) );
1687 OKButton::OKButton( vcl::Window
* pParent
, WinBits nStyle
) :
1688 PushButton( WindowType::OKBUTTON
)
1690 ImplInit( pParent
, nStyle
);
1693 void OKButton::Click()
1695 // close parent if no link set
1696 if ( !GetClickHdl() )
1698 vcl::Window
* pParent
= getNonLayoutParent(this);
1699 if ( pParent
->IsSystemWindow() )
1701 if ( pParent
->IsDialog() )
1703 if ( static_cast<Dialog
*>(pParent
)->IsInExecute() )
1704 static_cast<Dialog
*>(pParent
)->EndDialog( RET_OK
);
1705 // prevent recursive calls
1706 else if ( !static_cast<Dialog
*>(pParent
)->IsInClose() )
1708 if ( pParent
->GetStyle() & WB_CLOSEABLE
)
1709 static_cast<Dialog
*>(pParent
)->Close();
1714 if ( pParent
->GetStyle() & WB_CLOSEABLE
)
1715 static_cast<SystemWindow
*>(pParent
)->Close();
1721 PushButton::Click();
1725 void CancelButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
1728 PushButton::ImplInit( pParent
, nStyle
);
1730 SetText( Button::GetStandardText( StandardButtonType::Cancel
) );
1733 CancelButton::CancelButton( vcl::Window
* pParent
, WinBits nStyle
) :
1734 PushButton( WindowType::CANCELBUTTON
)
1736 ImplInit( pParent
, nStyle
);
1739 void CancelButton::Click()
1741 // close parent if link not set
1742 if ( !GetClickHdl() )
1744 vcl::Window
* pParent
= getNonLayoutParent(this);
1745 if ( pParent
->IsSystemWindow() )
1747 if ( pParent
->IsDialog() )
1749 if ( static_cast<Dialog
*>(pParent
)->IsInExecute() )
1750 static_cast<Dialog
*>(pParent
)->EndDialog();
1751 // prevent recursive calls
1752 else if ( !static_cast<Dialog
*>(pParent
)->IsInClose() )
1754 if ( pParent
->GetStyle() & WB_CLOSEABLE
)
1755 static_cast<Dialog
*>(pParent
)->Close();
1760 if ( pParent
->GetStyle() & WB_CLOSEABLE
)
1761 static_cast<SystemWindow
*>(pParent
)->Close();
1767 PushButton::Click();
1771 CloseButton::CloseButton( vcl::Window
* pParent
, WinBits nStyle
)
1772 : CancelButton(pParent
, nStyle
)
1774 SetText( Button::GetStandardText( StandardButtonType::Close
) );
1777 void HelpButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
1780 PushButton::ImplInit( pParent
, nStyle
| WB_NOPOINTERFOCUS
);
1782 SetText( Button::GetStandardText( StandardButtonType::Help
) );
1785 HelpButton::HelpButton( vcl::Window
* pParent
, WinBits nStyle
) :
1786 PushButton( WindowType::HELPBUTTON
)
1788 ImplInit( pParent
, nStyle
);
1791 void HelpButton::Click()
1793 // trigger help if no link set
1794 if ( !GetClickHdl() )
1796 vcl::Window
* pFocusWin
= Application::GetFocusWindow();
1800 HelpEvent
aEvt( pFocusWin
->GetPointerPosPixel(), HelpEventMode::CONTEXT
);
1801 pFocusWin
->RequestHelp( aEvt
);
1803 PushButton::Click();
1806 void HelpButton::StateChanged( StateChangedType nStateChange
)
1808 // Hide when we have no help URL.
1809 if (comphelper::LibreOfficeKit::isActive() &&
1810 officecfg::Office::Common::Help::HelpRootURL::get().isEmpty())
1813 PushButton::StateChanged(nStateChange
);
1816 void RadioButton::ImplInitRadioButtonData()
1819 mbRadioCheck
= true;
1820 mbStateChanged
= false;
1823 void RadioButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
1825 nStyle
= ImplInitStyle(getPreviousSibling(pParent
), nStyle
);
1826 Button::ImplInit( pParent
, nStyle
, nullptr );
1828 ImplInitSettings( true );
1831 WinBits
RadioButton::ImplInitStyle( const vcl::Window
* pPrevWindow
, WinBits nStyle
)
1833 if ( !(nStyle
& WB_NOGROUP
) &&
1834 (!pPrevWindow
|| (pPrevWindow
->GetType() != WindowType::RADIOBUTTON
)) )
1836 if ( !(nStyle
& WB_NOTABSTOP
) )
1837 nStyle
|= WB_TABSTOP
;
1839 if ( IsChecked() && IsRadioCheckEnabled() )
1840 ImplUncheckAllOther( /*bSetStyle=*/false );
1845 const vcl::Font
& RadioButton::GetCanonicalFont( const StyleSettings
& _rStyle
) const
1847 return _rStyle
.GetRadioCheckFont();
1850 const Color
& RadioButton::GetCanonicalTextColor( const StyleSettings
& _rStyle
) const
1852 return _rStyle
.GetRadioCheckTextColor();
1855 void RadioButton::ImplInitSettings( bool bBackground
)
1857 Button::ImplInitSettings();
1861 vcl::Window
* pParent
= GetParent();
1862 if ( !IsControlBackground() &&
1863 (pParent
->IsChildTransparentModeEnabled() || IsNativeControlSupported( ControlType::Radiobutton
, ControlPart::Entire
) ) )
1865 EnableChildTransparentMode();
1866 SetParentClipMode( ParentClipMode::NoClip
);
1867 SetPaintTransparent( true );
1869 if( IsNativeControlSupported( ControlType::Radiobutton
, ControlPart::Entire
) )
1870 mpWindowImpl
->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
1874 EnableChildTransparentMode( false );
1875 SetParentClipMode();
1876 SetPaintTransparent( false );
1878 if ( IsControlBackground() )
1879 SetBackground( GetControlBackground() );
1881 SetBackground( pParent
->GetBackground() );
1886 void RadioButton::ImplDrawRadioButtonState(vcl::RenderContext
& rRenderContext
)
1888 bool bNativeOK
= false;
1890 // no native drawing for image radio buttons
1891 if (!maImage
&& rRenderContext
.IsNativeControlSupported(ControlType::Radiobutton
, ControlPart::Entire
))
1893 ImplControlValue
aControlValue( mbChecked
? ButtonValue::On
: ButtonValue::Off
);
1894 tools::Rectangle
aCtrlRect(maStateRect
.TopLeft(), maStateRect
.GetSize());
1895 ControlState nState
= ControlState::NONE
;
1897 if (ImplGetButtonState() & DrawButtonFlags::Pressed
)
1898 nState
|= ControlState::PRESSED
;
1900 nState
|= ControlState::FOCUSED
;
1901 if (ImplGetButtonState() & DrawButtonFlags::Default
)
1902 nState
|= ControlState::DEFAULT
;
1904 nState
|= ControlState::ENABLED
;
1906 if (IsMouseOver() && maMouseRect
.IsInside(GetPointerPosPixel()))
1907 nState
|= ControlState::ROLLOVER
;
1909 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Radiobutton
, ControlPart::Entire
, aCtrlRect
,
1910 nState
, aControlValue
, OUString());
1917 DrawButtonFlags nStyle
= ImplGetButtonState();
1919 nStyle
|= DrawButtonFlags::Disabled
;
1921 nStyle
|= DrawButtonFlags::Checked
;
1922 Image aImage
= GetRadioImage(rRenderContext
.GetSettings(), nStyle
);
1924 rRenderContext
.DrawImage(maStateRect
.TopLeft(), maStateRect
.GetSize(), aImage
);
1926 rRenderContext
.DrawImage(maStateRect
.TopLeft(), aImage
);
1932 DecorationView
aDecoView(&rRenderContext
);
1933 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
1934 tools::Rectangle aImageRect
= maStateRect
;
1935 Size aImageSize
= maImage
.GetSizePixel();
1936 bool bEnabled
= IsEnabled();
1938 aImageSize
.setWidth( CalcZoom(aImageSize
.Width()) );
1939 aImageSize
.setHeight( CalcZoom(aImageSize
.Height()) );
1941 aImageRect
.AdjustLeft( 1 );
1942 aImageRect
.AdjustTop( 1 );
1943 aImageRect
.AdjustRight( -1 );
1944 aImageRect
.AdjustBottom( -1 );
1946 // display border and selection status
1947 aImageRect
= aDecoView
.DrawFrame(aImageRect
, DrawFrameStyle::DoubleIn
);
1948 if ((ImplGetButtonState() & DrawButtonFlags::Pressed
) || !bEnabled
)
1949 rRenderContext
.SetFillColor( rStyleSettings
.GetFaceColor());
1951 rRenderContext
.SetFillColor(rStyleSettings
.GetFieldColor());
1952 rRenderContext
.SetLineColor();
1953 rRenderContext
.DrawRect(aImageRect
);
1956 DrawImageFlags nImageStyle
= DrawImageFlags::NONE
;
1958 nImageStyle
|= DrawImageFlags::Disable
;
1960 Image
* pImage
= &maImage
;
1962 Point
aImagePos(aImageRect
.TopLeft());
1963 aImagePos
.AdjustX((aImageRect
.GetWidth() - aImageSize
.Width()) / 2 );
1964 aImagePos
.AdjustY((aImageRect
.GetHeight() - aImageSize
.Height()) / 2 );
1966 rRenderContext
.DrawImage(aImagePos
, aImageSize
, *pImage
, nImageStyle
);
1968 rRenderContext
.DrawImage(aImagePos
, *pImage
, nImageStyle
);
1970 aImageRect
.AdjustLeft( 1 );
1971 aImageRect
.AdjustTop( 1 );
1972 aImageRect
.AdjustRight( -1 );
1973 aImageRect
.AdjustBottom( -1 );
1975 ImplSetFocusRect(aImageRect
);
1979 rRenderContext
.SetLineColor(rStyleSettings
.GetHighlightColor());
1980 rRenderContext
.SetFillColor();
1981 if ((aImageSize
.Width() >= 20) || (aImageSize
.Height() >= 20))
1983 aImageRect
.AdjustLeft( 1 );
1984 aImageRect
.AdjustTop( 1 );
1985 aImageRect
.AdjustRight( -1 );
1986 aImageRect
.AdjustBottom( -1 );
1988 rRenderContext
.DrawRect(aImageRect
);
1989 aImageRect
.AdjustLeft( 1 );
1990 aImageRect
.AdjustTop( 1 );
1991 aImageRect
.AdjustRight( -1 );
1992 aImageRect
.AdjustBottom( -1 );
1993 rRenderContext
.DrawRect(aImageRect
);
1997 ShowFocus(ImplGetFocusRect());
2002 void RadioButton::ImplDraw( OutputDevice
* pDev
, DrawFlags nDrawFlags
,
2003 const Point
& rPos
, const Size
& rSize
,
2004 const Size
& rImageSize
, tools::Rectangle
& rStateRect
,
2005 tools::Rectangle
& rMouseRect
)
2007 WinBits nWinStyle
= GetStyle();
2008 OUString
aText( GetText() );
2010 pDev
->Push( PushFlags::CLIPREGION
);
2011 pDev
->IntersectClipRegion( tools::Rectangle( rPos
, rSize
) );
2013 // no image radio button
2016 if (!aText
.isEmpty() || HasImage())
2018 DrawTextFlags nTextStyle
= Button::ImplGetTextStyle( nWinStyle
, nDrawFlags
);
2020 const long nImageSep
= GetDrawPixel( pDev
, ImplGetImageToTextDistance() );
2021 Size
aSize( rSize
);
2023 aPos
.AdjustX(rImageSize
.Width() + nImageSep
);
2024 aSize
.AdjustWidth( -(rImageSize
.Width() + nImageSep
) );
2026 // if the text rect height is smaller than the height of the image
2027 // then for single lines the default should be centered text
2028 if( (nWinStyle
& (WB_TOP
|WB_VCENTER
|WB_BOTTOM
)) == 0 &&
2029 (rImageSize
.Height() > rSize
.Height() || ! (nWinStyle
& WB_WORDBREAK
) ) )
2031 nTextStyle
&= ~DrawTextFlags(DrawTextFlags::Top
|DrawTextFlags::Bottom
);
2032 nTextStyle
|= DrawTextFlags::VCenter
;
2033 aSize
.setHeight( rImageSize
.Height() );
2036 ImplDrawAlignedImage( pDev
, aPos
, aSize
, 1, nTextStyle
);
2038 rMouseRect
= tools::Rectangle(aPos
, aSize
);
2039 rMouseRect
.SetLeft(rPos
.X());
2040 rMouseRect
.SetTop(rPos
.Y());
2042 rStateRect
.SetLeft( rPos
.X() );
2043 rStateRect
.SetTop( rMouseRect
.Top() );
2045 if ( aSize
.Height() > rImageSize
.Height() )
2046 rStateRect
.AdjustTop(( aSize
.Height() - rImageSize
.Height() ) / 2 );
2049 rStateRect
.AdjustTop( -(( rImageSize
.Height() - aSize
.Height() ) / 2) );
2050 if( rStateRect
.Top() < 0 )
2051 rStateRect
.SetTop( 0 );
2054 rStateRect
.SetRight( rStateRect
.Left() + rImageSize
.Width()-1 );
2055 rStateRect
.SetBottom( rStateRect
.Top() + rImageSize
.Height()-1 );
2057 if ( rStateRect
.Bottom() > rMouseRect
.Bottom() )
2058 rMouseRect
.SetBottom( rStateRect
.Bottom() );
2062 rStateRect
.SetLeft( rPos
.X() );
2063 if ( nWinStyle
& WB_VCENTER
)
2064 rStateRect
.SetTop( rPos
.Y()+((rSize
.Height()-rImageSize
.Height())/2) );
2065 else if ( nWinStyle
& WB_BOTTOM
)
2066 rStateRect
.SetTop( rPos
.Y()+rSize
.Height()-rImageSize
.Height() ); //-1;
2068 rStateRect
.SetTop( rPos
.Y() );
2069 rStateRect
.SetRight( rStateRect
.Left()+rImageSize
.Width()-1 );
2070 rStateRect
.SetBottom( rStateRect
.Top()+rImageSize
.Height()-1 );
2071 rMouseRect
= rStateRect
;
2073 ImplSetFocusRect( rStateRect
);
2078 bool bTopImage
= (nWinStyle
& WB_TOP
) != 0;
2079 Size aImageSize
= maImage
.GetSizePixel();
2080 tools::Rectangle
aImageRect( rPos
, rSize
);
2081 long nTextHeight
= pDev
->GetTextHeight();
2082 long nTextWidth
= pDev
->GetCtrlTextWidth( aText
);
2084 // calculate position and sizes
2085 if (!aText
.isEmpty())
2087 Size
aTmpSize( (aImageSize
.Width()+8), (aImageSize
.Height()+8) );
2090 aImageRect
.SetLeft( (rSize
.Width()-aTmpSize
.Width())/2 );
2091 aImageRect
.SetTop( (rSize
.Height()-(aTmpSize
.Height()+nTextHeight
+6))/2 );
2094 aImageRect
.SetTop( (rSize
.Height()-aTmpSize
.Height())/2 );
2096 aImageRect
.SetRight( aImageRect
.Left()+aTmpSize
.Width() );
2097 aImageRect
.SetBottom( aImageRect
.Top()+aTmpSize
.Height() );
2100 Point aTxtPos
= rPos
;
2103 aTxtPos
.AdjustX((rSize
.Width()-nTextWidth
)/2 );
2104 aTxtPos
.AdjustY(aImageRect
.Bottom()+6 );
2108 aTxtPos
.AdjustX(aImageRect
.Right()+8 );
2109 aTxtPos
.AdjustY((rSize
.Height()-nTextHeight
)/2 );
2111 pDev
->DrawCtrlText( aTxtPos
, aText
, 0, aText
.getLength() );
2114 rMouseRect
= aImageRect
;
2115 rStateRect
= aImageRect
;
2121 void RadioButton::ImplDrawRadioButton(vcl::RenderContext
& rRenderContext
)
2127 aImageSize
= ImplGetRadioImageSize();
2129 aImageSize
= maImage
.GetSizePixel();
2131 aImageSize
.setWidth( CalcZoom(aImageSize
.Width()) );
2132 aImageSize
.setHeight( CalcZoom(aImageSize
.Height()) );
2134 // Draw control text
2135 ImplDraw(&rRenderContext
, DrawFlags::NONE
, Point(), GetOutputSizePixel(),
2136 aImageSize
, maStateRect
, maMouseRect
);
2138 if (!maImage
&& HasFocus())
2139 ShowFocus(ImplGetFocusRect());
2141 ImplDrawRadioButtonState(rRenderContext
);
2144 void RadioButton::group(RadioButton
&rOther
)
2146 if (&rOther
== this)
2151 m_xGroup
.reset(new std::vector
<VclPtr
<RadioButton
> >);
2152 m_xGroup
->push_back(this);
2155 auto aFind
= std::find(m_xGroup
->begin(), m_xGroup
->end(), VclPtr
<RadioButton
>(&rOther
));
2156 if (aFind
== m_xGroup
->end())
2158 m_xGroup
->push_back(&rOther
);
2160 if (rOther
.m_xGroup
)
2162 std::vector
< VclPtr
<RadioButton
> > aOthers(rOther
.GetRadioButtonGroup(false));
2163 //make all members of the group share the same button group
2164 for (auto const& elem
: aOthers
)
2166 aFind
= std::find(m_xGroup
->begin(), m_xGroup
->end(), elem
);
2167 if (aFind
== m_xGroup
->end())
2168 m_xGroup
->push_back(elem
);
2172 //make all members of the group share the same button group
2173 for (VclPtr
<RadioButton
> const & pButton
: *m_xGroup
)
2175 pButton
->m_xGroup
= m_xGroup
;
2179 //if this one is checked, uncheck all the others
2181 ImplUncheckAllOther();
2184 std::vector
< VclPtr
<RadioButton
> > RadioButton::GetRadioButtonGroup(bool bIncludeThis
) const
2190 std::vector
< VclPtr
<RadioButton
> > aGroup
;
2191 for (VclPtr
<RadioButton
> const & pRadioButton
: *m_xGroup
)
2193 if (pRadioButton
== this)
2195 aGroup
.push_back(pRadioButton
);
2202 // go back to first in group;
2203 vcl::Window
* pFirst
= const_cast<RadioButton
*>(this);
2204 while( ( pFirst
->GetStyle() & WB_GROUP
) == 0 )
2206 vcl::Window
* pWindow
= pFirst
->GetWindow( GetWindowType::Prev
);
2212 std::vector
< VclPtr
<RadioButton
> > aGroup
;
2213 // insert radiobuttons up to next group
2216 if( pFirst
->GetType() == WindowType::RADIOBUTTON
)
2218 if( pFirst
!= this || bIncludeThis
)
2219 aGroup
.emplace_back(static_cast<RadioButton
*>(pFirst
) );
2221 pFirst
= pFirst
->GetWindow( GetWindowType::Next
);
2222 } while( pFirst
&& ( ( pFirst
->GetStyle() & WB_GROUP
) == 0 ) );
2227 void RadioButton::ImplUncheckAllOther( const bool bSetStyle
)
2230 mpWindowImpl
->mnStyle
|= WB_TABSTOP
;
2232 std::vector
<VclPtr
<RadioButton
> > aGroup(GetRadioButtonGroup(false));
2233 // iterate over radio button group and checked buttons
2234 for (VclPtr
<RadioButton
>& pWindow
: aGroup
)
2236 if ( pWindow
->IsChecked() )
2238 pWindow
->SetState( false );
2239 if ( pWindow
->IsDisposed() )
2243 // not inside if clause to always remove wrongly set WB_TABSTOPS
2244 pWindow
->mpWindowImpl
->mnStyle
&= ~WB_TABSTOP
;
2248 void RadioButton::ImplCallClick( bool bGrabFocus
, GetFocusFlags nFocusFlags
)
2250 mbStateChanged
= !mbChecked
;
2252 mpWindowImpl
->mnStyle
|= WB_TABSTOP
;
2255 VclPtr
<vcl::Window
> xWindow
= this;
2257 ImplUncheckAllOther();
2258 if ( xWindow
->IsDisposed() )
2261 ImplGrabFocus( nFocusFlags
);
2262 if ( xWindow
->IsDisposed() )
2264 if ( mbStateChanged
)
2266 if ( xWindow
->IsDisposed() )
2269 if ( xWindow
->IsDisposed() )
2271 mbStateChanged
= false;
2274 RadioButton::RadioButton( vcl::Window
* pParent
, WinBits nStyle
) :
2275 Button( WindowType::RADIOBUTTON
)
2277 ImplInitRadioButtonData();
2278 ImplInit( pParent
, nStyle
);
2281 RadioButton::~RadioButton()
2286 void RadioButton::dispose()
2290 m_xGroup
->erase(std::remove(m_xGroup
->begin(), m_xGroup
->end(), VclPtr
<RadioButton
>(this)),
2297 void RadioButton::MouseButtonDown( const MouseEvent
& rMEvt
)
2299 if ( rMEvt
.IsLeft() && maMouseRect
.IsInside( rMEvt
.GetPosPixel() ) )
2301 ImplGetButtonState() |= DrawButtonFlags::Pressed
;
2308 Button::MouseButtonDown( rMEvt
);
2311 void RadioButton::Tracking( const TrackingEvent
& rTEvt
)
2313 if ( rTEvt
.IsTrackingEnded() )
2315 if ( ImplGetButtonState() & DrawButtonFlags::Pressed
)
2317 if ( !(GetStyle() & WB_NOPOINTERFOCUS
) && !rTEvt
.IsTrackingCanceled() )
2320 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
2322 // do not call click handler if aborted
2323 if ( !rTEvt
.IsTrackingCanceled() )
2334 if ( maMouseRect
.IsInside( rTEvt
.GetMouseEvent().GetPosPixel() ) )
2336 if ( !(ImplGetButtonState() & DrawButtonFlags::Pressed
) )
2338 ImplGetButtonState() |= DrawButtonFlags::Pressed
;
2345 if ( ImplGetButtonState() & DrawButtonFlags::Pressed
)
2347 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
2355 void RadioButton::KeyInput( const KeyEvent
& rKEvt
)
2357 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
2359 if ( !aKeyCode
.GetModifier() && (aKeyCode
.GetCode() == KEY_SPACE
) )
2361 if ( !(ImplGetButtonState() & DrawButtonFlags::Pressed
) )
2363 ImplGetButtonState() |= DrawButtonFlags::Pressed
;
2368 else if ( (ImplGetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_ESCAPE
) )
2370 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
2375 Button::KeyInput( rKEvt
);
2378 void RadioButton::KeyUp( const KeyEvent
& rKEvt
)
2380 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
2382 if ( (ImplGetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_SPACE
) )
2384 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
2388 Button::KeyUp( rKEvt
);
2391 void RadioButton::FillLayoutData() const
2393 mpControlData
->mpLayoutData
.reset( new vcl::ControlLayoutData
);
2394 const_cast<RadioButton
*>(this)->Invalidate();
2397 void RadioButton::Paint( vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& )
2399 ImplDrawRadioButton(rRenderContext
);
2402 void RadioButton::Draw( OutputDevice
* pDev
, const Point
& rPos
, const Size
& rSize
,
2407 MapMode
aResMapMode( MapUnit::Map100thMM
);
2408 Point aPos
= pDev
->LogicToPixel( rPos
);
2409 Size aSize
= pDev
->LogicToPixel( rSize
);
2410 Size aImageSize
= pDev
->LogicToPixel( Size( 300, 300 ), aResMapMode
);
2411 Size aBrd1Size
= pDev
->LogicToPixel( Size( 20, 20 ), aResMapMode
);
2412 Size aBrd2Size
= pDev
->LogicToPixel( Size( 60, 60 ), aResMapMode
);
2413 vcl::Font aFont
= GetDrawPixelFont( pDev
);
2414 tools::Rectangle aStateRect
;
2415 tools::Rectangle aMouseRect
;
2417 aImageSize
.setWidth( CalcZoom( aImageSize
.Width() ) );
2418 aImageSize
.setHeight( CalcZoom( aImageSize
.Height() ) );
2419 aBrd1Size
.setWidth( CalcZoom( aBrd1Size
.Width() ) );
2420 aBrd1Size
.setHeight( CalcZoom( aBrd1Size
.Height() ) );
2421 aBrd2Size
.setWidth( CalcZoom( aBrd2Size
.Width() ) );
2422 aBrd2Size
.setHeight( CalcZoom( aBrd2Size
.Height() ) );
2424 if ( !aBrd1Size
.Width() )
2425 aBrd1Size
.setWidth( 1 );
2426 if ( !aBrd1Size
.Height() )
2427 aBrd1Size
.setHeight( 1 );
2428 if ( !aBrd2Size
.Width() )
2429 aBrd2Size
.setWidth( 1 );
2430 if ( !aBrd2Size
.Height() )
2431 aBrd2Size
.setHeight( 1 );
2435 pDev
->SetFont( aFont
);
2436 if ( nFlags
& DrawFlags::Mono
)
2437 pDev
->SetTextColor( COL_BLACK
);
2439 pDev
->SetTextColor( GetTextColor() );
2440 pDev
->SetTextFillColor();
2442 ImplDraw( pDev
, nFlags
, aPos
, aSize
,
2443 aImageSize
, aStateRect
, aMouseRect
);
2445 Point aCenterPos
= aStateRect
.Center();
2446 long nRadX
= aImageSize
.Width()/2;
2447 long nRadY
= aImageSize
.Height()/2;
2449 pDev
->SetLineColor();
2450 pDev
->SetFillColor( COL_BLACK
);
2451 pDev
->DrawPolygon( tools::Polygon( aCenterPos
, nRadX
, nRadY
) );
2452 nRadX
-= aBrd1Size
.Width();
2453 nRadY
-= aBrd1Size
.Height();
2454 pDev
->SetFillColor( COL_WHITE
);
2455 pDev
->DrawPolygon( tools::Polygon( aCenterPos
, nRadX
, nRadY
) );
2458 nRadX
-= aBrd1Size
.Width();
2459 nRadY
-= aBrd1Size
.Height();
2464 pDev
->SetFillColor( COL_BLACK
);
2465 pDev
->DrawPolygon( tools::Polygon( aCenterPos
, nRadX
, nRadY
) );
2472 OSL_FAIL( "RadioButton::Draw() - not implemented for RadioButton with Image" );
2476 void RadioButton::Resize()
2482 void RadioButton::GetFocus()
2484 ShowFocus( ImplGetFocusRect() );
2485 SetInputContext( InputContext( GetFont() ) );
2489 void RadioButton::LoseFocus()
2491 if ( ImplGetButtonState() & DrawButtonFlags::Pressed
)
2493 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
2499 Button::LoseFocus();
2502 void RadioButton::StateChanged( StateChangedType nType
)
2504 Button::StateChanged( nType
);
2506 if ( nType
== StateChangedType::State
)
2508 if ( IsReallyVisible() && IsUpdateMode() )
2509 Invalidate( maStateRect
);
2511 else if ( (nType
== StateChangedType::Enable
) ||
2512 (nType
== StateChangedType::Text
) ||
2513 (nType
== StateChangedType::Data
) ||
2514 (nType
== StateChangedType::UpdateMode
) )
2516 if ( IsUpdateMode() )
2519 else if ( nType
== StateChangedType::Style
)
2521 SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev
), GetStyle() ) );
2523 if ( (GetPrevStyle() & RADIOBUTTON_VIEW_STYLE
) !=
2524 (GetStyle() & RADIOBUTTON_VIEW_STYLE
) )
2526 if ( IsUpdateMode() )
2530 else if ( (nType
== StateChangedType::Zoom
) ||
2531 (nType
== StateChangedType::ControlFont
) )
2533 ImplInitSettings( false );
2536 else if ( nType
== StateChangedType::ControlForeground
)
2538 ImplInitSettings( false );
2541 else if ( nType
== StateChangedType::ControlBackground
)
2543 ImplInitSettings( true );
2548 void RadioButton::DataChanged( const DataChangedEvent
& rDCEvt
)
2550 Button::DataChanged( rDCEvt
);
2552 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
2553 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
2554 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
2555 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
2557 ImplInitSettings( true );
2562 bool RadioButton::PreNotify( NotifyEvent
& rNEvt
)
2564 const MouseEvent
* pMouseEvt
= nullptr;
2566 if( (rNEvt
.GetType() == MouseNotifyEvent::MOUSEMOVE
) && (pMouseEvt
= rNEvt
.GetMouseEvent()) != nullptr )
2568 if( !pMouseEvt
->GetButtons() && !pMouseEvt
->IsSynthetic() && !pMouseEvt
->IsModifierChanged() )
2570 // trigger redraw if mouse over state has changed
2571 if( IsNativeControlSupported(ControlType::Radiobutton
, ControlPart::Entire
) )
2573 if (maMouseRect
.IsInside(GetPointerPosPixel()) != maMouseRect
.IsInside(GetLastPointerPosPixel()) ||
2574 pMouseEvt
->IsLeaveWindow() || pMouseEvt
->IsEnterWindow())
2576 Invalidate( maStateRect
);
2582 return Button::PreNotify(rNEvt
);
2585 void RadioButton::Toggle()
2587 ImplCallEventListenersAndHandler( VclEventId::RadiobuttonToggle
, [this] () { maToggleHdl
.Call(*this); } );
2590 void RadioButton::SetModeRadioImage( const Image
& rImage
)
2592 if ( rImage
!= maImage
)
2595 CompatStateChanged( StateChangedType::Data
);
2601 void RadioButton::SetState( bool bCheck
)
2603 // carry the TabStop flag along correctly
2605 mpWindowImpl
->mnStyle
|= WB_TABSTOP
;
2607 mpWindowImpl
->mnStyle
&= ~WB_TABSTOP
;
2609 if ( mbChecked
!= bCheck
)
2612 CompatStateChanged( StateChangedType::State
);
2617 bool RadioButton::set_property(const OString
&rKey
, const OUString
&rValue
)
2619 if (rKey
== "active")
2620 SetState(toBool(rValue
));
2621 else if (rKey
== "image-position")
2623 WinBits nBits
= GetStyle();
2624 if (rValue
== "left")
2626 nBits
&= ~(WB_CENTER
| WB_RIGHT
);
2629 else if (rValue
== "right")
2631 nBits
&= ~(WB_CENTER
| WB_LEFT
);
2634 else if (rValue
== "top")
2636 nBits
&= ~(WB_VCENTER
| WB_BOTTOM
);
2639 else if (rValue
== "bottom")
2641 nBits
&= ~(WB_VCENTER
| WB_TOP
);
2644 //It's rather mad to have to set these bits when there is the other
2645 //image align. Looks like e.g. the radiobuttons etc weren't converted
2646 //over to image align fully.
2648 //Deliberate to set the sane ImageAlign property
2649 return Button::set_property(rKey
, rValue
);
2652 return Button::set_property(rKey
, rValue
);
2656 void RadioButton::Check( bool bCheck
)
2658 // TabStop-Flag richtig mitfuehren
2660 mpWindowImpl
->mnStyle
|= WB_TABSTOP
;
2662 mpWindowImpl
->mnStyle
&= ~WB_TABSTOP
;
2664 if ( mbChecked
!= bCheck
)
2667 VclPtr
<vcl::Window
> xWindow
= this;
2668 CompatStateChanged( StateChangedType::State
);
2669 if ( xWindow
->IsDisposed() )
2671 if ( bCheck
&& mbRadioCheck
)
2672 ImplUncheckAllOther();
2673 if ( xWindow
->IsDisposed() )
2679 long RadioButton::ImplGetImageToTextDistance() const
2681 // 4 pixels, but take zoom into account, so the text doesn't "jump" relative to surrounding elements,
2682 // which might have been aligned with the text of the check box
2683 return CalcZoom( 4 );
2686 Size
RadioButton::ImplGetRadioImageSize() const
2689 bool bDefaultSize
= true;
2690 if( IsNativeControlSupported( ControlType::Radiobutton
, ControlPart::Entire
) )
2692 ImplControlValue aControlValue
;
2693 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), GetSizePixel() );
2694 tools::Rectangle aBoundingRgn
, aContentRgn
;
2696 // get native size of a radio button
2697 if( GetNativeControlRegion( ControlType::Radiobutton
, ControlPart::Entire
, aCtrlRegion
,
2698 ControlState::DEFAULT
|ControlState::ENABLED
,
2700 aBoundingRgn
, aContentRgn
) )
2702 aSize
= aContentRgn
.GetSize();
2703 bDefaultSize
= false;
2707 aSize
= GetRadioImage( GetSettings(), DrawButtonFlags::NONE
).GetSizePixel();
2711 static void LoadThemedImageList(const StyleSettings
&rStyleSettings
,
2712 std::vector
<Image
>& rList
, const std::vector
<OUString
> &rResources
)
2714 Color aColorAry1
[6];
2715 Color aColorAry2
[6];
2716 aColorAry1
[0] = Color( 0xC0, 0xC0, 0xC0 );
2717 aColorAry1
[1] = Color( 0xFF, 0xFF, 0x00 );
2718 aColorAry1
[2] = Color( 0xFF, 0xFF, 0xFF );
2719 aColorAry1
[3] = Color( 0x80, 0x80, 0x80 );
2720 aColorAry1
[4] = Color( 0x00, 0x00, 0x00 );
2721 aColorAry1
[5] = Color( 0x00, 0xFF, 0x00 );
2722 aColorAry2
[0] = rStyleSettings
.GetFaceColor();
2723 aColorAry2
[1] = rStyleSettings
.GetWindowColor();
2724 aColorAry2
[2] = rStyleSettings
.GetLightColor();
2725 aColorAry2
[3] = rStyleSettings
.GetShadowColor();
2726 aColorAry2
[4] = rStyleSettings
.GetDarkShadowColor();
2727 aColorAry2
[5] = rStyleSettings
.GetWindowTextColor();
2729 static_assert( sizeof(aColorAry1
) == sizeof(aColorAry2
), "aColorAry1 must match aColorAry2" );
2731 for (const auto &a
: rResources
)
2734 aBmpEx
.Replace(aColorAry1
, aColorAry2
, SAL_N_ELEMENTS(aColorAry1
));
2735 rList
.emplace_back(aBmpEx
);
2739 Image
RadioButton::GetRadioImage( const AllSettings
& rSettings
, DrawButtonFlags nFlags
)
2741 ImplSVData
* pSVData
= ImplGetSVData();
2742 const StyleSettings
& rStyleSettings
= rSettings
.GetStyleSettings();
2743 sal_uInt16 nStyle
= 0;
2745 if ( rStyleSettings
.GetOptions() & StyleSettingsOptions::Mono
)
2746 nStyle
= STYLE_RADIOBUTTON_MONO
;
2748 if ( pSVData
->maCtrlData
.maRadioImgList
.empty() ||
2749 (pSVData
->maCtrlData
.mnRadioStyle
!= nStyle
) ||
2750 (pSVData
->maCtrlData
.mnLastRadioFColor
!= rStyleSettings
.GetFaceColor()) ||
2751 (pSVData
->maCtrlData
.mnLastRadioWColor
!= rStyleSettings
.GetWindowColor()) ||
2752 (pSVData
->maCtrlData
.mnLastRadioLColor
!= rStyleSettings
.GetLightColor()) )
2754 pSVData
->maCtrlData
.maRadioImgList
.clear();
2756 pSVData
->maCtrlData
.mnLastRadioFColor
= rStyleSettings
.GetFaceColor();
2757 pSVData
->maCtrlData
.mnLastRadioWColor
= rStyleSettings
.GetWindowColor();
2758 pSVData
->maCtrlData
.mnLastRadioLColor
= rStyleSettings
.GetLightColor();
2760 std::vector
<OUString
> aResources
;
2763 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO1
);
2764 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO2
);
2765 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO3
);
2766 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO4
);
2767 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO5
);
2768 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO6
);
2772 aResources
.emplace_back(SV_RESID_BITMAP_RADIO1
);
2773 aResources
.emplace_back(SV_RESID_BITMAP_RADIO2
);
2774 aResources
.emplace_back(SV_RESID_BITMAP_RADIO3
);
2775 aResources
.emplace_back(SV_RESID_BITMAP_RADIO4
);
2776 aResources
.emplace_back(SV_RESID_BITMAP_RADIO5
);
2777 aResources
.emplace_back(SV_RESID_BITMAP_RADIO6
);
2779 LoadThemedImageList( rStyleSettings
, pSVData
->maCtrlData
.maRadioImgList
, aResources
);
2780 pSVData
->maCtrlData
.mnRadioStyle
= nStyle
;
2784 if ( nFlags
& DrawButtonFlags::Disabled
)
2786 if ( nFlags
& DrawButtonFlags::Checked
)
2791 else if ( nFlags
& DrawButtonFlags::Pressed
)
2793 if ( nFlags
& DrawButtonFlags::Checked
)
2800 if ( nFlags
& DrawButtonFlags::Checked
)
2805 return pSVData
->maCtrlData
.maRadioImgList
[nIndex
];
2808 void RadioButton::ImplSetMinimumNWFSize()
2810 Push( PushFlags::MAPMODE
);
2811 SetMapMode(MapMode(MapUnit::MapPixel
));
2813 ImplControlValue aControlValue
;
2814 Size
aCurSize( GetSizePixel() );
2815 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), aCurSize
);
2816 tools::Rectangle aBoundingRgn
, aContentRgn
;
2818 // get native size of a radiobutton
2819 if( GetNativeControlRegion( ControlType::Radiobutton
, ControlPart::Entire
, aCtrlRegion
,
2820 ControlState::DEFAULT
|ControlState::ENABLED
, aControlValue
,
2821 aBoundingRgn
, aContentRgn
) )
2823 Size aSize
= aContentRgn
.GetSize();
2825 if( aSize
.Height() > aCurSize
.Height() )
2827 aCurSize
.setHeight( aSize
.Height() );
2828 SetSizePixel( aCurSize
);
2835 Size
RadioButton::CalcMinimumSize() const
2839 aSize
= ImplGetRadioImageSize();
2842 aSize
= maImage
.GetSizePixel();
2843 aSize
.AdjustWidth(8);
2844 aSize
.AdjustHeight(8);
2847 if (Button::HasImage())
2849 Size aImgSize
= GetModeImage().GetSizePixel();
2850 aSize
= Size(std::max(aImgSize
.Width(), aSize
.Width()),
2851 std::max(aImgSize
.Height(), aSize
.Height()));
2854 OUString aText
= GetText();
2855 if (!aText
.isEmpty())
2857 bool bTopImage
= (GetStyle() & WB_TOP
) != 0;
2859 Size aTextSize
= GetTextRect( tools::Rectangle( Point(), Size( 0x7fffffff, 0x7fffffff ) ),
2860 aText
, FixedText::ImplGetTextStyle( GetStyle() ) ).GetSize();
2862 aSize
.AdjustWidth(2 ); // for focus rect
2866 aSize
.AdjustWidth(ImplGetImageToTextDistance() );
2867 aSize
.AdjustWidth(aTextSize
.Width() );
2868 if ( aSize
.Height() < aTextSize
.Height() )
2869 aSize
.setHeight( aTextSize
.Height() );
2873 aSize
.AdjustHeight(6 );
2874 aSize
.AdjustHeight(GetTextHeight() );
2875 if ( aSize
.Width() < aTextSize
.Width() )
2876 aSize
.setWidth( aTextSize
.Width() );
2880 return CalcWindowSize( aSize
);
2883 Size
RadioButton::GetOptimalSize() const
2885 return CalcMinimumSize();
2888 void RadioButton::ShowFocus(const tools::Rectangle
& rRect
)
2890 if (IsNativeControlSupported(ControlType::Radiobutton
, ControlPart::Focus
))
2892 ImplControlValue aControlValue
;
2893 tools::Rectangle
aInRect(Point(0, 0), GetSizePixel());
2895 aInRect
.SetLeft( rRect
.Left() ); // exclude the radio element itself from the focusrect
2897 DrawNativeControl(ControlType::Radiobutton
, ControlPart::Focus
, aInRect
,
2898 ControlState::FOCUSED
, aControlValue
, OUString());
2900 Button::ShowFocus(rRect
);
2903 FactoryFunction
RadioButton::GetUITestFactory() const
2905 return RadioButtonUIObject::create
;
2908 void CheckBox::ImplInitCheckBoxData()
2910 meState
= TRISTATE_FALSE
;
2911 meSaveValue
= TRISTATE_FALSE
;
2915 void CheckBox::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
2917 nStyle
= ImplInitStyle(getPreviousSibling(pParent
), nStyle
);
2918 Button::ImplInit( pParent
, nStyle
, nullptr );
2920 ImplInitSettings( true );
2923 WinBits
CheckBox::ImplInitStyle( const vcl::Window
* pPrevWindow
, WinBits nStyle
)
2925 if ( !(nStyle
& WB_NOTABSTOP
) )
2926 nStyle
|= WB_TABSTOP
;
2927 if ( !(nStyle
& WB_NOGROUP
) &&
2928 (!pPrevWindow
|| (pPrevWindow
->GetType() != WindowType::CHECKBOX
)) )
2933 const vcl::Font
& CheckBox::GetCanonicalFont( const StyleSettings
& _rStyle
) const
2935 return _rStyle
.GetRadioCheckFont();
2938 const Color
& CheckBox::GetCanonicalTextColor( const StyleSettings
& _rStyle
) const
2940 return _rStyle
.GetRadioCheckTextColor();
2943 void CheckBox::ImplInitSettings( bool bBackground
)
2945 Button::ImplInitSettings();
2949 vcl::Window
* pParent
= GetParent();
2950 if ( !IsControlBackground() &&
2951 (pParent
->IsChildTransparentModeEnabled() || IsNativeControlSupported( ControlType::Checkbox
, ControlPart::Entire
) ) )
2953 EnableChildTransparentMode();
2954 SetParentClipMode( ParentClipMode::NoClip
);
2955 SetPaintTransparent( true );
2957 if( IsNativeControlSupported( ControlType::Checkbox
, ControlPart::Entire
) )
2958 ImplGetWindowImpl()->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
2962 EnableChildTransparentMode( false );
2963 SetParentClipMode();
2964 SetPaintTransparent( false );
2966 if ( IsControlBackground() )
2967 SetBackground( GetControlBackground() );
2969 SetBackground( pParent
->GetBackground() );
2974 void CheckBox::ImplDrawCheckBoxState(vcl::RenderContext
& rRenderContext
)
2976 bool bNativeOK
= rRenderContext
.IsNativeControlSupported(ControlType::Checkbox
, ControlPart::Entire
);
2979 ImplControlValue
aControlValue(meState
== TRISTATE_TRUE
? ButtonValue::On
: ButtonValue::Off
);
2980 tools::Rectangle
aCtrlRegion(maStateRect
);
2981 ControlState nState
= ControlState::NONE
;
2984 nState
|= ControlState::FOCUSED
;
2985 if (ImplGetButtonState() & DrawButtonFlags::Default
)
2986 nState
|= ControlState::DEFAULT
;
2987 if (ImplGetButtonState() & DrawButtonFlags::Pressed
)
2988 nState
|= ControlState::PRESSED
;
2990 nState
|= ControlState::ENABLED
;
2992 if (meState
== TRISTATE_TRUE
)
2993 aControlValue
.setTristateVal(ButtonValue::On
);
2994 else if (meState
== TRISTATE_INDET
)
2995 aControlValue
.setTristateVal(ButtonValue::Mixed
);
2997 if (IsMouseOver() && maMouseRect
.IsInside(GetPointerPosPixel()))
2998 nState
|= ControlState::ROLLOVER
;
3000 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Checkbox
, ControlPart::Entire
, aCtrlRegion
,
3001 nState
, aControlValue
, OUString());
3006 DrawButtonFlags nStyle
= ImplGetButtonState();
3008 nStyle
|= DrawButtonFlags::Disabled
;
3009 if (meState
== TRISTATE_INDET
)
3010 nStyle
|= DrawButtonFlags::DontKnow
;
3011 else if (meState
== TRISTATE_TRUE
)
3012 nStyle
|= DrawButtonFlags::Checked
;
3013 Image aImage
= GetCheckImage(GetSettings(), nStyle
);
3015 rRenderContext
.DrawImage(maStateRect
.TopLeft(), maStateRect
.GetSize(), aImage
);
3017 rRenderContext
.DrawImage(maStateRect
.TopLeft(), aImage
);
3021 void CheckBox::ImplDraw( OutputDevice
* pDev
, DrawFlags nDrawFlags
,
3022 const Point
& rPos
, const Size
& rSize
,
3023 const Size
& rImageSize
, tools::Rectangle
& rStateRect
,
3024 tools::Rectangle
& rMouseRect
)
3026 WinBits nWinStyle
= GetStyle();
3027 OUString
aText( GetText() );
3029 pDev
->Push( PushFlags::CLIPREGION
| PushFlags::LINECOLOR
);
3030 pDev
->IntersectClipRegion( tools::Rectangle( rPos
, rSize
) );
3032 if (!aText
.isEmpty() || HasImage())
3034 DrawTextFlags nTextStyle
= Button::ImplGetTextStyle( nWinStyle
, nDrawFlags
);
3036 const long nImageSep
= GetDrawPixel( pDev
, ImplGetImageToTextDistance() );
3037 Size
aSize( rSize
);
3039 aPos
.AdjustX(rImageSize
.Width() + nImageSep
);
3040 aSize
.AdjustWidth( -(rImageSize
.Width() + nImageSep
) );
3042 // if the text rect height is smaller than the height of the image
3043 // then for single lines the default should be centered text
3044 if( (nWinStyle
& (WB_TOP
|WB_VCENTER
|WB_BOTTOM
)) == 0 &&
3045 (rImageSize
.Height() > rSize
.Height() || ! (nWinStyle
& WB_WORDBREAK
) ) )
3047 nTextStyle
&= ~DrawTextFlags(DrawTextFlags::Top
|DrawTextFlags::Bottom
);
3048 nTextStyle
|= DrawTextFlags::VCenter
;
3049 aSize
.setHeight( rImageSize
.Height() );
3052 ImplDrawAlignedImage( pDev
, aPos
, aSize
, 1, nTextStyle
);
3054 rMouseRect
= tools::Rectangle( aPos
, aSize
);
3055 rMouseRect
.SetLeft( rPos
.X() );
3056 rStateRect
.SetLeft( rPos
.X() );
3057 rStateRect
.SetTop( rMouseRect
.Top() );
3059 if ( aSize
.Height() > rImageSize
.Height() )
3060 rStateRect
.AdjustTop(( aSize
.Height() - rImageSize
.Height() ) / 2 );
3063 rStateRect
.AdjustTop( -(( rImageSize
.Height() - aSize
.Height() ) / 2) );
3064 if( rStateRect
.Top() < 0 )
3065 rStateRect
.SetTop( 0 );
3068 rStateRect
.SetRight( rStateRect
.Left()+rImageSize
.Width()-1 );
3069 rStateRect
.SetBottom( rStateRect
.Top()+rImageSize
.Height()-1 );
3070 if ( rStateRect
.Bottom() > rMouseRect
.Bottom() )
3071 rMouseRect
.SetBottom( rStateRect
.Bottom() );
3075 if ( mbLegacyNoTextAlign
&& ( nWinStyle
& WB_CENTER
) )
3076 rStateRect
.SetLeft( rPos
.X()+((rSize
.Width()-rImageSize
.Width())/2) );
3077 else if ( mbLegacyNoTextAlign
&& ( nWinStyle
& WB_RIGHT
) )
3078 rStateRect
.SetLeft( rPos
.X()+rSize
.Width()-rImageSize
.Width() );
3080 rStateRect
.SetLeft( rPos
.X() );
3081 if ( nWinStyle
& WB_VCENTER
)
3082 rStateRect
.SetTop( rPos
.Y()+((rSize
.Height()-rImageSize
.Height())/2) );
3083 else if ( nWinStyle
& WB_BOTTOM
)
3084 rStateRect
.SetTop( rPos
.Y()+rSize
.Height()-rImageSize
.Height() );
3086 rStateRect
.SetTop( rPos
.Y() );
3087 rStateRect
.SetRight( rStateRect
.Left()+rImageSize
.Width()-1 );
3088 rStateRect
.SetBottom( rStateRect
.Top()+rImageSize
.Height()-1 );
3089 // provide space for focusrect
3090 // note: this assumes that the control's size was adjusted
3091 // accordingly in Get/LoseFocus, so the onscreen position won't change
3093 rStateRect
.Move( 1, 1 );
3094 rMouseRect
= rStateRect
;
3096 ImplSetFocusRect( rStateRect
);
3102 void CheckBox::ImplDrawCheckBox(vcl::RenderContext
& rRenderContext
)
3104 Size aImageSize
= ImplGetCheckImageSize();
3105 aImageSize
.setWidth( CalcZoom( aImageSize
.Width() ) );
3106 aImageSize
.setHeight( CalcZoom( aImageSize
.Height() ) );
3110 ImplDraw(&rRenderContext
, DrawFlags::NONE
, Point(), GetOutputSizePixel(),
3111 aImageSize
, maStateRect
, maMouseRect
);
3113 ImplDrawCheckBoxState(rRenderContext
);
3115 ShowFocus(ImplGetFocusRect());
3118 void CheckBox::ImplCheck()
3121 if ( meState
== TRISTATE_FALSE
)
3122 eNewState
= TRISTATE_TRUE
;
3123 else if ( !mbTriState
)
3124 eNewState
= TRISTATE_FALSE
;
3125 else if ( meState
== TRISTATE_TRUE
)
3126 eNewState
= TRISTATE_INDET
;
3128 eNewState
= TRISTATE_FALSE
;
3129 meState
= eNewState
;
3131 VclPtr
<vcl::Window
> xWindow
= this;
3135 if ( xWindow
->IsDisposed() )
3140 CheckBox::CheckBox( vcl::Window
* pParent
, WinBits nStyle
) :
3141 Button( WindowType::CHECKBOX
), mbLegacyNoTextAlign( false )
3143 ImplInitCheckBoxData();
3144 ImplInit( pParent
, nStyle
);
3147 void CheckBox::MouseButtonDown( const MouseEvent
& rMEvt
)
3149 if ( rMEvt
.IsLeft() && maMouseRect
.IsInside( rMEvt
.GetPosPixel() ) )
3151 ImplGetButtonState() |= DrawButtonFlags::Pressed
;
3158 Button::MouseButtonDown( rMEvt
);
3161 void CheckBox::Tracking( const TrackingEvent
& rTEvt
)
3163 if ( rTEvt
.IsTrackingEnded() )
3165 if ( ImplGetButtonState() & DrawButtonFlags::Pressed
)
3167 if ( !(GetStyle() & WB_NOPOINTERFOCUS
) && !rTEvt
.IsTrackingCanceled() )
3170 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
3172 // do not call click handler if aborted
3173 if ( !rTEvt
.IsTrackingCanceled() )
3184 if ( maMouseRect
.IsInside( rTEvt
.GetMouseEvent().GetPosPixel() ) )
3186 if ( !(ImplGetButtonState() & DrawButtonFlags::Pressed
) )
3188 ImplGetButtonState() |= DrawButtonFlags::Pressed
;
3195 if ( ImplGetButtonState() & DrawButtonFlags::Pressed
)
3197 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
3205 void CheckBox::KeyInput( const KeyEvent
& rKEvt
)
3207 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
3209 if ( !aKeyCode
.GetModifier() && (aKeyCode
.GetCode() == KEY_SPACE
) )
3211 if ( !(ImplGetButtonState() & DrawButtonFlags::Pressed
) )
3213 ImplGetButtonState() |= DrawButtonFlags::Pressed
;
3218 else if ( (ImplGetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_ESCAPE
) )
3220 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
3225 Button::KeyInput( rKEvt
);
3228 void CheckBox::KeyUp( const KeyEvent
& rKEvt
)
3230 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
3232 if ( (ImplGetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_SPACE
) )
3234 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
3238 Button::KeyUp( rKEvt
);
3241 void CheckBox::FillLayoutData() const
3243 mpControlData
->mpLayoutData
.reset( new vcl::ControlLayoutData
);
3244 const_cast<CheckBox
*>(this)->Invalidate();
3247 void CheckBox::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
3249 ImplDrawCheckBox(rRenderContext
);
3252 void CheckBox::Draw( OutputDevice
* pDev
, const Point
& rPos
, const Size
& rSize
,
3255 MapMode
aResMapMode( MapUnit::Map100thMM
);
3256 Point aPos
= pDev
->LogicToPixel( rPos
);
3257 Size aSize
= pDev
->LogicToPixel( rSize
);
3258 Size aImageSize
= pDev
->LogicToPixel( Size( 300, 300 ), aResMapMode
);
3259 Size aBrd1Size
= pDev
->LogicToPixel( Size( 20, 20 ), aResMapMode
);
3260 Size aBrd2Size
= pDev
->LogicToPixel( Size( 30, 30 ), aResMapMode
);
3261 long nCheckWidth
= pDev
->LogicToPixel( Size( 20, 20 ), aResMapMode
).Width();
3262 vcl::Font aFont
= GetDrawPixelFont( pDev
);
3263 tools::Rectangle aStateRect
;
3264 tools::Rectangle aMouseRect
;
3266 aImageSize
.setWidth( CalcZoom( aImageSize
.Width() ) );
3267 aImageSize
.setHeight( CalcZoom( aImageSize
.Height() ) );
3268 aBrd1Size
.setWidth( CalcZoom( aBrd1Size
.Width() ) );
3269 aBrd1Size
.setHeight( CalcZoom( aBrd1Size
.Height() ) );
3270 aBrd2Size
.setWidth( CalcZoom( aBrd2Size
.Width() ) );
3271 aBrd2Size
.setHeight( CalcZoom( aBrd2Size
.Height() ) );
3273 if ( !aBrd1Size
.Width() )
3274 aBrd1Size
.setWidth( 1 );
3275 if ( !aBrd1Size
.Height() )
3276 aBrd1Size
.setHeight( 1 );
3277 if ( !aBrd2Size
.Width() )
3278 aBrd2Size
.setWidth( 1 );
3279 if ( !aBrd2Size
.Height() )
3280 aBrd2Size
.setHeight( 1 );
3286 pDev
->SetFont( aFont
);
3287 if ( nFlags
& DrawFlags::Mono
)
3288 pDev
->SetTextColor( COL_BLACK
);
3290 pDev
->SetTextColor( GetTextColor() );
3291 pDev
->SetTextFillColor();
3293 ImplDraw( pDev
, nFlags
, aPos
, aSize
,
3294 aImageSize
, aStateRect
, aMouseRect
);
3296 pDev
->SetLineColor();
3297 pDev
->SetFillColor( COL_BLACK
);
3298 pDev
->DrawRect( aStateRect
);
3299 aStateRect
.AdjustLeft(aBrd1Size
.Width() );
3300 aStateRect
.AdjustTop(aBrd1Size
.Height() );
3301 aStateRect
.AdjustRight( -(aBrd1Size
.Width()) );
3302 aStateRect
.AdjustBottom( -(aBrd1Size
.Height()) );
3303 if ( meState
== TRISTATE_INDET
)
3304 pDev
->SetFillColor( COL_LIGHTGRAY
);
3306 pDev
->SetFillColor( COL_WHITE
);
3307 pDev
->DrawRect( aStateRect
);
3309 if ( meState
== TRISTATE_TRUE
)
3311 aStateRect
.AdjustLeft(aBrd2Size
.Width() );
3312 aStateRect
.AdjustTop(aBrd2Size
.Height() );
3313 aStateRect
.AdjustRight( -(aBrd2Size
.Width()) );
3314 aStateRect
.AdjustBottom( -(aBrd2Size
.Height()) );
3315 Point
aPos11( aStateRect
.TopLeft() );
3316 Point
aPos12( aStateRect
.BottomRight() );
3317 Point
aPos21( aStateRect
.TopRight() );
3318 Point
aPos22( aStateRect
.BottomLeft() );
3319 Point
aTempPos11( aPos11
);
3320 Point
aTempPos12( aPos12
);
3321 Point
aTempPos21( aPos21
);
3322 Point
aTempPos22( aPos22
);
3323 pDev
->SetLineColor( COL_BLACK
);
3325 for ( long i
= 0; i
< nCheckWidth
; i
++ )
3329 aTempPos11
.setX( aPos11
.X()+nDX
);
3330 aTempPos12
.setX( aPos12
.X()+nDX
);
3331 aTempPos21
.setX( aPos21
.X()+nDX
);
3332 aTempPos22
.setX( aPos22
.X()+nDX
);
3337 aTempPos11
.setX( aPos11
.X()-nDX
);
3338 aTempPos12
.setX( aPos12
.X()-nDX
);
3339 aTempPos21
.setX( aPos21
.X()-nDX
);
3340 aTempPos22
.setX( aPos22
.X()-nDX
);
3342 pDev
->DrawLine( aTempPos11
, aTempPos12
);
3343 pDev
->DrawLine( aTempPos21
, aTempPos22
);
3350 void CheckBox::Resize()
3356 void CheckBox::GetFocus()
3358 if (GetText().isEmpty())
3360 // increase button size to have space for focus rect
3361 // checkboxes without text will draw focusrect around the check
3362 // See CheckBox::ImplDraw()
3363 Point
aPos( GetPosPixel() );
3364 Size
aSize( GetSizePixel() );
3366 aSize
.AdjustHeight(2 );
3367 aSize
.AdjustWidth(2 );
3368 setPosSizePixel( aPos
.X(), aPos
.Y(), aSize
.Width(), aSize
.Height() );
3370 // Trigger drawing to initialize the mouse rectangle, otherwise the mouse button down
3371 // handler would ignore the mouse event.
3375 ShowFocus( ImplGetFocusRect() );
3377 SetInputContext( InputContext( GetFont() ) );
3381 void CheckBox::LoseFocus()
3383 if ( ImplGetButtonState() & DrawButtonFlags::Pressed
)
3385 ImplGetButtonState() &= ~DrawButtonFlags::Pressed
;
3391 Button::LoseFocus();
3393 if (GetText().isEmpty())
3395 // decrease button size again (see GetFocus())
3396 // checkboxes without text will draw focusrect around the check
3397 Point
aPos( GetPosPixel() );
3398 Size
aSize( GetSizePixel() );
3400 aSize
.AdjustHeight( -2 );
3401 aSize
.AdjustWidth( -2 );
3402 setPosSizePixel( aPos
.X(), aPos
.Y(), aSize
.Width(), aSize
.Height() );
3407 void CheckBox::StateChanged( StateChangedType nType
)
3409 Button::StateChanged( nType
);
3411 if ( nType
== StateChangedType::State
)
3413 if ( IsReallyVisible() && IsUpdateMode() )
3414 Invalidate( maStateRect
);
3416 else if ( (nType
== StateChangedType::Enable
) ||
3417 (nType
== StateChangedType::Text
) ||
3418 (nType
== StateChangedType::Data
) ||
3419 (nType
== StateChangedType::UpdateMode
) )
3421 if ( IsUpdateMode() )
3424 else if ( nType
== StateChangedType::Style
)
3426 SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev
), GetStyle() ) );
3428 if ( (GetPrevStyle() & CHECKBOX_VIEW_STYLE
) !=
3429 (GetStyle() & CHECKBOX_VIEW_STYLE
) )
3431 if ( IsUpdateMode() )
3435 else if ( (nType
== StateChangedType::Zoom
) ||
3436 (nType
== StateChangedType::ControlFont
) )
3438 ImplInitSettings( false );
3441 else if ( nType
== StateChangedType::ControlForeground
)
3443 ImplInitSettings( false );
3446 else if ( nType
== StateChangedType::ControlBackground
)
3448 ImplInitSettings( true );
3453 void CheckBox::DataChanged( const DataChangedEvent
& rDCEvt
)
3455 Button::DataChanged( rDCEvt
);
3457 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
3458 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
3459 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
3460 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
3462 ImplInitSettings( true );
3467 bool CheckBox::PreNotify( NotifyEvent
& rNEvt
)
3469 const MouseEvent
* pMouseEvt
= nullptr;
3471 if( (rNEvt
.GetType() == MouseNotifyEvent::MOUSEMOVE
) && (pMouseEvt
= rNEvt
.GetMouseEvent()) != nullptr )
3473 if( !pMouseEvt
->GetButtons() && !pMouseEvt
->IsSynthetic() && !pMouseEvt
->IsModifierChanged() )
3475 // trigger redraw if mouse over state has changed
3476 if( IsNativeControlSupported(ControlType::Checkbox
, ControlPart::Entire
) )
3478 if (maMouseRect
.IsInside(GetPointerPosPixel()) != maMouseRect
.IsInside(GetLastPointerPosPixel()) ||
3479 pMouseEvt
->IsLeaveWindow() || pMouseEvt
->IsEnterWindow())
3481 Invalidate( maStateRect
);
3487 return Button::PreNotify(rNEvt
);
3490 void CheckBox::Toggle()
3492 ImplCallEventListenersAndHandler( VclEventId::CheckboxToggle
, [this] () { maToggleHdl
.Call(*this); } );
3495 void CheckBox::SetState( TriState eState
)
3497 if ( !mbTriState
&& (eState
== TRISTATE_INDET
) )
3498 eState
= TRISTATE_FALSE
;
3500 if ( meState
!= eState
)
3503 StateChanged( StateChangedType::State
);
3508 bool CheckBox::set_property(const OString
&rKey
, const OUString
&rValue
)
3510 if (rKey
== "active")
3511 SetState(toBool(rValue
) ? TRISTATE_TRUE
: TRISTATE_FALSE
);
3513 return Button::set_property(rKey
, rValue
);
3517 void CheckBox::EnableTriState( bool bTriState
)
3519 if ( mbTriState
!= bTriState
)
3521 mbTriState
= bTriState
;
3523 if ( !bTriState
&& (meState
== TRISTATE_INDET
) )
3524 SetState( TRISTATE_FALSE
);
3528 long CheckBox::ImplGetImageToTextDistance() const
3530 // 4 pixels, but take zoom into account, so the text doesn't "jump" relative to surrounding elements,
3531 // which might have been aligned with the text of the check box
3532 return CalcZoom( 4 );
3535 Size
CheckBox::ImplGetCheckImageSize() const
3538 bool bDefaultSize
= true;
3539 if( IsNativeControlSupported( ControlType::Checkbox
, ControlPart::Entire
) )
3541 ImplControlValue aControlValue
;
3542 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), GetSizePixel() );
3543 tools::Rectangle aBoundingRgn
, aContentRgn
;
3545 // get native size of a check box
3546 if( GetNativeControlRegion( ControlType::Checkbox
, ControlPart::Entire
, aCtrlRegion
,
3547 ControlState::DEFAULT
|ControlState::ENABLED
,
3549 aBoundingRgn
, aContentRgn
) )
3551 aSize
= aContentRgn
.GetSize();
3552 bDefaultSize
= false;
3556 aSize
= GetCheckImage( GetSettings(), DrawButtonFlags::NONE
).GetSizePixel();
3560 Image
CheckBox::GetCheckImage( const AllSettings
& rSettings
, DrawButtonFlags nFlags
)
3562 ImplSVData
* pSVData
= ImplGetSVData();
3563 const StyleSettings
& rStyleSettings
= rSettings
.GetStyleSettings();
3564 sal_uInt16 nStyle
= 0;
3566 if ( rStyleSettings
.GetOptions() & StyleSettingsOptions::Mono
)
3567 nStyle
= STYLE_CHECKBOX_MONO
;
3569 if ( pSVData
->maCtrlData
.maCheckImgList
.empty() ||
3570 (pSVData
->maCtrlData
.mnCheckStyle
!= nStyle
) ||
3571 (pSVData
->maCtrlData
.mnLastCheckFColor
!= rStyleSettings
.GetFaceColor()) ||
3572 (pSVData
->maCtrlData
.mnLastCheckWColor
!= rStyleSettings
.GetWindowColor()) ||
3573 (pSVData
->maCtrlData
.mnLastCheckLColor
!= rStyleSettings
.GetLightColor()) )
3575 pSVData
->maCtrlData
.maCheckImgList
.clear();
3577 pSVData
->maCtrlData
.mnLastCheckFColor
= rStyleSettings
.GetFaceColor();
3578 pSVData
->maCtrlData
.mnLastCheckWColor
= rStyleSettings
.GetWindowColor();
3579 pSVData
->maCtrlData
.mnLastCheckLColor
= rStyleSettings
.GetLightColor();
3581 std::vector
<OUString
> aResources
;
3584 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO1
);
3585 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO2
);
3586 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO3
);
3587 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO4
);
3588 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO5
);
3589 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO6
);
3590 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO7
);
3591 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO8
);
3592 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO9
);
3596 aResources
.emplace_back(SV_RESID_BITMAP_CHECK1
);
3597 aResources
.emplace_back(SV_RESID_BITMAP_CHECK2
);
3598 aResources
.emplace_back(SV_RESID_BITMAP_CHECK3
);
3599 aResources
.emplace_back(SV_RESID_BITMAP_CHECK4
);
3600 aResources
.emplace_back(SV_RESID_BITMAP_CHECK5
);
3601 aResources
.emplace_back(SV_RESID_BITMAP_CHECK6
);
3602 aResources
.emplace_back(SV_RESID_BITMAP_CHECK7
);
3603 aResources
.emplace_back(SV_RESID_BITMAP_CHECK8
);
3604 aResources
.emplace_back(SV_RESID_BITMAP_CHECK9
);
3606 LoadThemedImageList(rStyleSettings
, pSVData
->maCtrlData
.maCheckImgList
, aResources
);
3607 pSVData
->maCtrlData
.mnCheckStyle
= nStyle
;
3611 if ( nFlags
& DrawButtonFlags::Disabled
)
3613 if ( nFlags
& DrawButtonFlags::DontKnow
)
3615 else if ( nFlags
& DrawButtonFlags::Checked
)
3620 else if ( nFlags
& DrawButtonFlags::Pressed
)
3622 if ( nFlags
& DrawButtonFlags::DontKnow
)
3624 else if ( nFlags
& DrawButtonFlags::Checked
)
3631 if ( nFlags
& DrawButtonFlags::DontKnow
)
3633 else if ( nFlags
& DrawButtonFlags::Checked
)
3638 return pSVData
->maCtrlData
.maCheckImgList
[nIndex
];
3641 void CheckBox::ImplSetMinimumNWFSize()
3643 Push( PushFlags::MAPMODE
);
3644 SetMapMode(MapMode(MapUnit::MapPixel
));
3646 ImplControlValue aControlValue
;
3647 Size
aCurSize( GetSizePixel() );
3648 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), aCurSize
);
3649 tools::Rectangle aBoundingRgn
, aContentRgn
;
3651 // get native size of a radiobutton
3652 if( GetNativeControlRegion( ControlType::Checkbox
, ControlPart::Entire
, aCtrlRegion
,
3653 ControlState::DEFAULT
|ControlState::ENABLED
, aControlValue
,
3654 aBoundingRgn
, aContentRgn
) )
3656 Size aSize
= aContentRgn
.GetSize();
3658 if( aSize
.Height() > aCurSize
.Height() )
3660 aCurSize
.setHeight( aSize
.Height() );
3661 SetSizePixel( aCurSize
);
3668 Size
CheckBox::CalcMinimumSize( long nMaxWidth
) const
3670 Size aSize
= ImplGetCheckImageSize();
3671 nMaxWidth
-= aSize
.Width();
3673 OUString aText
= GetText();
3674 if (!aText
.isEmpty())
3676 // subtract what will be added later
3678 nMaxWidth
-= ImplGetImageToTextDistance();
3680 Size aTextSize
= GetTextRect( tools::Rectangle( Point(), Size( nMaxWidth
> 0 ? nMaxWidth
: 0x7fffffff, 0x7fffffff ) ),
3681 aText
, FixedText::ImplGetTextStyle( GetStyle() ) ).GetSize();
3682 aSize
.AdjustWidth(2 ); // for focus rect
3683 aSize
.AdjustWidth(ImplGetImageToTextDistance() );
3684 aSize
.AdjustWidth(aTextSize
.Width() );
3685 if ( aSize
.Height() < aTextSize
.Height() )
3686 aSize
.setHeight( aTextSize
.Height() );
3690 // is this still correct ? since the checkbox now
3691 // shows a focus rect it should be 2 pixels wider and longer
3692 /* since otherwise the controls in the Writer hang too far up
3694 aSize.Height() += 2;
3698 return CalcWindowSize( aSize
);
3701 Size
CheckBox::GetOptimalSize() const
3703 int nWidthRequest(get_width_request());
3704 return CalcMinimumSize(nWidthRequest
!= -1 ? nWidthRequest
: 0);
3707 void CheckBox::ShowFocus(const tools::Rectangle
& rRect
)
3709 if (IsNativeControlSupported(ControlType::Checkbox
, ControlPart::Focus
))
3711 ImplControlValue aControlValue
;
3712 tools::Rectangle
aInRect(Point(0, 0), GetSizePixel());
3714 aInRect
.SetLeft( rRect
.Left() ); // exclude the checkbox itself from the focusrect
3716 DrawNativeControl(ControlType::Checkbox
, ControlPart::Focus
, aInRect
,
3717 ControlState::FOCUSED
, aControlValue
, OUString());
3719 Button::ShowFocus(rRect
);
3722 FactoryFunction
CheckBox::GetUITestFactory() const
3724 return CheckBoxUIObject::create
;
3727 ImageButton::ImageButton( vcl::Window
* pParent
, WinBits nStyle
) :
3728 PushButton( pParent
, nStyle
)
3733 void ImageButton::ImplInitStyle()
3735 WinBits nStyle
= GetStyle();
3737 if ( ! ( nStyle
& ( WB_RIGHT
| WB_LEFT
) ) )
3738 nStyle
|= WB_CENTER
;
3740 if ( ! ( nStyle
& ( WB_TOP
| WB_BOTTOM
) ) )
3741 nStyle
|= WB_VCENTER
;
3746 ImageRadioButton::ImageRadioButton( vcl::Window
* pParent
) :
3747 RadioButton( pParent
, 0 )
3751 TriStateBox::TriStateBox( vcl::Window
* pParent
, WinBits nStyle
) :
3752 CheckBox( pParent
, nStyle
)
3757 DisclosureButton::DisclosureButton( vcl::Window
* pParent
) :
3758 CheckBox( pParent
, 0 )
3762 void DisclosureButton::ImplDrawCheckBoxState(vcl::RenderContext
& rRenderContext
)
3764 /* HACK: DisclosureButton is currently assuming, that the disclosure sign
3765 will fit into the rectangle occupied by a normal checkbox on all themes.
3766 If this does not hold true for some theme, ImplGetCheckImageSize
3767 would have to be overridden for DisclosureButton; also GetNativeControlRegion
3768 for ControlType::ListNode would have to be implemented and taken into account
3771 tools::Rectangle
aStateRect(GetStateRect());
3773 ImplControlValue
aControlValue(GetState() == TRISTATE_TRUE
? ButtonValue::On
: ButtonValue::Off
);
3774 tools::Rectangle
aCtrlRegion(aStateRect
);
3775 ControlState nState
= ControlState::NONE
;
3778 nState
|= ControlState::FOCUSED
;
3779 if (ImplGetButtonState() & DrawButtonFlags::Default
)
3780 nState
|= ControlState::DEFAULT
;
3781 if (Window::IsEnabled())
3782 nState
|= ControlState::ENABLED
;
3783 if (IsMouseOver() && GetMouseRect().IsInside(GetPointerPosPixel()))
3784 nState
|= ControlState::ROLLOVER
;
3786 if (rRenderContext
.DrawNativeControl(ControlType::ListNode
, ControlPart::Entire
, aCtrlRegion
,
3787 nState
, aControlValue
, OUString()))
3790 ImplSVCtrlData
& rCtrlData(ImplGetSVData()->maCtrlData
);
3791 if (!rCtrlData
.mpDisclosurePlus
)
3792 rCtrlData
.mpDisclosurePlus
.reset(new Image(StockImage::Yes
, SV_DISCLOSURE_PLUS
));
3793 if (!rCtrlData
.mpDisclosureMinus
)
3794 rCtrlData
.mpDisclosureMinus
.reset(new Image(StockImage::Yes
, SV_DISCLOSURE_MINUS
));
3797 = IsChecked() ? rCtrlData
.mpDisclosureMinus
.get() : rCtrlData
.mpDisclosurePlus
.get();
3799 DrawImageFlags nStyle
= DrawImageFlags::NONE
;
3801 nStyle
|= DrawImageFlags::Disable
;
3803 Size
aSize(aStateRect
.GetSize());
3804 Size
aImgSize(pImg
->GetSizePixel());
3805 Point
aOff((aSize
.Width() - aImgSize
.Width()) / 2,
3806 (aSize
.Height() - aImgSize
.Height()) / 2);
3807 aOff
+= aStateRect
.TopLeft();
3808 rRenderContext
.DrawImage(aOff
, *pImg
, nStyle
);
3811 void DisclosureButton::KeyInput( const KeyEvent
& rKEvt
)
3813 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
3815 if( !aKeyCode
.GetModifier() &&
3816 ( ( aKeyCode
.GetCode() == KEY_ADD
) ||
3817 ( aKeyCode
.GetCode() == KEY_SUBTRACT
) )
3820 Check( aKeyCode
.GetCode() == KEY_ADD
);
3823 CheckBox::KeyInput( rKEvt
);
3826 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */