Coverage Report

Created: 2025-12-08 09:28

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