997 lines
39 KiB
C++
997 lines
39 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
#define _SV_SALNATIVEWIDGETS_KDE_CXX
|
|
|
|
#define Region QtXRegion
|
|
|
|
#include <QStyle>
|
|
#include <QStyleOption>
|
|
#include <QPainter>
|
|
#include <QFrame>
|
|
#include <QLabel>
|
|
|
|
#include <kapplication.h>
|
|
#include <kdebug.h>
|
|
|
|
#undef Region
|
|
|
|
#include "KDESalGraphics.hxx"
|
|
|
|
#include <vcl/settings.hxx>
|
|
#include <vcl/decoview.hxx>
|
|
#include <rtl/ustrbuf.hxx>
|
|
|
|
using namespace ::rtl;
|
|
|
|
/**
|
|
Conversion function between VCL ControlState together with
|
|
ImplControlValue and Qt state flags.
|
|
@param nControlState State of the widget (default, focused, ...) in Native Widget Framework.
|
|
@param aValue Value held by the widget (on, off, ...)
|
|
*/
|
|
QStyle::State vclStateValue2StateFlag( ControlState nControlState,
|
|
const ImplControlValue& aValue )
|
|
{
|
|
QStyle::State nState =
|
|
( (nControlState & CTRL_STATE_DEFAULT)? QStyle::State_None: QStyle::State_None ) |
|
|
( (nControlState & CTRL_STATE_ENABLED)? QStyle::State_Enabled: QStyle::State_None ) |
|
|
( (nControlState & CTRL_STATE_FOCUSED)? QStyle::State_HasFocus: QStyle::State_None ) |
|
|
( (nControlState & CTRL_STATE_PRESSED)? QStyle::State_Sunken: QStyle::State_None ) |
|
|
( (nControlState & CTRL_STATE_SELECTED)? QStyle::State_Selected : QStyle::State_None ) |
|
|
( (nControlState & CTRL_STATE_ROLLOVER)? QStyle::State_MouseOver: QStyle::State_None );
|
|
//TODO ( (nControlState & CTRL_STATE_HIDDEN)? QStyle::State_: QStyle::State_None ) |
|
|
|
|
switch ( aValue.getTristateVal() )
|
|
{
|
|
case BUTTONVALUE_ON: nState |= QStyle::State_On; break;
|
|
case BUTTONVALUE_OFF: nState |= QStyle::State_Off; break;
|
|
case BUTTONVALUE_MIXED: nState |= QStyle::State_NoChange; break;
|
|
default: break;
|
|
}
|
|
|
|
return nState;
|
|
}
|
|
|
|
/**
|
|
Convert VCL Rectangle to QRect.
|
|
@param rControlRegion The Rectangle to convert.
|
|
@return The matching QRect
|
|
*/
|
|
QRect region2QRect( const Rectangle& rControlRegion )
|
|
{
|
|
return QRect(rControlRegion.Left(), rControlRegion.Top(), rControlRegion.GetWidth(), rControlRegion.GetHeight());
|
|
}
|
|
|
|
KDESalGraphics::KDESalGraphics() :
|
|
m_image(0)
|
|
{
|
|
}
|
|
|
|
KDESalGraphics::~KDESalGraphics()
|
|
{
|
|
if (m_image)
|
|
delete m_image;
|
|
}
|
|
|
|
sal_Bool KDESalGraphics::IsNativeControlSupported( ControlType type, ControlPart part )
|
|
{
|
|
if (type == CTRL_PUSHBUTTON) return true;
|
|
|
|
if (type == CTRL_MENUBAR) return true;
|
|
|
|
if (type == CTRL_MENU_POPUP) return true;
|
|
|
|
if (type == CTRL_EDITBOX) return true;
|
|
|
|
if (type == CTRL_COMBOBOX) return true;
|
|
|
|
if (type == CTRL_TOOLBAR) return true;
|
|
|
|
if (type == CTRL_CHECKBOX) return true;
|
|
|
|
if (type == CTRL_LISTBOX) return true;
|
|
|
|
if (type == CTRL_LISTNODE) return true;
|
|
|
|
if (type == CTRL_FRAME) return true;
|
|
|
|
if (type == CTRL_SCROLLBAR) return true;
|
|
|
|
if (type == CTRL_WINDOW_BACKGROUND) return true;
|
|
|
|
if (type == CTRL_SPINBOX && (part == PART_ENTIRE_CONTROL || part == HAS_BACKGROUND_TEXTURE) ) return true;
|
|
|
|
// no spinbuttons for KDE, paint spinbox complete
|
|
//if (type == CTRL_SPINBUTTONS) return true;
|
|
|
|
if (type == CTRL_GROUPBOX) return true;
|
|
|
|
if (type == CTRL_FIXEDLINE) return true;
|
|
|
|
if (type == CTRL_FIXEDBORDER) return true;
|
|
|
|
if (type == CTRL_TOOLTIP) return true;
|
|
|
|
if (type == CTRL_RADIOBUTTON) return true;
|
|
|
|
if (type == CTRL_SLIDER && (part == PART_TRACK_HORZ_AREA || part == PART_TRACK_VERT_AREA) )
|
|
return true;
|
|
|
|
if ( (type == CTRL_PROGRESS) && (part == PART_ENTIRE_CONTROL) ) return true;
|
|
|
|
return false;
|
|
|
|
if ( (type == CTRL_TAB_ITEM) && (part == PART_ENTIRE_CONTROL) ) return true;
|
|
if ( (type == CTRL_TAB_PANE) && (part == PART_ENTIRE_CONTROL) ) return true;
|
|
// no CTRL_TAB_BODY for KDE
|
|
|
|
return false;
|
|
}
|
|
|
|
/// helper drawing methods
|
|
namespace
|
|
{
|
|
void draw( QStyle::ControlElement element, QStyleOption* option, QImage* image, QStyle::State state, QRect rect = QRect())
|
|
{
|
|
option->state |= state;
|
|
option->rect = !rect.isNull() ? rect : image->rect();
|
|
|
|
QPainter painter(image);
|
|
kapp->style()->drawControl(element, option, &painter);
|
|
}
|
|
|
|
void draw( QStyle::PrimitiveElement element, QStyleOption* option, QImage* image, QStyle::State state, QRect rect = QRect())
|
|
{
|
|
option->state |= state;
|
|
option->rect = !rect.isNull() ? rect : image->rect();
|
|
|
|
QPainter painter(image);
|
|
kapp->style()->drawPrimitive(element, option, &painter);
|
|
}
|
|
|
|
void draw( QStyle::ComplexControl element, QStyleOptionComplex* option, QImage* image, QStyle::State state )
|
|
{
|
|
option->state |= state;
|
|
option->rect = image->rect();
|
|
|
|
QPainter painter(image);
|
|
kapp->style()->drawComplexControl(element, option, &painter);
|
|
}
|
|
|
|
int getFrameWidth()
|
|
{
|
|
static int s_nFrameWidth = -1;
|
|
if( s_nFrameWidth < 0 )
|
|
{
|
|
// fill in a default
|
|
s_nFrameWidth = 2;
|
|
QFrame aFrame( NULL );
|
|
aFrame.setFrameRect( QRect(0, 0, 100, 30) );
|
|
aFrame.setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
|
|
aFrame.ensurePolished();
|
|
s_nFrameWidth = aFrame.frameWidth();
|
|
}
|
|
return s_nFrameWidth;
|
|
}
|
|
|
|
void lcl_drawFrame(QStyle::PrimitiveElement element, QImage* image, QStyle::State state)
|
|
{
|
|
#if ( QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 ) )
|
|
QStyleOptionFrameV3 option;
|
|
option.frameShape = QFrame::StyledPanel;
|
|
option.state = QStyle::State_Sunken;
|
|
#else
|
|
QStyleOptionFrame option;
|
|
|
|
QFrame aFrame( NULL );
|
|
aFrame.setFrameRect( QRect(0, 0, image->width(), image->height()) );
|
|
aFrame.setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
|
|
aFrame.ensurePolished();
|
|
|
|
option.initFrom( &aFrame );
|
|
option.lineWidth = aFrame.lineWidth();
|
|
option.midLineWidth = aFrame.midLineWidth();
|
|
#endif
|
|
|
|
draw(element, &option, image, state);
|
|
}
|
|
}
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 )
|
|
#define IMAGE_BASED_PAINTING
|
|
#else
|
|
#undef IMAGE_BASED_PAINTING
|
|
#endif
|
|
|
|
#ifdef IMAGE_BASED_PAINTING
|
|
// There is a small catch with this function, although hopefully only philosophical.
|
|
// Officially Xlib's Region is an opaque data type, with only functions for manipulating it.
|
|
// However, whoever designed it apparently didn't give it that much thought, as it's impossible
|
|
// to find out what exactly a region actually is (except for really weird ways like XClipBox()
|
|
// and repeated XPointInRegion(), which would be awfully slow). Fortunately, the header file
|
|
// describing the structure actually happens to be installed too, and there's at least one
|
|
// widely used software using it (Compiz). So access the data directly too and assume that
|
|
// everybody who compiles with Qt4 support has Xlib new enough and good enough to support this.
|
|
// In case this doesn't work for somebody, try #include <X11/region.h> instead, or build
|
|
// without IMAGE_BASED_PAINTING (in which case QApplication::setGraphicsSystem( "native" ) may
|
|
// be needed too).
|
|
#include <X11/Xregion.h>
|
|
static QRegion XRegionToQRegion( XLIB_Region xr )
|
|
{
|
|
QRegion qr;
|
|
for( int i = 0;
|
|
i < xr->numRects;
|
|
++i )
|
|
{
|
|
BOX& b = xr->rects[ i ];
|
|
qr |= QRect( b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1 ); // x2,y2 is outside, not the bottom-right corner
|
|
}
|
|
return qr;
|
|
}
|
|
#endif
|
|
|
|
sal_Bool KDESalGraphics::drawNativeControl( ControlType type, ControlPart part,
|
|
const Rectangle& rControlRegion, ControlState nControlState,
|
|
const ImplControlValue& value,
|
|
const OUString& )
|
|
{
|
|
if( lastPopupRect.isValid() && ( type != CTRL_MENU_POPUP || part != PART_MENU_ITEM ))
|
|
lastPopupRect = QRect();
|
|
|
|
// put not implemented types here
|
|
if (type == CTRL_SPINBUTTONS)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
sal_Bool returnVal = true;
|
|
|
|
QRect widgetRect = region2QRect(rControlRegion);
|
|
if( type == CTRL_SPINBOX && part == PART_ALL_BUTTONS )
|
|
type = CTRL_SPINBUTTONS;
|
|
if( type == CTRL_SPINBUTTONS )
|
|
{
|
|
OSL_ASSERT( value.getType() != CTRL_SPINBUTTONS );
|
|
const SpinbuttonValue* pSpinVal = static_cast<const SpinbuttonValue *>(&value);
|
|
Rectangle aButtonRect( pSpinVal->maUpperRect);
|
|
aButtonRect.Union( pSpinVal->maLowerRect );;
|
|
widgetRect = QRect( aButtonRect.Left(), aButtonRect.Top(),
|
|
aButtonRect.Right(), aButtonRect.Bottom() );
|
|
}
|
|
|
|
//if no image, or resized, make a new image
|
|
if (!m_image || m_image->size() != widgetRect.size())
|
|
{
|
|
if (m_image)
|
|
delete m_image;
|
|
|
|
m_image = new QImage( widgetRect.width(),
|
|
widgetRect.height(),
|
|
QImage::Format_ARGB32 );
|
|
}
|
|
m_image->fill(KApplication::palette().color(QPalette::Window).rgb());
|
|
|
|
QRegion* clipRegion = NULL;
|
|
|
|
if (type == CTRL_PUSHBUTTON)
|
|
{
|
|
QStyleOptionButton option;
|
|
draw( QStyle::CE_PushButton, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else if ( (type == CTRL_MENUBAR))
|
|
{
|
|
if (part == PART_MENU_ITEM)
|
|
{
|
|
QStyleOptionMenuItem option;
|
|
draw( QStyle::CE_MenuBarItem, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else if (part == PART_ENTIRE_CONTROL)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
returnVal = false;
|
|
}
|
|
}
|
|
else if (type == CTRL_MENU_POPUP)
|
|
{
|
|
OSL_ASSERT( part == PART_MENU_ITEM ? lastPopupRect.isValid() : !lastPopupRect.isValid());
|
|
if( part == PART_MENU_ITEM )
|
|
{
|
|
QStyleOptionMenuItem option;
|
|
draw( QStyle::CE_MenuItem, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
// HACK: LO core first paints the entire popup and only then it paints menu items,
|
|
// but QMenu::paintEvent() paints popup frame after all items. That means highlighted
|
|
// items here would paint the highlight over the frame border. Since calls to PART_MENU_ITEM
|
|
// are always preceded by calls to PART_ENTIRE_CONTROL, just remember the size for the whole
|
|
// popup (otherwise not possible to get here) and draw the border afterwards.
|
|
QRect framerect( lastPopupRect.topLeft() - widgetRect.topLeft(),
|
|
widgetRect.size().expandedTo( lastPopupRect.size()));
|
|
QStyleOptionFrame frame;
|
|
draw( QStyle::PE_FrameMenu, &frame, m_image, vclStateValue2StateFlag( nControlState, value ), framerect );
|
|
}
|
|
else if( part == PART_MENU_SEPARATOR )
|
|
{
|
|
QStyleOptionMenuItem option;
|
|
option.menuItemType = QStyleOptionMenuItem::Separator;
|
|
// Painting the whole menu item area results in different background
|
|
// with at least Plastique style, so clip only to the separator itself
|
|
// (QSize( 2, 2 ) is hardcoded in Qt)
|
|
option.rect = m_image->rect();
|
|
QSize size = kapp->style()->sizeFromContents( QStyle::CT_MenuItem, &option, QSize( 2, 2 ));
|
|
QRect rect = m_image->rect();
|
|
QPoint center = rect.center();
|
|
rect.setHeight( size.height());
|
|
rect.moveCenter( center );
|
|
// don't paint over popup frame border (like the hack above, but here it can be simpler)
|
|
int fw = kapp->style()->pixelMetric( QStyle::PM_MenuPanelWidth );
|
|
clipRegion = new QRegion( rect.translated( widgetRect.topLeft()).adjusted( fw, 0, -fw, 0 ));
|
|
draw( QStyle::CE_MenuItem, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value), rect );
|
|
}
|
|
else if( part == PART_MENU_ITEM_CHECK_MARK || part == PART_MENU_ITEM_RADIO_MARK )
|
|
{
|
|
QStyleOptionMenuItem option;
|
|
option.checkType = ( part == PART_MENU_ITEM_CHECK_MARK )
|
|
? QStyleOptionMenuItem::NonExclusive : QStyleOptionMenuItem::Exclusive;
|
|
option.checked = ( nControlState & CTRL_STATE_PRESSED );
|
|
// widgetRect is now the rectangle for the checkbox/radiobutton itself, but Qt
|
|
// paints the whole menu item, so translate position (and it'll be clipped);
|
|
// it is also necessary to fill the background transparently first, as this
|
|
// is painted after menuitem highlight, otherwise there would be a grey area
|
|
const MenupopupValue* menuVal = static_cast<const MenupopupValue*>(&value);
|
|
QRect menuItemRect( region2QRect( menuVal->maItemRect ));
|
|
QRect rect( menuItemRect.topLeft() - widgetRect.topLeft(),
|
|
widgetRect.size().expandedTo( menuItemRect.size()));
|
|
m_image->fill( Qt::transparent );
|
|
draw( QStyle::CE_MenuItem, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value), rect );
|
|
}
|
|
else if( part == PART_ENTIRE_CONTROL )
|
|
{
|
|
QStyleOptionMenuItem option;
|
|
draw( QStyle::PE_PanelMenu, &option, m_image, vclStateValue2StateFlag( nControlState, value ));
|
|
QStyleOptionFrame frame;
|
|
draw( QStyle::PE_FrameMenu, &frame, m_image, vclStateValue2StateFlag( nControlState, value ));
|
|
lastPopupRect = widgetRect;
|
|
}
|
|
else
|
|
returnVal = false;
|
|
}
|
|
else if ( (type == CTRL_TOOLBAR) && (part == PART_BUTTON) )
|
|
{
|
|
QStyleOptionToolButton option;
|
|
|
|
option.arrowType = Qt::NoArrow;
|
|
option.subControls = QStyle::SC_ToolButton;
|
|
|
|
option.state = vclStateValue2StateFlag( nControlState, value );
|
|
option.state |= QStyle::State_Raised | QStyle::State_Enabled | QStyle::State_AutoRaise;
|
|
|
|
draw( QStyle::CC_ToolButton, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else if ( (type == CTRL_TOOLBAR) && (part == PART_ENTIRE_CONTROL) )
|
|
{
|
|
QStyleOptionToolBar option;
|
|
|
|
option.rect = QRect(0, 0, widgetRect.width(), widgetRect.height());
|
|
option.state = vclStateValue2StateFlag( nControlState, value );
|
|
|
|
draw( QStyle::CE_ToolBar, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else if ( (type == CTRL_TOOLBAR) && (part == PART_THUMB_VERT) )
|
|
{ // reduce paint area only to the handle area
|
|
const int width = kapp->style()->pixelMetric(QStyle::PM_ToolBarHandleExtent);
|
|
QRect rect( 0, 0, width, widgetRect.height());
|
|
clipRegion = new QRegion( widgetRect.x(), widgetRect.y(), width, widgetRect.height());
|
|
|
|
QStyleOption option;
|
|
option.state = QStyle::State_Horizontal;
|
|
|
|
draw( QStyle::PE_IndicatorToolBarHandle, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value), rect );
|
|
}
|
|
else if (type == CTRL_EDITBOX)
|
|
{
|
|
QStyleOptionFrameV2 option;
|
|
draw( QStyle::PE_PanelLineEdit, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value), m_image->rect().adjusted( 2, 2, -2, -2 ));
|
|
|
|
draw( QStyle::PE_FrameLineEdit, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value));
|
|
}
|
|
else if (type == CTRL_COMBOBOX)
|
|
{
|
|
QStyleOptionComboBox option;
|
|
option.editable = true;
|
|
|
|
draw( QStyle::CC_ComboBox, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else if (type == CTRL_LISTBOX)
|
|
{
|
|
if( part == PART_WINDOW )
|
|
{
|
|
lcl_drawFrame( QStyle::PE_Frame, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else
|
|
{
|
|
QStyleOptionComboBox option;
|
|
if (part == PART_SUB_EDIT)
|
|
{
|
|
draw( QStyle::CE_ComboBoxLabel, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else
|
|
{
|
|
draw( QStyle::CC_ComboBox, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
}
|
|
}
|
|
else if (type == CTRL_LISTNODE)
|
|
{
|
|
QStyleOption option;
|
|
option.state = QStyle::State_Item | QStyle::State_Children;
|
|
|
|
if (nControlState & CTRL_STATE_PRESSED)
|
|
option.state |= QStyle::State_Open;
|
|
|
|
draw( QStyle::PE_IndicatorBranch, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else if (type == CTRL_CHECKBOX)
|
|
{
|
|
QStyleOptionButton option;
|
|
draw( QStyle::CE_CheckBox, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else if (type == CTRL_SCROLLBAR)
|
|
{
|
|
if ((part == PART_DRAW_BACKGROUND_VERT) || (part == PART_DRAW_BACKGROUND_HORZ))
|
|
{
|
|
QStyleOptionSlider option;
|
|
OSL_ASSERT( value.getType() == CTRL_SCROLLBAR );
|
|
const ScrollbarValue* sbVal = static_cast<const ScrollbarValue *>(&value);
|
|
|
|
//if the scroll bar is active (aka not degenrate...allow for hover events
|
|
if (sbVal->mnVisibleSize < sbVal->mnMax)
|
|
option.state = QStyle::State_MouseOver;
|
|
|
|
bool horizontal = ( part == PART_DRAW_BACKGROUND_HORZ ); //horizontal or vertical
|
|
option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical;
|
|
if( horizontal )
|
|
option.state |= QStyle::State_Horizontal;
|
|
|
|
//setup parameters from the OO values
|
|
option.minimum = sbVal->mnMin;
|
|
option.maximum = sbVal->mnMax - sbVal->mnVisibleSize;
|
|
option.maximum = qMax( option.maximum, option.minimum ); // bnc#619772
|
|
option.sliderValue = sbVal->mnCur;
|
|
option.sliderPosition = sbVal->mnCur;
|
|
option.pageStep = sbVal->mnVisibleSize;
|
|
|
|
//setup the active control...always the slider
|
|
if (sbVal->mnThumbState & CTRL_STATE_ROLLOVER)
|
|
option.activeSubControls = QStyle::SC_ScrollBarSlider;
|
|
|
|
draw( QStyle::CC_ScrollBar, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else
|
|
{
|
|
returnVal = false;
|
|
}
|
|
}
|
|
else if (type == CTRL_SPINBOX)
|
|
{
|
|
QStyleOptionSpinBox option;
|
|
|
|
// determine active control
|
|
if( value.getType() == CTRL_SPINBUTTONS )
|
|
{
|
|
const SpinbuttonValue* pSpinVal = static_cast<const SpinbuttonValue *>(&value);
|
|
if( (pSpinVal->mnUpperState & CTRL_STATE_PRESSED) )
|
|
option.activeSubControls |= QStyle::SC_SpinBoxUp;
|
|
if( (pSpinVal->mnLowerState & CTRL_STATE_PRESSED) )
|
|
option.activeSubControls |= QStyle::SC_SpinBoxDown;
|
|
}
|
|
|
|
draw( QStyle::CC_SpinBox, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else if (type == CTRL_GROUPBOX)
|
|
{
|
|
QStyleOptionGroupBox option;
|
|
draw( QStyle::CC_GroupBox, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else if (type == CTRL_RADIOBUTTON)
|
|
{
|
|
QStyleOptionButton option;
|
|
draw( QStyle::CE_RadioButton, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else if (type == CTRL_TOOLTIP)
|
|
{
|
|
QStyleOption option;
|
|
draw( QStyle::PE_PanelTipLabel, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else if (type == CTRL_FRAME)
|
|
{
|
|
lcl_drawFrame( QStyle::PE_Frame, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
|
|
// draw just the border, see http://qa.openoffice.org/issues/show_bug.cgi?id=107945
|
|
int fw = getFrameWidth();
|
|
clipRegion = new QRegion( QRegion( widgetRect ).subtracted( widgetRect.adjusted( fw, fw, -fw, -fw )));
|
|
}
|
|
else if (type == CTRL_FIXEDBORDER)
|
|
{
|
|
lcl_drawFrame( QStyle::PE_FrameWindow, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else if (type == CTRL_WINDOW_BACKGROUND)
|
|
{
|
|
m_image->fill(KApplication::palette().color(QPalette::Window).rgb());
|
|
}
|
|
else if (type == CTRL_FIXEDLINE)
|
|
{
|
|
QStyleOptionMenuItem option;
|
|
option.menuItemType = QStyleOptionMenuItem::Separator;
|
|
option.state |= QStyle::State_Item;
|
|
|
|
draw( QStyle::CE_MenuItem, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else if (type == CTRL_SLIDER && (part == PART_TRACK_HORZ_AREA || part == PART_TRACK_VERT_AREA))
|
|
{
|
|
OSL_ASSERT( value.getType() == CTRL_SLIDER );
|
|
const SliderValue* slVal = static_cast<const SliderValue *>(&value);
|
|
QStyleOptionSlider option;
|
|
|
|
option.rect = QRect(0, 0, widgetRect.width(), widgetRect.height());
|
|
option.state = vclStateValue2StateFlag( nControlState, value );
|
|
option.maximum = slVal->mnMax;
|
|
option.minimum = slVal->mnMin;
|
|
option.sliderPosition = option.sliderValue = slVal->mnCur;
|
|
bool horizontal = ( part == PART_TRACK_HORZ_AREA ); //horizontal or vertical
|
|
option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical;
|
|
if( horizontal )
|
|
option.state |= QStyle::State_Horizontal;
|
|
|
|
draw( QStyle::CC_Slider, &option, m_image, vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else if( type == CTRL_PROGRESS && part == PART_ENTIRE_CONTROL )
|
|
{
|
|
QStyleOptionProgressBarV2 option;
|
|
option.minimum = 0;
|
|
option.maximum = widgetRect.width();
|
|
option.progress = value.getNumericVal();
|
|
option.rect = QRect(0, 0, widgetRect.width(), widgetRect.height());
|
|
option.state = vclStateValue2StateFlag( nControlState, value );
|
|
|
|
draw( QStyle::CE_ProgressBar, &option, m_image,
|
|
vclStateValue2StateFlag(nControlState, value) );
|
|
}
|
|
else
|
|
{
|
|
returnVal = false;
|
|
}
|
|
|
|
if (returnVal)
|
|
{
|
|
#ifdef IMAGE_BASED_PAINTING
|
|
// Create a wrapper QPixmap around the destination pixmap, allowing the use of QPainter.
|
|
// Using X11SalGraphics::CopyScreenArea() would require using QPixmap and if Qt uses
|
|
// other graphics system than native, QPixmap::handle() would be 0 (i.e. it wouldn't work),
|
|
// I have no idea how to create QPixmap with non-null handle() in such case, so go this way.
|
|
// See XRegionToQRegion() comment for a small catch (although not real hopefully).
|
|
QPixmap destPixmap = QPixmap::fromX11Pixmap( GetDrawable(), QPixmap::ExplicitlyShared );
|
|
QPainter paint( &destPixmap );
|
|
if( clipRegion && mpClipRegion )
|
|
paint.setClipRegion( clipRegion->intersected( XRegionToQRegion( mpClipRegion )));
|
|
else if( clipRegion )
|
|
paint.setClipRegion( *clipRegion );
|
|
else if( mpClipRegion )
|
|
paint.setClipRegion( XRegionToQRegion( mpClipRegion ));
|
|
paint.drawImage( widgetRect.left(), widgetRect.top(), *m_image,
|
|
0, 0, widgetRect.width(), widgetRect.height(),
|
|
Qt::ColorOnly | Qt::OrderedDither | Qt::OrderedAlphaDither );
|
|
#else
|
|
GC gc = SelectFont();
|
|
if( gc )
|
|
{
|
|
XLIB_Region pTempClipRegion = NULL;
|
|
if( clipRegion )
|
|
{
|
|
pTempClipRegion = XCreateRegion();
|
|
foreach( const QRect& r, clipRegion->rects())
|
|
{
|
|
XRectangle xr;
|
|
xr.x = r.x();
|
|
xr.y = r.y();
|
|
xr.width = r.width();
|
|
xr.height = r.height();
|
|
XUnionRectWithRegion( &xr, pTempClipRegion, pTempClipRegion );
|
|
}
|
|
if( mpClipRegion )
|
|
XIntersectRegion( pTempClipRegion, mpClipRegion, pTempClipRegion );
|
|
XSetRegion( GetXDisplay(), gc, pTempClipRegion );
|
|
}
|
|
QPixmap pixmap = QPixmap::fromImage(*m_image, Qt::ColorOnly | Qt::OrderedDither | Qt::OrderedAlphaDither);
|
|
X11SalGraphics::CopyScreenArea( GetXDisplay(),
|
|
pixmap.handle(), pixmap.x11Info().screen(), pixmap.x11Info().depth(),
|
|
GetDrawable(), GetScreenNumber(), GetVisual().GetDepth(),
|
|
gc, 0, 0, widgetRect.width(), widgetRect.height(), widgetRect.left(), widgetRect.top());
|
|
|
|
if( pTempClipRegion )
|
|
{
|
|
if( mpClipRegion )
|
|
XSetRegion( GetXDisplay(), gc, mpClipRegion );
|
|
else
|
|
XSetClipMask( GetXDisplay(), gc, None );
|
|
XDestroyRegion( pTempClipRegion );
|
|
}
|
|
}
|
|
else
|
|
returnVal = false;
|
|
#endif
|
|
}
|
|
delete clipRegion;
|
|
return returnVal;
|
|
}
|
|
|
|
sal_Bool KDESalGraphics::getNativeControlRegion( ControlType type, ControlPart part,
|
|
const Rectangle& controlRegion, ControlState controlState,
|
|
const ImplControlValue& val,
|
|
const OUString&,
|
|
Rectangle &nativeBoundingRegion, Rectangle &nativeContentRegion )
|
|
{
|
|
sal_Bool retVal = false;
|
|
|
|
QRect boundingRect = region2QRect( controlRegion );
|
|
QRect contentRect = boundingRect;
|
|
QStyleOptionComplex styleOption;
|
|
|
|
switch ( type )
|
|
{
|
|
// Metrics of the push button
|
|
case CTRL_PUSHBUTTON:
|
|
if (part == PART_ENTIRE_CONTROL)
|
|
{
|
|
styleOption.state = vclStateValue2StateFlag(controlState, val);
|
|
|
|
if ( controlState & CTRL_STATE_DEFAULT )
|
|
{
|
|
int size = kapp->style()->pixelMetric(
|
|
QStyle::PM_ButtonDefaultIndicator, &styleOption );
|
|
|
|
boundingRect.adjust( -size, -size, size, size );
|
|
|
|
retVal = true;
|
|
}
|
|
}
|
|
break;
|
|
case CTRL_EDITBOX:
|
|
{
|
|
int nFontHeight = kapp->fontMetrics().height();
|
|
//int nFrameSize = kapp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
|
int nLayoutTop = kapp->style()->pixelMetric(QStyle::PM_LayoutTopMargin);
|
|
int nLayoutBottom = kapp->style()->pixelMetric(QStyle::PM_LayoutBottomMargin);
|
|
int nLayoutLeft = kapp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
|
|
int nLayoutRight = kapp->style()->pixelMetric(QStyle::PM_LayoutRightMargin);
|
|
|
|
int nMinHeight = (nFontHeight + nLayoutTop + nLayoutBottom);
|
|
if( boundingRect.height() < nMinHeight )
|
|
{
|
|
int delta = nMinHeight - boundingRect.height();
|
|
boundingRect.adjust( 0, 0, 0, delta );
|
|
}
|
|
contentRect = boundingRect;
|
|
contentRect.adjust( -nLayoutLeft+1, -nLayoutTop+1, nLayoutRight-1, nLayoutBottom-1 );
|
|
retVal = true;
|
|
|
|
break;
|
|
}
|
|
case CTRL_CHECKBOX:
|
|
if (part == PART_ENTIRE_CONTROL)
|
|
{
|
|
styleOption.state = vclStateValue2StateFlag(controlState, val);
|
|
|
|
contentRect.setWidth(kapp->style()->pixelMetric(
|
|
QStyle::PM_IndicatorWidth, &styleOption));
|
|
contentRect.setHeight(kapp->style()->pixelMetric(
|
|
QStyle::PM_IndicatorHeight, &styleOption));
|
|
|
|
contentRect.adjust(0, 0,
|
|
2 * kapp->style()->pixelMetric(
|
|
QStyle::PM_FocusFrameHMargin, &styleOption),
|
|
2 * kapp->style()->pixelMetric(
|
|
QStyle::PM_FocusFrameVMargin, &styleOption)
|
|
);
|
|
|
|
boundingRect = contentRect;
|
|
|
|
retVal = true;
|
|
|
|
break;
|
|
}
|
|
case CTRL_COMBOBOX:
|
|
case CTRL_LISTBOX:
|
|
{
|
|
QStyleOptionComboBox cbo;
|
|
|
|
cbo.rect = QRect(0, 0, contentRect.width(), contentRect.height());
|
|
cbo.state = vclStateValue2StateFlag(controlState, val);
|
|
|
|
switch ( part )
|
|
{
|
|
case PART_ENTIRE_CONTROL:
|
|
{
|
|
int size = kapp->style()->pixelMetric(QStyle::PM_ComboBoxFrameWidth) - 2;
|
|
|
|
// find out the minimum size that should be used
|
|
// assume contents is a text ling
|
|
int nHeight = kapp->fontMetrics().height();
|
|
QSize aContentSize( contentRect.width(), nHeight );
|
|
QSize aMinSize = kapp->style()->
|
|
sizeFromContents( QStyle::CT_ComboBox, &cbo, aContentSize );
|
|
if( aMinSize.height() > contentRect.height() )
|
|
contentRect.adjust( 0, 0, 0, aMinSize.height() - contentRect.height() );
|
|
boundingRect = contentRect;
|
|
// FIXME: why this difference between comboboxes and listboxes ?
|
|
// because a combobox has a sub edit and that is positioned
|
|
// inside the outer bordered control ?
|
|
if( type == CTRL_COMBOBOX )
|
|
contentRect.adjust(-size,-size,size,size);
|
|
retVal = true;
|
|
break;
|
|
}
|
|
case PART_BUTTON_DOWN:
|
|
//the entire control can be used as the "down" button
|
|
retVal = true;
|
|
break;
|
|
case PART_SUB_EDIT:
|
|
contentRect = kapp->style()->subControlRect(
|
|
QStyle::CC_ComboBox, &cbo, QStyle::SC_ComboBoxEditField );
|
|
|
|
contentRect.translate( boundingRect.left(), boundingRect.top() );
|
|
|
|
retVal = true;
|
|
break;
|
|
case PART_WINDOW:
|
|
retVal = true;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case CTRL_SPINBOX:
|
|
{
|
|
QStyleOptionSpinBox sbo;
|
|
|
|
sbo.rect = QRect(0, 0, contentRect.width(), contentRect.height());
|
|
sbo.state = vclStateValue2StateFlag(controlState, val);
|
|
|
|
switch ( part )
|
|
{
|
|
case PART_BUTTON_UP:
|
|
contentRect = kapp->style()->subControlRect(
|
|
QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxUp );
|
|
contentRect.translate( boundingRect.left(), boundingRect.top() );
|
|
retVal = true;
|
|
boundingRect = QRect();
|
|
break;
|
|
|
|
case PART_BUTTON_DOWN:
|
|
contentRect = kapp->style()->subControlRect(
|
|
QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxDown );
|
|
retVal = true;
|
|
contentRect.translate( boundingRect.left(), boundingRect.top() );
|
|
boundingRect = QRect();
|
|
break;
|
|
|
|
case PART_SUB_EDIT:
|
|
contentRect = kapp->style()->subControlRect(
|
|
QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxEditField );
|
|
retVal = true;
|
|
contentRect.translate( boundingRect.left(), boundingRect.top() );
|
|
break;
|
|
default:
|
|
retVal = true;
|
|
}
|
|
break;
|
|
}
|
|
case CTRL_MENU_POPUP:
|
|
if (part == PART_MENU_ITEM_CHECK_MARK || part == PART_MENU_ITEM_RADIO_MARK)
|
|
{ // core uses this to detect radio/checkbox sizes, so just set a square
|
|
contentRect.setWidth(contentRect.height());
|
|
retVal = true;
|
|
}
|
|
break;
|
|
case CTRL_FRAME:
|
|
{
|
|
if( part == PART_BORDER )
|
|
{
|
|
int nFrameWidth = getFrameWidth();
|
|
sal_uInt16 nStyle = val.getNumericVal();
|
|
if( nStyle & FRAME_DRAW_NODRAW )
|
|
{
|
|
// in this case the question is: how thick would a frame be
|
|
// see brdwin.cxx, decoview.cxx
|
|
// most probably the behavior in decoview.cxx is wrong.
|
|
contentRect.adjust(nFrameWidth, nFrameWidth, -nFrameWidth, -nFrameWidth);
|
|
}
|
|
retVal = true;
|
|
}
|
|
break;
|
|
}
|
|
case CTRL_RADIOBUTTON:
|
|
{
|
|
const int h = kapp->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorHeight);
|
|
const int w = kapp->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth);
|
|
|
|
contentRect = QRect(boundingRect.left(), boundingRect.top(), w, h);
|
|
contentRect.adjust(0, 0,
|
|
2 * kapp->style()->pixelMetric(
|
|
QStyle::PM_FocusFrameHMargin, &styleOption),
|
|
2 * kapp->style()->pixelMetric(
|
|
QStyle::PM_FocusFrameVMargin, &styleOption)
|
|
);
|
|
boundingRect = contentRect;
|
|
|
|
retVal = true;
|
|
break;
|
|
}
|
|
case CTRL_SLIDER:
|
|
{
|
|
const int w = kapp->style()->pixelMetric(QStyle::PM_SliderLength);
|
|
if( part == PART_THUMB_HORZ )
|
|
{
|
|
contentRect = QRect(boundingRect.left(), boundingRect.top(), w, boundingRect.height());
|
|
boundingRect = contentRect;
|
|
retVal = true;
|
|
}
|
|
else if( part == PART_THUMB_VERT )
|
|
{
|
|
contentRect = QRect(boundingRect.left(), boundingRect.top(), boundingRect.width(), w);
|
|
boundingRect = contentRect;
|
|
retVal = true;
|
|
}
|
|
break;
|
|
}
|
|
case CTRL_SCROLLBAR:
|
|
{
|
|
// core can't handle 3-button scrollbars well, so we fix that in hitTestNativeControl(),
|
|
// for the rest also provide the track area (i.e. area not taken by buttons)
|
|
if( part == PART_TRACK_VERT_AREA || part == PART_TRACK_HORZ_AREA )
|
|
{
|
|
QStyleOptionSlider option;
|
|
bool horizontal = ( part == PART_TRACK_HORZ_AREA ); //horizontal or vertical
|
|
option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical;
|
|
if( horizontal )
|
|
option.state |= QStyle::State_Horizontal;
|
|
// getNativeControlRegion usually gets ImplControlValue as 'val' (i.e. not the proper
|
|
// subclass), so use random sensible values (doesn't matter anyway, as the wanted
|
|
// geometry here depends only on button sizes)
|
|
option.maximum = 10;
|
|
option.minimum = 0;
|
|
option.sliderPosition = option.sliderValue = 4;
|
|
option.pageStep = 2;
|
|
// Adjust coordinates to make the widget appear to be at (0,0), i.e. make
|
|
// widget and screen coordinates the same. QStyle functions should use screen
|
|
// coordinates but at least QPlastiqueStyle::subControlRect() is buggy
|
|
// and sometimes uses widget coordinates.
|
|
QRect rect = contentRect;
|
|
rect.moveTo( 0, 0 );
|
|
option.rect = rect;
|
|
rect = kapp->style()->subControlRect( QStyle::CC_ScrollBar, &option,
|
|
QStyle::SC_ScrollBarGroove );
|
|
rect.translate( contentRect.topLeft()); // reverse the workaround above
|
|
contentRect = boundingRect = rect;
|
|
retVal = true;
|
|
}
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
if (retVal)
|
|
{
|
|
// Bounding region
|
|
Point aBPoint( boundingRect.x(), boundingRect.y() );
|
|
Size aBSize( boundingRect.width(), boundingRect.height() );
|
|
nativeBoundingRegion = Rectangle( aBPoint, aBSize );
|
|
|
|
// Region of the content
|
|
Point aPoint( contentRect.x(), contentRect.y() );
|
|
Size aSize( contentRect.width(), contentRect.height() );
|
|
nativeContentRegion = Rectangle( aPoint, aSize );
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
/** Test whether the position is in the native widget.
|
|
If the return value is TRUE, bIsInside contains information whether
|
|
aPos was or was not inside the native widget specified by the
|
|
nType/nPart combination.
|
|
*/
|
|
sal_Bool KDESalGraphics::hitTestNativeControl( ControlType nType, ControlPart nPart,
|
|
const Rectangle& rControlRegion, const Point& rPos,
|
|
sal_Bool& rIsInside )
|
|
{
|
|
if ( nType == CTRL_SCROLLBAR )
|
|
{
|
|
if( nPart != PART_BUTTON_UP && nPart != PART_BUTTON_DOWN
|
|
&& nPart != PART_BUTTON_LEFT && nPart != PART_BUTTON_RIGHT )
|
|
{ // we adjust only for buttons (because some scrollbars have 3 buttons,
|
|
// and LO core doesn't handle such scrollbars well)
|
|
return FALSE;
|
|
}
|
|
rIsInside = FALSE;
|
|
bool bHorizontal = ( nPart == PART_BUTTON_LEFT || nPart == PART_BUTTON_RIGHT );
|
|
QRect rect = region2QRect( rControlRegion );
|
|
QPoint pos( rPos.X(), rPos.Y());
|
|
// Adjust coordinates to make the widget appear to be at (0,0), i.e. make
|
|
// widget and screen coordinates the same. QStyle functions should use screen
|
|
// coordinates but at least QPlastiqueStyle::subControlRect() is buggy
|
|
// and sometimes uses widget coordinates.
|
|
pos -= rect.topLeft();
|
|
rect.moveTo( 0, 0 );
|
|
QStyleOptionSlider options;
|
|
options.orientation = bHorizontal ? Qt::Horizontal : Qt::Vertical;
|
|
if( bHorizontal )
|
|
options.state |= QStyle::State_Horizontal;
|
|
options.rect = rect;
|
|
// some random sensible values, since we call this code only for scrollbar buttons,
|
|
// the slider position does not exactly matter
|
|
options.maximum = 10;
|
|
options.minimum = 0;
|
|
options.sliderPosition = options.sliderValue = 4;
|
|
options.pageStep = 2;
|
|
QStyle::SubControl control = kapp->style()->hitTestComplexControl( QStyle::CC_ScrollBar, &options, pos );
|
|
if( nPart == PART_BUTTON_UP || nPart == PART_BUTTON_LEFT )
|
|
rIsInside = ( control == QStyle::SC_ScrollBarSubLine );
|
|
else // DOWN, RIGHT
|
|
rIsInside = ( control == QStyle::SC_ScrollBarAddLine );
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|