Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/control/button.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
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 .
18
 */
19
20
#include <tools/poly.hxx>
21
22
#include <vcl/builder.hxx>
23
#include <vcl/cvtgrf.hxx>
24
#include <vcl/image.hxx>
25
#include <vcl/bitmap.hxx>
26
#include <vcl/decoview.hxx>
27
#include <vcl/event.hxx>
28
#include <vcl/rendercontext/SystemTextColorFlags.hxx>
29
#include <vcl/svapp.hxx>
30
#include <vcl/settings.hxx>
31
#include <vcl/toolkit/dialog.hxx>
32
#include <vcl/toolkit/fixed.hxx>
33
#include <vcl/toolkit/button.hxx>
34
#include <vcl/salnativewidgets.hxx>
35
#include <vcl/toolkit/edit.hxx>
36
#include <vcl/layout.hxx>
37
#include <vcl/stdtext.hxx>
38
#include <vcl/uitest/uiobject.hxx>
39
40
#include <accessibility/vclxaccessiblebutton.hxx>
41
#include <accessibility/vclxaccessiblecheckbox.hxx>
42
#include <accessibility/vclxaccessibleradiobutton.hxx>
43
#include <bitmaps.hlst>
44
#include <svdata.hxx>
45
#include <window.h>
46
#include <vclstatuslistener.hxx>
47
#include <osl/diagnose.h>
48
49
#include <comphelper/base64.hxx>
50
#include <comphelper/dispatchcommand.hxx>
51
#include <comphelper/lok.hxx>
52
#include <officecfg/Office/Common.hxx>
53
#include <boost/property_tree/ptree.hpp>
54
#include <tools/json_writer.hxx>
55
#include <tools/mapunit.hxx>
56
#include <tools/stream.hxx>
57
58
59
using namespace css;
60
61
constexpr auto PUSHBUTTON_VIEW_STYLE = WB_3DLOOK |
62
                                     WB_LEFT | WB_CENTER | WB_RIGHT |
63
                                     WB_TOP | WB_VCENTER | WB_BOTTOM |
64
                                     WB_WORDBREAK | WB_NOLABEL |
65
                                     WB_DEFBUTTON | WB_NOLIGHTBORDER |
66
                                     WB_RECTSTYLE | WB_SMALLSTYLE |
67
                                     WB_TOGGLE;
68
constexpr auto RADIOBUTTON_VIEW_STYLE = WB_3DLOOK |
69
                                     WB_LEFT | WB_CENTER | WB_RIGHT |
70
                                     WB_TOP | WB_VCENTER | WB_BOTTOM |
71
                                     WB_WORDBREAK | WB_NOLABEL;
72
constexpr auto CHECKBOX_VIEW_STYLE = WB_3DLOOK |
73
                                     WB_LEFT | WB_CENTER | WB_RIGHT |
74
                                     WB_TOP | WB_VCENTER | WB_BOTTOM |
75
                                     WB_WORDBREAK | WB_NOLABEL;
76
77
0
#define STYLE_RADIOBUTTON_MONO      (sal_uInt16(0x0001)) // legacy
78
0
#define STYLE_CHECKBOX_MONO         (sal_uInt16(0x0001)) // legacy
79
80
class ImplCommonButtonData
81
{
82
public:
83
    ImplCommonButtonData();
84
85
    tools::Rectangle       maFocusRect;
86
    DrawButtonFlags mnButtonState;
87
    bool            mbSmallSymbol;
88
    bool            mbGeneratedTooltip;
89
90
    Image           maImage;
91
    ImageAlign      meImageAlign;
92
    SymbolAlign     meSymbolAlign;
93
94
    Image           maCustomContentImage;
95
96
    /** StatusListener. Updates the button as the slot state changes */
97
    rtl::Reference<VclStatusListener<Button>> mpStatusListener;
98
};
99
100
0
ImplCommonButtonData::ImplCommonButtonData() :  mnButtonState(DrawButtonFlags::NONE),
101
0
mbSmallSymbol(false), mbGeneratedTooltip(false),  meImageAlign(ImageAlign::Top), meSymbolAlign(SymbolAlign::LEFT)
102
0
{
103
0
}
104
105
Button::Button( WindowType eType ) :
106
0
    Control( eType ),
107
0
    mpButtonData( std::make_unique<ImplCommonButtonData>() )
108
0
{
109
0
}
Unexecuted instantiation: Button::Button(WindowType)
Unexecuted instantiation: Button::Button(WindowType)
110
111
Button::~Button()
112
0
{
113
0
    disposeOnce();
114
0
}
115
116
void Button::dispose()
117
0
{
118
0
    if (mpButtonData->mpStatusListener.is())
119
0
        mpButtonData->mpStatusListener->dispose();
120
0
    Control::dispose();
121
0
}
122
123
void Button::SetCommandHandler(const OUString& aCommand, const css::uno::Reference<css::frame::XFrame>& rFrame)
124
0
{
125
0
    maCommand = aCommand;
126
0
    SetClickHdl( LINK( this, Button, dispatchCommandHandler) );
127
128
0
    mpButtonData->mpStatusListener = new VclStatusListener<Button>(this, rFrame, aCommand);
129
0
    mpButtonData->mpStatusListener->startListening();
130
0
}
131
132
void Button::Click()
133
0
{
134
0
    ImplCallEventListenersAndHandler( VclEventId::ButtonClick, [this] () { maClickHdl.Call(this); } );
135
0
}
136
137
void Button::SetModeImage( const Image& rImage )
138
0
{
139
0
    if ( rImage != mpButtonData->maImage )
140
0
    {
141
0
        mpButtonData->maImage = rImage;
142
0
        StateChanged( StateChangedType::Data );
143
0
        queue_resize();
144
0
    }
145
0
}
146
147
Image const & Button::GetModeImage( ) const
148
0
{
149
0
    return mpButtonData->maImage;
150
0
}
151
152
bool Button::HasImage() const
153
0
{
154
0
    return !!(mpButtonData->maImage);
155
0
}
156
157
void Button::SetImageAlign( ImageAlign eAlign )
158
0
{
159
0
    if ( mpButtonData->meImageAlign != eAlign )
160
0
    {
161
0
        mpButtonData->meImageAlign = eAlign;
162
0
        StateChanged( StateChangedType::Data );
163
0
    }
164
0
}
165
166
ImageAlign Button::GetImageAlign() const
167
0
{
168
0
    return mpButtonData->meImageAlign;
169
0
}
170
171
void Button::SetCustomButtonImage(const Image& rImage)
172
0
{
173
0
    if (rImage != mpButtonData->maCustomContentImage)
174
0
    {
175
0
        mpButtonData->maCustomContentImage = rImage;
176
0
        StateChanged( StateChangedType::Data );
177
0
    }
178
0
}
179
180
Image const & Button::GetCustomButtonImage() const
181
0
{
182
0
    return mpButtonData->maCustomContentImage;
183
0
}
184
185
DrawTextFlags Button::ImplGetTextStyle( WinBits nWinStyle, SystemTextColorFlags nSystemTextColorFlags ) const
186
0
{
187
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
188
0
    DrawTextFlags nTextStyle = FixedText::ImplGetTextStyle(nWinStyle & ~WB_DEFBUTTON);
189
190
0
    if (!IsEnabled())
191
0
        nTextStyle |= DrawTextFlags::Disable;
192
193
0
    if ((nSystemTextColorFlags & SystemTextColorFlags::Mono) ||
194
0
        (rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
195
0
    {
196
0
        nTextStyle |= DrawTextFlags::Mono;
197
0
    }
198
199
0
    return nTextStyle;
200
0
}
201
202
void Button::ImplDrawAlignedImage(OutputDevice* pDev, Point& rPos,
203
                                  Size& rSize,
204
                                  sal_Int32 nImageSep,
205
                                  DrawTextFlags nTextStyle, tools::Rectangle *pSymbolRect,
206
                                  bool bAddImageSep)
207
0
{
208
0
    OUString aText(GetText());
209
0
    bool bDrawImage = HasImage();
210
0
    bool bDrawText  = !aText.isEmpty();
211
0
    bool bHasSymbol = pSymbolRect != nullptr;
212
213
    // No text and no image => nothing to do => return
214
0
    if (!bDrawImage && !bDrawText && !bHasSymbol)
215
0
        return;
216
217
0
    WinBits nWinStyle = GetStyle();
218
0
    tools::Rectangle aOutRect( rPos, rSize );
219
0
    ImageAlign eImageAlign = mpButtonData->meImageAlign;
220
0
    Size aImageSize = mpButtonData->maImage.GetSizePixel();
221
222
0
    aImageSize.setWidth( CalcZoom( aImageSize.Width() ) );
223
0
    aImageSize.setHeight( CalcZoom( aImageSize.Height() ) );
224
225
    // Drawing text or symbol only is simple, use style and output rectangle
226
0
    if (bHasSymbol && !bDrawImage && !bDrawText)
227
0
    {
228
0
        *pSymbolRect = aOutRect;
229
0
        return;
230
0
    }
231
0
    else if (bDrawText && !bDrawImage && !bHasSymbol)
232
0
    {
233
0
        aOutRect = DrawControlText(*pDev, aOutRect, aText, nTextStyle, nullptr, nullptr);
234
0
        tools::Rectangle textRect = GetTextRect(
235
0
            tools::Rectangle(Point(), Size(0x7fffffff, 0x7fffffff)), aText, nTextStyle);
236
        // If the button text doesn't fit into it, put it into a tooltip (might happen in sidebar)
237
0
        if (GetQuickHelpText()!= aText && mpButtonData->mbGeneratedTooltip)
238
0
            SetQuickHelpText(u""_ustr);
239
0
        if (GetQuickHelpText().isEmpty() && textRect.getOpenWidth() > rSize.getWidth())
240
0
        {
241
0
            SetQuickHelpText(aText);
242
0
            mpButtonData->mbGeneratedTooltip = true;
243
0
        }
244
245
0
        ImplSetFocusRect(aOutRect);
246
0
        rSize = aOutRect.GetSize();
247
0
        rPos = aOutRect.TopLeft();
248
249
0
        return;
250
0
    }
251
252
    // check for HC mode ( image only! )
253
0
    Image* pImage = &(mpButtonData->maImage);
254
255
0
    Size aTextSize;
256
0
    Size aSymbolSize;
257
0
    Size aDeviceTextSize;
258
0
    Point aImagePos = rPos;
259
0
    Point aTextPos = rPos;
260
0
    tools::Rectangle aUnion(aImagePos, aImageSize);
261
0
    tools::Long nSymbolHeight = 0;
262
263
0
    if (bDrawText || bHasSymbol)
264
0
    {
265
        // Get the size of the text output area ( the symbol will be drawn in
266
        // this area as well, so the symbol rectangle will be calculated here, too )
267
268
0
        tools::Rectangle aRect(Point(), rSize);
269
0
        Size aTSSize;
270
271
0
        if (bHasSymbol)
272
0
        {
273
0
            tools::Rectangle aSymbol;
274
0
            if (bDrawText)
275
0
            {
276
0
                nSymbolHeight = pDev->GetTextHeight();
277
0
                if (mpButtonData->mbSmallSymbol)
278
0
                    nSymbolHeight = nSymbolHeight * 3 / 4;
279
280
0
                aSymbol = tools::Rectangle(Point(), Size(nSymbolHeight, nSymbolHeight));
281
0
                ImplCalcSymbolRect(aSymbol);
282
0
                aRect.AdjustLeft(3 * nSymbolHeight / 2 );
283
0
                aTSSize.setWidth( 3 * nSymbolHeight / 2 );
284
0
            }
285
0
            else
286
0
            {
287
0
                aSymbol = tools::Rectangle(Point(), rSize);
288
0
                ImplCalcSymbolRect(aSymbol);
289
0
                aTSSize.setWidth( aSymbol.GetWidth() );
290
0
            }
291
0
            aTSSize.setHeight( aSymbol.GetHeight() );
292
0
            aSymbolSize = aSymbol.GetSize();
293
0
        }
294
295
0
        if (bDrawText)
296
0
        {
297
0
            if ((eImageAlign == ImageAlign::LeftTop)     ||
298
0
                (eImageAlign == ImageAlign::Left )        ||
299
0
                (eImageAlign == ImageAlign::LeftBottom)  ||
300
0
                (eImageAlign == ImageAlign::RightTop)    ||
301
0
                (eImageAlign == ImageAlign::Right)        ||
302
0
                (eImageAlign == ImageAlign::RightBottom))
303
0
            {
304
0
                aRect.AdjustRight( -sal_Int32(aImageSize.Width() + nImageSep) );
305
0
            }
306
0
            else if ((eImageAlign == ImageAlign::TopLeft)    ||
307
0
                     (eImageAlign == ImageAlign::Top)         ||
308
0
                     (eImageAlign == ImageAlign::TopRight)   ||
309
0
                     (eImageAlign == ImageAlign::BottomLeft) ||
310
0
                     (eImageAlign == ImageAlign::Bottom)      ||
311
0
                     (eImageAlign == ImageAlign::BottomRight))
312
0
            {
313
0
                aRect.AdjustBottom( -sal_Int32(aImageSize.Height() + nImageSep) );
314
0
            }
315
316
0
            aRect = GetControlTextRect(*pDev, aRect, aText, nTextStyle, &aDeviceTextSize);
317
0
            aTextSize = aRect.GetSize();
318
319
0
            aTSSize.AdjustWidth(aTextSize.Width() );
320
321
0
            if (aTSSize.Height() < aTextSize.Height())
322
0
                aTSSize.setHeight( aTextSize.Height() );
323
324
0
            if (bAddImageSep && bDrawImage)
325
0
            {
326
0
                tools::Long nDiff = (aImageSize.Height() - aTextSize.Height()) / 3;
327
0
                if (nDiff > 0)
328
0
                    nImageSep += nDiff;
329
0
            }
330
0
        }
331
332
0
        Size aMax;
333
0
        aMax.setWidth( std::max(aTSSize.Width(), aImageSize.Width()) );
334
0
        aMax.setHeight( std::max(aTSSize.Height(), aImageSize.Height()) );
335
336
        // Now calculate the output area for the image and the text according to the image align flags
337
338
0
        if ((eImageAlign == ImageAlign::Left) ||
339
0
            (eImageAlign == ImageAlign::Right))
340
0
        {
341
0
            aImagePos.setY( rPos.Y() + (aMax.Height() - aImageSize.Height()) / 2 );
342
0
            aTextPos.setY( rPos.Y() + (aMax.Height() - aTSSize.Height()) / 2 );
343
0
        }
344
0
        else if ((eImageAlign == ImageAlign::LeftBottom) ||
345
0
                 (eImageAlign == ImageAlign::RightBottom))
346
0
        {
347
0
            aImagePos.setY( rPos.Y() + aMax.Height() - aImageSize.Height() );
348
0
            aTextPos.setY( rPos.Y() + aMax.Height() - aTSSize.Height() );
349
0
        }
350
0
        else if ((eImageAlign == ImageAlign::Top) ||
351
0
                 (eImageAlign == ImageAlign::Bottom))
352
0
        {
353
0
            aImagePos.setX( rPos.X() + (aMax.Width() - aImageSize.Width()) / 2 );
354
0
            aTextPos.setX( rPos.X() + (aMax.Width() - aTSSize.Width()) / 2 );
355
0
        }
356
0
        else if ((eImageAlign == ImageAlign::TopRight) ||
357
0
                 (eImageAlign == ImageAlign::BottomRight))
358
0
        {
359
0
            aImagePos.setX( rPos.X() + aMax.Width() - aImageSize.Width() );
360
0
            aTextPos.setX( rPos.X() + aMax.Width() - aTSSize.Width() );
361
0
        }
362
363
0
        if ((eImageAlign == ImageAlign::LeftTop) ||
364
0
            (eImageAlign == ImageAlign::Left)     ||
365
0
            (eImageAlign == ImageAlign::LeftBottom))
366
0
        {
367
0
            aTextPos.setX( rPos.X() + aImageSize.Width() + nImageSep );
368
0
        }
369
0
        else if ((eImageAlign == ImageAlign::RightTop) ||
370
0
                 (eImageAlign == ImageAlign::Right)     ||
371
0
                 (eImageAlign == ImageAlign::RightBottom))
372
0
        {
373
0
            aImagePos.setX( rPos.X() + aTSSize.Width() + nImageSep );
374
0
        }
375
0
        else if ((eImageAlign == ImageAlign::TopLeft) ||
376
0
                 (eImageAlign == ImageAlign::Top)      ||
377
0
                 (eImageAlign == ImageAlign::TopRight))
378
0
        {
379
0
            aTextPos.setY( rPos.Y() + aImageSize.Height() + nImageSep );
380
0
        }
381
0
        else if ((eImageAlign == ImageAlign::BottomLeft) ||
382
0
                 (eImageAlign == ImageAlign::Bottom)      ||
383
0
                 (eImageAlign == ImageAlign::BottomRight))
384
0
        {
385
0
            aImagePos.setY( rPos.Y() + aTSSize.Height() + nImageSep );
386
0
        }
387
0
        else if (eImageAlign == ImageAlign::Center)
388
0
        {
389
0
            aImagePos.setX( rPos.X() + (aMax.Width()  - aImageSize.Width()) / 2 );
390
0
            aImagePos.setY( rPos.Y() + (aMax.Height() - aImageSize.Height()) / 2 );
391
0
            aTextPos.setX( rPos.X() + (aMax.Width()  - aTSSize.Width()) / 2 );
392
0
            aTextPos.setY( rPos.Y() + (aMax.Height() - aTSSize.Height()) / 2 );
393
0
        }
394
0
        aUnion = tools::Rectangle(aImagePos, aImageSize);
395
0
        aUnion.Union(tools::Rectangle(aTextPos, aTSSize));
396
0
    }
397
398
    // Now place the combination of text and image in the output area of the button
399
    // according to the window style (WinBits)
400
0
    tools::Long nXOffset = 0;
401
0
    tools::Long nYOffset = 0;
402
403
0
    if (nWinStyle & WB_CENTER)
404
0
    {
405
0
        nXOffset = (rSize.Width() - aUnion.GetWidth()) / 2;
406
0
    }
407
0
    else if (nWinStyle & WB_RIGHT)
408
0
    {
409
0
        nXOffset = rSize.Width() - aUnion.GetWidth();
410
0
    }
411
412
0
    if (nWinStyle & WB_VCENTER)
413
0
    {
414
0
        nYOffset = (rSize.Height() - aUnion.GetHeight()) / 2;
415
0
    }
416
0
    else if (nWinStyle & WB_BOTTOM)
417
0
    {
418
0
        nYOffset = rSize.Height() - aUnion.GetHeight();
419
0
    }
420
421
    // the top left corner should always be visible, so we don't allow negative offsets
422
0
    if (nXOffset < 0) nXOffset = 0;
423
0
    if (nYOffset < 0) nYOffset = 0;
424
425
0
    aImagePos.AdjustX(nXOffset );
426
0
    aImagePos.AdjustY(nYOffset );
427
0
    aTextPos.AdjustX(nXOffset );
428
0
    aTextPos.AdjustY(nYOffset );
429
430
    // set rPos and rSize to the union
431
0
    rSize = aUnion.GetSize();
432
0
    rPos.AdjustX(nXOffset );
433
0
    rPos.AdjustY(nYOffset );
434
435
0
    if (bHasSymbol)
436
0
    {
437
0
        if (mpButtonData->meSymbolAlign == SymbolAlign::RIGHT)
438
0
        {
439
0
            Point aRightPos(aTextPos.X() + aTextSize.Width() + aSymbolSize.Width() / 2, aTextPos.Y());
440
0
            *pSymbolRect = tools::Rectangle(aRightPos, aSymbolSize);
441
0
        }
442
0
        else
443
0
        {
444
0
            *pSymbolRect = tools::Rectangle(aTextPos, aSymbolSize);
445
0
            aTextPos.AdjustX(3 * nSymbolHeight / 2 );
446
0
        }
447
0
        if (mpButtonData->mbSmallSymbol)
448
0
        {
449
0
            nYOffset = (aUnion.GetHeight() - aSymbolSize.Height()) / 2;
450
0
            pSymbolRect->SetPosY(aTextPos.Y() + nYOffset);
451
0
        }
452
0
    }
453
454
0
    DrawImageFlags nStyle = DrawImageFlags::NONE;
455
456
0
    if (!IsEnabled())
457
0
    {
458
0
        nStyle |= DrawImageFlags::Disable;
459
0
    }
460
461
0
    if (IsZoom())
462
0
        pDev->DrawImage(aImagePos, aImageSize, *pImage, nStyle);
463
0
    else
464
0
        pDev->DrawImage(aImagePos, *pImage, nStyle);
465
466
0
    if (bDrawText)
467
0
    {
468
0
        const tools::Rectangle aTOutRect(aTextPos, aTextSize);
469
0
        ImplSetFocusRect(aTOutRect);
470
0
        DrawControlText(*pDev, aTOutRect, aText, nTextStyle, nullptr, nullptr, &aDeviceTextSize);
471
0
    }
472
0
    else
473
0
    {
474
0
        ImplSetFocusRect(tools::Rectangle(aImagePos, aImageSize));
475
0
    }
476
0
}
477
478
void Button::ImplSetFocusRect(const tools::Rectangle &rFocusRect)
479
0
{
480
0
    tools::Rectangle aFocusRect = rFocusRect;
481
0
    tools::Rectangle aOutputRect(Point(), GetOutputSizePixel());
482
483
0
    if (!aFocusRect.IsEmpty())
484
0
    {
485
0
        aFocusRect.AdjustLeft( -1 );
486
0
        aFocusRect.AdjustTop( -1 );
487
0
        aFocusRect.AdjustRight( 1 );
488
0
        aFocusRect.AdjustBottom( 1 );
489
0
    }
490
491
0
    if (aFocusRect.Left()   < aOutputRect.Left())
492
0
        aFocusRect.SetLeft( aOutputRect.Left() );
493
0
    if (aFocusRect.Top()    < aOutputRect.Top())
494
0
        aFocusRect.SetTop( aOutputRect.Top() );
495
0
    if (aFocusRect.Right()  > aOutputRect.Right())
496
0
        aFocusRect.SetRight( aOutputRect.Right() );
497
0
    if (aFocusRect.Bottom() > aOutputRect.Bottom())
498
0
        aFocusRect.SetBottom( aOutputRect.Bottom() );
499
500
0
    mpButtonData->maFocusRect = aFocusRect;
501
0
}
502
503
const tools::Rectangle& Button::ImplGetFocusRect() const
504
0
{
505
0
    return mpButtonData->maFocusRect;
506
0
}
507
508
DrawButtonFlags& Button::GetButtonState()
509
0
{
510
0
    return mpButtonData->mnButtonState;
511
0
}
512
513
DrawButtonFlags Button::GetButtonState() const
514
0
{
515
0
    return mpButtonData->mnButtonState;
516
0
}
517
518
void Button::ImplSetSymbolAlign( SymbolAlign eAlign )
519
0
{
520
0
    if ( mpButtonData->meSymbolAlign != eAlign )
521
0
    {
522
0
        mpButtonData->meSymbolAlign = eAlign;
523
0
        StateChanged( StateChangedType::Data );
524
0
    }
525
0
}
526
527
void Button::SetSmallSymbol()
528
0
{
529
0
    mpButtonData->mbSmallSymbol = true;
530
0
}
531
532
bool Button::IsSmallSymbol () const
533
0
{
534
0
    return mpButtonData->mbSmallSymbol;
535
0
}
536
537
bool Button::set_property(const OUString &rKey, const OUString &rValue)
538
0
{
539
0
    if (rKey == "image-position")
540
0
    {
541
0
        ImageAlign eAlign = ImageAlign::Left;
542
0
        if (rValue == "left")
543
0
            eAlign = ImageAlign::Left;
544
0
        else if (rValue == "right")
545
0
            eAlign = ImageAlign::Right;
546
0
        else if (rValue == "top")
547
0
            eAlign = ImageAlign::Top;
548
0
        else if (rValue == "bottom")
549
0
            eAlign = ImageAlign::Bottom;
550
0
        SetImageAlign(eAlign);
551
0
    }
552
0
    else if (rKey == "focus-on-click")
553
0
    {
554
0
        WinBits nBits = GetStyle();
555
0
        nBits &= ~WB_NOPOINTERFOCUS;
556
0
        if (!toBool(rValue))
557
0
            nBits |= WB_NOPOINTERFOCUS;
558
0
        SetStyle(nBits);
559
0
    }
560
0
    else
561
0
        return Control::set_property(rKey, rValue);
562
0
    return true;
563
0
}
564
565
void Button::statusChanged(const css::frame::FeatureStateEvent& rEvent)
566
0
{
567
0
    Enable(rEvent.IsEnabled);
568
0
}
569
570
FactoryFunction Button::GetUITestFactory() const
571
0
{
572
0
    return ButtonUIObject::create;
573
0
}
574
575
namespace
576
{
577
578
std::string_view symbolTypeName(SymbolType eSymbolType)
579
0
{
580
0
    switch (eSymbolType)
581
0
    {
582
0
        case SymbolType::DONTKNOW:         return "DONTKNOW";
583
0
        case SymbolType::IMAGE:            return "IMAGE";
584
0
        case SymbolType::ARROW_UP:         return "ARROW_UP";
585
0
        case SymbolType::ARROW_DOWN:       return "ARROW_DOWN";
586
0
        case SymbolType::ARROW_LEFT:       return "ARROW_LEFT";
587
0
        case SymbolType::ARROW_RIGHT:      return "ARROW_RIGHT";
588
0
        case SymbolType::SPIN_UP:          return "SPIN_UP";
589
0
        case SymbolType::SPIN_DOWN:        return "SPIN_DOWN";
590
0
        case SymbolType::SPIN_LEFT:        return "SPIN_LEFT";
591
0
        case SymbolType::SPIN_RIGHT:       return "SPIN_RIGHT";
592
0
        case SymbolType::FIRST:            return "FIRST";
593
0
        case SymbolType::LAST:             return "LAST";
594
0
        case SymbolType::PREV:             return "PREV";
595
0
        case SymbolType::NEXT:             return "NEXT";
596
0
        case SymbolType::PAGEUP:           return "PAGEUP";
597
0
        case SymbolType::PAGEDOWN:         return "PAGEDOWN";
598
0
        case SymbolType::PLAY:             return "PLAY";
599
0
        case SymbolType::STOP:             return "STOP";
600
0
        case SymbolType::CLOSE:            return "CLOSE";
601
0
        case SymbolType::CHECKMARK:        return "CHECKMARK";
602
0
        case SymbolType::RADIOCHECKMARK:   return "RADIOCHECKMARK";
603
0
        case SymbolType::FLOAT:            return "FLOAT";
604
0
        case SymbolType::DOCK:             return "DOCK";
605
0
        case SymbolType::HIDE:             return "HIDE";
606
0
        case SymbolType::HELP:             return "HELP";
607
0
        case SymbolType::PLUS:             return "PLUS";
608
0
    }
609
610
0
    return "UNKNOWN";
611
0
}
612
613
}
614
615
void Button::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
616
0
{
617
0
    Control::DumpAsPropertyTree(rJsonWriter);
618
0
    rJsonWriter.put("text", GetText());
619
0
    if (HasImage())
620
0
    {
621
0
        SvMemoryStream aOStm(6535, 6535);
622
0
        if(GraphicConverter::Export(aOStm, GetModeImage().GetBitmap(), ConvertDataFormat::PNG) == ERRCODE_NONE)
623
0
        {
624
0
            css::uno::Sequence<sal_Int8> aSeq( static_cast<sal_Int8 const *>(aOStm.GetData()), aOStm.Tell());
625
0
            OStringBuffer aBuffer("data:image/png;base64,");
626
0
            ::comphelper::Base64::encode(aBuffer, aSeq);
627
0
            rJsonWriter.put("image", aBuffer);
628
0
        }
629
0
    }
630
631
0
    if (GetStyle() & WB_DEFBUTTON)
632
0
        rJsonWriter.put("has_default", true);
633
0
}
634
635
void PushButton::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
636
0
{
637
0
    Button::DumpAsPropertyTree(rJsonWriter);
638
0
    if (GetSymbol() != SymbolType::DONTKNOW)
639
0
        rJsonWriter.put("symbol", symbolTypeName(GetSymbol()));
640
0
    if (isToggleButton())
641
0
    {
642
0
        rJsonWriter.put("isToggle", true);
643
0
        if (IsChecked())
644
0
            rJsonWriter.put("checked", true);
645
0
    }
646
0
}
647
648
IMPL_STATIC_LINK( Button, dispatchCommandHandler, Button*, pButton, void )
649
0
{
650
0
    if (pButton == nullptr)
651
0
        return;
652
653
0
    comphelper::dispatchCommand(pButton->maCommand, uno::Sequence<beans::PropertyValue>());
654
0
}
655
656
void PushButton::ImplInitPushButtonData()
657
0
{
658
0
    mpWindowImpl->mbPushButton    = true;
659
660
0
    meSymbol        = SymbolType::DONTKNOW;
661
0
    meState         = TRISTATE_FALSE;
662
0
    mnDDStyle       = PushButtonDropdownStyle::NONE;
663
0
    mbPressed       = false;
664
0
    mbIsAction      = false;
665
0
}
666
667
namespace
668
{
669
    vcl::Window* getPreviousSibling(vcl::Window const *pParent)
670
0
    {
671
0
        return pParent ? pParent->GetWindow(GetWindowType::LastChild) : nullptr;
672
0
    }
673
}
674
675
void PushButton::ImplInit( vcl::Window* pParent, WinBits nStyle )
676
0
{
677
0
    nStyle = ImplInitStyle(getPreviousSibling(pParent), nStyle);
678
0
    Button::ImplInit( pParent, nStyle, nullptr );
679
680
0
    if ( nStyle & WB_NOLIGHTBORDER )
681
0
        GetButtonState() |= DrawButtonFlags::NoLightBorder;
682
683
0
    ImplInitSettings( true );
684
0
}
685
686
WinBits PushButton::ImplInitStyle( const vcl::Window* pPrevWindow, WinBits nStyle )
687
0
{
688
0
    if ( !(nStyle & WB_NOTABSTOP) )
689
0
        nStyle |= WB_TABSTOP;
690
691
    // if no alignment is given, default to "vertically centered". This is because since
692
    // #i26046#, we respect the vertical alignment flags (previously we didn't completely),
693
    // but we of course want to look as before when no vertical alignment is specified
694
0
    if ( ( nStyle & ( WB_TOP | WB_VCENTER | WB_BOTTOM ) ) == 0 )
695
0
        nStyle |= WB_VCENTER;
696
697
0
    if ( !(nStyle & WB_NOGROUP) &&
698
0
         (!pPrevWindow ||
699
0
          ((pPrevWindow->GetType() != WindowType::PUSHBUTTON  ) &&
700
0
           (pPrevWindow->GetType() != WindowType::OKBUTTON    ) &&
701
0
           (pPrevWindow->GetType() != WindowType::CANCELBUTTON) &&
702
0
           (pPrevWindow->GetType() != WindowType::HELPBUTTON  )) ) )
703
0
        nStyle |= WB_GROUP;
704
0
    return nStyle;
705
0
}
706
707
const vcl::Font& PushButton::GetCanonicalFont( const StyleSettings& _rStyle ) const
708
0
{
709
0
    return _rStyle.GetPushButtonFont();
710
0
}
711
712
const Color& PushButton::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
713
0
{
714
0
    return _rStyle.GetButtonTextColor();
715
0
}
716
717
void PushButton::ImplInitSettings( bool bBackground )
718
0
{
719
0
    Button::ImplInitSettings();
720
721
0
    if ( !bBackground )
722
0
        return;
723
724
0
    SetBackground();
725
    // #i38498#: do not check for GetParent()->IsChildTransparentModeEnabled()
726
    // otherwise the formcontrol button will be overdrawn due to ParentClipMode::NoClip
727
    // for radio and checkbox this is ok as they should appear transparent in documents
728
0
    if ( IsNativeControlSupported( ControlType::Pushbutton, ControlPart::Entire ) ||
729
0
         (GetStyle() & WB_FLATBUTTON) != 0 )
730
0
    {
731
0
        EnableChildTransparentMode();
732
0
        SetParentClipMode( ParentClipMode::NoClip );
733
0
        SetPaintTransparent( true );
734
735
0
        if ((GetStyle() & WB_FLATBUTTON) == 0)
736
0
            mpWindowImpl->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects;
737
0
        else
738
0
            mpWindowImpl->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRectsForFlatButtons;
739
0
    }
740
0
    else
741
0
    {
742
0
        EnableChildTransparentMode( false );
743
0
        SetParentClipMode();
744
0
        SetPaintTransparent( false );
745
0
    }
746
0
}
747
748
void PushButton::ImplDrawPushButtonFrame(vcl::RenderContext& rRenderContext,
749
                                         tools::Rectangle& rRect, DrawButtonFlags nStyle)
750
0
{
751
0
    if (!(GetStyle() & (WB_RECTSTYLE | WB_SMALLSTYLE)))
752
0
    {
753
0
        StyleSettings aStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
754
0
        if (IsControlBackground())
755
0
            aStyleSettings.Set3DColors(GetControlBackground());
756
0
    }
757
758
0
    DecorationView aDecoView(&rRenderContext);
759
0
    if (IsControlBackground())
760
0
    {
761
0
        AllSettings aSettings = rRenderContext.GetSettings();
762
0
        AllSettings aOldSettings = aSettings;
763
0
        StyleSettings aStyleSettings = aSettings.GetStyleSettings();
764
0
        if (nStyle & DrawButtonFlags::Highlight)
765
0
        {
766
            // with the custom background, native highlight do nothing, so code below mimic
767
            // native highlight by changing luminance
768
0
            Color controlBackgroundColorHighlighted = GetControlBackground();
769
0
            sal_uInt8 colorLuminance = controlBackgroundColorHighlighted.GetLuminance();
770
0
            if (colorLuminance < 205)
771
0
                controlBackgroundColorHighlighted.IncreaseLuminance(50);
772
0
            else
773
0
                controlBackgroundColorHighlighted.DecreaseLuminance(50);
774
0
            aStyleSettings.Set3DColors(controlBackgroundColorHighlighted);
775
0
        }
776
0
        else
777
0
            aStyleSettings.Set3DColors(GetControlBackground());
778
0
        aSettings.SetStyleSettings(aStyleSettings);
779
780
        // Call OutputDevice::SetSettings() explicitly, as rRenderContext may
781
        // be a vcl::Window in fact, and vcl::Window::SetSettings() will call
782
        // Invalidate(), which is a problem, since we're in Paint().
783
0
        rRenderContext.OutputDevice::SetSettings(aSettings);
784
0
        rRect = aDecoView.DrawButton(rRect, nStyle);
785
0
        rRenderContext.OutputDevice::SetSettings(aOldSettings);
786
0
    }
787
0
    else
788
0
        rRect = aDecoView.DrawButton(rRect, nStyle);
789
0
}
790
791
bool PushButton::ImplHitTestPushButton( vcl::Window const * pDev,
792
                                        const Point& rPos )
793
0
{
794
0
    tools::Rectangle   aTestRect( Point(), pDev->GetOutputSizePixel() );
795
796
0
    return aTestRect.Contains( rPos );
797
0
}
798
799
DrawTextFlags PushButton::ImplGetTextStyle( SystemTextColorFlags nSystemTextColorFlags ) const
800
0
{
801
0
    const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
802
803
0
    DrawTextFlags nTextStyle = DrawTextFlags::Mnemonic | DrawTextFlags::MultiLine | DrawTextFlags::EndEllipsis;
804
805
0
    if ( ( rStyleSettings.GetOptions() & StyleSettingsOptions::Mono ) ||
806
0
         ( nSystemTextColorFlags & SystemTextColorFlags::Mono ) )
807
0
        nTextStyle |= DrawTextFlags::Mono;
808
809
0
    if ( GetStyle() & WB_WORDBREAK )
810
0
        nTextStyle |= DrawTextFlags::WordBreak;
811
0
    if ( GetStyle() & WB_NOLABEL )
812
0
        nTextStyle &= ~DrawTextFlags::Mnemonic;
813
814
0
    if ( GetStyle() & WB_LEFT )
815
0
        nTextStyle |= DrawTextFlags::Left;
816
0
    else if ( GetStyle() & WB_RIGHT )
817
0
        nTextStyle |= DrawTextFlags::Right;
818
0
    else
819
0
        nTextStyle |= DrawTextFlags::Center;
820
821
0
    if ( GetStyle() & WB_TOP )
822
0
        nTextStyle |= DrawTextFlags::Top;
823
0
    else if ( GetStyle() & WB_BOTTOM )
824
0
        nTextStyle |= DrawTextFlags::Bottom;
825
0
    else
826
0
        nTextStyle |= DrawTextFlags::VCenter;
827
828
0
    if ( !IsEnabled() )
829
0
        nTextStyle |= DrawTextFlags::Disable;
830
831
0
    return nTextStyle;
832
0
}
833
834
void PushButton::ImplDrawPushButtonContent(OutputDevice *pDev, SystemTextColorFlags nSystemTextColorFlags,
835
                                           const tools::Rectangle &rRect, bool bMenuBtnSep,
836
                                           DrawButtonFlags nButtonFlags)
837
0
{
838
0
    const StyleSettings &rStyleSettings = GetSettings().GetStyleSettings();
839
0
    tools::Rectangle aInRect = rRect;
840
0
    Color aColor;
841
0
    DrawTextFlags nTextStyle = ImplGetTextStyle(nSystemTextColorFlags);
842
0
    DrawSymbolFlags nStyle;
843
844
0
    if (aInRect.Right() < aInRect.Left() || aInRect.Bottom() < aInRect.Top())
845
0
        return;
846
847
0
    auto popIt = pDev->ScopedPush(vcl::PushFlags::CLIPREGION);
848
0
    pDev->IntersectClipRegion(aInRect);
849
850
0
    if (nSystemTextColorFlags & SystemTextColorFlags::Mono)
851
0
        aColor = COL_BLACK;
852
853
0
    else if (IsControlForeground())
854
0
        aColor = GetControlForeground();
855
856
    // Button types with possibly different text coloring are flat buttons and regular buttons. Regular buttons may be action
857
    // buttons and may have an additional default status. Moreover all buttons may have an additional pressed and rollover
858
    // (highlight) status. Pressed buttons are always in rollover status.
859
860
0
    else if (GetStyle() & WB_FLATBUTTON)
861
0
        if (nButtonFlags & DrawButtonFlags::Pressed)
862
0
            aColor = rStyleSettings.GetFlatButtonPressedRolloverTextColor();
863
0
        else if (nButtonFlags & DrawButtonFlags::Highlight)
864
0
            aColor = rStyleSettings.GetFlatButtonRolloverTextColor();
865
0
        else
866
0
            aColor = rStyleSettings.GetFlatButtonTextColor();
867
0
    else
868
0
        if (isAction() && (nButtonFlags & DrawButtonFlags::Default))
869
0
            if (nButtonFlags & DrawButtonFlags::Pressed)
870
0
                aColor = rStyleSettings.GetDefaultActionButtonPressedRolloverTextColor();
871
0
            else if (nButtonFlags & DrawButtonFlags::Highlight)
872
0
                aColor = rStyleSettings.GetDefaultActionButtonRolloverTextColor();
873
0
            else
874
0
                aColor = rStyleSettings.GetDefaultActionButtonTextColor();
875
0
        else if (isAction())
876
0
            if (nButtonFlags & DrawButtonFlags::Pressed)
877
0
                aColor = rStyleSettings.GetActionButtonPressedRolloverTextColor();
878
0
            else if (nButtonFlags & DrawButtonFlags::Highlight)
879
0
                aColor = rStyleSettings.GetActionButtonRolloverTextColor();
880
0
            else
881
0
                aColor = rStyleSettings.GetActionButtonTextColor();
882
0
        else if (nButtonFlags & DrawButtonFlags::Default)
883
0
            if (nButtonFlags & DrawButtonFlags::Pressed)
884
0
                aColor = rStyleSettings.GetDefaultButtonPressedRolloverTextColor();
885
0
            else if (nButtonFlags & DrawButtonFlags::Highlight)
886
0
                aColor = rStyleSettings.GetDefaultButtonRolloverTextColor();
887
0
            else
888
0
                aColor = rStyleSettings.GetDefaultButtonTextColor();
889
0
        else
890
0
            if (nButtonFlags & DrawButtonFlags::Pressed)
891
0
                aColor = rStyleSettings.GetButtonPressedRolloverTextColor();
892
0
            else if (nButtonFlags & DrawButtonFlags::Highlight)
893
0
                aColor = rStyleSettings.GetButtonRolloverTextColor();
894
0
            else
895
0
                aColor = rStyleSettings.GetButtonTextColor();
896
897
#if defined(MACOSX) || defined(IOS)
898
    // tdf#152486 These are the buttons in infobars where the infobar has a custom
899
    // background color and on these platforms the buttons blend with
900
    // their background.
901
    vcl::Window* pParent = GetParent();
902
    if (pParent->get_id() == "ExtraButton")
903
    {
904
        while (pParent && !pParent->IsControlBackground())
905
            pParent = pParent->GetParent();
906
        if (pParent)
907
        {
908
            if (aColor.IsBright() && !pParent->GetControlBackground().IsDark())
909
                aColor = COL_BLACK;
910
        }
911
    }
912
#endif
913
914
0
    pDev->SetTextColor(aColor);
915
916
0
    if ( IsEnabled() )
917
0
        nStyle = DrawSymbolFlags::NONE;
918
0
    else
919
0
        nStyle = DrawSymbolFlags::Disable;
920
921
0
    Size aSize = rRect.GetSize();
922
0
    Point aPos = rRect.TopLeft();
923
924
0
    sal_Int32 nImageSep = 1 + (pDev->GetTextHeight()-10)/2;
925
0
    if( nImageSep < 1 )
926
0
        nImageSep = 1;
927
0
    if ( mnDDStyle == PushButtonDropdownStyle::MenuButton )
928
0
    {
929
0
        tools::Long nSeparatorX = 0;
930
0
        tools::Rectangle aSymbolRect = aInRect;
931
932
        // calculate symbol size
933
0
        tools::Long nSymbolSize    = pDev->GetTextHeight() / 2 + 1;
934
0
        if (nSymbolSize > aSize.Width() / 2)
935
0
            nSymbolSize = aSize.Width() / 2;
936
937
0
        nSeparatorX = aInRect.Right() - 2*nSymbolSize;
938
939
        // tdf#141761 Minimum width should be (1) Pixel, see comment
940
        // with same task number above for more info
941
0
        const tools::Long nWidthAdjust(2*nSymbolSize);
942
0
        aSize.setWidth(std::max(static_cast<tools::Long>(1), aSize.getWidth() - nWidthAdjust));
943
944
        // center symbol rectangle in the separated area
945
0
        aSymbolRect.AdjustRight( -(nSymbolSize/2) );
946
0
        aSymbolRect.SetLeft( aSymbolRect.Right() - nSymbolSize );
947
948
0
        ImplDrawAlignedImage( pDev, aPos, aSize, nImageSep,
949
0
                              nTextStyle, nullptr, true );
950
951
0
        tools::Long nDistance = (aSymbolRect.GetHeight() > 10) ? 2 : 1;
952
0
        DecorationView aDecoView( pDev );
953
0
        if( bMenuBtnSep && nSeparatorX > 0 )
954
0
        {
955
0
            Point aStartPt( nSeparatorX, aSymbolRect.Top()+nDistance );
956
0
            Point aEndPt( nSeparatorX, aSymbolRect.Bottom()-nDistance );
957
0
            aDecoView.DrawSeparator( aStartPt, aEndPt );
958
0
        }
959
960
0
        aDecoView.DrawSymbol( aSymbolRect, SymbolType::SPIN_DOWN, aColor, nStyle );
961
962
0
    }
963
0
    else
964
0
    {
965
0
        tools::Rectangle aSymbolRect;
966
0
        ImplDrawAlignedImage( pDev, aPos, aSize, nImageSep,
967
0
                              nTextStyle, IsSymbol() ? &aSymbolRect : nullptr, true );
968
969
0
        if ( IsSymbol() )
970
0
        {
971
0
            DecorationView aDecoView( pDev );
972
0
            aDecoView.DrawSymbol( aSymbolRect, meSymbol, aColor, nStyle );
973
0
        }
974
0
    }
975
0
}
976
977
void PushButton::ImplDrawPushButton(vcl::RenderContext& rRenderContext)
978
0
{
979
0
    HideFocus();
980
981
0
    DrawButtonFlags nButtonStyle = GetButtonState();
982
0
    Size aOutSz(GetOutputSizePixel());
983
0
    tools::Rectangle aRect(Point(), aOutSz);
984
0
    tools::Rectangle aInRect = aRect;
985
0
    bool bNativeOK = false;
986
987
    // adjust style if button should be rendered 'pressed'
988
0
    if (mbPressed)
989
0
        nButtonStyle |= DrawButtonFlags::Pressed;
990
991
0
    if (GetStyle() & WB_FLATBUTTON)
992
0
        nButtonStyle |= DrawButtonFlags::Flat;
993
994
    // TODO: move this to Window class or make it a member !!!
995
0
    ControlType aCtrlType = ControlType::Generic;
996
0
    switch(GetParent()->GetType())
997
0
    {
998
0
        case WindowType::LISTBOX:
999
0
        case WindowType::MULTILISTBOX:
1000
0
        case WindowType::TREELISTBOX:
1001
0
            aCtrlType = ControlType::Listbox;
1002
0
            break;
1003
1004
0
        case WindowType::COMBOBOX:
1005
0
        case WindowType::PATTERNBOX:
1006
0
        case WindowType::NUMERICBOX:
1007
0
        case WindowType::METRICBOX:
1008
0
        case WindowType::CURRENCYBOX:
1009
0
        case WindowType::DATEBOX:
1010
0
        case WindowType::TIMEBOX:
1011
0
        case WindowType::LONGCURRENCYBOX:
1012
0
            aCtrlType = ControlType::Combobox;
1013
0
            break;
1014
0
        default:
1015
0
            break;
1016
0
    }
1017
1018
0
    bool bDropDown = (IsSymbol() && (GetSymbol() == SymbolType::SPIN_DOWN) && GetText().isEmpty());
1019
1020
0
    if( bDropDown && (aCtrlType == ControlType::Combobox || aCtrlType == ControlType::Listbox))
1021
0
    {
1022
0
        if (GetParent()->IsNativeControlSupported(aCtrlType, ControlPart::Entire))
1023
0
        {
1024
            // skip painting if the button was already drawn by the theme
1025
0
            if (aCtrlType == ControlType::Combobox)
1026
0
            {
1027
0
                Edit* pEdit = static_cast<Edit*>(GetParent());
1028
0
                if (pEdit->ImplUseNativeBorder(rRenderContext, pEdit->GetStyle()))
1029
0
                    bNativeOK = true;
1030
0
            }
1031
0
            else if (GetParent()->IsNativeControlSupported(aCtrlType, ControlPart::HasBackgroundTexture))
1032
0
            {
1033
0
                bNativeOK = true;
1034
0
            }
1035
1036
0
            if (!bNativeOK && GetParent()->IsNativeControlSupported(aCtrlType, ControlPart::ButtonDown))
1037
0
            {
1038
                // let the theme draw it, note we then need support
1039
                // for ControlType::Listbox/ControlPart::ButtonDown and ControlType::Combobox/ControlPart::ButtonDown
1040
1041
0
                ImplControlValue aControlValue;
1042
0
                ControlState nState = ControlState::NONE;
1043
1044
0
                if (mbPressed)
1045
0
                    nState |= ControlState::PRESSED;
1046
0
                if (GetButtonState() & DrawButtonFlags::Pressed)
1047
0
                    nState |= ControlState::PRESSED;
1048
0
                if (HasFocus())
1049
0
                    nState |= ControlState::FOCUSED;
1050
0
                if (GetButtonState() & DrawButtonFlags::Default)
1051
0
                    nState |= ControlState::DEFAULT;
1052
0
                if (Window::IsEnabled())
1053
0
                    nState |= ControlState::ENABLED;
1054
1055
0
                if (IsMouseOver() && aInRect.Contains(GetPointerPosPixel()))
1056
0
                    nState |= ControlState::ROLLOVER;
1057
1058
0
                bNativeOK = rRenderContext.DrawNativeControl(aCtrlType, ControlPart::ButtonDown, aInRect, nState,
1059
0
                                                             aControlValue, OUString());
1060
0
            }
1061
0
        }
1062
0
    }
1063
1064
0
    if (bNativeOK)
1065
0
        return;
1066
1067
0
    bool bRollOver = (IsMouseOver() && aInRect.Contains(GetPointerPosPixel()));
1068
0
    if (bRollOver)
1069
0
        nButtonStyle |= DrawButtonFlags::Highlight;
1070
    // tdf#123175 if there is a custom control bg set, draw the button without outsourcing to the NWF
1071
0
    bNativeOK = !IsControlBackground() && rRenderContext.IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Entire);
1072
0
    if (bNativeOK)
1073
0
    {
1074
0
        PushButtonValue aControlValue;
1075
0
        aControlValue.mbIsAction = isAction();
1076
1077
0
        tools::Rectangle aCtrlRegion(aInRect);
1078
0
        ControlState nState = ControlState::NONE;
1079
1080
0
        if (mbPressed || IsChecked())
1081
0
        {
1082
0
            nState |= ControlState::PRESSED;
1083
0
            nButtonStyle |= DrawButtonFlags::Pressed;
1084
0
        }
1085
0
        if (GetButtonState() & DrawButtonFlags::Pressed)
1086
0
            nState |= ControlState::PRESSED;
1087
0
        if (HasFocus())
1088
0
            nState |= ControlState::FOCUSED;
1089
0
        if (GetButtonState() & DrawButtonFlags::Default)
1090
0
            nState |= ControlState::DEFAULT;
1091
0
        if (Window::IsEnabled())
1092
0
            nState |= ControlState::ENABLED;
1093
1094
0
        if (bRollOver)
1095
0
        {
1096
0
            nButtonStyle |= DrawButtonFlags::Highlight;
1097
0
            nState |= ControlState::ROLLOVER;
1098
0
        }
1099
1100
0
        if (GetStyle() & WB_FLATBUTTON)
1101
0
            aControlValue.m_bFlatButton = true;
1102
1103
        // draw frame into invisible window to have aInRect modified correctly
1104
        // but do not shift the inner rect for pressed buttons (ie remove DrawButtonFlags::Pressed)
1105
        // this assumes the theme has enough visual cues to signalize the button was pressed
1106
        //Window aWin( this );
1107
        //ImplDrawPushButtonFrame( &aWin, aInRect, nButtonStyle & ~DrawButtonFlags::Pressed );
1108
1109
        // looks better this way as symbols were displaced slightly using the above approach
1110
0
        aInRect.AdjustTop(4 );
1111
0
        aInRect.AdjustBottom( -4 );
1112
0
        aInRect.AdjustLeft(4 );
1113
0
        aInRect.AdjustRight( -4 );
1114
1115
        // prepare single line hint (needed on mac to decide between normal push button and
1116
        // rectangular bevel button look)
1117
0
        Size aFontSize(Application::GetSettings().GetStyleSettings().GetPushButtonFont().GetFontSize());
1118
0
        aFontSize = rRenderContext.LogicToPixel(aFontSize, MapMode(MapUnit::MapPoint));
1119
0
        Size aInRectSize(rRenderContext.LogicToPixel(Size(aInRect.GetWidth(), aInRect.GetHeight())));
1120
0
        aControlValue.mbSingleLine = (aInRectSize.Height() < 2 * aFontSize.Height());
1121
1122
0
        if (!aControlValue.m_bFlatButton || (nState & ControlState::ROLLOVER) || (nState & ControlState::PRESSED)
1123
0
            || (HasFocus() && mpWindowImpl->mbUseNativeFocus
1124
0
                && !IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Focus)))
1125
0
        {
1126
0
            bNativeOK = rRenderContext.DrawNativeControl(ControlType::Pushbutton, ControlPart::Entire, aCtrlRegion, nState,
1127
0
                                                         aControlValue, OUString() /*PushButton::GetText()*/);
1128
0
        }
1129
0
        else
1130
0
        {
1131
0
            bNativeOK = true;
1132
0
        }
1133
1134
        // draw content using the same aInRect as non-native VCL would do
1135
0
        ImplDrawPushButtonContent(&rRenderContext, SystemTextColorFlags::NONE,
1136
0
                                  aInRect, /*bDrawMenuSep*/false, nButtonStyle);
1137
1138
0
        if (HasFocus())
1139
0
            ShowFocus(ImplGetFocusRect());
1140
0
    }
1141
1142
0
    if (bNativeOK)
1143
0
        return;
1144
1145
    // draw PushButtonFrame, aInRect has content size afterwards
1146
0
    if (GetStyle() & WB_FLATBUTTON)
1147
0
    {
1148
0
        tools::Rectangle aTempRect(aInRect);
1149
0
        ImplDrawPushButtonFrame(rRenderContext, aTempRect, nButtonStyle);
1150
0
        aInRect.AdjustLeft(2 );
1151
0
        aInRect.AdjustTop(2 );
1152
0
        aInRect.AdjustRight( -2 );
1153
0
        aInRect.AdjustBottom( -2 );
1154
0
    }
1155
0
    else
1156
0
    {
1157
0
        ImplDrawPushButtonFrame(rRenderContext, aInRect, nButtonStyle);
1158
0
    }
1159
1160
    // draw content
1161
0
    ImplDrawPushButtonContent(&rRenderContext, SystemTextColorFlags::NONE, aInRect, /*bDrawMenuSep*/false, nButtonStyle);
1162
1163
0
    if (HasFocus())
1164
0
    {
1165
0
        ShowFocus(ImplGetFocusRect());
1166
0
    }
1167
0
}
1168
1169
void PushButton::ImplSetDefButton( bool bSet )
1170
0
{
1171
0
    Size aSize( GetSizePixel() );
1172
0
    Point aPos( GetPosPixel() );
1173
0
    int dLeft(0), dRight(0), dTop(0), dBottom(0);
1174
0
    bool bSetPos = false;
1175
1176
0
    if ( IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Entire) )
1177
0
    {
1178
0
        tools::Rectangle aBound, aCont;
1179
0
        tools::Rectangle aCtrlRegion( 0, 0, 80, 20 ); // use a constant size to avoid accumulating
1180
                                             // will not work if the theme has dynamic adornment sizes
1181
0
        ImplControlValue aControlValue;
1182
1183
        // get native size of a 'default' button
1184
        // and adjust the VCL button if more space for adornment is required
1185
0
        if( GetNativeControlRegion( ControlType::Pushbutton, ControlPart::Entire, aCtrlRegion,
1186
0
                                    ControlState::DEFAULT|ControlState::ENABLED,
1187
0
                                    aControlValue,
1188
0
                                    aBound, aCont ) )
1189
0
        {
1190
0
            dLeft = aCont.Left() - aBound.Left();
1191
0
            dTop = aCont.Top() - aBound.Top();
1192
0
            dRight = aBound.Right() - aCont.Right();
1193
0
            dBottom = aBound.Bottom() - aCont.Bottom();
1194
0
            bSetPos = dLeft || dTop || dRight || dBottom;
1195
0
        }
1196
0
    }
1197
1198
0
    if ( bSet )
1199
0
    {
1200
0
        if( !(GetButtonState() & DrawButtonFlags::Default) && bSetPos )
1201
0
        {
1202
            // adjust pos/size when toggling from non-default to default
1203
0
            aPos.Move(-dLeft, -dTop);
1204
0
            aSize.AdjustWidth(dLeft + dRight );
1205
0
            aSize.AdjustHeight(dTop + dBottom );
1206
0
        }
1207
0
        GetButtonState() |= DrawButtonFlags::Default;
1208
0
    }
1209
0
    else
1210
0
    {
1211
0
        if( (GetButtonState() & DrawButtonFlags::Default) && bSetPos )
1212
0
        {
1213
            // adjust pos/size when toggling from default to non-default
1214
0
            aPos.Move(dLeft, dTop);
1215
0
            aSize.AdjustWidth( -(dLeft + dRight) );
1216
0
            aSize.AdjustHeight( -(dTop + dBottom) );
1217
0
        }
1218
0
        GetButtonState() &= ~DrawButtonFlags::Default;
1219
0
    }
1220
0
    if( bSetPos )
1221
0
        setPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height() );
1222
1223
0
    Invalidate();
1224
0
}
1225
1226
bool PushButton::ImplIsDefButton() const
1227
0
{
1228
0
    return bool(GetButtonState() & DrawButtonFlags::Default);
1229
0
}
1230
1231
PushButton::PushButton( WindowType nType ) :
1232
0
    Button( nType )
1233
0
{
1234
0
    ImplInitPushButtonData();
1235
0
}
Unexecuted instantiation: PushButton::PushButton(WindowType)
Unexecuted instantiation: PushButton::PushButton(WindowType)
1236
1237
PushButton::PushButton( vcl::Window* pParent, WinBits nStyle ) :
1238
0
    Button( WindowType::PUSHBUTTON )
1239
0
{
1240
0
    ImplInitPushButtonData();
1241
0
    ImplInit( pParent, nStyle );
1242
0
}
Unexecuted instantiation: PushButton::PushButton(vcl::Window*, long)
Unexecuted instantiation: PushButton::PushButton(vcl::Window*, long)
1243
1244
rtl::Reference<comphelper::OAccessible> PushButton::CreateAccessible()
1245
0
{
1246
0
    return new VCLXAccessibleButton(this);
1247
0
}
1248
1249
void PushButton::MouseButtonDown( const MouseEvent& rMEvt )
1250
0
{
1251
0
    if ( !(rMEvt.IsLeft() &&
1252
0
         ImplHitTestPushButton( this, rMEvt.GetPosPixel() )) )
1253
0
        return;
1254
1255
0
    StartTrackingFlags nTrackFlags = StartTrackingFlags::NONE;
1256
1257
0
    if ( ( GetStyle() & WB_REPEAT ) &&
1258
0
         ! ( GetStyle() & WB_TOGGLE ) )
1259
0
        nTrackFlags |= StartTrackingFlags::ButtonRepeat;
1260
1261
0
    GetButtonState() |= DrawButtonFlags::Pressed;
1262
0
    Invalidate();
1263
0
    StartTracking( nTrackFlags );
1264
1265
0
    if ( nTrackFlags & StartTrackingFlags::ButtonRepeat )
1266
0
        Click();
1267
0
}
1268
1269
void PushButton::Tracking( const TrackingEvent& rTEvt )
1270
0
{
1271
0
    if ( rTEvt.IsTrackingEnded() )
1272
0
    {
1273
0
        if ( GetButtonState() & DrawButtonFlags::Pressed )
1274
0
        {
1275
0
            if ( !(GetStyle() & WB_NOPOINTERFOCUS) && !rTEvt.IsTrackingCanceled() )
1276
0
                GrabFocus();
1277
1278
0
            if ( GetStyle() & WB_TOGGLE )
1279
0
            {
1280
                // Don't toggle, when aborted
1281
0
                if ( !rTEvt.IsTrackingCanceled() )
1282
0
                {
1283
0
                    if ( IsChecked() )
1284
0
                    {
1285
0
                        Check( false );
1286
0
                        GetButtonState() &= ~DrawButtonFlags::Pressed;
1287
0
                    }
1288
0
                    else
1289
0
                        Check();
1290
0
                }
1291
0
            }
1292
0
            else
1293
0
                GetButtonState() &= ~DrawButtonFlags::Pressed;
1294
1295
0
            Invalidate();
1296
1297
            // do not call Click handler if aborted
1298
0
            if ( !rTEvt.IsTrackingCanceled() )
1299
0
            {
1300
0
                if ( ! ( GetStyle() & WB_REPEAT ) || ( GetStyle() & WB_TOGGLE ) )
1301
0
                    Click();
1302
0
            }
1303
0
        }
1304
0
    }
1305
0
    else
1306
0
    {
1307
0
        if ( ImplHitTestPushButton( this, rTEvt.GetMouseEvent().GetPosPixel() ) )
1308
0
        {
1309
0
            if ( GetButtonState() & DrawButtonFlags::Pressed )
1310
0
            {
1311
0
                if ( rTEvt.IsTrackingRepeat() && (GetStyle() & WB_REPEAT) &&
1312
0
                     ! ( GetStyle() & WB_TOGGLE ) )
1313
0
                    Click();
1314
0
            }
1315
0
            else
1316
0
            {
1317
0
                GetButtonState() |= DrawButtonFlags::Pressed;
1318
0
                Invalidate();
1319
0
            }
1320
0
        }
1321
0
        else
1322
0
        {
1323
0
            if ( GetButtonState() & DrawButtonFlags::Pressed )
1324
0
            {
1325
0
                GetButtonState() &= ~DrawButtonFlags::Pressed;
1326
0
                Invalidate();
1327
0
            }
1328
0
        }
1329
0
    }
1330
0
}
1331
1332
void PushButton::KeyInput( const KeyEvent& rKEvt )
1333
0
{
1334
0
    vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
1335
1336
0
    if ( !aKeyCode.GetModifier() &&
1337
0
         ((aKeyCode.GetCode() == KEY_RETURN) || (aKeyCode.GetCode() == KEY_SPACE)) )
1338
0
    {
1339
0
        if ( !(GetButtonState() & DrawButtonFlags::Pressed) )
1340
0
        {
1341
0
            GetButtonState() |= DrawButtonFlags::Pressed;
1342
0
            Invalidate();
1343
0
        }
1344
1345
0
        if ( ( GetStyle() & WB_REPEAT ) &&
1346
0
             ! ( GetStyle() & WB_TOGGLE ) )
1347
0
            Click();
1348
0
    }
1349
0
    else if ( (GetButtonState() & DrawButtonFlags::Pressed) && (aKeyCode.GetCode() == KEY_ESCAPE) )
1350
0
    {
1351
0
        GetButtonState() &= ~DrawButtonFlags::Pressed;
1352
0
        Invalidate();
1353
0
    }
1354
0
    else
1355
0
        Button::KeyInput( rKEvt );
1356
0
}
1357
1358
void PushButton::KeyUp( const KeyEvent& rKEvt )
1359
0
{
1360
0
    vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
1361
1362
0
    if ( (GetButtonState() & DrawButtonFlags::Pressed) &&
1363
0
         ((aKeyCode.GetCode() == KEY_RETURN) || (aKeyCode.GetCode() == KEY_SPACE)) )
1364
0
    {
1365
0
        if ( GetStyle() & WB_TOGGLE )
1366
0
        {
1367
0
            if ( IsChecked() )
1368
0
            {
1369
0
                Check( false );
1370
0
                GetButtonState() &= ~DrawButtonFlags::Pressed;
1371
0
            }
1372
0
            else
1373
0
                Check();
1374
1375
0
            Toggle();
1376
0
        }
1377
0
        else
1378
0
            GetButtonState() &= ~DrawButtonFlags::Pressed;
1379
1380
0
        Invalidate();
1381
1382
0
        if ( !( GetStyle() & WB_REPEAT ) || ( GetStyle() & WB_TOGGLE ) )
1383
0
            Click();
1384
0
    }
1385
0
    else
1386
0
        Button::KeyUp( rKEvt );
1387
0
}
1388
1389
void PushButton::FillLayoutData() const
1390
0
{
1391
0
    mxLayoutData.emplace();
1392
0
    const_cast<PushButton*>(this)->Invalidate();
1393
0
}
1394
1395
void PushButton::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
1396
0
{
1397
0
    const Image& rCustomButtonImage = GetCustomButtonImage();
1398
0
    if (!!rCustomButtonImage)
1399
0
    {
1400
0
        rRenderContext.DrawImage(Point(0, 0), rCustomButtonImage);
1401
0
        return;
1402
0
    }
1403
0
    ImplDrawPushButton(rRenderContext);
1404
0
}
1405
1406
void PushButton::Draw( OutputDevice* pDev, const Point& rPos,
1407
                       SystemTextColorFlags nFlags )
1408
0
{
1409
0
    Point       aPos  = pDev->LogicToPixel( rPos );
1410
0
    Size        aSize = GetSizePixel();
1411
0
    tools::Rectangle   aRect( aPos, aSize );
1412
0
    vcl::Font   aFont = GetDrawPixelFont( pDev );
1413
1414
0
    auto popIt = pDev->ScopedPush();
1415
0
    pDev->SetMapMode();
1416
0
    pDev->SetFont( aFont );
1417
1418
0
    std::optional<StyleSettings> oOrigDevStyleSettings;
1419
1420
0
    if ( nFlags & SystemTextColorFlags::Mono )
1421
0
    {
1422
0
        pDev->SetTextColor( COL_BLACK );
1423
0
    }
1424
0
    else
1425
0
    {
1426
0
        pDev->SetTextColor( GetTextColor() );
1427
        // DecoView uses the FaceColor...
1428
0
        AllSettings aSettings = pDev->GetSettings();
1429
0
        StyleSettings aStyleSettings = aSettings.GetStyleSettings();
1430
0
        oOrigDevStyleSettings = aStyleSettings;
1431
0
        if ( IsControlBackground() )
1432
0
            aStyleSettings.SetFaceColor( GetControlBackground() );
1433
0
        else
1434
0
            aStyleSettings.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() );
1435
0
        aSettings.SetStyleSettings( aStyleSettings );
1436
0
        pDev->OutputDevice::SetSettings( aSettings );
1437
0
    }
1438
0
    pDev->SetTextFillColor();
1439
1440
0
    DecorationView aDecoView( pDev );
1441
0
    DrawButtonFlags nButtonStyle = DrawButtonFlags::NONE;
1442
0
    if ( nFlags & SystemTextColorFlags::Mono )
1443
0
        nButtonStyle |= DrawButtonFlags::Mono;
1444
0
    if ( IsChecked() )
1445
0
        nButtonStyle |= DrawButtonFlags::Checked;
1446
0
    aRect = aDecoView.DrawButton( aRect, nButtonStyle );
1447
1448
0
    ImplDrawPushButtonContent( pDev, nFlags, aRect, true, nButtonStyle );
1449
1450
    // restore original settings (which are not affected by Push/Pop) after
1451
    // finished drawing
1452
0
    if (oOrigDevStyleSettings)
1453
0
    {
1454
0
        AllSettings aSettings = pDev->GetSettings();
1455
0
        aSettings.SetStyleSettings(*oOrigDevStyleSettings);
1456
0
        pDev->OutputDevice::SetSettings( aSettings );
1457
0
    }
1458
0
}
1459
1460
void PushButton::Resize()
1461
0
{
1462
0
    Control::Resize();
1463
0
    Invalidate();
1464
0
}
1465
1466
void PushButton::GetFocus()
1467
0
{
1468
0
    ShowFocus( ImplGetFocusRect() );
1469
0
    SetInputContext( InputContext( GetFont() ) );
1470
0
    Button::GetFocus();
1471
0
}
1472
1473
void PushButton::LoseFocus()
1474
0
{
1475
0
    EndSelection();
1476
0
    HideFocus();
1477
0
    Button::LoseFocus();
1478
0
}
1479
1480
void PushButton::StateChanged( StateChangedType nType )
1481
0
{
1482
0
    Button::StateChanged( nType );
1483
1484
0
    if ( (nType == StateChangedType::Enable) ||
1485
0
         (nType == StateChangedType::Text) ||
1486
0
         (nType == StateChangedType::Data) ||
1487
0
         (nType == StateChangedType::State) ||
1488
0
         (nType == StateChangedType::UpdateMode) )
1489
0
    {
1490
0
        if ( IsReallyVisible() && IsUpdateMode() )
1491
0
            Invalidate();
1492
0
    }
1493
0
    else if ( nType == StateChangedType::Style )
1494
0
    {
1495
0
        SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev ), GetStyle() ) );
1496
1497
0
        bool bIsDefButton = ( GetStyle() & WB_DEFBUTTON ) != 0;
1498
0
        bool bWasDefButton = ( GetPrevStyle() & WB_DEFBUTTON ) != 0;
1499
0
        if ( bIsDefButton != bWasDefButton )
1500
0
            ImplSetDefButton( bIsDefButton );
1501
1502
0
        if ( IsReallyVisible() && IsUpdateMode() )
1503
0
        {
1504
0
            if ( (GetPrevStyle() & PUSHBUTTON_VIEW_STYLE) !=
1505
0
                 (GetStyle() & PUSHBUTTON_VIEW_STYLE) )
1506
0
                Invalidate();
1507
0
        }
1508
0
    }
1509
0
    else if ( (nType == StateChangedType::Zoom) ||
1510
0
              (nType == StateChangedType::ControlFont) )
1511
0
    {
1512
0
        ImplInitSettings( false );
1513
0
        Invalidate();
1514
0
    }
1515
0
    else if ( nType == StateChangedType::ControlForeground )
1516
0
    {
1517
0
        ImplInitSettings( false );
1518
0
        Invalidate();
1519
0
    }
1520
0
    else if ( nType == StateChangedType::ControlBackground )
1521
0
    {
1522
0
        ImplInitSettings( true );
1523
0
        Invalidate();
1524
0
    }
1525
0
}
1526
1527
void PushButton::DataChanged( const DataChangedEvent& rDCEvt )
1528
0
{
1529
0
    Button::DataChanged( rDCEvt );
1530
1531
0
    if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
1532
0
         (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
1533
0
         ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1534
0
          (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
1535
0
    {
1536
0
        ImplInitSettings( true );
1537
0
        Invalidate();
1538
0
    }
1539
0
}
1540
1541
bool PushButton::PreNotify( NotifyEvent& rNEvt )
1542
0
{
1543
0
    if( rNEvt.GetType() == NotifyEventType::MOUSEMOVE )
1544
0
    {
1545
0
        const MouseEvent* pMouseEvt = rNEvt.GetMouseEvent();
1546
0
        if( pMouseEvt && (pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow()) )
1547
0
        {
1548
            // trigger redraw as mouse over state has changed
1549
1550
            // TODO: move this to Window class or make it a member !!!
1551
0
            ControlType aCtrlType = ControlType::Generic;
1552
0
            switch( GetParent()->GetType() )
1553
0
            {
1554
0
                case WindowType::LISTBOX:
1555
0
                case WindowType::MULTILISTBOX:
1556
0
                case WindowType::TREELISTBOX:
1557
0
                    aCtrlType = ControlType::Listbox;
1558
0
                    break;
1559
1560
0
                case WindowType::COMBOBOX:
1561
0
                case WindowType::PATTERNBOX:
1562
0
                case WindowType::NUMERICBOX:
1563
0
                case WindowType::METRICBOX:
1564
0
                case WindowType::CURRENCYBOX:
1565
0
                case WindowType::DATEBOX:
1566
0
                case WindowType::TIMEBOX:
1567
0
                case WindowType::LONGCURRENCYBOX:
1568
0
                    aCtrlType = ControlType::Combobox;
1569
0
                    break;
1570
0
                default:
1571
0
                    break;
1572
0
            }
1573
1574
0
            bool bDropDown = ( IsSymbol() && (GetSymbol()==SymbolType::SPIN_DOWN) && GetText().isEmpty() );
1575
1576
0
            if( bDropDown && GetParent()->IsNativeControlSupported( aCtrlType, ControlPart::Entire) &&
1577
0
                   !GetParent()->IsNativeControlSupported( aCtrlType, ControlPart::ButtonDown) )
1578
0
            {
1579
0
                vcl::Window *pBorder = GetParent()->GetWindow( GetWindowType::Border );
1580
0
                if(aCtrlType == ControlType::Combobox)
1581
0
                {
1582
                    // only paint the button part to avoid flickering of the combobox text
1583
0
                    tools::Rectangle aClipRect( Point(), GetOutputSizePixel() );
1584
0
                    aClipRect.SetPos(pBorder->ScreenToOutputPixel(OutputToScreenPixel(aClipRect.TopLeft())));
1585
0
                    pBorder->Invalidate( aClipRect );
1586
0
                }
1587
0
                else
1588
0
                {
1589
0
                    pBorder->Invalidate( InvalidateFlags::NoErase );
1590
0
                }
1591
0
            }
1592
0
            else if( (GetStyle() & WB_FLATBUTTON) ||
1593
0
                     IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Entire) )
1594
0
            {
1595
0
                Invalidate();
1596
0
            }
1597
0
        }
1598
0
    }
1599
1600
0
    return Button::PreNotify(rNEvt);
1601
0
}
1602
1603
void PushButton::Toggle()
1604
0
{
1605
0
    ImplCallEventListenersAndHandler( VclEventId::PushbuttonToggle, nullptr );
1606
0
}
1607
1608
void PushButton::SetSymbol( SymbolType eSymbol )
1609
0
{
1610
0
    if ( meSymbol != eSymbol )
1611
0
    {
1612
0
        meSymbol = eSymbol;
1613
0
        CompatStateChanged( StateChangedType::Data );
1614
0
    }
1615
0
}
1616
1617
void PushButton::SetSymbolAlign( SymbolAlign eAlign )
1618
0
{
1619
0
    ImplSetSymbolAlign( eAlign );
1620
0
}
1621
1622
void PushButton::SetDropDown( PushButtonDropdownStyle nStyle )
1623
0
{
1624
0
    if ( mnDDStyle != nStyle )
1625
0
    {
1626
0
        mnDDStyle = nStyle;
1627
0
        CompatStateChanged( StateChangedType::Data );
1628
0
    }
1629
0
}
1630
1631
void PushButton::SetState( TriState eState )
1632
0
{
1633
0
    if ( meState == eState )
1634
0
        return;
1635
1636
0
    meState = eState;
1637
0
    if ( meState == TRISTATE_FALSE )
1638
0
        GetButtonState() &= ~DrawButtonFlags(DrawButtonFlags::Checked | DrawButtonFlags::DontKnow);
1639
0
    else if ( meState == TRISTATE_TRUE )
1640
0
    {
1641
0
        GetButtonState() &= ~DrawButtonFlags::DontKnow;
1642
0
        GetButtonState() |= DrawButtonFlags::Checked;
1643
0
    }
1644
0
    else // TRISTATE_INDET
1645
0
    {
1646
0
        GetButtonState() &= ~DrawButtonFlags::Checked;
1647
0
        GetButtonState() |= DrawButtonFlags::DontKnow;
1648
0
    }
1649
1650
0
    CompatStateChanged( StateChangedType::State );
1651
0
    Toggle();
1652
0
}
1653
1654
void PushButton::statusChanged(const css::frame::FeatureStateEvent& rEvent)
1655
0
{
1656
0
    Button::statusChanged(rEvent);
1657
0
    if (rEvent.State.has<bool>())
1658
0
        SetPressed(rEvent.State.get<bool>());
1659
0
}
1660
1661
void PushButton::SetPressed( bool bPressed )
1662
0
{
1663
0
    if ( mbPressed != bPressed )
1664
0
    {
1665
0
        mbPressed = bPressed;
1666
0
        CompatStateChanged( StateChangedType::Data );
1667
0
    }
1668
0
}
1669
1670
void PushButton::EndSelection()
1671
0
{
1672
0
    EndTracking( TrackingEventFlags::Cancel );
1673
0
    if ( !isDisposed() &&
1674
0
         GetButtonState() & DrawButtonFlags::Pressed )
1675
0
    {
1676
0
        GetButtonState() &= ~DrawButtonFlags::Pressed;
1677
0
        if ( !mbPressed )
1678
0
            Invalidate();
1679
0
    }
1680
0
}
1681
1682
Size PushButton::CalcMinimumSize() const
1683
0
{
1684
0
    Size aSize;
1685
1686
0
    if ( IsSymbol() )
1687
0
    {
1688
0
        if ( IsSmallSymbol ())
1689
0
            aSize = Size( 16, 12 );
1690
0
        else
1691
0
            aSize = Size( 26, 24 );
1692
0
    }
1693
0
    else if ( Button::HasImage() )
1694
0
        aSize = GetModeImage().GetSizePixel();
1695
0
    if( mnDDStyle == PushButtonDropdownStyle::MenuButton )
1696
0
    {
1697
0
        tools::Long nSymbolSize = GetTextHeight() / 2 + 1;
1698
0
        aSize.AdjustWidth(2*nSymbolSize );
1699
0
    }
1700
0
    if (!PushButton::GetText().isEmpty())
1701
0
    {
1702
0
        Size textSize = GetTextRect( tools::Rectangle( Point(), Size( 0x7fffffff, 0x7fffffff ) ),
1703
0
                                     PushButton::GetText(), ImplGetTextStyle( SystemTextColorFlags::NONE ) ).GetSize();
1704
1705
0
        tools::Long nTextHeight = textSize.Height() * 1.15;
1706
1707
0
        ImageAlign eImageAlign = GetImageAlign();
1708
        // tdf#142337 only considering the simple top/bottom/left/right possibilities
1709
0
        if (eImageAlign == ImageAlign::Top || eImageAlign == ImageAlign::Bottom)
1710
0
        {
1711
0
            aSize.AdjustHeight(nTextHeight);
1712
0
            aSize.setWidth(std::max(aSize.Width(), textSize.Width()));
1713
0
        }
1714
0
        else
1715
0
        {
1716
0
            aSize.AdjustWidth(textSize.Width());
1717
0
            aSize.setHeight(std::max(aSize.Height(), nTextHeight));
1718
0
        }
1719
0
    }
1720
1721
    // cf. ImplDrawPushButton ...
1722
0
    if( (GetStyle() & WB_SMALLSTYLE) == 0 )
1723
0
    {
1724
0
        aSize.AdjustWidth(24 );
1725
0
        aSize.AdjustHeight(12 );
1726
0
    }
1727
1728
0
    return CalcWindowSize( aSize );
1729
0
}
1730
1731
Size PushButton::GetOptimalSize() const
1732
0
{
1733
0
    return CalcMinimumSize();
1734
0
}
1735
1736
bool PushButton::set_property(const OUString &rKey, const OUString &rValue)
1737
0
{
1738
0
    if (rKey == "has-default")
1739
0
    {
1740
0
        WinBits nBits = GetStyle();
1741
0
        nBits &= ~WB_DEFBUTTON;
1742
0
        if (toBool(rValue))
1743
0
            nBits |= WB_DEFBUTTON;
1744
0
        SetStyle(nBits);
1745
0
    }
1746
0
    else
1747
0
        return Button::set_property(rKey, rValue);
1748
0
    return true;
1749
0
}
1750
1751
void PushButton::ShowFocus(const tools::Rectangle& rRect)
1752
0
{
1753
0
    if (IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Focus))
1754
0
    {
1755
0
        PushButtonValue aControlValue;
1756
0
        aControlValue.mbIsAction = isAction();
1757
0
        tools::Rectangle aInRect(Point(), GetOutputSizePixel());
1758
0
        GetOutDev()->DrawNativeControl(ControlType::Pushbutton, ControlPart::Focus, aInRect,
1759
0
                                       ControlState::FOCUSED, aControlValue, OUString());
1760
0
    }
1761
0
    Button::ShowFocus(rRect);
1762
0
}
1763
1764
void OKButton::ImplInit( vcl::Window* pParent, WinBits nStyle )
1765
0
{
1766
0
    set_id(u"ok"_ustr);
1767
0
    PushButton::ImplInit( pParent, nStyle );
1768
1769
0
    SetText( GetStandardText( StandardButtonType::OK ) );
1770
0
}
1771
1772
OKButton::OKButton( vcl::Window* pParent, WinBits nStyle ) :
1773
0
    PushButton( WindowType::OKBUTTON )
1774
0
{
1775
0
    ImplInit( pParent, nStyle );
1776
0
}
Unexecuted instantiation: OKButton::OKButton(vcl::Window*, long)
Unexecuted instantiation: OKButton::OKButton(vcl::Window*, long)
1777
1778
void OKButton::Click()
1779
0
{
1780
    // close parent if no link set
1781
0
    if ( !GetClickHdl() )
1782
0
    {
1783
0
        vcl::Window* pParent = getNonLayoutParent(this);
1784
0
        if ( pParent->IsSystemWindow() )
1785
0
        {
1786
0
            if ( pParent->IsDialog() )
1787
0
            {
1788
0
                VclPtr<Dialog> xParent( static_cast<Dialog*>(pParent) );
1789
0
                if ( xParent->IsInExecute() )
1790
0
                    xParent->EndDialog( RET_OK );
1791
                // prevent recursive calls
1792
0
                else if ( !xParent->IsInClose() )
1793
0
                {
1794
0
                    if ( pParent->GetStyle() & WB_CLOSEABLE )
1795
0
                        xParent->Close();
1796
0
                }
1797
0
            }
1798
0
            else
1799
0
            {
1800
0
                if ( pParent->GetStyle() & WB_CLOSEABLE )
1801
0
                    static_cast<SystemWindow*>(pParent)->Close();
1802
0
            }
1803
0
        }
1804
0
    }
1805
0
    else
1806
0
    {
1807
0
        PushButton::Click();
1808
0
    }
1809
0
}
1810
1811
void CancelButton::ImplInit( vcl::Window* pParent, WinBits nStyle )
1812
0
{
1813
0
    set_id(u"cancel"_ustr);
1814
0
    PushButton::ImplInit( pParent, nStyle );
1815
1816
0
    SetText( GetStandardText( StandardButtonType::Cancel ) );
1817
0
}
1818
1819
CancelButton::CancelButton( vcl::Window* pParent, WinBits nStyle ) :
1820
0
    PushButton( WindowType::CANCELBUTTON )
1821
0
{
1822
0
    ImplInit( pParent, nStyle );
1823
0
}
Unexecuted instantiation: CancelButton::CancelButton(vcl::Window*, long)
Unexecuted instantiation: CancelButton::CancelButton(vcl::Window*, long)
1824
1825
void CancelButton::Click()
1826
0
{
1827
    // close parent if link not set
1828
0
    if ( !GetClickHdl() )
1829
0
    {
1830
0
        vcl::Window* pParent = getNonLayoutParent(this);
1831
0
        if ( pParent->IsSystemWindow() )
1832
0
        {
1833
0
            if ( pParent->IsDialog() )
1834
0
            {
1835
0
                Dialog* pDialog = static_cast<Dialog*>(pParent);
1836
0
                if (pDialog->IsInExecute())
1837
0
                    pDialog->EndDialog();
1838
                // prevent recursive calls
1839
0
                else if (!pDialog->IsInClose())
1840
0
                {
1841
0
                    if ( pParent->GetStyle() & WB_CLOSEABLE )
1842
0
                        pDialog->Close();
1843
0
                }
1844
0
            }
1845
0
            else
1846
0
            {
1847
0
                if ( pParent->GetStyle() & WB_CLOSEABLE )
1848
0
                    static_cast<SystemWindow*>(pParent)->Close();
1849
0
            }
1850
0
        }
1851
0
    }
1852
0
    else
1853
0
    {
1854
0
        PushButton::Click();
1855
0
    }
1856
0
}
1857
1858
CloseButton::CloseButton( vcl::Window* pParent )
1859
0
    : CancelButton(pParent, 0)
1860
0
{
1861
0
    SetText( GetStandardText( StandardButtonType::Close ) );
1862
0
}
Unexecuted instantiation: CloseButton::CloseButton(vcl::Window*)
Unexecuted instantiation: CloseButton::CloseButton(vcl::Window*)
1863
1864
void HelpButton::ImplInit( vcl::Window* pParent, WinBits nStyle )
1865
0
{
1866
0
    set_id(u"help"_ustr);
1867
0
    PushButton::ImplInit( pParent, nStyle | WB_NOPOINTERFOCUS );
1868
1869
0
    SetText( GetStandardText( StandardButtonType::Help ) );
1870
0
}
1871
1872
HelpButton::HelpButton( vcl::Window* pParent, WinBits nStyle ) :
1873
0
    PushButton( WindowType::HELPBUTTON )
1874
0
{
1875
0
    ImplInit( pParent, nStyle );
1876
0
}
Unexecuted instantiation: HelpButton::HelpButton(vcl::Window*, long)
Unexecuted instantiation: HelpButton::HelpButton(vcl::Window*, long)
1877
1878
void HelpButton::Click()
1879
0
{
1880
    // trigger help if no link set
1881
0
    if ( !GetClickHdl() )
1882
0
    {
1883
0
        vcl::Window* pFocusWin = Application::GetFocusWindow();
1884
0
        if ( !pFocusWin || comphelper::LibreOfficeKit::isActive() )
1885
0
            pFocusWin = this;
1886
1887
0
        HelpEvent aEvt( pFocusWin->GetPointerPosPixel(), HelpEventMode::CONTEXT );
1888
0
        pFocusWin->RequestHelp( aEvt );
1889
0
    }
1890
0
    PushButton::Click();
1891
0
}
1892
1893
void HelpButton::StateChanged( StateChangedType nStateChange )
1894
0
{
1895
    // Hide when we have no help URL.
1896
0
    if (comphelper::LibreOfficeKit::isActive() &&
1897
0
        officecfg::Office::Common::Help::HelpRootURL::get().isEmpty())
1898
0
        Hide();
1899
0
    else
1900
0
        PushButton::StateChanged(nStateChange);
1901
0
}
1902
1903
void RadioButton::ImplInitRadioButtonData()
1904
0
{
1905
0
    mbChecked       = false;
1906
0
    mbRadioCheck    = true;
1907
0
    mbStateChanged  = false;
1908
0
}
1909
1910
void RadioButton::ImplInit( vcl::Window* pParent, WinBits nStyle )
1911
0
{
1912
0
    nStyle = ImplInitStyle(getPreviousSibling(pParent), nStyle);
1913
0
    Button::ImplInit( pParent, nStyle, nullptr );
1914
1915
0
    ImplInitSettings( true );
1916
0
}
1917
1918
WinBits RadioButton::ImplInitStyle( const vcl::Window* pPrevWindow, WinBits nStyle ) const
1919
0
{
1920
0
    if ( !(nStyle & WB_NOGROUP) &&
1921
0
         (!pPrevWindow || (pPrevWindow->GetType() != WindowType::RADIOBUTTON)) )
1922
0
        nStyle |= WB_GROUP;
1923
0
    if ( !(nStyle & WB_NOTABSTOP) )
1924
0
    {
1925
0
        if ( IsChecked() )
1926
0
            nStyle |= WB_TABSTOP;
1927
0
        else
1928
0
            nStyle &= ~WB_TABSTOP;
1929
0
    }
1930
1931
0
    return nStyle;
1932
0
}
1933
1934
const vcl::Font& RadioButton::GetCanonicalFont( const StyleSettings& _rStyle ) const
1935
0
{
1936
0
    return _rStyle.GetRadioCheckFont();
1937
0
}
1938
1939
const Color& RadioButton::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
1940
0
{
1941
0
    return _rStyle.GetRadioCheckTextColor();
1942
0
}
1943
1944
void RadioButton::ImplInitSettings( bool bBackground )
1945
0
{
1946
0
    Button::ImplInitSettings();
1947
1948
0
    if ( !bBackground )
1949
0
        return;
1950
1951
0
    vcl::Window* pParent = GetParent();
1952
0
    if ( !IsControlBackground() &&
1953
0
        (pParent->IsChildTransparentModeEnabled() || IsNativeControlSupported( ControlType::Radiobutton, ControlPart::Entire ) ) )
1954
0
    {
1955
0
        EnableChildTransparentMode();
1956
0
        SetParentClipMode( ParentClipMode::NoClip );
1957
0
        SetPaintTransparent( true );
1958
0
        SetBackground();
1959
0
        if( IsNativeControlSupported( ControlType::Radiobutton, ControlPart::Entire ) )
1960
0
            mpWindowImpl->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects;
1961
0
    }
1962
0
    else
1963
0
    {
1964
0
        EnableChildTransparentMode( false );
1965
0
        SetParentClipMode();
1966
0
        SetPaintTransparent( false );
1967
1968
0
        if ( IsControlBackground() )
1969
0
            SetBackground( GetControlBackground() );
1970
0
        else
1971
0
            SetBackground( pParent->GetBackground() );
1972
0
    }
1973
0
}
1974
1975
void RadioButton::ImplDrawRadioButtonState(vcl::RenderContext& rRenderContext)
1976
0
{
1977
0
    bool bNativeOK = false;
1978
1979
    // no native drawing for image radio buttons
1980
0
    if (!maImage && rRenderContext.IsNativeControlSupported(ControlType::Radiobutton, ControlPart::Entire))
1981
0
    {
1982
0
        ImplControlValue aControlValue( mbChecked ? ButtonValue::On : ButtonValue::Off );
1983
0
        tools::Rectangle aCtrlRect(maStateRect.TopLeft(), maStateRect.GetSize());
1984
0
        ControlState nState = ControlState::NONE;
1985
1986
0
        if (GetButtonState() & DrawButtonFlags::Pressed)
1987
0
            nState |= ControlState::PRESSED;
1988
0
        if (HasFocus())
1989
0
            nState |= ControlState::FOCUSED;
1990
0
        if (GetButtonState() & DrawButtonFlags::Default)
1991
0
            nState |= ControlState::DEFAULT;
1992
0
        if (IsEnabled())
1993
0
            nState |= ControlState::ENABLED;
1994
1995
0
        if (IsMouseOver() && maMouseRect.Contains(GetPointerPosPixel()))
1996
0
            nState |= ControlState::ROLLOVER;
1997
1998
0
        bNativeOK = rRenderContext.DrawNativeControl(ControlType::Radiobutton, ControlPart::Entire, aCtrlRect,
1999
0
                                                     nState, aControlValue, OUString());
2000
0
    }
2001
2002
0
    if (bNativeOK)
2003
0
        return;
2004
2005
0
    if (!maImage)
2006
0
    {
2007
0
        DrawButtonFlags nStyle = GetButtonState();
2008
0
        if (!IsEnabled())
2009
0
            nStyle |= DrawButtonFlags::Disabled;
2010
0
        if (mbChecked)
2011
0
            nStyle |= DrawButtonFlags::Checked;
2012
0
        Image aImage = GetRadioImage(rRenderContext.GetSettings(), nStyle);
2013
0
        if (IsZoom())
2014
0
            rRenderContext.DrawImage(maStateRect.TopLeft(), maStateRect.GetSize(), aImage);
2015
0
        else
2016
0
            rRenderContext.DrawImage(maStateRect.TopLeft(), aImage);
2017
0
    }
2018
0
    else
2019
0
    {
2020
0
        HideFocus();
2021
2022
0
        DecorationView aDecoView(&rRenderContext);
2023
0
        const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
2024
0
        tools::Rectangle aImageRect  = maStateRect;
2025
0
        Size aImageSize = maImage.GetSizePixel();
2026
0
        bool bEnabled = IsEnabled();
2027
2028
0
        aImageSize.setWidth( CalcZoom(aImageSize.Width()) );
2029
0
        aImageSize.setHeight( CalcZoom(aImageSize.Height()) );
2030
2031
0
        aImageRect.AdjustLeft( 1 );
2032
0
        aImageRect.AdjustTop( 1 );
2033
0
        aImageRect.AdjustRight( -1 );
2034
0
        aImageRect.AdjustBottom( -1 );
2035
2036
        // display border and selection status
2037
0
        aImageRect = aDecoView.DrawFrame(aImageRect, DrawFrameStyle::DoubleIn);
2038
0
        if ((GetButtonState() & DrawButtonFlags::Pressed) || !bEnabled)
2039
0
            rRenderContext.SetFillColor( rStyleSettings.GetFaceColor());
2040
0
        else
2041
0
            rRenderContext.SetFillColor(rStyleSettings.GetFieldColor());
2042
0
        rRenderContext.SetLineColor();
2043
0
        rRenderContext.DrawRect(aImageRect);
2044
2045
        // display image
2046
0
        DrawImageFlags nImageStyle = DrawImageFlags::NONE;
2047
0
        if (!bEnabled)
2048
0
            nImageStyle |= DrawImageFlags::Disable;
2049
2050
0
        Image* pImage = &maImage;
2051
2052
0
        Point aImagePos(aImageRect.TopLeft());
2053
0
        aImagePos.AdjustX((aImageRect.GetWidth() - aImageSize.Width()) / 2 );
2054
0
        aImagePos.AdjustY((aImageRect.GetHeight() - aImageSize.Height()) / 2 );
2055
0
        if (IsZoom())
2056
0
            rRenderContext.DrawImage(aImagePos, aImageSize, *pImage, nImageStyle);
2057
0
        else
2058
0
            rRenderContext.DrawImage(aImagePos, *pImage, nImageStyle);
2059
2060
0
        aImageRect.AdjustLeft( 1 );
2061
0
        aImageRect.AdjustTop( 1 );
2062
0
        aImageRect.AdjustRight( -1 );
2063
0
        aImageRect.AdjustBottom( -1 );
2064
2065
0
        ImplSetFocusRect(aImageRect);
2066
2067
0
        if (mbChecked)
2068
0
        {
2069
0
            rRenderContext.SetLineColor(rStyleSettings.GetHighlightColor());
2070
0
            rRenderContext.SetFillColor();
2071
0
            if ((aImageSize.Width() >= 20) || (aImageSize.Height() >= 20))
2072
0
            {
2073
0
                aImageRect.AdjustLeft( 1 );
2074
0
                aImageRect.AdjustTop( 1 );
2075
0
                aImageRect.AdjustRight( -1 );
2076
0
                aImageRect.AdjustBottom( -1 );
2077
0
            }
2078
0
            rRenderContext.DrawRect(aImageRect);
2079
0
            aImageRect.AdjustLeft( 1 );
2080
0
            aImageRect.AdjustTop( 1 );
2081
0
            aImageRect.AdjustRight( -1 );
2082
0
            aImageRect.AdjustBottom( -1 );
2083
0
            rRenderContext.DrawRect(aImageRect);
2084
0
        }
2085
2086
0
        if (HasFocus())
2087
0
            ShowFocus(ImplGetFocusRect());
2088
0
    }
2089
0
}
2090
2091
// for drawing RadioButton or CheckButton that has Text and/or Image
2092
void Button::ImplDrawRadioCheck(OutputDevice* pDev, WinBits nWinStyle, SystemTextColorFlags nSystemTextColorFlags,
2093
                                const Point& rPos, const Size& rSize,
2094
                                const Size& rImageSize, tools::Rectangle& rStateRect,
2095
                                tools::Rectangle& rMouseRect)
2096
0
{
2097
0
    DrawTextFlags nTextStyle = Button::ImplGetTextStyle( nWinStyle, nSystemTextColorFlags );
2098
2099
0
    const tools::Long nImageSep = GetDrawPixel( pDev, ImplGetImageToTextDistance() );
2100
0
    Size aSize( rSize );
2101
0
    Point aPos( rPos );
2102
0
    aPos.AdjustX(rImageSize.Width() + nImageSep );
2103
2104
    // tdf#141761 Old (convenience?) adjustment of width may lead to empty
2105
    // or negative(!) Size, that needs to be avoided. The coordinate context
2106
    // is pixel-oriented (all Paints of Controls are, historically), so
2107
    // the minimum width should be '1' Pixel.
2108
    // Hint: nImageSep is based on Zoom (using Window::CalcZoom) and
2109
    // MapModes (using Window::GetDrawPixel) - so potentially a wide range
2110
    // of unpredictable values is possible
2111
0
    const tools::Long nWidthAdjust(rImageSize.Width() + nImageSep);
2112
0
    aSize.setWidth(std::max(static_cast<tools::Long>(1), aSize.getWidth() - nWidthAdjust));
2113
2114
    // if the text rect height is smaller than the height of the image
2115
    // then for single lines the default should be centered text
2116
0
    if( (nWinStyle & (WB_TOP|WB_VCENTER|WB_BOTTOM)) == 0 &&
2117
0
        (rImageSize.Height() > rSize.Height() || ! (nWinStyle & WB_WORDBREAK) ) )
2118
0
    {
2119
0
        nTextStyle &= ~DrawTextFlags(DrawTextFlags::Top|DrawTextFlags::Bottom);
2120
0
        nTextStyle |= DrawTextFlags::VCenter;
2121
0
        aSize.setHeight( rImageSize.Height() );
2122
0
    }
2123
2124
0
    ImplDrawAlignedImage( pDev, aPos, aSize, 1, nTextStyle );
2125
2126
0
    rMouseRect = tools::Rectangle( aPos, aSize );
2127
0
    rMouseRect.SetLeft( rPos.X() );
2128
2129
0
    rStateRect.SetLeft( rPos.X() );
2130
0
    rStateRect.SetTop( rMouseRect.Top() );
2131
2132
0
    if ( aSize.Height() > rImageSize.Height() )
2133
0
        rStateRect.AdjustTop(( aSize.Height() - rImageSize.Height() ) / 2 );
2134
0
    else
2135
0
    {
2136
0
        rStateRect.AdjustTop( -(( rImageSize.Height() - aSize.Height() ) / 2) );
2137
0
        if( rStateRect.Top() < 0 )
2138
0
            rStateRect.SetTop( 0 );
2139
0
    }
2140
2141
0
    rStateRect.SetRight( rStateRect.Left()+rImageSize.Width()-1 );
2142
0
    rStateRect.SetBottom( rStateRect.Top()+rImageSize.Height()-1 );
2143
2144
0
    if ( rStateRect.Bottom() > rMouseRect.Bottom() )
2145
0
        rMouseRect.SetBottom( rStateRect.Bottom() );
2146
0
}
2147
2148
void RadioButton::ImplDraw( OutputDevice* pDev, SystemTextColorFlags nSystemTextColorFlags,
2149
                            const Point& rPos, const Size& rSize,
2150
                            const Size& rImageSize, tools::Rectangle& rStateRect,
2151
                            tools::Rectangle& rMouseRect )
2152
0
{
2153
0
    WinBits                 nWinStyle = GetStyle();
2154
0
    OUString                aText( GetText() );
2155
2156
0
    auto popIt = pDev->ScopedPush(vcl::PushFlags::CLIPREGION);
2157
0
    pDev->IntersectClipRegion( tools::Rectangle( rPos, rSize ) );
2158
2159
    // no image radio button
2160
0
    if ( !maImage )
2161
0
    {
2162
0
        if (!aText.isEmpty() || HasImage())
2163
0
        {
2164
0
            Button::ImplDrawRadioCheck(pDev, nWinStyle, nSystemTextColorFlags,
2165
0
                                       rPos, rSize, rImageSize,
2166
0
                                       rStateRect, rMouseRect);
2167
0
        }
2168
0
        else
2169
0
        {
2170
0
            rStateRect.SetLeft( rPos.X() );
2171
0
            if ( nWinStyle & WB_VCENTER )
2172
0
                rStateRect.SetTop( rPos.Y()+((rSize.Height()-rImageSize.Height())/2) );
2173
0
            else if ( nWinStyle & WB_BOTTOM )
2174
0
                rStateRect.SetTop( rPos.Y()+rSize.Height()-rImageSize.Height() ); //-1;
2175
0
            else
2176
0
                rStateRect.SetTop( rPos.Y() );
2177
0
            rStateRect.SetRight( rStateRect.Left()+rImageSize.Width()-1 );
2178
0
            rStateRect.SetBottom( rStateRect.Top()+rImageSize.Height()-1 );
2179
0
            rMouseRect          = rStateRect;
2180
2181
0
            ImplSetFocusRect( rStateRect );
2182
0
        }
2183
0
    }
2184
0
    else
2185
0
    {
2186
0
        bool        bTopImage   = (nWinStyle & WB_TOP) != 0;
2187
0
        Size        aImageSize  = maImage.GetSizePixel();
2188
0
        tools::Rectangle   aImageRect( rPos, rSize );
2189
0
        tools::Long        nTextHeight = pDev->GetTextHeight();
2190
0
        tools::Long        nTextWidth  = pDev->GetCtrlTextWidth( aText );
2191
2192
        // calculate position and sizes
2193
0
        if (!aText.isEmpty())
2194
0
        {
2195
0
            Size aTmpSize( (aImageSize.Width()+8), (aImageSize.Height()+8) );
2196
0
            if ( bTopImage )
2197
0
            {
2198
0
                aImageRect.SetLeft( (rSize.Width()-aTmpSize.Width())/2 );
2199
0
                aImageRect.SetTop( (rSize.Height()-(aTmpSize.Height()+nTextHeight+6))/2 );
2200
0
            }
2201
0
            else
2202
0
                aImageRect.SetTop( (rSize.Height()-aTmpSize.Height())/2 );
2203
2204
0
            aImageRect.SetRight( aImageRect.Left()+aTmpSize.Width() );
2205
0
            aImageRect.SetBottom( aImageRect.Top()+aTmpSize.Height() );
2206
2207
            // display text
2208
0
            Point aTxtPos = rPos;
2209
0
            if ( bTopImage )
2210
0
            {
2211
0
                aTxtPos.AdjustX((rSize.Width()-nTextWidth)/2 );
2212
0
                aTxtPos.AdjustY(aImageRect.Bottom()+6 );
2213
0
            }
2214
0
            else
2215
0
            {
2216
0
                aTxtPos.AdjustX(aImageRect.Right()+8 );
2217
0
                aTxtPos.AdjustY((rSize.Height()-nTextHeight)/2 );
2218
0
            }
2219
0
            pDev->DrawCtrlText( aTxtPos, aText, 0, aText.getLength() );
2220
0
        }
2221
2222
0
        rMouseRect = aImageRect;
2223
0
        rStateRect = aImageRect;
2224
0
    }
2225
0
}
2226
2227
void RadioButton::ImplDrawRadioButton(vcl::RenderContext& rRenderContext)
2228
0
{
2229
0
    HideFocus();
2230
2231
0
    Size aImageSize;
2232
0
    if (!maImage)
2233
0
        aImageSize = ImplGetRadioImageSize();
2234
0
    else
2235
0
        aImageSize  = maImage.GetSizePixel();
2236
2237
0
    aImageSize.setWidth( CalcZoom(aImageSize.Width()) );
2238
0
    aImageSize.setHeight( CalcZoom(aImageSize.Height()) );
2239
2240
    // Draw control text
2241
0
    ImplDraw(&rRenderContext, SystemTextColorFlags::NONE, Point(), GetOutputSizePixel(),
2242
0
             aImageSize, maStateRect, maMouseRect);
2243
2244
0
    if (!maImage && HasFocus())
2245
0
        ShowFocus(ImplGetFocusRect());
2246
2247
0
    ImplDrawRadioButtonState(rRenderContext);
2248
0
}
2249
2250
void RadioButton::group(RadioButton &rOther)
2251
0
{
2252
0
    if (&rOther == this)
2253
0
        return;
2254
2255
0
    if (!m_xGroup)
2256
0
    {
2257
0
        m_xGroup = std::make_shared<std::vector<VclPtr<RadioButton> >>();
2258
0
        m_xGroup->push_back(this);
2259
0
    }
2260
2261
0
    auto aFind = std::find(m_xGroup->begin(), m_xGroup->end(), VclPtr<RadioButton>(&rOther));
2262
0
    if (aFind == m_xGroup->end())
2263
0
    {
2264
0
        m_xGroup->push_back(&rOther);
2265
2266
0
        if (rOther.m_xGroup)
2267
0
        {
2268
0
            std::vector< VclPtr<RadioButton> > aOthers(rOther.GetRadioButtonGroup(false));
2269
            //make all members of the group share the same button group
2270
0
            for (auto const& elem : aOthers)
2271
0
            {
2272
0
                aFind = std::find(m_xGroup->begin(), m_xGroup->end(), elem);
2273
0
                if (aFind == m_xGroup->end())
2274
0
                    m_xGroup->push_back(elem);
2275
0
            }
2276
0
        }
2277
2278
        //make all members of the group share the same button group
2279
0
        for (VclPtr<RadioButton> const & pButton : *m_xGroup)
2280
0
        {
2281
0
            pButton->m_xGroup = m_xGroup;
2282
0
        }
2283
0
    }
2284
2285
    //if this one is checked, uncheck all the others
2286
0
    if (mbChecked)
2287
0
        ImplUncheckAllOther();
2288
0
}
2289
2290
std::vector< VclPtr<RadioButton> > RadioButton::GetRadioButtonGroup(bool bIncludeThis) const
2291
0
{
2292
0
    if (m_xGroup)
2293
0
    {
2294
0
        if (bIncludeThis)
2295
0
            return *m_xGroup;
2296
0
        std::vector< VclPtr<RadioButton> > aGroup;
2297
0
        for (VclPtr<RadioButton> const & pRadioButton : *m_xGroup)
2298
0
        {
2299
0
            if (pRadioButton == this)
2300
0
                continue;
2301
0
            aGroup.push_back(pRadioButton);
2302
0
        }
2303
0
        return aGroup;
2304
0
    }
2305
2306
0
    std::vector<VclPtr<RadioButton>> aGroup;
2307
0
    if (mbUsesExplicitGroup)
2308
0
        return aGroup;
2309
2310
    //old-school
2311
2312
    // go back to first in group;
2313
0
    vcl::Window* pFirst = const_cast<RadioButton*>(this);
2314
0
    while( ( pFirst->GetStyle() & WB_GROUP ) == 0 )
2315
0
    {
2316
0
        vcl::Window* pWindow = pFirst->GetWindow( GetWindowType::Prev );
2317
0
        if( pWindow )
2318
0
            pFirst = pWindow;
2319
0
        else
2320
0
            break;
2321
0
    }
2322
    // insert radiobuttons up to next group
2323
0
    do
2324
0
    {
2325
0
        if( pFirst->GetType() == WindowType::RADIOBUTTON )
2326
0
        {
2327
0
            if( pFirst != this || bIncludeThis )
2328
0
                aGroup.emplace_back(static_cast<RadioButton*>(pFirst) );
2329
0
        }
2330
0
        pFirst = pFirst->GetWindow( GetWindowType::Next );
2331
0
    } while( pFirst && ( ( pFirst->GetStyle() & WB_GROUP ) == 0 ) );
2332
2333
0
    return aGroup;
2334
0
}
2335
2336
void RadioButton::ImplUncheckAllOther()
2337
0
{
2338
0
    mpWindowImpl->mnStyle |= WB_TABSTOP;
2339
2340
0
    std::vector<VclPtr<RadioButton> > aGroup(GetRadioButtonGroup(false));
2341
    // iterate over radio button group and checked buttons
2342
0
    for (VclPtr<RadioButton>& pWindow : aGroup)
2343
0
    {
2344
0
        if ( pWindow->IsChecked() )
2345
0
        {
2346
0
            pWindow->SetState( false );
2347
0
            if ( pWindow->isDisposed() )
2348
0
                return;
2349
0
        }
2350
2351
        // not inside if clause to always remove wrongly set WB_TABSTOPS
2352
0
        pWindow->mpWindowImpl->mnStyle &= ~WB_TABSTOP;
2353
0
    }
2354
0
}
2355
2356
void RadioButton::ImplCallClick( bool bGrabFocus, GetFocusFlags nFocusFlags )
2357
0
{
2358
0
    mbStateChanged = !mbChecked;
2359
0
    mbChecked = true;
2360
0
    mpWindowImpl->mnStyle |= WB_TABSTOP;
2361
0
    Invalidate();
2362
0
    VclPtr<vcl::Window> xWindow = this;
2363
0
    if ( mbRadioCheck )
2364
0
        ImplUncheckAllOther();
2365
0
    if ( xWindow->isDisposed() )
2366
0
        return;
2367
0
    if ( bGrabFocus )
2368
0
        ImplGrabFocus( nFocusFlags );
2369
0
    if ( xWindow->isDisposed() )
2370
0
        return;
2371
0
    if ( mbStateChanged )
2372
0
        Toggle();
2373
0
    if ( xWindow->isDisposed() )
2374
0
        return;
2375
0
    Click();
2376
0
    if ( xWindow->isDisposed() )
2377
0
        return;
2378
0
    mbStateChanged = false;
2379
0
}
2380
2381
RadioButton::RadioButton(vcl::Window* pParent, bool bUsesExplicitGroup, WinBits nStyle)
2382
0
    : Button(WindowType::RADIOBUTTON)
2383
0
    , mbUsesExplicitGroup(bUsesExplicitGroup)
2384
0
{
2385
0
    ImplInitRadioButtonData();
2386
0
    ImplInit( pParent, nStyle );
2387
0
}
Unexecuted instantiation: RadioButton::RadioButton(vcl::Window*, bool, long)
Unexecuted instantiation: RadioButton::RadioButton(vcl::Window*, bool, long)
2388
2389
RadioButton::~RadioButton()
2390
0
{
2391
0
    disposeOnce();
2392
0
}
2393
2394
void RadioButton::dispose()
2395
0
{
2396
0
    if (m_xGroup)
2397
0
    {
2398
0
        std::erase(*m_xGroup, VclPtr<RadioButton>(this));
2399
0
        m_xGroup.reset();
2400
0
    }
2401
0
    Button::dispose();
2402
0
}
2403
2404
rtl::Reference<comphelper::OAccessible> RadioButton::CreateAccessible()
2405
0
{
2406
0
    return new VCLXAccessibleRadioButton(this);
2407
0
}
2408
2409
void RadioButton::MouseButtonDown( const MouseEvent& rMEvt )
2410
0
{
2411
0
    if ( rMEvt.IsLeft() && maMouseRect.Contains( rMEvt.GetPosPixel() ) )
2412
0
    {
2413
0
        GetButtonState() |= DrawButtonFlags::Pressed;
2414
0
        Invalidate();
2415
0
        StartTracking();
2416
0
        return;
2417
0
    }
2418
2419
0
    Button::MouseButtonDown( rMEvt );
2420
0
}
2421
2422
void RadioButton::Tracking( const TrackingEvent& rTEvt )
2423
0
{
2424
0
    if ( rTEvt.IsTrackingEnded() )
2425
0
    {
2426
0
        if ( GetButtonState() & DrawButtonFlags::Pressed )
2427
0
        {
2428
0
            if ( !(GetStyle() & WB_NOPOINTERFOCUS) && !rTEvt.IsTrackingCanceled() )
2429
0
                GrabFocus();
2430
2431
0
            GetButtonState() &= ~DrawButtonFlags::Pressed;
2432
2433
            // do not call click handler if aborted
2434
0
            if ( !rTEvt.IsTrackingCanceled() )
2435
0
                ImplCallClick();
2436
0
            else
2437
0
            {
2438
0
                Invalidate();
2439
0
            }
2440
0
        }
2441
0
    }
2442
0
    else
2443
0
    {
2444
0
        if ( maMouseRect.Contains( rTEvt.GetMouseEvent().GetPosPixel() ) )
2445
0
        {
2446
0
            if ( !(GetButtonState() & DrawButtonFlags::Pressed) )
2447
0
            {
2448
0
                GetButtonState() |= DrawButtonFlags::Pressed;
2449
0
                Invalidate();
2450
0
            }
2451
0
        }
2452
0
        else
2453
0
        {
2454
0
            if ( GetButtonState() & DrawButtonFlags::Pressed )
2455
0
            {
2456
0
                GetButtonState() &= ~DrawButtonFlags::Pressed;
2457
0
                Invalidate();
2458
0
            }
2459
0
        }
2460
0
    }
2461
0
}
2462
2463
void RadioButton::KeyInput( const KeyEvent& rKEvt )
2464
0
{
2465
0
    vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
2466
2467
0
    if ( !aKeyCode.GetModifier() && (aKeyCode.GetCode() == KEY_SPACE) )
2468
0
    {
2469
0
        if ( !(GetButtonState() & DrawButtonFlags::Pressed) )
2470
0
        {
2471
0
            GetButtonState() |= DrawButtonFlags::Pressed;
2472
0
            Invalidate();
2473
0
        }
2474
0
    }
2475
0
    else if ( (GetButtonState() & DrawButtonFlags::Pressed) && (aKeyCode.GetCode() == KEY_ESCAPE) )
2476
0
    {
2477
0
        GetButtonState() &= ~DrawButtonFlags::Pressed;
2478
0
        Invalidate();
2479
0
    }
2480
0
    else
2481
0
        Button::KeyInput( rKEvt );
2482
0
}
2483
2484
void RadioButton::KeyUp( const KeyEvent& rKEvt )
2485
0
{
2486
0
    vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
2487
2488
0
    if ( (GetButtonState() & DrawButtonFlags::Pressed) && (aKeyCode.GetCode() == KEY_SPACE) )
2489
0
    {
2490
0
        GetButtonState() &= ~DrawButtonFlags::Pressed;
2491
0
        ImplCallClick();
2492
0
    }
2493
0
    else
2494
0
        Button::KeyUp( rKEvt );
2495
0
}
2496
2497
void RadioButton::FillLayoutData() const
2498
0
{
2499
0
    mxLayoutData.emplace();
2500
0
    const_cast<RadioButton*>(this)->Invalidate();
2501
0
}
2502
2503
void RadioButton::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& )
2504
0
{
2505
0
    ImplDrawRadioButton(rRenderContext);
2506
0
}
2507
2508
void RadioButton::Draw( OutputDevice* pDev, const Point& rPos,
2509
                        SystemTextColorFlags nFlags )
2510
0
{
2511
0
    if ( !maImage )
2512
0
    {
2513
0
        MapMode     aResMapMode( MapUnit::Map100thMM );
2514
0
        Point       aPos  = pDev->LogicToPixel( rPos );
2515
0
        Size        aSize = GetSizePixel();
2516
0
        Size        aImageSize = pDev->LogicToPixel( Size( 300, 300 ), aResMapMode );
2517
0
        Size        aBrd1Size = pDev->LogicToPixel( Size( 20, 20 ), aResMapMode );
2518
0
        Size        aBrd2Size = pDev->LogicToPixel( Size( 60, 60 ), aResMapMode );
2519
0
        vcl::Font   aFont = GetDrawPixelFont( pDev );
2520
0
        tools::Rectangle   aStateRect;
2521
0
        tools::Rectangle   aMouseRect;
2522
2523
0
        aImageSize.setWidth( CalcZoom( aImageSize.Width() ) );
2524
0
        aImageSize.setHeight( CalcZoom( aImageSize.Height() ) );
2525
0
        aBrd1Size.setWidth( CalcZoom( aBrd1Size.Width() ) );
2526
0
        aBrd1Size.setHeight( CalcZoom( aBrd1Size.Height() ) );
2527
0
        aBrd2Size.setWidth( CalcZoom( aBrd2Size.Width() ) );
2528
0
        aBrd2Size.setHeight( CalcZoom( aBrd2Size.Height() ) );
2529
2530
0
        if ( !aBrd1Size.Width() )
2531
0
            aBrd1Size.setWidth( 1 );
2532
0
        if ( !aBrd1Size.Height() )
2533
0
            aBrd1Size.setHeight( 1 );
2534
0
        if ( !aBrd2Size.Width() )
2535
0
            aBrd2Size.setWidth( 1 );
2536
0
        if ( !aBrd2Size.Height() )
2537
0
            aBrd2Size.setHeight( 1 );
2538
2539
0
        auto popIt = pDev->ScopedPush();
2540
0
        pDev->SetMapMode();
2541
0
        pDev->SetFont( aFont );
2542
0
        if ( nFlags & SystemTextColorFlags::Mono )
2543
0
            pDev->SetTextColor( COL_BLACK );
2544
0
        else
2545
0
            pDev->SetTextColor( GetTextColor() );
2546
0
        pDev->SetTextFillColor();
2547
2548
0
        ImplDraw( pDev, nFlags, aPos, aSize,
2549
0
                  aImageSize, aStateRect, aMouseRect );
2550
2551
0
        Point   aCenterPos = aStateRect.Center();
2552
0
        tools::Long    nRadX = aImageSize.Width()/2;
2553
0
        tools::Long    nRadY = aImageSize.Height()/2;
2554
2555
0
        pDev->SetLineColor();
2556
0
        pDev->SetFillColor( COL_BLACK );
2557
0
        pDev->DrawPolygon( tools::Polygon( aCenterPos, nRadX, nRadY ) );
2558
0
        nRadX -= aBrd1Size.Width();
2559
0
        nRadY -= aBrd1Size.Height();
2560
0
        pDev->SetFillColor( COL_WHITE );
2561
0
        pDev->DrawPolygon( tools::Polygon( aCenterPos, nRadX, nRadY ) );
2562
0
        if ( mbChecked )
2563
0
        {
2564
0
            nRadX -= aBrd1Size.Width();
2565
0
            nRadY -= aBrd1Size.Height();
2566
0
            if ( !nRadX )
2567
0
                nRadX = 1;
2568
0
            if ( !nRadY )
2569
0
                nRadY = 1;
2570
0
            pDev->SetFillColor( COL_BLACK );
2571
0
            pDev->DrawPolygon( tools::Polygon( aCenterPos, nRadX, nRadY ) );
2572
0
        }
2573
0
    }
2574
0
    else
2575
0
    {
2576
0
        OSL_FAIL( "RadioButton::Draw() - not implemented for RadioButton with Image" );
2577
0
    }
2578
0
}
2579
2580
void RadioButton::Resize()
2581
0
{
2582
0
    Control::Resize();
2583
0
    Invalidate();
2584
0
}
2585
2586
void RadioButton::GetFocus()
2587
0
{
2588
0
    ShowFocus( ImplGetFocusRect() );
2589
0
    SetInputContext( InputContext( GetFont() ) );
2590
0
    Button::GetFocus();
2591
0
}
2592
2593
void RadioButton::LoseFocus()
2594
0
{
2595
0
    if ( GetButtonState() & DrawButtonFlags::Pressed )
2596
0
    {
2597
0
        GetButtonState() &= ~DrawButtonFlags::Pressed;
2598
0
        Invalidate();
2599
0
    }
2600
2601
0
    HideFocus();
2602
0
    Button::LoseFocus();
2603
0
}
2604
2605
void RadioButton::StateChanged( StateChangedType nType )
2606
0
{
2607
0
    Button::StateChanged( nType );
2608
2609
0
    if ( nType == StateChangedType::State )
2610
0
    {
2611
0
        if ( IsReallyVisible() && IsUpdateMode() )
2612
0
            Invalidate( maStateRect );
2613
0
    }
2614
0
    else if ( (nType == StateChangedType::Enable) ||
2615
0
              (nType == StateChangedType::Text) ||
2616
0
              (nType == StateChangedType::Data) ||
2617
0
              (nType == StateChangedType::UpdateMode) )
2618
0
    {
2619
0
        if ( IsUpdateMode() )
2620
0
            Invalidate();
2621
0
    }
2622
0
    else if ( nType == StateChangedType::Style )
2623
0
    {
2624
0
        SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev ), GetStyle() ) );
2625
2626
0
        if ( (GetPrevStyle() & RADIOBUTTON_VIEW_STYLE) !=
2627
0
             (GetStyle() & RADIOBUTTON_VIEW_STYLE) )
2628
0
        {
2629
0
            if ( IsUpdateMode() )
2630
0
                Invalidate();
2631
0
        }
2632
0
    }
2633
0
    else if ( (nType == StateChangedType::Zoom) ||
2634
0
              (nType == StateChangedType::ControlFont) )
2635
0
    {
2636
0
        ImplInitSettings( false );
2637
0
        Invalidate();
2638
0
    }
2639
0
    else if ( nType == StateChangedType::ControlForeground )
2640
0
    {
2641
0
        ImplInitSettings( false );
2642
0
        Invalidate();
2643
0
    }
2644
0
    else if ( nType == StateChangedType::ControlBackground )
2645
0
    {
2646
0
        ImplInitSettings( true );
2647
0
        Invalidate();
2648
0
    }
2649
0
}
2650
2651
void RadioButton::DataChanged( const DataChangedEvent& rDCEvt )
2652
0
{
2653
0
    Button::DataChanged( rDCEvt );
2654
2655
0
    if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
2656
0
         (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
2657
0
         ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
2658
0
          (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
2659
0
    {
2660
0
        ImplInitSettings( true );
2661
0
        Invalidate();
2662
0
    }
2663
0
}
2664
2665
bool RadioButton::PreNotify( NotifyEvent& rNEvt )
2666
0
{
2667
0
    if( rNEvt.GetType() == NotifyEventType::MOUSEMOVE )
2668
0
    {
2669
0
        const MouseEvent* pMouseEvt = rNEvt.GetMouseEvent();
2670
0
        if( pMouseEvt && !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
2671
0
        {
2672
            // trigger redraw if mouse over state has changed
2673
0
            if( IsNativeControlSupported(ControlType::Radiobutton, ControlPart::Entire) )
2674
0
            {
2675
0
                if (maMouseRect.Contains(GetPointerPosPixel()) != maMouseRect.Contains(GetLastPointerPosPixel()) ||
2676
0
                    pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow())
2677
0
                {
2678
0
                    Invalidate( maStateRect );
2679
0
                }
2680
0
            }
2681
0
        }
2682
0
    }
2683
2684
0
    return Button::PreNotify(rNEvt);
2685
0
}
2686
2687
void RadioButton::Toggle()
2688
0
{
2689
0
    ImplCallEventListenersAndHandler( VclEventId::RadiobuttonToggle, [this] () { maToggleHdl.Call(*this); } );
2690
0
}
2691
2692
void RadioButton::SetModeRadioImage( const Image& rImage )
2693
0
{
2694
0
    if ( rImage != maImage )
2695
0
    {
2696
0
        maImage = rImage;
2697
0
        CompatStateChanged( StateChangedType::Data );
2698
0
        queue_resize();
2699
0
    }
2700
0
}
2701
2702
2703
void RadioButton::SetState( bool bCheck )
2704
0
{
2705
    // carry the TabStop flag along correctly
2706
0
    if ( bCheck )
2707
0
        mpWindowImpl->mnStyle |= WB_TABSTOP;
2708
0
    else
2709
0
        mpWindowImpl->mnStyle &= ~WB_TABSTOP;
2710
2711
0
    if ( mbChecked != bCheck )
2712
0
    {
2713
0
        mbChecked = bCheck;
2714
0
        CompatStateChanged( StateChangedType::State );
2715
0
        Toggle();
2716
0
    }
2717
0
}
2718
2719
bool RadioButton::set_property(const OUString &rKey, const OUString &rValue)
2720
0
{
2721
0
    if (rKey == "active")
2722
0
        SetState(toBool(rValue));
2723
0
    else if (rKey == "image-position")
2724
0
    {
2725
0
        WinBits nBits = GetStyle();
2726
0
        if (rValue == "left")
2727
0
        {
2728
0
            nBits &= ~(WB_CENTER | WB_RIGHT);
2729
0
            nBits |= WB_LEFT;
2730
0
        }
2731
0
        else if (rValue == "right")
2732
0
        {
2733
0
            nBits &= ~(WB_CENTER | WB_LEFT);
2734
0
            nBits |= WB_RIGHT;
2735
0
        }
2736
0
        else if (rValue == "top")
2737
0
        {
2738
0
            nBits &= ~(WB_VCENTER | WB_BOTTOM);
2739
0
            nBits |= WB_TOP;
2740
0
        }
2741
0
        else if (rValue == "bottom")
2742
0
        {
2743
0
            nBits &= ~(WB_VCENTER | WB_TOP);
2744
0
            nBits |= WB_BOTTOM;
2745
0
        }
2746
        //It's rather mad to have to set these bits when there is the other
2747
        //image align. Looks like e.g. the radiobuttons etc weren't converted
2748
        //over to image align fully.
2749
0
        SetStyle(nBits);
2750
        //Deliberate to set the sane ImageAlign property
2751
0
        return Button::set_property(rKey, rValue);
2752
0
    }
2753
0
    else
2754
0
        return Button::set_property(rKey, rValue);
2755
0
    return true;
2756
0
}
2757
2758
void RadioButton::Check( bool bCheck )
2759
0
{
2760
    // TabStop-Flag richtig mitfuehren
2761
0
    if ( bCheck )
2762
0
        mpWindowImpl->mnStyle |= WB_TABSTOP;
2763
0
    else
2764
0
        mpWindowImpl->mnStyle &= ~WB_TABSTOP;
2765
2766
0
    if ( mbChecked == bCheck )
2767
0
        return;
2768
2769
0
    mbChecked = bCheck;
2770
0
    VclPtr<vcl::Window> xWindow = this;
2771
0
    CompatStateChanged( StateChangedType::State );
2772
0
    if ( xWindow->isDisposed() )
2773
0
        return;
2774
0
    if ( bCheck && mbRadioCheck )
2775
0
        ImplUncheckAllOther();
2776
0
    if ( xWindow->isDisposed() )
2777
0
        return;
2778
0
    Toggle();
2779
0
}
2780
2781
tools::Long Button::ImplGetImageToTextDistance() const
2782
0
{
2783
    // 4 pixels, but take zoom into account, so the text doesn't "jump" relative to surrounding elements,
2784
    // which might have been aligned with the text of the check box
2785
0
    return CalcZoom( 4 );
2786
0
}
2787
2788
Size RadioButton::ImplGetRadioImageSize() const
2789
0
{
2790
0
    Size aSize;
2791
0
    bool bDefaultSize = true;
2792
0
    if( IsNativeControlSupported( ControlType::Radiobutton, ControlPart::Entire ) )
2793
0
    {
2794
0
        ImplControlValue aControlValue;
2795
0
        tools::Rectangle aCtrlRegion( Point( 0, 0 ), GetSizePixel() );
2796
0
        tools::Rectangle aBoundingRgn, aContentRgn;
2797
2798
        // get native size of a radio button
2799
0
        if( GetNativeControlRegion( ControlType::Radiobutton, ControlPart::Entire, aCtrlRegion,
2800
0
                                    ControlState::DEFAULT|ControlState::ENABLED,
2801
0
                                    aControlValue,
2802
0
                                    aBoundingRgn, aContentRgn ) )
2803
0
        {
2804
0
            aSize = aContentRgn.GetSize();
2805
0
            bDefaultSize = false;
2806
0
        }
2807
0
    }
2808
0
    if( bDefaultSize )
2809
0
        aSize = GetRadioImage( GetSettings(), DrawButtonFlags::NONE ).GetSizePixel();
2810
0
    return aSize;
2811
0
}
2812
2813
static void LoadThemedImageList(const StyleSettings &rStyleSettings,
2814
                                std::vector<Image>& rList, const std::vector<OUString> &rResources)
2815
0
{
2816
0
    Color aColorAry1[6];
2817
0
    Color aColorAry2[6];
2818
0
    aColorAry1[0] = Color( 0xC0, 0xC0, 0xC0 );
2819
0
    aColorAry1[1] = Color( 0xFF, 0xFF, 0x00 );
2820
0
    aColorAry1[2] = Color( 0xFF, 0xFF, 0xFF );
2821
0
    aColorAry1[3] = Color( 0x80, 0x80, 0x80 );
2822
0
    aColorAry1[4] = Color( 0x00, 0x00, 0x00 );
2823
0
    aColorAry1[5] = Color( 0x00, 0xFF, 0x00 );
2824
0
    aColorAry2[0] = rStyleSettings.GetFaceColor();
2825
0
    aColorAry2[1] = rStyleSettings.GetWindowColor();
2826
0
    aColorAry2[2] = rStyleSettings.GetLightColor();
2827
0
    aColorAry2[3] = rStyleSettings.GetShadowColor();
2828
0
    aColorAry2[4] = rStyleSettings.GetDarkShadowColor();
2829
0
    aColorAry2[5] = rStyleSettings.GetWindowTextColor();
2830
2831
0
    static_assert( sizeof(aColorAry1) == sizeof(aColorAry2), "aColorAry1 must match aColorAry2" );
2832
2833
0
    for (const auto &a : rResources)
2834
0
    {
2835
0
        Bitmap aBmp(a);
2836
0
        aBmp.Replace(aColorAry1, aColorAry2, SAL_N_ELEMENTS(aColorAry1), nullptr);
2837
0
        rList.emplace_back(aBmp);
2838
0
    }
2839
0
}
2840
2841
Image RadioButton::GetRadioImage( const AllSettings& rSettings, DrawButtonFlags nFlags )
2842
0
{
2843
0
    ImplSVData*             pSVData = ImplGetSVData();
2844
0
    const StyleSettings&    rStyleSettings = rSettings.GetStyleSettings();
2845
0
    sal_uInt16              nStyle = 0;
2846
2847
0
    if ( rStyleSettings.GetOptions() & StyleSettingsOptions::Mono )
2848
0
        nStyle = STYLE_RADIOBUTTON_MONO;
2849
2850
0
    if ( pSVData->maCtrlData.maRadioImgList.empty() ||
2851
0
         (pSVData->maCtrlData.mnRadioStyle != nStyle) ||
2852
0
         (pSVData->maCtrlData.mnLastRadioFColor != rStyleSettings.GetFaceColor()) ||
2853
0
         (pSVData->maCtrlData.mnLastRadioWColor != rStyleSettings.GetWindowColor()) ||
2854
0
         (pSVData->maCtrlData.mnLastRadioLColor != rStyleSettings.GetLightColor()) )
2855
0
    {
2856
0
        pSVData->maCtrlData.maRadioImgList.clear();
2857
2858
0
        pSVData->maCtrlData.mnLastRadioFColor = rStyleSettings.GetFaceColor();
2859
0
        pSVData->maCtrlData.mnLastRadioWColor = rStyleSettings.GetWindowColor();
2860
0
        pSVData->maCtrlData.mnLastRadioLColor = rStyleSettings.GetLightColor();
2861
2862
0
        std::vector<OUString> aResources;
2863
0
        if (nStyle)
2864
0
        {
2865
0
            aResources.emplace_back(SV_RESID_BITMAP_RADIOMONO1);
2866
0
            aResources.emplace_back(SV_RESID_BITMAP_RADIOMONO2);
2867
0
            aResources.emplace_back(SV_RESID_BITMAP_RADIOMONO3);
2868
0
            aResources.emplace_back(SV_RESID_BITMAP_RADIOMONO4);
2869
0
            aResources.emplace_back(SV_RESID_BITMAP_RADIOMONO5);
2870
0
            aResources.emplace_back(SV_RESID_BITMAP_RADIOMONO6);
2871
0
        }
2872
0
        else
2873
0
        {
2874
0
            aResources.emplace_back(SV_RESID_BITMAP_RADIO1);
2875
0
            aResources.emplace_back(SV_RESID_BITMAP_RADIO2);
2876
0
            aResources.emplace_back(SV_RESID_BITMAP_RADIO3);
2877
0
            aResources.emplace_back(SV_RESID_BITMAP_RADIO4);
2878
0
            aResources.emplace_back(SV_RESID_BITMAP_RADIO5);
2879
0
            aResources.emplace_back(SV_RESID_BITMAP_RADIO6);
2880
0
        }
2881
0
        LoadThemedImageList( rStyleSettings, pSVData->maCtrlData.maRadioImgList, aResources);
2882
0
        pSVData->maCtrlData.mnRadioStyle = nStyle;
2883
0
    }
2884
2885
0
    sal_uInt16 nIndex;
2886
0
    if ( nFlags & DrawButtonFlags::Disabled )
2887
0
    {
2888
0
        if ( nFlags & DrawButtonFlags::Checked )
2889
0
            nIndex = 5;
2890
0
        else
2891
0
            nIndex = 4;
2892
0
    }
2893
0
    else if ( nFlags & DrawButtonFlags::Pressed )
2894
0
    {
2895
0
        if ( nFlags & DrawButtonFlags::Checked )
2896
0
            nIndex = 3;
2897
0
        else
2898
0
            nIndex = 2;
2899
0
    }
2900
0
    else
2901
0
    {
2902
0
        if ( nFlags & DrawButtonFlags::Checked )
2903
0
            nIndex = 1;
2904
0
        else
2905
0
            nIndex = 0;
2906
0
    }
2907
0
    return pSVData->maCtrlData.maRadioImgList[nIndex];
2908
0
}
2909
2910
void RadioButton::ImplAdjustNWFSizes()
2911
0
{
2912
0
    auto popIt = GetOutDev()->ScopedPush(vcl::PushFlags::MAPMODE);
2913
0
    SetMapMode(MapMode(MapUnit::MapPixel));
2914
2915
0
    ImplControlValue aControlValue;
2916
0
    Size aCurSize( GetSizePixel() );
2917
0
    tools::Rectangle aCtrlRegion( Point( 0, 0 ), aCurSize );
2918
0
    tools::Rectangle aBoundingRgn, aContentRgn;
2919
2920
    // get native size of a radiobutton
2921
0
    if( GetNativeControlRegion( ControlType::Radiobutton, ControlPart::Entire, aCtrlRegion,
2922
0
                                ControlState::DEFAULT|ControlState::ENABLED, aControlValue,
2923
0
                                aBoundingRgn, aContentRgn ) )
2924
0
    {
2925
0
        Size aSize = aContentRgn.GetSize();
2926
2927
0
        if( aSize.Height() > aCurSize.Height() )
2928
0
        {
2929
0
            aCurSize.setHeight( aSize.Height() );
2930
0
            SetSizePixel( aCurSize );
2931
0
        }
2932
0
    }
2933
0
}
2934
2935
Size RadioButton::CalcMinimumSize(tools::Long nMaxWidth) const
2936
0
{
2937
0
    Size aSize;
2938
0
    if ( !maImage )
2939
0
        aSize = ImplGetRadioImageSize();
2940
0
    else
2941
0
    {
2942
0
        aSize = maImage.GetSizePixel();
2943
0
        aSize.AdjustWidth(8);
2944
0
        aSize.AdjustHeight(8);
2945
0
    }
2946
2947
0
    if (Button::HasImage())
2948
0
    {
2949
0
        Size aImgSize = GetModeImage().GetSizePixel();
2950
0
        aSize = Size(std::max(aImgSize.Width(), aSize.Width()),
2951
0
                     std::max(aImgSize.Height(), aSize.Height()));
2952
0
    }
2953
2954
0
    OUString aText = GetText();
2955
0
    if (!aText.isEmpty())
2956
0
    {
2957
0
        bool bTopImage = (GetStyle() & WB_TOP) != 0;
2958
2959
0
        Size aTextSize = GetTextRect( tools::Rectangle( Point(), Size( nMaxWidth > 0 ? nMaxWidth : 0x7fffffff, 0x7fffffff ) ),
2960
0
                                      aText, FixedText::ImplGetTextStyle( GetStyle() ) ).GetSize();
2961
2962
0
        aSize.AdjustWidth(2 );   // for focus rect
2963
2964
0
        if (!bTopImage)
2965
0
        {
2966
0
            aSize.AdjustWidth(ImplGetImageToTextDistance() );
2967
0
            aSize.AdjustWidth(aTextSize.Width() );
2968
0
            if ( aSize.Height() < aTextSize.Height() )
2969
0
                aSize.setHeight( aTextSize.Height() );
2970
0
        }
2971
0
        else
2972
0
        {
2973
0
            aSize.AdjustHeight(6 );
2974
0
            aSize.AdjustHeight(GetTextHeight() );
2975
0
            if ( aSize.Width() < aTextSize.Width() )
2976
0
                aSize.setWidth( aTextSize.Width() );
2977
0
        }
2978
0
    }
2979
2980
0
    return CalcWindowSize( aSize );
2981
0
}
2982
2983
Size RadioButton::GetOptimalSize() const
2984
0
{
2985
0
    return CalcMinimumSize();
2986
0
}
2987
2988
void RadioButton::ShowFocus(const tools::Rectangle& rRect)
2989
0
{
2990
0
    if (IsNativeControlSupported(ControlType::Radiobutton, ControlPart::Focus))
2991
0
    {
2992
0
        ImplControlValue aControlValue;
2993
0
        tools::Rectangle aInRect(Point(0, 0), GetSizePixel());
2994
2995
0
        aInRect.SetLeft( rRect.Left() );  // exclude the radio element itself from the focusrect
2996
2997
0
        GetOutDev()->DrawNativeControl(ControlType::Radiobutton, ControlPart::Focus, aInRect,
2998
0
                          ControlState::FOCUSED, aControlValue, OUString());
2999
0
    }
3000
0
    Button::ShowFocus(rRect);
3001
0
}
3002
3003
void RadioButton::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
3004
0
{
3005
0
    Button::DumpAsPropertyTree(rJsonWriter);
3006
0
    rJsonWriter.put("checked", IsChecked());
3007
3008
0
    OUStringBuffer sGroupId;
3009
0
    std::vector<VclPtr<RadioButton>> aGroup = GetRadioButtonGroup();
3010
0
    for(const auto& pButton : aGroup)
3011
0
        sGroupId.append(pButton->get_id());
3012
3013
0
    if (!sGroupId.isEmpty())
3014
0
        rJsonWriter.put("group", sGroupId.toString());
3015
3016
0
    if (!!maImage)
3017
0
    {
3018
0
        SvMemoryStream aOStm(6535, 6535);
3019
0
        if(GraphicConverter::Export(aOStm, maImage.GetBitmap(), ConvertDataFormat::PNG) == ERRCODE_NONE)
3020
0
        {
3021
0
            css::uno::Sequence<sal_Int8> aSeq( static_cast<sal_Int8 const *>(aOStm.GetData()), aOStm.Tell());
3022
0
            OStringBuffer aBuffer("data:image/png;base64,");
3023
0
            ::comphelper::Base64::encode(aBuffer, aSeq);
3024
0
            rJsonWriter.put("image", aBuffer);
3025
0
        }
3026
0
    }
3027
0
}
3028
3029
FactoryFunction RadioButton::GetUITestFactory() const
3030
0
{
3031
0
    return RadioButtonUIObject::create;
3032
0
}
3033
3034
void CheckBox::ImplInitCheckBoxData()
3035
0
{
3036
0
    meState         = TRISTATE_FALSE;
3037
0
    mbTriState      = false;
3038
0
}
3039
3040
void CheckBox::ImplInit( vcl::Window* pParent, WinBits nStyle )
3041
0
{
3042
0
    nStyle = ImplInitStyle(getPreviousSibling(pParent), nStyle);
3043
0
    Button::ImplInit( pParent, nStyle, nullptr );
3044
3045
0
    ImplInitSettings( true );
3046
0
}
3047
3048
WinBits CheckBox::ImplInitStyle( const vcl::Window* pPrevWindow, WinBits nStyle )
3049
0
{
3050
0
    if ( !(nStyle & WB_NOTABSTOP) )
3051
0
        nStyle |= WB_TABSTOP;
3052
0
    if ( !(nStyle & WB_NOGROUP) &&
3053
0
         (!pPrevWindow || (pPrevWindow->GetType() != WindowType::CHECKBOX)) )
3054
0
        nStyle |= WB_GROUP;
3055
0
    return nStyle;
3056
0
}
3057
3058
const vcl::Font& CheckBox::GetCanonicalFont( const StyleSettings& _rStyle ) const
3059
0
{
3060
0
    return _rStyle.GetRadioCheckFont();
3061
0
}
3062
3063
const Color& CheckBox::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
3064
0
{
3065
0
    return _rStyle.GetRadioCheckTextColor();
3066
0
}
3067
3068
void CheckBox::ImplInitSettings( bool bBackground )
3069
0
{
3070
0
    Button::ImplInitSettings();
3071
3072
0
    if ( !bBackground )
3073
0
        return;
3074
3075
0
    vcl::Window* pParent = GetParent();
3076
0
    if ( !IsControlBackground() &&
3077
0
        (pParent->IsChildTransparentModeEnabled() || IsNativeControlSupported( ControlType::Checkbox, ControlPart::Entire ) ) )
3078
0
    {
3079
0
        EnableChildTransparentMode();
3080
0
        SetParentClipMode( ParentClipMode::NoClip );
3081
0
        SetPaintTransparent( true );
3082
0
        SetBackground();
3083
0
        if( IsNativeControlSupported( ControlType::Checkbox, ControlPart::Entire ) )
3084
0
            ImplGetWindowImpl()->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects;
3085
0
    }
3086
0
    else
3087
0
    {
3088
0
        EnableChildTransparentMode( false );
3089
0
        SetParentClipMode();
3090
0
        SetPaintTransparent( false );
3091
3092
0
        if ( IsControlBackground() )
3093
0
            SetBackground( GetControlBackground() );
3094
0
        else
3095
0
            SetBackground( pParent->GetBackground() );
3096
0
    }
3097
0
}
3098
3099
void CheckBox::ImplDrawCheckBoxState(vcl::RenderContext& rRenderContext)
3100
0
{
3101
0
    bool bNativeOK = rRenderContext.IsNativeControlSupported(ControlType::Checkbox, ControlPart::Entire);
3102
0
    if (bNativeOK)
3103
0
    {
3104
0
        ImplControlValue aControlValue(meState == TRISTATE_TRUE ? ButtonValue::On : ButtonValue::Off);
3105
0
        tools::Rectangle aCtrlRegion(maStateRect);
3106
0
        ControlState nState = ControlState::NONE;
3107
3108
0
        if (HasFocus())
3109
0
            nState |= ControlState::FOCUSED;
3110
0
        if (GetButtonState() & DrawButtonFlags::Default)
3111
0
            nState |= ControlState::DEFAULT;
3112
0
        if (GetButtonState() & DrawButtonFlags::Pressed)
3113
0
            nState |= ControlState::PRESSED;
3114
0
        if (IsEnabled())
3115
0
            nState |= ControlState::ENABLED;
3116
3117
0
        if (meState == TRISTATE_TRUE)
3118
0
            aControlValue.setTristateVal(ButtonValue::On);
3119
0
        else if (meState == TRISTATE_INDET)
3120
0
            aControlValue.setTristateVal(ButtonValue::Mixed);
3121
3122
0
        if (IsMouseOver() && maMouseRect.Contains(GetPointerPosPixel()))
3123
0
            nState |= ControlState::ROLLOVER;
3124
3125
0
        bNativeOK = rRenderContext.DrawNativeControl(ControlType::Checkbox, ControlPart::Entire, aCtrlRegion,
3126
0
                                                     nState, aControlValue, OUString());
3127
0
    }
3128
3129
0
    if (bNativeOK)
3130
0
        return;
3131
3132
0
    DrawButtonFlags nStyle = GetButtonState();
3133
0
    if (!IsEnabled())
3134
0
        nStyle |= DrawButtonFlags::Disabled;
3135
0
    if (meState == TRISTATE_INDET)
3136
0
        nStyle |= DrawButtonFlags::DontKnow;
3137
0
    else if (meState == TRISTATE_TRUE)
3138
0
        nStyle |= DrawButtonFlags::Checked;
3139
0
    Image aImage = GetCheckImage(GetSettings(), nStyle);
3140
0
    if (IsZoom())
3141
0
        rRenderContext.DrawImage(maStateRect.TopLeft(), maStateRect.GetSize(), aImage);
3142
0
    else
3143
0
        rRenderContext.DrawImage(maStateRect.TopLeft(), aImage);
3144
0
}
3145
3146
void CheckBox::ImplDraw( OutputDevice* pDev, SystemTextColorFlags nSystemTextColorFlags,
3147
                         const Point& rPos, const Size& rSize,
3148
                         const Size& rImageSize, tools::Rectangle& rStateRect,
3149
                         tools::Rectangle& rMouseRect )
3150
0
{
3151
0
    WinBits                 nWinStyle = GetStyle();
3152
0
    OUString                aText( GetText() );
3153
3154
0
    auto popIt = pDev->ScopedPush(vcl::PushFlags::CLIPREGION | vcl::PushFlags::LINECOLOR);
3155
0
    pDev->IntersectClipRegion( tools::Rectangle( rPos, rSize ) );
3156
3157
0
    if (!aText.isEmpty() || HasImage())
3158
0
    {
3159
0
        Button::ImplDrawRadioCheck(pDev, nWinStyle, nSystemTextColorFlags,
3160
0
                                   rPos, rSize, rImageSize,
3161
0
                                   rStateRect, rMouseRect);
3162
0
    }
3163
0
    else
3164
0
    {
3165
0
        rStateRect.SetLeft( rPos.X() );
3166
0
        if ( nWinStyle & WB_VCENTER )
3167
0
            rStateRect.SetTop( rPos.Y()+((rSize.Height()-rImageSize.Height())/2) );
3168
0
        else if ( nWinStyle & WB_BOTTOM )
3169
0
            rStateRect.SetTop( rPos.Y()+rSize.Height()-rImageSize.Height() );
3170
0
        else
3171
0
            rStateRect.SetTop( rPos.Y() );
3172
0
        rStateRect.SetRight( rStateRect.Left()+rImageSize.Width()-1 );
3173
0
        rStateRect.SetBottom( rStateRect.Top()+rImageSize.Height()-1 );
3174
        // provide space for focusrect
3175
        // note: this assumes that the control's size was adjusted
3176
        // accordingly in Get/LoseFocus, so the onscreen position won't change
3177
0
        if( HasFocus() )
3178
0
            rStateRect.Move( 1, 1 );
3179
0
        rMouseRect          = rStateRect;
3180
3181
0
        ImplSetFocusRect( rStateRect );
3182
0
    }
3183
0
}
3184
3185
void CheckBox::ImplDrawCheckBox(vcl::RenderContext& rRenderContext)
3186
0
{
3187
0
    Size aImageSize = ImplGetCheckImageSize();
3188
0
    aImageSize.setWidth( CalcZoom( aImageSize.Width() ) );
3189
0
    aImageSize.setHeight( CalcZoom( aImageSize.Height() ) );
3190
3191
0
    HideFocus();
3192
3193
0
    ImplDraw(&rRenderContext, SystemTextColorFlags::NONE, Point(), GetOutputSizePixel(),
3194
0
             aImageSize, maStateRect, maMouseRect);
3195
3196
0
    ImplDrawCheckBoxState(rRenderContext);
3197
0
    if (HasFocus())
3198
0
        ShowFocus(ImplGetFocusRect());
3199
0
}
3200
3201
void CheckBox::ImplCheck()
3202
0
{
3203
0
    TriState eNewState;
3204
0
    if ( meState == TRISTATE_FALSE )
3205
0
        eNewState = TRISTATE_TRUE;
3206
0
    else if ( !mbTriState )
3207
0
        eNewState = TRISTATE_FALSE;
3208
0
    else if ( meState == TRISTATE_TRUE )
3209
0
        eNewState = TRISTATE_INDET;
3210
0
    else
3211
0
        eNewState = TRISTATE_FALSE;
3212
0
    meState = eNewState;
3213
3214
0
    VclPtr<vcl::Window> xWindow = this;
3215
0
    Invalidate();
3216
0
    Toggle();
3217
0
    if ( xWindow->isDisposed() )
3218
0
        return;
3219
0
    Click();
3220
0
}
3221
3222
CheckBox::CheckBox( vcl::Window* pParent, WinBits nStyle ) :
3223
0
    Button( WindowType::CHECKBOX )
3224
0
{
3225
0
    ImplInitCheckBoxData();
3226
0
    ImplInit( pParent, nStyle );
3227
0
}
Unexecuted instantiation: CheckBox::CheckBox(vcl::Window*, long)
Unexecuted instantiation: CheckBox::CheckBox(vcl::Window*, long)
3228
3229
rtl::Reference<comphelper::OAccessible> CheckBox::CreateAccessible()
3230
0
{
3231
0
    return new VCLXAccessibleCheckBox(this);
3232
0
}
3233
3234
void CheckBox::MouseButtonDown( const MouseEvent& rMEvt )
3235
0
{
3236
0
    if ( rMEvt.IsLeft() && maMouseRect.Contains( rMEvt.GetPosPixel() ) )
3237
0
    {
3238
0
        GetButtonState() |= DrawButtonFlags::Pressed;
3239
0
        Invalidate();
3240
0
        StartTracking();
3241
0
        return;
3242
0
    }
3243
3244
0
    Button::MouseButtonDown( rMEvt );
3245
0
}
3246
3247
void CheckBox::Tracking( const TrackingEvent& rTEvt )
3248
0
{
3249
0
    if ( rTEvt.IsTrackingEnded() )
3250
0
    {
3251
0
        if ( GetButtonState() & DrawButtonFlags::Pressed )
3252
0
        {
3253
0
            if ( !(GetStyle() & WB_NOPOINTERFOCUS) && !rTEvt.IsTrackingCanceled() )
3254
0
                GrabFocus();
3255
3256
0
            GetButtonState() &= ~DrawButtonFlags::Pressed;
3257
3258
            // do not call click handler if aborted
3259
0
            if ( !rTEvt.IsTrackingCanceled() )
3260
0
                ImplCheck();
3261
0
            else
3262
0
            {
3263
0
                Invalidate();
3264
0
            }
3265
0
        }
3266
0
    }
3267
0
    else
3268
0
    {
3269
0
        if ( maMouseRect.Contains( rTEvt.GetMouseEvent().GetPosPixel() ) )
3270
0
        {
3271
0
            if ( !(GetButtonState() & DrawButtonFlags::Pressed) )
3272
0
            {
3273
0
                GetButtonState() |= DrawButtonFlags::Pressed;
3274
0
                Invalidate();
3275
0
            }
3276
0
        }
3277
0
        else
3278
0
        {
3279
0
            if ( GetButtonState() & DrawButtonFlags::Pressed )
3280
0
            {
3281
0
                GetButtonState() &= ~DrawButtonFlags::Pressed;
3282
0
                Invalidate();
3283
0
            }
3284
0
        }
3285
0
    }
3286
0
}
3287
3288
void CheckBox::KeyInput( const KeyEvent& rKEvt )
3289
0
{
3290
0
    vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
3291
3292
0
    if ( !aKeyCode.GetModifier() && (aKeyCode.GetCode() == KEY_SPACE) )
3293
0
    {
3294
0
        if ( !(GetButtonState() & DrawButtonFlags::Pressed) )
3295
0
        {
3296
0
            GetButtonState() |= DrawButtonFlags::Pressed;
3297
0
            Invalidate();
3298
0
        }
3299
0
    }
3300
0
    else if ( (GetButtonState() & DrawButtonFlags::Pressed) && (aKeyCode.GetCode() == KEY_ESCAPE) )
3301
0
    {
3302
0
        GetButtonState() &= ~DrawButtonFlags::Pressed;
3303
0
        Invalidate();
3304
0
    }
3305
0
    else
3306
0
        Button::KeyInput( rKEvt );
3307
0
}
3308
3309
void CheckBox::KeyUp( const KeyEvent& rKEvt )
3310
0
{
3311
0
    vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
3312
3313
0
    if ( (GetButtonState() & DrawButtonFlags::Pressed) && (aKeyCode.GetCode() == KEY_SPACE) )
3314
0
    {
3315
0
        GetButtonState() &= ~DrawButtonFlags::Pressed;
3316
0
        ImplCheck();
3317
0
    }
3318
0
    else
3319
0
        Button::KeyUp( rKEvt );
3320
0
}
3321
3322
void CheckBox::FillLayoutData() const
3323
0
{
3324
0
    mxLayoutData.emplace();
3325
0
    const_cast<CheckBox*>(this)->Invalidate();
3326
0
}
3327
3328
void CheckBox::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
3329
0
{
3330
0
    ImplDrawCheckBox(rRenderContext);
3331
0
}
3332
3333
void CheckBox::Draw( OutputDevice* pDev, const Point& rPos,
3334
                     SystemTextColorFlags nFlags )
3335
0
{
3336
0
    MapMode     aResMapMode( MapUnit::Map100thMM );
3337
0
    Point       aPos  = pDev->LogicToPixel( rPos );
3338
0
    Size        aSize = GetSizePixel();
3339
0
    Size        aImageSize = pDev->LogicToPixel( Size( 300, 300 ), aResMapMode );
3340
0
    Size        aBrd1Size = pDev->LogicToPixel( Size( 20, 20 ), aResMapMode );
3341
0
    Size        aBrd2Size = pDev->LogicToPixel( Size( 30, 30 ), aResMapMode );
3342
0
    tools::Long        nCheckWidth = pDev->LogicToPixel( Size( 20, 20 ), aResMapMode ).Width();
3343
0
    vcl::Font   aFont = GetDrawPixelFont( pDev );
3344
0
    tools::Rectangle   aStateRect;
3345
0
    tools::Rectangle   aMouseRect;
3346
3347
0
    aImageSize.setWidth( CalcZoom( aImageSize.Width() ) );
3348
0
    aImageSize.setHeight( CalcZoom( aImageSize.Height() ) );
3349
0
    aBrd1Size.setWidth( CalcZoom( aBrd1Size.Width() ) );
3350
0
    aBrd1Size.setHeight( CalcZoom( aBrd1Size.Height() ) );
3351
0
    aBrd2Size.setWidth( CalcZoom( aBrd2Size.Width() ) );
3352
0
    aBrd2Size.setHeight( CalcZoom( aBrd2Size.Height() ) );
3353
3354
0
    if ( !aBrd1Size.Width() )
3355
0
        aBrd1Size.setWidth( 1 );
3356
0
    if ( !aBrd1Size.Height() )
3357
0
        aBrd1Size.setHeight( 1 );
3358
0
    if ( !aBrd2Size.Width() )
3359
0
        aBrd2Size.setWidth( 1 );
3360
0
    if ( !aBrd2Size.Height() )
3361
0
        aBrd2Size.setHeight( 1 );
3362
0
    if ( !nCheckWidth )
3363
0
        nCheckWidth = 1;
3364
3365
0
    auto popIt = pDev->ScopedPush();
3366
0
    pDev->SetMapMode();
3367
0
    pDev->SetFont( aFont );
3368
0
    if ( nFlags & SystemTextColorFlags::Mono )
3369
0
        pDev->SetTextColor( COL_BLACK );
3370
0
    else
3371
0
        pDev->SetTextColor( GetTextColor() );
3372
0
    pDev->SetTextFillColor();
3373
3374
0
    ImplDraw( pDev, nFlags, aPos, aSize,
3375
0
              aImageSize, aStateRect, aMouseRect );
3376
3377
0
    pDev->SetLineColor();
3378
0
    pDev->SetFillColor( COL_BLACK );
3379
0
    pDev->DrawRect( aStateRect );
3380
0
    aStateRect.AdjustLeft(aBrd1Size.Width() );
3381
0
    aStateRect.AdjustTop(aBrd1Size.Height() );
3382
0
    aStateRect.AdjustRight( -(aBrd1Size.Width()) );
3383
0
    aStateRect.AdjustBottom( -(aBrd1Size.Height()) );
3384
0
    if ( meState == TRISTATE_INDET )
3385
0
        pDev->SetFillColor( COL_LIGHTGRAY );
3386
0
    else
3387
0
        pDev->SetFillColor( COL_WHITE );
3388
0
    pDev->DrawRect( aStateRect );
3389
3390
0
    if ( meState == TRISTATE_TRUE )
3391
0
    {
3392
0
        aStateRect.AdjustLeft(aBrd2Size.Width() );
3393
0
        aStateRect.AdjustTop(aBrd2Size.Height() );
3394
0
        aStateRect.AdjustRight( -(aBrd2Size.Width()) );
3395
0
        aStateRect.AdjustBottom( -(aBrd2Size.Height()) );
3396
0
        Point   aPos11( aStateRect.TopLeft() );
3397
0
        Point   aPos12( aStateRect.BottomRight() );
3398
0
        Point   aPos21( aStateRect.TopRight() );
3399
0
        Point   aPos22( aStateRect.BottomLeft() );
3400
0
        Point   aTempPos11( aPos11 );
3401
0
        Point   aTempPos12( aPos12 );
3402
0
        Point   aTempPos21( aPos21 );
3403
0
        Point   aTempPos22( aPos22 );
3404
0
        pDev->SetLineColor( COL_BLACK );
3405
0
        tools::Long nDX = 0;
3406
0
        for ( tools::Long i = 0; i < nCheckWidth; i++ )
3407
0
        {
3408
0
            if ( !(i % 2) )
3409
0
            {
3410
0
                aTempPos11.setX( aPos11.X()+nDX );
3411
0
                aTempPos12.setX( aPos12.X()+nDX );
3412
0
                aTempPos21.setX( aPos21.X()+nDX );
3413
0
                aTempPos22.setX( aPos22.X()+nDX );
3414
0
            }
3415
0
            else
3416
0
            {
3417
0
                nDX++;
3418
0
                aTempPos11.setX( aPos11.X()-nDX );
3419
0
                aTempPos12.setX( aPos12.X()-nDX );
3420
0
                aTempPos21.setX( aPos21.X()-nDX );
3421
0
                aTempPos22.setX( aPos22.X()-nDX );
3422
0
            }
3423
0
            pDev->DrawLine( aTempPos11, aTempPos12 );
3424
0
            pDev->DrawLine( aTempPos21, aTempPos22 );
3425
0
        }
3426
0
    }
3427
0
}
3428
3429
void CheckBox::Resize()
3430
0
{
3431
0
    Control::Resize();
3432
0
    Invalidate();
3433
0
}
3434
3435
void CheckBox::GetFocus()
3436
0
{
3437
0
    if (GetText().isEmpty())
3438
0
    {
3439
        // increase button size to have space for focus rect
3440
        // checkboxes without text will draw focusrect around the check
3441
        // See CheckBox::ImplDraw()
3442
0
        Point aPos( GetPosPixel() );
3443
0
        Size aSize( GetSizePixel() );
3444
0
        aPos.Move(-1,-1);
3445
0
        aSize.AdjustHeight(2 );
3446
0
        aSize.AdjustWidth(2 );
3447
0
        setPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height() );
3448
0
        Invalidate();
3449
        // Trigger drawing to initialize the mouse rectangle, otherwise the mouse button down
3450
        // handler would ignore the mouse event.
3451
0
        PaintImmediately();
3452
0
    }
3453
0
    else
3454
0
        ShowFocus( ImplGetFocusRect() );
3455
3456
0
    SetInputContext( InputContext( GetFont() ) );
3457
0
    Button::GetFocus();
3458
0
}
3459
3460
void CheckBox::LoseFocus()
3461
0
{
3462
0
    if ( GetButtonState() & DrawButtonFlags::Pressed )
3463
0
    {
3464
0
        GetButtonState() &= ~DrawButtonFlags::Pressed;
3465
0
        Invalidate();
3466
0
    }
3467
3468
0
    HideFocus();
3469
0
    Button::LoseFocus();
3470
3471
0
    if (GetText().isEmpty())
3472
0
    {
3473
        // decrease button size again (see GetFocus())
3474
        // checkboxes without text will draw focusrect around the check
3475
0
        Point aPos( GetPosPixel() );
3476
0
        Size aSize( GetSizePixel() );
3477
0
        aPos.Move(1,1);
3478
0
        aSize.AdjustHeight( -2 );
3479
0
        aSize.AdjustWidth( -2 );
3480
0
        setPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height() );
3481
0
        Invalidate();
3482
0
    }
3483
0
}
3484
3485
void CheckBox::StateChanged( StateChangedType nType )
3486
0
{
3487
0
    Button::StateChanged( nType );
3488
3489
0
    if ( nType == StateChangedType::State )
3490
0
    {
3491
0
        if ( IsReallyVisible() && IsUpdateMode() )
3492
0
            Invalidate( maStateRect );
3493
0
    }
3494
0
    else if ( (nType == StateChangedType::Enable) ||
3495
0
              (nType == StateChangedType::Text) ||
3496
0
              (nType == StateChangedType::Data) ||
3497
0
              (nType == StateChangedType::UpdateMode) )
3498
0
    {
3499
0
        if ( IsUpdateMode() )
3500
0
            Invalidate();
3501
0
    }
3502
0
    else if ( nType == StateChangedType::Style )
3503
0
    {
3504
0
        SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev ), GetStyle() ) );
3505
3506
0
        if ( (GetPrevStyle() & CHECKBOX_VIEW_STYLE) !=
3507
0
             (GetStyle() & CHECKBOX_VIEW_STYLE) )
3508
0
        {
3509
0
            if ( IsUpdateMode() )
3510
0
                Invalidate();
3511
0
        }
3512
0
    }
3513
0
    else if ( (nType == StateChangedType::Zoom) ||
3514
0
              (nType == StateChangedType::ControlFont) )
3515
0
    {
3516
0
        ImplInitSettings( false );
3517
0
        Invalidate();
3518
0
    }
3519
0
    else if ( nType == StateChangedType::ControlForeground )
3520
0
    {
3521
0
        ImplInitSettings( false );
3522
0
        Invalidate();
3523
0
    }
3524
0
    else if ( nType == StateChangedType::ControlBackground )
3525
0
    {
3526
0
        ImplInitSettings( true );
3527
0
        Invalidate();
3528
0
    }
3529
0
}
3530
3531
void CheckBox::DataChanged( const DataChangedEvent& rDCEvt )
3532
0
{
3533
0
    Button::DataChanged( rDCEvt );
3534
3535
0
    if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
3536
0
         (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
3537
0
         ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
3538
0
          (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
3539
0
    {
3540
0
        ImplInitSettings( true );
3541
0
        Invalidate();
3542
0
    }
3543
0
}
3544
3545
bool CheckBox::PreNotify( NotifyEvent& rNEvt )
3546
0
{
3547
0
    if( rNEvt.GetType() == NotifyEventType::MOUSEMOVE )
3548
0
    {
3549
0
        const MouseEvent* pMouseEvt = rNEvt.GetMouseEvent();
3550
0
        if( pMouseEvt && !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
3551
0
        {
3552
            // trigger redraw if mouse over state has changed
3553
0
            if( IsNativeControlSupported(ControlType::Checkbox, ControlPart::Entire) )
3554
0
            {
3555
0
                if (maMouseRect.Contains(GetPointerPosPixel()) != maMouseRect.Contains(GetLastPointerPosPixel()) ||
3556
0
                    pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow())
3557
0
                {
3558
0
                    Invalidate( maStateRect );
3559
0
                }
3560
0
            }
3561
0
        }
3562
0
    }
3563
3564
0
    return Button::PreNotify(rNEvt);
3565
0
}
3566
3567
void CheckBox::Toggle()
3568
0
{
3569
0
    ImplCallEventListenersAndHandler( VclEventId::CheckboxToggle, [this] () { maToggleHdl.Call(*this); } );
3570
0
}
3571
3572
void CheckBox::SetState( TriState eState )
3573
0
{
3574
0
    if ( !mbTriState && (eState == TRISTATE_INDET) )
3575
0
        eState = TRISTATE_FALSE;
3576
3577
0
    if ( meState != eState )
3578
0
    {
3579
0
        meState = eState;
3580
0
        StateChanged( StateChangedType::State );
3581
0
        if (eState != TRISTATE_INDET) // just removing Toggle() fails at the ui test /tdf65334.py
3582
0
            Toggle();
3583
0
    }
3584
0
}
3585
3586
bool CheckBox::set_property(const OUString &rKey, const OUString &rValue)
3587
0
{
3588
0
    if (rKey == "active")
3589
0
        SetState(toBool(rValue) ? TRISTATE_TRUE : TRISTATE_FALSE);
3590
0
    else
3591
0
        return Button::set_property(rKey, rValue);
3592
0
    return true;
3593
0
}
3594
3595
void CheckBox::EnableTriState( bool bTriState )
3596
0
{
3597
0
    if ( mbTriState != bTriState )
3598
0
    {
3599
0
        mbTriState = bTriState;
3600
3601
0
        if ( !bTriState && (meState == TRISTATE_INDET) )
3602
0
            SetState( TRISTATE_FALSE );
3603
0
    }
3604
0
}
3605
3606
Size CheckBox::ImplGetCheckImageSize() const
3607
0
{
3608
0
    Size aSize;
3609
0
    bool bDefaultSize = true;
3610
0
    if( IsNativeControlSupported( ControlType::Checkbox, ControlPart::Entire ) )
3611
0
    {
3612
0
        ImplControlValue aControlValue;
3613
0
        tools::Rectangle aCtrlRegion( Point( 0, 0 ), GetSizePixel() );
3614
0
        tools::Rectangle aBoundingRgn, aContentRgn;
3615
3616
        // get native size of a check box
3617
0
        if( GetNativeControlRegion( ControlType::Checkbox, ControlPart::Entire, aCtrlRegion,
3618
0
                                    ControlState::DEFAULT|ControlState::ENABLED,
3619
0
                                    aControlValue,
3620
0
                                    aBoundingRgn, aContentRgn ) )
3621
0
        {
3622
0
            aSize = aContentRgn.GetSize();
3623
0
            bDefaultSize = false;
3624
0
        }
3625
0
    }
3626
0
    if( bDefaultSize )
3627
0
        aSize = GetCheckImage( GetSettings(), DrawButtonFlags::NONE ).GetSizePixel();
3628
0
    return aSize;
3629
0
}
3630
3631
Image CheckBox::GetCheckImage( const AllSettings& rSettings, DrawButtonFlags nFlags )
3632
0
{
3633
0
    ImplSVData*             pSVData = ImplGetSVData();
3634
0
    const StyleSettings&    rStyleSettings = rSettings.GetStyleSettings();
3635
0
    sal_uInt16              nStyle = 0;
3636
3637
0
    if ( rStyleSettings.GetOptions() & StyleSettingsOptions::Mono )
3638
0
        nStyle = STYLE_CHECKBOX_MONO;
3639
3640
0
    if ( pSVData->maCtrlData.maCheckImgList.empty() ||
3641
0
         (pSVData->maCtrlData.mnCheckStyle != nStyle) ||
3642
0
         (pSVData->maCtrlData.mnLastCheckFColor != rStyleSettings.GetFaceColor()) ||
3643
0
         (pSVData->maCtrlData.mnLastCheckWColor != rStyleSettings.GetWindowColor()) ||
3644
0
         (pSVData->maCtrlData.mnLastCheckLColor != rStyleSettings.GetLightColor()) )
3645
0
    {
3646
0
        pSVData->maCtrlData.maCheckImgList.clear();
3647
3648
0
        pSVData->maCtrlData.mnLastCheckFColor = rStyleSettings.GetFaceColor();
3649
0
        pSVData->maCtrlData.mnLastCheckWColor = rStyleSettings.GetWindowColor();
3650
0
        pSVData->maCtrlData.mnLastCheckLColor = rStyleSettings.GetLightColor();
3651
3652
0
        std::vector<OUString> aResources;
3653
0
        if (nStyle)
3654
0
        {
3655
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO1);
3656
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO2);
3657
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO3);
3658
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO4);
3659
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO5);
3660
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO6);
3661
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO7);
3662
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO8);
3663
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO9);
3664
0
        }
3665
0
        else
3666
0
        {
3667
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECK1);
3668
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECK2);
3669
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECK3);
3670
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECK4);
3671
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECK5);
3672
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECK6);
3673
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECK7);
3674
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECK8);
3675
0
            aResources.emplace_back(SV_RESID_BITMAP_CHECK9);
3676
0
        }
3677
0
        LoadThemedImageList(rStyleSettings, pSVData->maCtrlData.maCheckImgList, aResources);
3678
0
        pSVData->maCtrlData.mnCheckStyle = nStyle;
3679
0
    }
3680
3681
0
    sal_uInt16 nIndex;
3682
0
    if ( nFlags & DrawButtonFlags::Disabled )
3683
0
    {
3684
0
        if ( nFlags & DrawButtonFlags::DontKnow )
3685
0
            nIndex = 8;
3686
0
        else if ( nFlags & DrawButtonFlags::Checked )
3687
0
            nIndex = 5;
3688
0
        else
3689
0
            nIndex = 4;
3690
0
    }
3691
0
    else if ( nFlags & DrawButtonFlags::Pressed )
3692
0
    {
3693
0
        if ( nFlags & DrawButtonFlags::DontKnow )
3694
0
            nIndex = 7;
3695
0
        else if ( nFlags & DrawButtonFlags::Checked )
3696
0
            nIndex = 3;
3697
0
        else
3698
0
            nIndex = 2;
3699
0
    }
3700
0
    else
3701
0
    {
3702
0
        if ( nFlags & DrawButtonFlags::DontKnow )
3703
0
            nIndex = 6;
3704
0
        else if ( nFlags & DrawButtonFlags::Checked )
3705
0
            nIndex = 1;
3706
0
        else
3707
0
            nIndex = 0;
3708
0
    }
3709
0
    return pSVData->maCtrlData.maCheckImgList[nIndex];
3710
0
}
3711
3712
void CheckBox::ImplAdjustNWFSizes()
3713
0
{
3714
0
    auto popIt = GetOutDev()->ScopedPush(vcl::PushFlags::MAPMODE);
3715
0
    SetMapMode(MapMode(MapUnit::MapPixel));
3716
3717
0
    ImplControlValue aControlValue;
3718
0
    Size aCurSize( GetSizePixel() );
3719
0
    tools::Rectangle aCtrlRegion( Point( 0, 0 ), aCurSize );
3720
0
    tools::Rectangle aBoundingRgn, aContentRgn;
3721
3722
    // get native size of a radiobutton
3723
0
    if( GetNativeControlRegion( ControlType::Checkbox, ControlPart::Entire, aCtrlRegion,
3724
0
                                ControlState::DEFAULT|ControlState::ENABLED, aControlValue,
3725
0
                                aBoundingRgn, aContentRgn ) )
3726
0
    {
3727
0
        Size aSize = aContentRgn.GetSize();
3728
3729
0
        if( aSize.Height() > aCurSize.Height() )
3730
0
        {
3731
0
            aCurSize.setHeight( aSize.Height() );
3732
0
            SetSizePixel( aCurSize );
3733
0
        }
3734
0
    }
3735
0
}
3736
3737
Size CheckBox::CalcMinimumSize( tools::Long nMaxWidth ) const
3738
0
{
3739
0
    Size aSize = ImplGetCheckImageSize();
3740
0
    nMaxWidth -= aSize.Width();
3741
3742
0
    OUString aText = GetText();
3743
0
    if (!aText.isEmpty())
3744
0
    {
3745
        // subtract what will be added later
3746
0
        nMaxWidth-=2;
3747
0
        nMaxWidth -= ImplGetImageToTextDistance();
3748
3749
0
        Size aTextSize = GetTextRect( tools::Rectangle( Point(), Size( nMaxWidth > 0 ? nMaxWidth : 0x7fffffff, 0x7fffffff ) ),
3750
0
                                      aText, FixedText::ImplGetTextStyle( GetStyle() ) ).GetSize();
3751
0
        aSize.AdjustWidth(2 );    // for focus rect
3752
0
        aSize.AdjustWidth(ImplGetImageToTextDistance() );
3753
0
        aSize.AdjustWidth(aTextSize.Width() );
3754
0
        if ( aSize.Height() < aTextSize.Height() )
3755
0
            aSize.setHeight( aTextSize.Height() );
3756
0
    }
3757
0
    else
3758
0
    {
3759
        // is this still correct ? since the checkbox now
3760
        // shows a focus rect it should be 2 pixels wider and longer
3761
/* since otherwise the controls in the Writer hang too far up
3762
        aSize.Width() += 2;
3763
        aSize.Height() += 2;
3764
*/
3765
0
    }
3766
3767
0
    return CalcWindowSize( aSize );
3768
0
}
3769
3770
Size CheckBox::GetOptimalSize() const
3771
0
{
3772
0
    int nWidthRequest(get_width_request());
3773
0
    return CalcMinimumSize(nWidthRequest != -1 ? nWidthRequest : 0);
3774
0
}
3775
3776
void CheckBox::ShowFocus(const tools::Rectangle& rRect)
3777
0
{
3778
0
    if (IsNativeControlSupported(ControlType::Checkbox, ControlPart::Focus))
3779
0
    {
3780
0
        ImplControlValue aControlValue;
3781
0
        tools::Rectangle aInRect(Point(0, 0), GetSizePixel());
3782
3783
0
        aInRect.SetLeft( rRect.Left() );  // exclude the checkbox itself from the focusrect
3784
3785
0
        GetOutDev()->DrawNativeControl(ControlType::Checkbox, ControlPart::Focus, aInRect,
3786
0
                          ControlState::FOCUSED, aControlValue, OUString());
3787
0
    }
3788
0
    Button::ShowFocus(rRect);
3789
0
}
3790
3791
void CheckBox::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
3792
0
{
3793
0
    Button::DumpAsPropertyTree(rJsonWriter);
3794
0
    rJsonWriter.put("checked", IsChecked());
3795
0
}
3796
3797
FactoryFunction CheckBox::GetUITestFactory() const
3798
0
{
3799
0
    return CheckBoxUIObject::create;
3800
0
}
3801
3802
ImageButton::ImageButton( vcl::Window* pParent, WinBits nStyle ) :
3803
0
    PushButton( pParent, nStyle )
3804
0
{
3805
0
    ImplInitStyle();
3806
0
}
Unexecuted instantiation: ImageButton::ImageButton(vcl::Window*, long)
Unexecuted instantiation: ImageButton::ImageButton(vcl::Window*, long)
3807
3808
void ImageButton::ImplInitStyle()
3809
0
{
3810
0
    WinBits nStyle = GetStyle();
3811
3812
0
    if ( ! ( nStyle & ( WB_RIGHT | WB_LEFT ) ) )
3813
0
        nStyle |= WB_CENTER;
3814
3815
0
    if ( ! ( nStyle & ( WB_TOP | WB_BOTTOM ) ) )
3816
0
        nStyle |= WB_VCENTER;
3817
3818
0
    SetStyle( nStyle );
3819
0
}
3820
3821
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */