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(u
""_ustr
);
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
)
1836 set_id(u
"cancel"_ustr
);
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
)
1888 set_id(u
"help"_ustr
);
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 std::erase(*m_xGroup
, VclPtr
<RadioButton
>(this));
2428 void RadioButton::MouseButtonDown( const MouseEvent
& rMEvt
)
2430 if ( rMEvt
.IsLeft() && maMouseRect
.Contains( rMEvt
.GetPosPixel() ) )
2432 GetButtonState() |= DrawButtonFlags::Pressed
;
2438 Button::MouseButtonDown( rMEvt
);
2441 void RadioButton::Tracking( const TrackingEvent
& rTEvt
)
2443 if ( rTEvt
.IsTrackingEnded() )
2445 if ( GetButtonState() & DrawButtonFlags::Pressed
)
2447 if ( !(GetStyle() & WB_NOPOINTERFOCUS
) && !rTEvt
.IsTrackingCanceled() )
2450 GetButtonState() &= ~DrawButtonFlags::Pressed
;
2452 // do not call click handler if aborted
2453 if ( !rTEvt
.IsTrackingCanceled() )
2463 if ( maMouseRect
.Contains( rTEvt
.GetMouseEvent().GetPosPixel() ) )
2465 if ( !(GetButtonState() & DrawButtonFlags::Pressed
) )
2467 GetButtonState() |= DrawButtonFlags::Pressed
;
2473 if ( GetButtonState() & DrawButtonFlags::Pressed
)
2475 GetButtonState() &= ~DrawButtonFlags::Pressed
;
2482 void RadioButton::KeyInput( const KeyEvent
& rKEvt
)
2484 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
2486 if ( !aKeyCode
.GetModifier() && (aKeyCode
.GetCode() == KEY_SPACE
) )
2488 if ( !(GetButtonState() & DrawButtonFlags::Pressed
) )
2490 GetButtonState() |= DrawButtonFlags::Pressed
;
2494 else if ( (GetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_ESCAPE
) )
2496 GetButtonState() &= ~DrawButtonFlags::Pressed
;
2500 Button::KeyInput( rKEvt
);
2503 void RadioButton::KeyUp( const KeyEvent
& rKEvt
)
2505 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
2507 if ( (GetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_SPACE
) )
2509 GetButtonState() &= ~DrawButtonFlags::Pressed
;
2513 Button::KeyUp( rKEvt
);
2516 void RadioButton::FillLayoutData() const
2518 mxLayoutData
.emplace();
2519 const_cast<RadioButton
*>(this)->Invalidate();
2522 void RadioButton::Paint( vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& )
2524 ImplDrawRadioButton(rRenderContext
);
2527 void RadioButton::Draw( OutputDevice
* pDev
, const Point
& rPos
,
2528 SystemTextColorFlags nFlags
)
2532 MapMode
aResMapMode( MapUnit::Map100thMM
);
2533 Point aPos
= pDev
->LogicToPixel( rPos
);
2534 Size aSize
= GetSizePixel();
2535 Size aImageSize
= pDev
->LogicToPixel( Size( 300, 300 ), aResMapMode
);
2536 Size aBrd1Size
= pDev
->LogicToPixel( Size( 20, 20 ), aResMapMode
);
2537 Size aBrd2Size
= pDev
->LogicToPixel( Size( 60, 60 ), aResMapMode
);
2538 vcl::Font aFont
= GetDrawPixelFont( pDev
);
2539 tools::Rectangle aStateRect
;
2540 tools::Rectangle aMouseRect
;
2542 aImageSize
.setWidth( CalcZoom( aImageSize
.Width() ) );
2543 aImageSize
.setHeight( CalcZoom( aImageSize
.Height() ) );
2544 aBrd1Size
.setWidth( CalcZoom( aBrd1Size
.Width() ) );
2545 aBrd1Size
.setHeight( CalcZoom( aBrd1Size
.Height() ) );
2546 aBrd2Size
.setWidth( CalcZoom( aBrd2Size
.Width() ) );
2547 aBrd2Size
.setHeight( CalcZoom( aBrd2Size
.Height() ) );
2549 if ( !aBrd1Size
.Width() )
2550 aBrd1Size
.setWidth( 1 );
2551 if ( !aBrd1Size
.Height() )
2552 aBrd1Size
.setHeight( 1 );
2553 if ( !aBrd2Size
.Width() )
2554 aBrd2Size
.setWidth( 1 );
2555 if ( !aBrd2Size
.Height() )
2556 aBrd2Size
.setHeight( 1 );
2560 pDev
->SetFont( aFont
);
2561 if ( nFlags
& SystemTextColorFlags::Mono
)
2562 pDev
->SetTextColor( COL_BLACK
);
2564 pDev
->SetTextColor( GetTextColor() );
2565 pDev
->SetTextFillColor();
2567 ImplDraw( pDev
, nFlags
, aPos
, aSize
,
2568 aImageSize
, aStateRect
, aMouseRect
);
2570 Point aCenterPos
= aStateRect
.Center();
2571 tools::Long nRadX
= aImageSize
.Width()/2;
2572 tools::Long nRadY
= aImageSize
.Height()/2;
2574 pDev
->SetLineColor();
2575 pDev
->SetFillColor( COL_BLACK
);
2576 pDev
->DrawPolygon( tools::Polygon( aCenterPos
, nRadX
, nRadY
) );
2577 nRadX
-= aBrd1Size
.Width();
2578 nRadY
-= aBrd1Size
.Height();
2579 pDev
->SetFillColor( COL_WHITE
);
2580 pDev
->DrawPolygon( tools::Polygon( aCenterPos
, nRadX
, nRadY
) );
2583 nRadX
-= aBrd1Size
.Width();
2584 nRadY
-= aBrd1Size
.Height();
2589 pDev
->SetFillColor( COL_BLACK
);
2590 pDev
->DrawPolygon( tools::Polygon( aCenterPos
, nRadX
, nRadY
) );
2597 OSL_FAIL( "RadioButton::Draw() - not implemented for RadioButton with Image" );
2601 void RadioButton::Resize()
2607 void RadioButton::GetFocus()
2609 ShowFocus( ImplGetFocusRect() );
2610 SetInputContext( InputContext( GetFont() ) );
2614 void RadioButton::LoseFocus()
2616 if ( GetButtonState() & DrawButtonFlags::Pressed
)
2618 GetButtonState() &= ~DrawButtonFlags::Pressed
;
2623 Button::LoseFocus();
2626 void RadioButton::StateChanged( StateChangedType nType
)
2628 Button::StateChanged( nType
);
2630 if ( nType
== StateChangedType::State
)
2632 if ( IsReallyVisible() && IsUpdateMode() )
2633 Invalidate( maStateRect
);
2635 else if ( (nType
== StateChangedType::Enable
) ||
2636 (nType
== StateChangedType::Text
) ||
2637 (nType
== StateChangedType::Data
) ||
2638 (nType
== StateChangedType::UpdateMode
) )
2640 if ( IsUpdateMode() )
2643 else if ( nType
== StateChangedType::Style
)
2645 SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev
), GetStyle() ) );
2647 if ( (GetPrevStyle() & RADIOBUTTON_VIEW_STYLE
) !=
2648 (GetStyle() & RADIOBUTTON_VIEW_STYLE
) )
2650 if ( IsUpdateMode() )
2654 else if ( (nType
== StateChangedType::Zoom
) ||
2655 (nType
== StateChangedType::ControlFont
) )
2657 ImplInitSettings( false );
2660 else if ( nType
== StateChangedType::ControlForeground
)
2662 ImplInitSettings( false );
2665 else if ( nType
== StateChangedType::ControlBackground
)
2667 ImplInitSettings( true );
2672 void RadioButton::DataChanged( const DataChangedEvent
& rDCEvt
)
2674 Button::DataChanged( rDCEvt
);
2676 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
2677 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
2678 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
2679 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
2681 ImplInitSettings( true );
2686 bool RadioButton::PreNotify( NotifyEvent
& rNEvt
)
2688 if( rNEvt
.GetType() == NotifyEventType::MOUSEMOVE
)
2690 const MouseEvent
* pMouseEvt
= rNEvt
.GetMouseEvent();
2691 if( pMouseEvt
&& !pMouseEvt
->GetButtons() && !pMouseEvt
->IsSynthetic() && !pMouseEvt
->IsModifierChanged() )
2693 // trigger redraw if mouse over state has changed
2694 if( IsNativeControlSupported(ControlType::Radiobutton
, ControlPart::Entire
) )
2696 if (maMouseRect
.Contains(GetPointerPosPixel()) != maMouseRect
.Contains(GetLastPointerPosPixel()) ||
2697 pMouseEvt
->IsLeaveWindow() || pMouseEvt
->IsEnterWindow())
2699 Invalidate( maStateRect
);
2705 return Button::PreNotify(rNEvt
);
2708 void RadioButton::Toggle()
2710 ImplCallEventListenersAndHandler( VclEventId::RadiobuttonToggle
, [this] () { maToggleHdl
.Call(*this); } );
2713 void RadioButton::SetModeRadioImage( const Image
& rImage
)
2715 if ( rImage
!= maImage
)
2718 CompatStateChanged( StateChangedType::Data
);
2724 void RadioButton::SetState( bool bCheck
)
2726 // carry the TabStop flag along correctly
2728 mpWindowImpl
->mnStyle
|= WB_TABSTOP
;
2730 mpWindowImpl
->mnStyle
&= ~WB_TABSTOP
;
2732 if ( mbChecked
!= bCheck
)
2735 CompatStateChanged( StateChangedType::State
);
2740 bool RadioButton::set_property(const OUString
&rKey
, const OUString
&rValue
)
2742 if (rKey
== "active")
2743 SetState(toBool(rValue
));
2744 else if (rKey
== "image-position")
2746 WinBits nBits
= GetStyle();
2747 if (rValue
== "left")
2749 nBits
&= ~(WB_CENTER
| WB_RIGHT
);
2752 else if (rValue
== "right")
2754 nBits
&= ~(WB_CENTER
| WB_LEFT
);
2757 else if (rValue
== "top")
2759 nBits
&= ~(WB_VCENTER
| WB_BOTTOM
);
2762 else if (rValue
== "bottom")
2764 nBits
&= ~(WB_VCENTER
| WB_TOP
);
2767 //It's rather mad to have to set these bits when there is the other
2768 //image align. Looks like e.g. the radiobuttons etc weren't converted
2769 //over to image align fully.
2771 //Deliberate to set the sane ImageAlign property
2772 return Button::set_property(rKey
, rValue
);
2775 return Button::set_property(rKey
, rValue
);
2779 void RadioButton::Check( bool bCheck
)
2781 // TabStop-Flag richtig mitfuehren
2783 mpWindowImpl
->mnStyle
|= WB_TABSTOP
;
2785 mpWindowImpl
->mnStyle
&= ~WB_TABSTOP
;
2787 if ( mbChecked
== bCheck
)
2791 VclPtr
<vcl::Window
> xWindow
= this;
2792 CompatStateChanged( StateChangedType::State
);
2793 if ( xWindow
->isDisposed() )
2795 if ( bCheck
&& mbRadioCheck
)
2796 ImplUncheckAllOther();
2797 if ( xWindow
->isDisposed() )
2802 tools::Long
Button::ImplGetImageToTextDistance() const
2804 // 4 pixels, but take zoom into account, so the text doesn't "jump" relative to surrounding elements,
2805 // which might have been aligned with the text of the check box
2806 return CalcZoom( 4 );
2809 Size
RadioButton::ImplGetRadioImageSize() const
2812 bool bDefaultSize
= true;
2813 if( IsNativeControlSupported( ControlType::Radiobutton
, ControlPart::Entire
) )
2815 ImplControlValue aControlValue
;
2816 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), GetSizePixel() );
2817 tools::Rectangle aBoundingRgn
, aContentRgn
;
2819 // get native size of a radio button
2820 if( GetNativeControlRegion( ControlType::Radiobutton
, ControlPart::Entire
, aCtrlRegion
,
2821 ControlState::DEFAULT
|ControlState::ENABLED
,
2823 aBoundingRgn
, aContentRgn
) )
2825 aSize
= aContentRgn
.GetSize();
2826 bDefaultSize
= false;
2830 aSize
= GetRadioImage( GetSettings(), DrawButtonFlags::NONE
).GetSizePixel();
2834 static void LoadThemedImageList(const StyleSettings
&rStyleSettings
,
2835 std::vector
<Image
>& rList
, const std::vector
<OUString
> &rResources
)
2837 Color aColorAry1
[6];
2838 Color aColorAry2
[6];
2839 aColorAry1
[0] = Color( 0xC0, 0xC0, 0xC0 );
2840 aColorAry1
[1] = Color( 0xFF, 0xFF, 0x00 );
2841 aColorAry1
[2] = Color( 0xFF, 0xFF, 0xFF );
2842 aColorAry1
[3] = Color( 0x80, 0x80, 0x80 );
2843 aColorAry1
[4] = Color( 0x00, 0x00, 0x00 );
2844 aColorAry1
[5] = Color( 0x00, 0xFF, 0x00 );
2845 aColorAry2
[0] = rStyleSettings
.GetFaceColor();
2846 aColorAry2
[1] = rStyleSettings
.GetWindowColor();
2847 aColorAry2
[2] = rStyleSettings
.GetLightColor();
2848 aColorAry2
[3] = rStyleSettings
.GetShadowColor();
2849 aColorAry2
[4] = rStyleSettings
.GetDarkShadowColor();
2850 aColorAry2
[5] = rStyleSettings
.GetWindowTextColor();
2852 static_assert( sizeof(aColorAry1
) == sizeof(aColorAry2
), "aColorAry1 must match aColorAry2" );
2854 for (const auto &a
: rResources
)
2857 aBmpEx
.Replace(aColorAry1
, aColorAry2
, SAL_N_ELEMENTS(aColorAry1
));
2858 rList
.emplace_back(aBmpEx
);
2862 Image
RadioButton::GetRadioImage( const AllSettings
& rSettings
, DrawButtonFlags nFlags
)
2864 ImplSVData
* pSVData
= ImplGetSVData();
2865 const StyleSettings
& rStyleSettings
= rSettings
.GetStyleSettings();
2866 sal_uInt16 nStyle
= 0;
2868 if ( rStyleSettings
.GetOptions() & StyleSettingsOptions::Mono
)
2869 nStyle
= STYLE_RADIOBUTTON_MONO
;
2871 if ( pSVData
->maCtrlData
.maRadioImgList
.empty() ||
2872 (pSVData
->maCtrlData
.mnRadioStyle
!= nStyle
) ||
2873 (pSVData
->maCtrlData
.mnLastRadioFColor
!= rStyleSettings
.GetFaceColor()) ||
2874 (pSVData
->maCtrlData
.mnLastRadioWColor
!= rStyleSettings
.GetWindowColor()) ||
2875 (pSVData
->maCtrlData
.mnLastRadioLColor
!= rStyleSettings
.GetLightColor()) )
2877 pSVData
->maCtrlData
.maRadioImgList
.clear();
2879 pSVData
->maCtrlData
.mnLastRadioFColor
= rStyleSettings
.GetFaceColor();
2880 pSVData
->maCtrlData
.mnLastRadioWColor
= rStyleSettings
.GetWindowColor();
2881 pSVData
->maCtrlData
.mnLastRadioLColor
= rStyleSettings
.GetLightColor();
2883 std::vector
<OUString
> aResources
;
2886 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO1
);
2887 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO2
);
2888 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO3
);
2889 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO4
);
2890 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO5
);
2891 aResources
.emplace_back(SV_RESID_BITMAP_RADIOMONO6
);
2895 aResources
.emplace_back(SV_RESID_BITMAP_RADIO1
);
2896 aResources
.emplace_back(SV_RESID_BITMAP_RADIO2
);
2897 aResources
.emplace_back(SV_RESID_BITMAP_RADIO3
);
2898 aResources
.emplace_back(SV_RESID_BITMAP_RADIO4
);
2899 aResources
.emplace_back(SV_RESID_BITMAP_RADIO5
);
2900 aResources
.emplace_back(SV_RESID_BITMAP_RADIO6
);
2902 LoadThemedImageList( rStyleSettings
, pSVData
->maCtrlData
.maRadioImgList
, aResources
);
2903 pSVData
->maCtrlData
.mnRadioStyle
= nStyle
;
2907 if ( nFlags
& DrawButtonFlags::Disabled
)
2909 if ( nFlags
& DrawButtonFlags::Checked
)
2914 else if ( nFlags
& DrawButtonFlags::Pressed
)
2916 if ( nFlags
& DrawButtonFlags::Checked
)
2923 if ( nFlags
& DrawButtonFlags::Checked
)
2928 return pSVData
->maCtrlData
.maRadioImgList
[nIndex
];
2931 void RadioButton::ImplAdjustNWFSizes()
2933 GetOutDev()->Push( vcl::PushFlags::MAPMODE
);
2934 SetMapMode(MapMode(MapUnit::MapPixel
));
2936 ImplControlValue aControlValue
;
2937 Size
aCurSize( GetSizePixel() );
2938 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), aCurSize
);
2939 tools::Rectangle aBoundingRgn
, aContentRgn
;
2941 // get native size of a radiobutton
2942 if( GetNativeControlRegion( ControlType::Radiobutton
, ControlPart::Entire
, aCtrlRegion
,
2943 ControlState::DEFAULT
|ControlState::ENABLED
, aControlValue
,
2944 aBoundingRgn
, aContentRgn
) )
2946 Size aSize
= aContentRgn
.GetSize();
2948 if( aSize
.Height() > aCurSize
.Height() )
2950 aCurSize
.setHeight( aSize
.Height() );
2951 SetSizePixel( aCurSize
);
2958 Size
RadioButton::CalcMinimumSize(tools::Long nMaxWidth
) const
2962 aSize
= ImplGetRadioImageSize();
2965 aSize
= maImage
.GetSizePixel();
2966 aSize
.AdjustWidth(8);
2967 aSize
.AdjustHeight(8);
2970 if (Button::HasImage())
2972 Size aImgSize
= GetModeImage().GetSizePixel();
2973 aSize
= Size(std::max(aImgSize
.Width(), aSize
.Width()),
2974 std::max(aImgSize
.Height(), aSize
.Height()));
2977 OUString aText
= GetText();
2978 if (!aText
.isEmpty())
2980 bool bTopImage
= (GetStyle() & WB_TOP
) != 0;
2982 Size aTextSize
= GetTextRect( tools::Rectangle( Point(), Size( nMaxWidth
> 0 ? nMaxWidth
: 0x7fffffff, 0x7fffffff ) ),
2983 aText
, FixedText::ImplGetTextStyle( GetStyle() ) ).GetSize();
2985 aSize
.AdjustWidth(2 ); // for focus rect
2989 aSize
.AdjustWidth(ImplGetImageToTextDistance() );
2990 aSize
.AdjustWidth(aTextSize
.Width() );
2991 if ( aSize
.Height() < aTextSize
.Height() )
2992 aSize
.setHeight( aTextSize
.Height() );
2996 aSize
.AdjustHeight(6 );
2997 aSize
.AdjustHeight(GetTextHeight() );
2998 if ( aSize
.Width() < aTextSize
.Width() )
2999 aSize
.setWidth( aTextSize
.Width() );
3003 return CalcWindowSize( aSize
);
3006 Size
RadioButton::GetOptimalSize() const
3008 return CalcMinimumSize();
3011 void RadioButton::ShowFocus(const tools::Rectangle
& rRect
)
3013 if (IsNativeControlSupported(ControlType::Radiobutton
, ControlPart::Focus
))
3015 ImplControlValue aControlValue
;
3016 tools::Rectangle
aInRect(Point(0, 0), GetSizePixel());
3018 aInRect
.SetLeft( rRect
.Left() ); // exclude the radio element itself from the focusrect
3020 GetOutDev()->DrawNativeControl(ControlType::Radiobutton
, ControlPart::Focus
, aInRect
,
3021 ControlState::FOCUSED
, aControlValue
, OUString());
3023 Button::ShowFocus(rRect
);
3026 void RadioButton::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
3028 Button::DumpAsPropertyTree(rJsonWriter
);
3029 rJsonWriter
.put("checked", IsChecked());
3032 std::vector
<VclPtr
<RadioButton
>> aGroup
= GetRadioButtonGroup();
3033 for(const auto& pButton
: aGroup
)
3034 sGroupId
+= pButton
->get_id();
3036 if (!sGroupId
.isEmpty())
3037 rJsonWriter
.put("group", sGroupId
);
3041 SvMemoryStream
aOStm(6535, 6535);
3042 if(GraphicConverter::Export(aOStm
, maImage
.GetBitmapEx(), ConvertDataFormat::PNG
) == ERRCODE_NONE
)
3044 css::uno::Sequence
<sal_Int8
> aSeq( static_cast<sal_Int8
const *>(aOStm
.GetData()), aOStm
.Tell());
3045 OStringBuffer
aBuffer("data:image/png;base64,");
3046 ::comphelper::Base64::encode(aBuffer
, aSeq
);
3047 rJsonWriter
.put("image", aBuffer
);
3052 FactoryFunction
RadioButton::GetUITestFactory() const
3054 return RadioButtonUIObject::create
;
3057 void CheckBox::ImplInitCheckBoxData()
3059 meState
= TRISTATE_FALSE
;
3063 void CheckBox::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
3065 nStyle
= ImplInitStyle(getPreviousSibling(pParent
), nStyle
);
3066 Button::ImplInit( pParent
, nStyle
, nullptr );
3068 ImplInitSettings( true );
3071 WinBits
CheckBox::ImplInitStyle( const vcl::Window
* pPrevWindow
, WinBits nStyle
)
3073 if ( !(nStyle
& WB_NOTABSTOP
) )
3074 nStyle
|= WB_TABSTOP
;
3075 if ( !(nStyle
& WB_NOGROUP
) &&
3076 (!pPrevWindow
|| (pPrevWindow
->GetType() != WindowType::CHECKBOX
)) )
3081 const vcl::Font
& CheckBox::GetCanonicalFont( const StyleSettings
& _rStyle
) const
3083 return _rStyle
.GetRadioCheckFont();
3086 const Color
& CheckBox::GetCanonicalTextColor( const StyleSettings
& _rStyle
) const
3088 return _rStyle
.GetRadioCheckTextColor();
3091 void CheckBox::ImplInitSettings( bool bBackground
)
3093 Button::ImplInitSettings();
3098 vcl::Window
* pParent
= GetParent();
3099 if ( !IsControlBackground() &&
3100 (pParent
->IsChildTransparentModeEnabled() || IsNativeControlSupported( ControlType::Checkbox
, ControlPart::Entire
) ) )
3102 EnableChildTransparentMode();
3103 SetParentClipMode( ParentClipMode::NoClip
);
3104 SetPaintTransparent( true );
3106 if( IsNativeControlSupported( ControlType::Checkbox
, ControlPart::Entire
) )
3107 ImplGetWindowImpl()->mbUseNativeFocus
= ImplGetSVData()->maNWFData
.mbNoFocusRects
;
3111 EnableChildTransparentMode( false );
3112 SetParentClipMode();
3113 SetPaintTransparent( false );
3115 if ( IsControlBackground() )
3116 SetBackground( GetControlBackground() );
3118 SetBackground( pParent
->GetBackground() );
3122 void CheckBox::ImplDrawCheckBoxState(vcl::RenderContext
& rRenderContext
)
3124 bool bNativeOK
= rRenderContext
.IsNativeControlSupported(ControlType::Checkbox
, ControlPart::Entire
);
3127 ImplControlValue
aControlValue(meState
== TRISTATE_TRUE
? ButtonValue::On
: ButtonValue::Off
);
3128 tools::Rectangle
aCtrlRegion(maStateRect
);
3129 ControlState nState
= ControlState::NONE
;
3132 nState
|= ControlState::FOCUSED
;
3133 if (GetButtonState() & DrawButtonFlags::Default
)
3134 nState
|= ControlState::DEFAULT
;
3135 if (GetButtonState() & DrawButtonFlags::Pressed
)
3136 nState
|= ControlState::PRESSED
;
3138 nState
|= ControlState::ENABLED
;
3140 if (meState
== TRISTATE_TRUE
)
3141 aControlValue
.setTristateVal(ButtonValue::On
);
3142 else if (meState
== TRISTATE_INDET
)
3143 aControlValue
.setTristateVal(ButtonValue::Mixed
);
3145 if (IsMouseOver() && maMouseRect
.Contains(GetPointerPosPixel()))
3146 nState
|= ControlState::ROLLOVER
;
3148 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Checkbox
, ControlPart::Entire
, aCtrlRegion
,
3149 nState
, aControlValue
, OUString());
3155 DrawButtonFlags nStyle
= GetButtonState();
3157 nStyle
|= DrawButtonFlags::Disabled
;
3158 if (meState
== TRISTATE_INDET
)
3159 nStyle
|= DrawButtonFlags::DontKnow
;
3160 else if (meState
== TRISTATE_TRUE
)
3161 nStyle
|= DrawButtonFlags::Checked
;
3162 Image aImage
= GetCheckImage(GetSettings(), nStyle
);
3164 rRenderContext
.DrawImage(maStateRect
.TopLeft(), maStateRect
.GetSize(), aImage
);
3166 rRenderContext
.DrawImage(maStateRect
.TopLeft(), aImage
);
3169 void CheckBox::ImplDraw( OutputDevice
* pDev
, SystemTextColorFlags nSystemTextColorFlags
,
3170 const Point
& rPos
, const Size
& rSize
,
3171 const Size
& rImageSize
, tools::Rectangle
& rStateRect
,
3172 tools::Rectangle
& rMouseRect
)
3174 WinBits nWinStyle
= GetStyle();
3175 OUString
aText( GetText() );
3177 pDev
->Push( vcl::PushFlags::CLIPREGION
| vcl::PushFlags::LINECOLOR
);
3178 pDev
->IntersectClipRegion( tools::Rectangle( rPos
, rSize
) );
3180 if (!aText
.isEmpty() || HasImage())
3182 Button::ImplDrawRadioCheck(pDev
, nWinStyle
, nSystemTextColorFlags
,
3183 rPos
, rSize
, rImageSize
,
3184 rStateRect
, rMouseRect
);
3188 rStateRect
.SetLeft( rPos
.X() );
3189 if ( nWinStyle
& WB_VCENTER
)
3190 rStateRect
.SetTop( rPos
.Y()+((rSize
.Height()-rImageSize
.Height())/2) );
3191 else if ( nWinStyle
& WB_BOTTOM
)
3192 rStateRect
.SetTop( rPos
.Y()+rSize
.Height()-rImageSize
.Height() );
3194 rStateRect
.SetTop( rPos
.Y() );
3195 rStateRect
.SetRight( rStateRect
.Left()+rImageSize
.Width()-1 );
3196 rStateRect
.SetBottom( rStateRect
.Top()+rImageSize
.Height()-1 );
3197 // provide space for focusrect
3198 // note: this assumes that the control's size was adjusted
3199 // accordingly in Get/LoseFocus, so the onscreen position won't change
3201 rStateRect
.Move( 1, 1 );
3202 rMouseRect
= rStateRect
;
3204 ImplSetFocusRect( rStateRect
);
3210 void CheckBox::ImplDrawCheckBox(vcl::RenderContext
& rRenderContext
)
3212 Size aImageSize
= ImplGetCheckImageSize();
3213 aImageSize
.setWidth( CalcZoom( aImageSize
.Width() ) );
3214 aImageSize
.setHeight( CalcZoom( aImageSize
.Height() ) );
3218 ImplDraw(&rRenderContext
, SystemTextColorFlags::NONE
, Point(), GetOutputSizePixel(),
3219 aImageSize
, maStateRect
, maMouseRect
);
3221 ImplDrawCheckBoxState(rRenderContext
);
3223 ShowFocus(ImplGetFocusRect());
3226 void CheckBox::ImplCheck()
3229 if ( meState
== TRISTATE_FALSE
)
3230 eNewState
= TRISTATE_TRUE
;
3231 else if ( !mbTriState
)
3232 eNewState
= TRISTATE_FALSE
;
3233 else if ( meState
== TRISTATE_TRUE
)
3234 eNewState
= TRISTATE_INDET
;
3236 eNewState
= TRISTATE_FALSE
;
3237 meState
= eNewState
;
3239 VclPtr
<vcl::Window
> xWindow
= this;
3242 if ( xWindow
->isDisposed() )
3247 CheckBox::CheckBox( vcl::Window
* pParent
, WinBits nStyle
) :
3248 Button( WindowType::CHECKBOX
)
3250 ImplInitCheckBoxData();
3251 ImplInit( pParent
, nStyle
);
3254 void CheckBox::MouseButtonDown( const MouseEvent
& rMEvt
)
3256 if ( rMEvt
.IsLeft() && maMouseRect
.Contains( rMEvt
.GetPosPixel() ) )
3258 GetButtonState() |= DrawButtonFlags::Pressed
;
3264 Button::MouseButtonDown( rMEvt
);
3267 void CheckBox::Tracking( const TrackingEvent
& rTEvt
)
3269 if ( rTEvt
.IsTrackingEnded() )
3271 if ( GetButtonState() & DrawButtonFlags::Pressed
)
3273 if ( !(GetStyle() & WB_NOPOINTERFOCUS
) && !rTEvt
.IsTrackingCanceled() )
3276 GetButtonState() &= ~DrawButtonFlags::Pressed
;
3278 // do not call click handler if aborted
3279 if ( !rTEvt
.IsTrackingCanceled() )
3289 if ( maMouseRect
.Contains( rTEvt
.GetMouseEvent().GetPosPixel() ) )
3291 if ( !(GetButtonState() & DrawButtonFlags::Pressed
) )
3293 GetButtonState() |= DrawButtonFlags::Pressed
;
3299 if ( GetButtonState() & DrawButtonFlags::Pressed
)
3301 GetButtonState() &= ~DrawButtonFlags::Pressed
;
3308 void CheckBox::KeyInput( const KeyEvent
& rKEvt
)
3310 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
3312 if ( !aKeyCode
.GetModifier() && (aKeyCode
.GetCode() == KEY_SPACE
) )
3314 if ( !(GetButtonState() & DrawButtonFlags::Pressed
) )
3316 GetButtonState() |= DrawButtonFlags::Pressed
;
3320 else if ( (GetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_ESCAPE
) )
3322 GetButtonState() &= ~DrawButtonFlags::Pressed
;
3326 Button::KeyInput( rKEvt
);
3329 void CheckBox::KeyUp( const KeyEvent
& rKEvt
)
3331 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
3333 if ( (GetButtonState() & DrawButtonFlags::Pressed
) && (aKeyCode
.GetCode() == KEY_SPACE
) )
3335 GetButtonState() &= ~DrawButtonFlags::Pressed
;
3339 Button::KeyUp( rKEvt
);
3342 void CheckBox::FillLayoutData() const
3344 mxLayoutData
.emplace();
3345 const_cast<CheckBox
*>(this)->Invalidate();
3348 void CheckBox::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
3350 ImplDrawCheckBox(rRenderContext
);
3353 void CheckBox::Draw( OutputDevice
* pDev
, const Point
& rPos
,
3354 SystemTextColorFlags nFlags
)
3356 MapMode
aResMapMode( MapUnit::Map100thMM
);
3357 Point aPos
= pDev
->LogicToPixel( rPos
);
3358 Size aSize
= GetSizePixel();
3359 Size aImageSize
= pDev
->LogicToPixel( Size( 300, 300 ), aResMapMode
);
3360 Size aBrd1Size
= pDev
->LogicToPixel( Size( 20, 20 ), aResMapMode
);
3361 Size aBrd2Size
= pDev
->LogicToPixel( Size( 30, 30 ), aResMapMode
);
3362 tools::Long nCheckWidth
= pDev
->LogicToPixel( Size( 20, 20 ), aResMapMode
).Width();
3363 vcl::Font aFont
= GetDrawPixelFont( pDev
);
3364 tools::Rectangle aStateRect
;
3365 tools::Rectangle aMouseRect
;
3367 aImageSize
.setWidth( CalcZoom( aImageSize
.Width() ) );
3368 aImageSize
.setHeight( CalcZoom( aImageSize
.Height() ) );
3369 aBrd1Size
.setWidth( CalcZoom( aBrd1Size
.Width() ) );
3370 aBrd1Size
.setHeight( CalcZoom( aBrd1Size
.Height() ) );
3371 aBrd2Size
.setWidth( CalcZoom( aBrd2Size
.Width() ) );
3372 aBrd2Size
.setHeight( CalcZoom( aBrd2Size
.Height() ) );
3374 if ( !aBrd1Size
.Width() )
3375 aBrd1Size
.setWidth( 1 );
3376 if ( !aBrd1Size
.Height() )
3377 aBrd1Size
.setHeight( 1 );
3378 if ( !aBrd2Size
.Width() )
3379 aBrd2Size
.setWidth( 1 );
3380 if ( !aBrd2Size
.Height() )
3381 aBrd2Size
.setHeight( 1 );
3387 pDev
->SetFont( aFont
);
3388 if ( nFlags
& SystemTextColorFlags::Mono
)
3389 pDev
->SetTextColor( COL_BLACK
);
3391 pDev
->SetTextColor( GetTextColor() );
3392 pDev
->SetTextFillColor();
3394 ImplDraw( pDev
, nFlags
, aPos
, aSize
,
3395 aImageSize
, aStateRect
, aMouseRect
);
3397 pDev
->SetLineColor();
3398 pDev
->SetFillColor( COL_BLACK
);
3399 pDev
->DrawRect( aStateRect
);
3400 aStateRect
.AdjustLeft(aBrd1Size
.Width() );
3401 aStateRect
.AdjustTop(aBrd1Size
.Height() );
3402 aStateRect
.AdjustRight( -(aBrd1Size
.Width()) );
3403 aStateRect
.AdjustBottom( -(aBrd1Size
.Height()) );
3404 if ( meState
== TRISTATE_INDET
)
3405 pDev
->SetFillColor( COL_LIGHTGRAY
);
3407 pDev
->SetFillColor( COL_WHITE
);
3408 pDev
->DrawRect( aStateRect
);
3410 if ( meState
== TRISTATE_TRUE
)
3412 aStateRect
.AdjustLeft(aBrd2Size
.Width() );
3413 aStateRect
.AdjustTop(aBrd2Size
.Height() );
3414 aStateRect
.AdjustRight( -(aBrd2Size
.Width()) );
3415 aStateRect
.AdjustBottom( -(aBrd2Size
.Height()) );
3416 Point
aPos11( aStateRect
.TopLeft() );
3417 Point
aPos12( aStateRect
.BottomRight() );
3418 Point
aPos21( aStateRect
.TopRight() );
3419 Point
aPos22( aStateRect
.BottomLeft() );
3420 Point
aTempPos11( aPos11
);
3421 Point
aTempPos12( aPos12
);
3422 Point
aTempPos21( aPos21
);
3423 Point
aTempPos22( aPos22
);
3424 pDev
->SetLineColor( COL_BLACK
);
3425 tools::Long nDX
= 0;
3426 for ( tools::Long i
= 0; i
< nCheckWidth
; i
++ )
3430 aTempPos11
.setX( aPos11
.X()+nDX
);
3431 aTempPos12
.setX( aPos12
.X()+nDX
);
3432 aTempPos21
.setX( aPos21
.X()+nDX
);
3433 aTempPos22
.setX( aPos22
.X()+nDX
);
3438 aTempPos11
.setX( aPos11
.X()-nDX
);
3439 aTempPos12
.setX( aPos12
.X()-nDX
);
3440 aTempPos21
.setX( aPos21
.X()-nDX
);
3441 aTempPos22
.setX( aPos22
.X()-nDX
);
3443 pDev
->DrawLine( aTempPos11
, aTempPos12
);
3444 pDev
->DrawLine( aTempPos21
, aTempPos22
);
3451 void CheckBox::Resize()
3457 void CheckBox::GetFocus()
3459 if (GetText().isEmpty())
3461 // increase button size to have space for focus rect
3462 // checkboxes without text will draw focusrect around the check
3463 // See CheckBox::ImplDraw()
3464 Point
aPos( GetPosPixel() );
3465 Size
aSize( GetSizePixel() );
3467 aSize
.AdjustHeight(2 );
3468 aSize
.AdjustWidth(2 );
3469 setPosSizePixel( aPos
.X(), aPos
.Y(), aSize
.Width(), aSize
.Height() );
3471 // Trigger drawing to initialize the mouse rectangle, otherwise the mouse button down
3472 // handler would ignore the mouse event.
3476 ShowFocus( ImplGetFocusRect() );
3478 SetInputContext( InputContext( GetFont() ) );
3482 void CheckBox::LoseFocus()
3484 if ( GetButtonState() & DrawButtonFlags::Pressed
)
3486 GetButtonState() &= ~DrawButtonFlags::Pressed
;
3491 Button::LoseFocus();
3493 if (GetText().isEmpty())
3495 // decrease button size again (see GetFocus())
3496 // checkboxes without text will draw focusrect around the check
3497 Point
aPos( GetPosPixel() );
3498 Size
aSize( GetSizePixel() );
3500 aSize
.AdjustHeight( -2 );
3501 aSize
.AdjustWidth( -2 );
3502 setPosSizePixel( aPos
.X(), aPos
.Y(), aSize
.Width(), aSize
.Height() );
3507 void CheckBox::StateChanged( StateChangedType nType
)
3509 Button::StateChanged( nType
);
3511 if ( nType
== StateChangedType::State
)
3513 if ( IsReallyVisible() && IsUpdateMode() )
3514 Invalidate( maStateRect
);
3516 else if ( (nType
== StateChangedType::Enable
) ||
3517 (nType
== StateChangedType::Text
) ||
3518 (nType
== StateChangedType::Data
) ||
3519 (nType
== StateChangedType::UpdateMode
) )
3521 if ( IsUpdateMode() )
3524 else if ( nType
== StateChangedType::Style
)
3526 SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev
), GetStyle() ) );
3528 if ( (GetPrevStyle() & CHECKBOX_VIEW_STYLE
) !=
3529 (GetStyle() & CHECKBOX_VIEW_STYLE
) )
3531 if ( IsUpdateMode() )
3535 else if ( (nType
== StateChangedType::Zoom
) ||
3536 (nType
== StateChangedType::ControlFont
) )
3538 ImplInitSettings( false );
3541 else if ( nType
== StateChangedType::ControlForeground
)
3543 ImplInitSettings( false );
3546 else if ( nType
== StateChangedType::ControlBackground
)
3548 ImplInitSettings( true );
3553 void CheckBox::DataChanged( const DataChangedEvent
& rDCEvt
)
3555 Button::DataChanged( rDCEvt
);
3557 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
3558 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
3559 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
3560 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
3562 ImplInitSettings( true );
3567 bool CheckBox::PreNotify( NotifyEvent
& rNEvt
)
3569 if( rNEvt
.GetType() == NotifyEventType::MOUSEMOVE
)
3571 const MouseEvent
* pMouseEvt
= rNEvt
.GetMouseEvent();
3572 if( pMouseEvt
&& !pMouseEvt
->GetButtons() && !pMouseEvt
->IsSynthetic() && !pMouseEvt
->IsModifierChanged() )
3574 // trigger redraw if mouse over state has changed
3575 if( IsNativeControlSupported(ControlType::Checkbox
, ControlPart::Entire
) )
3577 if (maMouseRect
.Contains(GetPointerPosPixel()) != maMouseRect
.Contains(GetLastPointerPosPixel()) ||
3578 pMouseEvt
->IsLeaveWindow() || pMouseEvt
->IsEnterWindow())
3580 Invalidate( maStateRect
);
3586 return Button::PreNotify(rNEvt
);
3589 void CheckBox::Toggle()
3591 ImplCallEventListenersAndHandler( VclEventId::CheckboxToggle
, [this] () { maToggleHdl
.Call(*this); } );
3594 void CheckBox::SetState( TriState eState
)
3596 if ( !mbTriState
&& (eState
== TRISTATE_INDET
) )
3597 eState
= TRISTATE_FALSE
;
3599 if ( meState
!= eState
)
3602 StateChanged( StateChangedType::State
);
3607 bool CheckBox::set_property(const OUString
&rKey
, const OUString
&rValue
)
3609 if (rKey
== "active")
3610 SetState(toBool(rValue
) ? TRISTATE_TRUE
: TRISTATE_FALSE
);
3612 return Button::set_property(rKey
, rValue
);
3616 void CheckBox::EnableTriState( bool bTriState
)
3618 if ( mbTriState
!= bTriState
)
3620 mbTriState
= bTriState
;
3622 if ( !bTriState
&& (meState
== TRISTATE_INDET
) )
3623 SetState( TRISTATE_FALSE
);
3627 Size
CheckBox::ImplGetCheckImageSize() const
3630 bool bDefaultSize
= true;
3631 if( IsNativeControlSupported( ControlType::Checkbox
, ControlPart::Entire
) )
3633 ImplControlValue aControlValue
;
3634 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), GetSizePixel() );
3635 tools::Rectangle aBoundingRgn
, aContentRgn
;
3637 // get native size of a check box
3638 if( GetNativeControlRegion( ControlType::Checkbox
, ControlPart::Entire
, aCtrlRegion
,
3639 ControlState::DEFAULT
|ControlState::ENABLED
,
3641 aBoundingRgn
, aContentRgn
) )
3643 aSize
= aContentRgn
.GetSize();
3644 bDefaultSize
= false;
3648 aSize
= GetCheckImage( GetSettings(), DrawButtonFlags::NONE
).GetSizePixel();
3652 Image
CheckBox::GetCheckImage( const AllSettings
& rSettings
, DrawButtonFlags nFlags
)
3654 ImplSVData
* pSVData
= ImplGetSVData();
3655 const StyleSettings
& rStyleSettings
= rSettings
.GetStyleSettings();
3656 sal_uInt16 nStyle
= 0;
3658 if ( rStyleSettings
.GetOptions() & StyleSettingsOptions::Mono
)
3659 nStyle
= STYLE_CHECKBOX_MONO
;
3661 if ( pSVData
->maCtrlData
.maCheckImgList
.empty() ||
3662 (pSVData
->maCtrlData
.mnCheckStyle
!= nStyle
) ||
3663 (pSVData
->maCtrlData
.mnLastCheckFColor
!= rStyleSettings
.GetFaceColor()) ||
3664 (pSVData
->maCtrlData
.mnLastCheckWColor
!= rStyleSettings
.GetWindowColor()) ||
3665 (pSVData
->maCtrlData
.mnLastCheckLColor
!= rStyleSettings
.GetLightColor()) )
3667 pSVData
->maCtrlData
.maCheckImgList
.clear();
3669 pSVData
->maCtrlData
.mnLastCheckFColor
= rStyleSettings
.GetFaceColor();
3670 pSVData
->maCtrlData
.mnLastCheckWColor
= rStyleSettings
.GetWindowColor();
3671 pSVData
->maCtrlData
.mnLastCheckLColor
= rStyleSettings
.GetLightColor();
3673 std::vector
<OUString
> aResources
;
3676 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO1
);
3677 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO2
);
3678 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO3
);
3679 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO4
);
3680 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO5
);
3681 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO6
);
3682 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO7
);
3683 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO8
);
3684 aResources
.emplace_back(SV_RESID_BITMAP_CHECKMONO9
);
3688 aResources
.emplace_back(SV_RESID_BITMAP_CHECK1
);
3689 aResources
.emplace_back(SV_RESID_BITMAP_CHECK2
);
3690 aResources
.emplace_back(SV_RESID_BITMAP_CHECK3
);
3691 aResources
.emplace_back(SV_RESID_BITMAP_CHECK4
);
3692 aResources
.emplace_back(SV_RESID_BITMAP_CHECK5
);
3693 aResources
.emplace_back(SV_RESID_BITMAP_CHECK6
);
3694 aResources
.emplace_back(SV_RESID_BITMAP_CHECK7
);
3695 aResources
.emplace_back(SV_RESID_BITMAP_CHECK8
);
3696 aResources
.emplace_back(SV_RESID_BITMAP_CHECK9
);
3698 LoadThemedImageList(rStyleSettings
, pSVData
->maCtrlData
.maCheckImgList
, aResources
);
3699 pSVData
->maCtrlData
.mnCheckStyle
= nStyle
;
3703 if ( nFlags
& DrawButtonFlags::Disabled
)
3705 if ( nFlags
& DrawButtonFlags::DontKnow
)
3707 else if ( nFlags
& DrawButtonFlags::Checked
)
3712 else if ( nFlags
& DrawButtonFlags::Pressed
)
3714 if ( nFlags
& DrawButtonFlags::DontKnow
)
3716 else if ( nFlags
& DrawButtonFlags::Checked
)
3723 if ( nFlags
& DrawButtonFlags::DontKnow
)
3725 else if ( nFlags
& DrawButtonFlags::Checked
)
3730 return pSVData
->maCtrlData
.maCheckImgList
[nIndex
];
3733 void CheckBox::ImplAdjustNWFSizes()
3735 GetOutDev()->Push( vcl::PushFlags::MAPMODE
);
3736 SetMapMode(MapMode(MapUnit::MapPixel
));
3738 ImplControlValue aControlValue
;
3739 Size
aCurSize( GetSizePixel() );
3740 tools::Rectangle
aCtrlRegion( Point( 0, 0 ), aCurSize
);
3741 tools::Rectangle aBoundingRgn
, aContentRgn
;
3743 // get native size of a radiobutton
3744 if( GetNativeControlRegion( ControlType::Checkbox
, ControlPart::Entire
, aCtrlRegion
,
3745 ControlState::DEFAULT
|ControlState::ENABLED
, aControlValue
,
3746 aBoundingRgn
, aContentRgn
) )
3748 Size aSize
= aContentRgn
.GetSize();
3750 if( aSize
.Height() > aCurSize
.Height() )
3752 aCurSize
.setHeight( aSize
.Height() );
3753 SetSizePixel( aCurSize
);
3760 Size
CheckBox::CalcMinimumSize( tools::Long nMaxWidth
) const
3762 Size aSize
= ImplGetCheckImageSize();
3763 nMaxWidth
-= aSize
.Width();
3765 OUString aText
= GetText();
3766 if (!aText
.isEmpty())
3768 // subtract what will be added later
3770 nMaxWidth
-= ImplGetImageToTextDistance();
3772 Size aTextSize
= GetTextRect( tools::Rectangle( Point(), Size( nMaxWidth
> 0 ? nMaxWidth
: 0x7fffffff, 0x7fffffff ) ),
3773 aText
, FixedText::ImplGetTextStyle( GetStyle() ) ).GetSize();
3774 aSize
.AdjustWidth(2 ); // for focus rect
3775 aSize
.AdjustWidth(ImplGetImageToTextDistance() );
3776 aSize
.AdjustWidth(aTextSize
.Width() );
3777 if ( aSize
.Height() < aTextSize
.Height() )
3778 aSize
.setHeight( aTextSize
.Height() );
3782 // is this still correct ? since the checkbox now
3783 // shows a focus rect it should be 2 pixels wider and longer
3784 /* since otherwise the controls in the Writer hang too far up
3786 aSize.Height() += 2;
3790 return CalcWindowSize( aSize
);
3793 Size
CheckBox::GetOptimalSize() const
3795 int nWidthRequest(get_width_request());
3796 return CalcMinimumSize(nWidthRequest
!= -1 ? nWidthRequest
: 0);
3799 void CheckBox::ShowFocus(const tools::Rectangle
& rRect
)
3801 if (IsNativeControlSupported(ControlType::Checkbox
, ControlPart::Focus
))
3803 ImplControlValue aControlValue
;
3804 tools::Rectangle
aInRect(Point(0, 0), GetSizePixel());
3806 aInRect
.SetLeft( rRect
.Left() ); // exclude the checkbox itself from the focusrect
3808 GetOutDev()->DrawNativeControl(ControlType::Checkbox
, ControlPart::Focus
, aInRect
,
3809 ControlState::FOCUSED
, aControlValue
, OUString());
3811 Button::ShowFocus(rRect
);
3814 void CheckBox::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
3816 Button::DumpAsPropertyTree(rJsonWriter
);
3817 rJsonWriter
.put("checked", IsChecked());
3820 FactoryFunction
CheckBox::GetUITestFactory() const
3822 return CheckBoxUIObject::create
;
3825 ImageButton::ImageButton( vcl::Window
* pParent
, WinBits nStyle
) :
3826 PushButton( pParent
, nStyle
)
3831 void ImageButton::ImplInitStyle()
3833 WinBits nStyle
= GetStyle();
3835 if ( ! ( nStyle
& ( WB_RIGHT
| WB_LEFT
) ) )
3836 nStyle
|= WB_CENTER
;
3838 if ( ! ( nStyle
& ( WB_TOP
| WB_BOTTOM
) ) )
3839 nStyle
|= WB_VCENTER
;
3844 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */