which benefits LOOL since we can delay creating the image until we know the dpi setting of the display we are going to write to. Achieved by perl -pi -w -e "s/\bImage\s*\(\s*BitmapEx\s*\((\w+)\s*\)\s*\)/Image\(\1\)/g" $( git grep -lw "BitmapEx" ) followed by git grep -nP '\bImage\s*\(\s*BitmapEx\s*\(' followed by commenting out the BitmapEx(OUString) constructor and seeing what needed adjusting. Change-Id: I3224e11937d720fa484b0d659d25673a9e809267 Reviewed-on: https://gerrit.libreoffice.org/64760 Tested-by: Jenkins Reviewed-by: Michael Meeks <michael.meeks@collabora.com>
3828 lines
121 KiB
C++
3828 lines
121 KiB
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/lineend.hxx>
|
|
#include <tools/poly.hxx>
|
|
|
|
#include <vcl/image.hxx>
|
|
#include <vcl/bitmap.hxx>
|
|
#include <vcl/bitmapex.hxx>
|
|
#include <vcl/builderfactory.hxx>
|
|
#include <vcl/decoview.hxx>
|
|
#include <vcl/event.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <vcl/dialog.hxx>
|
|
#include <vcl/fixed.hxx>
|
|
#include <vcl/button.hxx>
|
|
#include <vcl/salnativewidgets.hxx>
|
|
#include <vcl/edit.hxx>
|
|
#include <vcl/layout.hxx>
|
|
#include <vcl/vclstatuslistener.hxx>
|
|
#include <vcl/uitest/uiobject.hxx>
|
|
|
|
#include <strings.hrc>
|
|
#include <bitmaps.hlst>
|
|
#include <svdata.hxx>
|
|
#include <window.h>
|
|
#include <controldata.hxx>
|
|
#include <o3tl/make_unique.hxx>
|
|
#include <sal/log.hxx>
|
|
#include <osl/diagnose.h>
|
|
|
|
#include <comphelper/dispatchcommand.hxx>
|
|
|
|
|
|
using namespace css;
|
|
|
|
static 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;
|
|
static constexpr auto RADIOBUTTON_VIEW_STYLE = WB_3DLOOK |
|
|
WB_LEFT | WB_CENTER | WB_RIGHT |
|
|
WB_TOP | WB_VCENTER | WB_BOTTOM |
|
|
WB_WORDBREAK | WB_NOLABEL;
|
|
static 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;
|
|
long mnSeparatorX;
|
|
DrawButtonFlags mnButtonState;
|
|
bool mbSmallSymbol;
|
|
|
|
Image maImage;
|
|
ImageAlign meImageAlign;
|
|
SymbolAlign meSymbolAlign;
|
|
|
|
/** StatusListener. Updates the button as the slot state changes */
|
|
rtl::Reference<VclStatusListener<Button>> mpStatusListener;
|
|
};
|
|
|
|
ImplCommonButtonData::ImplCommonButtonData() : maFocusRect(), mnSeparatorX(0), mnButtonState(DrawButtonFlags::NONE),
|
|
mbSmallSymbol(false), maImage(), meImageAlign(ImageAlign::Top), meSymbolAlign(SymbolAlign::LEFT)
|
|
{
|
|
}
|
|
|
|
Button::Button( WindowType nType ) :
|
|
Control( nType ),
|
|
mpButtonData( o3tl::make_unique<ImplCommonButtonData>() )
|
|
{
|
|
}
|
|
|
|
Button::~Button()
|
|
{
|
|
disposeOnce();
|
|
}
|
|
|
|
void Button::dispose()
|
|
{
|
|
if (mpButtonData->mpStatusListener.is())
|
|
mpButtonData->mpStatusListener->dispose();
|
|
Control::dispose();
|
|
}
|
|
|
|
void Button::SetCommandHandler(const OUString& aCommand)
|
|
{
|
|
maCommand = aCommand;
|
|
SetClickHdl( LINK( this, Button, dispatchCommandHandler) );
|
|
|
|
mpButtonData->mpStatusListener = new VclStatusListener<Button>(this, aCommand);
|
|
mpButtonData->mpStatusListener->startListening();
|
|
}
|
|
|
|
void Button::Click()
|
|
{
|
|
ImplCallEventListenersAndHandler( VclEventId::ButtonClick, [this] () { maClickHdl.Call(this); } );
|
|
}
|
|
|
|
OUString Button::GetStandardText(StandardButtonType eButton)
|
|
{
|
|
static const char* aResIdAry[static_cast<int>(StandardButtonType::Count)] =
|
|
{
|
|
// http://lists.freedesktop.org/archives/libreoffice/2013-January/044513.html
|
|
// Under windows we don't want accelerators on ok/cancel but do on other
|
|
// buttons
|
|
#ifdef _WIN32
|
|
SV_BUTTONTEXT_OK_NOMNEMONIC,
|
|
SV_BUTTONTEXT_CANCEL_NOMNEMONIC,
|
|
#else
|
|
SV_BUTTONTEXT_OK,
|
|
SV_BUTTONTEXT_CANCEL,
|
|
#endif
|
|
SV_BUTTONTEXT_YES,
|
|
SV_BUTTONTEXT_NO,
|
|
SV_BUTTONTEXT_RETRY,
|
|
SV_BUTTONTEXT_HELP,
|
|
SV_BUTTONTEXT_CLOSE,
|
|
SV_BUTTONTEXT_MORE,
|
|
SV_BUTTONTEXT_IGNORE,
|
|
SV_BUTTONTEXT_ABORT,
|
|
SV_BUTTONTEXT_LESS,
|
|
};
|
|
|
|
return VclResId(aResIdAry[static_cast<sal_uInt16>(eButton)]);
|
|
}
|
|
|
|
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::SetFocusRect( const tools::Rectangle& rFocusRect )
|
|
{
|
|
ImplSetFocusRect( rFocusRect );
|
|
}
|
|
|
|
long Button::ImplGetSeparatorX() const
|
|
{
|
|
return mpButtonData->mnSeparatorX;
|
|
}
|
|
|
|
void Button::ImplSetSeparatorX( long nX )
|
|
{
|
|
mpButtonData->mnSeparatorX = nX;
|
|
}
|
|
|
|
DrawTextFlags Button::ImplGetTextStyle( WinBits nWinStyle, DrawFlags nDrawFlags )
|
|
{
|
|
const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
|
|
DrawTextFlags nTextStyle = FixedText::ImplGetTextStyle(nWinStyle & ~WB_DEFBUTTON);
|
|
|
|
if (!IsEnabled())
|
|
nTextStyle |= DrawTextFlags::Disable;
|
|
|
|
if ((nDrawFlags & DrawFlags::Mono) ||
|
|
(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
|
|
{
|
|
nTextStyle |= DrawTextFlags::Mono;
|
|
}
|
|
|
|
return nTextStyle;
|
|
}
|
|
|
|
void Button::ImplDrawAlignedImage(OutputDevice* pDev, Point& rPos,
|
|
Size& rSize,
|
|
sal_uLong nImageSep,
|
|
DrawTextFlags nTextStyle, tools::Rectangle *pSymbolRect,
|
|
bool bAddImageSep)
|
|
{
|
|
OUString aText(GetText());
|
|
bool bDrawImage = HasImage() && ! (ImplGetButtonState() & DrawButtonFlags::NoImage);
|
|
bool bDrawText = !aText.isEmpty() && ! (ImplGetButtonState() & DrawButtonFlags::NoText);
|
|
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);
|
|
|
|
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;
|
|
Size aMax;
|
|
Point aImagePos = rPos;
|
|
Point aTextPos = rPos;
|
|
tools::Rectangle aUnion = tools::Rectangle(aImagePos, aImageSize);
|
|
tools::Rectangle aSymbol;
|
|
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 = tools::Rectangle(Point(), rSize);
|
|
Size aTSSize;
|
|
|
|
if (bHasSymbol)
|
|
{
|
|
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)
|
|
{
|
|
long nDiff = (aImageSize.Height() - aTextSize.Height()) / 3;
|
|
if (nDiff > 0)
|
|
nImageSep += nDiff;
|
|
}
|
|
}
|
|
|
|
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)
|
|
long nXOffset = 0;
|
|
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 = Point(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->setY(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 = tools::Rectangle(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::ImplGetButtonState()
|
|
{
|
|
return mpButtonData->mnButtonState;
|
|
}
|
|
|
|
DrawButtonFlags Button::ImplGetButtonState() 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;
|
|
}
|
|
|
|
void Button::EnableImageDisplay( bool bEnable )
|
|
{
|
|
if( bEnable )
|
|
mpButtonData->mnButtonState &= ~DrawButtonFlags::NoImage;
|
|
else
|
|
mpButtonData->mnButtonState |= DrawButtonFlags::NoImage;
|
|
}
|
|
|
|
void Button::EnableTextDisplay( bool bEnable )
|
|
{
|
|
if( bEnable )
|
|
mpButtonData->mnButtonState &= ~DrawButtonFlags::NoText;
|
|
else
|
|
mpButtonData->mnButtonState |= DrawButtonFlags::NoText;
|
|
}
|
|
|
|
bool Button::IsSmallSymbol () const
|
|
{
|
|
return mpButtonData->mbSmallSymbol;
|
|
}
|
|
|
|
bool Button::set_property(const OString &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;
|
|
}
|
|
|
|
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 )
|
|
ImplGetButtonState() |= 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 )
|
|
{
|
|
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();
|
|
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.IsInside( rPos );
|
|
}
|
|
|
|
DrawTextFlags PushButton::ImplGetTextStyle( DrawFlags nDrawFlags ) const
|
|
{
|
|
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
|
|
|
|
DrawTextFlags nTextStyle = DrawTextFlags::Mnemonic | DrawTextFlags::MultiLine | DrawTextFlags::EndEllipsis;
|
|
|
|
if ( ( rStyleSettings.GetOptions() & StyleSettingsOptions::Mono ) ||
|
|
( nDrawFlags & DrawFlags::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;
|
|
}
|
|
|
|
static void ImplDrawBtnDropDownArrow( OutputDevice* pDev,
|
|
long nX, long nY,
|
|
Color const & rColor, bool bBlack )
|
|
{
|
|
Color aOldLineColor = pDev->GetLineColor();
|
|
Color aOldFillColor = pDev->GetFillColor();
|
|
|
|
pDev->SetLineColor();
|
|
if ( bBlack )
|
|
pDev->SetFillColor( COL_BLACK );
|
|
else
|
|
pDev->SetFillColor( rColor );
|
|
pDev->DrawRect( tools::Rectangle( nX+0, nY+0, nX+6, nY+0 ) );
|
|
pDev->DrawRect( tools::Rectangle( nX+1, nY+1, nX+5, nY+1 ) );
|
|
pDev->DrawRect( tools::Rectangle( nX+2, nY+2, nX+4, nY+2 ) );
|
|
pDev->DrawRect( tools::Rectangle( nX+3, nY+3, nX+3, nY+3 ) );
|
|
if ( bBlack )
|
|
{
|
|
pDev->SetFillColor( rColor );
|
|
pDev->DrawRect( tools::Rectangle( nX+2, nY+1, nX+4, nY+1 ) );
|
|
pDev->DrawRect( tools::Rectangle( nX+3, nY+2, nX+3, nY+2 ) );
|
|
}
|
|
pDev->SetLineColor( aOldLineColor );
|
|
pDev->SetFillColor( aOldFillColor );
|
|
}
|
|
|
|
void PushButton::ImplDrawPushButtonContent(OutputDevice* pDev, DrawFlags nDrawFlags,
|
|
const tools::Rectangle& rRect, bool bMenuBtnSep,
|
|
DrawButtonFlags nButtonFlags)
|
|
{
|
|
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
|
|
tools::Rectangle aInRect = rRect;
|
|
Color aColor;
|
|
DrawTextFlags nTextStyle = ImplGetTextStyle( nDrawFlags );
|
|
DrawSymbolFlags nStyle;
|
|
|
|
if( aInRect.Right() < aInRect.Left() || aInRect.Bottom() < aInRect.Top() )
|
|
aInRect.SetEmpty();
|
|
|
|
pDev->Push( PushFlags::CLIPREGION );
|
|
pDev->IntersectClipRegion( aInRect );
|
|
|
|
if ( nDrawFlags & DrawFlags::Mono )
|
|
aColor = COL_BLACK;
|
|
else if( (nButtonFlags & DrawButtonFlags::Highlight) && IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Entire) )
|
|
{
|
|
if (nButtonFlags & DrawButtonFlags::Pressed)
|
|
aColor = rStyleSettings.GetButtonPressedRolloverTextColor();
|
|
else
|
|
aColor = rStyleSettings.GetButtonRolloverTextColor();
|
|
}
|
|
else if ( IsControlForeground() )
|
|
aColor = GetControlForeground();
|
|
else if( nButtonFlags & DrawButtonFlags::Highlight )
|
|
{
|
|
if (nButtonFlags & DrawButtonFlags::Pressed)
|
|
aColor = rStyleSettings.GetButtonPressedRolloverTextColor();
|
|
else
|
|
aColor = rStyleSettings.GetButtonRolloverTextColor();
|
|
}
|
|
else
|
|
aColor = rStyleSettings.GetButtonTextColor();
|
|
|
|
pDev->SetTextColor( aColor );
|
|
|
|
if ( IsEnabled() )
|
|
nStyle = DrawSymbolFlags::NONE;
|
|
else
|
|
nStyle = DrawSymbolFlags::Disable;
|
|
|
|
Size aSize = rRect.GetSize();
|
|
Point aPos = rRect.TopLeft();
|
|
|
|
sal_uLong nImageSep = 1 + (pDev->GetTextHeight()-10)/2;
|
|
if( nImageSep < 1 )
|
|
nImageSep = 1;
|
|
if ( mnDDStyle == PushButtonDropdownStyle::MenuButton ||
|
|
mnDDStyle == PushButtonDropdownStyle::SplitMenuButton )
|
|
{
|
|
long nSeparatorX = 0;
|
|
tools::Rectangle aSymbolRect = aInRect;
|
|
if (!(ImplGetButtonState() & DrawButtonFlags::NoText))
|
|
{
|
|
// calculate symbol size
|
|
long nSymbolSize = pDev->GetTextHeight() / 2 + 1;
|
|
|
|
nSeparatorX = aInRect.Right() - 2*nSymbolSize;
|
|
aSize.AdjustWidth( -(2*nSymbolSize) );
|
|
|
|
// center symbol rectangle in the separated area
|
|
aSymbolRect.AdjustRight( -(nSymbolSize/2) );
|
|
aSymbolRect.SetLeft( aSymbolRect.Right() - nSymbolSize );
|
|
|
|
ImplDrawAlignedImage( pDev, aPos, aSize, nImageSep,
|
|
nTextStyle, nullptr, true );
|
|
}
|
|
else
|
|
ImplCalcSymbolRect( aSymbolRect );
|
|
|
|
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 );
|
|
}
|
|
|
|
if ( mnDDStyle == PushButtonDropdownStyle::Toolbox )
|
|
{
|
|
bool bBlack = false;
|
|
Color aArrowColor( COL_BLACK );
|
|
|
|
if ( !(nDrawFlags & DrawFlags::Mono) )
|
|
{
|
|
if ( !IsEnabled() )
|
|
aArrowColor = rStyleSettings.GetShadowColor();
|
|
else
|
|
{
|
|
aArrowColor = COL_LIGHTGREEN;
|
|
bBlack = true;
|
|
}
|
|
}
|
|
|
|
ImplDrawBtnDropDownArrow( pDev, aInRect.Right()-6, aInRect.Top()+1,
|
|
aArrowColor, bBlack );
|
|
}
|
|
}
|
|
|
|
pDev->Pop(); // restore clipregion
|
|
}
|
|
|
|
void PushButton::ImplDrawPushButton(vcl::RenderContext& rRenderContext)
|
|
{
|
|
HideFocus();
|
|
|
|
DrawButtonFlags nButtonStyle = ImplGetButtonState();
|
|
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;
|
|
|
|
// 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 (ImplGetButtonState() & DrawButtonFlags::Pressed)
|
|
nState |= ControlState::PRESSED;
|
|
if (HasFocus())
|
|
nState |= ControlState::FOCUSED;
|
|
if (ImplGetButtonState() & DrawButtonFlags::Default)
|
|
nState |= ControlState::DEFAULT;
|
|
if (Window::IsEnabled())
|
|
nState |= ControlState::ENABLED;
|
|
|
|
if (IsMouseOver() && aInRect.IsInside(GetPointerPosPixel()))
|
|
nState |= ControlState::ROLLOVER;
|
|
|
|
if ( IsMouseOver() && aInRect.IsInside(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.IsInside(GetPointerPosPixel()));
|
|
if (bRollOver)
|
|
nButtonStyle |= DrawButtonFlags::Highlight;
|
|
bool bDrawMenuSep = mnDDStyle == PushButtonDropdownStyle::SplitMenuButton;
|
|
if (GetStyle() & WB_FLATBUTTON)
|
|
{
|
|
if (!bRollOver && !HasFocus())
|
|
bDrawMenuSep = false;
|
|
}
|
|
bNativeOK = 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 (ImplGetButtonState() & DrawButtonFlags::Pressed)
|
|
nState |= ControlState::PRESSED;
|
|
if (HasFocus())
|
|
nState |= ControlState::FOCUSED;
|
|
if (ImplGetButtonState() & 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_BEVELBUTTON)
|
|
aControlValue.mbBevelButton = 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 ((nState & ControlState::ROLLOVER) || !(GetStyle() & WB_FLATBUTTON))
|
|
{
|
|
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, DrawFlags::NONE,
|
|
aInRect, bDrawMenuSep, nButtonStyle);
|
|
|
|
if (HasFocus())
|
|
ShowFocus(ImplGetFocusRect());
|
|
}
|
|
|
|
if (!bNativeOK)
|
|
{
|
|
// draw PushButtonFrame, aInRect has content size afterwards
|
|
if (GetStyle() & WB_FLATBUTTON)
|
|
{
|
|
tools::Rectangle aTempRect(aInRect);
|
|
if (bRollOver)
|
|
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, DrawFlags::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( !(ImplGetButtonState() & 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 );
|
|
}
|
|
ImplGetButtonState() |= DrawButtonFlags::Default;
|
|
}
|
|
else
|
|
{
|
|
if( (ImplGetButtonState() & 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) );
|
|
}
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Default;
|
|
}
|
|
if( bSetPos )
|
|
setPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height() );
|
|
|
|
Invalidate();
|
|
}
|
|
|
|
bool PushButton::ImplIsDefButton() const
|
|
{
|
|
return bool(ImplGetButtonState() & DrawButtonFlags::Default);
|
|
}
|
|
|
|
PushButton::PushButton( WindowType nType ) :
|
|
Button( nType )
|
|
{
|
|
ImplInitPushButtonData();
|
|
}
|
|
|
|
PushButton::PushButton( vcl::Window* pParent, WinBits nStyle ) :
|
|
Button( WindowType::PUSHBUTTON )
|
|
{
|
|
ImplInitPushButtonData();
|
|
ImplInit( pParent, nStyle );
|
|
}
|
|
|
|
void PushButton::MouseButtonDown( const MouseEvent& rMEvt )
|
|
{
|
|
if ( rMEvt.IsLeft() &&
|
|
ImplHitTestPushButton( this, rMEvt.GetPosPixel() ) )
|
|
{
|
|
StartTrackingFlags nTrackFlags = StartTrackingFlags::NONE;
|
|
|
|
if ( ( GetStyle() & WB_REPEAT ) &&
|
|
! ( GetStyle() & WB_TOGGLE ) )
|
|
nTrackFlags |= StartTrackingFlags::ButtonRepeat;
|
|
|
|
ImplGetButtonState() |= DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
StartTracking( nTrackFlags );
|
|
|
|
if ( nTrackFlags & StartTrackingFlags::ButtonRepeat )
|
|
Click();
|
|
}
|
|
}
|
|
|
|
void PushButton::Tracking( const TrackingEvent& rTEvt )
|
|
{
|
|
if ( rTEvt.IsTrackingEnded() )
|
|
{
|
|
if ( ImplGetButtonState() & 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 );
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Pressed;
|
|
}
|
|
else
|
|
Check();
|
|
}
|
|
}
|
|
else
|
|
ImplGetButtonState() &= ~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 ( ImplGetButtonState() & DrawButtonFlags::Pressed )
|
|
{
|
|
if ( rTEvt.IsTrackingRepeat() && (GetStyle() & WB_REPEAT) &&
|
|
! ( GetStyle() & WB_TOGGLE ) )
|
|
Click();
|
|
}
|
|
else
|
|
{
|
|
ImplGetButtonState() |= DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ImplGetButtonState() & DrawButtonFlags::Pressed )
|
|
{
|
|
ImplGetButtonState() &= ~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 ( !(ImplGetButtonState() & DrawButtonFlags::Pressed) )
|
|
{
|
|
ImplGetButtonState() |= DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
}
|
|
|
|
if ( ( GetStyle() & WB_REPEAT ) &&
|
|
! ( GetStyle() & WB_TOGGLE ) )
|
|
Click();
|
|
}
|
|
else if ( (ImplGetButtonState() & DrawButtonFlags::Pressed) && (aKeyCode.GetCode() == KEY_ESCAPE) )
|
|
{
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
}
|
|
else
|
|
Button::KeyInput( rKEvt );
|
|
}
|
|
|
|
void PushButton::KeyUp( const KeyEvent& rKEvt )
|
|
{
|
|
vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
|
|
|
|
if ( (ImplGetButtonState() & DrawButtonFlags::Pressed) &&
|
|
((aKeyCode.GetCode() == KEY_RETURN) || (aKeyCode.GetCode() == KEY_SPACE)) )
|
|
{
|
|
if ( GetStyle() & WB_TOGGLE )
|
|
{
|
|
if ( IsChecked() )
|
|
{
|
|
Check( false );
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Pressed;
|
|
}
|
|
else
|
|
Check();
|
|
|
|
Toggle();
|
|
}
|
|
else
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Pressed;
|
|
|
|
Invalidate();
|
|
|
|
if ( !( ( GetStyle() & WB_REPEAT ) &&
|
|
! ( GetStyle() & WB_TOGGLE ) ) )
|
|
Click();
|
|
}
|
|
else
|
|
Button::KeyUp( rKEvt );
|
|
}
|
|
|
|
void PushButton::FillLayoutData() const
|
|
{
|
|
mpControlData->mpLayoutData.reset( new vcl::ControlLayoutData );
|
|
const_cast<PushButton*>(this)->Invalidate();
|
|
}
|
|
|
|
void PushButton::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
|
|
{
|
|
ImplDrawPushButton(rRenderContext);
|
|
}
|
|
|
|
void PushButton::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize,
|
|
DrawFlags nFlags )
|
|
{
|
|
Point aPos = pDev->LogicToPixel( rPos );
|
|
Size aSize = pDev->LogicToPixel( rSize );
|
|
tools::Rectangle aRect( aPos, aSize );
|
|
vcl::Font aFont = GetDrawPixelFont( pDev );
|
|
|
|
pDev->Push();
|
|
pDev->SetMapMode();
|
|
pDev->SetFont( aFont );
|
|
if ( nFlags & DrawFlags::Mono )
|
|
{
|
|
pDev->SetTextColor( COL_BLACK );
|
|
}
|
|
else
|
|
{
|
|
pDev->SetTextColor( GetTextColor() );
|
|
|
|
// DecoView uses the FaceColor...
|
|
AllSettings aSettings = pDev->GetSettings();
|
|
StyleSettings aStyleSettings = aSettings.GetStyleSettings();
|
|
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 & DrawFlags::Mono )
|
|
nButtonStyle |= DrawButtonFlags::Mono;
|
|
if ( IsChecked() )
|
|
nButtonStyle |= DrawButtonFlags::Checked;
|
|
aRect = aDecoView.DrawButton( aRect, nButtonStyle );
|
|
|
|
ImplDrawPushButtonContent( pDev, nFlags, aRect, true, nButtonStyle );
|
|
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 )
|
|
{
|
|
const MouseEvent* pMouseEvt = nullptr;
|
|
|
|
if( (rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != nullptr )
|
|
{
|
|
if( 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 );
|
|
pBorder->Update();
|
|
}
|
|
}
|
|
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 )
|
|
{
|
|
meState = eState;
|
|
if ( meState == TRISTATE_FALSE )
|
|
ImplGetButtonState() &= ~DrawButtonFlags(DrawButtonFlags::Checked | DrawButtonFlags::DontKnow);
|
|
else if ( meState == TRISTATE_TRUE )
|
|
{
|
|
ImplGetButtonState() &= ~DrawButtonFlags::DontKnow;
|
|
ImplGetButtonState() |= DrawButtonFlags::Checked;
|
|
}
|
|
else // TRISTATE_INDET
|
|
{
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Checked;
|
|
ImplGetButtonState() |= 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() &&
|
|
ImplGetButtonState() & DrawButtonFlags::Pressed )
|
|
{
|
|
ImplGetButtonState() &= ~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() && ! (ImplGetButtonState() & DrawButtonFlags::NoImage) )
|
|
aSize = GetModeImage().GetSizePixel();
|
|
if( mnDDStyle == PushButtonDropdownStyle::MenuButton ||
|
|
mnDDStyle == PushButtonDropdownStyle::SplitMenuButton )
|
|
{
|
|
long nSymbolSize = GetTextHeight() / 2 + 1;
|
|
aSize.AdjustWidth(2*nSymbolSize );
|
|
}
|
|
if ( !PushButton::GetText().isEmpty() && ! (ImplGetButtonState() & DrawButtonFlags::NoText) )
|
|
{
|
|
Size textSize = GetTextRect( tools::Rectangle( Point(), Size( 0x7fffffff, 0x7fffffff ) ),
|
|
PushButton::GetText(), ImplGetTextStyle( DrawFlags::NONE ) ).GetSize();
|
|
aSize.AdjustWidth(textSize.Width() );
|
|
aSize.setHeight( std::max( aSize.Height(), long( textSize.Height() * 1.15 ) ) );
|
|
}
|
|
|
|
// 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 OString &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("ok");
|
|
PushButton::ImplInit( pParent, nStyle );
|
|
|
|
SetText( Button::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() )
|
|
{
|
|
if ( static_cast<Dialog*>(pParent)->IsInExecute() )
|
|
static_cast<Dialog*>(pParent)->EndDialog( RET_OK );
|
|
// prevent recursive calls
|
|
else if ( !static_cast<Dialog*>(pParent)->IsInClose() )
|
|
{
|
|
if ( pParent->GetStyle() & WB_CLOSEABLE )
|
|
static_cast<Dialog*>(pParent)->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("cancel");
|
|
PushButton::ImplInit( pParent, nStyle );
|
|
|
|
SetText( Button::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() )
|
|
{
|
|
if ( static_cast<Dialog*>(pParent)->IsInExecute() )
|
|
static_cast<Dialog*>(pParent)->EndDialog();
|
|
// prevent recursive calls
|
|
else if ( !static_cast<Dialog*>(pParent)->IsInClose() )
|
|
{
|
|
if ( pParent->GetStyle() & WB_CLOSEABLE )
|
|
static_cast<Dialog*>(pParent)->Close();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( pParent->GetStyle() & WB_CLOSEABLE )
|
|
static_cast<SystemWindow*>(pParent)->Close();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PushButton::Click();
|
|
}
|
|
}
|
|
|
|
CloseButton::CloseButton( vcl::Window* pParent, WinBits nStyle )
|
|
: CancelButton(pParent, nStyle)
|
|
{
|
|
SetText( Button::GetStandardText( StandardButtonType::Close ) );
|
|
}
|
|
|
|
void HelpButton::ImplInit( vcl::Window* pParent, WinBits nStyle )
|
|
{
|
|
set_id("help");
|
|
PushButton::ImplInit( pParent, nStyle | WB_NOPOINTERFOCUS );
|
|
|
|
SetText( Button::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 )
|
|
pFocusWin = this;
|
|
|
|
HelpEvent aEvt( pFocusWin->GetPointerPosPixel(), HelpEventMode::CONTEXT );
|
|
pFocusWin->RequestHelp( aEvt );
|
|
}
|
|
PushButton::Click();
|
|
}
|
|
|
|
void RadioButton::ImplInitRadioButtonData()
|
|
{
|
|
mbChecked = false;
|
|
mbSaveValue = 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 )
|
|
{
|
|
if ( !(nStyle & WB_NOGROUP) &&
|
|
(!pPrevWindow || (pPrevWindow->GetType() != WindowType::RADIOBUTTON)) )
|
|
nStyle |= WB_GROUP;
|
|
if ( !(nStyle & WB_NOTABSTOP) )
|
|
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 )
|
|
{
|
|
vcl::Window* pParent = GetParent();
|
|
if ( !IsControlBackground() &&
|
|
(pParent->IsChildTransparentModeEnabled() || IsNativeControlSupported( ControlType::Radiobutton, ControlPart::Entire ) ) )
|
|
{
|
|
EnableChildTransparentMode();
|
|
SetParentClipMode( ParentClipMode::NoClip );
|
|
SetPaintTransparent( true );
|
|
SetBackground();
|
|
if( IsNativeControlSupported( ControlType::Radiobutton, ControlPart::Entire ) )
|
|
mpWindowImpl->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects;
|
|
}
|
|
else
|
|
{
|
|
EnableChildTransparentMode( false );
|
|
SetParentClipMode();
|
|
SetPaintTransparent( false );
|
|
|
|
if ( IsControlBackground() )
|
|
SetBackground( GetControlBackground() );
|
|
else
|
|
SetBackground( pParent->GetBackground() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void RadioButton::DrawRadioButtonState(vcl::RenderContext& rRenderContext)
|
|
{
|
|
ImplDrawRadioButtonState(rRenderContext);
|
|
}
|
|
|
|
void RadioButton::ImplDrawRadioButtonState(vcl::RenderContext& rRenderContext)
|
|
{
|
|
bool bNativeOK = false;
|
|
|
|
// no native drawing for image radio buttons
|
|
if (!maImage && rRenderContext.IsNativeControlSupported(ControlType::Radiobutton, ControlPart::Entire))
|
|
{
|
|
ImplControlValue aControlValue( mbChecked ? ButtonValue::On : ButtonValue::Off );
|
|
tools::Rectangle aCtrlRect(maStateRect.TopLeft(), maStateRect.GetSize());
|
|
ControlState nState = ControlState::NONE;
|
|
|
|
if (ImplGetButtonState() & DrawButtonFlags::Pressed)
|
|
nState |= ControlState::PRESSED;
|
|
if (HasFocus())
|
|
nState |= ControlState::FOCUSED;
|
|
if (ImplGetButtonState() & DrawButtonFlags::Default)
|
|
nState |= ControlState::DEFAULT;
|
|
if (IsEnabled())
|
|
nState |= ControlState::ENABLED;
|
|
|
|
if (IsMouseOver() && maMouseRect.IsInside(GetPointerPosPixel()))
|
|
nState |= ControlState::ROLLOVER;
|
|
|
|
bNativeOK = rRenderContext.DrawNativeControl(ControlType::Radiobutton, ControlPart::Entire, aCtrlRect,
|
|
nState, aControlValue, OUString());
|
|
}
|
|
|
|
if (!bNativeOK)
|
|
{
|
|
if (!maImage)
|
|
{
|
|
DrawButtonFlags nStyle = ImplGetButtonState();
|
|
if (!IsEnabled())
|
|
nStyle |= DrawButtonFlags::Disabled;
|
|
if (mbChecked)
|
|
nStyle |= DrawButtonFlags::Checked;
|
|
Image aImage = GetRadioImage(rRenderContext.GetSettings(), nStyle);
|
|
if (IsZoom())
|
|
rRenderContext.DrawImage(maStateRect.TopLeft(), maStateRect.GetSize(), aImage);
|
|
else
|
|
rRenderContext.DrawImage(maStateRect.TopLeft(), aImage);
|
|
}
|
|
else
|
|
{
|
|
HideFocus();
|
|
|
|
DecorationView aDecoView(&rRenderContext);
|
|
const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
|
|
tools::Rectangle aImageRect = maStateRect;
|
|
Size aImageSize = maImage.GetSizePixel();
|
|
bool bEnabled = IsEnabled();
|
|
|
|
aImageSize.setWidth( CalcZoom(aImageSize.Width()) );
|
|
aImageSize.setHeight( CalcZoom(aImageSize.Height()) );
|
|
|
|
aImageRect.AdjustLeft( 1 );
|
|
aImageRect.AdjustTop( 1 );
|
|
aImageRect.AdjustRight( -1 );
|
|
aImageRect.AdjustBottom( -1 );
|
|
|
|
// display border and selection status
|
|
aImageRect = aDecoView.DrawFrame(aImageRect, DrawFrameStyle::DoubleIn);
|
|
if ((ImplGetButtonState() & DrawButtonFlags::Pressed) || !bEnabled)
|
|
rRenderContext.SetFillColor( rStyleSettings.GetFaceColor());
|
|
else
|
|
rRenderContext.SetFillColor(rStyleSettings.GetFieldColor());
|
|
rRenderContext.SetLineColor();
|
|
rRenderContext.DrawRect(aImageRect);
|
|
|
|
// display image
|
|
DrawImageFlags nImageStyle = DrawImageFlags::NONE;
|
|
if (!bEnabled)
|
|
nImageStyle |= DrawImageFlags::Disable;
|
|
|
|
Image* pImage = &maImage;
|
|
|
|
Point aImagePos(aImageRect.TopLeft());
|
|
aImagePos.AdjustX((aImageRect.GetWidth() - aImageSize.Width()) / 2 );
|
|
aImagePos.AdjustY((aImageRect.GetHeight() - aImageSize.Height()) / 2 );
|
|
if (IsZoom())
|
|
rRenderContext.DrawImage(aImagePos, aImageSize, *pImage, nImageStyle);
|
|
else
|
|
rRenderContext.DrawImage(aImagePos, *pImage, nImageStyle);
|
|
|
|
aImageRect.AdjustLeft( 1 );
|
|
aImageRect.AdjustTop( 1 );
|
|
aImageRect.AdjustRight( -1 );
|
|
aImageRect.AdjustBottom( -1 );
|
|
|
|
ImplSetFocusRect(aImageRect);
|
|
|
|
if (mbChecked)
|
|
{
|
|
rRenderContext.SetLineColor(rStyleSettings.GetHighlightColor());
|
|
rRenderContext.SetFillColor();
|
|
if ((aImageSize.Width() >= 20) || (aImageSize.Height() >= 20))
|
|
{
|
|
aImageRect.AdjustLeft( 1 );
|
|
aImageRect.AdjustTop( 1 );
|
|
aImageRect.AdjustRight( -1 );
|
|
aImageRect.AdjustBottom( -1 );
|
|
}
|
|
rRenderContext.DrawRect(aImageRect);
|
|
aImageRect.AdjustLeft( 1 );
|
|
aImageRect.AdjustTop( 1 );
|
|
aImageRect.AdjustRight( -1 );
|
|
aImageRect.AdjustBottom( -1 );
|
|
rRenderContext.DrawRect(aImageRect);
|
|
}
|
|
|
|
if (HasFocus())
|
|
ShowFocus(ImplGetFocusRect());
|
|
}
|
|
}
|
|
}
|
|
|
|
void RadioButton::ImplDraw( OutputDevice* pDev, DrawFlags nDrawFlags,
|
|
const Point& rPos, const Size& rSize,
|
|
const Size& rImageSize, tools::Rectangle& rStateRect,
|
|
tools::Rectangle& rMouseRect )
|
|
{
|
|
WinBits nWinStyle = GetStyle();
|
|
OUString aText( GetText() );
|
|
|
|
pDev->Push( PushFlags::CLIPREGION );
|
|
pDev->IntersectClipRegion( tools::Rectangle( rPos, rSize ) );
|
|
|
|
// no image radio button
|
|
if ( !maImage )
|
|
{
|
|
if ( ( !aText.isEmpty() && ! (ImplGetButtonState() & DrawButtonFlags::NoText) ) ||
|
|
( HasImage() && ! (ImplGetButtonState() & DrawButtonFlags::NoImage) ) )
|
|
{
|
|
DrawTextFlags nTextStyle = Button::ImplGetTextStyle( nWinStyle, nDrawFlags );
|
|
|
|
const long nImageSep = GetDrawPixel( pDev, ImplGetImageToTextDistance() );
|
|
Size aSize( rSize );
|
|
Point aPos( rPos );
|
|
aPos.AdjustX(rImageSize.Width() + nImageSep );
|
|
aSize.AdjustWidth( -(rImageSize.Width() + nImageSep) );
|
|
|
|
// if the text rect height is smaller than the height of the image
|
|
// then for single lines the default should be centered text
|
|
if( (nWinStyle & (WB_TOP|WB_VCENTER|WB_BOTTOM)) == 0 &&
|
|
(rImageSize.Height() > rSize.Height() || ! (nWinStyle & WB_WORDBREAK) ) )
|
|
{
|
|
nTextStyle &= ~DrawTextFlags(DrawTextFlags::Top|DrawTextFlags::Bottom);
|
|
nTextStyle |= DrawTextFlags::VCenter;
|
|
aSize.setHeight( rImageSize.Height() );
|
|
}
|
|
|
|
ImplDrawAlignedImage( pDev, aPos, aSize, 1, nTextStyle );
|
|
|
|
rMouseRect = tools::Rectangle( aPos, aSize );
|
|
rMouseRect.SetLeft( rPos.X() );
|
|
|
|
rStateRect.SetLeft( rPos.X() );
|
|
rStateRect.SetTop( rMouseRect.Top() );
|
|
|
|
if ( aSize.Height() > rImageSize.Height() )
|
|
rStateRect.AdjustTop(( aSize.Height() - rImageSize.Height() ) / 2 );
|
|
else
|
|
{
|
|
rStateRect.AdjustTop( -(( rImageSize.Height() - aSize.Height() ) / 2) );
|
|
if( rStateRect.Top() < 0 )
|
|
rStateRect.SetTop( 0 );
|
|
}
|
|
|
|
rStateRect.SetRight( rStateRect.Left() + rImageSize.Width()-1 );
|
|
rStateRect.SetBottom( rStateRect.Top() + rImageSize.Height()-1 );
|
|
|
|
if ( rStateRect.Bottom() > rMouseRect.Bottom() )
|
|
rMouseRect.SetBottom( rStateRect.Bottom() );
|
|
}
|
|
else
|
|
{
|
|
rStateRect.SetLeft( rPos.X() );
|
|
if ( nWinStyle & WB_VCENTER )
|
|
rStateRect.SetTop( rPos.Y()+((rSize.Height()-rImageSize.Height())/2) );
|
|
else if ( nWinStyle & WB_BOTTOM )
|
|
rStateRect.SetTop( rPos.Y()+rSize.Height()-rImageSize.Height() ); //-1;
|
|
else
|
|
rStateRect.SetTop( rPos.Y() );
|
|
rStateRect.SetRight( rStateRect.Left()+rImageSize.Width()-1 );
|
|
rStateRect.SetBottom( rStateRect.Top()+rImageSize.Height()-1 );
|
|
rMouseRect = rStateRect;
|
|
|
|
ImplSetFocusRect( rStateRect );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool bTopImage = (nWinStyle & WB_TOP) != 0;
|
|
Size aImageSize = maImage.GetSizePixel();
|
|
tools::Rectangle aImageRect( rPos, rSize );
|
|
long nTextHeight = pDev->GetTextHeight();
|
|
long nTextWidth = pDev->GetCtrlTextWidth( aText );
|
|
|
|
// calculate position and sizes
|
|
if ( !aText.isEmpty() && ! (ImplGetButtonState() & DrawButtonFlags::NoText) )
|
|
{
|
|
Size aTmpSize( (aImageSize.Width()+8), (aImageSize.Height()+8) );
|
|
if ( bTopImage )
|
|
{
|
|
aImageRect.SetLeft( (rSize.Width()-aTmpSize.Width())/2 );
|
|
aImageRect.SetTop( (rSize.Height()-(aTmpSize.Height()+nTextHeight+6))/2 );
|
|
}
|
|
else
|
|
aImageRect.SetTop( (rSize.Height()-aTmpSize.Height())/2 );
|
|
|
|
aImageRect.SetRight( aImageRect.Left()+aTmpSize.Width() );
|
|
aImageRect.SetBottom( aImageRect.Top()+aTmpSize.Height() );
|
|
|
|
// display text
|
|
Point aTxtPos = rPos;
|
|
if ( bTopImage )
|
|
{
|
|
aTxtPos.AdjustX((rSize.Width()-nTextWidth)/2 );
|
|
aTxtPos.AdjustY(aImageRect.Bottom()+6 );
|
|
}
|
|
else
|
|
{
|
|
aTxtPos.AdjustX(aImageRect.Right()+8 );
|
|
aTxtPos.AdjustY((rSize.Height()-nTextHeight)/2 );
|
|
}
|
|
pDev->DrawCtrlText( aTxtPos, aText, 0, aText.getLength() );
|
|
}
|
|
|
|
rMouseRect = aImageRect;
|
|
rStateRect = aImageRect;
|
|
}
|
|
|
|
pDev->Pop();
|
|
}
|
|
|
|
void RadioButton::ImplDrawRadioButton(vcl::RenderContext& rRenderContext)
|
|
{
|
|
HideFocus();
|
|
|
|
Size aImageSize;
|
|
if (!maImage)
|
|
aImageSize = ImplGetRadioImageSize();
|
|
else
|
|
aImageSize = maImage.GetSizePixel();
|
|
|
|
aImageSize.setWidth( CalcZoom(aImageSize.Width()) );
|
|
aImageSize.setHeight( CalcZoom(aImageSize.Height()) );
|
|
|
|
// Draw control text
|
|
ImplDraw(&rRenderContext, DrawFlags::NONE, Point(), GetOutputSizePixel(),
|
|
aImageSize, maStateRect, maMouseRect);
|
|
|
|
if (!maImage && HasFocus())
|
|
ShowFocus(ImplGetFocusRect());
|
|
|
|
ImplDrawRadioButtonState(rRenderContext);
|
|
}
|
|
|
|
void RadioButton::group(RadioButton &rOther)
|
|
{
|
|
if (&rOther == this)
|
|
return;
|
|
|
|
if (!m_xGroup)
|
|
{
|
|
m_xGroup.reset(new std::vector<VclPtr<RadioButton> >);
|
|
m_xGroup->push_back(this);
|
|
}
|
|
|
|
auto aFind = std::find(m_xGroup->begin(), m_xGroup->end(), VclPtr<RadioButton>(&rOther));
|
|
if (aFind == m_xGroup->end())
|
|
{
|
|
m_xGroup->push_back(&rOther);
|
|
|
|
if (rOther.m_xGroup)
|
|
{
|
|
std::vector< VclPtr<RadioButton> > aOthers(rOther.GetRadioButtonGroup(false));
|
|
//make all members of the group share the same button group
|
|
for (auto const& elem : aOthers)
|
|
{
|
|
aFind = std::find(m_xGroup->begin(), m_xGroup->end(), elem);
|
|
if (aFind == m_xGroup->end())
|
|
m_xGroup->push_back(elem);
|
|
}
|
|
}
|
|
|
|
//make all members of the group share the same button group
|
|
for (VclPtr<RadioButton> const & pButton : *m_xGroup)
|
|
{
|
|
pButton->m_xGroup = m_xGroup;
|
|
}
|
|
}
|
|
|
|
//if this one is checked, uncheck all the others
|
|
if (mbChecked)
|
|
ImplUncheckAllOther();
|
|
}
|
|
|
|
std::vector< VclPtr<RadioButton> > RadioButton::GetRadioButtonGroup(bool bIncludeThis) const
|
|
{
|
|
if (m_xGroup)
|
|
{
|
|
if (bIncludeThis)
|
|
return *m_xGroup;
|
|
std::vector< VclPtr<RadioButton> > aGroup;
|
|
for (VclPtr<RadioButton> const & pRadioButton : *m_xGroup)
|
|
{
|
|
if (pRadioButton == this)
|
|
continue;
|
|
aGroup.push_back(pRadioButton);
|
|
}
|
|
return aGroup;
|
|
}
|
|
|
|
//old-school
|
|
|
|
// go back to first in group;
|
|
vcl::Window* pFirst = const_cast<RadioButton*>(this);
|
|
while( ( pFirst->GetStyle() & WB_GROUP ) == 0 )
|
|
{
|
|
vcl::Window* pWindow = pFirst->GetWindow( GetWindowType::Prev );
|
|
if( pWindow )
|
|
pFirst = pWindow;
|
|
else
|
|
break;
|
|
}
|
|
std::vector< VclPtr<RadioButton> > aGroup;
|
|
// insert radiobuttons up to next group
|
|
do
|
|
{
|
|
if( pFirst->GetType() == WindowType::RADIOBUTTON )
|
|
{
|
|
if( pFirst != this || bIncludeThis )
|
|
aGroup.emplace_back(static_cast<RadioButton*>(pFirst) );
|
|
}
|
|
pFirst = pFirst->GetWindow( GetWindowType::Next );
|
|
} while( pFirst && ( ( pFirst->GetStyle() & WB_GROUP ) == 0 ) );
|
|
|
|
return aGroup;
|
|
}
|
|
|
|
void RadioButton::ImplUncheckAllOther()
|
|
{
|
|
mpWindowImpl->mnStyle |= WB_TABSTOP;
|
|
|
|
std::vector<VclPtr<RadioButton> > aGroup(GetRadioButtonGroup(false));
|
|
// iterate over radio button group and checked buttons
|
|
for (VclPtr<RadioButton>& pWindow : aGroup)
|
|
{
|
|
if ( pWindow->IsChecked() )
|
|
{
|
|
pWindow->SetState( false );
|
|
if ( pWindow->IsDisposed() )
|
|
return;
|
|
}
|
|
|
|
// not inside if clause to always remove wrongly set WB_TABSTOPS
|
|
pWindow->mpWindowImpl->mnStyle &= ~WB_TABSTOP;
|
|
}
|
|
}
|
|
|
|
void RadioButton::ImplCallClick( bool bGrabFocus, GetFocusFlags nFocusFlags )
|
|
{
|
|
mbStateChanged = !mbChecked;
|
|
mbChecked = true;
|
|
mpWindowImpl->mnStyle |= WB_TABSTOP;
|
|
Invalidate();
|
|
Update();
|
|
VclPtr<vcl::Window> xWindow = this;
|
|
if ( mbRadioCheck )
|
|
ImplUncheckAllOther();
|
|
if ( xWindow->IsDisposed() )
|
|
return;
|
|
if ( bGrabFocus )
|
|
ImplGrabFocus( nFocusFlags );
|
|
if ( xWindow->IsDisposed() )
|
|
return;
|
|
if ( mbStateChanged )
|
|
Toggle();
|
|
if ( xWindow->IsDisposed() )
|
|
return;
|
|
Click();
|
|
if ( xWindow->IsDisposed() )
|
|
return;
|
|
mbStateChanged = false;
|
|
}
|
|
|
|
RadioButton::RadioButton( vcl::Window* pParent, WinBits nStyle ) :
|
|
Button( WindowType::RADIOBUTTON )
|
|
{
|
|
ImplInitRadioButtonData();
|
|
ImplInit( pParent, nStyle );
|
|
}
|
|
|
|
RadioButton::~RadioButton()
|
|
{
|
|
disposeOnce();
|
|
}
|
|
|
|
void RadioButton::dispose()
|
|
{
|
|
if (m_xGroup)
|
|
{
|
|
m_xGroup->erase(std::remove(m_xGroup->begin(), m_xGroup->end(), VclPtr<RadioButton>(this)),
|
|
m_xGroup->end());
|
|
m_xGroup.reset();
|
|
}
|
|
Button::dispose();
|
|
}
|
|
|
|
void RadioButton::MouseButtonDown( const MouseEvent& rMEvt )
|
|
{
|
|
if ( rMEvt.IsLeft() && maMouseRect.IsInside( rMEvt.GetPosPixel() ) )
|
|
{
|
|
ImplGetButtonState() |= DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
Update();
|
|
StartTracking();
|
|
return;
|
|
}
|
|
|
|
Button::MouseButtonDown( rMEvt );
|
|
}
|
|
|
|
void RadioButton::Tracking( const TrackingEvent& rTEvt )
|
|
{
|
|
if ( rTEvt.IsTrackingEnded() )
|
|
{
|
|
if ( ImplGetButtonState() & DrawButtonFlags::Pressed )
|
|
{
|
|
if ( !(GetStyle() & WB_NOPOINTERFOCUS) && !rTEvt.IsTrackingCanceled() )
|
|
GrabFocus();
|
|
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Pressed;
|
|
|
|
// do not call click handler if aborted
|
|
if ( !rTEvt.IsTrackingCanceled() )
|
|
ImplCallClick();
|
|
else
|
|
{
|
|
Invalidate();
|
|
Update();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( maMouseRect.IsInside( rTEvt.GetMouseEvent().GetPosPixel() ) )
|
|
{
|
|
if ( !(ImplGetButtonState() & DrawButtonFlags::Pressed) )
|
|
{
|
|
ImplGetButtonState() |= DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
Update();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ImplGetButtonState() & DrawButtonFlags::Pressed )
|
|
{
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
Update();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RadioButton::KeyInput( const KeyEvent& rKEvt )
|
|
{
|
|
vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
|
|
|
|
if ( !aKeyCode.GetModifier() && (aKeyCode.GetCode() == KEY_SPACE) )
|
|
{
|
|
if ( !(ImplGetButtonState() & DrawButtonFlags::Pressed) )
|
|
{
|
|
ImplGetButtonState() |= DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
Update();
|
|
}
|
|
}
|
|
else if ( (ImplGetButtonState() & DrawButtonFlags::Pressed) && (aKeyCode.GetCode() == KEY_ESCAPE) )
|
|
{
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
Update();
|
|
}
|
|
else
|
|
Button::KeyInput( rKEvt );
|
|
}
|
|
|
|
void RadioButton::KeyUp( const KeyEvent& rKEvt )
|
|
{
|
|
vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
|
|
|
|
if ( (ImplGetButtonState() & DrawButtonFlags::Pressed) && (aKeyCode.GetCode() == KEY_SPACE) )
|
|
{
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Pressed;
|
|
ImplCallClick();
|
|
}
|
|
else
|
|
Button::KeyUp( rKEvt );
|
|
}
|
|
|
|
void RadioButton::FillLayoutData() const
|
|
{
|
|
mpControlData->mpLayoutData.reset( new vcl::ControlLayoutData );
|
|
const_cast<RadioButton*>(this)->Invalidate();
|
|
}
|
|
|
|
void RadioButton::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& )
|
|
{
|
|
ImplDrawRadioButton(rRenderContext);
|
|
}
|
|
|
|
void RadioButton::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize,
|
|
DrawFlags nFlags )
|
|
{
|
|
if ( !maImage )
|
|
{
|
|
MapMode aResMapMode( MapUnit::Map100thMM );
|
|
Point aPos = pDev->LogicToPixel( rPos );
|
|
Size aSize = pDev->LogicToPixel( rSize );
|
|
Size aImageSize = pDev->LogicToPixel( Size( 300, 300 ), aResMapMode );
|
|
Size aBrd1Size = pDev->LogicToPixel( Size( 20, 20 ), aResMapMode );
|
|
Size aBrd2Size = pDev->LogicToPixel( Size( 60, 60 ), aResMapMode );
|
|
vcl::Font aFont = GetDrawPixelFont( pDev );
|
|
tools::Rectangle aStateRect;
|
|
tools::Rectangle aMouseRect;
|
|
|
|
aImageSize.setWidth( CalcZoom( aImageSize.Width() ) );
|
|
aImageSize.setHeight( CalcZoom( aImageSize.Height() ) );
|
|
aBrd1Size.setWidth( CalcZoom( aBrd1Size.Width() ) );
|
|
aBrd1Size.setHeight( CalcZoom( aBrd1Size.Height() ) );
|
|
aBrd2Size.setWidth( CalcZoom( aBrd2Size.Width() ) );
|
|
aBrd2Size.setHeight( CalcZoom( aBrd2Size.Height() ) );
|
|
|
|
if ( !aBrd1Size.Width() )
|
|
aBrd1Size.setWidth( 1 );
|
|
if ( !aBrd1Size.Height() )
|
|
aBrd1Size.setHeight( 1 );
|
|
if ( !aBrd2Size.Width() )
|
|
aBrd2Size.setWidth( 1 );
|
|
if ( !aBrd2Size.Height() )
|
|
aBrd2Size.setHeight( 1 );
|
|
|
|
pDev->Push();
|
|
pDev->SetMapMode();
|
|
pDev->SetFont( aFont );
|
|
if ( nFlags & DrawFlags::Mono )
|
|
pDev->SetTextColor( COL_BLACK );
|
|
else
|
|
pDev->SetTextColor( GetTextColor() );
|
|
pDev->SetTextFillColor();
|
|
|
|
ImplDraw( pDev, nFlags, aPos, aSize,
|
|
aImageSize, aStateRect, aMouseRect );
|
|
|
|
Point aCenterPos = aStateRect.Center();
|
|
long nRadX = aImageSize.Width()/2;
|
|
long nRadY = aImageSize.Height()/2;
|
|
|
|
pDev->SetLineColor();
|
|
pDev->SetFillColor( COL_BLACK );
|
|
pDev->DrawPolygon( tools::Polygon( aCenterPos, nRadX, nRadY ) );
|
|
nRadX -= aBrd1Size.Width();
|
|
nRadY -= aBrd1Size.Height();
|
|
pDev->SetFillColor( COL_WHITE );
|
|
pDev->DrawPolygon( tools::Polygon( aCenterPos, nRadX, nRadY ) );
|
|
if ( mbChecked )
|
|
{
|
|
nRadX -= aBrd1Size.Width();
|
|
nRadY -= aBrd1Size.Height();
|
|
if ( !nRadX )
|
|
nRadX = 1;
|
|
if ( !nRadY )
|
|
nRadY = 1;
|
|
pDev->SetFillColor( COL_BLACK );
|
|
pDev->DrawPolygon( tools::Polygon( aCenterPos, nRadX, nRadY ) );
|
|
}
|
|
|
|
pDev->Pop();
|
|
}
|
|
else
|
|
{
|
|
OSL_FAIL( "RadioButton::Draw() - not implemented for RadioButton with Image" );
|
|
}
|
|
}
|
|
|
|
void RadioButton::Resize()
|
|
{
|
|
Control::Resize();
|
|
Invalidate();
|
|
}
|
|
|
|
void RadioButton::GetFocus()
|
|
{
|
|
ShowFocus( ImplGetFocusRect() );
|
|
SetInputContext( InputContext( GetFont() ) );
|
|
Button::GetFocus();
|
|
}
|
|
|
|
void RadioButton::LoseFocus()
|
|
{
|
|
if ( ImplGetButtonState() & DrawButtonFlags::Pressed )
|
|
{
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
Update();
|
|
}
|
|
|
|
HideFocus();
|
|
Button::LoseFocus();
|
|
}
|
|
|
|
void RadioButton::StateChanged( StateChangedType nType )
|
|
{
|
|
Button::StateChanged( nType );
|
|
|
|
if ( nType == StateChangedType::State )
|
|
{
|
|
if ( IsReallyVisible() && IsUpdateMode() )
|
|
Invalidate( maStateRect );
|
|
}
|
|
else if ( (nType == StateChangedType::Enable) ||
|
|
(nType == StateChangedType::Text) ||
|
|
(nType == StateChangedType::Data) ||
|
|
(nType == StateChangedType::UpdateMode) )
|
|
{
|
|
if ( IsUpdateMode() )
|
|
Invalidate();
|
|
}
|
|
else if ( nType == StateChangedType::Style )
|
|
{
|
|
SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev ), GetStyle() ) );
|
|
|
|
if ( (GetPrevStyle() & RADIOBUTTON_VIEW_STYLE) !=
|
|
(GetStyle() & RADIOBUTTON_VIEW_STYLE) )
|
|
{
|
|
if ( IsUpdateMode() )
|
|
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 RadioButton::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 RadioButton::PreNotify( NotifyEvent& rNEvt )
|
|
{
|
|
const MouseEvent* pMouseEvt = nullptr;
|
|
|
|
if( (rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != nullptr )
|
|
{
|
|
if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
|
|
{
|
|
// trigger redraw if mouse over state has changed
|
|
if( IsNativeControlSupported(ControlType::Radiobutton, ControlPart::Entire) )
|
|
{
|
|
if (maMouseRect.IsInside(GetPointerPosPixel()) != maMouseRect.IsInside(GetLastPointerPosPixel()) ||
|
|
pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow())
|
|
{
|
|
Invalidate( maStateRect );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Button::PreNotify(rNEvt);
|
|
}
|
|
|
|
void RadioButton::Toggle()
|
|
{
|
|
ImplCallEventListenersAndHandler( VclEventId::RadiobuttonToggle, [this] () { maToggleHdl.Call(*this); } );
|
|
}
|
|
|
|
void RadioButton::SetModeRadioImage( const Image& rImage )
|
|
{
|
|
if ( rImage != maImage )
|
|
{
|
|
maImage = rImage;
|
|
CompatStateChanged( StateChangedType::Data );
|
|
queue_resize();
|
|
}
|
|
}
|
|
|
|
|
|
void RadioButton::SetState( bool bCheck )
|
|
{
|
|
// carry the TabStop flag along correctly
|
|
if ( bCheck )
|
|
mpWindowImpl->mnStyle |= WB_TABSTOP;
|
|
else
|
|
mpWindowImpl->mnStyle &= ~WB_TABSTOP;
|
|
|
|
if ( mbChecked != bCheck )
|
|
{
|
|
mbChecked = bCheck;
|
|
CompatStateChanged( StateChangedType::State );
|
|
Toggle();
|
|
}
|
|
}
|
|
|
|
bool RadioButton::set_property(const OString &rKey, const OUString &rValue)
|
|
{
|
|
if (rKey == "active")
|
|
SetState(toBool(rValue));
|
|
else if (rKey == "image-position")
|
|
{
|
|
WinBits nBits = GetStyle();
|
|
if (rValue == "left")
|
|
{
|
|
nBits &= ~(WB_CENTER | WB_RIGHT);
|
|
nBits |= WB_LEFT;
|
|
}
|
|
else if (rValue == "right")
|
|
{
|
|
nBits &= ~(WB_CENTER | WB_LEFT);
|
|
nBits |= WB_RIGHT;
|
|
}
|
|
else if (rValue == "top")
|
|
{
|
|
nBits &= ~(WB_VCENTER | WB_BOTTOM);
|
|
nBits |= WB_TOP;
|
|
}
|
|
else if (rValue == "bottom")
|
|
{
|
|
nBits &= ~(WB_VCENTER | WB_TOP);
|
|
nBits |= WB_BOTTOM;
|
|
}
|
|
//Its rather mad to have to set these bits when there is the other
|
|
//image align. Looks like e.g. the radiobuttons etc weren't converted
|
|
//over to image align fully.
|
|
SetStyle(nBits);
|
|
//Deliberate to set the sane ImageAlign property
|
|
return Button::set_property(rKey, rValue);
|
|
}
|
|
else
|
|
return Button::set_property(rKey, rValue);
|
|
return true;
|
|
}
|
|
|
|
void RadioButton::Check( bool bCheck )
|
|
{
|
|
// TabStop-Flag richtig mitfuehren
|
|
if ( bCheck )
|
|
mpWindowImpl->mnStyle |= WB_TABSTOP;
|
|
else
|
|
mpWindowImpl->mnStyle &= ~WB_TABSTOP;
|
|
|
|
if ( mbChecked != bCheck )
|
|
{
|
|
mbChecked = bCheck;
|
|
VclPtr<vcl::Window> xWindow = this;
|
|
CompatStateChanged( StateChangedType::State );
|
|
if ( xWindow->IsDisposed() )
|
|
return;
|
|
if ( bCheck && mbRadioCheck )
|
|
ImplUncheckAllOther();
|
|
if ( xWindow->IsDisposed() )
|
|
return;
|
|
Toggle();
|
|
}
|
|
}
|
|
|
|
long RadioButton::ImplGetImageToTextDistance() const
|
|
{
|
|
// 4 pixels, but take zoom into account, so the text doesn't "jump" relative to surrounding elements,
|
|
// which might have been aligned with the text of the check box
|
|
return CalcZoom( 4 );
|
|
}
|
|
|
|
Size RadioButton::ImplGetRadioImageSize() const
|
|
{
|
|
Size aSize;
|
|
bool bDefaultSize = true;
|
|
if( IsNativeControlSupported( ControlType::Radiobutton, ControlPart::Entire ) )
|
|
{
|
|
ImplControlValue aControlValue;
|
|
tools::Rectangle aCtrlRegion( Point( 0, 0 ), GetSizePixel() );
|
|
tools::Rectangle aBoundingRgn, aContentRgn;
|
|
|
|
// get native size of a radio button
|
|
if( GetNativeControlRegion( ControlType::Radiobutton, ControlPart::Entire, aCtrlRegion,
|
|
ControlState::DEFAULT|ControlState::ENABLED,
|
|
aControlValue,
|
|
aBoundingRgn, aContentRgn ) )
|
|
{
|
|
aSize = aContentRgn.GetSize();
|
|
bDefaultSize = false;
|
|
}
|
|
}
|
|
if( bDefaultSize )
|
|
aSize = GetRadioImage( GetSettings(), DrawButtonFlags::NONE ).GetSizePixel();
|
|
return aSize;
|
|
}
|
|
|
|
static void LoadThemedImageList(const StyleSettings &rStyleSettings,
|
|
std::vector<Image>& rList, const std::vector<OUString> &rResources)
|
|
{
|
|
Color aColorAry1[6];
|
|
Color aColorAry2[6];
|
|
aColorAry1[0] = Color( 0xC0, 0xC0, 0xC0 );
|
|
aColorAry1[1] = Color( 0xFF, 0xFF, 0x00 );
|
|
aColorAry1[2] = Color( 0xFF, 0xFF, 0xFF );
|
|
aColorAry1[3] = Color( 0x80, 0x80, 0x80 );
|
|
aColorAry1[4] = Color( 0x00, 0x00, 0x00 );
|
|
aColorAry1[5] = Color( 0x00, 0xFF, 0x00 );
|
|
aColorAry2[0] = rStyleSettings.GetFaceColor();
|
|
aColorAry2[1] = rStyleSettings.GetWindowColor();
|
|
aColorAry2[2] = rStyleSettings.GetLightColor();
|
|
aColorAry2[3] = rStyleSettings.GetShadowColor();
|
|
aColorAry2[4] = rStyleSettings.GetDarkShadowColor();
|
|
aColorAry2[5] = rStyleSettings.GetWindowTextColor();
|
|
|
|
static_assert( sizeof(aColorAry1) == sizeof(aColorAry2), "aColorAry1 must match aColorAry2" );
|
|
|
|
for (const auto &a : rResources)
|
|
{
|
|
BitmapEx aBmpEx(a);
|
|
aBmpEx.Replace(aColorAry1, aColorAry2, SAL_N_ELEMENTS(aColorAry1));
|
|
rList.emplace_back(aBmpEx);
|
|
}
|
|
}
|
|
|
|
Image RadioButton::GetRadioImage( const AllSettings& rSettings, DrawButtonFlags nFlags )
|
|
{
|
|
ImplSVData* pSVData = ImplGetSVData();
|
|
const StyleSettings& rStyleSettings = rSettings.GetStyleSettings();
|
|
sal_uInt16 nStyle = 0;
|
|
|
|
if ( rStyleSettings.GetOptions() & StyleSettingsOptions::Mono )
|
|
nStyle = STYLE_RADIOBUTTON_MONO;
|
|
|
|
if ( pSVData->maCtrlData.maRadioImgList.empty() ||
|
|
(pSVData->maCtrlData.mnRadioStyle != nStyle) ||
|
|
(pSVData->maCtrlData.mnLastRadioFColor != rStyleSettings.GetFaceColor()) ||
|
|
(pSVData->maCtrlData.mnLastRadioWColor != rStyleSettings.GetWindowColor()) ||
|
|
(pSVData->maCtrlData.mnLastRadioLColor != rStyleSettings.GetLightColor()) )
|
|
{
|
|
pSVData->maCtrlData.maRadioImgList.clear();
|
|
|
|
pSVData->maCtrlData.mnLastRadioFColor = rStyleSettings.GetFaceColor();
|
|
pSVData->maCtrlData.mnLastRadioWColor = rStyleSettings.GetWindowColor();
|
|
pSVData->maCtrlData.mnLastRadioLColor = rStyleSettings.GetLightColor();
|
|
|
|
std::vector<OUString> aResources;
|
|
if (nStyle)
|
|
{
|
|
aResources.emplace_back(SV_RESID_BITMAP_RADIOMONO1);
|
|
aResources.emplace_back(SV_RESID_BITMAP_RADIOMONO2);
|
|
aResources.emplace_back(SV_RESID_BITMAP_RADIOMONO3);
|
|
aResources.emplace_back(SV_RESID_BITMAP_RADIOMONO4);
|
|
aResources.emplace_back(SV_RESID_BITMAP_RADIOMONO5);
|
|
aResources.emplace_back(SV_RESID_BITMAP_RADIOMONO6);
|
|
}
|
|
else
|
|
{
|
|
aResources.emplace_back(SV_RESID_BITMAP_RADIO1);
|
|
aResources.emplace_back(SV_RESID_BITMAP_RADIO2);
|
|
aResources.emplace_back(SV_RESID_BITMAP_RADIO3);
|
|
aResources.emplace_back(SV_RESID_BITMAP_RADIO4);
|
|
aResources.emplace_back(SV_RESID_BITMAP_RADIO5);
|
|
aResources.emplace_back(SV_RESID_BITMAP_RADIO6);
|
|
}
|
|
LoadThemedImageList( rStyleSettings, pSVData->maCtrlData.maRadioImgList, aResources);
|
|
pSVData->maCtrlData.mnRadioStyle = nStyle;
|
|
}
|
|
|
|
sal_uInt16 nIndex;
|
|
if ( nFlags & DrawButtonFlags::Disabled )
|
|
{
|
|
if ( nFlags & DrawButtonFlags::Checked )
|
|
nIndex = 5;
|
|
else
|
|
nIndex = 4;
|
|
}
|
|
else if ( nFlags & DrawButtonFlags::Pressed )
|
|
{
|
|
if ( nFlags & DrawButtonFlags::Checked )
|
|
nIndex = 3;
|
|
else
|
|
nIndex = 2;
|
|
}
|
|
else
|
|
{
|
|
if ( nFlags & DrawButtonFlags::Checked )
|
|
nIndex = 1;
|
|
else
|
|
nIndex = 0;
|
|
}
|
|
return pSVData->maCtrlData.maRadioImgList[nIndex];
|
|
}
|
|
|
|
void RadioButton::ImplSetMinimumNWFSize()
|
|
{
|
|
Push( PushFlags::MAPMODE );
|
|
SetMapMode(MapMode(MapUnit::MapPixel));
|
|
|
|
ImplControlValue aControlValue;
|
|
Size aCurSize( GetSizePixel() );
|
|
tools::Rectangle aCtrlRegion( Point( 0, 0 ), aCurSize );
|
|
tools::Rectangle aBoundingRgn, aContentRgn;
|
|
|
|
// get native size of a radiobutton
|
|
if( GetNativeControlRegion( ControlType::Radiobutton, ControlPart::Entire, aCtrlRegion,
|
|
ControlState::DEFAULT|ControlState::ENABLED, aControlValue,
|
|
aBoundingRgn, aContentRgn ) )
|
|
{
|
|
Size aSize = aContentRgn.GetSize();
|
|
|
|
if( aSize.Height() > aCurSize.Height() )
|
|
{
|
|
aCurSize.setHeight( aSize.Height() );
|
|
SetSizePixel( aCurSize );
|
|
}
|
|
}
|
|
|
|
Pop();
|
|
}
|
|
|
|
Size RadioButton::CalcMinimumSize() const
|
|
{
|
|
Size aSize;
|
|
if ( !maImage )
|
|
aSize = ImplGetRadioImageSize();
|
|
else
|
|
{
|
|
aSize = maImage.GetSizePixel();
|
|
aSize.AdjustWidth(8 );
|
|
aSize.AdjustHeight(8 );
|
|
}
|
|
|
|
OUString aText = GetText();
|
|
if ( !aText.isEmpty() && ! (ImplGetButtonState() & DrawButtonFlags::NoText) )
|
|
{
|
|
bool bTopImage = (GetStyle() & WB_TOP) != 0;
|
|
|
|
Size aTextSize = GetTextRect( tools::Rectangle( Point(), Size( 0x7fffffff, 0x7fffffff ) ),
|
|
aText, FixedText::ImplGetTextStyle( GetStyle() ) ).GetSize();
|
|
|
|
aSize.AdjustWidth(2 ); // for focus rect
|
|
|
|
if (!bTopImage)
|
|
{
|
|
aSize.AdjustWidth(ImplGetImageToTextDistance() );
|
|
aSize.AdjustWidth(aTextSize.Width() );
|
|
if ( aSize.Height() < aTextSize.Height() )
|
|
aSize.setHeight( aTextSize.Height() );
|
|
}
|
|
else
|
|
{
|
|
aSize.AdjustHeight(6 );
|
|
aSize.AdjustHeight(GetTextHeight() );
|
|
if ( aSize.Width() < aTextSize.Width() )
|
|
aSize.setWidth( aTextSize.Width() );
|
|
}
|
|
}
|
|
|
|
return CalcWindowSize( aSize );
|
|
}
|
|
|
|
Size RadioButton::GetOptimalSize() const
|
|
{
|
|
return CalcMinimumSize();
|
|
}
|
|
|
|
void RadioButton::ShowFocus(const tools::Rectangle& rRect)
|
|
{
|
|
if (IsNativeControlSupported(ControlType::Radiobutton, ControlPart::Focus))
|
|
{
|
|
ImplControlValue aControlValue;
|
|
tools::Rectangle aInRect(Point(0, 0), GetSizePixel());
|
|
|
|
aInRect.SetLeft( rRect.Left() ); // exclude the radio element itself from the focusrect
|
|
|
|
DrawNativeControl(ControlType::Radiobutton, ControlPart::Focus, aInRect,
|
|
ControlState::FOCUSED, aControlValue, OUString());
|
|
}
|
|
Button::ShowFocus(rRect);
|
|
}
|
|
|
|
FactoryFunction RadioButton::GetUITestFactory() const
|
|
{
|
|
return RadioButtonUIObject::create;
|
|
}
|
|
|
|
void CheckBox::ImplInitCheckBoxData()
|
|
{
|
|
meState = TRISTATE_FALSE;
|
|
meSaveValue = TRISTATE_FALSE;
|
|
mbTriState = false;
|
|
}
|
|
|
|
void CheckBox::ImplInit( vcl::Window* pParent, WinBits nStyle )
|
|
{
|
|
nStyle = ImplInitStyle(getPreviousSibling(pParent), nStyle);
|
|
Button::ImplInit( pParent, nStyle, nullptr );
|
|
|
|
ImplInitSettings( true );
|
|
}
|
|
|
|
WinBits CheckBox::ImplInitStyle( const vcl::Window* pPrevWindow, WinBits nStyle )
|
|
{
|
|
if ( !(nStyle & WB_NOTABSTOP) )
|
|
nStyle |= WB_TABSTOP;
|
|
if ( !(nStyle & WB_NOGROUP) &&
|
|
(!pPrevWindow || (pPrevWindow->GetType() != WindowType::CHECKBOX)) )
|
|
nStyle |= WB_GROUP;
|
|
return nStyle;
|
|
}
|
|
|
|
const vcl::Font& CheckBox::GetCanonicalFont( const StyleSettings& _rStyle ) const
|
|
{
|
|
return _rStyle.GetRadioCheckFont();
|
|
}
|
|
|
|
const Color& CheckBox::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
|
|
{
|
|
return _rStyle.GetRadioCheckTextColor();
|
|
}
|
|
|
|
void CheckBox::ImplInitSettings( bool bBackground )
|
|
{
|
|
Button::ImplInitSettings();
|
|
|
|
if ( bBackground )
|
|
{
|
|
vcl::Window* pParent = GetParent();
|
|
if ( !IsControlBackground() &&
|
|
(pParent->IsChildTransparentModeEnabled() || IsNativeControlSupported( ControlType::Checkbox, ControlPart::Entire ) ) )
|
|
{
|
|
EnableChildTransparentMode();
|
|
SetParentClipMode( ParentClipMode::NoClip );
|
|
SetPaintTransparent( true );
|
|
SetBackground();
|
|
if( IsNativeControlSupported( ControlType::Checkbox, ControlPart::Entire ) )
|
|
ImplGetWindowImpl()->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects;
|
|
}
|
|
else
|
|
{
|
|
EnableChildTransparentMode( false );
|
|
SetParentClipMode();
|
|
SetPaintTransparent( false );
|
|
|
|
if ( IsControlBackground() )
|
|
SetBackground( GetControlBackground() );
|
|
else
|
|
SetBackground( pParent->GetBackground() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void CheckBox::ImplDrawCheckBoxState(vcl::RenderContext& rRenderContext)
|
|
{
|
|
bool bNativeOK = rRenderContext.IsNativeControlSupported(ControlType::Checkbox, ControlPart::Entire);
|
|
if (bNativeOK)
|
|
{
|
|
ImplControlValue aControlValue(meState == TRISTATE_TRUE ? ButtonValue::On : ButtonValue::Off);
|
|
tools::Rectangle aCtrlRegion(maStateRect);
|
|
ControlState nState = ControlState::NONE;
|
|
|
|
if (HasFocus())
|
|
nState |= ControlState::FOCUSED;
|
|
if (ImplGetButtonState() & DrawButtonFlags::Default)
|
|
nState |= ControlState::DEFAULT;
|
|
if (ImplGetButtonState() & DrawButtonFlags::Pressed)
|
|
nState |= ControlState::PRESSED;
|
|
if (IsEnabled())
|
|
nState |= ControlState::ENABLED;
|
|
|
|
if (meState == TRISTATE_TRUE)
|
|
aControlValue.setTristateVal(ButtonValue::On);
|
|
else if (meState == TRISTATE_INDET)
|
|
aControlValue.setTristateVal(ButtonValue::Mixed);
|
|
|
|
if (IsMouseOver() && maMouseRect.IsInside(GetPointerPosPixel()))
|
|
nState |= ControlState::ROLLOVER;
|
|
|
|
bNativeOK = rRenderContext.DrawNativeControl(ControlType::Checkbox, ControlPart::Entire, aCtrlRegion,
|
|
nState, aControlValue, OUString());
|
|
}
|
|
|
|
if (!bNativeOK)
|
|
{
|
|
DrawButtonFlags nStyle = ImplGetButtonState();
|
|
if (!IsEnabled())
|
|
nStyle |= DrawButtonFlags::Disabled;
|
|
if (meState == TRISTATE_INDET)
|
|
nStyle |= DrawButtonFlags::DontKnow;
|
|
else if (meState == TRISTATE_TRUE)
|
|
nStyle |= DrawButtonFlags::Checked;
|
|
Image aImage = GetCheckImage(GetSettings(), nStyle);
|
|
if (IsZoom())
|
|
rRenderContext.DrawImage(maStateRect.TopLeft(), maStateRect.GetSize(), aImage);
|
|
else
|
|
rRenderContext.DrawImage(maStateRect.TopLeft(), aImage);
|
|
}
|
|
}
|
|
|
|
void CheckBox::ImplDraw( OutputDevice* pDev, DrawFlags nDrawFlags,
|
|
const Point& rPos, const Size& rSize,
|
|
const Size& rImageSize, tools::Rectangle& rStateRect,
|
|
tools::Rectangle& rMouseRect )
|
|
{
|
|
WinBits nWinStyle = GetStyle();
|
|
OUString aText( GetText() );
|
|
|
|
pDev->Push( PushFlags::CLIPREGION | PushFlags::LINECOLOR );
|
|
pDev->IntersectClipRegion( tools::Rectangle( rPos, rSize ) );
|
|
|
|
if ( ( !aText.isEmpty() && ! (ImplGetButtonState() & DrawButtonFlags::NoText) ) ||
|
|
( HasImage() && ! (ImplGetButtonState() & DrawButtonFlags::NoImage) ) )
|
|
{
|
|
DrawTextFlags nTextStyle = Button::ImplGetTextStyle( nWinStyle, nDrawFlags );
|
|
|
|
const long nImageSep = GetDrawPixel( pDev, ImplGetImageToTextDistance() );
|
|
Size aSize( rSize );
|
|
Point aPos( rPos );
|
|
aPos.AdjustX(rImageSize.Width() + nImageSep );
|
|
aSize.AdjustWidth( -(rImageSize.Width() + nImageSep) );
|
|
|
|
// if the text rect height is smaller than the height of the image
|
|
// then for single lines the default should be centered text
|
|
if( (nWinStyle & (WB_TOP|WB_VCENTER|WB_BOTTOM)) == 0 &&
|
|
(rImageSize.Height() > rSize.Height() || ! (nWinStyle & WB_WORDBREAK) ) )
|
|
{
|
|
nTextStyle &= ~DrawTextFlags(DrawTextFlags::Top|DrawTextFlags::Bottom);
|
|
nTextStyle |= DrawTextFlags::VCenter;
|
|
aSize.setHeight( rImageSize.Height() );
|
|
}
|
|
|
|
ImplDrawAlignedImage( pDev, aPos, aSize, 1, nTextStyle );
|
|
|
|
rMouseRect = tools::Rectangle( aPos, aSize );
|
|
rMouseRect.SetLeft( rPos.X() );
|
|
rStateRect.SetLeft( rPos.X() );
|
|
rStateRect.SetTop( rMouseRect.Top() );
|
|
|
|
if ( aSize.Height() > rImageSize.Height() )
|
|
rStateRect.AdjustTop(( aSize.Height() - rImageSize.Height() ) / 2 );
|
|
else
|
|
{
|
|
rStateRect.AdjustTop( -(( rImageSize.Height() - aSize.Height() ) / 2) );
|
|
if( rStateRect.Top() < 0 )
|
|
rStateRect.SetTop( 0 );
|
|
}
|
|
|
|
rStateRect.SetRight( rStateRect.Left()+rImageSize.Width()-1 );
|
|
rStateRect.SetBottom( rStateRect.Top()+rImageSize.Height()-1 );
|
|
if ( rStateRect.Bottom() > rMouseRect.Bottom() )
|
|
rMouseRect.SetBottom( rStateRect.Bottom() );
|
|
}
|
|
else
|
|
{
|
|
if ( mbLegacyNoTextAlign && ( nWinStyle & WB_CENTER ) )
|
|
rStateRect.SetLeft( rPos.X()+((rSize.Width()-rImageSize.Width())/2) );
|
|
else if ( mbLegacyNoTextAlign && ( nWinStyle & WB_RIGHT ) )
|
|
rStateRect.SetLeft( rPos.X()+rSize.Width()-rImageSize.Width() );
|
|
else
|
|
rStateRect.SetLeft( rPos.X() );
|
|
if ( nWinStyle & WB_VCENTER )
|
|
rStateRect.SetTop( rPos.Y()+((rSize.Height()-rImageSize.Height())/2) );
|
|
else if ( nWinStyle & WB_BOTTOM )
|
|
rStateRect.SetTop( rPos.Y()+rSize.Height()-rImageSize.Height() );
|
|
else
|
|
rStateRect.SetTop( rPos.Y() );
|
|
rStateRect.SetRight( rStateRect.Left()+rImageSize.Width()-1 );
|
|
rStateRect.SetBottom( rStateRect.Top()+rImageSize.Height()-1 );
|
|
// provide space for focusrect
|
|
// note: this assumes that the control's size was adjusted
|
|
// accordingly in Get/LoseFocus, so the onscreen position won't change
|
|
if( HasFocus() )
|
|
rStateRect.Move( 1, 1 );
|
|
rMouseRect = rStateRect;
|
|
|
|
ImplSetFocusRect( rStateRect );
|
|
}
|
|
|
|
pDev->Pop();
|
|
}
|
|
|
|
void CheckBox::ImplDrawCheckBox(vcl::RenderContext& rRenderContext)
|
|
{
|
|
Size aImageSize = ImplGetCheckImageSize();
|
|
aImageSize.setWidth( CalcZoom( aImageSize.Width() ) );
|
|
aImageSize.setHeight( CalcZoom( aImageSize.Height() ) );
|
|
|
|
HideFocus();
|
|
|
|
ImplDraw(&rRenderContext, DrawFlags::NONE, Point(), GetOutputSizePixel(),
|
|
aImageSize, maStateRect, maMouseRect);
|
|
|
|
ImplDrawCheckBoxState(rRenderContext);
|
|
if (HasFocus())
|
|
ShowFocus(ImplGetFocusRect());
|
|
}
|
|
|
|
void CheckBox::ImplCheck()
|
|
{
|
|
TriState eNewState;
|
|
if ( meState == TRISTATE_FALSE )
|
|
eNewState = TRISTATE_TRUE;
|
|
else if ( !mbTriState )
|
|
eNewState = TRISTATE_FALSE;
|
|
else if ( meState == TRISTATE_TRUE )
|
|
eNewState = TRISTATE_INDET;
|
|
else
|
|
eNewState = TRISTATE_FALSE;
|
|
meState = eNewState;
|
|
|
|
VclPtr<vcl::Window> xWindow = this;
|
|
Invalidate();
|
|
Update();
|
|
Toggle();
|
|
if ( xWindow->IsDisposed() )
|
|
return;
|
|
Click();
|
|
}
|
|
|
|
CheckBox::CheckBox( vcl::Window* pParent, WinBits nStyle ) :
|
|
Button( WindowType::CHECKBOX ), mbLegacyNoTextAlign( false )
|
|
{
|
|
ImplInitCheckBoxData();
|
|
ImplInit( pParent, nStyle );
|
|
}
|
|
|
|
void CheckBox::MouseButtonDown( const MouseEvent& rMEvt )
|
|
{
|
|
if ( rMEvt.IsLeft() && maMouseRect.IsInside( rMEvt.GetPosPixel() ) )
|
|
{
|
|
ImplGetButtonState() |= DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
Update();
|
|
StartTracking();
|
|
return;
|
|
}
|
|
|
|
Button::MouseButtonDown( rMEvt );
|
|
}
|
|
|
|
void CheckBox::Tracking( const TrackingEvent& rTEvt )
|
|
{
|
|
if ( rTEvt.IsTrackingEnded() )
|
|
{
|
|
if ( ImplGetButtonState() & DrawButtonFlags::Pressed )
|
|
{
|
|
if ( !(GetStyle() & WB_NOPOINTERFOCUS) && !rTEvt.IsTrackingCanceled() )
|
|
GrabFocus();
|
|
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Pressed;
|
|
|
|
// do not call click handler if aborted
|
|
if ( !rTEvt.IsTrackingCanceled() )
|
|
ImplCheck();
|
|
else
|
|
{
|
|
Invalidate();
|
|
Update();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( maMouseRect.IsInside( rTEvt.GetMouseEvent().GetPosPixel() ) )
|
|
{
|
|
if ( !(ImplGetButtonState() & DrawButtonFlags::Pressed) )
|
|
{
|
|
ImplGetButtonState() |= DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
Update();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ImplGetButtonState() & DrawButtonFlags::Pressed )
|
|
{
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
Update();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CheckBox::KeyInput( const KeyEvent& rKEvt )
|
|
{
|
|
vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
|
|
|
|
if ( !aKeyCode.GetModifier() && (aKeyCode.GetCode() == KEY_SPACE) )
|
|
{
|
|
if ( !(ImplGetButtonState() & DrawButtonFlags::Pressed) )
|
|
{
|
|
ImplGetButtonState() |= DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
Update();
|
|
}
|
|
}
|
|
else if ( (ImplGetButtonState() & DrawButtonFlags::Pressed) && (aKeyCode.GetCode() == KEY_ESCAPE) )
|
|
{
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
Update();
|
|
}
|
|
else
|
|
Button::KeyInput( rKEvt );
|
|
}
|
|
|
|
void CheckBox::KeyUp( const KeyEvent& rKEvt )
|
|
{
|
|
vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
|
|
|
|
if ( (ImplGetButtonState() & DrawButtonFlags::Pressed) && (aKeyCode.GetCode() == KEY_SPACE) )
|
|
{
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Pressed;
|
|
ImplCheck();
|
|
}
|
|
else
|
|
Button::KeyUp( rKEvt );
|
|
}
|
|
|
|
void CheckBox::FillLayoutData() const
|
|
{
|
|
mpControlData->mpLayoutData.reset( new vcl::ControlLayoutData );
|
|
const_cast<CheckBox*>(this)->Invalidate();
|
|
}
|
|
|
|
void CheckBox::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
|
|
{
|
|
ImplDrawCheckBox(rRenderContext);
|
|
}
|
|
|
|
void CheckBox::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize,
|
|
DrawFlags nFlags )
|
|
{
|
|
MapMode aResMapMode( MapUnit::Map100thMM );
|
|
Point aPos = pDev->LogicToPixel( rPos );
|
|
Size aSize = pDev->LogicToPixel( rSize );
|
|
Size aImageSize = pDev->LogicToPixel( Size( 300, 300 ), aResMapMode );
|
|
Size aBrd1Size = pDev->LogicToPixel( Size( 20, 20 ), aResMapMode );
|
|
Size aBrd2Size = pDev->LogicToPixel( Size( 30, 30 ), aResMapMode );
|
|
long nCheckWidth = pDev->LogicToPixel( Size( 20, 20 ), aResMapMode ).Width();
|
|
vcl::Font aFont = GetDrawPixelFont( pDev );
|
|
tools::Rectangle aStateRect;
|
|
tools::Rectangle aMouseRect;
|
|
|
|
aImageSize.setWidth( CalcZoom( aImageSize.Width() ) );
|
|
aImageSize.setHeight( CalcZoom( aImageSize.Height() ) );
|
|
aBrd1Size.setWidth( CalcZoom( aBrd1Size.Width() ) );
|
|
aBrd1Size.setHeight( CalcZoom( aBrd1Size.Height() ) );
|
|
aBrd2Size.setWidth( CalcZoom( aBrd2Size.Width() ) );
|
|
aBrd2Size.setHeight( CalcZoom( aBrd2Size.Height() ) );
|
|
|
|
if ( !aBrd1Size.Width() )
|
|
aBrd1Size.setWidth( 1 );
|
|
if ( !aBrd1Size.Height() )
|
|
aBrd1Size.setHeight( 1 );
|
|
if ( !aBrd2Size.Width() )
|
|
aBrd2Size.setWidth( 1 );
|
|
if ( !aBrd2Size.Height() )
|
|
aBrd2Size.setHeight( 1 );
|
|
if ( !nCheckWidth )
|
|
nCheckWidth = 1;
|
|
|
|
pDev->Push();
|
|
pDev->SetMapMode();
|
|
pDev->SetFont( aFont );
|
|
if ( nFlags & DrawFlags::Mono )
|
|
pDev->SetTextColor( COL_BLACK );
|
|
else
|
|
pDev->SetTextColor( GetTextColor() );
|
|
pDev->SetTextFillColor();
|
|
|
|
ImplDraw( pDev, nFlags, aPos, aSize,
|
|
aImageSize, aStateRect, aMouseRect );
|
|
|
|
pDev->SetLineColor();
|
|
pDev->SetFillColor( COL_BLACK );
|
|
pDev->DrawRect( aStateRect );
|
|
aStateRect.AdjustLeft(aBrd1Size.Width() );
|
|
aStateRect.AdjustTop(aBrd1Size.Height() );
|
|
aStateRect.AdjustRight( -(aBrd1Size.Width()) );
|
|
aStateRect.AdjustBottom( -(aBrd1Size.Height()) );
|
|
if ( meState == TRISTATE_INDET )
|
|
pDev->SetFillColor( COL_LIGHTGRAY );
|
|
else
|
|
pDev->SetFillColor( COL_WHITE );
|
|
pDev->DrawRect( aStateRect );
|
|
|
|
if ( meState == TRISTATE_TRUE )
|
|
{
|
|
aStateRect.AdjustLeft(aBrd2Size.Width() );
|
|
aStateRect.AdjustTop(aBrd2Size.Height() );
|
|
aStateRect.AdjustRight( -(aBrd2Size.Width()) );
|
|
aStateRect.AdjustBottom( -(aBrd2Size.Height()) );
|
|
Point aPos11( aStateRect.TopLeft() );
|
|
Point aPos12( aStateRect.BottomRight() );
|
|
Point aPos21( aStateRect.TopRight() );
|
|
Point aPos22( aStateRect.BottomLeft() );
|
|
Point aTempPos11( aPos11 );
|
|
Point aTempPos12( aPos12 );
|
|
Point aTempPos21( aPos21 );
|
|
Point aTempPos22( aPos22 );
|
|
pDev->SetLineColor( COL_BLACK );
|
|
long nDX = 0;
|
|
for ( long i = 0; i < nCheckWidth; i++ )
|
|
{
|
|
if ( !(i % 2) )
|
|
{
|
|
aTempPos11.setX( aPos11.X()+nDX );
|
|
aTempPos12.setX( aPos12.X()+nDX );
|
|
aTempPos21.setX( aPos21.X()+nDX );
|
|
aTempPos22.setX( aPos22.X()+nDX );
|
|
}
|
|
else
|
|
{
|
|
nDX++;
|
|
aTempPos11.setX( aPos11.X()-nDX );
|
|
aTempPos12.setX( aPos12.X()-nDX );
|
|
aTempPos21.setX( aPos21.X()-nDX );
|
|
aTempPos22.setX( aPos22.X()-nDX );
|
|
}
|
|
pDev->DrawLine( aTempPos11, aTempPos12 );
|
|
pDev->DrawLine( aTempPos21, aTempPos22 );
|
|
}
|
|
}
|
|
|
|
pDev->Pop();
|
|
}
|
|
|
|
void CheckBox::Resize()
|
|
{
|
|
Control::Resize();
|
|
Invalidate();
|
|
}
|
|
|
|
void CheckBox::GetFocus()
|
|
{
|
|
if ( GetText().isEmpty() || (ImplGetButtonState() & DrawButtonFlags::NoText) )
|
|
{
|
|
// increase button size to have space for focus rect
|
|
// checkboxes without text will draw focusrect around the check
|
|
// See CheckBox::ImplDraw()
|
|
Point aPos( GetPosPixel() );
|
|
Size aSize( GetSizePixel() );
|
|
aPos.Move(-1,-1);
|
|
aSize.AdjustHeight(2 );
|
|
aSize.AdjustWidth(2 );
|
|
setPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height() );
|
|
Invalidate();
|
|
}
|
|
else
|
|
ShowFocus( ImplGetFocusRect() );
|
|
|
|
SetInputContext( InputContext( GetFont() ) );
|
|
Button::GetFocus();
|
|
}
|
|
|
|
void CheckBox::LoseFocus()
|
|
{
|
|
if ( ImplGetButtonState() & DrawButtonFlags::Pressed )
|
|
{
|
|
ImplGetButtonState() &= ~DrawButtonFlags::Pressed;
|
|
Invalidate();
|
|
Update();
|
|
}
|
|
|
|
HideFocus();
|
|
Button::LoseFocus();
|
|
|
|
if ( GetText().isEmpty() || (ImplGetButtonState() & DrawButtonFlags::NoText) )
|
|
{
|
|
// decrease button size again (see GetFocus())
|
|
// checkboxes without text will draw focusrect around the check
|
|
Point aPos( GetPosPixel() );
|
|
Size aSize( GetSizePixel() );
|
|
aPos.Move(1,1);
|
|
aSize.AdjustHeight( -2 );
|
|
aSize.AdjustWidth( -2 );
|
|
setPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height() );
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
void CheckBox::StateChanged( StateChangedType nType )
|
|
{
|
|
Button::StateChanged( nType );
|
|
|
|
if ( nType == StateChangedType::State )
|
|
{
|
|
if ( IsReallyVisible() && IsUpdateMode() )
|
|
Invalidate( maStateRect );
|
|
}
|
|
else if ( (nType == StateChangedType::Enable) ||
|
|
(nType == StateChangedType::Text) ||
|
|
(nType == StateChangedType::Data) ||
|
|
(nType == StateChangedType::UpdateMode) )
|
|
{
|
|
if ( IsUpdateMode() )
|
|
Invalidate();
|
|
}
|
|
else if ( nType == StateChangedType::Style )
|
|
{
|
|
SetStyle( ImplInitStyle( GetWindow( GetWindowType::Prev ), GetStyle() ) );
|
|
|
|
if ( (GetPrevStyle() & CHECKBOX_VIEW_STYLE) !=
|
|
(GetStyle() & CHECKBOX_VIEW_STYLE) )
|
|
{
|
|
if ( IsUpdateMode() )
|
|
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 CheckBox::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 CheckBox::PreNotify( NotifyEvent& rNEvt )
|
|
{
|
|
const MouseEvent* pMouseEvt = nullptr;
|
|
|
|
if( (rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != nullptr )
|
|
{
|
|
if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
|
|
{
|
|
// trigger redraw if mouse over state has changed
|
|
if( IsNativeControlSupported(ControlType::Checkbox, ControlPart::Entire) )
|
|
{
|
|
if (maMouseRect.IsInside(GetPointerPosPixel()) != maMouseRect.IsInside(GetLastPointerPosPixel()) ||
|
|
pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow())
|
|
{
|
|
Invalidate( maStateRect );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Button::PreNotify(rNEvt);
|
|
}
|
|
|
|
void CheckBox::Toggle()
|
|
{
|
|
ImplCallEventListenersAndHandler( VclEventId::CheckboxToggle, [this] () { maToggleHdl.Call(*this); } );
|
|
}
|
|
|
|
void CheckBox::SetState( TriState eState )
|
|
{
|
|
if ( !mbTriState && (eState == TRISTATE_INDET) )
|
|
eState = TRISTATE_FALSE;
|
|
|
|
if ( meState != eState )
|
|
{
|
|
meState = eState;
|
|
StateChanged( StateChangedType::State );
|
|
Toggle();
|
|
}
|
|
}
|
|
|
|
bool CheckBox::set_property(const OString &rKey, const OUString &rValue)
|
|
{
|
|
if (rKey == "active")
|
|
SetState(toBool(rValue) ? TRISTATE_TRUE : TRISTATE_FALSE);
|
|
else
|
|
return Button::set_property(rKey, rValue);
|
|
return true;
|
|
}
|
|
|
|
void CheckBox::EnableTriState( bool bTriState )
|
|
{
|
|
if ( mbTriState != bTriState )
|
|
{
|
|
mbTriState = bTriState;
|
|
|
|
if ( !bTriState && (meState == TRISTATE_INDET) )
|
|
SetState( TRISTATE_FALSE );
|
|
}
|
|
}
|
|
|
|
long CheckBox::ImplGetImageToTextDistance() const
|
|
{
|
|
// 4 pixels, but take zoom into account, so the text doesn't "jump" relative to surrounding elements,
|
|
// which might have been aligned with the text of the check box
|
|
return CalcZoom( 4 );
|
|
}
|
|
|
|
Size CheckBox::ImplGetCheckImageSize() const
|
|
{
|
|
Size aSize;
|
|
bool bDefaultSize = true;
|
|
if( IsNativeControlSupported( ControlType::Checkbox, ControlPart::Entire ) )
|
|
{
|
|
ImplControlValue aControlValue;
|
|
tools::Rectangle aCtrlRegion( Point( 0, 0 ), GetSizePixel() );
|
|
tools::Rectangle aBoundingRgn, aContentRgn;
|
|
|
|
// get native size of a check box
|
|
if( GetNativeControlRegion( ControlType::Checkbox, ControlPart::Entire, aCtrlRegion,
|
|
ControlState::DEFAULT|ControlState::ENABLED,
|
|
aControlValue,
|
|
aBoundingRgn, aContentRgn ) )
|
|
{
|
|
aSize = aContentRgn.GetSize();
|
|
bDefaultSize = false;
|
|
}
|
|
}
|
|
if( bDefaultSize )
|
|
aSize = GetCheckImage( GetSettings(), DrawButtonFlags::NONE ).GetSizePixel();
|
|
return aSize;
|
|
}
|
|
|
|
Image CheckBox::GetCheckImage( const AllSettings& rSettings, DrawButtonFlags nFlags )
|
|
{
|
|
ImplSVData* pSVData = ImplGetSVData();
|
|
const StyleSettings& rStyleSettings = rSettings.GetStyleSettings();
|
|
sal_uInt16 nStyle = 0;
|
|
|
|
if ( rStyleSettings.GetOptions() & StyleSettingsOptions::Mono )
|
|
nStyle = STYLE_CHECKBOX_MONO;
|
|
|
|
if ( pSVData->maCtrlData.maCheckImgList.empty() ||
|
|
(pSVData->maCtrlData.mnCheckStyle != nStyle) ||
|
|
(pSVData->maCtrlData.mnLastCheckFColor != rStyleSettings.GetFaceColor()) ||
|
|
(pSVData->maCtrlData.mnLastCheckWColor != rStyleSettings.GetWindowColor()) ||
|
|
(pSVData->maCtrlData.mnLastCheckLColor != rStyleSettings.GetLightColor()) )
|
|
{
|
|
pSVData->maCtrlData.maCheckImgList.clear();
|
|
|
|
pSVData->maCtrlData.mnLastCheckFColor = rStyleSettings.GetFaceColor();
|
|
pSVData->maCtrlData.mnLastCheckWColor = rStyleSettings.GetWindowColor();
|
|
pSVData->maCtrlData.mnLastCheckLColor = rStyleSettings.GetLightColor();
|
|
|
|
std::vector<OUString> aResources;
|
|
if (nStyle)
|
|
{
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO1);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO2);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO3);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO4);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO5);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO6);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO7);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO8);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECKMONO9);
|
|
}
|
|
else
|
|
{
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECK1);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECK2);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECK3);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECK4);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECK5);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECK6);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECK7);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECK8);
|
|
aResources.emplace_back(SV_RESID_BITMAP_CHECK9);
|
|
}
|
|
LoadThemedImageList(rStyleSettings, pSVData->maCtrlData.maCheckImgList, aResources);
|
|
pSVData->maCtrlData.mnCheckStyle = nStyle;
|
|
}
|
|
|
|
sal_uInt16 nIndex;
|
|
if ( nFlags & DrawButtonFlags::Disabled )
|
|
{
|
|
if ( nFlags & DrawButtonFlags::DontKnow )
|
|
nIndex = 8;
|
|
else if ( nFlags & DrawButtonFlags::Checked )
|
|
nIndex = 5;
|
|
else
|
|
nIndex = 4;
|
|
}
|
|
else if ( nFlags & DrawButtonFlags::Pressed )
|
|
{
|
|
if ( nFlags & DrawButtonFlags::DontKnow )
|
|
nIndex = 7;
|
|
else if ( nFlags & DrawButtonFlags::Checked )
|
|
nIndex = 3;
|
|
else
|
|
nIndex = 2;
|
|
}
|
|
else
|
|
{
|
|
if ( nFlags & DrawButtonFlags::DontKnow )
|
|
nIndex = 6;
|
|
else if ( nFlags & DrawButtonFlags::Checked )
|
|
nIndex = 1;
|
|
else
|
|
nIndex = 0;
|
|
}
|
|
return pSVData->maCtrlData.maCheckImgList[nIndex];
|
|
}
|
|
|
|
void CheckBox::ImplSetMinimumNWFSize()
|
|
{
|
|
Push( PushFlags::MAPMODE );
|
|
SetMapMode(MapMode(MapUnit::MapPixel));
|
|
|
|
ImplControlValue aControlValue;
|
|
Size aCurSize( GetSizePixel() );
|
|
tools::Rectangle aCtrlRegion( Point( 0, 0 ), aCurSize );
|
|
tools::Rectangle aBoundingRgn, aContentRgn;
|
|
|
|
// get native size of a radiobutton
|
|
if( GetNativeControlRegion( ControlType::Checkbox, ControlPart::Entire, aCtrlRegion,
|
|
ControlState::DEFAULT|ControlState::ENABLED, aControlValue,
|
|
aBoundingRgn, aContentRgn ) )
|
|
{
|
|
Size aSize = aContentRgn.GetSize();
|
|
|
|
if( aSize.Height() > aCurSize.Height() )
|
|
{
|
|
aCurSize.setHeight( aSize.Height() );
|
|
SetSizePixel( aCurSize );
|
|
}
|
|
}
|
|
|
|
Pop();
|
|
}
|
|
|
|
Size CheckBox::CalcMinimumSize( long nMaxWidth ) const
|
|
{
|
|
Size aSize = ImplGetCheckImageSize();
|
|
nMaxWidth -= aSize.Width();
|
|
|
|
OUString aText = GetText();
|
|
if ( !aText.isEmpty() && ! (ImplGetButtonState() & DrawButtonFlags::NoText) )
|
|
{
|
|
// subtract what will be added later
|
|
nMaxWidth-=2;
|
|
nMaxWidth -= ImplGetImageToTextDistance();
|
|
|
|
Size aTextSize = GetTextRect( tools::Rectangle( Point(), Size( nMaxWidth > 0 ? nMaxWidth : 0x7fffffff, 0x7fffffff ) ),
|
|
aText, FixedText::ImplGetTextStyle( GetStyle() ) ).GetSize();
|
|
aSize.AdjustWidth(2 ); // for focus rect
|
|
aSize.AdjustWidth(ImplGetImageToTextDistance() );
|
|
aSize.AdjustWidth(aTextSize.Width() );
|
|
if ( aSize.Height() < aTextSize.Height() )
|
|
aSize.setHeight( aTextSize.Height() );
|
|
}
|
|
else
|
|
{
|
|
// is this still correct ? since the checkbox now
|
|
// shows a focus rect it should be 2 pixels wider and longer
|
|
/* since otherwise the controls in the Writer hang too far up
|
|
aSize.Width() += 2;
|
|
aSize.Height() += 2;
|
|
*/
|
|
}
|
|
|
|
return CalcWindowSize( aSize );
|
|
}
|
|
|
|
Size CheckBox::GetOptimalSize() const
|
|
{
|
|
int nWidthRequest(get_width_request());
|
|
return CalcMinimumSize(nWidthRequest != -1 ? nWidthRequest : 0);
|
|
}
|
|
|
|
void CheckBox::ShowFocus(const tools::Rectangle& rRect)
|
|
{
|
|
if (IsNativeControlSupported(ControlType::Checkbox, ControlPart::Focus))
|
|
{
|
|
ImplControlValue aControlValue;
|
|
tools::Rectangle aInRect(Point(0, 0), GetSizePixel());
|
|
|
|
aInRect.SetLeft( rRect.Left() ); // exclude the checkbox itself from the focusrect
|
|
|
|
DrawNativeControl(ControlType::Checkbox, ControlPart::Focus, aInRect,
|
|
ControlState::FOCUSED, aControlValue, OUString());
|
|
}
|
|
Button::ShowFocus(rRect);
|
|
}
|
|
|
|
FactoryFunction CheckBox::GetUITestFactory() const
|
|
{
|
|
return CheckBoxUIObject::create;
|
|
}
|
|
|
|
ImageButton::ImageButton( vcl::Window* pParent, WinBits nStyle ) :
|
|
PushButton( pParent, nStyle )
|
|
{
|
|
ImplInitStyle();
|
|
}
|
|
|
|
void ImageButton::ImplInitStyle()
|
|
{
|
|
WinBits nStyle = GetStyle();
|
|
|
|
if ( ! ( nStyle & ( WB_RIGHT | WB_LEFT ) ) )
|
|
nStyle |= WB_CENTER;
|
|
|
|
if ( ! ( nStyle & ( WB_TOP | WB_BOTTOM ) ) )
|
|
nStyle |= WB_VCENTER;
|
|
|
|
SetStyle( nStyle );
|
|
}
|
|
|
|
ImageRadioButton::ImageRadioButton( vcl::Window* pParent ) :
|
|
RadioButton( pParent, 0 )
|
|
{
|
|
}
|
|
|
|
TriStateBox::TriStateBox( vcl::Window* pParent, WinBits nStyle ) :
|
|
CheckBox( pParent, nStyle )
|
|
{
|
|
EnableTriState();
|
|
}
|
|
|
|
DisclosureButton::DisclosureButton( vcl::Window* pParent ) :
|
|
CheckBox( pParent, 0 )
|
|
{
|
|
}
|
|
|
|
void DisclosureButton::ImplDrawCheckBoxState(vcl::RenderContext& rRenderContext)
|
|
{
|
|
/* HACK: DisclosureButton is currently assuming, that the disclosure sign
|
|
will fit into the rectangle occupied by a normal checkbox on all themes.
|
|
If this does not hold true for some theme, ImplGetCheckImageSize
|
|
would have to be overridden for DisclosureButton; also GetNativeControlRegion
|
|
for ControlType::ListNode would have to be implemented and taken into account
|
|
*/
|
|
|
|
tools::Rectangle aStateRect(GetStateRect());
|
|
|
|
ImplControlValue aControlValue(GetState() == TRISTATE_TRUE ? ButtonValue::On : ButtonValue::Off);
|
|
tools::Rectangle aCtrlRegion(aStateRect);
|
|
ControlState nState = ControlState::NONE;
|
|
|
|
if (HasFocus())
|
|
nState |= ControlState::FOCUSED;
|
|
if (ImplGetButtonState() & DrawButtonFlags::Default)
|
|
nState |= ControlState::DEFAULT;
|
|
if (Window::IsEnabled())
|
|
nState |= ControlState::ENABLED;
|
|
if (IsMouseOver() && GetMouseRect().IsInside(GetPointerPosPixel()))
|
|
nState |= ControlState::ROLLOVER;
|
|
|
|
if (rRenderContext.DrawNativeControl(ControlType::ListNode, ControlPart::Entire, aCtrlRegion,
|
|
nState, aControlValue, OUString()))
|
|
return;
|
|
|
|
ImplSVCtrlData& rCtrlData(ImplGetSVData()->maCtrlData);
|
|
if (!rCtrlData.mpDisclosurePlus)
|
|
rCtrlData.mpDisclosurePlus.reset(new Image(StockImage::Yes, SV_DISCLOSURE_PLUS));
|
|
if (!rCtrlData.mpDisclosureMinus)
|
|
rCtrlData.mpDisclosureMinus.reset(new Image(StockImage::Yes, SV_DISCLOSURE_MINUS));
|
|
|
|
Image* pImg
|
|
= IsChecked() ? rCtrlData.mpDisclosureMinus.get() : rCtrlData.mpDisclosurePlus.get();
|
|
|
|
DrawImageFlags nStyle = DrawImageFlags::NONE;
|
|
if (!IsEnabled())
|
|
nStyle |= DrawImageFlags::Disable;
|
|
|
|
Size aSize(aStateRect.GetSize());
|
|
Size aImgSize(pImg->GetSizePixel());
|
|
Point aOff((aSize.Width() - aImgSize.Width()) / 2,
|
|
(aSize.Height() - aImgSize.Height()) / 2);
|
|
aOff += aStateRect.TopLeft();
|
|
rRenderContext.DrawImage(aOff, *pImg, nStyle);
|
|
}
|
|
|
|
void DisclosureButton::KeyInput( const KeyEvent& rKEvt )
|
|
{
|
|
vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
|
|
|
|
if( !aKeyCode.GetModifier() &&
|
|
( ( aKeyCode.GetCode() == KEY_ADD ) ||
|
|
( aKeyCode.GetCode() == KEY_SUBTRACT ) )
|
|
)
|
|
{
|
|
Check( aKeyCode.GetCode() == KEY_ADD );
|
|
}
|
|
else
|
|
CheckBox::KeyInput( rKEvt );
|
|
}
|
|
|
|
extern "C" SAL_DLLPUBLIC_EXPORT void makeSmallButton(VclPtr<vcl::Window> & rRet, VclPtr<vcl::Window> & pParent, VclBuilder::stringmap &)
|
|
{
|
|
rRet = VclPtr<PushButton>::Create(pParent, WB_CLIPCHILDREN|WB_CENTER|WB_VCENTER|WB_FLATBUTTON|WB_SMALLSTYLE);
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|