1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #define Region QtXRegion
23 #include <QStyleOption>
28 #include <kapplication.h>
33 #include "KDESalGraphics.hxx"
34 #include "KDESalInstance.hxx"
36 #include <vcl/settings.hxx>
37 #include <vcl/decoview.hxx>
38 #include <rtl/ustrbuf.hxx>
39 #include <unx/saldata.hxx>
41 using namespace ::rtl
;
44 Conversion function between VCL ControlState together with
45 ImplControlValue and Qt state flags.
46 @param nControlState State of the widget (default, focused, ...) in Native Widget Framework.
47 @param aValue Value held by the widget (on, off, ...)
49 QStyle::State
vclStateValue2StateFlag( ControlState nControlState
,
50 const ImplControlValue
& aValue
)
52 QStyle::State nState
=
53 ( (nControlState
& CTRL_STATE_DEFAULT
)? QStyle::State_None
: QStyle::State_None
) |
54 ( (nControlState
& CTRL_STATE_ENABLED
)? QStyle::State_Enabled
: QStyle::State_None
) |
55 ( (nControlState
& CTRL_STATE_FOCUSED
)? QStyle::State_HasFocus
: QStyle::State_None
) |
56 ( (nControlState
& CTRL_STATE_PRESSED
)? QStyle::State_Sunken
: QStyle::State_None
) |
57 ( (nControlState
& CTRL_STATE_SELECTED
)? QStyle::State_Selected
: QStyle::State_None
) |
58 ( (nControlState
& CTRL_STATE_ROLLOVER
)? QStyle::State_MouseOver
: QStyle::State_None
);
59 //TODO ( (nControlState & CTRL_STATE_HIDDEN)? QStyle::State_: QStyle::State_None ) |
61 switch ( aValue
.getTristateVal() )
63 case BUTTONVALUE_ON
: nState
|= QStyle::State_On
; break;
64 case BUTTONVALUE_OFF
: nState
|= QStyle::State_Off
; break;
65 case BUTTONVALUE_MIXED
: nState
|= QStyle::State_NoChange
; break;
73 Convert VCL Rectangle to QRect.
74 @param rControlRegion The Rectangle to convert.
75 @return The matching QRect
77 QRect
region2QRect( const Rectangle
& rControlRegion
)
79 return QRect(rControlRegion
.Left(), rControlRegion
.Top(), rControlRegion
.GetWidth(), rControlRegion
.GetHeight());
82 KDESalGraphics::KDESalGraphics() :
87 KDESalGraphics::~KDESalGraphics()
93 bool KDESalGraphics::IsNativeControlSupported( ControlType type
, ControlPart part
)
95 if (type
== CTRL_PUSHBUTTON
) return true;
97 if (type
== CTRL_MENUBAR
) return true;
99 if (type
== CTRL_MENU_POPUP
) return true;
101 if (type
== CTRL_EDITBOX
) return true;
103 if (type
== CTRL_COMBOBOX
) return true;
105 if (type
== CTRL_TOOLBAR
) return true;
107 if (type
== CTRL_CHECKBOX
) return true;
109 if (type
== CTRL_LISTBOX
) return true;
111 if (type
== CTRL_LISTNODE
) return true;
113 if (type
== CTRL_FRAME
) return true;
115 if (type
== CTRL_SCROLLBAR
) return true;
117 if (type
== CTRL_WINDOW_BACKGROUND
) return true;
119 if (type
== CTRL_SPINBOX
&& (part
== PART_ENTIRE_CONTROL
|| part
== HAS_BACKGROUND_TEXTURE
) ) return true;
121 // no spinbuttons for KDE, paint spinbox complete
122 //if (type == CTRL_SPINBUTTONS) return true;
124 if (type
== CTRL_GROUPBOX
) return true;
126 if (type
== CTRL_FIXEDLINE
) return true;
128 if (type
== CTRL_TOOLTIP
) return true;
130 if (type
== CTRL_RADIOBUTTON
) return true;
132 if (type
== CTRL_SLIDER
&& (part
== PART_TRACK_HORZ_AREA
|| part
== PART_TRACK_VERT_AREA
) )
135 if ( (type
== CTRL_PROGRESS
) && (part
== PART_ENTIRE_CONTROL
) ) return true;
140 /// helper drawing methods
143 void draw( QStyle::ControlElement element
, QStyleOption
* option
, QImage
* image
, QStyle::State state
, QRect rect
= QRect())
145 option
->state
|= state
;
146 option
->rect
= !rect
.isNull() ? rect
: image
->rect();
148 QPainter
painter(image
);
149 kapp
->style()->drawControl(element
, option
, &painter
);
152 void draw( QStyle::PrimitiveElement element
, QStyleOption
* option
, QImage
* image
, QStyle::State state
, QRect rect
= QRect())
154 option
->state
|= state
;
155 option
->rect
= !rect
.isNull() ? rect
: image
->rect();
157 QPainter
painter(image
);
158 kapp
->style()->drawPrimitive(element
, option
, &painter
);
161 void draw( QStyle::ComplexControl element
, QStyleOptionComplex
* option
, QImage
* image
, QStyle::State state
)
163 option
->state
|= state
;
164 option
->rect
= image
->rect();
166 QPainter
painter(image
);
167 kapp
->style()->drawComplexControl(element
, option
, &painter
);
170 void lcl_drawFrame(QStyle::PrimitiveElement element
, QImage
* image
, QStyle::State state
)
172 #if ( QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 ) )
173 QStyleOptionFrameV3 option
;
174 option
.frameShape
= QFrame::StyledPanel
;
175 option
.state
= QStyle::State_Sunken
;
177 QStyleOptionFrame option
;
179 QFrame
aFrame( NULL
);
180 aFrame
.setFrameRect( QRect(0, 0, image
->width(), image
->height()) );
181 aFrame
.setFrameStyle( QFrame::StyledPanel
| QFrame::Sunken
);
182 aFrame
.ensurePolished();
184 option
.initFrom( &aFrame
);
185 option
.lineWidth
= aFrame
.lineWidth();
186 option
.midLineWidth
= aFrame
.midLineWidth();
189 draw(element
, &option
, image
, state
);
193 #if QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 )
194 #define IMAGE_BASED_PAINTING
196 #undef IMAGE_BASED_PAINTING
199 #ifdef IMAGE_BASED_PAINTING
200 // There is a small catch with this function, although hopefully only philosophical.
201 // Officially Xlib's Region is an opaque data type, with only functions for manipulating it.
202 // However, whoever designed it apparently didn't give it that much thought, as it's impossible
203 // to find out what exactly a region actually is (except for really weird ways like XClipBox()
204 // and repeated XPointInRegion(), which would be awfully slow). Fortunately, the header file
205 // describing the structure actually happens to be installed too, and there's at least one
206 // widely used software using it (Compiz). So access the data directly too and assume that
207 // everybody who compiles with Qt4 support has Xlib new enough and good enough to support this.
208 // In case this doesn't work for somebody, try #include <X11/region.h> instead, or build
209 // without IMAGE_BASED_PAINTING (in which case QApplication::setGraphicsSystem( "native" ) may
211 #include <X11/Xregion.h>
212 static QRegion
XRegionToQRegion( XLIB_Region xr
)
219 BOX
& b
= xr
->rects
[ i
];
220 qr
|= QRect( b
.x1
, b
.y1
, b
.x2
- b
.x1
, b
.y2
- b
.y1
); // x2,y2 is outside, not the bottom-right corner
226 bool KDESalGraphics::drawNativeControl( ControlType type
, ControlPart part
,
227 const Rectangle
& rControlRegion
, ControlState nControlState
,
228 const ImplControlValue
& value
,
231 if( lastPopupRect
.isValid() && ( type
!= CTRL_MENU_POPUP
|| part
!= PART_MENU_ITEM
))
232 lastPopupRect
= QRect();
234 // put not implemented types here
235 if (type
== CTRL_SPINBUTTONS
)
240 bool returnVal
= true;
242 QRect widgetRect
= region2QRect(rControlRegion
);
243 if( type
== CTRL_SPINBOX
&& part
== PART_ALL_BUTTONS
)
244 type
= CTRL_SPINBUTTONS
;
245 if( type
== CTRL_SPINBUTTONS
)
247 OSL_ASSERT( value
.getType() != CTRL_SPINBUTTONS
);
248 const SpinbuttonValue
* pSpinVal
= static_cast<const SpinbuttonValue
*>(&value
);
249 Rectangle
aButtonRect( pSpinVal
->maUpperRect
);
250 aButtonRect
.Union( pSpinVal
->maLowerRect
);
251 widgetRect
= QRect( aButtonRect
.Left(), aButtonRect
.Top(),
252 aButtonRect
.Right(), aButtonRect
.Bottom() );
255 //if no image, or resized, make a new image
256 if (!m_image
|| m_image
->size() != widgetRect
.size())
261 m_image
= new QImage( widgetRect
.width(),
263 QImage::Format_ARGB32
);
265 m_image
->fill(KApplication::palette().color(QPalette::Window
).rgb());
267 QRegion
* clipRegion
= NULL
;
269 if (type
== CTRL_PUSHBUTTON
)
271 m_image
->fill( Qt::transparent
);
272 QStyleOptionButton option
;
273 draw( QStyle::CE_PushButton
, &option
, m_image
,
274 vclStateValue2StateFlag(nControlState
, value
) );
276 else if (type
== CTRL_MENUBAR
)
278 if (part
== PART_MENU_ITEM
)
280 QStyleOptionMenuItem option
;
281 if ( ( nControlState
& CTRL_STATE_ROLLOVER
)
282 && kapp
->style()->styleHint( QStyle::SH_MenuBar_MouseTracking
) )
283 option
.state
|= QStyle::State_Selected
;
285 if ( nControlState
& CTRL_STATE_SELECTED
) // Passing State_Sunken is currently not documented.
286 option
.state
|= QStyle::State_Sunken
; // But some kinds of QStyle interpret it.
288 draw( QStyle::CE_MenuBarItem
, &option
, m_image
,
289 vclStateValue2StateFlag(nControlState
, value
) );
291 else if (part
== PART_ENTIRE_CONTROL
)
293 QStyleOptionMenuItem option
;
294 draw( QStyle::CE_MenuBarEmptyArea
, &option
, m_image
,
295 vclStateValue2StateFlag(nControlState
, value
) );
302 else if (type
== CTRL_MENU_POPUP
)
304 OSL_ASSERT( part
== PART_MENU_ITEM
? lastPopupRect
.isValid() : !lastPopupRect
.isValid());
305 if( part
== PART_MENU_ITEM
)
307 QStyleOptionMenuItem option
;
308 draw( QStyle::CE_MenuItem
, &option
, m_image
,
309 vclStateValue2StateFlag(nControlState
, value
) );
310 // HACK: LO core first paints the entire popup and only then it paints menu items,
311 // but QMenu::paintEvent() paints popup frame after all items. That means highlighted
312 // items here would paint the highlight over the frame border. Since calls to PART_MENU_ITEM
313 // are always preceded by calls to PART_ENTIRE_CONTROL, just remember the size for the whole
314 // popup (otherwise not possible to get here) and draw the border afterwards.
315 QRect
framerect( lastPopupRect
.topLeft() - widgetRect
.topLeft(),
316 widgetRect
.size().expandedTo( lastPopupRect
.size()));
317 QStyleOptionFrame frame
;
318 draw( QStyle::PE_FrameMenu
, &frame
, m_image
, vclStateValue2StateFlag( nControlState
, value
), framerect
);
320 else if( part
== PART_MENU_SEPARATOR
)
322 QStyleOptionMenuItem option
;
323 option
.menuItemType
= QStyleOptionMenuItem::Separator
;
324 // Painting the whole menu item area results in different background
325 // with at least Plastique style, so clip only to the separator itself
326 // (QSize( 2, 2 ) is hardcoded in Qt)
327 option
.rect
= m_image
->rect();
328 QSize size
= kapp
->style()->sizeFromContents( QStyle::CT_MenuItem
, &option
, QSize( 2, 2 ));
329 QRect rect
= m_image
->rect();
330 QPoint center
= rect
.center();
331 rect
.setHeight( size
.height());
332 rect
.moveCenter( center
);
333 // don't paint over popup frame border (like the hack above, but here it can be simpler)
334 int fw
= kapp
->style()->pixelMetric( QStyle::PM_MenuPanelWidth
);
335 clipRegion
= new QRegion( rect
.translated( widgetRect
.topLeft()).adjusted( fw
, 0, -fw
, 0 ));
336 draw( QStyle::CE_MenuItem
, &option
, m_image
,
337 vclStateValue2StateFlag(nControlState
, value
), rect
);
339 else if( part
== PART_MENU_ITEM_CHECK_MARK
|| part
== PART_MENU_ITEM_RADIO_MARK
)
341 QStyleOptionMenuItem option
;
342 option
.checkType
= ( part
== PART_MENU_ITEM_CHECK_MARK
)
343 ? QStyleOptionMenuItem::NonExclusive
: QStyleOptionMenuItem::Exclusive
;
344 option
.checked
= ( nControlState
& CTRL_STATE_PRESSED
);
345 // widgetRect is now the rectangle for the checkbox/radiobutton itself, but Qt
346 // paints the whole menu item, so translate position (and it'll be clipped);
347 // it is also necessary to fill the background transparently first, as this
348 // is painted after menuitem highlight, otherwise there would be a grey area
349 assert( value
.getType() == CTRL_MENU_POPUP
);
350 const MenupopupValue
* menuVal
= static_cast<const MenupopupValue
*>(&value
);
351 QRect
menuItemRect( region2QRect( menuVal
->maItemRect
));
352 QRect
rect( menuItemRect
.topLeft() - widgetRect
.topLeft(),
353 widgetRect
.size().expandedTo( menuItemRect
.size()));
354 m_image
->fill( Qt::transparent
);
355 draw( QStyle::CE_MenuItem
, &option
, m_image
,
356 vclStateValue2StateFlag(nControlState
, value
), rect
);
358 else if( part
== PART_ENTIRE_CONTROL
)
360 QStyleOptionMenuItem option
;
361 draw( QStyle::PE_PanelMenu
, &option
, m_image
, vclStateValue2StateFlag( nControlState
, value
));
362 // Try hard to get any frame!
363 QStyleOptionFrame frame
;
364 draw( QStyle::PE_FrameMenu
, &frame
, m_image
, vclStateValue2StateFlag( nControlState
, value
));
365 draw( QStyle::PE_FrameWindow
, &frame
, m_image
, vclStateValue2StateFlag( nControlState
, value
));
366 lastPopupRect
= widgetRect
;
371 else if ( (type
== CTRL_TOOLBAR
) && (part
== PART_BUTTON
) )
373 m_image
->fill( Qt::transparent
);
374 QStyleOptionToolButton option
;
376 option
.arrowType
= Qt::NoArrow
;
377 option
.subControls
= QStyle::SC_ToolButton
;
379 option
.state
= vclStateValue2StateFlag( nControlState
, value
);
380 option
.state
|= QStyle::State_Raised
| QStyle::State_Enabled
| QStyle::State_AutoRaise
;
382 draw( QStyle::CC_ToolButton
, &option
, m_image
,
383 vclStateValue2StateFlag(nControlState
, value
) );
385 else if ( (type
== CTRL_TOOLBAR
) && (part
== PART_ENTIRE_CONTROL
) )
387 QStyleOptionToolBar option
;
389 option
.rect
= QRect(0, 0, widgetRect
.width(), widgetRect
.height());
390 option
.state
= vclStateValue2StateFlag( nControlState
, value
);
392 draw( QStyle::CE_ToolBar
, &option
, m_image
,
393 vclStateValue2StateFlag(nControlState
, value
) );
395 else if ( (type
== CTRL_TOOLBAR
) && (part
== PART_THUMB_VERT
) )
396 { // reduce paint area only to the handle area
397 const int width
= kapp
->style()->pixelMetric(QStyle::PM_ToolBarHandleExtent
);
398 QRect
rect( 0, 0, width
, widgetRect
.height());
399 clipRegion
= new QRegion( widgetRect
.x(), widgetRect
.y(), width
, widgetRect
.height());
402 option
.state
= QStyle::State_Horizontal
;
404 draw( QStyle::PE_IndicatorToolBarHandle
, &option
, m_image
,
405 vclStateValue2StateFlag(nControlState
, value
), rect
);
407 else if (type
== CTRL_EDITBOX
)
409 QStyleOptionFrameV2 option
;
410 draw( QStyle::PE_PanelLineEdit
, &option
, m_image
,
411 vclStateValue2StateFlag(nControlState
, value
), m_image
->rect().adjusted( 2, 2, -2, -2 ));
413 draw( QStyle::PE_FrameLineEdit
, &option
, m_image
,
414 vclStateValue2StateFlag(nControlState
, value
));
416 else if (type
== CTRL_COMBOBOX
)
418 QStyleOptionComboBox option
;
419 option
.editable
= true;
421 draw( QStyle::CC_ComboBox
, &option
, m_image
,
422 vclStateValue2StateFlag(nControlState
, value
) );
424 else if (type
== CTRL_LISTBOX
)
426 if( part
== PART_WINDOW
)
428 lcl_drawFrame( QStyle::PE_Frame
, m_image
,
429 vclStateValue2StateFlag(nControlState
, value
) );
433 QStyleOptionComboBox option
;
434 if (part
== PART_SUB_EDIT
)
436 draw( QStyle::CE_ComboBoxLabel
, &option
, m_image
,
437 vclStateValue2StateFlag(nControlState
, value
) );
441 draw( QStyle::CC_ComboBox
, &option
, m_image
,
442 vclStateValue2StateFlag(nControlState
, value
) );
446 else if (type
== CTRL_LISTNODE
)
448 m_image
->fill( Qt::transparent
);
450 option
.state
= QStyle::State_Item
| QStyle::State_Children
;
452 if (value
.getTristateVal() == BUTTONVALUE_ON
)
453 option
.state
|= QStyle::State_Open
;
455 draw( QStyle::PE_IndicatorBranch
, &option
, m_image
,
456 vclStateValue2StateFlag(nControlState
, value
) );
458 else if (type
== CTRL_CHECKBOX
)
460 m_image
->fill( Qt::transparent
);
461 QStyleOptionButton option
;
462 draw( QStyle::CE_CheckBox
, &option
, m_image
,
463 vclStateValue2StateFlag(nControlState
, value
) );
465 else if (type
== CTRL_SCROLLBAR
)
467 if ((part
== PART_DRAW_BACKGROUND_VERT
) || (part
== PART_DRAW_BACKGROUND_HORZ
))
469 QStyleOptionSlider option
;
470 OSL_ASSERT( value
.getType() == CTRL_SCROLLBAR
);
471 const ScrollbarValue
* sbVal
= static_cast<const ScrollbarValue
*>(&value
);
473 //if the scroll bar is active (aka not degenrate...allow for hover events
474 if (sbVal
->mnVisibleSize
< sbVal
->mnMax
)
475 option
.state
= QStyle::State_MouseOver
;
477 bool horizontal
= ( part
== PART_DRAW_BACKGROUND_HORZ
); //horizontal or vertical
478 option
.orientation
= horizontal
? Qt::Horizontal
: Qt::Vertical
;
480 option
.state
|= QStyle::State_Horizontal
;
482 //setup parameters from the OO values
483 option
.minimum
= sbVal
->mnMin
;
484 option
.maximum
= sbVal
->mnMax
- sbVal
->mnVisibleSize
;
485 option
.maximum
= qMax( option
.maximum
, option
.minimum
); // bnc#619772
486 option
.sliderValue
= sbVal
->mnCur
;
487 option
.sliderPosition
= sbVal
->mnCur
;
488 option
.pageStep
= sbVal
->mnVisibleSize
;
490 //setup the active control...always the slider
491 if (sbVal
->mnThumbState
& CTRL_STATE_ROLLOVER
)
492 option
.activeSubControls
= QStyle::SC_ScrollBarSlider
;
494 draw( QStyle::CC_ScrollBar
, &option
, m_image
,
495 vclStateValue2StateFlag(nControlState
, value
) );
502 else if (type
== CTRL_SPINBOX
)
504 QStyleOptionSpinBox option
;
506 // determine active control
507 if( value
.getType() == CTRL_SPINBUTTONS
)
509 const SpinbuttonValue
* pSpinVal
= static_cast<const SpinbuttonValue
*>(&value
);
510 if( (pSpinVal
->mnUpperState
& CTRL_STATE_PRESSED
) )
511 option
.activeSubControls
|= QStyle::SC_SpinBoxUp
;
512 if( (pSpinVal
->mnLowerState
& CTRL_STATE_PRESSED
) )
513 option
.activeSubControls
|= QStyle::SC_SpinBoxDown
;
516 draw( QStyle::CC_SpinBox
, &option
, m_image
,
517 vclStateValue2StateFlag(nControlState
, value
) );
519 else if (type
== CTRL_GROUPBOX
)
521 QStyleOptionGroupBox option
;
522 draw( QStyle::CC_GroupBox
, &option
, m_image
,
523 vclStateValue2StateFlag(nControlState
, value
) );
525 else if (type
== CTRL_RADIOBUTTON
)
527 m_image
->fill( Qt::transparent
);
528 QStyleOptionButton option
;
529 draw( QStyle::CE_RadioButton
, &option
, m_image
,
530 vclStateValue2StateFlag(nControlState
, value
) );
532 else if (type
== CTRL_TOOLTIP
)
535 draw( QStyle::PE_PanelTipLabel
, &option
, m_image
,
536 vclStateValue2StateFlag(nControlState
, value
) );
538 else if (type
== CTRL_FRAME
)
540 lcl_drawFrame( QStyle::PE_Frame
, m_image
,
541 vclStateValue2StateFlag(nControlState
, value
) );
543 // draw just the border, see http://qa.openoffice.org/issues/show_bug.cgi?id=107945
544 int fw
= static_cast< KDESalInstance
* >(GetSalData()->m_pInstance
)->getFrameWidth();
545 clipRegion
= new QRegion( QRegion( widgetRect
).subtracted( widgetRect
.adjusted( fw
, fw
, -fw
, -fw
)));
547 else if (type
== CTRL_WINDOW_BACKGROUND
)
549 m_image
->fill(KApplication::palette().color(QPalette::Window
).rgb());
551 else if (type
== CTRL_FIXEDLINE
)
553 QStyleOptionMenuItem option
;
554 option
.menuItemType
= QStyleOptionMenuItem::Separator
;
555 option
.state
|= QStyle::State_Item
;
557 draw( QStyle::CE_MenuItem
, &option
, m_image
,
558 vclStateValue2StateFlag(nControlState
, value
) );
560 else if (type
== CTRL_SLIDER
&& (part
== PART_TRACK_HORZ_AREA
|| part
== PART_TRACK_VERT_AREA
))
562 OSL_ASSERT( value
.getType() == CTRL_SLIDER
);
563 const SliderValue
* slVal
= static_cast<const SliderValue
*>(&value
);
564 QStyleOptionSlider option
;
566 option
.rect
= QRect(0, 0, widgetRect
.width(), widgetRect
.height());
567 option
.state
= vclStateValue2StateFlag( nControlState
, value
);
568 option
.maximum
= slVal
->mnMax
;
569 option
.minimum
= slVal
->mnMin
;
570 option
.sliderPosition
= option
.sliderValue
= slVal
->mnCur
;
571 bool horizontal
= ( part
== PART_TRACK_HORZ_AREA
); //horizontal or vertical
572 option
.orientation
= horizontal
? Qt::Horizontal
: Qt::Vertical
;
574 option
.state
|= QStyle::State_Horizontal
;
576 draw( QStyle::CC_Slider
, &option
, m_image
, vclStateValue2StateFlag(nControlState
, value
) );
578 else if( type
== CTRL_PROGRESS
&& part
== PART_ENTIRE_CONTROL
)
580 QStyleOptionProgressBarV2 option
;
582 option
.maximum
= widgetRect
.width();
583 option
.progress
= value
.getNumericVal();
584 option
.rect
= QRect(0, 0, widgetRect
.width(), widgetRect
.height());
585 option
.state
= vclStateValue2StateFlag( nControlState
, value
);
587 draw( QStyle::CE_ProgressBar
, &option
, m_image
,
588 vclStateValue2StateFlag(nControlState
, value
) );
597 #ifdef IMAGE_BASED_PAINTING
598 // Create a wrapper QPixmap around the destination pixmap, allowing the use of QPainter.
599 // Using X11SalGraphics::CopyScreenArea() would require using QPixmap and if Qt uses
600 // other graphics system than native, QPixmap::handle() would be 0 (i.e. it wouldn't work),
601 // I have no idea how to create QPixmap with non-null handle() in such case, so go this way.
602 // See XRegionToQRegion() comment for a small catch (although not real hopefully).
603 QPixmap destPixmap
= QPixmap::fromX11Pixmap( GetDrawable(), QPixmap::ExplicitlyShared
);
604 QPainter
paint( &destPixmap
);
605 if( clipRegion
&& mpClipRegion
)
606 paint
.setClipRegion( clipRegion
->intersected( XRegionToQRegion( mpClipRegion
)));
607 else if( clipRegion
)
608 paint
.setClipRegion( *clipRegion
);
609 else if( mpClipRegion
)
610 paint
.setClipRegion( XRegionToQRegion( mpClipRegion
));
611 paint
.drawImage( widgetRect
.left(), widgetRect
.top(), *m_image
,
612 0, 0, widgetRect
.width(), widgetRect
.height(),
613 Qt::ColorOnly
| Qt::OrderedDither
| Qt::OrderedAlphaDither
);
618 XLIB_Region pTempClipRegion
= NULL
;
621 pTempClipRegion
= XCreateRegion();
622 foreach( const QRect
& r
, clipRegion
->rects())
627 xr
.width
= r
.width();
628 xr
.height
= r
.height();
629 XUnionRectWithRegion( &xr
, pTempClipRegion
, pTempClipRegion
);
632 XIntersectRegion( pTempClipRegion
, mpClipRegion
, pTempClipRegion
);
633 XSetRegion( GetXDisplay(), gc
, pTempClipRegion
);
635 QPixmap pixmap
= QPixmap::fromImage(*m_image
, Qt::ColorOnly
| Qt::OrderedDither
| Qt::OrderedAlphaDither
);
636 X11SalGraphics::CopyScreenArea( GetXDisplay(),
637 pixmap
.handle(), pixmap
.x11Info().screen(), pixmap
.x11Info().depth(),
638 GetDrawable(), GetScreenNumber(), GetVisual().GetDepth(),
639 gc
, 0, 0, widgetRect
.width(), widgetRect
.height(), widgetRect
.left(), widgetRect
.top());
641 if( pTempClipRegion
)
644 XSetRegion( GetXDisplay(), gc
, mpClipRegion
);
646 XSetClipMask( GetXDisplay(), gc
, None
);
647 XDestroyRegion( pTempClipRegion
);
658 bool KDESalGraphics::getNativeControlRegion( ControlType type
, ControlPart part
,
659 const Rectangle
& controlRegion
, ControlState controlState
,
660 const ImplControlValue
& val
,
662 Rectangle
&nativeBoundingRegion
, Rectangle
&nativeContentRegion
)
666 QRect boundingRect
= region2QRect( controlRegion
);
667 QRect contentRect
= boundingRect
;
668 QStyleOptionComplex styleOption
;
672 // Metrics of the push button
673 case CTRL_PUSHBUTTON
:
674 if (part
== PART_ENTIRE_CONTROL
)
676 styleOption
.state
= vclStateValue2StateFlag(controlState
, val
);
678 if ( controlState
& CTRL_STATE_DEFAULT
)
680 int size
= kapp
->style()->pixelMetric(
681 QStyle::PM_ButtonDefaultIndicator
, &styleOption
);
683 boundingRect
.adjust( -size
, -size
, size
, size
);
691 int nFontHeight
= kapp
->fontMetrics().height();
692 //int nFrameSize = kapp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
693 int nLayoutTop
= kapp
->style()->pixelMetric(QStyle::PM_LayoutTopMargin
);
694 int nLayoutBottom
= kapp
->style()->pixelMetric(QStyle::PM_LayoutBottomMargin
);
695 int nLayoutLeft
= kapp
->style()->pixelMetric(QStyle::PM_LayoutLeftMargin
);
696 int nLayoutRight
= kapp
->style()->pixelMetric(QStyle::PM_LayoutRightMargin
);
698 int nMinHeight
= (nFontHeight
+ nLayoutTop
+ nLayoutBottom
);
699 if( boundingRect
.height() < nMinHeight
)
701 int delta
= nMinHeight
- boundingRect
.height();
702 boundingRect
.adjust( 0, 0, 0, delta
);
704 contentRect
= boundingRect
;
705 contentRect
.adjust( -nLayoutLeft
+1, -nLayoutTop
+1, nLayoutRight
-1, nLayoutBottom
-1 );
711 if (part
== PART_ENTIRE_CONTROL
)
713 styleOption
.state
= vclStateValue2StateFlag(controlState
, val
);
715 contentRect
.setWidth(kapp
->style()->pixelMetric(
716 QStyle::PM_IndicatorWidth
, &styleOption
));
717 contentRect
.setHeight(kapp
->style()->pixelMetric(
718 QStyle::PM_IndicatorHeight
, &styleOption
));
720 contentRect
.adjust(0, 0,
721 2 * kapp
->style()->pixelMetric(
722 QStyle::PM_FocusFrameHMargin
, &styleOption
),
723 2 * kapp
->style()->pixelMetric(
724 QStyle::PM_FocusFrameVMargin
, &styleOption
)
727 boundingRect
= contentRect
;
736 QStyleOptionComboBox cbo
;
738 cbo
.rect
= QRect(0, 0, contentRect
.width(), contentRect
.height());
739 cbo
.state
= vclStateValue2StateFlag(controlState
, val
);
743 case PART_ENTIRE_CONTROL
:
745 int size
= kapp
->style()->pixelMetric(QStyle::PM_ComboBoxFrameWidth
) - 2;
747 // find out the minimum size that should be used
748 // assume contents is a text ling
749 int nHeight
= kapp
->fontMetrics().height();
750 QSize
aContentSize( contentRect
.width(), nHeight
);
751 QSize aMinSize
= kapp
->style()->
752 sizeFromContents( QStyle::CT_ComboBox
, &cbo
, aContentSize
);
753 if( aMinSize
.height() > contentRect
.height() )
754 contentRect
.adjust( 0, 0, 0, aMinSize
.height() - contentRect
.height() );
755 boundingRect
= contentRect
;
756 // FIXME: why this difference between comboboxes and listboxes ?
757 // because a combobox has a sub edit and that is positioned
758 // inside the outer bordered control ?
759 if( type
== CTRL_COMBOBOX
)
760 contentRect
.adjust(-size
,-size
,size
,size
);
764 case PART_BUTTON_DOWN
:
765 contentRect
= kapp
->style()->subControlRect(
766 QStyle::CC_ComboBox
, &cbo
, QStyle::SC_ComboBoxArrow
);
768 contentRect
.translate( boundingRect
.left(), boundingRect
.top() );
773 contentRect
= kapp
->style()->subControlRect(
774 QStyle::CC_ComboBox
, &cbo
, QStyle::SC_ComboBoxEditField
);
776 contentRect
.translate( boundingRect
.left(), boundingRect
.top() );
788 QStyleOptionSpinBox sbo
;
790 sbo
.rect
= QRect(0, 0, contentRect
.width(), contentRect
.height());
791 sbo
.state
= vclStateValue2StateFlag(controlState
, val
);
796 contentRect
= kapp
->style()->subControlRect(
797 QStyle::CC_SpinBox
, &sbo
, QStyle::SC_SpinBoxUp
);
798 contentRect
.translate( boundingRect
.left(), boundingRect
.top() );
800 boundingRect
= QRect();
803 case PART_BUTTON_DOWN
:
804 contentRect
= kapp
->style()->subControlRect(
805 QStyle::CC_SpinBox
, &sbo
, QStyle::SC_SpinBoxDown
);
807 contentRect
.translate( boundingRect
.left(), boundingRect
.top() );
808 boundingRect
= QRect();
812 contentRect
= kapp
->style()->subControlRect(
813 QStyle::CC_SpinBox
, &sbo
, QStyle::SC_SpinBoxEditField
);
815 contentRect
.translate( boundingRect
.left(), boundingRect
.top() );
822 case CTRL_MENU_POPUP
:
826 case PART_MENU_ITEM_CHECK_MARK
:
827 h
= kapp
->style()->pixelMetric(QStyle::PM_IndicatorHeight
);
828 w
= kapp
->style()->pixelMetric(QStyle::PM_IndicatorWidth
);
831 case PART_MENU_ITEM_RADIO_MARK
:
832 h
= kapp
->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorHeight
);
833 w
= kapp
->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth
);
838 contentRect
= QRect(0, 0, w
, h
);
839 boundingRect
= contentRect
;
845 if( part
== PART_BORDER
)
847 int nFrameWidth
= static_cast< KDESalInstance
* >(GetSalData()->m_pInstance
)->getFrameWidth();
848 sal_uInt16 nStyle
= val
.getNumericVal();
849 if( nStyle
& FRAME_DRAW_NODRAW
)
851 // in this case the question is: how thick would a frame be
852 // see brdwin.cxx, decoview.cxx
853 // most probably the behavior in decoview.cxx is wrong.
854 contentRect
.adjust(nFrameWidth
, nFrameWidth
, -nFrameWidth
, -nFrameWidth
);
860 case CTRL_RADIOBUTTON
:
862 const int h
= kapp
->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorHeight
);
863 const int w
= kapp
->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth
);
865 contentRect
= QRect(boundingRect
.left(), boundingRect
.top(), w
, h
);
866 contentRect
.adjust(0, 0,
867 2 * kapp
->style()->pixelMetric(
868 QStyle::PM_FocusFrameHMargin
, &styleOption
),
869 2 * kapp
->style()->pixelMetric(
870 QStyle::PM_FocusFrameVMargin
, &styleOption
)
872 boundingRect
= contentRect
;
879 const int w
= kapp
->style()->pixelMetric(QStyle::PM_SliderLength
);
880 if( part
== PART_THUMB_HORZ
)
882 contentRect
= QRect(boundingRect
.left(), boundingRect
.top(), w
, boundingRect
.height());
883 boundingRect
= contentRect
;
886 else if( part
== PART_THUMB_VERT
)
888 contentRect
= QRect(boundingRect
.left(), boundingRect
.top(), boundingRect
.width(), w
);
889 boundingRect
= contentRect
;
896 // core can't handle 3-button scrollbars well, so we fix that in hitTestNativeControl(),
897 // for the rest also provide the track area (i.e. area not taken by buttons)
898 if( part
== PART_TRACK_VERT_AREA
|| part
== PART_TRACK_HORZ_AREA
)
900 QStyleOptionSlider option
;
901 bool horizontal
= ( part
== PART_TRACK_HORZ_AREA
); //horizontal or vertical
902 option
.orientation
= horizontal
? Qt::Horizontal
: Qt::Vertical
;
904 option
.state
|= QStyle::State_Horizontal
;
905 // getNativeControlRegion usually gets ImplControlValue as 'val' (i.e. not the proper
906 // subclass), so use random sensible values (doesn't matter anyway, as the wanted
907 // geometry here depends only on button sizes)
910 option
.sliderPosition
= option
.sliderValue
= 4;
912 // Adjust coordinates to make the widget appear to be at (0,0), i.e. make
913 // widget and screen coordinates the same. QStyle functions should use screen
914 // coordinates but at least QPlastiqueStyle::subControlRect() is buggy
915 // and sometimes uses widget coordinates.
916 QRect rect
= contentRect
;
919 rect
= kapp
->style()->subControlRect( QStyle::CC_ScrollBar
, &option
,
920 QStyle::SC_ScrollBarGroove
);
921 rect
.translate( contentRect
.topLeft()); // reverse the workaround above
922 contentRect
= boundingRect
= rect
;
932 Point
aBPoint( boundingRect
.x(), boundingRect
.y() );
933 Size
aBSize( boundingRect
.width(), boundingRect
.height() );
934 nativeBoundingRegion
= Rectangle( aBPoint
, aBSize
);
936 // Region of the content
937 Point
aPoint( contentRect
.x(), contentRect
.y() );
938 Size
aSize( contentRect
.width(), contentRect
.height() );
939 nativeContentRegion
= Rectangle( aPoint
, aSize
);
945 /** Test whether the position is in the native widget.
946 If the return value is TRUE, bIsInside contains information whether
947 aPos was or was not inside the native widget specified by the
948 nType/nPart combination.
950 bool KDESalGraphics::hitTestNativeControl( ControlType nType
, ControlPart nPart
,
951 const Rectangle
& rControlRegion
, const Point
& rPos
,
954 if ( nType
== CTRL_SCROLLBAR
)
956 if( nPart
!= PART_BUTTON_UP
&& nPart
!= PART_BUTTON_DOWN
957 && nPart
!= PART_BUTTON_LEFT
&& nPart
!= PART_BUTTON_RIGHT
)
958 { // we adjust only for buttons (because some scrollbars have 3 buttons,
959 // and LO core doesn't handle such scrollbars well)
963 bool bHorizontal
= ( nPart
== PART_BUTTON_LEFT
|| nPart
== PART_BUTTON_RIGHT
);
964 QRect rect
= region2QRect( rControlRegion
);
965 QPoint
pos( rPos
.X(), rPos
.Y());
966 // Adjust coordinates to make the widget appear to be at (0,0), i.e. make
967 // widget and screen coordinates the same. QStyle functions should use screen
968 // coordinates but at least QPlastiqueStyle::subControlRect() is buggy
969 // and sometimes uses widget coordinates.
970 pos
-= rect
.topLeft();
972 QStyleOptionSlider options
;
973 options
.orientation
= bHorizontal
? Qt::Horizontal
: Qt::Vertical
;
975 options
.state
|= QStyle::State_Horizontal
;
977 // some random sensible values, since we call this code only for scrollbar buttons,
978 // the slider position does not exactly matter
979 options
.maximum
= 10;
981 options
.sliderPosition
= options
.sliderValue
= 4;
982 options
.pageStep
= 2;
983 QStyle::SubControl control
= kapp
->style()->hitTestComplexControl( QStyle::CC_ScrollBar
, &options
, pos
);
984 if( nPart
== PART_BUTTON_UP
|| nPart
== PART_BUTTON_LEFT
)
985 rIsInside
= ( control
== QStyle::SC_ScrollBarSubLine
);
987 rIsInside
= ( control
== QStyle::SC_ScrollBarAddLine
);
993 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */