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/builder.hxx>
23 #include <vcl/cvtgrf.hxx>
24 #include <vcl/image.hxx>
25 #include <vcl/bitmapex.hxx>
26 #include <vcl/decoview.hxx>
27 #include <vcl/event.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/settings.hxx>
30 #include <vcl/toolkit/dialog.hxx>
31 #include <vcl/toolkit/fixed.hxx>
32 #include <vcl/toolkit/button.hxx>
33 #include <vcl/salnativewidgets.hxx>
34 #include <vcl/toolkit/edit.hxx>
35 #include <vcl/layout.hxx>
36 #include <vcl/stdtext.hxx>
37 #include <vcl/uitest/uiobject.hxx>
39 #include <bitmaps.hlst>
42 #include <vclstatuslistener.hxx>
43 #include <osl/diagnose.h>
45 #include <comphelper/base64.hxx>
46 #include <comphelper/dispatchcommand.hxx>
47 #include <comphelper/lok.hxx>
48 #include <officecfg/Office/Common.hxx>
49 #include <boost/property_tree/ptree.hpp>
50 #include <tools/json_writer.hxx>
51 #include <tools/stream.hxx>
56 constexpr auto PUSHBUTTON_VIEW_STYLE
= WB_3DLOOK
|
57 WB_LEFT
| WB_CENTER
| WB_RIGHT
|
58 WB_TOP
| WB_VCENTER
| WB_BOTTOM
|
59 WB_WORDBREAK
| WB_NOLABEL
|
60 WB_DEFBUTTON
| WB_NOLIGHTBORDER
|
61 WB_RECTSTYLE
| WB_SMALLSTYLE
|
63 constexpr auto RADIOBUTTON_VIEW_STYLE
= WB_3DLOOK
|
64 WB_LEFT
| WB_CENTER
| WB_RIGHT
|
65 WB_TOP
| WB_VCENTER
| WB_BOTTOM
|
66 WB_WORDBREAK
| WB_NOLABEL
;
67 constexpr auto CHECKBOX_VIEW_STYLE
= WB_3DLOOK
|
68 WB_LEFT
| WB_CENTER
| WB_RIGHT
|
69 WB_TOP
| WB_VCENTER
| WB_BOTTOM
|
70 WB_WORDBREAK
| WB_NOLABEL
;
72 #define STYLE_RADIOBUTTON_MONO (sal_uInt16(0x0001)) // legacy
73 #define STYLE_CHECKBOX_MONO (sal_uInt16(0x0001)) // legacy
75 class ImplCommonButtonData
78 ImplCommonButtonData();
80 tools::Rectangle maFocusRect
;
81 tools::Long mnSeparatorX
;
82 DrawButtonFlags mnButtonState
;
84 bool mbGeneratedTooltip
;
87 ImageAlign meImageAlign
;
88 SymbolAlign meSymbolAlign
;
90 Image maCustomContentImage
;
92 /** StatusListener. Updates the button as the slot state changes */
93 rtl::Reference
<VclStatusListener
<Button
>> mpStatusListener
;
96 ImplCommonButtonData::ImplCommonButtonData() : mnSeparatorX(0), mnButtonState(DrawButtonFlags::NONE
),
97 mbSmallSymbol(false), mbGeneratedTooltip(false), meImageAlign(ImageAlign::Top
), meSymbolAlign(SymbolAlign::LEFT
)
101 Button::Button( WindowType nType
) :
103 mpButtonData( std::make_unique
<ImplCommonButtonData
>() )
112 void Button::dispose()
114 if (mpButtonData
->mpStatusListener
.is())
115 mpButtonData
->mpStatusListener
->dispose();
119 void Button::SetCommandHandler(const OUString
& aCommand
, const css::uno::Reference
<css::frame::XFrame
>& rFrame
)
121 maCommand
= aCommand
;
122 SetClickHdl( LINK( this, Button
, dispatchCommandHandler
) );
124 mpButtonData
->mpStatusListener
= new VclStatusListener
<Button
>(this, rFrame
, aCommand
);
125 mpButtonData
->mpStatusListener
->startListening();
130 ImplCallEventListenersAndHandler( VclEventId::ButtonClick
, [this] () { maClickHdl
.Call(this); } );
133 void Button::SetModeImage( const Image
& rImage
)
135 if ( rImage
!= mpButtonData
->maImage
)
137 mpButtonData
->maImage
= rImage
;
138 StateChanged( StateChangedType::Data
);
143 Image
const & Button::GetModeImage( ) const
145 return mpButtonData
->maImage
;
148 bool Button::HasImage() const
150 return !!(mpButtonData
->maImage
);
153 void Button::SetImageAlign( ImageAlign eAlign
)
155 if ( mpButtonData
->meImageAlign
!= eAlign
)
157 mpButtonData
->meImageAlign
= eAlign
;
158 StateChanged( StateChangedType::Data
);
162 ImageAlign
Button::GetImageAlign() const
164 return mpButtonData
->meImageAlign
;
167 void Button::SetCustomButtonImage(const Image
& rImage
)
169 if (rImage
!= mpButtonData
->maCustomContentImage
)
171 mpButtonData
->maCustomContentImage
= rImage
;
172 StateChanged( StateChangedType::Data
);
176 Image
const & Button::GetCustomButtonImage() const
178 return mpButtonData
->maCustomContentImage
;
181 tools::Long
Button::ImplGetSeparatorX() const
183 return mpButtonData
->mnSeparatorX
;
186 void Button::ImplSetSeparatorX( tools::Long nX
)
188 mpButtonData
->mnSeparatorX
= nX
;
191 DrawTextFlags
Button::ImplGetTextStyle( WinBits nWinStyle
, SystemTextColorFlags nSystemTextColorFlags
) const
193 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
194 DrawTextFlags nTextStyle
= FixedText::ImplGetTextStyle(nWinStyle
& ~WB_DEFBUTTON
);
197 nTextStyle
|= DrawTextFlags::Disable
;
199 if ((nSystemTextColorFlags
& SystemTextColorFlags::Mono
) ||
200 (rStyleSettings
.GetOptions() & StyleSettingsOptions::Mono
))
202 nTextStyle
|= DrawTextFlags::Mono
;
208 void Button::ImplDrawAlignedImage(OutputDevice
* pDev
, Point
& rPos
,
211 DrawTextFlags nTextStyle
, tools::Rectangle
*pSymbolRect
,
214 OUString
aText(GetText());
215 bool bDrawImage
= HasImage();
216 bool bDrawText
= !aText
.isEmpty();
217 bool bHasSymbol
= pSymbolRect
!= nullptr;
219 // No text and no image => nothing to do => return
220 if (!bDrawImage
&& !bDrawText
&& !bHasSymbol
)
223 WinBits nWinStyle
= GetStyle();
224 tools::Rectangle
aOutRect( rPos
, rSize
);
225 ImageAlign eImageAlign
= mpButtonData
->meImageAlign
;
226 Size aImageSize
= mpButtonData
->maImage
.GetSizePixel();
228 aImageSize
.setWidth( CalcZoom( aImageSize
.Width() ) );
229 aImageSize
.setHeight( CalcZoom( aImageSize
.Height() ) );
231 // Drawing text or symbol only is simple, use style and output rectangle
232 if (bHasSymbol
&& !bDrawImage
&& !bDrawText
)
234 *pSymbolRect
= aOutRect
;
237 else if (bDrawText
&& !bDrawImage
&& !bHasSymbol
)
239 aOutRect
= DrawControlText(*pDev
, aOutRect
, aText
, nTextStyle
, nullptr, nullptr);
240 tools::Rectangle textRect
= GetTextRect(
241 tools::Rectangle(Point(), Size(0x7fffffff, 0x7fffffff)), aText
, nTextStyle
);
242 // If the button text doesn't fit into it, put it into a tooltip (might happen in sidebar)
243 if (GetQuickHelpText()!= aText
&& mpButtonData
->mbGeneratedTooltip
)
244 SetQuickHelpText("");
245 if (GetQuickHelpText().isEmpty() && textRect
.getOpenWidth() > rSize
.getWidth())
247 SetQuickHelpText(aText
);
248 mpButtonData
->mbGeneratedTooltip
= true;
251 ImplSetFocusRect(aOutRect
);
252 rSize
= aOutRect
.GetSize();
253 rPos
= aOutRect
.TopLeft();
258 // check for HC mode ( image only! )
259 Image
* pImage
= &(mpButtonData
->maImage
);
263 Size aDeviceTextSize
;
264 Point aImagePos
= rPos
;
265 Point aTextPos
= rPos
;
266 tools::Rectangle
aUnion(aImagePos
, aImageSize
);
267 tools::Long nSymbolHeight
= 0;
269 if (bDrawText
|| bHasSymbol
)
271 // Get the size of the text output area ( the symbol will be drawn in
272 // this area as well, so the symbol rectangle will be calculated here, too )
274 tools::Rectangle
aRect(Point(), rSize
);
279 tools::Rectangle aSymbol
;
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 tools::Long nDiff
= (aImageSize
.Height() - aTextSize
.Height()) / 3;
339 aMax
.setWidth( std::max(aTSSize
.Width(), aImageSize
.Width()) );
340 aMax
.setHeight( std::max(aTSSize
.Height(), aImageSize
.Height()) );
342 // Now calculate the output area for the image and the text according to the image align flags
344 if ((eImageAlign
== ImageAlign::Left
) ||
345 (eImageAlign
== ImageAlign::Right
))
347 aImagePos
.setY( rPos
.Y() + (aMax
.Height() - aImageSize
.Height()) / 2 );
348 aTextPos
.setY( rPos
.Y() + (aMax
.Height() - aTSSize
.Height()) / 2 );
350 else if ((eImageAlign
== ImageAlign::LeftBottom
) ||
351 (eImageAlign
== ImageAlign::RightBottom
))
353 aImagePos
.setY( rPos
.Y() + aMax
.Height() - aImageSize
.Height() );
354 aTextPos
.setY( rPos
.Y() + aMax
.Height() - aTSSize
.Height() );
356 else if ((eImageAlign
== ImageAlign::Top
) ||
357 (eImageAlign
== ImageAlign::Bottom
))
359 aImagePos
.setX( rPos
.X() + (aMax
.Width() - aImageSize
.Width()) / 2 );
360 aTextPos
.setX( rPos
.X() + (aMax
.Width() - aTSSize
.Width()) / 2 );
362 else if ((eImageAlign
== ImageAlign::TopRight
) ||
363 (eImageAlign
== ImageAlign::BottomRight
))
365 aImagePos
.setX( rPos
.X() + aMax
.Width() - aImageSize
.Width() );
366 aTextPos
.setX( rPos
.X() + aMax
.Width() - aTSSize
.Width() );
369 if ((eImageAlign
== ImageAlign::LeftTop
) ||
370 (eImageAlign
== ImageAlign::Left
) ||
371 (eImageAlign
== ImageAlign::LeftBottom
))
373 aTextPos
.setX( rPos
.X() + aImageSize
.Width() + nImageSep
);
375 else if ((eImageAlign
== ImageAlign::RightTop
) ||
376 (eImageAlign
== ImageAlign::Right
) ||
377 (eImageAlign
== ImageAlign::RightBottom
))
379 aImagePos
.setX( rPos
.X() + aTSSize
.Width() + nImageSep
);
381 else if ((eImageAlign
== ImageAlign::TopLeft
) ||
382 (eImageAlign
== ImageAlign::Top
) ||
383 (eImageAlign
== ImageAlign::TopRight
))
385 aTextPos
.setY( rPos
.Y() + aImageSize
.Height() + nImageSep
);
387 else if ((eImageAlign
== ImageAlign::BottomLeft
) ||
388 (eImageAlign
== ImageAlign::Bottom
) ||
389 (eImageAlign
== ImageAlign::BottomRight
))
391 aImagePos
.setY( rPos
.Y() + aTSSize
.Height() + nImageSep
);
393 else if (eImageAlign
== ImageAlign::Center
)
395 aImagePos
.setX( rPos
.X() + (aMax
.Width() - aImageSize
.Width()) / 2 );
396 aImagePos
.setY( rPos
.Y() + (aMax
.Height() - aImageSize
.Height()) / 2 );
397 aTextPos
.setX( rPos
.X() + (aMax
.Width() - aTSSize
.Width()) / 2 );
398 aTextPos
.setY( rPos
.Y() + (aMax
.Height() - aTSSize
.Height()) / 2 );
400 aUnion
= tools::Rectangle(aImagePos
, aImageSize
);
401 aUnion
.Union(tools::Rectangle(aTextPos
, aTSSize
));
404 // Now place the combination of text and image in the output area of the button
405 // according to the window style (WinBits)
406 tools::Long nXOffset
= 0;
407 tools::Long nYOffset
= 0;
409 if (nWinStyle
& WB_CENTER
)
411 nXOffset
= (rSize
.Width() - aUnion
.GetWidth()) / 2;
413 else if (nWinStyle
& WB_RIGHT
)
415 nXOffset
= rSize
.Width() - aUnion
.GetWidth();
418 if (nWinStyle
& WB_VCENTER
)
420 nYOffset
= (rSize
.Height() - aUnion
.GetHeight()) / 2;
422 else if (nWinStyle
& WB_BOTTOM
)
424 nYOffset
= rSize
.Height() - aUnion
.GetHeight();
427 // the top left corner should always be visible, so we don't allow negative offsets
428 if (nXOffset
< 0) nXOffset
= 0;
429 if (nYOffset
< 0) nYOffset
= 0;
431 aImagePos
.AdjustX(nXOffset
);
432 aImagePos
.AdjustY(nYOffset
);
433 aTextPos
.AdjustX(nXOffset
);
434 aTextPos
.AdjustY(nYOffset
);
436 // set rPos and rSize to the union
437 rSize
= aUnion
.GetSize();
438 rPos
.AdjustX(nXOffset
);
439 rPos
.AdjustY(nYOffset
);
443 if (mpButtonData
->meSymbolAlign
== SymbolAlign::RIGHT
)
445 Point
aRightPos(aTextPos
.X() + aTextSize
.Width() + aSymbolSize
.Width() / 2, aTextPos
.Y());
446 *pSymbolRect
= tools::Rectangle(aRightPos
, aSymbolSize
);
450 *pSymbolRect
= tools::Rectangle(aTextPos
, aSymbolSize
);
451 aTextPos
.AdjustX(3 * nSymbolHeight
/ 2 );
453 if (mpButtonData
->mbSmallSymbol
)
455 nYOffset
= (aUnion
.GetHeight() - aSymbolSize
.Height()) / 2;
456 pSymbolRect
->SetPosY(aTextPos
.Y() + nYOffset
);
460 DrawImageFlags nStyle
= DrawImageFlags::NONE
;
464 nStyle
|= DrawImageFlags::Disable
;
468 pDev
->DrawImage(aImagePos
, aImageSize
, *pImage
, nStyle
);
470 pDev
->DrawImage(aImagePos
, *pImage
, nStyle
);
474 const tools::Rectangle
aTOutRect(aTextPos
, aTextSize
);
475 ImplSetFocusRect(aTOutRect
);
476 DrawControlText(*pDev
, aTOutRect
, aText
, nTextStyle
, nullptr, nullptr, &aDeviceTextSize
);
480 ImplSetFocusRect(tools::Rectangle(aImagePos
, aImageSize
));
484 void Button::ImplSetFocusRect(const tools::Rectangle
&rFocusRect
)
486 tools::Rectangle aFocusRect
= rFocusRect
;
487 tools::Rectangle
aOutputRect(Point(), GetOutputSizePixel());
489 if (!aFocusRect
.IsEmpty())
491 aFocusRect
.AdjustLeft( -1 );
492 aFocusRect
.AdjustTop( -1 );
493 aFocusRect
.AdjustRight( 1 );
494 aFocusRect
.AdjustBottom( 1 );
497 if (aFocusRect
.Left() < aOutputRect
.Left())
498 aFocusRect
.SetLeft( aOutputRect
.Left() );
499 if (aFocusRect
.Top() < aOutputRect
.Top())
500 aFocusRect
.SetTop( aOutputRect
.Top() );
501 if (aFocusRect
.Right() > aOutputRect
.Right())
502 aFocusRect
.SetRight( aOutputRect
.Right() );
503 if (aFocusRect
.Bottom() > aOutputRect
.Bottom())
504 aFocusRect
.SetBottom( aOutputRect
.Bottom() );
506 mpButtonData
->maFocusRect
= aFocusRect
;
509 const tools::Rectangle
& Button::ImplGetFocusRect() const
511 return mpButtonData
->maFocusRect
;
514 DrawButtonFlags
& Button::GetButtonState()
516 return mpButtonData
->mnButtonState
;
519 DrawButtonFlags
Button::GetButtonState() const
521 return mpButtonData
->mnButtonState
;
524 void Button::ImplSetSymbolAlign( SymbolAlign eAlign
)
526 if ( mpButtonData
->meSymbolAlign
!= eAlign
)
528 mpButtonData
->meSymbolAlign
= eAlign
;
529 StateChanged( StateChangedType::Data
);
533 void Button::SetSmallSymbol()
535 mpButtonData
->mbSmallSymbol
= true;
538 bool Button::IsSmallSymbol () const
540 return mpButtonData
->mbSmallSymbol
;
543 bool Button::set_property(const OUString
&rKey
, const OUString
&rValue
)
545 if (rKey
== "image-position")
547 ImageAlign eAlign
= ImageAlign::Left
;
548 if (rValue
== "left")
549 eAlign
= ImageAlign::Left
;
550 else if (rValue
== "right")
551 eAlign
= ImageAlign::Right
;
552 else if (rValue
== "top")
553 eAlign
= ImageAlign::Top
;
554 else if (rValue
== "bottom")
555 eAlign
= ImageAlign::Bottom
;
556 SetImageAlign(eAlign
);
558 else if (rKey
== "focus-on-click")
560 WinBits nBits
= GetStyle();
561 nBits
&= ~WB_NOPOINTERFOCUS
;
563 nBits
|= WB_NOPOINTERFOCUS
;
567 return Control::set_property(rKey
, rValue
);
571 void Button::statusChanged(const css::frame::FeatureStateEvent
& rEvent
)
573 Enable(rEvent
.IsEnabled
);
576 FactoryFunction
Button::GetUITestFactory() const
578 return ButtonUIObject::create
;
584 std::string_view
symbolTypeName(SymbolType eSymbolType
)
588 case SymbolType::DONTKNOW
: return "DONTKNOW";
589 case SymbolType::IMAGE
: return "IMAGE";
590 case SymbolType::ARROW_UP
: return "ARROW_UP";
591 case SymbolType::ARROW_DOWN
: return "ARROW_DOWN";
592 case SymbolType::ARROW_LEFT
: return "ARROW_LEFT";
593 case SymbolType::ARROW_RIGHT
: return "ARROW_RIGHT";
594 case SymbolType::SPIN_UP
: return "SPIN_UP";
595 case SymbolType::SPIN_DOWN
: return "SPIN_DOWN";
596 case SymbolType::SPIN_LEFT
: return "SPIN_LEFT";
597 case SymbolType::SPIN_RIGHT
: return "SPIN_RIGHT";
598 case SymbolType::FIRST
: return "FIRST";
599 case SymbolType::LAST
: return "LAST";
600 case SymbolType::PREV
: return "PREV";
601 case SymbolType::NEXT
: return "NEXT";
602 case SymbolType::PAGEUP
: return "PAGEUP";
603 case SymbolType::PAGEDOWN
: return "PAGEDOWN";
604 case SymbolType::PLAY
: return "PLAY";
605 case SymbolType::STOP
: return "STOP";
606 case SymbolType::CLOSE
: return "CLOSE";
607 case SymbolType::CHECKMARK
: return "CHECKMARK";
608 case SymbolType::RADIOCHECKMARK
: return "RADIOCHECKMARK";
609 case SymbolType::FLOAT
: return "FLOAT";
610 case SymbolType::DOCK
: return "DOCK";
611 case SymbolType::HIDE
: return "HIDE";
612 case SymbolType::HELP
: return "HELP";
613 case SymbolType::PLUS
: return "PLUS";
621 void Button::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
623 Control::DumpAsPropertyTree(rJsonWriter
);
624 rJsonWriter
.put("text", GetText());
627 SvMemoryStream
aOStm(6535, 6535);
628 if(GraphicConverter::Export(aOStm
, GetModeImage().GetBitmapEx(), ConvertDataFormat::PNG
) == ERRCODE_NONE
)
630 css::uno::Sequence
<sal_Int8
> aSeq( static_cast<sal_Int8
const *>(aOStm
.GetData()), aOStm
.Tell());
631 OStringBuffer
aBuffer("data:image/png;base64,");
632 ::comphelper::Base64::encode(aBuffer
, aSeq
);
633 rJsonWriter
.put("image", aBuffer
);
637 if (GetStyle() & WB_DEFBUTTON
)
638 rJsonWriter
.put("has_default", true);
641 void PushButton::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
643 Button::DumpAsPropertyTree(rJsonWriter
);
644 if (GetSymbol() != SymbolType::DONTKNOW
)
645 rJsonWriter
.put("symbol", symbolTypeName(GetSymbol()));
646 if (isToggleButton())
647 rJsonWriter
.put("isToggle", true);
650 IMPL_STATIC_LINK( Button
, dispatchCommandHandler
, Button
*, pButton
, void )
652 if (pButton
== nullptr)
655 comphelper::dispatchCommand(pButton
->maCommand
, uno::Sequence
<beans::PropertyValue
>());
658 void PushButton::ImplInitPushButtonData()
660 mpWindowImpl
->mbPushButton
= true;
662 meSymbol
= SymbolType::DONTKNOW
;
663 meState
= TRISTATE_FALSE
;
664 mnDDStyle
= PushButtonDropdownStyle::NONE
;
672 vcl::Window
* getPreviousSibling(vcl::Window
const *pParent
)
674 return pParent
? pParent
->GetWindow(GetWindowType::LastChild
) : nullptr;
678 void PushButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
680 nStyle
= ImplInitStyle(getPreviousSibling(pParent
), nStyle
);
681 Button::ImplInit( pParent
, nStyle
, nullptr );
683 if ( nStyle
& WB_NOLIGHTBORDER
)
684 GetButtonState() |= DrawButtonFlags::NoLightBorder
;
686 ImplInitSettings( true );
689 WinBits
PushButton::ImplInitStyle( const vcl::Window
* pPrevWindow
, WinBits nStyle
)
691 if ( !(nStyle
& WB_NOTABSTOP
) )
692 nStyle
|= WB_TABSTOP
;
694 // if no alignment is given, default to "vertically centered". This is because since
695 // #i26046#, we respect the vertical alignment flags (previously we didn't completely),
696 // but we of course want to look as before when no vertical alignment is specified
697 if ( ( nStyle
& ( WB_TOP
| WB_VCENTER
| WB_BOTTOM
) ) == 0 )
698 nStyle
|= WB_VCENTER
;
700 if ( !(nStyle
& WB_NOGROUP
) &&
702 ((pPrevWindow
->GetType() != WindowType::PUSHBUTTON
) &&
703 (pPrevWindow
->GetType() != WindowType::OKBUTTON
) &&
704 (pPrevWindow
->GetType() != WindowType::CANCELBUTTON
) &&
705 (pPrevWindow
->GetType() != WindowType::HELPBUTTON
)) ) )
710 const vcl::Font
& PushButton::GetCanonicalFont( const StyleSettings
& _rStyle
) const
712 return _rStyle
.GetPushButtonFont();
715 const Color
& PushButton::GetCanonicalTextColor( const StyleSettings
& _rStyle
) const
717 return _rStyle
.GetButtonTextColor();
720 void PushButton::ImplInitSettings( bool bBackground
)
722 Button::ImplInitSettings();
728 // #i38498#: do not check for GetParent()->IsChildTransparentModeEnabled()
729 // otherwise the formcontrol button will be overdrawn due to ParentClipMode::NoClip
730 // for radio and checkbox this is ok as they should appear transparent in documents
731 if ( IsNativeControlSupported( ControlType::Pushbutton
, ControlPart::Entire
) ||
732 (GetStyle() & WB_FLATBUTTON
) != 0 )
734 EnableChildTransparentMode();
735 SetParentClipMode( ParentClipMode::NoClip
);
736 SetPaintTransparent( true );
738 if ((GetStyle() & WB_FLATBUTTON
) == 0)
739 mpWindowImpl
->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
741 mpWindowImpl
->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRectsForFlatButtons
;
745 EnableChildTransparentMode( false );
747 SetPaintTransparent( false );
751 void PushButton::ImplDrawPushButtonFrame(vcl::RenderContext
& rRenderContext
,
752 tools::Rectangle
& rRect
, DrawButtonFlags nStyle
)
754 if (!(GetStyle() & (WB_RECTSTYLE
| WB_SMALLSTYLE
)))
756 StyleSettings aStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
757 if (IsControlBackground())
758 aStyleSettings
.Set3DColors(GetControlBackground());
761 DecorationView
aDecoView(&rRenderContext
);
762 if (IsControlBackground())
764 AllSettings aSettings
= rRenderContext
.GetSettings();
765 AllSettings aOldSettings
= aSettings
;
766 StyleSettings aStyleSettings
= aSettings
.GetStyleSettings();
767 if (nStyle
& DrawButtonFlags::Highlight
)
769 // with the custom background, native highlight do nothing, so code below mimic
770 // native highlight by changing luminance
771 Color controlBackgroundColorHighlighted
= GetControlBackground();
772 sal_uInt8 colorLuminance
= controlBackgroundColorHighlighted
.GetLuminance();
773 if (colorLuminance
< 205)
774 controlBackgroundColorHighlighted
.IncreaseLuminance(50);
776 controlBackgroundColorHighlighted
.DecreaseLuminance(50);
777 aStyleSettings
.Set3DColors(controlBackgroundColorHighlighted
);
780 aStyleSettings
.Set3DColors(GetControlBackground());
781 aSettings
.SetStyleSettings(aStyleSettings
);
783 // Call OutputDevice::SetSettings() explicitly, as rRenderContext may
784 // be a vcl::Window in fact, and vcl::Window::SetSettings() will call
785 // Invalidate(), which is a problem, since we're in Paint().
786 rRenderContext
.OutputDevice::SetSettings(aSettings
);
787 rRect
= aDecoView
.DrawButton(rRect
, nStyle
);
788 rRenderContext
.OutputDevice::SetSettings(aOldSettings
);
791 rRect
= aDecoView
.DrawButton(rRect
, nStyle
);
794 bool PushButton::ImplHitTestPushButton( vcl::Window
const * pDev
,
797 tools::Rectangle
aTestRect( Point(), pDev
->GetOutputSizePixel() );
799 return aTestRect
.Contains( rPos
);
802 DrawTextFlags
PushButton::ImplGetTextStyle( SystemTextColorFlags nSystemTextColorFlags
) const
804 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
806 DrawTextFlags nTextStyle
= DrawTextFlags::Mnemonic
| DrawTextFlags::MultiLine
| DrawTextFlags::EndEllipsis
;
808 if ( ( rStyleSettings
.GetOptions() & StyleSettingsOptions::Mono
) ||
809 ( nSystemTextColorFlags
& SystemTextColorFlags::Mono
) )
810 nTextStyle
|= DrawTextFlags::Mono
;
812 if ( GetStyle() & WB_WORDBREAK
)
813 nTextStyle
|= DrawTextFlags::WordBreak
;
814 if ( GetStyle() & WB_NOLABEL
)
815 nTextStyle
&= ~DrawTextFlags::Mnemonic
;
817 if ( GetStyle() & WB_LEFT
)
818 nTextStyle
|= DrawTextFlags::Left
;
819 else if ( GetStyle() & WB_RIGHT
)
820 nTextStyle
|= DrawTextFlags::Right
;
822 nTextStyle
|= DrawTextFlags::Center
;
824 if ( GetStyle() & WB_TOP
)
825 nTextStyle
|= DrawTextFlags::Top
;
826 else if ( GetStyle() & WB_BOTTOM
)
827 nTextStyle
|= DrawTextFlags::Bottom
;
829 nTextStyle
|= DrawTextFlags::VCenter
;
832 nTextStyle
|= DrawTextFlags::Disable
;
837 void PushButton::ImplDrawPushButtonContent(OutputDevice
*pDev
, SystemTextColorFlags nSystemTextColorFlags
,
838 const tools::Rectangle
&rRect
, bool bMenuBtnSep
,
839 DrawButtonFlags nButtonFlags
)
841 const StyleSettings
&rStyleSettings
= GetSettings().GetStyleSettings();
842 tools::Rectangle aInRect
= rRect
;
844 DrawTextFlags nTextStyle
= ImplGetTextStyle(nSystemTextColorFlags
);
845 DrawSymbolFlags nStyle
;
847 if (aInRect
.Right() < aInRect
.Left() || aInRect
.Bottom() < aInRect
.Top())
850 pDev
->Push(vcl::PushFlags::CLIPREGION
);
851 pDev
->IntersectClipRegion(aInRect
);
853 if (nSystemTextColorFlags
& SystemTextColorFlags::Mono
)
856 else if (IsControlForeground())
857 aColor
= GetControlForeground();
859 // Button types with possibly different text coloring are flat buttons and regular buttons. Regular buttons may be action
860 // buttons and may have an additional default status. Moreover all buttons may have an additional pressed and rollover
861 // (highlight) status. Pressed buttons are always in rollover status.
863 else if (GetStyle() & WB_FLATBUTTON
)
864 if (nButtonFlags
& DrawButtonFlags::Pressed
)
865 aColor
= rStyleSettings
.GetFlatButtonPressedRolloverTextColor();
866 else if (nButtonFlags
& DrawButtonFlags::Highlight
)
867 aColor
= rStyleSettings
.GetFlatButtonRolloverTextColor();
869 aColor
= rStyleSettings
.GetFlatButtonTextColor();
871 if (isAction() && (nButtonFlags
& DrawButtonFlags::Default
))
872 if (nButtonFlags
& DrawButtonFlags::Pressed
)
873 aColor
= rStyleSettings
.GetDefaultActionButtonPressedRolloverTextColor();
874 else if (nButtonFlags
& DrawButtonFlags::Highlight
)
875 aColor
= rStyleSettings
.GetDefaultActionButtonRolloverTextColor();
877 aColor
= rStyleSettings
.GetDefaultActionButtonTextColor();
879 if (nButtonFlags
& DrawButtonFlags::Pressed
)
880 aColor
= rStyleSettings
.GetActionButtonPressedRolloverTextColor();
881 else if (nButtonFlags
& DrawButtonFlags::Highlight
)
882 aColor
= rStyleSettings
.GetActionButtonRolloverTextColor();
884 aColor
= rStyleSettings
.GetActionButtonTextColor();
885 else if (nButtonFlags
& DrawButtonFlags::Default
)
886 if (nButtonFlags
& DrawButtonFlags::Pressed
)
887 aColor
= rStyleSettings
.GetDefaultButtonPressedRolloverTextColor();
888 else if (nButtonFlags
& DrawButtonFlags::Highlight
)
889 aColor
= rStyleSettings
.GetDefaultButtonRolloverTextColor();
891 aColor
= rStyleSettings
.GetDefaultButtonTextColor();
893 if (nButtonFlags
& DrawButtonFlags::Pressed
)
894 aColor
= rStyleSettings
.GetButtonPressedRolloverTextColor();
895 else if (nButtonFlags
& DrawButtonFlags::Highlight
)
896 aColor
= rStyleSettings
.GetButtonRolloverTextColor();
898 aColor
= rStyleSettings
.GetButtonTextColor();
900 #if defined(MACOSX) || defined(IOS)
901 // tdf#152486 These are the buttons in infobars where the infobar has a custom
902 // background color and on these platforms the buttons blend with
904 vcl::Window
* pParent
= GetParent();
905 if (pParent
->get_id() == "ExtraButton")
907 while (pParent
&& !pParent
->IsControlBackground())
908 pParent
= pParent
->GetParent();
911 if (aColor
.IsBright() && !pParent
->GetControlBackground().IsDark())
917 pDev
->SetTextColor(aColor
);
920 nStyle
= DrawSymbolFlags::NONE
;
922 nStyle
= DrawSymbolFlags::Disable
;
924 Size aSize
= rRect
.GetSize();
925 Point aPos
= rRect
.TopLeft();
927 sal_Int32 nImageSep
= 1 + (pDev
->GetTextHeight()-10)/2;
930 if ( mnDDStyle
== PushButtonDropdownStyle::MenuButton
||
931 mnDDStyle
== PushButtonDropdownStyle::SplitMenuButton
)
933 tools::Long nSeparatorX
= 0;
934 tools::Rectangle aSymbolRect
= aInRect
;
936 // calculate symbol size
937 tools::Long nSymbolSize
= pDev
->GetTextHeight() / 2 + 1;
938 if (nSymbolSize
> aSize
.Width() / 2)
939 nSymbolSize
= aSize
.Width() / 2;
941 nSeparatorX
= aInRect
.Right() - 2*nSymbolSize
;
943 // tdf#141761 Minimum width should be (1) Pixel, see comment
944 // with same task number above for more info
945 const tools::Long
nWidthAdjust(2*nSymbolSize
);
946 aSize
.setWidth(std::max(static_cast<tools::Long
>(1), aSize
.getWidth() - nWidthAdjust
));
948 // center symbol rectangle in the separated area
949 aSymbolRect
.AdjustRight( -(nSymbolSize
/2) );
950 aSymbolRect
.SetLeft( aSymbolRect
.Right() - nSymbolSize
);
952 ImplDrawAlignedImage( pDev
, aPos
, aSize
, nImageSep
,
953 nTextStyle
, nullptr, true );
955 tools::Long nDistance
= (aSymbolRect
.GetHeight() > 10) ? 2 : 1;
956 DecorationView
aDecoView( pDev
);
957 if( bMenuBtnSep
&& nSeparatorX
> 0 )
959 Point
aStartPt( nSeparatorX
, aSymbolRect
.Top()+nDistance
);
960 Point
aEndPt( nSeparatorX
, aSymbolRect
.Bottom()-nDistance
);
961 aDecoView
.DrawSeparator( aStartPt
, aEndPt
);
963 ImplSetSeparatorX( nSeparatorX
);
965 aDecoView
.DrawSymbol( aSymbolRect
, SymbolType::SPIN_DOWN
, aColor
, nStyle
);
970 tools::Rectangle aSymbolRect
;
971 ImplDrawAlignedImage( pDev
, aPos
, aSize
, nImageSep
,
972 nTextStyle
, IsSymbol() ? &aSymbolRect
: nullptr, true );
976 DecorationView
aDecoView( pDev
);
977 aDecoView
.DrawSymbol( aSymbolRect
, meSymbol
, aColor
, nStyle
);
981 pDev
->Pop(); // restore clipregion
984 void PushButton::ImplDrawPushButton(vcl::RenderContext
& rRenderContext
)
988 DrawButtonFlags nButtonStyle
= GetButtonState();
989 Size
aOutSz(GetOutputSizePixel());
990 tools::Rectangle
aRect(Point(), aOutSz
);
991 tools::Rectangle aInRect
= aRect
;
992 bool bNativeOK
= false;
994 // adjust style if button should be rendered 'pressed'
995 if (mbPressed
|| mbIsActive
)
996 nButtonStyle
|= DrawButtonFlags::Pressed
;
998 if (GetStyle() & WB_FLATBUTTON
)
999 nButtonStyle
|= DrawButtonFlags::Flat
;
1001 // TODO: move this to Window class or make it a member !!!
1002 ControlType aCtrlType
= ControlType::Generic
;
1003 switch(GetParent()->GetType())
1005 case WindowType::LISTBOX
:
1006 case WindowType::MULTILISTBOX
:
1007 case WindowType::TREELISTBOX
:
1008 aCtrlType
= ControlType::Listbox
;
1011 case WindowType::COMBOBOX
:
1012 case WindowType::PATTERNBOX
:
1013 case WindowType::NUMERICBOX
:
1014 case WindowType::METRICBOX
:
1015 case WindowType::CURRENCYBOX
:
1016 case WindowType::DATEBOX
:
1017 case WindowType::TIMEBOX
:
1018 case WindowType::LONGCURRENCYBOX
:
1019 aCtrlType
= ControlType::Combobox
;
1025 bool bDropDown
= (IsSymbol() && (GetSymbol() == SymbolType::SPIN_DOWN
) && GetText().isEmpty());
1027 if( bDropDown
&& (aCtrlType
== ControlType::Combobox
|| aCtrlType
== ControlType::Listbox
))
1029 if (GetParent()->IsNativeControlSupported(aCtrlType
, ControlPart::Entire
))
1031 // skip painting if the button was already drawn by the theme
1032 if (aCtrlType
== ControlType::Combobox
)
1034 Edit
* pEdit
= static_cast<Edit
*>(GetParent());
1035 if (pEdit
->ImplUseNativeBorder(rRenderContext
, pEdit
->GetStyle()))
1038 else if (GetParent()->IsNativeControlSupported(aCtrlType
, ControlPart::HasBackgroundTexture
))
1043 if (!bNativeOK
&& GetParent()->IsNativeControlSupported(aCtrlType
, ControlPart::ButtonDown
))
1045 // let the theme draw it, note we then need support
1046 // for ControlType::Listbox/ControlPart::ButtonDown and ControlType::Combobox/ControlPart::ButtonDown
1048 ImplControlValue aControlValue
;
1049 ControlState nState
= ControlState::NONE
;
1051 if (mbPressed
|| mbIsActive
)
1052 nState
|= ControlState::PRESSED
;
1053 if (GetButtonState() & DrawButtonFlags::Pressed
)
1054 nState
|= ControlState::PRESSED
;
1056 nState
|= ControlState::FOCUSED
;
1057 if (GetButtonState() & DrawButtonFlags::Default
)
1058 nState
|= ControlState::DEFAULT
;
1059 if (Window::IsEnabled())
1060 nState
|= ControlState::ENABLED
;
1062 if (IsMouseOver() && aInRect
.Contains(GetPointerPosPixel()))
1063 nState
|= ControlState::ROLLOVER
;
1065 if ( IsMouseOver() && aInRect
.Contains(GetPointerPosPixel()) && mbIsActive
)
1067 nState
|= ControlState::ROLLOVER
;
1068 nButtonStyle
&= ~DrawButtonFlags::Pressed
;
1071 bNativeOK
= rRenderContext
.DrawNativeControl(aCtrlType
, ControlPart::ButtonDown
, aInRect
, nState
,
1072 aControlValue
, OUString());
1080 bool bRollOver
= (IsMouseOver() && aInRect
.Contains(GetPointerPosPixel()));
1082 nButtonStyle
|= DrawButtonFlags::Highlight
;
1083 bool bDrawMenuSep
= mnDDStyle
== PushButtonDropdownStyle::SplitMenuButton
;
1084 if (GetStyle() & WB_FLATBUTTON
)
1086 if (!bRollOver
&& !HasFocus())
1087 bDrawMenuSep
= false;
1089 // tdf#123175 if there is a custom control bg set, draw the button without outsourcing to the NWF
1090 bNativeOK
= !IsControlBackground() && rRenderContext
.IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Entire
);
1093 PushButtonValue aControlValue
;
1094 aControlValue
.mbIsAction
= isAction();
1096 tools::Rectangle
aCtrlRegion(aInRect
);
1097 ControlState nState
= ControlState::NONE
;
1099 if (mbPressed
|| IsChecked() || mbIsActive
)
1101 nState
|= ControlState::PRESSED
;
1102 nButtonStyle
|= DrawButtonFlags::Pressed
;
1104 if (GetButtonState() & DrawButtonFlags::Pressed
)
1105 nState
|= ControlState::PRESSED
;
1107 nState
|= ControlState::FOCUSED
;
1108 if (GetButtonState() & DrawButtonFlags::Default
)
1109 nState
|= ControlState::DEFAULT
;
1110 if (Window::IsEnabled())
1111 nState
|= ControlState::ENABLED
;
1113 if (bRollOver
|| mbIsActive
)
1115 nButtonStyle
|= DrawButtonFlags::Highlight
;
1116 nState
|= ControlState::ROLLOVER
;
1119 if (mbIsActive
&& bRollOver
)
1121 nState
&= ~ControlState::PRESSED
;
1122 nButtonStyle
&= ~DrawButtonFlags::Pressed
;
1125 if (GetStyle() & WB_FLATBUTTON
)
1126 aControlValue
.m_bFlatButton
= true;
1128 // draw frame into invisible window to have aInRect modified correctly
1129 // but do not shift the inner rect for pressed buttons (ie remove DrawButtonFlags::Pressed)
1130 // this assumes the theme has enough visual cues to signalize the button was pressed
1131 //Window aWin( this );
1132 //ImplDrawPushButtonFrame( &aWin, aInRect, nButtonStyle & ~DrawButtonFlags::Pressed );
1134 // looks better this way as symbols were displaced slightly using the above approach
1135 aInRect
.AdjustTop(4 );
1136 aInRect
.AdjustBottom( -4 );
1137 aInRect
.AdjustLeft(4 );
1138 aInRect
.AdjustRight( -4 );
1140 // prepare single line hint (needed on mac to decide between normal push button and
1141 // rectangular bevel button look)
1142 Size
aFontSize(Application::GetSettings().GetStyleSettings().GetPushButtonFont().GetFontSize());
1143 aFontSize
= rRenderContext
.LogicToPixel(aFontSize
, MapMode(MapUnit::MapPoint
));
1144 Size
aInRectSize(rRenderContext
.LogicToPixel(Size(aInRect
.GetWidth(), aInRect
.GetHeight())));
1145 aControlValue
.mbSingleLine
= (aInRectSize
.Height() < 2 * aFontSize
.Height());
1147 if (!aControlValue
.m_bFlatButton
|| (nState
& ControlState::ROLLOVER
) || (nState
& ControlState::PRESSED
)
1148 || (HasFocus() && mpWindowImpl
->mbUseNativeFocus
1149 && !IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Focus
)))
1151 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Pushbutton
, ControlPart::Entire
, aCtrlRegion
, nState
,
1152 aControlValue
, OUString() /*PushButton::GetText()*/);
1159 // draw content using the same aInRect as non-native VCL would do
1160 ImplDrawPushButtonContent(&rRenderContext
, SystemTextColorFlags::NONE
,
1161 aInRect
, bDrawMenuSep
, nButtonStyle
);
1164 ShowFocus(ImplGetFocusRect());
1170 // draw PushButtonFrame, aInRect has content size afterwards
1171 if (GetStyle() & WB_FLATBUTTON
)
1173 tools::Rectangle
aTempRect(aInRect
);
1174 ImplDrawPushButtonFrame(rRenderContext
, aTempRect
, nButtonStyle
);
1175 aInRect
.AdjustLeft(2 );
1176 aInRect
.AdjustTop(2 );
1177 aInRect
.AdjustRight( -2 );
1178 aInRect
.AdjustBottom( -2 );
1182 ImplDrawPushButtonFrame(rRenderContext
, aInRect
, nButtonStyle
);
1186 ImplDrawPushButtonContent(&rRenderContext
, SystemTextColorFlags::NONE
, aInRect
, bDrawMenuSep
, nButtonStyle
);
1190 ShowFocus(ImplGetFocusRect());
1194 void PushButton::ImplSetDefButton( bool bSet
)
1196 Size
aSize( GetSizePixel() );
1197 Point
aPos( GetPosPixel() );
1198 int dLeft(0), dRight(0), dTop(0), dBottom(0);
1199 bool bSetPos
= false;
1201 if ( IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Entire
) )
1203 tools::Rectangle aBound
, aCont
;
1204 tools::Rectangle
aCtrlRegion( 0, 0, 80, 20 ); // use a constant size to avoid accumulating
1205 // will not work if the theme has dynamic adornment sizes
1206 ImplControlValue aControlValue
;
1208 // get native size of a 'default' button
1209 // and adjust the VCL button if more space for adornment is required
1210 if( GetNativeControlRegion( ControlType::Pushbutton
, ControlPart::Entire
, aCtrlRegion
,
1211 ControlState::DEFAULT
|ControlState::ENABLED
,
1215 dLeft
= aCont
.Left() - aBound
.Left();
1216 dTop
= aCont
.Top() - aBound
.Top();
1217 dRight
= aBound
.Right() - aCont
.Right();
1218 dBottom
= aBound
.Bottom() - aCont
.Bottom();
1219 bSetPos
= dLeft
|| dTop
|| dRight
|| dBottom
;
1225 if( !(GetButtonState() & DrawButtonFlags::Default
) && bSetPos
)
1227 // adjust pos/size when toggling from non-default to default
1228 aPos
.Move(-dLeft
, -dTop
);
1229 aSize
.AdjustWidth(dLeft
+ dRight
);
1230 aSize
.AdjustHeight(dTop
+ dBottom
);
1232 GetButtonState() |= DrawButtonFlags::Default
;
1236 if( (GetButtonState() & DrawButtonFlags::Default
) && bSetPos
)
1238 // adjust pos/size when toggling from default to non-default
1239 aPos
.Move(dLeft
, dTop
);
1240 aSize
.AdjustWidth( -(dLeft
+ dRight
) );
1241 aSize
.AdjustHeight( -(dTop
+ dBottom
) );
1243 GetButtonState() &= ~DrawButtonFlags::Default
;
1246 setPosSizePixel( aPos
.X(), aPos
.Y(), aSize
.Width(), aSize
.Height() );
1251 bool PushButton::ImplIsDefButton() const
1253 return bool(GetButtonState() & DrawButtonFlags::Default
);
1256 PushButton::PushButton( WindowType nType
) :
1259 ImplInitPushButtonData();
1262 PushButton::PushButton( vcl::Window
* pParent
, WinBits nStyle
) :
1263 Button( WindowType::PUSHBUTTON
)
1265 ImplInitPushButtonData();
1266 ImplInit( pParent
, nStyle
);
1269 void PushButton::MouseButtonDown( const MouseEvent
& rMEvt
)
1271 if ( !(rMEvt
.IsLeft() &&
1272 ImplHitTestPushButton( this, rMEvt
.GetPosPixel() )) )
1275 StartTrackingFlags nTrackFlags
= StartTrackingFlags::NONE
;
1277 if ( ( GetStyle() & WB_REPEAT
) &&
1278 ! ( GetStyle() & WB_TOGGLE
) )
1279 nTrackFlags
|= StartTrackingFlags::ButtonRepeat
;
1281 GetButtonState() |= DrawButtonFlags::Pressed
;
1283 StartTracking( nTrackFlags
);
1285 if ( nTrackFlags
& StartTrackingFlags::ButtonRepeat
)
1289 void PushButton::Tracking( const TrackingEvent
& rTEvt
)
1291 if ( rTEvt
.IsTrackingEnded() )
1293 if ( GetButtonState() & DrawButtonFlags::Pressed
)
1295 if ( !(GetStyle() & WB_NOPOINTERFOCUS
) && !rTEvt
.IsTrackingCanceled() )
1298 if ( GetStyle() & WB_TOGGLE
)
1300 // Don't toggle, when aborted
1301 if ( !rTEvt
.IsTrackingCanceled() )
1306 GetButtonState() &= ~DrawButtonFlags::Pressed
;
1313 GetButtonState() &= ~DrawButtonFlags::Pressed
;
1317 // do not call Click handler if aborted
1318 if ( !rTEvt
.IsTrackingCanceled() )
1320 if ( ! ( GetStyle() & WB_REPEAT
) || ( GetStyle() & WB_TOGGLE
) )
1327 if ( ImplHitTestPushButton( this, rTEvt
.GetMouseEvent().GetPosPixel() ) )
1329 if ( GetButtonState() & DrawButtonFlags::Pressed
)
1331 if ( rTEvt
.IsTrackingRepeat() && (GetStyle() & WB_REPEAT
) &&
1332 ! ( GetStyle() & WB_TOGGLE
) )
1337 GetButtonState() |= DrawButtonFlags::Pressed
;
1343 if ( GetButtonState() & DrawButtonFlags::Pressed
)
1345 GetButtonState() &= ~DrawButtonFlags::Pressed
;
1352 void PushButton::KeyInput( const KeyEvent
& rKEvt
)
1354 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
1356 if ( !aKeyCode
.GetModifier() &&
1357 ((aKeyCode
.GetCode() == KEY_RETURN
) || (aKeyCode
.GetCode() == KEY_SPACE
)) )
1359 if ( !(GetButtonState() & DrawButtonFlags::Pressed
) )
1361 GetButtonState() |= DrawButtonFlags::Pressed
;
1365 if ( ( GetStyle() & WB_REPEAT
) &&
1366 ! ( GetStyle() & WB_TOGGLE
) )
1369 else if ( (GetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_ESCAPE
) )
1371 GetButtonState() &= ~DrawButtonFlags::Pressed
;
1375 Button::KeyInput( rKEvt
);
1378 void PushButton::KeyUp( const KeyEvent
& rKEvt
)
1380 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
1382 if ( (GetButtonState() & DrawButtonFlags::Pressed
) &&
1383 ((aKeyCode
.GetCode() == KEY_RETURN
) || (aKeyCode
.GetCode() == KEY_SPACE
)) )
1385 if ( GetStyle() & WB_TOGGLE
)
1390 GetButtonState() &= ~DrawButtonFlags::Pressed
;
1398 GetButtonState() &= ~DrawButtonFlags::Pressed
;
1402 if ( !( GetStyle() & WB_REPEAT
) || ( GetStyle() & WB_TOGGLE
) )
1406 Button::KeyUp( rKEvt
);
1409 void PushButton::FillLayoutData() const
1411 mxLayoutData
.emplace();
1412 const_cast<PushButton
*>(this)->Invalidate();
1415 void PushButton::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
1417 const Image
& rCustomButtonImage
= GetCustomButtonImage();
1418 if (!!rCustomButtonImage
)
1420 rRenderContext
.DrawImage(Point(0, 0), rCustomButtonImage
);
1423 ImplDrawPushButton(rRenderContext
);
1426 void PushButton::Draw( OutputDevice
* pDev
, const Point
& rPos
,
1427 SystemTextColorFlags nFlags
)
1429 Point aPos
= pDev
->LogicToPixel( rPos
);
1430 Size aSize
= GetSizePixel();
1431 tools::Rectangle
aRect( aPos
, aSize
);
1432 vcl::Font aFont
= GetDrawPixelFont( pDev
);
1436 pDev
->SetFont( aFont
);
1438 std::optional
<StyleSettings
> oOrigDevStyleSettings
;
1440 if ( nFlags
& SystemTextColorFlags::Mono
)
1442 pDev
->SetTextColor( COL_BLACK
);
1446 pDev
->SetTextColor( GetTextColor() );
1447 // DecoView uses the FaceColor...
1448 AllSettings aSettings
= pDev
->GetSettings();
1449 StyleSettings aStyleSettings
= aSettings
.GetStyleSettings();
1450 oOrigDevStyleSettings
= aStyleSettings
;
1451 if ( IsControlBackground() )
1452 aStyleSettings
.SetFaceColor( GetControlBackground() );
1454 aStyleSettings
.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() );
1455 aSettings
.SetStyleSettings( aStyleSettings
);
1456 pDev
->OutputDevice::SetSettings( aSettings
);
1458 pDev
->SetTextFillColor();
1460 DecorationView
aDecoView( pDev
);
1461 DrawButtonFlags nButtonStyle
= DrawButtonFlags::NONE
;
1462 if ( nFlags
& SystemTextColorFlags::Mono
)
1463 nButtonStyle
|= DrawButtonFlags::Mono
;
1465 nButtonStyle
|= DrawButtonFlags::Checked
;
1466 aRect
= aDecoView
.DrawButton( aRect
, nButtonStyle
);
1468 ImplDrawPushButtonContent( pDev
, nFlags
, aRect
, true, nButtonStyle
);
1470 // restore original settings (which are not affected by Push/Pop) after
1472 if (oOrigDevStyleSettings
)
1474 AllSettings aSettings
= pDev
->GetSettings();
1475 aSettings
.SetStyleSettings(*oOrigDevStyleSettings
);
1476 pDev
->OutputDevice::SetSettings( aSettings
);
1482 void PushButton::Resize()
1488 void PushButton::GetFocus()
1490 ShowFocus( ImplGetFocusRect() );
1491 SetInputContext( InputContext( GetFont() ) );
1495 void PushButton::LoseFocus()
1499 Button::LoseFocus();
1502 void PushButton::StateChanged( StateChangedType nType
)
1504 Button::StateChanged( nType
);
1506 if ( (nType
== StateChangedType::Enable
) ||
1507 (nType
== StateChangedType::Text
) ||
1508 (nType
== StateChangedType::Data
) ||
1509 (nType
== StateChangedType::State
) ||
1510 (nType
== StateChangedType::UpdateMode
) )
1512 if ( IsReallyVisible() && IsUpdateMode() )
1515 else if ( nType
== StateChangedType::Style
)
1517 SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev
), GetStyle() ) );
1519 bool bIsDefButton
= ( GetStyle() & WB_DEFBUTTON
) != 0;
1520 bool bWasDefButton
= ( GetPrevStyle() & WB_DEFBUTTON
) != 0;
1521 if ( bIsDefButton
!= bWasDefButton
)
1522 ImplSetDefButton( bIsDefButton
);
1524 if ( IsReallyVisible() && IsUpdateMode() )
1526 if ( (GetPrevStyle() & PUSHBUTTON_VIEW_STYLE
) !=
1527 (GetStyle() & PUSHBUTTON_VIEW_STYLE
) )
1531 else if ( (nType
== StateChangedType::Zoom
) ||
1532 (nType
== StateChangedType::ControlFont
) )
1534 ImplInitSettings( false );
1537 else if ( nType
== StateChangedType::ControlForeground
)
1539 ImplInitSettings( false );
1542 else if ( nType
== StateChangedType::ControlBackground
)
1544 ImplInitSettings( true );
1549 void PushButton::DataChanged( const DataChangedEvent
& rDCEvt
)
1551 Button::DataChanged( rDCEvt
);
1553 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
1554 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
1555 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
1556 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
1558 ImplInitSettings( true );
1563 bool PushButton::PreNotify( NotifyEvent
& rNEvt
)
1565 if( rNEvt
.GetType() == NotifyEventType::MOUSEMOVE
)
1567 const MouseEvent
* pMouseEvt
= rNEvt
.GetMouseEvent();
1568 if( pMouseEvt
&& (pMouseEvt
->IsEnterWindow() || pMouseEvt
->IsLeaveWindow()) )
1570 // trigger redraw as mouse over state has changed
1572 // TODO: move this to Window class or make it a member !!!
1573 ControlType aCtrlType
= ControlType::Generic
;
1574 switch( GetParent()->GetType() )
1576 case WindowType::LISTBOX
:
1577 case WindowType::MULTILISTBOX
:
1578 case WindowType::TREELISTBOX
:
1579 aCtrlType
= ControlType::Listbox
;
1582 case WindowType::COMBOBOX
:
1583 case WindowType::PATTERNBOX
:
1584 case WindowType::NUMERICBOX
:
1585 case WindowType::METRICBOX
:
1586 case WindowType::CURRENCYBOX
:
1587 case WindowType::DATEBOX
:
1588 case WindowType::TIMEBOX
:
1589 case WindowType::LONGCURRENCYBOX
:
1590 aCtrlType
= ControlType::Combobox
;
1596 bool bDropDown
= ( IsSymbol() && (GetSymbol()==SymbolType::SPIN_DOWN
) && GetText().isEmpty() );
1598 if( bDropDown
&& GetParent()->IsNativeControlSupported( aCtrlType
, ControlPart::Entire
) &&
1599 !GetParent()->IsNativeControlSupported( aCtrlType
, ControlPart::ButtonDown
) )
1601 vcl::Window
*pBorder
= GetParent()->GetWindow( GetWindowType::Border
);
1602 if(aCtrlType
== ControlType::Combobox
)
1604 // only paint the button part to avoid flickering of the combobox text
1605 tools::Rectangle
aClipRect( Point(), GetOutputSizePixel() );
1606 aClipRect
.SetPos(pBorder
->ScreenToOutputPixel(OutputToScreenPixel(aClipRect
.TopLeft())));
1607 pBorder
->Invalidate( aClipRect
);
1611 pBorder
->Invalidate( InvalidateFlags::NoErase
);
1614 else if( (GetStyle() & WB_FLATBUTTON
) ||
1615 IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Entire
) )
1622 return Button::PreNotify(rNEvt
);
1625 void PushButton::Toggle()
1627 ImplCallEventListenersAndHandler( VclEventId::PushbuttonToggle
, nullptr );
1630 void PushButton::SetSymbol( SymbolType eSymbol
)
1632 if ( meSymbol
!= eSymbol
)
1635 CompatStateChanged( StateChangedType::Data
);
1639 void PushButton::SetSymbolAlign( SymbolAlign eAlign
)
1641 ImplSetSymbolAlign( eAlign
);
1644 void PushButton::SetDropDown( PushButtonDropdownStyle nStyle
)
1646 if ( mnDDStyle
!= nStyle
)
1649 CompatStateChanged( StateChangedType::Data
);
1653 void PushButton::SetState( TriState eState
)
1655 if ( meState
== eState
)
1659 if ( meState
== TRISTATE_FALSE
)
1660 GetButtonState() &= ~DrawButtonFlags(DrawButtonFlags::Checked
| DrawButtonFlags::DontKnow
);
1661 else if ( meState
== TRISTATE_TRUE
)
1663 GetButtonState() &= ~DrawButtonFlags::DontKnow
;
1664 GetButtonState() |= DrawButtonFlags::Checked
;
1666 else // TRISTATE_INDET
1668 GetButtonState() &= ~DrawButtonFlags::Checked
;
1669 GetButtonState() |= DrawButtonFlags::DontKnow
;
1672 CompatStateChanged( StateChangedType::State
);
1676 void PushButton::statusChanged(const css::frame::FeatureStateEvent
& rEvent
)
1678 Button::statusChanged(rEvent
);
1679 if (rEvent
.State
.has
<bool>())
1680 SetPressed(rEvent
.State
.get
<bool>());
1683 void PushButton::SetPressed( bool bPressed
)
1685 if ( mbPressed
!= bPressed
)
1687 mbPressed
= bPressed
;
1688 CompatStateChanged( StateChangedType::Data
);
1692 void PushButton::EndSelection()
1694 EndTracking( TrackingEventFlags::Cancel
);
1695 if ( !isDisposed() &&
1696 GetButtonState() & DrawButtonFlags::Pressed
)
1698 GetButtonState() &= ~DrawButtonFlags::Pressed
;
1704 Size
PushButton::CalcMinimumSize() const
1710 if ( IsSmallSymbol ())
1711 aSize
= Size( 16, 12 );
1713 aSize
= Size( 26, 24 );
1715 else if ( Button::HasImage() )
1716 aSize
= GetModeImage().GetSizePixel();
1717 if( mnDDStyle
== PushButtonDropdownStyle::MenuButton
||
1718 mnDDStyle
== PushButtonDropdownStyle::SplitMenuButton
)
1720 tools::Long nSymbolSize
= GetTextHeight() / 2 + 1;
1721 aSize
.AdjustWidth(2*nSymbolSize
);
1723 if (!PushButton::GetText().isEmpty())
1725 Size textSize
= GetTextRect( tools::Rectangle( Point(), Size( 0x7fffffff, 0x7fffffff ) ),
1726 PushButton::GetText(), ImplGetTextStyle( SystemTextColorFlags::NONE
) ).GetSize();
1728 tools::Long nTextHeight
= textSize
.Height() * 1.15;
1730 ImageAlign eImageAlign
= GetImageAlign();
1731 // tdf#142337 only considering the simple top/bottom/left/right possibilities
1732 if (eImageAlign
== ImageAlign::Top
|| eImageAlign
== ImageAlign::Bottom
)
1734 aSize
.AdjustHeight(nTextHeight
);
1735 aSize
.setWidth(std::max(aSize
.Width(), textSize
.Width()));
1739 aSize
.AdjustWidth(textSize
.Width());
1740 aSize
.setHeight(std::max(aSize
.Height(), nTextHeight
));
1744 // cf. ImplDrawPushButton ...
1745 if( (GetStyle() & WB_SMALLSTYLE
) == 0 )
1747 aSize
.AdjustWidth(24 );
1748 aSize
.AdjustHeight(12 );
1751 return CalcWindowSize( aSize
);
1754 Size
PushButton::GetOptimalSize() const
1756 return CalcMinimumSize();
1759 bool PushButton::set_property(const OUString
&rKey
, const OUString
&rValue
)
1761 if (rKey
== "has-default")
1763 WinBits nBits
= GetStyle();
1764 nBits
&= ~WB_DEFBUTTON
;
1766 nBits
|= WB_DEFBUTTON
;
1770 return Button::set_property(rKey
, rValue
);
1774 void PushButton::ShowFocus(const tools::Rectangle
& rRect
)
1776 if (IsNativeControlSupported(ControlType::Pushbutton
, ControlPart::Focus
))
1778 PushButtonValue aControlValue
;
1779 aControlValue
.mbIsAction
= isAction();
1780 tools::Rectangle
aInRect(Point(), GetOutputSizePixel());
1781 GetOutDev()->DrawNativeControl(ControlType::Pushbutton
, ControlPart::Focus
, aInRect
,
1782 ControlState::FOCUSED
, aControlValue
, OUString());
1784 Button::ShowFocus(rRect
);
1787 void OKButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
1790 PushButton::ImplInit( pParent
, nStyle
);
1792 SetText( GetStandardText( StandardButtonType::OK
) );
1795 OKButton::OKButton( vcl::Window
* pParent
, WinBits nStyle
) :
1796 PushButton( WindowType::OKBUTTON
)
1798 ImplInit( pParent
, nStyle
);
1801 void OKButton::Click()
1803 // close parent if no link set
1804 if ( !GetClickHdl() )
1806 vcl::Window
* pParent
= getNonLayoutParent(this);
1807 if ( pParent
->IsSystemWindow() )
1809 if ( pParent
->IsDialog() )
1811 VclPtr
<Dialog
> xParent( static_cast<Dialog
*>(pParent
) );
1812 if ( xParent
->IsInExecute() )
1813 xParent
->EndDialog( RET_OK
);
1814 // prevent recursive calls
1815 else if ( !xParent
->IsInClose() )
1817 if ( pParent
->GetStyle() & WB_CLOSEABLE
)
1823 if ( pParent
->GetStyle() & WB_CLOSEABLE
)
1824 static_cast<SystemWindow
*>(pParent
)->Close();
1830 PushButton::Click();
1834 void CancelButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
1837 PushButton::ImplInit( pParent
, nStyle
);
1839 SetText( GetStandardText( StandardButtonType::Cancel
) );
1842 CancelButton::CancelButton( vcl::Window
* pParent
, WinBits nStyle
) :
1843 PushButton( WindowType::CANCELBUTTON
)
1845 ImplInit( pParent
, nStyle
);
1848 void CancelButton::Click()
1850 // close parent if link not set
1851 if ( !GetClickHdl() )
1853 vcl::Window
* pParent
= getNonLayoutParent(this);
1854 if ( pParent
->IsSystemWindow() )
1856 if ( pParent
->IsDialog() )
1858 if ( static_cast<Dialog
*>(pParent
)->IsInExecute() )
1859 static_cast<Dialog
*>(pParent
)->EndDialog();
1860 // prevent recursive calls
1861 else if ( !static_cast<Dialog
*>(pParent
)->IsInClose() )
1863 if ( pParent
->GetStyle() & WB_CLOSEABLE
)
1864 static_cast<Dialog
*>(pParent
)->Close();
1869 if ( pParent
->GetStyle() & WB_CLOSEABLE
)
1870 static_cast<SystemWindow
*>(pParent
)->Close();
1876 PushButton::Click();
1880 CloseButton::CloseButton( vcl::Window
* pParent
)
1881 : CancelButton(pParent
, 0)
1883 SetText( GetStandardText( StandardButtonType::Close
) );
1886 void HelpButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
1889 PushButton::ImplInit( pParent
, nStyle
| WB_NOPOINTERFOCUS
);
1891 SetText( GetStandardText( StandardButtonType::Help
) );
1894 HelpButton::HelpButton( vcl::Window
* pParent
, WinBits nStyle
) :
1895 PushButton( WindowType::HELPBUTTON
)
1897 ImplInit( pParent
, nStyle
);
1900 void HelpButton::Click()
1902 // trigger help if no link set
1903 if ( !GetClickHdl() )
1905 vcl::Window
* pFocusWin
= Application::GetFocusWindow();
1906 if ( !pFocusWin
|| comphelper::LibreOfficeKit::isActive() )
1909 HelpEvent
aEvt( pFocusWin
->GetPointerPosPixel(), HelpEventMode::CONTEXT
);
1910 pFocusWin
->RequestHelp( aEvt
);
1912 PushButton::Click();
1915 void HelpButton::StateChanged( StateChangedType nStateChange
)
1917 // Hide when we have no help URL.
1918 if (comphelper::LibreOfficeKit::isActive() &&
1919 officecfg::Office::Common::Help::HelpRootURL::get().isEmpty())
1922 PushButton::StateChanged(nStateChange
);
1925 void RadioButton::ImplInitRadioButtonData()
1928 mbRadioCheck
= true;
1929 mbStateChanged
= false;
1932 void RadioButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
1934 nStyle
= ImplInitStyle(getPreviousSibling(pParent
), nStyle
);
1935 Button::ImplInit( pParent
, nStyle
, nullptr );
1937 ImplInitSettings( true );
1940 WinBits
RadioButton::ImplInitStyle( const vcl::Window
* pPrevWindow
, WinBits nStyle
) const
1942 if ( !(nStyle
& WB_NOGROUP
) &&
1943 (!pPrevWindow
|| (pPrevWindow
->GetType() != WindowType::RADIOBUTTON
)) )
1945 if ( !(nStyle
& WB_NOTABSTOP
) )
1948 nStyle
|= WB_TABSTOP
;
1950 nStyle
&= ~WB_TABSTOP
;
1956 const vcl::Font
& RadioButton::GetCanonicalFont( const StyleSettings
& _rStyle
) const
1958 return _rStyle
.GetRadioCheckFont();
1961 const Color
& RadioButton::GetCanonicalTextColor( const StyleSettings
& _rStyle
) const
1963 return _rStyle
.GetRadioCheckTextColor();
1966 void RadioButton::ImplInitSettings( bool bBackground
)
1968 Button::ImplInitSettings();
1973 vcl::Window
* pParent
= GetParent();
1974 if ( !IsControlBackground() &&
1975 (pParent
->IsChildTransparentModeEnabled() || IsNativeControlSupported( ControlType::Radiobutton
, ControlPart::Entire
) ) )
1977 EnableChildTransparentMode();
1978 SetParentClipMode( ParentClipMode::NoClip
);
1979 SetPaintTransparent( true );
1981 if( IsNativeControlSupported( ControlType::Radiobutton
, ControlPart::Entire
) )
1982 mpWindowImpl
->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
1986 EnableChildTransparentMode( false );
1987 SetParentClipMode();
1988 SetPaintTransparent( false );
1990 if ( IsControlBackground() )
1991 SetBackground( GetControlBackground() );
1993 SetBackground( pParent
->GetBackground() );
1997 void RadioButton::ImplDrawRadioButtonState(vcl::RenderContext
& rRenderContext
)
1999 bool bNativeOK
= false;
2001 // no native drawing for image radio buttons
2002 if (!maImage
&& rRenderContext
.IsNativeControlSupported(ControlType::Radiobutton
, ControlPart::Entire
))
2004 ImplControlValue
aControlValue( mbChecked
? ButtonValue::On
: ButtonValue::Off
);
2005 tools::Rectangle
aCtrlRect(maStateRect
.TopLeft(), maStateRect
.GetSize());
2006 ControlState nState
= ControlState::NONE
;
2008 if (GetButtonState() & DrawButtonFlags::Pressed
)
2009 nState
|= ControlState::PRESSED
;
2011 nState
|= ControlState::FOCUSED
;
2012 if (GetButtonState() & DrawButtonFlags::Default
)
2013 nState
|= ControlState::DEFAULT
;
2015 nState
|= ControlState::ENABLED
;
2017 if (IsMouseOver() && maMouseRect
.Contains(GetPointerPosPixel()))
2018 nState
|= ControlState::ROLLOVER
;
2020 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Radiobutton
, ControlPart::Entire
, aCtrlRect
,
2021 nState
, aControlValue
, OUString());
2029 DrawButtonFlags nStyle
= GetButtonState();
2031 nStyle
|= DrawButtonFlags::Disabled
;
2033 nStyle
|= DrawButtonFlags::Checked
;
2034 Image aImage
= GetRadioImage(rRenderContext
.GetSettings(), nStyle
);
2036 rRenderContext
.DrawImage(maStateRect
.TopLeft(), maStateRect
.GetSize(), aImage
);
2038 rRenderContext
.DrawImage(maStateRect
.TopLeft(), aImage
);
2044 DecorationView
aDecoView(&rRenderContext
);
2045 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
2046 tools::Rectangle aImageRect
= maStateRect
;
2047 Size aImageSize
= maImage
.GetSizePixel();
2048 bool bEnabled
= IsEnabled();
2050 aImageSize
.setWidth( CalcZoom(aImageSize
.Width()) );
2051 aImageSize
.setHeight( CalcZoom(aImageSize
.Height()) );
2053 aImageRect
.AdjustLeft( 1 );
2054 aImageRect
.AdjustTop( 1 );
2055 aImageRect
.AdjustRight( -1 );
2056 aImageRect
.AdjustBottom( -1 );
2058 // display border and selection status
2059 aImageRect
= aDecoView
.DrawFrame(aImageRect
, DrawFrameStyle::DoubleIn
);
2060 if ((GetButtonState() & DrawButtonFlags::Pressed
) || !bEnabled
)
2061 rRenderContext
.SetFillColor( rStyleSettings
.GetFaceColor());
2063 rRenderContext
.SetFillColor(rStyleSettings
.GetFieldColor());
2064 rRenderContext
.SetLineColor();
2065 rRenderContext
.DrawRect(aImageRect
);
2068 DrawImageFlags nImageStyle
= DrawImageFlags::NONE
;
2070 nImageStyle
|= DrawImageFlags::Disable
;
2072 Image
* pImage
= &maImage
;
2074 Point
aImagePos(aImageRect
.TopLeft());
2075 aImagePos
.AdjustX((aImageRect
.GetWidth() - aImageSize
.Width()) / 2 );
2076 aImagePos
.AdjustY((aImageRect
.GetHeight() - aImageSize
.Height()) / 2 );
2078 rRenderContext
.DrawImage(aImagePos
, aImageSize
, *pImage
, nImageStyle
);
2080 rRenderContext
.DrawImage(aImagePos
, *pImage
, nImageStyle
);
2082 aImageRect
.AdjustLeft( 1 );
2083 aImageRect
.AdjustTop( 1 );
2084 aImageRect
.AdjustRight( -1 );
2085 aImageRect
.AdjustBottom( -1 );
2087 ImplSetFocusRect(aImageRect
);
2091 rRenderContext
.SetLineColor(rStyleSettings
.GetHighlightColor());
2092 rRenderContext
.SetFillColor();
2093 if ((aImageSize
.Width() >= 20) || (aImageSize
.Height() >= 20))
2095 aImageRect
.AdjustLeft( 1 );
2096 aImageRect
.AdjustTop( 1 );
2097 aImageRect
.AdjustRight( -1 );
2098 aImageRect
.AdjustBottom( -1 );
2100 rRenderContext
.DrawRect(aImageRect
);
2101 aImageRect
.AdjustLeft( 1 );
2102 aImageRect
.AdjustTop( 1 );
2103 aImageRect
.AdjustRight( -1 );
2104 aImageRect
.AdjustBottom( -1 );
2105 rRenderContext
.DrawRect(aImageRect
);
2109 ShowFocus(ImplGetFocusRect());
2113 // for drawing RadioButton or CheckButton that has Text and/or Image
2114 void Button::ImplDrawRadioCheck(OutputDevice
* pDev
, WinBits nWinStyle
, SystemTextColorFlags nSystemTextColorFlags
,
2115 const Point
& rPos
, const Size
& rSize
,
2116 const Size
& rImageSize
, tools::Rectangle
& rStateRect
,
2117 tools::Rectangle
& rMouseRect
)
2119 DrawTextFlags nTextStyle
= Button::ImplGetTextStyle( nWinStyle
, nSystemTextColorFlags
);
2121 const tools::Long nImageSep
= GetDrawPixel( pDev
, ImplGetImageToTextDistance() );
2122 Size
aSize( rSize
);
2124 aPos
.AdjustX(rImageSize
.Width() + nImageSep
);
2126 // tdf#141761 Old (convenience?) adjustment of width may lead to empty
2127 // or negative(!) Size, that needs to be avoided. The coordinate context
2128 // is pixel-oriented (all Paints of Controls are, historically), so
2129 // the minimum width should be '1' Pixel.
2130 // Hint: nImageSep is based on Zoom (using Window::CalcZoom) and
2131 // MapModes (using Window::GetDrawPixel) - so potentially a wide range
2132 // of unpredictable values is possible
2133 const tools::Long
nWidthAdjust(rImageSize
.Width() + nImageSep
);
2134 aSize
.setWidth(std::max(static_cast<tools::Long
>(1), aSize
.getWidth() - nWidthAdjust
));
2136 // if the text rect height is smaller than the height of the image
2137 // then for single lines the default should be centered text
2138 if( (nWinStyle
& (WB_TOP
|WB_VCENTER
|WB_BOTTOM
)) == 0 &&
2139 (rImageSize
.Height() > rSize
.Height() || ! (nWinStyle
& WB_WORDBREAK
) ) )
2141 nTextStyle
&= ~DrawTextFlags(DrawTextFlags::Top
|DrawTextFlags::Bottom
);
2142 nTextStyle
|= DrawTextFlags::VCenter
;
2143 aSize
.setHeight( rImageSize
.Height() );
2146 ImplDrawAlignedImage( pDev
, aPos
, aSize
, 1, nTextStyle
);
2148 rMouseRect
= tools::Rectangle( aPos
, aSize
);
2149 rMouseRect
.SetLeft( rPos
.X() );
2151 rStateRect
.SetLeft( rPos
.X() );
2152 rStateRect
.SetTop( rMouseRect
.Top() );
2154 if ( aSize
.Height() > rImageSize
.Height() )
2155 rStateRect
.AdjustTop(( aSize
.Height() - rImageSize
.Height() ) / 2 );
2158 rStateRect
.AdjustTop( -(( rImageSize
.Height() - aSize
.Height() ) / 2) );
2159 if( rStateRect
.Top() < 0 )
2160 rStateRect
.SetTop( 0 );
2163 rStateRect
.SetRight( rStateRect
.Left()+rImageSize
.Width()-1 );
2164 rStateRect
.SetBottom( rStateRect
.Top()+rImageSize
.Height()-1 );
2166 if ( rStateRect
.Bottom() > rMouseRect
.Bottom() )
2167 rMouseRect
.SetBottom( rStateRect
.Bottom() );
2170 void RadioButton::ImplDraw( OutputDevice
* pDev
, SystemTextColorFlags nSystemTextColorFlags
,
2171 const Point
& rPos
, const Size
& rSize
,
2172 const Size
& rImageSize
, tools::Rectangle
& rStateRect
,
2173 tools::Rectangle
& rMouseRect
)
2175 WinBits nWinStyle
= GetStyle();
2176 OUString
aText( GetText() );
2178 pDev
->Push( vcl::PushFlags::CLIPREGION
);
2179 pDev
->IntersectClipRegion( tools::Rectangle( rPos
, rSize
) );
2181 // no image radio button
2184 if (!aText
.isEmpty() || HasImage())
2186 Button::ImplDrawRadioCheck(pDev
, nWinStyle
, nSystemTextColorFlags
,
2187 rPos
, rSize
, rImageSize
,
2188 rStateRect
, rMouseRect
);
2192 rStateRect
.SetLeft( rPos
.X() );
2193 if ( nWinStyle
& WB_VCENTER
)
2194 rStateRect
.SetTop( rPos
.Y()+((rSize
.Height()-rImageSize
.Height())/2) );
2195 else if ( nWinStyle
& WB_BOTTOM
)
2196 rStateRect
.SetTop( rPos
.Y()+rSize
.Height()-rImageSize
.Height() ); //-1;
2198 rStateRect
.SetTop( rPos
.Y() );
2199 rStateRect
.SetRight( rStateRect
.Left()+rImageSize
.Width()-1 );
2200 rStateRect
.SetBottom( rStateRect
.Top()+rImageSize
.Height()-1 );
2201 rMouseRect
= rStateRect
;
2203 ImplSetFocusRect( rStateRect
);
2208 bool bTopImage
= (nWinStyle
& WB_TOP
) != 0;
2209 Size aImageSize
= maImage
.GetSizePixel();
2210 tools::Rectangle
aImageRect( rPos
, rSize
);
2211 tools::Long nTextHeight
= pDev
->GetTextHeight();
2212 tools::Long nTextWidth
= pDev
->GetCtrlTextWidth( aText
);
2214 // calculate position and sizes
2215 if (!aText
.isEmpty())
2217 Size
aTmpSize( (aImageSize
.Width()+8), (aImageSize
.Height()+8) );
2220 aImageRect
.SetLeft( (rSize
.Width()-aTmpSize
.Width())/2 );
2221 aImageRect
.SetTop( (rSize
.Height()-(aTmpSize
.Height()+nTextHeight
+6))/2 );
2224 aImageRect
.SetTop( (rSize
.Height()-aTmpSize
.Height())/2 );
2226 aImageRect
.SetRight( aImageRect
.Left()+aTmpSize
.Width() );
2227 aImageRect
.SetBottom( aImageRect
.Top()+aTmpSize
.Height() );
2230 Point aTxtPos
= rPos
;
2233 aTxtPos
.AdjustX((rSize
.Width()-nTextWidth
)/2 );
2234 aTxtPos
.AdjustY(aImageRect
.Bottom()+6 );
2238 aTxtPos
.AdjustX(aImageRect
.Right()+8 );
2239 aTxtPos
.AdjustY((rSize
.Height()-nTextHeight
)/2 );
2241 pDev
->DrawCtrlText( aTxtPos
, aText
, 0, aText
.getLength() );
2244 rMouseRect
= aImageRect
;
2245 rStateRect
= aImageRect
;
2251 void RadioButton::ImplDrawRadioButton(vcl::RenderContext
& rRenderContext
)
2257 aImageSize
= ImplGetRadioImageSize();
2259 aImageSize
= maImage
.GetSizePixel();
2261 aImageSize
.setWidth( CalcZoom(aImageSize
.Width()) );
2262 aImageSize
.setHeight( CalcZoom(aImageSize
.Height()) );
2264 // Draw control text
2265 ImplDraw(&rRenderContext
, SystemTextColorFlags::NONE
, Point(), GetOutputSizePixel(),
2266 aImageSize
, maStateRect
, maMouseRect
);
2268 if (!maImage
&& HasFocus())
2269 ShowFocus(ImplGetFocusRect());
2271 ImplDrawRadioButtonState(rRenderContext
);
2274 void RadioButton::group(RadioButton
&rOther
)
2276 if (&rOther
== this)
2281 m_xGroup
= std::make_shared
<std::vector
<VclPtr
<RadioButton
> >>();
2282 m_xGroup
->push_back(this);
2285 auto aFind
= std::find(m_xGroup
->begin(), m_xGroup
->end(), VclPtr
<RadioButton
>(&rOther
));
2286 if (aFind
== m_xGroup
->end())
2288 m_xGroup
->push_back(&rOther
);
2290 if (rOther
.m_xGroup
)
2292 std::vector
< VclPtr
<RadioButton
> > aOthers(rOther
.GetRadioButtonGroup(false));
2293 //make all members of the group share the same button group
2294 for (auto const& elem
: aOthers
)
2296 aFind
= std::find(m_xGroup
->begin(), m_xGroup
->end(), elem
);
2297 if (aFind
== m_xGroup
->end())
2298 m_xGroup
->push_back(elem
);
2302 //make all members of the group share the same button group
2303 for (VclPtr
<RadioButton
> const & pButton
: *m_xGroup
)
2305 pButton
->m_xGroup
= m_xGroup
;
2309 //if this one is checked, uncheck all the others
2311 ImplUncheckAllOther();
2314 std::vector
< VclPtr
<RadioButton
> > RadioButton::GetRadioButtonGroup(bool bIncludeThis
) const
2320 std::vector
< VclPtr
<RadioButton
> > aGroup
;
2321 for (VclPtr
<RadioButton
> const & pRadioButton
: *m_xGroup
)
2323 if (pRadioButton
== this)
2325 aGroup
.push_back(pRadioButton
);
2330 std::vector
<VclPtr
<RadioButton
>> aGroup
;
2331 if (mbUsesExplicitGroup
)
2336 // go back to first in group;
2337 vcl::Window
* pFirst
= const_cast<RadioButton
*>(this);
2338 while( ( pFirst
->GetStyle() & WB_GROUP
) == 0 )
2340 vcl::Window
* pWindow
= pFirst
->GetWindow( GetWindowType::Prev
);
2346 // insert radiobuttons up to next group
2349 if( pFirst
->GetType() == WindowType::RADIOBUTTON
)
2351 if( pFirst
!= this || bIncludeThis
)
2352 aGroup
.emplace_back(static_cast<RadioButton
*>(pFirst
) );
2354 pFirst
= pFirst
->GetWindow( GetWindowType::Next
);
2355 } while( pFirst
&& ( ( pFirst
->GetStyle() & WB_GROUP
) == 0 ) );
2360 void RadioButton::ImplUncheckAllOther()
2362 mpWindowImpl
->mnStyle
|= WB_TABSTOP
;
2364 std::vector
<VclPtr
<RadioButton
> > aGroup(GetRadioButtonGroup(false));
2365 // iterate over radio button group and checked buttons
2366 for (VclPtr
<RadioButton
>& pWindow
: aGroup
)
2368 if ( pWindow
->IsChecked() )
2370 pWindow
->SetState( false );
2371 if ( pWindow
->isDisposed() )
2375 // not inside if clause to always remove wrongly set WB_TABSTOPS
2376 pWindow
->mpWindowImpl
->mnStyle
&= ~WB_TABSTOP
;
2380 void RadioButton::ImplCallClick( bool bGrabFocus
, GetFocusFlags nFocusFlags
)
2382 mbStateChanged
= !mbChecked
;
2384 mpWindowImpl
->mnStyle
|= WB_TABSTOP
;
2386 VclPtr
<vcl::Window
> xWindow
= this;
2388 ImplUncheckAllOther();
2389 if ( xWindow
->isDisposed() )
2392 ImplGrabFocus( nFocusFlags
);
2393 if ( xWindow
->isDisposed() )
2395 if ( mbStateChanged
)
2397 if ( xWindow
->isDisposed() )
2400 if ( xWindow
->isDisposed() )
2402 mbStateChanged
= false;
2405 RadioButton::RadioButton(vcl::Window
* pParent
, bool bUsesExplicitGroup
, WinBits nStyle
)
2406 : Button(WindowType::RADIOBUTTON
)
2407 , mbUsesExplicitGroup(bUsesExplicitGroup
)
2409 ImplInitRadioButtonData();
2410 ImplInit( pParent
, nStyle
);
2413 RadioButton::~RadioButton()
2418 void RadioButton::dispose()
2422 m_xGroup
->erase(std::remove(m_xGroup
->begin(), m_xGroup
->end(), VclPtr
<RadioButton
>(this)),
2429 void RadioButton::MouseButtonDown( const MouseEvent
& rMEvt
)
2431 if ( rMEvt
.IsLeft() && maMouseRect
.Contains( rMEvt
.GetPosPixel() ) )
2433 GetButtonState() |= DrawButtonFlags::Pressed
;
2439 Button::MouseButtonDown( rMEvt
);
2442 void RadioButton::Tracking( const TrackingEvent
& rTEvt
)
2444 if ( rTEvt
.IsTrackingEnded() )
2446 if ( GetButtonState() & DrawButtonFlags::Pressed
)
2448 if ( !(GetStyle() & WB_NOPOINTERFOCUS
) && !rTEvt
.IsTrackingCanceled() )
2451 GetButtonState() &= ~DrawButtonFlags::Pressed
;
2453 // do not call click handler if aborted
2454 if ( !rTEvt
.IsTrackingCanceled() )
2464 if ( maMouseRect
.Contains( rTEvt
.GetMouseEvent().GetPosPixel() ) )
2466 if ( !(GetButtonState() & DrawButtonFlags::Pressed
) )
2468 GetButtonState() |= DrawButtonFlags::Pressed
;
2474 if ( GetButtonState() & DrawButtonFlags::Pressed
)
2476 GetButtonState() &= ~DrawButtonFlags::Pressed
;
2483 void RadioButton::KeyInput( const KeyEvent
& rKEvt
)
2485 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
2487 if ( !aKeyCode
.GetModifier() && (aKeyCode
.GetCode() == KEY_SPACE
) )
2489 if ( !(GetButtonState() & DrawButtonFlags::Pressed
) )
2491 GetButtonState() |= DrawButtonFlags::Pressed
;
2495 else if ( (GetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_ESCAPE
) )
2497 GetButtonState() &= ~DrawButtonFlags::Pressed
;
2501 Button::KeyInput( rKEvt
);
2504 void RadioButton::KeyUp( const KeyEvent
& rKEvt
)
2506 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
2508 if ( (GetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_SPACE
) )
2510 GetButtonState() &= ~DrawButtonFlags::Pressed
;
2514 Button::KeyUp( rKEvt
);
2517 void RadioButton::FillLayoutData() const
2519 mxLayoutData
.emplace();
2520 const_cast<RadioButton
*>(this)->Invalidate();
2523 void RadioButton::Paint( vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& )
2525 ImplDrawRadioButton(rRenderContext
);
2528 void RadioButton::Draw( OutputDevice
* pDev
, const Point
& rPos
,
2529 SystemTextColorFlags nFlags
)
2533 MapMode
aResMapMode( MapUnit::Map100thMM
);
2534 Point aPos
= pDev
->LogicToPixel( rPos
);
2535 Size aSize
= GetSizePixel();
2536 Size aImageSize
= pDev
->LogicToPixel( Size( 300, 300 ), aResMapMode
);
2537 Size aBrd1Size
= pDev
->LogicToPixel( Size( 20, 20 ), aResMapMode
);
2538 Size aBrd2Size
= pDev
->LogicToPixel( Size( 60, 60 ), aResMapMode
);
2539 vcl::Font aFont
= GetDrawPixelFont( pDev
);
2540 tools::Rectangle aStateRect
;
2541 tools::Rectangle aMouseRect
;
2543 aImageSize
.setWidth( CalcZoom( aImageSize
.Width() ) );
2544 aImageSize
.setHeight( CalcZoom( aImageSize
.Height() ) );
2545 aBrd1Size
.setWidth( CalcZoom( aBrd1Size
.Width() ) );
2546 aBrd1Size
.setHeight( CalcZoom( aBrd1Size
.Height() ) );
2547 aBrd2Size
.setWidth( CalcZoom( aBrd2Size
.Width() ) );
2548 aBrd2Size
.setHeight( CalcZoom( aBrd2Size
.Height() ) );
2550 if ( !aBrd1Size
.Width() )
2551 aBrd1Size
.setWidth( 1 );
2552 if ( !aBrd1Size
.Height() )
2553 aBrd1Size
.setHeight( 1 );
2554 if ( !aBrd2Size
.Width() )
2555 aBrd2Size
.setWidth( 1 );
2556 if ( !aBrd2Size
.Height() )
2557 aBrd2Size
.setHeight( 1 );
2561 pDev
->SetFont( aFont
);
2562 if ( nFlags
& SystemTextColorFlags::Mono
)
2563 pDev
->SetTextColor( COL_BLACK
);
2565 pDev
->SetTextColor( GetTextColor() );
2566 pDev
->SetTextFillColor();
2568 ImplDraw( pDev
, nFlags
, aPos
, aSize
,
2569 aImageSize
, aStateRect
, aMouseRect
);
2571 Point aCenterPos
= aStateRect
.Center();
2572 tools::Long nRadX
= aImageSize
.Width()/2;
2573 tools::Long nRadY
= aImageSize
.Height()/2;
2575 pDev
->SetLineColor();
2576 pDev
->SetFillColor( COL_BLACK
);
2577 pDev
->DrawPolygon( tools::Polygon( aCenterPos
, nRadX
, nRadY
) );
2578 nRadX
-= aBrd1Size
.Width();
2579 nRadY
-= aBrd1Size
.Height();
2580 pDev
->SetFillColor( COL_WHITE
);
2581 pDev
->DrawPolygon( tools::Polygon( aCenterPos
, nRadX
, nRadY
) );
2584 nRadX
-= aBrd1Size
.Width();
2585 nRadY
-= aBrd1Size
.Height();
2590 pDev
->SetFillColor( COL_BLACK
);
2591 pDev
->DrawPolygon( tools::Polygon( aCenterPos
, nRadX
, nRadY
) );
2598 OSL_FAIL( "RadioButton::Draw() - not implemented for RadioButton with Image" );
2602 void RadioButton::Resize()
2608 void RadioButton::GetFocus()
2610 ShowFocus( ImplGetFocusRect() );
2611 SetInputContext( InputContext( GetFont() ) );
2615 void RadioButton::LoseFocus()
2617 if ( GetButtonState() & DrawButtonFlags::Pressed
)
2619 GetButtonState() &= ~DrawButtonFlags::Pressed
;
2624 Button::LoseFocus();
2627 void RadioButton::StateChanged( StateChangedType nType
)
2629 Button::StateChanged( nType
);
2631 if ( nType
== StateChangedType::State
)
2633 if ( IsReallyVisible() && IsUpdateMode() )
2634 Invalidate( maStateRect
);
2636 else if ( (nType
== StateChangedType::Enable
) ||
2637 (nType
== StateChangedType::Text
) ||
2638 (nType
== StateChangedType::Data
) ||
2639 (nType
== StateChangedType::UpdateMode
) )
2641 if ( IsUpdateMode() )
2644 else if ( nType
== StateChangedType::Style
)
2646 SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev
), GetStyle() ) );
2648 if ( (GetPrevStyle() & RADIOBUTTON_VIEW_STYLE
) !=
2649 (GetStyle() & RADIOBUTTON_VIEW_STYLE
) )
2651 if ( IsUpdateMode() )
2655 else if ( (nType
== StateChangedType::Zoom
) ||
2656 (nType
== StateChangedType::ControlFont
) )
2658 ImplInitSettings( false );
2661 else if ( nType
== StateChangedType::ControlForeground
)
2663 ImplInitSettings( false );
2666 else if ( nType
== StateChangedType::ControlBackground
)
2668 ImplInitSettings( true );
2673 void RadioButton::DataChanged( const DataChangedEvent
& rDCEvt
)
2675 Button::DataChanged( rDCEvt
);
2677 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
2678 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
2679 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
2680 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
2682 ImplInitSettings( true );
2687 bool RadioButton::PreNotify( NotifyEvent
& rNEvt
)
2689 if( rNEvt
.GetType() == NotifyEventType::MOUSEMOVE
)
2691 const MouseEvent
* pMouseEvt
= rNEvt
.GetMouseEvent();
2692 if( pMouseEvt
&& !pMouseEvt
->GetButtons() && !pMouseEvt
->IsSynthetic() && !pMouseEvt
->IsModifierChanged() )
2694 // trigger redraw if mouse over state has changed
2695 if( IsNativeControlSupported(ControlType::Radiobutton
, ControlPart::Entire
) )
2697 if (maMouseRect
.Contains(GetPointerPosPixel()) != maMouseRect
.Contains(GetLastPointerPosPixel()) ||
2698 pMouseEvt
->IsLeaveWindow() || pMouseEvt
->IsEnterWindow())
2700 Invalidate( maStateRect
);
2706 return Button::PreNotify(rNEvt
);
2709 void RadioButton::Toggle()
2711 ImplCallEventListenersAndHandler( VclEventId::RadiobuttonToggle
, [this] () { maToggleHdl
.Call(*this); } );
2714 void RadioButton::SetModeRadioImage( const Image
& rImage
)
2716 if ( rImage
!= maImage
)
2719 CompatStateChanged( StateChangedType::Data
);
2725 void RadioButton::SetState( bool bCheck
)
2727 // carry the TabStop flag along correctly
2729 mpWindowImpl
->mnStyle
|= WB_TABSTOP
;
2731 mpWindowImpl
->mnStyle
&= ~WB_TABSTOP
;
2733 if ( mbChecked
!= bCheck
)
2736 CompatStateChanged( StateChangedType::State
);
2741 bool RadioButton::set_property(const OUString
&rKey
, const OUString
&rValue
)
2743 if (rKey
== "active")
2744 SetState(toBool(rValue
));
2745 else if (rKey
== "image-position")
2747 WinBits nBits
= GetStyle();
2748 if (rValue
== "left")
2750 nBits
&= ~(WB_CENTER
| WB_RIGHT
);
2753 else if (rValue
== "right")
2755 nBits
&= ~(WB_CENTER
| WB_LEFT
);
2758 else if (rValue
== "top")
2760 nBits
&= ~(WB_VCENTER
| WB_BOTTOM
);
2763 else if (rValue
== "bottom")
2765 nBits
&= ~(WB_VCENTER
| WB_TOP
);
2768 //It's rather mad to have to set these bits when there is the other
2769 //image align. Looks like e.g. the radiobuttons etc weren't converted
2770 //over to image align fully.
2772 //Deliberate to set the sane ImageAlign property
2773 return Button::set_property(rKey
, rValue
);
2776 return Button::set_property(rKey
, rValue
);
2780 void RadioButton::Check( bool bCheck
)
2782 // TabStop-Flag richtig mitfuehren
2784 mpWindowImpl
->mnStyle
|= WB_TABSTOP
;
2786 mpWindowImpl
->mnStyle
&= ~WB_TABSTOP
;
2788 if ( mbChecked
== bCheck
)
2792 VclPtr
<vcl::Window
> xWindow
= this;
2793 CompatStateChanged( StateChangedType::State
);
2794 if ( xWindow
->isDisposed() )
2796 if ( bCheck
&& mbRadioCheck
)
2797 ImplUncheckAllOther();
2798 if ( xWindow
->isDisposed() )
2803 tools::Long
Button::ImplGetImageToTextDistance() const
2805 // 4 pixels, but take zoom into account, so the text doesn't "jump" relative to surrounding elements,
2806 // which might have been aligned with the text of the check box
2807 return CalcZoom( 4 );
2810 Size
RadioButton::ImplGetRadioImageSize() const
2813 bool bDefaultSize
= true;
2814 if( IsNativeControlSupported( ControlType::Radiobutton
, ControlPart::Entire
) )
2816 ImplControlValue aControlValue
;
2817 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), GetSizePixel() );
2818 tools::Rectangle aBoundingRgn
, aContentRgn
;
2820 // get native size of a radio button
2821 if( GetNativeControlRegion( ControlType::Radiobutton
, ControlPart::Entire
, aCtrlRegion
,
2822 ControlState::DEFAULT
|ControlState::ENABLED
,
2824 aBoundingRgn
, aContentRgn
) )
2826 aSize
= aContentRgn
.GetSize();
2827 bDefaultSize
= false;
2831 aSize
= GetRadioImage( GetSettings(), DrawButtonFlags::NONE
).GetSizePixel();
2835 static void LoadThemedImageList(const StyleSettings
&rStyleSettings
,
2836 std::vector
<Image
>& rList
, const std::vector
<OUString
> &rResources
)
2838 Color aColorAry1
[6];
2839 Color aColorAry2
[6];
2840 aColorAry1
[0] = Color( 0xC0, 0xC0, 0xC0 );
2841 aColorAry1
[1] = Color( 0xFF, 0xFF, 0x00 );
2842 aColorAry1
[2] = Color( 0xFF, 0xFF, 0xFF );
2843 aColorAry1
[3] = Color( 0x80, 0x80, 0x80 );
2844 aColorAry1
[4] = Color( 0x00, 0x00, 0x00 );
2845 aColorAry1
[5] = Color( 0x00, 0xFF, 0x00 );
2846 aColorAry2
[0] = rStyleSettings
.GetFaceColor();
2847 aColorAry2
[1] = rStyleSettings
.GetWindowColor();
2848 aColorAry2
[2] = rStyleSettings
.GetLightColor();
2849 aColorAry2
[3] = rStyleSettings
.GetShadowColor();
2850 aColorAry2
[4] = rStyleSettings
.GetDarkShadowColor();
2851 aColorAry2
[5] = rStyleSettings
.GetWindowTextColor();
2853 static_assert( sizeof(aColorAry1
) == sizeof(aColorAry2
), "aColorAry1 must match aColorAry2" );
2855 for (const auto &a
: rResources
)
2858 aBmpEx
.Replace(aColorAry1
, aColorAry2
, SAL_N_ELEMENTS(aColorAry1
));
2859 rList
.emplace_back(aBmpEx
);
2863 Image
RadioButton::GetRadioImage( const AllSettings
& rSettings
, DrawButtonFlags nFlags
)
2865 ImplSVData
* pSVData
= ImplGetSVData();
2866 const StyleSettings
& rStyleSettings
= rSettings
.GetStyleSettings();
2867 sal_uInt16 nStyle
= 0;
2869 if ( rStyleSettings
.GetOptions() & StyleSettingsOptions::Mono
)
2870 nStyle
= STYLE_RADIOBUTTON_MONO
;
2872 if ( pSVData
->maCtrlData
.maRadioImgList
.empty() ||
2873 (pSVData
->maCtrlData
.mnRadioStyle
!= nStyle
) ||
2874 (pSVData
->maCtrlData
.mnLastRadioFColor
!= rStyleSettings
.GetFaceColor()) ||
2875 (pSVData
->maCtrlData
.mnLastRadioWColor
!= rStyleSettings
.GetWindowColor()) ||
2876 (pSVData
->maCtrlData
.mnLastRadioLColor
!= rStyleSettings
.GetLightColor()) )
2878 pSVData
->maCtrlData
.maRadioImgList
.clear();
2880 pSVData
->maCtrlData
.mnLastRadioFColor
= rStyleSettings
.GetFaceColor();
2881 pSVData
->maCtrlData
.mnLastRadioWColor
= rStyleSettings
.GetWindowColor();
2882 pSVData
->maCtrlData
.mnLastRadioLColor
= rStyleSettings
.GetLightColor();
2884 std::vector
<OUString
> aResources
;
2887 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO1
);
2888 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO2
);
2889 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO3
);
2890 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO4
);
2891 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO5
);
2892 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO6
);
2896 aResources
.emplace_back(SV_RESID_BITMAP_RADIO1
);
2897 aResources
.emplace_back(SV_RESID_BITMAP_RADIO2
);
2898 aResources
.emplace_back(SV_RESID_BITMAP_RADIO3
);
2899 aResources
.emplace_back(SV_RESID_BITMAP_RADIO4
);
2900 aResources
.emplace_back(SV_RESID_BITMAP_RADIO5
);
2901 aResources
.emplace_back(SV_RESID_BITMAP_RADIO6
);
2903 LoadThemedImageList( rStyleSettings
, pSVData
->maCtrlData
.maRadioImgList
, aResources
);
2904 pSVData
->maCtrlData
.mnRadioStyle
= nStyle
;
2908 if ( nFlags
& DrawButtonFlags::Disabled
)
2910 if ( nFlags
& DrawButtonFlags::Checked
)
2915 else if ( nFlags
& DrawButtonFlags::Pressed
)
2917 if ( nFlags
& DrawButtonFlags::Checked
)
2924 if ( nFlags
& DrawButtonFlags::Checked
)
2929 return pSVData
->maCtrlData
.maRadioImgList
[nIndex
];
2932 void RadioButton::ImplAdjustNWFSizes()
2934 GetOutDev()->Push( vcl::PushFlags::MAPMODE
);
2935 SetMapMode(MapMode(MapUnit::MapPixel
));
2937 ImplControlValue aControlValue
;
2938 Size
aCurSize( GetSizePixel() );
2939 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), aCurSize
);
2940 tools::Rectangle aBoundingRgn
, aContentRgn
;
2942 // get native size of a radiobutton
2943 if( GetNativeControlRegion( ControlType::Radiobutton
, ControlPart::Entire
, aCtrlRegion
,
2944 ControlState::DEFAULT
|ControlState::ENABLED
, aControlValue
,
2945 aBoundingRgn
, aContentRgn
) )
2947 Size aSize
= aContentRgn
.GetSize();
2949 if( aSize
.Height() > aCurSize
.Height() )
2951 aCurSize
.setHeight( aSize
.Height() );
2952 SetSizePixel( aCurSize
);
2959 Size
RadioButton::CalcMinimumSize(tools::Long nMaxWidth
) const
2963 aSize
= ImplGetRadioImageSize();
2966 aSize
= maImage
.GetSizePixel();
2967 aSize
.AdjustWidth(8);
2968 aSize
.AdjustHeight(8);
2971 if (Button::HasImage())
2973 Size aImgSize
= GetModeImage().GetSizePixel();
2974 aSize
= Size(std::max(aImgSize
.Width(), aSize
.Width()),
2975 std::max(aImgSize
.Height(), aSize
.Height()));
2978 OUString aText
= GetText();
2979 if (!aText
.isEmpty())
2981 bool bTopImage
= (GetStyle() & WB_TOP
) != 0;
2983 Size aTextSize
= GetTextRect( tools::Rectangle( Point(), Size( nMaxWidth
> 0 ? nMaxWidth
: 0x7fffffff, 0x7fffffff ) ),
2984 aText
, FixedText::ImplGetTextStyle( GetStyle() ) ).GetSize();
2986 aSize
.AdjustWidth(2 ); // for focus rect
2990 aSize
.AdjustWidth(ImplGetImageToTextDistance() );
2991 aSize
.AdjustWidth(aTextSize
.Width() );
2992 if ( aSize
.Height() < aTextSize
.Height() )
2993 aSize
.setHeight( aTextSize
.Height() );
2997 aSize
.AdjustHeight(6 );
2998 aSize
.AdjustHeight(GetTextHeight() );
2999 if ( aSize
.Width() < aTextSize
.Width() )
3000 aSize
.setWidth( aTextSize
.Width() );
3004 return CalcWindowSize( aSize
);
3007 Size
RadioButton::GetOptimalSize() const
3009 return CalcMinimumSize();
3012 void RadioButton::ShowFocus(const tools::Rectangle
& rRect
)
3014 if (IsNativeControlSupported(ControlType::Radiobutton
, ControlPart::Focus
))
3016 ImplControlValue aControlValue
;
3017 tools::Rectangle
aInRect(Point(0, 0), GetSizePixel());
3019 aInRect
.SetLeft( rRect
.Left() ); // exclude the radio element itself from the focusrect
3021 GetOutDev()->DrawNativeControl(ControlType::Radiobutton
, ControlPart::Focus
, aInRect
,
3022 ControlState::FOCUSED
, aControlValue
, OUString());
3024 Button::ShowFocus(rRect
);
3027 void RadioButton::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
3029 Button::DumpAsPropertyTree(rJsonWriter
);
3030 rJsonWriter
.put("checked", IsChecked());
3033 std::vector
<VclPtr
<RadioButton
>> aGroup
= GetRadioButtonGroup();
3034 for(const auto& pButton
: aGroup
)
3035 sGroupId
+= pButton
->get_id();
3037 if (!sGroupId
.isEmpty())
3038 rJsonWriter
.put("group", sGroupId
);
3042 SvMemoryStream
aOStm(6535, 6535);
3043 if(GraphicConverter::Export(aOStm
, maImage
.GetBitmapEx(), ConvertDataFormat::PNG
) == ERRCODE_NONE
)
3045 css::uno::Sequence
<sal_Int8
> aSeq( static_cast<sal_Int8
const *>(aOStm
.GetData()), aOStm
.Tell());
3046 OStringBuffer
aBuffer("data:image/png;base64,");
3047 ::comphelper::Base64::encode(aBuffer
, aSeq
);
3048 rJsonWriter
.put("image", aBuffer
);
3053 FactoryFunction
RadioButton::GetUITestFactory() const
3055 return RadioButtonUIObject::create
;
3058 void CheckBox::ImplInitCheckBoxData()
3060 meState
= TRISTATE_FALSE
;
3064 void CheckBox::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
3066 nStyle
= ImplInitStyle(getPreviousSibling(pParent
), nStyle
);
3067 Button::ImplInit( pParent
, nStyle
, nullptr );
3069 ImplInitSettings( true );
3072 WinBits
CheckBox::ImplInitStyle( const vcl::Window
* pPrevWindow
, WinBits nStyle
)
3074 if ( !(nStyle
& WB_NOTABSTOP
) )
3075 nStyle
|= WB_TABSTOP
;
3076 if ( !(nStyle
& WB_NOGROUP
) &&
3077 (!pPrevWindow
|| (pPrevWindow
->GetType() != WindowType::CHECKBOX
)) )
3082 const vcl::Font
& CheckBox::GetCanonicalFont( const StyleSettings
& _rStyle
) const
3084 return _rStyle
.GetRadioCheckFont();
3087 const Color
& CheckBox::GetCanonicalTextColor( const StyleSettings
& _rStyle
) const
3089 return _rStyle
.GetRadioCheckTextColor();
3092 void CheckBox::ImplInitSettings( bool bBackground
)
3094 Button::ImplInitSettings();
3099 vcl::Window
* pParent
= GetParent();
3100 if ( !IsControlBackground() &&
3101 (pParent
->IsChildTransparentModeEnabled() || IsNativeControlSupported( ControlType::Checkbox
, ControlPart::Entire
) ) )
3103 EnableChildTransparentMode();
3104 SetParentClipMode( ParentClipMode::NoClip
);
3105 SetPaintTransparent( true );
3107 if( IsNativeControlSupported( ControlType::Checkbox
, ControlPart::Entire
) )
3108 ImplGetWindowImpl()->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
3112 EnableChildTransparentMode( false );
3113 SetParentClipMode();
3114 SetPaintTransparent( false );
3116 if ( IsControlBackground() )
3117 SetBackground( GetControlBackground() );
3119 SetBackground( pParent
->GetBackground() );
3123 void CheckBox::ImplDrawCheckBoxState(vcl::RenderContext
& rRenderContext
)
3125 bool bNativeOK
= rRenderContext
.IsNativeControlSupported(ControlType::Checkbox
, ControlPart::Entire
);
3128 ImplControlValue
aControlValue(meState
== TRISTATE_TRUE
? ButtonValue::On
: ButtonValue::Off
);
3129 tools::Rectangle
aCtrlRegion(maStateRect
);
3130 ControlState nState
= ControlState::NONE
;
3133 nState
|= ControlState::FOCUSED
;
3134 if (GetButtonState() & DrawButtonFlags::Default
)
3135 nState
|= ControlState::DEFAULT
;
3136 if (GetButtonState() & DrawButtonFlags::Pressed
)
3137 nState
|= ControlState::PRESSED
;
3139 nState
|= ControlState::ENABLED
;
3141 if (meState
== TRISTATE_TRUE
)
3142 aControlValue
.setTristateVal(ButtonValue::On
);
3143 else if (meState
== TRISTATE_INDET
)
3144 aControlValue
.setTristateVal(ButtonValue::Mixed
);
3146 if (IsMouseOver() && maMouseRect
.Contains(GetPointerPosPixel()))
3147 nState
|= ControlState::ROLLOVER
;
3149 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Checkbox
, ControlPart::Entire
, aCtrlRegion
,
3150 nState
, aControlValue
, OUString());
3156 DrawButtonFlags nStyle
= GetButtonState();
3158 nStyle
|= DrawButtonFlags::Disabled
;
3159 if (meState
== TRISTATE_INDET
)
3160 nStyle
|= DrawButtonFlags::DontKnow
;
3161 else if (meState
== TRISTATE_TRUE
)
3162 nStyle
|= DrawButtonFlags::Checked
;
3163 Image aImage
= GetCheckImage(GetSettings(), nStyle
);
3165 rRenderContext
.DrawImage(maStateRect
.TopLeft(), maStateRect
.GetSize(), aImage
);
3167 rRenderContext
.DrawImage(maStateRect
.TopLeft(), aImage
);
3170 void CheckBox::ImplDraw( OutputDevice
* pDev
, SystemTextColorFlags nSystemTextColorFlags
,
3171 const Point
& rPos
, const Size
& rSize
,
3172 const Size
& rImageSize
, tools::Rectangle
& rStateRect
,
3173 tools::Rectangle
& rMouseRect
)
3175 WinBits nWinStyle
= GetStyle();
3176 OUString
aText( GetText() );
3178 pDev
->Push( vcl::PushFlags::CLIPREGION
| vcl::PushFlags::LINECOLOR
);
3179 pDev
->IntersectClipRegion( tools::Rectangle( rPos
, rSize
) );
3181 if (!aText
.isEmpty() || HasImage())
3183 Button::ImplDrawRadioCheck(pDev
, nWinStyle
, nSystemTextColorFlags
,
3184 rPos
, rSize
, rImageSize
,
3185 rStateRect
, rMouseRect
);
3189 rStateRect
.SetLeft( rPos
.X() );
3190 if ( nWinStyle
& WB_VCENTER
)
3191 rStateRect
.SetTop( rPos
.Y()+((rSize
.Height()-rImageSize
.Height())/2) );
3192 else if ( nWinStyle
& WB_BOTTOM
)
3193 rStateRect
.SetTop( rPos
.Y()+rSize
.Height()-rImageSize
.Height() );
3195 rStateRect
.SetTop( rPos
.Y() );
3196 rStateRect
.SetRight( rStateRect
.Left()+rImageSize
.Width()-1 );
3197 rStateRect
.SetBottom( rStateRect
.Top()+rImageSize
.Height()-1 );
3198 // provide space for focusrect
3199 // note: this assumes that the control's size was adjusted
3200 // accordingly in Get/LoseFocus, so the onscreen position won't change
3202 rStateRect
.Move( 1, 1 );
3203 rMouseRect
= rStateRect
;
3205 ImplSetFocusRect( rStateRect
);
3211 void CheckBox::ImplDrawCheckBox(vcl::RenderContext
& rRenderContext
)
3213 Size aImageSize
= ImplGetCheckImageSize();
3214 aImageSize
.setWidth( CalcZoom( aImageSize
.Width() ) );
3215 aImageSize
.setHeight( CalcZoom( aImageSize
.Height() ) );
3219 ImplDraw(&rRenderContext
, SystemTextColorFlags::NONE
, Point(), GetOutputSizePixel(),
3220 aImageSize
, maStateRect
, maMouseRect
);
3222 ImplDrawCheckBoxState(rRenderContext
);
3224 ShowFocus(ImplGetFocusRect());
3227 void CheckBox::ImplCheck()
3230 if ( meState
== TRISTATE_FALSE
)
3231 eNewState
= TRISTATE_TRUE
;
3232 else if ( !mbTriState
)
3233 eNewState
= TRISTATE_FALSE
;
3234 else if ( meState
== TRISTATE_TRUE
)
3235 eNewState
= TRISTATE_INDET
;
3237 eNewState
= TRISTATE_FALSE
;
3238 meState
= eNewState
;
3240 VclPtr
<vcl::Window
> xWindow
= this;
3243 if ( xWindow
->isDisposed() )
3248 CheckBox::CheckBox( vcl::Window
* pParent
, WinBits nStyle
) :
3249 Button( WindowType::CHECKBOX
)
3251 ImplInitCheckBoxData();
3252 ImplInit( pParent
, nStyle
);
3255 void CheckBox::MouseButtonDown( const MouseEvent
& rMEvt
)
3257 if ( rMEvt
.IsLeft() && maMouseRect
.Contains( rMEvt
.GetPosPixel() ) )
3259 GetButtonState() |= DrawButtonFlags::Pressed
;
3265 Button::MouseButtonDown( rMEvt
);
3268 void CheckBox::Tracking( const TrackingEvent
& rTEvt
)
3270 if ( rTEvt
.IsTrackingEnded() )
3272 if ( GetButtonState() & DrawButtonFlags::Pressed
)
3274 if ( !(GetStyle() & WB_NOPOINTERFOCUS
) && !rTEvt
.IsTrackingCanceled() )
3277 GetButtonState() &= ~DrawButtonFlags::Pressed
;
3279 // do not call click handler if aborted
3280 if ( !rTEvt
.IsTrackingCanceled() )
3290 if ( maMouseRect
.Contains( rTEvt
.GetMouseEvent().GetPosPixel() ) )
3292 if ( !(GetButtonState() & DrawButtonFlags::Pressed
) )
3294 GetButtonState() |= DrawButtonFlags::Pressed
;
3300 if ( GetButtonState() & DrawButtonFlags::Pressed
)
3302 GetButtonState() &= ~DrawButtonFlags::Pressed
;
3309 void CheckBox::KeyInput( const KeyEvent
& rKEvt
)
3311 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
3313 if ( !aKeyCode
.GetModifier() && (aKeyCode
.GetCode() == KEY_SPACE
) )
3315 if ( !(GetButtonState() & DrawButtonFlags::Pressed
) )
3317 GetButtonState() |= DrawButtonFlags::Pressed
;
3321 else if ( (GetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_ESCAPE
) )
3323 GetButtonState() &= ~DrawButtonFlags::Pressed
;
3327 Button::KeyInput( rKEvt
);
3330 void CheckBox::KeyUp( const KeyEvent
& rKEvt
)
3332 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
3334 if ( (GetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_SPACE
) )
3336 GetButtonState() &= ~DrawButtonFlags::Pressed
;
3340 Button::KeyUp( rKEvt
);
3343 void CheckBox::FillLayoutData() const
3345 mxLayoutData
.emplace();
3346 const_cast<CheckBox
*>(this)->Invalidate();
3349 void CheckBox::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
3351 ImplDrawCheckBox(rRenderContext
);
3354 void CheckBox::Draw( OutputDevice
* pDev
, const Point
& rPos
,
3355 SystemTextColorFlags nFlags
)
3357 MapMode
aResMapMode( MapUnit::Map100thMM
);
3358 Point aPos
= pDev
->LogicToPixel( rPos
);
3359 Size aSize
= GetSizePixel();
3360 Size aImageSize
= pDev
->LogicToPixel( Size( 300, 300 ), aResMapMode
);
3361 Size aBrd1Size
= pDev
->LogicToPixel( Size( 20, 20 ), aResMapMode
);
3362 Size aBrd2Size
= pDev
->LogicToPixel( Size( 30, 30 ), aResMapMode
);
3363 tools::Long nCheckWidth
= pDev
->LogicToPixel( Size( 20, 20 ), aResMapMode
).Width();
3364 vcl::Font aFont
= GetDrawPixelFont( pDev
);
3365 tools::Rectangle aStateRect
;
3366 tools::Rectangle aMouseRect
;
3368 aImageSize
.setWidth( CalcZoom( aImageSize
.Width() ) );
3369 aImageSize
.setHeight( CalcZoom( aImageSize
.Height() ) );
3370 aBrd1Size
.setWidth( CalcZoom( aBrd1Size
.Width() ) );
3371 aBrd1Size
.setHeight( CalcZoom( aBrd1Size
.Height() ) );
3372 aBrd2Size
.setWidth( CalcZoom( aBrd2Size
.Width() ) );
3373 aBrd2Size
.setHeight( CalcZoom( aBrd2Size
.Height() ) );
3375 if ( !aBrd1Size
.Width() )
3376 aBrd1Size
.setWidth( 1 );
3377 if ( !aBrd1Size
.Height() )
3378 aBrd1Size
.setHeight( 1 );
3379 if ( !aBrd2Size
.Width() )
3380 aBrd2Size
.setWidth( 1 );
3381 if ( !aBrd2Size
.Height() )
3382 aBrd2Size
.setHeight( 1 );
3388 pDev
->SetFont( aFont
);
3389 if ( nFlags
& SystemTextColorFlags::Mono
)
3390 pDev
->SetTextColor( COL_BLACK
);
3392 pDev
->SetTextColor( GetTextColor() );
3393 pDev
->SetTextFillColor();
3395 ImplDraw( pDev
, nFlags
, aPos
, aSize
,
3396 aImageSize
, aStateRect
, aMouseRect
);
3398 pDev
->SetLineColor();
3399 pDev
->SetFillColor( COL_BLACK
);
3400 pDev
->DrawRect( aStateRect
);
3401 aStateRect
.AdjustLeft(aBrd1Size
.Width() );
3402 aStateRect
.AdjustTop(aBrd1Size
.Height() );
3403 aStateRect
.AdjustRight( -(aBrd1Size
.Width()) );
3404 aStateRect
.AdjustBottom( -(aBrd1Size
.Height()) );
3405 if ( meState
== TRISTATE_INDET
)
3406 pDev
->SetFillColor( COL_LIGHTGRAY
);
3408 pDev
->SetFillColor( COL_WHITE
);
3409 pDev
->DrawRect( aStateRect
);
3411 if ( meState
== TRISTATE_TRUE
)
3413 aStateRect
.AdjustLeft(aBrd2Size
.Width() );
3414 aStateRect
.AdjustTop(aBrd2Size
.Height() );
3415 aStateRect
.AdjustRight( -(aBrd2Size
.Width()) );
3416 aStateRect
.AdjustBottom( -(aBrd2Size
.Height()) );
3417 Point
aPos11( aStateRect
.TopLeft() );
3418 Point
aPos12( aStateRect
.BottomRight() );
3419 Point
aPos21( aStateRect
.TopRight() );
3420 Point
aPos22( aStateRect
.BottomLeft() );
3421 Point
aTempPos11( aPos11
);
3422 Point
aTempPos12( aPos12
);
3423 Point
aTempPos21( aPos21
);
3424 Point
aTempPos22( aPos22
);
3425 pDev
->SetLineColor( COL_BLACK
);
3426 tools::Long nDX
= 0;
3427 for ( tools::Long i
= 0; i
< nCheckWidth
; i
++ )
3431 aTempPos11
.setX( aPos11
.X()+nDX
);
3432 aTempPos12
.setX( aPos12
.X()+nDX
);
3433 aTempPos21
.setX( aPos21
.X()+nDX
);
3434 aTempPos22
.setX( aPos22
.X()+nDX
);
3439 aTempPos11
.setX( aPos11
.X()-nDX
);
3440 aTempPos12
.setX( aPos12
.X()-nDX
);
3441 aTempPos21
.setX( aPos21
.X()-nDX
);
3442 aTempPos22
.setX( aPos22
.X()-nDX
);
3444 pDev
->DrawLine( aTempPos11
, aTempPos12
);
3445 pDev
->DrawLine( aTempPos21
, aTempPos22
);
3452 void CheckBox::Resize()
3458 void CheckBox::GetFocus()
3460 if (GetText().isEmpty())
3462 // increase button size to have space for focus rect
3463 // checkboxes without text will draw focusrect around the check
3464 // See CheckBox::ImplDraw()
3465 Point
aPos( GetPosPixel() );
3466 Size
aSize( GetSizePixel() );
3468 aSize
.AdjustHeight(2 );
3469 aSize
.AdjustWidth(2 );
3470 setPosSizePixel( aPos
.X(), aPos
.Y(), aSize
.Width(), aSize
.Height() );
3472 // Trigger drawing to initialize the mouse rectangle, otherwise the mouse button down
3473 // handler would ignore the mouse event.
3477 ShowFocus( ImplGetFocusRect() );
3479 SetInputContext( InputContext( GetFont() ) );
3483 void CheckBox::LoseFocus()
3485 if ( GetButtonState() & DrawButtonFlags::Pressed
)
3487 GetButtonState() &= ~DrawButtonFlags::Pressed
;
3492 Button::LoseFocus();
3494 if (GetText().isEmpty())
3496 // decrease button size again (see GetFocus())
3497 // checkboxes without text will draw focusrect around the check
3498 Point
aPos( GetPosPixel() );
3499 Size
aSize( GetSizePixel() );
3501 aSize
.AdjustHeight( -2 );
3502 aSize
.AdjustWidth( -2 );
3503 setPosSizePixel( aPos
.X(), aPos
.Y(), aSize
.Width(), aSize
.Height() );
3508 void CheckBox::StateChanged( StateChangedType nType
)
3510 Button::StateChanged( nType
);
3512 if ( nType
== StateChangedType::State
)
3514 if ( IsReallyVisible() && IsUpdateMode() )
3515 Invalidate( maStateRect
);
3517 else if ( (nType
== StateChangedType::Enable
) ||
3518 (nType
== StateChangedType::Text
) ||
3519 (nType
== StateChangedType::Data
) ||
3520 (nType
== StateChangedType::UpdateMode
) )
3522 if ( IsUpdateMode() )
3525 else if ( nType
== StateChangedType::Style
)
3527 SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev
), GetStyle() ) );
3529 if ( (GetPrevStyle() & CHECKBOX_VIEW_STYLE
) !=
3530 (GetStyle() & CHECKBOX_VIEW_STYLE
) )
3532 if ( IsUpdateMode() )
3536 else if ( (nType
== StateChangedType::Zoom
) ||
3537 (nType
== StateChangedType::ControlFont
) )
3539 ImplInitSettings( false );
3542 else if ( nType
== StateChangedType::ControlForeground
)
3544 ImplInitSettings( false );
3547 else if ( nType
== StateChangedType::ControlBackground
)
3549 ImplInitSettings( true );
3554 void CheckBox::DataChanged( const DataChangedEvent
& rDCEvt
)
3556 Button::DataChanged( rDCEvt
);
3558 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
3559 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
3560 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
3561 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
3563 ImplInitSettings( true );
3568 bool CheckBox::PreNotify( NotifyEvent
& rNEvt
)
3570 if( rNEvt
.GetType() == NotifyEventType::MOUSEMOVE
)
3572 const MouseEvent
* pMouseEvt
= rNEvt
.GetMouseEvent();
3573 if( pMouseEvt
&& !pMouseEvt
->GetButtons() && !pMouseEvt
->IsSynthetic() && !pMouseEvt
->IsModifierChanged() )
3575 // trigger redraw if mouse over state has changed
3576 if( IsNativeControlSupported(ControlType::Checkbox
, ControlPart::Entire
) )
3578 if (maMouseRect
.Contains(GetPointerPosPixel()) != maMouseRect
.Contains(GetLastPointerPosPixel()) ||
3579 pMouseEvt
->IsLeaveWindow() || pMouseEvt
->IsEnterWindow())
3581 Invalidate( maStateRect
);
3587 return Button::PreNotify(rNEvt
);
3590 void CheckBox::Toggle()
3592 ImplCallEventListenersAndHandler( VclEventId::CheckboxToggle
, [this] () { maToggleHdl
.Call(*this); } );
3595 void CheckBox::SetState( TriState eState
)
3597 if ( !mbTriState
&& (eState
== TRISTATE_INDET
) )
3598 eState
= TRISTATE_FALSE
;
3600 if ( meState
!= eState
)
3603 StateChanged( StateChangedType::State
);
3608 bool CheckBox::set_property(const OUString
&rKey
, const OUString
&rValue
)
3610 if (rKey
== "active")
3611 SetState(toBool(rValue
) ? TRISTATE_TRUE
: TRISTATE_FALSE
);
3613 return Button::set_property(rKey
, rValue
);
3617 void CheckBox::EnableTriState( bool bTriState
)
3619 if ( mbTriState
!= bTriState
)
3621 mbTriState
= bTriState
;
3623 if ( !bTriState
&& (meState
== TRISTATE_INDET
) )
3624 SetState( TRISTATE_FALSE
);
3628 Size
CheckBox::ImplGetCheckImageSize() const
3631 bool bDefaultSize
= true;
3632 if( IsNativeControlSupported( ControlType::Checkbox
, ControlPart::Entire
) )
3634 ImplControlValue aControlValue
;
3635 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), GetSizePixel() );
3636 tools::Rectangle aBoundingRgn
, aContentRgn
;
3638 // get native size of a check box
3639 if( GetNativeControlRegion( ControlType::Checkbox
, ControlPart::Entire
, aCtrlRegion
,
3640 ControlState::DEFAULT
|ControlState::ENABLED
,
3642 aBoundingRgn
, aContentRgn
) )
3644 aSize
= aContentRgn
.GetSize();
3645 bDefaultSize
= false;
3649 aSize
= GetCheckImage( GetSettings(), DrawButtonFlags::NONE
).GetSizePixel();
3653 Image
CheckBox::GetCheckImage( const AllSettings
& rSettings
, DrawButtonFlags nFlags
)
3655 ImplSVData
* pSVData
= ImplGetSVData();
3656 const StyleSettings
& rStyleSettings
= rSettings
.GetStyleSettings();
3657 sal_uInt16 nStyle
= 0;
3659 if ( rStyleSettings
.GetOptions() & StyleSettingsOptions::Mono
)
3660 nStyle
= STYLE_CHECKBOX_MONO
;
3662 if ( pSVData
->maCtrlData
.maCheckImgList
.empty() ||
3663 (pSVData
->maCtrlData
.mnCheckStyle
!= nStyle
) ||
3664 (pSVData
->maCtrlData
.mnLastCheckFColor
!= rStyleSettings
.GetFaceColor()) ||
3665 (pSVData
->maCtrlData
.mnLastCheckWColor
!= rStyleSettings
.GetWindowColor()) ||
3666 (pSVData
->maCtrlData
.mnLastCheckLColor
!= rStyleSettings
.GetLightColor()) )
3668 pSVData
->maCtrlData
.maCheckImgList
.clear();
3670 pSVData
->maCtrlData
.mnLastCheckFColor
= rStyleSettings
.GetFaceColor();
3671 pSVData
->maCtrlData
.mnLastCheckWColor
= rStyleSettings
.GetWindowColor();
3672 pSVData
->maCtrlData
.mnLastCheckLColor
= rStyleSettings
.GetLightColor();
3674 std::vector
<OUString
> aResources
;
3677 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO1
);
3678 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO2
);
3679 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO3
);
3680 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO4
);
3681 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO5
);
3682 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO6
);
3683 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO7
);
3684 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO8
);
3685 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO9
);
3689 aResources
.emplace_back(SV_RESID_BITMAP_CHECK1
);
3690 aResources
.emplace_back(SV_RESID_BITMAP_CHECK2
);
3691 aResources
.emplace_back(SV_RESID_BITMAP_CHECK3
);
3692 aResources
.emplace_back(SV_RESID_BITMAP_CHECK4
);
3693 aResources
.emplace_back(SV_RESID_BITMAP_CHECK5
);
3694 aResources
.emplace_back(SV_RESID_BITMAP_CHECK6
);
3695 aResources
.emplace_back(SV_RESID_BITMAP_CHECK7
);
3696 aResources
.emplace_back(SV_RESID_BITMAP_CHECK8
);
3697 aResources
.emplace_back(SV_RESID_BITMAP_CHECK9
);
3699 LoadThemedImageList(rStyleSettings
, pSVData
->maCtrlData
.maCheckImgList
, aResources
);
3700 pSVData
->maCtrlData
.mnCheckStyle
= nStyle
;
3704 if ( nFlags
& DrawButtonFlags::Disabled
)
3706 if ( nFlags
& DrawButtonFlags::DontKnow
)
3708 else if ( nFlags
& DrawButtonFlags::Checked
)
3713 else if ( nFlags
& DrawButtonFlags::Pressed
)
3715 if ( nFlags
& DrawButtonFlags::DontKnow
)
3717 else if ( nFlags
& DrawButtonFlags::Checked
)
3724 if ( nFlags
& DrawButtonFlags::DontKnow
)
3726 else if ( nFlags
& DrawButtonFlags::Checked
)
3731 return pSVData
->maCtrlData
.maCheckImgList
[nIndex
];
3734 void CheckBox::ImplAdjustNWFSizes()
3736 GetOutDev()->Push( vcl::PushFlags::MAPMODE
);
3737 SetMapMode(MapMode(MapUnit::MapPixel
));
3739 ImplControlValue aControlValue
;
3740 Size
aCurSize( GetSizePixel() );
3741 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), aCurSize
);
3742 tools::Rectangle aBoundingRgn
, aContentRgn
;
3744 // get native size of a radiobutton
3745 if( GetNativeControlRegion( ControlType::Checkbox
, ControlPart::Entire
, aCtrlRegion
,
3746 ControlState::DEFAULT
|ControlState::ENABLED
, aControlValue
,
3747 aBoundingRgn
, aContentRgn
) )
3749 Size aSize
= aContentRgn
.GetSize();
3751 if( aSize
.Height() > aCurSize
.Height() )
3753 aCurSize
.setHeight( aSize
.Height() );
3754 SetSizePixel( aCurSize
);
3761 Size
CheckBox::CalcMinimumSize( tools::Long nMaxWidth
) const
3763 Size aSize
= ImplGetCheckImageSize();
3764 nMaxWidth
-= aSize
.Width();
3766 OUString aText
= GetText();
3767 if (!aText
.isEmpty())
3769 // subtract what will be added later
3771 nMaxWidth
-= ImplGetImageToTextDistance();
3773 Size aTextSize
= GetTextRect( tools::Rectangle( Point(), Size( nMaxWidth
> 0 ? nMaxWidth
: 0x7fffffff, 0x7fffffff ) ),
3774 aText
, FixedText::ImplGetTextStyle( GetStyle() ) ).GetSize();
3775 aSize
.AdjustWidth(2 ); // for focus rect
3776 aSize
.AdjustWidth(ImplGetImageToTextDistance() );
3777 aSize
.AdjustWidth(aTextSize
.Width() );
3778 if ( aSize
.Height() < aTextSize
.Height() )
3779 aSize
.setHeight( aTextSize
.Height() );
3783 // is this still correct ? since the checkbox now
3784 // shows a focus rect it should be 2 pixels wider and longer
3785 /* since otherwise the controls in the Writer hang too far up
3787 aSize.Height() += 2;
3791 return CalcWindowSize( aSize
);
3794 Size
CheckBox::GetOptimalSize() const
3796 int nWidthRequest(get_width_request());
3797 return CalcMinimumSize(nWidthRequest
!= -1 ? nWidthRequest
: 0);
3800 void CheckBox::ShowFocus(const tools::Rectangle
& rRect
)
3802 if (IsNativeControlSupported(ControlType::Checkbox
, ControlPart::Focus
))
3804 ImplControlValue aControlValue
;
3805 tools::Rectangle
aInRect(Point(0, 0), GetSizePixel());
3807 aInRect
.SetLeft( rRect
.Left() ); // exclude the checkbox itself from the focusrect
3809 GetOutDev()->DrawNativeControl(ControlType::Checkbox
, ControlPart::Focus
, aInRect
,
3810 ControlState::FOCUSED
, aControlValue
, OUString());
3812 Button::ShowFocus(rRect
);
3815 void CheckBox::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
3817 Button::DumpAsPropertyTree(rJsonWriter
);
3818 rJsonWriter
.put("checked", IsChecked());
3821 FactoryFunction
CheckBox::GetUITestFactory() const
3823 return CheckBoxUIObject::create
;
3826 ImageButton::ImageButton( vcl::Window
* pParent
, WinBits nStyle
) :
3827 PushButton( pParent
, nStyle
)
3832 void ImageButton::ImplInitStyle()
3834 WinBits nStyle
= GetStyle();
3836 if ( ! ( nStyle
& ( WB_RIGHT
| WB_LEFT
) ) )
3837 nStyle
|= WB_CENTER
;
3839 if ( ! ( nStyle
& ( WB_TOP
| WB_BOTTOM
) ) )
3840 nStyle
|= WB_VCENTER
;
3845 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */