Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/vcl/source/control/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 122 kB image not shown  

Quelle  button.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <tools/poly.hxx>

#include <vcl/builder.hxx>
#include <vcl/cvtgrf.hxx>
#include <vcl/image.hxx>
#include <vcl/bitmapex.hxx>
#include <vcl/decoview.hxx>
#include <vcl/event.hxx>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <vcl/toolkit/dialog.hxx>
#include <vcl/toolkit/fixed.hxx>
#include <vcl/toolkit/button.hxx>
#include <vcl/salnativewidgets.hxx>
#include <vcl/toolkit/edit.hxx>
#include <vcl/layout.hxx>
#include <vcl/stdtext.hxx>
#include <vcl/uitest/uiobject.hxx>

#include <accessibility/vclxaccessiblebutton.hxx>
#include <accessibility/vclxaccessiblecheckbox.hxx>
#include <accessibility/vclxaccessibleradiobutton.hxx>
#include <bitmaps.hlst>
#include <svdata.hxx>
#include <window.h>
#include <vclstatuslistener.hxx>
#include <osl/diagnose.h>

#include <comphelper/base64.hxx>
#include <comphelper/dispatchcommand.hxx>
#include <comphelper/lok.hxx>
#include <officecfg/Office/Common.hxx>
#include <boost/property_tree/ptree.hpp>
#include <tools/json_writer.hxx>
#include <tools/stream.hxx>


using namespace css;

constexpr auto PUSHBUTTON_VIEW_STYLE = WB_3DLOOK |
                                     WB_LEFT | WB_CENTER | WB_RIGHT |
                                     WB_TOP | WB_VCENTER | WB_BOTTOM |
                                     WB_WORDBREAK | WB_NOLABEL |
                                     WB_DEFBUTTON | WB_NOLIGHTBORDER |
                                     WB_RECTSTYLE | WB_SMALLSTYLE |
                                     WB_TOGGLE;
constexpr auto RADIOBUTTON_VIEW_STYLE = WB_3DLOOK |
                                     WB_LEFT | WB_CENTER | WB_RIGHT |
                                     WB_TOP | WB_VCENTER | WB_BOTTOM |
                                     WB_WORDBREAK | WB_NOLABEL;
constexpr auto CHECKBOX_VIEW_STYLE = WB_3DLOOK |
                                     WB_LEFT | WB_CENTER | WB_RIGHT |
                                     WB_TOP | WB_VCENTER | WB_BOTTOM |
                                     WB_WORDBREAK | WB_NOLABEL;

#define STYLE_RADIOBUTTON_MONO      (sal_uInt16(0x0001)) // legacy
#define STYLE_CHECKBOX_MONO         (sal_uInt16(0x0001)) // legacy

class ImplCommonButtonData
{
public:
    ImplCommonButtonData();

    tools::Rectangle       maFocusRect;
    tools::Long            mnSeparatorX;
    DrawButtonFlags mnButtonState;
    bool            mbSmallSymbol;
    bool            mbGeneratedTooltip;

    Image           maImage;
    ImageAlign      meImageAlign;
    SymbolAlign     meSymbolAlign;

    Image           maCustomContentImage;

    /** StatusListener. Updates the button as the slot state changes */
    rtl::Reference<VclStatusListener<Button>> mpStatusListener;
};

ImplCommonButtonData::ImplCommonButtonData() :  mnSeparatorX(0), mnButtonState(DrawButtonFlags::NONE),
mbSmallSymbol(false), mbGeneratedTooltip(false),  meImageAlign(ImageAlign::Top), meSymbolAlign(SymbolAlign::LEFT)
{
}

Button::Button( WindowType eType ) :
    Control( eType ),
    mpButtonData( std::make_unique<ImplCommonButtonData>() )
{
}

Button::~Button()
{
    disposeOnce();
}

void Button::dispose()
{
    if (mpButtonData->mpStatusListener.is())
        mpButtonData->mpStatusListener->dispose();
    Control::dispose();
}

void Button::SetCommandHandler(const OUString& aCommand, const css::uno::Reference<css::frame::XFrame>& rFrame)
{
    maCommand = aCommand;
    SetClickHdl( LINK( this, Button, dispatchCommandHandler) );

    mpButtonData->mpStatusListener = new VclStatusListener<Button>(this, rFrame, aCommand);
    mpButtonData->mpStatusListener->startListening();
}

void Button::Click()
{
    ImplCallEventListenersAndHandler( VclEventId::ButtonClick, [this] () { maClickHdl.Call(this); } );
}

void Button::SetModeImage( const Image& rImage )
{
    if ( rImage != mpButtonData->maImage )
    {
        mpButtonData->maImage = rImage;
        StateChanged( StateChangedType::Data );
        queue_resize();
    }
}

Image const & Button::GetModeImage( ) const
{
    return mpButtonData->maImage;
}

bool Button::HasImage() const
{
    return !!(mpButtonData->maImage);
}

void Button::SetImageAlign( ImageAlign eAlign )
{
    if ( mpButtonData->meImageAlign != eAlign )
    {
        mpButtonData->meImageAlign = eAlign;
        StateChanged( StateChangedType::Data );
    }
}

ImageAlign Button::GetImageAlign() const
{
    return mpButtonData->meImageAlign;
}

void Button::SetCustomButtonImage(const Image& rImage)
{
    if (rImage != mpButtonData->maCustomContentImage)
    {
        mpButtonData->maCustomContentImage = rImage;
        StateChanged( StateChangedType::Data );
    }
}

Image const & Button::GetCustomButtonImage() const
{
    return mpButtonData->maCustomContentImage;
}

tools::Long Button::ImplGetSeparatorX() const
{
    return mpButtonData->mnSeparatorX;
}

void Button::ImplSetSeparatorX( tools::Long nX )
{
    mpButtonData->mnSeparatorX = nX;
}

DrawTextFlags Button::ImplGetTextStyle( WinBits nWinStyle, SystemTextColorFlags nSystemTextColorFlags ) const
{
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
    DrawTextFlags nTextStyle = FixedText::ImplGetTextStyle(nWinStyle & ~WB_DEFBUTTON);

    if (!IsEnabled())
        nTextStyle |= DrawTextFlags::Disable;

    if ((nSystemTextColorFlags & SystemTextColorFlags::Mono) ||
        (rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
    {
        nTextStyle |= DrawTextFlags::Mono;
    }

    return nTextStyle;
}

void Button::ImplDrawAlignedImage(OutputDevice* pDev, Point& rPos,
                                  Size& rSize,
                                  sal_Int32 nImageSep,
                                  DrawTextFlags nTextStyle, tools::Rectangle *pSymbolRect,
                                  bool bAddImageSep)
{
    OUString aText(GetText());
    bool bDrawImage = HasImage();
    bool bDrawText  = !aText.isEmpty();
    bool bHasSymbol = pSymbolRect != nullptr;

    // No text and no image => nothing to do => return
    if (!bDrawImage && !bDrawText && !bHasSymbol)
        return;

    WinBits nWinStyle = GetStyle();
    tools::Rectangle aOutRect( rPos, rSize );
    ImageAlign eImageAlign = mpButtonData->meImageAlign;
    Size aImageSize = mpButtonData->maImage.GetSizePixel();

    aImageSize.setWidth( CalcZoom( aImageSize.Width() ) );
    aImageSize.setHeight( CalcZoom( aImageSize.Height() ) );

    // Drawing text or symbol only is simple, use style and output rectangle
    if (bHasSymbol && !bDrawImage && !bDrawText)
    {
        *pSymbolRect = aOutRect;
        return;
    }
    else if (bDrawText && !bDrawImage && !bHasSymbol)
    {
        aOutRect = DrawControlText(*pDev, aOutRect, aText, nTextStyle, nullptr, nullptr);
        tools::Rectangle textRect = GetTextRect(
            tools::Rectangle(Point(), Size(0x7fffffff, 0x7fffffff)), aText, nTextStyle);
        // If the button text doesn't fit into it, put it into a tooltip (might happen in sidebar)
        if (GetQuickHelpText()!= aText && mpButtonData->mbGeneratedTooltip)
            SetQuickHelpText(u""_ustr);
        if (GetQuickHelpText().isEmpty() && textRect.getOpenWidth() > rSize.getWidth())
        {
            SetQuickHelpText(aText);
            mpButtonData->mbGeneratedTooltip = true;
        }

        ImplSetFocusRect(aOutRect);
        rSize = aOutRect.GetSize();
        rPos = aOutRect.TopLeft();

        return;
    }

    // check for HC mode ( image only! )
    Image* pImage = &(mpButtonData->maImage);

    Size aTextSize;
    Size aSymbolSize;
    Size aDeviceTextSize;
    Point aImagePos = rPos;
    Point aTextPos = rPos;
    tools::Rectangle aUnion(aImagePos, aImageSize);
    tools::Long nSymbolHeight = 0;

    if (bDrawText || bHasSymbol)
    {
        // Get the size of the text output area ( the symbol will be drawn in
        // this area as well, so the symbol rectangle will be calculated here, too )

        tools::Rectangle aRect(Point(), rSize);
        Size aTSSize;

        if (bHasSymbol)
        {
            tools::Rectangle aSymbol;
            if (bDrawText)
            {
                nSymbolHeight = pDev->GetTextHeight();
                if (mpButtonData->mbSmallSymbol)
                    nSymbolHeight = nSymbolHeight * 3 / 4;

                aSymbol = tools::Rectangle(Point(), Size(nSymbolHeight, nSymbolHeight));
                ImplCalcSymbolRect(aSymbol);
                aRect.AdjustLeft(3 * nSymbolHeight / 2 );
                aTSSize.setWidth( 3 * nSymbolHeight / 2 );
            }
            else
            {
                aSymbol = tools::Rectangle(Point(), rSize);
                ImplCalcSymbolRect(aSymbol);
                aTSSize.setWidth( aSymbol.GetWidth() );
            }
            aTSSize.setHeight( aSymbol.GetHeight() );
            aSymbolSize = aSymbol.GetSize();
        }

        if (bDrawText)
        {
            if ((eImageAlign == ImageAlign::LeftTop)     ||
                (eImageAlign == ImageAlign::Left )        ||
                (eImageAlign == ImageAlign::LeftBottom)  ||
                (eImageAlign == ImageAlign::RightTop)    ||
                (eImageAlign == ImageAlign::Right)        ||
                (eImageAlign == ImageAlign::RightBottom))
            {
                aRect.AdjustRight( -sal_Int32(aImageSize.Width() + nImageSep) );
            }
            else if ((eImageAlign == ImageAlign::TopLeft)    ||
                     (eImageAlign == ImageAlign::Top)         ||
                     (eImageAlign == ImageAlign::TopRight)   ||
                     (eImageAlign == ImageAlign::BottomLeft) ||
                     (eImageAlign == ImageAlign::Bottom)      ||
                     (eImageAlign == ImageAlign::BottomRight))
            {
                aRect.AdjustBottom( -sal_Int32(aImageSize.Height() + nImageSep) );
            }

            aRect = GetControlTextRect(*pDev, aRect, aText, nTextStyle, &aDeviceTextSize);
            aTextSize = aRect.GetSize();

            aTSSize.AdjustWidth(aTextSize.Width() );

            if (aTSSize.Height() < aTextSize.Height())
                aTSSize.setHeight( aTextSize.Height() );

            if (bAddImageSep && bDrawImage)
            {
                tools::Long nDiff = (aImageSize.Height() - aTextSize.Height()) / 3;
                if (nDiff > 0)
                    nImageSep += nDiff;
            }
        }

        Size aMax;
        aMax.setWidth( std::max(aTSSize.Width(), aImageSize.Width()) );
        aMax.setHeight( std::max(aTSSize.Height(), aImageSize.Height()) );

        // Now calculate the output area for the image and the text according to the image align flags

        if ((eImageAlign == ImageAlign::Left) ||
            (eImageAlign == ImageAlign::Right))
        {
            aImagePos.setY( rPos.Y() + (aMax.Height() - aImageSize.Height()) / 2 );
            aTextPos.setY( rPos.Y() + (aMax.Height() - aTSSize.Height()) / 2 );
        }
        else if ((eImageAlign == ImageAlign::LeftBottom) ||
                 (eImageAlign == ImageAlign::RightBottom))
        {
            aImagePos.setY( rPos.Y() + aMax.Height() - aImageSize.Height() );
            aTextPos.setY( rPos.Y() + aMax.Height() - aTSSize.Height() );
        }
        else if ((eImageAlign == ImageAlign::Top) ||
                 (eImageAlign == ImageAlign::Bottom))
        {
            aImagePos.setX( rPos.X() + (aMax.Width() - aImageSize.Width()) / 2 );
            aTextPos.setX( rPos.X() + (aMax.Width() - aTSSize.Width()) / 2 );
        }
        else if ((eImageAlign == ImageAlign::TopRight) ||
                 (eImageAlign == ImageAlign::BottomRight))
        {
            aImagePos.setX( rPos.X() + aMax.Width() - aImageSize.Width() );
            aTextPos.setX( rPos.X() + aMax.Width() - aTSSize.Width() );
        }

        if ((eImageAlign == ImageAlign::LeftTop) ||
            (eImageAlign == ImageAlign::Left)     ||
            (eImageAlign == ImageAlign::LeftBottom))
        {
            aTextPos.setX( rPos.X() + aImageSize.Width() + nImageSep );
        }
        else if ((eImageAlign == ImageAlign::RightTop) ||
                 (eImageAlign == ImageAlign::Right)     ||
                 (eImageAlign == ImageAlign::RightBottom))
        {
            aImagePos.setX( rPos.X() + aTSSize.Width() + nImageSep );
        }
        else if ((eImageAlign == ImageAlign::TopLeft) ||
                 (eImageAlign == ImageAlign::Top)      ||
                 (eImageAlign == ImageAlign::TopRight))
        {
            aTextPos.setY( rPos.Y() + aImageSize.Height() + nImageSep );
        }
        else if ((eImageAlign == ImageAlign::BottomLeft) ||
                 (eImageAlign == ImageAlign::Bottom)      ||
                 (eImageAlign == ImageAlign::BottomRight))
        {
            aImagePos.setY( rPos.Y() + aTSSize.Height() + nImageSep );
        }
        else if (eImageAlign == ImageAlign::Center)
        {
            aImagePos.setX( rPos.X() + (aMax.Width()  - aImageSize.Width()) / 2 );
            aImagePos.setY( rPos.Y() + (aMax.Height() - aImageSize.Height()) / 2 );
            aTextPos.setX( rPos.X() + (aMax.Width()  - aTSSize.Width()) / 2 );
            aTextPos.setY( rPos.Y() + (aMax.Height() - aTSSize.Height()) / 2 );
        }
        aUnion = tools::Rectangle(aImagePos, aImageSize);
        aUnion.Union(tools::Rectangle(aTextPos, aTSSize));
    }

    // Now place the combination of text and image in the output area of the button
    // according to the window style (WinBits)
    tools::Long nXOffset = 0;
    tools::Long nYOffset = 0;

    if (nWinStyle & WB_CENTER)
    {
        nXOffset = (rSize.Width() - aUnion.GetWidth()) / 2;
    }
    else if (nWinStyle & WB_RIGHT)
    {
        nXOffset = rSize.Width() - aUnion.GetWidth();
    }

    if (nWinStyle & WB_VCENTER)
    {
        nYOffset = (rSize.Height() - aUnion.GetHeight()) / 2;
    }
    else if (nWinStyle & WB_BOTTOM)
    {
        nYOffset = rSize.Height() - aUnion.GetHeight();
    }

    // the top left corner should always be visible, so we don't allow negative offsets
    if (nXOffset < 0) nXOffset = 0;
    if (nYOffset < 0) nYOffset = 0;

    aImagePos.AdjustX(nXOffset );
    aImagePos.AdjustY(nYOffset );
    aTextPos.AdjustX(nXOffset );
    aTextPos.AdjustY(nYOffset );

    // set rPos and rSize to the union
    rSize = aUnion.GetSize();
    rPos.AdjustX(nXOffset );
    rPos.AdjustY(nYOffset );

    if (bHasSymbol)
    {
        if (mpButtonData->meSymbolAlign == SymbolAlign::RIGHT)
        {
            Point aRightPos(aTextPos.X() + aTextSize.Width() + aSymbolSize.Width() / 2, aTextPos.Y());
            *pSymbolRect = tools::Rectangle(aRightPos, aSymbolSize);
        }
        else
        {
            *pSymbolRect = tools::Rectangle(aTextPos, aSymbolSize);
            aTextPos.AdjustX(3 * nSymbolHeight / 2 );
        }
        if (mpButtonData->mbSmallSymbol)
        {
            nYOffset = (aUnion.GetHeight() - aSymbolSize.Height()) / 2;
            pSymbolRect->SetPosY(aTextPos.Y() + nYOffset);
        }
    }

    DrawImageFlags nStyle = DrawImageFlags::NONE;

    if (!IsEnabled())
    {
        nStyle |= DrawImageFlags::Disable;
    }

    if (IsZoom())
        pDev->DrawImage(aImagePos, aImageSize, *pImage, nStyle);
    else
        pDev->DrawImage(aImagePos, *pImage, nStyle);

    if (bDrawText)
    {
        const tools::Rectangle aTOutRect(aTextPos, aTextSize);
        ImplSetFocusRect(aTOutRect);
        DrawControlText(*pDev, aTOutRect, aText, nTextStyle, nullptr, nullptr, &aDeviceTextSize);
    }
    else
    {
        ImplSetFocusRect(tools::Rectangle(aImagePos, aImageSize));
    }
}

void Button::ImplSetFocusRect(const tools::Rectangle &rFocusRect)
{
    tools::Rectangle aFocusRect = rFocusRect;
    tools::Rectangle aOutputRect(Point(), GetOutputSizePixel());

    if (!aFocusRect.IsEmpty())
    {
        aFocusRect.AdjustLeft( -1 );
        aFocusRect.AdjustTop( -1 );
        aFocusRect.AdjustRight( 1 );
        aFocusRect.AdjustBottom( 1 );
    }

    if (aFocusRect.Left()   < aOutputRect.Left())
        aFocusRect.SetLeft( aOutputRect.Left() );
    if (aFocusRect.Top()    < aOutputRect.Top())
        aFocusRect.SetTop( aOutputRect.Top() );
    if (aFocusRect.Right()  > aOutputRect.Right())
        aFocusRect.SetRight( aOutputRect.Right() );
    if (aFocusRect.Bottom() > aOutputRect.Bottom())
        aFocusRect.SetBottom( aOutputRect.Bottom() );

    mpButtonData->maFocusRect = aFocusRect;
}

const tools::Rectangle& Button::ImplGetFocusRect() const
{
    return mpButtonData->maFocusRect;
}

DrawButtonFlags& Button::GetButtonState()
{
    return mpButtonData->mnButtonState;
}

DrawButtonFlags Button::GetButtonState() const
{
    return mpButtonData->mnButtonState;
}

void Button::ImplSetSymbolAlign( SymbolAlign eAlign )
{
    if ( mpButtonData->meSymbolAlign != eAlign )
    {
        mpButtonData->meSymbolAlign = eAlign;
        StateChanged( StateChangedType::Data );
    }
}

void Button::SetSmallSymbol()
{
    mpButtonData->mbSmallSymbol = true;
}

bool Button::IsSmallSymbol () const
{
    return mpButtonData->mbSmallSymbol;
}

bool Button::set_property(const OUString &rKey, const OUString &rValue)
{
    if (rKey == "image-position")
    {
        ImageAlign eAlign = ImageAlign::Left;
        if (rValue == "left")
            eAlign = ImageAlign::Left;
        else if (rValue == "right")
            eAlign = ImageAlign::Right;
        else if (rValue == "top")
            eAlign = ImageAlign::Top;
        else if (rValue == "bottom")
            eAlign = ImageAlign::Bottom;
        SetImageAlign(eAlign);
    }
    else if (rKey == "focus-on-click")
    {
        WinBits nBits = GetStyle();
        nBits &= ~WB_NOPOINTERFOCUS;
        if (!toBool(rValue))
            nBits |= WB_NOPOINTERFOCUS;
        SetStyle(nBits);
    }
    else
        return Control::set_property(rKey, rValue);
    return true;
}

void Button::statusChanged(const css::frame::FeatureStateEvent& rEvent)
{
    Enable(rEvent.IsEnabled);
}

FactoryFunction Button::GetUITestFactory() const
{
    return ButtonUIObject::create;
}

namespace
{

std::string_view symbolTypeName(SymbolType eSymbolType)
{
    switch (eSymbolType)
    {
        case SymbolType::DONTKNOW:         return "DONTKNOW";
        case SymbolType::IMAGE:            return "IMAGE";
        case SymbolType::ARROW_UP:         return "ARROW_UP";
        case SymbolType::ARROW_DOWN:       return "ARROW_DOWN";
        case SymbolType::ARROW_LEFT:       return "ARROW_LEFT";
        case SymbolType::ARROW_RIGHT:      return "ARROW_RIGHT";
        case SymbolType::SPIN_UP:          return "SPIN_UP";
        case SymbolType::SPIN_DOWN:        return "SPIN_DOWN";
        case SymbolType::SPIN_LEFT:        return "SPIN_LEFT";
        case SymbolType::SPIN_RIGHT:       return "SPIN_RIGHT";
        case SymbolType::FIRST:            return "FIRST";
        case SymbolType::LAST:             return "LAST";
        case SymbolType::PREV:             return "PREV";
        case SymbolType::NEXT:             return "NEXT";
        case SymbolType::PAGEUP:           return "PAGEUP";
        case SymbolType::PAGEDOWN:         return "PAGEDOWN";
        case SymbolType::PLAY:             return "PLAY";
        case SymbolType::STOP:             return "STOP";
        case SymbolType::CLOSE:            return "CLOSE";
        case SymbolType::CHECKMARK:        return "CHECKMARK";
        case SymbolType::RADIOCHECKMARK:   return "RADIOCHECKMARK";
        case SymbolType::FLOAT:            return "FLOAT";
        case SymbolType::DOCK:             return "DOCK";
        case SymbolType::HIDE:             return "HIDE";
        case SymbolType::HELP:             return "HELP";
        case SymbolType::PLUS:             return "PLUS";
    }

    return "UNKNOWN";
}

}

void Button::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
{
    Control::DumpAsPropertyTree(rJsonWriter);
    rJsonWriter.put("text", GetText());
    if (HasImage())
    {
        SvMemoryStream aOStm(6535, 6535);
        if(GraphicConverter::Export(aOStm, GetModeImage().GetBitmapEx(), ConvertDataFormat::PNG) == ERRCODE_NONE)
        {
            css::uno::Sequence<sal_Int8> aSeq( static_cast<sal_Int8 const *>(aOStm.GetData()), aOStm.Tell());
            OStringBuffer aBuffer("data:image/png;base64,");
            ::comphelper::Base64::encode(aBuffer, aSeq);
            rJsonWriter.put("image", aBuffer);
        }
    }

    if (GetStyle() & WB_DEFBUTTON)
        rJsonWriter.put("has_default"true);
}

void PushButton::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
{
    Button::DumpAsPropertyTree(rJsonWriter);
    if (GetSymbol() != SymbolType::DONTKNOW)
        rJsonWriter.put("symbol", symbolTypeName(GetSymbol()));
    if (isToggleButton())
        rJsonWriter.put("isToggle"true);
}

IMPL_STATIC_LINK( Button, dispatchCommandHandler, Button*, pButton, void )
{
    if (pButton == nullptr)
        return;

    comphelper::dispatchCommand(pButton->maCommand, uno::Sequence<beans::PropertyValue>());
}

void PushButton::ImplInitPushButtonData()
{
    mpWindowImpl->mbPushButton    = true;

    meSymbol        = SymbolType::DONTKNOW;
    meState         = TRISTATE_FALSE;
    mnDDStyle       = PushButtonDropdownStyle::NONE;
    mbIsActive    = false;
    mbPressed       = false;
    mbIsAction      = false;
}

namespace
{
    vcl::Window* getPreviousSibling(vcl::Window const *pParent)
    {
        return pParent ? pParent->GetWindow(GetWindowType::LastChild) : nullptr;
    }
}

void PushButton::ImplInit( vcl::Window* pParent, WinBits nStyle )
{
    nStyle = ImplInitStyle(getPreviousSibling(pParent), nStyle);
    Button::ImplInit( pParent, nStyle, nullptr );

    if ( nStyle & WB_NOLIGHTBORDER )
        GetButtonState() |= DrawButtonFlags::NoLightBorder;

    ImplInitSettings( true );
}

WinBits PushButton::ImplInitStyle( const vcl::Window* pPrevWindow, WinBits nStyle )
{
    if ( !(nStyle & WB_NOTABSTOP) )
        nStyle |= WB_TABSTOP;

    // if no alignment is given, default to "vertically centered". This is because since
    // #i26046#, we respect the vertical alignment flags (previously we didn't completely),
    // but we of course want to look as before when no vertical alignment is specified
    if ( ( nStyle & ( WB_TOP | WB_VCENTER | WB_BOTTOM ) ) == 0 )
        nStyle |= WB_VCENTER;

    if ( !(nStyle & WB_NOGROUP) &&
         (!pPrevWindow ||
          ((pPrevWindow->GetType() != WindowType::PUSHBUTTON  ) &&
           (pPrevWindow->GetType() != WindowType::OKBUTTON    ) &&
           (pPrevWindow->GetType() != WindowType::CANCELBUTTON) &&
           (pPrevWindow->GetType() != WindowType::HELPBUTTON  )) ) )
        nStyle |= WB_GROUP;
    return nStyle;
}

const vcl::Font& PushButton::GetCanonicalFont( const StyleSettings& _rStyle ) const
{
    return _rStyle.GetPushButtonFont();
}

const Color& PushButton::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
{
    return _rStyle.GetButtonTextColor();
}

void PushButton::ImplInitSettings( bool bBackground )
{
    Button::ImplInitSettings();

    if ( !bBackground )
        return;

    SetBackground();
    // #i38498#: do not check for GetParent()->IsChildTransparentModeEnabled()
    // otherwise the formcontrol button will be overdrawn due to ParentClipMode::NoClip
    // for radio and checkbox this is ok as they should appear transparent in documents
    if ( IsNativeControlSupported( ControlType::Pushbutton, ControlPart::Entire ) ||
         (GetStyle() & WB_FLATBUTTON) != 0 )
    {
        EnableChildTransparentMode();
        SetParentClipMode( ParentClipMode::NoClip );
        SetPaintTransparent( true );

        if ((GetStyle() & WB_FLATBUTTON) == 0)
            mpWindowImpl->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects;
        else
            mpWindowImpl->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRectsForFlatButtons;
    }
    else
    {
        EnableChildTransparentMode( false );
        SetParentClipMode();
        SetPaintTransparent( false );
    }
}

void PushButton::ImplDrawPushButtonFrame(vcl::RenderContext& rRenderContext,
                                         tools::Rectangle& rRect, DrawButtonFlags nStyle)
{
    if (!(GetStyle() & (WB_RECTSTYLE | WB_SMALLSTYLE)))
    {
        StyleSettings aStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
        if (IsControlBackground())
            aStyleSettings.Set3DColors(GetControlBackground());
    }

    DecorationView aDecoView(&rRenderContext);
    if (IsControlBackground())
    {
        AllSettings aSettings = rRenderContext.GetSettings();
        AllSettings aOldSettings = aSettings;
        StyleSettings aStyleSettings = aSettings.GetStyleSettings();
        if (nStyle & DrawButtonFlags::Highlight)
        {
            // with the custom background, native highlight do nothing, so code below mimic
            // native highlight by changing luminance
            Color controlBackgroundColorHighlighted = GetControlBackground();
            sal_uInt8 colorLuminance = controlBackgroundColorHighlighted.GetLuminance();
            if (colorLuminance < 205)
                controlBackgroundColorHighlighted.IncreaseLuminance(50);
            else
                controlBackgroundColorHighlighted.DecreaseLuminance(50);
            aStyleSettings.Set3DColors(controlBackgroundColorHighlighted);
        }
        else
            aStyleSettings.Set3DColors(GetControlBackground());
        aSettings.SetStyleSettings(aStyleSettings);

        // Call OutputDevice::SetSettings() explicitly, as rRenderContext may
        // be a vcl::Window in fact, and vcl::Window::SetSettings() will call
        // Invalidate(), which is a problem, since we're in Paint().
        rRenderContext.OutputDevice::SetSettings(aSettings);
        rRect = aDecoView.DrawButton(rRect, nStyle);
        rRenderContext.OutputDevice::SetSettings(aOldSettings);
    }
    else
        rRect = aDecoView.DrawButton(rRect, nStyle);
}

bool PushButton::ImplHitTestPushButton( vcl::Window const * pDev,
                                        const Point& rPos )
{
    tools::Rectangle   aTestRect( Point(), pDev->GetOutputSizePixel() );

    return aTestRect.Contains( rPos );
}

DrawTextFlags PushButton::ImplGetTextStyle( SystemTextColorFlags nSystemTextColorFlags ) const
{
    const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();

    DrawTextFlags nTextStyle = DrawTextFlags::Mnemonic | DrawTextFlags::MultiLine | DrawTextFlags::EndEllipsis;

    if ( ( rStyleSettings.GetOptions() & StyleSettingsOptions::Mono ) ||
         ( nSystemTextColorFlags & SystemTextColorFlags::Mono ) )
        nTextStyle |= DrawTextFlags::Mono;

    if ( GetStyle() & WB_WORDBREAK )
        nTextStyle |= DrawTextFlags::WordBreak;
    if ( GetStyle() & WB_NOLABEL )
        nTextStyle &= ~DrawTextFlags::Mnemonic;

    if ( GetStyle() & WB_LEFT )
        nTextStyle |= DrawTextFlags::Left;
    else if ( GetStyle() & WB_RIGHT )
        nTextStyle |= DrawTextFlags::Right;
    else
        nTextStyle |= DrawTextFlags::Center;

    if ( GetStyle() & WB_TOP )
        nTextStyle |= DrawTextFlags::Top;
    else if ( GetStyle() & WB_BOTTOM )
        nTextStyle |= DrawTextFlags::Bottom;
    else
        nTextStyle |= DrawTextFlags::VCenter;

    if ( !IsEnabled() )
        nTextStyle |= DrawTextFlags::Disable;

    return nTextStyle;
}

void PushButton::ImplDrawPushButtonContent(OutputDevice *pDev, SystemTextColorFlags nSystemTextColorFlags,
                                           const tools::Rectangle &rRect, bool bMenuBtnSep,
                                           DrawButtonFlags nButtonFlags)
{
    const StyleSettings &rStyleSettings = GetSettings().GetStyleSettings();
    tools::Rectangle aInRect = rRect;
    Color aColor;
    DrawTextFlags nTextStyle = ImplGetTextStyle(nSystemTextColorFlags);
    DrawSymbolFlags nStyle;

    if (aInRect.Right() < aInRect.Left() || aInRect.Bottom() < aInRect.Top())
        return;

    pDev->Push(vcl::PushFlags::CLIPREGION);
    pDev->IntersectClipRegion(aInRect);

    if (nSystemTextColorFlags & SystemTextColorFlags::Mono)
        aColor = COL_BLACK;

    else if (IsControlForeground())
        aColor = GetControlForeground();

    // Button types with possibly different text coloring are flat buttons and regular buttons. Regular buttons may be action
    // buttons and may have an additional default status. Moreover all buttons may have an additional pressed and rollover
    // (highlight) status. Pressed buttons are always in rollover status.

    else if (GetStyle() & WB_FLATBUTTON)
        if (nButtonFlags & DrawButtonFlags::Pressed)
            aColor = rStyleSettings.GetFlatButtonPressedRolloverTextColor();
        else if (nButtonFlags & DrawButtonFlags::Highlight)
            aColor = rStyleSettings.GetFlatButtonRolloverTextColor();
        else
            aColor = rStyleSettings.GetFlatButtonTextColor();
    else
        if (isAction() && (nButtonFlags & DrawButtonFlags::Default))
            if (nButtonFlags & DrawButtonFlags::Pressed)
                aColor = rStyleSettings.GetDefaultActionButtonPressedRolloverTextColor();
            else if (nButtonFlags & DrawButtonFlags::Highlight)
                aColor = rStyleSettings.GetDefaultActionButtonRolloverTextColor();
            else
                aColor = rStyleSettings.GetDefaultActionButtonTextColor();
        else if (isAction())
            if (nButtonFlags & DrawButtonFlags::Pressed)
                aColor = rStyleSettings.GetActionButtonPressedRolloverTextColor();
            else if (nButtonFlags & DrawButtonFlags::Highlight)
                aColor = rStyleSettings.GetActionButtonRolloverTextColor();
            else
                aColor = rStyleSettings.GetActionButtonTextColor();
        else if (nButtonFlags & DrawButtonFlags::Default)
            if (nButtonFlags & DrawButtonFlags::Pressed)
                aColor = rStyleSettings.GetDefaultButtonPressedRolloverTextColor();
            else if (nButtonFlags & DrawButtonFlags::Highlight)
                aColor = rStyleSettings.GetDefaultButtonRolloverTextColor();
            else
                aColor = rStyleSettings.GetDefaultButtonTextColor();
        else
            if (nButtonFlags & DrawButtonFlags::Pressed)
                aColor = rStyleSettings.GetButtonPressedRolloverTextColor();
            else if (nButtonFlags & DrawButtonFlags::Highlight)
                aColor = rStyleSettings.GetButtonRolloverTextColor();
            else
                aColor = rStyleSettings.GetButtonTextColor();

#if defined(MACOSX) || defined(IOS)
    // tdf#152486 These are the buttons in infobars where the infobar has a custom
    // background color and on these platforms the buttons blend with
    // their background.
    vcl::Window* pParent = GetParent();
    if (pParent->get_id() == "ExtraButton")
    {
        while (pParent && !pParent->IsControlBackground())
            pParent = pParent->GetParent();
        if (pParent)
        {
            if (aColor.IsBright() && !pParent->GetControlBackground().IsDark())
                aColor = COL_BLACK;
        }
    }
#endif

    pDev->SetTextColor(aColor);

    if ( IsEnabled() )
        nStyle = DrawSymbolFlags::NONE;
    else
        nStyle = DrawSymbolFlags::Disable;

    Size aSize = rRect.GetSize();
    Point aPos = rRect.TopLeft();

    sal_Int32 nImageSep = 1 + (pDev->GetTextHeight()-10)/2;
    if( nImageSep < 1 )
        nImageSep = 1;
    if ( mnDDStyle == PushButtonDropdownStyle::MenuButton ||
         mnDDStyle == PushButtonDropdownStyle::SplitMenuButton )
    {
        tools::Long nSeparatorX = 0;
        tools::Rectangle aSymbolRect = aInRect;

        // calculate symbol size
        tools::Long nSymbolSize    = pDev->GetTextHeight() / 2 + 1;
        if (nSymbolSize > aSize.Width() / 2)
            nSymbolSize = aSize.Width() / 2;

        nSeparatorX = aInRect.Right() - 2*nSymbolSize;

        // tdf#141761 Minimum width should be (1) Pixel, see comment
        // with same task number above for more info
        const tools::Long nWidthAdjust(2*nSymbolSize);
        aSize.setWidth(std::max(static_cast<tools::Long>(1), aSize.getWidth() - nWidthAdjust));

        // center symbol rectangle in the separated area
        aSymbolRect.AdjustRight( -(nSymbolSize/2) );
        aSymbolRect.SetLeft( aSymbolRect.Right() - nSymbolSize );

        ImplDrawAlignedImage( pDev, aPos, aSize, nImageSep,
                              nTextStyle, nullptr, true );

        tools::Long nDistance = (aSymbolRect.GetHeight() > 10) ? 2 : 1;
        DecorationView aDecoView( pDev );
        if( bMenuBtnSep && nSeparatorX > 0 )
        {
            Point aStartPt( nSeparatorX, aSymbolRect.Top()+nDistance );
            Point aEndPt( nSeparatorX, aSymbolRect.Bottom()-nDistance );
            aDecoView.DrawSeparator( aStartPt, aEndPt );
        }
        ImplSetSeparatorX( nSeparatorX );

        aDecoView.DrawSymbol( aSymbolRect, SymbolType::SPIN_DOWN, aColor, nStyle );

    }
    else
    {
        tools::Rectangle aSymbolRect;
        ImplDrawAlignedImage( pDev, aPos, aSize, nImageSep,
                              nTextStyle, IsSymbol() ? &aSymbolRect : nullptr, true );

        if ( IsSymbol() )
        {
            DecorationView aDecoView( pDev );
            aDecoView.DrawSymbol( aSymbolRect, meSymbol, aColor, nStyle );
        }
    }

    pDev->Pop();  // restore clipregion
}

void PushButton::ImplDrawPushButton(vcl::RenderContext& rRenderContext)
{
    HideFocus();

    DrawButtonFlags nButtonStyle = GetButtonState();
    Size aOutSz(GetOutputSizePixel());
    tools::Rectangle aRect(Point(), aOutSz);
    tools::Rectangle aInRect = aRect;
    bool bNativeOK = false;

    // adjust style if button should be rendered 'pressed'
    if (mbPressed || mbIsActive)
        nButtonStyle |= DrawButtonFlags::Pressed;

    if (GetStyle() & WB_FLATBUTTON)
        nButtonStyle |= DrawButtonFlags::Flat;

    // TODO: move this to Window class or make it a member !!!
    ControlType aCtrlType = ControlType::Generic;
    switch(GetParent()->GetType())
    {
        case WindowType::LISTBOX:
        case WindowType::MULTILISTBOX:
        case WindowType::TREELISTBOX:
            aCtrlType = ControlType::Listbox;
            break;

        case WindowType::COMBOBOX:
        case WindowType::PATTERNBOX:
        case WindowType::NUMERICBOX:
        case WindowType::METRICBOX:
        case WindowType::CURRENCYBOX:
        case WindowType::DATEBOX:
        case WindowType::TIMEBOX:
        case WindowType::LONGCURRENCYBOX:
            aCtrlType = ControlType::Combobox;
            break;
        default:
            break;
    }

    bool bDropDown = (IsSymbol() && (GetSymbol() == SymbolType::SPIN_DOWN) && GetText().isEmpty());

    if( bDropDown && (aCtrlType == ControlType::Combobox || aCtrlType == ControlType::Listbox))
    {
        if (GetParent()->IsNativeControlSupported(aCtrlType, ControlPart::Entire))
        {
            // skip painting if the button was already drawn by the theme
            if (aCtrlType == ControlType::Combobox)
            {
                Edit* pEdit = static_cast<Edit*>(GetParent());
                if (pEdit->ImplUseNativeBorder(rRenderContext, pEdit->GetStyle()))
                    bNativeOK = true;
            }
            else if (GetParent()->IsNativeControlSupported(aCtrlType, ControlPart::HasBackgroundTexture))
            {
                bNativeOK = true;
            }

            if (!bNativeOK && GetParent()->IsNativeControlSupported(aCtrlType, ControlPart::ButtonDown))
            {
                // let the theme draw it, note we then need support
                // for ControlType::Listbox/ControlPart::ButtonDown and ControlType::Combobox/ControlPart::ButtonDown

                ImplControlValue aControlValue;
                ControlState nState = ControlState::NONE;

                if (mbPressed || mbIsActive)
                    nState |= ControlState::PRESSED;
                if (GetButtonState() & DrawButtonFlags::Pressed)
                    nState |= ControlState::PRESSED;
                if (HasFocus())
                    nState |= ControlState::FOCUSED;
                if (GetButtonState() & DrawButtonFlags::Default)
                    nState |= ControlState::DEFAULT;
                if (Window::IsEnabled())
                    nState |= ControlState::ENABLED;

                if (IsMouseOver() && aInRect.Contains(GetPointerPosPixel()))
                    nState |= ControlState::ROLLOVER;

                if ( IsMouseOver() && aInRect.Contains(GetPointerPosPixel()) && mbIsActive)
                {
                    nState |= ControlState::ROLLOVER;
                    nButtonStyle &= ~DrawButtonFlags::Pressed;
                }

                bNativeOK = rRenderContext.DrawNativeControl(aCtrlType, ControlPart::ButtonDown, aInRect, nState,
                                                             aControlValue, OUString());
            }
        }
    }

    if (bNativeOK)
        return;

    bool bRollOver = (IsMouseOver() && aInRect.Contains(GetPointerPosPixel()));
    if (bRollOver)
        nButtonStyle |= DrawButtonFlags::Highlight;
    bool bDrawMenuSep = mnDDStyle == PushButtonDropdownStyle::SplitMenuButton;
    if (GetStyle() & WB_FLATBUTTON)
    {
        if (!bRollOver && !HasFocus())
            bDrawMenuSep = false;
    }
    // tdf#123175 if there is a custom control bg set, draw the button without outsourcing to the NWF
    bNativeOK = !IsControlBackground() && rRenderContext.IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Entire);
    if (bNativeOK)
    {
        PushButtonValue aControlValue;
        aControlValue.mbIsAction = isAction();

        tools::Rectangle aCtrlRegion(aInRect);
        ControlState nState = ControlState::NONE;

        if (mbPressed || IsChecked() || mbIsActive)
        {
            nState |= ControlState::PRESSED;
            nButtonStyle |= DrawButtonFlags::Pressed;
        }
        if (GetButtonState() & DrawButtonFlags::Pressed)
            nState |= ControlState::PRESSED;
        if (HasFocus())
            nState |= ControlState::FOCUSED;
        if (GetButtonState() & DrawButtonFlags::Default)
            nState |= ControlState::DEFAULT;
        if (Window::IsEnabled())
            nState |= ControlState::ENABLED;

        if (bRollOver || mbIsActive)
        {
            nButtonStyle |= DrawButtonFlags::Highlight;
            nState |= ControlState::ROLLOVER;
        }

        if (mbIsActive && bRollOver)
        {
            nState &= ~ControlState::PRESSED;
            nButtonStyle &= ~DrawButtonFlags::Pressed;
        }

        if (GetStyle() & WB_FLATBUTTON)
            aControlValue.m_bFlatButton = true;

        // draw frame into invisible window to have aInRect modified correctly
        // but do not shift the inner rect for pressed buttons (ie remove DrawButtonFlags::Pressed)
        // this assumes the theme has enough visual cues to signalize the button was pressed
        //Window aWin( this );
        //ImplDrawPushButtonFrame( &aWin, aInRect, nButtonStyle & ~DrawButtonFlags::Pressed );

        // looks better this way as symbols were displaced slightly using the above approach
        aInRect.AdjustTop(4 );
        aInRect.AdjustBottom( -4 );
        aInRect.AdjustLeft(4 );
        aInRect.AdjustRight( -4 );

        // prepare single line hint (needed on mac to decide between normal push button and
        // rectangular bevel button look)
        Size aFontSize(Application::GetSettings().GetStyleSettings().GetPushButtonFont().GetFontSize());
        aFontSize = rRenderContext.LogicToPixel(aFontSize, MapMode(MapUnit::MapPoint));
        Size aInRectSize(rRenderContext.LogicToPixel(Size(aInRect.GetWidth(), aInRect.GetHeight())));
        aControlValue.mbSingleLine = (aInRectSize.Height() < 2 * aFontSize.Height());

        if (!aControlValue.m_bFlatButton || (nState & ControlState::ROLLOVER) || (nState &&nbsp;ControlState::PRESSED)
            || (HasFocus() && mpWindowImpl->mbUseNativeFocus
                && !IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Focus)))
        {
            bNativeOK = rRenderContext.DrawNativeControl(ControlType::Pushbutton, ControlPart::Entire, aCtrlRegion, nState,
                                                         aControlValue, OUString() /*PushButton::GetText()*/);
        }
        else
        {
            bNativeOK = true;
        }

        // draw content using the same aInRect as non-native VCL would do
        ImplDrawPushButtonContent(&rRenderContext, SystemTextColorFlags::NONE,
                                  aInRect, bDrawMenuSep, nButtonStyle);

        if (HasFocus())
            ShowFocus(ImplGetFocusRect());
    }

    if (bNativeOK)
        return;

    // draw PushButtonFrame, aInRect has content size afterwards
    if (GetStyle() & WB_FLATBUTTON)
    {
        tools::Rectangle aTempRect(aInRect);
        ImplDrawPushButtonFrame(rRenderContext, aTempRect, nButtonStyle);
        aInRect.AdjustLeft(2 );
        aInRect.AdjustTop(2 );
        aInRect.AdjustRight( -2 );
        aInRect.AdjustBottom( -2 );
    }
    else
    {
        ImplDrawPushButtonFrame(rRenderContext, aInRect, nButtonStyle);
    }

    // draw content
    ImplDrawPushButtonContent(&rRenderContext, SystemTextColorFlags::NONE, aInRect, bDrawMenuSep, nButtonStyle);

    if (HasFocus())
    {
        ShowFocus(ImplGetFocusRect());
    }
}

void PushButton::ImplSetDefButton( bool bSet )
{
    Size aSize( GetSizePixel() );
    Point aPos( GetPosPixel() );
    int dLeft(0), dRight(0), dTop(0), dBottom(0);
    bool bSetPos = false;

    if ( IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Entire) )
    {
        tools::Rectangle aBound, aCont;
        tools::Rectangle aCtrlRegion( 0, 0, 80, 20 ); // use a constant size to avoid accumulating
                                             // will not work if the theme has dynamic adornment sizes
        ImplControlValue aControlValue;

        // get native size of a 'default' button
        // and adjust the VCL button if more space for adornment is required
        if( GetNativeControlRegion( ControlType::Pushbutton, ControlPart::Entire, aCtrlRegion,
                                    ControlState::DEFAULT|ControlState::ENABLED,
                                    aControlValue,
                                    aBound, aCont ) )
        {
            dLeft = aCont.Left() - aBound.Left();
            dTop = aCont.Top() - aBound.Top();
            dRight = aBound.Right() - aCont.Right();
            dBottom = aBound.Bottom() - aCont.Bottom();
            bSetPos = dLeft || dTop || dRight || dBottom;
        }
    }

    if ( bSet )
    {
        if( !(GetButtonState() & DrawButtonFlags::Default) && bSetPos )
        {
            // adjust pos/size when toggling from non-default to default
            aPos.Move(-dLeft, -dTop);
            aSize.AdjustWidth(dLeft + dRight );
            aSize.AdjustHeight(dTop + dBottom );
        }
        GetButtonState() |= DrawButtonFlags::Default;
    }
    else
    {
        if( (GetButtonState() & DrawButtonFlags::Default) && bSetPos )
        {
            // adjust pos/size when toggling from default to non-default
            aPos.Move(dLeft, dTop);
            aSize.AdjustWidth( -(dLeft + dRight) );
            aSize.AdjustHeight( -(dTop + dBottom) );
        }
        GetButtonState() &= ~DrawButtonFlags::Default;
    }
    if( bSetPos )
        setPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height() );

    Invalidate();
}

bool PushButton::ImplIsDefButton() const
{
    return bool(GetButtonState() & DrawButtonFlags::Default);
}

PushButton::PushButton( WindowType nType ) :
    Button( nType )
{
    ImplInitPushButtonData();
}

PushButton::PushButton( vcl::Window* pParent, WinBits nStyle ) :
    Button( WindowType::PUSHBUTTON )
{
    ImplInitPushButtonData();
    ImplInit( pParent, nStyle );
}

css::uno::Reference<css::accessibility::XAccessible> PushButton::CreateAccessible()
{
    return new VCLXAccessibleButton(this);
}

void PushButton::MouseButtonDown( const MouseEvent& rMEvt )
{
    if ( !(rMEvt.IsLeft() &&
         ImplHitTestPushButton( this, rMEvt.GetPosPixel() )) )
        return;

    StartTrackingFlags nTrackFlags = StartTrackingFlags::NONE;

    if ( ( GetStyle() & WB_REPEAT ) &&
         ! ( GetStyle() & WB_TOGGLE ) )
        nTrackFlags |= StartTrackingFlags::ButtonRepeat;

    GetButtonState() |= DrawButtonFlags::Pressed;
    Invalidate();
    StartTracking( nTrackFlags );

    if ( nTrackFlags & StartTrackingFlags::ButtonRepeat )
        Click();
}

void PushButton::Tracking( const TrackingEvent& rTEvt )
{
    if ( rTEvt.IsTrackingEnded() )
    {
        if ( GetButtonState() & DrawButtonFlags::Pressed )
        {
            if ( !(GetStyle() & WB_NOPOINTERFOCUS) && !rTEvt.IsTrackingCanceled() )
                GrabFocus();

            if ( GetStyle() & WB_TOGGLE )
            {
                // Don't toggle, when aborted
                if ( !rTEvt.IsTrackingCanceled() )
                {
                    if ( IsChecked() )
                    {
                        Check( false );
                        GetButtonState() &= ~DrawButtonFlags::Pressed;
                    }
                    else
                        Check();
                }
            }
            else
                GetButtonState() &= ~DrawButtonFlags::Pressed;

            Invalidate();

            // do not call Click handler if aborted
            if ( !rTEvt.IsTrackingCanceled() )
            {
                if ( ! ( GetStyle() & WB_REPEAT ) || ( GetStyle() & WB_TOGGLE ) )
                    Click();
            }
        }
    }
    else
    {
        if ( ImplHitTestPushButton( this, rTEvt.GetMouseEvent().GetPosPixel() ) )
        {
            if ( GetButtonState() & DrawButtonFlags::Pressed )
            {
                if ( rTEvt.IsTrackingRepeat() && (GetStyle() & WB_REPEAT) &&
                     ! ( GetStyle() & WB_TOGGLE ) )
                    Click();
            }
            else
            {
                GetButtonState() |= DrawButtonFlags::Pressed;
                Invalidate();
            }
        }
        else
        {
            if ( GetButtonState() & DrawButtonFlags::Pressed )
            {
                GetButtonState() &= ~DrawButtonFlags::Pressed;
                Invalidate();
            }
        }
    }
}

void PushButton::KeyInput( const KeyEvent& rKEvt )
{
    vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();

    if ( !aKeyCode.GetModifier() &&
         ((aKeyCode.GetCode() == KEY_RETURN) || (aKeyCode.GetCode() == KEY_SPACE)) )
    {
        if ( !(GetButtonState() & DrawButtonFlags::Pressed) )
        {
            GetButtonState() |= DrawButtonFlags::Pressed;
            Invalidate();
        }

        if ( ( GetStyle() & WB_REPEAT ) &&
             ! ( GetStyle() & WB_TOGGLE ) )
            Click();
    }
    else if ( (GetButtonState() & DrawButtonFlags::Pressed) && (aKeyCode.GetCode() == KEY_ESCAPE) )
    {
        GetButtonState() &= ~DrawButtonFlags::Pressed;
        Invalidate();
    }
    else
        Button::KeyInput( rKEvt );
}

void PushButton::KeyUp( const KeyEvent& rKEvt )
{
    vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();

    if ( (GetButtonState() & DrawButtonFlags::Pressed) &&
         ((aKeyCode.GetCode() == KEY_RETURN) || (aKeyCode.GetCode() == KEY_SPACE)) )
    {
        if ( GetStyle() & WB_TOGGLE )
        {
            if ( IsChecked() )
            {
                Check( false );
                GetButtonState() &= ~DrawButtonFlags::Pressed;
            }
            else
                Check();

            Toggle();
        }
        else
            GetButtonState() &= ~DrawButtonFlags::Pressed;

        Invalidate();

        if ( !( GetStyle() & WB_REPEAT ) || ( GetStyle() & WB_TOGGLE ) )
            Click();
    }
    else
        Button::KeyUp( rKEvt );
}

void PushButton::FillLayoutData() const
{
    mxLayoutData.emplace();
    const_cast<PushButton*>(this)->Invalidate();
}

void PushButton::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
{
    const Image& rCustomButtonImage = GetCustomButtonImage();
    if (!!rCustomButtonImage)
    {
        rRenderContext.DrawImage(Point(0, 0), rCustomButtonImage);
        return;
    }
    ImplDrawPushButton(rRenderContext);
}

void PushButton::Draw( OutputDevice* pDev, const Point& rPos,
                       SystemTextColorFlags nFlags )
{
    Point       aPos  = pDev->LogicToPixel( rPos );
    Size        aSize = GetSizePixel();
    tools::Rectangle   aRect( aPos, aSize );
    vcl::Font   aFont = GetDrawPixelFont( pDev );

    pDev->Push();
    pDev->SetMapMode();
    pDev->SetFont( aFont );

    std::optional<StyleSettings> oOrigDevStyleSettings;

    if ( nFlags & SystemTextColorFlags::Mono )
    {
        pDev->SetTextColor( COL_BLACK );
    }
    else
    {
        pDev->SetTextColor( GetTextColor() );
        // DecoView uses the FaceColor...
        AllSettings aSettings = pDev->GetSettings();
        StyleSettings aStyleSettings = aSettings.GetStyleSettings();
        oOrigDevStyleSettings = aStyleSettings;
        if ( IsControlBackground() )
            aStyleSettings.SetFaceColor( GetControlBackground() );
        else
            aStyleSettings.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() );
        aSettings.SetStyleSettings( aStyleSettings );
        pDev->OutputDevice::SetSettings( aSettings );
    }
    pDev->SetTextFillColor();

    DecorationView aDecoView( pDev );
    DrawButtonFlags nButtonStyle = DrawButtonFlags::NONE;
    if ( nFlags & SystemTextColorFlags::Mono )
        nButtonStyle |= DrawButtonFlags::Mono;
    if ( IsChecked() )
        nButtonStyle |= DrawButtonFlags::Checked;
    aRect = aDecoView.DrawButton( aRect, nButtonStyle );

    ImplDrawPushButtonContent( pDev, nFlags, aRect, true, nButtonStyle );

    // restore original settings (which are not affected by Push/Pop) after
    // finished drawing
    if (oOrigDevStyleSettings)
    {
        AllSettings aSettings = pDev->GetSettings();
        aSettings.SetStyleSettings(*oOrigDevStyleSettings);
        pDev->OutputDevice::SetSettings( aSettings );
    }

    pDev->Pop();
}

void PushButton::Resize()
{
    Control::Resize();
    Invalidate();
}

void PushButton::GetFocus()
{
    ShowFocus( ImplGetFocusRect() );
    SetInputContext( InputContext( GetFont() ) );
    Button::GetFocus();
}

void PushButton::LoseFocus()
{
    EndSelection();
    HideFocus();
    Button::LoseFocus();
}

void PushButton::StateChanged( StateChangedType nType )
{
    Button::StateChanged( nType );

    if ( (nType == StateChangedType::Enable) ||
         (nType == StateChangedType::Text) ||
         (nType == StateChangedType::Data) ||
         (nType == StateChangedType::State) ||
         (nType == StateChangedType::UpdateMode) )
    {
        if ( IsReallyVisible() && IsUpdateMode() )
            Invalidate();
    }
    else if ( nType == StateChangedType::Style )
    {
        SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev ), GetStyle() ) );

        bool bIsDefButton = ( GetStyle() & WB_DEFBUTTON ) != 0;
        bool bWasDefButton = ( GetPrevStyle() & WB_DEFBUTTON ) != 0;
        if ( bIsDefButton != bWasDefButton )
            ImplSetDefButton( bIsDefButton );

        if ( IsReallyVisible() && IsUpdateMode() )
        {
            if ( (GetPrevStyle() & PUSHBUTTON_VIEW_STYLE) !=
                 (GetStyle() & PUSHBUTTON_VIEW_STYLE) )
                Invalidate();
        }
    }
    else if ( (nType == StateChangedType::Zoom) ||
              (nType == StateChangedType::ControlFont) )
    {
        ImplInitSettings( false );
        Invalidate();
    }
    else if ( nType == StateChangedType::ControlForeground )
    {
        ImplInitSettings( false );
        Invalidate();
    }
    else if ( nType == StateChangedType::ControlBackground )
    {
        ImplInitSettings( true );
        Invalidate();
    }
}

void PushButton::DataChanged( const DataChangedEvent& rDCEvt )
{
    Button::DataChanged( rDCEvt );

    if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
         (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
         ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
          (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
    {
        ImplInitSettings( true );
        Invalidate();
    }
}

bool PushButton::PreNotify( NotifyEvent& rNEvt )
{
    if( rNEvt.GetType() == NotifyEventType::MOUSEMOVE )
    {
        const MouseEvent* pMouseEvt = rNEvt.GetMouseEvent();
        if( pMouseEvt && (pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow()) )
        {
            // trigger redraw as mouse over state has changed

            // TODO: move this to Window class or make it a member !!!
            ControlType aCtrlType = ControlType::Generic;
            switch( GetParent()->GetType() )
            {
                case WindowType::LISTBOX:
                case WindowType::MULTILISTBOX:
                case WindowType::TREELISTBOX:
                    aCtrlType = ControlType::Listbox;
                    break;

                case WindowType::COMBOBOX:
                case WindowType::PATTERNBOX:
                case WindowType::NUMERICBOX:
                case WindowType::METRICBOX:
                case WindowType::CURRENCYBOX:
                case WindowType::DATEBOX:
                case WindowType::TIMEBOX:
                case WindowType::LONGCURRENCYBOX:
                    aCtrlType = ControlType::Combobox;
                    break;
                default:
                    break;
            }

            bool bDropDown = ( IsSymbol() && (GetSymbol()==SymbolType::SPIN_DOWN) && GetText().isEmpty() );

            if( bDropDown && GetParent()->IsNativeControlSupported( aCtrlType, ControlPart::Entire) &&
                   !GetParent()->IsNativeControlSupported( aCtrlType, ControlPart::ButtonDown) )
            {
                vcl::Window *pBorder = GetParent()->GetWindow( GetWindowType::Border );
                if(aCtrlType == ControlType::Combobox)
                {
                    // only paint the button part to avoid flickering of the combobox text
                    tools::Rectangle aClipRect( Point(), GetOutputSizePixel() );
                    aClipRect.SetPos(pBorder->ScreenToOutputPixel(OutputToScreenPixel(aClipRect.TopLeft())));
                    pBorder->Invalidate( aClipRect );
                }
                else
                {
                    pBorder->Invalidate( InvalidateFlags::NoErase );
                }
            }
            else if( (GetStyle() & WB_FLATBUTTON) ||
                     IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Entire) )
            {
                Invalidate();
            }
        }
    }

    return Button::PreNotify(rNEvt);
}

void PushButton::Toggle()
{
    ImplCallEventListenersAndHandler( VclEventId::PushbuttonToggle, nullptr );
}

void PushButton::SetSymbol( SymbolType eSymbol )
{
    if ( meSymbol != eSymbol )
    {
        meSymbol = eSymbol;
        CompatStateChanged( StateChangedType::Data );
    }
}

void PushButton::SetSymbolAlign( SymbolAlign eAlign )
{
    ImplSetSymbolAlign( eAlign );
}

void PushButton::SetDropDown( PushButtonDropdownStyle nStyle )
{
    if ( mnDDStyle != nStyle )
    {
        mnDDStyle = nStyle;
        CompatStateChanged( StateChangedType::Data );
    }
}

void PushButton::SetState( TriState eState )
{
    if ( meState == eState )
        return;

    meState = eState;
    if ( meState == TRISTATE_FALSE )
        GetButtonState() &= ~DrawButtonFlags(DrawButtonFlags::Checked | DrawButtonFlags::DontKnow);
    else if ( meState == TRISTATE_TRUE )
    {
        GetButtonState() &= ~DrawButtonFlags::DontKnow;
        GetButtonState() |= DrawButtonFlags::Checked;
    }
    else // TRISTATE_INDET
    {
        GetButtonState() &= ~DrawButtonFlags::Checked;
        GetButtonState() |= DrawButtonFlags::DontKnow;
    }

    CompatStateChanged( StateChangedType::State );
    Toggle();
}

void PushButton::statusChanged(const css::frame::FeatureStateEvent& rEvent)
{
    Button::statusChanged(rEvent);
    if (rEvent.State.has<bool>())
        SetPressed(rEvent.State.get<bool>());
}

void PushButton::SetPressed( bool bPressed )
{
    if ( mbPressed != bPressed )
    {
        mbPressed = bPressed;
        CompatStateChanged( StateChangedType::Data );
    }
}

void PushButton::EndSelection()
{
    EndTracking( TrackingEventFlags::Cancel );
    if ( !isDisposed() &&
         GetButtonState() & DrawButtonFlags::Pressed )
    {
        GetButtonState() &= ~DrawButtonFlags::Pressed;
        if ( !mbPressed )
            Invalidate();
    }
}

Size PushButton::CalcMinimumSize() const
{
    Size aSize;

    if ( IsSymbol() )
    {
        if ( IsSmallSymbol ())
            aSize = Size( 16, 12 );
        else
            aSize = Size( 26, 24 );
    }
    else if ( Button::HasImage() )
        aSize = GetModeImage().GetSizePixel();
    if( mnDDStyle == PushButtonDropdownStyle::MenuButton ||
        mnDDStyle == PushButtonDropdownStyle::SplitMenuButton )
    {
        tools::Long nSymbolSize = GetTextHeight() / 2 + 1;
        aSize.AdjustWidth(2*nSymbolSize );
    }
    if (!PushButton::GetText().isEmpty())
    {
        Size textSize = GetTextRect( tools::Rectangle( Point(), Size( 0x7fffffff, 0x7fffffff ) ),
                                     PushButton::GetText(), ImplGetTextStyle( SystemTextColorFlags::NONE ) ).GetSize();

        tools::Long nTextHeight = textSize.Height() * 1.15;

        ImageAlign eImageAlign = GetImageAlign();
        // tdf#142337 only considering the simple top/bottom/left/right possibilities
        if (eImageAlign == ImageAlign::Top || eImageAlign == ImageAlign::Bottom)
        {
            aSize.AdjustHeight(nTextHeight);
            aSize.setWidth(std::max(aSize.Width(), textSize.Width()));
        }
        else
        {
            aSize.AdjustWidth(textSize.Width());
            aSize.setHeight(std::max(aSize.Height(), nTextHeight));
        }
    }

    // cf. ImplDrawPushButton ...
    if( (GetStyle() & WB_SMALLSTYLE) == 0 )
    {
        aSize.AdjustWidth(24 );
        aSize.AdjustHeight(12 );
    }

    return CalcWindowSize( aSize );
}

Size PushButton::GetOptimalSize() const
{
    return CalcMinimumSize();
}

bool PushButton::set_property(const OUString &rKey, const OUString &rValue)
{
    if (rKey == "has-default")
    {
        WinBits nBits = GetStyle();
        nBits &= ~WB_DEFBUTTON;
        if (toBool(rValue))
            nBits |= WB_DEFBUTTON;
        SetStyle(nBits);
    }
    else
        return Button::set_property(rKey, rValue);
    return true;
}

void PushButton::ShowFocus(const tools::Rectangle& rRect)
{
    if (IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Focus))
    {
        PushButtonValue aControlValue;
        aControlValue.mbIsAction = isAction();
        tools::Rectangle aInRect(Point(), GetOutputSizePixel());
        GetOutDev()->DrawNativeControl(ControlType::Pushbutton, ControlPart::Focus, aInRect,
                                       ControlState::FOCUSED, aControlValue, OUString());
    }
    Button::ShowFocus(rRect);
}

void OKButton::ImplInit( vcl::Window* pParent, WinBits nStyle )
{
    set_id(u"ok"_ustr);
    PushButton::ImplInit( pParent, nStyle );

    SetText( GetStandardText( StandardButtonType::OK ) );
}

OKButton::OKButton( vcl::Window* pParent, WinBits nStyle ) :
    PushButton( WindowType::OKBUTTON )
{
    ImplInit( pParent, nStyle );
}

void OKButton::Click()
{
    // close parent if no link set
    if ( !GetClickHdl() )
    {
        vcl::Window* pParent = getNonLayoutParent(this);
        if ( pParent->IsSystemWindow() )
        {
            if ( pParent->IsDialog() )
            {
                VclPtr<Dialog> xParent( static_cast<Dialog*>(pParent) );
                if ( xParent->IsInExecute() )
                    xParent->EndDialog( RET_OK );
                // prevent recursive calls
                else if ( !xParent->IsInClose() )
                {
                    if ( pParent->GetStyle() & WB_CLOSEABLE )
                        xParent->Close();
                }
            }
            else
            {
                if ( pParent->GetStyle() & WB_CLOSEABLE )
                    static_cast<SystemWindow*>(pParent)->Close();
            }
        }
    }
    else
    {
        PushButton::Click();
    }
}

void CancelButton::ImplInit( vcl::Window* pParent, WinBits nStyle )
{
    set_id(u"cancel"_ustr);
    PushButton::ImplInit( pParent, nStyle );

    SetText( GetStandardText( StandardButtonType::Cancel ) );
}

CancelButton::CancelButton( vcl::Window* pParent, WinBits nStyle ) :
    PushButton( WindowType::CANCELBUTTON )
{
    ImplInit( pParent, nStyle );
}

void CancelButton::Click()
{
    // close parent if link not set
    if ( !GetClickHdl() )
    {
        vcl::Window* pParent = getNonLayoutParent(this);
        if ( pParent->IsSystemWindow() )
        {
            if ( pParent->IsDialog() )
            {
                Dialog* pDialog = static_cast<Dialog*>(pParent);
                if (pDialog->IsInExecute())
                    pDialog->EndDialog();
                // prevent recursive calls
                else if (!pDialog->IsInClose())
                {
                    if ( pParent->GetStyle() & WB_CLOSEABLE )
                        pDialog->Close();
                }
            }
            else
            {
                if ( pParent->GetStyle() & WB_CLOSEABLE )
                    static_cast<SystemWindow*>(pParent)->Close();
            }
        }
    }
    else
    {
        PushButton::Click();
    }
}

CloseButton::CloseButton( vcl::Window* pParent )
    : CancelButton(pParent, 0)
{
    SetText( GetStandardText( StandardButtonType::Close ) );
}

void HelpButton::ImplInit( vcl::Window* pParent, WinBits nStyle )
{
    set_id(u"help"_ustr);
    PushButton::ImplInit( pParent, nStyle | WB_NOPOINTERFOCUS );

    SetText( GetStandardText( StandardButtonType::Help ) );
}

HelpButton::HelpButton( vcl::Window* pParent, WinBits nStyle ) :
    PushButton( WindowType::HELPBUTTON )
{
    ImplInit( pParent, nStyle );
}

void HelpButton::Click()
{
    // trigger help if no link set
    if ( !GetClickHdl() )
    {
        vcl::Window* pFocusWin = Application::GetFocusWindow();
        if ( !pFocusWin || comphelper::LibreOfficeKit::isActive() )
            pFocusWin = this;

        HelpEvent aEvt( pFocusWin->GetPointerPosPixel(), HelpEventMode::CONTEXT );
        pFocusWin->RequestHelp( aEvt );
    }
    PushButton::Click();
}

void HelpButton::StateChanged( StateChangedType nStateChange )
{
    // Hide when we have no help URL.
    if (comphelper::LibreOfficeKit::isActive() &&
        officecfg::Office::Common::Help::HelpRootURL::get().isEmpty())
        Hide();
    else
        PushButton::StateChanged(nStateChange);
}

void RadioButton::ImplInitRadioButtonData()
{
    mbChecked       = false;
    mbRadioCheck    = true;
    mbStateChanged  = false;
}

void RadioButton::ImplInit( vcl::Window* pParent, WinBits nStyle )
{
    nStyle = ImplInitStyle(getPreviousSibling(pParent), nStyle);
    Button::ImplInit( pParent, nStyle, nullptr );

    ImplInitSettings( true );
}

WinBits RadioButton::ImplInitStyle( const vcl::Window* pPrevWindow, WinBits nStyle ) const
{
    if ( !(nStyle & WB_NOGROUP) &&
         (!pPrevWindow || (pPrevWindow->GetType() != WindowType::RADIOBUTTON)) )
        nStyle |= WB_GROUP;
    if ( !(nStyle & WB_NOTABSTOP) )
    {
        if ( IsChecked() )
            nStyle |= WB_TABSTOP;
        else
            nStyle &= ~WB_TABSTOP;
    }

    return nStyle;
}

const vcl::Font& RadioButton::GetCanonicalFont( const StyleSettings& _rStyle ) const
{
    return _rStyle.GetRadioCheckFont();
}

const Color& RadioButton::GetCanonicalTextColor( const StyleSettings& _rStyle const
{
    return _rStyle.GetRadioCheckTextColor();
}

void RadioButton::ImplInitSettings( bool bBackground )
{
    Button::ImplInitSettings();

    if ( !bBackground )
        return;

    vcl::Window* pParent = GetParent();
    if ( !IsControlBackground() &&
        (pParent->IsChildTransparentModeEnabled() || IsNativeControlSupported( ControlType::Radiobutton, ControlPart::Entire ) ) )
    {
        EnableChildTransparentMode();
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=93 H=97 G=94

¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.30Angebot  Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können  ¤

*Eine klare Vorstellung vom Zielzustand






Versionsinformation zu Columbo

Bemerkung:

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Anfrage:

Dauer der Verarbeitung:

Sekunden

sprechenden Kalenders